Bug 936378 - Fix PanelUI.show() to not require an event. r=Unfocused
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Tue, 12 Nov 2013 19:19:09 -0800
changeset 155993 672ff858678a250df7db3293505c0709a8e9f91d
parent 155992 903d51e5303e6105dabaf17084709e5acae791c9
child 155994 c49faf118145befc4fb1ccf46ae79dee281f24ce
push id25666
push userjwein@mozilla.com
push dateMon, 18 Nov 2013 15:56:58 +0000
treeherdermozilla-central@f2adb62d07eb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersUnfocused
bugs936378
milestone28.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 936378 - Fix PanelUI.show() to not require an event. r=Unfocused
browser/components/customizableui/content/panelUI.js
browser/components/customizableui/test/browser.ini
browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js
browser/components/customizableui/test/browser_panel_toggle.js
browser/components/customizableui/test/head.js
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -124,29 +124,29 @@ const PanelUI = {
     this.ensureReady().then(() => {
       this.panel.hidden = false;
       let editControlPlacement = CustomizableUI.getPlacementOfWidget("edit-controls");
       if (editControlPlacement && editControlPlacement.area == CustomizableUI.AREA_PANEL) {
         updateEditUIVisibility();
       }
 
       let anchor;
-      if (aEvent.type == "mousedown" ||
+      if (!aEvent ||
           aEvent.type == "command") {
         anchor = this.menuButton;
       } else {
         anchor = aEvent.target;
       }
       let iconAnchor =
         document.getAnonymousElementByAttribute(anchor, "class",
                                                 "toolbarbutton-icon");
 
       // Only focus the panel if it's opened using the keyboard, so that
       // cut/copy/paste buttons will work for mouse users.
-      let keyboardOpened = aEvent.sourceEvent &&
+      let keyboardOpened = aEvent && aEvent.sourceEvent &&
                            aEvent.sourceEvent.target.localName == "key";
       this.panel.setAttribute("noautofocus", !keyboardOpened);
       this.panel.openPopup(iconAnchor || anchor, "bottomcenter topright");
     });
   },
 
   /**
    * If the menu panel is being shown, hide it.
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -29,8 +29,9 @@ run-if = os == "mac"
 [browser_918049_skipintoolbarset_dnd.js]
 [browser_923857_customize_mode_event_wrapping_during_reset.js]
 [browser_927717_customize_drag_empty_toolbar.js]
 
 [browser_934113_menubar_removable.js]
 # Because this test is about the menubar, it can't be run on mac
 skip-if = os == "mac"
 
+[browser_panel_toggle.js]
--- a/browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js
+++ b/browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js
@@ -109,18 +109,23 @@ function checkPalette(id, method) {
 
 let otherWin;
 let gTests = [
   {
     desc: "Moving widgets in two windows, one with customize mode and one without, should work",
     setup: startCustomizing,
     run: function() {
       otherWin = yield openAndLoadWindow(null, true);
-      // Open panel to force its construction:
-      yield afterPanelOpen(otherWin);
+      // Open and close the panel to force its construction:
+      let shownPromise = promisePanelShown(otherWin);
+      otherWin.PanelUI.toggle({type: "command"});
+      yield shownPromise;
+      let hiddenPromise = promisePanelHidden(otherWin);
+      otherWin.PanelUI.toggle({type: "command"});
+      yield hiddenPromise;
 
       ok(CustomizableUI.inDefaultState, "Should start in default state");
 
       for (let widgetId of [kXULWidgetId, kAPIWidgetId]) {
         for (let method of ["API", "drag", "dragToItem"]) {
           info("Moving widget " + widgetId + " using " + method);
           checkToolbar(widgetId, method);
           checkPanel(widgetId, method);
@@ -138,33 +143,16 @@ let gTests = [
       if (otherWin) {
         otherWin.close();
       }
       yield endCustomizing();
     }
   }
 ];
 
-function afterPanelOpen(win) {
-  let panelEl = win.PanelUI.panel;
-  let deferred = Promise.defer();
-  function onPanelClose(e) {
-    panelEl.removeEventListener("popuphidden", onPanelClose);
-    deferred.resolve();
-  }
-  function onPanelOpen(e) {
-    panelEl.removeEventListener("popupshown", onPanelOpen);
-    panelEl.addEventListener("popuphidden", onPanelClose);
-    win.PanelUI.toggle({type: "command"});
-  };
-  panelEl.addEventListener("popupshown", onPanelOpen);
-  win.PanelUI.toggle({type: "command"});
-  return deferred.promise;
-}
-
 function asyncCleanup() {
   Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck");
   yield resetCustomization();
 }
 
 function test() {
   Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true);
   waitForExplicitFinish();
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/test/browser_panel_toggle.js
@@ -0,0 +1,53 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Test opening and closing the menu panel UI.
+ */
+
+let gTests = [
+  {
+    desc: "Show and hide the menu panel programmatically without an event (like UITour.jsm would)",
+    setup: null,
+    run: function() {
+      let shownPromise = promisePanelShown(window);
+      PanelUI.show();
+      yield shownPromise;
+
+      is(PanelUI.panel.getAttribute("panelopen"), "true", "Check that panel has panelopen attribute");
+      is(PanelUI.panel.state, "open", "Check that panel state is 'open'");
+
+      let hiddenPromise = promisePanelHidden(window);
+      PanelUI.hide();
+      yield hiddenPromise;
+
+      ok(!PanelUI.panel.hasAttribute("panelopen"), "Check that panel doesn't have the panelopen attribute");
+      is(PanelUI.panel.state, "closed", "Check that panel state is 'closed'");
+    },
+  },
+  {
+    desc: "Toggle the menu panel open and closed",
+    setup: null,
+    run: function() {
+      let shownPromise = promisePanelShown(window);
+      PanelUI.toggle({type: "command"});
+      yield shownPromise;
+
+      is(PanelUI.panel.getAttribute("panelopen"), "true", "Check that panel has panelopen attribute");
+      is(PanelUI.panel.state, "open", "Check that panel state is 'open'");
+
+      let hiddenPromise = promisePanelHidden(window);
+      PanelUI.toggle({type: "command"});
+      yield hiddenPromise;
+
+      ok(!PanelUI.panel.hasAttribute("panelopen"), "Check that panel doesn't have the panelopen attribute");
+      is(PanelUI.panel.state, "closed", "Check that panel state is 'closed'");
+    },
+  },
+];
+
+function test() {
+  waitForExplicitFinish();
+  runTests(gTests);
+}
--- a/browser/components/customizableui/test/head.js
+++ b/browser/components/customizableui/test/head.js
@@ -169,16 +169,38 @@ function openAndLoadWindow(aOptions, aWa
     win.addEventListener("load", function onLoad() {
       win.removeEventListener("load", onLoad);
       deferred.resolve(win);
     });
   }
   return deferred.promise;
 }
 
+function promisePanelShown(win) {
+  let panelEl = win.PanelUI.panel;
+  let deferred = Promise.defer();
+  function onPanelOpen(e) {
+    panelEl.removeEventListener("popupshown", onPanelOpen);
+    deferred.resolve();
+  };
+  panelEl.addEventListener("popupshown", onPanelOpen);
+  return deferred.promise;
+}
+
+function promisePanelHidden(win) {
+  let panelEl = win.PanelUI.panel;
+  let deferred = Promise.defer();
+  function onPanelClose(e) {
+    panelEl.removeEventListener("popuphidden", onPanelClose);
+    deferred.resolve();
+  }
+  panelEl.addEventListener("popuphidden", onPanelClose);
+  return deferred.promise;
+}
+
 function waitForCondition(aConditionFn, aMaxTries=50, aCheckInterval=100) {
   function tryNow() {
     tries++;
     if (aConditionFn()) {
       deferred.resolve();
     } else if (tries < aMaxTries) {
       tryAgain();
     } else {