[FIX] web_editor: adapt unit tests
* Adapt Unit tests to always have a container block element * Add some tests to ensure the editable root direct child nodes are all blocks * Fix paste HTML unit tests to properly check that we never paste inline elements or text nodes outside the target container Part-of: odoo/odoo#95347 # Conflicts: # addons/web_editor/static/lib/odoo-editor/test/spec/collab.test.js # addons/web_editor/static/lib/odoo-editor/test/spec/copyPaste.test.js # addons/web_editor/static/lib/odoo-editor/test/spec/editor.test.js Part-of: odoo/odoo#95445
This commit is contained in:
@@ -56,9 +56,9 @@ const testSameHistory = clientInfos => {
|
||||
window.chai
|
||||
.expect(firstClientInfo.editor._historySteps[i].id)
|
||||
.to.be.equal(
|
||||
clientInfo.editor._historySteps[i].id,
|
||||
`History steps are not consistent accross clients.`,
|
||||
);
|
||||
clientInfo.editor._historySteps[i].id,
|
||||
`History steps are not consistent accross clients.`,
|
||||
);
|
||||
} catch (e) {
|
||||
console.log(
|
||||
'Clients steps:',
|
||||
@@ -233,7 +233,7 @@ describe('Collaboration', () => {
|
||||
it('all client steps should be on the same order', () => {
|
||||
testMultiEditor({
|
||||
clientIds: ['c1', 'c2', 'c3'],
|
||||
contentBefore: '<x>a[c1}{c1]</x><y>e[c2}{c2]</y><z>i[c3}{c3]</z>',
|
||||
contentBefore: '<p><x>a[c1}{c1]</x><y>e[c2}{c2]</y><z>i[c3}{c3]</z></p>',
|
||||
afterCreate: clientInfos => {
|
||||
applyConcurentActions(clientInfos, {
|
||||
c1: editor => {
|
||||
@@ -255,7 +255,7 @@ describe('Collaboration', () => {
|
||||
mergeClientsSteps(clientInfos);
|
||||
testSameHistory(clientInfos);
|
||||
},
|
||||
contentAfter: '<x>abcd[c1}{c1]</x><y>efgh[c2}{c2]</y><z>ijkl[c3}{c3]</z>',
|
||||
contentAfter: '<p><x>abcd[c1}{c1]</x><y>efgh[c2}{c2]</y><z>ijkl[c3}{c3]</z></p>',
|
||||
});
|
||||
});
|
||||
it('should 2 client insertText in 2 different paragraph', () => {
|
||||
@@ -301,7 +301,7 @@ describe('Collaboration', () => {
|
||||
it('should insertText with client 1 and deleteBackward with client 2', () => {
|
||||
testMultiEditor({
|
||||
clientIds: ['c1', 'c2'],
|
||||
contentBefore: 'ab[c1}{c1][c2}{c2]c',
|
||||
contentBefore: '<p>ab[c1}{c1][c2}{c2]c</p>',
|
||||
afterCreate: clientInfos => {
|
||||
applyConcurentActions(clientInfos, {
|
||||
c1: editor => {
|
||||
@@ -314,13 +314,13 @@ describe('Collaboration', () => {
|
||||
mergeClientsSteps(clientInfos);
|
||||
testSameHistory(clientInfos);
|
||||
},
|
||||
contentAfter: 'a[c2}{c2]c[c1}{c1]dc',
|
||||
contentAfter: '<p>a[c2}{c2]c[c1}{c1]dc</p>',
|
||||
});
|
||||
});
|
||||
it('should insertText twice with client 1 and deleteBackward twice with client 2', () => {
|
||||
testMultiEditor({
|
||||
clientIds: ['c1', 'c2'],
|
||||
contentBefore: 'ab[c1}{c1][c2}{c2]c',
|
||||
contentBefore: '<p>ab[c1}{c1][c2}{c2]c</p>',
|
||||
afterCreate: clientInfos => {
|
||||
applyConcurentActions(clientInfos, {
|
||||
c1: editor => {
|
||||
@@ -335,14 +335,14 @@ describe('Collaboration', () => {
|
||||
mergeClientsSteps(clientInfos);
|
||||
testSameHistory(clientInfos);
|
||||
},
|
||||
contentAfter: '[c2}{c2]cd[c1}{c1]ec',
|
||||
contentAfter: '<p>[c2}{c2]cd[c1}{c1]ec</p>',
|
||||
});
|
||||
});
|
||||
});
|
||||
it('should reset from snapshot', () => {
|
||||
testMultiEditor({
|
||||
clientIds: ['c1', 'c2'],
|
||||
contentBefore: 'a[c1}{c1]',
|
||||
contentBefore: '<p>a[c1}{c1]</p>',
|
||||
afterCreate: clientInfos => {
|
||||
clientInfos.c1.editor.execCommand('insertText', 'b');
|
||||
clientInfos.c1.editor._historyMakeSnapshot();
|
||||
@@ -356,16 +356,16 @@ describe('Collaboration', () => {
|
||||
]);
|
||||
chai.expect(
|
||||
clientInfos.c2.editor._historySteps[0].mutations.map(x => x.id),
|
||||
).to.deep.equal(['fake_id_1', 'fake_concurent_id_1']);
|
||||
).to.deep.equal(['fake_id_1']);
|
||||
},
|
||||
contentAfter: 'ab[c1}{c1]',
|
||||
contentAfter: '<p>ab[c1}{c1]</p>',
|
||||
});
|
||||
});
|
||||
describe('steps whith no parent in history', () => {
|
||||
it('should be able to retreive steps when disconnected from clients that has send step', () => {
|
||||
testMultiEditor({
|
||||
clientIds: ['c1', 'c2', 'c3'],
|
||||
contentBefore: '<x>a[c1}{c1]</x><y>b[c2}{c2]</y><z>c[c3}{c3]</z>',
|
||||
contentBefore: '<p><x>a[c1}{c1]</x><y>b[c2}{c2]</y><z>c[c3}{c3]</z></p>',
|
||||
afterCreate: clientInfos => {
|
||||
clientInfos.c1.editor.execCommand('insertText', 'd');
|
||||
clientInfos.c2.editor.onExternalHistorySteps([
|
||||
@@ -384,13 +384,13 @@ describe('Collaboration', () => {
|
||||
]);
|
||||
testSameHistory(clientInfos);
|
||||
},
|
||||
contentAfter: '<x>ad[c1}{c1]</x><y>be[c2}{c2]</y><z>c[c3}{c3]</z>',
|
||||
contentAfter: '<p><x>ad[c1}{c1]</x><y>be[c2}{c2]</y><z>c[c3}{c3]</z></p>',
|
||||
});
|
||||
});
|
||||
it('should receive steps where parent was not received', () => {
|
||||
testMultiEditor({
|
||||
clientIds: ['c1', 'c2', 'c3'],
|
||||
contentBefore: '<i>a[c1}{c1]</i><b>b[c2}{c2]</b>',
|
||||
contentBefore: '<p><i>a[c1}{c1]</i><b>b[c2}{c2]</b></p>',
|
||||
afterCreate: clientInfos => {
|
||||
clientInfos.c1.editor.execCommand('insertText', 'c');
|
||||
clientInfos.c2.editor.onExternalHistorySteps([
|
||||
@@ -425,7 +425,7 @@ describe('Collaboration', () => {
|
||||
clientInfos.c2.editor._historySteps[4],
|
||||
]);
|
||||
},
|
||||
contentAfter: '<i>ac[c1}{c1]</i><b>bdef[c2}{c2]</b>',
|
||||
contentAfter: '<p><i>ac[c1}{c1]</i><b>bdef[c2}{c2]</b></p>',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -433,7 +433,7 @@ describe('Collaboration', () => {
|
||||
it('should sanitize when adding a node', () => {
|
||||
testMultiEditor({
|
||||
clientIds: ['c1', 'c2'],
|
||||
contentBefore: '<x>a</x>',
|
||||
contentBefore: '<p><x>a</x></p>',
|
||||
afterCreate: clientInfos => {
|
||||
const script = document.createElement('script');
|
||||
script.innerHTML = 'console.log("xss")';
|
||||
@@ -445,14 +445,14 @@ describe('Collaboration', () => {
|
||||
]);
|
||||
window.chai
|
||||
.expect(clientInfos.c2.editor.editable.innerHTML)
|
||||
.to.equal('<x>a</x>');
|
||||
.to.equal('<p><x>a</x></p>');
|
||||
},
|
||||
});
|
||||
});
|
||||
it('should sanitize when adding a script as descendant', async () => {
|
||||
testMultiEditor({
|
||||
clientIds: ['c1', 'c2'],
|
||||
contentBefore: '<x>a[c1}{c1][c2}{c2]</x>',
|
||||
contentBefore: '<p>a[c1}{c1][c2}{c2]</p>',
|
||||
afterCreate: clientInfos => {
|
||||
const i = document.createElement('i');
|
||||
i.innerHTML = '<b>b</b><script>alert("c");</script>';
|
||||
@@ -464,7 +464,7 @@ describe('Collaboration', () => {
|
||||
},
|
||||
afterCursorInserted: clientInfos => {
|
||||
chai.expect(clientInfos.c2.editable.innerHTML).to.equal(
|
||||
'<x>a[c1}{c1][c2}{c2]</x><i><b>b</b></i>',
|
||||
'<p>a[c1}{c1][c2}{c2]</p><i><b>b</b></i>',
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -472,7 +472,7 @@ describe('Collaboration', () => {
|
||||
it('should sanitize when changing an attribute', () => {
|
||||
testMultiEditor({
|
||||
clientIds: ['c1', 'c2'],
|
||||
contentBefore: '<x>a<img></x>',
|
||||
contentBefore: '<p>a<img></p>',
|
||||
afterCreate: clientInfos => {
|
||||
const img = clientInfos.c1.editable.childNodes[0].childNodes[1];
|
||||
img.setAttribute('class', 'b');
|
||||
@@ -483,10 +483,10 @@ describe('Collaboration', () => {
|
||||
]);
|
||||
window.chai
|
||||
.expect(clientInfos.c1.editor.editable.innerHTML)
|
||||
.to.equal('<x>a<img class="b" onerror="console.log("xss")"></x>');
|
||||
.to.equal('<p>a<img class="b" onerror="console.log("xss")"></p>');
|
||||
window.chai
|
||||
.expect(clientInfos.c2.editor.editable.innerHTML)
|
||||
.to.equal('<x>a<img class="b"></x>');
|
||||
.to.equal('<p>a<img class="b"></p>');
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -494,7 +494,7 @@ describe('Collaboration', () => {
|
||||
it('should sanitize when undo is adding a script node', () => {
|
||||
testMultiEditor({
|
||||
clientIds: ['c1', 'c2'],
|
||||
contentBefore: '<x>a</x>',
|
||||
contentBefore: '<p>a</p>',
|
||||
afterCreate: clientInfos => {
|
||||
const script = document.createElement('script');
|
||||
script.innerHTML = 'console.log("xss")';
|
||||
@@ -513,14 +513,14 @@ describe('Collaboration', () => {
|
||||
clientInfos.c2.editor.historyUndo();
|
||||
window.chai
|
||||
.expect(clientInfos.c2.editor.editable.innerHTML)
|
||||
.to.equal('<x>a</x>');
|
||||
.to.equal('<p>a</p>');
|
||||
},
|
||||
});
|
||||
});
|
||||
it('should sanitize when undo is adding a descendant script node', () => {
|
||||
testMultiEditor({
|
||||
clientIds: ['c1', 'c2'],
|
||||
contentBefore: '<x>a</x>',
|
||||
contentBefore: '<p>a</p>',
|
||||
afterCreate: clientInfos => {
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = '<i>b</i><script>console.log("xss")</script>';
|
||||
@@ -539,14 +539,14 @@ describe('Collaboration', () => {
|
||||
clientInfos.c2.editor.historyUndo();
|
||||
window.chai
|
||||
.expect(clientInfos.c2.editor.editable.innerHTML)
|
||||
.to.equal('<x>a</x><div><i>b</i></div>');
|
||||
.to.equal('<p>a</p><div><i>b</i></div>');
|
||||
},
|
||||
});
|
||||
});
|
||||
it('should sanitize when undo is changing an attribute', () => {
|
||||
testMultiEditor({
|
||||
clientIds: ['c1', 'c2'],
|
||||
contentBefore: '<x>a<img></x>',
|
||||
contentBefore: '<p>a<img></p>',
|
||||
afterCreate: clientInfos => {
|
||||
const img = clientInfos.c1.editable.childNodes[0].childNodes[1];
|
||||
img.setAttribute('class', 'b');
|
||||
@@ -566,7 +566,7 @@ describe('Collaboration', () => {
|
||||
clientInfos.c2.editor.historyUndo();
|
||||
window.chai
|
||||
.expect(clientInfos.c2.editor.editable.innerHTML)
|
||||
.to.equal('<x>a<img class="b"></x>');
|
||||
.to.equal('<p>a<img class="b"></p>');
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,70 +26,90 @@ describe('Copy and paste', () => {
|
||||
describe('Html Paste cleaning', () => {
|
||||
describe('whitelist', async () => {
|
||||
it('should keep whitelisted Tags tag', async () => {
|
||||
for (const node of CLIPBOARD_WHITELISTS.nodes) {
|
||||
if (!['TABLE', 'THEAD', 'TH', 'TBODY', 'TR', 'TD', 'IMG', 'BR', 'LI', '.fa'].includes(node)) {
|
||||
const isInline = ['I', 'B', 'U', 'EM', 'STRONG', 'IMG', 'BR', 'A'].includes(node)
|
||||
const html = isInline ? `a<${node.toLowerCase()}>b</${node.toLowerCase()}>c` : `a</p><${node.toLowerCase()}>b</${node.toLowerCase()}><p>c`;
|
||||
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>123[]4</p>',
|
||||
stepFunction: async editor => {
|
||||
await pasteHtml(editor, `a<${node.toLowerCase()}>b</${node.toLowerCase()}>c`);
|
||||
},
|
||||
contentAfter: '<p>123' + html + '[]4</p>',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
it('should keep whitelisted Tags tag (2)', async () => {
|
||||
const tagsToKeep = [
|
||||
'a<img src="http://www.imgurl.com/img.jpg">d', // img tag
|
||||
'a<br>b' // br tags
|
||||
];
|
||||
|
||||
for (const node of CLIPBOARD_WHITELISTS.nodes) {
|
||||
if (!['TABLE', 'THEAD', 'TH', 'TBODY', 'TR', 'TD', 'IMG', 'BR', 'LI', '.fa'].includes(node)) {
|
||||
tagsToKeep.push(`a<${node.toLowerCase()}>b</${node.toLowerCase()}>c`);
|
||||
}
|
||||
}
|
||||
|
||||
for (const tagToKeep of tagsToKeep) {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '123[]',
|
||||
contentBefore: '<p>123[]</p>',
|
||||
stepFunction: async editor => {
|
||||
await pasteHtml(editor, tagToKeep);
|
||||
},
|
||||
contentAfter: '123' + tagToKeep + '[]',
|
||||
contentAfter: '<p>123' + tagToKeep + '[]</p>',
|
||||
});
|
||||
}
|
||||
});
|
||||
it('should keep tables Tags tag and add classes', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '123[]',
|
||||
contentBefore: '<p>123[]</p>',
|
||||
stepFunction: async editor => {
|
||||
await pasteHtml(editor, 'a<table><thead><tr><th>h</th></tr></thead><tbody><tr><td>b</td></tr></tbody></table>d');
|
||||
},
|
||||
contentAfter: '123a<table class="table table-bordered"><thead><tr><th>h</th></tr></thead><tbody><tr><td>b</td></tr></tbody></table>d[]',
|
||||
contentAfter: '<p>123a</p><table class="table table-bordered"><thead><tr><th>h</th></tr></thead><tbody><tr><td>b</td></tr></tbody></table><p>d[]</p>',
|
||||
});
|
||||
});
|
||||
it('should not keep span', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '123[]',
|
||||
contentBefore: '<p>123[]</p>',
|
||||
stepFunction: async editor => {
|
||||
await pasteHtml(editor, 'a<span>bc</span>d');
|
||||
},
|
||||
contentAfter: '123abcd[]',
|
||||
contentAfter: '<p>123abcd[]</p>',
|
||||
});
|
||||
});
|
||||
it('should not keep orphan LI', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '123[]',
|
||||
contentBefore: '<p>123[]</p>',
|
||||
stepFunction: async editor => {
|
||||
await pasteHtml(editor, 'a<li>bc</li>d');
|
||||
},
|
||||
contentAfter: '123a<p>bc</p>d[]',
|
||||
contentAfter: '<p>123a</p><p>bc</p><p>d[]</p>',
|
||||
});
|
||||
});
|
||||
it('should keep LI in UL', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '123[]',
|
||||
contentBefore: '<p>123[]</p>',
|
||||
stepFunction: async editor => {
|
||||
await pasteHtml(editor, 'a<ul><li>bc</li></ul>d');
|
||||
},
|
||||
contentAfter: '123a<ul><li>bc</li></ul>d[]',
|
||||
contentAfter: '<p>123a</p><ul><li>bc</li></ul><p>d[]</p>',
|
||||
});
|
||||
});
|
||||
it('should keep P and B and not span', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>123[]xx</p>',
|
||||
stepFunction: async editor => {
|
||||
await pasteHtml(editor, 'a<p>bc</p>d<span>e</span>f<b>g</b>h');
|
||||
},
|
||||
contentAfter: '<p>123a</p><p>bc</p><p>def<b>g</b>h[]xx</p>',
|
||||
});
|
||||
});
|
||||
it('should keep styled span', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '123[]',
|
||||
contentBefore: '<p>123[]</p>',
|
||||
stepFunction: async editor => {
|
||||
await pasteHtml(editor, 'a<span style="text-decoration: underline">bc</span>d');
|
||||
},
|
||||
contentAfter: '123a<span style="text-decoration: underline">bc</span>d[]',
|
||||
contentAfter: '<p>123a<span style="text-decoration: underline">bc</span>d[]</p>',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,6 +21,70 @@ async function twoDeleteForward(editor) {
|
||||
}
|
||||
|
||||
describe('Editor', () => {
|
||||
describe('init', () => {
|
||||
describe('No orphan inline elements compatibility mode', () => {
|
||||
it('should transform root <br> into <p>', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<br>c',
|
||||
contentAfter: '<p style="margin-bottom: 0px;">ab</p><p style="margin-bottom: 0px;">c</p>',
|
||||
});
|
||||
});
|
||||
it('should keep <br> if necessary', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<br><br>c',
|
||||
contentAfter: '<p style="margin-bottom: 0px;">ab</p><p style="margin-bottom: 0px;"><br></p><p style="margin-bottom: 0px;">c</p>',
|
||||
});
|
||||
});
|
||||
it('should keep multiple conecutive <br> if necessary', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<br><br><br><br>c',
|
||||
contentAfter: '<p style="margin-bottom: 0px;">ab</p><p style="margin-bottom: 0px;"><br></p><p style="margin-bottom: 0px;"><br></p><p style="margin-bottom: 0px;"><br></p><p style="margin-bottom: 0px;">c</p>',
|
||||
});
|
||||
});
|
||||
it('should transform complex <br>', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<br>c<br>d<span class="keep">xxx</span>e<br>f',
|
||||
contentAfter: '<p style="margin-bottom: 0px;">ab</p><p style="margin-bottom: 0px;">c</p><p style="margin-bottom: 0px;">d<span class="keep">xxx</span>e</p><p style="margin-bottom: 0px;">f</p>',
|
||||
});
|
||||
});
|
||||
it('should transform complex <br> + keep li ', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<br>c<ul><li>d</li><li>e</li></ul> f<br>g',
|
||||
contentAfter: '<p style="margin-bottom: 0px;">ab</p><p style="margin-bottom: 0px;">c</p><ul><li>d</li><li>e</li></ul><p style="margin-bottom: 0px;"> f</p><p style="margin-bottom: 0px;">g</p>',
|
||||
});
|
||||
});
|
||||
it('should not transform <br> inside <p>', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>ab<br>c</p>',
|
||||
contentAfter: '<p>ab<br>c</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>ab<br>c</p><p>d<br></p>',
|
||||
contentAfter: '<p>ab<br>c</p><p>d<br></p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'xx<p>ab<br>c</p>d<br>yy',
|
||||
contentAfter: '<p style="margin-bottom: 0px;">xx</p><p>ab<br>c</p><p style="margin-bottom: 0px;">d</p><p style="margin-bottom: 0px;">yy</p>',
|
||||
});
|
||||
});
|
||||
it('should not transform indentation', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: `
|
||||
<p>ab</p>
|
||||
<p>c</p>`,
|
||||
contentAfter: `
|
||||
<p>ab</p>
|
||||
<p>c</p>`,
|
||||
});
|
||||
});
|
||||
it('should transform root .fa', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>ab</p><i class="fa fa-beer"></i><p>c</p>',
|
||||
contentAfter: '<p>ab</p><p style="margin-bottom: 0px;"><i class="fa fa-beer"></i></p><p>c</p>',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('deleteForward', () => {
|
||||
describe('Selection collapsed', () => {
|
||||
describe('Basic', () => {
|
||||
@@ -310,6 +374,11 @@ X[]
|
||||
stepFunction: deleteForward,
|
||||
contentAfter: '<p>abc[]def</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>abc[]</p> <p>def</p> orphan node',
|
||||
stepFunction: deleteForward,
|
||||
contentAfter: '<p>abc[]def</p><p style="margin-bottom: 0px;"> orphan node</p>',
|
||||
});
|
||||
});
|
||||
it('should delete the space if the second <p> is display inline', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
@@ -1367,11 +1436,11 @@ X[]
|
||||
});
|
||||
it('should remove a fontawesome', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: `<p>abc</p><span class="fa"></span><p>[]def</p>`,
|
||||
contentBefore: `<div><p>abc</p><span class="fa"></span><p>[]def</p></div>`,
|
||||
stepFunction: async editor => {
|
||||
await deleteBackward(editor);
|
||||
},
|
||||
contentAfter: `<p>abc</p><p>[]def</p>`,
|
||||
contentAfter: `<div><p>abc</p><p>[]def</p></div>`,
|
||||
});
|
||||
});
|
||||
it('should remove a media element', async () => {
|
||||
@@ -1826,14 +1895,14 @@ X[]
|
||||
});
|
||||
it('should merge a text preceding a paragraph (removing the paragraph)', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<p>[]cd</p>',
|
||||
contentBefore: '<div>ab<p>[]cd</p></div>',
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: 'ab[]cd',
|
||||
contentAfter: '<div>ab[]cd</div>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<p>[]cd</p>ef',
|
||||
contentBefore: '<div>ab<p>[]cd</p>ef</div>',
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: 'ab[]cd<br>ef',
|
||||
contentAfter: '<div>ab[]cd<br>ef</div>',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1985,9 +2054,9 @@ X[]
|
||||
});
|
||||
it('should ignore empty inline node between blocks being merged', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '<p>abc</p><i> </i><p>[]def</p>',
|
||||
contentBefore: '<div><p>abc</p><i> </i><p>[]def</p></div>',
|
||||
stepFunction: deleteBackward,
|
||||
contentAfter: '<p>abc[]def</p>',
|
||||
contentAfter: '<div><p>abc[]def</p></div>',
|
||||
});
|
||||
});
|
||||
it('should merge in nested paragraphs and remove invisible inline content', async () => {
|
||||
@@ -3363,7 +3432,7 @@ X[]
|
||||
contentAfter: '<p>a http://test.com b http://test.com [] c http://test.com d</p>',
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
describe('history', () => {
|
||||
describe('undo', () => {
|
||||
@@ -3537,252 +3606,250 @@ X[]
|
||||
describe('ArrowRight', () => {
|
||||
it('should move past a zws (collapsed)', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab[]<span>\u200B</span>cd',
|
||||
contentBefore: '<p>ab[]<span>\u200B</span>cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowRight'});
|
||||
},
|
||||
contentAfter: 'ab<span>\u200B[]</span>cd',
|
||||
// Final state: 'ab<span>\u200B</span>c[]d'
|
||||
contentAfter: '<p>ab<span>\u200B[]</span>cd</p>',
|
||||
// Final state: '<p>ab<span>\u200B</span>c[]d</p>'
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<span>[]\u200B</span>cd',
|
||||
contentBefore: '<p>ab<span>[]\u200B</span>cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowRight'});
|
||||
},
|
||||
contentAfter: 'ab<span>\u200B[]</span>cd',
|
||||
// Final state: 'ab<span>\u200B</span>c[]d'
|
||||
contentAfter: '<p>ab<span>\u200B[]</span>cd</p>',
|
||||
// Final state: '<p>ab<span>\u200B</span>c[]d</p>'
|
||||
});
|
||||
});
|
||||
it('should select a zws', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '[ab]<span>\u200B</span>cd',
|
||||
contentBefore: '<p>[ab]<span>\u200B</span>cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowRight', shiftKey: true });
|
||||
},
|
||||
contentAfter: '[ab<span>\u200B]</span>cd',
|
||||
// Final state: '[ab<span>\u200B</span>c]d'
|
||||
contentAfter: '<p>[ab<span>\u200B]</span>cd</p>',
|
||||
// Final state: '<p>[ab<span>\u200B</span>c]d</p>'
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '[ab<span>]\u200B</span>cd',
|
||||
contentBefore: '<p>[ab<span>]\u200B</span>cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowRight', shiftKey: true });
|
||||
},
|
||||
contentAfter: '[ab<span>\u200B]</span>cd',
|
||||
// Final state: '[ab<span>\u200B</span>c]d'
|
||||
contentAfter: '<p>[ab<span>\u200B]</span>cd</p>',
|
||||
// Final state: '<p>[ab<span>\u200B</span>c]d</p>'
|
||||
});
|
||||
});
|
||||
it('should select a zws (2)', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'a[b]<span>\u200B</span>cd',
|
||||
contentBefore: '<p>a[b]<span>\u200B</span>cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowRight', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'a[b<span>\u200B]</span>cd',
|
||||
// Final state: 'a[b<span>\u200B</span>c]d'
|
||||
contentAfter: '<p>a[b<span>\u200B]</span>cd</p>',
|
||||
// Final state: '<p>a[b<span>\u200B</span>c]d</p>'
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'a[b<span>]\u200B</span>cd',
|
||||
contentBefore: '<p>a[b<span>]\u200B</span>cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowRight', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'a[b<span>\u200B]</span>cd',
|
||||
// Final state: 'a[b<span>\u200B</span>c]d'
|
||||
contentAfter: '<p>a[b<span>\u200B]</span>cd</p>',
|
||||
// Final state: '<p>a[b<span>\u200B</span>c]d</p>'
|
||||
});
|
||||
});
|
||||
it('should select a zws (3)', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab[]<span>\u200B</span>cd',
|
||||
contentBefore: '<p>ab[]<span>\u200B</span>cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowRight', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab[<span>\u200B]</span>cd',
|
||||
// Final state: 'ab[<span>\u200B</span>c]d'
|
||||
contentAfter: '<p>ab[<span>\u200B]</span>cd</p>',
|
||||
// Final state: '<p>ab[<span>\u200B</span>c]d</p>'
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<span>[]\u200B</span>cd',
|
||||
contentBefore: '<p>ab<span>[]\u200B</span>cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowRight', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab<span>[\u200B]</span>cd',
|
||||
// Final state: 'ab<span>[\u200B</span>c]d'
|
||||
contentAfter: '<p>ab<span>[\u200B]</span>cd</p>',
|
||||
// Final state: '<p>ab<span>[\u200B</span>c]d</p>'
|
||||
});
|
||||
});
|
||||
it('should select a zws backwards', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<span>]\u200B[</span>cd',
|
||||
contentBefore: '<p>ab<span>]\u200B[</span>cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowRight', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab<span>\u200B[]</span>cd',
|
||||
// Final state: 'ab<span>\u200B</span>[c]d'
|
||||
contentAfter: '<p>ab<span>\u200B[]</span>cd</p>',
|
||||
// Final state: '<p>ab<span>\u200B</span>[c]d</p>'
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<span>]\u200B</span>[cd',
|
||||
contentBefore: '<p>ab<span>]\u200B</span>[cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowRight', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab<span>\u200B[]</span>cd',
|
||||
// Final state: 'ab<span>\u200B</span>[c]d'
|
||||
contentAfter: '<p>ab<span>\u200B[]</span>cd</p>',
|
||||
// Final state: '<p>ab<span>\u200B</span>[c]d</p>'
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab]<span>\u200B</span>[cd',
|
||||
contentBefore: '<p>ab]<span>\u200B</span>[cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowRight', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab<span>\u200B[]</span>cd',
|
||||
// Final state: 'ab<span>\u200B</span>[c]d'
|
||||
contentAfter: '<p>ab<span>\u200B[]</span>cd</p>',
|
||||
// Final state: '<p>ab<span>\u200B</span>[c]d</p>'
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab]<span>\u200B[</span>cd',
|
||||
contentBefore: '<p>ab]<span>\u200B[</span>cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowRight', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab<span>\u200B[]</span>cd',
|
||||
// Final state: 'ab<span>\u200B</span>[c]d'
|
||||
contentAfter: '<p>ab<span>\u200B[]</span>cd</p>',
|
||||
// Final state: '<p>ab<span>\u200B</span>[c]d</p>'
|
||||
});
|
||||
});
|
||||
it('should select a zws backwards (2)', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<span>]\u200B</span>c[d',
|
||||
contentBefore: '<p>ab<span>]\u200B</span>c[d</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowRight', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab<span>\u200B]</span>c[d',
|
||||
// Final state: 'ab<span>\u200B</span>c[]d'
|
||||
contentAfter: '<p>ab<span>\u200B]</span>c[d</p>',
|
||||
// Final state: '<p>ab<span>\u200B</span>c[]d</p>'
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab]<span>\u200B</span>c[d',
|
||||
contentBefore: '<p>ab]<span>\u200B</span>c[d</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowRight', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab<span>\u200B]</span>c[d',
|
||||
// Final state: 'ab<span>\u200B</span>c[]d'
|
||||
contentAfter: '<p>ab<span>\u200B]</span>c[d</p>',
|
||||
// Final state: '<p>ab<span>\u200B</span>c[]d</p>'
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('ArrowLeft', () => {
|
||||
it('should move past a zws (collapsed)', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<span>\u200B[]</span>cd',
|
||||
contentBefore: '<p>ab<span>\u200B[]</span>cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowLeft'});
|
||||
},
|
||||
contentAfter: 'ab<span>[]\u200B</span>cd',
|
||||
// Final state: 'a[]b<span>\u200B</span>cd'
|
||||
contentAfter: '<p>ab<span>[]\u200B</span>cd</p>',
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<span>\u200B</span>[]cd',
|
||||
contentBefore: '<p>ab<span>\u200B</span>[]cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowLeft'});
|
||||
},
|
||||
contentAfter: 'ab<span>[]\u200B</span>cd',
|
||||
// Final state: 'a[]b<span>\u200B</span>cd'
|
||||
contentAfter: '<p>ab<span>[]\u200B</span>cd</p>',
|
||||
});
|
||||
});
|
||||
it('should select a zws backwards', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<span>\u200B[]</span>cd',
|
||||
contentBefore: '<p>ab<span>\u200B[]</span>cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowLeft', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab<span>]\u200B[</span>cd',
|
||||
// Final state: 'a]b<span>\u200B[</span>cd'
|
||||
contentAfter: '<p>ab<span>]\u200B[</span>cd</p>',
|
||||
// Final state: '<p>a]b<span>\u200B[</span>cd</p>'
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<span>\u200B</span>[]cd',
|
||||
contentBefore: '<p>ab<span>\u200B</span>[]cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowLeft', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab<span>]\u200B[</span>cd',
|
||||
// Final state: 'a]b<span>\u200B[</span>cd'
|
||||
contentAfter: '<p>ab<span>]\u200B[</span>cd</p>',
|
||||
// Final state: '<p>a]b<span>\u200B[</span>cd</p>'
|
||||
});
|
||||
});
|
||||
it('should select a zws backwards (2)', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<span>\u200B</span>]cd[',
|
||||
contentBefore: '<p>ab<span>\u200B</span>]cd[</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowLeft', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab<span>]\u200B</span>cd[',
|
||||
// Final state: 'a]b<span>\u200B</span>cd['
|
||||
contentAfter: '<p>ab<span>]\u200B</span>cd[</p>',
|
||||
// Final state: '<p>a]b<span>\u200B</span>cd[</p>'
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<span>\u200B]</span>cd[',
|
||||
contentBefore: '<p>ab<span>\u200B]</span>cd[</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowLeft', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab<span>]\u200B</span>cd[',
|
||||
// Final state: 'a]b<span>\u200B</span>cd['
|
||||
contentAfter: '<p>ab<span>]\u200B</span>cd[</p>',
|
||||
// Final state: '<p>a]b<span>\u200B</span>cd[</p>'
|
||||
});
|
||||
});
|
||||
it('should select a zws backwards (3)', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<span>\u200B</span>]c[d',
|
||||
contentBefore: '<p>ab<span>\u200B</span>]c[d</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowLeft', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab<span>]\u200B</span>c[d',
|
||||
// Final state: 'a]b<span>\u200B</span>c[d'
|
||||
contentAfter: '<p>ab<span>]\u200B</span>c[d</p>',
|
||||
// Final state: '<p>a]b<span>\u200B</span>c[d</p>'
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<span>\u200B]</span>c[d',
|
||||
contentBefore: '<p>ab<span>\u200B]</span>c[d</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowLeft', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab<span>]\u200B</span>c[d',
|
||||
// Final state: 'a]b<span>\u200B</span>c[d'
|
||||
contentAfter: '<p>ab<span>]\u200B</span>c[d</p>',
|
||||
// Final state: '<p>a]b<span>\u200B</span>c[d</p>'
|
||||
});
|
||||
});
|
||||
it('should deselect a zws', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<span>[\u200B]</span>cd',
|
||||
contentBefore: '<p>ab<span>[\u200B]</span>cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowLeft', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab<span>[]\u200B</span>cd',
|
||||
// Final state: 'a]b<span>[\u200B</span>cd'
|
||||
contentAfter: '<p>ab<span>[]\u200B</span>cd</p>',
|
||||
// Final state: '<p>a]b<span>[\u200B</span>cd</p>'
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab<span>[\u200B</span>]cd',
|
||||
contentBefore: '<p>ab<span>[\u200B</span>]cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowLeft', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab<span>[]\u200B</span>cd',
|
||||
// Final state: 'a]b<span>[\u200B</span>cd'
|
||||
contentAfter: '<p>ab<span>[]\u200B</span>cd</p>',
|
||||
// Final state: '<p>a]b<span>[\u200B</span>cd</p>'
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab[<span>\u200B]</span>cd',
|
||||
contentBefore: '<p>ab[<span>\u200B]</span>cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowLeft', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab[<span>]\u200B</span>cd',
|
||||
// Final state: 'a]b[<span>\u200B</span>cd'
|
||||
contentAfter: '<p>ab[<span>]\u200B</span>cd</p>',
|
||||
// Final state: '<p>a]b[<span>\u200B</span>cd</p>'
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'ab[<span>\u200B</span>]cd',
|
||||
contentBefore: '<p>ab[<span>\u200B</span>]cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowLeft', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'ab[<span>]\u200B</span>cd',
|
||||
// Final state: 'a]b[<span>\u200B</span>cd'
|
||||
contentAfter: '<p>ab[<span>]\u200B</span>cd</p>',
|
||||
// Final state: '<p>a]b[<span>\u200B</span>cd</p>'
|
||||
});
|
||||
});
|
||||
it('should deselect a zws (2)', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'a[b<span>\u200B]</span>cd',
|
||||
contentBefore: '<p>a[b<span>\u200B]</span>cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowLeft', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'a[b<span>]\u200B</span>cd',
|
||||
// Final state: 'a[]b<span>\u200B</span>cd'
|
||||
contentAfter: '<p>a[b<span>]\u200B</span>cd</p>',
|
||||
// Final state: '<p>a[]b<span>\u200B</span>cd</p>'
|
||||
});
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'a[b<span>\u200B</span>]cd',
|
||||
contentBefore: '<p>a[b<span>\u200B</span>]cd</p>',
|
||||
stepFunction: async editor => {
|
||||
triggerEvent(editor.editable, 'keydown', { key: 'ArrowLeft', shiftKey: true });
|
||||
},
|
||||
contentAfter: 'a[b<span>]\u200B</span>cd',
|
||||
// Final state: 'a[]b<span>\u200B</span>cd'
|
||||
contentAfter: '<p>a[b<span>]\u200B</span>cd</p>',
|
||||
// Final state: '<p>a[]b<span>\u200B</span>cd</p>'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { BasicEditor, testEditor } from '../utils.js';
|
||||
|
||||
describe('insetHTML', () => {
|
||||
describe('insert HTML', () => {
|
||||
describe('collapsed selection', () => {
|
||||
it('should insert html in an empty paragraph', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
@@ -37,55 +37,55 @@ describe('insetHTML', () => {
|
||||
});
|
||||
it('should insert html in an empty editable', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '[]<br>',
|
||||
contentBefore: '<p>[]<br></p>',
|
||||
stepFunction: async editor => {
|
||||
await editor.execCommand('insertHTML', '<i class="fa fa-pastafarianism"></i>');
|
||||
},
|
||||
contentAfterEdit: '<i class="fa fa-pastafarianism" contenteditable="false">\u200b</i>[]<br>',
|
||||
contentAfter: '<i class="fa fa-pastafarianism"></i>[]<br>',
|
||||
contentAfterEdit: '<p><i class="fa fa-pastafarianism" contenteditable="false">\u200b</i>[]<br></p>',
|
||||
contentAfter: '<p><i class="fa fa-pastafarianism"></i>[]<br></p>',
|
||||
});
|
||||
});
|
||||
it('should insert html in between naked text in the editable', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'a[]b<br>',
|
||||
contentBefore: '<p>a[]b<br></p>',
|
||||
stepFunction: async editor => {
|
||||
await editor.execCommand('insertHTML', '<i class="fa fa-pastafarianism"></i>');
|
||||
},
|
||||
contentAfterEdit:
|
||||
'a<i class="fa fa-pastafarianism" contenteditable="false">\u200b</i>[]b<br>',
|
||||
contentAfter: 'a<i class="fa fa-pastafarianism"></i>[]b<br>',
|
||||
'<p>a<i class="fa fa-pastafarianism" contenteditable="false">\u200b</i>[]b<br></p>',
|
||||
contentAfter: '<p>a<i class="fa fa-pastafarianism"></i>[]b<br></p>',
|
||||
});
|
||||
});
|
||||
it('should insert several html nodes in between naked text in the editable', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'a[]e<br>',
|
||||
contentBefore: '<p>a[]e<br></p>',
|
||||
stepFunction: async editor => {
|
||||
await editor.execCommand('insertHTML', '<p>b</p><p>c</p><p>d</p>');
|
||||
},
|
||||
contentAfter: 'ab<p>c</p>d[]e<br>',
|
||||
contentAfter: '<p>ab</p><p>c</p><p>d[]e<br></p>',
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('not collapsed selection', () => {
|
||||
it('should delete selection and insert html in its place', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: '[a]<br>',
|
||||
contentBefore: '<p>[a]<br></p>',
|
||||
stepFunction: async editor => {
|
||||
await editor.execCommand('insertHTML', '<i class="fa fa-pastafarianism"></i>');
|
||||
},
|
||||
contentAfterEdit: '<i class="fa fa-pastafarianism" contenteditable="false">\u200b</i>[]<br>',
|
||||
contentAfter: '<i class="fa fa-pastafarianism"></i>[]<br>',
|
||||
contentAfterEdit: '<p><i class="fa fa-pastafarianism" contenteditable="false">\u200b</i>[]<br></p>',
|
||||
contentAfter: '<p><i class="fa fa-pastafarianism"></i>[]<br></p>',
|
||||
});
|
||||
});
|
||||
it('should delete selection and insert html in its place', async () => {
|
||||
it('should delete selection and insert html in its place (2)', async () => {
|
||||
await testEditor(BasicEditor, {
|
||||
contentBefore: 'a[b]c<br>',
|
||||
contentBefore: '<p>a[b]c<br></p>',
|
||||
stepFunction: async editor => {
|
||||
await editor.execCommand('insertHTML', '<i class="fa fa-pastafarianism"></i>');
|
||||
},
|
||||
contentAfterEdit:
|
||||
'a<i class="fa fa-pastafarianism" contenteditable="false">\u200b</i>[]c<br>',
|
||||
contentAfter: 'a<i class="fa fa-pastafarianism"></i>[]c<br>',
|
||||
'<p>a<i class="fa fa-pastafarianism" contenteditable="false">\u200b</i>[]c<br></p>',
|
||||
contentAfter: '<p>a<i class="fa fa-pastafarianism"></i>[]c<br></p>',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user