Integrate Vue-based editor with rich and simple mode toggle

Replaced CKEditor initialization with a Vue-based editor component. Introduced a toggle to switch between rich and simple editing modes, persisting the state in local storage. Updated CKEditor dependency to version 45.1.0.
This commit is contained in:
Julien Fastré 2025-05-23 13:34:50 +02:00
parent 976f293f28
commit 19dd4667f2
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
5 changed files with 159 additions and 8 deletions

View File

@ -0,0 +1,6 @@
kind: Feature
body: Create editor which allow us to toggle between rich and simple text editor
time: 2025-05-23T13:34:34.56795603+02:00
custom:
Issue: "321"
SchemaChange: No schema change

View File

@ -20,7 +20,7 @@
"bindings": "^1.5.0",
"bootstrap": "5.2.3",
"chokidar": "^3.5.1",
"ckeditor5": "^44.1.0",
"ckeditor5": "^45.1.0",
"dompurify": "^3.1.0",
"eslint": "^9.14.0",
"eslint-config-prettier": "^9.1.0",

View File

@ -1,12 +1,32 @@
import config from "./editor_config";
import { ClassicEditor } from "ckeditor5";
import { createApp } from "vue";
import CommentEditor from "ChillMainAssets/vuejs/_components/CommentEditor/CommentEditor.vue";
const ckeditorFields: NodeListOf<HTMLTextAreaElement> =
document.querySelectorAll("textarea[ckeditor]");
ckeditorFields.forEach((field: HTMLTextAreaElement): void => {
ClassicEditor.create(field, config).catch((error) => {
console.error(error.stack);
throw error;
});
const content = field.value;
const div = document.createElement("div");
if (field.parentNode !== null) {
field.parentNode.insertBefore(div, field);
} else {
throw "parent is null";
}
createApp({
components: { CommentEditor },
template: `<comment-editor v-model="content" @input="handleInput"></comment-editor>`,
data() {
return {
content,
};
},
methods: {
handleInput() {
field.value = this.content;
},
},
}).mount(div);
field.style.display = "none";
});
//Fields.push.apply(Fields, document.querySelectorAll('.cf-fields textarea'));

View File

@ -0,0 +1,121 @@
<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref } from "vue";
import { Ckeditor } from "@ckeditor/ckeditor5-vue";
import { ClassicEditor } from "ckeditor5";
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
import {
trans,
EDITOR_SWITCH_TO_SIMPLE,
EDITOR_SWITCH_TO_COMPLEX,
} from "translator";
const EDITOR_MODE_KEY = "editorMode";
const kind = ref<"simple" | "rich">("simple");
const value = defineModel({ required: true });
const isSimple = computed(() => kind.value === "simple");
const toggleButtonClass = computed(() => {
return {
["toggle-button"]: true,
onEditor: !isSimple.value,
onSimple: isSimple.value,
};
});
const toggleEditor = () => {
console.log("toggleEditor");
let newValue;
newValue = kind.value === "simple" ? "rich" : "simple";
kind.value = "rich";
window.localStorage.setItem(EDITOR_MODE_KEY, newValue);
window.dispatchEvent(new Event("toggleEditorKind"));
console.log("new storage", window.localStorage.getItem(EDITOR_MODE_KEY));
};
const onKindChange = function (/* event: StorageEvent | Event */) {
const newValue = window.localStorage.getItem(EDITOR_MODE_KEY);
if (null === newValue || !(newValue === "rich" || newValue === "simple")) {
throw "invalid new value: " + newValue;
}
if (kind.value !== newValue) {
kind.value = newValue;
}
};
onMounted(function () {
const storage = window.localStorage;
const savedKind = storage.getItem(EDITOR_MODE_KEY);
if (
null !== kind.value &&
(savedKind === "simple" || savedKind === "rich")
) {
kind.value = savedKind;
}
window.addEventListener("storage", onKindChange);
window.addEventListener("toggleEditorKind", onKindChange);
});
onUnmounted(function () {
window.removeEventListener("storage", onKindChange);
window.removeEventListener("toggleEditorKind", onKindChange);
});
</script>
<template>
<div>
<div v-if="'rich' === kind">
<Ckeditor
:editor="ClassicEditor"
:config="classicEditorConfig"
v-model="value"
/>
</div>
<div v-else>
<textarea
v-model="value"
class="form-control simple-editor"
></textarea>
</div>
<button :class="toggleButtonClass" type="button" @click="toggleEditor">
{{
isSimple
? trans(EDITOR_SWITCH_TO_COMPLEX)
: trans(EDITOR_SWITCH_TO_SIMPLE)
}}
</button>
</div>
</template>
<style scoped lang="scss">
.toggle-button {
background: white;
border: none;
padding: 0.15rem;
color: #069;
cursor: pointer;
&.onEditor {
position: relative;
left: 1rem;
top: -1.5rem;
}
&.onSimple {
position: relative;
top: -0.75rem;
left: 1rem;
}
}
.simple-editor {
min-height: 190px;
}
</style>

View File

@ -915,3 +915,7 @@ multiselect:
select_group_label: Appuyer sur "Entrée" pour sélectionner ce groupe
deselect_group_label: Appuyer sur "Entrée" pour désélectionner ce groupe
selected_label: Sélectionné'
editor:
switch_to_simple: Éditeur simple
switch_to_complex: Éditeur riche