| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <title>Selection.modify() inside contenteditable</title> | |
| <script src="/resources/testharness.js"></script> | |
| <script src="/resources/testharnessreport.js"></script> | |
| <div contenteditable id="host">Editable</div> | |
| <div>Non-editable</div> | |
| <div id="inlinehosts"> | |
| Prefix: <span contenteditable title="inline">Editable</span>: Suffix<br> | |
| Prefix: <span contenteditable style="display:inline-block;" title="inline-block">Editable</span>: Suffix<br> | |
| <span contenteditable title="suffix only">Editable</span>: Suffix<br> | |
| Prefix: <span contenteditable title="prefix only">Editable</span><br> | |
| <span contenteditable title="standalone">Editable</span><br> | |
| Prefix: <span contenteditable title="inline linebreak">Edit<br>able</span>: Suffix<br> | |
| Prefix: <span contenteditable style="display:inline-block;" title="inline-block linebreak">Edit<br>able</span>: | |
| Suffix<br> | |
| </div> | |
| <script> | |
| /** @param {Node} parent */ | |
| function* textNodeEntries(parent) { | |
| for (const [i, node] of parent.childNodes.entries()) { | |
| if (node.nodeType === Node.TEXT_NODE) { | |
| yield [i, node]; | |
| } | |
| } | |
| } | |
| const selection = getSelection(); | |
| test(() => { | |
| selection.collapse(host); | |
| selection.modify('extend', 'forward', 'word'); | |
| selection.modify('extend', 'forward', 'word'); | |
| assert_equals(selection.focusNode.parentElement, host); | |
| }, "Selection.modify() must not select outside of the host"); | |
| /** @type {NodeListOf<HTMLElement>} */ | |
| const hosts = inlinehosts.querySelectorAll("span[contenteditable]"); | |
| for (const host of hosts) { | |
| test(() => { | |
| for (const [i, text] of textNodeEntries(host)) { | |
| selection.collapse(text, 1); | |
| selection.modify("move", "forward", "lineboundary"); | |
| if (selection.focusNode === host) { | |
| assert_equals(selection.focusOffset, i + 1, "focusOffset should be after the text node"); | |
| } else { | |
| assert_equals(selection.focusNode, text, "focusNode should be the text node"); | |
| assert_equals(selection.focusOffset, text.textContent.length, "focusOffset should be the length of the text node"); | |
| } | |
| } | |
| }, `Selection.modify('move', 'forward', 'lineboundary') must be within the inline editing host: ${host.title}`); | |
| test(() => { | |
| for (const [i, text] of textNodeEntries(host)) { | |
| selection.collapse(text, 1); | |
| selection.modify("move", "backward", "lineboundary"); | |
| assert_equals(selection.focusNode, text, "focusNode should be the text node"); | |
| assert_equals(selection.focusOffset, 0, "focusOffset should be 0"); | |
| } | |
| }, `Selection.modify('move', 'backward', 'lineboundary') must be within the inline editing host: ${host.title}`); | |
| } | |
| </script> |