mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-07 16:29:51 +00:00
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:
parent
976f293f28
commit
19dd4667f2
6
.changes/unreleased/Feature-20250523-133434.yaml
Normal file
6
.changes/unreleased/Feature-20250523-133434.yaml
Normal 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
|
@ -20,7 +20,7 @@
|
|||||||
"bindings": "^1.5.0",
|
"bindings": "^1.5.0",
|
||||||
"bootstrap": "5.2.3",
|
"bootstrap": "5.2.3",
|
||||||
"chokidar": "^3.5.1",
|
"chokidar": "^3.5.1",
|
||||||
"ckeditor5": "^44.1.0",
|
"ckeditor5": "^45.1.0",
|
||||||
"dompurify": "^3.1.0",
|
"dompurify": "^3.1.0",
|
||||||
"eslint": "^9.14.0",
|
"eslint": "^9.14.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
|
@ -1,12 +1,32 @@
|
|||||||
import config from "./editor_config";
|
import { createApp } from "vue";
|
||||||
import { ClassicEditor } from "ckeditor5";
|
import CommentEditor from "ChillMainAssets/vuejs/_components/CommentEditor/CommentEditor.vue";
|
||||||
|
|
||||||
const ckeditorFields: NodeListOf<HTMLTextAreaElement> =
|
const ckeditorFields: NodeListOf<HTMLTextAreaElement> =
|
||||||
document.querySelectorAll("textarea[ckeditor]");
|
document.querySelectorAll("textarea[ckeditor]");
|
||||||
ckeditorFields.forEach((field: HTMLTextAreaElement): void => {
|
ckeditorFields.forEach((field: HTMLTextAreaElement): void => {
|
||||||
ClassicEditor.create(field, config).catch((error) => {
|
const content = field.value;
|
||||||
console.error(error.stack);
|
const div = document.createElement("div");
|
||||||
throw error;
|
|
||||||
});
|
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'));
|
|
||||||
|
@ -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>
|
@ -915,3 +915,7 @@ multiselect:
|
|||||||
select_group_label: Appuyer sur "Entrée" pour sélectionner ce groupe
|
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
|
deselect_group_label: Appuyer sur "Entrée" pour désélectionner ce groupe
|
||||||
selected_label: Sélectionné'
|
selected_label: Sélectionné'
|
||||||
|
|
||||||
|
editor:
|
||||||
|
switch_to_simple: Éditeur simple
|
||||||
|
switch_to_complex: Éditeur riche
|
||||||
|
Loading…
x
Reference in New Issue
Block a user