import { expect, test } from "@odoo/hoot"; import { deleteBackward, insertText } from "../_helpers/user_actions"; import { setupEditor, testEditor } from "../_helpers/editor"; import { descendants } from "@html_editor/utils/dom_traversal"; import { tick } from "@odoo/hoot-mock"; import { getContent, setSelection } from "../_helpers/selection"; import { cleanLinkArtifacts } from "../_helpers/format"; import { waitFor } from "@odoo/hoot-dom"; import { dispatchNormalize } from "../_helpers/dispatch"; test("should pad a link with ZWNBSPs and add visual indication", async () => { await testEditor({ contentBefore: '
abc
', contentBeforeEdit: 'a\ufeff\ufeffb\ufeff\ufeffc
', stepFunction: async (editor) => { setSelection({ anchorNode: editor.editable.querySelector("a"), anchorOffset: 1 }); await tick(); }, contentAfterEdit: 'a\ufeff\ufeff[]b\ufeff\ufeffc
', contentAfter: 'a[]bc
', }); }); test("should pad a link with ZWNBSPs and add visual indication (2)", async () => { await testEditor({ contentBefore: 'ab
', contentBeforeEdit: 'a\ufeff\ufeffb\ufeff\ufeff
', stepFunction: async (editor) => { setSelection({ anchorNode: editor.editable.querySelector("a span"), anchorOffset: 0 }); await tick(); }, contentAfterEdit: 'a\ufeff\ufeff[]b\ufeff\ufeff
', contentAfter: 'a[]b
', }); }); test("should keep link padded with ZWNBSPs after a delete", async () => { await testEditor({ contentBefore: 'ab[]c
', stepFunction: deleteBackward, contentAfterEdit: 'a\ufeff\ufeff[]\ufeff\ufeffc
', contentAfter: "a[]c
", }); }); test("should keep isolated link after a delete and typing", async () => { await testEditor({ contentBefore: 'ab[]c
', stepFunction: async (editor) => { deleteBackward(editor); await insertText(editor, "a"); await insertText(editor, "b"); await insertText(editor, "c"); }, contentAfter: 'aabc[]c
', }); }); test("should delete the content from the link when popover is active", async () => { const { editor, el } = await setupEditor(''); await waitFor(".o-we-linkpopover"); expect(".o-we-linkpopover").toHaveCount(1); deleteBackward(editor); deleteBackward(editor); deleteBackward(editor); const content = getContent(el); expect(content).toBe( '\ufeff\ufeff[]abc\ufeff\ufeff
' ); expect(cleanLinkArtifacts(content)).toBe(''); }); test("should zwnbsp-pad simple text link", async () => { const removeZwnbsp = (editor) => { for (const descendant of descendants(editor.editable)) { if (descendant.nodeType === Node.TEXT_NODE && descendant.textContent === "\ufeff") { descendant.remove(); } } }; await testEditor({ contentBefore: 'a[]bcd
', contentBeforeEdit: 'a[]\ufeff\ufeffbc\ufeff\ufeffd
', stepFunction: async (editor) => { removeZwnbsp(editor); const p = editor.editable.querySelector("p"); // set the selection via the parent setSelection({ anchorNode: p, anchorOffset: 1 }); // insert the zwnbsp again dispatchNormalize(editor); }, contentAfterEdit: 'a\ufeff[]\ufeffbc\ufeff\ufeffd
', }); await testEditor({ contentBefore: 'a[]bcd
', contentBeforeEdit: 'a\ufeff\ufeff[]bc\ufeff\ufeffd
', stepFunction: async (editor) => { removeZwnbsp(editor); const a = editor.editable.querySelector("a"); // set the selection via the parent setSelection({ anchorNode: a, anchorOffset: 0 }); await tick(); // insert the zwnbsp again dispatchNormalize(editor); }, contentAfterEdit: 'a\ufeff\ufeff[]bc\ufeff\ufeffd
', }); await testEditor({ contentBefore: 'ab[]d
', contentBeforeEdit: 'a\ufeff\ufeffb[]\ufeff\ufeffd
', stepFunction: async (editor) => { const a = editor.editable.querySelector("a"); // Insert an extra character as a text node so we can set // the selection between the characters while still // targetting their parent. a.appendChild(editor.document.createTextNode("c")); removeZwnbsp(editor); // set the selection via the parent setSelection({ anchorNode: a, anchorOffset: 1 }); await tick(); // insert the zwnbsp again dispatchNormalize(editor); }, contentAfterEdit: 'a\ufeff\ufeffb[]c\ufeff\ufeffd
', }); await testEditor({ contentBefore: 'abc[]d
', contentBeforeEdit: 'a\ufeff\ufeffbc[]\ufeff\ufeffd
', stepFunction: async (editor) => { removeZwnbsp(editor); const a = editor.editable.querySelector("a"); // set the selection via the parent setSelection({ anchorNode: a, anchorOffset: 1 }); await tick(); // insert the zwnbsp again dispatchNormalize(editor); }, contentAfterEdit: 'a\ufeff\ufeffbc[]\ufeff\ufeffd
', }); await testEditor({ contentBefore: 'abc[]d
', contentBeforeEdit: 'a\ufeff\ufeffbc\ufeff\ufeff[]d
', stepFunction: async (editor) => { removeZwnbsp(editor); const p = editor.editable.querySelector("p"); // set the selection via the parent setSelection({ anchorNode: p, anchorOffset: 2 }); await tick(); // insert the zwnbsp again dispatchNormalize(editor); }, contentAfterEdit: 'a\ufeff\ufeffbc\ufeff\ufeff[]d
', }); }); test("should not zwnbsp-pad nav-link", async () => { await testEditor({ contentBefore: 'a[]bc
', contentBeforeEdit: 'a[]bc
', }); }); test("should not zwnbsp-pad in nav", async () => { await testEditor({ contentBefore: '', contentBeforeEdit: '', }); }); test("should not zwnbsp-pad link with block fontawesome", async () => { await testEditor({ contentBefore: 'a[]b
', contentBeforeEdit: 'a[]\u200bb
', }); }); test("should not zwnbsp-pad link with image", async () => { await testEditor({ contentBefore: 'a[]b
a[]b
\ufeff\ufeffcontent\ufeff\ufeff
', stepFunction: async (editor) => { // Cursor before the FEFF text node setSelection({ anchorNode: editor.editable.querySelector("a"), anchorOffset: 0 }); await insertText(editor, "more "); }, contentAfterEdit: '\ufeff\ufeffmore []content\ufeff\ufeff
', contentAfter: '', }); }); test("should remove zwnbsp from middle of the link (2)", async () => { await testEditor({ contentBefore: '', contentBeforeEdit: '\ufeff\ufeffcontent\ufeff\ufeff
', stepFunction: async (editor) => { // Cursor inside the FEFF text node setSelection({ anchorNode: editor.editable.querySelector("a").firstChild, anchorOffset: 0, }); await insertText(editor, "more "); }, contentAfterEdit: '\ufeff\ufeffmore []content\ufeff\ufeff
', contentAfter: '', }); }); test("should zwnbps-pad links with .btn class", async () => { await testEditor({ contentBefore: '', contentBeforeEdit: '\ufeff\ufeffcontent\ufeff\ufeff
', }); }); test("should not add visual indication to a button", async () => { await testEditor({ contentBefore: '', contentBeforeEdit: '\ufeff\ufeffcontent\ufeff\ufeff
', }); });