BookStack/resources/js/wysiwyg/fixes.js
Dan Brown 5395ca2f00
WYSWIYG: Allowed video/embed alignment controls
Required a lot of working around TinyMCE since it added a
preview/wrapper element in the editor which complicates things.
Added view new "fixes.js" file so large hacks to default TinyMCe
functionality are kept in one place.
2023-12-16 12:22:40 +00:00

56 lines
2.3 KiB
JavaScript

/**
* Handle alignment for embed (iframe/video) content.
* TinyMCE built-in handling doesn't work well for these when classes are used for
* alignment, since the editor wraps these elements in a non-editable preview span
* which looses tracking and setting of alignment options.
* Here we manually manage these properties and formatting events, by effectively
* syncing the alignment classes to the parent preview span.
* @param {Editor} editor
*/
export function handleEmbedAlignmentChanges(editor) {
function updateClassesForPreview(previewElem) {
const mediaTarget = previewElem.querySelector('iframe, video');
if (!mediaTarget) {
return;
}
const alignmentClasses = [...mediaTarget.classList.values()].filter(c => c.startsWith('align-'));
const previewAlignClasses = [...previewElem.classList.values()].filter(c => c.startsWith('align-'));
previewElem.classList.remove(...previewAlignClasses);
previewElem.classList.add(...alignmentClasses);
}
editor.on('SetContent', () => {
const previewElems = editor.dom.select('span.mce-preview-object');
for (const previewElem of previewElems) {
updateClassesForPreview(previewElem);
}
});
editor.on('FormatApply', event => {
const isAlignment = event.format.startsWith('align');
if (!event.node || !event.node.matches('.mce-preview-object')) {
return;
}
const realTarget = event.node.querySelector('iframe, video');
if (isAlignment && realTarget) {
const className = (editor.formatter.get(event.format)[0]?.classes || [])[0];
const toAdd = !realTarget.classList.contains(className);
const wrapperClasses = (event.node.getAttribute('data-mce-p-class') || '').split(' ');
const wrapperClassesFiltered = wrapperClasses.filter(c => !c.startsWith('align-'));
if (toAdd) {
wrapperClassesFiltered.push(className);
}
const classesToApply = wrapperClassesFiltered.join(' ');
event.node.setAttribute('data-mce-p-class', classesToApply);
realTarget.setAttribute('class', classesToApply);
editor.formatter.apply(event.format, {}, realTarget);
updateClassesForPreview(event.node);
}
});
}