c3lf-system-3/web/src/components/inputs/FormatedText.vue
2024-06-23 04:31:28 +02:00

106 lines
No EOL
3.2 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 = (elem) => {
if (elem === node) {
found = true;
return;
}
if (elem.nodeType === 3) {
position += elem.length;
} else {
for (let i = 0; i < elem.childNodes.length; i++) {
walk(elem.childNodes[i]);
if (found) {
return;
}
}
}
};
walk(container);
return position + offset;
},
findNode(container, offset) {
let position = 0;
let found = false;
let node = null;
const walk = (elem) => {
if (position + elem.length >= offset) {
found = true;
node = elem;
return;
}
if (elem.nodeType === 3) {
position += elem.length;
} else {
for (let i = 0; i < elem.childNodes.length; i++) {
walk(elem.childNodes[i]);
if (found) {
return;
}
}
}
};
walk(container);
return [node, offset - position]
},
},
watch: {
value() {
if (this.selection) {
const div = this.$refs.text;
const sel = window.getSelection();
sel.removeAllRanges();
const range = document.createRange();
console.log(this.selection);
range.setStart(...this.findNode(div, this.selection.start));
range.setEnd(...this.findNode(div, this.selection.end));
sel.addRange(range);
//this.selection.removeAllRanges();
//this.selection.addRange(range);
}
}
}
};
</script>