X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/94f464cd14a8f2a54a8fada9cb777c0e6f28fa93..refs/pull/5153/head:/resources/js/wysiwyg/plugin-codeeditor.js diff --git a/resources/js/wysiwyg/plugin-codeeditor.js b/resources/js/wysiwyg/plugin-codeeditor.js index 9e681486d..c01a7eca0 100644 --- a/resources/js/wysiwyg/plugin-codeeditor.js +++ b/resources/js/wysiwyg/plugin-codeeditor.js @@ -6,12 +6,20 @@ function elemIsCodeBlock(elem) { * @param {Editor} editor * @param {String} code * @param {String} language + * @param {String} direction * @param {function(string, string)} callback (Receives (code: string,language: string) */ -function showPopup(editor, code, language, callback) { - window.$components.first('code-editor').open(code, language, (newCode, newLang) => { - callback(newCode, newLang) - editor.focus() +function showPopup(editor, code, language, direction, callback) { + /** @var {CodeEditor} codeEditor * */ + const codeEditor = window.$components.first('code-editor'); + const bookMark = editor.selection.getBookmark(); + codeEditor.open(code, language, direction, (newCode, newLang) => { + callback(newCode, newLang); + editor.focus(); + editor.selection.moveToBookmark(bookMark); + }, () => { + editor.focus(); + editor.selection.moveToBookmark(bookMark); }); } @@ -20,7 +28,8 @@ function showPopup(editor, code, language, callback) { * @param {CodeBlockElement} codeBlock */ function showPopupForCodeBlock(editor, codeBlock) { - showPopup(editor, codeBlock.getContent(), codeBlock.getLanguage(), (newCode, newLang) => { + const direction = codeBlock.getAttribute('dir') || ''; + showPopup(editor, codeBlock.getContent(), codeBlock.getLanguage(), direction, (newCode, newLang) => { codeBlock.setContent(newCode, newLang); }); } @@ -46,8 +55,8 @@ function defineCodeBlockCustomElement(editor) { super(); this.attachShadow({mode: 'open'}); - const stylesToCopy = document.querySelectorAll('link[rel="stylesheet"]:not([media="print"])'); - const copiedStyles = Array.from(stylesToCopy).map(styleEl => styleEl.cloneNode(false)); + const stylesToCopy = document.head.querySelectorAll('link[rel="stylesheet"]:not([media="print"]),style'); + const copiedStyles = Array.from(stylesToCopy).map(styleEl => styleEl.cloneNode(true)); const cmContainer = document.createElement('div'); cmContainer.style.pointerEvents = 'none'; @@ -59,7 +68,7 @@ function defineCodeBlockCustomElement(editor) { } getLanguage() { - const getLanguageFromClassList = (classes) => { + const getLanguageFromClassList = classes => { const langClasses = classes.split(' ').filter(cssClass => cssClass.startsWith('language-')); return (langClasses[0] || '').replace('language-', ''); }; @@ -114,12 +123,14 @@ function defineCodeBlockCustomElement(editor) { this.style.height = `${height}px`; const container = this.shadowRoot.querySelector('.CodeMirrorContainer'); - const renderEditor = (Code) => { + const renderEditor = Code => { this.editor = Code.wysiwygView(container, this.shadowRoot, content, this.getLanguage()); - setTimeout(() => this.style.height = null, 12); + setTimeout(() => { + this.style.height = null; + }, 12); }; - window.importVersioned('code').then((Code) => { + window.importVersioned('code').then(Code => { const timeout = (Date.now() - connectedTime < 20) ? 20 : 0; setTimeout(() => renderEditor(Code), timeout); }); @@ -135,26 +146,24 @@ function defineCodeBlockCustomElement(editor) { } } } + } win.customElements.define('code-block', CodeBlockElement); } - /** * @param {Editor} editor - * @param {String} url */ -function register(editor, url) { - - editor.ui.registry.addIcon('codeblock', '') +function register(editor) { + editor.ui.registry.addIcon('codeblock', ''); editor.ui.registry.addButton('codeeditor', { tooltip: 'Insert code block', icon: 'codeblock', onAction() { editor.execCommand('codeeditor'); - } + }, }); editor.ui.registry.addButton('editcodeeditor', { @@ -162,7 +171,7 @@ function register(editor, url) { icon: 'edit-block', onAction() { editor.execCommand('codeeditor'); - } + }, }); editor.addCommand('codeeditor', () => { @@ -172,32 +181,42 @@ function register(editor, url) { showPopupForCodeBlock(editor, selectedNode); } else { const textContent = editor.selection.getContent({format: 'text'}); - showPopup(editor, textContent, '', (newCode, newLang) => { + const direction = document.dir === 'rtl' ? 'ltr' : ''; + showPopup(editor, textContent, '', direction, (newCode, newLang) => { const pre = doc.createElement('pre'); const code = doc.createElement('code'); code.classList.add(`language-${newLang}`); code.innerText = newCode; - pre.append(code); + if (direction) { + pre.setAttribute('dir', direction); + } + pre.append(code); editor.insertContent(pre.outerHTML); }); } }); - editor.on('dblclick', event => { - let selectedNode = editor.selection.getNode(); + editor.on('dblclick', () => { + const selectedNode = editor.selection.getNode(); if (elemIsCodeBlock(selectedNode)) { showPopupForCodeBlock(editor, selectedNode); } }); editor.on('PreInit', () => { - editor.parser.addNodeFilter('pre', function(elms) { + editor.parser.addNodeFilter('pre', elms => { for (const el of elms) { - const wrapper = tinymce.html.Node.create('code-block', { + const wrapper = window.tinymce.html.Node.create('code-block', { contenteditable: 'false', }); + const childCodeBlock = el.children().filter(child => child.name === 'code')[0] || null; + const direction = el.attr('dir') || (childCodeBlock && childCodeBlock.attr('dir')) || ''; + if (direction) { + wrapper.attr('dir', direction); + } + const spans = el.getAll('span'); for (const span of spans) { span.unwrap(); @@ -207,26 +226,33 @@ function register(editor, url) { } }); - editor.parser.addNodeFilter('code-block', function(elms) { + editor.parser.addNodeFilter('code-block', elms => { for (const el of elms) { el.attr('contenteditable', 'false'); } }); - editor.serializer.addNodeFilter('code-block', function(elms) { + editor.serializer.addNodeFilter('code-block', elms => { for (const el of elms) { + const direction = el.attr('dir'); + if (direction && el.firstChild) { + el.firstChild.attr('dir', direction); + } else if (el.firstChild) { + el.firstChild.attr('dir', null); + } + el.unwrap(); } }); }); editor.ui.registry.addContextToolbar('codeeditor', { - predicate: function (node) { + predicate(node) { return node.nodeName.toLowerCase() === 'code-block'; }, items: 'editcodeeditor', position: 'node', - scope: 'node' + scope: 'node', }); editor.on('PreInit', () => { @@ -235,9 +261,8 @@ function register(editor, url) { } /** - * @param {WysiwygConfigOptions} options * @return {register} */ -export function getPlugin(options) { +export function getPlugin() { return register; -} \ No newline at end of file +}