import { describe, expect, test } from "@odoo/hoot"; import { animationFrame, tick } from "@odoo/hoot-mock"; import { setupEditor, testEditor } from "../_helpers/editor"; import { unformat } from "../_helpers/format"; import { bold, resetSize, setColor } from "../_helpers/user_actions"; import { getContent, setSelection } from "../_helpers/selection"; import { manuallyDispatchProgrammaticEvent, queryAll } from "@odoo/hoot-dom"; import { nodeSize } from "@html_editor/utils/position"; describe("custom selection", () => { test("should indicate selected cells with blue background", async () => { const { el } = await setupEditor( unformat(`
ab c[d e]f
`) ); expect(getContent(el)).toBe( unformat(`
ab c[d e]f
`) ); const overlayColorTDs = queryAll("table td").map( (td) => getComputedStyle(td)["box-shadow"] ); // Unselected cells should have the default background color, without any overlay expect(overlayColorTDs[0]).toBe("none"); // Selected cells should have a box-shadow color expect(overlayColorTDs[1]).not.toBe("none"); expect(overlayColorTDs[2]).not.toBe("none"); }); }); describe("select a full table on cross over", () => { describe("select", () => { test("should select some characters and a table", async () => { await testEditor({ contentBefore: "

a[bc

a]bcdef
", contentAfterEdit: "

a[bc

" + '' + '' + '' + '' + "
a]bcdef
", }); }); test("should select a table and some characters", async () => { await testEditor({ contentBefore: "
abcde[f

a]bc

", contentAfterEdit: '' + '' + '' + '
abcde[f

a]bc

', }); }); test("should select some characters, a table and some more characters", async () => { await testEditor({ contentBefore: "

a[bc

abcdef

a]bc

", contentAfterEdit: '

a[bc

' + '' + '' + '
abcdef

a]bc

', }); }); test("should select some characters, a table, some more characters and another table", async () => { await testEditor({ contentBefore: "

a[bc

abcdef

abc

a]bcdef
", contentAfterEdit: '

a[bc

' + '' + '' + '
abcdef
' + '

abc

' + '' + '' + '
a]bcdef
', }); }); test("should select some characters, a table, some more characters, another table and some more characters", async () => { await testEditor({ contentBefore: "

a[bc

abcdef

abc

abcdef

a]bc

", contentAfterEdit: '

a[bc

' + '' + '' + '
abcdef
' + '

abc

' + '' + '' + '
abcdef

a]bc

', }); }); }); describe("toggleFormat", () => { test("should apply bold to some characters and a table", async () => { await testEditor({ contentBefore: "

a[bc

" + "" + "" + "" + "
a]bcdef
", stepFunction: bold, contentAfterEdit: "

a[bc

" + '' + '' + '' + '' + "
abcdef]
", }); }); test("should apply bold to a table and some characters", async () => { await testEditor({ contentBefore: "" + "" + "" + "" + "
abcde[f

a]bc

", stepFunction: bold, contentAfterEdit: '' + '' + '' + '' + "
[abcdef
" + "

a]bc

", }); }); test("should apply bold to some characters, a table and some more characters", async () => { await testEditor({ contentBefore: "

a[bc

" + "" + "" + "" + "" + "
abcdef
" + "

a]bc

", stepFunction: bold, contentAfterEdit: "

a[bc

" + '' + '' + '' + '' + "
abcdef
" + "

a]bc

", }); }); test("should apply bold to some characters, a table, some more characters and another table", async () => { await testEditor({ contentBefore: "

a[bc

" + "" + "" + "" + "" + "
abcdef
" + "

abc

" + "" + "" + "" + "" + "
a]bcdef
", stepFunction: bold, contentAfterEdit: "

a[bc

" + '' + '' + '' + '' + "
abcdef
" + "

abc

" + '' + '' + '' + '' + "
abcdef]
", }); }); test("should apply bold to some characters, a table, some more characters, another table and some more characters", async () => { await testEditor({ contentBefore: "

a[bc

" + "" + "" + "" + "" + "
abcdef
" + "

abc

" + "" + "" + "" + "" + "
abcdef
" + "

a]bc

", stepFunction: bold, contentAfterEdit: "

a[bc

" + '' + '' + '' + '' + "
abcdef
" + "

abc

" + '' + '' + '' + '' + "
abcdef
" + "

a]bc

", }); }); }); describe("color", () => { test("should apply a color to some characters and a table", async () => { await testEditor({ contentBefore: unformat(`

a[bc

a]b cd ef
`), stepFunction: async editor => { // Table selection happens on selectionchange // event which is fired in the next tick. await tick(); setColor("aquamarine", "color")(editor); }, contentAfterEdit: unformat(`

a[bc

a]b cd ef
`), }); }); test("should apply a color to a table and some characters", async () => { await testEditor({ contentBefore: "" + "" + "" + "" + "
abcde[f

a]bc

", stepFunction: setColor("aquamarine", "color"), contentAfterEdit: unformat(`
ab cd e[f

a]bc

`), }); }); test("should apply a color to some characters, a table and some more characters", async () => { await testEditor({ contentBefore: "

a[bc

" + "" + "" + "" + "" + "
abcdef
" + "

a]bc

", stepFunction: setColor("aquamarine", "color"), contentAfterEdit: unformat(`

a[bc

ab cd ef

a]bc

`), }); }); test("should apply a color to some characters, a table, some more characters and another table", async () => { await testEditor({ contentBefore: "

a[bc

" + "" + "" + "" + "" + "
abcdef
" + "

abc

" + "" + "" + "" + "" + "
a]bcdef
", stepFunction: async (editor) => { // Table selection happens on selectionchange // event which is fired in the next tick. await tick(); setColor("aquamarine", "color")(editor); }, contentAfterEdit: unformat(`

a[bc

ab cd ef

abc

a]b cd ef
`), }); }); test("should apply a color to some characters, a table, some more characters, another table and some more characters", async () => { await testEditor({ contentBefore: "

a[bc

" + "" + "" + "" + "" + "
abcdef
" + "

abc

" + "" + "" + "" + "" + "
abcdef
" + "

a]bc

", stepFunction: setColor("aquamarine", "color"), contentAfterEdit: unformat(`

a[bc

ab cd ef

abc

ab cd ef

a]bc

`), }); }); }); }); describe("single cell selection", () => { test("should not select single cell via mouse movement if content is not fully selected", async () => { const content = unformat(`

abcd




`); const { el } = await setupEditor(content); const firstTd = el.querySelector("td"); const firstP = firstTd.firstElementChild; const textNode = firstP.firstChild; // Get bounding rect of selection range at the end of text. const range = document.createRange(); range.setStart(textNode, nodeSize(textNode)); range.setEnd(textNode, nodeSize(textNode)); const rangeRect = range.getBoundingClientRect(); // Simulate mousedown at the end of text. await manuallyDispatchProgrammaticEvent(firstP, "mousedown", { detail: 1, clientX: rangeRect.right, clientY: rangeRect.top, }); // Put cursor at the end of text. setSelection({ anchorNode: textNode, anchorOffset: nodeSize(textNode), }); await animationFrame(); // Simulate attempt to select single cell. manuallyDispatchProgrammaticEvent(firstP, "mousemove", { detail: 1, clientX: rangeRect.right, clientY: rangeRect.top, }); manuallyDispatchProgrammaticEvent(firstP, "mousemove", { detail: 1, clientX: rangeRect.right + 15, clientY: rangeRect.top, }); manuallyDispatchProgrammaticEvent(firstP, "mouseup", { detail: 1, clientX: rangeRect.right + 15, clientY: rangeRect.top, }); await animationFrame(); expect(firstTd).not.toHaveClass("o_selected_td"); }); }); describe("select columns on cross over", () => { describe("select", () => { test("should select two columns", async () => { await testEditor({ contentBefore: "
a[bc]def
", contentAfterEdit: '' + '' + '' + "" + "
a[bc]def
", }); }); test("should select a whole row", async () => { await testEditor({ contentBefore: "
a[bcde]f
abcdef
", contentAfterEdit: '' + '' + '' + '' + "
a[bcde]f
abcdef
", }); }); test("should select a whole column", async () => { await testEditor({ contentBefore: "" + "" + "" + "" + "
a[bcdef
abcdef
a]bcdef
", contentAfterEdit: '' + "" + '' + "" + "" + "" + "" + '' + "" + "" + "" + "" + '' + "" + "" + "" + "
a[bcdef
abcdef
a]bcdef
", }); }); test("should select from (0,0) to (1,1) in a 3x3 table", async () => { await testEditor({ contentBefore: "" + "" + "" + "" + "
a[bcdef
abc]def
abcdef
", contentAfterEdit: '' + "" + '' + '' + "" + "" + "" + '' + '' + "" + "" + "" + "" + "" + "" + "" + "
a[bcdef
abc]def
abcdef
", }); }); test("should select a whole table", async () => { await testEditor({ contentBefore: "" + "" + "" + "" + "
a[bcdef
abcdef
abcde]f
", contentAfterEdit: '' + "" + '' + '' + '' + "" + "" + '' + '' + '' + "" + "" + '' + '' + '' + "" + "
a[bcdef
abcdef
abcde]f
", }); }); }); describe("toggleFormat", () => { test("should apply bold to two columns", async () => { await testEditor({ contentBefore: "" + "" + "" + "" + "
a[bc]def
", stepFunction: bold, contentAfterEdit: '' + '' + '' + "" + "
[abcd]ef
", }); }); test("should apply bold to a whole row", async () => { await testEditor({ contentBefore: "" + "" + "" + "" + "
a[bcde]f
abcdef
", stepFunction: bold, contentAfterEdit: '' + '' + '' + '' + "
[abcdef]
abcdef
", }); }); test("should apply bold to a whole column", async () => { await testEditor({ contentBefore: "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
a[bcdef
abcdef
a]bcdef
", stepFunction: bold, contentAfterEdit: '' + "" + '' + "" + "" + "" + "" + '' + "" + "" + "" + "" + '' + "" + "" + "" + "
[abcdef
abcdef
ab]cdef
", }); }); test("should apply bold from (0,0) to (1,1) in a 3x3 table", async () => { await testEditor({ contentBefore: "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
a[bcdef
abc]def
abcdef
", stepFunction: bold, contentAfterEdit: '' + "" + '' + '' + "" + "" + "" + '' + '' + "" + "" + "" + "" + "" + "" + "" + "
[abcdef
abcd]ef
abcdef
", }); }); test("should apply bold to a whole table", async () => { await testEditor({ contentBefore: "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
a[bcdef
abcdef
abcde]f
", stepFunction: bold, contentAfterEdit: '' + "" + '' + '' + '' + "" + "" + '' + '' + '' + "" + "" + '' + '' + '' + "" + "
[abcdef
abcdef
abcdef]
", }); }); }); describe("reset size", () => { test("should remove any height or width of the table and bring it back to it original form", async () => { await testEditor({ contentBefore: `

[]












`, stepFunction: resetSize, contentAfter: `

[]












`, }); }); test("should remove any height or width of the table without loosing the style of the element inside it.", async () => { await testEditor({ contentBefore: `

[]TESTTEXT


  • test
  • test
  • test


TESTTEXT


codeTEST


  1. text
  2. text
  3. text
`, stepFunction: resetSize, contentAfter: `

[]TESTTEXT


  • test
  • test
  • test


TESTTEXT


codeTEST


  1. text
  2. text
  3. text
`, }); }); test("should remove any height or width of the table without removig the style of the table.", async () => { await testEditor({ contentBefore: `

[]









`, stepFunction: resetSize, contentAfter: `

[]









`, }); }); }); describe("color", () => { test("should apply a color to two columns", async () => { await testEditor({ contentBefore: "" + "" + "" + "" + "
a[bc]def
", stepFunction: setColor("aquamarine", "color"), contentAfterEdit: unformat(`
a[b c]d ef
`), }); }); test("should apply a color to a whole row", async () => { await testEditor({ contentBefore: "" + "" + "" + "" + "
a[bcde]f
abcdef
", stepFunction: setColor("aquamarine", "color"), contentAfterEdit: unformat(`
a[b cd e]f
ab cd ef
`), }); }); test("should apply a color to a whole column", async () => { await testEditor({ contentBefore: "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
a[bcdef
abcdef
a]bcdef
", stepFunction: setColor("aquamarine", "color"), contentAfterEdit: unformat(`
a[b cd ef
ab cd ef
a]b cd ef
`), }); }); test("should apply a color from (0,0) to (1,1) in a 3x3 table", async () => { await testEditor({ contentBefore: "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
a[bcdef
abc]def
abcdef
", stepFunction: setColor("aquamarine", "color"), contentAfterEdit: unformat(`
a[b cd ef
ab c]d ef
ab cd ef
`), }); }); test("should apply a color to a whole table", async () => { await testEditor({ contentBefore: "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
a[bcdef
abcdef
abcde]f
", stepFunction: setColor("aquamarine", "color"), contentAfterEdit: unformat(`
a[b cd ef
ab cd ef
ab cd e]f
`), }); }); }); });