Bug 1874684 - Part 17: Fix uninitialised variable warnings from clang-tidy. r=allstarschh
[gecko.git] / editor / libeditor / tests / test_contenteditable_focus.html
blob741a5b48bff6be639ec0e9660530e3533bceb8f7
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 is(
89 getSelection().rangeCount,
91 "There should be no selection range at start"
93 ok(!selCon.caretVisible, "The caret should not be visible in the document");
94 // Move focus to <input type="text"> in the primary editor
95 primaryEditor.querySelector("input[type=text]").focus();
96 is(
97 SpecialPowers.unwrap(fm.focusedElement),
98 primaryEditor.querySelector("input[type=text]"),
99 '<input type="text"> in the primary editor should get focus'
101 todo_is(
102 getSelection().rangeCount,
104 'There should be no selection range after calling focus() of <input type="text"> in the primary editor'
107 selCon.caretVisible,
108 'The caret should not be visible in the <input type="text"> in the primary editor'
110 })();
111 // Move focus to the editor
112 (function test_move_focus_from_child_input_to_parent_editor() {
113 primaryEditor.focus();
115 SpecialPowers.unwrap(fm.focusedElement),
116 primaryEditor,
117 `The editor should steal focus from <input type="text"> in the primary editor with calling its focus() (got ${
118 getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
122 getSelection().rangeCount,
124 "There should be one range after focus() of the editor is called"
126 const range = getSelection().getRangeAt(0);
128 range.collapsed,
129 "The selection range should be collapsed (immediately after calling focus() of the editor)"
132 range.startContainer,
133 primaryEditor.firstChild,
134 `The selection range should be in the first text node of the editor (immediately after calling focus() of the editor, got ${
135 getNodeDescription(range.startContainer)
139 selCon.caretVisible,
140 "The caret should be visible in the primary editor (immediately after calling focus() of the editor)"
142 })();
143 // Move focus to other editor
144 (function test_move_focus_from_editor_to_the_other_editor() {
145 otherEditor.focus();
147 SpecialPowers.unwrap(fm.focusedElement),
148 otherEditor,
149 `The other editor should steal focus from the editor (got ${
150 getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
154 getSelection().rangeCount,
156 "There should be one range after focus() of the other editor is called"
158 const range = getSelection().getRangeAt(0);
160 range.collapsed,
161 "The selection range should be collapsed (immediately after calling focus() of the other editor)"
164 range.startContainer,
165 otherEditor.firstChild,
166 `The selection range should be in the first text node of the editor (immediately after calling focus() of the other editor, got ${
167 getNodeDescription(range.startContainer)
171 selCon.caretVisible,
172 "The caret should be visible in the primary editor (immediately after calling focus() of the other editor)"
174 })();
175 // Move focus to <input type="text"> in the primary editor
176 (function test_move_focus_from_the_other_editor_to_input_in_the_editor() {
177 primaryEditor.querySelector("input[type=text]").focus();
179 SpecialPowers.unwrap(fm.focusedElement),
180 primaryEditor.querySelector("input[type=text]"),
181 `<input type="text"> in the primary editor should steal focus from the other editor (got ${
182 getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
183 }`);
185 getSelection().rangeCount,
187 'There should be one range after focus() of the <input type="text"> in the primary editor is called'
189 const range = getSelection().getRangeAt(0);
191 range.collapsed,
192 'The selection range should be collapsed (immediately after calling focus() of the <input type="text"> in the primary editor)'
194 // XXX maybe, the caret can stay on the other editor if it's better.
196 range.startContainer,
197 primaryEditor.firstChild,
198 `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 ${
199 getNodeDescription(range.startContainer)
203 selCon.caretVisible,
204 'The caret should be visible in the <input type="text"> (immediately after calling focus() of the <input type="text"> in the primary editor)'
206 })();
207 // Move focus to the other editor again
208 (function test_move_focus_from_the_other_editor_to_the_editor_with_Selection_API() {
209 otherEditor.focus();
211 SpecialPowers.unwrap(fm.focusedElement),
212 otherEditor,
213 `The other editor should steal focus from the <input type="text"> in the primary editor with its focus() (got ${
214 getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
217 // Set selection to the span element in the primary editor.
218 getSelection().collapse(spanInEditor.firstChild, 5);
220 getSelection().rangeCount,
222 "There should be one selection range after collapsing selection into the <span> in the primary editor when the other editor has focus"
225 SpecialPowers.unwrap(fm.focusedElement),
226 primaryEditor,
227 `The editor should steal focus from the other editor with Selection API (got ${
228 getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
232 selCon.caretVisible,
233 "The caret should be visible in the primary editor (immediately after moving focus with Selection API)"
235 })();
236 // Move focus to the editor
237 (function test_move_focus() {
238 primaryEditor.focus();
240 SpecialPowers.unwrap(fm.focusedElement),
241 primaryEditor,
242 "The editor should keep having focus (immediately after calling focus() of the editor when it has focus)"
245 getSelection().rangeCount,
247 "There should be one selection range in the primary editor (immediately after calling focus() of the editor when it has focus)"
249 const range = getSelection().getRangeAt(0);
251 range.collapsed,
252 "The selection range should be collapsed in the primary editor (immediately after calling focus() of the editor when it has focus)"
255 range.startOffset,
257 "The startOffset of the selection range shouldn't be changed (immediately after calling focus() of the editor when it has focus)"
260 range.startContainer.parentNode,
261 spanInEditor,
262 `The startContainer of the selection range shouldn't be changed (immediately after calling focus() of the editor when it has focus, got ${
263 getNodeDescription(range.startContainer)
264 })`);
266 selCon.caretVisible,
267 "The caret should be visible in the primary editor (immediately after calling focus() of the editor when it has focus)"
269 })();
271 // Move focus to each focusable element in the primary editor.
272 function test_move_focus_from_the_editor(aTargetElement, aFocusable, aCaretVisible) {
273 primaryEditor.focus();
275 SpecialPowers.unwrap(fm.focusedElement),
276 primaryEditor,
277 `The editor should have focus at preparing to move focus to ${
278 getNodeDescription(aTargetElement)
279 } (got ${
280 getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
281 }`);
282 aTargetElement.focus();
283 if (aFocusable) {
285 SpecialPowers.unwrap(fm.focusedElement),
286 aTargetElement,
288 getNodeDescription(aTargetElement)
289 } should get focus with calling its focus() (got ${
290 getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
293 } else {
295 SpecialPowers.unwrap(fm.focusedElement),
296 primaryEditor,
298 getNodeDescription(aTargetElement)
299 } should not take focus with calling its focus() (got ${
300 getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
305 selCon.caretVisible,
306 aCaretVisible,
307 `The caret ${
308 aCaretVisible ? "should" : "should not"
309 } visible after calling focus() of ${
310 getNodeDescription(aTargetElement)
314 test_move_focus_from_the_editor(primaryEditor.querySelector("input[type=text]"), true, true);
315 test_move_focus_from_the_editor(primaryEditor.querySelector("input[type=text][readonly]"), true, true);
316 // XXX shouldn't the caret become invisible?
317 test_move_focus_from_the_editor(primaryEditor.querySelector("input[type=button]"), true, true);
318 test_move_focus_from_the_editor(primaryEditor.querySelector("button"), true, true);
319 test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false]"), false, true);
320 test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > span"), false, true);
321 test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > input[type=text]"), true, true);
322 test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > input[type=text][readonly]"), true, true);
323 test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > input[type=button]"), true, false);
324 test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > button"), true, false);
325 test_move_focus_from_the_editor(spanInEditor, false, true);
326 test_move_focus_from_the_editor(document.querySelector("input[type=text]"), true, true);
327 test_move_focus_from_the_editor(document.querySelector("input[type=text][readonly]"), true, true);
328 test_move_focus_from_the_editor(document.querySelector("input[type=button]"), true, false);
329 test_move_focus_from_the_editor(document.querySelector("button"), true, false);
331 SimpleTest.finish();
333 </script>
334 </body>
335 </html>