input-events-get-target-ranges-deleting-in-list-items.tentative.html (57167B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <meta name="timeout" content="long"> 4 <meta name="variant" content="?Backspace,ul"> 5 <meta name="variant" content="?Backspace,ol"> 6 <meta name="variant" content="?Delete,ul"> 7 <meta name="variant" content="?Delete,ol"> 8 <title>InputEvent.getTargetRanges() at deleting in/around/across list item elements</title> 9 <div contenteditable></div> 10 <script src="input-events-get-target-ranges.js"></script> 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> 17 "use strict"; 18 19 const [action, list] = location.search.substring(1).split(","); 20 function run() { 21 switch (action) { 22 case "Backspace": 23 return sendBackspaceKey(); 24 case "Delete": 25 return sendDeleteKey(); 26 default: 27 throw "Unhandled variant"; 28 } 29 } 30 31 /** 32 * @param innerHTML Initial `innerHTML` value of the editor. 33 * @param data 34 * expectedInnerHTML 35 * Expected `innerHTML` of the editor after calling 36 * `run()`. This can be array of string if there are 37 * some acceptable differences like whether there is 38 * an invisible `<br>` element at end of list item. 39 * expectedTargetRanges 40 * `null` or `unspecified` if `beforeinput` event shouldn't 41 * be fired. 42 * Otherwise, function returning an array of objects 43 * which have `startContainer`, `startOffset`, 44 * `endContainer`, `endOffset`. This will be called 45 * before calling `run()` and compared with 46 * `getTargetRanges()` after that. 47 * expectInputEvent: 48 * `true` if it should cause an `input` event. 49 */ 50 function addPromiseTest(innerHTML, data) { 51 promise_test(async (t) => { 52 initializeTest(innerHTML); 53 let expectedTargetRanges = 54 typeof data.expectedTargetRanges === "function" 55 ? data.expectedTargetRanges() 56 : null; 57 await run(); 58 checkEditorContentResultAsSubTest(data.expectedInnerHTML, t.name); 59 if (expectedTargetRanges !== null) { 60 checkGetTargetRangesOfBeforeinputOnDeleteSomething(expectedTargetRanges); 61 if (data.expectInputEvent) { 62 checkGetTargetRangesOfInputOnDeleteSomething(); 63 } else { 64 checkGetTargetRangesOfInputOnDoNothing(); 65 } 66 } else { 67 checkBeforeinputAndInputEventsOnNOOP(); 68 } 69 }, `${action} at "${innerHTML}"`); 70 } 71 72 addPromiseTest( 73 `<${list}><li>list[-item1</li><li>list]-item2</li></${list}>`, 74 { 75 expectedInnerHTML: `<${list}><li>list-item2</li></${list}>`, 76 expectedTargetRanges: () => { 77 return [ 78 { 79 startContainer: gEditor.querySelector("li").firstChild, 80 startOffset: "list".length, 81 endContainer: gEditor.querySelector("li + li").firstChild, 82 endOffset: "list".length, 83 }, 84 ]; 85 }, 86 expectInputEvent: true, 87 } 88 ); 89 90 addPromiseTest( 91 `<${list}><li>list-[item1</li><li>]list-item2</li></${list}>`, 92 { 93 expectedInnerHTML: `<${list}><li>list-list-item2</li></${list}>`, 94 expectedTargetRanges: () => { 95 return [ 96 { 97 startContainer: gEditor.querySelector("li").firstChild, 98 startOffset: "list-".length, 99 endContainer: gEditor.querySelector("li + li").firstChild, 100 endOffset: 0, 101 }, 102 ]; 103 }, 104 expectInputEvent: true, 105 } 106 ); 107 108 addPromiseTest( 109 `<${list}><li>list-[item1</li><li>}list-item2</li></${list}>`, 110 { 111 expectedInnerHTML: `<${list}><li>list-list-item2</li></${list}>`, 112 expectedTargetRanges: () => { 113 return [ 114 { 115 startContainer: gEditor.querySelector("li").firstChild, 116 startOffset: "list-".length, 117 endContainer: gEditor.querySelector("li + li"), 118 endOffset: 0, 119 }, 120 ]; 121 }, 122 expectInputEvent: true, 123 } 124 ); 125 126 addPromiseTest( 127 `<${list}><li>list-item1[</li><li>list]-item2</li></${list}>`, 128 { 129 expectedInnerHTML: `<${list}><li>list-item1-item2</li></${list}>`, 130 expectedTargetRanges: () => { 131 return [ 132 { 133 startContainer: gEditor.querySelector("li").firstChild, 134 startOffset: gEditor.querySelector("li").firstChild.length, 135 endContainer: gEditor.querySelector("li + li").firstChild, 136 endOffset: "list".length, 137 }, 138 ]; 139 }, 140 expectInputEvent: true, 141 } 142 ); 143 144 addPromiseTest( 145 `<${list}><li>list-item1{</li><li>list]-item2</li></${list}>`, 146 { 147 expectedInnerHTML: `<${list}><li>list-item1-item2</li></${list}>`, 148 expectedTargetRanges: () => { 149 return [ 150 { 151 startContainer: gEditor.querySelector("li"), 152 startOffset: 1, 153 endContainer: gEditor.querySelector("li + li").firstChild, 154 endOffset: "list".length, 155 }, 156 ]; 157 }, 158 expectInputEvent: true, 159 } 160 ); 161 162 addPromiseTest( 163 `<${list}><li>list-item1[</li><li>]list-item2</li></${list}>`, 164 { 165 expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`, 166 expectedTargetRanges: () => { 167 return [ 168 { 169 startContainer: gEditor.querySelector("li").firstChild, 170 startOffset: gEditor.querySelector("li").firstChild.length, 171 endContainer: gEditor.querySelector("li + li").firstChild, 172 endOffset: 0, 173 }, 174 ]; 175 }, 176 expectInputEvent: true, 177 } 178 ); 179 180 addPromiseTest( 181 action === "Backspace" 182 ? `<${list}><li>list-item1</li><li>[]list-item2</li></${list}>` 183 : `<${list}><li>list-item1[]</li><li>list-item2</li></${list}>`, 184 { 185 expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`, 186 expectedTargetRanges: () => { 187 return [ 188 { 189 startContainer: gEditor.querySelector("li").firstChild, 190 startOffset: gEditor.querySelector("li").firstChild.length, 191 endContainer: gEditor.querySelector("li + li").firstChild, 192 endOffset: 0, 193 }, 194 ]; 195 }, 196 expectInputEvent: true, 197 } 198 ); 199 200 addPromiseTest( 201 action === "Backspace" 202 ? `<${list}><li>list-item1<br></li><li>[]list-item2</li></${list}>` 203 : `<${list}><li>list-item1[]<br></li><li>list-item2</li></${list}>`, 204 { 205 expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`, 206 expectedTargetRanges: () => { 207 return action === "Backspace" 208 ? [ 209 { 210 startContainer: gEditor.querySelector("li"), 211 startOffset: 1, 212 endContainer: gEditor.querySelector("li + li").firstChild, 213 endOffset: 0, 214 }, 215 ] 216 : [ 217 { 218 startContainer: gEditor.querySelector("li").firstChild, 219 startOffset: gEditor.querySelector("li").firstChild.length, 220 endContainer: gEditor.querySelector("li + li").firstChild, 221 endOffset: 0, 222 }, 223 ]; 224 }, 225 expectInputEvent: true, 226 } 227 ); 228 229 addPromiseTest( 230 action === "Backspace" 231 ? `<${list}><li>list-item1<br><br></li><li>[]list-item2</li></${list}>` 232 : `<${list}><li>list-item1[]<br><br></li><li>list-item2</li></${list}>`, 233 { 234 expectedInnerHTML: [ 235 `<${list}><li>list-item1<br>list-item2</li></${list}>`, 236 `<${list}><li>list-item1<br>list-item2<br></li></${list}>`, 237 ], 238 expectedTargetRanges: () => { 239 return action === "Backspace" 240 ? [ 241 { 242 startContainer: gEditor.querySelector("li"), 243 startOffset: 1, 244 endContainer: gEditor.querySelector("li + li").firstChild, 245 endOffset: 0, 246 }, 247 ] 248 : [ 249 { 250 startContainer: gEditor.querySelector("li").firstChild, 251 startOffset: gEditor.querySelector("li").firstChild.length, 252 endContainer: gEditor.querySelector("li + li").firstChild, 253 endOffset: 0, 254 }, 255 ]; 256 }, 257 expectInputEvent: true, 258 } 259 ); 260 261 addPromiseTest( 262 action === "Backspace" 263 ? `<${list}><li>list-item1</li><li>[]list-item2<br>second line of list-item2</li></${list}>` 264 : `<${list}><li>list-item1[]</li><li>list-item2<br>second line of list-item2</li></${list}>`, 265 { 266 expectedInnerHTML: `<${list}><li>list-item1list-item2</li><li>second line of list-item2</li></${list}>`, 267 expectedTargetRanges: () => { 268 return action === "Backspace" 269 ? [ 270 { 271 startContainer: gEditor.querySelector("li"), 272 startOffset: 1, 273 endContainer: gEditor.querySelector("li + li").firstChild, 274 endOffset: 0, 275 }, 276 ] 277 : [ 278 { 279 startContainer: gEditor.querySelector("li").firstChild, 280 startOffset: gEditor.querySelector("li").firstChild.length, 281 endContainer: gEditor.querySelector("li + li").firstChild, 282 endOffset: 0, 283 }, 284 ]; 285 }, 286 expectInputEvent: true, 287 } 288 ); 289 290 addPromiseTest( 291 action === "Backspace" 292 ? `<${list}><li><p>list-item1</p></li><li>[]list-item2</li></${list}>` 293 : `<${list}><li><p>list-item1[]</p></li><li>list-item2</li></${list}>`, 294 { 295 expectedInnerHTML: `<${list}><li><p>list-item1list-item2</p></li></${list}>`, 296 expectedTargetRanges: () => { 297 return action === "Backspace" 298 ? [ 299 { 300 startContainer: gEditor.querySelector("p").firstChild, 301 startOffset: gEditor.querySelector("p").firstChild.length, 302 endContainer: gEditor.querySelector("li + li").firstChild, 303 endOffset: 0, 304 }, 305 ] 306 : [ 307 { 308 startContainer: gEditor.querySelector("p").firstChild, 309 startOffset: gEditor.querySelector("p").firstChild.length, 310 endContainer: gEditor.querySelector("li + li").firstChild, 311 endOffset: 0, 312 }, 313 ]; 314 }, 315 expectInputEvent: true, 316 } 317 ); 318 319 addPromiseTest( 320 action === "Backspace" 321 ? `<${list}><li>list-item1</li><li><p>[]list-item2</p></li></${list}>` 322 : `<${list}><li>list-item1[]</li><li><p>list-item2</p></li></${list}>`, 323 { 324 expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`, 325 expectedTargetRanges: () => { 326 return action === "Backspace" 327 ? [ 328 { 329 startContainer: gEditor.querySelector("li").firstChild, 330 startOffset: gEditor.querySelector("li").firstChild.length, 331 endContainer: gEditor.querySelector("p").firstChild, 332 endOffset: 0, 333 }, 334 ] 335 : [ 336 { 337 startContainer: gEditor.querySelector("li").firstChild, 338 startOffset: gEditor.querySelector("li").firstChild.length, 339 endContainer: gEditor.querySelector("p").firstChild, 340 endOffset: 0, 341 }, 342 ]; 343 }, 344 expectInputEvent: true, 345 } 346 ); 347 348 addPromiseTest( 349 `<${list}><li>[list-item1]</li></${list}>`, 350 { 351 expectedInnerHTML: `<${list}><li><br></li></${list}>`, 352 expectedTargetRanges: () => { 353 return [ 354 { 355 startContainer: gEditor.querySelector("li").firstChild, 356 startOffset: 0, 357 endContainer: gEditor.querySelector("li").firstChild, 358 endOffset: gEditor.querySelector("li").firstChild.length, 359 }, 360 ]; 361 }, 362 expectInputEvent: true, 363 } 364 ); 365 366 addPromiseTest( 367 `<${list}><li>{list-item1}</li></${list}>`, 368 { 369 expectedInnerHTML: `<${list}><li><br></li></${list}>`, 370 expectedTargetRanges: () => { 371 return [ 372 { 373 startContainer: gEditor.querySelector("li").firstChild, 374 startOffset: 0, 375 endContainer: gEditor.querySelector("li").firstChild, 376 endOffset: gEditor.querySelector("li").firstChild.length, 377 }, 378 ]; 379 }, 380 expectInputEvent: true, 381 } 382 ); 383 384 // Even if the last list item is selected, don't delete the list and 385 // the last list item element. This is a triple click case on Gecko. 386 addPromiseTest( 387 `<${list}>{<li>list-item1</li>}</${list}>`, 388 { 389 expectedInnerHTML: `<${list}><li><br></li></${list}>`, 390 expectedTargetRanges: () => { 391 return [ 392 { 393 startContainer: gEditor.querySelector("li").firstChild, 394 startOffset: 0, 395 endContainer: gEditor.querySelector("li").firstChild, 396 endOffset: gEditor.querySelector("li").firstChild.length, 397 }, 398 ]; 399 }, 400 expectInputEvent: true, 401 } 402 ); 403 404 // A list item is selected and it's not the last one, can delete it. 405 addPromiseTest( 406 `<${list}>{<li>list-item1</li>}<li>list-item2</li></${list}>`, 407 { 408 expectedInnerHTML: `<${list}><li>list-item2</li></${list}>`, 409 expectedTargetRanges: () => { 410 return [ 411 { 412 startContainer: gEditor.querySelector(`${list}`), 413 startOffset: 0, 414 endContainer: gEditor.querySelector(`${list}`), 415 endOffset: 1, 416 }, 417 ]; 418 }, 419 expectInputEvent: true, 420 } 421 ); 422 423 // Delete list element when deleting from empty last list item. 424 addPromiseTest( 425 `<${list}><li>{}<br></li></${list}>`, 426 { 427 expectedInnerHTML: ["", "<br>", "<div><br></div>"], 428 expectedTargetRanges: () => { 429 return [ 430 { 431 startContainer: gEditor, 432 startOffset: 0, 433 endContainer: gEditor, 434 endOffset: 1, 435 }, 436 ]; 437 }, 438 expectInputEvent: true, 439 } 440 ); 441 442 addPromiseTest( 443 `{<${list}><li><br></li></${list}>}`, 444 { 445 expectedInnerHTML: ["", "<br>", "<div><br></div>"], 446 expectedTargetRanges: () => { 447 return [ 448 { 449 startContainer: gEditor, 450 startOffset: 0, 451 endContainer: gEditor, 452 endOffset: 1, 453 }, 454 ]; 455 }, 456 expectInputEvent: true, 457 } 458 ); 459 460 addPromiseTest( 461 `<div>{<${list}><li><br></li></${list}>}</div>`, 462 { 463 expectedInnerHTML: ["<div><br></div>", "<div><div><br></div></div>"], 464 expectedTargetRanges: () => { 465 return [ 466 { 467 startContainer: gEditor.querySelector("div"), 468 startOffset: 0, 469 endContainer: gEditor.querySelector("div"), 470 endOffset: 1, 471 }, 472 ]; 473 }, 474 expectInputEvent: true, 475 } 476 ); 477 478 // It may be better to ignore the invisible white-space and take same action 479 // as above, but it requires more expensive check before deleting. So perhaps, 480 // this behavior is reasonable. 481 addPromiseTest( 482 `<div>{ <${list}><li><br></li></${list}> }</div>`, 483 { 484 expectedInnerHTML: ["<div><br></div>", "<div><div><br></div></div>"], 485 expectedTargetRanges: () => { 486 return [ 487 { 488 startContainer: gEditor.querySelector("div"), 489 startOffset: 0, 490 endContainer: gEditor.querySelector("div"), 491 endOffset: 3, 492 }, 493 ]; 494 }, 495 expectInputEvent: true, 496 } 497 ); 498 499 addPromiseTest( 500 `<div><${list}><li>{}<br></li></${list}></div>`, 501 { 502 expectedInnerHTML: ["<div><br></div>", "<div><div><br></div></div>"], 503 expectedTargetRanges: () => { 504 return [ 505 { 506 startContainer: gEditor.querySelector("div"), 507 startOffset: 0, 508 endContainer: gEditor.querySelector("div"), 509 endOffset: 1, 510 }, 511 ]; 512 }, 513 expectInputEvent: true, 514 } 515 ); 516 517 // XXX Blink does not delete the list element if its first or last <li> element 518 // is not editable. However, it means that user cannot delete the list 519 // element, and it's not consistent behavior when only middle list item(s) 520 // are not editable. Perhaps, once it makes the list element has only 521 // one empty list item element, then, another deleting operation allows to 522 // delete the list element. 523 addPromiseTest( 524 `<div>{<${list}><li contenteditable="false"><br></li></${list}>}</div>`, 525 { 526 expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`, 527 expectedTargetRanges: () => { 528 return [ 529 { 530 startContainer: gEditor.querySelector(list), 531 startOffset: 0, 532 endContainer: gEditor.querySelector(list), 533 endOffset: 1, 534 }, 535 ]; 536 }, 537 expectInputEvent: true, 538 } 539 ); 540 541 addPromiseTest( 542 `<div>{<${list}><li contenteditable="false">list-item1</li></${list}>}</div>`, 543 { 544 expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`, 545 expectedTargetRanges: () => { 546 return [ 547 { 548 startContainer: gEditor.querySelector(list), 549 startOffset: 0, 550 endContainer: gEditor.querySelector(list), 551 endOffset: 1, 552 }, 553 ]; 554 }, 555 expectInputEvent: true, 556 } 557 ); 558 559 addPromiseTest( 560 `<div>{<${list}><li contenteditable="false">list-item1</li><li><br></li></${list}>}</div>`, 561 { 562 expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`, 563 expectedTargetRanges: () => { 564 return [ 565 { 566 startContainer: gEditor.querySelector(list), 567 startOffset: 0, 568 endContainer: gEditor.querySelector("li + li"), 569 endOffset: 1, 570 }, 571 ]; 572 }, 573 expectInputEvent: true, 574 } 575 ); 576 577 addPromiseTest( 578 `<div>{<${list}><li contenteditable="false">list-item1</li><li>list-item2</li></${list}>}</div>`, 579 { 580 expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`, 581 expectedTargetRanges: () => { 582 return [ 583 { 584 startContainer: gEditor.querySelector(list), 585 startOffset: 0, 586 endContainer: gEditor.querySelector("li + li").firstChild, 587 endOffset: gEditor.querySelector("li + li").firstChild.length, 588 }, 589 ]; 590 }, 591 expectInputEvent: true, 592 } 593 ); 594 595 addPromiseTest( 596 `<div>{<${list}><li><br></li><li contenteditable="false">list-item2</li></${list}>}</div>`, 597 { 598 expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`, 599 expectedTargetRanges: () => { 600 return [ 601 { 602 startContainer: gEditor.querySelector("li").firstChild, 603 startOffset: 0, 604 endContainer: gEditor.querySelector(list), 605 endOffset: 2, 606 }, 607 ]; 608 }, 609 expectInputEvent: true, 610 } 611 ); 612 613 addPromiseTest( 614 `<div>{<${list}><li>list-item1</li><li contenteditable="false">list-item2</li></${list}>}</div>`, 615 { 616 expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`, 617 expectedTargetRanges: () => { 618 return [ 619 { 620 startContainer: gEditor.querySelector("li").firstChild, 621 startOffset: 0, 622 endContainer: gEditor.querySelector(list), 623 endOffset: 2, 624 }, 625 ]; 626 }, 627 expectInputEvent: true, 628 } 629 ); 630 631 addPromiseTest( 632 `<div>{<${list}><li><br></li><li contenteditable="false">list-item2</li><li><br></li></${list}>}</div>`, 633 { 634 expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`, 635 expectedTargetRanges: () => { 636 return [ 637 { 638 startContainer: gEditor.querySelector("li").firstChild, 639 startOffset: 0, 640 endContainer: gEditor.querySelector("li + li + li"), 641 endOffset: 1, 642 }, 643 ]; 644 }, 645 expectInputEvent: true, 646 } 647 ); 648 649 addPromiseTest( 650 `<div>{<${list}><li>list-item1</li><li contenteditable="false">list-item2</li><li>list-item3</li></${list}>}</div>`, 651 { 652 expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`, 653 expectedTargetRanges: () => { 654 return [ 655 { 656 startContainer: gEditor.querySelector("li").firstChild, 657 startOffset: 0, 658 endContainer: gEditor.querySelector("li + li + li").firstChild, 659 endOffset: gEditor.querySelector("li + li + li").firstChild.length, 660 }, 661 ]; 662 }, 663 expectInputEvent: true, 664 } 665 ); 666 667 addPromiseTest( 668 `<${list}><li>list-item1</li>{<li>list-item2</li>}<li>list-item3</li></${list}>`, 669 { 670 expectedInnerHTML: `<${list}><li>list-item1</li><li>list-item3</li></${list}>`, 671 expectedTargetRanges: () => { 672 return [ 673 { 674 startContainer: gEditor.querySelector(`${list}`), 675 startOffset: 1, 676 endContainer: gEditor.querySelector(`${list}`), 677 endOffset: 2, 678 }, 679 ]; 680 }, 681 expectInputEvent: true, 682 } 683 ); 684 685 // Selecting last list item element shouldn't delete the list item. 686 addPromiseTest( 687 `<${list}><li>list-item1</li>{<li>list-item2</li>}</${list}>`, 688 { 689 expectedInnerHTML: `<${list}><li>list-item1</li><li><br></li></${list}>`, 690 expectedTargetRanges: () => { 691 return [ 692 { 693 startContainer: gEditor.querySelector(`${list} > li + li`).firstChild, 694 startOffset: 0, 695 endContainer: gEditor.querySelector(`${list} > li + li`).firstChild, 696 endOffset: gEditor.querySelector(`${list} > li + li`).firstChild.length, 697 }, 698 ]; 699 }, 700 expectInputEvent: true, 701 } 702 ); 703 704 addPromiseTest( 705 `<${list}><li>list-item1</li><li>list-item2</li>{<li>list-item3</li>}</${list}>`, 706 { 707 expectedInnerHTML: `<${list}><li>list-item1</li><li>list-item2</li><li><br></li></${list}>`, 708 expectedTargetRanges: () => { 709 return [ 710 { 711 startContainer: gEditor.querySelector(`${list} > li + li + li`).firstChild, 712 startOffset: 0, 713 endContainer: gEditor.querySelector(`${list} > li + li + li`).firstChild, 714 endOffset: gEditor.querySelector(`${list} > li + li + li`).firstChild.length, 715 }, 716 ]; 717 }, 718 expectInputEvent: true, 719 } 720 ); 721 722 for (let childList of ["ul", "ol"]) { 723 addPromiseTest( 724 `<${list}><li>list-item1</li>{<li>list-item2</li>}<li><${childList}><li><br></li></${childList}></li></${list}>`, 725 { 726 expectedInnerHTML: `<${list}><li>list-item1</li><li><${childList}><li><br></li></${childList}></li></${list}>`, 727 expectedTargetRanges: () => { 728 return [ 729 { 730 startContainer: gEditor.querySelector(`${list}`), 731 startOffset: 1, 732 endContainer: gEditor.querySelector(`${list}`), 733 endOffset: 2, 734 }, 735 ]; 736 }, 737 expectInputEvent: true, 738 } 739 ); 740 741 // Invalid nested list elements cases. Treat the nested list element as a list item element. 742 addPromiseTest( 743 `<${list}><li>list-item1</li>{<li>list-item2</li>}<${childList}><li><br></li></${childList}></${list}>`, 744 { 745 expectedInnerHTML: `<${list}><li>list-item1</li><${childList}><li><br></li></${childList}></${list}>`, 746 expectedTargetRanges: () => { 747 return [ 748 { 749 startContainer: gEditor.querySelector(`${list}`), 750 startOffset: 1, 751 endContainer: gEditor.querySelector(`${list}`), 752 endOffset: 2, 753 }, 754 ]; 755 }, 756 expectInputEvent: true, 757 } 758 ); 759 760 addPromiseTest( 761 `<${list}><li>list-item1</li><li>list-item2</li>{<${childList}><li><br></li></${childList}>}</${list}>`, 762 { 763 expectedInnerHTML: `<${list}><li>list-item1</li><li>list-item2</li><li><br></li></${list}>`, 764 expectedTargetRanges: () => { 765 return [ 766 { 767 startContainer: gEditor.querySelector(`${list}`), 768 startOffset: 2, 769 endContainer: gEditor.querySelector(`${list}`), 770 endOffset: 3, 771 }, 772 ]; 773 }, 774 expectInputEvent: true, 775 } 776 ); 777 } 778 779 // Don't delete list and joined list items when only there content are selected. 780 addPromiseTest( 781 `<${list}><li>[list-item1</li><li>list-item2]</li></${list}>`, 782 { 783 expectedInnerHTML: `<${list}><li><br></li></${list}>`, 784 expectedTargetRanges: () => { 785 return [ 786 { 787 startContainer: gEditor.querySelector("li").firstChild, 788 startOffset: 0, 789 endContainer: gEditor.querySelector("li + li").firstChild, 790 endOffset: gEditor.querySelector("li + li").firstChild.length, 791 }, 792 ]; 793 }, 794 expectInputEvent: true, 795 } 796 ); 797 798 addPromiseTest( 799 `<${list}><li>[list-item1</li><li>list-item2]</li><li>list-item3</li></${list}>`, 800 { 801 expectedInnerHTML: `<${list}><li><br></li><li>list-item3</li></${list}>`, 802 expectedTargetRanges: () => { 803 return [ 804 { 805 startContainer: gEditor.querySelector("li").firstChild, 806 startOffset: 0, 807 endContainer: gEditor.querySelector("li + li").firstChild, 808 endOffset: gEditor.querySelector("li + li").firstChild.length, 809 }, 810 ]; 811 }, 812 expectInputEvent: true, 813 } 814 ); 815 816 addPromiseTest( 817 `<${list}><li>list-item1</li><li>[list-item2]</li><li>list-item3</li></${list}>`, 818 { 819 expectedInnerHTML: `<${list}><li>list-item1</li><li><br></li><li>list-item3</li></${list}>`, 820 expectedTargetRanges: () => { 821 return [ 822 { 823 startContainer: gEditor.querySelector("li + li").firstChild, 824 startOffset: 0, 825 endContainer: gEditor.querySelector("li + li").firstChild, 826 endOffset: gEditor.querySelector("li + li").firstChild.length, 827 }, 828 ]; 829 }, 830 expectInputEvent: true, 831 } 832 ); 833 834 addPromiseTest( 835 `<${list}><li>list-item1</li><li>[list-item2</li><li>list-item3]</li></${list}>`, 836 { 837 expectedInnerHTML: `<${list}><li>list-item1</li><li><br></li></${list}>`, 838 expectedTargetRanges: () => { 839 return [ 840 { 841 startContainer: gEditor.querySelector("li + li").firstChild, 842 startOffset: 0, 843 endContainer: gEditor.querySelector("li + li + li").firstChild, 844 endOffset: gEditor.querySelector("li + li + li").firstChild.length, 845 }, 846 ]; 847 }, 848 expectInputEvent: true, 849 } 850 ); 851 852 // Ported tests from editing/delete.js and editing/forwarddelete.js 853 for (let otherList of ["ul", "ol"]) { 854 if (action === "Backspace") { 855 addPromiseTest( 856 `<${otherList}><li>list-item1</li></${otherList}><${list}><li>l[]ist-item2</li></${list}>`, 857 { 858 expectedInnerHTML: `<${otherList}><li>list-item1</li></${otherList}><${list}><li>ist-item2</li></${list}>`, 859 expectedTargetRanges: () => { 860 return [ 861 { 862 startContainer: gEditor.querySelector(`${otherList} + ${list} > li`).firstChild, 863 startOffset: 0, 864 endContainer: gEditor.querySelector(`${otherList} + ${list} > li`).firstChild, 865 endOffset: "l".length, 866 }, 867 ]; 868 }, 869 expectInputEvent: true, 870 } 871 ); 872 873 addPromiseTest( 874 `<${list}><li>list-item1[]</li></${list}><${otherList}><li>list-item2</li></${otherList}>`, 875 { 876 expectedInnerHTML: `<${list}><li>list-item</li></${list}><${otherList}><li>list-item2</li></${otherList}>`, 877 expectedTargetRanges: () => { 878 return [ 879 { 880 startContainer: gEditor.querySelector("li").firstChild, 881 startOffset: "list-item".length, 882 endContainer: gEditor.querySelector("li").firstChild, 883 endOffset: "list-item1".length, 884 }, 885 ]; 886 }, 887 expectInputEvent: true, 888 } 889 ); 890 } else { 891 addPromiseTest( 892 `<${list}><li>list-item[]1</li></${list}><${otherList}><li>list-item2</li></${otherList}>`, 893 { 894 expectedInnerHTML: `<${list}><li>list-item</li></${list}><${otherList}><li>list-item2</li></${otherList}>`, 895 expectedTargetRanges: () => { 896 return [ 897 { 898 startContainer: gEditor.querySelector("li").firstChild, 899 startOffset: "list-item".length, 900 endContainer: gEditor.querySelector("li").firstChild, 901 endOffset: "list-item1".length, 902 }, 903 ]; 904 }, 905 expectInputEvent: true, 906 } 907 ); 908 909 addPromiseTest( 910 `<${otherList}><li>list-item1</li></${otherList}><${list}><li>[]list-item2</li></${list}>`, 911 { 912 expectedInnerHTML: `<${otherList}><li>list-item1</li></${otherList}><${list}><li>ist-item2</li></${list}>`, 913 expectedTargetRanges: () => { 914 return [ 915 { 916 startContainer: gEditor.querySelector(`${otherList} + ${list} > li`).firstChild, 917 startOffset: 0, 918 endContainer: gEditor.querySelector(`${otherList} + ${list} > li`).firstChild, 919 endOffset: "l".length, 920 }, 921 ]; 922 }, 923 expectInputEvent: true, 924 } 925 ); 926 } 927 928 addPromiseTest( 929 `<${list}><li>list-item1[</li><li>list-item2]</li></${list}><${otherList}><li>list-item3</li></${otherList}>`, 930 { 931 expectedInnerHTML: `<${list}><li>list-item1</li></${list}><${otherList}><li>ist-item3</li><li>ist-item4</li></${otherList}>`, 932 expectedTargetRanges: () => { 933 return [ 934 { 935 startContainer: gEditor.querySelector("li").firstChild, 936 startOffset: gEditor.querySelector("li").firstChild.length, 937 endContainer: gEditor.querySelector("li + li").firstChild, 938 endOffset: gEditor.querySelector("li + li").firstChild.length, 939 }, 940 ]; 941 }, 942 expectInputEvent: true, 943 } 944 ); 945 } 946 947 948 // Invalid nested list element cases. Traditionally, all browser engines 949 // insert child list element without wrapping it with a list item element. 950 // So, keeping the behavior in these cases are important for backward 951 // compatibility. 952 // https://bugzilla.mozilla.org/show_bug.cgi?id=487524 953 for (let childList of ["ul", "ol"]) { 954 addPromiseTest( 955 `<${list}><li>[list-item1</li><${childList}><li>}list-item2</li></ul></${list}>`, 956 { 957 expectedInnerHTML: [ 958 `<${list}><${childList}><li>list-item2</li></${childList}></${list}>`, 959 `<${list}><${childList}><li>list-item2<br></li></${childList}></${list}>`, 960 ], 961 expectedTargetRanges: () => { 962 return [ 963 { 964 startContainer: gEditor.querySelector("li").firstChild, 965 startOffset: 0, 966 endContainer: gEditor.querySelector(`${list} > ${childList} > li`), 967 endOffset: 0, 968 }, 969 ]; 970 }, 971 expectInputEvent: true, 972 } 973 ); 974 975 addPromiseTest( 976 `<${list}><li>[list-item1</li><${childList}><li>list-item2]</li></${childList}></${list}>`, 977 { 978 expectedInnerHTML: `<${list}><${childList}><li><br></li></${childList}></${list}>`, 979 expectedTargetRanges: () => { 980 return [ 981 { 982 startContainer: gEditor.querySelector("li").firstChild, 983 startOffset: 0, 984 endContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild, 985 endOffset: gEditor.querySelector(`${list} > ${childList} > li`).firstChild.length, 986 }, 987 ]; 988 }, 989 expectInputEvent: true, 990 } 991 ); 992 993 addPromiseTest( 994 `<${list}><${childList}><li>[list-item1</li></${childList}><li>}list-item2</li></${list}>`, 995 { 996 expectedInnerHTML: [ 997 `<${list}><${childList}><li>list-item2</li></${childList}></${list}>`, 998 `<${list}><${childList}><li>list-item2<br></li></${childList}></${list}>`, 999 ], 1000 expectedTargetRanges: () => { 1001 return [ 1002 { 1003 startContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild, 1004 startOffset: 0, 1005 endContainer: gEditor.querySelector(`${list} > li`), 1006 endOffset: 0, 1007 }, 1008 ]; 1009 }, 1010 expectInputEvent: true, 1011 } 1012 ); 1013 1014 addPromiseTest( 1015 `<${list}><${childList}><li>[list-item1</li></${childList}><li>list-item2]</li></${list}>`, 1016 { 1017 expectedInnerHTML: `<${list}><${childList}><li><br></li></${childList}></${list}>`, 1018 expectedTargetRanges: () => { 1019 return [ 1020 { 1021 startContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild, 1022 startOffset: 0, 1023 endContainer: gEditor.querySelector(`${childList} + li`).firstChild, 1024 endOffset: gEditor.querySelector(`${childList} + li`).firstChild.length, 1025 }, 1026 ]; 1027 }, 1028 expectInputEvent: true, 1029 } 1030 ); 1031 1032 addPromiseTest( 1033 `<${list}><${childList}><li>list-item1</li><li>[list-item2</li></${childList}><li>}list-item3</li></${list}>`, 1034 { 1035 expectedInnerHTML: `<${list}><${childList}><li>list-item1</li><li>list-item3</li></${childList}></${list}>`, 1036 expectedTargetRanges: () => { 1037 return [ 1038 { 1039 startContainer: gEditor.querySelector(`${list} > ${childList} > li + li`).firstChild, 1040 startOffset: 0, 1041 endContainer: gEditor.querySelector(`${list} > li`), 1042 endOffset: 0, 1043 }, 1044 ]; 1045 }, 1046 expectInputEvent: true, 1047 } 1048 ); 1049 1050 addPromiseTest( 1051 `<${list}><li>[list-item1</li><${childList}><li>list-item2</li><li>}list-item3</li></${childList}></${list}>`, 1052 { 1053 expectedInnerHTML: [ 1054 `<${list}><${childList}><li>list-item3</li></${childList}></${list}>`, 1055 `<${list}><${childList}><li>list-item3<br></li></${childList}></${list}>`, 1056 ], 1057 expectedTargetRanges: () => { 1058 return [ 1059 { 1060 startContainer: gEditor.querySelector(`li`).firstChild, 1061 startOffset: 0, 1062 endContainer: gEditor.querySelector(`${list} > ${childList} > li + li`), 1063 endOffset: 0, 1064 }, 1065 ]; 1066 }, 1067 expectInputEvent: true, 1068 } 1069 ); 1070 1071 addPromiseTest( 1072 `<${list}><li>list-item1</li><li>[list-item2</li><${childList}><li>list-item3</li><li>}list-item4</li></${childList}></${list}>`, 1073 { 1074 expectedInnerHTML: `<${list}><li>list-item1</li><${childList}><li>list-item4</li></${childList}></${list}>`, 1075 expectedTargetRanges: () => { 1076 return [ 1077 { 1078 startContainer: gEditor.querySelector(`li + li`).firstChild, 1079 startOffset: 0, 1080 endContainer: gEditor.querySelector(`${list} > ${childList} > li + li`), 1081 endOffset: 0, 1082 }, 1083 ]; 1084 }, 1085 expectInputEvent: true, 1086 } 1087 ); 1088 1089 // Valid sub list element cases. 1090 addPromiseTest( 1091 `<${list}><li>[list-item1</li><li><${childList}><li>list-item2]</li></${childList}></li></${list}>`, 1092 { 1093 expectedInnerHTML: `<${list}><li><${childList}><li><br></li></${childList}></li></${list}>`, 1094 expectedTargetRanges: () => { 1095 return [ 1096 { 1097 startContainer: gEditor.querySelector(`li`).firstChild, 1098 startOffset: 0, 1099 endContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild, 1100 endOffset: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild.length, 1101 }, 1102 ]; 1103 }, 1104 expectInputEvent: true, 1105 } 1106 ); 1107 1108 addPromiseTest( 1109 `<${list}><li><${childList}><li>[list-item1</li></${childList}><li>}list-item2</li></${list}>`, 1110 { 1111 expectedInnerHTML: [ 1112 `<${list}><li><${childList}><li>list-item2</li></${childList}></li></${list}>`, 1113 `<${list}><li><${childList}><li>list-item2<br></li></${childList}></li></${list}>`, 1114 ], 1115 expectedTargetRanges: () => { 1116 return [ 1117 { 1118 startContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild, 1119 startOffset: 0, 1120 endContainer: gEditor.querySelector(`${list} > li + li`), 1121 endOffset: 0, 1122 }, 1123 ]; 1124 }, 1125 expectInputEvent: true, 1126 } 1127 ); 1128 1129 addPromiseTest( 1130 `<${list}><li><${childList}><li>[list-item1</li></${childList}><li>list-item2]</li></${list}>`, 1131 { 1132 expectedInnerHTML: `<${list}><li><${childList}><li><br></li></${childList}></li></${list}>`, 1133 expectedTargetRanges: () => { 1134 return [ 1135 { 1136 startContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild, 1137 startOffset: 0, 1138 endContainer: gEditor.querySelector(`${list} > li + li`).firstChild, 1139 endOffset: gEditor.querySelector(`${list} > li + li`).firstChild.length, 1140 }, 1141 ]; 1142 }, 1143 expectInputEvent: true, 1144 } 1145 ); 1146 } 1147 1148 // When deleting the last list item in a sub list, only the list should 1149 // be removed. This makes users feel like doing outdent. 1150 for (let childList of ["ul", "ol"]) { 1151 addPromiseTest( 1152 `<${list}><li><${childList}><li>{}<br></li></${childList}></li></${list}>`, 1153 { 1154 expectedInnerHTML: `<${list}><li><br></li></${list}>`, 1155 expectedTargetRanges: () => { 1156 return [ 1157 { 1158 startContainer: gEditor.querySelector(`li`), 1159 startOffset: 0, 1160 endContainer: gEditor.querySelector(`li`), 1161 endOffset: 1, 1162 }, 1163 ]; 1164 }, 1165 expectInputEvent: true, 1166 } 1167 ); 1168 1169 addPromiseTest( 1170 `<${list}><li><${childList}><li>[list-item1]</li></${childList}></li></${list}>`, 1171 { 1172 expectedInnerHTML: `<${list}><li><${childList}><li><br></li></${childList}></li></${list}>`, 1173 expectedTargetRanges: () => { 1174 return [ 1175 { 1176 startContainer: gEditor.querySelector(`li li`).firstChild, 1177 startOffset: 0, 1178 endContainer: gEditor.querySelector(`li li`).firstChild, 1179 endOffset: gEditor.querySelector(`li li`).firstChild.length, 1180 }, 1181 ]; 1182 }, 1183 expectInputEvent: true, 1184 } 1185 ); 1186 1187 addPromiseTest( 1188 `<${list}><li>{<${childList}><li>list-item1</li></${childList}>}</li></${list}>`, 1189 { 1190 expectedInnerHTML: `<${list}><li><${childList}><li><br></li></${childList}></li></${list}>`, 1191 expectedTargetRanges: () => { 1192 return [ 1193 { 1194 startContainer: gEditor.querySelector(`li li`).firstChild, 1195 startOffset: 0, 1196 endContainer: gEditor.querySelector(`li li`).firstChild, 1197 endOffset: gEditor.querySelector(`li li`).firstChild.length, 1198 }, 1199 ]; 1200 }, 1201 expectInputEvent: true, 1202 } 1203 ); 1204 1205 addPromiseTest( 1206 `<${list}><li><${childList}><li>{}<br></li></${childList}></li><li>list-item2</li></${list}>`, 1207 { 1208 expectedInnerHTML: `<${list}><li><br></li><li>list-item2</li></${list}>`, 1209 expectedTargetRanges: () => { 1210 return [ 1211 { 1212 startContainer: gEditor.querySelector(`li`), 1213 startOffset: 0, 1214 endContainer: gEditor.querySelector(`li`), 1215 endOffset: 1, 1216 }, 1217 ]; 1218 }, 1219 expectInputEvent: true, 1220 } 1221 ); 1222 1223 addPromiseTest( 1224 `<${list}><li>list-item1</li><li><${childList}><li>{}<br></li></${childList}></li></${list}>`, 1225 { 1226 expectedInnerHTML: `<${list}><li>list-item1</li><li><br></li></${list}>`, 1227 expectedTargetRanges: () => { 1228 return [ 1229 { 1230 startContainer: gEditor.querySelector(`li + li`), 1231 startOffset: 0, 1232 endContainer: gEditor.querySelector(`li + li`), 1233 endOffset: 1, 1234 }, 1235 ]; 1236 }, 1237 expectInputEvent: true, 1238 } 1239 ); 1240 1241 // Invalid cases. 1242 addPromiseTest( 1243 `<${list}><${childList}><li>{}<br></li></${childList}></${list}>`, 1244 { 1245 expectedInnerHTML: `<${list}><li><br></li></${list}>`, 1246 expectedTargetRanges: () => { 1247 return [ 1248 { 1249 startContainer: gEditor.querySelector(`${list}`), 1250 startOffset: 0, 1251 endContainer: gEditor.querySelector(`${list}`), 1252 endOffset: 1, 1253 }, 1254 ]; 1255 }, 1256 expectInputEvent: true, 1257 } 1258 ); 1259 1260 addPromiseTest( 1261 `<${list}><${childList}><li>[list-item1]</li></${childList}></${list}>`, 1262 { 1263 expectedInnerHTML: `<${list}><${childList}><li><br></li></${childList}></${list}>`, 1264 expectedTargetRanges: () => { 1265 return [ 1266 { 1267 startContainer: gEditor.querySelector(`li`).firstChild, 1268 startOffset: 0, 1269 endContainer: gEditor.querySelector(`li`).firstChild, 1270 endOffset: gEditor.querySelector(`li`).firstChild.length, 1271 }, 1272 ]; 1273 }, 1274 expectInputEvent: true, 1275 } 1276 ); 1277 1278 addPromiseTest( 1279 `<${list}>{<${childList}><li>list-item1</li></${childList}>}</${list}>`, 1280 { 1281 expectedInnerHTML: `<${list}><${childList}><li><br></li></${childList}></${list}>`, 1282 expectedTargetRanges: () => { 1283 return [ 1284 { 1285 startContainer: gEditor.querySelector(`li`).firstChild, 1286 startOffset: 0, 1287 endContainer: gEditor.querySelector(`li`).firstChild, 1288 endOffset: gEditor.querySelector(`li`).firstChild.length, 1289 }, 1290 ]; 1291 }, 1292 expectInputEvent: true, 1293 } 1294 ); 1295 1296 addPromiseTest( 1297 `<${list}><${childList}><li>{}<br></li></${childList}><li>list-item2</li></${list}>`, 1298 { 1299 expectedInnerHTML: `<${list}><li><br></li><li>list-item2</li></${list}>`, 1300 expectedTargetRanges: () => { 1301 return [ 1302 { 1303 startContainer: gEditor.querySelector(`${list}`), 1304 startOffset: 0, 1305 endContainer: gEditor.querySelector(`${list}`), 1306 endOffset: 1, 1307 }, 1308 ]; 1309 }, 1310 expectInputEvent: true, 1311 } 1312 ); 1313 1314 addPromiseTest( 1315 `<${list}><li>list-item1</li><${childList}><li>{}<br></li></${childList}></${list}>`, 1316 { 1317 expectedInnerHTML: `<${list}><li>list-item1</li><li><br></li></${list}>`, 1318 expectedTargetRanges: () => { 1319 return [ 1320 { 1321 startContainer: gEditor.querySelector(`${list}`), 1322 startOffset: 1, 1323 endContainer: gEditor.querySelector(`${list}`), 1324 endOffset: 2, 1325 }, 1326 ]; 1327 }, 1328 expectInputEvent: true, 1329 } 1330 ); 1331 } 1332 1333 // Joining same level list elements. 1334 for (let otherList of ["ul", "ol"]) { 1335 addPromiseTest( 1336 `<${list}><li>[list-item1</li></${list}><${otherList}><li>}list-item2</li></${otherList}>`, 1337 { 1338 expectedInnerHTML: [ 1339 `<${list}><li>list-item2</li></${list}>`, 1340 `<${list}><li>list-item2<br></li></${list}>`, 1341 ], 1342 expectedTargetRanges: () => { 1343 return [ 1344 { 1345 startContainer: gEditor.querySelector(`${list} > li`).firstChild, 1346 startOffset: 0, 1347 endContainer: gEditor.querySelector(`${list} + ${otherList} > li`), 1348 endOffset: 0, 1349 }, 1350 ]; 1351 }, 1352 expectInputEvent: true, 1353 } 1354 ); 1355 1356 addPromiseTest( 1357 `<${list}><li>[list-item1</li></${list}><${otherList}><li>list-item2]</li></${otherList}>`, 1358 { 1359 expectedInnerHTML: `<${list}><li><br></li></${list}>`, 1360 expectedTargetRanges: () => { 1361 return [ 1362 { 1363 startContainer: gEditor.querySelector(`${list} > li`).firstChild, 1364 startOffset: 0, 1365 endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild, 1366 endOffset: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild.length, 1367 }, 1368 ]; 1369 }, 1370 expectInputEvent: true, 1371 } 1372 ); 1373 1374 addPromiseTest( 1375 `<${list}><li>list-item1[</li></${list}><${otherList}><li>}list-item2</li></${otherList}>`, 1376 { 1377 expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`, 1378 expectedTargetRanges: () => { 1379 return [ 1380 { 1381 startContainer: gEditor.querySelector(`${list} > li`).firstChild, 1382 startOffset: gEditor.querySelector(`${list} > li`).firstChild.length, 1383 endContainer: gEditor.querySelector(`${list} + ${otherList} > li`), 1384 endOffset: 0, 1385 }, 1386 ]; 1387 }, 1388 expectInputEvent: true, 1389 } 1390 ); 1391 1392 addPromiseTest( 1393 `<${list}><li>first line in list-item1<br>list-item1[</li></${list}><${otherList}><li>}list-item2</li></${otherList}>`, 1394 { 1395 expectedInnerHTML: `<${list}><li>first line in list-item1<br>list-item1list-item2</li></${list}>`, 1396 expectedTargetRanges: () => { 1397 return [ 1398 { 1399 startContainer: gEditor.querySelector(`${list} > li > br`).nextSibling, 1400 startOffset: gEditor.querySelector(`${list} > li > br`).nextSibling.length, 1401 endContainer: gEditor.querySelector(`${list} + ${otherList} > li`), 1402 endOffset: 0, 1403 }, 1404 ]; 1405 }, 1406 expectInputEvent: true, 1407 } 1408 ); 1409 1410 addPromiseTest( 1411 `<${list}><li>list-item1[</li></${list}><${otherList}><li>}list-item2<br>second line in list-item2</li></${otherList}>`, 1412 { 1413 expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}><${otherList}><li>second line in list-item2</li></${otherList}>`, 1414 expectedTargetRanges: () => { 1415 return [ 1416 { 1417 startContainer: gEditor.querySelector(`${list} > li`).firstChild, 1418 startOffset: gEditor.querySelector(`${list} > li`).firstChild.length, 1419 endContainer: gEditor.querySelector(`${list} + ${otherList} > li`), 1420 endOffset: 0, 1421 }, 1422 ]; 1423 }, 1424 expectInputEvent: true, 1425 } 1426 ); 1427 1428 addPromiseTest( 1429 `<${list}><li>list-item1</li><li>list-item2[</li></${list}><${otherList}><li>}list-item3</li></${otherList}>`, 1430 { 1431 expectedInnerHTML: `<${list}><li>list-item1</li><li>list-item2list-item3</li></${list}>`, 1432 expectedTargetRanges: () => { 1433 return [ 1434 { 1435 startContainer: gEditor.querySelector(`${list} > li + li`).firstChild, 1436 startOffset: gEditor.querySelector(`${list} > li + li`).firstChild.length, 1437 endContainer: gEditor.querySelector(`${list} + ${otherList} > li`), 1438 endOffset: 0, 1439 }, 1440 ]; 1441 }, 1442 expectInputEvent: true, 1443 } 1444 ); 1445 1446 addPromiseTest( 1447 `<${list}><li>list-item1[</li></${list}><${otherList}><li>}list-item2</li><li>list-item3</li></${otherList}>`, 1448 { 1449 expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}><${otherList}><li>list-item3</li></${otherList}>`, 1450 expectedTargetRanges: () => { 1451 return [ 1452 { 1453 startContainer: gEditor.querySelector(`${list} > li`).firstChild, 1454 startOffset: gEditor.querySelector(`${list} > li`).firstChild.length, 1455 endContainer: gEditor.querySelector(`${list} + ${otherList} > li`), 1456 endOffset: 0, 1457 }, 1458 ]; 1459 }, 1460 expectInputEvent: true, 1461 } 1462 ); 1463 } 1464 1465 // Joining nested left list and right list element. Move the content in first line from selection end in the right 1466 // list item element into end of the left list item element. 1467 for (let childList of ["ul", "ol"]) { 1468 for (let otherList of ["ul", "ol"]) { 1469 addPromiseTest( 1470 `<${list}><li><${childList}><li>[list-item1</li></${childList}></li></${list}><${otherList}><li>}list-item2</li></${otherList}>`, 1471 { 1472 expectedInnerHTML: [ 1473 `<${list}><li><${childList}><li>list-item2</li></${childList}></li></${list}>`, 1474 `<${list}><li><${childList}><li>list-item2<br></li></${childList}></li></${list}>`, 1475 ], 1476 expectedTargetRanges: () => { 1477 return [ 1478 { 1479 startContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild, 1480 startOffset: 0, 1481 endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild, 1482 endOffset: 0, 1483 }, 1484 ]; 1485 }, 1486 expectInputEvent: true, 1487 } 1488 ); 1489 1490 addPromiseTest( 1491 `<${list}><li><${childList}><li>[list-item1</li></${childList}></li></${list}><${otherList}><li>list-item2]</li></${otherList}>`, 1492 { 1493 expectedInnerHTML: `<${list}><li><${childList}><li><br></li></${childList}></li></${list}>`, 1494 expectedTargetRanges: () => { 1495 return [ 1496 { 1497 startContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild, 1498 startOffset: 0, 1499 endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild, 1500 endOffset: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild.length, 1501 }, 1502 ]; 1503 }, 1504 expectInputEvent: true, 1505 } 1506 ); 1507 1508 addPromiseTest( 1509 `<${list}><li><${childList}><li>list-item1[</li></${childList}></li></${list}><${otherList}><li>list-item2]</li></${otherList}>`, 1510 { 1511 expectedInnerHTML: `<${list}><li><${childList}><li>list-item1</li></${childList}></li></${list}>`, 1512 expectedTargetRanges: () => { 1513 return [ 1514 { 1515 startContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild, 1516 startOffset: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild.length, 1517 endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild, 1518 endOffset: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild.length, 1519 }, 1520 ]; 1521 }, 1522 expectInputEvent: true, 1523 } 1524 ); 1525 1526 // Invalid cases. 1527 addPromiseTest( 1528 `<${list}><${childList}><li>[list-item1</li></${childList}></${list}><${otherList}><li>}list-item2</li></${otherList}>`, 1529 { 1530 expectedInnerHTML: [ 1531 `<${list}><${childList}><li>list-item2</li></${childList}></${list}>`, 1532 `<${list}><${childList}><li>list-item2<br></li></${childList}></${list}>`, 1533 ], 1534 expectedTargetRanges: () => { 1535 return [ 1536 { 1537 startContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild, 1538 startOffset: 0, 1539 endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild, 1540 endOffset: 0, 1541 }, 1542 ]; 1543 }, 1544 expectInputEvent: true, 1545 } 1546 ); 1547 1548 addPromiseTest( 1549 `<${list}><${childList}><li>[list-item1</li></${childList}></${list}><${otherList}><li>list-item2]</li></${otherList}>`, 1550 { 1551 expectedInnerHTML: `<${list}><${childList}><li><br></li></${childList}></${list}>`, 1552 expectedTargetRanges: () => { 1553 return [ 1554 { 1555 startContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild, 1556 startOffset: 0, 1557 endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild, 1558 endOffset: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild.length, 1559 }, 1560 ]; 1561 }, 1562 expectInputEvent: true, 1563 } 1564 ); 1565 1566 addPromiseTest( 1567 `<${list}><${childList}><li>list-item1[</li></${childList}></${list}><${otherList}><li>list-item2]</li></${otherList}>`, 1568 { 1569 expectedInnerHTML: `<${list}><${childList}><li>list-item1</li></${childList}></${list}>`, 1570 expectedTargetRanges: () => { 1571 return [ 1572 { 1573 startContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild, 1574 startOffset: gEditor.querySelector(`${list} > ${childList} > li`).firstChild.length, 1575 endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild, 1576 endOffset: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild.length, 1577 }, 1578 ]; 1579 }, 1580 expectInputEvent: true, 1581 } 1582 ); 1583 } 1584 } 1585 1586 // Joining left list and nested right list element. Basically, the first line from the selection end should 1587 // be moved into the end of the left list item element, but if all content in the left list is being deleted, 1588 // keep the right list elements. 1589 for (let childList of ["ul", "ol"]) { 1590 for (let otherList of ["ul", "ol"]) { 1591 addPromiseTest( 1592 `<${list}><li>list-item1[</li></${list}><${otherList}><li><${childList}><li>}list-item2</li></${childList}></li></${otherList}>`, 1593 { 1594 expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`, 1595 expectedTargetRanges: () => { 1596 return [ 1597 { 1598 startContainer: gEditor.querySelector(`${list} > li`).firstChild, 1599 startOffset: gEditor.querySelector(`${list} > li`).firstChild.length, 1600 endContainer: gEditor.querySelector(`${list} + ${otherList} > li > ${childList} > li`), 1601 endOffset: 0, 1602 }, 1603 ]; 1604 }, 1605 expectInputEvent: true, 1606 } 1607 ); 1608 1609 addPromiseTest( 1610 `<${list}><li>[list-item1</li></${list}><${otherList}><li><${childList}><li>}list-item2</li></${childList}></li></${otherList}>`, 1611 { 1612 expectedInnerHTML: [ 1613 `<${otherList}><li><${childList}><li>list-item2</li></${childList}></li></${otherList}>`, 1614 `<${otherList}><li><${childList}><li>list-item2<br></li></${childList}></li></${otherList}>`, 1615 ], 1616 expectedTargetRanges: () => { 1617 return [ 1618 { 1619 startContainer: gEditor.querySelector(`${list} > li`).firstChild, 1620 startOffset: 0, 1621 endContainer: gEditor.querySelector(`${list} + ${otherList} > li > ${childList} > li`), 1622 endOffset: 0, 1623 }, 1624 ]; 1625 }, 1626 expectInputEvent: true, 1627 } 1628 ); 1629 1630 addPromiseTest( 1631 `<${list}><li>[list-item1</li></${list}><${otherList}><li><${childList}><li>list-item2]</li></${childList}></li></${otherList}>`, 1632 { 1633 expectedInnerHTML: `<${list}><li><br></li></${list}>`, 1634 expectedTargetRanges: () => { 1635 return [ 1636 { 1637 startContainer: gEditor.querySelector(`${list} > li`).firstChild, 1638 startOffset: 0, 1639 endContainer: gEditor.querySelector(`${list} + ${otherList} > li > ${childList} > li`).firstChild, 1640 endOffset: gEditor.querySelector(`${list} + ${otherList} > li > ${childList} > li`).firstChild.length, 1641 }, 1642 ]; 1643 }, 1644 expectInputEvent: true, 1645 } 1646 ); 1647 1648 addPromiseTest( 1649 `<${list}><li>list-item1[</li></${list}><${otherList}><li><${childList}><li>}list-item2<br>second line of list-item2</li></${childList}></li></${otherList}>`, 1650 { 1651 expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}><${otherList}><li><${childList}><li>second line of list-item2</li></${childList}></li></${otherList}>`, 1652 expectedTargetRanges: () => { 1653 return [ 1654 { 1655 startContainer: gEditor.querySelector(`${list} > li`).firstChild, 1656 startOffset: gEditor.querySelector(`${list} > li`).firstChild.length, 1657 endContainer: gEditor.querySelector(`${list} + ${otherList} > li > ${childList} > li`), 1658 endOffset: 0, 1659 }, 1660 ]; 1661 }, 1662 expectInputEvent: true, 1663 } 1664 ); 1665 1666 // Invalid cases. 1667 addPromiseTest( 1668 `<${list}><li>list-item1[</li></${list}><${otherList}><${childList}><li>}list-item2</li></${childList}></${otherList}>`, 1669 { 1670 expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`, 1671 expectedTargetRanges: () => { 1672 return [ 1673 { 1674 startContainer: gEditor.querySelector(`${list} > li`).firstChild, 1675 startOffset: gEditor.querySelector(`${list} > li`).firstChild.length, 1676 endContainer: gEditor.querySelector(`${list} + ${otherList} > ${childList} > li`), 1677 endOffset: 0, 1678 }, 1679 ]; 1680 }, 1681 expectInputEvent: true, 1682 } 1683 ); 1684 1685 addPromiseTest( 1686 `<${list}><li>[list-item1</li></${list}><${otherList}><${childList}><li>}list-item2</li></${childList}></${otherList}>`, 1687 { 1688 expectedInnerHTML: [ 1689 `<${otherList}><${childList}><li>list-item2</li></${childList}></${otherList}>`, 1690 `<${otherList}><${childList}><li>list-item2<br></li></${childList}></${otherList}>`, 1691 ], 1692 expectedTargetRanges: () => { 1693 return [ 1694 { 1695 startContainer: gEditor.querySelector(`${list} > li`).firstChild, 1696 startOffset: 0, 1697 endContainer: gEditor.querySelector(`${list} + ${otherList} > ${childList} > li`), 1698 endOffset: 0, 1699 }, 1700 ]; 1701 }, 1702 expectInputEvent: true, 1703 } 1704 ); 1705 1706 addPromiseTest( 1707 `<${list}><li>[list-item1</li></${list}><${otherList}><${childList}><li>list-item2]</li></${childList}></${otherList}>`, 1708 { 1709 expectedInnerHTML: `<${list}><li><br></li></${list}>`, 1710 expectedTargetRanges: () => { 1711 return [ 1712 { 1713 startContainer: gEditor.querySelector(`${list} > li`).firstChild, 1714 startOffset: 0, 1715 endContainer: gEditor.querySelector(`${list} + ${otherList} > ${childList} > li`).firstChild, 1716 endOffset: gEditor.querySelector(`${list} + ${otherList} > ${childList} > li`).firstChild.length, 1717 }, 1718 ]; 1719 }, 1720 expectInputEvent: true, 1721 } 1722 ); 1723 1724 addPromiseTest( 1725 `<${list}><li>list-item1[</li></${list}><${otherList}><${childList}><li>}list-item2<br>second line of list-item2</li></${childList}></${otherList}>`, 1726 { 1727 expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}><${otherList}><${childList}><li>second line of list-item2</li></${childList}></${otherList}>`, 1728 expectedTargetRanges: () => { 1729 return [ 1730 { 1731 startContainer: gEditor.querySelector(`${list} > li`).firstChild, 1732 startOffset: gEditor.querySelector(`${list} > li`).firstChild.length, 1733 endContainer: gEditor.querySelector(`${list} + ${otherList} > ${childList} > li`), 1734 endOffset: 0, 1735 }, 1736 ]; 1737 }, 1738 expectInputEvent: true, 1739 } 1740 ); 1741 } 1742 } 1743 1744 </script>