[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:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user