]> BookStack Code Mirror - bookstack/commitdiff
Started draw.io integration
authorDan Brown <redacted>
Sun, 24 Dec 2017 14:28:35 +0000 (14:28 +0000)
committerDan Brown <redacted>
Sun, 24 Dec 2017 14:28:35 +0000 (14:28 +0000)
resources/assets/js/pages/page-form.js
resources/assets/sass/styles.scss

index 904403fc1a5afbb2d9ceb2a0924d0eff5589aca4..e47c575f3c70f08bc87c28b690e6b99626b8e57e 100644 (file)
@@ -220,6 +220,124 @@ function codePlugin() {
 }
 codePlugin();
 
+function drawIoPlugin() {
+
+    const drawIoUrl = 'https://www.draw.io/?embed=1&ui=atlas&spin=1&proto=json';
+    let iframe = null;
+    let pageEditor = null;
+
+    function isDrawing(node) {
+        return node.hasAttribute('drawio-diagram');
+    }
+
+    function showDrawingEditor(mceEditor) {
+        pageEditor = mceEditor;
+        iframe = document.createElement('iframe');
+        iframe.setAttribute('frameborder', '0');
+        window.addEventListener('message', drawReceive);
+        iframe.setAttribute('src', drawIoUrl);
+        iframe.setAttribute('class', 'fullscreen');
+        document.body.appendChild(iframe);
+    }
+
+    function drawReceive(event) {
+        if (!event.data || event.data.length < 1) return;
+        let message = JSON.parse(event.data);
+        console.log(message);
+        if (message.event === 'init') {
+            drawEventInit();
+        } else if (message.event === 'exit') {
+            drawEventClose();
+        } else if (message.event === 'save') {
+            drawEventSave(message);
+        } else if (message.event === 'export') {
+            drawEventExport(message);
+        }
+    }
+
+    function updateContent(svg) {
+        let svgWrap = document.createElement('div');
+        svgWrap.setAttribute('drawio-diagram', svg);
+        svgWrap.setAttribute('contenteditable', 'false');
+        pageEditor.insertContent(svgWrap.outerHTML);
+    }
+
+    function b64DecodeUnicode(str) {
+        str = str.split(';base64,')[1];
+        // Going backwards: from bytestream, to percent-encoding, to original string.
+        return decodeURIComponent(atob(str).split('').map(function(c) {
+            return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
+        }).join(''));
+    }
+
+    function drawEventExport(message) {
+        updateContent(message.data);
+    }
+
+    function drawEventSave(message) {
+        drawPostMessage({action: 'export', format: 'svg', xml: message.xml, spin: 'Updating drawing'});
+    }
+
+    function drawEventInit() {
+        drawPostMessage({action: 'load', autosave: 1, xml: ''});
+    }
+
+    function drawEventClose() {
+        window.removeEventListener('message', drawReceive);
+        if (iframe) document.body.removeChild(iframe);
+    }
+
+    function drawPostMessage(data) {
+        iframe.contentWindow.postMessage(JSON.stringify(data), '*');
+    }
+
+    window.tinymce.PluginManager.add('drawio', function(editor, url) {
+
+        let $ = editor.$;
+
+        editor.addCommand('drawio', () => {
+            showDrawingEditor(editor);
+        });
+
+        editor.addButton('drawio', {
+            text: 'Drawing',
+            icon: false,
+            cmd: 'drawio'
+        });
+
+        editor.on('dblclick', event => {
+            let selectedNode = editor.selection.getNode();
+            if (!isDrawing(selectedNode)) return;
+            showDrawingEditor(editor);
+        });
+
+        editor.on('PreProcess', function (e) {
+            $('div[drawio-diagram]', e.node).
+            each((index, elem) => {
+                let $elem = $(elem);
+                let svgData = b64DecodeUnicode($elem.attr('drawio-diagram'));
+                $elem.html(svgData);
+            });
+        });
+
+        editor.on('SetContent', function () {
+
+            let drawings = $('body > div[drawio-diagram]');
+
+            if (!drawings.length) return;
+            editor.undoManager.transact(function () {
+                drawings.each((index, elem) => {
+                    let svgContent =  b64DecodeUnicode(elem.getAttribute('drawio-diagram'));
+                    elem.setAttribute('contenteditable', 'false');
+                    elem.innerHTML = svgContent;
+                });
+            });
+        });
+
+    });
+}
+drawIoPlugin();
+
 window.tinymce.PluginManager.add('customhr', function (editor) {
     editor.addCommand('InsertHorizontalRule', function () {
         let hrElem = document.createElement('hr');
@@ -259,12 +377,12 @@ module.exports = {
     statusbar: false,
     menubar: false,
     paste_data_images: false,
-    extended_valid_elements: 'pre[*]',
+    extended_valid_elements: 'pre[*],svg[*],div[drawio-diagram]',
     automatic_uploads: false,
-    valid_children: "-div[p|h1|h2|h3|h4|h5|h6|blockquote],+div[pre]",
-    plugins: "image table textcolor paste link autolink fullscreen imagetools code customhr autosave lists codeeditor",
+    valid_children: "-div[p|h1|h2|h3|h4|h5|h6|blockquote],+div[pre],+div[svg],+svg",
+    plugins: "image table textcolor paste link autolink fullscreen imagetools code customhr autosave lists codeeditor drawio",
     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 | removeformat code fullscreen",
+    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 | removeformat code fullscreen drawio",
     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"},
index 6a80237c5b6a674b9cd4763408e6b82a95002f3c..2cb72bd75a0313280197c5fad42fbfe075f1db05 100644 (file)
@@ -231,4 +231,16 @@ $btt-size: 40px;
   input {
     width: 100%;
   }
+}
+
+.fullscreen {
+  border:0;
+  position:fixed;
+  top:0;
+  left:0;
+  right:0;
+  bottom:0;
+  width:100%;
+  height:100%;
+  z-index: 150;
 }
\ No newline at end of file