1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/tests/window_imestate_iframes.html Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,380 @@ 1.4 +<html> 1.5 +<head> 1.6 + <title>Test for IME state controling and focus moving for iframes</title> 1.7 + <script type="text/javascript" 1.8 + src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> 1.9 + <link rel="stylesheet" type="text/css" 1.10 + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> 1.11 + <style type="text/css"> 1.12 + iframe { 1.13 + border: none; 1.14 + height: 100px; 1.15 + } 1.16 + </style> 1.17 +</head> 1.18 +<body onunload="onUnload();"> 1.19 +<p id="display"> 1.20 + <!-- Use input[readonly] because it isn't affected by the partial focus 1.21 + movement on Mac --> 1.22 + <input id="prev" readonly><br> 1.23 + <iframe id="iframe_not_editable" 1.24 + src="data:text/html,<html><body><input id='editor'></body></html>"></iframe><br> 1.25 + 1.26 + <!-- Testing IME state and focus movement, the anchor elements cannot get focus --> 1.27 + <iframe id="iframe_html" 1.28 + src="data:text/html,<html id='editor' contenteditable='true'><body><a href='about:blank'>about:blank;</a></body></html>"></iframe><br> 1.29 + <iframe id="iframe_designMode" 1.30 + src="data:text/html,<body id='editor' onload='document.designMode="on";'><a href='about:blank'>about:blank;</a></body>"></iframe><br> 1.31 + <iframe id="iframe_body" 1.32 + src="data:text/html,<body id='editor' contenteditable='true'><a href='about:blank'>about:blank;</a></body>"></iframe><br> 1.33 + <iframe id="iframe_p" 1.34 + src="data:text/html,<body><p id='editor' contenteditable='true'><a href='about:blank'>about:blank;</a></p></body>"></iframe><br> 1.35 + 1.36 + <input id="next" readonly><br> 1.37 +</p> 1.38 +<script class="testbody" type="application/javascript"> 1.39 + 1.40 +window.opener.wrappedJSObject.SimpleTest.waitForFocus(runTests, window); 1.41 + 1.42 +function ok(aCondition, aMessage) 1.43 +{ 1.44 + window.opener.wrappedJSObject.SimpleTest.ok(aCondition, aMessage); 1.45 +} 1.46 + 1.47 +function is(aLeft, aRight, aMessage) 1.48 +{ 1.49 + window.opener.wrappedJSObject.SimpleTest.is(aLeft, aRight, aMessage); 1.50 +} 1.51 + 1.52 +function onUnload() 1.53 +{ 1.54 + window.opener.wrappedJSObject.onFinish(); 1.55 +} 1.56 + 1.57 +var gFocusObservingElement = null; 1.58 +var gBlurObservingElement = null; 1.59 + 1.60 +function onFocus(aEvent) 1.61 +{ 1.62 + if (aEvent.target != gFocusObservingElement) { 1.63 + return; 1.64 + } 1.65 + ok(gFocusObservingElement.willFocus, 1.66 + "focus event is fired on unexpected element"); 1.67 + gFocusObservingElement.willFocus = false; 1.68 +} 1.69 + 1.70 +function onBlur(aEvent) 1.71 +{ 1.72 + if (aEvent.target != gBlurObservingElement) { 1.73 + return; 1.74 + } 1.75 + ok(gBlurObservingElement.willBlur, 1.76 + "blur event is fired on unexpected element"); 1.77 + gBlurObservingElement.willBlur = false; 1.78 +} 1.79 + 1.80 +function observeFocusBlur(aNextFocusedNode, aWillFireFocusEvent, 1.81 + aNextBlurredNode, aWillFireBlurEvent) 1.82 +{ 1.83 + if (gFocusObservingElement) { 1.84 + if (gFocusObservingElement.willFocus) { 1.85 + ok(false, "focus event was never fired on " + gFocusObservingElement); 1.86 + } 1.87 + gFocusObservingElement.removeEventListener("focus", onFocus, true); 1.88 + gFocusObservingElement.willFocus = NaN; 1.89 + gFocusObservingElement = null; 1.90 + } 1.91 + if (gBlurObservingElement) { 1.92 + if (gBlurObservingElement.willBlur) { 1.93 + ok(false, "blur event was never fired on " + gBlurObservingElement); 1.94 + } 1.95 + gBlurObservingElement.removeEventListener("blur", onBlur, true); 1.96 + gBlurObservingElement.willBlur = NaN; 1.97 + gBlurObservingElement = null; 1.98 + } 1.99 + if (aNextFocusedNode) { 1.100 + gFocusObservingElement = aNextFocusedNode; 1.101 + gFocusObservingElement.willFocus = aWillFireFocusEvent; 1.102 + gFocusObservingElement.addEventListener("focus", onFocus, true); 1.103 + } 1.104 + if (aNextBlurredNode) { 1.105 + gBlurObservingElement = aNextBlurredNode; 1.106 + gBlurObservingElement.willBlur = aWillFireBlurEvent; 1.107 + gBlurObservingElement.addEventListener("blur", onBlur, true); 1.108 + } 1.109 +} 1.110 + 1.111 +function runTests() 1.112 +{ 1.113 + var utils = 1.114 + window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) 1.115 + .getInterface(Components.interfaces.nsIDOMWindowUtils); 1.116 + var fm = 1.117 + Components.classes["@mozilla.org/focus-manager;1"] 1.118 + .getService(Components.interfaces.nsIFocusManager); 1.119 + 1.120 + var iframe, editor, root, input; 1.121 + var prev = document.getElementById("prev"); 1.122 + var next = document.getElementById("next"); 1.123 + var html = document.documentElement; 1.124 + 1.125 + function resetFocusToInput(aDescription) 1.126 + { 1.127 + observeFocusBlur(null, false, null, false); 1.128 + prev.focus(); 1.129 + is(fm.focusedElement, prev, 1.130 + "input#prev[readonly] element didn't get focus: " + aDescription); 1.131 + is(utils.IMEStatus, utils.IME_STATUS_DISABLED, 1.132 + "IME enabled on input#prev[readonly]: " + aDescription); 1.133 + } 1.134 + 1.135 + function resetFocusToParentHTML(aDescription) 1.136 + { 1.137 + observeFocusBlur(null, false, null, false); 1.138 + html.focus(); 1.139 + is(fm.focusedElement, html, 1.140 + "Parent html element didn't get focus: " + aDescription); 1.141 + is(utils.IMEStatus, utils.IME_STATUS_DISABLED, 1.142 + "IME enabled on parent html element: " + aDescription); 1.143 + } 1.144 + 1.145 + function testTabKey(aForward, 1.146 + aNextFocusedNode, aWillFireFocusEvent, 1.147 + aNextBlurredNode, aWillFireBlurEvent, 1.148 + aIMEShouldBeEnabled, aTestingCaseDescription) 1.149 + { 1.150 + observeFocusBlur(aNextFocusedNode, aWillFireFocusEvent, 1.151 + aNextBlurredNode, aWillFireBlurEvent); 1.152 + synthesizeKey("VK_TAB", { shiftKey: !aForward }); 1.153 + var description = "Tab key test: "; 1.154 + if (!aForward) { 1.155 + description = "Shift-" + description; 1.156 + } 1.157 + description += aTestingCaseDescription + ": "; 1.158 + is(fm.focusedElement, aNextFocusedNode, 1.159 + description + "didn't move focus as expected"); 1.160 + is(utils.IMEStatus, 1.161 + aIMEShouldBeEnabled ? 1.162 + utils.IME_STATUS_ENABLED : utils.IME_STATUS_DISABLED, 1.163 + description + "didn't set IME state as expected"); 1.164 + } 1.165 + 1.166 + function testMouseClick(aNextFocusedNode, aWillFireFocusEvent, 1.167 + aWillAllNodeLostFocus, 1.168 + aNextBlurredNode, aWillFireBlurEvent, 1.169 + aIMEShouldBeEnabled, aTestingCaseDescription) 1.170 + { 1.171 + observeFocusBlur(aNextFocusedNode, aWillFireFocusEvent, 1.172 + aNextBlurredNode, aWillFireBlurEvent); 1.173 + // We're relying on layout inside the iframe being up to date, so make it so 1.174 + iframe.contentDocument.documentElement.getBoundingClientRect(); 1.175 + synthesizeMouse(iframe, 10, 80, { }); 1.176 + var description = "Click test: " + aTestingCaseDescription + ": "; 1.177 + is(fm.focusedElement, !aWillAllNodeLostFocus ? aNextFocusedNode : null, 1.178 + description + "didn't move focus as expected"); 1.179 + is(utils.IMEStatus, 1.180 + aIMEShouldBeEnabled ? 1.181 + utils.IME_STATUS_ENABLED : utils.IME_STATUS_DISABLED, 1.182 + description + "didn't set IME state as expected"); 1.183 + } 1.184 + 1.185 + function testOnEditorFlagChange(aDescription, aIsInDesignMode) 1.186 + { 1.187 + const kReadonly = 1.188 + Components.interfaces.nsIPlaintextEditor.eEditorReadonlyMask; 1.189 + var description = "testOnEditorFlagChange: " + aDescription; 1.190 + resetFocusToParentHTML(description); 1.191 + var htmlEditor = 1.192 + iframe.contentWindow. 1.193 + QueryInterface(Components.interfaces.nsIInterfaceRequestor). 1.194 + getInterface(Components.interfaces.nsIWebNavigation). 1.195 + QueryInterface(Components.interfaces.nsIDocShell).editor; 1.196 + var e = aIsInDesignMode ? root : editor; 1.197 + e.focus(); 1.198 + is(fm.focusedElement, e, 1.199 + description + ": focus() of editor didn't move focus as expected"); 1.200 + is(utils.IMEStatus, utils.IME_STATUS_ENABLED, 1.201 + description + ": IME isn't enabled when the editor gets focus"); 1.202 + var flags = htmlEditor.flags; 1.203 + htmlEditor.flags |= kReadonly; 1.204 + is(fm.focusedElement, e, 1.205 + description + ": when editor becomes readonly, focus moved unexpectedly"); 1.206 + is(utils.IMEStatus, utils.IME_STATUS_DISABLED, 1.207 + description + ": when editor becomes readonly, IME is still enabled"); 1.208 + htmlEditor.flags = flags; 1.209 + is(fm.focusedElement, e, 1.210 + description + ": when editor becomes read-write, focus moved unexpectedly"); 1.211 + is(utils.IMEStatus, utils.IME_STATUS_ENABLED, 1.212 + description + ": when editor becomes read-write, IME is still disabled"); 1.213 + } 1.214 + 1.215 + // hide all iframes 1.216 + document.getElementById("iframe_not_editable").style.display = "none"; 1.217 + document.getElementById("iframe_html").style.display = "none"; 1.218 + document.getElementById("iframe_designMode").style.display = "none"; 1.219 + document.getElementById("iframe_body").style.display = "none"; 1.220 + document.getElementById("iframe_p").style.display = "none"; 1.221 + 1.222 + // non editable HTML element and input element can get focus. 1.223 + iframe = document.getElementById("iframe_not_editable"); 1.224 + iframe.style.display = "inline"; 1.225 + editor = iframe.contentDocument.getElementById("editor"); 1.226 + root = iframe.contentDocument.documentElement; 1.227 + resetFocusToInput("initializing for iframe_not_editable"); 1.228 + 1.229 + testTabKey(true, root, false, prev, true, 1.230 + false, "input#prev[readonly] -> html"); 1.231 + testTabKey(true, editor, true, root, false, 1.232 + true, "html -> input in the subdoc"); 1.233 + testTabKey(true, next, true, editor, true, 1.234 + false, "input in the subdoc -> input#next[readonly]"); 1.235 + testTabKey(false, editor, true, next, true, 1.236 + true, "input#next[readonly] -> input in the subdoc"); 1.237 + testTabKey(false, root, false, editor, true, 1.238 + false, "input in the subdoc -> html"); 1.239 + testTabKey(false, prev, true, root, false, 1.240 + false, "html -> input#next[readonly]"); 1.241 + 1.242 + iframe.style.display = "none"; 1.243 + 1.244 + // HTML element (of course, it's root) must enables IME. 1.245 + iframe = document.getElementById("iframe_html"); 1.246 + iframe.style.display = "inline"; 1.247 + editor = iframe.contentDocument.getElementById("editor"); 1.248 + root = iframe.contentDocument.documentElement; 1.249 + resetFocusToInput("initializing for iframe_html"); 1.250 + 1.251 + testTabKey(true, editor, true, prev, true, 1.252 + true, "input#prev[readonly] -> html[contentediable=true]"); 1.253 + testTabKey(true, next, true, editor, true, 1.254 + false, "html[contentediable=true] -> input#next[readonly]"); 1.255 + testTabKey(false, editor, true, next, true, 1.256 + true, "input#next[readonly] -> html[contentediable=true]"); 1.257 + testTabKey(false, prev, true, editor, true, 1.258 + false, "html[contenteditable=true] -> input[readonly]"); 1.259 + 1.260 + prev.style.display = "none"; 1.261 + resetFocusToParentHTML("testing iframe_html"); 1.262 + testTabKey(true, editor, true, html, false, 1.263 + true, "html of parent -> html[contentediable=true]"); 1.264 + testTabKey(false, html, false, editor, true, 1.265 + false, "html[contenteditable=true] -> html of parent"); 1.266 + prev.style.display = "inline"; 1.267 + resetFocusToInput("after parent html <-> html[contenteditable=true]"); 1.268 + 1.269 + testMouseClick(editor, true, false, prev, true, true, "iframe_html"); 1.270 + 1.271 + testOnEditorFlagChange("html[contentediable=true]", false); 1.272 + 1.273 + iframe.style.display = "none"; 1.274 + 1.275 + // designMode should behave like <html contenteditable="true"></html> 1.276 + // but focus/blur events shouldn't be fired on its root element because 1.277 + // any elements shouldn't be focused state in designMode. 1.278 + iframe = document.getElementById("iframe_designMode"); 1.279 + iframe.style.display = "inline"; 1.280 + iframe.contentDocument.designMode = "on"; 1.281 + editor = iframe.contentDocument.getElementById("editor"); 1.282 + root = iframe.contentDocument.documentElement; 1.283 + resetFocusToInput("initializing for iframe_designMode"); 1.284 + 1.285 + testTabKey(true, root, false, prev, true, 1.286 + true, "input#prev[readonly] -> html in designMode"); 1.287 + testTabKey(true, next, true, root, false, 1.288 + false, "html in designMode -> input#next[readonly]"); 1.289 + testTabKey(false, root, false, next, true, 1.290 + true, "input#next[readonly] -> html in designMode"); 1.291 + testTabKey(false, prev, true, root, false, 1.292 + false, "html in designMode -> input#prev[readonly]"); 1.293 + 1.294 + prev.style.display = "none"; 1.295 + resetFocusToParentHTML("testing iframe_designMode"); 1.296 + testTabKey(true, root, false, html, false, 1.297 + true, "html of parent -> html in designMode"); 1.298 + testTabKey(false, html, false, root, false, 1.299 + false, "html in designMode -> html of parent"); 1.300 + prev.style.display = "inline"; 1.301 + resetFocusToInput("after parent html <-> html in designMode"); 1.302 + 1.303 + testMouseClick(editor, false, true, prev, true, true, "iframe_designMode"); 1.304 + 1.305 + testOnEditorFlagChange("html in designMode", true); 1.306 + 1.307 + iframe.style.display = "none"; 1.308 + 1.309 + // When there is no HTML element but the BODY element is editable, 1.310 + // the body element should get focus and enables IME. 1.311 + iframe = document.getElementById("iframe_body"); 1.312 + iframe.style.display = "inline"; 1.313 + editor = iframe.contentDocument.getElementById("editor"); 1.314 + root = iframe.contentDocument.documentElement; 1.315 + resetFocusToInput("initializing for iframe_body"); 1.316 + 1.317 + testTabKey(true, editor, true, prev, true, 1.318 + true, "input#prev[readonly] -> body[contentediable=true]"); 1.319 + testTabKey(true, next, true, editor, true, 1.320 + false, "body[contentediable=true] -> input#next[readonly]"); 1.321 + testTabKey(false, editor, true, next, true, 1.322 + true, "input#next[readonly] -> body[contentediable=true]"); 1.323 + testTabKey(false, prev, true, editor, true, 1.324 + false, "body[contenteditable=true] -> input#prev[readonly]"); 1.325 + 1.326 + prev.style.display = "none"; 1.327 + resetFocusToParentHTML("testing iframe_body"); 1.328 + testTabKey(true, editor, true, html, false, 1.329 + true, "html of parent -> body[contentediable=true]"); 1.330 + testTabKey(false, html, false, editor, true, 1.331 + false, "body[contenteditable=true] -> html of parent"); 1.332 + prev.style.display = "inline"; 1.333 + resetFocusToInput("after parent html <-> body[contenteditable=true]"); 1.334 + 1.335 + testMouseClick(editor, true, false, prev, true, true, "iframe_body"); 1.336 + 1.337 + testOnEditorFlagChange("body[contentediable=true]", false); 1.338 + 1.339 + iframe.style.display = "none"; 1.340 + 1.341 + // When HTML/BODY elements are not editable, focus shouldn't be moved to 1.342 + // the editable content directly. 1.343 + iframe = document.getElementById("iframe_p"); 1.344 + iframe.style.display = "inline"; 1.345 + editor = iframe.contentDocument.getElementById("editor"); 1.346 + root = iframe.contentDocument.documentElement; 1.347 + resetFocusToInput("initializing for iframe_p"); 1.348 + 1.349 + testTabKey(true, root, false, prev, true, 1.350 + false, "input#prev[readonly] -> html (has p[contenteditable=true])"); 1.351 + testTabKey(true, editor, true, root, false, 1.352 + true, "html (has p[contenteditable=true]) -> p[contentediable=true]"); 1.353 + testTabKey(true, next, true, editor, true, 1.354 + false, "p[contentediable=true] -> input#next[readonly]"); 1.355 + testTabKey(false, editor, true, next, true, 1.356 + true, "input#next[readonly] -> p[contentediable=true]"); 1.357 + testTabKey(false, root, false, editor, true, 1.358 + false, "p[contenteditable=true] -> html (has p[contenteditable=true])"); 1.359 + testTabKey(false, prev, true, root, false, 1.360 + false, "html (has p[contenteditable=true]) -> input#prev[readonly]"); 1.361 + prev.style.display = "none"; 1.362 + 1.363 + resetFocusToParentHTML("testing iframe_p"); 1.364 + testTabKey(true, root, false, html, false, 1.365 + false, "html of parent -> html (has p[contentediable=true])"); 1.366 + testTabKey(false, html, false, root, false, 1.367 + false, "html (has p[contentediable=true]) -> html of parent"); 1.368 + prev.style.display = "inline"; 1.369 + resetFocusToInput("after parent html <-> html (has p[contentediable=true])"); 1.370 + 1.371 + testMouseClick(root, false, true, prev, true, false, "iframe_p"); 1.372 + 1.373 + testOnEditorFlagChange("p[contenteditable=true]", false); 1.374 + 1.375 + iframe.style.display = "none"; 1.376 + 1.377 + window.close(); 1.378 +} 1.379 + 1.380 +</script> 1.381 +</body> 1.382 + 1.383 +</html>