From c53ebf824451b880de3189b18edf6bfb31417fc2 Mon Sep 17 00:00:00 2001 From: Antoine Guenet Date: Fri, 17 Dec 2021 15:15:06 +0000 Subject: [PATCH] [FIX] web_editor: prevent line breaks at edges of anchor on press enter When pressing enter at the edge of an anchor that is a child of an unbreakable element, we inserted line breaks in the anchor itself, which is unexpected. This inserts the anchors after/before it instead. closes odoo/odoo#81662 X-original-commit: df6f8dd0c54c40ea7edbd3821ae068d79b1b7af7 Signed-off-by: David Monjoie (dmo) --- .../static/lib/odoo-editor/src/OdooEditor.js | 17 ++++++++++++- .../odoo-editor/src/commands/shiftEnter.js | 4 ++- .../lib/odoo-editor/test/spec/collab.test.js | 2 +- .../lib/odoo-editor/test/spec/editor.test.js | 25 +++++++++++++++++++ .../static/lib/odoo-editor/test/utils.js | 3 ++- 5 files changed, 47 insertions(+), 4 deletions(-) diff --git a/addons/web_editor/static/lib/odoo-editor/src/OdooEditor.js b/addons/web_editor/static/lib/odoo-editor/src/OdooEditor.js index 668b3a086f3..45c59b3faad 100644 --- a/addons/web_editor/static/lib/odoo-editor/src/OdooEditor.js +++ b/addons/web_editor/static/lib/odoo-editor/src/OdooEditor.js @@ -46,6 +46,7 @@ import { YOUTUBE_URL_GET_VIDEO_ID, unwrapContents, peek, + rightPos, } from './utils/utils.js'; import { editorCommands } from './commands/commands.js'; import { Powerbox } from './powerbox/Powerbox.js'; @@ -2138,7 +2139,21 @@ export class OdooEditor extends EventTarget { this.historyRollback(); ev.preventDefault(); if (this._applyCommand('oEnter') === UNBREAKABLE_ROLLBACK_CODE) { - this._applyCommand('oShiftEnter'); + const brs = this._applyCommand('oShiftEnter'); + const anchor = brs[0].parentElement; + if (anchor.nodeName === 'A') { + if (brs.includes(anchor.firstChild)) { + brs.forEach(br => anchor.before(br)); + setSelection(...rightPos(brs[brs.length - 1])); + this.sanitize(); + this.historyStep(); + } else if (brs.includes(anchor.lastChild)) { + brs.forEach(br => anchor.after(br)); + setSelection(...rightPos(brs[0])); + this.sanitize(); + this.historyStep(); + } + } } } else if (['insertText', 'insertCompositionText'].includes(ev.inputType)) { // insertCompositionText, courtesy of Samsung keyboard. diff --git a/addons/web_editor/static/lib/odoo-editor/src/commands/shiftEnter.js b/addons/web_editor/static/lib/odoo-editor/src/commands/shiftEnter.js index 3b106e124f2..20c56ee8ec3 100644 --- a/addons/web_editor/static/lib/odoo-editor/src/commands/shiftEnter.js +++ b/addons/web_editor/static/lib/odoo-editor/src/commands/shiftEnter.js @@ -12,7 +12,7 @@ import { } from '../utils/utils.js'; Text.prototype.oShiftEnter = function (offset) { - this.parentElement.oShiftEnter(splitTextNode(this, offset)); + return this.parentElement.oShiftEnter(splitTextNode(this, offset)); }; HTMLElement.prototype.oShiftEnter = function (offset) { @@ -39,4 +39,6 @@ HTMLElement.prototype.oShiftEnter = function (offset) { break; } } + + return brEls; }; diff --git a/addons/web_editor/static/lib/odoo-editor/test/spec/collab.test.js b/addons/web_editor/static/lib/odoo-editor/test/spec/collab.test.js index 7eed71df836..9dcd7b73e7a 100644 --- a/addons/web_editor/static/lib/odoo-editor/test/spec/collab.test.js +++ b/addons/web_editor/static/lib/odoo-editor/test/spec/collab.test.js @@ -139,7 +139,7 @@ const testMultiEditor = spec => { clientInfo.editor.onExternalHistorySteps(missingSteps.concat([step])); }, }); - clientInfo.editor.keyboardType = 'PHYSICAL_KEYBOARD'; + clientInfo.editor.keyboardType = 'PHYSICAL'; const selection = selections[clientInfo.clientId]; if (selection) { setTestSelection(selection, iframeDocument); diff --git a/addons/web_editor/static/lib/odoo-editor/test/spec/editor.test.js b/addons/web_editor/static/lib/odoo-editor/test/spec/editor.test.js index 66ac039f857..ab79496d972 100644 --- a/addons/web_editor/static/lib/odoo-editor/test/spec/editor.test.js +++ b/addons/web_editor/static/lib/odoo-editor/test/spec/editor.test.js @@ -2248,6 +2248,31 @@ X[] contentAfter: '

abc

[]

', }); }); + it.only('should insert line breaks outside the edges of an anchor', async () => { + const pressEnter = editor => { + editor.document.execCommand('insertParagraph'); + } + await testEditor(BasicEditor, { + contentBefore: '
ab[]cd
', + stepFunction: pressEnter, + contentAfter: '
ab
[]cd
', + }); + await testEditor(BasicEditor, { + contentBefore: '
a[]b
', + stepFunction: pressEnter, + contentAfter: '
a
[]b
', + }); + await testEditor(BasicEditor, { + contentBefore: '
ab[]
', + stepFunction: pressEnter, + contentAfter: '
ab
[]
', + }); + await testEditor(BasicEditor, { + contentBefore: '
ab[]cd
', + stepFunction: pressEnter, + contentAfter: '
ab
[]cd
', + }); + }); }); describe('With attributes', () => { it('should insert an empty paragraph before a paragraph with a span with a class', async () => { diff --git a/addons/web_editor/static/lib/odoo-editor/test/utils.js b/addons/web_editor/static/lib/odoo-editor/test/utils.js index 53eb7f6b495..9b3150518b3 100644 --- a/addons/web_editor/static/lib/odoo-editor/test/utils.js +++ b/addons/web_editor/static/lib/odoo-editor/test/utils.js @@ -296,9 +296,10 @@ export async function testEditor(Editor = OdooEditor, spec) { const selection = parseTextualSelection(testNode); const editor = new Editor(testNode, { toSanitize: false }); - editor.keyboardType = 'PHYSICAL_KEYBOARD'; + editor.keyboardType = 'PHYSICAL'; if (selection) { setTestSelection(selection); + editor._recordHistorySelection(); } else { document.getSelection().removeAllRanges(); }