Bug 1267916 - part 1 - Open about preferences #containers in any existing menu (except context menu), r=jaws
authorJonathan Kingston <jkt@mozilla.com>
Thu, 03 Nov 2016 19:31:28 +0100
changeset 363757 127379f03ad8a60918cfddf0db15d77c1fc32921
parent 363756 f54a717c6fc663d5ccad40340c4139282b0607a1
child 363758 964223d37a2e59a28c4ee1df5a808252442ea94f
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-beta@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs1267916
milestone52.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 1267916 - part 1 - Open about preferences #containers in any existing menu (except context menu), r=jaws
browser/base/content/browser-sets.inc
browser/base/content/nsContextMenu.js
browser/base/content/utilityOverlay.js
browser/components/customizableui/CustomizableWidgets.jsm
browser/locales/en-US/chrome/browser/browser.properties
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -88,16 +88,17 @@
     <command id="cmd_fullZoomReset"   oncommand="FullZoom.reset()"/>
     <command id="cmd_fullZoomToggle"  oncommand="ZoomManager.toggleZoom();"/>
     <command id="cmd_gestureRotateLeft" oncommand="gGestureSupport.rotate(event.sourceEvent)"/>
     <command id="cmd_gestureRotateRight" oncommand="gGestureSupport.rotate(event.sourceEvent)"/>
     <command id="cmd_gestureRotateEnd" oncommand="gGestureSupport.rotateEnd()"/>
     <command id="Browser:OpenLocation" oncommand="openLocation();"/>
     <command id="Browser:RestoreLastSession" oncommand="restoreLastSession();" disabled="true"/>
     <command id="Browser:NewUserContextTab" oncommand="openNewUserContextTab(event.sourceEvent);" reserved="true"/>
+    <command id="Browser:OpenAboutContainers" oncommand="openPreferences('paneContainers');"/>
 
     <command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
     <command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
     <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
     <command id="Tools:Sanitize"
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
     <command id="Tools:PrivateBrowsing"
       oncommand="OpenBrowserWindow({private: true});" reserved="true"/>
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -1862,12 +1862,12 @@ nsContextMenu.prototype = {
   _checkTelemetryForMenu: function(aXulMenu) {
     this._telemetryClickID = null;
     this._telemetryPageContext = this._getTelemetryPageContextInfo();
     this._telemetryHadCustomItems = this.hasPageMenu;
     this._getTelemetryClickInfo(aXulMenu);
   },
 
   createContainerMenu: function(aEvent) {
-    return createUserContextMenu(aEvent, false,
+    return createUserContextMenu(aEvent, true,
                                  gContextMenuContentData.userContextId);
   },
 };
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -433,36 +433,35 @@ function checkForMiddleClick(node, event
 
     // If the middle-click was on part of a menu, close the menu.
     // (Menus close automatically with left-click but not with middle-click.)
     closeMenus(event.target);
   }
 }
 
 // Populate a menu with user-context menu items. This method should be called
-// by onpopupshowing passing the event as first argument. addCommandAttribute
-// param is used to set the 'command' attribute in the new menuitem elements.
-function createUserContextMenu(event, addCommandAttribute = true, excludeUserContextId = 0) {
+// by onpopupshowing passing the event as first argument.
+function createUserContextMenu(event, isContextMenu = false, excludeUserContextId = 0) {
   while (event.target.hasChildNodes()) {
     event.target.removeChild(event.target.firstChild);
   }
 
   let bundle = document.getElementById("bundle_browser");
   let docfrag = document.createDocumentFragment();
 
   // If we are excluding a userContextId, we want to add a 'no-container' item.
   if (excludeUserContextId) {
     let menuitem = document.createElement("menuitem");
     menuitem.setAttribute("data-usercontextid", "0");
     menuitem.setAttribute("label", bundle.getString("userContextNone.label"));
     menuitem.setAttribute("accesskey", bundle.getString("userContextNone.accesskey"));
 
-    // We don't set an oncommand/command attribute attribute because if we have
+    // We don't set an oncommand/command attribute because if we have
     // to exclude a userContextId we are generating the contextMenu and
-    // addCommandAttribute will be false.
+    // isContextMenu will be true.
 
     docfrag.appendChild(menuitem);
 
     let menuseparator = document.createElement("menuseparator");
     docfrag.appendChild(menuseparator);
   }
 
   ContextualIdentityService.getIdentities().forEach(identity => {
@@ -476,25 +475,37 @@ function createUserContextMenu(event, ad
 
     if (identity.accessKey) {
       menuitem.setAttribute("accesskey", bundle.getString(identity.accessKey));
     }
 
     menuitem.classList.add("menuitem-iconic");
     menuitem.setAttribute("data-identity-color", identity.color);
 
-    if (addCommandAttribute) {
+    if (!isContextMenu) {
       menuitem.setAttribute("command", "Browser:NewUserContextTab");
     }
 
     menuitem.setAttribute("data-identity-icon", identity.icon);
 
     docfrag.appendChild(menuitem);
   });
 
+  if (!isContextMenu) {
+    docfrag.appendChild(document.createElement("menuseparator"));
+
+    let menuitem = document.createElement("menuitem");
+    menuitem.setAttribute("label",
+                          bundle.getString("userContext.aboutPage.label"));
+    menuitem.setAttribute("accesskey",
+                          bundle.getString("userContext.aboutPage.accesskey"));
+    menuitem.setAttribute("command", "Browser:OpenAboutContainers");
+    docfrag.appendChild(menuitem);
+  }
+
   event.target.appendChild(docfrag);
   return true;
 }
 
 // Closes all popups that are ancestors of the node.
 function closeMenus(node)
 {
   if ("tagName" in node) {
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -1103,18 +1103,20 @@ const CustomizableWidgets = [
     hasObserver: false,
     onCreated: function(aNode) {
       let doc = aNode.ownerDocument;
       let win = doc.defaultView;
       let items = doc.getElementById("PanelUI-containersItems");
 
       let onItemCommand = function (aEvent) {
         let item = aEvent.target;
-        let userContextId = parseInt(item.getAttribute("usercontextid"));
-        win.openUILinkIn(win.BROWSER_NEW_TAB_URL, "tab", {userContextId});
+        if (item.hasAttribute("usercontextid")) {
+          let userContextId = parseInt(item.getAttribute("usercontextid"));
+          win.openUILinkIn(win.BROWSER_NEW_TAB_URL, "tab", {userContextId});
+        }
       };
       items.addEventListener("command", onItemCommand);
 
       if (PrivateBrowsingUtils.isWindowPrivate(win)) {
         aNode.setAttribute("disabled", "true");
       }
 
       this.updateVisibility(aNode);
@@ -1129,31 +1131,39 @@ const CustomizableWidgets = [
 
       let items = doc.getElementById("PanelUI-containersItems");
 
       while (items.firstChild) {
         items.firstChild.remove();
       }
 
       let fragment = doc.createDocumentFragment();
+      let bundle = doc.getElementById("bundle_browser");
 
       ContextualIdentityService.getIdentities().forEach(identity => {
-        let bundle = doc.getElementById("bundle_browser");
         let label = ContextualIdentityService.getUserContextLabel(identity.userContextId);
 
         let item = doc.createElementNS(kNSXUL, "toolbarbutton");
         item.setAttribute("label", label);
         item.setAttribute("usercontextid", identity.userContextId);
         item.setAttribute("class", "subviewbutton");
         item.setAttribute("data-identity-color", identity.color);
         item.setAttribute("data-identity-icon", identity.icon);
 
         fragment.appendChild(item);
       });
 
+      fragment.appendChild(doc.createElementNS(kNSXUL, "menuseparator"));
+
+      let item = doc.createElementNS(kNSXUL, "toolbarbutton");
+      item.setAttribute("label", bundle.getString("userContext.aboutPage.label"));
+      item.setAttribute("command", "Browser:OpenAboutContainers");
+      item.setAttribute("class", "subviewbutton");
+      fragment.appendChild(item);
+
       items.appendChild(fragment);
     },
 
     updateVisibility(aNode) {
       aNode.hidden = !Services.prefs.getBoolPref("privacy.userContext.enabled");
     },
 
     observe(aSubject, aTopic, aData) {
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -689,16 +689,19 @@ userContextShopping.label = Shopping
 userContextNone.label = No Container
 
 userContextPersonal.accesskey = P
 userContextWork.accesskey = W
 userContextBanking.accesskey = B
 userContextShopping.accesskey = S
 userContextNone.accesskey = N
 
+userContext.aboutPage.label = Manage containers
+userContext.aboutPage.accesskey = O
+
 userContextOpenLink.label = Open Link in New %S Tab
 
 muteTab.label = Mute Tab
 muteTab.accesskey = M
 unmuteTab.label = Unmute Tab
 unmuteTab.accesskey = M
 
 # LOCALIZATION NOTE (weakCryptoOverriding.message): %S is brandShortName