]> BookStack Code Mirror - bookstack/blobdiff - resources/js/components/markdown-editor.js
Updated markdown editor to use svg drawio images
[bookstack] / resources / js / components / markdown-editor.js
index 78581ec447f5cf099d64d681c976295d3c6875af..8d117870c180edfc81cf81e43bd43902d128db07 100644 (file)
@@ -1,6 +1,5 @@
 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";
 
@@ -14,6 +13,7 @@ class MarkdownEditor {
         this.pageId = this.$opts.pageId;
         this.textDirection = this.$opts.textDirection;
         this.imageUploadErrorText = this.$opts.imageUploadErrorText;
+        this.serverUploadLimitText = this.$opts.serverUploadLimitText;
 
         this.markdown = new MarkdownIt({html: true});
         this.markdown.use(mdTasksLists, {label: true});
@@ -22,13 +22,20 @@ class MarkdownEditor {
 
         this.displayStylesLoaded = false;
         this.input = this.elem.querySelector('textarea');
-        this.cm = code.markdownEditor(this.input);
+
+        this.cm = null;
+        this.Code = null;
+        const cmLoadPromise = window.importVersioned('code').then(Code => {
+            this.cm = Code.markdownEditor(this.input);
+            this.Code = Code;
+            return this.cm;
+        });
 
         this.onMarkdownScroll = this.onMarkdownScroll.bind(this);
 
         const displayLoad = () => {
             this.displayDoc = this.display.contentDocument;
-            this.init();
+            this.init(cmLoadPromise);
         };
 
         if (this.display.contentDocument.readyState === 'complete') {
@@ -44,7 +51,7 @@ class MarkdownEditor {
         });
     }
 
-    init() {
+    init(cmLoadPromise) {
 
         let lastClick = 0;
 
@@ -97,12 +104,15 @@ class MarkdownEditor {
             toolbarLabel.closest('.markdown-editor-wrap').classList.add('active');
         });
 
-        window.$events.listen('editor-markdown-update', value => {
-            this.cm.setValue(value);
-            this.updateAndRender();
+        cmLoadPromise.then(cm => {
+            this.codeMirrorSetup(cm);
+
+            // Refresh CodeMirror on container resize
+            const resizeDebounced = debounce(() => this.Code.updateLayout(cm), 100, false);
+            const observer = new ResizeObserver(resizeDebounced);
+            observer.observe(this.elem);
         });
 
-        this.codeMirrorSetup();
         this.listenForBookStackEditorEvents();
 
         // Scroll to text if needed.
@@ -157,15 +167,14 @@ class MarkdownEditor {
         topElem.scrollIntoView({ block: 'start', inline: 'nearest', behavior: 'smooth'});
     }
 
-    codeMirrorSetup() {
-        const cm = this.cm;
+    codeMirrorSetup(cm) {
         const context = this;
 
         // Text direction
         // cm.setOption('direction', this.textDirection);
         cm.setOption('direction', 'ltr'); // Will force to remain as ltr for now due to issues when HTML is in editor.
         // Custom key commands
-        let metaKey = code.getMetaKey();
+        let metaKey = this.Code.getMetaKey();
         const extraKeys = {};
         // Insert Image shortcut
         extraKeys[`${metaKey}-Alt-I`] = function(cm) {
@@ -394,8 +403,9 @@ class MarkdownEditor {
     actionInsertImage() {
         const cursorPos = this.cm.getCursor('from');
         window.ImageManager.show(image => {
+            const imageUrl = image.thumbs.display || image.url;
             let selectedText = this.cm.getSelection();
-            let newText = "[![" + (selectedText || image.name) + "](" + image.thumbs.display + ")](" + image.url + ")";
+            let newText = "[![" + (selectedText || image.name) + "](" + imageUrl + ")](" + image.url + ")";
             this.cm.focus();
             this.cm.replaceSelection(newText);
             this.cm.setCursor(cursorPos.line, cursorPos.ch + newText.length);
@@ -435,10 +445,10 @@ class MarkdownEditor {
 
         DrawIO.show(url,() => {
             return Promise.resolve('');
-        }, (pngData) => {
+        }, (drawingData) => {
 
             const data = {
-                image: pngData,
+                image: drawingData,
                 uploaded_to: Number(this.pageId),
             };
 
@@ -446,14 +456,13 @@ class MarkdownEditor {
                 this.insertDrawing(resp.data, cursorPos);
                 DrawIO.close();
             }).catch(err => {
-                window.$events.emit('error', trans('errors.image_upload_error'));
-                console.log(err);
+                this.handleDrawingUploadError(err);
             });
         });
     }
 
     insertDrawing(image, originalCursor) {
-        const newText = `<div drawio-diagram="${image.id}"><img src="${image.url}"></div>`;
+        const newText = DrawIO.buildDrawingContentHtml(image);
         this.cm.focus();
         this.cm.replaceSelection(newText);
         this.cm.setCursor(originalCursor.line, originalCursor.ch + newText.length);
@@ -471,32 +480,41 @@ class MarkdownEditor {
 
         DrawIO.show(drawioUrl, () => {
             return DrawIO.load(drawingId);
-        }, (pngData) => {
+        }, (drawingData) => {
 
             let data = {
-                image: pngData,
+                image: drawingData,
                 uploaded_to: Number(this.pageId),
             };
 
             window.$http.post("/images/drawio", data).then(resp => {
-                let newText = `<div drawio-diagram="${resp.data.id}"><img src="${resp.data.url}"></div>`;
-                let newContent = this.cm.getValue().split('\n').map(line => {
-                    if (line.indexOf(`drawio-diagram="${drawingId}"`) !== -1) {
-                        return newText;
-                    }
-                    return line;
+                const image = resp.data;
+                const newText = DrawIO.buildDrawingContentHtml(image);
+
+                const newContent = this.cm.getValue().split('\n').map(line => {
+                    const isDrawing = line.includes(`drawio-diagram="${drawingId}"`);
+                    return isDrawing ? newText : line;
                 }).join('\n');
+
                 this.cm.setValue(newContent);
                 this.cm.setCursor(cursorPos);
                 this.cm.focus();
                 DrawIO.close();
             }).catch(err => {
-                window.$events.emit('error', this.imageUploadErrorText);
-                console.log(err);
+                this.handleDrawingUploadError(err);
             });
         });
     }
 
+    handleDrawingUploadError(error) {
+        if (error.status === 413) {
+            window.$events.emit('error', this.serverUploadLimitText);
+        } else {
+            window.$events.emit('error', this.imageUploadErrorText);
+        }
+        console.log(error);
+    }
+
     // Make the editor full screen
     actionFullScreen() {
         const alreadyFullscreen = this.elem.classList.contains('fullscreen');