import { CTYPES } from "@html_editor/utils/content_types"; import { enforceWhitespace, getState, restoreState } from "@html_editor/utils/dom_state"; import { DIRECTIONS } from "@html_editor/utils/position"; import { describe, expect, test } from "@odoo/hoot"; import { setupEditor } from "../_helpers/editor"; import { splitTextNode } from "@html_editor/utils/dom"; describe("getState", () => { test("should recognize invisible space to the right", async () => { // We'll be looking to the right while standing at `a[] `. const { el } = await setupEditor("
a
"); const p = el.firstChild; splitTextNode(p.firstChild, 1); // "a"" " expect(p.childNodes.length).toBe(2); const position = [p, 1]; // `"a"[]" "
` expect(getState(...position, DIRECTIONS.RIGHT)).toEqual({ // We look to the right of "a" (`a[] `): node: p.firstChild, // "a" direction: DIRECTIONS.RIGHT, // The browser strips the space away so we ignore it and see // ``: the closing tag from the inside. cType: CTYPES.BLOCK_INSIDE, }); }); test("should recognize invisible space to the right (among consecutive space within content)", async () => { // We'll be looking to the right while standing at `a [] `. The // first space is visible, the rest isn't. const { el } = await setupEditor("a b
"); const p = el.firstChild; splitTextNode(p.firstChild, 2); // "a "" b" expect(p.childNodes.length).toBe(2); const position = [p, 1]; // `"a "[]" b"
` expect(getState(...position, DIRECTIONS.RIGHT)).toEqual({ // We look to the right of "a " (`a []`): node: p.firstChild, // "a " direction: DIRECTIONS.RIGHT, // The browser strips the space away so we ignore it and see // "b": visible content. cType: CTYPES.CONTENT, }); }); test("should recognize visible space to the left (followed by consecutive space within content)", async () => { // We'll be looking to the left while standing at `[] b`. The // first space is visible, the rest isn't. const { el } = await setupEditor("a b
"); const p = el.firstChild; splitTextNode(p.firstChild, 2); // "a "" b" expect(p.childNodes.length).toBe(2); const position = [p, 1]; // `"a "[]" b"
` expect(getState(...position, DIRECTIONS.LEFT)).toEqual({ // We look to the left of " b" (`[] b`): node: p.lastChild, // "a" direction: DIRECTIONS.LEFT, // Left of " b" we see visible space that we should // preserve. cType: CTYPES.SPACE, }); }); test("should recognize invisible space to the left (nothing after)", async () => { // We'll be looking to the left while standing at ` [] `. const { el } = await setupEditor(""); const p = el.firstChild; p.append(document.createTextNode("")); // " """ expect(getState(p, 1, DIRECTIONS.LEFT)).toEqual({ // We look to the left of " " (` []`): node: p.lastChild, // "" direction: DIRECTIONS.LEFT, // The browser strips the space away so we ignore it and see // `
`: the opening tag from the inside. cType: CTYPES.BLOCK_INSIDE, }); }); test("should recognize invisible space to the left (more space after)", async () => { // We'll be looking to the left while standing at ` [] `. const { el } = await setupEditor("
"); const p = el.firstChild; splitTextNode(p.firstChild, 1); // " "" " expect(getState(p, 1, DIRECTIONS.LEFT)).toEqual({ // We look to the left of " " (` [] `): node: p.lastChild, // " ". direction: DIRECTIONS.LEFT, // The browser strips the space away so we ignore it and see // `
`: the opening tag from the inside. cType: CTYPES.BLOCK_INSIDE, }); }); test("should recognize invisible space to the left (br after)", async () => { // We'll be looking to the left while standing at ` [] `. const { el } = await setupEditor("
`: the opening tag from the inside. cType: CTYPES.BLOCK_INSIDE, }); }); }); describe("restoreState", () => { test("should restore invisible space to the left (looking right)", async () => { // We'll be restoring the state of "a []" in `
a
`. const { el } = await setupEditor("a b
"); const p = el.firstChild; splitTextNode(p.firstChild, 2); // "a ""b" const rule = restoreState({ // We look to the right of "a " (`a []b`) to see if we need // to preserve the space at the end of "a ": node: p.firstChild, // "a " direction: DIRECTIONS.RIGHT, // The DOM used to be `a
` so to the right of "a " we // used to see ``: the closing tag from the inside. cType: CTYPES.BLOCK_INSIDE, }); // Now looking to the right of "a " we see "b", which is content // and makes the formerly invisible space visible. We should get // back a rule that will enforce the invisibility of the space. expect(rule.spaceVisibility).not.toBe(true); }); test("should restore visible space to the left (looking right) (among consecutive space within content)", async () => { // We'll be restoring the state of "a []" in `a b
`. // The first space is visible, the rest isn't. const { el } = await setupEditor("a
"); const p = el.firstChild; splitTextNode(p.firstChild, 2); // "a "" " const rule = restoreState({ // We look to the right of "a " (`a []`) to see if we need // to preserve the space at the end of "a ": node: p.firstChild, // "a " direction: DIRECTIONS.RIGHT, // The DOM used to be `a b
` so to the right of "a " we // used to see "b" which is visible content. cType: CTYPES.CONTENT, }); // Now looking to the right of "a " we see ``: the closing // tag, from the inside. This makes the formerly visible space // invisible. We should get back a rule that will enforce the // visibility of the space. expect(rule.spaceVisibility).toBe(true); }); test("should restore visible space to the right (looking left) (followed by consecutive space within content)", async () => { // We'll be restoring the state of "[] b" in `a b
`. // The first space is visible, the rest isn't. const { el } = await setupEditor("a
"); const p = el.firstChild; splitTextNode(p.firstChild, 2); // "a "" " const rule = restoreState({ // We look to the left of " " (`[] `) to see if we need // to preserve the space of " ": node: p.lastChild, // " " direction: DIRECTIONS.LEFT, // The DOM used to be `a b
` so to the left of " b" we // used to see " " which is visible space. cType: CTYPES.SPACE, }); // Now looking to the left of " " we see " " which is now // invisible. This means the space we're examining is also still // invisible. Since it should be invisible, we should get back a // rule that will enforce the invisibility of the space (but no // rule would work as well). expect(rule.spaceVisibility).not.toBe(true); }); test("should restore invisible space to the right (looking left) (nothing after)", async () => { // We'll be restoring the state of " []" in ``. const { el } = await setupEditor("
a
"); const p = el.firstChild; splitTextNode(p.firstChild, 1); // "a"" " const rule = restoreState({ // We look to the left of " " (`a[] `) to see if we need // to preserve the space of " ": node: p.lastChild, // " " direction: DIRECTIONS.LEFT, // The DOM used to be `` so to the left of " " we // used to see `
`: the opening tag from the inside. cType: CTYPES.BLOCK_INSIDE, }); // Now looking to the left of " " we see "a", which is content // but since it's to the left of our space it has no incidence // on its visibility. Either way it should be invisible so we // should get back a rule that will enforce the invisibility of // the space (but no rule would work as well). expect(rule.spaceVisibility).not.toBe(true); }); test("should restore invisible space to the right (looking left) (more space after)", async () => { // We'll be restoring the state of " [] " in `
`. const { el } = await setupEditor("
a
"); const p = el.firstChild; splitTextNode(p.firstChild, 2); // "a "" " const rule = restoreState({ // We look to the left of " " (`a [] `) to see if we need // to preserve the space of " ": node: p.lastChild, // " " direction: DIRECTIONS.LEFT, // The DOM used to be `` so to the left of " " // we used to see `
`: the opening tag from the inside.
cType: CTYPES.BLOCK_INSIDE,
});
// Now looking to the left of " " we see "a", which is content
// but since it's to the left of our space it has no incidence
// on its visibility. Either way it should be invisible so we
// should get back a rule that will enforce the invisibility of
// the space (but no rule would work as well).
expect(rule.spaceVisibility).not.toBe(true);
});
test("should restore invisible space to the right (looking left) (br after)", async () => {
// We'll be restoring the state of " []
" in `
[]
a
`: the opening tag from the
// inside.
cType: CTYPES.BLOCK_INSIDE,
});
// Now looking to the left of `
` we see "a", which is
// content but since it's to the left of our space it has no
// incidence on its visibility. Either way it should be
// invisible so we should get back a rule that will enforce the
// invisibility of the space (but no rule would work as well).
expect(rule.spaceVisibility).not.toBe(true);
});
});
describe("enforceWhitespace", () => {
test("should enforce invisible space to the left", async () => {
// We'll be making the space between "a" and "b" invisible.
const { el } = await setupEditor("
a b
"); const p = el.firstChild; splitTextNode(p.firstChild, 2); // "a ""b" // We look to the left while standing at "a []": enforceWhitespace(p, 1, DIRECTIONS.LEFT, { spaceVisibility: false }); expect(p.innerHTML).toBe("ab"); }); test("should restore visible space to the left (among consecutive space within content)", async () => { // We'll be making the first space after "a" visible. const { el } = await setupEditor("a
"); const p = el.firstChild; splitTextNode(p.firstChild, 2); // "a "" " // We look to the left while standing at "a []": enforceWhitespace(p, 1, DIRECTIONS.LEFT, { spaceVisibility: true }); expect(p.innerHTML).toBe("a "); }); test("should not enforce already invisible space to the right (followed by consecutive space within content)", async () => { // We'll be keeping the last (invisible) space after "a" (we // could remove it but we don't need to - mostly we should not // make it visible). const { el } = await setupEditor("a
"); const p = el.firstChild; splitTextNode(p.firstChild, 2); // "a "" " // We look to the left while standing at "a []": enforceWhitespace(p, 0, DIRECTIONS.RIGHT, { spaceVisibility: false }); expect(p.innerHTML).toBe("a "); }); test("should not enforce already invisible space to the right (nothing after)", async () => { // We'll be keeping the invisible space after "a" (we could // remove it but we don't need to - mostly we should not make it // visible). const { el } = await setupEditor("a
"); const p = el.firstChild; splitTextNode(p.firstChild, 1); // "a"" " // We look to the right while standing at "a[]": enforceWhitespace(p, 0, DIRECTIONS.RIGHT, { spaceVisibility: false }); expect(p.innerHTML).toBe("a "); }); test("should not enforce already invisible space to the left (more space after)", async () => { // We'll be keeping the invisible space after "a" (we could // remove it but we don't need to - mostly we should not make it // visible). const { el } = await setupEditor("a
"); const p = el.firstChild; splitTextNode(p.firstChild, 1); // "a"" " // We look to the right while standing at "a[]": enforceWhitespace(p, 0, DIRECTIONS.RIGHT, { spaceVisibility: false }); expect(p.innerHTML).toBe("a "); }); test("should not enforce already invisible space to the left (br after)", async () => { // We'll be keeping the invisible space after "a" (we could // remove it but we don't need to - mostly we should not make it // visible). const { el } = await setupEditor("a