[FIX] web_editor: preserve style on empty element
Make sure not to remove inline styles when emptying an element. task-3102841 X-original-commit: 8d0397c99798f05a41276d62a66f47c41f255ef8 Part-of: odoo/odoo#116558
This commit is contained in:
@@ -1853,6 +1853,19 @@ export class OdooEditor extends EventTarget {
|
||||
range.setEnd(commonAncestorContainer, nodeSize(commonAncestorContainer));
|
||||
}
|
||||
}
|
||||
let insertedZws;
|
||||
if (sel && !sel.isCollapsed && !range.startOffset && !range.startContainer.previousSibling) {
|
||||
// Insert a zero-width space before the selection if the selection
|
||||
// is non-collapsed and at the beginning of its parent, so said
|
||||
// parent will have content after extraction. This ensures that the
|
||||
// parent will not be removed by "tricking" `range.extractContents`.
|
||||
// Eg, <h1><font>[...]</font></h1> will preserve the styles of the
|
||||
// <font> node. If it remains empty, it will be cleaned up later by
|
||||
// the sanitizer.
|
||||
const zws = document.createTextNode('\u200B');
|
||||
range.startContainer.before(zws);
|
||||
insertedZws = zws;
|
||||
}
|
||||
let start = range.startContainer;
|
||||
let end = range.endContainer;
|
||||
// Let the DOM split and delete the range.
|
||||
@@ -1925,6 +1938,14 @@ export class OdooEditor extends EventTarget {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (insertedZws) {
|
||||
// Remove the zero-width space (zws) that was added to preserve the
|
||||
// parent styles, then call `fillEmpty` to properly add a flagged
|
||||
// zws if still needed.
|
||||
const el = closestElement(insertedZws);
|
||||
insertedZws.remove();
|
||||
el && fillEmpty(el);
|
||||
}
|
||||
next = range.endContainer && rightLeafOnlyNotBlockPath(range.endContainer).next().value;
|
||||
if (
|
||||
shouldPreserveSpace && next && !(next && next.nodeType === Node.TEXT_NODE && next.textContent.startsWith(' '))
|
||||
|
||||
@@ -1003,11 +1003,16 @@ X[]
|
||||
contentAfter: '<div>a<p>b[]e</p>f</div>',
|
||||
});
|
||||
});
|
||||
it('should delete empty nodes ', async () => {
|
||||
it('should not delete single remaining empty inline', async () => {
|
||||
// Forward selection
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1><font>[abcdef]</font></h1>',
|
||||
stepFunction: deleteForward,
|
||||
// The flagged 200B is there to preserve the font so if we
|
||||
// write now, we still write in the font element's style.
|
||||
contentAfterEdit: '<h1><font data-oe-zws-empty-inline="">[]\u200B</font><br></h1>',
|
||||
// The flagged 200B is removed by the sanitizer if its
|
||||
// parent remains empty.
|
||||
contentAfter: '<h1>[]<br></h1>',
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { parseHTML } from '../../src/utils/utils.js';
|
||||
import { BasicEditor, testEditor, unformat } from '../utils.js';
|
||||
import { BasicEditor, testEditor, unformat, insertText, deleteBackward } from '../utils.js';
|
||||
|
||||
const span = text => {
|
||||
const span = document.createElement('span');
|
||||
@@ -264,3 +264,22 @@ describe('insert HTML', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('insert text', () => {
|
||||
describe('not collapsed selection', () => {
|
||||
it('should insert a character in a fully selected font in a heading, preserving its style', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1><font style="background-color: red;">[abc</font><br></h1><p>]def</p>',
|
||||
stepFunction: async editor => insertText(editor, 'g'),
|
||||
contentAfter: '<h1><font style="background-color: red;">g[]</font><br></h1><p>def</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<h1><font style="background-color: red;">[abc</font><br></h1><p>]def</p>',
|
||||
stepFunction: async editor => {
|
||||
await deleteBackward(editor);
|
||||
await insertText(editor, 'g');
|
||||
},
|
||||
contentAfter: '<h1><font style="background-color: red;">g[]</font><br></h1><p>def</p>',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user