275 lines
9.5 KiB
HTML
275 lines
9.5 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="timeout" content="long">
|
|
<meta name="variant" content="?white-space=normal">
|
|
<meta name="variant" content="?white-space=pre">
|
|
<meta name="variant" content="?white-space=pre-line">
|
|
<meta name="variant" content="?white-space=pre-wrap">
|
|
<title>Inserting text in plaintext-only</title>
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="/resources/testdriver.js"></script>
|
|
<script src="/resources/testdriver-vendor.js"></script>
|
|
<script src="/resources/testdriver-actions.js"></script>
|
|
<script src="../include/editor-test-utils.js"></script>
|
|
<script>
|
|
"use strict";
|
|
|
|
const searchParams = new URLSearchParams(document.location.search);
|
|
const whiteSpace = searchParams.get("white-space");
|
|
const useBR = whiteSpace == "normal";
|
|
const collapseWhiteSpaces = whiteSpace == "normal" || whiteSpace == "pre-line";
|
|
const isSafari = navigator.platform.includes("Mac") &&
|
|
navigator.userAgent.includes("Safari") &&
|
|
!navigator.userAgent.includes("Chrome");
|
|
|
|
addEventListener("load", () => {
|
|
const editingHost = document.createElement("div");
|
|
editingHost.style.whiteSpace = whiteSpace;
|
|
editingHost.setAttribute("contenteditable", "plaintext-only");
|
|
document.body.appendChild(editingHost);
|
|
editingHost.focus();
|
|
editingHost.getBoundingClientRect();
|
|
const utils = new EditorTestUtils(editingHost);
|
|
|
|
for (const data of [
|
|
{
|
|
initialInnerHTML: "{}<br>",
|
|
insertText: " ",
|
|
expected: collapseWhiteSpaces
|
|
? [" <br>", " "]
|
|
: " ",
|
|
},
|
|
{
|
|
initialInnerHTML: "{}<br>",
|
|
insertText: "a",
|
|
expected: "a",
|
|
},
|
|
{
|
|
initialInnerHTML: "[]\n",
|
|
skipIf: () => useBR,
|
|
insertText: "a",
|
|
expected: "a",
|
|
},
|
|
{
|
|
initialInnerHTML: "A[]B",
|
|
insertText: "a",
|
|
expected: "AaB",
|
|
},
|
|
{
|
|
initialInnerHTML: "<b>A[]B</b>",
|
|
insertText: "a",
|
|
expected: "<b>AaB</b>",
|
|
},
|
|
{
|
|
initialInnerHTML: "A[]B",
|
|
insertText: " ",
|
|
expected: "A B",
|
|
},
|
|
{
|
|
initialInnerHTML: "<b>A[]B</b>",
|
|
insertText: " ",
|
|
expected: "<b>A B</b>",
|
|
},
|
|
{
|
|
initialInnerHTML: "<b>A[]B</b>",
|
|
insertText: " ",
|
|
expected: collapseWhiteSpaces
|
|
? ["<b>A B</b>", "<b>A B</b>"]
|
|
: "<b>A B</b>",
|
|
},
|
|
{
|
|
initialInnerHTML: `<p style="white-space:normal">A[]B</p>`,
|
|
insertText: " ",
|
|
expected: [`<p style="white-space:normal">A B</p>`, `<p style="white-space:normal">A B</p>`],
|
|
},
|
|
{
|
|
initialInnerHTML: `<p style="white-space:pre">A[]B</p>`,
|
|
insertText: " ",
|
|
expected: `<p style="white-space:pre">A B</p>`,
|
|
},
|
|
{
|
|
initialInnerHTML: `<p style="white-space:pre-line">A[]B</p>`,
|
|
insertText: " ",
|
|
expected: [`<p style="white-space:pre-line">A B</p>`, `<p style="white-space:pre-line">A B</p>`],
|
|
},
|
|
{
|
|
initialInnerHTML: `<p style="white-space:pre-wrap">A[]B</p>`,
|
|
insertText: " ",
|
|
expected: `<p style="white-space:pre-wrap">A B</p>`,
|
|
},
|
|
{
|
|
initialInnerHTML: "<p><b>[]AB</b></p>",
|
|
prepareDescription: "execCommand(\"insertParagraph\")",
|
|
prepare: () => document.execCommand("insertParagraph"),
|
|
insertText: "a",
|
|
// To keep the style of next typing even after lost focus, the placeholder line break in
|
|
// the empty paragraph should be wrapped in the <b>.
|
|
expected: "<p><b><br></b></p><p><b>aAB</b></p>",
|
|
},
|
|
{
|
|
initialInnerHTML: "<p><b>A[]B</b></p>",
|
|
prepareDescription: "execCommand(\"insertParagraph\")",
|
|
prepare: () => document.execCommand("insertParagraph"),
|
|
insertText: "a",
|
|
expected: "<p><b>A</b></p><p><b>aB</b></p>",
|
|
},
|
|
{
|
|
initialInnerHTML: "<p><b>AB[]</b></p>",
|
|
prepareDescription: "execCommand(\"insertParagraph\")",
|
|
prepare: () => document.execCommand("insertParagraph"),
|
|
insertText: "a",
|
|
// To keep the style of next typing even after lost focus, the placeholder line break in
|
|
// the empty paragraph after "insertParagraph" should be wrapped in the <b>.
|
|
expected: "<p><b>AB</b></p><p><b>a</b></p>",
|
|
},
|
|
{
|
|
initialInnerHTML: "<p><b>[AB]</b></p>",
|
|
prepareDescription: "execCommand(\"insertParagraph\")",
|
|
prepare: () => document.execCommand("insertParagraph"),
|
|
insertText: "a",
|
|
expected: "<p><b><br></b></p><p><b>a</b></p>",
|
|
},
|
|
{
|
|
initialInnerHTML: "<p><b>[]AB</b></p>",
|
|
prepareDescription: "execCommand(\"insertLineBreak\")",
|
|
prepare: () => document.execCommand("insertLineBreak"),
|
|
insertText: "a",
|
|
expected: useBR
|
|
? "<p><b><br>aAB</b></p>"
|
|
: "<p><b>\naAB</b></p>",
|
|
},
|
|
{
|
|
initialInnerHTML: "<p><b>A[]B</b></p>",
|
|
prepareDescription: "execCommand(\"insertLineBreak\")",
|
|
prepare: () => document.execCommand("insertLineBreak"),
|
|
insertText: "a",
|
|
expected: useBR
|
|
? "<p><b>A<br>aB</b></p>"
|
|
: "<p><b>A\naB</b></p>",
|
|
},
|
|
{
|
|
initialInnerHTML: "<p><b>AB[]</b></p>",
|
|
prepareDescription: "execCommand(\"insertLineBreak\")",
|
|
prepare: () => document.execCommand("insertLineBreak"),
|
|
insertText: "a",
|
|
// To keep the style of next typing even after once the paragraph becomes empty,
|
|
// the placeholder line break (if there is) should be in <b>.
|
|
expected: useBR
|
|
? "<p><b>AB<br>a</b></p>"
|
|
: "<p><b>AB\na</b></p>",
|
|
},
|
|
{
|
|
initialInnerHTML: "<p><b>[AB]</b></p>",
|
|
prepareDescription: "execCommand(\"insertLineBreak\")",
|
|
prepare: () => document.execCommand("insertLineBreak"),
|
|
insertText: "a",
|
|
// To keep the style of next typing even after once the paragraph becomes empty,
|
|
// the placeholder line break (if there is) should be in <b>.
|
|
expected: useBR
|
|
? "<p><b><br>a</b></p>"
|
|
: "<p><b>\na</b></p>",
|
|
},
|
|
{
|
|
initialInnerHTML: "<p><b>[AB]</b></p>",
|
|
prepareDescription: "execCommand(\"delete\")",
|
|
prepare: () => document.execCommand("delete"),
|
|
insertText: "a",
|
|
// To keep the style of next typing even after blur, the placeholder line break
|
|
// (if there is) should be in <b>.
|
|
expected: "<p><b>a</b></p>",
|
|
},
|
|
{
|
|
initialInnerHTML: "<p><b>A[]</b></p><p>B</p>",
|
|
prepareDescription: "execCommand(\"delete\") and move caret to the following paragraph temporarily",
|
|
prepare: () => {
|
|
document.execCommand("delete");
|
|
getSelection().modify("move", "forward", "Line");
|
|
getSelection().modify("move", "backward", "Line");
|
|
},
|
|
insertText: "a",
|
|
// Moving caret shouldn't cause loosing the style.
|
|
expected: "<p><b>a</b></p><p>B</p>",
|
|
},
|
|
{
|
|
initialInnerHTML: "<p><b>[]A</b></p><p>B</p>",
|
|
prepareDescription: "execCommand(\"forwardDelete\") and move caret to the following paragraph temporarily",
|
|
prepare: () => {
|
|
document.execCommand("forwardDelete");
|
|
getSelection().modify("move", "forward", "Line");
|
|
getSelection().modify("move", "backward", "Line");
|
|
},
|
|
insertText: "a",
|
|
// Moving caret shouldn't cause loosing the style.
|
|
expected: "<p><b>a</b></p><p>B</p>",
|
|
},
|
|
{
|
|
initialInnerHTML: "<p><b>[A]</b></p><p>B</p>",
|
|
prepareDescription: "execCommand(\"delete\") and move caret to the following paragraph temporarily",
|
|
prepare: () => {
|
|
document.execCommand("delete");
|
|
getSelection().modify("move", "forward", "Line");
|
|
getSelection().modify("move", "backward", "Line");
|
|
},
|
|
insertText: "a",
|
|
// Moving caret shouldn't cause loosing the style.
|
|
expected: "<p><b>a</b></p><p>B</p>",
|
|
},
|
|
{
|
|
initialInnerHTML: "<p><b>A[]</b></b>",
|
|
prepareDescription: "execCommand(\"insertParagraph\") and move caret to the preceding paragraph temporarily",
|
|
prepare: () => {
|
|
document.execCommand("insertParagraph");
|
|
getSelection().modify("move", "backward", "Line");
|
|
getSelection().modify("move", "forward", "Line");
|
|
},
|
|
insertText: "a",
|
|
// Moving caret shouldn't cause loosing the style.
|
|
expected: "<p><b>A</b></p><p><b>a</b></p>",
|
|
},
|
|
]) {
|
|
if (data.skipIf !== undefined && data.skipIf()) {
|
|
continue;
|
|
}
|
|
test(() => {
|
|
utils.setupEditingHost(data.initialInnerHTML);
|
|
if (data.prepare) {
|
|
data.prepare();
|
|
}
|
|
document.execCommand("insertText", false, data.insertText);
|
|
if (Array.isArray(data.expected)) {
|
|
assert_in_array(editingHost.innerHTML, data.expected);
|
|
} else {
|
|
assert_equals(editingHost.innerHTML, data.expected);
|
|
}
|
|
}, `execCommand("insertText", false, "${data.insertText.replaceAll("\n", "\\n")}") when ${
|
|
data.initialInnerHTML.replaceAll("\n", "\\n")
|
|
}${
|
|
data.prepareDescription ? ` and ${data.prepareDescription.replaceAll("\n", "\\n")}` : ""
|
|
}`);
|
|
promise_test(async t => {
|
|
utils.setupEditingHost(data.initialInnerHTML);
|
|
if (data.prepare) {
|
|
data.prepare();
|
|
}
|
|
for (const char of data.insertText) {
|
|
await utils.sendKey(char);
|
|
}
|
|
if (Array.isArray(data.expected)) {
|
|
assert_in_array(editingHost.innerHTML, data.expected);
|
|
} else {
|
|
assert_equals(editingHost.innerHTML, data.expected);
|
|
}
|
|
}, `Typing "${data.insertText.replaceAll("\n", "\\n")}" when ${
|
|
data.initialInnerHTML.replaceAll("\n", "\\n")
|
|
}${
|
|
data.prepareDescription ? ` and ${data.prepareDescription.replaceAll("\n", "\\n")}` : ""
|
|
}`);
|
|
}
|
|
}, {once: true});
|
|
</script>
|
|
</head>
|
|
<body></body>
|
|
</html>
|