delete-in-child-of-head.tentative.html (17427B)
1 <!doctype html> 2 <html> 3 <head> 4 <meta chareset="utf-8"> 5 <meta name="timeout" content="long"> 6 <meta name="variant" content="?designMode=off&method=backspace"> 7 <meta name="variant" content="?designMode=off&method=forwarddelete"> 8 <meta name="variant" content="?designMode=on&method=backspace"> 9 <meta name="variant" content="?designMode=on&method=forwarddelete"> 10 <title>Join paragraphs in the head element</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 </head> 18 <body> 19 <iframe srcdoc=""></iframe> 20 <script> 21 "use strict"; 22 23 const searchParams = new URLSearchParams(document.location.search); 24 const testingBackspace = searchParams.get("method") == "backspace"; 25 const commandName = testingBackspace ? "delete" : "forwarddelete"; 26 const testingDesignMode = searchParams.get("designMode") == "on"; 27 28 const iframe = document.querySelector("iframe"); 29 const minimumSrcDoc = 30 "<html>" + 31 '<head style="display:block">' + 32 "<title>iframe</title>" + 33 "<script src='/resources/testdriver.js'></" + "script>" + 34 "<script src='/resources/testdriver-vendor.js'></" + "script>" + 35 "<script src='/resources/testdriver-actions.js'></" + "script>" + 36 "</head>" + 37 "<body><br></body>" + 38 "</html>"; 39 40 async function initializeAndWaitForLoad(iframeElement, srcDocValue) { 41 const waitForLoad = 42 new Promise( 43 resolve => iframeElement.addEventListener("load", resolve, {once: true}) 44 ); 45 iframeElement.srcdoc = srcDocValue; 46 await waitForLoad; 47 if (testingDesignMode) { 48 iframeElement.contentDocument.designMode = "on"; 49 } else { 50 iframeElement.contentDocument.documentElement.setAttribute("contenteditable", ""); 51 } 52 iframeElement.contentWindow.focus(); 53 iframeElement.contentDocument.execCommand("defaultParagraphSeparator", false, "div"); 54 } 55 56 function removeResourceScriptElements(node) { 57 node.querySelectorAll("script").forEach( 58 element => { 59 if (element.getAttribute("src")?.startsWith("/resources")) { 60 element.remove() 61 } 62 } 63 ); 64 } 65 66 // DO NOT USE multi-line comment in this file, then, you can comment out 67 // unnecessary tests when you need to attach the browser with a debugger. 68 69 // For backward compatibility, normal block elements in <head> should be 70 // joined by deletion. 71 promise_test(async () => { 72 await initializeAndWaitForLoad(iframe, minimumSrcDoc); 73 const childDoc = iframe.contentDocument; 74 const utils = new EditorTestUtils(childDoc.documentElement); 75 const div1 = childDoc.createElement("div"); 76 div1.innerHTML = "abc"; 77 const div2 = childDoc.createElement("div"); 78 div2.innerHTML = "def"; 79 childDoc.head.appendChild(div1); 80 childDoc.head.appendChild(div2); 81 // Now: <head><title>...</title><div>abc</div><div>def</div></head>... 82 childDoc.getSelection().collapse( 83 testingBackspace ? div2.firstChild : div1.firstChild, 84 testingBackspace ? 0 : div1.firstChild.length 85 ); 86 await (testingBackspace ? utils.sendBackspaceKey() : utils.sendDeleteKey()); 87 removeResourceScriptElements(childDoc); 88 childDoc.head.removeAttribute("style"); 89 90 assert_in_array( 91 childDoc.documentElement.innerHTML, 92 [ 93 '<head><title>iframe</title><div>abcdef</div></head><body><br></body>', 94 '<head><title>iframe</title><div>abcdef<br></div></head><body><br></body>', 95 ], 96 "The <div> elements should be merged" 97 ); 98 assert_equals( 99 div1.isConnected ^ div2.isConnected, 100 1, 101 "One <div> element should be removed, and the other should stay" 102 ); 103 }, `${commandName} in <div> elements in <head> should join them`); 104 105 // The following void elements shouldn't be deleted for avoiding various 106 // affection to the document. 107 for (const tag of ["meta", "title", "style", "script", "link", "base", "template"]) { 108 promise_test(async () => { 109 await initializeAndWaitForLoad(iframe, minimumSrcDoc); 110 const childDoc = iframe.contentDocument; 111 const utils = new EditorTestUtils(childDoc.documentElement); 112 const div1 = childDoc.createElement("div"); 113 div1.innerHTML = "abc"; 114 const div2 = childDoc.createElement("div"); 115 div2.innerHTML = "def"; 116 const element = childDoc.createElement(tag); 117 childDoc.head.appendChild(div1); 118 childDoc.head.appendChild(element); 119 childDoc.head.appendChild(div2); 120 // Now: <head><title>...</title><div>abc</div><tag/><div>def</div></head>... 121 childDoc.getSelection().collapse( 122 testingBackspace ? div2.firstChild : div1.firstChild, 123 testingBackspace ? 0 : div1.firstChild.length 124 ); 125 await (testingBackspace ? utils.sendBackspaceKey() : utils.sendDeleteKey()); 126 removeResourceScriptElements(childDoc); 127 childDoc.head.removeAttribute("style"); 128 129 if (["title", "style", "script", "template"].includes(tag)) { 130 assert_in_array( 131 childDoc.documentElement.innerHTML, 132 [ 133 `<head><title>iframe</title><div>abcdef</div><${tag}></${tag}></head><body><br></body>`, 134 `<head><title>iframe</title><div>abcdef<br></div><${tag}></${tag}></head><body><br></body>`, 135 `<head><title>iframe</title><${tag}></${tag}><div>abcdef</div></head><body><br></body>`, 136 `<head><title>iframe</title><${tag}></${tag}><div>abcdef<br></div></head><body><br></body>`, 137 ], 138 `The <div> elements should be merged without deleting <${tag}>` 139 ); 140 } else { 141 assert_in_array( 142 childDoc.documentElement.innerHTML, 143 [ 144 `<head><title>iframe</title><div>abcdef</div><${tag}></head><body><br></body>`, 145 `<head><title>iframe</title><div>abcdef<br></div><${tag}></head><body><br></body>`, 146 `<head><title>iframe</title><${tag}><div>abcdef</div></head><body><br></body>`, 147 `<head><title>iframe</title><${tag}><div>abcdef<br></div></head><body><br></body>`, 148 ], 149 `The <div> elements should be merged without deleting <${tag}>` 150 ); 151 } 152 }, `${commandName} around invisible <${tag}> should not delete it at joining paragraphs`); 153 } 154 155 // Visible <script>, <style>, <title> elements shouldn't be joined 156 promise_test(async () => { 157 await initializeAndWaitForLoad(iframe, minimumSrcDoc); 158 const childDoc = iframe.contentDocument; 159 const utils = new EditorTestUtils(childDoc.documentElement); 160 const script1 = childDoc.createElement("script"); 161 script1.innerHTML = "// abc"; 162 script1.setAttribute("style", "display:block"); 163 const script2 = childDoc.createElement("script"); 164 script2.innerHTML = "// def"; 165 script2.setAttribute("style", "display:block"); 166 childDoc.head.appendChild(script1); 167 childDoc.head.appendChild(script2); 168 // Now: <head><title>...</title><script>// abc</ script><script>// def</ script></head>... 169 childDoc.getSelection().collapse( 170 testingBackspace ? script2.firstChild : script1.firstChild, 171 testingBackspace ? 0 : script1.firstChild.length 172 ); 173 await (testingBackspace ? utils.sendBackspaceKey() : utils.sendDeleteKey()); 174 removeResourceScriptElements(childDoc); 175 childDoc.head.removeAttribute("style"); 176 script1.removeAttribute("style"); 177 script2.removeAttribute("style"); 178 179 assert_equals( 180 childDoc.documentElement.innerHTML, 181 "<head><title>iframe</title><script>// abc</" + "script><script>// def</" + "script></head><body><br></body>", 182 "Visible <script> elements shouldn't be merged" 183 ); 184 }, `${commandName} in visible <script> elements in <head> should not join them`); 185 186 promise_test(async () => { 187 await initializeAndWaitForLoad(iframe, minimumSrcDoc); 188 const childDoc = iframe.contentDocument; 189 const utils = new EditorTestUtils(childDoc.documentElement); 190 const style1 = childDoc.createElement("style"); 191 style1.innerHTML = "abc"; 192 style1.setAttribute("style", "display:block"); 193 const style2 = childDoc.createElement("style"); 194 style2.innerHTML = "def"; 195 style2.setAttribute("style", "display:block"); 196 childDoc.head.appendChild(style1); 197 childDoc.head.appendChild(style2); 198 // Now: <head><title>...</title><style>abc</style><style>def</style></head>... 199 childDoc.getSelection().collapse( 200 testingBackspace ? style2.firstChild : style1.firstChild, 201 testingBackspace ? 0 : style1.firstChild.length 202 ); 203 await (testingBackspace ? utils.sendBackspaceKey() : utils.sendDeleteKey()); 204 removeResourceScriptElements(childDoc); 205 childDoc.head.removeAttribute("style"); 206 style1.removeAttribute("style"); 207 style2.removeAttribute("style"); 208 209 assert_equals( 210 childDoc.documentElement.innerHTML, 211 "<head><title>iframe</title><style>abc</style><style>def</style></head><body><br></body>", 212 "Visible <style> elements shouldn't be merged" 213 ); 214 }, `${commandName} in visible <style> elements in <head> should not join them`); 215 216 promise_test(async () => { 217 await initializeAndWaitForLoad(iframe, minimumSrcDoc); 218 const childDoc = iframe.contentDocument; 219 const utils = new EditorTestUtils(childDoc.documentElement); 220 const title1 = childDoc.createElement("title"); 221 title1.innerHTML = "abc"; 222 title1.setAttribute("style", "display:block"); 223 const title2 = childDoc.createElement("title"); 224 title2.innerHTML = "def"; 225 title2.setAttribute("style", "display:block"); 226 childDoc.head.appendChild(title1); 227 childDoc.head.appendChild(title2); 228 // Now: <head><title>...</title><title>abc</title><title>def</title></head>... 229 childDoc.getSelection().collapse( 230 testingBackspace ? title2.firstChild : title1.firstChild, 231 testingBackspace ? 0 : title1.firstChild.length 232 ); 233 await (testingBackspace ? utils.sendBackspaceKey() : utils.sendDeleteKey()); 234 removeResourceScriptElements(childDoc); 235 childDoc.head.removeAttribute("style"); 236 title1.removeAttribute("style"); 237 title2.removeAttribute("style"); 238 239 assert_equals( 240 childDoc.documentElement.innerHTML, 241 "<head><title>iframe</title><title>abc</title><title>def</title></head><body><br></body>", 242 "Visible <title> elements shouldn't be merged" 243 ); 244 }, `${commandName} in visible <title> elements in <head> should not join them`); 245 246 // Visible <script>, <style>, <title> shouldn't be joined with following <div> 247 promise_test(async () => { 248 await initializeAndWaitForLoad(iframe, minimumSrcDoc); 249 const childDoc = iframe.contentDocument; 250 const utils = new EditorTestUtils(childDoc.documentElement); 251 const script = childDoc.createElement("script"); 252 script.innerHTML = "// abc"; 253 script.setAttribute("style", "display:block"); 254 const div = childDoc.createElement("div"); 255 div.innerHTML = "// def"; 256 childDoc.head.appendChild(script); 257 childDoc.head.appendChild(div); 258 // Now: <head><title>...</title><script>// abc</ script><div>// def</div></head>... 259 childDoc.getSelection().collapse( 260 testingBackspace ? div.firstChild : script.firstChild, 261 testingBackspace ? 0 : script.firstChild.length 262 ); 263 await (testingBackspace ? utils.sendBackspaceKey() : utils.sendDeleteKey()); 264 removeResourceScriptElements(childDoc); 265 childDoc.head.removeAttribute("style"); 266 script.removeAttribute("style"); 267 268 assert_equals( 269 childDoc.documentElement.innerHTML, 270 "<head><title>iframe</title><script>// abc</" + "script><div>// def</div></head><body><br></body>", 271 "Visible <script> and <div> shouldn't be merged" 272 ); 273 }, `${commandName} at boundary of <script> and <div> in <head> should not join them`); 274 275 promise_test(async () => { 276 await initializeAndWaitForLoad(iframe, minimumSrcDoc); 277 const childDoc = iframe.contentDocument; 278 const utils = new EditorTestUtils(childDoc.documentElement); 279 const style = childDoc.createElement("style"); 280 style.innerHTML = "abc"; 281 style.setAttribute("style", "display:block"); 282 const div = childDoc.createElement("div"); 283 div.innerHTML = "def"; 284 childDoc.head.appendChild(style); 285 childDoc.head.appendChild(div); 286 // Now: <head><title>...</title><style>abc</style><div>def</div></head>... 287 childDoc.getSelection().collapse( 288 testingBackspace ? div.firstChild : style.firstChild, 289 testingBackspace ? 0 : style.firstChild.length 290 ); 291 await (testingBackspace ? utils.sendBackspaceKey() : utils.sendDeleteKey()); 292 removeResourceScriptElements(childDoc); 293 childDoc.head.removeAttribute("style"); 294 style.removeAttribute("style"); 295 296 assert_equals( 297 childDoc.documentElement.innerHTML, 298 "<head><title>iframe</title><style>abc</style><div>def</div></head><body><br></body>", 299 "Visible <style> and <div> shouldn't be merged" 300 ); 301 }, `${commandName} at boundary of <style> and <div> in <head> should not join them`); 302 303 promise_test(async () => { 304 await initializeAndWaitForLoad(iframe, minimumSrcDoc); 305 const childDoc = iframe.contentDocument; 306 const utils = new EditorTestUtils(childDoc.documentElement); 307 const title = childDoc.createElement("title"); 308 title.innerHTML = "abc"; 309 title.setAttribute("title", "display:block"); 310 const div = childDoc.createElement("div"); 311 div.innerHTML = "def"; 312 childDoc.head.appendChild(title); 313 childDoc.head.appendChild(div); 314 // Now: <head><title>...</title><title>abc</title><div>def</div></head>... 315 childDoc.getSelection().collapse( 316 testingBackspace ? div.firstChild : title.firstChild, 317 testingBackspace ? 0 : title.firstChild.length 318 ); 319 await (testingBackspace ? utils.sendBackspaceKey() : utils.sendDeleteKey()); 320 removeResourceScriptElements(childDoc); 321 childDoc.head.removeAttribute("style"); 322 title.removeAttribute("style"); 323 324 assert_equals( 325 childDoc.documentElement.innerHTML, 326 "<head><title>iframe</title><title>abc</title><div>def</div></head><body><br></body>", 327 "Visible <title> and <div> shouldn't be merged" 328 ); 329 }, `${commandName} at boundary of <title> and <div> in <head> should not join them`); 330 331 // Visible <script>, <style>, <title> shouldn't be joined with preceding <div> 332 promise_test(async () => { 333 await initializeAndWaitForLoad(iframe, minimumSrcDoc); 334 const childDoc = iframe.contentDocument; 335 const utils = new EditorTestUtils(childDoc.documentElement); 336 const div = childDoc.createElement("div"); 337 div.innerHTML = "// abc"; 338 const script = childDoc.createElement("script"); 339 script.innerHTML = "// def"; 340 script.setAttribute("style", "display:block"); 341 childDoc.head.appendChild(div); 342 childDoc.head.appendChild(script); 343 // Now: <head><title>...</title><div>// abc</div><script>// def</ script></head>... 344 childDoc.getSelection().collapse( 345 testingBackspace ? script.firstChild : div.firstChild, 346 testingBackspace ? 0 : div.firstChild.length 347 ); 348 await (testingBackspace ? utils.sendBackspaceKey() : utils.sendDeleteKey()); 349 removeResourceScriptElements(childDoc); 350 childDoc.head.removeAttribute("style"); 351 script.removeAttribute("style"); 352 353 assert_equals( 354 childDoc.documentElement.innerHTML, 355 "<head><title>iframe</title><div>// abc</div><script>// def</" + "script></head><body><br></body>", 356 "<div> and visible <script> shouldn't be merged" 357 ); 358 }, `${commandName} at boundary of <div> and <script> in <head> should not join them`); 359 360 promise_test(async () => { 361 await initializeAndWaitForLoad(iframe, minimumSrcDoc); 362 const childDoc = iframe.contentDocument; 363 const utils = new EditorTestUtils(childDoc.documentElement); 364 const div = childDoc.createElement("div"); 365 div.innerHTML = "abc"; 366 const style = childDoc.createElement("style"); 367 style.innerHTML = "def"; 368 style.setAttribute("style", "display:block"); 369 childDoc.head.appendChild(div); 370 childDoc.head.appendChild(style); 371 // Now: <head><title>...</title><div>abc</div><style>def</style></head>... 372 childDoc.getSelection().collapse( 373 testingBackspace ? style.firstChild : div.firstChild, 374 testingBackspace ? 0 : div.firstChild.length 375 ); 376 await (testingBackspace ? utils.sendBackspaceKey() : utils.sendDeleteKey()); 377 removeResourceScriptElements(childDoc); 378 childDoc.head.removeAttribute("style"); 379 style.removeAttribute("style"); 380 381 assert_equals( 382 childDoc.documentElement.innerHTML, 383 "<head><title>iframe</title><div>abc</div><style>def</style></head><body><br></body>", 384 "<div> and visible <style> shouldn't be merged" 385 ); 386 }, `${commandName} at boundary of <div> and <style> in <head> should not join them`); 387 388 promise_test(async () => { 389 await initializeAndWaitForLoad(iframe, minimumSrcDoc); 390 const childDoc = iframe.contentDocument; 391 const utils = new EditorTestUtils(childDoc.documentElement); 392 const div = childDoc.createElement("div"); 393 div.innerHTML = "abc"; 394 const title = childDoc.createElement("title"); 395 title.innerHTML = "def"; 396 title.setAttribute("style", "display:block"); 397 childDoc.head.appendChild(div); 398 childDoc.head.appendChild(title); 399 // Now: <head><title>...</title><div>abc</div><title>def</title></head>... 400 childDoc.getSelection().collapse( 401 testingBackspace ? title.firstChild : div.firstChild, 402 testingBackspace ? 0 : div.firstChild.length 403 ); 404 await (testingBackspace ? utils.sendBackspaceKey() : utils.sendDeleteKey()); 405 removeResourceScriptElements(childDoc); 406 childDoc.head.removeAttribute("style"); 407 title.removeAttribute("style"); 408 409 assert_equals( 410 childDoc.documentElement.innerHTML, 411 "<head><title>iframe</title><div>abc</div><title>def</title></head><body><br></body>", 412 "<div> and visible <title> shouldn't be merged" 413 ); 414 }, `${commandName} at boundary of <div> and <title> in <head> should not join them`); 415 416 </script> 417 </body> 418 </html>