]> BookStack Code Mirror - bookstack/blobdiff - resources/assets/js/components/wysiwyg-editor.js
Rolled tri-layout to page edit and book-create
[bookstack] / resources / assets / js / components / wysiwyg-editor.js
index 5392332043e9bca56615be5e68c14a567bf33d9d..39bce49591e490a90559c8f8e34a95d6aafe66f5 100644 (file)
@@ -1,5 +1,5 @@
-const Code = require('../services/code');
-const DrawIO = require('../services/drawio');
+import Code from "../services/code";
+import DrawIO from "../services/drawio";
 
 /**
  * Handle pasting images from clipboard.
@@ -221,8 +221,6 @@ function codePlugin() {
 
 function drawIoPlugin() {
 
-    const drawIoUrl = 'https://www.draw.io/?embed=1&ui=atlas&spin=1&proto=json';
-    let iframe = null;
     let pageEditor = null;
     let currentNode = null;
 
@@ -230,6 +228,22 @@ function drawIoPlugin() {
         return node.hasAttribute('drawio-diagram');
     }
 
+    function showDrawingManager(mceEditor, selectedNode = null) {
+        pageEditor = mceEditor;
+        currentNode = selectedNode;
+        // Show image manager
+        window.ImageManager.show(function (image) {
+            if (selectedNode) {
+                let imgElem = selectedNode.querySelector('img');
+                pageEditor.dom.setAttrib(imgElem, 'src', image.url);
+                pageEditor.dom.setAttrib(selectedNode, 'drawio-diagram', image.id);
+            } else {
+                let imgHTML = `<div drawio-diagram="${image.id}" contenteditable="false"><img src="${image.url}"></div>`;
+                pageEditor.insertContent(imgHTML);
+            }
+        }, 'drawio');
+    }
+
     function showDrawingEditor(mceEditor, selectedNode = null) {
         pageEditor = mceEditor;
         currentNode = selectedNode;
@@ -248,9 +262,9 @@ function drawIoPlugin() {
         if (currentNode) {
             DrawIO.close();
             let imgElem = currentNode.querySelector('img');
-            let drawingId = currentNode.getAttribute('drawio-diagram');
-            window.$http.put(window.baseUrl(`/images/drawing/upload/${drawingId}`), data).then(resp => {
-                pageEditor.dom.setAttrib(imgElem, 'src', `${resp.data.url}?updated=${Date.now()}`);
+            window.$http.post(window.baseUrl(`/images/drawing/upload`), data).then(resp => {
+                pageEditor.dom.setAttrib(imgElem, 'src', resp.data.url);
+                pageEditor.dom.setAttrib(currentNode, 'drawio-diagram', resp.data.id);
             }).catch(err => {
                 window.$events.emit('error', trans('errors.image_upload_error'));
                 console.log(err);
@@ -287,13 +301,24 @@ function drawIoPlugin() {
     window.tinymce.PluginManager.add('drawio', function(editor, url) {
 
         editor.addCommand('drawio', () => {
-            showDrawingEditor(editor);
+            let selectedNode = editor.selection.getNode();
+            showDrawingEditor(editor, isDrawing(selectedNode) ? selectedNode : null);
         });
 
         editor.addButton('drawio', {
+            type: 'splitbutton',
             tooltip: 'Drawing',
-            image: window.baseUrl('/icon/drawing.svg?color=000000'),
-            cmd: 'drawio'
+            image: `data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9IiMwMDAwMDAiICB4bWxucz0iaHR0cDovL3d3 dy53My5vcmcvMjAwMC9zdmciPgogICAgPHBhdGggZD0iTTIzIDdWMWgtNnYySDdWMUgxdjZoMnYx MEgxdjZoNnYtMmgxMHYyaDZ2LTZoLTJWN2gyek0zIDNoMnYySDNWM3ptMiAxOEgzdi0yaDJ2Mnpt MTItMkg3di0ySDVWN2gyVjVoMTB2MmgydjEwaC0ydjJ6bTQgMmgtMnYtMmgydjJ6TTE5IDVWM2gy djJoLTJ6bS01LjI3IDloLTMuNDlsLS43MyAySDcuODlsMy40LTloMS40bDMuNDEgOWgtMS42M2wt Ljc0LTJ6bS0zLjA0LTEuMjZoMi42MUwxMiA4LjkxbC0xLjMxIDMuODN6Ii8+CiAgICA8cGF0aCBk PSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+Cjwvc3ZnPg==`,
+            cmd: 'drawio',
+            menu: [
+                {
+                    text: 'Drawing Manager',
+                    onclick() {
+                        let selectedNode = editor.selection.getNode();
+                        showDrawingManager(editor, isDrawing(selectedNode) ? selectedNode : null);
+                    }
+                }
+            ]
         });
 
         editor.on('dblclick', event => {
@@ -345,8 +370,9 @@ class WysiwygEditor {
 
     constructor(elem) {
         this.elem = elem;
+        this.textDirection = document.getElementById('page-editor').getAttribute('text-direction');
 
-        this.plugins = "image table textcolor paste link autolink fullscreen imagetools code customhr autosave lists codeeditor";
+        this.plugins = "image table textcolor paste link autolink fullscreen imagetools code customhr autosave lists codeeditor media";
         this.loadPlugins();
 
         this.tinyMceConfig = this.getTinyMceConfig();
@@ -360,6 +386,14 @@ class WysiwygEditor {
             drawIoPlugin();
             this.plugins += ' drawio';
         }
+        if (this.textDirection === 'rtl') {
+            this.plugins += ' directionality'
+        }
+    }
+
+    getToolBar() {
+        const textDirPlugins = this.textDirection === 'rtl' ? 'ltr rtl' : '';
+        return `undo redo | styleselect | bold italic underline strikethrough superscript subscript | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image-insert link hr drawio media | removeformat code ${textDirPlugins} fullscreen`
     }
 
     getTinyMceConfig() {
@@ -372,8 +406,10 @@ class WysiwygEditor {
             body_class: 'page-content',
             browser_spellcheck: true,
             relative_urls: false,
+            directionality : this.textDirection,
             remove_script_host: false,
             document_base_url: window.baseUrl('/'),
+            end_container_on_empty_block: true,
             statusbar: false,
             menubar: false,
             paste_data_images: false,
@@ -382,7 +418,7 @@ class WysiwygEditor {
             valid_children: "-div[p|h1|h2|h3|h4|h5|h6|blockquote],+div[pre],+div[img]",
             plugins: this.plugins,
             imagetools_toolbar: 'imageoptions',
-            toolbar: "undo redo | styleselect | bold italic underline strikethrough superscript subscript | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image-insert link hr drawio | removeformat code fullscreen",
+            toolbar: this.getToolBar(),
             content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
             style_formats: [
                 {title: "Header Large", format: "h2"},
@@ -401,6 +437,8 @@ class WysiwygEditor {
                     ]},
             ],
             style_formats_merge: false,
+            media_alt_source: false,
+            media_poster: false,
             formats: {
                 codeeditor: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div'},
                 alignleft: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-left'},
@@ -441,7 +479,7 @@ class WysiwygEditor {
                         html += `<img src="${image.thumbs.display}" alt="${image.name}">`;
                         html += '</a>';
                         win.tinyMCE.activeEditor.execCommand('mceInsertContent', false, html);
-                    });
+                    }, 'gallery');
                 }
 
             },
@@ -456,13 +494,36 @@ class WysiwygEditor {
             },
             setup: function (editor) {
 
-                editor.on('init ExecCommand change input NodeChange ObjectResized', editorChange);
+                editor.on('ExecCommand change input NodeChange ObjectResized', editorChange);
+
+                editor.on('init', () => {
+                    editorChange();
+                    // Scroll to the content if needed.
+                    const queryParams = (new URL(window.location)).searchParams;
+                    const scrollId = queryParams.get('content-id');
+                    if (scrollId) {
+                        scrollToText(scrollId);
+                    }
+                });
 
                 function editorChange() {
                     let content = editor.getContent();
                     window.$events.emit('editor-html-change', content);
                 }
 
+                function scrollToText(scrollId) {
+                    const element = editor.dom.get(encodeURIComponent(scrollId).replace(/!/g, '%21'));
+                    if (!element) {
+                        return;
+                    }
+
+                    // scroll the element into the view and put the cursor at the end.
+                    element.scrollIntoView();
+                    editor.selection.select(element, true);
+                    editor.selection.collapse(false);
+                    editor.focus();
+                }
+
                 window.$events.listen('editor-html-update', html => {
                     editor.setContent(html);
                     editor.selection.select(editor.getBody(), true);
@@ -520,7 +581,7 @@ class WysiwygEditor {
                             html += `<img src="${image.thumbs.display}" alt="${image.name}">`;
                             html += '</a>';
                             editor.execCommand('mceInsertContent', false, html);
-                        });
+                        }, 'gallery');
                     }
                 });
 
@@ -532,4 +593,4 @@ class WysiwygEditor {
 
 }
 
-module.exports = WysiwygEditor;
\ No newline at end of file
+export default WysiwygEditor;