From e4bf97865578624946cdc9230fefe729f27f447c Mon Sep 17 00:00:00 2001 From: Adrian Dimitrov Date: Mon, 15 Feb 2021 17:15:11 +0200 Subject: [PATCH] Add file library integration for WYSIWYG interface (#3263) * Add file library integration for WYSIWYG interface * Fix typing; Prevent selecting non-image on image field * Allow imageToken in the interface; addTokenToURL() replace token if presents * Add file library integration for WYSIWYG interface * Fix typing; Prevent selecting non-image on image field * Allow imageToken in the interface; addTokenToURL() replace token if presents Co-authored-by: Nitwel --- app/src/interfaces/wysiwyg/index.ts | 10 +++ .../interfaces/wysiwyg/tinymce-overrides.css | 6 +- app/src/interfaces/wysiwyg/wysiwyg.vue | 68 ++++++++++++++++++- 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/app/src/interfaces/wysiwyg/index.ts b/app/src/interfaces/wysiwyg/index.ts index 114f3b3f36..982549efdf 100644 --- a/app/src/interfaces/wysiwyg/index.ts +++ b/app/src/interfaces/wysiwyg/index.ts @@ -272,5 +272,15 @@ export default defineInterface(({ i18n }) => ({ }, }, }, + { + field: 'imageToken', + name: i18n.t('interfaces.markdown.imageToken'), + type: 'string', + meta: { + note: i18n.t('interfaces.markdown.imageToken_label'), + width: 'full', + interface: 'text-input', + }, + }, ], })); diff --git a/app/src/interfaces/wysiwyg/tinymce-overrides.css b/app/src/interfaces/wysiwyg/tinymce-overrides.css index 1771e23acc..590088ecbb 100644 --- a/app/src/interfaces/wysiwyg/tinymce-overrides.css +++ b/app/src/interfaces/wysiwyg/tinymce-overrides.css @@ -175,7 +175,11 @@ body.dark .tox .tox-toolbar__overflow { /* Modal */ .tox .tox-dialog-wrap__backdrop { - background-color: rgba(0, 0, 0, 0.75); + background-color: var(--v-overlay-color); +} + +.tox.tox-tinymce-aux { + z-index: 400; } .tox .tox-dialog { diff --git a/app/src/interfaces/wysiwyg/wysiwyg.vue b/app/src/interfaces/wysiwyg/wysiwyg.vue index 3579ce3062..db29b5776e 100644 --- a/app/src/interfaces/wysiwyg/wysiwyg.vue +++ b/app/src/interfaces/wysiwyg/wysiwyg.vue @@ -8,6 +8,17 @@ @onFocusIn="setFocus(true)" @onFocusOut="setFocus(false)" /> + + + {{ $t('upload_from_device') }} + + + + + {{ $t('cancel') }} + + + @@ -37,6 +48,9 @@ import Editor from '@tinymce/tinymce-vue'; import getEditorStyles from './get-editor-styles'; +import { getPublicURL } from '@/utils/get-root-path'; +import { addTokenToURL } from '@/api'; + type CustomFormat = { title: string; inline: string; @@ -89,9 +103,16 @@ export default defineComponent({ type: Boolean, default: true, }, + imageToken: { + type: String, + default: undefined, + }, }, setup(props, { emit }) { const editorElement = ref(null); + const imageUploadHandler = ref(null); + + const _imageDialogOpen = computed(() => !!imageUploadHandler.value); const _value = computed({ get() { @@ -131,11 +152,56 @@ export default defineComponent({ extended_valid_elements: 'audio[loop],source', toolbar: toolbarString, style_formats: styleFormats, + file_picker_types: 'image media', + file_picker_callback: setImageUploadHandler, + urlconverter_callback: urlConverter, ...(props.tinymceOverrides || {}), }; }); - return { editorElement, editorOptions, _value, setFocus }; + return { + editorElement, + editorOptions, + _value, + setFocus, + onImageUpload, + unsetImageUploadHandler, + _imageDialogOpen, + }; + + function onImageUpload(file: Record) { + if (imageUploadHandler.value) imageUploadHandler.value(file); + unsetImageUploadHandler(); + } + + function setImageUploadHandler(cb: CallableFunction, value: any, meta: Record) { + imageUploadHandler.value = (result: Record) => { + if (meta.filetype === 'image' && !/^image\//.test(result.type)) return; + + const imageUrl = getPublicURL() + 'assets/' + result.id; + + cb(imageUrl, { + alt: result.title, + title: result.title, + width: (result.width || '').toString(), + height: (result.height || '').toString(), + }); + }; + } + + function urlConverter(url: string, node: string) { + if (url && props.imageToken && ['img', 'source', 'poster', 'audio'].includes(node)) { + const baseUrl = getPublicURL() + 'assets/'; + if (url.includes(baseUrl)) { + url = addTokenToURL(url, props.imageToken); + } + } + return url; + } + + function unsetImageUploadHandler() { + imageUploadHandler.value = null; + } function setFocus(val: boolean) { if (editorElement.value == null) return;