3 <title>Test for IME state controling and focus moving for iframes
</title>
4 <script type=
"text/javascript"
5 src=
"chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
6 <link rel=
"stylesheet" type=
"text/css"
7 href=
"chrome://mochikit/content/tests/SimpleTest/test.css" />
8 <style type=
"text/css">
15 <body onunload=
"onUnload();">
17 <!-- Use input[readonly] because it isn't affected by the partial focus
19 <input id=
"prev" readonly
><br>
20 <iframe id=
"iframe_not_editable"
21 src=
"data:text/html,<html><body><input id='editor'></body></html>"></iframe><br>
23 <!-- Testing IME state and focus movement, the anchor elements cannot get focus -->
24 <iframe id=
"iframe_html"
25 src=
"data:text/html,<html id='editor' contenteditable='true'><body><a href='about:blank'>about:blank;</a></body></html>"></iframe><br>
26 <iframe id=
"iframe_designMode"
27 src=
"data:text/html,<body id='editor' onload='document.designMode="on";'><a href='about:blank'>about:blank;</a></body>"></iframe><br>
28 <iframe id=
"iframe_body"
29 src=
"data:text/html,<body id='editor' contenteditable='true'><a href='about:blank'>about:blank;</a></body>"></iframe><br>
31 src=
"data:text/html,<body><p id='editor' contenteditable='true'><a href='about:blank'>about:blank;</a></p></body>"></iframe><br>
33 <input id=
"next" readonly
><br>
35 <script class=
"testbody" type=
"application/javascript">
37 window.opener.wrappedJSObject.SimpleTest.waitForFocus(runTests, window);
39 function ok(aCondition, aMessage)
41 window.opener.wrappedJSObject.SimpleTest.ok(aCondition, aMessage);
44 function is(aLeft, aRight, aMessage)
46 window.opener.wrappedJSObject.SimpleTest.is(aLeft, aRight, aMessage);
51 window.opener.wrappedJSObject.onFinish();
54 var gFocusObservingElement = null;
55 var gBlurObservingElement = null;
57 function onFocus(aEvent)
59 if (aEvent.target != gFocusObservingElement) {
62 ok(gFocusObservingElement.willFocus,
63 "focus event is fired on unexpected element");
64 gFocusObservingElement.willFocus = false;
67 function onBlur(aEvent)
69 if (aEvent.target != gBlurObservingElement) {
72 ok(gBlurObservingElement.willBlur,
73 "blur event is fired on unexpected element");
74 gBlurObservingElement.willBlur = false;
77 function observeFocusBlur(aNextFocusedNode, aWillFireFocusEvent,
78 aNextBlurredNode, aWillFireBlurEvent)
80 if (gFocusObservingElement) {
81 if (gFocusObservingElement.willFocus) {
82 ok(false,
"focus event was never fired on " + gFocusObservingElement);
84 gFocusObservingElement.removeEventListener(
"focus", onFocus, true);
85 gFocusObservingElement.willFocus = NaN;
86 gFocusObservingElement = null;
88 if (gBlurObservingElement) {
89 if (gBlurObservingElement.willBlur) {
90 ok(false,
"blur event was never fired on " + gBlurObservingElement);
92 gBlurObservingElement.removeEventListener(
"blur", onBlur, true);
93 gBlurObservingElement.willBlur = NaN;
94 gBlurObservingElement = null;
96 if (aNextFocusedNode) {
97 gFocusObservingElement = aNextFocusedNode;
98 gFocusObservingElement.willFocus = aWillFireFocusEvent;
99 gFocusObservingElement.addEventListener(
"focus", onFocus, true);
101 if (aNextBlurredNode) {
102 gBlurObservingElement = aNextBlurredNode;
103 gBlurObservingElement.willBlur = aWillFireBlurEvent;
104 gBlurObservingElement.addEventListener(
"blur", onBlur, true);
111 window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
112 .getInterface(Components.interfaces.nsIDOMWindowUtils);
114 Components.classes[
"@mozilla.org/focus-manager;1"]
115 .getService(Components.interfaces.nsIFocusManager);
117 var iframe, editor, root, input;
118 var prev = document.getElementById(
"prev");
119 var next = document.getElementById(
"next");
120 var html = document.documentElement;
122 function resetFocusToInput(aDescription)
124 observeFocusBlur(null, false, null, false);
126 is(fm.focusedElement, prev,
127 "input#prev[readonly] element didn't get focus: " + aDescription);
128 is(utils.IMEStatus, utils.IME_STATUS_DISABLED,
129 "IME enabled on input#prev[readonly]: " + aDescription);
132 function resetFocusToParentHTML(aDescription)
134 observeFocusBlur(null, false, null, false);
136 is(fm.focusedElement, html,
137 "Parent html element didn't get focus: " + aDescription);
138 is(utils.IMEStatus, utils.IME_STATUS_DISABLED,
139 "IME enabled on parent html element: " + aDescription);
142 function testTabKey(aForward,
143 aNextFocusedNode, aWillFireFocusEvent,
144 aNextBlurredNode, aWillFireBlurEvent,
145 aIMEShouldBeEnabled, aTestingCaseDescription)
147 observeFocusBlur(aNextFocusedNode, aWillFireFocusEvent,
148 aNextBlurredNode, aWillFireBlurEvent);
149 synthesizeKey(
"VK_TAB", { shiftKey: !aForward });
150 var description =
"Tab key test: ";
152 description =
"Shift-" + description;
154 description += aTestingCaseDescription +
": ";
155 is(fm.focusedElement, aNextFocusedNode,
156 description +
"didn't move focus as expected");
158 aIMEShouldBeEnabled ?
159 utils.IME_STATUS_ENABLED : utils.IME_STATUS_DISABLED,
160 description +
"didn't set IME state as expected");
163 function testMouseClick(aNextFocusedNode, aWillFireFocusEvent,
164 aWillAllNodeLostFocus,
165 aNextBlurredNode, aWillFireBlurEvent,
166 aIMEShouldBeEnabled, aTestingCaseDescription)
168 observeFocusBlur(aNextFocusedNode, aWillFireFocusEvent,
169 aNextBlurredNode, aWillFireBlurEvent);
170 // We're relying on layout inside the iframe being up to date, so make it so
171 iframe.contentDocument.documentElement.getBoundingClientRect();
172 synthesizeMouse(iframe,
10,
80, { });
173 var description =
"Click test: " + aTestingCaseDescription +
": ";
174 is(fm.focusedElement, !aWillAllNodeLostFocus ? aNextFocusedNode : null,
175 description +
"didn't move focus as expected");
177 aIMEShouldBeEnabled ?
178 utils.IME_STATUS_ENABLED : utils.IME_STATUS_DISABLED,
179 description +
"didn't set IME state as expected");
182 function testOnEditorFlagChange(aDescription, aIsInDesignMode)
185 Components.interfaces.nsIPlaintextEditor.eEditorReadonlyMask;
186 var description =
"testOnEditorFlagChange: " + aDescription;
187 resetFocusToParentHTML(description);
189 iframe.contentWindow.
190 QueryInterface(Components.interfaces.nsIInterfaceRequestor).
191 getInterface(Components.interfaces.nsIWebNavigation).
192 QueryInterface(Components.interfaces.nsIDocShell).editor;
193 var e = aIsInDesignMode ? root : editor;
195 is(fm.focusedElement, e,
196 description +
": focus() of editor didn't move focus as expected");
197 is(utils.IMEStatus, utils.IME_STATUS_ENABLED,
198 description +
": IME isn't enabled when the editor gets focus");
199 var flags = htmlEditor.flags;
200 htmlEditor.flags |= kReadonly;
201 is(fm.focusedElement, e,
202 description +
": when editor becomes readonly, focus moved unexpectedly");
203 is(utils.IMEStatus, utils.IME_STATUS_DISABLED,
204 description +
": when editor becomes readonly, IME is still enabled");
205 htmlEditor.flags = flags;
206 is(fm.focusedElement, e,
207 description +
": when editor becomes read-write, focus moved unexpectedly");
208 is(utils.IMEStatus, utils.IME_STATUS_ENABLED,
209 description +
": when editor becomes read-write, IME is still disabled");
213 document.getElementById(
"iframe_not_editable").style.display =
"none";
214 document.getElementById(
"iframe_html").style.display =
"none";
215 document.getElementById(
"iframe_designMode").style.display =
"none";
216 document.getElementById(
"iframe_body").style.display =
"none";
217 document.getElementById(
"iframe_p").style.display =
"none";
219 // non editable HTML element and input element can get focus.
220 iframe = document.getElementById(
"iframe_not_editable");
221 iframe.style.display =
"inline";
222 editor = iframe.contentDocument.getElementById(
"editor");
223 root = iframe.contentDocument.documentElement;
224 resetFocusToInput(
"initializing for iframe_not_editable");
226 testTabKey(true, root, false, prev, true,
227 false,
"input#prev[readonly] -> html");
228 testTabKey(true, editor, true, root, false,
229 true,
"html -> input in the subdoc");
230 testTabKey(true, next, true, editor, true,
231 false,
"input in the subdoc -> input#next[readonly]");
232 testTabKey(false, editor, true, next, true,
233 true,
"input#next[readonly] -> input in the subdoc");
234 testTabKey(false, root, false, editor, true,
235 false,
"input in the subdoc -> html");
236 testTabKey(false, prev, true, root, false,
237 false,
"html -> input#next[readonly]");
239 iframe.style.display =
"none";
241 // HTML element (of course, it's root) must enables IME.
242 iframe = document.getElementById(
"iframe_html");
243 iframe.style.display =
"inline";
244 editor = iframe.contentDocument.getElementById(
"editor");
245 root = iframe.contentDocument.documentElement;
246 resetFocusToInput(
"initializing for iframe_html");
248 testTabKey(true, editor, true, prev, true,
249 true,
"input#prev[readonly] -> html[contentediable=true]");
250 testTabKey(true, next, true, editor, true,
251 false,
"html[contentediable=true] -> input#next[readonly]");
252 testTabKey(false, editor, true, next, true,
253 true,
"input#next[readonly] -> html[contentediable=true]");
254 testTabKey(false, prev, true, editor, true,
255 false,
"html[contenteditable=true] -> input[readonly]");
257 prev.style.display =
"none";
258 resetFocusToParentHTML(
"testing iframe_html");
259 testTabKey(true, editor, true, html, false,
260 true,
"html of parent -> html[contentediable=true]");
261 testTabKey(false, html, false, editor, true,
262 false,
"html[contenteditable=true] -> html of parent");
263 prev.style.display =
"inline";
264 resetFocusToInput(
"after parent html <-> html[contenteditable=true]");
266 testMouseClick(editor, true, false, prev, true, true,
"iframe_html");
268 testOnEditorFlagChange(
"html[contentediable=true]", false);
270 iframe.style.display =
"none";
272 // designMode should behave like
<html contenteditable=
"true"></html>
273 // but focus/blur events shouldn't be fired on its root element because
274 // any elements shouldn't be focused state in designMode.
275 iframe = document.getElementById(
"iframe_designMode");
276 iframe.style.display =
"inline";
277 iframe.contentDocument.designMode =
"on";
278 editor = iframe.contentDocument.getElementById(
"editor");
279 root = iframe.contentDocument.documentElement;
280 resetFocusToInput(
"initializing for iframe_designMode");
282 testTabKey(true, root, false, prev, true,
283 true,
"input#prev[readonly] -> html in designMode");
284 testTabKey(true, next, true, root, false,
285 false,
"html in designMode -> input#next[readonly]");
286 testTabKey(false, root, false, next, true,
287 true,
"input#next[readonly] -> html in designMode");
288 testTabKey(false, prev, true, root, false,
289 false,
"html in designMode -> input#prev[readonly]");
291 prev.style.display =
"none";
292 resetFocusToParentHTML(
"testing iframe_designMode");
293 testTabKey(true, root, false, html, false,
294 true,
"html of parent -> html in designMode");
295 testTabKey(false, html, false, root, false,
296 false,
"html in designMode -> html of parent");
297 prev.style.display =
"inline";
298 resetFocusToInput(
"after parent html <-> html in designMode");
300 testMouseClick(editor, false, true, prev, true, true,
"iframe_designMode");
302 testOnEditorFlagChange(
"html in designMode", true);
304 iframe.style.display =
"none";
306 // When there is no HTML element but the BODY element is editable,
307 // the body element should get focus and enables IME.
308 iframe = document.getElementById(
"iframe_body");
309 iframe.style.display =
"inline";
310 editor = iframe.contentDocument.getElementById(
"editor");
311 root = iframe.contentDocument.documentElement;
312 resetFocusToInput(
"initializing for iframe_body");
314 testTabKey(true, editor, true, prev, true,
315 true,
"input#prev[readonly] -> body[contentediable=true]");
316 testTabKey(true, next, true, editor, true,
317 false,
"body[contentediable=true] -> input#next[readonly]");
318 testTabKey(false, editor, true, next, true,
319 true,
"input#next[readonly] -> body[contentediable=true]");
320 testTabKey(false, prev, true, editor, true,
321 false,
"body[contenteditable=true] -> input#prev[readonly]");
323 prev.style.display =
"none";
324 resetFocusToParentHTML(
"testing iframe_body");
325 testTabKey(true, editor, true, html, false,
326 true,
"html of parent -> body[contentediable=true]");
327 testTabKey(false, html, false, editor, true,
328 false,
"body[contenteditable=true] -> html of parent");
329 prev.style.display =
"inline";
330 resetFocusToInput(
"after parent html <-> body[contenteditable=true]");
332 testMouseClick(editor, true, false, prev, true, true,
"iframe_body");
334 testOnEditorFlagChange(
"body[contentediable=true]", false);
336 iframe.style.display =
"none";
338 // When HTML/BODY elements are not editable, focus shouldn't be moved to
339 // the editable content directly.
340 iframe = document.getElementById(
"iframe_p");
341 iframe.style.display =
"inline";
342 editor = iframe.contentDocument.getElementById(
"editor");
343 root = iframe.contentDocument.documentElement;
344 resetFocusToInput(
"initializing for iframe_p");
346 testTabKey(true, root, false, prev, true,
347 false,
"input#prev[readonly] -> html (has p[contenteditable=true])");
348 testTabKey(true, editor, true, root, false,
349 true,
"html (has p[contenteditable=true]) -> p[contentediable=true]");
350 testTabKey(true, next, true, editor, true,
351 false,
"p[contentediable=true] -> input#next[readonly]");
352 testTabKey(false, editor, true, next, true,
353 true,
"input#next[readonly] -> p[contentediable=true]");
354 testTabKey(false, root, false, editor, true,
355 false,
"p[contenteditable=true] -> html (has p[contenteditable=true])");
356 testTabKey(false, prev, true, root, false,
357 false,
"html (has p[contenteditable=true]) -> input#prev[readonly]");
358 prev.style.display =
"none";
360 resetFocusToParentHTML(
"testing iframe_p");
361 testTabKey(true, root, false, html, false,
362 false,
"html of parent -> html (has p[contentediable=true])");
363 testTabKey(false, html, false, root, false,
364 false,
"html (has p[contentediable=true]) -> html of parent");
365 prev.style.display =
"inline";
366 resetFocusToInput(
"after parent html <-> html (has p[contentediable=true])");
368 testMouseClick(root, false, true, prev, true, false,
"iframe_p");
370 testOnEditorFlagChange(
"p[contenteditable=true]", false);
372 iframe.style.display =
"none";