Bug 1551515 - Fix Library button focused/unfocused when clicking on a abuse report panel's radio button. r=mstriemer
authorLuca Greco <lgreco@mozilla.com>
Mon, 24 Jun 2019 17:18:23 +0000
changeset 479959 be82b2bd60e53730ff880428f17000df9c5af047
parent 479958 fb13459f32e45df0922b4cbb67e4ab5887467c8a
child 479960 e65bee2165ec5b7db8e2a5fa6422a001eac25324
push id88390
push userluca.greco@alcacoop.it
push dateMon, 24 Jun 2019 17:49:22 +0000
treeherderautoland@be82b2bd60e5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstriemer
bugs1551515
milestone69.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1551515 - Fix Library button focused/unfocused when clicking on a abuse report panel's radio button. r=mstriemer Differential Revision: https://phabricator.services.mozilla.com/D31600
toolkit/mozapps/extensions/content/abuse-report-frame.html
toolkit/mozapps/extensions/content/abuse-report-frame.js
toolkit/mozapps/extensions/content/abuse-report-panel.js
--- a/toolkit/mozapps/extensions/content/abuse-report-frame.html
+++ b/toolkit/mozapps/extensions/content/abuse-report-frame.html
@@ -7,17 +7,17 @@
 
     <link rel="localization" href="branding/brand.ftl">
     <link rel="localization" href="toolkit/about/aboutAddons.ftl">
     <link rel="localization" href="toolkit/about/abuseReports.ftl">
 
     <script src="chrome://mozapps/content/extensions/abuse-report-panel.js"></script>
   </head>
 
-  <body tabindex="0">
+  <body>
     <!-- WebComponents Templates -->
     <template id="tmpl-abuse-report">
       <div class="modal-overlay-outer"></div>
       <div class="modal-panel-container">
         <form class="card addon-abuse-report" onsubmit="return false;">
           <div class="abuse-report-header">
             <img class="card-heading-icon addon-icon"/>
             <div class="card-contents">
--- a/toolkit/mozapps/extensions/content/abuse-report-frame.js
+++ b/toolkit/mozapps/extensions/content/abuse-report-frame.js
@@ -152,17 +152,17 @@
           abuseReport.addEventListener("abuse-report:updated", this, {once: true});
           abuseReport.addEventListener("abuse-report:submit", this, {once: true});
           abuseReport.addEventListener("abuse-report:cancel", this, {once: true});
           abuseReport.setAbuseReport(report);
           // Hide the content of the underlying about:addons page from
           // screen readers.
           this.aboutAddonsContent.setAttribute("aria-hidden", true);
           // Move the focus to the embedded window.
-          fm.moveFocus(abuseReport.ownerGlobal, null, fm.MOVEFOCUS_ROOT, fm.FLAG_BYKEY);
+          this.focus();
           this.dispatchEvent(new CustomEvent("abuse-report:frame-shown"));
         });
       } else {
         this.hidden = true;
         this.removeAttribute("addon-id");
         this.removeAttribute("report-entry-point");
 
         // Make the content of the underlying about:addons page visible
--- a/toolkit/mozapps/extensions/content/abuse-report-panel.js
+++ b/toolkit/mozapps/extensions/content/abuse-report-panel.js
@@ -399,69 +399,53 @@ class AbuseReport extends HTMLElement {
       _linkAddonAuthor: ".abuse-report-header .addon-author-box a.author",
     });
   }
 
   connectedCallback() {
     this.render();
 
     this.addEventListener("click", this);
-    // Start listening to focus events (to adjust the focused
-    // element during keyboard navigation).
-    document.addEventListener("focus", this, true);
+
     // Start listening to keydown events (to close the modal
-    // when Escape has been pressed).
+    // when Escape has been pressed and to handling the keyboard
+    // navigation).
     document.addEventListener("keydown", this);
   }
 
   disconnectedCallback() {
     this.textContent = "";
     this.removeEventListener("click", this);
-    document.removeEventListener("focus", this, true);
     document.removeEventListener("keydown", this);
   }
 
   handleEvent(evt) {
     if (!this.isConnected || !this.addon) {
       return;
     }
 
     switch (evt.type) {
-      case "focus":
-        if (evt.target === document.body) {
-          // Return the focus to the Firefox UI when the body has been focused
-          // (as it is only reached when navigating back from the last focusable
-          // objects in the abuse report panel).
-          const chromeWin = window.windowRoot.ownerGlobal;
-          // Top level browser's previous sibling.
-          const {
-            previousElementSibling,
-          } = window.parent.docShell.chromeEventHandler;
-          Services.focus.moveFocus(
-            chromeWin, previousElementSibling,
-            Services.focus.MOVE_BACKWARD, Services.focus.FLAG_BYKEY);
-          return;
-        } else if (this.contains(evt.target)) {
-          return;
-        }
-        this.focus();
-        break;
       case "keydown":
         if (evt.key === "Escape") {
           // Prevent Esc to close the panel if the textarea is
           // empty.
           if (this.message && !this._submitPanel.hidden) {
             return;
           }
           this.cancel();
         }
+        this.handleKeyboardNavigation(evt);
         break;
       case "click":
         if (evt.target === this._iconClose ||
             evt.target === this._btnCancel) {
+          // NOTE: clear the focus on the clicked element to ensure that
+          // -moz-focusring pseudo class is not still set on the element
+          // when the panel is going to be shown again (See Bug 1560949).
+          evt.target.blur();
           this.cancel();
         }
         if (evt.target === this._btnNext) {
           this.switchToSubmitMode();
         }
         if (evt.target === this._btnGoBack) {
           this.switchToListMode();
         }
@@ -478,16 +462,51 @@ class AbuseReport extends HTMLElement {
               relatedToCurrent: true,
             });
           }
         }
         break;
     }
   }
 
+  handleKeyboardNavigation(evt) {
+    if (evt.keyCode !== evt.DOM_VK_TAB ||
+      evt.altKey || evt.controlKey || evt.metaKey) {
+      return;
+    }
+
+    const fm = Services.focus;
+    const backward = evt.shiftKey;
+
+    const isFirstFocusableElement = el => {
+      // Also consider the document body as a valid first focusable element.
+      if (el === document.body) {
+        return true;
+      }
+      // XXXrpl unfortunately there is no way to get the first focusable element
+      // without asking the focus manager to move focus to it (similar strategy
+      // is also being used in about:prefereces subdialog.js).
+      const rv = el == fm.moveFocus(window, null, fm.MOVEFOCUS_FIRST, 0);
+      fm.setFocus(el, 0);
+      return rv;
+    };
+
+    // If the focus is exiting the panel while navigating
+    // backward, focus the previous element sibling on the
+    // Firefox UI.
+    if (backward && isFirstFocusableElement(evt.target)) {
+      evt.preventDefault();
+      evt.stopImmediatePropagation();
+      const chromeWin = window.windowRoot.ownerGlobal;
+      Services.focus.moveFocus(
+        chromeWin, null,
+        Services.MOVEFOCUS_BACKWARD, Services.focus.FLAG_BYKEY);
+    }
+  }
+
   render() {
     this.textContent = "";
     this.appendChild(document.importNode(this.template.content, true));
   }
 
   async update() {
     if (!this.addon) {
       return;