From 951ea9ea3d79637d0d8dd5b731fe934dd21a6859 Mon Sep 17 00:00:00 2001 From: Antoine Guenet Date: Thu, 15 Feb 2024 14:39:54 +0000 Subject: [PATCH] [FIX] web_editor: prevent traceback on arrow keypress at editor edge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Steps to reproduce: 1. Type a backtick 2. Type "A" 3. Type a backtick 4. Hit Left Arrow key 5. Hit Right Arrow key 2x This led to a traceback ("Cannot read properties of null (reading 'isContentEditable') at OdooEditor._onKeyDown") because using `nextLeaf` without specifying the editable bounds returned a node that was not within these bounds, and a subsequent call to `closestElement` on this node returned `null` as a result. task-3749506 closes odoo/odoo#154484 X-original-commit: ec1fe7b05e0d91605f78dd1844c7d2222671eab3 Signed-off-by: Geelen Sébastien (sge) Signed-off-by: Antoine Guenet (age) --- .../js/editor/odoo-editor/src/OdooEditor.js | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) 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 b0566eb399f..87b368ced4f 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 @@ -4070,20 +4070,22 @@ export class OdooEditor extends EventTarget { // Find previous character. let previousCharacter = focusOffset > 0 && focusNode.textContent[focusOffset - 1]; if (!previousCharacter) { - focusNode = previousLeaf(focusNode); - focusOffset = nodeSize(focusNode); - previousCharacter = focusNode.textContent[focusOffset - 1]; + focusNode = previousLeaf(focusNode, this.editable); + focusOffset = focusNode && nodeSize(focusNode); + previousCharacter = focusNode && focusNode.textContent[focusOffset - 1]; } // Move selection if previous character is zero-width space - if (previousCharacter === '\u200B' && !focusNode.parentElement.hasAttribute('data-o-link-zws')) { + if (focusNode && previousCharacter === '\u200B' && !focusNode.parentElement.hasAttribute('data-o-link-zws')) { focusOffset -= 1; while (focusNode && (focusOffset < 0 || !focusNode.textContent[focusOffset])) { - focusNode = nextLeaf(focusNode); + focusNode = nextLeaf(focusNode, this.editable); focusOffset = focusNode && nodeSize(focusNode); } - const startContainer = ev.shiftKey ? anchorNode : focusNode; - const startOffset = ev.shiftKey ? anchorOffset : focusOffset; - setSelection(startContainer, startOffset, focusNode, focusOffset); + if (focusNode) { + const startContainer = ev.shiftKey ? anchorNode : focusNode; + const startOffset = ev.shiftKey ? anchorOffset : focusOffset; + setSelection(startContainer, startOffset, focusNode, focusOffset); + } } } } else if (IS_KEYBOARD_EVENT_RIGHT_ARROW(ev)) { @@ -4111,25 +4113,27 @@ export class OdooEditor extends EventTarget { // Find next character. let nextCharacter = focusNode.textContent[focusOffset]; if (!nextCharacter) { - focusNode = nextLeaf(focusNode); + focusNode = nextLeaf(focusNode, this.editable); focusOffset = 0; - nextCharacter = focusNode.textContent[focusOffset]; + nextCharacter = focusNode && focusNode.textContent[focusOffset]; } // Move selection if next character is zero-width space if (nextCharacter === '\u200B' && !focusNode.parentElement.hasAttribute('data-o-link-zws')) { focusOffset += 1; let newFocusNode = focusNode; while (newFocusNode && (!newFocusNode.textContent[focusOffset] || !closestElement(newFocusNode).isContentEditable)) { - newFocusNode = nextLeaf(newFocusNode); + newFocusNode = nextLeaf(newFocusNode, this.editable); focusOffset = 0; } - if (!focusOffset && closestBlock(focusNode) !== closestBlock(newFocusNode)) { + if (newFocusNode && !focusOffset && closestBlock(focusNode) !== closestBlock(newFocusNode)) { newFocusNode = focusNode; // Do not move selection to next block. - focusOffset = nodeSize(focusNode); + focusOffset = focusNode && nodeSize(focusNode); + } + if (newFocusNode) { + const startContainer = ev.shiftKey ? anchorNode : newFocusNode; + const startOffset = ev.shiftKey ? anchorOffset : focusOffset; + setSelection(startContainer, startOffset, newFocusNode, focusOffset); } - const startContainer = ev.shiftKey ? anchorNode : newFocusNode; - const startOffset = ev.shiftKey ? anchorOffset : focusOffset; - setSelection(startContainer, startOffset, newFocusNode, focusOffset); } } }