Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  window_focus.xhtml   Sprache: unbekannt

 
<?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"?>
<?xml-stylesheet href="data:text/css,dropmarker{min-width: 12px; min-height: 12px;}" 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.importESModule(
  "resource://testing-common/ContentTask.sys.mjs"
);

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;
var gCanTabMoveFocusToRootElement =
    !SpecialPowers.getBoolPref("dom.disable_tab_focus_to_root_element");


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;
}

// eslint-disable-next-line complexity
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;
}

// eslint-disable-next-line complexity
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;
    if (gCanTabMoveFocusToRootElement) {
      partialTabList = ["t3", "t5", "t9", "t10", "t11", "t12", "t13", "t14", "t15",
                        "t16", "t19", "t20", "t21", "t22", "t26", "t27", "t28", "t29", "t30"];
    } else {
      // !gCanTabMoveFocusToRootElement
      // t13 is the <html> element in child_focus_frame.html,
      // and it's not getting the focus
      // when gCanTabMoveFocusToRootElement is false.
      partialTabList = ["t3", "t5", "t9", "t10", "t11", "t12", "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++) {
      if (!gCanTabMoveFocusToRootElement) {
        if (idx == kChildDocumentRootIndex)
          // t13 is the <html> element in child_focus_frame.html,
          // and it's not getting the focus
          // when gCanTabMoveFocusToRootElement is false.
          continue;
      }
      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--) {
      if (!gCanTabMoveFocusToRootElement) {
        if (idx == kChildDocumentRootIndex) {
          // t13 is the <html> element in child_focus_frame.html,
          // and it's not getting the focus
          // when gCanTabMoveFocusToRootElement is false.
          continue;
        }
      }
      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);
  expectFocusShift(() => t19.select(),
                   null, getById("t" + 19), true, "input.select()");
  t19.removeEventListener("select", selectListener);
  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);
    blurFunction();
    element.removeEventListener("blur", eventListener);
  }

  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);
    element.focus();
    element.removeEventListener("focus", eventListener);
  }

  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
  window.openDialog("focus_window2.xhtml", "_blank", "chrome,modal", modalWindowOpened);
}

async 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");

  // For silly reasons (see the comments around nsCloseEvent), close() doesn't
  // synchronously close the modal window. If we try to focus the window before
  // the modal window is fully closed, we fail to focus it (see
  // AppWindow::EnableParent).
  //
  // Wait for the unload event to make sure that we get enabled on time. Another
  // alternative would be to use the xul-window-destroyed topic.
  await new Promise(r => {
    modalWindow.addEventListener("unload", r, { once: true });
    modalWindow.close();
  });
  await SimpleTest.promiseFocus();
  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;
  let steps = gCanTabMoveFocusToRootElement ? 8 : 4;
  for (var idx = 1; idx <= steps; idx++) {
    let frameIndex = gCanTabMoveFocusToRootElement ? (idx - 1) >> 1 : idx - 1;
    gNewExpectedWindow = framesetWindow.frames[frameIndex];
    if (gCanTabMoveFocusToRootElement) {
      if (idx % 2) {
        initEvents(gNewExpectedWindow);
      }
    } else {
      initEvents(gNewExpectedWindow);
    }
    expectFocusShift(() => synthesizeKey("KEY_Tab", {}, framesetWindow),
                     gNewExpectedWindow, getById("f" + (gCanTabMoveFocusToRootElement ? idx : idx * 2)), true, "frameset tab key f" + idx);
    gMoveToFocusFrame = false;
    gOldExpectedWindow = gNewExpectedWindow;
  }

  gNewExpectedWindow = framesetWindow.frames[0];
  expectFocusShift(() => synthesizeKey("KEY_Tab", {}, framesetWindow),
                   gNewExpectedWindow, gCanTabMoveFocusToRootElement ? getById("f1") : getById("f2"), 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");

  steps = gCanTabMoveFocusToRootElement ? 7 : 3;
  for (idx = steps; idx >= 1; idx--) {
    gOldExpectedWindow = gNewExpectedWindow;
    let frameIndex = gCanTabMoveFocusToRootElement ? (idx - 1) >> 1 : idx - 1;
    gNewExpectedWindow = framesetWindow.frames[frameIndex];
    expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}, framesetWindow),
                     gNewExpectedWindow, getById("f" + (gCanTabMoveFocusToRootElement ? idx : idx * 2)), 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],
--> --------------------

--> maximum size reached

--> --------------------

[ Dauer der Verarbeitung: 0.66 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge