[FIX] web_editor: fix issues caused by textContent
Issue #1: reading textContent When reading the textContent property of an element, its does not take into account line breaks introduced by <br> and block elements, whilst innerHtml does. This commit solves the issue of updating a link's href to a non-sense url upon label change. Before this commit, "www.abc.com <br> www.xyz.com" was being incorrectely parsed as "www.abc.comwww.xyz.com". Issue #2: setting textContent When setting the textContent property of an element, all of its child nodes are removed and replaced by a single text node. While this is fine when the element contains a single text node, it might not be the desired result when the element contains other children. This commit solves the issue obtained when pasting html such as "link.com<br>link.be" inside an empty inline element such as STRONG or A, in which cleanForSave was changing its content (removing the line-break) due to misuse of textContent, when the intended effected was simply removing ZeroWidthSpace characters. A safer alternative for removing ZeroWidthSpace is thus provided. task-3081254 closes odoo/odoo#112579 X-original-commit: 9ff7c2ccff5f959f2a1cd7334c42b7bf0134f5d2 Signed-off-by: David Monjoie (dmo) <dmo@odoo.com>
This commit is contained in:
committed by
Rodolpho
parent
0639a99a9a
commit
f60e8faaca
@@ -13,7 +13,6 @@ import './commands/align.js';
|
||||
import { sanitize } from './utils/sanitize.js';
|
||||
import { serializeNode, unserializeNode, serializeSelection } from './utils/serialize.js';
|
||||
import {
|
||||
isMacOS,
|
||||
closestBlock,
|
||||
commonParentGet,
|
||||
containsUnremovable,
|
||||
@@ -70,7 +69,10 @@ import {
|
||||
parseHTML,
|
||||
splitTextNode,
|
||||
isEditorTab,
|
||||
isVoidElement
|
||||
isMacOS,
|
||||
isVoidElement,
|
||||
cleanZWS,
|
||||
isZWS,
|
||||
} from './utils/utils.js';
|
||||
import { editorCommands } from './commands/commands.js';
|
||||
import { Powerbox } from './powerbox/Powerbox.js';
|
||||
@@ -3762,14 +3764,14 @@ export class OdooEditor extends EventTarget {
|
||||
// we only remove the attribute to ensure we don't break some style.
|
||||
// Otherwise we remove the entire inline element.
|
||||
for (const emptyElement of element.querySelectorAll('[data-oe-zws-empty-inline]')) {
|
||||
if (emptyElement.textContent.length === 1 && emptyElement.textContent.includes('\u200B')) {
|
||||
if (isZWS(emptyElement)) {
|
||||
if (emptyElement.classList.length > 0) {
|
||||
emptyElement.removeAttribute('data-oe-zws-empty-inline');
|
||||
} else {
|
||||
emptyElement.remove();
|
||||
}
|
||||
} else {
|
||||
emptyElement.textContent = emptyElement.textContent.replace('\u200B', '');
|
||||
cleanZWS(emptyElement);
|
||||
emptyElement.removeAttribute('data-oe-zws-empty-inline');
|
||||
}
|
||||
}
|
||||
@@ -3796,7 +3798,7 @@ export class OdooEditor extends EventTarget {
|
||||
// Remove Zero Width Spaces on Font awesome elements
|
||||
const faSelector = 'i.fa,span.fa,i.fab,span.fab,i.fad,span.fad,i.far,span.far';
|
||||
for (const el of element.querySelectorAll(faSelector)) {
|
||||
el.textContent = el.textContent.replace('\u200B', '');
|
||||
cleanZWS(el);
|
||||
}
|
||||
|
||||
// Clean custom selections
|
||||
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
isEditorTab,
|
||||
isZWS,
|
||||
getUrlsInfosInString,
|
||||
URL_REGEX,
|
||||
isVoidElement,
|
||||
} from './utils.js';
|
||||
|
||||
@@ -240,16 +239,17 @@ class Sanitize {
|
||||
) {
|
||||
node.setAttribute('contenteditable', 'false');
|
||||
}
|
||||
|
||||
if (node.firstChild) {
|
||||
this._parse(node.firstChild);
|
||||
}
|
||||
|
||||
// Update link URL if label is a new valid link.
|
||||
if (node.nodeName === 'A' && anchorEl === node) {
|
||||
const linkLabel = node.textContent;
|
||||
const match = linkLabel.match(URL_REGEX);
|
||||
if (match && match[0] === node.textContent && !node.href.startsWith('mailto:')) {
|
||||
const urlInfo = getUrlsInfosInString(linkLabel)[0];
|
||||
node.setAttribute('href', urlInfo.url);
|
||||
const linkLabel = node.innerText;
|
||||
const urlInfo = getUrlsInfosInString(linkLabel);
|
||||
if (urlInfo.length && urlInfo[0].label === linkLabel && !node.href.startsWith('mailto:')) {
|
||||
node.setAttribute('href', urlInfo[0].url);
|
||||
}
|
||||
}
|
||||
node = node.nextSibling;
|
||||
|
||||
@@ -2574,3 +2574,14 @@ export function peek(arr) {
|
||||
export function isMacOS() {
|
||||
return window.navigator.userAgent.includes('Mac');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove zero-width spaces from the provided node and its descendants.
|
||||
*
|
||||
* @param {Node} node
|
||||
*/
|
||||
export function cleanZWS(node) {
|
||||
[node, ...descendants(node)]
|
||||
.filter(node => node.nodeType === Node.TEXT_NODE)
|
||||
.forEach(node => node.nodeValue = node.nodeValue.replace(/\u200B/g, ''));
|
||||
}
|
||||
|
||||
@@ -239,6 +239,14 @@ describe('Link', () => {
|
||||
},
|
||||
contentAfter: '<p>a<a href="https://google.com">google.comu[]</a>b</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>a<a href="https://google.com">google.com[]</a></p>',
|
||||
stepFunction: async editor => {
|
||||
await insertLineBreak(editor);
|
||||
await insertText(editor, 'odoo.com')
|
||||
},
|
||||
contentAfter: '<p>a<a href="https://google.com">google.com<br>odoo.com[]</a></p>',
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('range not collapsed', () => {
|
||||
|
||||
Reference in New Issue
Block a user