502 lines
18 KiB
HTML
502 lines
18 KiB
HTML
<!doctype html>
|
|
<meta chareset="utf-8">
|
|
<meta name="timeout" content="long">
|
|
|
|
<meta name="variant" content="?white-space=normal&display=inline&method=enter">
|
|
<meta name="variant" content="?white-space=normal&display=inline&method=shift-enter">
|
|
<meta name="variant" content="?white-space=normal&display=inline-block&method=enter">
|
|
<meta name="variant" content="?white-space=normal&display=inline-block&method=shift-enter">
|
|
<meta name="variant" content="?white-space=normal&display=block&method=enter">
|
|
<meta name="variant" content="?white-space=normal&display=block&method=shift-enter">
|
|
<meta name="variant" content="?white-space=normal&display=list-item&method=enter">
|
|
<meta name="variant" content="?white-space=normal&display=list-item&method=shift-enter">
|
|
<meta name="variant" content="?white-space=normal&display=table-cell&method=enter">
|
|
<meta name="variant" content="?white-space=normal&display=table-cell&method=shift-enter">
|
|
|
|
<meta name="variant" content="?white-space=pre&display=inline&method=enter">
|
|
<meta name="variant" content="?white-space=pre&display=inline&method=shift-enter">
|
|
<meta name="variant" content="?white-space=pre&display=inline-block&method=enter">
|
|
<meta name="variant" content="?white-space=pre&display=inline-block&method=shift-enter">
|
|
<meta name="variant" content="?white-space=pre&display=block&method=enter">
|
|
<meta name="variant" content="?white-space=pre&display=block&method=shift-enter">
|
|
<meta name="variant" content="?white-space=pre&display=list-item&method=enter">
|
|
<meta name="variant" content="?white-space=pre&display=list-item&method=shift-enter">
|
|
<meta name="variant" content="?white-space=pre&display=table-cell&method=enter">
|
|
<meta name="variant" content="?white-space=pre&display=table-cell&method=shift-enter">
|
|
|
|
<meta name="variant" content="?white-space=pre-line&display=inline&method=enter">
|
|
<meta name="variant" content="?white-space=pre-line&display=inline&method=shift-enter">
|
|
<meta name="variant" content="?white-space=pre-line&display=inline-block&method=enter">
|
|
<meta name="variant" content="?white-space=pre-line&display=inline-block&method=shift-enter">
|
|
<meta name="variant" content="?white-space=pre-line&display=block&method=enter">
|
|
<meta name="variant" content="?white-space=pre-line&display=block&method=shift-enter">
|
|
<meta name="variant" content="?white-space=pre-line&display=list-item&method=enter">
|
|
<meta name="variant" content="?white-space=pre-line&display=list-item&method=shift-enter">
|
|
<meta name="variant" content="?white-space=pre-line&display=table-cell&method=enter">
|
|
<meta name="variant" content="?white-space=pre-line&display=table-cell&method=shift-enter">
|
|
|
|
<meta name="variant" content="?white-space=pre-wrap&display=inline&method=enter">
|
|
<meta name="variant" content="?white-space=pre-wrap&display=inline&method=shift-enter">
|
|
<meta name="variant" content="?white-space=pre-wrap&display=inline-block&method=enter">
|
|
<meta name="variant" content="?white-space=pre-wrap&display=inline-block&method=shift-enter">
|
|
<meta name="variant" content="?white-space=pre-wrap&display=block&method=enter">
|
|
<meta name="variant" content="?white-space=pre-wrap&display=block&method=shift-enter">
|
|
<meta name="variant" content="?white-space=pre-wrap&display=list-item&method=enter">
|
|
<meta name="variant" content="?white-space=pre-wrap&display=list-item&method=shift-enter">
|
|
<meta name="variant" content="?white-space=pre-wrap&display=table-cell&method=enter">
|
|
<meta name="variant" content="?white-space=pre-wrap&display=table-cell&method=shift-enter">
|
|
|
|
<title>Line breaking in inline editing host</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>
|
|
<div><span contenteditable></span></div>
|
|
<script>
|
|
"use strict";
|
|
|
|
const searchParams = new URLSearchParams(document.location.search);
|
|
const testingInsertParagraph = searchParams.get("method") == "enter";
|
|
const whiteSpace = searchParams.get("white-space");
|
|
const display = searchParams.get("display");
|
|
|
|
const isPreformatted =
|
|
whiteSpace == "pre" || whiteSpace == "pre-line" || whiteSpace == "pre-wrap";
|
|
|
|
const editingHost = document.querySelector("span[contenteditable]");
|
|
const container = editingHost.parentElement;
|
|
const utils = new EditorTestUtils(editingHost);
|
|
const modifiers = (() => {
|
|
if (testingInsertParagraph) {
|
|
return null;
|
|
}
|
|
// Only Safari treats `Ctrl+Enter` as insertLineBreak
|
|
if (navigator.platform.includes("Mac") &&
|
|
navigator.userAgent.includes("Safari") &&
|
|
!navigator.userAgent.includes("Chrom")) {
|
|
return utils.kControl;
|
|
}
|
|
// The others including WebKitGTK treat `Shift+Enter` as it.
|
|
return utils.kShift;
|
|
})();
|
|
|
|
for (const defaultParagraphSeparator of ["div", "p"]) {
|
|
document.execCommand(
|
|
"defaultParagraphSeparator",
|
|
false,
|
|
defaultParagraphSeparator
|
|
);
|
|
|
|
promise_test(async t => {
|
|
editingHost.setAttribute(
|
|
"style",
|
|
`display:${display};white-space:${whiteSpace}`
|
|
);
|
|
utils.setupEditingHost("{}");
|
|
await utils.sendEnterKey(modifiers);
|
|
editingHost.removeAttribute("style");
|
|
// In this case, the inserting line break is the last visible thing in the
|
|
// block. Therefore, additional <br> or a preformatted linefeed is also
|
|
// required to make the new line visible.
|
|
if (!isPreformatted) {
|
|
assert_equals(
|
|
container.innerHTML,
|
|
'<span contenteditable=""><br><br></span>',
|
|
`A <br> and additional <br> should be inserted when ${t.name}`
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
container.innerHTML,
|
|
[
|
|
'<span contenteditable="">\n<br></span>',
|
|
'<span contenteditable="">\n\n</span>',
|
|
],
|
|
`A linefeed and additional line breaker should be inserted when ${t.name}`
|
|
);
|
|
}
|
|
}, `${
|
|
testingInsertParagraph ? "insertParagraph" : "insertLineBreak"
|
|
} in <span contenteditable style="display:${
|
|
display
|
|
};white-space:${whiteSpace}">{}</span> (defaultParagraphSeparator=${
|
|
defaultParagraphSeparator
|
|
})`);
|
|
|
|
promise_test(async t => {
|
|
editingHost.setAttribute(
|
|
"style",
|
|
`display:${display};white-space:${whiteSpace}`
|
|
);
|
|
const brElement = document.createElement("br");
|
|
try {
|
|
container.appendChild(brElement);
|
|
utils.setupEditingHost("{}");
|
|
await utils.sendEnterKey(modifiers);
|
|
editingHost.removeAttribute("style");
|
|
// Even if the <span> element is followed by an invisible <br>, it does
|
|
// not make the new line in the <span> element visible. Therefore,
|
|
// inserting additional line break is required in this case too.
|
|
if (!isPreformatted) {
|
|
assert_equals(
|
|
container.innerHTML,
|
|
'<span contenteditable=""><br><br></span><br>',
|
|
`A <br> and additional <br> should be inserted when ${t.name}`
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
container.innerHTML,
|
|
[
|
|
`<span contenteditable="">\n\n</span><br>`,
|
|
`<span contenteditable="">\n<br></span><br>`,
|
|
],
|
|
`A linefeed and additional line break should be inserted when ${t.name}`
|
|
);
|
|
}
|
|
} finally {
|
|
brElement.remove();
|
|
}
|
|
}, `${
|
|
testingInsertParagraph ? "insertParagraph" : "insertLineBreak"
|
|
} in <span contenteditable style="display:${
|
|
display
|
|
};white-space:${
|
|
whiteSpace
|
|
}">{}</span> followed by a <br> (defaultParagraphSeparator=${
|
|
defaultParagraphSeparator
|
|
})`);
|
|
|
|
promise_test(async t => {
|
|
editingHost.setAttribute(
|
|
"style",
|
|
`display:${display};white-space:${whiteSpace}`
|
|
);
|
|
const divElement = document.createElement("div");
|
|
divElement.textContent = "efg";
|
|
try {
|
|
container.appendChild(divElement);
|
|
utils.setupEditingHost("{}");
|
|
await utils.sendEnterKey(modifiers);
|
|
editingHost.removeAttribute("style");
|
|
// When the <span> element is followed by a <div>, making empty last
|
|
// line visible requires an invisible <br> after a line break.
|
|
if (!isPreformatted) {
|
|
assert_equals(
|
|
container.innerHTML,
|
|
'<span contenteditable=""><br><br></span><div>efg</div>',
|
|
`A <br> and additional <br> should be inserted when ${t.name}`
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
container.innerHTML,
|
|
[
|
|
`<span contenteditable="">\n\n</span><div>efg</div>`,
|
|
`<span contenteditable="">\n<br></span><div>efg</div>`,
|
|
],
|
|
`A linefeed and additional line break should be inserted when ${t.name}`
|
|
);
|
|
}
|
|
} finally {
|
|
divElement.remove();
|
|
}
|
|
}, `${
|
|
testingInsertParagraph ? "insertParagraph" : "insertLineBreak"
|
|
} in <span contenteditable style="display:${
|
|
display
|
|
};white-space:${
|
|
whiteSpace
|
|
}">{}</span> followed by a <div> (defaultParagraphSeparator=${
|
|
defaultParagraphSeparator
|
|
})`);
|
|
|
|
promise_test(async t => {
|
|
editingHost.setAttribute(
|
|
"style",
|
|
`display:${display};white-space:${whiteSpace}`
|
|
);
|
|
const text = document.createTextNode("abc");
|
|
try {
|
|
container.appendChild(text);
|
|
utils.setupEditingHost("{}");
|
|
await utils.sendEnterKey(modifiers);
|
|
editingHost.removeAttribute("style");
|
|
// Even if the <span> element is followed by visible text, it does
|
|
// not make the new line in the <span> element visible. Therefore,
|
|
// inserting additional line break is required in this case too.
|
|
if (!isPreformatted) {
|
|
assert_equals(
|
|
container.innerHTML,
|
|
'<span contenteditable=""><br><br></span>abc',
|
|
`A <br> and additional <br> should be inserted when ${t.name}`
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
container.innerHTML,
|
|
[
|
|
`<span contenteditable="">\n\n</span>abc`,
|
|
`<span contenteditable="">\n<br></span>abc`,
|
|
],
|
|
`A linefeed and additional line break should be inserted when ${t.name}`
|
|
);
|
|
}
|
|
} finally {
|
|
text.remove();
|
|
}
|
|
}, `${
|
|
testingInsertParagraph ? "insertParagraph" : "insertLineBreak"
|
|
} in <span contenteditable style="display:${
|
|
display
|
|
};white-space:${
|
|
whiteSpace
|
|
}">{}</span> followed by text (defaultParagraphSeparator=${
|
|
defaultParagraphSeparator
|
|
})`);
|
|
|
|
promise_test(async t => {
|
|
editingHost.setAttribute(
|
|
"style",
|
|
`display:${display};white-space:${whiteSpace}`
|
|
);
|
|
utils.setupEditingHost("{}<br>");
|
|
await utils.sendEnterKey(modifiers);
|
|
editingHost.removeAttribute("style");
|
|
// In this case, there is a <br> element which makes the new line (last
|
|
// line) visible. Therefore, only a line break should be inserted.
|
|
if (!isPreformatted) {
|
|
assert_equals(
|
|
container.innerHTML,
|
|
`<span contenteditable=""><br><br></span>`,
|
|
`A <br> should be inserted when ${t.name}`
|
|
);
|
|
} else {
|
|
assert_equals(
|
|
container.innerHTML,
|
|
`<span contenteditable="">\n<br></span>`,
|
|
`A <br> should be inserted when ${t.name}`
|
|
);
|
|
}
|
|
}, `${
|
|
testingInsertParagraph ? "insertParagraph" : "insertLineBreak"
|
|
} in <span contenteditable style="display:${
|
|
display
|
|
};white-space:${whiteSpace}">{}<br></span> (defaultParagraphSeparator=${
|
|
defaultParagraphSeparator
|
|
})`);
|
|
|
|
promise_test(async t => {
|
|
editingHost.setAttribute(
|
|
"style",
|
|
`display:${display};white-space:${whiteSpace}`
|
|
);
|
|
utils.setupEditingHost("[]abcd");
|
|
await utils.sendEnterKey(modifiers);
|
|
editingHost.removeAttribute("style");
|
|
assert_equals(
|
|
container.innerHTML,
|
|
`<span contenteditable="">${
|
|
isPreformatted ? "\n" : "<br>"
|
|
}abcd</span>`,
|
|
`${
|
|
isPreformatted ? "A linefeed" : "A <br>"
|
|
} should be inserted when ${t.name}`
|
|
);
|
|
}, `${
|
|
testingInsertParagraph ? "insertParagraph" : "insertLineBreak"
|
|
} in <span contenteditable style="display:${
|
|
display
|
|
};white-space:${whiteSpace}">[]abcd</span> (defaultParagraphSeparator=${
|
|
defaultParagraphSeparator
|
|
})`);
|
|
|
|
promise_test(async t => {
|
|
editingHost.setAttribute(
|
|
"style",
|
|
`display:${display};white-space:${whiteSpace}`
|
|
);
|
|
utils.setupEditingHost("ab[]cd");
|
|
await utils.sendEnterKey(modifiers);
|
|
editingHost.removeAttribute("style");
|
|
assert_equals(
|
|
container.innerHTML,
|
|
`<span contenteditable="">ab${
|
|
isPreformatted ? "\n" : "<br>"
|
|
}cd</span>`,
|
|
`${
|
|
isPreformatted ? "A linefeed" : "A <br>"
|
|
} should be inserted when ${t.name}`
|
|
);
|
|
}, `${
|
|
testingInsertParagraph ? "insertParagraph" : "insertLineBreak"
|
|
} in <span contenteditable style="display:${
|
|
display
|
|
};white-space:${whiteSpace}">ab[]cd</span> (defaultParagraphSeparator=${
|
|
defaultParagraphSeparator
|
|
})`);
|
|
|
|
promise_test(async t => {
|
|
editingHost.setAttribute(
|
|
"style",
|
|
`display:${display};white-space:${whiteSpace}`
|
|
);
|
|
utils.setupEditingHost("abcd[]");
|
|
await utils.sendEnterKey(modifiers);
|
|
editingHost.removeAttribute("style");
|
|
// In this case, the inserting line break is the last visible thing in the
|
|
// block. Therefore, additional line break is also required to make the
|
|
// new line visible.
|
|
if (!isPreformatted) {
|
|
assert_equals(
|
|
container.innerHTML,
|
|
`<span contenteditable="">abcd<br><br></span>`,
|
|
`A <br> and additional <br> should be inserted when ${t.name}`
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
container.innerHTML,
|
|
[
|
|
`<span contenteditable="">abcd\n<br></span>`,
|
|
`<span contenteditable="">abcd\n\n</span>`,
|
|
],
|
|
`A linefeed and additional line break should be inserted when ${t.name}`
|
|
);
|
|
}
|
|
}, `${
|
|
testingInsertParagraph ? "insertParagraph" : "insertLineBreak"
|
|
} in <span contenteditable style="display:${
|
|
display
|
|
};white-space:${whiteSpace}">abcd[]</span> (defaultParagraphSeparator=${
|
|
defaultParagraphSeparator
|
|
})`);
|
|
|
|
promise_test(async t => {
|
|
editingHost.setAttribute(
|
|
"style",
|
|
`display:${display};white-space:${whiteSpace}`
|
|
);
|
|
const brElement = document.createElement("br");
|
|
try {
|
|
container.appendChild(brElement);
|
|
utils.setupEditingHost("abcd[]");
|
|
await utils.sendEnterKey(modifiers);
|
|
editingHost.removeAttribute("style");
|
|
// Even if the <span> element is followed by an invisible <br>, it does
|
|
// not make the new line in the <span> element visible. Therefore,
|
|
// inserting additional line break is required in this case too.
|
|
if (!isPreformatted) {
|
|
assert_equals(
|
|
container.innerHTML,
|
|
'<span contenteditable="">abcd<br><br></span><br>',
|
|
`A <br> and additional <br> should be inserted when ${t.name}`
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
container.innerHTML,
|
|
[
|
|
`<span contenteditable="">abcd\n<br></span><br>`,
|
|
`<span contenteditable="">abcd\n\n</span><br>`,
|
|
],
|
|
`A linefeed and additional line break should be inserted when ${t.name}`
|
|
);
|
|
}
|
|
} finally {
|
|
brElement.remove();
|
|
}
|
|
}, `${
|
|
testingInsertParagraph ? "insertParagraph" : "insertLineBreak"
|
|
} in <span contenteditable style="display:${
|
|
display
|
|
};white-space:${
|
|
whiteSpace
|
|
}">abcd[]</span> followed by a <br> element (defaultParagraphSeparator=${
|
|
defaultParagraphSeparator
|
|
})`);
|
|
|
|
promise_test(async t => {
|
|
editingHost.setAttribute(
|
|
"style",
|
|
`display:${display};white-space:${whiteSpace}`
|
|
);
|
|
const divElement = document.createElement("div");
|
|
divElement.textContent = "efg";
|
|
try {
|
|
container.appendChild(divElement);
|
|
utils.setupEditingHost("abcd[]");
|
|
await utils.sendEnterKey(modifiers);
|
|
editingHost.removeAttribute("style");
|
|
// When the <span> element is followed by a <div>, making empty last
|
|
// line visible requires an invisible <br> after a line break.
|
|
if (!isPreformatted) {
|
|
assert_equals(
|
|
container.innerHTML,
|
|
'<span contenteditable="">abcd<br><br></span><div>efg</div>',
|
|
`A <br> and additional <br> should be inserted when ${t.name}`
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
container.innerHTML,
|
|
[
|
|
`<span contenteditable="">abcd\n<br></span><div>efg</div>`,
|
|
`<span contenteditable="">abcd\n\n</span><div>efg</div>`,
|
|
],
|
|
`A linefeed and additional line break should be inserted when ${t.name}`
|
|
);
|
|
}
|
|
} finally {
|
|
divElement.remove();
|
|
}
|
|
}, `${
|
|
testingInsertParagraph ? "insertParagraph" : "insertLineBreak"
|
|
} in <span contenteditable style="display:${
|
|
display
|
|
};white-space:${
|
|
whiteSpace
|
|
}">abcd[]</span> followed by a <div> element (defaultParagraphSeparator=${
|
|
defaultParagraphSeparator
|
|
})`);
|
|
|
|
promise_test(async t => {
|
|
editingHost.setAttribute(
|
|
"style",
|
|
`display:${display};white-space:${whiteSpace}`
|
|
);
|
|
const text = document.createTextNode("efg");
|
|
try {
|
|
container.appendChild(text);
|
|
utils.setupEditingHost("abcd[]");
|
|
await utils.sendEnterKey(modifiers);
|
|
editingHost.removeAttribute("style");
|
|
// Even if the <span> element is followed by visible text, it does
|
|
// not make the new line in the <span> element visible. Therefore,
|
|
// inserting additional line break is required in this case too.
|
|
if (!isPreformatted) {
|
|
assert_equals(
|
|
container.innerHTML,
|
|
'<span contenteditable="">abcd<br><br></span>efg',
|
|
`A <br> and additional <br> should be inserted when ${t.name}`
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
container.innerHTML,
|
|
[
|
|
`<span contenteditable="">abcd\n<br></span>efg`,
|
|
`<span contenteditable="">abcd\n\n</span>efg`,
|
|
],
|
|
`A linefeed and additional line break should be inserted when ${t.name}`
|
|
);
|
|
}
|
|
} finally {
|
|
text.remove();
|
|
}
|
|
}, `${
|
|
testingInsertParagraph ? "insertParagraph" : "insertLineBreak"
|
|
} in <span contenteditable style="display:${
|
|
display
|
|
};white-space:${
|
|
whiteSpace
|
|
}">abcd[]</span> followed by text (defaultParagraphSeparator=${
|
|
defaultParagraphSeparator
|
|
})`);
|
|
}
|
|
|
|
</script>
|