mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
WYSIWYG: Added text direction support for code editor popup
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
This commit is contained in:
parent
4c1c315594
commit
f9e087330b
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -182,7 +182,7 @@
|
||||
flex: 0;
|
||||
.popup-title {
|
||||
color: #FFF;
|
||||
margin-right: auto;
|
||||
margin-inline-end: auto;
|
||||
padding: 8px $-m;
|
||||
}
|
||||
&.flex-container-row {
|
||||
|
Loading…
Reference in New Issue
Block a user