diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js b/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js index ca88dc6303a..ba6937af5dd 100644 --- a/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js +++ b/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js @@ -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; diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/utils.js b/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/utils.js index be1dacca72f..64af7c5f6e0 100644 --- a/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/utils.js +++ b/addons/web_editor/static/src/js/editor/odoo-editor/src/utils/utils.js @@ -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 { diff --git a/addons/web_editor/static/tests/banner_tests.js b/addons/web_editor/static/tests/banner_tests.js index 174eb7bc527..d1e1bb21c8c 100644 --- a/addons/web_editor/static/tests/banner_tests.js +++ b/addons/web_editor/static/tests/banner_tests.js @@ -100,5 +100,32 @@ QUnit.module(


`, ); }); + + 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, + `

Test

+ +
+



`, + ); + }); + } );