window_focus.xhtml (74798B)
1 <?xml version="1.0"?> 2 <?xml-stylesheet href="chrome://global/skin" type="text/css"?> 3 <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" 4 type="text/css"?> 5 <?xml-stylesheet href="data:text/css,dropmarker{min-width: 12px; min-height: 12px;}" type="text/css"?> 6 <!-- 7 This test checks focus in various ways 8 --> 9 <window id="outer-document" title="Focus Test" width="600" height="550" 10 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> 11 <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> 12 <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> 13 14 <body xmlns="http://www.w3.org/1999/xhtml"/> 15 16 <script type="application/javascript"><![CDATA[ 17 18 const { BrowserTestUtils } = ChromeUtils.importESModule( 19 "resource://testing-common/BrowserTestUtils.sys.mjs" 20 ); 21 const { ContentTask } = ChromeUtils.importESModule( 22 "resource://testing-common/ContentTask.sys.mjs" 23 ); 24 25 var fm = Cc["@mozilla.org/focus-manager;1"]. 26 getService(Ci.nsIFocusManager); 27 28 const kChildDocumentRootIndex = 13; 29 const kBeforeTabboxIndex = 34; 30 const kTabbableSteps = 38; 31 const kFocusSteps = 26; 32 const kNoFocusSteps = 7; 33 const kOverflowElementIndex = 27; 34 35 var gTestStarted = false; 36 var gPartialTabbing = false; 37 var gMoveToFocusFrame = false; 38 var gLastFocus = null; 39 var gLastFocusWindow = window; 40 var gLastFocusMethod = -1; 41 var gEvents = ""; 42 var gExpectedEvents = ""; 43 var gEventMatched = true; 44 var gShowOutput = false; 45 var gChildWindow = null; 46 47 var gOldExpectedWindow = null; 48 var gNewExpectedWindow = null; 49 50 function is(l, r, n) { window.arguments[0].SimpleTest.is(l,r,n); } 51 function ok(v, n) { window.arguments[0].SimpleTest.ok(v,n); } 52 53 function initEvents(target) 54 { 55 target.addEventListener("focus", eventOccured, true); 56 target.addEventListener("blur", eventOccured, true); 57 getTopWindow(target).addEventListener("activate", eventOccured, true); 58 getTopWindow(target).addEventListener("deactivate", eventOccured, true); 59 } 60 61 function eventOccured(event) 62 { 63 // iframes should never receive focus or blur events directly 64 if (Element.isInstance(event.target) && event.target.localName == "iframe") 65 ok(false, "iframe " + event.type + "occured"); 66 67 var id; 68 if (gOldExpectedWindow && event.type == "blur") { 69 if (Window.isInstance(event.target)) 70 id = "frame-" + gOldExpectedWindow.document.documentElement.id + "-window"; 71 else if (Document.isInstance(event.target)) 72 id = "frame-" + gOldExpectedWindow.document.documentElement.id + "-document"; 73 else 74 id = event.originalTarget.id; 75 } 76 else if (gNewExpectedWindow && event.type == "focus") { 77 if (Window.isInstance(event.target)) 78 id = "frame-" + gNewExpectedWindow.document.documentElement.id + "-window"; 79 else if (Document.isInstance(event.target)) 80 id = "frame-" + gNewExpectedWindow.document.documentElement.id + "-document"; 81 else 82 id = event.originalTarget.id; 83 } 84 else if (event.type == "activate" || event.type == "deactivate") 85 id = event.target.document.documentElement.id + "-window"; 86 else if (Window.isInstance(event.target)) 87 id = (event.target == window) ? "outer-window" : "child-window"; 88 else if (Document.isInstance(event.target)) 89 id = (event.target == document) ? "outer-document" : "child-document"; 90 else 91 id = event.originalTarget.id; 92 93 if (gEvents) 94 gEvents += " "; 95 gEvents += event.type + ": " + id; 96 } 97 98 // eslint-disable-next-line complexity 99 function expectFocusShift(callback, expectedWindow, expectedElement, focusChanged, testid) 100 { 101 if (expectedWindow == null) 102 expectedWindow = expectedElement ? 103 expectedElement.ownerGlobal : 104 gLastFocusWindow; 105 106 var expectedEvents = ""; 107 if (focusChanged) { 108 var id; 109 if (getTopWindow(gLastFocusWindow) != getTopWindow(expectedWindow)) { 110 id = getTopWindow(gLastFocusWindow).document.documentElement.id; 111 expectedEvents += "deactivate: " + id + "-window"; 112 } 113 114 if (gLastFocus && gLastFocus.id != "t" + kChildDocumentRootIndex && 115 (!gOldExpectedWindow || gOldExpectedWindow.document.documentElement != gLastFocus)) { 116 if (expectedEvents) 117 expectedEvents += " "; 118 if (!gOldExpectedWindow) 119 expectedEvents += "commandupdate: cu "; 120 expectedEvents += "blur: " + gLastFocus.id; 121 } 122 123 if (gLastFocusWindow && gLastFocusWindow != expectedWindow) { 124 if (!gMoveToFocusFrame) { 125 if (gOldExpectedWindow) 126 id = "frame-" + gOldExpectedWindow.document.documentElement.id; 127 else 128 id = (gLastFocusWindow == window) ? "outer" : "child"; 129 if (expectedEvents) 130 expectedEvents += " "; 131 expectedEvents += "blur: " + id + "-document " + 132 "blur: " + id + "-window"; 133 } 134 } 135 136 if (getTopWindow(gLastFocusWindow) != getTopWindow(expectedWindow)) { 137 id = getTopWindow(expectedWindow).document.documentElement.id; 138 if (expectedEvents) 139 expectedEvents += " "; 140 expectedEvents += "activate: " + id + "-window"; 141 } 142 143 if (expectedWindow && gLastFocusWindow != expectedWindow) { 144 if (gNewExpectedWindow) 145 id = "frame-" + gNewExpectedWindow.document.documentElement.id; 146 else 147 id = (expectedWindow == window) ? "outer" : "child"; 148 if (expectedEvents) 149 expectedEvents += " "; 150 expectedEvents += "focus: " + id + "-document " + 151 "focus: " + id + "-window"; 152 } 153 154 // for this test which fires a mouse event on a label, the document will 155 // be focused first and then the label code will focus the related 156 // control. This doesn't result in different focus events, but a command 157 // update will occur for the document and then a second command update will 158 // occur when the control is focused. However, this will only happen on 159 // platforms or controls where mouse clicks cause trigger focus. 160 if (testid == "mouse on html label with content inside" && 161 mouseWillTriggerFocus(expectedElement)) { 162 expectedEvents += " commandupdate: cu"; 163 } 164 165 if (expectedElement && 166 (!gNewExpectedWindow || gNewExpectedWindow.document.documentElement != expectedElement)) { 167 if (!gNewExpectedWindow) { 168 if (expectedEvents) 169 expectedEvents += " "; 170 expectedEvents += "commandupdate: cu"; 171 } 172 if (expectedElement.id != "t" + kChildDocumentRootIndex) { 173 if (expectedEvents) 174 expectedEvents += " "; 175 expectedEvents += "focus: " + expectedElement.id; 176 } 177 } 178 else if (expectedWindow && gLastFocusWindow != expectedWindow && 179 !expectedElement) { 180 if (expectedEvents) 181 expectedEvents += " "; 182 expectedEvents += "commandupdate: cu"; 183 } 184 } 185 186 gLastFocus = expectedElement; 187 gLastFocusWindow = expectedWindow; 188 189 callback(); 190 191 compareEvents(expectedEvents, expectedWindow, expectedElement, testid); 192 } 193 194 function compareEvents(expectedEvents, expectedWindow, expectedElement, testid) 195 { 196 if (!gShowOutput) { 197 gEvents = ""; 198 return; 199 } 200 201 is(gEvents, expectedEvents, testid + " events"); 202 gEvents = ""; 203 204 var doc; 205 if (expectedWindow == window) 206 doc = "outer-document"; 207 else if (expectedWindow == gChildWindow) 208 doc = "inner-document"; 209 else if (gNewExpectedWindow) 210 doc = gNewExpectedWindow.document.body ? gNewExpectedWindow.document.body.id : 211 gNewExpectedWindow.document.documentElement.id; 212 else 213 doc = "other-document"; 214 215 var focusedElement = fm.focusedElement; 216 is(focusedElement ? focusedElement.id : "none", 217 expectedElement ? expectedElement.id : "none", testid + " focusedElement"); 218 is(fm.focusedWindow, expectedWindow, testid + " focusedWindow"); 219 var focusedWindow = {}; 220 is(fm.getFocusedElementForWindow(expectedWindow, false, focusedWindow), 221 expectedElement, testid + " getFocusedElementForWindow"); 222 is(focusedWindow.value, expectedWindow, testid + " getFocusedElementForWindow frame"); 223 is(expectedWindow.document.hasFocus(), true, testid + " hasFocus"); 224 is(expectedWindow.document.activeElement ? expectedWindow.document.activeElement.id : "none", 225 expectedElement ? expectedElement.id : doc, testid + " activeElement"); 226 var cdwindow = getTopWindow(expectedWindow); 227 if (cdwindow.document.commandDispatcher) { 228 is(cdwindow.document.commandDispatcher.focusedWindow, expectedWindow, testid + " commandDispatcher focusedWindow"); 229 is(cdwindow.document.commandDispatcher.focusedElement, focusedElement, testid + " commandDispatcher focusedElement"); 230 } 231 232 if (gLastFocusMethod != -1) { 233 is(fm.getLastFocusMethod(null), gLastFocusMethod, testid + " lastFocusMethod null"); 234 is(fm.getLastFocusMethod(expectedWindow), gLastFocusMethod, testid + " lastFocusMethod window"); 235 } 236 237 // the parent should have the iframe focused 238 if (doc == "inner-document") { 239 is(document.hasFocus(), true, testid + " hasFocus"); 240 is(fm.getFocusedElementForWindow(window, false, focusedWindow), 241 $("childframe"), testid + " getFocusedElementForWindow for parent"); 242 is(focusedWindow.value, window, testid + " getFocusedElementForWindow for parent frame"); 243 is(fm.getFocusedElementForWindow(window, true, focusedWindow), 244 expectedElement, testid + " getFocusedElementForWindow deep for parent"); 245 is(focusedWindow.value, gChildWindow, testid + " getFocusedElementForWindow deep for parent frame"); 246 is(document.activeElement.id, "childframe", testid + " activeElement for parent"); 247 } 248 249 // compare the selection for the child window. Skip mouse tests as the caret 250 // is adjusted by the selection code for mouse clicks, and not the focus code. 251 if (expectedWindow == window) { 252 var selection = window.getSelection(); 253 ok(selection.focusNode == null && selection.focusOffset == 0 && 254 selection.anchorNode == null && selection.anchorOffset == 0, testid + " selection"); 255 } 256 else if ((expectedWindow == gChildWindow) && !testid.indexOf("mouse") == -1) { 257 checkSelection(expectedElement, testid); 258 } 259 } 260 261 function checkSelection(node, testid) 262 { 263 var selection = gChildWindow.getSelection(); 264 265 var range = gChildWindow.document.createRange(); 266 range.selectNodeContents(node); 267 if (!node.firstChild || node.localName == "input" || 268 node.localName == "select" || node.localName == "button") { 269 range.setStartBefore(node); 270 range.setEndBefore(node); 271 } 272 273 if (node.firstChild) 274 range.setEnd(range.startContainer, range.startOffset); 275 276 is(selection.focusNode, range.startContainer, testid + " selection focusNode"); 277 is(selection.focusOffset, range.startOffset, testid + " selection focusOffset"); 278 is(selection.anchorNode, range.endContainer, testid + " selection anchorNode"); 279 is(selection.anchorOffset, range.endOffset, testid + " selection anchorOffset"); 280 } 281 282 function getTopWindow(win) 283 { 284 return win.browsingContext.topChromeWindow; 285 } 286 287 function mouseWillTriggerFocus(element) 288 { 289 if (!element) { 290 return false; 291 } 292 293 if (SpecialPowers.getIntPref("accessibility.mouse_focuses_formcontrol") == 1) { 294 // This is a chrome document, so we'll only trigger focus with the mouse if the value of the pref is 1. 295 return true; 296 } 297 298 if (element.namespaceURI == "http://www.w3.org/1999/xhtml") { 299 // links are special. They can be focused but show no focus ring 300 if (element.localName == "a" || element.localName == "div" || 301 element.localName == "select" || 302 element.localName == "input" && (element.type == "text" || 303 element.type == "password")) { 304 return true; 305 } 306 } else if (element.localName == "richlistbox") { 307 return true; 308 } 309 310 return false; 311 } 312 313 function mouseOnElement(element, expectedElement, focusChanged, testid) 314 { 315 var expectedWindow = (element.ownerGlobal == gChildWindow) ? gChildWindow : window; 316 // on Mac, form elements are not focused when clicking, except for lists and inputs. 317 var noFocusOnMouse = !mouseWillTriggerFocus(element) 318 319 if (noFocusOnMouse) { 320 // no focus so the last focus method will be 0 321 gLastFocusMethod = 0; 322 expectFocusShift(() => synthesizeMouse(element, 4, 4, { }, element.ownerGlobal), 323 expectedWindow, null, true, testid); 324 gLastFocusMethod = fm.FLAG_BYMOUSE; 325 } 326 else { 327 expectFocusShift(() => synthesizeMouse(element, 4, 4, { }, element.ownerGlobal), 328 element.ownerGlobal, 329 expectedElement, focusChanged, testid); 330 } 331 } 332 333 function done() 334 { 335 var opener = window.arguments[0]; 336 window.close(); 337 window.arguments[0].SimpleTest.finish(); 338 } 339 340 var pressTab = () => synthesizeKey("KEY_Tab"); 341 342 function setFocusTo(id, fwindow) 343 { 344 gLastFocus = getById(id); 345 gLastFocusWindow = fwindow; 346 if (gLastFocus) 347 gLastFocus.focus(); 348 else 349 fm.clearFocus(fwindow); 350 gEvents = ""; 351 } 352 353 function getById(id) 354 { 355 if (gNewExpectedWindow) 356 return gNewExpectedWindow.document.getElementById(id); 357 var element = $(id); 358 if (!element) 359 element = $("childframe").contentDocument.getElementById(id); 360 return element; 361 } 362 363 // eslint-disable-next-line complexity 364 function startTest() 365 { 366 if (gTestStarted) 367 return; 368 gTestStarted = true; 369 370 gChildWindow = $("childframe").contentWindow; 371 gShowOutput = true; 372 373 // synthesize a mousemove over the image to ensure that the imagemap data is 374 // created. Otherwise, the special imagemap frames might not exist, and 375 // won't be focusable. 376 synthesizeMouse(getById("image"), 4, 4, { type: "mousemove" }, gChildWindow); 377 378 initEvents(window); 379 380 is(fm.activeWindow, window, "activeWindow"); 381 is(gChildWindow.document.hasFocus(), false, " child document hasFocus"); 382 383 // test to see if the Mac Full Keyboard Access setting is set. If t3 is 384 // focused after tab is pressed, then it is set to inputs and lists only. 385 // Otherwise, all elements are in the tab order. 386 pressTab(); 387 388 if (fm.focusedElement.id == "t3") 389 gPartialTabbing = true; 390 else 391 is(fm.focusedElement.id, "t1", "initial tab key"); 392 393 is(fm.getLastFocusMethod(null), fm.FLAG_BYKEY, "last focus method null start"); 394 is(fm.getLastFocusMethod(window), fm.FLAG_BYKEY, "last focus method window start"); 395 396 fm.clearFocus(window); 397 gEvents = ""; 398 399 gLastFocusMethod = fm.FLAG_BYKEY; 400 if (gPartialTabbing) { 401 var partialTabList = ["t3", "t5", "t9", "t10", "t11", "t12", "t14", "t15", 402 "t16", "t19", "t20", "t21", "t22", "t26", "t27", "t28", "t29", "t30"]; 403 for (var idx = 0; idx < partialTabList.length; idx++) { 404 expectFocusShift(pressTab, null, getById(partialTabList[idx]), true, "partial tab key " + partialTabList[idx]); 405 } 406 setFocusTo("last", window); 407 expectFocusShift(pressTab, null, getById(partialTabList[0]), true, "partial tab key wrap to start"); 408 expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}), 409 null, getById("last"), true, "partial shift tab key wrap to end"); 410 for (var idx = partialTabList.length - 1; idx >= 0; idx--) { 411 expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}), 412 null, getById(partialTabList[idx]), true, "partial tab key " + partialTabList[idx]); 413 } 414 } 415 else { 416 // TAB key 417 for (var idx = 1; idx <= kTabbableSteps; idx++) { 418 if (idx == kChildDocumentRootIndex) { 419 continue; 420 } 421 expectFocusShift(pressTab, null, getById("t" + idx), true, "tab key t" + idx); 422 } 423 424 // wrapping around at end with TAB key 425 setFocusTo("last", window); 426 expectFocusShift(pressTab, null, getById("t1"), true, "tab key wrap to start"); 427 expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}), 428 null, getById("last"), true, "shift tab key wrap to end"); 429 430 // Shift+TAB key 431 setFocusTo("o5", window); 432 for (idx = kTabbableSteps; idx > 0; idx--) { 433 if (idx == kChildDocumentRootIndex) { 434 continue; 435 } 436 expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}), 437 null, getById("t" + idx), true, "shift tab key t" + idx); 438 } 439 } 440 441 var t19 = getById("t19"); 442 is(t19.selectionStart, 0, "input focused from tab key selectionStart"); 443 is(t19.selectionEnd, 5, "input focused from tab key selectionEnd"); 444 t19.setSelectionRange(0, 0); 445 446 gLastFocusMethod = 0; 447 var selectFired = false; 448 function selectListener() { selectFired = true; } 449 t19.addEventListener("select", selectListener); 450 expectFocusShift(() => t19.select(), 451 null, getById("t" + 19), true, "input.select()"); 452 t19.removeEventListener("select", selectListener); 453 ok(!selectFired, "select event does not fire asynchronously for input"); 454 455 // mouse clicking 456 gLastFocusMethod = fm.FLAG_BYMOUSE; 457 for (idx = kTabbableSteps; idx >= 1; idx--) { 458 // skip the document root and the overflow element 459 if (idx == kChildDocumentRootIndex || idx == kOverflowElementIndex) 460 continue; 461 if ((navigator.platform.indexOf("Mac") == 0) && (idx == kBeforeTabboxIndex + 1)) 462 continue; 463 464 var element = getById("t" + idx); 465 // skip area elements, as getBoundingClientRect doesn't return their actual coordinates 466 if (element.localName == "area") 467 continue; 468 469 mouseOnElement(element, element, true, "mouse on element t" + idx); 470 var expectedWindow = (element.ownerGlobal == gChildWindow) ? gChildWindow : window; 471 if (element.localName == "richlistbox" && expectedWindow == window && 472 navigator.platform.indexOf("Mac") == 0) { 473 // after focusing a listbox on Mac, clear the focus before continuing. 474 setFocusTo(null, window); 475 } 476 } 477 478 ok(t19.selectionStart == t19.selectionEnd, "input focused from mouse selection"); 479 480 // mouse clicking on elements that are not tabbable 481 for (idx = 1; idx <= kFocusSteps; idx++) { 482 var element = getById("o" + (idx % 2 ? idx : idx - 1)); 483 484 mouseOnElement(element, element, idx % 2, 485 "mouse on non-tabbable element o" + idx); 486 } 487 488 // mouse clicking on elements that are not tabbable and have user-focus: none 489 // or are not focusable for other reasons (for instance, being disabled) 490 // These elements will clear the focus when clicked. 491 for (idx = 1; idx <= kNoFocusSteps; idx++) { 492 var element = getById("n" + idx); 493 gLastFocusMethod = idx % 2 ? 0 : fm.FLAG_BYMOUSE; 494 495 mouseOnElement(element, idx % 2 ? null: element, true, "mouse on unfocusable element n" + idx); 496 } 497 498 if (idx == kOverflowElementIndex) { 499 gLastFocusMethod = fm.FLAG_BYMOUSE; 500 var element = getById("t" + idx); 501 expectFocusShift(() => synthesizeMouse(element, 4, 4, { }, element.ownerGlobal), 502 window, null, true, "mouse on scrollable element"); 503 } 504 505 // focus() method 506 gLastFocusMethod = fm.FLAG_BYJS; 507 for (idx = kTabbableSteps; idx >= 1; idx--) { 508 if ((navigator.platform.indexOf("Mac") == 0) && (idx == kBeforeTabboxIndex + 1)) 509 continue; 510 expectFocusShift(() => getById("t" + idx).focus(), 511 null, getById("t" + idx), true, "focus method on element t" + idx); 512 } 513 514 $("t1").focus(); 515 ok(gEvents === "", "focusing element that is already focused"); 516 517 $("t2").blur(); 518 $("t7").blur(); 519 ok(gEvents === "", "blurring element that is not focused"); 520 is(document.activeElement, $("t1"), "old element still focused after blur() on another element"); 521 522 // focus() method on elements that are not tabbable 523 for (idx = 1; idx <= kFocusSteps; idx++) { 524 var expected = getById("o" + (idx % 2 ? idx : idx - 1)); 525 expectFocusShift(() => getById("o" + idx).focus(), 526 expected.ownerGlobal, 527 expected, idx % 2, "focus method on non-tabbable element o" + idx); 528 } 529 530 // focus() method on elements that are not tabbable and have user-focus: none 531 // or are not focusable for other reasons (for instance, being disabled) 532 for (idx = 1; idx <= kNoFocusSteps; idx++) { 533 var expected = getById("o" + (idx % 2 ? idx : idx - 1)); 534 expectFocusShift(() => getById("o" + idx).focus(), 535 expected.ownerGlobal, 536 expected, idx % 2, "focus method on unfocusable element n" + idx); 537 } 538 539 // the focus() method on the legend element should focus the legend if it is 540 // focusable, or the first element after the legend if it is not focusable. 541 if (!gPartialTabbing) { 542 gLastFocusMethod = fm.FLAG_BYJS; 543 var legend = getById("legend"); 544 expectFocusShift(() => legend.focus(), 545 null, getById("t28"), true, "focus method on unfocusable legend"); 546 legend.tabIndex = "0"; 547 expectFocusShift(() => legend.focus(), 548 null, getById("legend"), true, "focus method on focusable legend"); 549 legend.tabIndex = "-1"; 550 } 551 552 var accessKeyDetails = (navigator.platform.includes("Mac")) ? 553 { ctrlKey : true } : { altKey : true }; 554 555 // test accesskeys 556 var keys = ["t26", "t19", "t22", "t29", "t15", "t17", "n6", 557 "t4", "o1", "o9", "n4"]; 558 for (var k = 0; k < keys.length; k++) { 559 var key = String.fromCharCode(65 + k); 560 561 // accesskeys D and G are for labels so get redirected 562 gLastFocusMethod = (key == "D" || key == "G") ? fm.FLAG_BYMOVEFOCUS : fm.FLAG_BYKEY; 563 564 // on Windows and Linux, the shift key must be pressed for content area access keys 565 // and on Mac, the alt key must be pressed for content area access keys 566 var isContent = (getById(keys[k]).ownerGlobal == gChildWindow); 567 if (!navigator.platform.includes("Mac")) { 568 accessKeyDetails.shiftKey = isContent; 569 } else { 570 accessKeyDetails.altKey = isContent; 571 } 572 573 expectFocusShift(() => synthesizeKey(key, accessKeyDetails), 574 null, getById(keys[k]), true, "accesskey " + key); 575 } 576 577 // clicking on the labels 578 gLastFocusMethod = fm.FLAG_BYMOVEFOCUS | fm.FLAG_BYMOUSE; 579 mouseOnElement(getById("ad"), getById("t29"), true, "mouse on html label with content inside"); 580 mouseOnElement(getById("ag"), getById("n6"), true, "mouse on html label with for attribute"); 581 gLastFocusMethod = fm.FLAG_BYJS; 582 expectFocusShift(() => synthesizeMouse(getById("aj"), 2, 2, { }), 583 null, getById("o9"), true, "mouse on xul label with content inside"); 584 expectFocusShift(() => synthesizeMouse(getById("ak"), 2, 2, { }), 585 null, getById("n4"), true, "mouse on xul label with control attribute"); 586 587 // test accesskeys that shouldn't work 588 k = "o".charCodeAt(0); 589 gLastFocusMethod = fm.FLAG_BYJS; 590 while (k++ < "v".charCodeAt(0)) { 591 var key = String.fromCharCode(k); 592 expectFocusShift(() => synthesizeKey(key, accessKeyDetails), 593 window, getById("n4"), false, "non accesskey " + key); 594 } 595 gLastFocusMethod = -1; 596 597 // should focus the for element when using the focus method on a label as well 598 expectFocusShift(() => getById("ad").focus(), 599 null, getById("t29"), true, "mouse on html label using focus method"); 600 601 // make sure that the text is selected when clicking a label associated with an input 602 getById("ag").htmlFor = "t19"; 603 expectFocusShift(() => synthesizeMouse(getById("ag"), 2, 2, { }, gChildWindow), 604 null, getById("t19"), true, "mouse on html label with for attribute changed"); 605 is(t19.selectionStart, 0, "input focused from label, selectionStart"); 606 is(t19.selectionEnd, 5, "input focused from label, selectionEnd"); 607 608 // switch to another panel in a tabbox and ensure that tabbing moves between 609 // elements on the new panel. 610 $("tabbox").selectedIndex = 1; 611 expectFocusShift(() => getById("t" + kBeforeTabboxIndex).focus(), 612 null, getById("t" + kBeforeTabboxIndex), true, "focus method on element before tabbox"); 613 614 if (!gPartialTabbing) { 615 expectFocusShift(pressTab, null, getById("tab2"), true, "focus method on tab"); 616 expectFocusShift(pressTab, null, getById("htab1"), true, "tab key switch tabpanel 1"); 617 expectFocusShift(pressTab, null, getById("htab2"), true, "tab key switch tabpanel 2"); 618 expectFocusShift(pressTab, null, getById("t" + (kBeforeTabboxIndex + 4)), true, "tab key switch tabpanel 3"); 619 } 620 $("tabbox").selectedIndex = 0; 621 622 // ---- the following checks when the focus changes during a blur or focus event ---- 623 624 var o5 = $("o5"); 625 var o9 = $("o9"); 626 var t3 = $("t3"); 627 var t17 = getById("t17"); 628 var t19 = getById("t19"); 629 var shiftFocusParentDocument = () => o9.focus(); 630 var shiftFocusChildDocument = () => t17.focus(); 631 632 var trapBlur = function (element, eventListener, blurFunction) 633 { 634 element.focus(); 635 gEvents = ""; 636 element.addEventListener("blur", eventListener); 637 blurFunction(); 638 element.removeEventListener("blur", eventListener); 639 } 640 641 var functions = [ 642 element => element.focus(), 643 element => synthesizeMouse(element, 4, 4, { }, element.ownerGlobal) 644 ]; 645 646 // first, check cases where the focus is adjusted during the blur event. Iterate twice, 647 // once with the focus method and then focusing by mouse clicking 648 for (var l = 0; l < 2; l++) { 649 var adjustFocus = functions[l]; 650 var mod = (l == 1) ? " with mouse" : ""; 651 652 // an attempt is made to switch the focus from one element (o5) to another 653 // element (t3) within the same document, yet the focus is shifted to a 654 // third element (o9) in the same document during the blur event for the 655 // first element. 656 trapBlur(o5, shiftFocusParentDocument, () => adjustFocus(t3)); 657 compareEvents("commandupdate: cu blur: o5 commandupdate: cu focus: o9", 658 window, o9, "change focus to sibling during element blur, attempted sibling" + mod); 659 660 // similar, but the third element (t17) is in a child document 661 trapBlur(o9, shiftFocusChildDocument, () => adjustFocus(t3)); 662 compareEvents("commandupdate: cu blur: o9 blur: outer-document blur: outer-window " + 663 "focus: child-document focus: child-window commandupdate: cu focus: t17", 664 gChildWindow, t17, "change focus to child document during element blur, attempted sibling" + mod); 665 666 // similar, but an attempt to switch focus within the same document, but the 667 // third element (t17) is in a parent document 668 trapBlur(t17, shiftFocusParentDocument, () => adjustFocus(t19)); 669 compareEvents("commandupdate: cu blur: t17 blur: child-document blur: child-window " + 670 "focus: outer-document focus: outer-window commandupdate: cu focus: o9", 671 window, o9, "change focus to parent document during element blur, attempted sibling" + mod); 672 673 // similar, but blur is called instead of switching focus 674 trapBlur(t3, shiftFocusParentDocument, () => t3.blur()); 675 compareEvents("commandupdate: cu blur: t3 commandupdate: cu focus: o9", 676 window, o9, "change focus to same document during clear focus" + mod); 677 678 // check when an element in the same document is focused during the 679 // element's blur event, but an attempt was made to focus an element in the 680 // child document. In this case, the focus in the parent document should be 681 // what was set during the blur event, but the actual focus should still 682 // move to the child document. 683 trapBlur(t3, shiftFocusParentDocument, () => adjustFocus(t17)); 684 compareEvents("commandupdate: cu blur: t3 commandupdate: cu focus: o9 " + 685 "blur: outer-document blur: outer-window " + 686 "focus: child-document focus: child-window commandupdate: cu focus: t17", 687 gChildWindow, t17, "change focus to sibling during element blur, attempted child" + mod); 688 is(fm.getFocusedElementForWindow(window, false, {}), $("childframe"), 689 "change focus to sibling during element blur, attempted child, focused in parent" + mod); 690 691 // similar, but with a parent 692 trapBlur(t19, shiftFocusChildDocument, () => adjustFocus(t3)); 693 compareEvents("commandupdate: cu blur: t19 commandupdate: cu focus: t17 " + 694 "blur: child-document blur: child-window " + 695 "focus: outer-document focus: outer-window commandupdate: cu focus: t3", 696 window, t3, "change focus to sibling during element blur, attempted parent" + mod); 697 is(fm.getFocusedElementForWindow(gChildWindow, false, {}), t17, 698 "change focus to sibling during element blur, attempted child, focused in child" + mod); 699 700 // similar, with a child, but the blur event focuses a child element also 701 trapBlur(t3, shiftFocusChildDocument, () => adjustFocus(t19)); 702 compareEvents("commandupdate: cu blur: t3 blur: outer-document blur: outer-window " + 703 "focus: child-document focus: child-window commandupdate: cu focus: t17", 704 gChildWindow, t17, "change focus to child during element blur, attempted child" + mod); 705 706 // similar, with a parent, where the blur event focuses a parent element also 707 trapBlur(t17, shiftFocusParentDocument, () => adjustFocus(t3)); 708 compareEvents("commandupdate: cu blur: t17 blur: child-document blur: child-window " + 709 "focus: outer-document focus: outer-window commandupdate: cu focus: o9", 710 window, o9, "change focus to parent during element blur, attempted parent" + mod); 711 } 712 713 var trapFocus = function (element, eventListener) 714 { 715 element.addEventListener("focus", eventListener); 716 element.focus(); 717 element.removeEventListener("focus", eventListener); 718 } 719 720 fm.clearFocus(window); 721 gEvents = ""; 722 723 // next, check cases where the focus is adjusted during the focus event 724 725 // switch focus to an element in the same document 726 trapFocus(o5, shiftFocusParentDocument); 727 compareEvents("commandupdate: cu focus: o5 commandupdate: cu blur: o5 commandupdate: cu focus: o9", 728 window, o9, "change focus to sibling during element focus"); 729 730 // similar, but the new element (t17) is in a child document 731 trapFocus(o5, shiftFocusChildDocument); 732 compareEvents("commandupdate: cu blur: o9 " + 733 "commandupdate: cu focus: o5 commandupdate: cu blur: o5 " + 734 "blur: outer-document blur: outer-window " + 735 "focus: child-document focus: child-window commandupdate: cu focus: t17", 736 gChildWindow, t17, "change focus to child document during element focus"); 737 738 // similar, but the new element (o9) is in a parent document. 739 trapFocus(t19, shiftFocusParentDocument); 740 compareEvents("commandupdate: cu blur: t17 " + 741 "commandupdate: cu focus: t19 commandupdate: cu blur: t19 " + 742 "blur: child-document blur: child-window " + 743 "focus: outer-document focus: outer-window commandupdate: cu focus: o9", 744 window, o9, "change focus to parent document during element focus"); 745 746 // clear the focus during the focus event 747 trapFocus(t3, () => fm.clearFocus(window)); 748 compareEvents("commandupdate: cu blur: o9 commandupdate: cu focus: t3 commandupdate: cu blur: t3", 749 window, null, "clear focus during focus event"); 750 751 if (!gPartialTabbing) 752 doCommandDispatcherTests(); 753 754 testMoveFocus(); 755 756 doRemoveTests(); 757 758 // tests various focus manager apis for null checks 759 var exh = false; 760 try { 761 fm.clearFocus(null); 762 } 763 catch (ex) { exh = true; } 764 is(exh, true, "clearFocus with null window causes exception"); 765 766 var exh = false; 767 try { 768 fm.getFocusedElementForWindow(null, false, focusedWindow); 769 } 770 catch (ex) { exh = true; } 771 is(exh, true, "getFocusedElementForWindow with null window causes exception"); 772 773 // just make sure that this doesn't crash 774 fm.moveCaretToFocus(null); 775 776 // ---- tests for the FLAG_NOSWITCHFRAME flag 777 getById("o5").focus(); 778 gLastFocusMethod = fm.FLAG_BYJS; 779 gEvents = ""; 780 // focus is being shifted in a child, so the focus should not change 781 expectFocusShift(() => fm.setFocus(getById("t20"), fm.FLAG_NOSWITCHFRAME), 782 window, getById("o5"), false, "no switch frame focus to child"); 783 setFocusTo("t20", gChildWindow); 784 785 gLastFocusMethod = 0; 786 787 // here, however, focus is being shifted in a parent, which will have to blur 788 // the child, so the focus will always change 789 expectFocusShift(() => fm.setFocus(getById("o5"), fm.FLAG_NOSWITCHFRAME), 790 window, getById("o5"), true, "no switch frame focus to parent"); 791 792 expectFocusShift(() => fm.setFocus(getById("t1"), fm.FLAG_NOSWITCHFRAME), 793 window, getById("t1"), true, "no switch frame focus to same window"); 794 795 // ---- tests for focus and scrolling into view ---- 796 var inscroll = getById("inscroll"); 797 inscroll.tabIndex = 0; 798 is(inscroll.parentNode.scrollTop, 0, "scroll position before focus"); 799 inscroll.focus(); 800 ok(inscroll.parentNode.scrollTop > 5, "scroll position after focus"); 801 inscroll.parentNode.scrollTop = 0; 802 fm.setFocus(inscroll, fm.FLAG_NOSCROLL); 803 is(inscroll.parentNode.scrollTop, 0, "scroll position after noscroll focus"); 804 805 getById("t9").focus(); 806 getById("inpopup1").focus(); 807 is(fm.focusedElement, getById("t9"), "focus in closed popup"); 808 809 // ---- tests to check if tabbing out of a input works 810 811 setFocusTo("t1", window); 812 813 var input1 = document.createElement("input"); 814 $("innerbox").appendChild(input1); 815 816 var input2 = document.createElement("input"); 817 $("innerbox").appendChild(input2); 818 819 gLastFocusMethod = fm.FLAG_BYJS; 820 expectFocusShift(() => input2.focus(), 821 null, input2, true, "focus on input"); 822 gLastFocusMethod = fm.FLAG_BYKEY; 823 expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}), 824 null, input1, true, "shift+tab on input"); 825 826 input1.tabIndex = 2; 827 input2.tabIndex = 2; 828 gLastFocusMethod = fm.FLAG_BYJS; 829 expectFocusShift(() => input2.focus(), 830 null, input2, true, "focus on input with tabindex set"); 831 gLastFocusMethod = fm.FLAG_BYKEY; 832 expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}), 833 null, input1, true, "shift+tab on input with tabindex set"); 834 835 // ---- test to check that refocusing an element during a blur event 836 837 var t1 = getById("t1"); 838 t1.addEventListener("blur", () => t1.focus(), {capture: true, once: true}); 839 t1.focus(); 840 var t3 = getById("t3"); 841 synthesizeMouse(t3, 2, 2, { }); 842 is(fm.focusedElement, t1, "focus during blur"); 843 844 setFocusTo("t9", window); 845 gLastFocusMethod = -1; 846 window.openDialog("focus_window2.xhtml", "_blank", "chrome", otherWindowFocused); 847 } 848 849 function doCommandDispatcherTests() 850 { 851 var t19 = getById("t19"); 852 t19.focus(); 853 gLastFocusWindow = gChildWindow; 854 gLastFocus = t19; 855 gEvents = ""; 856 857 expectFocusShift(() => document.commandDispatcher.focusedElement = getById("o9"), 858 null, getById("o9"), true, "command dispatcher set focusedElement"); 859 expectFocusShift(() => document.commandDispatcher.advanceFocus(), 860 null, getById("o13"), true, "command dispatcher advanceFocus"); 861 expectFocusShift(() => document.commandDispatcher.rewindFocus(), 862 null, getById("o9"), true, "command dispatcher rewindFocus"); 863 expectFocusShift(() => document.commandDispatcher.focusedElement = null, 864 null, null, true, "command dispatcher set focusedElement to null"); 865 expectFocusShift(() => document.commandDispatcher.focusedWindow = gChildWindow, 866 null, getById("t19"), true, "command dispatcher set focusedElement to null"); 867 expectFocusShift(() => document.commandDispatcher.focusedElement = null, 868 gChildWindow, null, true, "command dispatcher set focusedElement to null in child"); 869 expectFocusShift(() => document.commandDispatcher.advanceFocusIntoSubtree(getById("t19")), 870 null, getById("t20"), true, "command dispatcher advanceFocusIntoSubtree child"); 871 expectFocusShift(() => document.commandDispatcher.advanceFocusIntoSubtree(null), 872 null, getById("t21"), true, "command dispatcher advanceFocusIntoSubtree null child"); 873 expectFocusShift(() => document.commandDispatcher.advanceFocusIntoSubtree(getById("o9").parentNode), 874 null, getById("o9"), true, "command dispatcher advanceFocusIntoSubtree parent"); 875 } 876 877 function doRemoveTests() 878 { 879 // next, some tests which remove elements 880 var t19 = getById("t19"); 881 t19.focus(); 882 t19.remove(); 883 884 is(fm.focusedElement, null, "removed element focusedElement"); 885 is(fm.focusedWindow, gChildWindow, "removed element focusedWindow"); 886 is(gChildWindow.document.hasFocus(), true, "removed element hasFocus"); 887 is(gChildWindow.document.activeElement, getById("inner-document"), "removed element activeElement"); 888 889 getById("t15").focus(); 890 var abs = getById("abs"); 891 abs.remove(); 892 893 is(fm.focusedElement, null, "removed ancestor focusedElement"); 894 is(fm.focusedWindow, gChildWindow, "removed ancestor focusedWindow"); 895 is(gChildWindow.document.hasFocus(), true, "removed ancestor hasFocus"); 896 is(gChildWindow.document.activeElement, getById("inner-document"), "removed ancestor activeElement"); 897 } 898 899 // tests for the FocusManager moveFocus method 900 function testMoveFocus() 901 { 902 setFocusTo("t6", window); 903 904 // moving focus while an element is already focused 905 var newFocus; 906 gLastFocusMethod = fm.FLAG_BYMOVEFOCUS; 907 var expectedFirst = getById(gPartialTabbing ? "t3" : "t1"); 908 expectFocusShift(() => newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_FIRST, 0), 909 window, expectedFirst, true, "moveFocus to first null window null content"); 910 is(newFocus, fm.focusedElement, "moveFocus to first null window null content return value"); 911 912 expectFocusShift(() => newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_LAST, 0), 913 window, getById("last"), true, "moveFocus to last null window null content"); 914 is(newFocus, fm.focusedElement, "moveFocus to last null window null content return value"); 915 916 gLastFocusMethod = 0; 917 newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_ROOT, 0); 918 is(newFocus, null, "moveFocus to root null window null content return value"); 919 is(fm.focusedWindow, window, "moveFocus to root null window null content focusedWindow"); 920 is(fm.focusedElement, null, "moveFocus to root null window null content focusedElement"); 921 922 // moving focus while no element is focused 923 fm.clearFocus(window); 924 gEvents = ""; 925 gLastFocus = null; 926 gLastFocusMethod = fm.FLAG_BYMOVEFOCUS; 927 expectFocusShift(() => newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_FIRST, 0), 928 window, expectedFirst, true, "moveFocus to first null window null content no focus"); 929 is(newFocus, fm.focusedElement, "moveFocus to first null window null content no focus return value"); 930 fm.clearFocus(window); 931 gEvents = ""; 932 gLastFocus = null; 933 expectFocusShift(() => newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_LAST, 0), 934 window, getById("last"), true, "moveFocus to last null window null content no focus"); 935 is(newFocus, fm.focusedElement, "moveFocus to last null window null content no focus return value"); 936 fm.clearFocus(window); 937 gEvents = ""; 938 gLastFocusMethod = 0; 939 newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_ROOT, 0); 940 is(newFocus, null, "moveFocus to root null window null content no focus return value"); 941 is(fm.focusedWindow, window, "moveFocus to root null window null content no focus focusedWindow"); 942 is(fm.focusedElement, null, "moveFocus to root null window null content no focus focusedElement"); 943 944 // moving focus from a specified element 945 setFocusTo("t6", window); 946 gLastFocusMethod = fm.FLAG_BYMOVEFOCUS; 947 expectFocusShift(() => newFocus = fm.moveFocus(null, getById("specialroot"), fm.MOVEFOCUS_FIRST, 0), 948 window, getById("t3"), true, "moveFocus to first null window with content"); 949 // XXXndeakin P3 this doesn't work 950 // expectFocusShift(() => newFocus = fm.moveFocus(null, getById("specialroot"), fm.MOVEFOCUS_LAST, 0), 951 // window, getById("o3"), true, "moveFocus to last null window with content"); 952 953 // move focus to first in child window 954 expectFocusShift(() => newFocus = fm.moveFocus(gChildWindow, null, fm.MOVEFOCUS_FIRST, 0), 955 gChildWindow, getById("t" + (kChildDocumentRootIndex + 1)), true, 956 "moveFocus to first child window null content"); 957 is(newFocus, getById("t" + (kChildDocumentRootIndex + 1)), 958 "moveFocus to first child window null content return value"); 959 960 // move focus to last in child window 961 setFocusTo("t6", window); 962 var expectedLast = getById(gPartialTabbing ? "t30" : "t" + (kBeforeTabboxIndex - 1)); 963 expectFocusShift(() => newFocus = fm.moveFocus(gChildWindow, null, fm.MOVEFOCUS_LAST, 0), 964 gChildWindow, expectedLast, true, 965 "moveFocus to last child window null content"); 966 is(newFocus, getById(expectedLast), 967 "moveFocus to last child window null content return value"); 968 969 // move focus to root in child window 970 setFocusTo("t6", window); 971 var childroot = getById("t" + kChildDocumentRootIndex); 972 gLastFocusMethod = 0; 973 newFocus = fm.moveFocus(gChildWindow, null, fm.MOVEFOCUS_ROOT, 0); 974 is(newFocus, childroot, "moveFocus to root child window null content return value"); 975 is(fm.focusedWindow, gChildWindow, "moveFocus to root child window null content focusedWindow"); 976 is(fm.focusedElement, childroot, "moveFocus to root child window null content focusedElement"); 977 978 // MOVEFOCUS_CARET tests 979 getById("t20").focus(); 980 gEvents = ""; 981 982 var selection = gChildWindow.getSelection(); 983 selection.removeAllRanges(); 984 985 newFocus = fm.moveFocus(gChildWindow, null, fm.MOVEFOCUS_CARET, 0); 986 is(newFocus, null, "move caret when at document root"); 987 is(fm.focusedElement, null, "move caret when at document root"); 988 989 var node = getById("t16").firstChild; 990 var range = gChildWindow.document.createRange(); 991 range.setStart(node, 3); 992 range.setEnd(node, 3); 993 selection.addRange(range); 994 995 newFocus = fm.moveFocus(gChildWindow, null, fm.MOVEFOCUS_CARET, 0); 996 is(newFocus, null, "move caret to non-link return value"); 997 is(fm.focusedElement, null, "move caret to non-link"); 998 999 var t25 = getById("t25"); 1000 var node = t25.firstChild; 1001 range.setStart(node, 1); 1002 range.setEnd(node, 1); 1003 newFocus = fm.moveFocus(gChildWindow, null, fm.MOVEFOCUS_CARET, 0); 1004 1005 is(newFocus, t25, "move caret to link return value"); 1006 is(fm.focusedElement, t25, "move caret to link focusedElement"); 1007 1008 // enable caret browsing temporarily to test caret movement 1009 var prefs = Cc["@mozilla.org/preferences-service;1"]. 1010 getService(Ci.nsIPrefBranch); 1011 prefs.setBoolPref("accessibility.browsewithcaret", true); 1012 1013 synthesizeKey("KEY_ArrowLeft", {}, gChildWindow); 1014 synthesizeKey("KEY_ArrowLeft", {}, gChildWindow); 1015 is(fm.focusedElement, null, "move caret away from link"); 1016 1017 synthesizeKey("KEY_ArrowLeft", {}, gChildWindow); 1018 is(fm.focusedElement, getById("t24"), "move caret away onto link"); 1019 1020 prefs.setBoolPref("accessibility.browsewithcaret", false); 1021 1022 // cases where focus in on a content node with no frame 1023 1024 if (!gPartialTabbing) { 1025 getById("t24").blur(); 1026 gEvents = ""; 1027 gLastFocus = null; 1028 gLastFocusWindow = gChildWindow; 1029 gLastFocusMethod = fm.FLAG_BYKEY; 1030 1031 selection.selectAllChildren(getById("hiddenspan")); 1032 expectFocusShift(() => synthesizeKey("KEY_Tab"), 1033 gChildWindow, getById("t26"), true, "tab with selection on hidden content"); 1034 1035 setFocusTo($("o15"), window); 1036 $("o15").hidden = true; 1037 document.documentElement.getBoundingClientRect(); // flush after hiding 1038 expectFocusShift(() => synthesizeKey("KEY_Tab"), 1039 window, $("o17"), true, "tab with focus on hidden content"); 1040 1041 $("o17").hidden = true; 1042 document.documentElement.getBoundingClientRect(); 1043 expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}), 1044 window, $("o13"), true, "shift+tab with focus on hidden content"); 1045 } 1046 1047 // cases with selection in an <input> 1048 1049 var t19 = getById("t19"); 1050 t19.setSelectionRange(0, 0); 1051 setFocusTo("t18", gChildWindow); 1052 1053 gLastFocusMethod = fm.FLAG_BYMOVEFOCUS; 1054 expectFocusShift(() => newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_FORWARD, 0), 1055 gChildWindow, t19, true, "moveFocus to next input"); 1056 is(t19.selectionStart, 0, "input focused after moveFocus selectionStart"); 1057 is(t19.selectionEnd, 5, "input focused after moveFocus selectionEnd"); 1058 1059 t19.setSelectionRange(0, 0); 1060 setFocusTo("t18", gChildWindow); 1061 gLastFocusMethod = fm.FLAG_BYKEY; 1062 expectFocusShift(() => newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_FORWARD, fm.FLAG_BYKEY), 1063 gChildWindow, t19, true, "moveFocus to next input by key"); 1064 is(t19.selectionStart, 0, "input focused after moveFocus by key selectionStart"); 1065 is(t19.selectionEnd, 5, "input focused after moveFocus by key selectionEnd"); 1066 } 1067 1068 function otherWindowFocused(otherWindow) 1069 { 1070 var expectedElement = getById("t9"); 1071 1072 is(fm.activeWindow, otherWindow, "other activeWindow"); 1073 is(fm.focusedWindow, otherWindow, "other focusedWindow"); 1074 is(window.document.hasFocus(), false, "when lowered document hasFocus"); 1075 var focusedWindow = {}; 1076 is(fm.getFocusedElementForWindow(window, false, focusedWindow), 1077 expectedElement, "when lowered getFocusedElementForWindow"); 1078 is(focusedWindow.value, window, "when lowered getFocusedElementForWindow frame"); 1079 is(document.activeElement.id, expectedElement.id, "when lowered activeElement"); 1080 is(window.document.commandDispatcher.focusedWindow, window, " commandDispatcher in other window focusedWindow"); 1081 is(window.document.commandDispatcher.focusedElement, expectedElement, " commandDispatcher in other window focusedElement"); 1082 1083 compareEvents("deactivate: outer-document-window blur: t9 blur: outer-document blur: outer-window", 1084 otherWindow, null, "other window opened"); 1085 1086 otherWindow.document.getElementById("other").focus(); 1087 1088 for (var idx = kTabbableSteps; idx >= 1; idx--) { 1089 expectedElement = getById("t" + idx); 1090 if (!expectedElement) // skip elements that were removed in doRemoveTests() 1091 continue; 1092 if ((navigator.platform.indexOf("Mac") == 0) && (idx == kBeforeTabboxIndex + 1)) 1093 continue; 1094 1095 expectedElement.focus(); 1096 1097 is(fm.focusedElement.id, "other", "when lowered focusedElement t" + idx); 1098 is(fm.focusedWindow, otherWindow, "when lowered focusedWindow t" + idx); 1099 1100 var checkWindow = expectedElement.ownerGlobal; 1101 is(fm.getFocusedElementForWindow(checkWindow, false, {}).id, expectedElement.id, 1102 "when lowered getFocusedElementForWindow t" + idx); 1103 is(checkWindow.document.activeElement.id, expectedElement.id, "when lowered activeElement t" + idx); 1104 if (checkWindow != window) { 1105 is(fm.getFocusedElementForWindow(window, false, {}), $("childframe"), 1106 "when lowered parent getFocusedElementForWindow t" + idx); 1107 is(document.activeElement.id, "childframe", 1108 "when lowered parent activeElement t" + idx); 1109 } 1110 } 1111 1112 gEvents = gEvents.replace(/commandupdate: cu\s?/g, ""); 1113 is(gEvents, "", "when lowered no events fired"); 1114 1115 var other = otherWindow.document.getElementById("other"); 1116 other.focus(); 1117 is(fm.focusedElement, other, "focus method in second window"); 1118 1119 otherWindow.close(); 1120 1121 getById("n2").focus(); 1122 1123 // next, check modal dialogs 1124 window.openDialog("focus_window2.xhtml", "_blank", "chrome,modal", modalWindowOpened); 1125 } 1126 1127 async function modalWindowOpened(modalWindow) 1128 { 1129 var elem = modalWindow.document.getElementById("other"); 1130 if (gPartialTabbing) 1131 elem.focus(); 1132 else 1133 synthesizeKey("KEY_Tab", {}, modalWindow); 1134 is(fm.activeWindow, modalWindow, "modal activeWindow"); 1135 is(fm.focusedElement, elem, "modal focusedElement"); 1136 1137 // For silly reasons (see the comments around nsCloseEvent), close() doesn't 1138 // synchronously close the modal window. If we try to focus the window before 1139 // the modal window is fully closed, we fail to focus it (see 1140 // AppWindow::EnableParent). 1141 // 1142 // Wait for the unload event to make sure that we get enabled on time. Another 1143 // alternative would be to use the xul-window-destroyed topic. 1144 await new Promise(r => { 1145 modalWindow.addEventListener("unload", r, { once: true }); 1146 modalWindow.close(); 1147 }); 1148 await SimpleTest.promiseFocus(); 1149 modalWindowClosed(); 1150 } 1151 1152 function modalWindowClosed() 1153 { 1154 is(fm.activeWindow, window, "modal window closed activeWindow"); 1155 is(fm.focusedElement, getById("n2"), "modal window closed focusedElement"); 1156 1157 window.arguments[0].framesetWindowLoaded = framesetWindowLoaded; 1158 window.arguments[0].open("focus_frameset.html", "_blank", "width=400,height=400,toolbar=no"); 1159 } 1160 1161 function framesetWindowLoaded(framesetWindow) 1162 { 1163 gLastFocus = null; 1164 gLastFocusWindow = framesetWindow; 1165 gEvents = ""; 1166 1167 is(fm.activeWindow, getTopWindow(framesetWindow), "frameset window active"); 1168 gOldExpectedWindow = getTopWindow(framesetWindow); 1169 1170 gMoveToFocusFrame = true; 1171 let steps = 4; 1172 for (var idx = 1; idx <= steps; idx++) { 1173 let frameIndex = idx - 1; 1174 gNewExpectedWindow = framesetWindow.frames[frameIndex]; 1175 initEvents(gNewExpectedWindow); 1176 expectFocusShift(() => synthesizeKey("KEY_Tab", {}, framesetWindow), 1177 gNewExpectedWindow, getById("f" + idx * 2), true, "frameset tab key f" + idx); 1178 gMoveToFocusFrame = false; 1179 gOldExpectedWindow = gNewExpectedWindow; 1180 } 1181 1182 gNewExpectedWindow = framesetWindow.frames[0]; 1183 expectFocusShift(() => synthesizeKey("KEY_Tab", {}, framesetWindow), 1184 gNewExpectedWindow, getById("f2"), true, "frameset tab key wrap to start"); 1185 gOldExpectedWindow = gNewExpectedWindow; 1186 gNewExpectedWindow = framesetWindow.frames[3]; 1187 expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}, framesetWindow), 1188 gNewExpectedWindow, getById("f8"), true, "frameset shift tab key wrap to end"); 1189 1190 steps = 3; 1191 for (idx = steps; idx >= 1; idx--) { 1192 gOldExpectedWindow = gNewExpectedWindow; 1193 let frameIndex = idx - 1; 1194 gNewExpectedWindow = framesetWindow.frames[frameIndex]; 1195 expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}, framesetWindow), 1196 gNewExpectedWindow, getById("f" + idx * 2), true, "frameset shift tab key f" + idx); 1197 } 1198 1199 // document shifting 1200 // XXXndeakin P3 ctrl+tab doesn't seem to be testable currently for some reason 1201 gNewExpectedWindow = framesetWindow.frames[1]; 1202 expectFocusShift(() => synthesizeKey("KEY_F6", {ctrlKey: true}, framesetWindow), 1203 gNewExpectedWindow, getById("f3"), true, "switch document forward with f6"); 1204 gOldExpectedWindow = gNewExpectedWindow; 1205 gNewExpectedWindow = framesetWindow.frames[2]; 1206 expectFocusShift(() => synthesizeKey("KEY_F6", {}, framesetWindow), 1207 gNewExpectedWindow, getById("f5"), true, "switch document forward with ctrl+tab"); 1208 gOldExpectedWindow = gNewExpectedWindow; 1209 gNewExpectedWindow = framesetWindow.frames[3]; 1210 expectFocusShift(() => synthesizeKey("KEY_F6", {ctrlKey: true}, framesetWindow), 1211 gNewExpectedWindow, getById("f7"), true, "switch document forward with ctrl+f6"); 1212 gOldExpectedWindow = gNewExpectedWindow; 1213 gNewExpectedWindow = framesetWindow.frames[0]; 1214 expectFocusShift(() => synthesizeKey("KEY_F6", {ctrlKey: true}, framesetWindow), 1215 gNewExpectedWindow, getById("f1"), true, "switch document forward and wrap"); 1216 1217 // going backwards by document and wrapping doesn't currently work, but didn't work 1218 // before the focus reworking either 1219 1220 /* 1221 gOldExpectedWindow = gNewExpectedWindow; 1222 gNewExpectedWindow = framesetWindow.frames[3]; 1223 expectFocusShift(() => synthesizeKey("KEY_F6", { ctrlKey: true, shiftKey: true }, framesetWindow), 1224 gNewExpectedWindow, getById("f7"), true, "switch document backward and wrap"); 1225 */ 1226 1227 fm.moveFocus(framesetWindow.frames[3], null, fm.MOVEFOCUS_ROOT, 0); 1228 gEvents = ""; 1229 1230 gOldExpectedWindow = gNewExpectedWindow; 1231 gNewExpectedWindow = framesetWindow.frames[2]; 1232 expectFocusShift(() => synthesizeKey("KEY_F6", {ctrlKey: true, shiftKey: true}, framesetWindow), 1233 gNewExpectedWindow, getById("f5"), true, "switch document backward with f6"); 1234 gOldExpectedWindow = gNewExpectedWindow; 1235 gNewExpectedWindow = framesetWindow.frames[1]; 1236 expectFocusShift(() => synthesizeKey("KEY_F6", {ctrlKey: true, shiftKey: true}, framesetWindow), 1237 gNewExpectedWindow, getById("f3"), true, "switch document backward with ctrl+tab"); 1238 gOldExpectedWindow = gNewExpectedWindow; 1239 gNewExpectedWindow = framesetWindow.frames[0]; 1240 expectFocusShift(() => synthesizeKey("KEY_F6", {ctrlKey: true, shiftKey: true}, framesetWindow), 1241 gNewExpectedWindow, getById("f1"), true, "switch document backward with ctrl+f6"); 1242 1243 // skip the window switching tests for now on Linux, as raising and lowering 1244 // a window is asynchronous there 1245 if (!navigator.platform.includes("Linux")) { 1246 window.openDialog("focus_window2.xhtml", "_blank", "chrome", switchWindowTest, framesetWindow); 1247 } 1248 else { 1249 gOldExpectedWindow = null; 1250 gNewExpectedWindow = null; 1251 framesetWindow.close(); 1252 SimpleTest.waitForFocus(doWindowNoRootTest); 1253 } 1254 } 1255 1256 // test switching between two windows 1257 function switchWindowTest(otherWindow, framesetWindow) 1258 { 1259 initEvents(otherWindow); 1260 var otherElement = otherWindow.document.getElementById("other"); 1261 otherElement.focus(); 1262 1263 framesetWindow.frames[1].document.getElementById("f4").focus(); 1264 1265 is(fm.focusedElement, otherElement, "focus after inactive window focus"); 1266 1267 gLastFocus = otherElement; 1268 gLastFocusWindow = otherWindow; 1269 gEvents = ""; 1270 gOldExpectedWindow = otherWindow; 1271 gNewExpectedWindow = framesetWindow.frames[1]; 1272 1273 expectFocusShift(() => gNewExpectedWindow.focus(), 1274 gNewExpectedWindow, getById("f4"), true, "switch to frame in another window"); 1275 is(fm.getFocusedElementForWindow(otherWindow, false, {}).id, "other", "inactive window has focused element"); 1276 1277 gOldExpectedWindow = framesetWindow.frames[1]; 1278 gNewExpectedWindow = otherWindow; 1279 expectFocusShift(() => otherWindow.focus(), 1280 gNewExpectedWindow, getById("other"), true, "switch to another window"); 1281 1282 var topWindow = getTopWindow(framesetWindow); 1283 1284 ok(topWindow.document.commandDispatcher.getControllerForCommand("cmd_copy"), 1285 "getControllerForCommand for focused window set"); 1286 ok(otherWindow.document.commandDispatcher.getControllerForCommand("cmd_copy"), 1287 "getControllerForCommand for non-focused window set"); 1288 ok(topWindow.document.commandDispatcher.getControllerForCommand("cmd_copy") != 1289 otherWindow.document.commandDispatcher.getControllerForCommand("cmd_copy"), 1290 "getControllerForCommand for two windows different"); 1291 ok(topWindow.document.commandDispatcher.getControllers() != 1292 otherWindow.document.commandDispatcher.getControllers(), 1293 "getControllers for two windows different"); 1294 1295 gOldExpectedWindow = otherWindow; 1296 gNewExpectedWindow = framesetWindow.frames[1]; 1297 expectFocusShift(() => topWindow.focus(), 1298 gNewExpectedWindow, getById("f4"), true, "switch to frame activeWindow"); 1299 1300 fm.clearFocus(otherWindow); 1301 gOldExpectedWindow = gNewExpectedWindow; 1302 gNewExpectedWindow = otherWindow; 1303 expectFocusShift(() => fm.setFocus(otherElement, fm.FLAG_RAISE), 1304 gNewExpectedWindow, getById("other"), true, "switch to window with raise"); 1305 1306 getTopWindow(framesetWindow).document.commandDispatcher.focusedWindow = gOldExpectedWindow; 1307 is(fm.activeWindow, gNewExpectedWindow, "setting commandDispatcher focusedWindow doesn't raise window"); 1308 1309 fm.moveFocus(otherWindow, null, fm.MOVEFOCUS_FORWARD, 0); 1310 var otherInput = otherWindow.document.getElementById("other-input"); 1311 otherInput.setSelectionRange(2, 3); 1312 topWindow.focus(); 1313 otherWindow.focus(); 1314 is(otherInput.selectionStart, 2, "selectionStart after input focus and window raise"); 1315 is(otherInput.selectionEnd, 3, "selectionEnd after input focus and window raise"); 1316 is(fm.getLastFocusMethod(null), fm.FLAG_BYMOVEFOCUS, "last focus method after input focus and window raise"); 1317 1318 fm.clearFocus(otherWindow); 1319 1320 // test to ensure that a synthetic event won't move focus 1321 var synevent = new FocusEvent("focus", {}); 1322 otherInput.dispatchEvent(synevent); 1323 is(synevent.type, "focus", "event.type after synthetic focus event"); 1324 is(synevent.target, otherInput, "event.target after synthetic focus event"); 1325 is(fm.focusedElement, null, "focusedElement after synthetic focus event"); 1326 is(otherWindow.document.activeElement, otherWindow.document.documentElement, 1327 "document.activeElement after synthetic focus event"); 1328 1329 // check accessing a focus event after the event has finishing firing 1330 function continueTest(event) { 1331 is(event.type, "focus", "event.type after accessing focus event in timeout"); 1332 is(event.target, otherInput, "event.target after accessing focus event in timeout"); 1333 1334 gOldExpectedWindow = null; 1335 gNewExpectedWindow = null; 1336 otherWindow.close(); 1337 framesetWindow.close(); 1338 1339 SimpleTest.waitForFocus(doWindowNoRootTest); 1340 } 1341 1342 function inputFocused(event) { 1343 otherInput.removeEventListener("focus", inputFocused, true); 1344 setTimeout(continueTest, 0, event); 1345 } 1346 1347 otherInput.addEventListener("focus", inputFocused, true); 1348 otherInput.focus(); 1349 } 1350 1351 // open a window with no root element 1352 var noRootWindow = null; 1353 function doWindowNoRootTest() 1354 { 1355 addEventListener("focus", doFrameSwitchingTests, true); 1356 noRootWindow = window.open("window_focus_inner.xhtml", "_blank", "chrome,width=100,height=100"); 1357 } 1358 1359 // these tests check when focus is moved between a tree of frames to ensure 1360 // that the focus is in the right place at each event step. 1361 function doFrameSwitchingTests() 1362 { 1363 removeEventListener("focus", doFrameSwitchingTests, true); 1364 noRootWindow.close(); 1365 1366 var framea = document.getElementById("ifa"); 1367 var frameb = document.getElementById("ifb"); 1368 framea.style.MozUserFocus = ""; 1369 frameb.style.MozUserFocus = ""; 1370 1371 window.removeEventListener("focus", eventOccured, true); 1372 window.removeEventListener("blur", eventOccured, true); 1373 1374 var inputa = framea.contentDocument.body.firstChild; 1375 inputa.focus(); 1376 1377 addFrameSwitchingListeners(framea); 1378 addFrameSwitchingListeners(frameb); 1379 var framec = framea.contentDocument.body.lastChild; 1380 addFrameSwitchingListeners(framec); 1381 1382 var framed = framec.contentDocument.body.lastChild; 1383 addFrameSwitchingListeners(framed); 1384 1385 var inputc = framec.contentDocument.body.firstChild; 1386 1387 var expectedMainWindowFocus = framea; 1388 1389 // An element in the immediate parent frame is focused. Focus an element in 1390 // the child. The child should be focused and the parent's current focus should 1391 // be the child iframe. 1392 gEventMatched = true; 1393 is(fm.getFocusedElementForWindow(window, false, {}), expectedMainWindowFocus, 1394 "parent of framea has iframe focused"); 1395 gExpectedEvents = [[inputa, "blur", null, framea.contentWindow, window, framea], 1396 [framea.contentDocument, "blur", null, null, window, framea], 1397 [framea.contentWindow, "blur", null, null, window, framea], 1398 [framec.contentDocument, "focus", null, framec.contentWindow, window, framea], 1399 [framec.contentWindow, "focus", null, framec.contentWindow, window, framea], 1400 [inputc, "focus", inputc, framec.contentWindow, window, framea]]; 1401 inputc.focus(); 1402 ok(gEventMatched && !gExpectedEvents.length, "frame switch from parent input to child input" + gExpectedEvents); 1403 1404 // An element in a child is focused. Focus an element in the immediate 1405 // parent. 1406 gEventMatched = true; 1407 gExpectedEvents = [[inputc, "blur", null, framec.contentWindow, window, framea], 1408 [framec.contentDocument, "blur", null, null, window, framea], 1409 [framec.contentWindow, "blur", null, null, window, framea], 1410 [framea.contentDocument, "focus", null, framea.contentWindow, window, framea], 1411 [framea.contentWindow, "focus", null, framea.contentWindow, window, framea], 1412 [inputa, "focus", inputa, framea.contentWindow, window, framea]]; 1413 inputa.focus(); 1414 ok(gEventMatched && !gExpectedEvents.length, "frame switch from child input to parent input"); 1415 1416 // An element in a frame is focused. Focus an element in a sibling frame. 1417 // The common ancestor of the two frames should have its focused node 1418 // cleared after the element is blurred. 1419 var inputb = frameb.contentDocument.body.firstChild; 1420 1421 gEventMatched = true; 1422 gExpectedEvents = [[inputa, "blur", null, framea.contentWindow, window, framea], 1423 [framea.contentDocument, "blur", null, null, window, null], 1424 [framea.contentWindow, "blur", null, null, window, null], 1425 [frameb.contentDocument, "focus", null, frameb.contentWindow, window, frameb], 1426 [frameb.contentWindow, "focus", null, frameb.contentWindow, window, frameb], 1427 [inputb, "focus", inputb, frameb.contentWindow, window, frameb]]; 1428 inputb.focus(); 1429 ok(gEventMatched && !gExpectedEvents.length, "frame switch from input to sibling frame"); 1430 is(fm.getFocusedElementForWindow(framea.contentWindow, false, {}), inputa, 1431 "blurred frame still has input as focus"); 1432 1433 // focus a descendant in a sibling 1434 var inputd = framed.contentDocument.body.firstChild; 1435 gEventMatched = true; 1436 gExpectedEvents = [[inputb, "blur", null, frameb.contentWindow, window, frameb], 1437 [frameb.contentDocument, "blur", null, null, window, null], 1438 [frameb.contentWindow, "blur", null, null, window, null], 1439 [framed.contentDocument, "focus", null, framed.contentWindow, window, framea], 1440 [framed.contentWindow, "focus", null, framed.contentWindow, window, framea], 1441 [inputd, "focus", inputd, framed.contentWindow, window, framea]]; 1442 inputd.focus(); 1443 ok(gEventMatched && !gExpectedEvents.length, "frame switch from input to sibling descendant"); 1444 is(fm.getFocusedElementForWindow(framea.contentWindow, false, {}), framec, 1445 "sibling parent focus has shifted to frame"); 1446 1447 // focus an ancestor 1448 gEventMatched = true; 1449 gExpectedEvents = [[inputd, "blur", null, framed.contentWindow, window, framea], 1450 [framed.contentDocument, "blur", null, null, window, framea], 1451 [framed.contentWindow, "blur", null, null, window, framea], 1452 [framea.contentDocument, "focus", null, framea.contentWindow, window, framea], 1453 [framea.contentWindow, "focus", null, framea.contentWindow, window, framea], 1454 [inputa, "focus", inputa, framea.contentWindow, window, framea]]; 1455 inputa.focus(); 1456 ok(gEventMatched && !gExpectedEvents.length, "frame switch from child input to ancestor"); 1457 1458 // focus a descendant 1459 gEventMatched = true; 1460 gExpectedEvents = [[inputa, "blur", null, framea.contentWindow, window, framea], 1461 [framea.contentDocument, "blur", null, null, window, framea], 1462 [framea.contentWindow, "blur", null, null, window, framea], 1463 [framed.contentDocument, "focus", null, framed.contentWindow, window, framea], 1464 [framed.contentWindow, "focus", null, framed.contentWindow, window, framea], 1465 [inputd, "focus", inputd, framed.contentWindow, window, framea]]; 1466 inputd.focus(); 1467 ok(gEventMatched && !gExpectedEvents.length, "frame switch from child input to ancestor"); 1468 is(fm.getFocusedElementForWindow(framea.contentWindow, false, {}), framec, 1469 "parent focus has shifted to frame"); 1470 1471 // focus a sibling frame by setting focusedWindow 1472 gEventMatched = true; 1473 gExpectedEvents = [[inputd, "blur", null, framed.contentWindow, window, framea], 1474 [framed.contentDocument, "blur", null, null, window, null], 1475 [framed.contentWindow, "blur", null, null, window, null], 1476 [frameb.contentDocument, "focus", null, frameb.contentWindow, window, frameb], 1477 [frameb.contentWindow, "focus", null, frameb.contentWindow, window, frameb]]; 1478 fm.focusedWindow = frameb.contentWindow; 1479 ok(gEventMatched && !gExpectedEvents.length, "frame switch using focusedWindow"); 1480 1481 // clear the focus in an unfocused frame 1482 gEventMatched = true; 1483 gExpectedEvents = []; 1484 fm.clearFocus(framec.contentWindow); 1485 ok(gEventMatched && !gExpectedEvents.length, "clearFocus in unfocused frame"); 1486 1487 // focus a sibling frame by setting focusedWindow when no element is focused in that frame 1488 gEventMatched = true; 1489 gExpectedEvents = [[frameb.contentDocument, "blur", null, null, window, null], 1490 [frameb.contentWindow, "blur", null, null, window, null], 1491 [framec.contentDocument, "focus", null, framec.contentWindow, window, framea], 1492 [framec.contentWindow, "focus", null, framec.contentWindow, window, framea]]; 1493 fm.focusedWindow = framec.contentWindow; 1494 ok(gEventMatched && !gExpectedEvents.length, "frame switch using focusedWindow with no element focused"); 1495 is(fm.getFocusedElementForWindow(framea.contentWindow, false, {}), framec, 1496 "parent focus has shifted to frame using focusedWindow"); 1497 1498 // focus the parent frame by setting focusedWindow. This should have no effect. 1499 gEventMatched = true; 1500 gExpectedEvents = []; 1501 fm.focusedWindow = framea.contentWindow; 1502 ok(gEventMatched && !gExpectedEvents.length, "frame switch to parent using focusedWindow"); 1503 1504 // clear the focus in the parent frame 1505 gEventMatched = true; 1506 gExpectedEvents = [[framec.contentDocument, "blur", null, null, window, framea], 1507 [framec.contentWindow, "blur", null, null, window, framea], 1508 [framea.contentDocument, "focus", null, framea.contentWindow, window, framea], 1509 [framea.contentWindow, "focus", null, framea.contentWindow, window, framea]]; 1510 fm.clearFocus(framea.contentWindow); 1511 ok(gEventMatched && !gExpectedEvents.length, "clearFocus in parent frame"); 1512 1513 // clear the focus in an unfocused child frame 1514 gEventMatched = true; 1515 gExpectedEvents = []; 1516 fm.clearFocus(framed.contentWindow); 1517 ok(gEventMatched && !gExpectedEvents.length, "clearFocus in unfocused child frame"); 1518 1519 var exh = false; 1520 try { 1521 fm.focusedWindow = null; 1522 } 1523 catch (ex) { exh = true; } 1524 is(exh, true, "focusedWindow set to null"); 1525 is(fm.focusedWindow, framea.contentWindow, "window not changed when focusedWindow set to null"); 1526 1527 doFrameHistoryTests() 1528 } 1529 1530 function doFrameHistoryTests() 1531 { 1532 let frame = $("childframe"); 1533 frame.setAttribute("maychangeremoteness", "true"); 1534 let loaded = BrowserTestUtils.browserLoaded(frame, true); 1535 let firstLocation = "https://example.org/chrome/dom/tests/mochitest/chrome/child_focus_frame.html"; 1536 frame.src = firstLocation; 1537 loaded.then(() => { 1538 return ContentTask.spawn(frame, {}, () => { 1539 let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); 1540 let t20 = content.document.getElementById("t20"); 1541 t20.focus(); 1542 let goneBack = new Promise(resolve => { 1543 content.addEventListener("pageshow", ({ persisted }) => { 1544 resolve({ location: content.location.href, persisted }); 1545 }, { once: true }); 1546 }); 1547 // Make sure that loading a new page and then going back maintains the focus, 1548 // but try to stabilize the page first so that it can enter bfcache. 1549 content.requestAnimationFrame(() => { 1550 content.requestAnimationFrame(() => { 1551 content.location = "data:text/html,<script>window.onload=function() {setTimeout(function () { history.back() }, 0);}</script>"; 1552 }); 1553 }); 1554 return goneBack; 1555 }); 1556 }).then(({ location, persisted }) => { 1557 is(location, firstLocation, "should go back to the right page"); 1558 ok(persisted, "test relies on BFCache"); 1559 return ContentTask.spawn(frame, {}, () => { 1560 let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); 1561 let t20 = content.document.getElementById("t20"); 1562 return fm.focusedElement === t20; 1563 }); 1564 }).then((focusCorrect) => { 1565 if (SpecialPowers.Services.appinfo.sessionHistoryInParent) { 1566 todo(focusCorrect, "focus restored after history back"); 1567 } else { 1568 ok(focusCorrect, "focus restored after history back"); 1569 } 1570 done(); 1571 }); 1572 } 1573 1574 function addFrameSwitchingListeners(frame) 1575 { 1576 frame.contentWindow.addEventListener("focus", frameSwitchingEventOccured); 1577 frame.contentWindow.addEventListener("blur", frameSwitchingEventOccured); 1578 frame.contentDocument.addEventListener("focus", frameSwitchingEventOccured); 1579 frame.contentDocument.addEventListener("blur", frameSwitchingEventOccured); 1580 1581 var node = frame.contentDocument.body.firstChild; 1582 node.addEventListener("focus", frameSwitchingEventOccured); 1583 node.addEventListener("blur", frameSwitchingEventOccured); 1584 } 1585 1586 function frameSwitchingEventOccured(event) 1587 { 1588 if (!gExpectedEvents.length) { 1589 gEventMatched = false; 1590 return; 1591 } 1592 1593 try { 1594 var events = gExpectedEvents.shift(); 1595 is(event.target, events[0], "event target"); 1596 is(event.type, events[1], "event type"); 1597 is(fm.focusedElement, events[2], "focused element"); 1598 is(fm.focusedWindow, events[3], "focused frame"); 1599 if (events[4]) 1600 is(fm.getFocusedElementForWindow(events[4], false, {}), events[5], "focused element in frame"); 1601 1602 if (gEventMatched && event.target == events[0] && event.type == events[1] && 1603 fm.focusedElement == events[2] && fm.focusedWindow == events[3]) { 1604 if (!events[4] || fm.getFocusedElementForWindow(events[4], false, {}) == events[5]) 1605 return; 1606 } 1607 } catch (ex) { ok(ex, "exception"); } 1608 1609 gEventMatched = false; 1610 } 1611 1612 SimpleTest.waitForExplicitFinish(); 1613 SimpleTest.waitForFocus(startTest); 1614 1615 ]]> 1616 </script> 1617 1618 <commandset id="cu" 1619 commandupdater="true" 1620 events="focus" 1621 oncommandupdate="eventOccured(event)"/> 1622 1623 <!-- 1624 The elements with ids starting with t are focusable and in the taborder. 1625 The elements with ids starting with o are: 1626 odd numbered ids - focusable but not part of the tab order 1627 even numbered ids - not focusable with -moz-user-focus: ignore or disabled 1628 The elements with ids starting with n are: 1629 odd numbered ids - not focusable with -moz-user-focus: none 1630 even numbered ids - focusable but not part of the tab order 1631 --> 1632 <vbox id="buttonbox"> 1633 <hbox id="innerbox"> 1634 <button id="t4" accesskey="h" label="no tabindex"/> 1635 <button id="o1" accesskey="i" label="tabindex = -1" tabindex="-1"/> 1636 <richlistbox id="t5" label="tabindex = 0" tabindex="0" style="width: 50px"> 1637 <richlistitem height="10"/> 1638 </richlistbox> 1639 <button id="t1" label="tabindex = 2" tabindex="2"/> 1640 </hbox> 1641 <hbox> 1642 <button id="o2" accesskey="o" style="-moz-user-focus: ignore;" label="no tabindex"/> 1643 <button id="o4" style="-moz-user-focus: ignore;" label="no tabindex"/> 1644 <button id="t6" style="-moz-user-focus: ignore;" label="tabindex = 0" tabindex="0"/> 1645 <button id="t2" style="-moz-user-focus: ignore;" label="tabindex = 2" tabindex="2"/> 1646 </hbox> 1647 <hbox id="specialroot"> 1648 <button id="t7" style="-moz-user-focus: normal;" label="no tabindex"/> 1649 <button id="o3" style="-moz-user-focus: normal;" label="tabindex = -1" tabindex="-1"/> 1650 <button id="t8" style="-moz-user-focus: normal;" label="tabindex = 0" tabindex="0"/> 1651 <richlistbox id="t3" style="-moz-user-focus: normal; width: 50px" label="tabindex = 2" tabindex="2"> 1652 <richlistitem style="height: 10px"/> 1653 </richlistbox> 1654 </hbox> 1655 <hbox> 1656 <button accesskey="p" style="display: none;"/> <button accesskey="q" style="visibility: collapse;"/> 1657 <button style="display: none;" tabindex="2"/> <button style="visibility: collapse;" tabindex="2"/> 1658 </hbox> 1659 <hbox> 1660 <button id="o20" accesskey="s" label="no tabindex" disabled="true"/> 1661 <button id="o22" label="tabindex = -1" tabindex="-1" disabled="true"/> 1662 <button id="o24" label="tabindex = 0" tabindex="0" disabled="true"/> 1663 <button id="o26" label="tabindex = 2" tabindex="2" disabled="true"/> 1664 </hbox> 1665 </vbox> 1666 <vbox> 1667 <hbox> 1668 <dropmarker id="o6" value="no tabindex"/> 1669 <dropmarker id="o8" value="no tabindex"/> 1670 <dropmarker id="o10" value="no tabindx"/> 1671 <dropmarker id="o12" value="no tabindex"/> 1672 <dropmarker id="t9" accesskey="r" style="-moz-user-focus: normal;" value="no tabindex" /> 1673 <dropmarker id="t10" style="-moz-user-focus: normal;" value="no tabindex"/> 1674 <dropmarker id="t11" style="-moz-user-focus: normal;" value="tabindex = 0" tabindex="0" /> 1675 <dropmarker id="t12" style="-moz-user-focus: normal;" value="no tabindex"/> 1676 <dropmarker id="o14" style="-moz-user-focus: ignore;" value="no tabindex"/> 1677 <dropmarker id="o16" style="-moz-user-focus: ignore;" value="no tabindex"/> 1678 <dropmarker id="n1" style="-moz-user-focus: none;" value="no tabindex"/> 1679 <dropmarker id="n3" style="-moz-user-focus: none;" value="no tabindex"/> 1680 </hbox> 1681 </vbox> 1682 <browser id="childframe" type="content" src="child_focus_frame.html" style="height: 195px"/> 1683 <button id="t34"/> 1684 <tabbox id="tabbox"> 1685 <tabs><tab id="t35" label="One"/><tab id="tab2" label="Two"/></tabs> 1686 <tabpanels> 1687 <tabpanel> 1688 <checkbox id="t36"/> 1689 <button id="t37"/> 1690 </tabpanel> 1691 <tabpanel> 1692 <checkbox id="htab1"/> 1693 <button id="nohtab2" tabindex="7"/> 1694 <checkbox id="htab2" tabindex="0"/> 1695 </tabpanel> 1696 </tabpanels> 1697 </tabbox> 1698 <hbox> 1699 <panel> 1700 <button id="inpopup1" label="One"/> 1701 <input xmlns="http://www.w3.org/1999/xhtml" label="Two"/> 1702 </panel> 1703 <description label="o" accesskey="v"/> 1704 <button id="t38"/> 1705 <!-- The 't' element tests end here so it doesn't matter that these elements are tabbable --> 1706 <label id="aj" value="j" accesskey="j" control="o9"/> 1707 <label id="ak" accesskey="k" control="n4">k</label> 1708 <checkbox id="o5"/><checkbox id="o7"/><hbox><checkbox id="o9"/></hbox> 1709 <checkbox id="o13"/><checkbox id="o15"/><checkbox id="o17"/><checkbox id="o19"/><checkbox id="o21"/><checkbox id="o23"/><checkbox id="o25"/> 1710 <checkbox id="n2"/><checkbox id="n4"/> 1711 <richlistbox id="last" style="width: 20px; height: 20px"/> 1712 1713 <iframe id="ifa" style="-moz-user-focus: ignore; width: 40px; height: 60px" type="content" 1714 src="data:text/html,<input id=fra size='2'><input id='fra-b' size='2'> 1715 <iframe src='data:text/html,<input id=frc><iframe src="data:text/html,<input id=frd>"></iframe>'></iframe>"/> 1716 <iframe id="ifb" style="-moz-user-focus: ignore; width: 20px; height: 20px" 1717 src="data:text/html,<input id=frd></iframe>"/> 1718 1719 </hbox> 1720 </window>