paste.https.html (10112B)
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <meta name="timeout" content="long"> 6 <meta name="variant" content="?white-space=normal"> 7 <meta name="variant" content="?white-space=pre"> 8 <meta name="variant" content="?white-space=pre-line"> 9 <meta name="variant" content="?white-space=pre-wrap"> 10 <title>Pasting rich text into contenteditable=plaintext-only</title> 11 <script src="/resources/testharness.js"></script> 12 <script src="/resources/testharnessreport.js"></script> 13 <script src="/resources/testdriver.js"></script> 14 <script src="/resources/testdriver-vendor.js"></script> 15 <script src="/resources/testdriver-actions.js"></script> 16 <script src="../include/editor-test-utils.js"></script> 17 <script> 18 "use strict"; 19 20 const searchParams = new URLSearchParams(document.location.search); 21 const whiteSpace = searchParams.get("white-space"); 22 const useBR = whiteSpace == "normal"; 23 24 addEventListener("load", () => { 25 const placeholderForCopy = document.createElement("div"); 26 document.body.appendChild(placeholderForCopy); 27 const editingHost = document.createElement("div"); 28 editingHost.style.whiteSpace = whiteSpace; 29 editingHost.setAttribute("contenteditable", "plaintext-only"); 30 document.body.appendChild(editingHost); 31 editingHost.focus(); 32 editingHost.getBoundingClientRect(); 33 const utils = new EditorTestUtils(editingHost); 34 let lastBeforeInput; 35 editingHost.addEventListener("beforeinput", event => lastBeforeInput = event); 36 37 /** 38 * Pasting HTML into contenteditable=plaintext-only should work as pasting 39 * text which is serialized by the browser or OS. Then, `beforeinput` event 40 * should have only dataTransfer and it should have "text/html" format to 41 * make it possible that web apps can serialize the data by themselves to 42 * avoid the browser/OS dependency. Finally, if white-space style is normal, 43 * line breaks should appear as <br>. Otherwise, either <br> or \n is fine 44 * because both breaks the lines. 45 */ 46 47 promise_test(async t => { 48 placeholderForCopy.innerHTML = "<b>abc</b>"; 49 document.activeElement?.blur(); 50 await test_driver.click(placeholderForCopy); 51 getSelection().selectAllChildren(placeholderForCopy); 52 await utils.sendCopyShortcutKey(); 53 utils.setupEditingHost("A[]B"); 54 lastBeforeInput = undefined; 55 await utils.sendPasteShortcutKey(); 56 test(() => { 57 assert_equals(lastBeforeInput?.inputType, "insertFromPaste", `inputType should be "insertFromPaste"`); 58 assert_equals(lastBeforeInput?.data, null, `data should be null`); 59 assert_true( 60 String(lastBeforeInput?.dataTransfer?.getData("text/html")).includes(placeholderForCopy.innerHTML), 61 `dataTransfer should have the copied HTML source` 62 ); 63 }, `${t.name}: beforeinput`); 64 test(() => { 65 assert_equals(editingHost.innerHTML, "AabcB", "<b> should not be pasted"); 66 }, `${t.name}: pasted result`); 67 }, "Pasting text in <b>"); 68 69 promise_test(async t => { 70 placeholderForCopy.innerHTML = "<span>abc</span>"; 71 document.activeElement?.blur(); 72 await test_driver.click(placeholderForCopy); 73 getSelection().selectAllChildren(placeholderForCopy); 74 await utils.sendCopyShortcutKey(); 75 utils.setupEditingHost("A[]B"); 76 lastBeforeInput = undefined; 77 await utils.sendPasteShortcutKey(); 78 test(() => { 79 assert_equals(lastBeforeInput?.inputType, "insertFromPaste", `inputType should be "insertFromPaste"`); 80 assert_equals(lastBeforeInput?.data, null, `data should be null`); 81 assert_true( 82 String(lastBeforeInput?.dataTransfer?.getData("text/html")).includes(placeholderForCopy.innerHTML), 83 `dataTransfer should have the copied HTML source` 84 ); 85 }, `${t.name}: beforeinput`); 86 test(() => { 87 assert_equals(editingHost.innerHTML, "AabcB", "<span> should not be pasted"); 88 }, `${t.name}: pasted result`); 89 }, "Pasting text in <span>"); 90 91 promise_test(async t => { 92 placeholderForCopy.innerHTML = "abc"; 93 document.activeElement?.blur(); 94 await test_driver.click(placeholderForCopy); 95 getSelection().selectAllChildren(placeholderForCopy); 96 await utils.sendCopyShortcutKey(); 97 utils.setupEditingHost("<b>A[]B</b>"); 98 lastBeforeInput = undefined; 99 await utils.sendPasteShortcutKey(); 100 test(() => { 101 assert_equals(lastBeforeInput?.inputType, "insertFromPaste", `inputType should be "insertFromPaste"`); 102 assert_equals(lastBeforeInput?.data, null, `data should be null`); 103 assert_true( 104 String(lastBeforeInput?.dataTransfer?.getData("text/html")).includes(placeholderForCopy.innerHTML), 105 `dataTransfer should have the copied HTML source` 106 ); 107 }, `${t.name}: beforeinput`); 108 test(() => { 109 assert_equals(editingHost.innerHTML, "<b>AabcB</b>", "text should be inserted into the editable <b>"); 110 }, `${t.name}: pasted result`); 111 }, "Pasting text into editable <b>"); 112 113 promise_test(async t => { 114 placeholderForCopy.innerHTML = "<i>abc</i>"; 115 document.activeElement?.blur(); 116 await test_driver.click(placeholderForCopy); 117 getSelection().selectAllChildren(placeholderForCopy); 118 await utils.sendCopyShortcutKey(); 119 utils.setupEditingHost("<b>A[]B</b>"); 120 lastBeforeInput = undefined; 121 await utils.sendPasteShortcutKey(); 122 test(() => { 123 assert_equals(lastBeforeInput?.inputType, "insertFromPaste", `inputType should be "insertFromPaste"`); 124 assert_equals(lastBeforeInput?.data, null, `data should be null`); 125 assert_true( 126 String(lastBeforeInput?.dataTransfer?.getData("text/html")).includes(placeholderForCopy.innerHTML), 127 `dataTransfer should have the copied HTML source` 128 ); 129 }, `${t.name}: beforeinput`); 130 test(() => { 131 assert_equals(editingHost.innerHTML, "<b>AabcB</b>", "text should be inserted into the editable <b> without copied <i>"); 132 }, `${t.name}: pasted result`); 133 }, "Pasting text in <i> into editable <b>"); 134 135 promise_test(async t => { 136 placeholderForCopy.innerHTML = "<div>abc</div><div>def</div>"; 137 document.activeElement?.blur(); 138 await test_driver.click(placeholderForCopy); 139 getSelection().selectAllChildren(placeholderForCopy); 140 await utils.sendCopyShortcutKey(); 141 utils.setupEditingHost("A[]B"); 142 lastBeforeInput = undefined; 143 await utils.sendPasteShortcutKey(); 144 test(() => { 145 assert_equals(lastBeforeInput?.inputType, "insertFromPaste", `inputType should be "insertFromPaste"`); 146 assert_equals(lastBeforeInput?.data, null, `data should be null`); 147 assert_true( 148 String(lastBeforeInput?.dataTransfer?.getData("text/html")).includes(placeholderForCopy.innerHTML), 149 `dataTransfer should have the copied HTML source` 150 ); 151 }, `${t.name}: beforeinput`); 152 test(() => { 153 if (useBR) { 154 assert_in_array( 155 editingHost.innerHTML, 156 [ 157 "Aabc<br>defB", 158 "A<br>abc<br>def<br>B", 159 ], 160 "Each paragraph should be pasted as a line" 161 ); 162 } else { 163 assert_in_array( 164 editingHost.innerHTML, 165 [ 166 "Aabc\ndefB", 167 "A\nabc\ndef\nB", 168 ], 169 "Each paragraph should be pasted as a line" 170 ); 171 } 172 }, `${t.name}: pasted result`); 173 }, "Pasting 2 paragraphs"); 174 175 promise_test(async t => { 176 placeholderForCopy.innerHTML = "<div>abc</div><div>def</div>"; 177 document.activeElement?.blur(); 178 await test_driver.click(placeholderForCopy); 179 getSelection().selectAllChildren(placeholderForCopy); 180 await utils.sendCopyShortcutKey(); 181 utils.setupEditingHost("<b>A[]B</b>"); 182 lastBeforeInput = undefined; 183 await utils.sendPasteShortcutKey(); 184 test(() => { 185 assert_equals(lastBeforeInput?.inputType, "insertFromPaste", `inputType should be "insertFromPaste"`); 186 assert_equals(lastBeforeInput?.data, null, `data should be null`); 187 assert_true( 188 String(lastBeforeInput?.dataTransfer?.getData("text/html")).includes(placeholderForCopy.innerHTML), 189 `dataTransfer should have the copied HTML source` 190 ); 191 }, `${t.name}: beforeinput`); 192 test(() => { 193 if (useBR) { 194 assert_in_array( 195 editingHost.innerHTML, 196 [ 197 "<b>Aabc<br>defB</b>", 198 "<b>A<br>abc<br>def<br>B</b>", 199 ], 200 "Each paragraph should be pasted as a line" 201 ); 202 } else { 203 assert_in_array( 204 editingHost.innerHTML, 205 [ 206 "<b>Aabc\ndefB</b>", 207 "<b>A\nabc\ndef\nB</b>", 208 ], 209 "Each paragraph should be pasted as a line" 210 ); 211 } 212 }, `${t.name}: pasted result`); 213 }, "Pasting 2 paragraphs into <b>"); 214 215 promise_test(async t => { 216 placeholderForCopy.innerHTML = "<div><b>abc</b></div><div><b>def</b></div>"; 217 document.activeElement?.blur(); 218 await test_driver.click(placeholderForCopy); 219 getSelection().selectAllChildren(placeholderForCopy); 220 await utils.sendCopyShortcutKey(); 221 utils.setupEditingHost("A[]B"); 222 lastBeforeInput = undefined; 223 await utils.sendPasteShortcutKey(); 224 test(() => { 225 assert_equals(lastBeforeInput?.inputType, "insertFromPaste", `inputType should be "insertFromPaste"`); 226 assert_equals(lastBeforeInput?.data, null, `data should be null`); 227 assert_true( 228 String(lastBeforeInput?.dataTransfer?.getData("text/html")).includes(placeholderForCopy.innerHTML), 229 `dataTransfer should have the copied HTML source` 230 ); 231 }, `${t.name}: beforeinput`); 232 test(() => { 233 if (useBR) { 234 assert_in_array( 235 editingHost.innerHTML, 236 [ 237 "Aabc<br>defB", 238 "A<br>abc<br>def<br>B", 239 ], 240 "Each paragraph should be pasted as a line" 241 ); 242 } else { 243 assert_in_array( 244 editingHost.innerHTML, 245 [ 246 "Aabc\ndefB", 247 "A\nabc\ndef\nB", 248 ], 249 "Each paragraph should be pasted as a line" 250 ); 251 } 252 }, `${t.name}: pasted result`); 253 }, "Pasting 2 paragraphs whose text is bold"); 254 }, {once: true}); 255 </script> 256 </head> 257 <body></body> 258 </html>