c3lf-system-3/web/src/components/inputs/FormatedText.vue
2024-06-23 02:16:24 +02:00

79 lines
No EOL
2.3 KiB
Vue

<template>
<div contenteditable @input="onchange" ref="text" v-html="rawhtml(value)">
</div>
</template>
<script>
export default {
name: 'FormatedText',
props: {
value: {
type: String,
required: true
},
format: {
type: Function,
default: null
}
},
data() {
return {
selection: {start: 0, end: 0}
};
},
emits: ['input'],
methods: {
rawhtml(value) {
if (typeof this.format === 'function') {
return this.format(value);
} else {
return value;
}
},
onchange(event) {
const div = this.$refs.text;
const sel = window.getSelection();
if (sel.rangeCount > 0) {
this.selection.start = this.calculateOffset(div, sel.anchorNode, sel.anchorOffset);
this.selection.end = this.calculateOffset(div, sel.focusNode, sel.focusOffset);
}
this.$emit('input', event.target.innerText);
},
calculateOffset(container, node, offset) {
let position = 0;
let found = false;
const walk = (node) => {
if (node === container) {
found = true;
return;
}
if (node.nodeType === 3) {
position += node.length;
} else {
for (let i = 0; i < node.childNodes.length; i++) {
walk(node.childNodes[i]);
if (found) {
return;
}
}
}
};
walk(node);
return position + offset;
}
},
watch: {
value() {
if (this.selection) {
const div = this.$refs.text;
const range = document.createRange();
console.log(this.selection);
range.setStart(div, Math.min(this.selection.anchorOffset, this.value.length));
range.setEnd(div, Math.min(this.selection.focusOffset, this.value.length));
this.selection.removeAllRanges();
this.selection.addRange(range);
}
}
}
};
</script>