mirror of
https://github.com/bringout/oca-ocb-web.git
synced 2026-04-19 03:52:05 +02:00
replace stale web_editor with html_editor and html_builder for 19.0
web_editor was removed in Odoo 19.0 and replaced by html_editor
and html_builder. The old web_editor was incorrectly included in
the 19.0 vanilla import.
🤖 assisted by claude
This commit is contained in:
parent
4b94f0abc5
commit
f866779561
1513 changed files with 396049 additions and 358525 deletions
|
|
@ -0,0 +1,283 @@
|
|||
import { expect, test } from "@odoo/hoot";
|
||||
import { animationFrame } from "@odoo/hoot-mock";
|
||||
import { setupEditor } from "../_helpers/editor";
|
||||
import { getContent } from "../_helpers/selection";
|
||||
import { insertText } from "../_helpers/user_actions";
|
||||
import { unformat } from "../_helpers/format";
|
||||
import { press, waitFor, queryOne } from "@odoo/hoot-dom";
|
||||
import { expectElementCount } from "../_helpers/ui_expectations";
|
||||
|
||||
function expectContentToBe(el, html) {
|
||||
expect(getContent(el)).toBe(unformat(html));
|
||||
}
|
||||
|
||||
test.tags("desktop");
|
||||
test("can add a table using the powerbox and keyboard", async () => {
|
||||
const { el, editor } = await setupEditor("<p>a[]</p>");
|
||||
await expectElementCount(".o-we-powerbox", 0);
|
||||
expectContentToBe(el, `<p>a[]</p>`);
|
||||
|
||||
// open powerbox
|
||||
await insertText(editor, "/");
|
||||
await waitFor(".o-we-powerbox");
|
||||
await expectElementCount(".o-we-tablepicker", 0);
|
||||
|
||||
// filter to get table command in first position
|
||||
await insertText(editor, "table");
|
||||
await animationFrame();
|
||||
|
||||
// press enter to open tablepicker
|
||||
await press("Enter");
|
||||
await waitFor(".o-we-tablepicker");
|
||||
await expectElementCount(".o-we-powerbox", 0);
|
||||
|
||||
// press enter to validate current dimension (3x3)
|
||||
await press("Enter");
|
||||
await animationFrame();
|
||||
await expectElementCount(".o-we-powerbox", 0);
|
||||
await expectElementCount(".o-we-tablepicker", 0);
|
||||
expectContentToBe(
|
||||
el,
|
||||
`<p>a</p>
|
||||
<table class="table table-bordered o_table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p o-we-hint-text='Type "/" for commands' class="o-we-hint">[]<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>
|
||||
<tr>
|
||||
<td><p><br></p></td>
|
||||
<td><p><br></p></td>
|
||||
<td><p><br></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><br></p>`
|
||||
);
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test("can close table picker with escape", async () => {
|
||||
const { el, editor } = await setupEditor("<p>a[]</p>");
|
||||
await insertText(editor, "/");
|
||||
await waitFor(".o-we-powerbox");
|
||||
await insertText(editor, "table");
|
||||
expectContentToBe(el, "<p>a/table[]</p>");
|
||||
await animationFrame();
|
||||
await press("Enter");
|
||||
await expectElementCount(".o-we-tablepicker", 1);
|
||||
expectContentToBe(el, "<p>a[]</p>");
|
||||
await press("escape");
|
||||
await animationFrame();
|
||||
await expectElementCount(".o-we-tablepicker", 0);
|
||||
});
|
||||
|
||||
test.tags("iframe", "desktop");
|
||||
test("in iframe, can add a table using the powerbox and keyboard", async () => {
|
||||
const { el, editor } = await setupEditor("<p>a[]</p>", {
|
||||
props: { iframe: true },
|
||||
});
|
||||
await expectElementCount(".o-we-powerbox", 0);
|
||||
expect(getContent(el)).toBe(`<p>a[]</p>`);
|
||||
expect(":iframe .o_table").toHaveCount(0);
|
||||
|
||||
// open powerbox
|
||||
await insertText(editor, "/");
|
||||
await waitFor(".o-we-powerbox");
|
||||
await expectElementCount(".o-we-tablepicker", 0);
|
||||
|
||||
// filter to get table command in first position
|
||||
await insertText(editor, "table");
|
||||
await animationFrame();
|
||||
|
||||
// press enter to open tablepicker
|
||||
await press("Enter");
|
||||
await waitFor(".o-we-tablepicker");
|
||||
await expectElementCount(".o-we-powerbox", 0);
|
||||
|
||||
// press enter to validate current dimension (3x3)
|
||||
await press("Enter");
|
||||
await animationFrame();
|
||||
await expectElementCount(".o-we-powerbox", 0);
|
||||
await expectElementCount(".o-we-tablepicker", 0);
|
||||
expect(":iframe .o_table").toHaveCount(1);
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test("Expand columns in the correct direction in 'rtl'", async () => {
|
||||
const { editor } = await setupEditor("<p>a[]</p>", {
|
||||
config: {
|
||||
direction: "rtl",
|
||||
},
|
||||
});
|
||||
await insertText(editor, "/table");
|
||||
await press("Enter");
|
||||
await waitFor(".o-we-tablepicker");
|
||||
|
||||
// Initially we have 3 columns
|
||||
const tablePickerOverlay = queryOne(".overlay");
|
||||
expect(tablePickerOverlay).toHaveStyle({ right: /px$/ });
|
||||
const right = tablePickerOverlay.style.right;
|
||||
const width3Columns = tablePickerOverlay.getBoundingClientRect().width;
|
||||
expect(".o-we-cell.active").toHaveCount(9);
|
||||
|
||||
// Add one column -> we have 4 columns
|
||||
await press("ArrowLeft");
|
||||
await animationFrame();
|
||||
expect(tablePickerOverlay.getBoundingClientRect().width).toBeGreaterThan(width3Columns);
|
||||
expect(tablePickerOverlay).toHaveStyle({ right });
|
||||
expect(".o-we-cell.active").toHaveCount(12);
|
||||
|
||||
// Remove one column -> we have 3 columns
|
||||
await press("ArrowRight");
|
||||
await animationFrame();
|
||||
expect(".o-we-cell.active").toHaveCount(9);
|
||||
expect(tablePickerOverlay).toHaveStyle({ right });
|
||||
|
||||
// Remove one column -> we have 2 columns
|
||||
await press("ArrowRight");
|
||||
await animationFrame();
|
||||
expect(tablePickerOverlay.getBoundingClientRect().width).toBeLessThan(width3Columns);
|
||||
expect(tablePickerOverlay).toHaveStyle({ right });
|
||||
expect(".o-we-cell.active").toHaveCount(6);
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test("add table inside empty list", async () => {
|
||||
const { el, editor } = await setupEditor("<ul><li>[]<br></li></ul>");
|
||||
|
||||
// open powerbox
|
||||
await insertText(editor, "/");
|
||||
await waitFor(".o-we-powerbox");
|
||||
await expectElementCount(".o-we-tablepicker", 0);
|
||||
|
||||
// filter to get table command in first position
|
||||
await insertText(editor, "table");
|
||||
await animationFrame();
|
||||
|
||||
// press enter to open tablepicker
|
||||
await press("Enter");
|
||||
await waitFor(".o-we-tablepicker");
|
||||
await expectElementCount(".o-we-powerbox", 0);
|
||||
|
||||
// press enter to validate current dimension (3x3)
|
||||
await press("Enter");
|
||||
await animationFrame();
|
||||
await expectElementCount(".o-we-powerbox", 0);
|
||||
await expectElementCount(".o-we-tablepicker", 0);
|
||||
expectContentToBe(
|
||||
el,
|
||||
`<ul>
|
||||
<li>
|
||||
<br>
|
||||
<table class="table table-bordered o_table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p o-we-hint-text='Type "/" for commands' class="o-we-hint">[]<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>
|
||||
<tr>
|
||||
<td><p><br></p></td>
|
||||
<td><p><br></p></td>
|
||||
<td><p><br></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
</li>
|
||||
</ul>`
|
||||
);
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test("add table inside non-empty list", async () => {
|
||||
const { el, editor } = await setupEditor("<ul><li>abc[]</li></ul>");
|
||||
|
||||
// open powerbox
|
||||
await insertText(editor, "/");
|
||||
await waitFor(".o-we-powerbox");
|
||||
await expectElementCount(".o-we-tablepicker", 0);
|
||||
|
||||
// filter to get table command in first position
|
||||
await insertText(editor, "table");
|
||||
await animationFrame();
|
||||
|
||||
// press enter to open tablepicker
|
||||
await press("Enter");
|
||||
await waitFor(".o-we-tablepicker");
|
||||
await expectElementCount(".o-we-powerbox", 0);
|
||||
|
||||
// press enter to validate current dimension (3x3)
|
||||
await press("Enter");
|
||||
await animationFrame();
|
||||
await expectElementCount(".o-we-powerbox", 0);
|
||||
await expectElementCount(".o-we-tablepicker", 0);
|
||||
expectContentToBe(
|
||||
el,
|
||||
`<ul>
|
||||
<li>
|
||||
abc
|
||||
<table class="table table-bordered o_table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p o-we-hint-text='Type "/" for commands' class="o-we-hint">[]<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>
|
||||
<tr>
|
||||
<td><p><br></p></td>
|
||||
<td><p><br></p></td>
|
||||
<td><p><br></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
</li>
|
||||
</ul>`
|
||||
);
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test("should close the table picker when any key except arrow keys pressed", async () => {
|
||||
const { el, editor } = await setupEditor("<p>a[]</p>");
|
||||
await insertText(editor, "/");
|
||||
await waitFor(".o-we-powerbox");
|
||||
await insertText(editor, "table");
|
||||
expectContentToBe(el, "<p>a/table[]</p>");
|
||||
await animationFrame();
|
||||
await press("Enter");
|
||||
await expectElementCount(".o-we-tablepicker", 1);
|
||||
expectContentToBe(el, "<p>a[]</p>");
|
||||
await insertText(editor, "b");
|
||||
await animationFrame();
|
||||
await expectElementCount(".o-we-tablepicker", 0);
|
||||
expectContentToBe(el, "<p>ab[]</p>");
|
||||
await insertText(editor, "/");
|
||||
await waitFor(".o-we-powerbox");
|
||||
await insertText(editor, "table");
|
||||
expectContentToBe(el, "<p>ab/table[]</p>");
|
||||
await animationFrame();
|
||||
await press("Enter");
|
||||
await expectElementCount(".o-we-tablepicker", 1);
|
||||
expectContentToBe(el, "<p>ab[]</p>");
|
||||
await insertText(editor, "/");
|
||||
await animationFrame();
|
||||
await expectElementCount(".o-we-tablepicker", 0);
|
||||
});
|
||||
|
|
@ -0,0 +1,756 @@
|
|||
import { findInSelection } from "@html_editor/utils/selection";
|
||||
import { describe, expect, test } from "@odoo/hoot";
|
||||
import { press } from "@odoo/hoot-dom";
|
||||
import { setupEditor, testEditor } from "../_helpers/editor";
|
||||
import { unformat } from "../_helpers/format";
|
||||
import { undo } from "../_helpers/user_actions";
|
||||
import { getContent } from "../_helpers/selection";
|
||||
|
||||
function addRow(position) {
|
||||
return (editor) => {
|
||||
const selection = editor.shared.selection.getEditableSelection();
|
||||
editor.shared.table.addRow(position, findInSelection(selection, "tr"));
|
||||
};
|
||||
}
|
||||
|
||||
function addColumn(position) {
|
||||
return (editor) => {
|
||||
const selection = editor.shared.selection.getEditableSelection();
|
||||
editor.shared.table.addColumn(position, findInSelection(selection, "td, th"));
|
||||
};
|
||||
}
|
||||
|
||||
function turnIntoHeader(row) {
|
||||
return (editor) => {
|
||||
if (!row) {
|
||||
const selection = editor.shared.selection.getEditableSelection();
|
||||
row = findInSelection(selection, "tr");
|
||||
}
|
||||
editor.shared.table.turnIntoHeader(row);
|
||||
};
|
||||
}
|
||||
|
||||
function turnIntoRow(row) {
|
||||
return (editor) => {
|
||||
if (!row) {
|
||||
const selection = editor.shared.selection.getEditableSelection();
|
||||
row = findInSelection(selection, "tr");
|
||||
}
|
||||
editor.shared.table.turnIntoRow(row);
|
||||
};
|
||||
}
|
||||
|
||||
function moveRow(position, row) {
|
||||
return (editor) => {
|
||||
if (!row) {
|
||||
const selection = editor.shared.selection.getEditableSelection();
|
||||
row = findInSelection(selection, "tr");
|
||||
}
|
||||
editor.shared.table.moveRow(position, row);
|
||||
};
|
||||
}
|
||||
|
||||
function removeRow(row) {
|
||||
return (editor) => {
|
||||
if (!row) {
|
||||
const selection = editor.shared.selection.getEditableSelection();
|
||||
row = findInSelection(selection, "tr");
|
||||
}
|
||||
editor.shared.table.removeRow(row);
|
||||
};
|
||||
}
|
||||
|
||||
function removeColumn(cell) {
|
||||
return (editor) => {
|
||||
if (!cell) {
|
||||
const selection = editor.shared.selection.getEditableSelection();
|
||||
cell = findInSelection(selection, "td");
|
||||
}
|
||||
editor.shared.table.removeColumn(cell);
|
||||
};
|
||||
}
|
||||
|
||||
describe("row", () => {
|
||||
describe("convert", () => {
|
||||
test("should convert the first row to table header", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr style="height: 20px;">
|
||||
<td style="width: 20px;">ab[]</td>
|
||||
<td style="width: 25px;">cd</td>
|
||||
<td style="width: 30px;">ef</td>
|
||||
</tr>
|
||||
<tr style="height: 30px;">
|
||||
<td>ab</td>
|
||||
<td>cd</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: turnIntoHeader(),
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr style="height: 20px;">
|
||||
<th class="o_table_header" style="width: 20px;">ab[]</th>
|
||||
<th class="o_table_header" style="width: 25px;">cd</th>
|
||||
<th class="o_table_header" style="width: 30px;">ef</th>
|
||||
</tr>
|
||||
<tr style="height: 30px;">
|
||||
<td>ab</td>
|
||||
<td>cd</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
|
||||
test("should convert table header to normal row", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr style="height: 20px;">
|
||||
<td style="width: 20px;">ab[]</td>
|
||||
<td style="width: 25px;">cd</td>
|
||||
<td style="width: 30px;">ef</td>
|
||||
</tr>
|
||||
<tr style="height: 30px;">
|
||||
<td>ab</td>
|
||||
<td>cd</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: turnIntoRow(),
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr style="height: 20px;">
|
||||
<td style="width: 20px;">ab[]</td>
|
||||
<td style="width: 25px;">cd</td>
|
||||
<td style="width: 30px;">ef</td>
|
||||
</tr>
|
||||
<tr style="height: 30px;">
|
||||
<td>ab</td>
|
||||
<td>cd</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("above", () => {
|
||||
test("should add a row above the top row", async () => {
|
||||
await testEditor({
|
||||
contentBefore:
|
||||
'<table><tbody><tr style="height: 20px;">' +
|
||||
'<td style="width: 20px;">ab</td>' +
|
||||
'<td style="width: 25px;">cd</td>' +
|
||||
'<td style="width: 30px;">ef[]</td>' +
|
||||
"</tr></tbody></table>",
|
||||
stepFunction: addRow("before"),
|
||||
contentAfter:
|
||||
'<table><tbody><tr style="height: 20px;">' +
|
||||
'<td style="width: 20px;"><p><br></p></td>' +
|
||||
'<td style="width: 25px;"><p><br></p></td>' +
|
||||
'<td style="width: 30px;"><p><br></p></td>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 20px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td>ef[]</td>" +
|
||||
"</tr></tbody></table>",
|
||||
});
|
||||
});
|
||||
|
||||
test("should add a row above the middle row", async () => {
|
||||
await testEditor({
|
||||
contentBefore:
|
||||
'<table><tbody><tr style="height: 20px;">' +
|
||||
'<td style="width: 20px;">ab</td>' +
|
||||
'<td style="width: 25px;">cd</td>' +
|
||||
'<td style="width: 30px;">ef</td>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td>ef[]</td>" +
|
||||
"</tr></tbody></table>",
|
||||
stepFunction: addRow("before"),
|
||||
contentAfter:
|
||||
'<table><tbody><tr style="height: 20px;">' +
|
||||
'<td style="width: 20px;">ab</td>' +
|
||||
'<td style="width: 25px;">cd</td>' +
|
||||
'<td style="width: 30px;">ef</td>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td><p><br></p></td>" +
|
||||
"<td><p><br></p></td>" +
|
||||
"<td><p><br></p></td>" +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td>ef[]</td>" +
|
||||
"</tr></tbody></table>",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("below", () => {
|
||||
test("should add a row below the bottom row", async () => {
|
||||
await testEditor({
|
||||
contentBefore:
|
||||
'<table><tbody><tr style="height: 20px;">' +
|
||||
'<td style="width: 20px;">ab</td>' +
|
||||
'<td style="width: 25px;">cd</td>' +
|
||||
'<td style="width: 30px;">ef[]</td>' +
|
||||
"</tr></tbody></table>",
|
||||
stepFunction: addRow("after"),
|
||||
contentAfter:
|
||||
'<table><tbody><tr style="height: 20px;">' +
|
||||
'<td style="width: 20px;">ab</td>' +
|
||||
'<td style="width: 25px;">cd</td>' +
|
||||
'<td style="width: 30px;">ef[]</td>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 20px;">' +
|
||||
"<td><p><br></p></td>" +
|
||||
"<td><p><br></p></td>" +
|
||||
"<td><p><br></p></td>" +
|
||||
"</tr></tbody></table>",
|
||||
});
|
||||
});
|
||||
|
||||
test("should add a row below the middle row", async () => {
|
||||
await testEditor({
|
||||
contentBefore:
|
||||
'<table><tbody><tr style="height: 20px;">' +
|
||||
'<td style="width: 20px;">ab</td>' +
|
||||
'<td style="width: 25px;">cd</td>' +
|
||||
'<td style="width: 30px;">ef[]</td>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr></tbody></table>",
|
||||
stepFunction: addRow("after"),
|
||||
contentAfter:
|
||||
'<table><tbody><tr style="height: 20px;">' +
|
||||
'<td style="width: 20px;">ab</td>' +
|
||||
'<td style="width: 25px;">cd</td>' +
|
||||
'<td style="width: 30px;">ef[]</td>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 20px;">' +
|
||||
"<td><p><br></p></td>" +
|
||||
"<td><p><br></p></td>" +
|
||||
"<td><p><br></p></td>" +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr></tbody></table>",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("move", () => {
|
||||
test("should move header row down and convert it to normal row", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr style="height: 20px;">
|
||||
<th class="o_table_header" style="width: 20px;">ab[]</th>
|
||||
<th class="o_table_header" style="width: 25px;">cd</th>
|
||||
<th class="o_table_header" style="width: 30px;">ef</th>
|
||||
</tr>
|
||||
<tr style="height: 30px;">
|
||||
<td>gh</td>
|
||||
<td>ij</td>
|
||||
<td>kl</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: moveRow("down"),
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr style="height: 30px;">
|
||||
<th class="o_table_header" style="width: 20px;">gh</th>
|
||||
<th class="o_table_header" style="width: 25px;">ij</th>
|
||||
<th class="o_table_header" style="width: 30px;">kl</th>
|
||||
</tr>
|
||||
<tr style="height: 20px;">
|
||||
<td style="width: 20px;">ab[]</td>
|
||||
<td style="width: 25px;">cd</td>
|
||||
<td style="width: 30px;">ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
|
||||
test("should move second row up and convert it to header row", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr style="height: 20px;">
|
||||
<th class="o_table_header" style="width: 20px;">ab</th>
|
||||
<th class="o_table_header" style="width: 25px;">cd</th>
|
||||
<th class="o_table_header" style="width: 30px;">ef</th>
|
||||
</tr>
|
||||
<tr style="height: 30px;">
|
||||
<td>gh</td>
|
||||
<td>ij</td>
|
||||
<td>kl[]</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: moveRow("up"),
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr style="height: 30px;">
|
||||
<th class="o_table_header" style="width: 20px;">gh</th>
|
||||
<th class="o_table_header" style="width: 25px;">ij</th>
|
||||
<th class="o_table_header" style="width: 30px;">kl[]</th>
|
||||
</tr>
|
||||
<tr style="height: 20px;">
|
||||
<td style="width: 20px;">ab</td>
|
||||
<td style="width: 25px;">cd</td>
|
||||
<td style="width: 30px;">ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("removal", () => {
|
||||
test("should remove a row based on selection", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[]ab</td> <td>cd</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ef</td> <td>gh</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: removeRow(),
|
||||
// @todo @phoenix: consider changing the behavior and placing the cursor
|
||||
// inside the td (normalize deep)
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[]ef</td> <td>gh</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
test("should remove the row passed as argument", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[]ab</td> <td>cd</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ef</td> <td>gh</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: (editor) => {
|
||||
// Select the second row
|
||||
const row = editor.editable.querySelectorAll("tr")[1];
|
||||
removeRow(row)(editor);
|
||||
},
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[]ab</td> <td>cd</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
test("should remove the table upon sole row removal", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[]ab</td> <td>cd</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: removeRow(),
|
||||
contentAfter: "<p>[]<br></p>",
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("column", () => {
|
||||
describe("left", () => {
|
||||
test("should add a column left of the leftmost column", async () => {
|
||||
await testEditor({
|
||||
contentBefore:
|
||||
'<table style="width: 150px;"><tbody><tr style="height: 20px;">' +
|
||||
'<td style="width: 40px;">ab[]</td>' +
|
||||
'<td style="width: 50px;">cd</td>' +
|
||||
'<td style="width: 60px;">ef</td>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr></tbody></table>",
|
||||
stepFunction: addColumn("before"),
|
||||
contentAfter:
|
||||
'<table style="width: 150px;"><tbody><tr style="height: 20px;">' +
|
||||
'<td style="width: 32px;"><p><br></p></td>' +
|
||||
'<td style="width: 32px;">ab[]</td>' +
|
||||
'<td style="width: 40px;">cd</td>' +
|
||||
'<td style="width: 45px;">ef</td>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td><p><br></p></td>" +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr></tbody></table>",
|
||||
});
|
||||
});
|
||||
|
||||
test("should add a `TH` column before", async () => {
|
||||
await testEditor({
|
||||
contentBefore:
|
||||
'<table style="width: 150px;"><tbody><tr style="height: 20px;">' +
|
||||
'<th style="width: 40px;">ab[]</th>' +
|
||||
'<th style="width: 50px;">cd</th>' +
|
||||
'<th style="width: 60px;">ef</th>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr></tbody></table>",
|
||||
stepFunction: addColumn("before"),
|
||||
contentAfter:
|
||||
'<table style="width: 150px;"><tbody><tr style="height: 20px;">' +
|
||||
'<th style="width: 32px;"><p><br></p></th>' +
|
||||
'<th style="width: 32px;">ab[]</th>' +
|
||||
'<th style="width: 40px;">cd</th>' +
|
||||
'<th style="width: 45px;">ef</th>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td><p><br></p></td>" +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr></tbody></table>",
|
||||
});
|
||||
});
|
||||
|
||||
test("should add a column left of the middle column", async () => {
|
||||
await testEditor({
|
||||
contentBefore:
|
||||
'<table style="width: 200px;"><tbody><tr style="height: 20px;">' +
|
||||
'<td style="width: 50px;">ab</td>' +
|
||||
'<td style="width: 65px;">cd</td>' +
|
||||
'<td style="width: 85px;">ef</td>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd[]</td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr>" +
|
||||
'<tr style="height: 40px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr></tbody></table>",
|
||||
stepFunction: addColumn("before"),
|
||||
contentAfter:
|
||||
'<table style="width: 200px;"><tbody><tr style="height: 20px;">' +
|
||||
'<td style="width: 38px;">ab</td>' +
|
||||
'<td style="width: 49px;"><p><br></p></td>' +
|
||||
'<td style="width: 49px;">cd</td>' +
|
||||
'<td style="width: 63px;">ef</td>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td><p><br></p></td>" +
|
||||
"<td>cd[]</td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr>" +
|
||||
'<tr style="height: 40px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td><p><br></p></td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr></tbody></table>",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("right", () => {
|
||||
test("should add a column right of the rightmost column", async () => {
|
||||
await testEditor({
|
||||
contentBefore:
|
||||
'<table style="width: 150px;"><tbody><tr style="height: 20px;">' +
|
||||
'<td style="width: 40px;">ab</td>' +
|
||||
'<td style="width: 50px;">cd</td>' +
|
||||
'<td style="width: 60px;">ef[]</td>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr></tbody></table>",
|
||||
stepFunction: addColumn("after"),
|
||||
contentAfter:
|
||||
'<table style="width: 150px;"><tbody><tr style="height: 20px;">' +
|
||||
'<td style="width: 29px;">ab</td>' +
|
||||
'<td style="width: 36px;">cd</td>' +
|
||||
'<td style="width: 41px;">ef[]</td>' +
|
||||
// size was slightly adjusted to
|
||||
// preserve table width in view on
|
||||
// fractional division results
|
||||
'<td style="width: 43px;"><p><br></p></td>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td>ef</td>" +
|
||||
"<td><p><br></p></td>" +
|
||||
"</tr></tbody></table>",
|
||||
});
|
||||
});
|
||||
|
||||
test("should add a `TH` column after", async () => {
|
||||
await testEditor({
|
||||
contentBefore:
|
||||
'<table style="width: 150px;"><tbody><tr style="height: 20px;">' +
|
||||
'<th style="width: 40px;">ab</th>' +
|
||||
'<th style="width: 50px;">cd[]</th>' +
|
||||
'<th style="width: 60px;">ef</th>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr></tbody></table>",
|
||||
stepFunction: addColumn("after"),
|
||||
contentAfter:
|
||||
'<table style="width: 150px;"><tbody><tr style="height: 20px;">' +
|
||||
'<th style="width: 30px;">ab</th>' +
|
||||
'<th style="width: 38px;">cd[]</th>' +
|
||||
'<th style="width: 38px;"><p><br></p></th>' +
|
||||
'<th style="width: 43px;">ef</th>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td><p><br></p></td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr></tbody></table>",
|
||||
});
|
||||
});
|
||||
|
||||
test("should add a column right of the middle column", async () => {
|
||||
await testEditor({
|
||||
contentBefore:
|
||||
'<table style="width: 200px;"><tbody><tr style="height: 20px;">' +
|
||||
'<td style="width: 50px;">ab</td>' +
|
||||
'<td style="width: 65px;">cd</td>' +
|
||||
'<td style="width: 85px;">ef</td>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd[]</td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr>" +
|
||||
'<tr style="height: 40px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr></tbody></table>",
|
||||
stepFunction: addColumn("after"),
|
||||
contentAfter:
|
||||
'<table style="width: 200px;"><tbody><tr style="height: 20px;">' +
|
||||
'<td style="width: 38px;">ab</td>' +
|
||||
'<td style="width: 49px;">cd</td>' +
|
||||
'<td style="width: 49px;"><p><br></p></td>' +
|
||||
'<td style="width: 63px;">ef</td>' +
|
||||
"</tr>" +
|
||||
'<tr style="height: 30px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd[]</td>" +
|
||||
"<td><p><br></p></td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr>" +
|
||||
'<tr style="height: 40px;">' +
|
||||
"<td>ab</td>" +
|
||||
"<td>cd</td>" +
|
||||
"<td><p><br></p></td>" +
|
||||
"<td>ef</td>" +
|
||||
"</tr></tbody></table>",
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("removal", () => {
|
||||
test("should remove a column based on selection", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[]ab</td> <td>cd</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ef</td> <td>gh</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: removeColumn(),
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[]cd</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>gh</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
test("should remove the column passed as argument", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[]ab</td> <td>cd</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ef</td> <td>gh</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: (editor) => {
|
||||
// Select the second cell
|
||||
const cell = editor.editable.querySelectorAll("td")[1];
|
||||
removeColumn(cell)(editor);
|
||||
},
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[]ab</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
test("should remove the table upon sole column removal", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr> <td>[]ab</td> </tr>
|
||||
<tr> <td>cd</td> </tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: removeColumn(),
|
||||
contentAfter: "<p>[]<br></p>",
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("tab", () => {
|
||||
test("should add a new row on press tab at the end of a table", async () => {
|
||||
const contentBefore = unformat(`
|
||||
<table><tbody>
|
||||
<tr style="height: 20px;">
|
||||
<td style="width: 20px;">ab</td>
|
||||
<td>cd</td>
|
||||
<td>ef[]</td>
|
||||
</tr>
|
||||
</tbody></table>`);
|
||||
const { el, editor } = await setupEditor(contentBefore);
|
||||
|
||||
await press("Tab");
|
||||
|
||||
const expectedContent = unformat(`
|
||||
<table><tbody>
|
||||
<tr style="height: 20px;">
|
||||
<td style="width: 20px;">ab</td>
|
||||
<td>cd</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
<tr style="height: 20px;">
|
||||
<td><p o-we-hint-text='Type "/" for commands' class="o-we-hint">[]<br></p></td>
|
||||
<td><p><br></p></td>
|
||||
<td><p><br></p></td>
|
||||
</tr>
|
||||
</tbody></table>`);
|
||||
|
||||
expect(getContent(el)).toBe(expectedContent);
|
||||
|
||||
// Check that it was registed as a history step.
|
||||
undo(editor);
|
||||
expect(getContent(el)).toBe(contentBefore);
|
||||
});
|
||||
|
||||
test("should not select whole text of the next cell", async () => {
|
||||
await testEditor({
|
||||
contentBefore:
|
||||
'<table><tbody><tr style="height: 20px;"><td style="width: 20px;">ab</td><td>[cd]</td><td>ef</td></tr></tbody></table>',
|
||||
stepFunction: () => press("Tab"),
|
||||
contentAfter:
|
||||
'<table><tbody><tr style="height: 20px;"><td style="width: 20px;">ab</td><td>cd</td><td>ef[]</td></tr></tbody></table>',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
import { expect, test } from "@odoo/hoot";
|
||||
import { setupEditor } from "../_helpers/editor";
|
||||
import { click, manuallyDispatchProgrammaticEvent, queryAll, queryFirst } from "@odoo/hoot-dom";
|
||||
import { animationFrame, tick } from "@odoo/hoot-mock";
|
||||
import { setSelection } from "../_helpers/selection";
|
||||
import { execCommand } from "../_helpers/userCommands";
|
||||
import { expandToolbar } from "../_helpers/toolbar";
|
||||
import { expectElementCount } from "../_helpers/ui_expectations";
|
||||
import { deleteBackward } from "../_helpers/user_actions";
|
||||
|
||||
function insertTable(editor, cols, rows) {
|
||||
execCommand(editor, "insertTable", { cols, rows });
|
||||
}
|
||||
|
||||
test("can insert a table", async () => {
|
||||
const { el, editor } = await setupEditor("<p>hello[]</p>", {});
|
||||
insertTable(editor, 4, 3);
|
||||
expect(el.querySelectorAll("tr").length).toBe(3);
|
||||
expect(el.querySelectorAll("td").length).toBe(12);
|
||||
});
|
||||
|
||||
test("can color cells", async () => {
|
||||
await setupEditor(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[ab</td>
|
||||
<td>c]</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>`);
|
||||
|
||||
await expandToolbar();
|
||||
expect(".o_font_color_selector").toHaveCount(0);
|
||||
await click(".o-select-color-background");
|
||||
await animationFrame();
|
||||
expect(".o_font_color_selector").toHaveCount(1);
|
||||
|
||||
await click(".o_color_button[data-color='#6BADDE']");
|
||||
await animationFrame();
|
||||
await expectElementCount(".o-we-toolbar", 1);
|
||||
expect(".o_font_color_selector").toHaveCount(0); // selector closed
|
||||
|
||||
// Collapse selection to deselect cells
|
||||
setSelection({ anchorNode: queryFirst("td"), anchorOffset: 0 });
|
||||
await tick();
|
||||
|
||||
const cells = queryAll("td");
|
||||
expect(cells[0]).toHaveStyle({ "background-color": "rgba(107, 173, 222, 0.6)" });
|
||||
expect(cells[1]).toHaveStyle({ "background-color": "rgba(107, 173, 222, 0.6)" });
|
||||
expect(cells[2]).not.toHaveStyle({ "background-color": "rgba(107, 173, 222, 0.6)" });
|
||||
});
|
||||
|
||||
test("remove text from single selected cell", async () => {
|
||||
const { editor } = await setupEditor(`
|
||||
<table class="table table-bordered o_table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p>[]abc</p></td>
|
||||
<td><p><br></p></td>
|
||||
<td><p><br></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>`);
|
||||
|
||||
const firstP = queryFirst("td p");
|
||||
const { left, top } = firstP.getBoundingClientRect();
|
||||
manuallyDispatchProgrammaticEvent(firstP, "mousedown", {
|
||||
detail: 3,
|
||||
clientX: left,
|
||||
clientY: top,
|
||||
});
|
||||
await animationFrame();
|
||||
|
||||
manuallyDispatchProgrammaticEvent(firstP, "mouseup", {
|
||||
detail: 3,
|
||||
clientX: left,
|
||||
clientY: top,
|
||||
});
|
||||
await animationFrame();
|
||||
deleteBackward(editor);
|
||||
|
||||
expect(queryFirst("td p")).toHaveOuterHTML("<p><br></p>");
|
||||
});
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,344 @@
|
|||
import { describe, test } from "@odoo/hoot";
|
||||
import { press } from "@odoo/hoot-dom";
|
||||
import { testEditor } from "../_helpers/editor";
|
||||
import { unformat } from "../_helpers/format";
|
||||
|
||||
describe("move selection with tab/shift+tab", () => {
|
||||
describe("tab", () => {
|
||||
test("should move cursor to the next th", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>[]ab</th>
|
||||
<th>cd</th>
|
||||
<th>ef</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: async () => press("Tab"),
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>ab</th>
|
||||
<th>cd[]</th>
|
||||
<th>ef</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
test("should move cursor to the next td", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>[]ab</th>
|
||||
<td>cd</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: async () => press("Tab"),
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>ab</th>
|
||||
<td>cd[]</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
test("should move cursor to the end of next cell", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[]ab</td>
|
||||
<td>cd</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: async () => press("Tab"),
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ab</td>
|
||||
<td>cd[]</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
test.tags("iframe", "desktop");
|
||||
test("in iframe, desktop: should move cursor to the end of next cell in an iframe", async () => {
|
||||
await testEditor({
|
||||
props: { iframe: true },
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[]ab</td>
|
||||
<td>cd</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: async () => press("Tab"),
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ab</td>
|
||||
<td>cd[]</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
test.tags("iframe", "mobile");
|
||||
test("in iframe, mobile: should move cursor to the end of next cell in an iframe", async () => {
|
||||
await testEditor({
|
||||
props: { iframe: true, mobile: true },
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[]ab</td>
|
||||
<td>cd</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: async () => press("Tab"),
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ab</td>
|
||||
<td>cd[]</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
test("should move cursor to the end of next cell in the row below", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ab</td>
|
||||
<td>[cd]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ef</td>
|
||||
<td>gh</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: async () => press("Tab"),
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ab</td>
|
||||
<td>cd</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ef[]</td>
|
||||
<td>gh</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
test("move cursor to end of next cell when selection is inside table", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<ul>
|
||||
<li>
|
||||
<br>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p>[]ab</p></td>
|
||||
<td><p>cd</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
</li>
|
||||
</ul>
|
||||
`),
|
||||
stepFunction: async () => press("Tab"),
|
||||
contentAfter: unformat(`
|
||||
<ul>
|
||||
<li>
|
||||
<br>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p>ab</p></td>
|
||||
<td><p>cd[]</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
</li>
|
||||
</ul>
|
||||
`),
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("shift+tab", () => {
|
||||
test("should move cursor to the end of previous cell", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ab</td>
|
||||
<td>[]cd</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: async () => press(["Shift", "Tab"]),
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ab[]</td>
|
||||
<td>cd</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
test("should move cursor to the end of previous cell in the row above", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ab</td>
|
||||
<td>cd</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[ef]</td>
|
||||
<td>gh</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: async () => press(["Shift", "Tab"]),
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ab</td>
|
||||
<td>cd[]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ef</td>
|
||||
<td>gh</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
test("should not cursor if there is no previous cell", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[ab]</td>
|
||||
<td>cd</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
stepFunction: async () => press(["Shift", "Tab"]),
|
||||
contentAfter: unformat(`
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[ab]</td>
|
||||
<td>cd</td>
|
||||
<td>ef</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`),
|
||||
});
|
||||
});
|
||||
test("move cursor to end of previous cell when selection is inside table", async () => {
|
||||
await testEditor({
|
||||
contentBefore: unformat(`
|
||||
<ul>
|
||||
<li>
|
||||
<br>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p>ab</p></td>
|
||||
<td><p>[]cd</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
</li>
|
||||
</ul>
|
||||
`),
|
||||
stepFunction: async () => press(["Shift", "Tab"]),
|
||||
contentAfter: unformat(`
|
||||
<ul>
|
||||
<li>
|
||||
<br>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><p>ab[]</p></td>
|
||||
<td><p>cd</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
</li>
|
||||
</ul>
|
||||
`),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue