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 62dc4064aef..c87c6c51086 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 @@ -763,17 +763,18 @@ export function getDeepRange(editable, { range, sel, splitText, select, correctT } } } - // A selection spanning multiple nodes and ending at position 0 of a - // node, like the one resulting from a triple click, are corrected so - // that it ends at the last position of the previous node instead. - const beforeEnd = end.previousSibling; + // A selection spanning multiple nodes and ending at position 0 of a node, + // like the one resulting from a triple click, is corrected so that it ends + // at the last position of the previous node instead. + const endLeaf = firstLeaf(end); + const beforeEnd = endLeaf.previousSibling; if ( correctTripleClick && !endOffset && (start !== end || startOffset !== endOffset) && (!beforeEnd || (beforeEnd.nodeType === Node.TEXT_NODE && !isVisibleStr(beforeEnd))) ) { - const previous = previousLeaf(end, editable, true); + const previous = previousLeaf(endLeaf, editable, true); if (previous && closestElement(previous).isContentEditable) { [end, endOffset] = [previous, nodeSize(previous)]; } diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/editor.test.js b/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/editor.test.js index 1db4573a8b1..427abd453e8 100644 --- a/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/editor.test.js +++ b/addons/web_editor/static/src/js/editor/odoo-editor/test/spec/editor.test.js @@ -1190,6 +1190,11 @@ X[] // JW cAfter: '
[]def
', contentAfter: 'def
', }); + await testEditor(BasicEditor, { + contentBefore: ']
def
', + stepFunction: deleteForward, + contentAfter: 'def
', + }); }); it('should delete last character of paragraph, ignoring the selected paragraph break', async () => { await testEditor(BasicEditor, { @@ -2668,6 +2673,11 @@ X[] // JW cAfter: '[]def
', contentAfter: 'def
', }); + await testEditor(BasicEditor, { + contentBefore: ']
def
', + stepFunction: deleteBackward, + contentAfter: 'def
', + }); }); it('should delete last character of paragraph, ignoring the selected paragraph break', async () => { await testEditor(BasicEditor, { @@ -2678,6 +2688,14 @@ X[] stepFunction: deleteBackward, contentAfter: 'ab[]
def
', }); + await testEditor(BasicEditor, { + contentBefore: 'ab[c
]
def
', + // This type of selection (typically done with a triple + // click) is "corrected" before remove so triple clicking + // doesn't remove a paragraph break. + stepFunction: deleteBackward, + contentAfter: 'ab[]
def
', + }); }); it('should delete first character of paragraph, as well as selected paragraph break', async () => { await testEditor(BasicEditor, { @@ -2695,6 +2713,22 @@ X[] stepFunction: deleteBackward, contentAfter: 'ab[]
def
', }); + await testEditor(BasicEditor, { + contentBefore: 'ab[c
]
def
', + // This type of selection (typically done with a triple + // click) is "corrected" before remove so triple clicking + // doesn't remove a paragraph break. + stepFunction: deleteBackward, + contentAfter: 'ab[]
def
', + }); + await testEditor(BasicEditor, { + contentBefore: 'ab[c
]
def
', + // This type of selection (typically done with a triple + // click) is "corrected" before remove so triple clicking + // doesn't remove a paragraph break. + stepFunction: deleteBackward, + contentAfter: 'ab[]
def
', + }); }); it('should delete first character of unbreakable, ignoring selected paragraph break', async () => { await testEditor(BasicEditor, {