[FIX] web_editor: should preserve first element inside banner.

Before this commit:

- Performing ctrl+a and backspace inside a banner would unintentionally remove
  its first element, which could be a block tag

After this commit:

- Now performing ctrl+a and backspace inside the banner will no longer remove its
  first element if it's a block tag.

task-3432167

X-original-commit: ddc8587f8a712fdddaa714bee2931cb149c03a38
Part-of: odoo/odoo#151735
This commit is contained in:
dhba
2024-02-05 08:34:50 +00:00
parent f50378db3c
commit e93fa23c29
3 changed files with 39 additions and 5 deletions
@@ -4204,13 +4204,20 @@ export class OdooEditor extends EventTarget {
// and the toolbar so we need to fix the selection to be based on the
// editable children. Calling `getDeepRange` ensure the selection is
// limited to the editable.
const containerSelector = '#wrap>*, .oe_structure>*, [contenteditable]';
const container =
(selection &&
closestElement(selection.anchorNode, containerSelector)) ||
// In case a suitable container could not be found then the
// selection is restricted inside the editable area.
this.editable;
if (
selection.anchorNode === this.editable &&
selection.focusNode === this.editable &&
selection.anchorNode === container &&
selection.focusNode === container &&
selection.anchorOffset === 0 &&
selection.focusOffset === [...this.editable.childNodes].length
selection.focusOffset === [...container.childNodes].length
) {
getDeepRange(this.editable, {select: true});
getDeepRange(container, {select: true});
// The selection is changed in `getDeepRange` and will therefore
// re-trigger the _onSelectionChange.
return;
@@ -866,7 +866,7 @@ export function getDeepestPosition(node, offset) {
// First switch direction to left if offset is at the end.
direction = offset < node.childNodes.length;
next = node.childNodes[direction ? offset : offset - 1];
} else if (direction && next.nextSibling && !isBlock(next.nextSibling)) {
} else if (direction && next.nextSibling) {
// Invalid node: skip to next sibling (without crossing blocks).
next = next.nextSibling;
} else {
@@ -100,5 +100,32 @@ QUnit.module(
</div><p><br></p>`,
);
});
QUnit.module("banner selection and backspace");
QUnit.test("preserves the first paragraph tag inside the banner", async function (assert) {
const { editor, editable } = onMount();
const node = editable.querySelector("p");
setSelection(node, 0);
insertText(editor, "Test");
setSelection(node.firstChild, 3, node.firstChild, 3);
insertText(editor, '/banner');
triggerEvent(editor.editable, "keydown", { key: "Enter" });
await nextTick();
insertText(editor, 'Test1');
triggerEvent(editor.editable, "input", { inputType: "insertParagraph" });
insertText(editor, 'Test2');
triggerEvent(editor.editable, "input", { inputType: "insertParagraph" });
triggerEvent(editor.editable, "keydown", { key: "a", ctrlKey: true });
await nextTick();
triggerEvent(editor.editable, "input", { inputType: "deleteContentBackward" });
assert.strictEqual(
editable.innerHTML,
`<p>Test</p><div class="o_editor_banner o_not_editable lh-1 d-flex align-items-center alert alert-info pb-0 pt-3" role="status" data-oe-protected="true" contenteditable="false">
<i class="fs-4 fa fa-info-circle mb-3" aria-label="Banner Info"></i>
<div class="w-100 ms-3" data-oe-protected="false" contenteditable="true">
<p placeholder=\"Type &quot;/&quot; for commands\" class=\"oe-hint oe-command-temporary-hint\"><br></p></div></div><p><br></p>`,
);
});
}
);