258 lines
9.9 KiB
HTML
258 lines
9.9 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>Pasting rich text into contenteditable=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";
|
|
|
|
addEventListener("load", () => {
|
|
const placeholderForCopy = document.createElement("div");
|
|
document.body.appendChild(placeholderForCopy);
|
|
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);
|
|
let lastBeforeInput;
|
|
editingHost.addEventListener("beforeinput", event => lastBeforeInput = event);
|
|
|
|
/**
|
|
* Pasting HTML into contenteditable=plaintext-only should work as pasting
|
|
* text which is serialized by the browser or OS. Then, `beforeinput` event
|
|
* should have only dataTransfer and it should have "text/html" format to
|
|
* make it possible that web apps can serialize the data by themselves to
|
|
* avoid the browser/OS dependency. Finally, if white-space style is normal,
|
|
* line breaks should appear as <br>. Otherwise, either <br> or \n is fine
|
|
* because both breaks the lines.
|
|
*/
|
|
|
|
promise_test(async t => {
|
|
placeholderForCopy.innerHTML = "<b>abc</b>";
|
|
document.activeElement?.blur();
|
|
await test_driver.click(placeholderForCopy);
|
|
getSelection().selectAllChildren(placeholderForCopy);
|
|
await utils.sendCopyShortcutKey();
|
|
utils.setupEditingHost("A[]B");
|
|
lastBeforeInput = undefined;
|
|
await utils.sendPasteShortcutKey();
|
|
test(() => {
|
|
assert_equals(lastBeforeInput?.inputType, "insertFromPaste", `inputType should be "insertFromPaste"`);
|
|
assert_equals(lastBeforeInput?.data, null, `data should be null`);
|
|
assert_true(
|
|
String(lastBeforeInput?.dataTransfer?.getData("text/html")).includes(placeholderForCopy.innerHTML),
|
|
`dataTransfer should have the copied HTML source`
|
|
);
|
|
}, `${t.name}: beforeinput`);
|
|
test(() => {
|
|
assert_equals(editingHost.innerHTML, "AabcB", "<b> should not be pasted");
|
|
}, `${t.name}: pasted result`);
|
|
}, "Pasting text in <b>");
|
|
|
|
promise_test(async t => {
|
|
placeholderForCopy.innerHTML = "<span>abc</span>";
|
|
document.activeElement?.blur();
|
|
await test_driver.click(placeholderForCopy);
|
|
getSelection().selectAllChildren(placeholderForCopy);
|
|
await utils.sendCopyShortcutKey();
|
|
utils.setupEditingHost("A[]B");
|
|
lastBeforeInput = undefined;
|
|
await utils.sendPasteShortcutKey();
|
|
test(() => {
|
|
assert_equals(lastBeforeInput?.inputType, "insertFromPaste", `inputType should be "insertFromPaste"`);
|
|
assert_equals(lastBeforeInput?.data, null, `data should be null`);
|
|
assert_true(
|
|
String(lastBeforeInput?.dataTransfer?.getData("text/html")).includes(placeholderForCopy.innerHTML),
|
|
`dataTransfer should have the copied HTML source`
|
|
);
|
|
}, `${t.name}: beforeinput`);
|
|
test(() => {
|
|
assert_equals(editingHost.innerHTML, "AabcB", "<span> should not be pasted");
|
|
}, `${t.name}: pasted result`);
|
|
}, "Pasting text in <span>");
|
|
|
|
promise_test(async t => {
|
|
placeholderForCopy.innerHTML = "abc";
|
|
document.activeElement?.blur();
|
|
await test_driver.click(placeholderForCopy);
|
|
getSelection().selectAllChildren(placeholderForCopy);
|
|
await utils.sendCopyShortcutKey();
|
|
utils.setupEditingHost("<b>A[]B</b>");
|
|
lastBeforeInput = undefined;
|
|
await utils.sendPasteShortcutKey();
|
|
test(() => {
|
|
assert_equals(lastBeforeInput?.inputType, "insertFromPaste", `inputType should be "insertFromPaste"`);
|
|
assert_equals(lastBeforeInput?.data, null, `data should be null`);
|
|
assert_true(
|
|
String(lastBeforeInput?.dataTransfer?.getData("text/html")).includes(placeholderForCopy.innerHTML),
|
|
`dataTransfer should have the copied HTML source`
|
|
);
|
|
}, `${t.name}: beforeinput`);
|
|
test(() => {
|
|
assert_equals(editingHost.innerHTML, "<b>AabcB</b>", "text should be inserted into the editable <b>");
|
|
}, `${t.name}: pasted result`);
|
|
}, "Pasting text into editable <b>");
|
|
|
|
promise_test(async t => {
|
|
placeholderForCopy.innerHTML = "<i>abc</i>";
|
|
document.activeElement?.blur();
|
|
await test_driver.click(placeholderForCopy);
|
|
getSelection().selectAllChildren(placeholderForCopy);
|
|
await utils.sendCopyShortcutKey();
|
|
utils.setupEditingHost("<b>A[]B</b>");
|
|
lastBeforeInput = undefined;
|
|
await utils.sendPasteShortcutKey();
|
|
test(() => {
|
|
assert_equals(lastBeforeInput?.inputType, "insertFromPaste", `inputType should be "insertFromPaste"`);
|
|
assert_equals(lastBeforeInput?.data, null, `data should be null`);
|
|
assert_true(
|
|
String(lastBeforeInput?.dataTransfer?.getData("text/html")).includes(placeholderForCopy.innerHTML),
|
|
`dataTransfer should have the copied HTML source`
|
|
);
|
|
}, `${t.name}: beforeinput`);
|
|
test(() => {
|
|
assert_equals(editingHost.innerHTML, "<b>AabcB</b>", "text should be inserted into the editable <b> without copied <i>");
|
|
}, `${t.name}: pasted result`);
|
|
}, "Pasting text in <i> into editable <b>");
|
|
|
|
promise_test(async t => {
|
|
placeholderForCopy.innerHTML = "<div>abc</div><div>def</div>";
|
|
document.activeElement?.blur();
|
|
await test_driver.click(placeholderForCopy);
|
|
getSelection().selectAllChildren(placeholderForCopy);
|
|
await utils.sendCopyShortcutKey();
|
|
utils.setupEditingHost("A[]B");
|
|
lastBeforeInput = undefined;
|
|
await utils.sendPasteShortcutKey();
|
|
test(() => {
|
|
assert_equals(lastBeforeInput?.inputType, "insertFromPaste", `inputType should be "insertFromPaste"`);
|
|
assert_equals(lastBeforeInput?.data, null, `data should be null`);
|
|
assert_true(
|
|
String(lastBeforeInput?.dataTransfer?.getData("text/html")).includes(placeholderForCopy.innerHTML),
|
|
`dataTransfer should have the copied HTML source`
|
|
);
|
|
}, `${t.name}: beforeinput`);
|
|
test(() => {
|
|
if (useBR) {
|
|
assert_in_array(
|
|
editingHost.innerHTML,
|
|
[
|
|
"Aabc<br>defB",
|
|
"A<br>abc<br>def<br>B",
|
|
],
|
|
"Each paragraph should be pasted as a line"
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
editingHost.innerHTML,
|
|
[
|
|
"Aabc\ndefB",
|
|
"A\nabc\ndef\nB",
|
|
],
|
|
"Each paragraph should be pasted as a line"
|
|
);
|
|
}
|
|
}, `${t.name}: pasted result`);
|
|
}, "Pasting 2 paragraphs");
|
|
|
|
promise_test(async t => {
|
|
placeholderForCopy.innerHTML = "<div>abc</div><div>def</div>";
|
|
document.activeElement?.blur();
|
|
await test_driver.click(placeholderForCopy);
|
|
getSelection().selectAllChildren(placeholderForCopy);
|
|
await utils.sendCopyShortcutKey();
|
|
utils.setupEditingHost("<b>A[]B</b>");
|
|
lastBeforeInput = undefined;
|
|
await utils.sendPasteShortcutKey();
|
|
test(() => {
|
|
assert_equals(lastBeforeInput?.inputType, "insertFromPaste", `inputType should be "insertFromPaste"`);
|
|
assert_equals(lastBeforeInput?.data, null, `data should be null`);
|
|
assert_true(
|
|
String(lastBeforeInput?.dataTransfer?.getData("text/html")).includes(placeholderForCopy.innerHTML),
|
|
`dataTransfer should have the copied HTML source`
|
|
);
|
|
}, `${t.name}: beforeinput`);
|
|
test(() => {
|
|
if (useBR) {
|
|
assert_in_array(
|
|
editingHost.innerHTML,
|
|
[
|
|
"<b>Aabc<br>defB</b>",
|
|
"<b>A<br>abc<br>def<br>B</b>",
|
|
],
|
|
"Each paragraph should be pasted as a line"
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
editingHost.innerHTML,
|
|
[
|
|
"<b>Aabc\ndefB</b>",
|
|
"<b>A\nabc\ndef\nB</b>",
|
|
],
|
|
"Each paragraph should be pasted as a line"
|
|
);
|
|
}
|
|
}, `${t.name}: pasted result`);
|
|
}, "Pasting 2 paragraphs into <b>");
|
|
|
|
promise_test(async t => {
|
|
placeholderForCopy.innerHTML = "<div><b>abc</b></div><div><b>def</b></div>";
|
|
document.activeElement?.blur();
|
|
await test_driver.click(placeholderForCopy);
|
|
getSelection().selectAllChildren(placeholderForCopy);
|
|
await utils.sendCopyShortcutKey();
|
|
utils.setupEditingHost("A[]B");
|
|
lastBeforeInput = undefined;
|
|
await utils.sendPasteShortcutKey();
|
|
test(() => {
|
|
assert_equals(lastBeforeInput?.inputType, "insertFromPaste", `inputType should be "insertFromPaste"`);
|
|
assert_equals(lastBeforeInput?.data, null, `data should be null`);
|
|
assert_true(
|
|
String(lastBeforeInput?.dataTransfer?.getData("text/html")).includes(placeholderForCopy.innerHTML),
|
|
`dataTransfer should have the copied HTML source`
|
|
);
|
|
}, `${t.name}: beforeinput`);
|
|
test(() => {
|
|
if (useBR) {
|
|
assert_in_array(
|
|
editingHost.innerHTML,
|
|
[
|
|
"Aabc<br>defB",
|
|
"A<br>abc<br>def<br>B",
|
|
],
|
|
"Each paragraph should be pasted as a line"
|
|
);
|
|
} else {
|
|
assert_in_array(
|
|
editingHost.innerHTML,
|
|
[
|
|
"Aabc\ndefB",
|
|
"A\nabc\ndef\nB",
|
|
],
|
|
"Each paragraph should be pasted as a line"
|
|
);
|
|
}
|
|
}, `${t.name}: pasted result`);
|
|
}, "Pasting 2 paragraphs whose text is bold");
|
|
}, {once: true});
|
|
</script>
|
|
</head>
|
|
<body></body>
|
|
</html>
|