]> BookStack Code Mirror - bookstack/commitdiff
WYSIWYG: Added text direction support for code editor popup
authorDan Brown <redacted>
Fri, 3 May 2024 12:35:30 +0000 (13:35 +0100)
committerDan Brown <redacted>
Fri, 3 May 2024 12:40:00 +0000 (13:40 +0100)
Editor popup will now reflect the direction of the opened code block.
This also updates in-editor codemirror instances to correcly reflect/use
the direction if set on the inner code elem.

This also defaults new code blocks, when in RTL languages, to be started
in LTR, which can then be changed via in-editor direction controls if
needed. This is on the assumption that most code will be LTR (could not
find much examples of RTL code use).

Fixes #4943

resources/js/code/index.mjs
resources/js/components/code-editor.js
resources/js/wysiwyg/plugin-codeeditor.js
resources/sass/_components.scss

index ab31e3f74e43d9ddf2334a9f5f7e183d906d1851..d2ea12a4c93cd6d8593cca9068e8801f9c55248d 100644 (file)
@@ -38,6 +38,23 @@ function addCopyIcon(editorView) {
     });
 }
 
+/**
+ * @param {HTMLElement} codeElem
+ * @returns {String}
+ */
+function getDirectionFromCodeBlock(codeElem) {
+    let dir = '';
+    const innerCodeElem = codeElem.querySelector('code');
+
+    if (innerCodeElem && innerCodeElem.hasAttribute('dir')) {
+        dir = innerCodeElem.getAttribute('dir');
+    } else if (codeElem.hasAttribute('dir')) {
+        dir = codeElem.getAttribute('dir');
+    }
+
+    return dir;
+}
+
 /**
  * Add code highlighting to a single element.
  * @param {HTMLElement} elem
@@ -48,16 +65,14 @@ function highlightElem(elem) {
     const content = elem.textContent.trimEnd();
 
     let langName = '';
-    let innerCodeDirection = '';
     if (innerCodeElem !== null) {
         langName = innerCodeElem.className.replace('language-', '');
-        innerCodeDirection = innerCodeElem.getAttribute('dir');
     }
 
     const wrapper = document.createElement('div');
     elem.parentNode.insertBefore(wrapper, elem);
 
-    const direction = innerCodeDirection || elem.getAttribute('dir') || '';
+    const direction = getDirectionFromCodeBlock(elem);
     if (direction) {
         wrapper.setAttribute('dir', direction);
     }
index 1c68c2048d2b695544e336c7291cb2a46350f12c..091c3483f4d6bd1ecffabb7f52f3f0b17933abfa 100644 (file)
@@ -129,7 +129,7 @@ export class CodeEditor extends Component {
         this.hide();
     }
 
-    async open(code, language, saveCallback, cancelCallback) {
+    async open(code, language, direction, saveCallback, cancelCallback) {
         this.languageInput.value = language;
         this.saveCallback = saveCallback;
         this.cancelCallback = cancelCallback;
@@ -137,6 +137,7 @@ export class CodeEditor extends Component {
         await this.show();
         this.languageInputChange(language);
         this.editor.setContent(code);
+        this.setDirection(direction);
     }
 
     async show() {
@@ -156,6 +157,15 @@ export class CodeEditor extends Component {
         });
     }
 
+    setDirection(direction) {
+        const target = this.editorInput.parentElement;
+        if (direction) {
+            target.setAttribute('dir', direction);
+        } else {
+            target.removeAttribute('dir');
+        }
+    }
+
     hide() {
         this.getPopup().hide();
         this.addHistory();
index f86760214e1ed93d124b6a9f777463f1bb1525e5..c01a7eca0298c857b34ee2519a4e745e62e08ea5 100644 (file)
@@ -6,13 +6,14 @@ 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) {
+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, (newCode, newLang) => {
+    codeEditor.open(code, language, direction, (newCode, newLang) => {
         callback(newCode, newLang);
         editor.focus();
         editor.selection.moveToBookmark(bookMark);
@@ -27,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);
     });
 }
@@ -179,13 +181,17 @@ function register(editor) {
             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);
             });
         }
@@ -205,7 +211,8 @@ function register(editor) {
                     contenteditable: 'false',
                 });
 
-                const direction = el.attr('dir');
+                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);
                 }
index ae899357c98f115ba27331e7ac2788870436d9e8..fc4ddeba4ae56d4805f7df3a70c6afd7aad38298 100644 (file)
   flex: 0;
   .popup-title {
     color: #FFF;
-    margin-right: auto;
+    margin-inline-end: auto;
     padding: 8px $-m;
   }
   &.flex-container-row {
Morty Proxy This is a proxified and sanitized view of the page, visit original site.