Bug 941990 - The customization context menus don't appear on buttons in the menu panel in customization mode if the panel is not opened prior to entering customization mode. r=Gijs
authorJared Wein <jwein@mozilla.com>
Fri, 22 Nov 2013 16:15:47 -0500
changeset 157195 0817a274a7aaaa6e0ee073a01bf909e634cb3d5e
parent 157194 5aad6e015530d39d22ee043fd9f81d55a74073ca
child 157196 a1d6c5cd7b2d75ca60bc5712ad4350ed2d7f6aef
push id25704
push usermbrubeck@mozilla.com
push dateSat, 23 Nov 2013 22:25:36 +0000
treeherdermozilla-central@74ab61b8d0f0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs
bugs941990
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 941990 - The customization context menus don't appear on buttons in the menu panel in customization mode if the panel is not opened prior to entering customization mode. r=Gijs
browser/components/customizableui/content/panelUI.js
browser/components/customizableui/src/CustomizableUI.jsm
browser/components/customizableui/test/browser_880164_customization_context_menus.js
browser/components/customizableui/test/head.js
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -117,17 +117,16 @@ const PanelUI = {
    */
   show: function(aEvent) {
     if (this.panel.state == "open" || this.panel.state == "showing" ||
         document.documentElement.hasAttribute("customizing")) {
       return;
     }
 
     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 ||
           aEvent.type == "command") {
@@ -219,16 +218,17 @@ const PanelUI = {
 
       if (aCustomizing) {
         CustomizableUI.registerMenuPanel(this.contents);
       } else {
         this.beginBatchUpdate();
         CustomizableUI.registerMenuPanel(this.contents);
         this.endBatchUpdate();
       }
+      this.panel.hidden = false;
     }.bind(this)).then(null, Cu.reportError);
 
     return this._readyPromise;
   },
 
   /**
    * Switch the panel to the main view if it's not already
    * in that view.
--- a/browser/components/customizableui/src/CustomizableUI.jsm
+++ b/browser/components/customizableui/src/CustomizableUI.jsm
@@ -554,31 +554,31 @@ let CustomizableUIInternal = {
   registerMenuPanel: function(aPanel) {
     if (gBuildAreas.has(CustomizableUI.AREA_PANEL) &&
         gBuildAreas.get(CustomizableUI.AREA_PANEL).has(aPanel)) {
       return;
     }
 
     let document = aPanel.ownerDocument;
 
+    aPanel.toolbox = document.getElementById("navigator-toolbox");
+    aPanel.customizationTarget = aPanel;
+
+    this.addPanelCloseListeners(aPanel);
+
+    let placements = gPlacements.get(CustomizableUI.AREA_PANEL);
+    this.buildArea(CustomizableUI.AREA_PANEL, placements, aPanel);
     for (let btn of aPanel.querySelectorAll("toolbarbutton")) {
       btn.setAttribute("tabindex", "0");
       this.ensureButtonContextMenu(btn, aPanel);
       if (!btn.hasAttribute("type")) {
         btn.setAttribute("type", "wrap");
       }
     }
 
-    aPanel.toolbox = document.getElementById("navigator-toolbox");
-    aPanel.customizationTarget = aPanel;
-
-    this.addPanelCloseListeners(aPanel);
-
-    let placements = gPlacements.get(CustomizableUI.AREA_PANEL);
-    this.buildArea(CustomizableUI.AREA_PANEL, placements, aPanel);
     this.registerBuildArea(CustomizableUI.AREA_PANEL, aPanel);
   },
 
   onWidgetAdded: function(aWidgetId, aArea, aPosition) {
     this.insertNode(aWidgetId, aArea, aPosition, true);
   },
 
   onWidgetRemoved: function(aWidgetId, aArea) {
--- a/browser/components/customizableui/test/browser_880164_customization_context_menus.js
+++ b/browser/components/customizableui/test/browser_880164_customization_context_menus.js
@@ -178,60 +178,102 @@ let gTests = [
       checkContextMenu(contextMenu, expectedEntries);
 
       let hiddenContextPromise = contextMenuHidden(contextMenu);
       contextMenu.hidePopup();
       yield hiddenContextPromise;
     },
     teardown: endCustomizing
   },
+  {
+    desc: "Test the toolbarbutton panel context menu in customization mode without opening the panel before customization mode",
+    setup: null,
+    run: function() {
+      this.otherWin = yield openAndLoadWindow(null, true);
+
+      yield startCustomizing(this.otherWin);
+
+      let contextMenu = this.otherWin.document.getElementById("customizationPanelItemContextMenu");
+      let shownPromise = contextMenuShown(contextMenu);
+      let newWindowButton = this.otherWin.document.getElementById("wrapper-new-window-button");
+      EventUtils.synthesizeMouse(newWindowButton, 2, 2, {type: "contextmenu", button: 2}, this.otherWin);
+      yield shownPromise;
+
+      let expectedEntries = [
+        [".customize-context-addToToolbar", true],
+        [".customize-context-removeFromPanel", true],
+        ["---"],
+        [".viewCustomizeToolbar", false]
+      ];
+      checkContextMenu(contextMenu, expectedEntries, this.otherWin);
+
+      let hiddenContextPromise = contextMenuHidden(contextMenu);
+      contextMenu.hidePopup();
+      yield hiddenContextPromise;
+    },
+    teardown: function() {
+      yield endCustomizing(this.otherWin);
+      this.otherWin.close();
+      this.otherWin = null;
+    }
+  },
 ];
 
 function test() {
   waitForExplicitFinish();
   runTests(gTests);
 }
 
 function contextMenuShown(aContextMenu) {
   let deferred = Promise.defer();
+  let win = aContextMenu.ownerDocument.defaultView;
+  let timeoutId = win.setTimeout(() => {
+    deferred.reject("Context menu (" + aContextMenu.id + ") did not show within 20 seconds.");
+  }, 20000);
   function onPopupShown(e) {
     aContextMenu.removeEventListener("popupshown", onPopupShown);
+    win.clearTimeout(timeoutId);
     deferred.resolve();
   };
   aContextMenu.addEventListener("popupshown", onPopupShown);
   return deferred.promise;
 }
 
 function contextMenuHidden(aContextMenu) {
   let deferred = Promise.defer();
+  let win = aContextMenu.ownerDocument.defaultView;
+  let timeoutId = win.setTimeout(() => {
+    deferred.reject("Context menu (" + aContextMenu.id + ") did not hide within 20 seconds.");
+  }, 20000);
   function onPopupHidden(e) {
+    win.clearTimeout(timeoutId);
     aContextMenu.removeEventListener("popuphidden", onPopupHidden);
     deferred.resolve();
   };
   aContextMenu.addEventListener("popuphidden", onPopupHidden);
   return deferred.promise;
 }
 
 // This is a simpler version of the context menu check that
 // exists in contextmenu_common.js.
-function checkContextMenu(aContextMenu, aExpectedEntries) {
+function checkContextMenu(aContextMenu, aExpectedEntries, aWindow=window) {
   let childNodes = aContextMenu.childNodes;
   for (let i = 0; i < childNodes.length; i++) {
     let menuitem = childNodes[i];
     try {
       if (aExpectedEntries[i][0] == "---") {
         is(menuitem.localName, "menuseparator", "menuseparator expected");
         continue;
       }
 
       let selector = aExpectedEntries[i][0];
       ok(menuitem.mozMatchesSelector(selector), "menuitem should match " + selector + " selector");
       let commandValue = menuitem.getAttribute("command");
-      let relatedCommand = commandValue ? document.getElementById(commandValue) : null;
+      let relatedCommand = commandValue ? aWindow.document.getElementById(commandValue) : null;
       let menuItemDisabled = relatedCommand ?
                                relatedCommand.getAttribute("disabled") == "true" :
                                menuitem.getAttribute("disabled") == "true";
-      is(menuItemDisabled, !aExpectedEntries[i][1], "disabled state wrong for " + selector);
+      is(menuItemDisabled, !aExpectedEntries[i][1], "disabled state for " + selector);
     } catch (e) {
       ok(false, "Exception when checking context menu: " + e);
     }
   }
 }
--- a/browser/components/customizableui/test/head.js
+++ b/browser/components/customizableui/test/head.js
@@ -99,33 +99,33 @@ function getAreaWidgetIds(areaId) {
 function simulateItemDrag(toDrag, target) {
   let docId = toDrag.ownerDocument.documentElement.id;
   let dragData = [[{type: 'text/toolbarwrapper-id/' + docId,
                     data: toDrag.id}]];
   synthesizeDragStart(toDrag.parentNode, dragData);
   synthesizeDrop(target, target, dragData);
 }
 
-function endCustomizing() {
-  if (document.documentElement.getAttribute("customizing") != "true") {
+function endCustomizing(aWindow=window) {
+  if (aWindow.document.documentElement.getAttribute("customizing") != "true") {
     return true;
   }
   let deferredEndCustomizing = Promise.defer();
   function onCustomizationEnds() {
-    window.gNavToolbox.removeEventListener("aftercustomization", onCustomizationEnds);
+    aWindow.gNavToolbox.removeEventListener("aftercustomization", onCustomizationEnds);
     deferredEndCustomizing.resolve();
   }
-  window.gNavToolbox.addEventListener("aftercustomization", onCustomizationEnds);
-  window.gCustomizeMode.exit();
+  aWindow.gNavToolbox.addEventListener("aftercustomization", onCustomizationEnds);
+  aWindow.gCustomizeMode.exit();
 
   return deferredEndCustomizing.promise.then(function() {
     let deferredLoadNewTab = Promise.defer();
 
     //XXXgijs so some tests depend on this tab being about:blank. Make it so.
-    let newTabBrowser = window.gBrowser.selectedBrowser;
+    let newTabBrowser = aWindow.gBrowser.selectedBrowser;
     newTabBrowser.stop();
 
     // If we stop early enough, this might actually be about:blank.
     if (newTabBrowser.contentDocument.location.href == "about:blank") {
       return;
     }
 
     // Otherwise, make it be about:blank, and wait for that to be done.
@@ -134,27 +134,27 @@ function endCustomizing() {
       deferredLoadNewTab.resolve();
     }
     newTabBrowser.addEventListener("load", onNewTabLoaded, true);
     newTabBrowser.contentDocument.location.replace("about:blank");
     return deferredLoadNewTab.promise;
   });
 }
 
-function startCustomizing() {
-  if (document.documentElement.getAttribute("customizing") == "true") {
+function startCustomizing(aWindow=window) {
+  if (aWindow.document.documentElement.getAttribute("customizing") == "true") {
     return;
   }
   let deferred = Promise.defer();
   function onCustomizing() {
-    window.gNavToolbox.removeEventListener("customizationready", onCustomizing);
+    aWindow.gNavToolbox.removeEventListener("customizationready", onCustomizing);
     deferred.resolve();
   }
-  window.gNavToolbox.addEventListener("customizationready", onCustomizing);
-  window.gCustomizeMode.enter();
+  aWindow.gNavToolbox.addEventListener("customizationready", onCustomizing);
+  aWindow.gCustomizeMode.enter();
   return deferred.promise;
 }
 
 function openAndLoadWindow(aOptions, aWaitForDelayedStartup=false) {
   let deferred = Promise.defer();
   let win = OpenBrowserWindow(aOptions);
   if (aWaitForDelayedStartup) {
     Services.obs.addObserver(function onDS(aSubject, aTopic, aData) {
@@ -172,29 +172,37 @@ function openAndLoadWindow(aOptions, aWa
     });
   }
   return deferred.promise;
 }
 
 function promisePanelShown(win) {
   let panelEl = win.PanelUI.panel;
   let deferred = Promise.defer();
+  let timeoutId = win.setTimeout(() => {
+    deferred.reject("Panel did not show within 20 seconds.");
+  }, 20000);
   function onPanelOpen(e) {
     panelEl.removeEventListener("popupshown", onPanelOpen);
+    win.clearTimeout(timeoutId);
     deferred.resolve();
   };
   panelEl.addEventListener("popupshown", onPanelOpen);
   return deferred.promise;
 }
 
 function promisePanelHidden(win) {
   let panelEl = win.PanelUI.panel;
   let deferred = Promise.defer();
+  let timeoutId = win.setTimeout(() => {
+    deferred.reject("Panel did not hide within 20 seconds.");
+  }, 20000);
   function onPanelClose(e) {
     panelEl.removeEventListener("popuphidden", onPanelClose);
+    win.clearTimeout(timeoutId);
     deferred.resolve();
   }
   panelEl.addEventListener("popuphidden", onPanelClose);
   return deferred.promise;
 }
 
 function waitForCondition(aConditionFn, aMaxTries=50, aCheckInterval=100) {
   function tryNow() {
@@ -226,17 +234,21 @@ function testRunner(testAry, asyncCleanu
   Services.prefs.setBoolPref("browser.uiCustomization.disableAnimation", true);
   for (let test of testAry) {
     info(test.desc);
 
     if (test.setup)
       yield test.setup();
 
     info("Running test");
-    yield test.run();
+    try {
+      yield test.run();
+    } catch (ex) {
+      ok(false, "Unexpected exception occurred while running the test:\n" + ex);
+    }
     info("Cleanup");
     if (test.teardown)
       yield test.teardown();
     ok(!document.getElementById(CustomizableUI.AREA_NAVBAR).hasAttribute("overflowing"), "Shouldn't overflow");
   }
   if (asyncCleanup) {
     yield asyncCleanup();
   }