<template>
    <div ref="textRef" class="input textarea" :class="{ suffix: $slots.icon || maxlength, disabled, right }">
        <div
            ref="inputRef"
            contenteditable="true"
            class="ui-text input-div"
            :placeholder="props.placeholder"
            :readonly="readonly"
            v-bind="other"
            @input="inputHandler"
            @click="emit('click')"
            @focus="focusHandler"
            @blur="blurHandler"
            @paste="pasteHandler"
            @compositionstart="compositionstartHandler"
            @compositionend="compositionendHandler"
        />
        <span class="replace" />
        <span v-if="$slots.icon || props.maxlength" class="retouch">
            <slot name="icon" />
            <span v-if="props.maxlength" class="len">
                <span>{{ length }}</span> / {{ maxlength }}
            </span>
        </span>
    </div>
</template>

<script setup lang="ts">
import { defineEmits, defineExpose, defineProps, nextTick, ref, watchEffect } from 'vue'
import { richTextProps } from './richtext'
const props = defineProps(richTextProps)

const emit = defineEmits(['update:modelValue', 'focus', 'blur', 'click', ''])
const textRef = ref(null)
const inputRef = ref(null)
const length = ref(0)

const updateContent = html => {
    inputRef.value.innerHTML = html
    length.value = inputRef.value.textContent.length
}

watchEffect(() => {
    if (inputRef.value && props.modelValue !== inputRef.value.innerHTML) {
        updateContent(props.modelValue)
    }
})

let inComposition = false
const compositionstartHandler = () => {
    inComposition = true
}
const compositionendHandler = (ev: any) => {
    inComposition = false
    inputHandler(ev)
}

const inputHandler = (ev: any) => {
    if (inComposition) return
    if (!props.maxlength || ev.target.textContent.length <= Number(props.maxlength)) {
        length.value = inputRef.value.textContent.length
        emit('update:modelValue', ev.target.innerHTML)
    } else {
        nextTick(() => {
            if (ev.target.innerHTML !== props.modelValue.toString()) {
                updateContent(props.modelValue.toString())
                inputFocus()
            }
        })
    }
}
//获取当前光标位置
const getCursortPosition = function (element = inputRef.value) {
    let caretOffset = 0
    const doc = element.ownerDocument || element.document
    const win = doc.defaultView || doc.parentWindow
    let sel
    if (typeof win.getSelection != 'undefined') {
        //谷歌、火狐
        sel = win.getSelection()
        if (sel.rangeCount > 0) {
            //选中的区域
            const range = win.getSelection().getRangeAt(0)
            const preCaretRange = range.cloneRange() //克隆一个选中区域
            preCaretRange.selectNodeContents(element) //设置选中区域的节点内容为当前节点
            preCaretRange.setEnd(range.endContainer, range.endOffset) //重置选中区域的结束位置
            caretOffset = preCaretRange.toString().length
        }
    } else if ((sel = doc.selection) && sel.type != 'Control') {
        //IE
        const textRange = sel.createRange()
        const preCaretTextRange = doc.body.createTextRange()
        preCaretTextRange.moveToElementText(element)
        preCaretTextRange.setEndPoint('EndToEnd', textRange)
        caretOffset = preCaretTextRange.text.length
    }
    return caretOffset
}

let interval: number
const focusHandler = () => {
    clearInterval(interval)
    interval = window.setInterval(() => {
        console.log(getCursortPosition())
        emit('updatePos', getCursortPosition())
    }, 100)
    emit('focus')
}
const blurHandler = () => {
    clearInterval(interval)
    emit('blur')
}

const inputFocus = () => {
    inputRef.value.focus()
    const range = window.getSelection()
    range.selectAllChildren(inputRef.value)
    range.collapseToEnd()
}

const getPasteText = text => {
    if (!props.maxlength) {
        return text
    }

    const $el = document.createElement('div')
    $el.innerHTML = text
    if ($el.textContent.length > props.maxlength - length.value) {
        return $el.textContent.slice(0, Math.max(0, props.maxlength - length.value))
    } else {
        return text
    }
}

const pasteHandler = event => {
    event.preventDefault()
    let text
    const clp = (event.originalEvent || event).clipboardData
    // 兼容针对于opera ie等浏览器
    if (clp === undefined || clp === null) {
        text = window.clipboardData.getData('text') || ''
        if (text !== '') {
            if (window.getSelection) {
                // 针对于ie11 10 9 safari
                const newNode = document.createElement('span')
                newNode.innerHTML = getPasteText(text)
                window.getSelection().getRangeAt(0).insertNode(newNode)
            } else {
                document.selection.createRange().pasteHTML(text)
            }
        }
    } else {
        // 兼容chorme或hotfire
        text = clp.getData('text/plain') || ''
        if (text !== '') {
            document.execCommand('insertText', false, getPasteText(text))
        }
    }
}

defineExpose({
    root: textRef,
    input: inputRef,
    getCursortPosition,
})
</script>
