mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-07-28 17:02:04 +03:00
Revamped workings of WYSIWYG code blocks
Code blocks in tinymce could sometimes end up exploded into the sub elements of the codemirror display. This changes the strategy to render codemirror within the shadow dom of a custom element while preserving the normal pre/code DOM structure. Still a little instability when moving/adding code blocks within details blocks but much harder to break things now.
This commit is contained in:
@ -29,12 +29,15 @@ function register(editor, url) {
|
||||
icon: 'togglelabel',
|
||||
tooltip: 'Edit label',
|
||||
onAction() {
|
||||
const details = getSelectedDetailsBlock(editor);
|
||||
const dialog = editor.windowManager.open(detailsDialog(editor));
|
||||
dialog.setData({summary: getSummaryTextFromDetails(details)});
|
||||
showDetailLabelEditWindow(editor);
|
||||
}
|
||||
});
|
||||
|
||||
editor.on('dblclick', event => {
|
||||
if (!getSelectedDetailsBlock(editor) || event.target.closest('doc-root')) return;
|
||||
showDetailLabelEditWindow(editor);
|
||||
});
|
||||
|
||||
editor.ui.registry.addButton('toggledetails', {
|
||||
icon: 'togglefold',
|
||||
tooltip: 'Toggle open/closed',
|
||||
@ -46,13 +49,29 @@ function register(editor, url) {
|
||||
});
|
||||
|
||||
editor.addCommand('InsertDetailsBlock', function () {
|
||||
const content = editor.selection.getContent({format: 'html'});
|
||||
let content = editor.selection.getContent({format: 'html'});
|
||||
const details = document.createElement('details');
|
||||
const summary = document.createElement('summary');
|
||||
const id = 'details-' + Date.now();
|
||||
details.setAttribute('data-id', id)
|
||||
details.appendChild(summary);
|
||||
details.innerHTML += content;
|
||||
|
||||
if (!content) {
|
||||
content = '<p><br></p>';
|
||||
}
|
||||
|
||||
details.innerHTML += content;
|
||||
editor.insertContent(details.outerHTML);
|
||||
editor.focus();
|
||||
|
||||
const domDetails = editor.dom.$(`[data-id="${id}"]`);
|
||||
if (domDetails) {
|
||||
const firstChild = domDetails.find('doc-root > *');
|
||||
if (firstChild) {
|
||||
firstChild[0].focus();
|
||||
}
|
||||
domDetails.removeAttr('data-id');
|
||||
}
|
||||
});
|
||||
|
||||
editor.ui.registry.addContextToolbar('details', {
|
||||
@ -69,6 +88,15 @@ function register(editor, url) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Editor} editor
|
||||
*/
|
||||
function showDetailLabelEditWindow(editor) {
|
||||
const details = getSelectedDetailsBlock(editor);
|
||||
const dialog = editor.windowManager.open(detailsDialog(editor));
|
||||
dialog.setData({summary: getSummaryTextFromDetails(details)});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Editor} editor
|
||||
*/
|
||||
@ -99,7 +127,7 @@ function detailsDialog(editor) {
|
||||
{
|
||||
type: 'input',
|
||||
name: 'summary',
|
||||
label: 'Toggle label text',
|
||||
label: 'Toggle label',
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -141,14 +169,13 @@ function setSummary(editor, summaryContent) {
|
||||
*/
|
||||
function unwrapDetailsInSelection(editor) {
|
||||
const details = editor.selection.getNode().closest('details');
|
||||
|
||||
if (details) {
|
||||
const summary = details.querySelector('summary');
|
||||
const elements = details.querySelectorAll('details > *:not(summary, doc-root), doc-root > *');
|
||||
|
||||
editor.undoManager.transact(() => {
|
||||
if (summary) {
|
||||
summary.remove();
|
||||
}
|
||||
while (details.firstChild) {
|
||||
details.parentNode.insertBefore(details.firstChild, details);
|
||||
for (const element of elements) {
|
||||
details.parentNode.insertBefore(element, details);
|
||||
}
|
||||
details.remove();
|
||||
});
|
||||
@ -172,6 +199,12 @@ function setupElementFilters(editor) {
|
||||
el.attr('open', null);
|
||||
}
|
||||
});
|
||||
|
||||
editor.serializer.addNodeFilter('doc-root', function(elms) {
|
||||
for (const el of elms) {
|
||||
el.unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user