diff options
Diffstat (limited to '')
-rw-r--r-- | widget/tests/window_imestate_iframes.html | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/widget/tests/window_imestate_iframes.html b/widget/tests/window_imestate_iframes.html new file mode 100644 index 0000000000..c8b182977f --- /dev/null +++ b/widget/tests/window_imestate_iframes.html @@ -0,0 +1,358 @@ +<html> +<head> + <title>Test for IME state controling and focus moving for iframes</title> + <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + <style type="text/css"> + iframe { + border: none; + height: 100px; + } + </style> +</head> +<body onunload="onUnload();"> +<p id="display"> + <!-- Use input[readonly] because it isn't affected by the partial focus + movement on Mac --> + <input id="prev" readonly><br> + <iframe id="iframe_not_editable" + src="data:text/html,<html><body><input id='editor'></body></html>"></iframe><br> + + <!-- Testing IME state and focus movement, the anchor elements cannot get focus --> + <iframe id="iframe_html" + src="data:text/html,<html id='editor' contenteditable='true'><body><a href='about:blank'>about:blank;</a></body></html>"></iframe><br> + <iframe id="iframe_designMode" + src="data:text/html,<body id='editor' onload='document.designMode="on";'><a href='about:blank'>about:blank;</a></body>"></iframe><br> + <iframe id="iframe_body" + src="data:text/html,<body id='editor' contenteditable='true'><a href='about:blank'>about:blank;</a></body>"></iframe><br> + <iframe id="iframe_p" + src="data:text/html,<body><p id='editor' contenteditable='true'><a href='about:blank'>about:blank;</a></p></body>"></iframe><br> + + <input id="next" readonly><br> +</p> +<script class="testbody" type="application/javascript"> + +window.opener.SimpleTest.waitForFocus(runTests, window); + +function ok(aCondition, aMessage) { + window.opener.SimpleTest.ok(aCondition, aMessage); +} + +function is(aLeft, aRight, aMessage) { + window.opener.SimpleTest.is(aLeft, aRight, aMessage); +} + +function onUnload() { + window.opener.onFinish(); +} + +var gFocusObservingElement = null; +var gBlurObservingElement = null; + +function onFocus(aEvent) { + if (aEvent.target != gFocusObservingElement) { + return; + } + ok(gFocusObservingElement.willFocus, + "focus event is fired on unexpected element"); + gFocusObservingElement.willFocus = false; +} + +function onBlur(aEvent) { + if (aEvent.target != gBlurObservingElement) { + return; + } + ok(gBlurObservingElement.willBlur, + "blur event is fired on unexpected element"); + gBlurObservingElement.willBlur = false; +} + +function observeFocusBlur(aNextFocusedNode, aWillFireFocusEvent, + aNextBlurredNode, aWillFireBlurEvent) { + if (gFocusObservingElement) { + if (gFocusObservingElement.willFocus) { + ok(false, "focus event was never fired on " + gFocusObservingElement); + } + gFocusObservingElement.removeEventListener("focus", onFocus, true); + gFocusObservingElement.willFocus = NaN; + gFocusObservingElement = null; + } + if (gBlurObservingElement) { + if (gBlurObservingElement.willBlur) { + ok(false, "blur event was never fired on " + gBlurObservingElement); + } + gBlurObservingElement.removeEventListener("blur", onBlur, true); + gBlurObservingElement.willBlur = NaN; + gBlurObservingElement = null; + } + if (aNextFocusedNode) { + gFocusObservingElement = aNextFocusedNode; + gFocusObservingElement.willFocus = aWillFireFocusEvent; + gFocusObservingElement.addEventListener("focus", onFocus, true); + } + if (aNextBlurredNode) { + gBlurObservingElement = aNextBlurredNode; + gBlurObservingElement.willBlur = aWillFireBlurEvent; + gBlurObservingElement.addEventListener("blur", onBlur, true); + } +} + +function runTests() { + var utils = window.windowUtils; + var fm = Services.focus; + + var iframe, editor, root; + var prev = document.getElementById("prev"); + var next = document.getElementById("next"); + var html = document.documentElement; + + function resetFocusToInput(aDescription) { + observeFocusBlur(null, false, null, false); + prev.focus(); + is(fm.focusedElement, prev, + "input#prev[readonly] element didn't get focus: " + aDescription); + is(utils.IMEStatus, utils.IME_STATUS_DISABLED, + "IME enabled on input#prev[readonly]: " + aDescription); + } + + function resetFocusToParentHTML(aDescription) { + observeFocusBlur(null, false, null, false); + html.focus(); + is(fm.focusedElement, html, + "Parent html element didn't get focus: " + aDescription); + is(utils.IMEStatus, utils.IME_STATUS_DISABLED, + "IME enabled on parent html element: " + aDescription); + } + + function testTabKey(aForward, + aNextFocusedNode, aWillFireFocusEvent, + aNextBlurredNode, aWillFireBlurEvent, + aIMEShouldBeEnabled, aTestingCaseDescription) { + observeFocusBlur(aNextFocusedNode, aWillFireFocusEvent, + aNextBlurredNode, aWillFireBlurEvent); + synthesizeKey("VK_TAB", { shiftKey: !aForward }); + var description = "Tab key test: "; + if (!aForward) { + description = "Shift-" + description; + } + description += aTestingCaseDescription + ": "; + is(fm.focusedElement, aNextFocusedNode, + description + "didn't move focus as expected"); + is(utils.IMEStatus, + aIMEShouldBeEnabled ? + utils.IME_STATUS_ENABLED : utils.IME_STATUS_DISABLED, + description + "didn't set IME state as expected"); + } + + function testMouseClick(aNextFocusedNode, aWillFireFocusEvent, + aWillAllNodeLostFocus, + aNextBlurredNode, aWillFireBlurEvent, + aIMEShouldBeEnabled, aTestingCaseDescription) { + observeFocusBlur(aNextFocusedNode, aWillFireFocusEvent, + aNextBlurredNode, aWillFireBlurEvent); + // We're relying on layout inside the iframe being up to date, so make it so + iframe.contentDocument.documentElement.getBoundingClientRect(); + synthesizeMouse(iframe, 10, 80, { }); + var description = "Click test: " + aTestingCaseDescription + ": "; + is(fm.focusedElement, !aWillAllNodeLostFocus ? aNextFocusedNode : null, + description + "didn't move focus as expected"); + is(utils.IMEStatus, + aIMEShouldBeEnabled ? + utils.IME_STATUS_ENABLED : utils.IME_STATUS_DISABLED, + description + "didn't set IME state as expected"); + } + + function testOnEditorFlagChange(aDescription, aIsInDesignMode) { + const kReadonly = Ci.nsIEditor.eEditorReadonlyMask; + var description = "testOnEditorFlagChange: " + aDescription; + resetFocusToParentHTML(description); + var htmlEditor = iframe.contentWindow.docShell.editor; + var e = aIsInDesignMode ? root : editor; + e.focus(); + is(fm.focusedElement, e, + description + ": focus() of editor didn't move focus as expected"); + is(utils.IMEStatus, utils.IME_STATUS_ENABLED, + description + ": IME isn't enabled when the editor gets focus"); + var flags = htmlEditor.flags; + htmlEditor.flags |= kReadonly; + is(fm.focusedElement, e, + description + ": when editor becomes readonly, focus moved unexpectedly"); + is(utils.IMEStatus, utils.IME_STATUS_DISABLED, + description + ": when editor becomes readonly, IME is still enabled"); + htmlEditor.flags = flags; + is(fm.focusedElement, e, + description + ": when editor becomes read-write, focus moved unexpectedly"); + is(utils.IMEStatus, utils.IME_STATUS_ENABLED, + description + ": when editor becomes read-write, IME is still disabled"); + } + + // hide all iframes + document.getElementById("iframe_not_editable").style.display = "none"; + document.getElementById("iframe_html").style.display = "none"; + document.getElementById("iframe_designMode").style.display = "none"; + document.getElementById("iframe_body").style.display = "none"; + document.getElementById("iframe_p").style.display = "none"; + + // non editable HTML element and input element can get focus. + iframe = document.getElementById("iframe_not_editable"); + iframe.style.display = "inline"; + editor = iframe.contentDocument.getElementById("editor"); + root = iframe.contentDocument.documentElement; + resetFocusToInput("initializing for iframe_not_editable"); + + testTabKey(true, root, false, prev, true, + false, "input#prev[readonly] -> html"); + testTabKey(true, editor, true, root, false, + true, "html -> input in the subdoc"); + testTabKey(true, next, true, editor, true, + false, "input in the subdoc -> input#next[readonly]"); + testTabKey(false, editor, true, next, true, + true, "input#next[readonly] -> input in the subdoc"); + testTabKey(false, root, false, editor, true, + false, "input in the subdoc -> html"); + testTabKey(false, prev, true, root, false, + false, "html -> input#next[readonly]"); + + iframe.style.display = "none"; + + // HTML element (of course, it's root) must enables IME. + iframe = document.getElementById("iframe_html"); + iframe.style.display = "inline"; + editor = iframe.contentDocument.getElementById("editor"); + root = iframe.contentDocument.documentElement; + resetFocusToInput("initializing for iframe_html"); + + testTabKey(true, editor, true, prev, true, + true, "input#prev[readonly] -> html[contentediable=true]"); + testTabKey(true, next, true, editor, true, + false, "html[contentediable=true] -> input#next[readonly]"); + testTabKey(false, editor, true, next, true, + true, "input#next[readonly] -> html[contentediable=true]"); + testTabKey(false, prev, true, editor, true, + false, "html[contenteditable=true] -> input[readonly]"); + + prev.style.display = "none"; + resetFocusToParentHTML("testing iframe_html"); + testTabKey(true, editor, true, html, false, + true, "html of parent -> html[contentediable=true]"); + testTabKey(false, html, false, editor, true, + false, "html[contenteditable=true] -> html of parent"); + prev.style.display = "inline"; + resetFocusToInput("after parent html <-> html[contenteditable=true]"); + + testMouseClick(editor, true, false, prev, true, true, "iframe_html"); + + testOnEditorFlagChange("html[contentediable=true]", false); + + iframe.style.display = "none"; + + // designMode should behave like <html contenteditable="true"></html> + // but focus/blur events shouldn't be fired on its root element because + // any elements shouldn't be focused state in designMode. + iframe = document.getElementById("iframe_designMode"); + iframe.style.display = "inline"; + iframe.contentDocument.designMode = "on"; + editor = iframe.contentDocument.getElementById("editor"); + root = iframe.contentDocument.documentElement; + resetFocusToInput("initializing for iframe_designMode"); + + testTabKey(true, root, false, prev, true, + true, "input#prev[readonly] -> html in designMode"); + testTabKey(true, next, true, root, false, + false, "html in designMode -> input#next[readonly]"); + testTabKey(false, root, false, next, true, + true, "input#next[readonly] -> html in designMode"); + testTabKey(false, prev, true, root, false, + false, "html in designMode -> input#prev[readonly]"); + + prev.style.display = "none"; + resetFocusToParentHTML("testing iframe_designMode"); + testTabKey(true, root, false, html, false, + true, "html of parent -> html in designMode"); + testTabKey(false, html, false, root, false, + false, "html in designMode -> html of parent"); + prev.style.display = "inline"; + resetFocusToInput("after parent html <-> html in designMode"); + + testMouseClick(editor, false, true, prev, true, true, "iframe_designMode"); + + testOnEditorFlagChange("html in designMode", true); + + iframe.style.display = "none"; + + // When there is no HTML element but the BODY element is editable, + // the body element should get focus and enables IME. + iframe = document.getElementById("iframe_body"); + iframe.style.display = "inline"; + editor = iframe.contentDocument.getElementById("editor"); + root = iframe.contentDocument.documentElement; + resetFocusToInput("initializing for iframe_body"); + + testTabKey(true, editor, true, prev, true, + true, "input#prev[readonly] -> body[contentediable=true]"); + testTabKey(true, next, true, editor, true, + false, "body[contentediable=true] -> input#next[readonly]"); + testTabKey(false, editor, true, next, true, + true, "input#next[readonly] -> body[contentediable=true]"); + testTabKey(false, prev, true, editor, true, + false, "body[contenteditable=true] -> input#prev[readonly]"); + + prev.style.display = "none"; + resetFocusToParentHTML("testing iframe_body"); + testTabKey(true, editor, true, html, false, + true, "html of parent -> body[contentediable=true]"); + testTabKey(false, html, false, editor, true, + false, "body[contenteditable=true] -> html of parent"); + prev.style.display = "inline"; + resetFocusToInput("after parent html <-> body[contenteditable=true]"); + + testMouseClick(editor, true, false, prev, true, true, "iframe_body"); + + testOnEditorFlagChange("body[contentediable=true]", false); + + iframe.style.display = "none"; + + // When HTML/BODY elements are not editable, focus shouldn't be moved to + // the editable content directly. + iframe = document.getElementById("iframe_p"); + iframe.style.display = "inline"; + editor = iframe.contentDocument.getElementById("editor"); + root = iframe.contentDocument.documentElement; + resetFocusToInput("initializing for iframe_p"); + + testTabKey(true, root, false, prev, true, + false, "input#prev[readonly] -> html (has p[contenteditable=true])"); + testTabKey(true, editor, true, root, false, + true, "html (has p[contenteditable=true]) -> p[contentediable=true]"); + testTabKey(true, next, true, editor, true, + false, "p[contentediable=true] -> input#next[readonly]"); + testTabKey(false, editor, true, next, true, + true, "input#next[readonly] -> p[contentediable=true]"); + testTabKey(false, root, false, editor, true, + false, "p[contenteditable=true] -> html (has p[contenteditable=true])"); + testTabKey(false, prev, true, root, false, + false, "html (has p[contenteditable=true]) -> input#prev[readonly]"); + prev.style.display = "none"; + + resetFocusToParentHTML("testing iframe_p"); + testTabKey(true, root, false, html, false, + false, "html of parent -> html (has p[contentediable=true])"); + testTabKey(false, html, false, root, false, + false, "html (has p[contentediable=true]) -> html of parent"); + prev.style.display = "inline"; + resetFocusToInput("after parent html <-> html (has p[contentediable=true])"); + + testMouseClick(root, false, true, prev, true, false, "iframe_p"); + + testOnEditorFlagChange("p[contenteditable=true]", false); + + iframe.style.display = "none"; + + window.close(); +} + +</script> +</body> + +</html> |