]> BookStack Code Mirror - bookstack/blobdiff - resources/assets/js/components/markdown-editor.js
Merge branch 'unicode' of git://github.com/kostasdizas/BookStack into kostasdizas...
[bookstack] / resources / assets / js / components / markdown-editor.js
index 770b4af5054a7b2665e23a6026a83f47bd326bca..7cb56eef831ee5fb75636a1f91345a505dd528a8 100644 (file)
@@ -1,6 +1,7 @@
 import MarkdownIt from "markdown-it";
 import mdTasksLists from 'markdown-it-task-lists';
 import code from '../services/code';
+import {debounce} from "../services/util";
 
 import DrawIO from "../services/drawio";
 
@@ -90,6 +91,7 @@ class MarkdownEditor {
         });
 
         this.codeMirrorSetup();
+        this.listenForBookStackEditorEvents();
     }
 
     // Update the input content and render the display.
@@ -104,14 +106,11 @@ class MarkdownEditor {
     }
 
     onMarkdownScroll(lineCount) {
-        let elems = this.display.children;
+        const elems = this.display.children;
         if (elems.length <= lineCount) return;
 
-        let topElem = (lineCount === -1) ? elems[elems.length-1] : elems[lineCount];
-        // TODO - Replace jQuery
-        $(this.display).animate({
-            scrollTop: topElem.offsetTop
-        }, {queue: false, duration: 200, easing: 'linear'});
+        const topElem = (lineCount === -1) ? elems[elems.length-1] : elems[lineCount];
+        topElem.scrollIntoView({ block: 'start', inline: 'nearest', behavior: 'smooth'});
     }
 
     codeMirrorSetup() {
@@ -160,8 +159,7 @@ class MarkdownEditor {
             this.updateAndRender();
         });
 
-        // Handle scroll to sync display view
-        cm.on('scroll', instance => {
+        const onScrollDebounced = debounce((instance) => {
             // Thanks to http://liuhao.im/english/2015/11/10/the-sync-scroll-of-markdown-editor-in-javascript.html
             let scroll = instance.getScrollInfo();
             let atEnd = scroll.top + scroll.clientHeight === scroll.height;
@@ -176,13 +174,29 @@ class MarkdownEditor {
             let doc = parser.parseFromString(this.markdown.render(range), 'text/html');
             let totalLines = doc.documentElement.querySelectorAll('body > *');
             this.onMarkdownScroll(totalLines.length);
+        }, 100);
+
+        // Handle scroll to sync display view
+        cm.on('scroll', instance => {
+            onScrollDebounced(instance);
         });
 
         // Handle image paste
         cm.on('paste', (cm, event) => {
-            if (!event.clipboardData || !event.clipboardData.items) return;
-            for (let i = 0; i < event.clipboardData.items.length; i++) {
-                uploadImage(event.clipboardData.items[i].getAsFile());
+            const clipboardItems = event.clipboardData.items;
+            if (!event.clipboardData || !clipboardItems) return;
+
+            // 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")) {
+                    uploadImage(clipboardItem.getAsFile());
+                }
             }
         });
 
@@ -448,6 +462,37 @@ class MarkdownEditor {
         })
     }
 
+    listenForBookStackEditorEvents() {
+
+        function getContentToInsert({html, markdown}) {
+            return markdown || html;
+        }
+
+        // Replace editor content
+        window.$events.listen('editor::replace', (eventContent) => {
+            const markdown = getContentToInsert(eventContent);
+            this.cm.setValue(markdown);
+        });
+
+        // Append editor content
+        window.$events.listen('editor::append', (eventContent) => {
+            const cursorPos = this.cm.getCursor('from');
+            const markdown = getContentToInsert(eventContent);
+            const content = this.cm.getValue() + '\n' + markdown;
+            this.cm.setValue(content);
+            this.cm.setCursor(cursorPos.line, cursorPos.ch);
+        });
+
+        // Prepend editor content
+        window.$events.listen('editor::prepend', (eventContent) => {
+            const cursorPos = this.cm.getCursor('from');
+            const markdown = getContentToInsert(eventContent);
+            const content = markdown + '\n' + this.cm.getValue();
+            this.cm.setValue(content);
+            const prependLineCount = markdown.split('\n').length;
+            this.cm.setCursor(cursorPos.line + prependLineCount, cursorPos.ch);
+        });
+    }
 }
 
 export default MarkdownEditor ;