Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!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>