[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:
committed by
Antoine Guenet
parent
17a0ec17b5
commit
1a91bd9ea5
@@ -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>
|
||||
`),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user