Bug 1343210 - Only move focus into identity popup when opened via keyboard. r=Gijs draft
authorJohann Hofmann <jhofmann@mozilla.com>
Tue, 28 Feb 2017 14:29:03 +0100
changeset 490721 144b81bf94259b4755db231989822db84a7c37f2
parent 490433 1bc2ad020aee2830e0a7941f10958dbec108c254
child 547358 238c4088e811626f1ad2c4bd9ecef49d1c0dd8e3
push id47206
push userbmo:jhofmann@mozilla.com
push dateWed, 01 Mar 2017 07:43:35 +0000
reviewersGijs
bugs1343210
milestone54.0a1
Bug 1343210 - Only move focus into identity popup when opened via keyboard. r=Gijs MozReview-Commit-ID: FZG2DKSM5Fh
browser/base/content/browser.js
browser/base/content/test/siteIdentity/browser.ini
browser/base/content/test/siteIdentity/browser_identityPopup_focus.js
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -6716,16 +6716,22 @@ var gIdentityHandler = {
    */
   _sslStatus: null,
 
   /**
    * Bitmask provided by nsIWebProgressListener.onSecurityChange.
    */
   _state: 0,
 
+  /**
+   * This flag gets set if the identity popup was opened by a keypress,
+   * to be able to focus it on the popupshown event.
+   */
+  _popupTriggeredByKeyboard: false,
+
   get _isBroken() {
     return this._state & Ci.nsIWebProgressListener.STATE_IS_BROKEN;
   },
 
   get _isSecure() {
     // If a <browser> is included within a chrome document, then this._state
     // will refer to the security state for the <browser> and not the top level
     // document. In this case, don't upgrade the security state in the UI
@@ -7356,16 +7362,18 @@ var gIdentityHandler = {
       return; // Left click, space or enter only
     }
 
     // Don't allow left click, space or enter if the location has been modified.
     if (gURLBar.getAttribute("pageproxystate") != "valid") {
       return;
     }
 
+    this._popupTriggeredByKeyboard = event.type == "keypress";
+
     // Make sure that the display:none style we set in xul is removed now that
     // the popup is actually needed
     this._identityPopup.hidden = false;
 
     // Remove the reload hint that we show after a user has cleared a permission.
     this._permissionReloadHint.setAttribute("hidden", "true");
 
     // Update the popup strings
@@ -7375,20 +7383,22 @@ var gIdentityHandler = {
     this._identityBox.setAttribute("open", "true");
 
     // Now open the popup, anchored off the primary chrome element
     this._identityPopup.openPopup(this._identityIcon, "bottomcenter topleft");
   },
 
   onPopupShown(event) {
     if (event.target == this._identityPopup) {
-      // Move focus to the next available element in the identity popup.
-      // This is required by role=alertdialog and fixes an issue where
-      // an already open panel would steal focus from the identity popup.
-      document.commandDispatcher.advanceFocusIntoSubtree(this._identityPopup);
+      if (this._popupTriggeredByKeyboard) {
+        // Move focus to the next available element in the identity popup.
+        // This is required by role=alertdialog and fixes an issue where
+        // an already open panel would steal focus from the identity popup.
+        document.commandDispatcher.advanceFocusIntoSubtree(this._identityPopup);
+      }
 
       window.addEventListener("focus", this, true);
     }
   },
 
   onPopupHidden(event) {
     if (event.target == this._identityPopup) {
       window.removeEventListener("focus", this, true);
--- a/browser/base/content/test/siteIdentity/browser.ini
+++ b/browser/base/content/test/siteIdentity/browser.ini
@@ -42,16 +42,17 @@ support-files =
 [browser_csp_block_all_mixedcontent.js]
 tags = mcb
 support-files =
   file_csp_block_all_mixedcontent.html
   file_csp_block_all_mixedcontent.js
 [browser_identity_UI.js]
 [browser_identityBlock_focus.js]
 support-files = ../general/permissions.html
+[browser_identityPopup_focus.js]
 [browser_insecureLoginForms.js]
 support-files =
   insecure_opener.html
   !/toolkit/components/passwordmgr/test/browser/form_basic.html
   !/toolkit/components/passwordmgr/test/browser/insecure_test.html
   !/toolkit/components/passwordmgr/test/browser/insecure_test_subframe.html
 [browser_mcb_redirect.js]
 tags = mcb
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/siteIdentity/browser_identityPopup_focus.js
@@ -0,0 +1,27 @@
+/* Tests the focus behavior of the identity popup. */
+
+// Access the identity popup via mouseclick. Focus should not be moved inside.
+add_task(function* testIdentityPopupFocusClick() {
+  yield SpecialPowers.pushPrefEnv({"set": [["accessibility.tabfocus", 7]]});
+  yield BrowserTestUtils.withNewTab("https://example.com", function*() {
+    let shown = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
+    EventUtils.synthesizeMouseAtCenter(gIdentityHandler._identityBox, {});
+    yield shown;
+    isnot(Services.focus.focusedElement, document.getElementById("identity-popup-security-expander"));
+  });
+});
+
+// Access the identity popup via keyboard. Focus should be moved inside.
+add_task(function* testIdentityPopupFocusKeyboard() {
+  yield SpecialPowers.pushPrefEnv({"set": [["accessibility.tabfocus", 7]]});
+  yield BrowserTestUtils.withNewTab("https://example.com", function*() {
+    let focused = BrowserTestUtils.waitForEvent(gIdentityHandler._identityBox, "focus");
+    gIdentityHandler._identityBox.focus();
+    yield focused;
+    let shown = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
+    EventUtils.synthesizeKey(" ", {});
+    yield shown;
+    is(Services.focus.focusedElement, document.getElementById("identity-popup-security-expander"));
+  });
+});
+