[FIX] web_editor: word tables are broken because of formatting spaces.

Before this commit:

When format styles were applied to the word table, it would break table.

After this commit:

Now, when format styles are applied to a word table, the style will be applied to it
without breaking the table.

task-3165767

closes odoo/odoo#129356

X-original-commit: 0b06ba23aa111f6a85929abe8018b6b18da79873
Signed-off-by: David Monjoie (dmo) <dmo@odoo.com>
This commit is contained in:
dhba-odoo
2023-07-24 21:27:24 +02:00
committed by Antoine Guenet
parent 17a0ec17b5
commit 1a91bd9ea5
3 changed files with 330 additions and 2 deletions
@@ -490,7 +490,11 @@ export const editorCommands = {
const li = new Set();
const blocks = new Set();
for (const node of getTraversedNodes(editor.editable)) {
const selectedBlocks = getTraversedNodes(editor.editable);
const deepestSelectedBlocks = selectedBlocks.filter(block => (
!descendants(block).some(descendant => selectedBlocks.includes(descendant))
));
for (const node of deepestSelectedBlocks) {
if (node.nodeType === Node.TEXT_NODE && isWhitespace(node) && closestElement(node).isContentEditable) {
node.remove();
} else {
@@ -1023,7 +1023,7 @@ export const formatSelection = (editor, formatName, {applyStyle, formatProps} =
}
const selectedTextNodes = getSelectedNodes(editor.editable)
.filter(n => n.nodeType === Node.TEXT_NODE && closestElement(n).isContentEditable);
.filter(n => n.nodeType === Node.TEXT_NODE && closestElement(n).isContentEditable && (isVisibleTextNode(n) || isZWS(n)));
const formatSpec = formatsSpecs[formatName];
for (const selectedTextNode of selectedTextNodes) {
@@ -59,6 +59,59 @@ describe('List', () => {
'<ul><li><span><b>ab</b></span> <span><i>cd</i></span> ef[]gh</li></ul>',
});
});
it('should turn an empty paragraph of multiple table cells into a list', async () => {
await testEditor(BasicEditor, {
contentBefore: unformat(`
<table class="table table-bordered">
<tbody>
<tr>
<td>[<br></td>
<td><br></td>
<td><br></td>
</tr>
<tr>
<td><br></td>
<td><br></td>
<td><br>]</td>
</tr>
</tbody>
</table>
`),
stepFunction: toggleUnorderedList,
contentAfterEdit: unformat(`
<table class="table table-bordered o_selected_table">
<tbody>
<tr>
<td class="o_selected_td">[<ul><li placeholder="List" class="oe-hint"><br></li></ul></td>
<td class="o_selected_td"><ul><li placeholder="List" class="oe-hint"><br></li></ul></td>
<td class="o_selected_td"><ul><li placeholder="List" class="oe-hint"><br></li></ul></td>
</tr>
<tr>
<td class="o_selected_td"><ul><li placeholder="List" class="oe-hint"><br></li></ul></td>
<td class="o_selected_td"><ul><li placeholder="List" class="oe-hint"><br></li></ul></td>
<td class="o_selected_td"><ul><li placeholder="List" class="oe-hint"><br></li></ul>]</td>
</tr>
</tbody>
</table>
`),
contentAfter: unformat(`
<table class="table table-bordered">
<tbody>
<tr>
<td>[]<ul><li><br></li></ul></td>
<td><ul><li><br></li></ul></td>
<td><ul><li><br></li></ul></td>
</tr>
<tr>
<td><ul><li><br></li></ul></td>
<td><ul><li><br></li></ul></td>
<td><ul><li><br></li></ul></td>
</tr>
</tbody>
</table>
`),
});
});
});
describe('Remove', () => {
it('should turn an empty list into a paragraph', async () => {
@@ -137,6 +190,59 @@ describe('List', () => {
</ul>`),
});
});
it('should turn an list of multiple table cells into a empty paragraph', async () => {
await testEditor(BasicEditor, {
contentBefore: unformat(`
<table class="table table-bordered">
<tbody>
<tr>
<td>[<ul><li><br></li></ul></td>
<td><ul><li><br></li></ul></td>
<td><ul><li><br></li></ul></td>
</tr>
<tr>
<td><ul><li><br></li></ul></td>
<td><ul><li><br></li></ul></td>
<td><ul><li><br></li></ul>]</td>
</tr>
</tbody>
</table>
`),
stepFunction: toggleUnorderedList,
contentAfterEdit: unformat(`
<table class="table table-bordered o_selected_table">
<tbody>
<tr>
<td class="o_selected_td">[<p><br></p></td>
<td class="o_selected_td"><p><br></p></td>
<td class="o_selected_td"><p><br></p></td>
</tr>
<tr>
<td class="o_selected_td"><p><br></p></td>
<td class="o_selected_td"><p><br></p></td>
<td class="o_selected_td"><p><br></p>]</td>
</tr>
</tbody>
</table>
`),
contentAfter: unformat(`
<table class="table table-bordered">
<tbody>
<tr>
<td>[]<p><br></p></td>
<td><p><br></p></td>
<td><p><br></p></td>
</tr>
<tr>
<td><p><br></p></td>
<td><p><br></p></td>
<td><p><br></p></td>
</tr>
</tbody>
</table>
`),
});
});
});
describe('Transform', () => {
it('should turn an empty ordered list into an unordered list', async () => {
@@ -194,6 +300,59 @@ describe('List', () => {
'<ol><li><span><b>ab</b></span> <span><i>cd</i></span> ef[]gh</li></ol>',
});
});
it('should turn an empty paragraph of multiple table cells into a list', async () => {
await testEditor(BasicEditor, {
contentBefore: unformat(`
<table class="table table-bordered">
<tbody>
<tr>
<td>[<br></td>
<td><br></td>
<td><br></td>
</tr>
<tr>
<td><br></td>
<td><br></td>
<td><br>]</td>
</tr>
</tbody>
</table>
`),
stepFunction: toggleOrderedList,
contentAfterEdit: unformat(`
<table class="table table-bordered o_selected_table">
<tbody>
<tr>
<td class="o_selected_td">[<ol><li placeholder="List" class="oe-hint"><br></li></ol></td>
<td class="o_selected_td"><ol><li placeholder="List" class="oe-hint"><br></li></ol></td>
<td class="o_selected_td"><ol><li placeholder="List" class="oe-hint"><br></li></ol></td>
</tr>
<tr>
<td class="o_selected_td"><ol><li placeholder="List" class="oe-hint"><br></li></ol></td>
<td class="o_selected_td"><ol><li placeholder="List" class="oe-hint"><br></li></ol></td>
<td class="o_selected_td"><ol><li placeholder="List" class="oe-hint"><br></li></ol>]</td>
</tr>
</tbody>
</table>
`),
contentAfter: unformat(`
<table class="table table-bordered">
<tbody>
<tr>
<td>[]<ol><li><br></li></ol></td>
<td><ol><li><br></li></ol></td>
<td><ol><li><br></li></ol></td>
</tr>
<tr>
<td><ol><li><br></li></ol></td>
<td><ol><li><br></li></ol></td>
<td><ol><li><br></li></ol></td>
</tr>
</tbody>
</table>
`),
});
});
});
describe('Remove', () => {
it('should turn an empty list into a paragraph', async () => {
@@ -233,6 +392,59 @@ describe('List', () => {
'<p><span><b>ab</b></span> <span><i>cd</i></span> ef[]gh</p>',
});
});
it('should turn an list of multiple table cells into a empty paragraph', async () => {
await testEditor(BasicEditor, {
contentBefore: unformat(`
<table class="table table-bordered">
<tbody>
<tr>
<td>[<ol><li><br></li></ol></td>
<td><ol><li><br></li></ol></td>
<td><ol><li><br></li></ol></td>
</tr>
<tr>
<td><ol><li><br></li></ol></td>
<td><ol><li><br></li></ol></td>
<td><ol><li><br></li></ol>]</td>
</tr>
</tbody>
</table>
`),
stepFunction: toggleOrderedList,
contentAfterEdit: unformat(`
<table class="table table-bordered o_selected_table">
<tbody>
<tr>
<td class="o_selected_td">[<p><br></p></td>
<td class="o_selected_td"><p><br></p></td>
<td class="o_selected_td"><p><br></p></td>
</tr>
<tr>
<td class="o_selected_td"><p><br></p></td>
<td class="o_selected_td"><p><br></p></td>
<td class="o_selected_td"><p><br></p>]</td>
</tr>
</tbody>
</table>
`),
contentAfter: unformat(`
<table class="table table-bordered">
<tbody>
<tr>
<td>[]<p><br></p></td>
<td><p><br></p></td>
<td><p><br></p></td>
</tr>
<tr>
<td><p><br></p></td>
<td><p><br></p></td>
<td><p><br></p></td>
</tr>
</tbody>
</table>
`),
});
});
});
});
describe('Checklist', () => {
@@ -401,6 +613,65 @@ describe('List', () => {
},
});
});
it('should turn an empty paragraph of multiple table cells into a checklist', async () => {
await testEditor(BasicEditor, {
removeCheckIds: true,
contentBefore: unformat(`
<table class="table table-bordered">
<tbody>
<tr>
<td>[<br></td>
<td><br></td>
<td><br></td>
</tr>
<tr>
<td><br></td>
<td><br></td>
<td><br>]</td>
</tr>
</tbody>
</table>
`),
stepFunction: editor => {
toggleCheckList(editor);
for (const li of editor.editable.querySelectorAll('li[id^=checkId-]')) {
li.removeAttribute('id');
}
},
contentAfterEdit: unformat(`
<table class="table table-bordered o_selected_table">
<tbody>
<tr>
<td class="o_selected_td">[<ul class="o_checklist"><li placeholder="List" class="oe-hint"><br></li></ul></td>
<td class="o_selected_td"><ul class="o_checklist"><li placeholder="List" class="oe-hint"><br></li></ul></td>
<td class="o_selected_td"><ul class="o_checklist"><li placeholder="List" class="oe-hint"><br></li></ul></td>
</tr>
<tr>
<td class="o_selected_td"><ul class="o_checklist"><li placeholder="List" class="oe-hint"><br></li></ul></td>
<td class="o_selected_td"><ul class="o_checklist"><li placeholder="List" class="oe-hint"><br></li></ul></td>
<td class="o_selected_td"><ul class="o_checklist"><li placeholder="List" class="oe-hint"><br></li></ul>]</td>
</tr>
</tbody>
</table>
`),
contentAfter: unformat(`
<table class="table table-bordered">
<tbody>
<tr>
<td>[]<ul class="o_checklist"><li><br></li></ul></td>
<td><ul class="o_checklist"><li><br></li></ul></td>
<td><ul class="o_checklist"><li><br></li></ul></td>
</tr>
<tr>
<td><ul class="o_checklist"><li><br></li></ul></td>
<td><ul class="o_checklist"><li><br></li></ul></td>
<td><ul class="o_checklist"><li><br></li></ul></td>
</tr>
</tbody>
</table>
`),
});
});
});
describe('Remove', () => {
it('should turn an empty list into a paragraph', async () => {
@@ -483,6 +754,59 @@ describe('List', () => {
</ul>`),
});
});
it('should turn an list of multiple table cells into a empty paragraph', async () => {
await testEditor(BasicEditor, {
contentBefore: unformat(`
<table class="table table-bordered">
<tbody>
<tr>
<td>[<ul class="o_checklist"><li><br></li></ul></td>
<td><ul class="o_checklist"><li><br></li></ul></td>
<td><ul class="o_checklist"><li><br></li></ul></td>
</tr>
<tr>
<td><ul class="o_checklist"><li><br></li></ul></td>
<td><ul class="o_checklist"><li><br></li></ul></td>
<td><ul class="o_checklist"><li><br></li></ul>]</td>
</tr>
</tbody>
</table>
`),
stepFunction: toggleCheckList,
contentAfterEdit: unformat(`
<table class="table table-bordered o_selected_table">
<tbody>
<tr>
<td class="o_selected_td">[<p><br></p></td>
<td class="o_selected_td"><p><br></p></td>
<td class="o_selected_td"><p><br></p></td>
</tr>
<tr>
<td class="o_selected_td"><p><br></p></td>
<td class="o_selected_td"><p><br></p></td>
<td class="o_selected_td"><p><br></p>]</td>
</tr>
</tbody>
</table>
`),
contentAfter: unformat(`
<table class="table table-bordered">
<tbody>
<tr>
<td>[]<p><br></p></td>
<td><p><br></p></td>
<td><p><br></p></td>
</tr>
<tr>
<td><p><br></p></td>
<td><p><br></p></td>
<td><p><br></p></td>
</tr>
</tbody>
</table>
`),
});
});
});
});
});