[FIX] web_editor: refine table selection exclusion for protected elements
Prevent custom editor selection of protected tables. The previous iteration (394e4fe) did not take into account non-collapsed selections. This iteration does not handle `data-oe-protected="true"` on `table` elements below the `<table>` tag (i.e. `<tbody>, <tr>, <td>`...), because there is no need for that currently and it would add further complexity to the code. task-3280704 X-original-commit: 885d52c9b814d908438e8e424d17c4e4b6e9e731 Part-of: odoo/odoo#125204
This commit is contained in:
@@ -2354,12 +2354,12 @@ export class OdooEditor extends EventTarget {
|
||||
const selection = this.document.getSelection();
|
||||
// Selection could be gone if the document comes from an iframe that has been removed.
|
||||
const anchorNode = selection && selection.rangeCount && selection.getRangeAt(0) && selection.anchorNode;
|
||||
if (isProtected(anchorNode) || !ancestors(anchorNode).includes(this.editable)) {
|
||||
if (anchorNode && !ancestors(anchorNode).includes(this.editable)) {
|
||||
return false;
|
||||
}
|
||||
this.deselectTable();
|
||||
const traversedNodes = getTraversedNodes(this.editable);
|
||||
if (this._isResizingTable || !traversedNodes.some(node => !!closestElement(node, 'td'))) {
|
||||
if (this._isResizingTable || !traversedNodes.some(node => !!closestElement(node, 'td') && !isProtected(node))) {
|
||||
return false;
|
||||
}
|
||||
let range;
|
||||
@@ -2385,15 +2385,21 @@ export class OdooEditor extends EventTarget {
|
||||
const startTable = ancestors(range.startContainer, this.editable).filter(node => node.nodeName === 'TABLE').pop();
|
||||
const endTable = ancestors(range.endContainer, this.editable).filter(node => node.nodeName === 'TABLE').pop();
|
||||
if (startTd !== endTd && startTable === endTable) {
|
||||
// The selection goes through at least two different cells -> select
|
||||
// cells.
|
||||
this._selectTableCells(range);
|
||||
appliedCustomSelection = true;
|
||||
if (!isProtected(startTable)) {
|
||||
// The selection goes through at least two different cells ->
|
||||
// select cells.
|
||||
this._selectTableCells(range);
|
||||
appliedCustomSelection = true;
|
||||
}
|
||||
} else if (!traversedNodes.every(node => node.parentElement && closestElement(node.parentElement, 'table'))) {
|
||||
// The selection goes through a table but also outside of it ->
|
||||
// select the whole table.
|
||||
this.observerUnactive('handleSelectionInTable');
|
||||
const traversedTables = new Set(traversedNodes.map(node => closestElement(node, 'table')));
|
||||
const traversedTables = new Set(
|
||||
traversedNodes
|
||||
.map((node) => closestElement(node, "table"))
|
||||
.filter((node) => !isProtected(node))
|
||||
);
|
||||
for (const table of traversedTables) {
|
||||
// Don't apply several nested levels of selection.
|
||||
if (table && !ancestors(table, this.editable).some(node => [...traversedTables].includes(node))) {
|
||||
@@ -2405,10 +2411,10 @@ export class OdooEditor extends EventTarget {
|
||||
}
|
||||
}
|
||||
this.observerActive('handleSelectionInTable');
|
||||
} else if (ev) {
|
||||
} else if (ev && startTd && !isProtected(startTd)) {
|
||||
// We're redirected from a mousemove event.
|
||||
const selectedNodes = getSelectedNodes(this.editable);
|
||||
const areCellContentsFullySelected = !!startTd && descendants(startTd).filter(d => !isBlock(d)).every(child => selectedNodes.includes(child));
|
||||
const areCellContentsFullySelected = descendants(startTd).filter(d => !isBlock(d)).every(child => selectedNodes.includes(child));
|
||||
if (areCellContentsFullySelected) {
|
||||
const SENSITIVITY = 5;
|
||||
const rangeRect = range.getBoundingClientRect();
|
||||
@@ -3693,9 +3699,6 @@ export class OdooEditor extends EventTarget {
|
||||
return;
|
||||
}
|
||||
const anchorNode = selection.anchorNode;
|
||||
if (isProtected(anchorNode)) {
|
||||
return;
|
||||
}
|
||||
// Correct cursor if at editable root.
|
||||
if (
|
||||
selection.isCollapsed &&
|
||||
|
||||
@@ -5995,6 +5995,28 @@ X[]
|
||||
`),
|
||||
});
|
||||
});
|
||||
it('should not select a protected table', async () => {
|
||||
// Individually protected cells are not yet supported for simplicity
|
||||
// since there is no need for that currently.
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: unformat(`
|
||||
<table data-oe-protected="true"><tbody><tr>
|
||||
<td>[ab</td>
|
||||
</tr></tbody></table>
|
||||
<table><tbody><tr>
|
||||
<td>cd]</td>
|
||||
</tr></tbody></table>
|
||||
`),
|
||||
contentAfterEdit: unformat(`
|
||||
<table data-oe-protected="true"><tbody><tr>
|
||||
<td>[ab</td>
|
||||
</tr></tbody></table>
|
||||
<table class="o_selected_table"><tbody><tr>
|
||||
<td class="o_selected_td">cd]</td>
|
||||
</tr></tbody></table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('false', () => {
|
||||
it('should not ignore unprotected elements children mutations', async () => {
|
||||
@@ -6110,7 +6132,7 @@ X[]
|
||||
},
|
||||
contentAfter: '<div><p>a</p></div><div data-oe-transient-content="true"></div>',
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
describe('selection', () => {
|
||||
describe('after an arrow key press', () => {
|
||||
|
||||
Reference in New Issue
Block a user