<template>
  <component
    :is="tagName"
    ref="contenteditableEle"
    class="contenteditable-ele"
    :contenteditable="contenteditable"
    @input="inputChange"
    @blur="inputChange"
    @click="$emit('click', $event)"
    @paste="paste"
  >
  </component>
</template>

<script setup lang="ts" name="ContentEditAble">
import { ref, onMounted, withDefaults, watch } from 'vue'
import useVModel from '@/hooks/useVModel'

defineEmits(['click'])

const props = withDefaults(
  defineProps<{
    modelValue?: string
    tagName?: string
    contenteditable?: boolean | string
    autofocus?: boolean
  }>(),
  {
    modelValue: '',
    tagName: 'div',
    contenteditable: true,
    autofocus: true,
  }
)

const contentValue = useVModel(props, 'modelValue')

const contenteditableEle = ref<HTMLElement | null>()

const paste = (event: any) => {
  let e = event || window.event
  // 阻止默认粘贴
  e.preventDefault()
  // 粘贴事件有一个clipboardData的属性，提供了对剪贴板的访问
  // clipboardData的getData(fomat) 从剪贴板获取指定格式的数据
  var text = (e.originalEvent || e).clipboardData.getData('text/plain') || prompt('在这里输入文本')
  //清除回车
  text = text.replace(/\[\d+\]|\n|\r/gi, '')
  // 插入
  if ((contentValue.value || '').length < 2000) {
    document.execCommand('insertText', false, text.substr(0, 2000 - (contentValue.value || '').length))
  }
}

function updateContent(content: string) {
  if (contenteditableEle.value) {
    contenteditableEle.value.innerHTML = content
    placeCaretAtEnd(contenteditableEle.value)
  }
}

function focus() {
  if (contenteditableEle.value) {
    contenteditableEle.value?.focus()
  }
}
function placeCaretAtEnd(el: any) {
  el.focus()
  if (window.getSelection) {
    if (typeof window.getSelection != 'undefined' && typeof document.createRange != 'undefined') {
      var range = document.createRange()
      range.selectNodeContents(el)
      range.collapse(false)
      var sel: any = window.getSelection()
      sel.removeAllRanges()
      sel.addRange(range)
    } else if (typeof (document.body as any).createTextRange != 'undefined') {
      var textRange = (document.body as any).createTextRange()
      textRange.moveToElementText(el)
      textRange.collapse(false)
      textRange.select()
    }
  }
}
function inputChange(event: Event) {
  const target = event.target as HTMLElement
  if (target.innerHTML.length > 2000) {
    target.innerHTML = target.innerHTML.substr(0, 2000)
    placeCaretAtEnd(target)
  }
  contentValue.value = target.innerHTML
}

watch(
  () => props.modelValue,
  () => {
    if (props.modelValue !== contenteditableEle.value?.innerHTML) {
      updateContent(props.modelValue ?? '')
    }
  }
)

onMounted(() => {
  updateContent(contentValue.value ?? '')
  setTimeout(() => {
    focus()
  })
})
</script>

<style scoped lang="scss"></style>
