[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) <dmo@odoo.com>
This commit is contained in:
Tom De Caluwé
2022-04-13 16:54:04 +02:00
parent 74d81d029b
commit b0108010d0
3 changed files with 33 additions and 7 deletions
@@ -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 {
@@ -1,5 +1,6 @@
import {
BasicEditor,
click,
insertText,
insertParagraphBreak,
insertLineBreak,
@@ -320,6 +321,32 @@ describe('Link', () => {
contentAfter: '<p>a<a href="exist">b</a></p><p>c[]d</p>',
});
});
it('should restrict editing to link when clicked', async () => {
const initialContent = '<p>a<a href="#/"><span>b</span></a></p>';
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: '<p>a<a href="#/" contenteditable="true"><span>b</span></a></p>',
});
// 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: '<p>a<a href="#/"><span contenteditable="true">b</span></a></p>',
}, {
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: '<div><p>[]123</p><p><a href="#">abc</a></p></div>',
@@ -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) {