| <!DOCTYPE html> |
| <meta charset="utf-8"> |
| <meta name="timeout" content="long"> |
| <meta name="variant" content="?Backspace,ul"> |
| <meta name="variant" content="?Backspace,ol"> |
| <meta name="variant" content="?Delete,ul"> |
| <meta name="variant" content="?Delete,ol"> |
| <title>InputEvent.getTargetRanges() at deleting in/around/across list item elements</title> |
| <div contenteditable></div> |
| <script src="input-events-get-target-ranges.js"></script> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="/resources/testdriver.js"></script> |
| <script src="/resources/testdriver-vendor.js"></script> |
| <script src="/resources/testdriver-actions.js"></script> |
| <script> |
| "use strict"; |
| |
| const [action, list] = location.search.substring(1).split(","); |
| function run() { |
| switch (action) { |
| case "Backspace": |
| return sendBackspaceKey(); |
| case "Delete": |
| return sendDeleteKey(); |
| default: |
| throw "Unhandled variant"; |
| } |
| } |
| |
| /** |
| * @param innerHTML Initial `innerHTML` value of the editor. |
| * @param data |
| * expectedInnerHTML |
| * Expected `innerHTML` of the editor after calling |
| * `run()`. This can be array of string if there are |
| * some acceptable differences like whether there is |
| * an invisible `<br>` element at end of list item. |
| * expectedTargetRanges |
| * `null` or `unspecified` if `beforeinput` event shouldn't |
| * be fired. |
| * Otherwise, function returning an array of objects |
| * which have `startContainer`, `startOffset`, |
| * `endContainer`, `endOffset`. This will be called |
| * before calling `run()` and compared with |
| * `getTargetRanges()` after that. |
| * expectInputEvent: |
| * `true` if it should cause an `input` event. |
| */ |
| function addPromiseTest(innerHTML, data) { |
| promise_test(async (t) => { |
| initializeTest(innerHTML); |
| let expectedTargetRanges = |
| typeof data.expectedTargetRanges === "function" |
| ? data.expectedTargetRanges() |
| : null; |
| await run(); |
| checkEditorContentResultAsSubTest(data.expectedInnerHTML, t.name); |
| if (expectedTargetRanges !== null) { |
| checkGetTargetRangesOfBeforeinputOnDeleteSomething(expectedTargetRanges); |
| if (data.expectInputEvent) { |
| checkGetTargetRangesOfInputOnDeleteSomething(); |
| } else { |
| checkGetTargetRangesOfInputOnDoNothing(); |
| } |
| } else { |
| checkBeforeinputAndInputEventsOnNOOP(); |
| } |
| }, `${action} at "${innerHTML}"`); |
| } |
| |
| addPromiseTest( |
| `<${list}><li>list[-item1</li><li>list]-item2</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: "list".length, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: "list".length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-[item1</li><li>]list-item2</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-list-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: "list-".length, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-[item1</li><li>}list-item2</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-list-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: "list-".length, |
| endContainer: gEditor.querySelector("li + li"), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1[</li><li>list]-item2</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: gEditor.querySelector("li").firstChild.length, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: "list".length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1{</li><li>list]-item2</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li"), |
| startOffset: 1, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: "list".length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1[</li><li>]list-item2</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: gEditor.querySelector("li").firstChild.length, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| action === "Backspace" |
| ? `<${list}><li>list-item1</li><li>[]list-item2</li></${list}>` |
| : `<${list}><li>list-item1[]</li><li>list-item2</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: gEditor.querySelector("li").firstChild.length, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| action === "Backspace" |
| ? `<${list}><li>list-item1<br></li><li>[]list-item2</li></${list}>` |
| : `<${list}><li>list-item1[]<br></li><li>list-item2</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return action === "Backspace" |
| ? [ |
| { |
| startContainer: gEditor.querySelector("li"), |
| startOffset: 1, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: 0, |
| }, |
| ] |
| : [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: gEditor.querySelector("li").firstChild.length, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| action === "Backspace" |
| ? `<${list}><li>list-item1<br><br></li><li>[]list-item2</li></${list}>` |
| : `<${list}><li>list-item1[]<br><br></li><li>list-item2</li></${list}>`, |
| { |
| expectedInnerHTML: [ |
| `<${list}><li>list-item1<br>list-item2</li></${list}>`, |
| `<${list}><li>list-item1<br>list-item2<br></li></${list}>`, |
| ], |
| expectedTargetRanges: () => { |
| return action === "Backspace" |
| ? [ |
| { |
| startContainer: gEditor.querySelector("li"), |
| startOffset: 1, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: 0, |
| }, |
| ] |
| : [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: gEditor.querySelector("li").firstChild.length, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| action === "Backspace" |
| ? `<${list}><li>list-item1</li><li>[]list-item2<br>second line of list-item2</li></${list}>` |
| : `<${list}><li>list-item1[]</li><li>list-item2<br>second line of list-item2</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1list-item2</li><li>second line of list-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return action === "Backspace" |
| ? [ |
| { |
| startContainer: gEditor.querySelector("li"), |
| startOffset: 1, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: 0, |
| }, |
| ] |
| : [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: gEditor.querySelector("li").firstChild.length, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| action === "Backspace" |
| ? `<${list}><li><p>list-item1</p></li><li>[]list-item2</li></${list}>` |
| : `<${list}><li><p>list-item1[]</p></li><li>list-item2</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li><p>list-item1list-item2</p></li></${list}>`, |
| expectedTargetRanges: () => { |
| return action === "Backspace" |
| ? [ |
| { |
| startContainer: gEditor.querySelector("p").firstChild, |
| startOffset: gEditor.querySelector("p").firstChild.length, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: 0, |
| }, |
| ] |
| : [ |
| { |
| startContainer: gEditor.querySelector("p").firstChild, |
| startOffset: gEditor.querySelector("p").firstChild.length, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| action === "Backspace" |
| ? `<${list}><li>list-item1</li><li><p>[]list-item2</p></li></${list}>` |
| : `<${list}><li>list-item1[]</li><li><p>list-item2</p></li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return action === "Backspace" |
| ? [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: gEditor.querySelector("li").firstChild.length, |
| endContainer: gEditor.querySelector("p").firstChild, |
| endOffset: 0, |
| }, |
| ] |
| : [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: gEditor.querySelector("li").firstChild.length, |
| endContainer: gEditor.querySelector("p").firstChild, |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>[list-item1]</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li><br></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector("li").firstChild, |
| endOffset: gEditor.querySelector("li").firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>{list-item1}</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li><br></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector("li").firstChild, |
| endOffset: gEditor.querySelector("li").firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| // Even if the last list item is selected, don't delete the list and |
| // the last list item element. This is a triple click case on Gecko. |
| addPromiseTest( |
| `<${list}>{<li>list-item1</li>}</${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li><br></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector("li").firstChild, |
| endOffset: gEditor.querySelector("li").firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| // A list item is selected and it's not the last one, can delete it. |
| addPromiseTest( |
| `<${list}>{<li>list-item1</li>}<li>list-item2</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list}`), |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list}`), |
| endOffset: 1, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| // Delete list element when deleting from empty last list item. |
| addPromiseTest( |
| `<${list}><li>{}<br></li></${list}>`, |
| { |
| expectedInnerHTML: ["", "<br>", "<div><br></div>"], |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor, |
| startOffset: 0, |
| endContainer: gEditor, |
| endOffset: 1, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `{<${list}><li><br></li></${list}>}`, |
| { |
| expectedInnerHTML: ["", "<br>", "<div><br></div>"], |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor, |
| startOffset: 0, |
| endContainer: gEditor, |
| endOffset: 1, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<div>{<${list}><li><br></li></${list}>}</div>`, |
| { |
| expectedInnerHTML: ["<div><br></div>", "<div><div><br></div></div>"], |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("div"), |
| startOffset: 0, |
| endContainer: gEditor.querySelector("div"), |
| endOffset: 1, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| // It may be better to ignore the invisible white-space and take same action |
| // as above, but it requires more expensive check before deleting. So perhaps, |
| // this behavior is reasonable. |
| addPromiseTest( |
| `<div>{ <${list}><li><br></li></${list}> }</div>`, |
| { |
| expectedInnerHTML: ["<div><br></div>", "<div><div><br></div></div>"], |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("div"), |
| startOffset: 0, |
| endContainer: gEditor.querySelector("div"), |
| endOffset: 3, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<div><${list}><li>{}<br></li></${list}></div>`, |
| { |
| expectedInnerHTML: ["<div><br></div>", "<div><div><br></div></div>"], |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("div"), |
| startOffset: 0, |
| endContainer: gEditor.querySelector("div"), |
| endOffset: 1, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| // XXX Blink does not delete the list element if its first or last <li> element |
| // is not editable. However, it means that user cannot delete the list |
| // element, and it's not consistent behavior when only middle list item(s) |
| // are not editable. Perhaps, once it makes the list element has only |
| // one empty list item element, then, another deleting operation allows to |
| // delete the list element. |
| addPromiseTest( |
| `<div>{<${list}><li contenteditable="false"><br></li></${list}>}</div>`, |
| { |
| expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(list), |
| startOffset: 0, |
| endContainer: gEditor.querySelector(list), |
| endOffset: 1, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<div>{<${list}><li contenteditable="false">list-item1</li></${list}>}</div>`, |
| { |
| expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(list), |
| startOffset: 0, |
| endContainer: gEditor.querySelector(list), |
| endOffset: 1, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<div>{<${list}><li contenteditable="false">list-item1</li><li><br></li></${list}>}</div>`, |
| { |
| expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(list), |
| startOffset: 0, |
| endContainer: gEditor.querySelector("li + li"), |
| endOffset: 1, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<div>{<${list}><li contenteditable="false">list-item1</li><li>list-item2</li></${list}>}</div>`, |
| { |
| expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(list), |
| startOffset: 0, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: gEditor.querySelector("li + li").firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<div>{<${list}><li><br></li><li contenteditable="false">list-item2</li></${list}>}</div>`, |
| { |
| expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(list), |
| endOffset: 2, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<div>{<${list}><li>list-item1</li><li contenteditable="false">list-item2</li></${list}>}</div>`, |
| { |
| expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(list), |
| endOffset: 2, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<div>{<${list}><li><br></li><li contenteditable="false">list-item2</li><li><br></li></${list}>}</div>`, |
| { |
| expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector("li + li + li"), |
| endOffset: 1, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<div>{<${list}><li>list-item1</li><li contenteditable="false">list-item2</li><li>list-item3</li></${list}>}</div>`, |
| { |
| expectedInnerHTML: `<div><${list}><li><br></li></${list}></div>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector("li + li + li").firstChild, |
| endOffset: gEditor.querySelector("li + li + li").firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1</li>{<li>list-item2</li>}<li>list-item3</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1</li><li>list-item3</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list}`), |
| startOffset: 1, |
| endContainer: gEditor.querySelector(`${list}`), |
| endOffset: 2, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| // Selecting last list item element shouldn't delete the list item. |
| addPromiseTest( |
| `<${list}><li>list-item1</li>{<li>list-item2</li>}</${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1</li><li><br></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li + li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} > li + li`).firstChild, |
| endOffset: gEditor.querySelector(`${list} > li + li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1</li><li>list-item2</li>{<li>list-item3</li>}</${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1</li><li>list-item2</li><li><br></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li + li + li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} > li + li + li`).firstChild, |
| endOffset: gEditor.querySelector(`${list} > li + li + li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| for (let childList of ["ul", "ol"]) { |
| addPromiseTest( |
| `<${list}><li>list-item1</li>{<li>list-item2</li>}<li><${childList}><li><br></li></${childList}></li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1</li><li><${childList}><li><br></li></${childList}></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list}`), |
| startOffset: 1, |
| endContainer: gEditor.querySelector(`${list}`), |
| endOffset: 2, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| // Invalid nested list elements cases. Treat the nested list element as a list item element. |
| addPromiseTest( |
| `<${list}><li>list-item1</li>{<li>list-item2</li>}<${childList}><li><br></li></${childList}></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1</li><${childList}><li><br></li></${childList}></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list}`), |
| startOffset: 1, |
| endContainer: gEditor.querySelector(`${list}`), |
| endOffset: 2, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1</li><li>list-item2</li>{<${childList}><li><br></li></${childList}>}</${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1</li><li>list-item2</li><li><br></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list}`), |
| startOffset: 2, |
| endContainer: gEditor.querySelector(`${list}`), |
| endOffset: 3, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| } |
| |
| // Don't delete list and joined list items when only there content are selected. |
| addPromiseTest( |
| `<${list}><li>[list-item1</li><li>list-item2]</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li><br></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: gEditor.querySelector("li + li").firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>[list-item1</li><li>list-item2]</li><li>list-item3</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li><br></li><li>list-item3</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: gEditor.querySelector("li + li").firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1</li><li>[list-item2]</li><li>list-item3</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1</li><li><br></li><li>list-item3</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li + li").firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: gEditor.querySelector("li + li").firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1</li><li>[list-item2</li><li>list-item3]</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1</li><li><br></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li + li").firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector("li + li + li").firstChild, |
| endOffset: gEditor.querySelector("li + li + li").firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| // Ported tests from editing/delete.js and editing/forwarddelete.js |
| for (let otherList of ["ul", "ol"]) { |
| if (action === "Backspace") { |
| addPromiseTest( |
| `<${otherList}><li>list-item1</li></${otherList}><${list}><li>l[]ist-item2</li></${list}>`, |
| { |
| expectedInnerHTML: `<${otherList}><li>list-item1</li></${otherList}><${list}><li>ist-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${otherList} + ${list} > li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${otherList} + ${list} > li`).firstChild, |
| endOffset: "l".length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1[]</li></${list}><${otherList}><li>list-item2</li></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item</li></${list}><${otherList}><li>list-item2</li></${otherList}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: "list-item".length, |
| endContainer: gEditor.querySelector("li").firstChild, |
| endOffset: "list-item1".length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| } else { |
| addPromiseTest( |
| `<${list}><li>list-item[]1</li></${list}><${otherList}><li>list-item2</li></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item</li></${list}><${otherList}><li>list-item2</li></${otherList}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: "list-item".length, |
| endContainer: gEditor.querySelector("li").firstChild, |
| endOffset: "list-item1".length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${otherList}><li>list-item1</li></${otherList}><${list}><li>[]list-item2</li></${list}>`, |
| { |
| expectedInnerHTML: `<${otherList}><li>list-item1</li></${otherList}><${list}><li>ist-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${otherList} + ${list} > li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${otherList} + ${list} > li`).firstChild, |
| endOffset: "l".length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| } |
| |
| addPromiseTest( |
| `<${list}><li>list-item1[</li><li>list-item2]</li></${list}><${otherList}><li>list-item3</li></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1</li></${list}><${otherList}><li>ist-item3</li><li>ist-item4</li></${otherList}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: gEditor.querySelector("li").firstChild.length, |
| endContainer: gEditor.querySelector("li + li").firstChild, |
| endOffset: gEditor.querySelector("li + li").firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| } |
| |
| |
| // Invalid nested list element cases. Traditionally, all browser engines |
| // insert child list element without wrapping it with a list item element. |
| // So, keeping the behavior in these cases are important for backward |
| // compatibility. |
| // https://bugzilla.mozilla.org/show_bug.cgi?id=487524 |
| for (let childList of ["ul", "ol"]) { |
| addPromiseTest( |
| `<${list}><li>[list-item1</li><${childList}><li>}list-item2</li></ul></${list}>`, |
| { |
| expectedInnerHTML: [ |
| `<${list}><${childList}><li>list-item2</li></${childList}></${list}>`, |
| `<${list}><${childList}><li>list-item2<br></li></${childList}></${list}>`, |
| ], |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} > ${childList} > li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>[list-item1</li><${childList}><li>list-item2]</li></${childList}></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><${childList}><li><br></li></${childList}></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector("li").firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild, |
| endOffset: gEditor.querySelector(`${list} > ${childList} > li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><${childList}><li>[list-item1</li></${childList}><li>}list-item2</li></${list}>`, |
| { |
| expectedInnerHTML: [ |
| `<${list}><${childList}><li>list-item2</li></${childList}></${list}>`, |
| `<${list}><${childList}><li>list-item2<br></li></${childList}></${list}>`, |
| ], |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} > li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><${childList}><li>[list-item1</li></${childList}><li>list-item2]</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><${childList}><li><br></li></${childList}></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${childList} + li`).firstChild, |
| endOffset: gEditor.querySelector(`${childList} + li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><${childList}><li>list-item1</li><li>[list-item2</li></${childList}><li>}list-item3</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><${childList}><li>list-item1</li><li>list-item3</li></${childList}></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > ${childList} > li + li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} > li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>[list-item1</li><${childList}><li>list-item2</li><li>}list-item3</li></${childList}></${list}>`, |
| { |
| expectedInnerHTML: [ |
| `<${list}><${childList}><li>list-item3</li></${childList}></${list}>`, |
| `<${list}><${childList}><li>list-item3<br></li></${childList}></${list}>`, |
| ], |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} > ${childList} > li + li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1</li><li>[list-item2</li><${childList}><li>list-item3</li><li>}list-item4</li></${childList}></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1</li><${childList}><li>list-item4</li></${childList}></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`li + li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} > ${childList} > li + li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| // Valid sub list element cases. |
| addPromiseTest( |
| `<${list}><li>[list-item1</li><li><${childList}><li>list-item2]</li></${childList}></li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li><${childList}><li><br></li></${childList}></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild, |
| endOffset: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li><${childList}><li>[list-item1</li></${childList}><li>}list-item2</li></${list}>`, |
| { |
| expectedInnerHTML: [ |
| `<${list}><li><${childList}><li>list-item2</li></${childList}></li></${list}>`, |
| `<${list}><li><${childList}><li>list-item2<br></li></${childList}></li></${list}>`, |
| ], |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} > li + li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li><${childList}><li>[list-item1</li></${childList}><li>list-item2]</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li><${childList}><li><br></li></${childList}></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} > li + li`).firstChild, |
| endOffset: gEditor.querySelector(`${list} > li + li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| } |
| |
| // When deleting the last list item in a sub list, only the list should |
| // be removed. This makes users feel like doing outdent. |
| for (let childList of ["ul", "ol"]) { |
| addPromiseTest( |
| `<${list}><li><${childList}><li>{}<br></li></${childList}></li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li><br></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`li`), |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`li`), |
| endOffset: 1, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li><${childList}><li>[list-item1]</li></${childList}></li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li><${childList}><li><br></li></${childList}></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`li li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`li li`).firstChild, |
| endOffset: gEditor.querySelector(`li li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>{<${childList}><li>list-item1</li></${childList}>}</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li><${childList}><li><br></li></${childList}></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`li li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`li li`).firstChild, |
| endOffset: gEditor.querySelector(`li li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li><${childList}><li>{}<br></li></${childList}></li><li>list-item2</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li><br></li><li>list-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`li`), |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`li`), |
| endOffset: 1, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1</li><li><${childList}><li>{}<br></li></${childList}></li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1</li><li><br></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`li + li`), |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`li + li`), |
| endOffset: 1, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| // Invalid cases. |
| addPromiseTest( |
| `<${list}><${childList}><li>{}<br></li></${childList}></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li><br></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list}`), |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list}`), |
| endOffset: 1, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><${childList}><li>[list-item1]</li></${childList}></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><${childList}><li><br></li></${childList}></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`li`).firstChild, |
| endOffset: gEditor.querySelector(`li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}>{<${childList}><li>list-item1</li></${childList}>}</${list}>`, |
| { |
| expectedInnerHTML: `<${list}><${childList}><li><br></li></${childList}></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`li`).firstChild, |
| endOffset: gEditor.querySelector(`li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><${childList}><li>{}<br></li></${childList}><li>list-item2</li></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li><br></li><li>list-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list}`), |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list}`), |
| endOffset: 1, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1</li><${childList}><li>{}<br></li></${childList}></${list}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1</li><li><br></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list}`), |
| startOffset: 1, |
| endContainer: gEditor.querySelector(`${list}`), |
| endOffset: 2, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| } |
| |
| // Joining same level list elements. |
| for (let otherList of ["ul", "ol"]) { |
| addPromiseTest( |
| `<${list}><li>[list-item1</li></${list}><${otherList}><li>}list-item2</li></${otherList}>`, |
| { |
| expectedInnerHTML: [ |
| `<${list}><li>list-item2</li></${list}>`, |
| `<${list}><li>list-item2<br></li></${list}>`, |
| ], |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>[list-item1</li></${list}><${otherList}><li>list-item2]</li></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li><br></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild, |
| endOffset: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1[</li></${list}><${otherList}><li>}list-item2</li></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li`).firstChild, |
| startOffset: gEditor.querySelector(`${list} > li`).firstChild.length, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>first line in list-item1<br>list-item1[</li></${list}><${otherList}><li>}list-item2</li></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li>first line in list-item1<br>list-item1list-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li > br`).nextSibling, |
| startOffset: gEditor.querySelector(`${list} > li > br`).nextSibling.length, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1[</li></${list}><${otherList}><li>}list-item2<br>second line in list-item2</li></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}><${otherList}><li>second line in list-item2</li></${otherList}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li`).firstChild, |
| startOffset: gEditor.querySelector(`${list} > li`).firstChild.length, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1</li><li>list-item2[</li></${list}><${otherList}><li>}list-item3</li></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1</li><li>list-item2list-item3</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li + li`).firstChild, |
| startOffset: gEditor.querySelector(`${list} > li + li`).firstChild.length, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1[</li></${list}><${otherList}><li>}list-item2</li><li>list-item3</li></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}><${otherList}><li>list-item3</li></${otherList}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li`).firstChild, |
| startOffset: gEditor.querySelector(`${list} > li`).firstChild.length, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| } |
| |
| // Joining nested left list and right list element. Move the content in first line from selection end in the right |
| // list item element into end of the left list item element. |
| for (let childList of ["ul", "ol"]) { |
| for (let otherList of ["ul", "ol"]) { |
| addPromiseTest( |
| `<${list}><li><${childList}><li>[list-item1</li></${childList}></li></${list}><${otherList}><li>}list-item2</li></${otherList}>`, |
| { |
| expectedInnerHTML: [ |
| `<${list}><li><${childList}><li>list-item2</li></${childList}></li></${list}>`, |
| `<${list}><li><${childList}><li>list-item2<br></li></${childList}></li></${list}>`, |
| ], |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild, |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li><${childList}><li>[list-item1</li></${childList}></li></${list}><${otherList}><li>list-item2]</li></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li><${childList}><li><br></li></${childList}></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild, |
| endOffset: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li><${childList}><li>list-item1[</li></${childList}></li></${list}><${otherList}><li>list-item2]</li></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li><${childList}><li>list-item1</li></${childList}></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild, |
| startOffset: gEditor.querySelector(`${list} > li > ${childList} > li`).firstChild.length, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild, |
| endOffset: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| // Invalid cases. |
| addPromiseTest( |
| `<${list}><${childList}><li>[list-item1</li></${childList}></${list}><${otherList}><li>}list-item2</li></${otherList}>`, |
| { |
| expectedInnerHTML: [ |
| `<${list}><${childList}><li>list-item2</li></${childList}></${list}>`, |
| `<${list}><${childList}><li>list-item2<br></li></${childList}></${list}>`, |
| ], |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild, |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><${childList}><li>[list-item1</li></${childList}></${list}><${otherList}><li>list-item2]</li></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><${childList}><li><br></li></${childList}></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild, |
| endOffset: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><${childList}><li>list-item1[</li></${childList}></${list}><${otherList}><li>list-item2]</li></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><${childList}><li>list-item1</li></${childList}></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > ${childList} > li`).firstChild, |
| startOffset: gEditor.querySelector(`${list} > ${childList} > li`).firstChild.length, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild, |
| endOffset: gEditor.querySelector(`${list} + ${otherList} > li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| } |
| } |
| |
| // Joining left list and nested right list element. Basically, the first line from the selection end should |
| // be moved into the end of the left list item element, but if all content in the left list is being deleted, |
| // keep the right list elements. |
| for (let childList of ["ul", "ol"]) { |
| for (let otherList of ["ul", "ol"]) { |
| addPromiseTest( |
| `<${list}><li>list-item1[</li></${list}><${otherList}><li><${childList}><li>}list-item2</li></${childList}></li></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li`).firstChild, |
| startOffset: gEditor.querySelector(`${list} > li`).firstChild.length, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li > ${childList} > li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>[list-item1</li></${list}><${otherList}><li><${childList}><li>}list-item2</li></${childList}></li></${otherList}>`, |
| { |
| expectedInnerHTML: [ |
| `<${otherList}><li><${childList}><li>list-item2</li></${childList}></li></${otherList}>`, |
| `<${otherList}><li><${childList}><li>list-item2<br></li></${childList}></li></${otherList}>`, |
| ], |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li > ${childList} > li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>[list-item1</li></${list}><${otherList}><li><${childList}><li>list-item2]</li></${childList}></li></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li><br></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li > ${childList} > li`).firstChild, |
| endOffset: gEditor.querySelector(`${list} + ${otherList} > li > ${childList} > li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1[</li></${list}><${otherList}><li><${childList}><li>}list-item2<br>second line of list-item2</li></${childList}></li></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}><${otherList}><li><${childList}><li>second line of list-item2</li></${childList}></li></${otherList}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li`).firstChild, |
| startOffset: gEditor.querySelector(`${list} > li`).firstChild.length, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > li > ${childList} > li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| // Invalid cases. |
| addPromiseTest( |
| `<${list}><li>list-item1[</li></${list}><${otherList}><${childList}><li>}list-item2</li></${childList}></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li`).firstChild, |
| startOffset: gEditor.querySelector(`${list} > li`).firstChild.length, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > ${childList} > li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>[list-item1</li></${list}><${otherList}><${childList}><li>}list-item2</li></${childList}></${otherList}>`, |
| { |
| expectedInnerHTML: [ |
| `<${otherList}><${childList}><li>list-item2</li></${childList}></${otherList}>`, |
| `<${otherList}><${childList}><li>list-item2<br></li></${childList}></${otherList}>`, |
| ], |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > ${childList} > li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>[list-item1</li></${list}><${otherList}><${childList}><li>list-item2]</li></${childList}></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li><br></li></${list}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li`).firstChild, |
| startOffset: 0, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > ${childList} > li`).firstChild, |
| endOffset: gEditor.querySelector(`${list} + ${otherList} > ${childList} > li`).firstChild.length, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| |
| addPromiseTest( |
| `<${list}><li>list-item1[</li></${list}><${otherList}><${childList}><li>}list-item2<br>second line of list-item2</li></${childList}></${otherList}>`, |
| { |
| expectedInnerHTML: `<${list}><li>list-item1list-item2</li></${list}><${otherList}><${childList}><li>second line of list-item2</li></${childList}></${otherList}>`, |
| expectedTargetRanges: () => { |
| return [ |
| { |
| startContainer: gEditor.querySelector(`${list} > li`).firstChild, |
| startOffset: gEditor.querySelector(`${list} > li`).firstChild.length, |
| endContainer: gEditor.querySelector(`${list} + ${otherList} > ${childList} > li`), |
| endOffset: 0, |
| }, |
| ]; |
| }, |
| expectInputEvent: true, |
| } |
| ); |
| } |
| } |
| |
| </script> |