Bug 1772588 [wpt PR 34302] - [wpt] Add test for block-in-inline offsetParent., a...
[gecko.git] / editor / libeditor / tests / test_contenteditable_focus.html
blobfc72e68539d329fb62cdea7c40da05dc910a919b
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title>Test for contenteditable focus</title>
6 <script src="/tests/SimpleTest/SimpleTest.js"></script>
7 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
8 </head>
9 <body>
10 <div id="display">
11 First text in this document.<br>
12 <input id="inputText" type="text"><br>
13 <input id="inputTextReadonly" type="text" readonly><br>
14 <input id="inputButton" type="button" value="input[type=button]"><br>
15 <button id="button">button</button><br>
16 <div id="primaryEditor" contenteditable="true">
17 editable contents.<br>
18 <input id="inputTextInEditor" type="text"><br>
19 <input id="inputTextReadonlyInEditor" type="text" readonly><br>
20 <input id="inputButtonInEditor" type="button" value="input[type=button]"><br>
21 <button id="buttonInEditor">button</button><br>
22 <div id="noeditableInEditor" contenteditable="false">
23 <span id="spanInNoneditableInEditor">span element in noneditable in editor</span><br>
24 <input id="inputTextInNoneditableInEditor" type="text"><br>
25 <input id="inputTextReadonlyInNoneditableInEditor" type="text" readonly><br>
26 <input id="inputButtonInNoneditableInEditor" type="button" value="input[type=button]"><br>
27 <button id="buttonInNoneditableInEditor">button</button><br>
28 </div>
29 <span id="spanInEditor">span element in editor</span><br>
30 </div>
31 <div id="otherEditor" contenteditable="true">
32 other editor.
33 </div>
34 </div>
35 <div id="content" style="display: none">
37 </div>
38 <pre id="test">
39 </pre>
41 <script>
42 "use strict";
44 SimpleTest.waitForExplicitFinish();
45 SimpleTest.waitForFocus(() => {
46 function getNodeDescription(aNode) {
47 if (aNode === undefined) {
48 return "undefined";
50 if (aNode === null) {
51 return "null";
53 switch (aNode.nodeType) {
54 case Node.TEXT_NODE:
55 return `${aNode.nodeName}, "${aNode.data.replace(/\n/g, "\\n")}"`;
56 case Node.ELEMENT_NODE:
57 return `<${aNode.tagName.toLowerCase()}${
58 aNode.getAttribute("id") !== null
59 ? ` id="${aNode.getAttribute("id")}"`
60 : ""
61 }${
62 aNode.getAttribute("readonly") !== null
63 ? " readonly"
64 : ""
65 }${
66 aNode.getAttribute("type") !== null
67 ? ` type="${aNode.getAttribute("type")}"`
68 : ""
69 }>`;
71 return aNode.nodeName;
74 const fm = SpecialPowers.Services.focus;
75 // XXX using selCon for checking the visibility of the caret, however,
76 // selCon is shared in document, cannot get the element of owner of the
77 // caret from javascript?
78 const selCon = SpecialPowers.wrap(window).docShell.
79 QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor).
80 getInterface(SpecialPowers.Ci.nsISelectionDisplay).
81 QueryInterface(SpecialPowers.Ci.nsISelectionController);
83 const primaryEditor = document.getElementById("primaryEditor");
84 const spanInEditor = document.getElementById("spanInEditor");
85 const otherEditor = document.getElementById("otherEditor");
87 (function test_initial_state_on_load() {
88 // XXX if there is a contenteditable element, HTML editor sets dom selection
89 // to first editable node, but this makes inconsistency with normal document
90 // behavior.
91 todo_is(
92 getSelection().rangeCount,
94 "There should be no selection range at start"
96 ok(!selCon.caretVisible, "The caret should not be visible in the document");
97 // Move focus to <input type="text"> in the primary editor
98 primaryEditor.querySelector("input[type=text]").focus();
99 is(
100 SpecialPowers.unwrap(fm.focusedElement),
101 primaryEditor.querySelector("input[type=text]"),
102 '<input type="text"> in the primary editor should get focus'
104 todo_is(
105 getSelection().rangeCount,
107 'There should be no selection range after calling focus() of <input type="text"> in the primary editor'
110 selCon.caretVisible,
111 'The caret should not be visible in the <input type="text"> in the primary editor'
113 })();
114 // Move focus to the editor
115 (function test_move_focus_from_child_input_to_parent_editor() {
116 primaryEditor.focus();
118 SpecialPowers.unwrap(fm.focusedElement),
119 primaryEditor,
120 `The editor should steal focus from <input type="text"> in the primary editor with calling its focus() (got ${
121 getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
125 getSelection().rangeCount,
127 "There should be one range after focus() of the editor is called"
129 const range = getSelection().getRangeAt(0);
131 range.collapsed,
132 "The selection range should be collapsed (immediately after calling focus() of the editor)"
135 range.startContainer,
136 primaryEditor.firstChild,
137 `The selection range should be in the first text node of the editor (immediately after calling focus() of the editor, got ${
138 getNodeDescription(range.startContainer)
142 selCon.caretVisible,
143 "The caret should be visible in the primary editor (immediately after calling focus() of the editor)"
145 })();
146 // Move focus to other editor
147 (function test_move_focus_from_editor_to_the_other_editor() {
148 otherEditor.focus();
150 SpecialPowers.unwrap(fm.focusedElement),
151 otherEditor,
152 `The other editor should steal focus from the editor (got ${
153 getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
157 getSelection().rangeCount,
159 "There should be one range after focus() of the other editor is called"
161 const range = getSelection().getRangeAt(0);
163 range.collapsed,
164 "The selection range should be collapsed (immediately after calling focus() of the other editor)"
167 range.startContainer,
168 otherEditor.firstChild,
169 `The selection range should be in the first text node of the editor (immediately after calling focus() of the other editor, got ${
170 getNodeDescription(range.startContainer)
174 selCon.caretVisible,
175 "The caret should be visible in the primary editor (immediately after calling focus() of the other editor)"
177 })();
178 // Move focus to <input type="text"> in the primary editor
179 (function test_move_focus_from_the_other_editor_to_input_in_the_editor() {
180 primaryEditor.querySelector("input[type=text]").focus();
182 SpecialPowers.unwrap(fm.focusedElement),
183 primaryEditor.querySelector("input[type=text]"),
184 `<input type="text"> in the primary editor should steal focus from the other editor (got ${
185 getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
186 }`);
188 getSelection().rangeCount,
190 'There should be one range after focus() of the <input type="text"> in the primary editor is called'
192 const range = getSelection().getRangeAt(0);
194 range.collapsed,
195 'The selection range should be collapsed (immediately after calling focus() of the <input type="text"> in the primary editor)'
197 // XXX maybe, the caret can stay on the other editor if it's better.
199 range.startContainer,
200 primaryEditor.firstChild,
201 `The selection range should be in the first text node of the editor (immediately after calling focus() of the <input type="text"> in the primary editor, got ${
202 getNodeDescription(range.startContainer)
206 selCon.caretVisible,
207 'The caret should be visible in the <input type="text"> (immediately after calling focus() of the <input type="text"> in the primary editor)'
209 })();
210 // Move focus to the other editor again
211 (function test_move_focus_from_the_other_editor_to_the_editor_with_Selection_API() {
212 otherEditor.focus();
214 SpecialPowers.unwrap(fm.focusedElement),
215 otherEditor,
216 `The other editor should steal focus from the <input type="text"> in the primary editor with its focus() (got ${
217 getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
220 // Set selection to the span element in the primary editor.
221 getSelection().collapse(spanInEditor.firstChild, 5);
223 getSelection().rangeCount,
225 "There should be one selection range after collapsing selection into the <span> in the primary editor when the other editor has focus"
228 SpecialPowers.unwrap(fm.focusedElement),
229 primaryEditor,
230 `The editor should steal focus from the other editor with Selection API (got ${
231 getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
235 selCon.caretVisible,
236 "The caret should be visible in the primary editor (immediately after moving focus with Selection API)"
238 })();
239 // Move focus to the editor
240 (function test_move_focus() {
241 primaryEditor.focus();
243 SpecialPowers.unwrap(fm.focusedElement),
244 primaryEditor,
245 "The editor should keep having focus (immediately after calling focus() of the editor when it has focus)"
248 getSelection().rangeCount,
250 "There should be one selection range in the primary editor (immediately after calling focus() of the editor when it has focus)"
252 const range = getSelection().getRangeAt(0);
254 range.collapsed,
255 "The selection range should be collapsed in the primary editor (immediately after calling focus() of the editor when it has focus)"
258 range.startOffset,
260 "The startOffset of the selection range shouldn't be changed (immediately after calling focus() of the editor when it has focus)"
263 range.startContainer.parentNode,
264 spanInEditor,
265 `The startContainer of the selection range shouldn't be changed (immediately after calling focus() of the editor when it has focus, got ${
266 getNodeDescription(range.startContainer)
267 })`);
269 selCon.caretVisible,
270 "The caret should be visible in the primary editor (immediately after calling focus() of the editor when it has focus)"
272 })();
274 // Move focus to each focusable element in the primary editor.
275 function test_move_focus_from_the_editor(aTargetElement, aFocusable, aCaretVisible) {
276 primaryEditor.focus();
278 SpecialPowers.unwrap(fm.focusedElement),
279 primaryEditor,
280 `The editor should have focus at preparing to move focus to ${
281 getNodeDescription(aTargetElement)
282 } (got ${
283 getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
284 }`);
285 aTargetElement.focus();
286 if (aFocusable) {
288 SpecialPowers.unwrap(fm.focusedElement),
289 aTargetElement,
291 getNodeDescription(aTargetElement)
292 } should get focus with calling its focus() (got ${
293 getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
296 } else {
298 SpecialPowers.unwrap(fm.focusedElement),
299 primaryEditor,
301 getNodeDescription(aTargetElement)
302 } should not take focus with calling its focus() (got ${
303 getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
308 selCon.caretVisible,
309 aCaretVisible,
310 `The caret ${
311 aCaretVisible ? "should" : "should not"
312 } visible after calling focus() of ${
313 getNodeDescription(aTargetElement)
317 test_move_focus_from_the_editor(primaryEditor.querySelector("input[type=text]"), true, true);
318 test_move_focus_from_the_editor(primaryEditor.querySelector("input[type=text][readonly]"), true, true);
319 // XXX shouldn't the caret become invisible?
320 test_move_focus_from_the_editor(primaryEditor.querySelector("input[type=button]"), true, true);
321 test_move_focus_from_the_editor(primaryEditor.querySelector("button"), true, true);
322 test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false]"), false, true);
323 test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > span"), false, true);
324 test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > input[type=text]"), true, true);
325 test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > input[type=text][readonly]"), true, true);
326 test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > input[type=button]"), true, false);
327 test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > button"), true, false);
328 test_move_focus_from_the_editor(spanInEditor, false, true);
329 test_move_focus_from_the_editor(document.querySelector("input[type=text]"), true, true);
330 test_move_focus_from_the_editor(document.querySelector("input[type=text][readonly]"), true, true);
331 test_move_focus_from_the_editor(document.querySelector("input[type=button]"), true, false);
332 test_move_focus_from_the_editor(document.querySelector("button"), true, false);
334 SimpleTest.finish();
336 </script>
337 </body>
338 </html>