Change implementation of content editable div

This commit is contained in:
Ramon Wenger 2022-02-23 23:45:47 +01:00
parent ad79285e20
commit 1043b647a0
1 changed files with 126 additions and 28 deletions

View File

@ -1,58 +1,150 @@
<template>
<!-- eslint-disable vue/no-v-html -->
<div class="text-form">
{{ isListLocal }}
<toggle
:checked="isListLocal"
label="Liste"
@input="isListLocal=$event"
/>
<button
class="button"
@click="makeList"
>
Test
</button>
<div
class="text-form__input skillbox-textarea"
contenteditable="true"
v-once
@input="change"
v-text="text"
/>
<textarea
:value="text"
class="text-form__input skillbox-textarea"
data-cy="text-form-input"
placeholder="Text erfassen..."
@input="$emit('change-text', $event.target.value, index)"
<div
contenteditable="true"
class="text-form__input skillbox-textarea text-form__contenteditable"
@input="changeSomeText"
@blur="updateSomeText"
v-html="localOnlyText"
/>
</div>
</template>
<script>
let selection;
export default {
<script lang="ts">
import Vue, {PropType} from "vue";
import Toggle from "@/components/ui/Toggle.vue";
interface Value {
text: string;
}
interface Data {
localOnlyText: string,
textToStoreWhileFocused: string,
textBuffer: string, // text that gets saved, but not updated, when the user is typing
htmlBuffer: string, // same as above, but this is the html that's generated
isListLocal: boolean,
// listHTML: string
}
const re = /<ul(\/)?>/;
export default Vue.extend({
props: {
value: {
type: Object,
default: null,
validator(value) {
type: Object as PropType<Value>,
validator(value: Value) {
return Object.prototype.hasOwnProperty.call(value, 'text');
},
},
index: {
type: Number,
default: -1,
},
asList: {
type: Boolean,
default: false
}
},
components: {Toggle},
data(): Data {
return {
// this is the text that's tracked by the input field. It will not update every time the prop updates, otherwise we keep losing focus
localOnlyText: '',
// this is the variable that stores our text while the user is typing and also updates the outer value
textToStoreWhileFocused: '', // we need to have a text that always updates for user input
textBuffer: '',
htmlBuffer: '',
isListLocal: false,
// listHTML: `<ul>
// <li>Hello</li>
// <li>World</li>
// </ul>`
};
},
computed: {
text() {
text(): string {
return this.value.text ? this.value.text.replace(/<br(\/)?>/, '\n').replace(/(<([^>]+)>)/ig, '') : '';
},
html(): string {
return this.value.text;
},
isList(): boolean {
return this.asList || this.value.text.indexOf('<li>') > -1;
}
},
mounted() {
console.log('i was mounted now');
// sync this only once, when the component gets mounted
this.localOnlyText = this.text;
// when mounted, we also check if the text already contains some li or ul elements
this.isListLocal = this.asList || re.test(this.value.text);
},
methods: {
log(e) {
console.log(e);
updateSomeText() {
console.log('updating some text');
console.log('htmlBuffer', this.htmlBuffer);
this.localOnlyText = this.htmlBuffer;
},
makeList() {
// this.localOnlyText = this.localOnlyText
let sep = /\n+/;
let lines = this.textBuffer.split(sep);
let listItems = lines.reduce((previous, current) => {
return `${previous}<li>${current}</li>`;
}, '');
let list = `
<ul>
${listItems}
</ul>`;
console.log(list);
this.localOnlyText = list;
},
changeSomeText(event: Event) {
console.log('changing some text');
const target = (<HTMLInputElement>event.target);
let newHtml = target.innerHTML;
let newText = target.innerText;
this.htmlBuffer = newHtml;
this.textBuffer = newText;
console.log("target.innerText");
console.log(target.innerText);
console.log(target.innerText.indexOf('\n'));
console.log(target.innerHTML);
console.log('textBuffer', this.textBuffer);
console.log('htmlBuffer', this.htmlBuffer);
this.$emit('change-text', newHtml);
},
change(event: Event) {
const target = (<HTMLInputElement>event.target);
const newText = target.innerText;
this.$emit('change-text', newText);
},
change(event) {
selection = window.getSelection().getRangeAt(0);
event.stopPropagation();
event.preventDefault();
this.$emit('change-text', event.target.innerText, this.index);
window.getSelection().addRange(selection);
}
},
};
});
</script>
<style scoped lang="scss">
@ -64,9 +156,15 @@
}
&__contenteditable {
width: 100%;
width: 100%;
height: 300px;
background-color: pink;
display: flex;
flex-direction: column;
}
/deep/ ul {
list-style: initial;
}
}
</style>