WYSIWYG: Added justify cell range cleanup

To help override & gain control of setting text alignment in tables.

- Adds support of clearing "align" attributes in certain operations.
- Updates cell range action handling to dedupe execcommand handling.
- Adds clearing of additional alignment classes on direction control.

Closes #5011
This commit is contained in:
Dan Brown 2024-05-16 14:54:44 +01:00
parent 38913288d8
commit 570af500f4
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
1 changed files with 64 additions and 27 deletions

View File

@ -55,6 +55,19 @@ export function handleEmbedAlignmentChanges(editor) {
}); });
} }
/**
* Cleans up and removes text-alignment specific properties on all child elements.
* @param {HTMLElement} element
*/
function cleanChildAlignment(element) {
const alignedChildren = element.querySelectorAll('[align],[style*="text-align"],.align-center,.align-left,.align-right');
for (const child of alignedChildren) {
child.removeAttribute('align');
child.style.textAlign = null;
child.classList.remove('align-center', 'align-right', 'align-left');
}
}
/** /**
* Cleans up the direction property for an element. * Cleans up the direction property for an element.
* Removes all inline direction control from child elements. * Removes all inline direction control from child elements.
@ -62,16 +75,23 @@ export function handleEmbedAlignmentChanges(editor) {
* @param {HTMLElement} element * @param {HTMLElement} element
*/ */
function cleanElementDirection(element) { function cleanElementDirection(element) {
const directionChildren = element.querySelectorAll('[dir],[style*="direction"],[style*="text-align"]'); const directionChildren = element.querySelectorAll('[dir],[style*="direction"]');
for (const child of directionChildren) { for (const child of directionChildren) {
child.removeAttribute('dir'); child.removeAttribute('dir');
child.style.direction = null; child.style.direction = null;
child.style.textAlign = null;
} }
cleanChildAlignment(element);
element.style.direction = null; element.style.direction = null;
element.style.textAlign = null; element.style.textAlign = null;
element.removeAttribute('align');
} }
/**
* @typedef {Function} TableCellHandler
* @param {HTMLTableCellElement} cell
*/
/** /**
* This tracks table cell range selection, so we can apply custom handling where * This tracks table cell range selection, so we can apply custom handling where
* required to actions applied to such selections. * required to actions applied to such selections.
@ -90,34 +110,51 @@ export function handleTableCellRangeEvents(editor) {
selectedCells = []; selectedCells = [];
}); });
// TinyMCE does not seem to do a great job on clearing styles in complex /**
// scenarios (like copied word content) when a range of table cells * @type {Object<String, TableCellHandler>}
// are selected. Here we watch for clear formatting events, so some manual */
// cleanup can be performed. const actionByCommand = {
const attrsToRemove = ['class', 'style', 'width', 'height']; // TinyMCE does not seem to do a great job on clearing styles in complex
editor.on('ExecCommand', event => { // scenarios (like copied word content) when a range of table cells
if (event.command === 'RemoveFormat') { // are selected. Here we watch for clear formatting events, so some manual
for (const cell of selectedCells) { // cleanup can be performed.
for (const attr of attrsToRemove) { RemoveFormat: cell => {
cell.removeAttribute(attr); const attrsToRemove = ['class', 'style', 'width', 'height', 'align'];
} for (const attr of attrsToRemove) {
cell.removeAttribute(attr);
} }
} },
});
// TinyMCE does not apply direction events to table cell range selections // TinyMCE does not apply direction events to table cell range selections
// so here we hastily patch in that ability by setting the direction ourselves // so here we hastily patch in that ability by setting the direction ourselves
// when a direction event is fired. // when a direction event is fired.
editor.on('ExecCommand', event => { mceDirectionLTR: cell => {
const command = event.command; cell.setAttribute('dir', 'ltr');
if (command !== 'mceDirectionLTR' && command !== 'mceDirectionRTL') {
return;
}
const dir = command === 'mceDirectionLTR' ? 'ltr' : 'rtl';
for (const cell of selectedCells) {
cell.setAttribute('dir', dir);
cleanElementDirection(cell); cleanElementDirection(cell);
},
mceDirectionRTL: cell => {
cell.setAttribute('dir', 'rtl');
cleanElementDirection(cell);
},
// The "align" attribute can exist on table elements so this clears
// the attribute, and also clears common child alignment properties,
// when a text direction action is made for a table cell range.
JustifyLeft: cell => {
cell.removeAttribute('align');
cleanChildAlignment(cell);
},
JustifyRight: this.JustifyLeft,
JustifyCenter: this.JustifyLeft,
JustifyFull: this.JustifyLeft,
};
editor.on('ExecCommand', event => {
const action = actionByCommand[event.command];
if (action) {
for (const cell of selectedCells) {
action(cell);
}
} }
}); });
} }