]> BookStack Code Mirror - bookstack/blobdiff - resources/assets/js/components/wysiwyg-editor.js
Fixed issue causing text overlap in sort select box
[bookstack] / resources / assets / js / components / wysiwyg-editor.js
index b894c3fa6151653f42d06a124140e32d358b4dd6..c03c0d2aa4e8bba75b8206e7060d50bb4dc26f06 100644 (file)
@@ -8,11 +8,20 @@ import DrawIO from "../services/drawio";
  * @param editor
  */
 function editorPaste(event, editor, wysiwygComponent) {
-    if (!event.clipboardData || !event.clipboardData.items) return;
+    const clipboardItems = event.clipboardData.items;
+    if (!event.clipboardData || !clipboardItems) return;
 
-    for (let clipboardItem of event.clipboardData.items) {
-        if (clipboardItem.type.indexOf("image") === -1) continue;
-        event.preventDefault();
+    // Don't handle if clipboard includes text content
+    for (let clipboardItem of clipboardItems) {
+        if (clipboardItem.type.includes('text/')) {
+            return;
+        }
+    }
+
+    for (let clipboardItem of clipboardItems) {
+        if (!clipboardItem.type.includes("image")) {
+            continue;
+        }
 
         const id = "image-" + Math.random().toString(16).slice(2);
         const loadingImage = window.baseUrl('/loading.gif');
@@ -53,7 +62,7 @@ async function uploadImageFile(file, wysiwygComponent) {
     formData.append('file', file, remoteFilename);
     formData.append('uploaded_to', wysiwygComponent.pageId);
 
-    const resp = await window.$http.post(window.baseUrl('/images/gallery/upload'), formData);
+    const resp = await window.$http.post(window.baseUrl('/images/gallery'), formData);
     return resp.data;
 }
 
@@ -159,23 +168,24 @@ function codePlugin() {
         });
     }
 
-    function codeMirrorContainerToPre($codeMirrorContainer) {
-        let textArea = $codeMirrorContainer[0].querySelector('textarea');
-        let code = textArea.textContent;
-        let lang = $codeMirrorContainer[0].getAttribute('data-lang');
-
-        $codeMirrorContainer.removeAttr('contentEditable');
-        let $pre = $('<pre></pre>');
-        $pre.append($('<code></code>').each((index, elem) => {
-            // Needs to be textContent since innerText produces BR:s
-            elem.textContent = code;
-        }).attr('class', `language-${lang}`));
-        $codeMirrorContainer.replaceWith($pre);
+    function codeMirrorContainerToPre(codeMirrorContainer) {
+        const textArea = codeMirrorContainer.querySelector('textarea');
+        const code = textArea.textContent;
+        const lang = codeMirrorContainer.getAttribute('data-lang');
+
+        codeMirrorContainer.removeAttribute('contentEditable');
+        const pre = document.createElement('pre');
+        const codeElem = document.createElement('code');
+        codeElem.classList.add(`language-${lang}`);
+        codeElem.textContent = code;
+        pre.appendChild(codeElem);
+
+        codeMirrorContainer.parentElement.replaceChild(pre, codeMirrorContainer);
     }
 
     window.tinymce.PluginManager.add('codeeditor', function(editor, url) {
 
-        let $ = editor.$;
+        const $ = editor.$;
 
         editor.addButton('codeeditor', {
             text: 'Code block',
@@ -189,10 +199,8 @@ function codePlugin() {
 
         // Convert
         editor.on('PreProcess', function (e) {
-            $('div.CodeMirrorContainer', e.node).
-            each((index, elem) => {
-                let $elem = $(elem);
-                codeMirrorContainerToPre($elem);
+            $('div.CodeMirrorContainer', e.node).each((index, elem) => {
+                codeMirrorContainerToPre(elem);
             });
         });
 
@@ -208,10 +216,10 @@ function codePlugin() {
             $('.CodeMirrorContainer').filter((index ,elem) => {
                 return typeof elem.querySelector('.CodeMirror').CodeMirror === 'undefined';
             }).each((index, elem) => {
-                codeMirrorContainerToPre($(elem));
+                codeMirrorContainerToPre(elem);
             });
 
-            let codeSamples = $('body > pre').filter((index, elem) => {
+            const codeSamples = $('body > pre').filter((index, elem) => {
                 return elem.contentEditable !== "false";
             });
 
@@ -332,7 +340,7 @@ function drawIoPlugin() {
         });
 
         editor.on('SetContent', function () {
-            let drawings = editor.$('body > div[drawio-diagram]');
+            const drawings = editor.$('body > div[drawio-diagram]');
             if (!drawings.length) return;
 
             editor.undoManager.transact(function () {
@@ -370,6 +378,27 @@ function customHrPlugin() {
 }
 
 
+function listenForBookStackEditorEvents(editor) {
+
+    // Replace editor content
+    window.$events.listen('editor::replace', ({html}) => {
+        editor.setContent(html);
+    });
+
+    // Append editor content
+    window.$events.listen('editor::append', ({html}) => {
+        const content = editor.getContent() + html;
+        editor.setContent(content);
+    });
+
+    // Prepend editor content
+    window.$events.listen('editor::prepend', ({html}) => {
+        const content = html + editor.getContent();
+        editor.setContent(content);
+    });
+
+}
+
 class WysiwygEditor {
 
     constructor(elem) {
@@ -463,9 +492,10 @@ class WysiwygEditor {
 
                 if (type === 'file') {
                     window.EntitySelectorPopup.show(function(entity) {
-                        let originalField = win.document.getElementById(field_name);
+                        const originalField = win.document.getElementById(field_name);
                         originalField.value = entity.link;
-                        $(originalField).closest('.mce-form').find('input').eq(2).val(entity.name);
+                        const mceForm = originalField.closest('.mce-form');
+                        mceForm.querySelectorAll('input')[2].value = entity.name;
                     });
                 }
 
@@ -544,6 +574,10 @@ class WysiwygEditor {
                     editor.focus();
                 }
 
+                listenForBookStackEditorEvents(editor);
+
+                // TODO - Update to standardise across both editors
+                // Use events within listenForBookStackEditorEvents instead (Different event signature)
                 window.$events.listen('editor-html-update', html => {
                     editor.setContent(html);
                     editor.selection.select(editor.getBody(), true);
@@ -574,6 +608,18 @@ class WysiwygEditor {
                     let dom = editor.dom,
                         rng = tinymce.dom.RangeUtils.getCaretRangeFromPoint(event.clientX, event.clientY, editor.getDoc());
 
+                    // Template insertion
+                    const templateId = event.dataTransfer.getData('bookstack/template');
+                    if (templateId) {
+                        event.preventDefault();
+                        window.$http.get(`/templates/${templateId}`).then(resp => {
+                            editor.selection.setRng(rng);
+                            editor.undoManager.transact(function () {
+                                editor.execCommand('mceInsertContent', false, resp.data.html);
+                            });
+                        });
+                    }
+
                     // Don't allow anything to be dropped in a captioned image.
                     if (dom.getParent(rng.startContainer, '.mceTemp')) {
                         event.preventDefault();