From b0108010d077bad21d2968a72637805ea5b424dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20De=20Caluw=C3=A9?= Date: Wed, 30 Mar 2022 09:13:40 +0000 Subject: [PATCH] [FIX] web_editor: make buttons properly translatable A mechanism is provided by the OdooEditor to circumvent certain problems while editing links. More specifically, editable zones are patched when editing a link. This avoids the cursor ending up outside the link whenever the link tag is emptied. However, the mechanism does not check if the link is also in the editable zone before doing so. In translation mode, the editable zones correspond to the individual translation strings. When translating link texts, this means the anchor tag containing the translation string is outside the editable zone. The patching mechanism still applies, resulting in the anchor tag becoming editable as well. This causes problems while translating links, for example oDeleteBackward commands are being rolled back. Checking if the anchor tag is inside the editable zone resolves the problem. opw-2780312 closes odoo/odoo#88674 X-original-commit: 99050b26446bbbe949e1fa797210c2a8a68d94cd Signed-off-by: David Monjoie (dmo) --- .../static/lib/odoo-editor/src/OdooEditor.js | 9 +++---- .../lib/odoo-editor/test/spec/link.test.js | 27 +++++++++++++++++++ .../static/lib/odoo-editor/test/utils.js | 4 +-- 3 files changed, 33 insertions(+), 7 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 c85d4e0aebe..103a49ee9ce 100644 --- a/addons/web_editor/static/lib/odoo-editor/src/OdooEditor.js +++ b/addons/web_editor/static/lib/odoo-editor/src/OdooEditor.js @@ -1606,7 +1606,7 @@ export class OdooEditor extends EventTarget { this.observerUnactive('_activateContenteditable'); this.editable.setAttribute('contenteditable', this.options.isRootEditable); - for (const node of this.options.getContentEditableAreas()) { + for (const node of this.options.getContentEditableAreas(this)) { if (!node.isContentEditable) { node.setAttribute('contenteditable', true); } @@ -1618,7 +1618,7 @@ export class OdooEditor extends EventTarget { if (this.options.isRootEditable) { this.editable.setAttribute('contenteditable', !this.options.isRootEditable); } - for (const node of this.options.getContentEditableAreas()) { + for (const node of this.options.getContentEditableAreas(this)) { if (node.getAttribute('contenteditable') === 'true') { node.setAttribute('contenteditable', false); } @@ -2771,10 +2771,9 @@ export class OdooEditor extends EventTarget { const link = closestElement(ev.target, 'a'); this.resetContenteditableLink(); if ( - link && + link && link.isContentEditable && !link.querySelector('div') && - !closestElement(ev.target, '.o_not_editable') && - link.getAttribute('contenteditable') !== 'false' + !closestElement(ev.target, '.o_not_editable') ) { this.setContenteditableLink(link); } else { diff --git a/addons/web_editor/static/lib/odoo-editor/test/spec/link.test.js b/addons/web_editor/static/lib/odoo-editor/test/spec/link.test.js index ca7b8958a31..88d0f8fdd49 100644 --- a/addons/web_editor/static/lib/odoo-editor/test/spec/link.test.js +++ b/addons/web_editor/static/lib/odoo-editor/test/spec/link.test.js @@ -1,5 +1,6 @@ import { BasicEditor, + click, insertText, insertParagraphBreak, insertLineBreak, @@ -320,6 +321,32 @@ describe('Link', () => { contentAfter: '

ab

c[]d

', }); }); + it('should restrict editing to link when clicked', async () => { + const initialContent = '

ab

'; + const editFunction = editableLink => async editor => { + const a = editor.editable.querySelector('a'); + await click(a, { clientX: a.getBoundingClientRect().left + 5 }); + window.chai.expect(a.isContentEditable).to.be.equal(editableLink); + }; + await testEditor(BasicEditor, { + contentBefore: initialContent, + stepFunction: editFunction(true), + contentAfter: '

ab

', + }); + // The following is a regression test, checking that the link + // remains non-editable whenever the editable zone is contained by + // the link. + await testEditor(BasicEditor, { + contentBefore: initialContent, + stepFunction: editFunction(false), + contentAfter: '

ab

', + }, { + isRootEditable: false, + getContentEditableAreas: function (editor) { + return editor.editable.querySelectorAll('a span'); + } + }); + }); // it('should select and replace all text and add the next char in bold', async () => { // await testEditor(BasicEditor, { // contentBefore: '

[]123

abc

', 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 f6119488c36..16006651136 100644 --- a/addons/web_editor/static/lib/odoo-editor/test/utils.js +++ b/addons/web_editor/static/lib/odoo-editor/test/utils.js @@ -267,7 +267,7 @@ export function customErrorMessage(assertLocation, value, expected) { return `[${assertLocation}]\nactual : '${value}'\nexpected: '${expected}'\n\nStackTrace `; } -export async function testEditor(Editor = OdooEditor, spec) { +export async function testEditor(Editor = OdooEditor, spec, options = {}) { const testNode = document.createElement('div'); document.querySelector('#editor-test-container').innerHTML = ''; document.querySelector('#editor-test-container').appendChild(testNode); @@ -278,7 +278,7 @@ export async function testEditor(Editor = OdooEditor, spec) { testNode.innerHTML = spec.contentBefore; const selection = parseTextualSelection(testNode); - const editor = new Editor(testNode, { toSanitize: false }); + const editor = new Editor(testNode, Object.assign({ toSanitize: false }, options)); editor.keyboardType = 'PHYSICAL'; editor.testMode = true; if (selection) {