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