[FIX] web_editor: consider Odoo icons properly (as fa icons)

The editor has specific behaviors when it comes to icons. For instance,
marking them as `contenteditable="false"` so no text can end up into
their container element. Those behaviors were only enabled for fa icons,
this commit enables them for the new Odoo icons introduced at [1].

[1]: https://github.com/odoo/odoo/commit/546477dafab327d9990a5176bed4a9c2565eef74

closes odoo/odoo#142985

X-original-commit: 4e33b5e4956da53558b0a36ae2e6da13220290ab
Signed-off-by: Geelen Sébastien (sge) <sge@odoo.com>
Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
This commit is contained in:
qsm-odoo
2023-11-22 00:46:22 +00:00
parent b316f9fc9a
commit 2c3f0ead11
3 changed files with 34 additions and 4 deletions
@@ -35,6 +35,7 @@ import {
isHtmlContentSupported,
rgbToHex,
isFontAwesome,
ICON_SELECTOR,
getInSelection,
getDeepRange,
getRowIndex,
@@ -4294,8 +4295,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)) {
for (const el of element.querySelectorAll(ICON_SELECTOR)) {
cleanZWS(el);
}
@@ -1410,13 +1410,24 @@ export function containsUnbreakable(node) {
}
return isUnbreakable(node) || containsUnbreakable(node.firstChild);
}
// TODO rename this function in master: it also handles Odoo icons, not only
// font awesome ones. Also maybe just use the ICON_SELECTOR and `matches`?
const iconTags = ['I', 'SPAN'];
const iconClasses = ['fa', 'fab', 'fad', 'far', 'oi'];
export function isFontAwesome(node) {
// See ICON_SELECTOR
return (
node &&
(node.nodeName === 'I' || node.nodeName === 'SPAN') &&
['fa', 'fab', 'fad', 'far'].some(faClass => node.classList.contains(faClass))
iconTags.includes(node.nodeName) &&
iconClasses.some(cls => node.classList.contains(cls))
);
}
export const ICON_SELECTOR = iconTags.map(tag => {
return iconClasses.map(cls => {
return `${tag}.${cls}`;
}).join(', ');
}).join(', ');
export function isZWS(node) {
return (
node &&
@@ -56,6 +56,12 @@ describe('FontAwesome', () => {
'<p><span class="fa fa-pastafarianism" contenteditable="false">\u200b</span></p>',
contentAfter: '<p><span class="fa fa-pastafarianism"></span></p>',
});
await testEditor(BasicEditor, {
contentBefore: '<p><span class="oi oi-pastafarianism"></span></p>',
contentBeforeEdit:
'<p><span class="oi oi-pastafarianism" contenteditable="false">\u200b</span></p>',
contentAfter: '<p><span class="oi oi-pastafarianism"></span></p>',
});
});
it('should parse a fontawesome in a <i>', async () => {
await testEditor(BasicEditor, {
@@ -64,6 +70,12 @@ describe('FontAwesome', () => {
'<p><i class="fa fa-pastafarianism" contenteditable="false">\u200b</i></p>',
contentAfter: '<p><i class="fa fa-pastafarianism"></i></p>',
});
await testEditor(BasicEditor, {
contentBefore: '<p><i class="oi oi-pastafarianism"></i></i></p>',
contentBeforeEdit:
'<p><i class="oi oi-pastafarianism" contenteditable="false">\u200b</i></p>',
contentAfter: '<p><i class="oi oi-pastafarianism"></i></p>',
});
});
it('should parse a fontawesome with more classes', async () => {
await testEditor(BasicEditor, {
@@ -305,6 +317,13 @@ describe('FontAwesome', () => {
stepFunction: deleteBackward,
contentAfter: '<p>ab[]cd</p>',
});
await testEditor(BasicEditor, {
contentBefore: '<p>ab<i class="oi oi-pastafarianism"></i>[]cd</p>',
contentBeforeEdit:
'<p>ab<i class="oi oi-pastafarianism" contenteditable="false">\u200b</i>[]cd</p>',
stepFunction: deleteBackward,
contentAfter: '<p>ab[]cd</p>',
});
});
it('should delete a fontawesome before a span', async () => {
await testEditor(BasicEditor, {