]> BookStack Code Mirror - bookstack/blobdiff - resources/assets/js/pages/page-form.js
Russian lang added
[bookstack] / resources / assets / js / pages / page-form.js
index a443213bf1a7f562bd701900a38f35963bcbfd7d..497dc0212521797f54eb410d0bc178cfa534b44d 100644 (file)
@@ -52,14 +52,36 @@ function editorPaste(e, editor) {
 function registerEditorShortcuts(editor) {
     // Headers
     for (let i = 1; i < 5; i++) {
-        editor.addShortcut('meta+' + i, '', ['FormatBlock', false, 'h' + i]);
+        editor.shortcuts.add('meta+' + i, '', ['FormatBlock', false, 'h' + (i+1)]);
     }
 
     // Other block shortcuts
-    editor.addShortcut('meta+q', '', ['FormatBlock', false, 'blockquote']);
-    editor.addShortcut('meta+d', '', ['FormatBlock', false, 'p']);
-    editor.addShortcut('meta+e', '', ['codeeditor', false, 'pre']);
-    editor.addShortcut('meta+shift+E', '', ['FormatBlock', false, 'code']);
+    editor.shortcuts.add('meta+5', '', ['FormatBlock', false, 'p']);
+    editor.shortcuts.add('meta+d', '', ['FormatBlock', false, 'p']);
+    editor.shortcuts.add('meta+6', '', ['FormatBlock', false, 'blockquote']);
+    editor.shortcuts.add('meta+q', '', ['FormatBlock', false, 'blockquote']);
+    editor.shortcuts.add('meta+7', '', ['codeeditor', false, 'pre']);
+    editor.shortcuts.add('meta+e', '', ['codeeditor', false, 'pre']);
+    editor.shortcuts.add('meta+8', '', ['FormatBlock', false, 'code']);
+    editor.shortcuts.add('meta+shift+E', '', ['FormatBlock', false, 'code']);
+    // Loop through callout styles
+    editor.shortcuts.add('meta+9', '', function() {
+        let selectedNode = editor.selection.getNode();
+        let formats = ['info', 'success', 'warning', 'danger'];
+
+        if (!selectedNode || selectedNode.className.indexOf('callout') === -1) {
+            editor.formatter.apply('calloutinfo');
+            return;
+        }
+
+        for (let i = 0; i < formats.length; i++) {
+            if (selectedNode.className.indexOf(formats[i]) === -1) continue;
+            let newFormat = (i === formats.length -1) ? formats[0] : formats[i+1];
+            editor.formatter.apply('callout' + newFormat);
+            return;
+        }
+        editor.formatter.apply('p');
+    });
 }
 
 
@@ -81,6 +103,7 @@ function codePlugin() {
                 let wrap = document.createElement('div');
                 wrap.innerHTML = `<pre><code class="language-${lang}"></code></pre>`;
                 wrap.querySelector('code').innerText = code;
+
                 editor.formatter.toggle('pre');
                 let node = editor.selection.getNode();
                 editor.dom.setHTML(node, wrap.querySelector('pre').innerHTML);
@@ -105,7 +128,21 @@ function codePlugin() {
         });
     }
 
