summaryrefslogtreecommitdiffstats
path: root/dom/tests/mochitest/chrome/window_focus.xhtml
diff options
context:
space:
mode:
Diffstat (limited to 'dom/tests/mochitest/chrome/window_focus.xhtml')
-rw-r--r--dom/tests/mochitest/chrome/window_focus.xhtml1699
1 files changed, 1699 insertions, 0 deletions
diff --git a/dom/tests/mochitest/chrome/window_focus.xhtml b/dom/tests/mochitest/chrome/window_focus.xhtml
new file mode 100644
index 0000000000..a2a1b5a2c3
--- /dev/null
+++ b/dom/tests/mochitest/chrome/window_focus.xhtml
@@ -0,0 +1,1699 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<!--
+ This test checks focus in various ways
+-->
+<window id="outer-document" title="Focus Test" width="600" height="550"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+<body xmlns="http://www.w3.org/1999/xhtml"/>
+
+ <script type="application/javascript"><![CDATA[
+
+const { BrowserTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/BrowserTestUtils.sys.mjs"
+);
+const { ContentTask } = ChromeUtils.import(
+ "resource://testing-common/ContentTask.jsm"
+);
+
+var fm = Cc["@mozilla.org/focus-manager;1"].
+ getService(Ci.nsIFocusManager);
+
+const kChildDocumentRootIndex = 13;
+const kBeforeTabboxIndex = 34;
+const kTabbableSteps = 38;
+const kFocusSteps = 26;
+const kNoFocusSteps = 7;
+const kOverflowElementIndex = 27;
+
+var gTestStarted = false;
+var gPartialTabbing = false;
+var gMoveToFocusFrame = false;
+var gLastFocus = null;
+var gLastFocusWindow = window;
+var gLastFocusMethod = -1;
+var gEvents = "";
+var gExpectedEvents = "";
+var gEventMatched = true;
+var gShowOutput = false;
+var gChildWindow = null;
+
+var gOldExpectedWindow = null;
+var gNewExpectedWindow = null;
+
+function is(l, r, n) { window.arguments[0].SimpleTest.is(l,r,n); }
+function ok(v, n) { window.arguments[0].SimpleTest.ok(v,n); }
+
+function initEvents(target)
+{
+ target.addEventListener("focus", eventOccured, true);
+ target.addEventListener("blur", eventOccured, true);
+ getTopWindow(target).addEventListener("activate", eventOccured, true);
+ getTopWindow(target).addEventListener("deactivate", eventOccured, true);
+}
+
+function eventOccured(event)
+{
+ // iframes should never receive focus or blur events directly
+ if (Element.isInstance(event.target) && event.target.localName == "iframe")
+ ok(false, "iframe " + event.type + "occured");
+
+ var id;
+ if (gOldExpectedWindow && event.type == "blur") {
+ if (Window.isInstance(event.target))
+ id = "frame-" + gOldExpectedWindow.document.documentElement.id + "-window";
+ else if (Document.isInstance(event.target))
+ id = "frame-" + gOldExpectedWindow.document.documentElement.id + "-document";
+ else
+ id = event.originalTarget.id;
+ }
+ else if (gNewExpectedWindow && event.type == "focus") {
+ if (Window.isInstance(event.target))
+ id = "frame-" + gNewExpectedWindow.document.documentElement.id + "-window";
+ else if (Document.isInstance(event.target))
+ id = "frame-" + gNewExpectedWindow.document.documentElement.id + "-document";
+ else
+ id = event.originalTarget.id;
+ }
+ else if (event.type == "activate" || event.type == "deactivate")
+ id = event.target.document.documentElement.id + "-window";
+ else if (Window.isInstance(event.target))
+ id = (event.target == window) ? "outer-window" : "child-window";
+ else if (Document.isInstance(event.target))
+ id = (event.target == document) ? "outer-document" : "child-document";
+ else
+ id = event.originalTarget.id;
+
+ if (gEvents)
+ gEvents += " ";
+ gEvents += event.type + ": " + id;
+}
+
+function expectFocusShift(callback, expectedWindow, expectedElement, focusChanged, testid)
+{
+ if (expectedWindow == null)
+ expectedWindow = expectedElement ?
+ expectedElement.ownerGlobal :
+ gLastFocusWindow;
+
+ var expectedEvents = "";
+ if (focusChanged) {
+ var id;
+ if (getTopWindow(gLastFocusWindow) != getTopWindow(expectedWindow)) {
+ id = getTopWindow(gLastFocusWindow).document.documentElement.id;
+ expectedEvents += "deactivate: " + id + "-window";
+ }
+
+ if (gLastFocus && gLastFocus.id != "t" + kChildDocumentRootIndex &&
+ (!gOldExpectedWindow || gOldExpectedWindow.document.documentElement != gLastFocus)) {
+ if (expectedEvents)
+ expectedEvents += " ";
+ if (!gOldExpectedWindow)
+ expectedEvents += "commandupdate: cu ";
+ expectedEvents += "blur: " + gLastFocus.id;
+ }
+
+ if (gLastFocusWindow && gLastFocusWindow != expectedWindow) {
+ if (!gMoveToFocusFrame) {
+ if (gOldExpectedWindow)
+ id = "frame-" + gOldExpectedWindow.document.documentElement.id;
+ else
+ id = (gLastFocusWindow == window) ? "outer" : "child";
+ if (expectedEvents)
+ expectedEvents += " ";
+ expectedEvents += "blur: " + id + "-document " +
+ "blur: " + id + "-window";
+ }
+ }
+
+ if (getTopWindow(gLastFocusWindow) != getTopWindow(expectedWindow)) {
+ id = getTopWindow(expectedWindow).document.documentElement.id;
+ if (expectedEvents)
+ expectedEvents += " ";
+ expectedEvents += "activate: " + id + "-window";
+ }
+
+ if (expectedWindow && gLastFocusWindow != expectedWindow) {
+ if (gNewExpectedWindow)
+ id = "frame-" + gNewExpectedWindow.document.documentElement.id;
+ else
+ id = (expectedWindow == window) ? "outer" : "child";
+ if (expectedEvents)
+ expectedEvents += " ";
+ expectedEvents += "focus: " + id + "-document " +
+ "focus: " + id + "-window";
+ }
+
+ // for this test which fires a mouse event on a label, the document will
+ // be focused first and then the label code will focus the related
+ // control. This doesn't result in different focus events, but a command
+ // update will occur for the document and then a second command update will
+ // occur when the control is focused. However, this will only happen on
+ // platforms or controls where mouse clicks cause trigger focus.
+ if (testid == "mouse on html label with content inside" &&
+ mouseWillTriggerFocus(expectedElement)) {
+ expectedEvents += " commandupdate: cu";
+ }
+
+ if (expectedElement &&
+ (!gNewExpectedWindow || gNewExpectedWindow.document.documentElement != expectedElement)) {
+ if (!gNewExpectedWindow) {
+ if (expectedEvents)
+ expectedEvents += " ";
+ expectedEvents += "commandupdate: cu";
+ }
+ if (expectedElement.id != "t" + kChildDocumentRootIndex) {
+ if (expectedEvents)
+ expectedEvents += " ";
+ expectedEvents += "focus: " + expectedElement.id;
+ }
+ }
+ else if (expectedWindow && gLastFocusWindow != expectedWindow &&
+ !expectedElement) {
+ if (expectedEvents)
+ expectedEvents += " ";
+ expectedEvents += "commandupdate: cu";
+ }
+ }
+
+ gLastFocus = expectedElement;
+ gLastFocusWindow = expectedWindow;
+
+ callback();
+
+ compareEvents(expectedEvents, expectedWindow, expectedElement, testid);
+}
+
+function compareEvents(expectedEvents, expectedWindow, expectedElement, testid)
+{
+ if (!gShowOutput) {
+ gEvents = "";
+ return;
+ }
+
+ is(gEvents, expectedEvents, testid + " events");
+ gEvents = "";
+
+ var doc;
+ if (expectedWindow == window)
+ doc = "outer-document";
+ else if (expectedWindow == gChildWindow)
+ doc = "inner-document";
+ else if (gNewExpectedWindow)
+ doc = gNewExpectedWindow.document.body ? gNewExpectedWindow.document.body.id :
+ gNewExpectedWindow.document.documentElement.id;
+ else
+ doc = "other-document";
+
+ var focusedElement = fm.focusedElement;
+ is(focusedElement ? focusedElement.id : "none",
+ expectedElement ? expectedElement.id : "none", testid + " focusedElement");
+ is(fm.focusedWindow, expectedWindow, testid + " focusedWindow");
+ var focusedWindow = {};
+ is(fm.getFocusedElementForWindow(expectedWindow, false, focusedWindow),
+ expectedElement, testid + " getFocusedElementForWindow");
+ is(focusedWindow.value, expectedWindow, testid + " getFocusedElementForWindow frame");
+ is(expectedWindow.document.hasFocus(), true, testid + " hasFocus");
+ is(expectedWindow.document.activeElement ? expectedWindow.document.activeElement.id : "none",
+ expectedElement ? expectedElement.id : doc, testid + " activeElement");
+ var cdwindow = getTopWindow(expectedWindow);
+ if (cdwindow.document.commandDispatcher) {
+ is(cdwindow.document.commandDispatcher.focusedWindow, expectedWindow, testid + " commandDispatcher focusedWindow");
+ is(cdwindow.document.commandDispatcher.focusedElement, focusedElement, testid + " commandDispatcher focusedElement");
+ }
+
+ if (gLastFocusMethod != -1) {
+ is(fm.getLastFocusMethod(null), gLastFocusMethod, testid + " lastFocusMethod null");
+ is(fm.getLastFocusMethod(expectedWindow), gLastFocusMethod, testid + " lastFocusMethod window");
+ }
+
+ // the parent should have the iframe focused
+ if (doc == "inner-document") {
+ is(document.hasFocus(), true, testid + " hasFocus");
+ is(fm.getFocusedElementForWindow(window, false, focusedWindow),
+ $("childframe"), testid + " getFocusedElementForWindow for parent");
+ is(focusedWindow.value, window, testid + " getFocusedElementForWindow for parent frame");
+ is(fm.getFocusedElementForWindow(window, true, focusedWindow),
+ expectedElement, testid + " getFocusedElementForWindow deep for parent");
+ is(focusedWindow.value, gChildWindow, testid + " getFocusedElementForWindow deep for parent frame");
+ is(document.activeElement.id, "childframe", testid + " activeElement for parent");
+ }
+
+ // compare the selection for the child window. Skip mouse tests as the caret
+ // is adjusted by the selection code for mouse clicks, and not the focus code.
+ if (expectedWindow == window) {
+ var selection = window.getSelection();
+ ok(selection.focusNode == null && selection.focusOffset == 0 &&
+ selection.anchorNode == null && selection.anchorOffset == 0, testid + " selection");
+ }
+ else if ((expectedWindow == gChildWindow) && !testid.indexOf("mouse") == -1) {
+ checkSelection(expectedElement, testid);
+ }
+}
+
+function checkSelection(node, testid)
+{
+ var selection = gChildWindow.getSelection();
+
+ var range = gChildWindow.document.createRange();
+ range.selectNodeContents(node);
+ if (!node.firstChild || node.localName == "input" ||
+ node.localName == "select" || node.localName == "button") {
+ range.setStartBefore(node);
+ range.setEndBefore(node);
+ }
+
+ if (node.firstChild)
+ range.setEnd(range.startContainer, range.startOffset);
+
+ is(selection.focusNode, range.startContainer, testid + " selection focusNode");
+ is(selection.focusOffset, range.startOffset, testid + " selection focusOffset");
+ is(selection.anchorNode, range.endContainer, testid + " selection anchorNode");
+ is(selection.anchorOffset, range.endOffset, testid + " selection anchorOffset");
+}
+
+function getTopWindow(win)
+{
+ return win.browsingContext.topChromeWindow;
+}
+
+function mouseWillTriggerFocus(element)
+{
+ if (!element) {
+ return false;
+ }
+
+ if (SpecialPowers.getIntPref("accessibility.mouse_focuses_formcontrol") == 1) {
+ // This is a chrome document, so we'll only trigger focus with the mouse if the value of the pref is 1.
+ return true;
+ }
+
+ if (element.namespaceURI == "http://www.w3.org/1999/xhtml") {
+ // links are special. They can be focused but show no focus ring
+ if (element.localName == "a" || element.localName == "div" ||
+ element.localName == "select" ||
+ element.localName == "input" && (element.type == "text" ||
+ element.type == "password")) {
+ return true;
+ }
+ } else if (element.localName == "richlistbox") {
+ return true;
+ }
+
+ return false;
+}
+
+function mouseOnElement(element, expectedElement, focusChanged, testid)
+{
+ var expectedWindow = (element.ownerGlobal == gChildWindow) ? gChildWindow : window;
+ // on Mac, form elements are not focused when clicking, except for lists and inputs.
+ var noFocusOnMouse = !mouseWillTriggerFocus(element)
+
+ if (noFocusOnMouse) {
+ // no focus so the last focus method will be 0
+ gLastFocusMethod = 0;
+ expectFocusShift(() => synthesizeMouse(element, 4, 4, { }, element.ownerGlobal),
+ expectedWindow, null, true, testid);
+ gLastFocusMethod = fm.FLAG_BYMOUSE;
+ }
+ else {
+ expectFocusShift(() => synthesizeMouse(element, 4, 4, { }, element.ownerGlobal),
+ element.ownerGlobal,
+ expectedElement, focusChanged, testid);
+ }
+}
+
+function done()
+{
+ var opener = window.arguments[0];
+ window.close();
+ window.arguments[0].SimpleTest.finish();
+}
+
+var pressTab = () => synthesizeKey("KEY_Tab");
+
+function setFocusTo(id, fwindow)
+{
+ gLastFocus = getById(id);
+ gLastFocusWindow = fwindow;
+ if (gLastFocus)
+ gLastFocus.focus();
+ else
+ fm.clearFocus(fwindow);
+ gEvents = "";
+}
+
+function getById(id)
+{
+ if (gNewExpectedWindow)
+ return gNewExpectedWindow.document.getElementById(id);
+ var element = $(id);
+ if (!element)
+ element = $("childframe").contentDocument.getElementById(id);
+ return element;
+}
+
+function startTest()
+{
+ if (gTestStarted)
+ return;
+ gTestStarted = true;
+
+ gChildWindow = $("childframe").contentWindow;
+ gShowOutput = true;
+
+ // synthesize a mousemove over the image to ensure that the imagemap data is
+ // created. Otherwise, the special imagemap frames might not exist, and
+ // won't be focusable.
+ synthesizeMouse(getById("image"), 4, 4, { type: "mousemove" }, gChildWindow);
+
+ initEvents(window);
+
+ is(fm.activeWindow, window, "activeWindow");
+ is(gChildWindow.document.hasFocus(), false, " child document hasFocus");
+
+ // test to see if the Mac Full Keyboard Access setting is set. If t3 is
+ // focused after tab is pressed, then it is set to inputs and lists only.
+ // Otherwise, all elements are in the tab order.
+ pressTab();
+
+ if (fm.focusedElement.id == "t3")
+ gPartialTabbing = true;
+ else
+ is(fm.focusedElement.id, "t1", "initial tab key");
+
+ is(fm.getLastFocusMethod(null), fm.FLAG_BYKEY, "last focus method null start");
+ is(fm.getLastFocusMethod(window), fm.FLAG_BYKEY, "last focus method window start");
+
+ fm.clearFocus(window);
+ gEvents = "";
+
+ gLastFocusMethod = fm.FLAG_BYKEY;
+ if (gPartialTabbing) {
+ var partialTabList = ["t3", "t5", "t9", "t10", "t11", "t12", "t13", "t14", "t15",
+ "t16", "t19", "t20", "t21", "t22", "t26", "t27", "t28", "t29", "t30"];
+ for (var idx = 0; idx < partialTabList.length; idx++) {
+ expectFocusShift(pressTab, null, getById(partialTabList[idx]), true, "partial tab key " + partialTabList[idx]);
+ }
+ setFocusTo("last", window);
+ expectFocusShift(pressTab, null, getById(partialTabList[0]), true, "partial tab key wrap to start");
+ expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}),
+ null, getById("last"), true, "partial shift tab key wrap to end");
+ for (var idx = partialTabList.length - 1; idx >= 0; idx--) {
+ expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}),
+ null, getById(partialTabList[idx]), true, "partial tab key " + partialTabList[idx]);
+ }
+ }
+ else {
+ // TAB key
+ for (var idx = 1; idx <= kTabbableSteps; idx++) {
+ expectFocusShift(pressTab, null, getById("t" + idx), true, "tab key t" + idx);
+ }
+
+ // wrapping around at end with TAB key
+ setFocusTo("last", window);
+ expectFocusShift(pressTab, null, getById("t1"), true, "tab key wrap to start");
+ expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}),
+ null, getById("last"), true, "shift tab key wrap to end");
+
+ // Shift+TAB key
+ setFocusTo("o5", window);
+ for (idx = kTabbableSteps; idx > 0; idx--) {
+ expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}),
+ null, getById("t" + idx), true, "shift tab key t" + idx);
+ }
+ }
+
+ var t19 = getById("t19");
+ is(t19.selectionStart, 0, "input focused from tab key selectionStart");
+ is(t19.selectionEnd, 5, "input focused from tab key selectionEnd");
+ t19.setSelectionRange(0, 0);
+
+ gLastFocusMethod = 0;
+ var selectFired = false;
+ function selectListener() { selectFired = true; }
+ t19.addEventListener("select", selectListener, false);
+ expectFocusShift(() => t19.select(),
+ null, getById("t" + 19), true, "input.select()");
+ t19.removeEventListener("select", selectListener, false);
+ ok(!selectFired, "select event does not fire asynchronously for input");
+
+ // mouse clicking
+ gLastFocusMethod = fm.FLAG_BYMOUSE;
+ for (idx = kTabbableSteps; idx >= 1; idx--) {
+ // skip the document root and the overflow element
+ if (idx == kChildDocumentRootIndex || idx == kOverflowElementIndex)
+ continue;
+ if ((navigator.platform.indexOf("Mac") == 0) && (idx == kBeforeTabboxIndex + 1))
+ continue;
+
+ var element = getById("t" + idx);
+ // skip area elements, as getBoundingClientRect doesn't return their actual coordinates
+ if (element.localName == "area")
+ continue;
+
+ mouseOnElement(element, element, true, "mouse on element t" + idx);
+ var expectedWindow = (element.ownerGlobal == gChildWindow) ? gChildWindow : window;
+ if (element.localName == "richlistbox" && expectedWindow == window &&
+ navigator.platform.indexOf("Mac") == 0) {
+ // after focusing a listbox on Mac, clear the focus before continuing.
+ setFocusTo(null, window);
+ }
+ }
+
+ ok(t19.selectionStart == t19.selectionEnd, "input focused from mouse selection");
+
+ // mouse clicking on elements that are not tabbable
+ for (idx = 1; idx <= kFocusSteps; idx++) {
+ var element = getById("o" + (idx % 2 ? idx : idx - 1));
+
+ mouseOnElement(element, element, idx % 2,
+ "mouse on non-tabbable element o" + idx);
+ }
+
+ // mouse clicking on elements that are not tabbable and have user-focus: none
+ // or are not focusable for other reasons (for instance, being disabled)
+ // These elements will clear the focus when clicked.
+ for (idx = 1; idx <= kNoFocusSteps; idx++) {
+ var element = getById("n" + idx);
+ gLastFocusMethod = idx % 2 ? 0 : fm.FLAG_BYMOUSE;
+
+ mouseOnElement(element, idx % 2 ? null: element, true, "mouse on unfocusable element n" + idx);
+ }
+
+ if (idx == kOverflowElementIndex) {
+ gLastFocusMethod = fm.FLAG_BYMOUSE;
+ var element = getById("t" + idx);
+ expectFocusShift(() => synthesizeMouse(element, 4, 4, { }, element.ownerGlobal),
+ window, null, true, "mouse on scrollable element");
+ }
+
+ // focus() method
+ gLastFocusMethod = fm.FLAG_BYJS;
+ for (idx = kTabbableSteps; idx >= 1; idx--) {
+ if ((navigator.platform.indexOf("Mac") == 0) && (idx == kBeforeTabboxIndex + 1))
+ continue;
+ expectFocusShift(() => getById("t" + idx).focus(),
+ null, getById("t" + idx), true, "focus method on element t" + idx);
+ }
+
+ $("t1").focus();
+ ok(gEvents === "", "focusing element that is already focused");
+
+ $("t2").blur();
+ $("t7").blur();
+ ok(gEvents === "", "blurring element that is not focused");
+ is(document.activeElement, $("t1"), "old element still focused after blur() on another element");
+
+ // focus() method on elements that are not tabbable
+ for (idx = 1; idx <= kFocusSteps; idx++) {
+ var expected = getById("o" + (idx % 2 ? idx : idx - 1));
+ expectFocusShift(() => getById("o" + idx).focus(),
+ expected.ownerGlobal,
+ expected, idx % 2, "focus method on non-tabbable element o" + idx);
+ }
+
+ // focus() method on elements that are not tabbable and have user-focus: none
+ // or are not focusable for other reasons (for instance, being disabled)
+ for (idx = 1; idx <= kNoFocusSteps; idx++) {
+ var expected = getById("o" + (idx % 2 ? idx : idx - 1));
+ expectFocusShift(() => getById("o" + idx).focus(),
+ expected.ownerGlobal,
+ expected, idx % 2, "focus method on unfocusable element n" + idx);
+ }
+
+ // the focus() method on the legend element should focus the legend if it is
+ // focusable, or the first element after the legend if it is not focusable.
+ if (!gPartialTabbing) {
+ gLastFocusMethod = fm.FLAG_BYJS;
+ var legend = getById("legend");
+ expectFocusShift(() => legend.focus(),
+ null, getById("t28"), true, "focus method on unfocusable legend");
+ legend.tabIndex = "0";
+ expectFocusShift(() => legend.focus(),
+ null, getById("legend"), true, "focus method on focusable legend");
+ legend.tabIndex = "-1";
+ }
+
+ var accessKeyDetails = (navigator.platform.includes("Mac")) ?
+ { ctrlKey : true } : { altKey : true };
+
+ // test accesskeys
+ var keys = ["t26", "t19", "t22", "t29", "t15", "t17", "n6",
+ "t4", "o1", "o9", "n4"];
+ for (var k = 0; k < keys.length; k++) {
+ var key = String.fromCharCode(65 + k);
+
+ // accesskeys D and G are for labels so get redirected
+ gLastFocusMethod = (key == "D" || key == "G") ? fm.FLAG_BYMOVEFOCUS : fm.FLAG_BYKEY;
+
+ // on Windows and Linux, the shift key must be pressed for content area access keys
+ // and on Mac, the alt key must be pressed for content area access keys
+ var isContent = (getById(keys[k]).ownerGlobal == gChildWindow);
+ if (!navigator.platform.includes("Mac")) {
+ accessKeyDetails.shiftKey = isContent;
+ } else {
+ accessKeyDetails.altKey = isContent;
+ }
+
+ expectFocusShift(() => synthesizeKey(key, accessKeyDetails),
+ null, getById(keys[k]), true, "accesskey " + key);
+ }
+
+ // clicking on the labels
+ gLastFocusMethod = fm.FLAG_BYMOVEFOCUS | fm.FLAG_BYMOUSE;
+ mouseOnElement(getById("ad"), getById("t29"), true, "mouse on html label with content inside");
+ mouseOnElement(getById("ag"), getById("n6"), true, "mouse on html label with for attribute");
+ gLastFocusMethod = fm.FLAG_BYJS;
+ expectFocusShift(() => synthesizeMouse(getById("aj"), 2, 2, { }),
+ null, getById("o9"), true, "mouse on xul label with content inside");
+ expectFocusShift(() => synthesizeMouse(getById("ak"), 2, 2, { }),
+ null, getById("n4"), true, "mouse on xul label with control attribute");
+
+ // test accesskeys that shouldn't work
+ k = "o".charCodeAt(0);
+ gLastFocusMethod = fm.FLAG_BYJS;
+ while (k++ < "v".charCodeAt(0)) {
+ var key = String.fromCharCode(k);
+ expectFocusShift(() => synthesizeKey(key, accessKeyDetails),
+ window, getById("n4"), false, "non accesskey " + key);
+ }
+ gLastFocusMethod = -1;
+
+ // should focus the for element when using the focus method on a label as well
+ expectFocusShift(() => getById("ad").focus(),
+ null, getById("t29"), true, "mouse on html label using focus method");
+
+ // make sure that the text is selected when clicking a label associated with an input
+ getById("ag").htmlFor = "t19";
+ expectFocusShift(() => synthesizeMouse(getById("ag"), 2, 2, { }, gChildWindow),
+ null, getById("t19"), true, "mouse on html label with for attribute changed");
+ is(t19.selectionStart, 0, "input focused from label, selectionStart");
+ is(t19.selectionEnd, 5, "input focused from label, selectionEnd");
+
+ // switch to another panel in a tabbox and ensure that tabbing moves between
+ // elements on the new panel.
+ $("tabbox").selectedIndex = 1;
+ expectFocusShift(() => getById("t" + kBeforeTabboxIndex).focus(),
+ null, getById("t" + kBeforeTabboxIndex), true, "focus method on element before tabbox");
+
+ if (!gPartialTabbing) {
+ expectFocusShift(pressTab, null, getById("tab2"), true, "focus method on tab");
+ expectFocusShift(pressTab, null, getById("htab1"), true, "tab key switch tabpanel 1");
+ expectFocusShift(pressTab, null, getById("htab2"), true, "tab key switch tabpanel 2");
+ expectFocusShift(pressTab, null, getById("t" + (kBeforeTabboxIndex + 4)), true, "tab key switch tabpanel 3");
+ }
+ $("tabbox").selectedIndex = 0;
+
+ // ---- the following checks when the focus changes during a blur or focus event ----
+
+ var o5 = $("o5");
+ var o9 = $("o9");
+ var t3 = $("t3");
+ var t17 = getById("t17");
+ var t19 = getById("t19");
+ var shiftFocusParentDocument = () => o9.focus();
+ var shiftFocusChildDocument = () => t17.focus();
+
+ var trapBlur = function (element, eventListener, blurFunction)
+ {
+ element.focus();
+ gEvents = "";
+ element.addEventListener("blur", eventListener, false);
+ blurFunction();
+ element.removeEventListener("blur", eventListener, false);
+ }
+
+ var functions = [
+ element => element.focus(),
+ element => synthesizeMouse(element, 4, 4, { }, element.ownerGlobal)
+ ];
+
+ // first, check cases where the focus is adjusted during the blur event. Iterate twice,
+ // once with the focus method and then focusing by mouse clicking
+ for (var l = 0; l < 2; l++) {
+ var adjustFocus = functions[l];
+ var mod = (l == 1) ? " with mouse" : "";
+
+ // an attempt is made to switch the focus from one element (o5) to another
+ // element (t3) within the same document, yet the focus is shifted to a
+ // third element (o9) in the same document during the blur event for the
+ // first element.
+ trapBlur(o5, shiftFocusParentDocument, () => adjustFocus(t3));
+ compareEvents("commandupdate: cu blur: o5 commandupdate: cu focus: o9",
+ window, o9, "change focus to sibling during element blur, attempted sibling" + mod);
+
+ // similar, but the third element (t17) is in a child document
+ trapBlur(o9, shiftFocusChildDocument, () => adjustFocus(t3));
+ compareEvents("commandupdate: cu blur: o9 blur: outer-document blur: outer-window " +
+ "focus: child-document focus: child-window commandupdate: cu focus: t17",
+ gChildWindow, t17, "change focus to child document during element blur, attempted sibling" + mod);
+
+ // similar, but an attempt to switch focus within the same document, but the
+ // third element (t17) is in a parent document
+ trapBlur(t17, shiftFocusParentDocument, () => adjustFocus(t19));
+ compareEvents("commandupdate: cu blur: t17 blur: child-document blur: child-window " +
+ "focus: outer-document focus: outer-window commandupdate: cu focus: o9",
+ window, o9, "change focus to parent document during element blur, attempted sibling" + mod);
+
+ // similar, but blur is called instead of switching focus
+ trapBlur(t3, shiftFocusParentDocument, () => t3.blur());
+ compareEvents("commandupdate: cu blur: t3 commandupdate: cu focus: o9",
+ window, o9, "change focus to same document during clear focus" + mod);
+
+ // check when an element in the same document is focused during the
+ // element's blur event, but an attempt was made to focus an element in the
+ // child document. In this case, the focus in the parent document should be
+ // what was set during the blur event, but the actual focus should still
+ // move to the child document.
+ trapBlur(t3, shiftFocusParentDocument, () => adjustFocus(t17));
+ compareEvents("commandupdate: cu blur: t3 commandupdate: cu focus: o9 " +
+ "blur: outer-document blur: outer-window " +
+ "focus: child-document focus: child-window commandupdate: cu focus: t17",
+ gChildWindow, t17, "change focus to sibling during element blur, attempted child" + mod);
+ is(fm.getFocusedElementForWindow(window, false, {}), $("childframe"),
+ "change focus to sibling during element blur, attempted child, focused in parent" + mod);
+
+ // similar, but with a parent
+ trapBlur(t19, shiftFocusChildDocument, () => adjustFocus(t3));
+ compareEvents("commandupdate: cu blur: t19 commandupdate: cu focus: t17 " +
+ "blur: child-document blur: child-window " +
+ "focus: outer-document focus: outer-window commandupdate: cu focus: t3",
+ window, t3, "change focus to sibling during element blur, attempted parent" + mod);
+ is(fm.getFocusedElementForWindow(gChildWindow, false, {}), t17,
+ "change focus to sibling during element blur, attempted child, focused in child" + mod);
+
+ // similar, with a child, but the blur event focuses a child element also
+ trapBlur(t3, shiftFocusChildDocument, () => adjustFocus(t19));
+ compareEvents("commandupdate: cu blur: t3 blur: outer-document blur: outer-window " +
+ "focus: child-document focus: child-window commandupdate: cu focus: t17",
+ gChildWindow, t17, "change focus to child during element blur, attempted child" + mod);
+
+ // similar, with a parent, where the blur event focuses a parent element also
+ trapBlur(t17, shiftFocusParentDocument, () => adjustFocus(t3));
+ compareEvents("commandupdate: cu blur: t17 blur: child-document blur: child-window " +
+ "focus: outer-document focus: outer-window commandupdate: cu focus: o9",
+ window, o9, "change focus to parent during element blur, attempted parent" + mod);
+ }
+
+ var trapFocus = function (element, eventListener)
+ {
+ element.addEventListener("focus", eventListener, false);
+ element.focus();
+ element.removeEventListener("focus", eventListener, false);
+ }
+
+ fm.clearFocus(window);
+ gEvents = "";
+
+ // next, check cases where the focus is adjusted during the focus event
+
+ // switch focus to an element in the same document
+ trapFocus(o5, shiftFocusParentDocument);
+ compareEvents("commandupdate: cu focus: o5 commandupdate: cu blur: o5 commandupdate: cu focus: o9",
+ window, o9, "change focus to sibling during element focus");
+
+ // similar, but the new element (t17) is in a child document
+ trapFocus(o5, shiftFocusChildDocument);
+ compareEvents("commandupdate: cu blur: o9 " +
+ "commandupdate: cu focus: o5 commandupdate: cu blur: o5 " +
+ "blur: outer-document blur: outer-window " +
+ "focus: child-document focus: child-window commandupdate: cu focus: t17",
+ gChildWindow, t17, "change focus to child document during element focus");
+
+ // similar, but the new element (o9) is in a parent document.
+ trapFocus(t19, shiftFocusParentDocument);
+ compareEvents("commandupdate: cu blur: t17 " +
+ "commandupdate: cu focus: t19 commandupdate: cu blur: t19 " +
+ "blur: child-document blur: child-window " +
+ "focus: outer-document focus: outer-window commandupdate: cu focus: o9",
+ window, o9, "change focus to parent document during element focus");
+
+ // clear the focus during the focus event
+ trapFocus(t3, () => fm.clearFocus(window));
+ compareEvents("commandupdate: cu blur: o9 commandupdate: cu focus: t3 commandupdate: cu blur: t3",
+ window, null, "clear focus during focus event");
+
+ if (!gPartialTabbing)
+ doCommandDispatcherTests();
+
+ testMoveFocus();
+
+ doRemoveTests();
+
+ // tests various focus manager apis for null checks
+ var exh = false;
+ try {
+ fm.clearFocus(null);
+ }
+ catch (ex) { exh = true; }
+ is(exh, true, "clearFocus with null window causes exception");
+
+ var exh = false;
+ try {
+ fm.getFocusedElementForWindow(null, false, focusedWindow);
+ }
+ catch (ex) { exh = true; }
+ is(exh, true, "getFocusedElementForWindow with null window causes exception");
+
+ // just make sure that this doesn't crash
+ fm.moveCaretToFocus(null);
+
+ // ---- tests for the FLAG_NOSWITCHFRAME flag
+ getById("o5").focus();
+ gLastFocusMethod = fm.FLAG_BYJS;
+ gEvents = "";
+ // focus is being shifted in a child, so the focus should not change
+ expectFocusShift(() => fm.setFocus(getById("t20"), fm.FLAG_NOSWITCHFRAME),
+ window, getById("o5"), false, "no switch frame focus to child");
+ setFocusTo("t20", gChildWindow);
+
+ gLastFocusMethod = 0;
+
+ // here, however, focus is being shifted in a parent, which will have to blur
+ // the child, so the focus will always change
+ expectFocusShift(() => fm.setFocus(getById("o5"), fm.FLAG_NOSWITCHFRAME),
+ window, getById("o5"), true, "no switch frame focus to parent");
+
+ expectFocusShift(() => fm.setFocus(getById("t1"), fm.FLAG_NOSWITCHFRAME),
+ window, getById("t1"), true, "no switch frame focus to same window");
+
+ // ---- tests for focus and scrolling into view ----
+ var inscroll = getById("inscroll");
+ inscroll.tabIndex = 0;
+ is(inscroll.parentNode.scrollTop, 0, "scroll position before focus");
+ inscroll.focus();
+ ok(inscroll.parentNode.scrollTop > 5, "scroll position after focus");
+ inscroll.parentNode.scrollTop = 0;
+ fm.setFocus(inscroll, fm.FLAG_NOSCROLL);
+ is(inscroll.parentNode.scrollTop, 0, "scroll position after noscroll focus");
+
+ getById("t9").focus();
+ getById("inpopup1").focus();
+ is(fm.focusedElement, getById("t9"), "focus in closed popup");
+
+ // ---- tests to check if tabbing out of a input works
+
+ setFocusTo("t1", window);
+
+ var input1 = document.createElement("input");
+ $("innerbox").appendChild(input1);
+
+ var input2 = document.createElement("input");
+ $("innerbox").appendChild(input2);
+
+ gLastFocusMethod = fm.FLAG_BYJS;
+ expectFocusShift(() => input2.focus(),
+ null, input2, true, "focus on input");
+ gLastFocusMethod = fm.FLAG_BYKEY;
+ expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}),
+ null, input1, true, "shift+tab on input");
+
+ input1.tabIndex = 2;
+ input2.tabIndex = 2;
+ gLastFocusMethod = fm.FLAG_BYJS;
+ expectFocusShift(() => input2.focus(),
+ null, input2, true, "focus on input with tabindex set");
+ gLastFocusMethod = fm.FLAG_BYKEY;
+ expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}),
+ null, input1, true, "shift+tab on input with tabindex set");
+
+ // ---- test to check that refocusing an element during a blur event doesn't succeed
+
+ var t1 = getById("t1");
+ t1.addEventListener("blur", () => t1.focus(), true);
+ t1.focus();
+ var t3 = getById("t3");
+ synthesizeMouse(t3, 2, 2, { });
+ is(fm.focusedElement, t3, "focus during blur");
+
+ setFocusTo("t9", window);
+ gLastFocusMethod = -1;
+ window.openDialog("focus_window2.xhtml", "_blank", "chrome", otherWindowFocused);
+}
+
+function doCommandDispatcherTests()
+{
+ var t19 = getById("t19");
+ t19.focus();
+ gLastFocusWindow = gChildWindow;
+ gLastFocus = t19;
+ gEvents = "";
+
+ expectFocusShift(() => document.commandDispatcher.focusedElement = getById("o9"),
+ null, getById("o9"), true, "command dispatcher set focusedElement");
+ expectFocusShift(() => document.commandDispatcher.advanceFocus(),
+ null, getById("o13"), true, "command dispatcher advanceFocus");
+ expectFocusShift(() => document.commandDispatcher.rewindFocus(),
+ null, getById("o9"), true, "command dispatcher rewindFocus");
+ expectFocusShift(() => document.commandDispatcher.focusedElement = null,
+ null, null, true, "command dispatcher set focusedElement to null");
+ expectFocusShift(() => document.commandDispatcher.focusedWindow = gChildWindow,
+ null, getById("t19"), true, "command dispatcher set focusedElement to null");
+ expectFocusShift(() => document.commandDispatcher.focusedElement = null,
+ gChildWindow, null, true, "command dispatcher set focusedElement to null in child");
+ expectFocusShift(() => document.commandDispatcher.advanceFocusIntoSubtree(getById("t19")),
+ null, getById("t20"), true, "command dispatcher advanceFocusIntoSubtree child");
+ expectFocusShift(() => document.commandDispatcher.advanceFocusIntoSubtree(null),
+ null, getById("t21"), true, "command dispatcher advanceFocusIntoSubtree null child");
+ expectFocusShift(() => document.commandDispatcher.advanceFocusIntoSubtree(getById("o9").parentNode),
+ null, getById("o9"), true, "command dispatcher advanceFocusIntoSubtree parent");
+}
+
+function doRemoveTests()
+{
+ // next, some tests which remove elements
+ var t19 = getById("t19");
+ t19.focus();
+ t19.remove();
+
+ is(fm.focusedElement, null, "removed element focusedElement");
+ is(fm.focusedWindow, gChildWindow, "removed element focusedWindow");
+ is(gChildWindow.document.hasFocus(), true, "removed element hasFocus");
+ is(gChildWindow.document.activeElement, getById("inner-document"), "removed element activeElement");
+
+ getById("t15").focus();
+ var abs = getById("abs");
+ abs.remove();
+
+ is(fm.focusedElement, null, "removed ancestor focusedElement");
+ is(fm.focusedWindow, gChildWindow, "removed ancestor focusedWindow");
+ is(gChildWindow.document.hasFocus(), true, "removed ancestor hasFocus");
+ is(gChildWindow.document.activeElement, getById("inner-document"), "removed ancestor activeElement");
+}
+
+// tests for the FocusManager moveFocus method
+function testMoveFocus()
+{
+ setFocusTo("t6", window);
+
+ // moving focus while an element is already focused
+ var newFocus;
+ gLastFocusMethod = fm.FLAG_BYMOVEFOCUS;
+ var expectedFirst = getById(gPartialTabbing ? "t3" : "t1");
+ expectFocusShift(() => newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_FIRST, 0),
+ window, expectedFirst, true, "moveFocus to first null window null content");
+ is(newFocus, fm.focusedElement, "moveFocus to first null window null content return value");
+
+ expectFocusShift(() => newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_LAST, 0),
+ window, getById("last"), true, "moveFocus to last null window null content");
+ is(newFocus, fm.focusedElement, "moveFocus to last null window null content return value");
+
+ gLastFocusMethod = 0;
+ newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_ROOT, 0);
+ is(newFocus, null, "moveFocus to root null window null content return value");
+ is(fm.focusedWindow, window, "moveFocus to root null window null content focusedWindow");
+ is(fm.focusedElement, null, "moveFocus to root null window null content focusedElement");
+
+ // moving focus while no element is focused
+ fm.clearFocus(window);
+ gEvents = "";
+ gLastFocus = null;
+ gLastFocusMethod = fm.FLAG_BYMOVEFOCUS;
+ expectFocusShift(() => newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_FIRST, 0),
+ window, expectedFirst, true, "moveFocus to first null window null content no focus");
+ is(newFocus, fm.focusedElement, "moveFocus to first null window null content no focus return value");
+ fm.clearFocus(window);
+ gEvents = "";
+ gLastFocus = null;
+ expectFocusShift(() => newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_LAST, 0),
+ window, getById("last"), true, "moveFocus to last null window null content no focus");
+ is(newFocus, fm.focusedElement, "moveFocus to last null window null content no focus return value");
+ fm.clearFocus(window);
+ gEvents = "";
+ gLastFocusMethod = 0;
+ newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_ROOT, 0);
+ is(newFocus, null, "moveFocus to root null window null content no focus return value");
+ is(fm.focusedWindow, window, "moveFocus to root null window null content no focus focusedWindow");
+ is(fm.focusedElement, null, "moveFocus to root null window null content no focus focusedElement");
+
+ // moving focus from a specified element
+ setFocusTo("t6", window);
+ gLastFocusMethod = fm.FLAG_BYMOVEFOCUS;
+ expectFocusShift(() => newFocus = fm.moveFocus(null, getById("specialroot"), fm.MOVEFOCUS_FIRST, 0),
+ window, getById("t3"), true, "moveFocus to first null window with content");
+// XXXndeakin P3 this doesn't work
+// expectFocusShift(() => newFocus = fm.moveFocus(null, getById("specialroot"), fm.MOVEFOCUS_LAST, 0),
+// window, getById("o3"), true, "moveFocus to last null window with content");
+
+ // move focus to first in child window
+ expectFocusShift(() => newFocus = fm.moveFocus(gChildWindow, null, fm.MOVEFOCUS_FIRST, 0),
+ gChildWindow, getById("t" + (kChildDocumentRootIndex + 1)), true,
+ "moveFocus to first child window null content");
+ is(newFocus, getById("t" + (kChildDocumentRootIndex + 1)),
+ "moveFocus to first child window null content return value");
+
+ // move focus to last in child window
+ setFocusTo("t6", window);
+ var expectedLast = getById(gPartialTabbing ? "t30" : "t" + (kBeforeTabboxIndex - 1));
+ expectFocusShift(() => newFocus = fm.moveFocus(gChildWindow, null, fm.MOVEFOCUS_LAST, 0),
+ gChildWindow, expectedLast, true,
+ "moveFocus to last child window null content");
+ is(newFocus, getById(expectedLast),
+ "moveFocus to last child window null content return value");
+
+ // move focus to root in child window
+ setFocusTo("t6", window);
+ var childroot = getById("t" + kChildDocumentRootIndex);
+ gLastFocusMethod = 0;
+ newFocus = fm.moveFocus(gChildWindow, null, fm.MOVEFOCUS_ROOT, 0),
+ is(newFocus, childroot, "moveFocus to root child window null content return value");
+ is(fm.focusedWindow, gChildWindow, "moveFocus to root child window null content focusedWindow");
+ is(fm.focusedElement, childroot, "moveFocus to root child window null content focusedElement");
+
+ // MOVEFOCUS_CARET tests
+ getById("t20").focus();
+ gEvents = "";
+
+ var selection = gChildWindow.getSelection();
+ selection.removeAllRanges();
+
+ newFocus = fm.moveFocus(gChildWindow, null, fm.MOVEFOCUS_CARET, 0);
+ is(newFocus, null, "move caret when at document root");
+ is(fm.focusedElement, null, "move caret when at document root");
+
+ var node = getById("t16").firstChild;
+ var range = gChildWindow.document.createRange();
+ range.setStart(node, 3);
+ range.setEnd(node, 3);
+ selection.addRange(range);
+
+ newFocus = fm.moveFocus(gChildWindow, null, fm.MOVEFOCUS_CARET, 0);
+ is(newFocus, null, "move caret to non-link return value");
+ is(fm.focusedElement, null, "move caret to non-link");
+
+ var t25 = getById("t25");
+ var node = t25.firstChild;
+ range.setStart(node, 1);
+ range.setEnd(node, 1);
+ newFocus = fm.moveFocus(gChildWindow, null, fm.MOVEFOCUS_CARET, 0);
+
+ is(newFocus, t25, "move caret to link return value");
+ is(fm.focusedElement, t25, "move caret to link focusedElement");
+
+ // enable caret browsing temporarily to test caret movement
+ var prefs = Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefBranch);
+ prefs.setBoolPref("accessibility.browsewithcaret", true);
+
+ synthesizeKey("KEY_ArrowLeft", {}, gChildWindow);
+ synthesizeKey("KEY_ArrowLeft", {}, gChildWindow);
+ is(fm.focusedElement, null, "move caret away from link");
+
+ synthesizeKey("KEY_ArrowLeft", {}, gChildWindow);
+ is(fm.focusedElement, getById("t24"), "move caret away onto link");
+
+ prefs.setBoolPref("accessibility.browsewithcaret", false);
+
+ // cases where focus in on a content node with no frame
+
+ if (!gPartialTabbing) {
+ getById("t24").blur();
+ gEvents = "";
+ gLastFocus = null;
+ gLastFocusWindow = gChildWindow;
+ gLastFocusMethod = fm.FLAG_BYKEY;
+
+ selection.selectAllChildren(getById("hiddenspan"));
+ expectFocusShift(() => synthesizeKey("KEY_Tab"),
+ gChildWindow, getById("t26"), true, "tab with selection on hidden content");
+
+ setFocusTo($("o15"), window);
+ $("o15").hidden = true;
+ document.documentElement.getBoundingClientRect(); // flush after hiding
+ expectFocusShift(() => synthesizeKey("KEY_Tab"),
+ window, $("o17"), true, "tab with focus on hidden content");
+
+ $("o17").hidden = true;
+ document.documentElement.getBoundingClientRect();
+ expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}),
+ window, $("o13"), true, "shift+tab with focus on hidden content");
+ }
+
+ // cases with selection in an <input>
+
+ var t19 = getById("t19");
+ t19.setSelectionRange(0, 0);
+ setFocusTo("t18", gChildWindow);
+
+ gLastFocusMethod = fm.FLAG_BYMOVEFOCUS;
+ expectFocusShift(() => newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_FORWARD, 0),
+ gChildWindow, t19, true, "moveFocus to next input");
+ is(t19.selectionStart, 0, "input focused after moveFocus selectionStart");
+ is(t19.selectionEnd, 5, "input focused after moveFocus selectionEnd");
+
+ t19.setSelectionRange(0, 0);
+ setFocusTo("t18", gChildWindow);
+ gLastFocusMethod = fm.FLAG_BYKEY;
+ expectFocusShift(() => newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_FORWARD, fm.FLAG_BYKEY),
+ gChildWindow, t19, true, "moveFocus to next input by key");
+ is(t19.selectionStart, 0, "input focused after moveFocus by key selectionStart");
+ is(t19.selectionEnd, 5, "input focused after moveFocus by key selectionEnd");
+}
+
+function otherWindowFocused(otherWindow)
+{
+ var expectedElement = getById("t9");
+
+ is(fm.activeWindow, otherWindow, "other activeWindow");
+ is(fm.focusedWindow, otherWindow, "other focusedWindow");
+ is(window.document.hasFocus(), false, "when lowered document hasFocus");
+ var focusedWindow = {};
+ is(fm.getFocusedElementForWindow(window, false, focusedWindow),
+ expectedElement, "when lowered getFocusedElementForWindow");
+ is(focusedWindow.value, window, "when lowered getFocusedElementForWindow frame");
+ is(document.activeElement.id, expectedElement.id, "when lowered activeElement");
+ is(window.document.commandDispatcher.focusedWindow, window, " commandDispatcher in other window focusedWindow");
+ is(window.document.commandDispatcher.focusedElement, expectedElement, " commandDispatcher in other window focusedElement");
+
+ compareEvents("deactivate: outer-document-window blur: t9 blur: outer-document blur: outer-window",
+ otherWindow, null, "other window opened");
+
+ otherWindow.document.getElementById("other").focus();
+
+ for (var idx = kTabbableSteps; idx >= 1; idx--) {
+ expectedElement = getById("t" + idx);
+ if (!expectedElement) // skip elements that were removed in doRemoveTests()
+ continue;
+ if ((navigator.platform.indexOf("Mac") == 0) && (idx == kBeforeTabboxIndex + 1))
+ continue;
+
+ expectedElement.focus();
+
+ is(fm.focusedElement.id, "other", "when lowered focusedElement t" + idx);
+ is(fm.focusedWindow, otherWindow, "when lowered focusedWindow t" + idx);
+
+ var checkWindow = expectedElement.ownerGlobal;
+ is(fm.getFocusedElementForWindow(checkWindow, false, {}).id, expectedElement.id,
+ "when lowered getFocusedElementForWindow t" + idx);
+ is(checkWindow.document.activeElement.id, expectedElement.id, "when lowered activeElement t" + idx);
+ if (checkWindow != window) {
+ is(fm.getFocusedElementForWindow(window, false, {}), $("childframe"),
+ "when lowered parent getFocusedElementForWindow t" + idx);
+ is(document.activeElement.id, "childframe",
+ "when lowered parent activeElement t" + idx);
+ }
+ }
+
+ gEvents = gEvents.replace(/commandupdate: cu\s?/g, "");
+ is(gEvents, "", "when lowered no events fired");
+
+ var other = otherWindow.document.getElementById("other");
+ other.focus();
+ is(fm.focusedElement, other, "focus method in second window");
+
+ otherWindow.close();
+
+ getById("n2").focus();
+
+ // next, check modal dialogs
+ // XXXndeakin Bug 621399 - the modal dialog test as well as later tests sometime fail
+ // on Windows 8 so just end the test here.
+ if (navigator.userAgent.includes("Windows NT 6.2")) {
+ done();
+ }
+ else {
+ window.openDialog("focus_window2.xhtml", "_blank", "chrome,modal", modalWindowOpened);
+ }
+}
+
+function modalWindowOpened(modalWindow)
+{
+ var elem = modalWindow.document.getElementById("other");
+ if (gPartialTabbing)
+ elem.focus();
+ else
+ synthesizeKey("KEY_Tab", {}, modalWindow);
+ is(fm.activeWindow, modalWindow, "modal activeWindow");
+ is(fm.focusedElement, elem, "modal focusedElement");
+
+ modalWindow.close();
+ SimpleTest.waitForFocus(modalWindowClosed);
+}
+
+function modalWindowClosed()
+{
+ is(fm.activeWindow, window, "modal window closed activeWindow");
+ is(fm.focusedElement, getById("n2"), "modal window closed focusedElement");
+
+ window.arguments[0].framesetWindowLoaded = framesetWindowLoaded;
+ window.arguments[0].open("focus_frameset.html", "_blank", "width=400,height=400,toolbar=no");
+}
+
+function framesetWindowLoaded(framesetWindow)
+{
+ gLastFocus = null;
+ gLastFocusWindow = framesetWindow;
+ gEvents = "";
+
+ is(fm.activeWindow, getTopWindow(framesetWindow), "frameset window active");
+ gOldExpectedWindow = getTopWindow(framesetWindow);
+
+ gMoveToFocusFrame = true;
+ for (var idx = 1; idx <= 8; idx++) {
+ gNewExpectedWindow = framesetWindow.frames[(idx - 1) >> 1];
+ if (idx % 2)
+ initEvents(gNewExpectedWindow);
+ expectFocusShift(() => synthesizeKey("KEY_Tab", {}, framesetWindow),
+ gNewExpectedWindow, getById("f" + idx), true, "frameset tab key f" + idx);
+ gMoveToFocusFrame = false;
+ gOldExpectedWindow = gNewExpectedWindow;
+ }
+
+ gNewExpectedWindow = framesetWindow.frames[0];
+ expectFocusShift(() => synthesizeKey("KEY_Tab", {}, framesetWindow),
+ gNewExpectedWindow, getById("f1"), true, "frameset tab key wrap to start");
+ gOldExpectedWindow = gNewExpectedWindow;
+ gNewExpectedWindow = framesetWindow.frames[3];
+ expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}, framesetWindow),
+ gNewExpectedWindow, getById("f8"), true, "frameset shift tab key wrap to end");
+
+ for (idx = 7; idx >= 1; idx--) {
+ gOldExpectedWindow = gNewExpectedWindow;
+ gNewExpectedWindow = framesetWindow.frames[(idx - 1) >> 1];
+ expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}, framesetWindow),
+ gNewExpectedWindow, getById("f" + idx), true, "frameset shift tab key f" + idx);
+ }
+
+ // document shifting
+ // XXXndeakin P3 ctrl+tab doesn't seem to be testable currently for some reason
+ gNewExpectedWindow = framesetWindow.frames[1];
+ expectFocusShift(() => synthesizeKey("KEY_F6", {ctrlKey: true}, framesetWindow),
+ gNewExpectedWindow, getById("f3"), true, "switch document forward with f6");
+ gOldExpectedWindow = gNewExpectedWindow;
+ gNewExpectedWindow = framesetWindow.frames[2];
+ expectFocusShift(() => synthesizeKey("KEY_F6", {}, framesetWindow),
+ gNewExpectedWindow, getById("f5"), true, "switch document forward with ctrl+tab");
+ gOldExpectedWindow = gNewExpectedWindow;
+ gNewExpectedWindow = framesetWindow.frames[3];
+ expectFocusShift(() => synthesizeKey("KEY_F6", {ctrlKey: true}, framesetWindow),
+ gNewExpectedWindow, getById("f7"), true, "switch document forward with ctrl+f6");
+ gOldExpectedWindow = gNewExpectedWindow;
+ gNewExpectedWindow = framesetWindow.frames[0];
+ expectFocusShift(() => synthesizeKey("KEY_F6", {ctrlKey: true}, framesetWindow),
+ gNewExpectedWindow, getById("f1"), true, "switch document forward and wrap");
+
+// going backwards by document and wrapping doesn't currently work, but didn't work
+// before the focus reworking either
+
+/*
+ gOldExpectedWindow = gNewExpectedWindow;
+ gNewExpectedWindow = framesetWindow.frames[3];
+ expectFocusShift(() => synthesizeKey("KEY_F6", { ctrlKey: true, shiftKey: true }, framesetWindow),
+ gNewExpectedWindow, getById("f7"), true, "switch document backward and wrap");
+ */
+
+ fm.moveFocus(framesetWindow.frames[3], null, fm.MOVEFOCUS_ROOT, 0);
+ gEvents = "";
+
+ gOldExpectedWindow = gNewExpectedWindow;
+ gNewExpectedWindow = framesetWindow.frames[2];
+ expectFocusShift(() => synthesizeKey("KEY_F6", {ctrlKey: true, shiftKey: true}, framesetWindow),
+ gNewExpectedWindow, getById("f5"), true, "switch document backward with f6");
+ gOldExpectedWindow = gNewExpectedWindow;
+ gNewExpectedWindow = framesetWindow.frames[1];
+ expectFocusShift(() => synthesizeKey("KEY_F6", {ctrlKey: true, shiftKey: true}, framesetWindow),
+ gNewExpectedWindow, getById("f3"), true, "switch document backward with ctrl+tab");
+ gOldExpectedWindow = gNewExpectedWindow;
+ gNewExpectedWindow = framesetWindow.frames[0];
+ expectFocusShift(() => synthesizeKey("KEY_F6", {ctrlKey: true, shiftKey: true}, framesetWindow),
+ gNewExpectedWindow, getById("f1"), true, "switch document backward with ctrl+f6");
+
+ // skip the window switching tests for now on Linux, as raising and lowering
+ // a window is asynchronous there
+ if (!navigator.platform.includes("Linux")) {
+ window.openDialog("focus_window2.xhtml", "_blank", "chrome", switchWindowTest, framesetWindow);
+ }
+ else {
+ gOldExpectedWindow = null;
+ gNewExpectedWindow = null;
+ framesetWindow.close();
+ SimpleTest.waitForFocus(doWindowNoRootTest);
+ }
+}
+
+// test switching between two windows
+function switchWindowTest(otherWindow, framesetWindow)
+{
+ initEvents(otherWindow);
+ var otherElement = otherWindow.document.getElementById("other");
+ otherElement.focus();
+
+ framesetWindow.frames[1].document.getElementById("f4").focus();
+
+ is(fm.focusedElement, otherElement, "focus after inactive window focus");
+
+ gLastFocus = otherElement;
+ gLastFocusWindow = otherWindow;
+ gEvents = "";
+ gOldExpectedWindow = otherWindow;
+ gNewExpectedWindow = framesetWindow.frames[1];
+
+ expectFocusShift(() => gNewExpectedWindow.focus(),
+ gNewExpectedWindow, getById("f4"), true, "switch to frame in another window");
+ is(fm.getFocusedElementForWindow(otherWindow, false, {}).id, "other", "inactive window has focused element");
+
+ gOldExpectedWindow = framesetWindow.frames[1];
+ gNewExpectedWindow = otherWindow;
+ expectFocusShift(() => otherWindow.focus(),
+ gNewExpectedWindow, getById("other"), true, "switch to another window");
+
+ var topWindow = getTopWindow(framesetWindow);
+
+ ok(topWindow.document.commandDispatcher.getControllerForCommand("cmd_copy"),
+ "getControllerForCommand for focused window set");
+ ok(otherWindow.document.commandDispatcher.getControllerForCommand("cmd_copy"),
+ "getControllerForCommand for non-focused window set");
+ ok(topWindow.document.commandDispatcher.getControllerForCommand("cmd_copy") !=
+ otherWindow.document.commandDispatcher.getControllerForCommand("cmd_copy"),
+ "getControllerForCommand for two windows different");
+ ok(topWindow.document.commandDispatcher.getControllers() !=
+ otherWindow.document.commandDispatcher.getControllers(),
+ "getControllers for two windows different");
+
+ gOldExpectedWindow = otherWindow;
+ gNewExpectedWindow = framesetWindow.frames[1];
+ expectFocusShift(() => topWindow.focus(),
+ gNewExpectedWindow, getById("f4"), true, "switch to frame activeWindow");
+
+ fm.clearFocus(otherWindow);
+ gOldExpectedWindow = gNewExpectedWindow;
+ gNewExpectedWindow = otherWindow;
+ expectFocusShift(() => fm.setFocus(otherElement, fm.FLAG_RAISE),
+ gNewExpectedWindow, getById("other"), true, "switch to window with raise");
+
+ getTopWindow(framesetWindow).document.commandDispatcher.focusedWindow = gOldExpectedWindow;
+ is(fm.activeWindow, gNewExpectedWindow, "setting commandDispatcher focusedWindow doesn't raise window");
+
+ fm.moveFocus(otherWindow, null, fm.MOVEFOCUS_FORWARD, 0);
+ var otherInput = otherWindow.document.getElementById("other-input");
+ otherInput.setSelectionRange(2, 3);
+ topWindow.focus();
+ otherWindow.focus();
+ is(otherInput.selectionStart, 2, "selectionStart after input focus and window raise");
+ is(otherInput.selectionEnd, 3, "selectionEnd after input focus and window raise");
+ is(fm.getLastFocusMethod(null), fm.FLAG_BYMOVEFOCUS, "last focus method after input focus and window raise");
+
+ fm.clearFocus(otherWindow);
+
+ // test to ensure that a synthetic event won't move focus
+ var synevent = new FocusEvent("focus", {});
+ otherInput.dispatchEvent(synevent);
+ is(synevent.type, "focus", "event.type after synthetic focus event");
+ is(synevent.target, otherInput, "event.target after synthetic focus event");
+ is(fm.focusedElement, null, "focusedElement after synthetic focus event");
+ is(otherWindow.document.activeElement, otherWindow.document.documentElement,
+ "document.activeElement after synthetic focus event");
+
+ // check accessing a focus event after the event has finishing firing
+ function continueTest(event) {
+ is(event.type, "focus", "event.type after accessing focus event in timeout");
+ is(event.target, otherInput, "event.target after accessing focus event in timeout");
+
+ gOldExpectedWindow = null;
+ gNewExpectedWindow = null;
+ otherWindow.close();
+ framesetWindow.close();
+
+ SimpleTest.waitForFocus(doWindowNoRootTest);
+ }
+
+ function inputFocused(event) {
+ otherInput.removeEventListener("focus", inputFocused, true);
+ setTimeout(continueTest, 0, event);
+ }
+
+ otherInput.addEventListener("focus", inputFocused, true);
+ otherInput.focus();
+}
+
+// open a window with no root element
+var noRootWindow = null;
+function doWindowNoRootTest()
+{
+ addEventListener("focus", doFrameSwitchingTests, true);
+ noRootWindow = window.open("window_focus_inner.xhtml", "_blank", "chrome,width=100,height=100");
+}
+
+// these tests check when focus is moved between a tree of frames to ensure
+// that the focus is in the right place at each event step.
+function doFrameSwitchingTests()
+{
+ removeEventListener("focus", doFrameSwitchingTests, true);
+ noRootWindow.close();
+
+ var framea = document.getElementById("ifa");
+ var frameb = document.getElementById("ifb");
+ framea.style.MozUserFocus = "";
+ frameb.style.MozUserFocus = "";
+
+ window.removeEventListener("focus", eventOccured, true);
+ window.removeEventListener("blur", eventOccured, true);
+
+ var inputa = framea.contentDocument.body.firstChild;
+ inputa.focus();
+
+ addFrameSwitchingListeners(framea);
+ addFrameSwitchingListeners(frameb);
+ var framec = framea.contentDocument.body.lastChild;
+ addFrameSwitchingListeners(framec);
+
+ var framed = framec.contentDocument.body.lastChild;
+ addFrameSwitchingListeners(framed);
+
+ var inputc = framec.contentDocument.body.firstChild;
+
+ var expectedMainWindowFocus = framea;
+
+ // An element in the immediate parent frame is focused. Focus an element in
+ // the child. The child should be focused and the parent's current focus should
+ // be the child iframe.
+ gEventMatched = true;
+ is(fm.getFocusedElementForWindow(window, false, {}), expectedMainWindowFocus,
+ "parent of framea has iframe focused");
+ gExpectedEvents = [[inputa, "blur", null, framea.contentWindow, window, framea],
+ [framea.contentDocument, "blur", null, null, window, framea],
+ [framea.contentWindow, "blur", null, null, window, framea],
+ [framec.contentDocument, "focus", null, framec.contentWindow, window, framea],
+ [framec.contentWindow, "focus", null, framec.contentWindow, window, framea],
+ [inputc, "focus", inputc, framec.contentWindow, window, framea]];
+ inputc.focus();
+ ok(gEventMatched && !gExpectedEvents.length, "frame switch from parent input to child input" + gExpectedEvents);
+
+ // An element in a child is focused. Focus an element in the immediate
+ // parent.
+ gEventMatched = true;
+ gExpectedEvents = [[inputc, "blur", null, framec.contentWindow, window, framea],
+ [framec.contentDocument, "blur", null, null, window, framea],
+ [framec.contentWindow, "blur", null, null, window, framea],
+ [framea.contentDocument, "focus", null, framea.contentWindow, window, framea],
+ [framea.contentWindow, "focus", null, framea.contentWindow, window, framea],
+ [inputa, "focus", inputa, framea.contentWindow, window, framea]];
+ inputa.focus();
+ ok(gEventMatched && !gExpectedEvents.length, "frame switch from child input to parent input");
+
+ // An element in a frame is focused. Focus an element in a sibling frame.
+ // The common ancestor of the two frames should have its focused node
+ // cleared after the element is blurred.
+ var inputb = frameb.contentDocument.body.firstChild;
+
+ gEventMatched = true;
+ gExpectedEvents = [[inputa, "blur", null, framea.contentWindow, window, framea],
+ [framea.contentDocument, "blur", null, null, window, null],
+ [framea.contentWindow, "blur", null, null, window, null],
+ [frameb.contentDocument, "focus", null, frameb.contentWindow, window, frameb],
+ [frameb.contentWindow, "focus", null, frameb.contentWindow, window, frameb],
+ [inputb, "focus", inputb, frameb.contentWindow, window, frameb]];
+ inputb.focus();
+ ok(gEventMatched && !gExpectedEvents.length, "frame switch from input to sibling frame");
+ is(fm.getFocusedElementForWindow(framea.contentWindow, false, {}), inputa,
+ "blurred frame still has input as focus");
+
+ // focus a descendant in a sibling
+ var inputd = framed.contentDocument.body.firstChild;
+ gEventMatched = true;
+ gExpectedEvents = [[inputb, "blur", null, frameb.contentWindow, window, frameb],
+ [frameb.contentDocument, "blur", null, null, window, null],
+ [frameb.contentWindow, "blur", null, null, window, null],
+ [framed.contentDocument, "focus", null, framed.contentWindow, window, framea],
+ [framed.contentWindow, "focus", null, framed.contentWindow, window, framea],
+ [inputd, "focus", inputd, framed.contentWindow, window, framea]];
+ inputd.focus();
+ ok(gEventMatched && !gExpectedEvents.length, "frame switch from input to sibling descendant");
+ is(fm.getFocusedElementForWindow(framea.contentWindow, false, {}), framec,
+ "sibling parent focus has shifted to frame");
+
+ // focus an ancestor
+ gEventMatched = true;
+ gExpectedEvents = [[inputd, "blur", null, framed.contentWindow, window, framea],
+ [framed.contentDocument, "blur", null, null, window, framea],
+ [framed.contentWindow, "blur", null, null, window, framea],
+ [framea.contentDocument, "focus", null, framea.contentWindow, window, framea],
+ [framea.contentWindow, "focus", null, framea.contentWindow, window, framea],
+ [inputa, "focus", inputa, framea.contentWindow, window, framea]];
+ inputa.focus();
+ ok(gEventMatched && !gExpectedEvents.length, "frame switch from child input to ancestor");
+
+ // focus a descendant
+ gEventMatched = true;
+ gExpectedEvents = [[inputa, "blur", null, framea.contentWindow, window, framea],
+ [framea.contentDocument, "blur", null, null, window, framea],
+ [framea.contentWindow, "blur", null, null, window, framea],
+ [framed.contentDocument, "focus", null, framed.contentWindow, window, framea],
+ [framed.contentWindow, "focus", null, framed.contentWindow, window, framea],
+ [inputd, "focus", inputd, framed.contentWindow, window, framea]];
+ inputd.focus();
+ ok(gEventMatched && !gExpectedEvents.length, "frame switch from child input to ancestor");
+ is(fm.getFocusedElementForWindow(framea.contentWindow, false, {}), framec,
+ "parent focus has shifted to frame");
+
+ // focus a sibling frame by setting focusedWindow
+ gEventMatched = true;
+ gExpectedEvents = [[inputd, "blur", null, framed.contentWindow, window, framea],
+ [framed.contentDocument, "blur", null, null, window, null],
+ [framed.contentWindow, "blur", null, null, window, null],
+ [frameb.contentDocument, "focus", null, frameb.contentWindow, window, frameb],
+ [frameb.contentWindow, "focus", null, frameb.contentWindow, window, frameb]];
+ fm.focusedWindow = frameb.contentWindow;
+ ok(gEventMatched && !gExpectedEvents.length, "frame switch using focusedWindow");
+
+ // clear the focus in an unfocused frame
+ gEventMatched = true;
+ gExpectedEvents = [];
+ fm.clearFocus(framec.contentWindow);
+ ok(gEventMatched && !gExpectedEvents.length, "clearFocus in unfocused frame");
+
+ // focus a sibling frame by setting focusedWindow when no element is focused in that frame
+ gEventMatched = true;
+ gExpectedEvents = [[frameb.contentDocument, "blur", null, null, window, null],
+ [frameb.contentWindow, "blur", null, null, window, null],
+ [framec.contentDocument, "focus", null, framec.contentWindow, window, framea],
+ [framec.contentWindow, "focus", null, framec.contentWindow, window, framea]];
+ fm.focusedWindow = framec.contentWindow;
+ ok(gEventMatched && !gExpectedEvents.length, "frame switch using focusedWindow with no element focused");
+ is(fm.getFocusedElementForWindow(framea.contentWindow, false, {}), framec,
+ "parent focus has shifted to frame using focusedWindow");
+
+ // focus the parent frame by setting focusedWindow. This should have no effect.
+ gEventMatched = true;
+ gExpectedEvents = [];
+ fm.focusedWindow = framea.contentWindow;
+ ok(gEventMatched && !gExpectedEvents.length, "frame switch to parent using focusedWindow");
+
+ // clear the focus in the parent frame
+ gEventMatched = true;
+ gExpectedEvents = [[framec.contentDocument, "blur", null, null, window, framea],
+ [framec.contentWindow, "blur", null, null, window, framea],
+ [framea.contentDocument, "focus", null, framea.contentWindow, window, framea],
+ [framea.contentWindow, "focus", null, framea.contentWindow, window, framea]];
+ fm.clearFocus(framea.contentWindow);
+ ok(gEventMatched && !gExpectedEvents.length, "clearFocus in parent frame");
+
+ // clear the focus in an unfocused child frame
+ gEventMatched = true;
+ gExpectedEvents = [];
+ fm.clearFocus(framed.contentWindow);
+ ok(gEventMatched && !gExpectedEvents.length, "clearFocus in unfocused child frame");
+
+ var exh = false;
+ try {
+ fm.focusedWindow = null;
+ }
+ catch (ex) { exh = true; }
+ is(exh, true, "focusedWindow set to null");
+ is(fm.focusedWindow, framea.contentWindow, "window not changed when focusedWindow set to null");
+
+ doFrameHistoryTests()
+}
+
+function doFrameHistoryTests()
+{
+ let frame = $("childframe");
+ frame.setAttribute("maychangeremoteness", "true");
+ let loaded = BrowserTestUtils.browserLoaded(frame, true);
+ let firstLocation = "https://example.org/chrome/dom/tests/mochitest/chrome/child_focus_frame.html";
+ frame.src = firstLocation;
+ loaded.then(() => {
+ return ContentTask.spawn(frame, {}, () => {
+ let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
+ let t20 = content.document.getElementById("t20");
+ t20.focus();
+ let goneBack = new Promise(resolve => {
+ content.addEventListener("pageshow", ({ persisted }) => {
+ resolve({ location: content.location.href, persisted });
+ }, { once: true });
+ });
+ // make sure that loading a new page and then going back maintains the focus
+ content.location = "data:text/html,<script>window.onload=function() {setTimeout(function () { history.back() }, 0);}</script>";
+ return goneBack;
+ });
+ }).then(({ location, persisted }) => {
+ is(location, firstLocation, "should go back to the right page");
+ ok(persisted, "test relies on BFCache");
+ return ContentTask.spawn(frame, {}, () => {
+ let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
+ let t20 = content.document.getElementById("t20");
+ return fm.focusedElement === t20;
+ });
+ }).then((focusCorrect) => {
+ if (SpecialPowers.Services.appinfo.sessionHistoryInParent) {
+ todo(focusCorrect, "focus restored after history back");
+ } else {
+ ok(focusCorrect, "focus restored after history back");
+ }
+ done();
+ });
+}
+
+function addFrameSwitchingListeners(frame)
+{
+ frame.contentWindow.addEventListener("focus", frameSwitchingEventOccured, false);
+ frame.contentWindow.addEventListener("blur", frameSwitchingEventOccured, false);
+ frame.contentDocument.addEventListener("focus", frameSwitchingEventOccured, false);
+ frame.contentDocument.addEventListener("blur", frameSwitchingEventOccured, false);
+
+ var node = frame.contentDocument.body.firstChild;
+ node.addEventListener("focus", frameSwitchingEventOccured, false);
+ node.addEventListener("blur", frameSwitchingEventOccured, false);
+}
+
+function frameSwitchingEventOccured(event)
+{
+ if (!gExpectedEvents.length) {
+ gEventMatched = false;
+ return;
+ }
+
+ try {
+ var events = gExpectedEvents.shift();
+ is(event.target, events[0], "event target");
+ is(event.type, events[1], "event type");
+ is(fm.focusedElement, events[2], "focused element");
+ is(fm.focusedWindow, events[3], "focused frame");
+ if (events[4])
+ is(fm.getFocusedElementForWindow(events[4], false, {}), events[5], "focused element in frame");
+
+ if (gEventMatched && event.target == events[0] && event.type == events[1] &&
+ fm.focusedElement == events[2] && fm.focusedWindow == events[3]) {
+ if (!events[4] || fm.getFocusedElementForWindow(events[4], false, {}) == events[5])
+ return;
+ }
+ } catch (ex) { ok(ex, "exception"); }
+
+ gEventMatched = false;
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(startTest);
+
+]]>
+</script>
+
+<commandset id="cu"
+ commandupdater="true"
+ events="focus"
+ oncommandupdate="eventOccured(event)"/>
+
+<!--
+ The elements with ids starting with t are focusable and in the taborder.
+ The elements with ids starting with o are:
+ odd numbered ids - focusable but not part of the tab order
+ even numbered ids - not focusable with -moz-user-focus: ignore or disabled
+ The elements with ids starting with n are:
+ odd numbered ids - not focusable with -moz-user-focus: none
+ even numbered ids - focusable but not part of the tab order
+ -->
+<vbox id="buttonbox">
+<hbox id="innerbox">
+ <button id="t4" accesskey="h" label="no tabindex"/>
+ <button id="o1" accesskey="i" label="tabindex = -1" tabindex="-1"/>
+ <richlistbox id="t5" label="tabindex = 0" tabindex="0" style="width: 50px">
+ <richlistitem height="10"/>
+ </richlistbox>
+ <button id="t1" label="tabindex = 2" tabindex="2"/>
+</hbox>
+<hbox>
+ <button id="o2" accesskey="o" style="-moz-user-focus: ignore;" label="no tabindex"/>
+ <button id="o4" style="-moz-user-focus: ignore;" label="no tabindex"/>
+ <button id="t6" style="-moz-user-focus: ignore;" label="tabindex = 0" tabindex="0"/>
+ <button id="t2" style="-moz-user-focus: ignore;" label="tabindex = 2" tabindex="2"/>
+</hbox>
+<hbox id="specialroot">
+ <button id="t7" style="-moz-user-focus: normal;" label="no tabindex"/>
+ <button id="o3" style="-moz-user-focus: normal;" label="tabindex = -1" tabindex="-1"/>
+ <button id="t8" style="-moz-user-focus: normal;" label="tabindex = 0" tabindex="0"/>
+ <richlistbox id="t3" style="-moz-user-focus: normal; width: 50px" label="tabindex = 2" tabindex="2">
+ <richlistitem style="height: 10px"/>
+ </richlistbox>
+</hbox>
+<hbox>
+ <button accesskey="p" style="display: none;"/> <button accesskey="q" style="visibility: collapse;"/>
+ <button style="display: none;" tabindex="2"/> <button style="visibility: collapse;" tabindex="2"/>
+</hbox>
+<hbox>
+ <button id="o20" accesskey="s" label="no tabindex" disabled="true"/>
+ <button id="o22" label="tabindex = -1" tabindex="-1" disabled="true"/>
+ <button id="o24" label="tabindex = 0" tabindex="0" disabled="true"/>
+ <button id="o26" label="tabindex = 2" tabindex="2" disabled="true"/>
+</hbox>
+</vbox>
+<vbox>
+<hbox>
+ <dropmarker id="o6" value="no tabindex"/>
+ <dropmarker id="o8" value="no tabindex"/>
+ <dropmarker id="o10" value="no tabindx"/>
+ <dropmarker id="o12" value="no tabindex"/>
+ <dropmarker id="t9" accesskey="r" style="-moz-user-focus: normal;" value="no tabindex" />
+ <dropmarker id="t10" style="-moz-user-focus: normal;" value="no tabindex"/>
+ <dropmarker id="t11" style="-moz-user-focus: normal;" value="tabindex = 0" tabindex="0" />
+ <dropmarker id="t12" style="-moz-user-focus: normal;" value="no tabindex"/>
+ <dropmarker id="o14" style="-moz-user-focus: ignore;" value="no tabindex"/>
+ <dropmarker id="o16" style="-moz-user-focus: ignore;" value="no tabindex"/>
+ <dropmarker id="n1" style="-moz-user-focus: none;" value="no tabindex"/>
+ <dropmarker id="n3" style="-moz-user-focus: none;" value="no tabindex"/>
+</hbox>
+</vbox>
+<browser id="childframe" type="content" src="child_focus_frame.html" style="height: 195px"/>
+<button id="t34"/>
+<tabbox id="tabbox">
+ <tabs><tab id="t35" label="One"/><tab id="tab2" label="Two"/></tabs>
+ <tabpanels>
+ <tabpanel>
+ <checkbox id="t36"/>
+ <button id="t37"/>
+ </tabpanel>
+ <tabpanel>
+ <checkbox id="htab1"/>
+ <button id="nohtab2" tabindex="7"/>
+ <checkbox id="htab2" tabindex="0"/>
+ </tabpanel>
+ </tabpanels>
+</tabbox>
+<hbox>
+<panel>
+ <button id="inpopup1" label="One"/>
+ <input xmlns="http://www.w3.org/1999/xhtml" label="Two"/>
+</panel>
+<description label="o" accesskey="v"/>
+<button id="t38"/>
+<!-- The 't' element tests end here so it doesn't matter that these elements are tabbable -->
+<label id="aj" value="j" accesskey="j" control="o9"/>
+<label id="ak" accesskey="k" control="n4">k</label>
+<checkbox id="o5"/><checkbox id="o7"/><hbox><checkbox id="o9"/></hbox>
+<checkbox id="o13"/><checkbox id="o15"/><checkbox id="o17"/><checkbox id="o19"/><checkbox id="o21"/><checkbox id="o23"/><checkbox id="o25"/>
+<checkbox id="n2"/><checkbox id="n4"/>
+<richlistbox id="last" style="width: 20px; height: 20px"/>
+
+<iframe id="ifa" style="-moz-user-focus: ignore; width: 40px; height: 60px" type="content"
+ src="data:text/html,&lt;input id=fra size='2'&gt;&lt;input id='fra-b' size='2'&gt;
+ &lt;iframe src='data:text/html,&lt;input id=frc&gt;&lt;iframe src=&quot;data:text/html,&lt;input id=frd&gt;&quot;&gt;&lt;/iframe&gt;'&gt;&lt;/iframe&gt;"/>
+<iframe id="ifb" style="-moz-user-focus: ignore; width: 20px; height: 20px"
+ src="data:text/html,&lt;input id=frd&gt;&lt;/iframe&gt;"/>
+
+</hbox>
+</window>