diff --git a/resources/js/components/markdown-editor.js b/resources/js/components/markdown-editor.js index de256a846..331cf2f01 100644 --- a/resources/js/components/markdown-editor.js +++ b/resources/js/components/markdown-editor.js @@ -1,6 +1,7 @@ import MarkdownIt from "markdown-it"; import mdTasksLists from 'markdown-it-task-lists'; import code from '../services/code'; +import Clipboard from "../services/clipboard"; import {debounce} from "../services/util"; import DrawIO from "../services/drawio"; @@ -215,20 +216,16 @@ class MarkdownEditor { // Handle image paste cm.on('paste', (cm, event) => { - const clipboardItems = event.clipboardData.items; - if (!event.clipboardData || !clipboardItems) return; + const clipboard = new Clipboard(event.clipboardData || event.dataTransfer); - // Don't handle if clipboard includes text content - for (let clipboardItem of clipboardItems) { - if (clipboardItem.type.includes('text/')) { - return; - } + // Don't handle the event ourselves if no items exist of contains table-looking data + if (!clipboard.hasItems() || clipboard.containsTabularData()) { + return; } - for (let clipboardItem of clipboardItems) { - if (clipboardItem.type.includes("image")) { - uploadImage(clipboardItem.getAsFile()); - } + const images = clipboard.getImages(); + for (const image of images) { + uploadImage(image); } }); @@ -246,13 +243,15 @@ class MarkdownEditor { }); } - if (event.dataTransfer && event.dataTransfer.files && event.dataTransfer.files.length > 0) { + const clipboard = new Clipboard(event.dataTransfer); + if (clipboard.hasItems()) { const cursorPos = cm.coordsChar({left: event.pageX, top: event.pageY}); cm.setCursor(cursorPos); event.stopPropagation(); event.preventDefault(); - for (let i = 0; i < event.dataTransfer.files.length; i++) { - uploadImage(event.dataTransfer.files[i]); + const images = clipboard.getImages(); + for (const image of images) { + uploadImage(image); } } diff --git a/resources/js/components/wysiwyg-editor.js b/resources/js/components/wysiwyg-editor.js index 41ce2705a..b9e3340a8 100644 --- a/resources/js/components/wysiwyg-editor.js +++ b/resources/js/components/wysiwyg-editor.js @@ -1,5 +1,6 @@ import Code from "../services/code"; import DrawIO from "../services/drawio"; +import Clipboard from "../services/clipboard"; /** * Handle pasting images from clipboard. @@ -8,30 +9,33 @@ import DrawIO from "../services/drawio"; * @param editor */ function editorPaste(event, editor, wysiwygComponent) { - const clipboardItems = event.clipboardData.items; - if (!event.clipboardData || !clipboardItems) return; + const clipboard = new Clipboard(event.clipboardData || event.dataTransfer); - // Don't handle if clipboard includes text content - for (let clipboardItem of clipboardItems) { - if (clipboardItem.type.includes('text/')) { - return; - } + // Don't handle the event ourselves if no items exist of contains table-looking data + if (!clipboard.hasItems() || clipboard.containsTabularData()) { + return; } - for (let clipboardItem of clipboardItems) { - if (!clipboardItem.type.includes("image")) { - continue; - } + const images = clipboard.getImages(); + for (const imageFile of images) { const id = "image-" + Math.random().toString(16).slice(2); const loadingImage = window.baseUrl('/loading.gif'); - const file = clipboardItem.getAsFile(); + event.preventDefault(); setTimeout(() => { editor.insertContent(`

`); - uploadImageFile(file, wysiwygComponent).then(resp => { - editor.dom.setAttrib(id, 'src', resp.thumbs.display); + uploadImageFile(imageFile, wysiwygComponent).then(resp => { + const safeName = resp.name.replace(/"/g, ''); + const newImageHtml = `${safeName}`; + + const newEl = editor.dom.create('a', { + target: '_blank', + href: resp.url, + }, newImageHtml); + + editor.dom.replace(newEl, id); }).catch(err => { editor.dom.remove(id); window.$events.emit('error', trans('errors.image_upload_error')); @@ -634,6 +638,10 @@ class WysiwygEditor { }); } + if (!event.isDefaultPrevented()) { + editorPaste(event, editor, context); + } + wrap = null; }); diff --git a/resources/js/services/clipboard.js b/resources/js/services/clipboard.js new file mode 100644 index 000000000..da921e515 --- /dev/null +++ b/resources/js/services/clipboard.js @@ -0,0 +1,54 @@ + +class Clipboard { + + /** + * Constructor + * @param {DataTransfer} clipboardData + */ + constructor(clipboardData) { + this.data = clipboardData; + } + + /** + * Check if the clipboard has any items. + */ + hasItems() { + return Boolean(this.data) && Boolean(this.data.types) && this.data.types.length > 0; + } + + /** + * Check if the given event has tabular-looking data in the clipboard. + * @return {boolean} + */ + containsTabularData() { + const rtfData = this.data.getData( 'text/rtf'); + return rtfData && rtfData.includes('\\trowd'); + } + + /** + * Get the images that are in the clipboard data. + * @return {Array} + */ + getImages() { + const types = this.data.types; + const files = this.data.files; + const images = []; + + for (const type of types) { + if (type.includes('image')) { + const item = this.data.getData(type); + images.push(item.getAsFile()); + } + } + + for (const file of files) { + if (file.type.includes('image')) { + images.push(file); + } + } + + return images; + } +} + +export default Clipboard; \ No newline at end of file