Bug 1543080 - Show more options menu on first click r=Gijs
authorMark Striemer <mstriemer@mozilla.com>
Wed, 24 Apr 2019 15:10:31 +0000
changeset 470738 92e638c435da77351cd0d9900d9e0d9bf85a610f
parent 470737 41ac1be62749371f9eefbfd6c3d8ab0747efac8e
child 470739 6f64c339a2a8f08693ff62512d6f730b2425dc1d
push id83948
push usermstriemer@mozilla.com
push dateWed, 24 Apr 2019 19:42:30 +0000
treeherderautoland@92e638c435da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs
bugs1543080
milestone68.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 1543080 - Show more options menu on first click r=Gijs There was a bug where the panel would be hidden on the first click on Windows (and I think Linux, too). This was happening because the focusin event would trigger after mousedown and hide the panel on the first click. Then the button would have focus and we wouldn't get a focusin on the second click. This updates the focusin handler to check if this is the first focusin event, and ignore it if the event target matches our triggering event's target. Differential Revision: https://phabricator.services.mozilla.com/D28587
toolkit/mozapps/extensions/content/aboutaddons.js
toolkit/mozapps/extensions/test/browser/browser_html_list_view.js
--- a/toolkit/mozapps/extensions/content/aboutaddons.js
+++ b/toolkit/mozapps/extensions/content/aboutaddons.js
@@ -90,23 +90,23 @@ class PanelList extends HTMLElement {
     if (val) {
       this.setAttribute("open", "true");
     } else {
       this.removeAttribute("open");
     }
   }
 
   show(triggeringEvent) {
+    this.triggeringEvent = triggeringEvent;
     this.open = true;
-    this.triggeringEvent = triggeringEvent;
   }
 
   hide(triggeringEvent) {
+    this.triggeringEvent = triggeringEvent;
     this.open = false;
-    this.triggeringEvent = triggeringEvent;
   }
 
   toggle(triggeringEvent) {
     if (this.open) {
       this.hide(triggeringEvent);
     } else {
       this.show(triggeringEvent);
     }
@@ -160,16 +160,18 @@ class PanelList extends HTMLElement {
 
   addHideListeners() {
     // Hide when a panel-item is clicked in the list.
     this.addEventListener("click", this);
     // Hide when a click is initiated outside the panel.
     document.addEventListener("mousedown", this);
     // Hide if focus changes and the panel isn't in focus.
     document.addEventListener("focusin", this);
+    // Reset or focus tracking, we treat the first focusin differently.
+    this.focusHasChanged = false;
     // Hide on resize, scroll or losing window focus.
     window.addEventListener("resize", this);
     window.addEventListener("scroll", this);
     window.addEventListener("blur", this);
   }
 
   removeHideListeners() {
     this.removeEventListener("click", this);
@@ -194,20 +196,30 @@ class PanelList extends HTMLElement {
         break;
       case "click":
         if (e.target.tagName == "PANEL-ITEM") {
           this.hide();
         }
         break;
       case "mousedown":
       case "focusin":
+        // There will be a focusin after the mousedown that opens the panel
+        // using the mouse. Ignore the first focusin event if it's on the
+        // triggering target.
+        if (this.triggeringEvent &&
+            e.target == this.triggeringEvent.target &&
+            !this.focusHasChanged) {
+          this.focusHasChanged = true;
         // If the target isn't in the panel, hide. This will close when focus
         // moves out of the panel, or there's a click started outside the panel.
-        if (!e.target || e.target.closest("panel-list") != this) {
+        } else if (!e.target || e.target.closest("panel-list") != this) {
           this.hide();
+        // Just record that there was a focusin event.
+        } else {
+          this.focusHasChanged = true;
         }
         break;
     }
   }
 
   onShow() {
     this.setAlign();
     this.addHideListeners();
--- a/toolkit/mozapps/extensions/test/browser/browser_html_list_view.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_html_list_view.js
@@ -122,16 +122,44 @@ add_task(async function testExtensionLis
 
   addon = await AddonManager.getAddonByID("test@mochi.test");
   ok(!addon, "The addon is not longer found");
 
   await extension.unload();
   await closeView(win);
 });
 
+add_task(async function testMouseSupport() {
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      name: "Test extension",
+      applications: {gecko: {id: "test@mochi.test"}},
+    },
+    useAddonManager: "temporary",
+  });
+  await extension.startup();
+
+  let win = await loadInitialView("extension");
+  let doc = win.document;
+
+  let [card] = getTestCards(doc);
+  is(card.addon.id, "test@mochi.test", "The right card is found");
+
+  let menuButton = card.querySelector('[action="more-options"]');
+  let panel = card.querySelector("panel-list");
+
+  ok(!panel.open, "The panel is initially closed");
+  await BrowserTestUtils.synthesizeMouseAtCenter(
+    menuButton, {type: "mousedown"}, gBrowser.selectedBrowser);
+  ok(panel.open, "The panel is now open");
+
+  await closeView(win);
+  await extension.unload();
+});
+
 add_task(async function testKeyboardSupport() {
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       name: "Test extension",
       applications: {gecko: {id: "test@mochi.test"}},
     },
     useAddonManager: "temporary",
   });