[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:
abd-msyukyu-odoo
2023-06-16 09:34:54 +02:00
parent c2683a7263
commit 1ef69821e6
2 changed files with 38 additions and 13 deletions
@@ -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', () => {