input-events-get-target-ranges-forwarddelete.tentative.html (76753B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <meta name="timeout" content="long"> 4 <title>InputEvent.getTargetRanges() at Delete (forward delete)</title> 5 <div contenteditable></div> 6 <script src="input-events-get-target-ranges.js"></script> 7 <script src="/resources/testharness.js"></script> 8 <script src="/resources/testharnessreport.js"></script> 9 <script src="/resources/testdriver.js"></script> 10 <script src="/resources/testdriver-vendor.js"></script> 11 <script src="/resources/testdriver-actions.js"></script> 12 <script> 13 "use strict"; 14 15 // Simply deletes the next ASCII character of caret position. 16 promise_test(async (t) => { 17 initializeTest("<p>abc</p>"); 18 gSelection.collapse(gEditor.firstChild.firstChild, 2); 19 await sendDeleteKey(); 20 checkEditorContentResultAsSubTest("<p>ab</p>", t.name); 21 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 22 startContainer: gEditor.firstChild.firstChild, 23 startOffset: 2, 24 endContainer: gEditor.firstChild.firstChild, 25 endOffset: 3, 26 }); 27 checkGetTargetRangesOfInputOnDeleteSomething(); 28 }, 'Delete at "<p>ab[]c</p>"'); 29 30 // Simply deletes the next ASCII character of caret position. 31 promise_test(async (t) => { 32 initializeTest("<p>abc</p>"); 33 gSelection.collapse(gEditor.firstChild.firstChild, 1); 34 await sendDeleteKey(); 35 checkEditorContentResultAsSubTest("<p>ac</p>", t.name); 36 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 37 startContainer: gEditor.firstChild.firstChild, 38 startOffset: 1, 39 endContainer: gEditor.firstChild.firstChild, 40 endOffset: 2, 41 }); 42 checkGetTargetRangesOfInputOnDeleteSomething(); 43 }, 'Delete at "<p>a[]bc</p>"'); 44 45 // Simply deletes the next ASCII character of caret position. 46 promise_test(async (t) => { 47 initializeTest("<p>abc</p>"); 48 gSelection.collapse(gEditor.firstChild.firstChild, 0); 49 await sendDeleteKey(); 50 checkEditorContentResultAsSubTest("<p>bc</p>", t.name); 51 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 52 startContainer: gEditor.firstChild.firstChild, 53 startOffset: 0, 54 endContainer: gEditor.firstChild.firstChild, 55 endOffset: 1, 56 }); 57 checkGetTargetRangesOfInputOnDeleteSomething(); 58 }, 'Delete at "<p>[]abc</p>"'); 59 60 promise_test(async (t) => { 61 initializeTest("<p>abc</p>"); 62 let abc = gEditor.querySelector("p").firstChild; 63 gSelection.collapse(abc, 3); 64 await sendDeleteKey(); 65 checkEditorContentResultAsSubTest("<p>abc</p>", t.name); 66 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 67 startContainer: abc, 68 startOffset: 3, 69 endContainer: abc, 70 endOffset: 3, 71 }); 72 checkGetTargetRangesOfInputOnDoNothing(); 73 }, 'Delete at "<p>abc[]</p>"'); 74 75 promise_test(async (t) => { 76 initializeTest("<p>abc<br></p>"); 77 let abc = gEditor.querySelector("p").firstChild; 78 gSelection.collapse(abc, 3); 79 await sendDeleteKey(); 80 checkEditorContentResultAsSubTest("<p>abc<br></p>", t.name); 81 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 82 startContainer: abc, 83 startOffset: 3, 84 endContainer: abc, 85 endOffset: 3, 86 }); 87 checkGetTargetRangesOfInputOnDoNothing(); 88 }, 'Delete at "<p>abc[]<br></p>"'); 89 90 promise_test(async (t) => { 91 initializeTest(`<p><img src="${kImgSrc}"><br></p>`); 92 let p = gEditor.querySelector("p"); 93 gSelection.collapse(p, 1); 94 await sendDeleteKey(); 95 checkEditorContentResultAsSubTest( 96 `<p><img src="${kImgSrc}"><br></p>`, 97 t.name 98 ); 99 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 100 startContainer: p, 101 startOffset: 1, 102 endContainer: p, 103 endOffset: 1, 104 }); 105 checkGetTargetRangesOfInputOnDoNothing(); 106 }, 'Delete at "<p><img>[]<br></p>"'); 107 108 // Should delete the `<span>` element because it becomes empty. 109 // However, we need discussion whether the `<span>` element should be 110 // contained by a range of `getTargetRanges()`. 111 // https://github.com/w3c/input-events/issues/112 112 promise_test(async (t) => { 113 initializeTest("<p>a<span>b</span>c</p>"); 114 let a = gEditor.querySelector("span").previousSibling; 115 gSelection.collapse(a, 1); 116 await sendDeleteKey(); 117 checkEditorContentResultAsSubTest("<p>ac</p>", t.name); 118 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 119 startContainer: a, 120 startOffset: 1, 121 endContainer: gEditor.firstChild, 122 endOffset: 2, 123 }); 124 checkGetTargetRangesOfInputOnDeleteSomething(); 125 }, 'Delete at "<p>a[]<span>b</span>c</p>"'); 126 127 // Should delete the `<span>` element because it becomes empty. 128 // However, we need discussion whether the `<span>` element should be 129 // contained by a range of `getTargetRanges()`. 130 // https://github.com/w3c/input-events/issues/112 131 promise_test(async (t) => { 132 initializeTest("<p>a<span>b</span>c</p>"); 133 let b = gEditor.querySelector("span").firstChild; 134 gSelection.collapse(b, 0); 135 await sendDeleteKey(); 136 checkEditorContentResultAsSubTest("<p>ac</p>", t.name); 137 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 138 startContainer: gEditor.firstChild, 139 startOffset: 1, 140 endContainer: gEditor.firstChild, 141 endOffset: 2, 142 }); 143 checkGetTargetRangesOfInputOnDeleteSomething(); 144 }, 'Delete at "<p>a<span>[]b</span>c</p>"'); 145 146 // Invisible trailing white-space may be deleted when the last visible 147 // character is deleted. If it's deleted, it should be contained by 148 // the range of `getTargetRanges()`, but needs discussion. 149 // https://github.com/w3c/input-events/issues/112 150 promise_test(async (t) => { 151 initializeTest("<p>abc </p>"); 152 gSelection.collapse(gEditor.firstChild.firstChild, 2); 153 await sendDeleteKey(); 154 checkEditorContentResultAsSubTest( 155 [ 156 "<p>ab</p>", 157 "<p>ab </p>", 158 ], 159 t.name 160 ); 161 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 162 startContainer: gEditor.firstChild.firstChild, 163 startOffset: 2, 164 endContainer: gEditor.firstChild.firstChild, 165 endOffset: gEditor.firstChild.firstChild.data.length == 2 ? 4 : 3, 166 }); 167 checkGetTargetRangesOfInputOnDeleteSomething(); 168 }, 'Delete at "<p>ab[]c </p>"'); 169 170 promise_test(async (t) => { 171 initializeTest("<p>abc</p><p>def</p>"); 172 let p1 = gEditor.firstChild; 173 let abc = p1.firstChild; 174 let p2 = p1.nextSibling; 175 let def = p2.firstChild; 176 gSelection.collapse(abc, 3); 177 await sendDeleteKey(); 178 checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name); 179 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 180 startContainer: abc, 181 startOffset: 3, 182 endContainer: def, 183 endOffset: 0, 184 }); 185 checkGetTargetRangesOfInputOnDeleteSomething(); 186 }, 'Delete at "<p>abc[]</p><p>def</p>"'); 187 188 // Invisible trailing white-spaces in current block and invisible leading 189 // white-spaces in the following block should be deleted for avoiding they 190 // becoming visible when the blocks are joined. Perhaps, they should be 191 // contained by the range of `getTargetRanges()`, but needs discussion. 192 // https://github.com/w3c/input-events/issues/112 193 promise_test(async (t) => { 194 initializeTest("<p>abc </p><p> def</p>"); 195 let p1 = gEditor.firstChild; 196 let abc = p1.firstChild; 197 let p2 = p1.nextSibling; 198 let def = p2.firstChild; 199 gSelection.collapse(abc, 3); 200 await sendDeleteKey(); 201 checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name); 202 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 203 startContainer: abc, 204 startOffset: 3, 205 endContainer: def, 206 endOffset: 3, 207 }); 208 checkGetTargetRangesOfInputOnDeleteSomething(); 209 }, 'Delete at "<p>abc[] </p><p> def</p>"'); 210 211 // Invisible trailing white-spaces in current block and invisible leading 212 // white-spaces in the following block should be deleted for avoiding they 213 // becoming visible when the blocks are joined. Perhaps, they should be 214 // contained by the range of `getTargetRanges()`, but needs discussion. 215 // https://github.com/w3c/input-events/issues/112 216 promise_test(async (t) => { 217 initializeTest("<p>abc </p><p> def</p>"); 218 let p1 = gEditor.firstChild; 219 let abc = p1.firstChild; 220 let p2 = p1.nextSibling; 221 let def = p2.firstChild; 222 gSelection.collapse(abc, 4); 223 await sendDeleteKey(); 224 checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name); 225 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 226 startContainer: abc, 227 startOffset: 3, 228 endContainer: def, 229 endOffset: 3, 230 }); 231 checkGetTargetRangesOfInputOnDeleteSomething(); 232 }, 'Delete at "<p>abc [] </p><p> def</p>"'); 233 234 // Invisible trailing white-spaces in current block and invisible leading 235 // white-spaces in the following block should be deleted for avoiding they 236 // becoming visible when the blocks are joined. Perhaps, they should be 237 // contained by the range of `getTargetRanges()`, but needs discussion. 238 // https://github.com/w3c/input-events/issues/112 239 promise_test(async (t) => { 240 initializeTest("<p>abc </p><p> def</p>"); 241 let p1 = gEditor.firstChild; 242 let abc = p1.firstChild; 243 let p2 = p1.nextSibling; 244 let def = p2.firstChild; 245 gSelection.collapse(abc, 5); 246 await sendDeleteKey(); 247 checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name); 248 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 249 startContainer: abc, 250 startOffset: 3, 251 endContainer: def, 252 endOffset: 3, 253 }); 254 checkGetTargetRangesOfInputOnDeleteSomething(); 255 }, 'Delete at "<p>abc [] </p><p> def</p>"'); 256 257 // Invisible trailing white-spaces in current block and invisible leading 258 // white-spaces in the following block should be deleted for avoiding they 259 // becoming visible when the blocks are joined. Perhaps, they should be 260 // contained by the range of `getTargetRanges()`, but needs discussion. 261 // https://github.com/w3c/input-events/issues/112 262 promise_test(async (t) => { 263 initializeTest("<p>abc </p><p> def</p>"); 264 let p1 = gEditor.firstChild; 265 let abc = p1.firstChild; 266 let p2 = p1.nextSibling; 267 let def = p2.firstChild; 268 gSelection.collapse(abc, 6); 269 await sendDeleteKey(); 270 checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name); 271 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 272 startContainer: abc, 273 startOffset: 3, 274 endContainer: def, 275 endOffset: 3, 276 }); 277 checkGetTargetRangesOfInputOnDeleteSomething(); 278 }, 'Delete at "<p>abc []</p><p> def</p>"'); 279 280 promise_test(async (t) => { 281 initializeTest("<p>abc</p><p><b>def</b></p>"); 282 let abc = gEditor.querySelector("p").firstChild; 283 let def = gEditor.querySelector("b").firstChild; 284 gSelection.collapse(abc, 3); 285 await sendDeleteKey(); 286 checkEditorContentResultAsSubTest("<p>abc<b>def</b></p>", t.name); 287 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 288 startContainer: abc, 289 startOffset: 3, 290 endContainer: def, 291 endOffset: 0, 292 }); 293 checkGetTargetRangesOfInputOnDeleteSomething(); 294 }, 'Delete at "<p>abc[]</p><p><b>def</b></p>"'); 295 296 promise_test(async (t) => { 297 initializeTest("<p><b>abc</b></p><p><b>def</b></p>"); 298 let abc = gEditor.querySelector("p > b").firstChild; 299 let def = gEditor.querySelector("P + p > b").firstChild; 300 gSelection.collapse(abc, 3); 301 await sendDeleteKey(); 302 checkEditorContentResultAsSubTest( 303 [ 304 "<p><b>abc</b><b>def</b></p>", 305 "<p><b>abcdef</b></p>", 306 ], 307 t.name 308 ); 309 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 310 startContainer: abc, 311 startOffset: 3, 312 endContainer: def, 313 endOffset: 0, 314 }); 315 checkGetTargetRangesOfInputOnDeleteSomething(); 316 }, 'Delete at "<p><b>abc[]</b></p><p><b>def</b></p>"'); 317 318 promise_test(async (t) => { 319 initializeTest("<p><i>abc</i></p><p><b>def</b></p>"); 320 let abc = gEditor.querySelector("i").firstChild; 321 let def = gEditor.querySelector("b").firstChild; 322 gSelection.collapse(abc, 3); 323 await sendDeleteKey(); 324 checkEditorContentResultAsSubTest("<p><i>abc</i><b>def</b></p>", t.name); 325 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 326 startContainer: abc, 327 startOffset: 3, 328 endContainer: def, 329 endOffset: 0, 330 }); 331 checkGetTargetRangesOfInputOnDeleteSomething(); 332 }, 'Delete at "<p><i>abc[]</i></p><p><b>def</b></p>"'); 333 334 // Invisible leading white-spaces in the following block should be deleted 335 // for avoiding they becoming visible when the blocks are joined, but 336 // preformatted trailing white-spaces in the first block shouldn't be 337 // deleted. Perhaps, the invisible white-spaces should be contained by 338 // the range of `getTargetRanges()`, but needs discussion. 339 // https://github.com/w3c/input-events/issues/112 340 promise_test(async (t) => { 341 initializeTest("<pre>abc </pre><p> def</p>"); 342 let pre = gEditor.firstChild; 343 let abc = pre.firstChild; 344 let p = pre.nextSibling; 345 let def = p.firstChild; 346 gSelection.collapse(abc, 6); 347 await sendDeleteKey(); 348 checkEditorContentResultAsSubTest("<pre>abc def</pre>", t.name); 349 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 350 startContainer: abc, 351 startOffset: 6, 352 endContainer: def, 353 endOffset: 3, 354 }); 355 checkGetTargetRangesOfInputOnDeleteSomething(); 356 }, 'Delete at "<pre>abc []</pre><p> def</p>"'); 357 358 // Invisible leading/trailing white-spaces in the following block should be 359 // deleted for avoiding they becoming visible when the blocks are joined, but 360 // preformatted trailing white-spaces in the first block shouldn't be 361 // deleted. Perhaps, the invisible leading white-spaces should be contained 362 // by the range of `getTargetRanges()`, but needs discussion. 363 // And also not sure whether the trailing white-spaces should be contained 364 // by additional range of `getTargetRanges()` or not because of the 365 // implementation cost and runtime cost. Needs discuss. 366 // https://github.com/w3c/input-events/issues/112 367 promise_test(async (t) => { 368 initializeTest("<pre>abc </pre><p> def</p>"); 369 let pre = gEditor.firstChild; 370 let abc = pre.firstChild; 371 let p = pre.nextSibling; 372 let def = p.firstChild; 373 gSelection.collapse(abc, 6); 374 await sendDeleteKey(); 375 checkEditorContentResultAsSubTest("<pre>abc def</pre>", t.name); 376 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 377 startContainer: abc, 378 startOffset: 6, 379 endContainer: def, 380 endOffset: 3, 381 }); 382 checkGetTargetRangesOfInputOnDeleteSomething(); 383 }, 'Delete at "<pre>abc []</pre><p> def </p>"'); 384 385 // Invisible trailing white-spaces in the first block should be deleted 386 // when the block is joined with the preformatted following block, but 387 // the leading white-spaces in the preformatted block shouldn't be 388 // removed. So, in this case, the invisible trailing white-spaces should 389 // be in the range of `getTargetRanges()`, but not so for the preformatted 390 // visible leading white-spaces. But needs discussion. 391 // https://github.com/w3c/input-events/issues/112 392 promise_test(async (t) => { 393 initializeTest("<p>abc </p><pre> def</pre>"); 394 let p = gEditor.firstChild; 395 let abc = p.firstChild; 396 let pre = p.nextSibling; 397 let def = pre.firstChild; 398 gSelection.collapse(abc, 3); 399 await sendDeleteKey(); 400 checkEditorContentResultAsSubTest( 401 [ 402 "<p>abc def</p>", 403 "<p>abc def</p>", 404 "<p>abc def</p>", 405 "<p>abc def</p>", 406 ], 407 t.name 408 ); 409 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 410 startContainer: abc, 411 startOffset: 3, 412 endContainer: def, 413 endOffset: 0, 414 }); 415 checkGetTargetRangesOfInputOnDeleteSomething(); 416 }, 'Delete at "<p>abc[] </p><pre> def</pre>"'); 417 418 promise_test(async (t) => { 419 initializeTest('<p style="white-space:pre-line">abc\ndef</p>'); 420 const p = gEditor.firstChild; 421 const text = p.firstChild; 422 gSelection.collapse(text, "abc".length); 423 await sendDeleteKey(); 424 checkEditorContentResultAsSubTest( 425 '<p style="white-space:pre-line">abcdef</p>', 426 t.name 427 ); 428 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 429 startContainer: text, 430 startOffset: "abc".length, 431 endContainer: text, 432 endOffset: "abc\n".length, 433 }); 434 checkGetTargetRangesOfInputOnDeleteSomething(); 435 }, 'Delete at "<p style="white-space:pre-line">abc[]\\ndef</p>"'); 436 437 promise_test(async (t) => { 438 initializeTest('<p style="white-space:pre-line">abc\n def</p>'); 439 const p = gEditor.firstChild; 440 const text = p.firstChild; 441 gSelection.collapse(text, "abc".length); 442 await sendDeleteKey(); 443 checkEditorContentResultAsSubTest( 444 '<p style="white-space:pre-line">abcdef</p>', 445 t.name 446 ); 447 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 448 startContainer: text, 449 startOffset: "abc".length, 450 endContainer: text, 451 endOffset: "abc\n ".length, 452 }); 453 checkGetTargetRangesOfInputOnDeleteSomething(); 454 }, 'Delete at "<p style="white-space:pre-line">abc[]\\n def</p>"'); 455 456 promise_test(async (t) => { 457 initializeTest('<p style="white-space:pre-line">abc \ndef</p>'); 458 const p = gEditor.firstChild; 459 const text = p.firstChild; 460 gSelection.collapse(text, "abc".length); 461 await sendDeleteKey(); 462 checkEditorContentResultAsSubTest( 463 '<p style="white-space:pre-line">abcdef</p>', 464 t.name 465 ); 466 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 467 startContainer: text, 468 startOffset: "abc".length, 469 endContainer: text, 470 endOffset: "abc \n ".length, 471 }); 472 checkGetTargetRangesOfInputOnDeleteSomething(); 473 }, 'Delete at "<p style="white-space:pre-line">abc[] \\ndef</p>"'); 474 475 promise_test(async (t) => { 476 initializeTest('<p style="white-space:pre-line">abc \n def</p>'); 477 const p = gEditor.firstChild; 478 const text = p.firstChild; 479 gSelection.collapse(text, "abc".length); 480 await sendDeleteKey(); 481 checkEditorContentResultAsSubTest( 482 '<p style="white-space:pre-line">abcdef</p>', 483 t.name 484 ); 485 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 486 startContainer: text, 487 startOffset: "abc".length, 488 endContainer: text, 489 endOffset: "abc \n ".length, 490 }); 491 checkGetTargetRangesOfInputOnDeleteSomething(); 492 }, 'Delete at "<p style="white-space:pre-line">abc[] \\n def</p>"'); 493 494 promise_test(async (t) => { 495 initializeTest('<p style="white-space:pre-line">abc \n \n def</p>'); 496 const p = gEditor.firstChild; 497 const text = p.firstChild; 498 gSelection.collapse(text, "abc".length); 499 await sendDeleteKey(); 500 checkEditorContentResultAsSubTest( 501 '<p style="white-space:pre-line">abc\n def</p>', 502 t.name 503 ); 504 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 505 startContainer: text, 506 startOffset: "abc".length, 507 endContainer: text, 508 endOffset: "abc \n \n ".length, 509 }); 510 checkGetTargetRangesOfInputOnDeleteSomething(); 511 }, 'Delete at "<p style="white-space:pre-line">abc[] \\n \\n def</p>"'); 512 513 // Deleting from before invisible trailing `<br>` element of a block 514 // should delete the `<br>` element and join the blocks. Therefore, 515 // the target range should contain the `<br>` element and block boundaries. 516 // But maybe needs discussion. 517 // https://github.com/w3c/input-events/issues/112 518 promise_test(async (t) => { 519 initializeTest("<p>abc<br></p><p>def</p>"); 520 let p1 = gEditor.firstChild; 521 let abc = p1.firstChild; 522 let p2 = p1.nextSibling; 523 let def = p2.firstChild; 524 gSelection.collapse(abc, 3); 525 await sendDeleteKey(); 526 checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name); 527 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 528 startContainer: abc, 529 startOffset: 3, 530 endContainer: def, 531 endOffset: 0, 532 }); 533 checkGetTargetRangesOfInputOnDeleteSomething(); 534 }, 'Delete at "<p>abc[]<br></p><p>def</p>"'); 535 536 promise_test(async (t) => { 537 initializeTest(`<p><img src="${kImgSrc}"><br></p><p>def</p>`); 538 let p1 = gEditor.firstChild; 539 let img = p1.firstChild; 540 let p2 = p1.nextSibling; 541 let def = p2.firstChild; 542 gSelection.collapse(p1, 1); 543 await sendDeleteKey(); 544 checkEditorContentResultAsSubTest(`<p><img src="${kImgSrc}">def</p>`, t.name); 545 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 546 startContainer: p1, 547 startOffset: 1, 548 endContainer: def, 549 endOffset: 0, 550 }); 551 checkGetTargetRangesOfInputOnDeleteSomething(); 552 }, `Delete at "<p><img>{}<br></p><p>def</p>"`); 553 554 // Deleting from last empty line in the first block should delete the 555 // invisible `<br>` element for the last empty line and join the blocks. 556 // In this case, the invisible `<br>` element should be contained in the 557 // range of `getTargetRanges()`, but needs discussion. 558 // https://github.com/w3c/input-events/issues/112 559 promise_test(async (t) => { 560 initializeTest("<p>abc<br><br></p><p>def</p>"); 561 let p1 = gEditor.firstChild; 562 let abc = p1.firstChild; 563 let p2 = p1.nextSibling; 564 let def = p2.firstChild; 565 gSelection.collapse(p1, 2); 566 await sendDeleteKey(); 567 checkEditorContentResultAsSubTest("<p>abc<br>def</p>", t.name); 568 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 569 startContainer: p1, 570 startOffset: 2, 571 endContainer: def, 572 endOffset: 0, 573 }); 574 checkGetTargetRangesOfInputOnDeleteSomething(); 575 }, 'Delete at "<p>abc<br>{}<br></p><p>def</p>"'); 576 577 // Deleting visible `<br>` element should be contained by a range of 578 // `getTargetRanges()`. 579 promise_test(async (t) => { 580 initializeTest("<p>abc<br>def</p>"); 581 let p = gEditor.querySelector("p"); 582 let abc = p.firstChild; 583 gSelection.collapse(abc, 3); 584 await sendDeleteKey(); 585 checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name); 586 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 587 startContainer: p, 588 startOffset: 1, 589 endContainer: p, 590 endOffset: 2, 591 }); 592 checkGetTargetRangesOfInputOnDeleteSomething(); 593 }, 'Delete at "<p>abc[]<br>def</p>"'); 594 595 // Deleting visible `<br>` element following white-space should not include 596 // the preceding white-space in the range. 597 promise_test(async (t) => { 598 initializeTest("<p>abc <br>def</p>"); 599 let p = gEditor.querySelector("p"); 600 let abc = p.firstChild; 601 gSelection.collapse(abc, 4); 602 await sendDeleteKey(); 603 checkEditorContentResultAsSubTest("<p>abc def</p>", t.name); 604 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 605 startContainer: p, 606 startOffset: 1, 607 endContainer: p, 608 endOffset: 2, 609 }); 610 checkGetTargetRangesOfInputOnDeleteSomething(); 611 }, 'Delete at "<p>abc []<br>def</p>"'); 612 613 // Deleting visible `<br>` element followed by white-space should include 614 // the following white-space in the range because it shouldn't become 615 // visible and should be deleted for avoiding it. 616 // https://github.com/w3c/input-events/issues/112 617 promise_test(async (t) => { 618 initializeTest("<p>abc<br> def</p>"); 619 let p = gEditor.querySelector("p"); 620 let abc = p.firstChild; 621 let def = gEditor.querySelector("br").nextSibling; 622 gSelection.collapse(abc, 3); 623 await sendDeleteKey(); 624 checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name); 625 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 626 startContainer: p, 627 startOffset: 1, 628 endContainer: def, 629 endOffset: 1, 630 }); 631 checkGetTargetRangesOfInputOnDeleteSomething(); 632 }, 'Delete at "<p>abc[]<br> def</p>"'); 633 634 promise_test(async (t) => { 635 initializeTest(`<p>abc<img src="${kImgSrc}">def</p>`); 636 let p = gEditor.querySelector("p"); 637 let abc = p.firstChild; 638 gSelection.collapse(abc, 3); 639 await sendDeleteKey(); 640 checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name); 641 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 642 startContainer: p, 643 startOffset: 1, 644 endContainer: p, 645 endOffset: 2, 646 }); 647 checkGetTargetRangesOfInputOnDeleteSomething(); 648 }, 'Delete at "<p>abc[]<img>def</p>"'); 649 650 // White-spaces around `<img>` element are visible so that they shouldn't 651 // be included into the target ranges. 652 promise_test(async (t) => { 653 initializeTest(`<p>abc <img src="${kImgSrc}">def</p>`); 654 let p = gEditor.querySelector("p"); 655 let abc = p.firstChild; 656 gSelection.collapse(abc, 4); 657 await sendDeleteKey(); 658 // If the browser does not join `Text` nodes around <img>, it's fine to 659 // convert the preceding white-space to an NBSP. 660 if ( 661 gEditor.querySelector("p")?.childNodes.length == 2 && 662 gEditor.querySelector("p").childNodes[0].length == "abc ".length 663 ) { 664 checkEditorContentResultAsSubTest([ 665 "<p>abc def</p>", 666 "<p>abc def</p>", 667 ], t.name); 668 } else { 669 checkEditorContentResultAsSubTest("<p>abc def</p>", t.name); 670 } 671 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 672 startContainer: p, 673 startOffset: 1, 674 endContainer: p, 675 endOffset: 2, 676 }); 677 checkGetTargetRangesOfInputOnDeleteSomething(); 678 }, 'Delete at "<p>abc []<img>def</p>"'); 679 680 // White-spaces around `<img>` element are visible so that they shouldn't 681 // be included into the target ranges. 682 promise_test(async (t) => { 683 initializeTest(`<p>abc<img src="${kImgSrc}"> def</p>`); 684 let p = gEditor.querySelector("p"); 685 let abc = p.firstChild; 686 gSelection.collapse(abc, 3); 687 await sendDeleteKey(); 688 // If the browser does not join `Text` nodes around <img>, it's fine to 689 // convert the preceding white-space to an NBSP. 690 if ( 691 gEditor.querySelector("p")?.childNodes.length == 2 && 692 gEditor.querySelector("p").childNodes[0].length == "abc".length 693 ) { 694 checkEditorContentResultAsSubTest([ 695 "<p>abc def</p>", 696 "<p>abc def</p>", 697 ], t.name); 698 } else { 699 checkEditorContentResultAsSubTest("<p>abc def</p>", t.name); 700 } 701 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 702 startContainer: p, 703 startOffset: 1, 704 endContainer: p, 705 endOffset: 2, 706 }); 707 checkGetTargetRangesOfInputOnDeleteSomething(); 708 }, 'Delete at "<p>abc[]<img> def</p>"'); 709 710 promise_test(async (t) => { 711 initializeTest(`<p>abc<img src="${kImgSrc}"><img src="${kImgSrc}">def</p>`); 712 let p = gEditor.querySelector("p"); 713 let abc = p.firstChild; 714 gSelection.collapse(abc, 3); 715 await sendDeleteKey(); 716 checkEditorContentResultAsSubTest( 717 `<p>abc<img src="${kImgSrc}">def</p>`, 718 t.name 719 ); 720 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 721 startContainer: p, 722 startOffset: 1, 723 endContainer: p, 724 endOffset: 2, 725 }); 726 checkGetTargetRangesOfInputOnDeleteSomething(); 727 }, 'Delete at "<p>abc[]<img><img>def</p>"'); 728 729 promise_test(async (t) => { 730 initializeTest(`<p>abc<img src="${kImgSrc}"><img src="${kImgSrc}">def</p>`); 731 let p = gEditor.querySelector("p"); 732 gSelection.collapse(p, 2); 733 await sendDeleteKey(); 734 checkEditorContentResultAsSubTest( 735 `<p>abc<img src="${kImgSrc}">def</p>`, 736 t.name 737 ); 738 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 739 startContainer: p, 740 startOffset: 2, 741 endContainer: p, 742 endOffset: 3, 743 }); 744 checkGetTargetRangesOfInputOnDeleteSomething(); 745 }, 'Delete at "<p>abc<img>{}<img>def</p>"'); 746 747 promise_test(async (t) => { 748 initializeTest(`<div>abc<hr>def</div>`); 749 let div = gEditor.querySelector("div"); 750 let abc = div.firstChild; 751 gSelection.collapse(abc, 3); 752 await sendDeleteKey(); 753 checkEditorContentResultAsSubTest("<div>abcdef</div>", t.name); 754 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 755 startContainer: div, 756 startOffset: 1, 757 endContainer: div, 758 endOffset: 2, 759 }); 760 checkGetTargetRangesOfInputOnDeleteSomething(); 761 }, 'Delete at "<div>abc[]<hr>def</div>"'); 762 763 // White-spaces around block element are invisible white-spaces so that 764 // they should be included into the target ranges to avoid they become 765 // visible. 766 // https://github.com/w3c/input-events/issues/112 767 promise_test(async (t) => { 768 initializeTest(`<div>abc <hr>def</div>`); 769 let div = gEditor.querySelector("div"); 770 let abc = div.firstChild; 771 gSelection.collapse(abc, 3); 772 await sendDeleteKey(); 773 checkEditorContentResultAsSubTest("<div>abcdef</div>", t.name); 774 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 775 startContainer: div, 776 startOffset: 1, 777 endContainer: div, 778 endOffset: 2, 779 }); 780 checkGetTargetRangesOfInputOnDeleteSomething(); 781 }, 'Delete at "<div>abc[] <hr>def</div>"'); 782 783 // White-spaces around block element are invisible white-spaces so that 784 // they should be included into the target ranges to avoid they become 785 // visible. 786 // https://github.com/w3c/input-events/issues/112 787 promise_test(async (t) => { 788 initializeTest(`<div>abc<hr> def</div>`); 789 let div = gEditor.querySelector("div"); 790 let abc = div.firstChild; 791 gSelection.collapse(abc, 3); 792 await sendDeleteKey(); 793 checkEditorContentResultAsSubTest("<div>abcdef</div>", t.name); 794 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 795 startContainer: div, 796 startOffset: 1, 797 endContainer: div, 798 endOffset: 2, 799 }); 800 checkGetTargetRangesOfInputOnDeleteSomething(); 801 }, 'Delete at "<div>abc[]<hr> def</div>"'); 802 803 // Invisible `<br>` element immediately before `<hr>` element should be 804 // delete once, and both of them should be included in the target range. 805 promise_test(async (t) => { 806 initializeTest(`<div>abc<br><hr>def</div>`); 807 let div = gEditor.querySelector("div"); 808 let abc = div.firstChild; 809 gSelection.collapse(abc, 3); 810 await sendDeleteKey(); 811 checkEditorContentResultAsSubTest("<div>abcdef</div>", t.name); 812 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 813 startContainer: div, 814 startOffset: 1, 815 endContainer: div, 816 endOffset: 3, 817 }); 818 checkGetTargetRangesOfInputOnDeleteSomething(); 819 }, 'Delete at "<div>abc[]<br><hr>def</div>"'); 820 821 promise_test(async (t) => { 822 initializeTest(`<div><img src="${kImgSrc}"><br><hr>def</div>`); 823 let div = gEditor.querySelector("div"); 824 let img = div.firstChild; 825 gSelection.collapse(div, 1); 826 await sendDeleteKey(); 827 checkEditorContentResultAsSubTest( 828 `<div><img src="${kImgSrc}">def</div>`, 829 t.name 830 ); 831 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 832 startContainer: div, 833 startOffset: 1, 834 endContainer: div, 835 endOffset: 3, 836 }); 837 checkGetTargetRangesOfInputOnDeleteSomething(); 838 }, 'Delete at "<div><img>{}<br><hr>def</div>"'); 839 840 promise_test(async (t) => { 841 initializeTest("<div>abc<p>def<br>ghi</p></div>"); 842 let p = gEditor.querySelector("p"); 843 let def = p.firstChild; 844 let abc = gEditor.firstChild.firstChild; 845 gSelection.collapse(abc, 3); 846 await sendDeleteKey(); 847 checkEditorContentResultAsSubTest( 848 [ 849 "<div>abcdef<p>ghi</p></div>", 850 "<div>abcdef<br><p>ghi</p></div>", 851 ], 852 t.name 853 ); 854 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 855 startContainer: abc, 856 startOffset: 3, 857 endContainer: def, 858 endOffset: 0, 859 }); 860 checkGetTargetRangesOfInputOnDeleteSomething(); 861 }, 'Delete at "<div>abc[]<p>def<br>ghi</p></div>"'); 862 863 promise_test(async (t) => { 864 initializeTest("<div>abc<br><p>def<br>ghi</p></div>"); 865 let div = gEditor.firstChild; 866 let p = gEditor.querySelector("p"); 867 let def = p.firstChild; 868 let abc = div.firstChild; 869 gSelection.collapse(abc, 3); 870 await sendDeleteKey(); 871 checkEditorContentResultAsSubTest( 872 [ 873 "<div>abcdef<p>ghi</p></div>", 874 "<div>abcdef<br><p>ghi</p></div>", 875 ], 876 t.name 877 ); 878 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 879 startContainer: div, 880 startOffset: 1, 881 endContainer: def, 882 endOffset: 0, 883 }); 884 checkGetTargetRangesOfInputOnDeleteSomething(); 885 }, 'Delete at "<div>abc[]<br><p>def<br>ghi</p></div>"'); 886 887 promise_test(async (t) => { 888 initializeTest(`<div><img src="${kImgSrc}"><br><p>def<br>ghi</p></div>`); 889 let div = gEditor.firstChild; 890 let p = gEditor.querySelector("p"); 891 let def = p.firstChild; 892 let abc = div.firstChild; 893 gSelection.collapse(div, 1); 894 await sendDeleteKey(); 895 checkEditorContentResultAsSubTest( 896 [ 897 `<div><img src="${kImgSrc}">def<p>ghi</p></div>`, 898 `<div><img src="${kImgSrc}">def<br><p>ghi</p></div>`, 899 ], 900 t.name 901 ); 902 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 903 startContainer: div, 904 startOffset: 1, 905 endContainer: def, 906 endOffset: 0, 907 }); 908 checkGetTargetRangesOfInputOnDeleteSomething(); 909 }, 'Delete at "<div><img>{}<br><p>def<br>ghi</p></div>"'); 910 911 // Joining parent block and child block should remove invisible preceding 912 // white-spaces of the child block and invisible leading white-spaces in 913 // the child block, and they should be contained in a range of 914 // `getTargetRanges()`, but maybe needs discussion. 915 // https://github.com/w3c/input-events/issues/112 916 promise_test(async (t) => { 917 initializeTest("<div>abc <p> def<br>ghi</p></div>"); 918 let p = gEditor.querySelector("p"); 919 let def = p.firstChild; 920 let abc = gEditor.firstChild.firstChild; 921 gSelection.collapse(abc, 3); 922 await sendDeleteKey(); 923 checkEditorContentResultAsSubTest( 924 [ 925 "<div>abcdef<p>ghi</p></div>", 926 "<div>abcdef<br><p>ghi</p></div>", 927 ], 928 t.name 929 ); 930 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 931 startContainer: abc, 932 startOffset: 3, 933 endContainer: def, 934 endOffset: 3, 935 }); 936 checkGetTargetRangesOfInputOnDeleteSomething(); 937 }, 'Delete at "<div>abc[] <p> def<br>ghi</p></div>"'); 938 939 promise_test(async (t) => { 940 initializeTest("<div>abc<p><b>def</b></p></div>"); 941 let abc = gEditor.querySelector("div").firstChild; 942 let def = gEditor.querySelector("b").firstChild; 943 gSelection.collapse(abc, 3); 944 await sendDeleteKey(); 945 checkEditorContentResultAsSubTest("<div>abc<b>def</b></div>", t.name); 946 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 947 startContainer: abc, 948 startOffset: 3, 949 endContainer: def, 950 endOffset: 0, 951 }); 952 checkGetTargetRangesOfInputOnDeleteSomething(); 953 }, 'Delete at "<div>abc[]<p><b>def</b></p></div>"'); 954 955 promise_test(async (t) => { 956 initializeTest("<div><b>abc</b><p><b>def</b></p></div>"); 957 let abc = gEditor.querySelector("b").firstChild; 958 let def = gEditor.querySelector("p > b").firstChild; 959 gSelection.collapse(abc, 3); 960 await sendDeleteKey(); 961 checkEditorContentResultAsSubTest( 962 [ 963 "<div><b>abc</b><b>def</b></div>", 964 "<div><b>abcdef</b></div>", 965 ], 966 t.name 967 ); 968 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 969 startContainer: abc, 970 startOffset: 3, 971 endContainer: def, 972 endOffset: 0, 973 }); 974 checkGetTargetRangesOfInputOnDeleteSomething(); 975 }, 'Delete at "<div><b>abc[]</b><p><b>def</b></p></div>"'); 976 977 promise_test(async (t) => { 978 initializeTest("<div><i>abc</i><p><b>def</b></p></div>"); 979 let abc = gEditor.querySelector("i").firstChild; 980 let def = gEditor.querySelector("b").firstChild; 981 gSelection.collapse(abc, 3); 982 await sendDeleteKey(); 983 checkEditorContentResultAsSubTest("<div><i>abc</i><b>def</b></div>", t.name); 984 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 985 startContainer: abc, 986 startOffset: 3, 987 endContainer: def, 988 endOffset: 0, 989 }); 990 checkGetTargetRangesOfInputOnDeleteSomething(); 991 }, 'Delete at "<div><i>abc[]</i><p><b>def</b></p></div>"'); 992 993 promise_test(async (t) => { 994 initializeTest("<div><p>abc</p>def</div>"); 995 let abc = gEditor.querySelector("p").firstChild; 996 let def = gEditor.querySelector("p").nextSibling; 997 gSelection.collapse(abc, 3); 998 await sendDeleteKey(); 999 checkEditorContentResultAsSubTest( 1000 [ 1001 "<div><p>abcdef</p></div>", 1002 "<div><p>abcdef<br></p></div>", 1003 ], 1004 t.name 1005 ); 1006 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1007 startContainer: abc, 1008 startOffset: 3, 1009 endContainer: def, 1010 endOffset: 0, 1011 }); 1012 checkGetTargetRangesOfInputOnDeleteSomething(); 1013 }, 'Delete at "<div><p>abc[]</p>def</div>"'); 1014 1015 promise_test(async (t) => { 1016 initializeTest("<div><p>abc<br></p>def</div>"); 1017 let p = gEditor.querySelector("p"); 1018 let abc = p.firstChild; 1019 let def = p.nextSibling; 1020 gSelection.collapse(abc, 3); 1021 await sendDeleteKey(); 1022 checkEditorContentResultAsSubTest( 1023 [ 1024 "<div><p>abcdef</p></div>", 1025 "<div><p>abcdef<br></p></div>", 1026 ], 1027 t.name 1028 ); 1029 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1030 startContainer: p, 1031 startOffset: 1, 1032 endContainer: def, 1033 endOffset: 0, 1034 }); 1035 checkGetTargetRangesOfInputOnDeleteSomething(); 1036 }, 'Delete at "<div><p>abc[]<br></p>def</div>"'); 1037 1038 promise_test(async (t) => { 1039 initializeTest(`<div><p><img src="${kImgSrc}"><br></p>def</div>`); 1040 let p = gEditor.querySelector("p"); 1041 let abc = p.firstChild; 1042 let def = p.nextSibling; 1043 gSelection.collapse(p, 1); 1044 await sendDeleteKey(); 1045 checkEditorContentResultAsSubTest( 1046 [ 1047 `<div><p><img src="${kImgSrc}">def</p></div>`, 1048 `<div><p><img src="${kImgSrc}">def<br></p></div>`, 1049 ], 1050 t.name 1051 ); 1052 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1053 startContainer: p, 1054 startOffset: 1, 1055 endContainer: def, 1056 endOffset: 0, 1057 }); 1058 checkGetTargetRangesOfInputOnDeleteSomething(); 1059 }, 'Delete at "<div><p><img>{}<br></p>def</div>"'); 1060 1061 // Joining child block and parent block should remove invisible trailing 1062 // white-spaces of the child block and invisible following white-spaces 1063 // in the parent block, and they should be contained by a range of 1064 // `getTargetRanges()`, but maybe needs discussion. 1065 // https://github.com/w3c/input-events/issues/112 1066 promise_test(async (t) => { 1067 initializeTest("<div><p>abc </p> def</div>"); 1068 let abc = gEditor.querySelector("p").firstChild; 1069 let def = gEditor.querySelector("p").nextSibling; 1070 gSelection.collapse(abc, 3); 1071 await sendDeleteKey(); 1072 checkEditorContentResultAsSubTest( 1073 [ 1074 "<div><p>abcdef</p></div>", 1075 "<div><p>abcdef<br></p></div>", 1076 ], 1077 t.name 1078 ); 1079 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1080 startContainer: abc, 1081 startOffset: 3, 1082 endContainer: def, 1083 endOffset: 3, 1084 }); 1085 checkGetTargetRangesOfInputOnDeleteSomething(); 1086 }, 'Delete at "<div><p>abc[] </p> def</div>"'); 1087 1088 promise_test(async (t) => { 1089 initializeTest("<div><p><b>abc</b></p>def</div>"); 1090 let abc = gEditor.querySelector("b").firstChild; 1091 let def = gEditor.querySelector("p").nextSibling; 1092 gSelection.collapse(abc, 3); 1093 await sendDeleteKey(); 1094 checkEditorContentResultAsSubTest("<div><p><b>abc</b>def</p></div>", t.name); 1095 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1096 startContainer: abc, 1097 startOffset: 3, 1098 endContainer: def, 1099 endOffset: 0, 1100 }); 1101 checkGetTargetRangesOfInputOnDeleteSomething(); 1102 }, 'Delete at "<div><p><b>abc[]</b></p>def</div>"'); 1103 1104 promise_test(async (t) => { 1105 initializeTest("<div><p><b>abc</b></p><b>def</b></div>"); 1106 let abc = gEditor.querySelector("b").firstChild; 1107 let def = gEditor.querySelector("div > b").firstChild; 1108 gSelection.collapse(abc, 3); 1109 await sendDeleteKey(); 1110 checkEditorContentResultAsSubTest( 1111 [ 1112 "<div><p><b>abc</b><b>def</b></p></div>", 1113 "<div><p><b>abcdef</b></p></div>", 1114 ], 1115 t.name 1116 ); 1117 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1118 startContainer: abc, 1119 startOffset: 3, 1120 endContainer: def, 1121 endOffset: 0, 1122 }); 1123 checkGetTargetRangesOfInputOnDeleteSomething(); 1124 }, 'Delete at "<div><p><b>abc[]</b></p><b>def</b></div>"'); 1125 1126 promise_test(async (t) => { 1127 initializeTest("<div><p><b>abc</b></p><i>def</i></div>"); 1128 let abc = gEditor.querySelector("b").firstChild; 1129 let def = gEditor.querySelector("i").firstChild; 1130 gSelection.collapse(abc, 3); 1131 await sendDeleteKey(); 1132 checkEditorContentResultAsSubTest( 1133 "<div><p><b>abc</b><i>def</i></p></div>", 1134 t.name 1135 ); 1136 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1137 startContainer: abc, 1138 startOffset: 3, 1139 endContainer: def, 1140 endOffset: 0, 1141 }); 1142 checkGetTargetRangesOfInputOnDeleteSomething(); 1143 }, 'Delete at "<div><p><b>abc[]</b></p><i>def</i></div>"'); 1144 1145 promise_test(async (t) => { 1146 initializeTest("<div>abc<ul><li>def</li></ul>ghi</div>"); 1147 let abc = gEditor.querySelector("div").firstChild; 1148 let def = gEditor.querySelector("li").firstChild; 1149 gSelection.collapse(abc, 3); 1150 await sendDeleteKey(); 1151 checkEditorContentResultAsSubTest("<div>abcdefghi</div>", t.name); 1152 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1153 startContainer: abc, 1154 startOffset: 3, 1155 endContainer: def, 1156 endOffset: 0, 1157 }); 1158 checkGetTargetRangesOfInputOnDeleteSomething(); 1159 }, 'Delete at "<div>abc[]<ul><li>def</li></ul>ghi</div>"'); 1160 1161 promise_test(async (t) => { 1162 initializeTest("<div>abc <ul><li> def </li></ul> ghi</div>"); 1163 let abc = gEditor.querySelector("div").firstChild; 1164 let def = gEditor.querySelector("li").firstChild; 1165 gSelection.collapse(abc, 3); 1166 await sendDeleteKey(); 1167 checkEditorContentResultAsSubTest("<div>abcdefghi</div>", t.name); 1168 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1169 startContainer: abc, 1170 startOffset: 3, 1171 endContainer: def, 1172 endOffset: 1, 1173 }); 1174 checkGetTargetRangesOfInputOnDeleteSomething(); 1175 }, 'Delete at "<div>abc[] <ul><li> def </li></ul> ghi</div>"'); 1176 1177 promise_test(async (t) => { 1178 initializeTest("<div>abc <ul><li> def </li></ul> ghi</div>"); 1179 let abc = gEditor.querySelector("div").firstChild; 1180 let def = gEditor.querySelector("li").firstChild; 1181 gSelection.collapse(abc, abc.length); 1182 await sendDeleteKey(); 1183 checkEditorContentResultAsSubTest("<div>abcdefghi</div>", t.name); 1184 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1185 startContainer: abc, 1186 startOffset: 3, 1187 endContainer: def, 1188 endOffset: 1, 1189 }); 1190 checkGetTargetRangesOfInputOnDeleteSomething(); 1191 }, 'Delete at "<div>abc []<ul><li> def </li></ul> ghi</div>"'); 1192 1193 promise_test(async (t) => { 1194 initializeTest("<div>abc<ul><li>def</li></ul>ghi</div>"); 1195 let def = gEditor.querySelector("li").firstChild; 1196 let ghi = gEditor.querySelector("ul").nextSibling; 1197 gSelection.collapse(def, 3); 1198 await sendDeleteKey(); 1199 checkEditorContentResultAsSubTest( 1200 "<div>abc<ul><li>defghi</li></ul></div>", 1201 t.name 1202 ); 1203 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1204 startContainer: def, 1205 startOffset: 3, 1206 endContainer: ghi, 1207 endOffset: 0, 1208 }); 1209 checkGetTargetRangesOfInputOnDeleteSomething(); 1210 }, 'Delete at "<div>abc<ul><li>def[]</li></ul>ghi</div>"'); 1211 1212 promise_test(async (t) => { 1213 initializeTest("<div>abc <ul><li> def </li></ul> ghi</div>"); 1214 let def = gEditor.querySelector("li").firstChild; 1215 let ghi = gEditor.querySelector("ul").nextSibling; 1216 gSelection.collapse(def, 5); 1217 await sendDeleteKey(); 1218 checkEditorContentResultAsSubTest( 1219 [ 1220 "<div>abc <ul><li> defghi</li></ul></div>", 1221 "<div>abc <ul><li>defghi</li></ul></div>", 1222 "<div>abc<ul><li>defghi</li></ul></div>", 1223 ], 1224 t.name 1225 ); 1226 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1227 startContainer: def, 1228 startOffset: 5, 1229 endContainer: ghi, 1230 endOffset: 1, 1231 }); 1232 checkGetTargetRangesOfInputOnDeleteSomething(); 1233 }, 'Delete at "<div>abc <ul><li> def[] </li></ul> ghi</div>"'); 1234 1235 promise_test(async (t) => { 1236 initializeTest("<div>abc <ul><li> def </li></ul> ghi</div>"); 1237 let def = gEditor.querySelector("li").firstChild; 1238 let ghi = gEditor.querySelector("ul").nextSibling; 1239 gSelection.collapse(def, def.length); 1240 await sendDeleteKey(); 1241 checkEditorContentResultAsSubTest( 1242 [ 1243 "<div>abc <ul><li> defghi</li></ul></div>", 1244 "<div>abc <ul><li>defghi</li></ul></div>", 1245 "<div>abc<ul><li>defghi</li></ul></div>", 1246 ], 1247 t.name 1248 ); 1249 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1250 startContainer: def, 1251 startOffset: 5, 1252 endContainer: ghi, 1253 endOffset: 1, 1254 }); 1255 checkGetTargetRangesOfInputOnDeleteSomething(); 1256 }, 'Delete at "<div>abc <ul><li> def []</li></ul> ghi</div>"'); 1257 1258 promise_test(async (t) => { 1259 initializeTest("<div>abc<ul><li>def</li><li>ghi</li></ul>jkl</div>"); 1260 let abc = gEditor.querySelector("div").firstChild; 1261 let def = gEditor.querySelector("li").firstChild; 1262 gSelection.collapse(abc, 3); 1263 await sendDeleteKey(); 1264 checkEditorContentResultAsSubTest( 1265 "<div>abcdef<ul><li>ghi</li></ul>jkl</div>", 1266 t.name 1267 ); 1268 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1269 startContainer: abc, 1270 startOffset: 3, 1271 endContainer: def, 1272 endOffset: 0, 1273 }); 1274 checkGetTargetRangesOfInputOnDeleteSomething(); 1275 }, 'Delete at "<div>abc[]<ul><li>def</li><li>ghi</li></ul>jkl</div>"'); 1276 1277 promise_test(async (t) => { 1278 initializeTest("<div>abc<ul><li>def</li><li>ghi</li></ul>jkl</div>"); 1279 let def = gEditor.querySelector("li").firstChild; 1280 let ghi = gEditor.querySelector("li + li").firstChild; 1281 gSelection.collapse(def, 3); 1282 await sendDeleteKey(); 1283 checkEditorContentResultAsSubTest( 1284 "<div>abc<ul><li>defghi</li></ul>jkl</div>", 1285 t.name 1286 ); 1287 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1288 startContainer: def, 1289 startOffset: 3, 1290 endContainer: ghi, 1291 endOffset: 0, 1292 }); 1293 checkGetTargetRangesOfInputOnDeleteSomething(); 1294 }, 'Delete at "<div>abc<ul><li>def[]</li><li>ghi</li></ul>jkl</div>"'); 1295 1296 promise_test(async (t) => { 1297 initializeTest("<div>abc<ul><li>def</li><li>ghi</li></ul>jkl</div>"); 1298 let ghi = gEditor.querySelector("li + li").firstChild; 1299 let jkl = gEditor.querySelector("ul").nextSibling; 1300 gSelection.collapse(ghi, 3); 1301 await sendDeleteKey(); 1302 checkEditorContentResultAsSubTest( 1303 "<div>abc<ul><li>def</li><li>ghijkl</li></ul></div>", 1304 t.name 1305 ); 1306 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1307 startContainer: ghi, 1308 startOffset: 3, 1309 endContainer: jkl, 1310 endOffset: 0, 1311 }); 1312 checkGetTargetRangesOfInputOnDeleteSomething(); 1313 }, 'Delete at "<div>abc<ul><li>def</li><li>ghi[]</li></ul>jkl</div>"'); 1314 1315 // Delete in empty paragraph should remove the empty paragraph. In this 1316 // case, it should be treated as joining with the previous paragraph. 1317 // The target range should include the invisible <br> element in the empty 1318 // paragraph. 1319 promise_test(async (t) => { 1320 initializeTest("<p><br></p><p>abc</p>"); 1321 let p1 = gEditor.querySelector("p"); 1322 let p2 = p1.nextSibling; 1323 let abc = p2.firstChild; 1324 gSelection.collapse(p1, 0); 1325 await sendDeleteKey(); 1326 checkEditorContentResultAsSubTest("<p>abc</p>", t.name); 1327 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1328 startContainer: p1, 1329 startOffset: 0, 1330 endContainer: abc, 1331 endOffset: 0, 1332 }); 1333 checkGetTargetRangesOfInputOnDeleteSomething(); 1334 }, 'Delete at "<p>{}<br></p><p>abc</p>"'); 1335 1336 // Delete ignore the empty span and the other things must be same as the 1337 // previous test. 1338 promise_test(async (t) => { 1339 initializeTest("<p><span></span><br></p><p>abc</p>"); 1340 let p1 = gEditor.querySelector("p"); 1341 let span = p1.firstChild; 1342 let p2 = p1.nextSibling; 1343 let abc = p2.firstChild; 1344 gSelection.collapse(span, 0); 1345 await sendDeleteKey(); 1346 checkEditorContentResultAsSubTest("<p>abc</p>", t.name); 1347 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1348 startContainer: p1, 1349 startOffset: 0, 1350 endContainer: abc, 1351 endOffset: 0, 1352 }); 1353 checkGetTargetRangesOfInputOnDeleteSomething(); 1354 }, 'Delete at "<p><span>{}</span><br></p><p>abc</p>"'); 1355 1356 // If invisible white-spaces are removed with same action as above tests, 1357 // the range should be included in the target ranges. 1358 promise_test(async (t) => { 1359 initializeTest("<p><br></p><p> abc</p>"); 1360 let p1 = gEditor.querySelector("p"); 1361 let p2 = p1.nextSibling; 1362 let abc = p2.firstChild; 1363 gSelection.collapse(p1, 0); 1364 await sendDeleteKey(); 1365 checkEditorContentResultAsSubTest( 1366 [ 1367 "<p> abc</p>", 1368 "<p>abc</p>", 1369 ], 1370 t.name 1371 ); 1372 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1373 startContainer: p1, 1374 startOffset: 0, 1375 endContainer: abc, 1376 endOffset: 5 - abc.length, 1377 }); 1378 checkGetTargetRangesOfInputOnDeleteSomething(); 1379 }, 'Delete at "<p>{}<br></p><p> abc</p>"'); 1380 1381 // If the next block begins with non-editable content, target range 1382 // should be at the non-editable content node. 1383 promise_test(async (t) => { 1384 initializeTest("<p><br></p><p><span contenteditable=\"false\">abc</span>def</p>"); 1385 let p1 = gEditor.querySelector("p"); 1386 let p2 = p1.nextSibling; 1387 let span = gEditor.querySelector("span"); 1388 gSelection.collapse(p1, 0); 1389 await sendDeleteKey(); 1390 checkEditorContentResultAsSubTest( 1391 "<p><span contenteditable=\"false\">abc</span>def</p>", 1392 t.name 1393 ); 1394 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1395 startContainer: p1, 1396 startOffset: 0, 1397 endContainer: p2, 1398 endOffset: 0, 1399 }); 1400 checkGetTargetRangesOfInputOnDeleteSomething(); 1401 }, 'Delete at "<p>{}<br></p><p><span contenteditable="false">abc</span>def</p>"'); 1402 1403 // If next non-editable paragraph is deleted, target range should end 1404 // with start of the text node in the last paragraph. Otherwise, ends at 1405 // the non-editable paragraph. 1406 promise_test(async (t) => { 1407 initializeTest("<p><br></p><p contenteditable=\"false\">abc</p><p>def</p>"); 1408 let p1 = gEditor.querySelector("p"); 1409 let p2 = p1.nextSibling; 1410 let p3 = p2.nextSibling; 1411 let def = p3.firstChild; 1412 gSelection.collapse(p3, 0); 1413 await sendDeleteKey(); 1414 checkEditorContentResultAsSubTest( 1415 [ 1416 "<p>def</p>", 1417 "<p contenteditable=\"false\">abc</p><p>def</p>", 1418 ], 1419 t.name 1420 ); 1421 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1422 startContainer: p1, 1423 startOffset: 0, 1424 endContainer: p2.isConnected ? gEditor : p3, 1425 endOffset: p2.isConnected ? 1 : 0, 1426 }); 1427 checkGetTargetRangesOfInputOnDeleteSomething(); 1428 }, 'Delete at "<p>{}<br></p><p contenteditable=\"false\">abc</p><p>def</p>"'); 1429 1430 promise_test(async (t) => { 1431 initializeTest("<p>abc<span contenteditable=\"false\">def</span>ghi</p>"); 1432 let p = gEditor.querySelector("p"); 1433 let abc = p.firstChild; 1434 gSelection.collapse(abc, 3); 1435 await sendDeleteKey(); 1436 checkEditorContentResultAsSubTest( 1437 [ 1438 "<p>abc<span contenteditable=\"false\">def</span>ghi</p>", 1439 "<p>abcghi</p>", 1440 "<p>abcghi<br></p>", 1441 ], 1442 t.name 1443 ); 1444 if (gEditor.innerHTML === "<p>abc<span contenteditable=\"false\">def</span>ghi</p>") { 1445 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1446 startContainer: abc, 1447 startOffset: 3, 1448 endContainer: abc, 1449 endOffset: 3, 1450 }); 1451 checkGetTargetRangesOfInputOnDoNothing(); 1452 } else { 1453 // If the non-editable `<span>` is deleted, it should be treated as 1454 // an atomic node. 1455 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1456 startContainer: p, 1457 startOffset: 1, 1458 endContainer: p, 1459 endOffset: 2, 1460 }); 1461 checkGetTargetRangesOfInputOnDeleteSomething(); 1462 } 1463 }, 'Delete at "<p>abc[]<span contenteditable=\"false\">def</span>ghi</p>"'); 1464 1465 // If just removes the paragraph, target range should end at the table element. 1466 promise_test(async (t) => { 1467 initializeTest("<p><br></p><table><tr><td>cell</td></tr></table>"); 1468 let cell = gEditor.querySelector("td"); 1469 let p = gEditor.querySelector("p"); 1470 gSelection.collapse(p, 0); 1471 await sendDeleteKey(); 1472 checkEditorContentResultAsSubTest( 1473 [ 1474 "<table><tbody><tr><td>cell</td></tr></tbody></table>", 1475 "<p><br></p><table><tbody><tr><td>cell</td></tr></tbody></table>", 1476 ], 1477 t.name 1478 ); 1479 if (p.isConnected) { 1480 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1481 startContainer: p, 1482 startOffset: 0, 1483 endContainer: p, 1484 endOffset: 0, 1485 }); 1486 checkGetTargetRangesOfInputOnDoNothing(); 1487 } else { 1488 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1489 startContainer: p, 1490 startOffset: 0, 1491 endContainer: gEditor, 1492 endOffset: 1, 1493 }); 1494 checkGetTargetRangesOfInputOnDeleteSomething(); 1495 } 1496 }, 'Delete at "<p>{}<br></p><table><tr><td>cell</td></tr></table>"'); 1497 1498 // If table cell won't be joined, target range should be collapsed in the 1499 // cell. 1500 promise_test(async (t) => { 1501 initializeTest("<table><tr><td><br></td><td>cell2</td></tr></table>"); 1502 let cell1 = gEditor.querySelector("td"); 1503 let cell2 = cell1.nextSibling; 1504 gSelection.collapse(cell1, 0); 1505 await sendDeleteKey(); 1506 checkEditorContentResultAsSubTest( 1507 "<table><tbody><tr><td><br></td><td>cell2</td></tr></tbody></table>", 1508 t.name 1509 ); 1510 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1511 startContainer: cell1, 1512 startOffset: 0, 1513 endContainer: cell1, 1514 endOffset: 0, 1515 }); 1516 checkGetTargetRangesOfInputOnDoNothing(); 1517 }, 'Delete at "<table><tr><td>{}<br></td><td>cell2</td></tr></table>"'); 1518 1519 // If table caption won't be deleted, target range should be collapsed in the 1520 // caption element. 1521 promise_test(async (t) => { 1522 initializeTest("<table><caption><br></caption><tr><td>cell</td></tr></table>"); 1523 let caption = gEditor.querySelector("caption"); 1524 gSelection.collapse(caption, 0); 1525 await sendDeleteKey(); 1526 checkEditorContentResultAsSubTest( 1527 "<table><caption><br></caption><tbody><tr><td>cell</td></tr></tbody></table>", 1528 t.name 1529 ); 1530 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1531 startContainer: caption, 1532 startOffset: 0, 1533 endContainer: caption, 1534 endOffset: 0, 1535 }); 1536 checkGetTargetRangesOfInputOnDoNothing(); 1537 }, 'Delete at "<table><caption>{}<br></caption><tr><td>cell</td></tr></table>"'); 1538 1539 // If a table cell element is selected, only its content should be deleted. 1540 promise_test(async (t) => { 1541 initializeTest("<table><tr><td>cell1</td><td>cell2</td></tr></table>"); 1542 let cell1 = gEditor.querySelector("td"); 1543 let tr = cell1.parentNode; 1544 gSelection.setBaseAndExtent(tr, 0, tr, 1); 1545 await sendDeleteKey(); 1546 checkEditorContentResultAsSubTest( 1547 [ 1548 "<table><tbody><tr><td></td><td>cell2</td></tr></tbody></table>", 1549 "<table><tbody><tr><td><br></td><td>cell2</td></tr></tbody></table>", 1550 ], 1551 t.name 1552 ); 1553 // XXX Perhaps, target range should be selecting only all children of 1554 // cell1 instead. 1555 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1556 startContainer: tr, 1557 startOffset: 0, 1558 endContainer: tr, 1559 endOffset: 1, 1560 }); 1561 checkGetTargetRangesOfInputOnDeleteSomething(); 1562 }, 'Delete at "<table><tr>{<td>cell1</td>}<td>cell2</td></tr></table>"'); 1563 1564 promise_test(async (t) => { 1565 initializeTest("<table><tr><td>cell1</td><td>cell2</td></tr></table>"); 1566 let cell2 = gEditor.querySelector("td + td"); 1567 let tr = cell2.parentNode; 1568 gSelection.setBaseAndExtent(tr, 1, tr, 2); 1569 await sendDeleteKey(); 1570 checkEditorContentResultAsSubTest( 1571 [ 1572 "<table><tbody><tr><td>cell1</td><td></td></tr></tbody></table>", 1573 "<table><tbody><tr><td>cell1</td><td><br></td></tr></tbody></table>", 1574 ], 1575 t.name 1576 ); 1577 // XXX Perhaps, target range should be selecting only all children of 1578 // cell1 instead. 1579 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1580 startContainer: tr, 1581 startOffset: 1, 1582 endContainer: tr, 1583 endOffset: 2, 1584 }); 1585 checkGetTargetRangesOfInputOnDeleteSomething(); 1586 }, 'Delete at "<table><tr><td>cell1</td>{<td>cell2</td>}</tr></table>"'); 1587 1588 // If the last table cell element is selected, what browsers should do? 1589 promise_test(async (t) => { 1590 initializeTest("<table><tr><td>cell</td></tr></table>"); 1591 let cell = gEditor.querySelector("td"); 1592 let tr = cell.parentNode; 1593 let table = gEditor.querySelector("table"); 1594 gSelection.setBaseAndExtent(tr, 0, tr, 1); 1595 await sendDeleteKey(); 1596 checkEditorContentResultAsSubTest( 1597 [ 1598 "<table><tbody><tr><td></td></tr></tbody></table>", 1599 "<table><tbody><tr><td><br></td></tr></tbody></table>", 1600 "<br>", 1601 ], 1602 t.name 1603 ); 1604 if (gEditor.querySelector("table")) { 1605 // XXX Perhaps, target range should be selecting only all children of 1606 // cell1 instead. 1607 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1608 startContainer: tr, 1609 startOffset: 0, 1610 endContainer: tr, 1611 endOffset: 1, 1612 }); 1613 } else { 1614 // If it causes deleting entire the table, the `<table>` element should 1615 // be in the target range. 1616 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1617 startContainer: gEditor, 1618 startOffset: 0, 1619 endContainer: gEditor, 1620 endOffset: 1, 1621 }); 1622 } 1623 checkGetTargetRangesOfInputOnDeleteSomething(); 1624 }, 'Delete at "<table><tr>{<td>cell</td>}</tr></table>"'); 1625 1626 // Testing multiple cell selection mode. 1627 promise_test(async (t) => { 1628 initializeTest("<table><tr><td>cell1</td><td>cell2</td></tr><tr><td>cell3</td><td>cell4</td></tr></table>"); 1629 let cell1 = gEditor.querySelector("td"); 1630 let cell4 = gEditor.querySelector("tr + tr > td + td"); 1631 let tr1 = cell1.parentNode; 1632 let tr2 = cell4.parentNode; 1633 gSelection.removeAllRanges(); 1634 let range = document.createRange(); 1635 range.selectNode(cell1); 1636 gSelection.addRange(range); 1637 range = document.createRange(); 1638 range.selectNode(cell4); 1639 gSelection.addRange(range); 1640 assert_equals(gSelection.rangeCount, 2, "Should support multiple cell selection"); 1641 await sendDeleteKey(); 1642 checkEditorContentResultAsSubTest( 1643 [ 1644 "<table><tbody><tr><td></td><td>cell2</td></tr><tr><td>cell3</td><td></td></tr></tbody></table>", 1645 "<table><tbody><tr><td><br></td><td>cell2</td></tr><tr><td>cell3</td><td><br></td></tr></tbody></table>", 1646 ], 1647 t.name 1648 ); 1649 // XXX Perhaps, target range should be selecting only all children of 1650 // cell1 and cell4 instead. 1651 checkGetTargetRangesOfBeforeinputOnDeleteSomething([ 1652 { 1653 startContainer: tr1, 1654 startOffset: 0, 1655 endContainer: tr1, 1656 endOffset: 1, 1657 }, 1658 { 1659 startContainer: tr2, 1660 startOffset: 1, 1661 endContainer: tr2, 1662 endOffset: 2, 1663 }, 1664 ]); 1665 checkGetTargetRangesOfInputOnDeleteSomething(); 1666 }, 'Delete at "<table><tr>{<td>cell1</td>}<td>cell2</td></tr><tr><td>cell3</td>{<td>cell4</td>}</tr></table>"'); 1667 1668 promise_test(async (t) => { 1669 initializeTest("<table><tr><td>cell1</td><td>cell2</td></tr><tr><td>cell3</td><td>cell4</td></tr></table>"); 1670 let cell1 = gEditor.querySelector("td"); 1671 let cell3 = gEditor.querySelector("tr + tr > td"); 1672 let tr1 = cell1.parentNode; 1673 let tr2 = cell3.parentNode; 1674 gSelection.removeAllRanges(); 1675 let range = document.createRange(); 1676 range.selectNode(cell1); 1677 gSelection.addRange(range); 1678 range = document.createRange(); 1679 range.selectNode(cell3); 1680 gSelection.addRange(range); 1681 assert_equals(gSelection.rangeCount, 2, "Should support multiple cell selection"); 1682 await sendDeleteKey(); 1683 checkEditorContentResultAsSubTest( 1684 [ 1685 "<table><tbody><tr><td></td><td>cell2</td></tr><tr><td></td><td>cell4</td></tr></tbody></table>", 1686 "<table><tbody><tr><td><br></td><td>cell2</td></tr><tr><td><br></td><td>cell4</td></tr></tbody></table>", 1687 "<table><tbody><tr><td>cell2</td></tr><tr><td>cell4</td></tr></tbody></table>", 1688 ], 1689 t.name 1690 ); 1691 // XXX Perhaps, target range should be selecting only all children of 1692 // cell1 and cell3 instead. 1693 checkGetTargetRangesOfBeforeinputOnDeleteSomething([ 1694 { 1695 startContainer: tr1, 1696 startOffset: 0, 1697 endContainer: tr1, 1698 endOffset: 1, 1699 }, 1700 { 1701 startContainer: tr2, 1702 startOffset: 0, 1703 endContainer: tr2, 1704 endOffset: 1, 1705 }, 1706 ]); 1707 checkGetTargetRangesOfInputOnDeleteSomething(); 1708 }, 'Delete at "<table><tr>{<td>cell1</td>}<td>cell2</td></tr><tr>{<td>cell3</td>}<td>cell4</td></tr></table>"'); 1709 1710 promise_test(async (t) => { 1711 initializeTest("<table><tr><td>cell1</td><td>cell2</td></tr><tr><td>cell3</td><td>cell4</td></tr></table>"); 1712 let cell1 = gEditor.querySelector("td"); 1713 let cell2 = gEditor.querySelector("td + td"); 1714 let tr1 = cell1.parentNode; 1715 let tbody = tr1.parentNode; 1716 gSelection.removeAllRanges(); 1717 let range = document.createRange(); 1718 range.selectNode(cell1); 1719 gSelection.addRange(range); 1720 range = document.createRange(); 1721 range.selectNode(cell2); 1722 gSelection.addRange(range); 1723 assert_equals(gSelection.rangeCount, 2, "Should support multiple cell selection"); 1724 await sendDeleteKey(); 1725 checkEditorContentResultAsSubTest( 1726 [ 1727 "<table><tbody><tr><td></td><td></td></tr><tr><td>cell3</td><td>cell4</td></tr></tbody></table>", 1728 "<table><tbody><tr><td><br></td><td><br></td></tr><tr><td>cell3</td><td>cell4</td></tr></tbody></table>", 1729 "<table><tbody><tr><td>cell3</td><td>cell4</td></tr></tbody></table>", 1730 ], 1731 t.name 1732 ); 1733 if (gEditor.querySelector("tr + tr")) { 1734 // XXX Perhaps, target range should be selecting only all children of 1735 // cell1 and cell2 instead. 1736 checkGetTargetRangesOfBeforeinputOnDeleteSomething([ 1737 { 1738 startContainer: tr1, 1739 startOffset: 0, 1740 endContainer: tr1, 1741 endOffset: 1, 1742 }, 1743 { 1744 startContainer: tr1, 1745 startOffset: 1, 1746 endContainer: tr1, 1747 endOffset: 2, 1748 }, 1749 ]); 1750 } else { 1751 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1752 startContainer: tbody, 1753 startOffset: 0, 1754 endContainer: tbody, 1755 endOffset: 1, 1756 }); 1757 } 1758 checkGetTargetRangesOfInputOnDeleteSomething(); 1759 }, 'Delete at "<table><tr>{<td>cell1</td>}{<td>cell2</td>}</tr><tr><td>cell3</td><td>cell4</td></tr></table>"'); 1760 1761 promise_test(async (t) => { 1762 initializeTest("<table><tr><td>cell1</td><td>cell2</td></tr><tr><td>cell3</td><td>cell4</td></tr></table>"); 1763 let cell3 = gEditor.querySelector("tr + tr > td"); 1764 let cell4 = gEditor.querySelector("tr + tr > td + td"); 1765 let tr2 = cell3.parentNode; 1766 gSelection.removeAllRanges(); 1767 let range = document.createRange(); 1768 range.selectNode(cell3); 1769 gSelection.addRange(range); 1770 range = document.createRange(); 1771 range.selectNode(cell4); 1772 gSelection.addRange(range); 1773 assert_equals(gSelection.rangeCount, 2, "Should support multiple cell selection"); 1774 await sendDeleteKey(); 1775 checkEditorContentResultAsSubTest( 1776 [ 1777 "<table><tbody><tr><td>cell1</td><td>cell2</td></tr><tr><td></td><td></td></tr></tbody></table>", 1778 "<table><tbody><tr><td>cell1</td><td>cell2</td></tr><tr><td><br></td><td><br></td></tr></tbody></table>", 1779 "<table><tbody><tr><td>cell1</td><td>cell2</td></tr></tbody></table>", 1780 ], 1781 t.name 1782 ); 1783 if (gEditor.querySelector("tr + tr")) { 1784 // XXX Perhaps, target range should be selecting only all children of 1785 // cell3 and cell4 instead. 1786 checkGetTargetRangesOfBeforeinputOnDeleteSomething([ 1787 { 1788 startContainer: tr2, 1789 startOffset: 0, 1790 endContainer: tr2, 1791 endOffset: 1, 1792 }, 1793 { 1794 startContainer: tr2, 1795 startOffset: 1, 1796 endContainer: tr2, 1797 endOffset: 2, 1798 }, 1799 ]); 1800 } else { 1801 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1802 startContainer: tbody, 1803 startOffset: 1, 1804 endContainer: tbody, 1805 endOffset: 2, 1806 }); 1807 } 1808 checkGetTargetRangesOfInputOnDeleteSomething(); 1809 }, 'Delete at "<table><tr><td>cell1</td><td>cell2</td></tr><tr>{<td>cell3</td>}{<td>cell4</td>}</tr></table>"'); 1810 1811 promise_test(async (t) => { 1812 initializeTest("<table><tr><td>cell1</td><td>cell2</td></tr><tr><td>cell3</td><td>cell4</td></tr></table>"); 1813 let cell1 = gEditor.querySelector("td"); 1814 let cell2 = gEditor.querySelector("td + td"); 1815 let cell3 = gEditor.querySelector("tr + tr > td"); 1816 let cell4 = gEditor.querySelector("tr + tr > td + td"); 1817 let tr1 = cell1.parentNode; 1818 let tr2 = cell3.parentNode; 1819 gSelection.removeAllRanges(); 1820 let range = document.createRange(); 1821 range.selectNode(cell1); 1822 gSelection.addRange(range); 1823 range = document.createRange(); 1824 range.selectNode(cell2); 1825 gSelection.addRange(range); 1826 range = document.createRange(); 1827 range.selectNode(cell3); 1828 gSelection.addRange(range); 1829 range = document.createRange(); 1830 range.selectNode(cell4); 1831 gSelection.addRange(range); 1832 assert_equals(gSelection.rangeCount, 4, "Should support multiple cell selection"); 1833 await sendDeleteKey(); 1834 checkEditorContentResultAsSubTest( 1835 [ 1836 "<table><tbody><tr><td></td><td></td></tr><tr><td></td><td></td></tr></tbody></table>", 1837 "<table><tbody><tr><td><br></td><td><br></td></tr><tr><td><br></td><td><br></td></tr></tbody></table>", 1838 "<br>", 1839 ], 1840 t.name 1841 ); 1842 if (gEditor.querySelector("table")) { 1843 // XXX Perhaps, target range should be selecting only all children of 1844 // cell1, cell2, cell3 and cell4 instead. 1845 checkGetTargetRangesOfBeforeinputOnDeleteSomething([ 1846 { 1847 startContainer: tr1, 1848 startOffset: 0, 1849 endContainer: tr1, 1850 endOffset: 1, 1851 }, 1852 { 1853 startContainer: tr1, 1854 startOffset: 1, 1855 endContainer: tr1, 1856 endOffset: 2, 1857 }, 1858 { 1859 startContainer: tr2, 1860 startOffset: 0, 1861 endContainer: tr2, 1862 endOffset: 1, 1863 }, 1864 { 1865 startContainer: tr2, 1866 startOffset: 1, 1867 endContainer: tr2, 1868 endOffset: 2, 1869 }, 1870 ]); 1871 } else { 1872 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1873 startContainer: gEditor, 1874 startOffset: 0, 1875 endContainer: gEditor, 1876 endOffset: 1, 1877 }); 1878 } 1879 checkGetTargetRangesOfInputOnDeleteSomething(); 1880 }, 'Delete at "<table><tr>{<td>cell1</td>}{<td>cell2</td>}</tr><tr>{<td>cell3</td>}{<td>cell4</td>}</tr></table>"'); 1881 1882 promise_test(async (t) => { 1883 initializeTest("<table><tr><td>cell1</td><td>cell2</td></tr><tr><td>cell3</td><td>cell4</td></tr></table>"); 1884 let cell1 = gEditor.querySelector("td"); 1885 let cell2 = gEditor.querySelector("td + td"); 1886 let cell4 = gEditor.querySelector("tr + tr > td + td"); 1887 let tr1 = cell1.parentNode; 1888 let tr2 = cell4.parentNode; 1889 gSelection.removeAllRanges(); 1890 let range = document.createRange(); 1891 range.selectNode(cell1); 1892 gSelection.addRange(range); 1893 range = document.createRange(); 1894 range.setStart(cell2.firstChild, 1); 1895 range.setEnd(cell2.firstChild, 4); 1896 gSelection.addRange(range); 1897 range = document.createRange(); 1898 range.selectNode(cell4); 1899 gSelection.addRange(range); 1900 assert_equals(gSelection.rangeCount, 3, "Should support multiple cell selection"); 1901 await sendDeleteKey(); 1902 checkEditorContentResultAsSubTest( 1903 [ 1904 "<table><tbody><tr><td></td><td>cell2</td></tr><tr><td>cell3</td><td></td></tr></tbody></table>", 1905 "<table><tbody><tr><td><br></td><td>cell2</td></tr><tr><td>cell3</td><td><br></td></tr></tbody></table>", 1906 "<table><tbody><tr><td></td><td>c2</td></tr><tr><td>cell3</td><td></td></tr></tbody></table>", 1907 "<table><tbody><tr><td><br></td><td>c2</td></tr><tr><td>cell3</td><td><br></td></tr></tbody></table>", 1908 ], 1909 t.name 1910 ); 1911 if (cell2.firstChild.length == "cell2".length) { 1912 // XXX Perhaps, target range should be selecting only all children of 1913 // cell1 and cell4 instead. 1914 checkGetTargetRangesOfBeforeinputOnDeleteSomething([ 1915 { 1916 startContainer: tr1, 1917 startOffset: 0, 1918 endContainer: tr1, 1919 endOffset: 1, 1920 }, 1921 { 1922 startContainer: tr2, 1923 startOffset: 1, 1924 endContainer: tr2, 1925 endOffset: 2, 1926 }, 1927 ]); 1928 } else { 1929 checkGetTargetRangesOfBeforeinputOnDeleteSomething([ 1930 { 1931 startContainer: tr1, 1932 startOffset: 0, 1933 endContainer: tr1, 1934 endOffset: 1, 1935 }, 1936 { 1937 startContainer: cell2.firstChild, 1938 startOffset: 1, 1939 endContainer: cell2.firstChild, 1940 endOffset: 4, 1941 }, 1942 { 1943 startContainer: tr2, 1944 startOffset: 1, 1945 endContainer: tr2, 1946 endOffset: 2, 1947 }, 1948 ]); 1949 } 1950 checkGetTargetRangesOfInputOnDeleteSomething(); 1951 }, 'Delete at "<table><tr>{<td>cell1</td>}<td>c[ell]2</td></tr><tr>{<td>cell3</td>}<td>cell4</td></tr></table>"'); 1952 1953 // If caret is not adjacent of deleting character, browser may not delete the 1954 // character, but update the caret position for next deletion. 1955 promise_test(async (t) => { 1956 initializeTest("<p>helloשלום</p>"); 1957 let text1 = gEditor.querySelector("p").firstChild; 1958 let text2 = text1.nextSibling; 1959 gSelection.collapse(text1, 4); 1960 await sendArrowRightKey(); 1961 await sendDeleteKey(); 1962 checkEditorContentResultAsSubTest( 1963 [ 1964 "<p>hello\u05E9\u05DC\u05D5\u05DD</p>", 1965 "<p>hello\u05DC\u05D5\u05DD</p>", 1966 "<p>hello\u05E9\u05DC\u05D5</p>", 1967 ], 1968 t.name 1969 ); 1970 if (gEditor.innerHTML === "<p>hello\u05E9\u05DC\u05D5\u05DD</p>") { 1971 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1972 startContainer: text2 ? text2 : text1, 1973 startOffset: text2 ? 0 : 5, 1974 endContainer: text2 ? text2 : text1, 1975 endOffset: text2 ? 0 : 5, 1976 }); 1977 checkGetTargetRangesOfInputOnDoNothing(); 1978 } else if (gEditor.innerHTML === "<p>hello\u05DC\u05D5\u05DD</p>") { 1979 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1980 startContainer: text2 ? text2: text1, 1981 startOffset: text2 ? 0 : 5, 1982 endContainer: text2 ? text2 : text1, 1983 endOffset: text2 ? 1 : 6, 1984 }); 1985 checkGetTargetRangesOfInputOnDeleteSomething(); 1986 } else { 1987 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 1988 startContainer: text2 ? text2: text1, 1989 startOffset: text2 ? 3 : 8, 1990 endContainer: text2 ? text2 : text1, 1991 endOffset: text2 ? 4 : 9, 1992 }); 1993 checkGetTargetRangesOfInputOnDeleteSomething(); 1994 } 1995 }, 'Delete at "<p>hello[]שלום</p>"'); 1996 1997 // The following tests check whether the range returned from 1998 // `beforeinput[0].getTargetRanges()` is modified or different range is 1999 // modified instead. I.e., they don't test which type of deletion should 2000 // occur. Therefore, their result depends on browser's key bindings, 2001 // system settings and running OS. 2002 2003 function getFirstDifferentOffset(currentString, originalString) { 2004 for (let i = 0; i < currentString.length; i++) { 2005 if (currentString.charAt(i) !== originalString.charAt(i) && 2006 (originalString.charAt(i) !== " " || !currentString.charAt("\u00A0"))) { 2007 return i; 2008 } 2009 } 2010 return currentString.length; 2011 } 2012 2013 promise_test(async (t) => { 2014 const kText = "abc def ghi"; 2015 initializeTest(`<p>${kText}</p>`); 2016 let p = gEditor.querySelector("p"); 2017 gSelection.collapse(p.firstChild, "abc ".length); 2018 await sendDeleteKey(kShift); 2019 let startOffset = getFirstDifferentOffset(p.firstChild.data, kText); 2020 let length = kText.length - p.firstChild.data.length; 2021 checkEditorContentResultAsSubTest( 2022 `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`, 2023 t.name, 2024 { ignoreWhiteSpaceDifference: true } 2025 ); 2026 if (startOffset === kText.length) { 2027 checkBeforeinputAndInputEventsOnNOOP(); 2028 return; 2029 } 2030 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 2031 startContainer: p.firstChild, 2032 startOffset: startOffset, 2033 endContainer: p.firstChild, 2034 endOffset: startOffset + length, 2035 }); 2036 checkGetTargetRangesOfInputOnDeleteSomething(); 2037 }, 'Shift + Delete at "<p>abc []def ghi</p>"'); 2038 2039 promise_test(async (t) => { 2040 const kText = "abc def ghi"; 2041 initializeTest(`<p>${kText}</p>`); 2042 let p = gEditor.querySelector("p"); 2043 gSelection.collapse(p.firstChild, "abc ".length); 2044 await sendDeleteKey(kControl); 2045 let startOffset = getFirstDifferentOffset(p.firstChild.data, kText); 2046 let length = kText.length - p.firstChild.data.length; 2047 checkEditorContentResultAsSubTest( 2048 `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`, 2049 t.name, 2050 { ignoreWhiteSpaceDifference: true } 2051 ); 2052 if (startOffset === kText.length) { 2053 checkBeforeinputAndInputEventsOnNOOP(); 2054 return; 2055 } 2056 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 2057 startContainer: p.firstChild, 2058 startOffset: startOffset, 2059 endContainer: p.firstChild, 2060 endOffset: startOffset + length, 2061 }); 2062 checkGetTargetRangesOfInputOnDeleteSomething(); 2063 }, 'Control + Delete at "<p>abc []def ghi</p>"'); 2064 2065 promise_test(async (t) => { 2066 const kText = "abc def ghi"; 2067 initializeTest(`<p>${kText}</p>`); 2068 let p = gEditor.querySelector("p"); 2069 gSelection.collapse(p.firstChild, "abc ".length); 2070 await sendDeleteKey(kAlt); 2071 let startOffset = getFirstDifferentOffset(p.firstChild.data, kText); 2072 let length = kText.length - p.firstChild.data.length; 2073 checkEditorContentResultAsSubTest( 2074 `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`, 2075 t.name, 2076 { ignoreWhiteSpaceDifference: true } 2077 ); 2078 if (startOffset === kText.length) { 2079 checkBeforeinputAndInputEventsOnNOOP(); 2080 return; 2081 } 2082 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 2083 startContainer: p.firstChild, 2084 startOffset: startOffset, 2085 endContainer: p.firstChild, 2086 endOffset: startOffset + length, 2087 }); 2088 checkGetTargetRangesOfInputOnDeleteSomething(); 2089 }, 'Alt + Delete at "<p>abc []def ghi</p>"'); 2090 2091 promise_test(async (t) => { 2092 const kText = "abc def ghi"; 2093 initializeTest(`<p>${kText}</p>`); 2094 let p = gEditor.querySelector("p"); 2095 gSelection.collapse(p.firstChild, "abc ".length); 2096 await sendDeleteKey(kMeta); 2097 let startOffset = getFirstDifferentOffset(p.firstChild.data, kText); 2098 let length = kText.length - p.firstChild.data.length; 2099 checkEditorContentResultAsSubTest( 2100 `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`, 2101 t.name, 2102 { ignoreWhiteSpaceDifference: true } 2103 ); 2104 if (startOffset === kText.length) { 2105 checkBeforeinputAndInputEventsOnNOOP(); 2106 return; 2107 } 2108 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 2109 startContainer: p.firstChild, 2110 startOffset: startOffset, 2111 endContainer: p.firstChild, 2112 endOffset: startOffset + length, 2113 }); 2114 checkGetTargetRangesOfInputOnDeleteSomething(); 2115 }, 'Meta + Delete at "<p>abc []def ghi</p>"'); 2116 2117 promise_test(async (t) => { 2118 const kText = "abc def"; 2119 initializeTest(`<p>${kText} </p>`); 2120 let p = gEditor.querySelector("p"); 2121 gSelection.collapse(p.firstChild, "abc ".length); 2122 await sendDeleteKey(kShift); 2123 let visibleText = p.firstChild.data.replace(/%s+$/, ""); 2124 let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length); 2125 let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText); 2126 let length = kText.length + 3 - p.firstChild.data.length; 2127 // If invisible white-spaces are deleted, they should be contained in the target range. 2128 checkEditorContentResultAsSubTest( 2129 `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length) + invisibleWhiteSpaces}</p>`, 2130 t.name, 2131 { ignoreWhiteSpaceDifference: true } 2132 ); 2133 if (startOffset === kText.length) { 2134 checkBeforeinputAndInputEventsOnNOOP(); 2135 return; 2136 } 2137 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 2138 startContainer: p.firstChild, 2139 startOffset: startOffset, 2140 endContainer: p.firstChild, 2141 endOffset: startOffset + length, 2142 }); 2143 checkGetTargetRangesOfInputOnDeleteSomething(); 2144 }, 'Shift + Delete at "<p>abc []def </p>"'); 2145 2146 promise_test(async (t) => { 2147 const kText = "abc def"; 2148 initializeTest(`<p>${kText} </p>`); 2149 let p = gEditor.querySelector("p"); 2150 gSelection.collapse(p.firstChild, "abc ".length); 2151 await sendDeleteKey(kControl); 2152 let visibleText = p.firstChild.data.replace(/%s+$/, ""); 2153 let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length); 2154 let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText); 2155 let length = kText.length + 3 - p.firstChild.data.length; 2156 // If invisible white-spaces are deleted, they should be contained in the target range. 2157 checkEditorContentResultAsSubTest( 2158 `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length) + invisibleWhiteSpaces}</p>`, 2159 t.name, 2160 { ignoreWhiteSpaceDifference: true } 2161 ); 2162 if (startOffset === kText.length) { 2163 checkBeforeinputAndInputEventsOnNOOP(); 2164 return; 2165 } 2166 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 2167 startContainer: p.firstChild, 2168 startOffset: startOffset, 2169 endContainer: p.firstChild, 2170 endOffset: startOffset + length, 2171 }); 2172 checkGetTargetRangesOfInputOnDeleteSomething(); 2173 }, 'Control + Delete at "<p>abc []def </p>"'); 2174 2175 promise_test(async (t) => { 2176 const kText = "abc def"; 2177 initializeTest(`<p>${kText} </p>`); 2178 let p = gEditor.querySelector("p"); 2179 gSelection.collapse(p.firstChild, "abc ".length); 2180 await sendDeleteKey(kAlt); 2181 let visibleText = p.firstChild.data.replace(/%s+$/, ""); 2182 let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length); 2183 let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText); 2184 let length = kText.length + 3 - p.firstChild.data.length; 2185 // If invisible white-spaces are deleted, they should be contained in the target range. 2186 checkEditorContentResultAsSubTest( 2187 `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length) + invisibleWhiteSpaces}</p>`, 2188 t.name, 2189 { ignoreWhiteSpaceDifference: true } 2190 ); 2191 if (startOffset === kText.length) { 2192 checkBeforeinputAndInputEventsOnNOOP(); 2193 return; 2194 } 2195 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 2196 startContainer: p.firstChild, 2197 startOffset: startOffset, 2198 endContainer: p.firstChild, 2199 endOffset: startOffset + length, 2200 }); 2201 checkGetTargetRangesOfInputOnDeleteSomething(); 2202 }, 'Alt + Delete at "<p>abc []def </p>"'); 2203 2204 promise_test(async (t) => { 2205 const kText = "abc def"; 2206 initializeTest(`<p>${kText} s</p>`); 2207 let p = gEditor.querySelector("p"); 2208 gSelection.collapse(p.firstChild, "abc ".length); 2209 await sendDeleteKey(kMeta); 2210 let visibleText = p.firstChild.data.replace(/%s+$/, ""); 2211 let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length); 2212 let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText); 2213 let length = kText.length + 3 - p.firstChild.data.length; 2214 // If invisible white-spaces are deleted, they should be contained in the target range. 2215 checkEditorContentResultAsSubTest( 2216 `<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length) + invisibleWhiteSpaces}</p>`, 2217 t.name, 2218 { ignoreWhiteSpaceDifference: true } 2219 ); 2220 if (startOffset === kText.length) { 2221 checkBeforeinputAndInputEventsOnNOOP(); 2222 return; 2223 } 2224 checkGetTargetRangesOfBeforeinputOnDeleteSomething({ 2225 startContainer: p.firstChild, 2226 startOffset: startOffset, 2227 endContainer: p.firstChild, 2228 endOffset: startOffset + length, 2229 }); 2230 checkGetTargetRangesOfInputOnDeleteSomething(); 2231 }, 'Meta + Delete at "<p>abc []def</p>"'); 2232 2233 </script>