X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/ef211a76aede33136416d50b6c636de7bff3fbed..refs/pull/3365/head:/resources/js/wysiwyg/plugin-codeeditor.js diff --git a/resources/js/wysiwyg/plugin-codeeditor.js b/resources/js/wysiwyg/plugin-codeeditor.js index 92781f024..82ab7d3c8 100644 --- a/resources/js/wysiwyg/plugin-codeeditor.js +++ b/resources/js/wysiwyg/plugin-codeeditor.js @@ -1,60 +1,135 @@ -import Code from "../services/code"; - function elemIsCodeBlock(elem) { - return elem.className === 'CodeMirrorContainer'; + return elem.tagName.toLowerCase() === 'code-block'; } -function showPopup(editor) { - const selectedNode = editor.selection.getNode(); +/** + * @param {Editor} editor + * @param {String} code + * @param {String} language + * @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() + }); +} - if (!elemIsCodeBlock(selectedNode)) { - const providedCode = editor.selection.getNode().textContent; - window.components.first('code-editor').open(providedCode, '', (code, lang) => { - const wrap = document.createElement('div'); - wrap.innerHTML = `
`;
- wrap.querySelector('code').innerText = code;
+/**
+ * @param {Editor} editor
+ * @param {CodeBlockElement} codeBlock
+ */
+function showPopupForCodeBlock(editor, codeBlock) {
+ showPopup(editor, codeBlock.getContent(), codeBlock.getLanguage(), (newCode, newLang) => {
+ codeBlock.setContent(newCode, newLang);
+ });
+}
- editor.formatter.toggle('pre');
- const node = editor.selection.getNode();
- editor.dom.setHTML(node, wrap.querySelector('pre').innerHTML);
- editor.fire('SetContent');
+/**
+ * Define our custom code-block HTML element that we use.
+ * Needs to be delayed since it needs to be defined within the context of the
+ * child editor window and document, hence its definition within a callback.
+ * @param {Editor} editor
+ */
+function defineCodeBlockCustomElement(editor) {
+ const doc = editor.getDoc();
+ const win = doc.defaultView;
+
+ class CodeBlockElement extends win.HTMLElement {
+ constructor() {
+ super();
+ this.attachShadow({mode: 'open'});
+ const linkElem = document.createElement('link');
+ linkElem.setAttribute('rel', 'stylesheet');
+ linkElem.setAttribute('href', window.baseUrl('/dist/styles.css'));
+
+ const cmContainer = document.createElement('div');
+ cmContainer.style.pointerEvents = 'none';
+ cmContainer.contentEditable = 'false';
+ cmContainer.classList.add('CodeMirrorContainer');
+
+ this.shadowRoot.append(linkElem, cmContainer);
+ }
- editor.focus()
- });
- return;
- }
+ getLanguage() {
+ const getLanguageFromClassList = (classes) => {
+ const langClasses = classes.split(' ').filter(cssClass => cssClass.startsWith('language-'));
+ return (langClasses[0] || '').replace('language-', '');
+ };
- const lang = selectedNode.hasAttribute('data-lang') ? selectedNode.getAttribute('data-lang') : '';
- const currentCode = selectedNode.querySelector('textarea').textContent;
+ const code = this.querySelector('code');
+ const pre = this.querySelector('pre');
+ return getLanguageFromClassList(pre.className) || (code && getLanguageFromClassList(code.className)) || '';
+ }
- window.components.first('code-editor').open(currentCode, lang, (code, lang) => {
- const editorElem = selectedNode.querySelector('.CodeMirror');
- const cmInstance = editorElem.CodeMirror;
- if (cmInstance) {
- Code.setContent(cmInstance, code);
- Code.setMode(cmInstance, lang, code);
+ setContent(content, language) {
+ if (this.cm) {
+ importVersioned('code').then(Code => {
+ Code.setContent(this.cm, content);
+ Code.setMode(this.cm, language, content);
+ });
+ }
+
+ let pre = this.querySelector('pre');
+ if (!pre) {
+ pre = doc.createElement('pre');
+ this.append(pre);
+ }
+ pre.innerHTML = '';
+
+ const code = doc.createElement('code');
+ pre.append(code);
+ code.innerText = content;
+ code.className = `language-${language}`;
}
- const textArea = selectedNode.querySelector('textarea');
- if (textArea) textArea.textContent = code;
- selectedNode.setAttribute('data-lang', lang);
- editor.focus()
- });
-}
+ getContent() {
+ const code = this.querySelector('code') || this.querySelector('pre');
+ const tempEl = document.createElement('pre');
+ tempEl.innerHTML = code.innerHTML.replace().replace(/