ldc-supportweb/resources/ts/bo/components/CkEditorComponent.vue
2023-10-12 15:56:11 +02:00

354 lines
9.9 KiB
Vue

<template>
<div>
<div ref="wordCounter" />
<div ref="ckeditor" />
<input
:id="internalId"
class="form-control"
type="hidden"
:name="intName"
:value="internalText"
:required="internalRequired"
>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import trans from "./../../modules/trans";
import "./../../../js/vendor/ckeditor";
// import { CKUploadAdaptater } from "../../bo/CkUploadAdaptater";
export default defineComponent({
name: "CkEditorComponent",
emits: ["input"],
mixins: [trans],
props: {
id: {
type: String,
default: String(Math.pow(10, 16) / Math.random()),
},
required: {
type: Boolean,
default: false,
},
name: {
type: String,
default: "",
},
dbtext: {
type: String,
default: "",
},
},
mounted() {
const json = String(this.$attrs.json ?? "{}"),
data = JSON.parse(json);
this.intName = data.name;
this.internalText = data.text ? String(data.text) : "";
this.internalId = data.id ? data.id : "";
this.internalRequired = Boolean(data.required);
this.makeSuperBuild();
},
data(): {
intName: string;
internalText: string;
internalId: string;
internalRequired: boolean;
// @ts-ignore
editor: ClassicEditor | null;
words: number;
chars: number;
} {
return {
intName: "",
internalText: "",
internalId: "",
internalRequired: false,
editor: null,
words: 0,
chars: 0,
};
},
watch: {
id() {
this.internalId = this.id;
},
name() {
this.intName = this.name;
},
required() {
this.internalRequired = this.required;
},
dbtext() {
if (this.internalText != this.dbtext) {
this.internalText = this.dbtext ? this.dbtext : "";
if (this.editor) {
const text = this.internalText;
Object.freeze(text);
this.editor.setData(text);
}
}
},
},
methods: {
makeSuperBuild() {
const self = this,
ckeditor = this.$refs.ckeditor as HTMLElement,
wordCounter = this.$refs.wordCounter as HTMLElement;
// * Specific to Calliope
// verticalTopMenuOffset = document.querySelector(
// "body > div> .navbar"
// ) as HTMLElement | null;
// if (!verticalTopMenuOffset) {
// throw new Error("Could not find bo Top menu navbar");
// }
// @ts-ignore
ClassicEditor.create(ckeditor, {
// https://github.com/ckeditor/ckeditor5-react/issues/267
extraPlugins: [
// // @ts-ignore
// (editor) => {
// editor.plugins.get("FileRepository").createUploadAdapter = (
// // @ts-ignore
// loader
// ) => {
// // Configure the URL to the upload script in your back-end here!
// return new CKUploadAdaptater(loader);
// };
// },
],
wordCount: {
container: wordCounter,
// @ts-ignore
onUpdate: (stats) => {
this.chars = stats.characters;
this.words = stats.words;
},
},
// ui: {
// viewportOffset: {
// top: verticalTopMenuOffset.getBoundingClientRect().height,
// right: 0,
// bottom: 0,
// left: 0,
// },
// },
link: {
// Automatically add target="_blank" and rel="noopener noreferrer" to all external links.
addTargetToExternalLinks: true,
// Let the users control the "download" attribute of each link.
decorators: [
{
mode: "manual",
label: "Ouvrir dans un nouvel onglet",
attributes: {
target: "_blank",
rel: "noopener noreferrer",
},
},
],
},
typing: {
transformations: {
extra: [
{ from: ":)", to: "😊" },
{ from: ":-P", to: "😛" },
{ from: "8-)", to: "😎" },
{ from: ";-)", to: "😉" },
{ from: ":-D", to: "😄" },
{ from: ":twisted:", to: "😈" },
{ from: ":mrgreen:", to: "😁" },
{ from: ":lol:", to: "😆" },
{ from: ":roll:", to: "🙄" },
{ from: ":-?", to: "😕" },
{ from: ":cry:", to: "😢" },
{ from: ":-o", to: "😮" },
{ from: ":evil:", to: "😡" },
{ from: ":-|", to: "😐" },
{ from: ":oops:", to: "😳" },
{ from: ":-x", to: "😠" },
{ from: "8-O", to: "😲" },
{ from: ":-(", to: "😧" },
{ from: ":arrow:", to: "➡" },
{ from: ":idea:", to: "💡" },
],
},
},
mediaEmbed: {
previewsInData: false,
removeProviders: [
"dailymotion",
"spotify",
"youtube",
"vimeo",
"instagram",
"twitter",
"googleMaps",
"flickr",
"facebook",
],
// // see https://github.com/ckeditor/ckeditor5/blob/master/packages/ckeditor5-media-embed/src/mediaembedediting.js
// providers: [
// {
// // display local videos in oembed tags
// name: "localVideo",
// url: /^(\/(?:content|storage|uploads)\/.*)/,
// html: (match: string[]) => {
// const path = match[1];
// return (
// "<video controls allowfullscreen style=\"max-width: 90%; margin: 0 auto; display: block;\">" +
// `<source src="${path}" type="video/mp4">` +
// `<p>Votre navigateur ne prend pas en charge les vidéos HTML5. Voici <a href="${path}">un lien pour télécharger la vidéo</a>.</p>` +
// "</video>"
// );
// },
// },
// ],
},
toolbar: {
items: [
"heading",
"|",
"findAndReplace",
"|",
"bold",
"italic",
"underline",
"strikethrough",
"link",
"bulletedList",
"numberedList",
// "code",
// "codeBlock",
"|",
"outdent",
"indent",
"alignment",
"|",
"undo",
"redo",
"selectAll",
"|",
// "laravelFileManager",
"blockQuote",
"|",
// "insertTable",
// "tableColumn",
// "tableRow",
// "mergeTableCells",
"|",
// "highlight",
// "removeHighlight",
// "fontColor",
// "fontBackgroundColor",
// "fontFamily",
"fontSize",
"horizontalLine",
// "specialCharacters",
"|",
"removeFormat",
"|",
"sourceEditing",
],
},
// table: {
// contentToolbar: [
// "tableColumn",
// "tableRow",
// "mergeTableCells",
// "tableProperties",
// "tableCellProperties",
// "toggleTableCaption",
// ],
// Configuration of the TableProperties plugin.
// tableProperties: {
// ...
// },
// Configuration of the TableCellProperties plugin.
// tableCellProperties: {
// ...
// },
// },
width: "auto",
language: "fr",
image: {
toolbar: [
"toggleImageCaption",
"imageTextAlternative",
"imageStyle:inline",
"imageStyle:alignLeft",
"imageStyle:alignRight",
"imageStyle:alignCenter",
"imageStyle:side",
"imageResize",
"linkImage",
],
},
})
// @ts-ignore
.then((editor: ClassicEditor) => {
let timer = null as number|null;
const updateContent = () => {
const data = editor.getData();
self.internalText = data;
self.$emit("input", data);
timer = null;
};
// Display all toolbar elements
// console.log(Array.from(editor.ui.componentFactory.names()));
self.editor = Object.freeze(editor);
editor.setData(this.internalText);
editor.model.document.on("change:data", () => {
if(timer) {
clearTimeout(timer);
}
// * Keep track of internal editor
timer = setTimeout(updateContent, 1000) as never as number;
});
})
// @ts-ignore
.catch((error) => {
console.error("Oops, something went wrong!");
console.error(
"Please, report the following error on https://github.com/ckeditor/ckeditor5/issues with the build id and the error stack trace:"
);
console.warn("Build id: x0tjc6omqq4d-iydt761tuj51");
console.error(error);
});
},
},
});
</script>
<style lang="scss">
@import url("./../../../js/vendor/ckeditor/build/styles.css");
.ck-rounded-corners {
border-radius: 0 0 0.375rem 0.375rem !important;
}
.ck-word-count {
background-color: #fafafa;
border: 1px solid #c4c4c4;
border-bottom: 0px;
border-top-left-radius: 0.375rem;
border-top-right-radius: 0.375rem;
color: initial;
display: flex;
flex-direction: row;
justify-content: space-around !important;
}
.ck-content {
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
.ck-focused {
border-color: #86b7fe !important;
box-shadow: 0 0 0 0.25rem rgb(13 110 253 / 25%) !important;
outline: 0 !important;
}
</style>