From 6568d60f0ffebb19fc0296de34919f073516b724 Mon Sep 17 00:00:00 2001 From: NathanViaud <nathan.viaud@inria.fr> Date: Thu, 25 May 2023 17:42:00 +0200 Subject: [PATCH] Replacing Quill by tinymce --- package-lock.json | 1 + package.json | 1 + .../forms/components/inputs/GenericInput.vue | 2 +- .../forms/components/inputs/HtmlInput.vue | 45 ++-- .../forms/components/inputs/QuillEditor.vue | 192 ++++++++++++++++++ 5 files changed, 207 insertions(+), 34 deletions(-) create mode 100644 src/features/forms/components/inputs/QuillEditor.vue diff --git a/package-lock.json b/package-lock.json index 8c3565a1..ca988b9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "pinia": "^2.0.28", "sass": "^1.56.2", "serve-static": "^1.15.0", + "tinymce": "^6.4.2", "vue": "3.3", "vue-router": "^4.1.6", "vue-tippy": "^6.0.0", diff --git a/package.json b/package.json index ae5c8db6..af50f823 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "pinia": "^2.0.28", "sass": "^1.56.2", "serve-static": "^1.15.0", + "tinymce": "^6.4.2", "vue": "3.3", "vue-router": "^4.1.6", "vue-tippy": "^6.0.0", diff --git a/src/features/forms/components/inputs/GenericInput.vue b/src/features/forms/components/inputs/GenericInput.vue index 99fbf01a..8c76525c 100644 --- a/src/features/forms/components/inputs/GenericInput.vue +++ b/src/features/forms/components/inputs/GenericInput.vue @@ -37,7 +37,7 @@ const emit = defineEmits<{ :inside-card="insideCard" @input="emit('input', $event)" /> - <HtmlInput + <HtmlInput v-if="input.type === 'html'" :label="input.label" :placeholder="input.placeholder" diff --git a/src/features/forms/components/inputs/HtmlInput.vue b/src/features/forms/components/inputs/HtmlInput.vue index a7a7ad5f..d11ec84e 100644 --- a/src/features/forms/components/inputs/HtmlInput.vue +++ b/src/features/forms/components/inputs/HtmlInput.vue @@ -1,8 +1,6 @@ <script setup lang="ts"> import Editor from '@tinymce/tinymce-vue'; -import { getTinymce } from '@tinymce/tinymce-vue/lib/cjs/main/ts/TinyMCE'; import { Ref, ref, watch } from 'vue'; -import {graphService} from '@/src/shared/services'; const props = defineProps<{ label: string; @@ -19,6 +17,7 @@ const editor = ref(null); const content: Ref<string> = ref(''); function textChange() { + console.log('textChange'); emit('input', content.value); } @@ -36,8 +35,8 @@ watch( } ); -const plugins = 'image link lists template code'; -const toolbar = 'bold italic alignleft aligncenter alignright link image bullist numlist outdent indent template code'; +const plugins = 'bold italic underline lists align link image searchreplace visualblocks preview wordcount code fullscreen media table template help textpattern'; +const toolbar = 'undo redo | bold italic underline | alignleft aligncenter alignright alignjustify | outdent indent | numlist bullist | link image | help | template | code'; const template = ` <details style="border: 1px solid lightgray; border-radius: 4px; padding: .5em .5em 0 .5em"> @@ -51,26 +50,8 @@ function init() { content.value = props.inputValue; } -async function drop(event) { - const file = event.dataTransfer.files[0]; - if (!file) return; - const url = await graphService.importFile(file.path); - const editor = getTinymce().activeEditor; - editor.setContent(editor.getContent() + `<img alt="" src="${url}"/>`); -} - -function handleFilePicker(callback) { - const input = document.createElement('input'); - input.type = 'file'; - document.body.appendChild(input); - input.click(); - input.addEventListener('change', async (e: any) => { - const fileInput = e.target as HTMLInputElement; - const file = fileInput.files[0]; - if (!file) return; - const url = await graphService.importFile(file.path); - callback(url); - }); +function drop(event) { + console.log('drop', event); } </script> @@ -84,18 +65,16 @@ function handleFilePicker(callback) { :plugins="plugins" :toolbar="toolbar" :init="{ - menubar: false, - statusbar: false, + menubar: 'file edit view insert custom', templates: [ - { title: 'Plier/déplier', content: template, description: 'Plier/déplier avec titre et contenu' } + { title: 'title 1', content: template, description: 'this is a test template' } ], - file_picker_types: 'image', - file_picker_callback: handleFilePicker, - link_default_target: '_blank', - link_target_list: false, - paste_data_images: false + file_picker_callback:(callback, value, meta) => { + console.log('file_picker_callback', callback, value, meta); + drop(value); + } }" @init="init" - @drop.stop.prevent="drop" + @drop="drop" /> </template> \ No newline at end of file diff --git a/src/features/forms/components/inputs/QuillEditor.vue b/src/features/forms/components/inputs/QuillEditor.vue new file mode 100644 index 00000000..35a1b8f0 --- /dev/null +++ b/src/features/forms/components/inputs/QuillEditor.vue @@ -0,0 +1,192 @@ +<!-- TODO: Delete this legacy component --> + +<script setup lang="ts"> +import { QuillEditor, Quill } from '@vueup/vue-quill'; +import '@vueup/vue-quill/dist/vue-quill.snow.css'; +import ImageUploader from 'quill-image-uploader/src/quill.imageUploader'; +import { Ref, ref, watch } from 'vue'; +import { graphService } from '@/src/shared/services'; +//@ts-ignore +import htmlEditButton from 'quill-html-edit-button'; + +const props = defineProps<{ + label: string; + inputValue: string; + placeholder?: string; + insideCard?: boolean; +}>(); + +const emit = defineEmits<{ + (e: 'input', value: string): void; +}>(); + +const toolbar = [ + [ + 'bold', + 'italic', + 'underline', + { 'list': 'ordered' }, + { 'list': 'bullet' }, + { 'align': null}, + {'align': 'center'}, + {'align': 'right'}, + 'link', + 'image' + ] +]; + +const image = Quill.import('formats/image'); + +image.sanitize = function(url) { + return url; +}; + +const modules = [ + { + name: 'imageUploader', + module: ImageUploader, + options: { + upload: (file) => graphService.importFile(file.path) + }, + }, + { + name: 'htmlEditButton', + module: htmlEditButton, + option: { + debug: true, + } + } +]; + +const qlEditor = ref(null); + +const content: Ref<string> = ref(''); + + +function textChange() { + emit('input', content.value); +} + +function initQuill() { + content.value = props.inputValue; +} + +watch( + () => props.inputValue, + () => { + content.value = props.inputValue; + } +); + +</script> + +<template> + <label for="ql-editor">{{ label }}</label> + <QuillEditor + id="ql-editor" + ref="qlEditor" + v-model:content="content" + content-type="html" + theme="snow" + :class="{ 'ql-card': insideCard }" + :modules="modules" + :toolbar="toolbar" + :placeholder="placeholder" + @text-change="textChange" + @ready="initQuill" + /> +</template> + +<style lang="scss"> + +.ql { + &-toolbar { + border: none !important; + &:hover { + border-radius: 8px; + } + } + &-container { + border: 1px solid var(--border) !important; + border-radius: 4px; + background-color: var(--item-background); + margin-bottom: 1.5rem; + &:focus-within { + border: 1px solid var(--editor-blue) !important; + box-shadow: 0 1px 8px 0 var(--editor-blue-shadow); + } + } + &-editor { + min-height: 10rem; + padding: .5rem; + font-size: 1rem; + color: var(--text); + width: 24rem; + + p { + margin-bottom: .5rem; + } + } + + &-active { + background-color: transparent !important; + &:hover { + background-color: #F3F4F6 !important; + } + } + + &-formats { + button:hover { + border-radius: 4px; + background-color: #F3F4F6 !important; + } + } + + &-card { + margin-bottom: 1rem; + } +} + +.ql-active .ql-stroke { + stroke: var(--editor-blue) !important; +} + +.ql-active .ql-fill { + fill: var(--editor-blue) !important; +} + +.ql-active:hover { + background-color: var(--) !important; +} + +.ql-blank::before { + color: var(--editor-grayblue) !important; + font-style: normal !important; + left: 0.5rem !important; +} + +// Quill Edit button + +.ql-html { + &-textContainer { + background: white; + } + + &-textArea { + border: 1px solid var(--border); + } + + &-buttonOk, &-buttonCancel { + border: none; + cursor: pointer; + color: var(--text); + border-radius: 6px; + transition: box-shadow .2s ease-in-out; + padding: .5rem 1rem; + + &:hover { + box-shadow: 0 1px 8px 0 var(--shadow-outer); + } + } +} +</style> -- GitLab