| <!doctype html> |
| <meta charset=utf-8> |
| <meta name="variant" content="?div"> |
| <meta name="variant" content="?span"> |
| <title>initial selection on focus of contenteditable</title> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script>var testsJsLibraryOnly = true</script> |
| <script src="../../editing/include/tests.js"></script> |
| <body> |
| <script> |
| "use strict"; |
| |
| (function() { |
| const editingHostTagName = document.location.search.substr(1); |
| const editor = document.createElement(editingHostTagName); |
| editor.style.minHeight = "1em"; |
| editor.setAttribute("contenteditable", ""); |
| document.body.insertBefore(editor, document.body.firstChild); |
| editor.focus(); |
| editor.getBoundingClientRect(); |
| |
| const tests = [ |
| { description: "empty editor should set focus to start of it", |
| content: "{}", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to start of the text node", |
| content: "[]abc", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the <br> node", |
| content: "{}<br>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the first <br> node", |
| content: "{}<br><br>", |
| canTestInInlineEditingHost: true, |
| }, |
| |
| { description: "editor should set selection to start of the text node in the <p> node", |
| content: "<p>[]abc</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to start of the first visible character in the text node in the <p> node", |
| content: "<p> []abc</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to start of the text node in the <p> node because of preformatted white-space", |
| content: "<p style=\"white-space: pre\">[] abc</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to start of the text node in the <p> node because of preformatted line break", |
| content: "<p style=\"white-space: pre\">[]\nabc</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to before the <br> node in the <p> node", |
| content: "<p>{}<br></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to before the first <br> node in the <p> node", |
| content: "<p>{}<br><br></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| |
| { description: "editor should set selection to start of the text node in the <span> node", |
| content: "<span>[]abc</span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the <br> node in the <span> node", |
| content: "<span>{}<br></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the first <br> node in the <span> node", |
| content: "<span>{}<br><br></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| |
| { description: "editor should set selection to before the empty <span> node", |
| content: "{}<span></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the empty <b> node", |
| content: "{}<b></b>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the empty <i> node", |
| content: "{}<i></i>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the empty <u> node", |
| content: "{}<u></u>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the empty <s> node", |
| content: "{}<s></s>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the empty <code> node", |
| content: "{}<code></code>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the empty <a> node", |
| content: "{}<a href=\"foo.html\"></a>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the empty <foobar> node", |
| content: "{}<foobar></foobar>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the <input> node", |
| content: "{}<input>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the <img> node", |
| content: "{}<img alt=\"foo\">", |
| canTestInInlineEditingHost: true, |
| }, |
| |
| { description: "editor should set selection to start of the text node in the second <span> node", |
| content: "<span></span><span>[]abc</span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the <br> node in the second <span> node", |
| content: "<span></span><span>{}<br></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to start of the text node in the first <span> node #1", |
| content: "<span>[]abc</span><span>abc</span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to start of the text node in the first <span> node #2", |
| content: "<span>[]abc</span><span><br></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the <br> node in the first <span> node #1", |
| content: "<span>{}<br></span><span><br></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the <br> node in the first <span> node #2", |
| content: "<span>{}<br></span><span>abc</span>", |
| canTestInInlineEditingHost: true, |
| }, |
| |
| { description: "editor should set selection to start of the text node in the second <span> node since the text node in the first <span> node is only whitespaces", |
| content: "<span> </span><span>[]abc</span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the <br> node in the second <span> node since the text node in the first <span> node is only whitespaces", |
| content: "<span> </span><span>{}<br></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to start of the text node in the second <span> node even if there is a whitespace only text node before the first <span> node", |
| content: " <span></span><span>[]abc</span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should set selection to before the <br> node in the second <span> node even if there is a whitespace only text node before the first <span> node", |
| content: " <span></span><span>{}<br></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| |
| { description: "editor should set selection to start of the text node in the second <p> node following the empty <p> node", |
| content: "<p></p><p>[]abc</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to start of the text node in the second <p> node following another <p> node containing only a comment node", |
| content: "<p><!-- comment --></p><p>[]abc</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to before the <br> node in the second <p> node", |
| content: "<p></p><p>{}<br></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to start of the text node in the first <p> node #1", |
| content: "<p>[]abc</p><p>abc</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to start of the text node in the first <p> node #2", |
| content: "<p>[]abc</p><p><br></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to before the <br> node in the first <p> node #1", |
| content: "<p>{}<br></p><p><br></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to before the <br> node in the first <p> node #2", |
| content: "<p>{}<br></p><p>abc</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| |
| { description: "editor should set selection to start of the text node in the second <p> node since the text node in the first <p> node is only whitespaces", |
| content: "<p> </p><p>[]abc</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to start of the text node in the first <p> node whose white-spaces are preformatted", |
| content: "<p style=\"white-space: pre\">[] </p><p>abc</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to start of the text node in the first <p> node whose line breaks are preformatted", |
| content: "<p style=\"white-space: pre\">[]\n</p><p>abc</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to before the <br> node in the second <p> node since the text node in the first <p> node is only whitespaces", |
| content: "<p> </p><p>{}<br></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to start of the text node in the second <p> node even if there is a whitespace only text node before the first <p> node", |
| content: " <p></p><p>[]abc</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to before the <br> node in the second <p> node even if there is a whitespace only text node before the first <p> node", |
| content: " <p></p><p>{}<br></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| |
| { description: "editor should set selection to start of the text node in the <span> node in the second <p> node", |
| content: "<p><span></span></p><p><span>[]abc</span></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to before the <br> node in the <span> node in the second <p> node", |
| content: "<p><span></span></p><p><span>{}<br></span></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to start of the text node in the <span> node in the first <p> node #1", |
| content: "<p><span>[]abc</span></p><p><span>abc</span></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to start of the text node in the <span> node in the first <p> node #2", |
| content: "<p><span>[]abc</span></p><p><span><br></span></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to before the <br> node in the <span> node in the first <p> node #1", |
| content: "<p><span>{}<br></span></p><p><span><br></span></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should set selection to before the <br> node in the <span> node in the first <p> node #2", |
| content: "<p><span>{}<br></span></p><p><span>abc</span></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| |
| { description: "editor should collapse selection before the non-editable <span> node", |
| content: "{}<span contenteditable=\"false\"></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection before the non-editable <span> node even if it has a text node", |
| content: "{}<span contenteditable=\"false\">abc</span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection before the non-editable <span> node even if it has a <br> node", |
| content: "{}<span contenteditable=\"false\"><br></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| |
| { description: "editor should collapse selection before the non-editable empty <span> node followed by a text node", |
| content: "{}<span contenteditable=\"false\"></span><span>abc</span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection before the non-editable <span> node having a text node and followed by another text node", |
| content: "{}<span contenteditable=\"false\">abc</span><span>def</span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection before the non-editable <span> node having a <br> node and followed by a text node", |
| content: "{}<span contenteditable=\"false\"><br></span><span>abc</span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection before the non-editable empty <span> node followed by a <br> node", |
| content: "{}<span contenteditable=\"false\"></span><span><br></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection before the non-editable <span> node having text node and followed by a <br> node", |
| content: "{}<span contenteditable=\"false\">abc</span><span><br></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection before the non-editable <span> node having a <br> node and followed by another <br> node", |
| content: "{}<span contenteditable=\"false\"><br></span><span><br></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| |
| { description: "editor should collapse selection before the non-editable empty <p> node followed by a text node", |
| content: "{}<p contenteditable=\"false\"></p><p>abc</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection before the non-editable <p> node having a text node and followed by another text node", |
| content: "{}<p contenteditable=\"false\">abc</p><p>def</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection before the non-editable <p> node having a <br> node and followed by a text node", |
| content: "{}<p contenteditable=\"false\"><br></p><p>abc</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection before the non-editable empty <p> node followed by a <br> node", |
| content: "{}<p contenteditable=\"false\"></p><p><br></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection before the non-editable <p> node having text node and followed by a <br> node", |
| content: "{}<p contenteditable=\"false\">abc</p><p><br></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection before the non-editable <p> node having a <br> node and followed by another <br> node", |
| content: "{}<p contenteditable=\"false\"><br></p><p><br></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| |
| { description: "editor should collapse selection to start of itself when there is only empty inline elements before the non-editable node before first editable text node", |
| content: "{}<span></span><span contenteditable=\"false\"></span><span>abc</span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection to start of itself when there is only empty inline elements before the non-editable node having a text node before first editable text node", |
| content: "{}<span></span><span contenteditable=\"false\">abc</span><span>def</span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection to start of itself when there is only empty inline elements before the non-editable node having a <br> node before first editable text node", |
| content: "{}<span></span><span contenteditable=\"false\"><br></span><span>abc</span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection to start of itself when there is only empty inline elements before the non-editable node before first editable <br> node", |
| content: "{}<span></span><span contenteditable=\"false\"></span><span><br></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection to start of itself when there is only empty inline elements before the non-editable node having a text node before first editable <br> node", |
| content: "{}<span></span><span contenteditable=\"false\">abc</span><span><br></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection to start of itself when there is only empty inline elements before the non-editable node having a <br> node before first editable <br> node", |
| content: "{}<span></span><span contenteditable=\"false\"><br></span><span><br></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| |
| { description: "editor should collapse selection to start of the first dive element when there is only empty inline elements before the non-editable node before first editable text node", |
| content: "<div>{}<span></span><span contenteditable=\"false\"></span><span>abc</span></div>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection to start of the first dive element when there is only empty inline elements before the non-editable node having a text node before first editable text node", |
| content: "<div>{}<span></span><span contenteditable=\"false\">abc</span><span>def</span></div>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection to start of the first dive element when there is only empty inline elements before the non-editable node having a <br> node before first editable text node", |
| content: "<div>{}<span></span><span contenteditable=\"false\"><br></span><span>abc</span></div>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection to start of the first dive element when there is only empty inline elements before the non-editable node before first editable <br> node", |
| content: "<div>{}<span></span><span contenteditable=\"false\"></span><span><br></span></div>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection to start of the first dive element when there is only empty inline elements before the non-editable node having a text node before first editable <br> node", |
| content: "<div>{}<span></span><span contenteditable=\"false\">abc</span><span><br></span></div>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection to start of the first dive element when there is only empty inline elements before the non-editable node having a <br> node before first editable <br> node", |
| content: "<div>{}<span></span><span contenteditable=\"false\"><br></span><span><br></span></div>", |
| canTestInInlineEditingHost: false, |
| }, |
| |
| { description: "editor should collapse selection to the first editable text node in the first <span> node even if followed by a non-editable node", |
| content: "<span>[]abc</span><span contenteditable=\"false\"></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection to the first editable text node in the first <span> node even if followed by a non-editable node having another text node", |
| content: "<span>[]abc</span><span contenteditable=\"false\">def</span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection to the first editable text node in the first <span> node even if followed by a non-editable node having a <br> node", |
| content: "<span>[]abc</span><span contenteditable=\"false\"><br></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection to the first editable <br> node in the first <span> node even if followed by a non-editable node", |
| content: "<span>{}<br></span><span contenteditable=\"false\"></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection to the first editable <br> node in the first <span> node even if followed by a non-editable node having a text node", |
| content: "<span>{}<br></span><span contenteditable=\"false\">abc</span>", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection to the first editable <br> node in the first <span> node even if followed by a non-editable node having a <br> node", |
| content: "<span>{}<br></span><span contenteditable=\"false\"><br></span>", |
| canTestInInlineEditingHost: true, |
| }, |
| |
| { description: "editor should collapse selection to the first editable text node in the first <p> node even if followed by a non-editable node", |
| content: "<p>[]abc</p><p contenteditable=\"false\"></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection to the first editable text node in the first <p> node even if followed by a non-editable node having another text node", |
| content: "<p>[]abc</p><p contenteditable=\"false\">def</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection to the first editable text node in the first <p> node even if followed by a non-editable node having a <br> node", |
| content: "<p>[]abc</p><p contenteditable=\"false\"><br></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection to the first editable <br> node in the first <p> node even if followed by a non-editable node", |
| content: "<p>{}<br></p><p contenteditable=\"false\"></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection to the first editable <br> node in the first <p> node even if followed by a non-editable node having a text node", |
| content: "<p>{}<br></p><p contenteditable=\"false\">abc</p>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection to the first editable <br> node in the first <p> node even if followed by a non-editable node having a <br> node", |
| content: "<p>{}<br></p><p contenteditable=\"false\"><br></p>", |
| canTestInInlineEditingHost: false, |
| }, |
| |
| { description: "editor should collapse selection to start of itself if first content is an input element", |
| content: "{}<input>abc", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection to start of itself if first content is an hr element", |
| content: "{}<hr>abc", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection to start of itself if first content is an textarea element", |
| content: "{}<textarea>abc</textarea>def", |
| canTestInInlineEditingHost: true, |
| }, |
| { description: "editor should collapse selection to the input element", |
| content: "<div>{}<input>abc</div>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection to the hr element", |
| content: "<div>{}<hr>abc</div>", |
| canTestInInlineEditingHost: false, |
| }, |
| { description: "editor should collapse selection to the textarea element", |
| content: "<div>{}<textarea>abc</textarea>def</div>", |
| canTestInInlineEditingHost: false, |
| }, |
| ]; |
| |
| const isInlineEditingHost = editingHostTagName == "span"; |
| |
| const selection = document.getSelection(); |
| for (const testData of tests) { |
| if (isInlineEditingHost && !testData.canTestInInlineEditingHost) { |
| continue; |
| } |
| test(function() { |
| editor.blur(); |
| selection.removeAllRanges(); |
| editor.innerHTML = testData.content.replace(/[{}\[\]]/g, ""); |
| editor.focus(); |
| editor.getBoundingClientRect(); |
| |
| assert_equals(selection.rangeCount, 1, "Only one caret should be in the editor"); |
| if (selection.rangeCount) { |
| addBrackets(selection.getRangeAt(0)); |
| assert_equals(editor.innerHTML, testData.content); |
| } |
| }, testData.description); |
| } |
| |
| test(function() { |
| // Check if selection is initialized after temporarily blurred. |
| editor.innerHTML = |
| `<${editingHostTagName}>abc</${editingHostTagName}><${editingHostTagName}>def</${editingHostTagName}>`; |
| editor.focus(); |
| // Move selection to the second paragraph. |
| selection.collapse(editor.firstChild.nextSibling.firstChild); |
| // Reset focus. |
| editor.blur(); |
| editor.focus(); |
| // Then, selection should still be in the second paragraph. |
| assert_equals(selection.rangeCount, 1, "Only one caret should be in the editor"); |
| if (selection.rangeCount) { |
| addBrackets(selection.getRangeAt(0)); |
| assert_equals( |
| editor.innerHTML, |
| `<${editingHostTagName}>abc</${editingHostTagName}><${editingHostTagName}>[]def</${editingHostTagName}>` |
| ); |
| } |
| }, "editor shouldn't reset selection when it gets focus again"); |
| })(); |
| </script> |