-    window.tinymce.PluginManager.add('codeeditor', (editor, url) => {
+    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);
+    }
+
+    window.tinymce.PluginManager.add('codeeditor', function(editor, url) {
 
         let $ = editor.$;
 
@@ -124,42 +161,66 @@ function codePlugin() {
             $('div.CodeMirrorContainer', e.node).
             each((index, elem) => {
                 let $elem = $(elem);
-                let textArea = elem.querySelector('textarea');
-                let code = textArea.textContent;
-                let lang = elem.getAttribute('data-lang');
-
-                // $elem.attr('class', $.trim($elem.attr('class')));
-                $elem.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}`));
-                $elem.replaceWith($pre);
+                codeMirrorContainerToPre($elem);
             });
         });
 
+        editor.on('dblclick', event => {
+            let selectedNode = editor.selection.getNode();
+            if (!elemIsCodeBlock(selectedNode)) return;
+            showPopup(editor);
+        });
+
         editor.on('SetContent', function () {
+
+            // Recover broken codemirror instances
+            $('.CodeMirrorContainer').filter((index ,elem) => {
+                return typeof elem.querySelector('.CodeMirror').CodeMirror === 'undefined';
+            }).each((index, elem) => {
+                codeMirrorContainerToPre($(elem));
+            });
+
             let codeSamples = $('body > pre').filter((index, elem) => {
                 return elem.contentEditable !== "false";
             });
 
-            if (codeSamples.length) {
-                editor.undoManager.transact(function () {
-                    codeSamples.each((index, elem) => {
-                        let editDetails = Code.wysiwygView(elem);
-                        editDetails.wrap.addEventListener('dblclick', () => {
-                            showPopup(editor, editDetails.wrap, editDetails.editor);
-                        });
-                    });
+            if (!codeSamples.length) return;
+            editor.undoManager.transact(function () {
+                codeSamples.each((index, elem) => {
+                    Code.wysiwygView(elem);
                 });
-            }
+            });
+        });
+
+    });
+}
+
+function hrPlugin() {
+    window.tinymce.PluginManager.add('customhr', function (editor) {
+        editor.addCommand('InsertHorizontalRule', function () {
+            let hrElem = document.createElement('hr');
+            let cNode = editor.selection.getNode();
+            let parentNode = cNode.parentNode;
+            parentNode.insertBefore(hrElem, cNode);
         });
 
+        editor.addButton('hr', {
+            icon: 'hr',
+            tooltip: 'Horizontal line',
+            cmd: 'InsertHorizontalRule'
+        });
+
+        editor.addMenuItem('hr', {
+            icon: 'hr',
+            text: 'Horizontal line',
+            cmd: 'InsertHorizontalRule',
+            context: 'insert'
+        });
     });
 }
 
 module.exports = function() {
+    hrPlugin();
     codePlugin();
     let settings = {
         selector: '#html-editor',
@@ -178,7 +239,7 @@ module.exports = function() {
         paste_data_images: false,
         extended_valid_elements: 'pre[*]',
         automatic_uploads: false,
-        valid_children: "-div[p|pre|h1|h2|h3|h4|h5|h6|blockquote]",
+        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",
         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",
@@ -190,25 +251,30 @@ module.exports = function() {
             {title: "Header Tiny", format: "h5"},
             {title: "Paragraph", format: "p", exact: true, classes: ''},
             {title: "Blockquote", format: "blockquote"},
-            {title: "Code Block", icon: "code", cmd: 'codeeditor'},
+            {title: "Code Block", icon: "code", cmd: 'codeeditor', format: 'codeeditor'},
             {title: "Inline Code", icon: "code", inline: "code"},
             {title: "Callouts", items: [
-                {title: "Success", block: 'p', exact: true, attributes : {'class' : 'callout success'}},
-                {title: "Info", block: 'p', exact: true, attributes : {'class' : 'callout info'}},
-                {title: "Warning", block: 'p', exact: true, attributes : {'class' : 'callout warning'}},
-                {title: "Danger", block: 'p', exact: true, attributes : {'class' : 'callout danger'}}
+                {title: "Info", format: 'calloutinfo'},
+                {title: "Success", format: 'calloutsuccess'},
+                {title: "Warning", format: 'calloutwarning'},
+                {title: "Danger", format: 'calloutdanger'}
             ]},
         ],
         style_formats_merge: 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'},
             aligncenter: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-center'},
             alignright: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-right'},
+            calloutsuccess: {block: 'p', exact: true, attributes: {class: 'callout success'}},
+            calloutinfo: {block: 'p', exact: true, attributes: {class: 'callout info'}},
+            calloutwarning: {block: 'p', exact: true, attributes: {class: 'callout warning'}},
+            calloutdanger: {block: 'p', exact: true, attributes: {class: 'callout danger'}}
         },
         file_browser_callback: function (field_name, url, type, win) {
 
             if (type === 'file') {
-                window.showEntityLinkSelector(function(entity) {
+                window.EntitySelectorPopup.show(function(entity) {
                     let originalField = win.document.getElementById(field_name);
                     originalField.value = entity.link;
                     $(originalField).closest('.mce-form').find('input').eq(2).val(entity.name);
@@ -217,7 +283,7 @@ module.exports = function() {
 
             if (type === 'image') {
                 // Show image manager
-                window.ImageManager.showExternal(function (image) {
+                window.ImageManager.show(function (image) {
 
                     // Set popover link input to image url then fire change event
                     // to ensure the new value sticks
@@ -299,7 +365,7 @@ module.exports = function() {
                 icon: 'image',
                 tooltip: 'Insert an image',
                 onclick: function () {
-                    window.ImageManager.showExternal(function (image) {
+                    window.ImageManager.show(function (image) {
                         let html = `<a href="${image.url}" target="_blank">`;
                         html += `<img src="${image.thumbs.display}" alt="${image.name}">`;
                         html += '</a>';