322 lines
No EOL
10 KiB
HTML
322 lines
No EOL
10 KiB
HTML
<!doctype html>
|
|
<meta charset=utf-8>
|
|
<title>Test insertText when selection collapsed in void element</title>
|
|
<meta name="timeout" content="long">
|
|
<script src=/resources/testharness.js></script>
|
|
<script src=/resources/testharnessreport.js></script>
|
|
<div contenteditable></div>
|
|
<script>
|
|
"use strict";
|
|
|
|
const voidElements = [
|
|
"br",
|
|
"embed",
|
|
"hr",
|
|
"img",
|
|
"input",
|
|
"wbr",
|
|
];
|
|
|
|
// This test tests whether the inserted text is inserted into, when selection
|
|
// is collapsed in the void element. The expected results are based on Blink,
|
|
// but the results of <embed> and <wbr> elements are not consistent with the
|
|
// other elements'. Therefore, Blink also does not pass some of the following
|
|
// tests.
|
|
// FYI: This cannot be tested by editing/run because there is no way to collapse
|
|
// selection into a void element with the framework.
|
|
|
|
const editor = document.querySelector("div[contenteditable]");
|
|
for (const tag of voidElements) {
|
|
test(() => {
|
|
editor.innerHTML = `<div></div>`;
|
|
const element = document.createElement(tag);
|
|
editor.firstChild.appendChild(element);
|
|
editor.focus();
|
|
const selection = getSelection();
|
|
selection.collapse(element, 0);
|
|
document.execCommand("insertText", false, "abc");
|
|
if (tag == "br") {
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
"<div>abc</div>",
|
|
"<div>abc<br></div>",
|
|
],
|
|
`The text should be inserted before the <br> element`
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
`<div>abc<${tag}></div>`,
|
|
`<div>abc<${tag}><br></div>`,
|
|
],
|
|
`The text should be inserted before the <${tag}> element`
|
|
);
|
|
}
|
|
}, `Inserting text when selection is collapsed in <${tag}> which is only child`);
|
|
|
|
test(() => {
|
|
editor.innerHTML = `<div></div>`;
|
|
const element = document.createElement(tag);
|
|
editor.firstChild.appendChild(element);
|
|
editor.focus();
|
|
const selection = getSelection();
|
|
selection.collapse(element, 0);
|
|
element.getBoundingClientRect();
|
|
document.execCommand("insertText", false, "abc");
|
|
if (tag == "br") {
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
"<div>abc</div>",
|
|
"<div>abc<br></div>",
|
|
],
|
|
`The text should be inserted before the <br> element`
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
`<div>abc<${tag}></div>`,
|
|
`<div>abc<${tag}><br></div>`,
|
|
],
|
|
`The text should be inserted before the <${tag}> element`
|
|
);
|
|
}
|
|
}, `Inserting text when selection is collapsed in <${tag}> which is only child (explicitly flushes maybe pending layout)`);
|
|
|
|
test(() => {
|
|
editor.innerHTML = `<div>abc</div>`;
|
|
const element = document.createElement(tag);
|
|
editor.firstChild.appendChild(element);
|
|
editor.focus();
|
|
const selection = getSelection();
|
|
selection.collapse(element, 0);
|
|
document.execCommand("insertText", false, "def");
|
|
if (tag == "br") {
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
"<div>abcdef</div>",
|
|
"<div>abcdef<br></div>",
|
|
],
|
|
`The text should be inserted before the <br> element`
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
`<div>abcdef<${tag}></div>`,
|
|
`<div>abcdef<${tag}><br></div>`,
|
|
],
|
|
`The text should be inserted before the <${tag}> element`
|
|
);
|
|
}
|
|
}, `Inserting text when selection is collapsed in <${tag}> which follows a text node`);
|
|
|
|
test(() => {
|
|
editor.innerHTML = `<div>def</div>`;
|
|
const element = document.createElement(tag);
|
|
editor.firstChild.insertBefore(element, editor.firstChild.firstChild);
|
|
editor.focus();
|
|
const selection = getSelection();
|
|
selection.collapse(element, 0);
|
|
document.execCommand("insertText", false, "abc");
|
|
if (tag == "br") {
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
"<div>abc<br>def</div>",
|
|
"<div>abc<br>def<br></div>",
|
|
],
|
|
`The text should be inserted before the <br> element`
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
`<div>abc<${tag}>def</div>`,
|
|
`<div>abc<${tag}>def<br></div>`,
|
|
],
|
|
`The text should be inserted before the <${tag}> element`
|
|
);
|
|
}
|
|
}, `Inserting text when selection is collapsed in <${tag}> which is followed by a text node`);
|
|
|
|
test(() => {
|
|
editor.innerHTML = `<div><span></span></div>`;
|
|
const element = document.createElement(tag);
|
|
editor.firstChild.appendChild(element);
|
|
editor.focus();
|
|
const selection = getSelection();
|
|
selection.collapse(element, 0);
|
|
document.execCommand("insertText", false, "abc");
|
|
if (tag == "br") {
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
"<div><span></span>abc</div>",
|
|
"<div><span></span>abc<br></div>",
|
|
],
|
|
`The text should be inserted after the previous empty inline element of <br>`
|
|
);
|
|
} else if (tag == "input") { // visible inline?
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
`<div><span></span>abc<${tag}></div>`,
|
|
`<div><span></span>abc<${tag}><br></div>`,
|
|
],
|
|
`The text should be inserted after the previous empty inline element of <${tag}>`
|
|
);
|
|
} else if (tag == "hr") { // block
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
`<div><span></span>abc<${tag}></div>`,
|
|
`<div><span></span>abc<br><${tag}></div>`,
|
|
],
|
|
`The text should be inserted after the previous empty inline element of <${tag}>`
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
`<div>abc<span></span><${tag}></div>`,
|
|
`<div>abc<span></span><${tag}><br></div>`,
|
|
],
|
|
`The text should be inserted before the previous empty inline element of <${tag}>`
|
|
);
|
|
}
|
|
}, `Inserting text when selection is collapsed in <${tag}> which follows an empty <span> element`);
|
|
|
|
test(() => {
|
|
editor.innerHTML = `<div>abc<span></span></div>`;
|
|
const element = document.createElement(tag);
|
|
editor.firstChild.appendChild(element);
|
|
editor.focus();
|
|
const selection = getSelection();
|
|
selection.collapse(element, 0);
|
|
document.execCommand("insertText", false, "def");
|
|
if (tag == "br") {
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
"<div>abcdef<span></span></div>",
|
|
"<div>abcdef<span></span><br></div>",
|
|
],
|
|
`The text should be inserted at end of the first text node before empty <span> and <br>`
|
|
);
|
|
} else if (tag == "hr") { // block
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
`<div>abc<span></span>def<${tag}></div>`,
|
|
`<div>abc<span></span>def<br><${tag}></div>`,
|
|
],
|
|
`The text should be inserted after the previous empty inline element of <${tag}> even if the empty element follows a text node`
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
`<div>abcdef<span></span><${tag}></div>`,
|
|
`<div>abcdef<span></span><${tag}><br></div>`,
|
|
],
|
|
`The text should be inserted before the previous empty inline element of <${tag}>`
|
|
);
|
|
}
|
|
}, `Inserting text when selection is collapsed in <${tag}> which follows a text node and an empty <span> element`);
|
|
|
|
test(() => {
|
|
editor.innerHTML = `<div><span>abc</span></div>`;
|
|
const element = document.createElement(tag);
|
|
editor.firstChild.appendChild(element);
|
|
editor.focus();
|
|
const selection = getSelection();
|
|
selection.collapse(element, 0);
|
|
document.execCommand("insertText", false, "def");
|
|
if (tag == "br") {
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
"<div><span>abcdef</span></div>",
|
|
"<div><span>abcdef</span><br></div>",
|
|
],
|
|
`The text should be inserted at end of the text node in <span>`
|
|
);
|
|
} else if (tag == "hr") { // block
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
`<div><span>abc</span>def<${tag}></div>`,
|
|
`<div><span>abc</span>def<br><${tag}></div>`,
|
|
],
|
|
`The text should be inserted at after the span and before <${tag}>`
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
`<div><span>abcdef</span><${tag}></div>`,
|
|
`<div><span>abcdef</span><${tag}><br></div>`,
|
|
],
|
|
`The text should be inserted at end of the text node in <span> before <${tag}>`
|
|
);
|
|
}
|
|
}, `Inserting text when selection is collapsed in <${tag}> which follows a non-empty <span> element`);
|
|
|
|
test(() => {
|
|
editor.innerHTML = `<div>abc<span></span>\n</div>`;
|
|
const element = document.createElement(tag);
|
|
editor.firstChild.appendChild(element);
|
|
editor.focus();
|
|
const selection = getSelection();
|
|
selection.collapse(element, 0);
|
|
document.execCommand("insertText", false, "def");
|
|
if (tag == "br") {
|
|
assert_in_array(
|
|
editor.innerHTML.replace(/\n/g, " "),
|
|
[
|
|
"<div>abcdef<span></span></div>",
|
|
"<div>abcdef<span></span><br></div>",
|
|
"<div>abcdef<span></span> </div>",
|
|
"<div>abcdef<span></span> <br></div>",
|
|
],
|
|
`The text should be inserted at end of the first text node with ignoring the empty <span> and invisible text node before <br>`
|
|
);
|
|
} else if (tag == "img" || tag == "input") { // visible inline
|
|
assert_in_array(
|
|
editor.innerHTML.replace(/\n/g, " "),
|
|
[
|
|
`<div>abc<span></span> def<${tag}></div>`,
|
|
`<div>abc<span></span> def<${tag}><br></div>`,
|
|
`<div>abc<span></span> def<${tag}></div>`,
|
|
`<div>abc<span></span> def<${tag}><br></div>`,
|
|
],
|
|
`The text should be inserted at end of the last visible text node`
|
|
);
|
|
} else if (tag == "hr") { // block
|
|
assert_in_array(
|
|
editor.innerHTML,
|
|
[
|
|
`<div>abc<span></span>def<${tag}></div>`,
|
|
`<div>abc<span></span>def<br><${tag}></div>`,
|
|
],
|
|
`The text should be inserted after the previous empty inline element`
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
editor.innerHTML.replace(/\n/g, " "),
|
|
[
|
|
`<div>abcdef<span></span> <${tag}></div>`,
|
|
`<div>abcdef<span></span> <${tag}><br></div>`,
|
|
],
|
|
`The text should be inserted before the previous empty inline element`
|
|
);
|
|
}
|
|
}, `Inserting text when selection is collapsed in <${tag}> which follows a text node, an empty <span> element and white-space only text node`);
|
|
}
|
|
|
|
</script> |