browser/components/customizableui/src/CustomizableWidgets.jsm

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/components/customizableui/src/CustomizableWidgets.jsm	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,969 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +"use strict";
     1.9 +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
    1.10 +
    1.11 +this.EXPORTED_SYMBOLS = ["CustomizableWidgets"];
    1.12 +
    1.13 +Cu.import("resource:///modules/CustomizableUI.jsm");
    1.14 +Cu.import("resource://gre/modules/Services.jsm");
    1.15 +Cu.import("resource://gre/modules/XPCOMUtils.jsm");
    1.16 +XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
    1.17 +  "resource://gre/modules/PlacesUtils.jsm");
    1.18 +XPCOMUtils.defineLazyModuleGetter(this, "PlacesUIUtils",
    1.19 +  "resource:///modules/PlacesUIUtils.jsm");
    1.20 +XPCOMUtils.defineLazyModuleGetter(this, "RecentlyClosedTabsAndWindowsMenuUtils",
    1.21 +  "resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm");
    1.22 +XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
    1.23 +  "resource://gre/modules/ShortcutUtils.jsm");
    1.24 +XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu",
    1.25 +  "resource://gre/modules/CharsetMenu.jsm");
    1.26 +XPCOMUtils.defineLazyServiceGetter(this, "CharsetManager",
    1.27 +                                   "@mozilla.org/charset-converter-manager;1",
    1.28 +                                   "nsICharsetConverterManager");
    1.29 +
    1.30 +XPCOMUtils.defineLazyGetter(this, "CharsetBundle", function() {
    1.31 +  const kCharsetBundle = "chrome://global/locale/charsetMenu.properties";
    1.32 +  return Services.strings.createBundle(kCharsetBundle);
    1.33 +});
    1.34 +XPCOMUtils.defineLazyGetter(this, "BrandBundle", function() {
    1.35 +  const kBrandBundle = "chrome://branding/locale/brand.properties";
    1.36 +  return Services.strings.createBundle(kBrandBundle);
    1.37 +});
    1.38 +
    1.39 +const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
    1.40 +const kPrefCustomizationDebug = "browser.uiCustomization.debug";
    1.41 +const kWidePanelItemClass = "panel-wide-item";
    1.42 +
    1.43 +let gModuleName = "[CustomizableWidgets]";
    1.44 +#include logging.js
    1.45 +
    1.46 +function setAttributes(aNode, aAttrs) {
    1.47 +  let doc = aNode.ownerDocument;
    1.48 +  for (let [name, value] of Iterator(aAttrs)) {
    1.49 +    if (!value) {
    1.50 +      if (aNode.hasAttribute(name))
    1.51 +        aNode.removeAttribute(name);
    1.52 +    } else {
    1.53 +      if (name == "shortcutId") {
    1.54 +        continue;
    1.55 +      }
    1.56 +      if (name == "label" || name == "tooltiptext") {
    1.57 +        let stringId = (typeof value == "string") ? value : name;
    1.58 +        let additionalArgs = [];
    1.59 +        if (aAttrs.shortcutId) {
    1.60 +          let shortcut = doc.getElementById(aAttrs.shortcutId);
    1.61 +          if (doc) {
    1.62 +            additionalArgs.push(ShortcutUtils.prettifyShortcut(shortcut));
    1.63 +          }
    1.64 +        }
    1.65 +        value = CustomizableUI.getLocalizedProperty({id: aAttrs.id}, stringId, additionalArgs);
    1.66 +      }
    1.67 +      aNode.setAttribute(name, value);
    1.68 +    }
    1.69 +  }
    1.70 +}
    1.71 +
    1.72 +function updateCombinedWidgetStyle(aNode, aArea, aModifyCloseMenu) {
    1.73 +  let inPanel = (aArea == CustomizableUI.AREA_PANEL);
    1.74 +  let cls = inPanel ? "panel-combined-button" : "toolbarbutton-1 toolbarbutton-combined";
    1.75 +  let attrs = {class: cls};
    1.76 +  if (aModifyCloseMenu) {
    1.77 +    attrs.closemenu = inPanel ? "none" : null;
    1.78 +  }
    1.79 +  attrs["cui-areatype"] = aArea ? CustomizableUI.getAreaType(aArea) : null;
    1.80 +  for (let i = 0, l = aNode.childNodes.length; i < l; ++i) {
    1.81 +    if (aNode.childNodes[i].localName == "separator")
    1.82 +      continue;
    1.83 +    setAttributes(aNode.childNodes[i], attrs);
    1.84 +  }
    1.85 +}
    1.86 +
    1.87 +function addShortcut(aNode, aDocument, aItem) {
    1.88 +  let shortcutId = aNode.getAttribute("key");
    1.89 +  if (!shortcutId) {
    1.90 +    return;
    1.91 +  }
    1.92 +  let shortcut = aDocument.getElementById(shortcutId);
    1.93 +  if (!shortcut) {
    1.94 +    return;
    1.95 +  }
    1.96 +  aItem.setAttribute("shortcut", ShortcutUtils.prettifyShortcut(shortcut));
    1.97 +}
    1.98 +
    1.99 +function fillSubviewFromMenuItems(aMenuItems, aSubview) {
   1.100 +  let attrs = ["oncommand", "onclick", "label", "key", "disabled",
   1.101 +               "command", "observes", "hidden", "class", "origin",
   1.102 +               "image", "checked"];
   1.103 +
   1.104 +  let doc = aSubview.ownerDocument;
   1.105 +  let fragment = doc.createDocumentFragment();
   1.106 +  for (let menuChild of aMenuItems) {
   1.107 +    if (menuChild.hidden)
   1.108 +      continue;
   1.109 +
   1.110 +    let subviewItem;
   1.111 +    if (menuChild.localName == "menuseparator") {
   1.112 +      // Don't insert duplicate or leading separators. This can happen if there are
   1.113 +      // menus (which we don't copy) above the separator.
   1.114 +      if (!fragment.lastChild || fragment.lastChild.localName == "menuseparator") {
   1.115 +        continue;
   1.116 +      }
   1.117 +      subviewItem = doc.createElementNS(kNSXUL, "menuseparator");
   1.118 +    } else if (menuChild.localName == "menuitem") {
   1.119 +      subviewItem = doc.createElementNS(kNSXUL, "toolbarbutton");
   1.120 +      addShortcut(menuChild, doc, subviewItem);
   1.121 +
   1.122 +      let item = menuChild;
   1.123 +      if (!item.hasAttribute("onclick")) {
   1.124 +        subviewItem.addEventListener("click", event => {
   1.125 +          let newEvent = new doc.defaultView.MouseEvent(event.type, event);
   1.126 +          item.dispatchEvent(newEvent);
   1.127 +        });
   1.128 +      }
   1.129 +
   1.130 +      if (!item.hasAttribute("oncommand")) {
   1.131 +        subviewItem.addEventListener("command", event => {
   1.132 +          let newEvent = doc.createEvent("XULCommandEvent");
   1.133 +          newEvent.initCommandEvent(
   1.134 +            event.type, event.bubbles, event.cancelable, event.view,
   1.135 +            event.detail, event.ctrlKey, event.altKey, event.shiftKey,
   1.136 +            event.metaKey, event.sourceEvent);
   1.137 +          item.dispatchEvent(newEvent);
   1.138 +        });
   1.139 +      }
   1.140 +    } else {
   1.141 +      continue;
   1.142 +    }
   1.143 +    for (let attr of attrs) {
   1.144 +      let attrVal = menuChild.getAttribute(attr);
   1.145 +      if (attrVal)
   1.146 +        subviewItem.setAttribute(attr, attrVal);
   1.147 +    }
   1.148 +    // We do this after so the .subviewbutton class doesn't get overriden.
   1.149 +    if (menuChild.localName == "menuitem") {
   1.150 +      subviewItem.classList.add("subviewbutton");
   1.151 +    }
   1.152 +    fragment.appendChild(subviewItem);
   1.153 +  }
   1.154 +  aSubview.appendChild(fragment);
   1.155 +}
   1.156 +
   1.157 +function clearSubview(aSubview) {
   1.158 +  let parent = aSubview.parentNode;
   1.159 +  // We'll take the container out of the document before cleaning it out
   1.160 +  // to avoid reflowing each time we remove something.
   1.161 +  parent.removeChild(aSubview);
   1.162 +
   1.163 +  while (aSubview.firstChild) {
   1.164 +    aSubview.firstChild.remove();
   1.165 +  }
   1.166 +
   1.167 +  parent.appendChild(aSubview);
   1.168 +}
   1.169 +
   1.170 +const CustomizableWidgets = [{
   1.171 +    id: "history-panelmenu",
   1.172 +    type: "view",
   1.173 +    viewId: "PanelUI-history",
   1.174 +    shortcutId: "key_gotoHistory",
   1.175 +    tooltiptext: "history-panelmenu.tooltiptext2",
   1.176 +    defaultArea: CustomizableUI.AREA_PANEL,
   1.177 +    onViewShowing: function(aEvent) {
   1.178 +      // Populate our list of history
   1.179 +      const kMaxResults = 15;
   1.180 +      let doc = aEvent.detail.ownerDocument;
   1.181 +
   1.182 +      let options = PlacesUtils.history.getNewQueryOptions();
   1.183 +      options.excludeQueries = true;
   1.184 +      options.includeHidden = false;
   1.185 +      options.resultType = options.RESULTS_AS_URI;
   1.186 +      options.queryType = options.QUERY_TYPE_HISTORY;
   1.187 +      options.sortingMode = options.SORT_BY_DATE_DESCENDING;
   1.188 +      options.maxResults = kMaxResults;
   1.189 +      let query = PlacesUtils.history.getNewQuery();
   1.190 +
   1.191 +      let items = doc.getElementById("PanelUI-historyItems");
   1.192 +      // Clear previous history items.
   1.193 +      while (items.firstChild) {
   1.194 +        items.removeChild(items.firstChild);
   1.195 +      }
   1.196 +
   1.197 +      PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
   1.198 +                         .asyncExecuteLegacyQueries([query], 1, options, {
   1.199 +        handleResult: function (aResultSet) {
   1.200 +          let onHistoryVisit = function (aUri, aEvent, aItem) {
   1.201 +            doc.defaultView.openUILink(aUri, aEvent);
   1.202 +            CustomizableUI.hidePanelForNode(aItem);
   1.203 +          };
   1.204 +          let fragment = doc.createDocumentFragment();
   1.205 +          for (let row, i = 0; (row = aResultSet.getNextRow()); i++) {
   1.206 +            try {
   1.207 +              let uri = row.getResultByIndex(1);
   1.208 +              let title = row.getResultByIndex(2);
   1.209 +              let icon = row.getResultByIndex(6);
   1.210 +
   1.211 +              let item = doc.createElementNS(kNSXUL, "toolbarbutton");
   1.212 +              item.setAttribute("label", title || uri);
   1.213 +              item.setAttribute("targetURI", uri);
   1.214 +              item.setAttribute("class", "subviewbutton");
   1.215 +              item.addEventListener("click", function (aEvent) {
   1.216 +                onHistoryVisit(uri, aEvent, item);
   1.217 +              });
   1.218 +              if (icon)
   1.219 +                item.setAttribute("image", "moz-anno:favicon:" + icon);
   1.220 +              fragment.appendChild(item);
   1.221 +            } catch (e) {
   1.222 +              ERROR("Error while showing history subview: " + e);
   1.223 +            }
   1.224 +          }
   1.225 +          items.appendChild(fragment);
   1.226 +        },
   1.227 +        handleError: function (aError) {
   1.228 +          LOG("History view tried to show but had an error: " + aError);
   1.229 +        },
   1.230 +        handleCompletion: function (aReason) {
   1.231 +          LOG("History view is being shown!");
   1.232 +        },
   1.233 +      });
   1.234 +
   1.235 +      let recentlyClosedTabs = doc.getElementById("PanelUI-recentlyClosedTabs");
   1.236 +      while (recentlyClosedTabs.firstChild) {
   1.237 +        recentlyClosedTabs.removeChild(recentlyClosedTabs.firstChild);
   1.238 +      }
   1.239 +
   1.240 +      let recentlyClosedWindows = doc.getElementById("PanelUI-recentlyClosedWindows");
   1.241 +      while (recentlyClosedWindows.firstChild) {
   1.242 +        recentlyClosedWindows.removeChild(recentlyClosedWindows.firstChild);
   1.243 +      }
   1.244 +
   1.245 +#ifdef MOZ_SERVICES_SYNC
   1.246 +      let tabsFromOtherComputers = doc.getElementById("sync-tabs-menuitem2");
   1.247 +      if (PlacesUIUtils.shouldShowTabsFromOtherComputersMenuitem()) {
   1.248 +        tabsFromOtherComputers.removeAttribute("hidden");
   1.249 +      } else {
   1.250 +        tabsFromOtherComputers.setAttribute("hidden", true);
   1.251 +      }
   1.252 +
   1.253 +      if (PlacesUIUtils.shouldEnableTabsFromOtherComputersMenuitem()) {
   1.254 +        tabsFromOtherComputers.removeAttribute("disabled");
   1.255 +      } else {
   1.256 +        tabsFromOtherComputers.setAttribute("disabled", true);
   1.257 +      }
   1.258 +#endif
   1.259 +
   1.260 +      let utils = RecentlyClosedTabsAndWindowsMenuUtils;
   1.261 +      let tabsFragment = utils.getTabsFragment(doc.defaultView, "toolbarbutton", true,
   1.262 +                                               "menuRestoreAllTabsSubview.label");
   1.263 +      let separator = doc.getElementById("PanelUI-recentlyClosedTabs-separator");
   1.264 +      let elementCount = tabsFragment.childElementCount;
   1.265 +      separator.hidden = !elementCount;
   1.266 +      while (--elementCount >= 0) {
   1.267 +        tabsFragment.children[elementCount].classList.add("subviewbutton");
   1.268 +      }
   1.269 +      recentlyClosedTabs.appendChild(tabsFragment);
   1.270 +
   1.271 +      let windowsFragment = utils.getWindowsFragment(doc.defaultView, "toolbarbutton", true,
   1.272 +                                                     "menuRestoreAllWindowsSubview.label");
   1.273 +      separator = doc.getElementById("PanelUI-recentlyClosedWindows-separator");
   1.274 +      elementCount = windowsFragment.childElementCount;
   1.275 +      separator.hidden = !elementCount;
   1.276 +      while (--elementCount >= 0) {
   1.277 +        windowsFragment.children[elementCount].classList.add("subviewbutton");
   1.278 +      }
   1.279 +      recentlyClosedWindows.appendChild(windowsFragment);
   1.280 +    },
   1.281 +    onCreated: function(aNode) {
   1.282 +      // Middle clicking recently closed items won't close the panel - cope:
   1.283 +      let onRecentlyClosedClick = function(aEvent) {
   1.284 +        if (aEvent.button == 1) {
   1.285 +          CustomizableUI.hidePanelForNode(this);
   1.286 +        }
   1.287 +      };
   1.288 +      let doc = aNode.ownerDocument;
   1.289 +      let recentlyClosedTabs = doc.getElementById("PanelUI-recentlyClosedTabs");
   1.290 +      let recentlyClosedWindows = doc.getElementById("PanelUI-recentlyClosedWindows");
   1.291 +      recentlyClosedTabs.addEventListener("click", onRecentlyClosedClick);
   1.292 +      recentlyClosedWindows.addEventListener("click", onRecentlyClosedClick);
   1.293 +    },
   1.294 +    onViewHiding: function(aEvent) {
   1.295 +      LOG("History view is being hidden!");
   1.296 +    }
   1.297 +  }, {
   1.298 +    id: "privatebrowsing-button",
   1.299 +    shortcutId: "key_privatebrowsing",
   1.300 +    defaultArea: CustomizableUI.AREA_PANEL,
   1.301 +    onCommand: function(e) {
   1.302 +      if (e.target && e.target.ownerDocument && e.target.ownerDocument.defaultView) {
   1.303 +        let win = e.target.ownerDocument.defaultView;
   1.304 +        if (typeof win.OpenBrowserWindow == "function") {
   1.305 +          win.OpenBrowserWindow({private: true});
   1.306 +        }
   1.307 +      }
   1.308 +    }
   1.309 +  }, {
   1.310 +    id: "save-page-button",
   1.311 +    shortcutId: "key_savePage",
   1.312 +    tooltiptext: "save-page-button.tooltiptext3",
   1.313 +    defaultArea: CustomizableUI.AREA_PANEL,
   1.314 +    onCommand: function(aEvent) {
   1.315 +      let win = aEvent.target &&
   1.316 +                aEvent.target.ownerDocument &&
   1.317 +                aEvent.target.ownerDocument.defaultView;
   1.318 +      if (win && typeof win.saveDocument == "function") {
   1.319 +        win.saveDocument(win.content.document);
   1.320 +      }
   1.321 +    }
   1.322 +  }, {
   1.323 +    id: "find-button",
   1.324 +    shortcutId: "key_find",
   1.325 +    tooltiptext: "find-button.tooltiptext3",
   1.326 +    defaultArea: CustomizableUI.AREA_PANEL,
   1.327 +    onCommand: function(aEvent) {
   1.328 +      let win = aEvent.target &&
   1.329 +                aEvent.target.ownerDocument &&
   1.330 +                aEvent.target.ownerDocument.defaultView;
   1.331 +      if (win && win.gFindBar) {
   1.332 +        win.gFindBar.onFindCommand();
   1.333 +      }
   1.334 +    }
   1.335 +  }, {
   1.336 +    id: "open-file-button",
   1.337 +    shortcutId: "openFileKb",
   1.338 +    tooltiptext: "open-file-button.tooltiptext3",
   1.339 +    defaultArea: CustomizableUI.AREA_PANEL,
   1.340 +    onCommand: function(aEvent) {
   1.341 +      let win = aEvent.target
   1.342 +                && aEvent.target.ownerDocument
   1.343 +                && aEvent.target.ownerDocument.defaultView;
   1.344 +      if (win && typeof win.BrowserOpenFileWindow == "function") {
   1.345 +        win.BrowserOpenFileWindow();
   1.346 +      }
   1.347 +    }
   1.348 +  }, {
   1.349 +    id: "developer-button",
   1.350 +    type: "view",
   1.351 +    viewId: "PanelUI-developer",
   1.352 +    shortcutId: "key_devToolboxMenuItem",
   1.353 +    tooltiptext: "developer-button.tooltiptext2",
   1.354 +    defaultArea: CustomizableUI.AREA_PANEL,
   1.355 +    onViewShowing: function(aEvent) {
   1.356 +      // Populate the subview with whatever menuitems are in the developer
   1.357 +      // menu. We skip menu elements, because the menu panel has no way
   1.358 +      // of dealing with those right now.
   1.359 +      let doc = aEvent.target.ownerDocument;
   1.360 +      let win = doc.defaultView;
   1.361 +
   1.362 +      let menu = doc.getElementById("menuWebDeveloperPopup");
   1.363 +
   1.364 +      let itemsToDisplay = [...menu.children];
   1.365 +      // Hardcode the addition of the "work offline" menuitem at the bottom:
   1.366 +      itemsToDisplay.push({localName: "menuseparator", getAttribute: () => {}});
   1.367 +      itemsToDisplay.push(doc.getElementById("goOfflineMenuitem"));
   1.368 +      fillSubviewFromMenuItems(itemsToDisplay, doc.getElementById("PanelUI-developerItems"));
   1.369 +
   1.370 +    },
   1.371 +    onViewHiding: function(aEvent) {
   1.372 +      let doc = aEvent.target.ownerDocument;
   1.373 +      clearSubview(doc.getElementById("PanelUI-developerItems"));
   1.374 +    }
   1.375 +  }, {
   1.376 +    id: "sidebar-button",
   1.377 +    type: "view",
   1.378 +    viewId: "PanelUI-sidebar",
   1.379 +    tooltiptext: "sidebar-button.tooltiptext2",
   1.380 +    onViewShowing: function(aEvent) {
   1.381 +      // Largely duplicated from the developer-button above with a couple minor
   1.382 +      // alterations.
   1.383 +      // Populate the subview with whatever menuitems are in the
   1.384 +      // sidebar menu. We skip menu elements, because the menu panel has no way
   1.385 +      // of dealing with those right now.
   1.386 +      let doc = aEvent.target.ownerDocument;
   1.387 +      let win = doc.defaultView;
   1.388 +      let menu = doc.getElementById("viewSidebarMenu");
   1.389 +
   1.390 +      // First clear any existing menuitems then populate. Social sidebar
   1.391 +      // options may not have been added yet, so we do that here. Add it to the
   1.392 +      // standard menu first, then copy all sidebar options to the panel.
   1.393 +      win.SocialSidebar.clearProviderMenus();
   1.394 +      let providerMenuSeps = menu.getElementsByClassName("social-provider-menu");
   1.395 +      if (providerMenuSeps.length > 0)
   1.396 +        win.SocialSidebar.populateProviderMenu(providerMenuSeps[0]);
   1.397 +
   1.398 +      fillSubviewFromMenuItems([...menu.children], doc.getElementById("PanelUI-sidebarItems"));
   1.399 +    },
   1.400 +    onViewHiding: function(aEvent) {
   1.401 +      let doc = aEvent.target.ownerDocument;
   1.402 +      clearSubview(doc.getElementById("PanelUI-sidebarItems"));
   1.403 +    }
   1.404 +  }, {
   1.405 +    id: "add-ons-button",
   1.406 +    shortcutId: "key_openAddons",
   1.407 +    tooltiptext: "add-ons-button.tooltiptext3",
   1.408 +    defaultArea: CustomizableUI.AREA_PANEL,
   1.409 +    onCommand: function(aEvent) {
   1.410 +      let win = aEvent.target &&
   1.411 +                aEvent.target.ownerDocument &&
   1.412 +                aEvent.target.ownerDocument.defaultView;
   1.413 +      if (win && typeof win.BrowserOpenAddonsMgr == "function") {
   1.414 +        win.BrowserOpenAddonsMgr();
   1.415 +      }
   1.416 +    }
   1.417 +  }, {
   1.418 +    id: "preferences-button",
   1.419 +    defaultArea: CustomizableUI.AREA_PANEL,
   1.420 +#ifdef XP_WIN
   1.421 +    label: "preferences-button.labelWin",
   1.422 +    tooltiptext: "preferences-button.tooltipWin2",
   1.423 +#else
   1.424 +#ifdef XP_MACOSX
   1.425 +    tooltiptext: "preferences-button.tooltiptext.withshortcut",
   1.426 +    shortcutId: "key_preferencesCmdMac",
   1.427 +#else
   1.428 +    tooltiptext: "preferences-button.tooltiptext2",
   1.429 +#endif
   1.430 +#endif
   1.431 +    onCommand: function(aEvent) {
   1.432 +      let win = aEvent.target &&
   1.433 +                aEvent.target.ownerDocument &&
   1.434 +                aEvent.target.ownerDocument.defaultView;
   1.435 +      if (win && typeof win.openPreferences == "function") {
   1.436 +        win.openPreferences();
   1.437 +      }
   1.438 +    }
   1.439 +  }, {
   1.440 +    id: "zoom-controls",
   1.441 +    type: "custom",
   1.442 +    tooltiptext: "zoom-controls.tooltiptext2",
   1.443 +    defaultArea: CustomizableUI.AREA_PANEL,
   1.444 +    onBuild: function(aDocument) {
   1.445 +      const kPanelId = "PanelUI-popup";
   1.446 +      let areaType = CustomizableUI.getAreaType(this.currentArea);
   1.447 +      let inPanel = areaType == CustomizableUI.TYPE_MENU_PANEL;
   1.448 +      let inToolbar = areaType == CustomizableUI.TYPE_TOOLBAR;
   1.449 +
   1.450 +      let buttons = [{
   1.451 +        id: "zoom-out-button",
   1.452 +        command: "cmd_fullZoomReduce",
   1.453 +        label: true,
   1.454 +        tooltiptext: "tooltiptext2",
   1.455 +        shortcutId: "key_fullZoomReduce",
   1.456 +      }, {
   1.457 +        id: "zoom-reset-button",
   1.458 +        command: "cmd_fullZoomReset",
   1.459 +        tooltiptext: "tooltiptext2",
   1.460 +        shortcutId: "key_fullZoomReset",
   1.461 +      }, {
   1.462 +        id: "zoom-in-button",
   1.463 +        command: "cmd_fullZoomEnlarge",
   1.464 +        label: true,
   1.465 +        tooltiptext: "tooltiptext2",
   1.466 +        shortcutId: "key_fullZoomEnlarge",
   1.467 +      }];
   1.468 +
   1.469 +      let node = aDocument.createElementNS(kNSXUL, "toolbaritem");
   1.470 +      node.setAttribute("id", "zoom-controls");
   1.471 +      node.setAttribute("label", CustomizableUI.getLocalizedProperty(this, "label"));
   1.472 +      node.setAttribute("title", CustomizableUI.getLocalizedProperty(this, "tooltiptext"));
   1.473 +      // Set this as an attribute in addition to the property to make sure we can style correctly.
   1.474 +      node.setAttribute("removable", "true");
   1.475 +      node.classList.add("chromeclass-toolbar-additional");
   1.476 +      node.classList.add("toolbaritem-combined-buttons");
   1.477 +      node.classList.add(kWidePanelItemClass);
   1.478 +
   1.479 +      buttons.forEach(function(aButton, aIndex) {
   1.480 +        if (aIndex != 0)
   1.481 +          node.appendChild(aDocument.createElementNS(kNSXUL, "separator"));
   1.482 +        let btnNode = aDocument.createElementNS(kNSXUL, "toolbarbutton");
   1.483 +        setAttributes(btnNode, aButton);
   1.484 +        node.appendChild(btnNode);
   1.485 +      });
   1.486 +
   1.487 +      // The middle node is the 'Reset Zoom' button.
   1.488 +      let zoomResetButton = node.childNodes[2];
   1.489 +      let window = aDocument.defaultView;
   1.490 +      function updateZoomResetButton() {
   1.491 +        let updateDisplay = true;
   1.492 +        // Label should always show 100% in customize mode, so don't update:
   1.493 +        if (aDocument.documentElement.hasAttribute("customizing")) {
   1.494 +          updateDisplay = false;
   1.495 +        }
   1.496 +        //XXXgijs in some tests we get called very early, and there's no docShell on the
   1.497 +        // tabbrowser. This breaks the zoom toolkit code (see bug 897410). Don't let that happen:
   1.498 +        let zoomFactor = 100;
   1.499 +        try {
   1.500 +          zoomFactor = Math.round(window.ZoomManager.zoom * 100);
   1.501 +        } catch (e) {}
   1.502 +        zoomResetButton.setAttribute("label", CustomizableUI.getLocalizedProperty(
   1.503 +          buttons[1], "label", [updateDisplay ? zoomFactor : 100]
   1.504 +        ));
   1.505 +      };
   1.506 +
   1.507 +      // Register ourselves with the service so we know when the zoom prefs change.
   1.508 +      Services.obs.addObserver(updateZoomResetButton, "browser-fullZoom:zoomChange", false);
   1.509 +      Services.obs.addObserver(updateZoomResetButton, "browser-fullZoom:zoomReset", false);
   1.510 +      Services.obs.addObserver(updateZoomResetButton, "browser-fullZoom:location-change", false);
   1.511 +
   1.512 +      if (inPanel) {
   1.513 +        let panel = aDocument.getElementById(kPanelId);
   1.514 +        panel.addEventListener("popupshowing", updateZoomResetButton);
   1.515 +      } else {
   1.516 +        if (inToolbar) {
   1.517 +          let container = window.gBrowser.tabContainer;
   1.518 +          container.addEventListener("TabSelect", updateZoomResetButton);
   1.519 +        }
   1.520 +        updateZoomResetButton();
   1.521 +      }
   1.522 +      updateCombinedWidgetStyle(node, this.currentArea, true);
   1.523 +
   1.524 +      let listener = {
   1.525 +        onWidgetAdded: function(aWidgetId, aArea, aPosition) {
   1.526 +          if (aWidgetId != this.id)
   1.527 +            return;
   1.528 +
   1.529 +          updateCombinedWidgetStyle(node, aArea, true);
   1.530 +          updateZoomResetButton();
   1.531 +
   1.532 +          let areaType = CustomizableUI.getAreaType(aArea);
   1.533 +          if (areaType == CustomizableUI.TYPE_MENU_PANEL) {
   1.534 +            let panel = aDocument.getElementById(kPanelId);
   1.535 +            panel.addEventListener("popupshowing", updateZoomResetButton);
   1.536 +          } else if (areaType == CustomizableUI.TYPE_TOOLBAR) {
   1.537 +            let container = window.gBrowser.tabContainer;
   1.538 +            container.addEventListener("TabSelect", updateZoomResetButton);
   1.539 +          }
   1.540 +        }.bind(this),
   1.541 +
   1.542 +        onWidgetRemoved: function(aWidgetId, aPrevArea) {
   1.543 +          if (aWidgetId != this.id)
   1.544 +            return;
   1.545 +
   1.546 +          let areaType = CustomizableUI.getAreaType(aPrevArea);
   1.547 +          if (areaType == CustomizableUI.TYPE_MENU_PANEL) {
   1.548 +            let panel = aDocument.getElementById(kPanelId);
   1.549 +            panel.removeEventListener("popupshowing", updateZoomResetButton);
   1.550 +          } else if (areaType == CustomizableUI.TYPE_TOOLBAR) {
   1.551 +            let container = window.gBrowser.tabContainer;
   1.552 +            container.removeEventListener("TabSelect", updateZoomResetButton);
   1.553 +          }
   1.554 +
   1.555 +          // When a widget is demoted to the palette ('removed'), it's visual
   1.556 +          // style should change.
   1.557 +          updateCombinedWidgetStyle(node, null, true);
   1.558 +          updateZoomResetButton();
   1.559 +        }.bind(this),
   1.560 +
   1.561 +        onWidgetReset: function(aWidgetNode) {
   1.562 +          if (aWidgetNode != node)
   1.563 +            return;
   1.564 +          updateCombinedWidgetStyle(node, this.currentArea, true);
   1.565 +          updateZoomResetButton();
   1.566 +        }.bind(this),
   1.567 +
   1.568 +        onWidgetMoved: function(aWidgetId, aArea) {
   1.569 +          if (aWidgetId != this.id)
   1.570 +            return;
   1.571 +          updateCombinedWidgetStyle(node, aArea, true);
   1.572 +          updateZoomResetButton();
   1.573 +        }.bind(this),
   1.574 +
   1.575 +        onWidgetInstanceRemoved: function(aWidgetId, aDoc) {
   1.576 +          if (aWidgetId != this.id || aDoc != aDocument)
   1.577 +            return;
   1.578 +
   1.579 +          CustomizableUI.removeListener(listener);
   1.580 +          Services.obs.removeObserver(updateZoomResetButton, "browser-fullZoom:zoomChange");
   1.581 +          Services.obs.removeObserver(updateZoomResetButton, "browser-fullZoom:zoomReset");
   1.582 +          Services.obs.removeObserver(updateZoomResetButton, "browser-fullZoom:location-change");
   1.583 +          let panel = aDoc.getElementById(kPanelId);
   1.584 +          panel.removeEventListener("popupshowing", updateZoomResetButton);
   1.585 +          let container = aDoc.defaultView.gBrowser.tabContainer;
   1.586 +          container.removeEventListener("TabSelect", updateZoomResetButton);
   1.587 +        }.bind(this),
   1.588 +
   1.589 +        onCustomizeStart: function(aWindow) {
   1.590 +          if (aWindow.document == aDocument) {
   1.591 +            updateZoomResetButton();
   1.592 +          }
   1.593 +        },
   1.594 +
   1.595 +        onCustomizeEnd: function(aWindow) {
   1.596 +          if (aWindow.document == aDocument) {
   1.597 +            updateZoomResetButton();
   1.598 +          }
   1.599 +        },
   1.600 +
   1.601 +        onWidgetDrag: function(aWidgetId, aArea) {
   1.602 +          if (aWidgetId != this.id)
   1.603 +            return;
   1.604 +          aArea = aArea || this.currentArea;
   1.605 +          updateCombinedWidgetStyle(node, aArea, true);
   1.606 +        }.bind(this)
   1.607 +      };
   1.608 +      CustomizableUI.addListener(listener);
   1.609 +
   1.610 +      return node;
   1.611 +    }
   1.612 +  }, {
   1.613 +    id: "edit-controls",
   1.614 +    type: "custom",
   1.615 +    tooltiptext: "edit-controls.tooltiptext2",
   1.616 +    defaultArea: CustomizableUI.AREA_PANEL,
   1.617 +    onBuild: function(aDocument) {
   1.618 +      let buttons = [{
   1.619 +        id: "cut-button",
   1.620 +        command: "cmd_cut",
   1.621 +        label: true,
   1.622 +        tooltiptext: "tooltiptext2",
   1.623 +        shortcutId: "key_cut",
   1.624 +      }, {
   1.625 +        id: "copy-button",
   1.626 +        command: "cmd_copy",
   1.627 +        label: true,
   1.628 +        tooltiptext: "tooltiptext2",
   1.629 +        shortcutId: "key_copy",
   1.630 +      }, {
   1.631 +        id: "paste-button",
   1.632 +        command: "cmd_paste",
   1.633 +        label: true,
   1.634 +        tooltiptext: "tooltiptext2",
   1.635 +        shortcutId: "key_paste",
   1.636 +      }];
   1.637 +
   1.638 +      let node = aDocument.createElementNS(kNSXUL, "toolbaritem");
   1.639 +      node.setAttribute("id", "edit-controls");
   1.640 +      node.setAttribute("label", CustomizableUI.getLocalizedProperty(this, "label"));
   1.641 +      node.setAttribute("title", CustomizableUI.getLocalizedProperty(this, "tooltiptext"));
   1.642 +      // Set this as an attribute in addition to the property to make sure we can style correctly.
   1.643 +      node.setAttribute("removable", "true");
   1.644 +      node.classList.add("chromeclass-toolbar-additional");
   1.645 +      node.classList.add("toolbaritem-combined-buttons");
   1.646 +      node.classList.add(kWidePanelItemClass);
   1.647 +
   1.648 +      buttons.forEach(function(aButton, aIndex) {
   1.649 +        if (aIndex != 0)
   1.650 +          node.appendChild(aDocument.createElementNS(kNSXUL, "separator"));
   1.651 +        let btnNode = aDocument.createElementNS(kNSXUL, "toolbarbutton");
   1.652 +        setAttributes(btnNode, aButton);
   1.653 +        node.appendChild(btnNode);
   1.654 +      });
   1.655 +
   1.656 +      updateCombinedWidgetStyle(node, this.currentArea);
   1.657 +
   1.658 +      let listener = {
   1.659 +        onWidgetAdded: function(aWidgetId, aArea, aPosition) {
   1.660 +          if (aWidgetId != this.id)
   1.661 +            return;
   1.662 +          updateCombinedWidgetStyle(node, aArea);
   1.663 +        }.bind(this),
   1.664 +
   1.665 +        onWidgetRemoved: function(aWidgetId, aPrevArea) {
   1.666 +          if (aWidgetId != this.id)
   1.667 +            return;
   1.668 +          // When a widget is demoted to the palette ('removed'), it's visual
   1.669 +          // style should change.
   1.670 +          updateCombinedWidgetStyle(node);
   1.671 +        }.bind(this),
   1.672 +
   1.673 +        onWidgetReset: function(aWidgetNode) {
   1.674 +          if (aWidgetNode != node)
   1.675 +            return;
   1.676 +          updateCombinedWidgetStyle(node, this.currentArea);
   1.677 +        }.bind(this),
   1.678 +
   1.679 +        onWidgetMoved: function(aWidgetId, aArea) {
   1.680 +          if (aWidgetId != this.id)
   1.681 +            return;
   1.682 +          updateCombinedWidgetStyle(node, aArea);
   1.683 +        }.bind(this),
   1.684 +
   1.685 +        onWidgetInstanceRemoved: function(aWidgetId, aDoc) {
   1.686 +          if (aWidgetId != this.id || aDoc != aDocument)
   1.687 +            return;
   1.688 +          CustomizableUI.removeListener(listener);
   1.689 +        }.bind(this),
   1.690 +
   1.691 +        onWidgetDrag: function(aWidgetId, aArea) {
   1.692 +          if (aWidgetId != this.id)
   1.693 +            return;
   1.694 +          aArea = aArea || this.currentArea;
   1.695 +          updateCombinedWidgetStyle(node, aArea);
   1.696 +        }.bind(this)
   1.697 +      };
   1.698 +      CustomizableUI.addListener(listener);
   1.699 +
   1.700 +      return node;
   1.701 +    }
   1.702 +  },
   1.703 +  {
   1.704 +    id: "feed-button",
   1.705 +    type: "view",
   1.706 +    viewId: "PanelUI-feeds",
   1.707 +    tooltiptext: "feed-button.tooltiptext2",
   1.708 +    defaultArea: CustomizableUI.AREA_PANEL,
   1.709 +    onClick: function(aEvent) {
   1.710 +      let win = aEvent.target.ownerDocument.defaultView;
   1.711 +      let feeds = win.gBrowser.selectedBrowser.feeds;
   1.712 +
   1.713 +      // Here, we only care about the case where we have exactly 1 feed and the
   1.714 +      // user clicked...
   1.715 +      let isClick = (aEvent.button == 0 || aEvent.button == 1);
   1.716 +      if (feeds && feeds.length == 1 && isClick) {
   1.717 +        aEvent.preventDefault();
   1.718 +        aEvent.stopPropagation();
   1.719 +        win.FeedHandler.subscribeToFeed(feeds[0].href, aEvent);
   1.720 +        CustomizableUI.hidePanelForNode(aEvent.target);
   1.721 +      }
   1.722 +    },
   1.723 +    onViewShowing: function(aEvent) {
   1.724 +      let doc = aEvent.detail.ownerDocument;
   1.725 +      let container = doc.getElementById("PanelUI-feeds");
   1.726 +      let gotView = doc.defaultView.FeedHandler.buildFeedList(container, true);
   1.727 +
   1.728 +      // For no feeds or only a single one, don't show the panel.
   1.729 +      if (!gotView) {
   1.730 +        aEvent.preventDefault();
   1.731 +        aEvent.stopPropagation();
   1.732 +        return;
   1.733 +      }
   1.734 +    },
   1.735 +    onCreated: function(node) {
   1.736 +      let win = node.ownerDocument.defaultView;
   1.737 +      let selectedBrowser = win.gBrowser.selectedBrowser;
   1.738 +      let feeds = selectedBrowser && selectedBrowser.feeds;
   1.739 +      if (!feeds || !feeds.length) {
   1.740 +        node.setAttribute("disabled", "true");
   1.741 +      }
   1.742 +    }
   1.743 +  }, {
   1.744 +    id: "characterencoding-button",
   1.745 +    type: "view",
   1.746 +    viewId: "PanelUI-characterEncodingView",
   1.747 +    tooltiptext: "characterencoding-button.tooltiptext2",
   1.748 +    defaultArea: CustomizableUI.AREA_PANEL,
   1.749 +    maybeDisableMenu: function(aDocument) {
   1.750 +      let window = aDocument.defaultView;
   1.751 +      return !(window.gBrowser &&
   1.752 +               window.gBrowser.docShell &&
   1.753 +               window.gBrowser.docShell.mayEnableCharacterEncodingMenu);
   1.754 +    },
   1.755 +    populateList: function(aDocument, aContainerId, aSection) {
   1.756 +      let containerElem = aDocument.getElementById(aContainerId);
   1.757 +
   1.758 +      containerElem.addEventListener("command", this.onCommand, false);
   1.759 +
   1.760 +      let list = this.charsetInfo[aSection];
   1.761 +
   1.762 +      for (let item of list) {
   1.763 +        let elem = aDocument.createElementNS(kNSXUL, "toolbarbutton");
   1.764 +        elem.setAttribute("label", item.label);
   1.765 +        elem.setAttribute("type", "checkbox");
   1.766 +        elem.section = aSection;
   1.767 +        elem.value = item.value;
   1.768 +        elem.setAttribute("class", "subviewbutton");
   1.769 +        containerElem.appendChild(elem);
   1.770 +      }
   1.771 +    },
   1.772 +    updateCurrentCharset: function(aDocument) {
   1.773 +      let content = aDocument.defaultView.content;
   1.774 +      let currentCharset = content && content.document && content.document.characterSet;
   1.775 +      currentCharset = CharsetMenu.foldCharset(currentCharset);
   1.776 +
   1.777 +      let pinnedContainer = aDocument.getElementById("PanelUI-characterEncodingView-pinned");
   1.778 +      let charsetContainer = aDocument.getElementById("PanelUI-characterEncodingView-charsets");
   1.779 +      let elements = [...(pinnedContainer.childNodes), ...(charsetContainer.childNodes)];
   1.780 +
   1.781 +      this._updateElements(elements, currentCharset);
   1.782 +    },
   1.783 +    updateCurrentDetector: function(aDocument) {
   1.784 +      let detectorContainer = aDocument.getElementById("PanelUI-characterEncodingView-autodetect");
   1.785 +      let currentDetector;
   1.786 +      try {
   1.787 +        currentDetector = Services.prefs.getComplexValue(
   1.788 +          "intl.charset.detector", Ci.nsIPrefLocalizedString).data;
   1.789 +      } catch (e) {}
   1.790 +
   1.791 +      this._updateElements(detectorContainer.childNodes, currentDetector);
   1.792 +    },
   1.793 +    _updateElements: function(aElements, aCurrentItem) {
   1.794 +      if (!aElements.length) {
   1.795 +        return;
   1.796 +      }
   1.797 +      let disabled = this.maybeDisableMenu(aElements[0].ownerDocument);
   1.798 +      for (let elem of aElements) {
   1.799 +        if (disabled) {
   1.800 +          elem.setAttribute("disabled", "true");
   1.801 +        } else {
   1.802 +          elem.removeAttribute("disabled");
   1.803 +        }
   1.804 +        if (elem.value.toLowerCase() == aCurrentItem.toLowerCase()) {
   1.805 +          elem.setAttribute("checked", "true");
   1.806 +        } else {
   1.807 +          elem.removeAttribute("checked");
   1.808 +        }
   1.809 +      }
   1.810 +    },
   1.811 +    onViewShowing: function(aEvent) {
   1.812 +      let document = aEvent.target.ownerDocument;
   1.813 +
   1.814 +      let autoDetectLabelId = "PanelUI-characterEncodingView-autodetect-label";
   1.815 +      let autoDetectLabel = document.getElementById(autoDetectLabelId);
   1.816 +      if (!autoDetectLabel.hasAttribute("value")) {
   1.817 +        let label = CharsetBundle.GetStringFromName("charsetMenuAutodet");
   1.818 +        autoDetectLabel.setAttribute("value", label);
   1.819 +        this.populateList(document,
   1.820 +                          "PanelUI-characterEncodingView-pinned",
   1.821 +                          "pinnedCharsets");
   1.822 +        this.populateList(document,
   1.823 +                          "PanelUI-characterEncodingView-charsets",
   1.824 +                          "otherCharsets");
   1.825 +        this.populateList(document,
   1.826 +                          "PanelUI-characterEncodingView-autodetect",
   1.827 +                          "detectors");
   1.828 +      }
   1.829 +      this.updateCurrentDetector(document);
   1.830 +      this.updateCurrentCharset(document);
   1.831 +    },
   1.832 +    onCommand: function(aEvent) {
   1.833 +      let node = aEvent.target;
   1.834 +      if (!node.hasAttribute || !node.section) {
   1.835 +        return;
   1.836 +      }
   1.837 +
   1.838 +      let window = node.ownerDocument.defaultView;
   1.839 +      let section = node.section;
   1.840 +      let value = node.value;
   1.841 +
   1.842 +      // The behavior as implemented here is directly based off of the
   1.843 +      // `MultiplexHandler()` method in browser.js.
   1.844 +      if (section != "detectors") {
   1.845 +        window.BrowserSetForcedCharacterSet(value);
   1.846 +      } else {
   1.847 +        // Set the detector pref.
   1.848 +        try {
   1.849 +          let str = Cc["@mozilla.org/supports-string;1"]
   1.850 +                      .createInstance(Ci.nsISupportsString);
   1.851 +          str.data = value;
   1.852 +          Services.prefs.setComplexValue("intl.charset.detector", Ci.nsISupportsString, str);
   1.853 +        } catch (e) {
   1.854 +          Cu.reportError("Failed to set the intl.charset.detector preference.");
   1.855 +        }
   1.856 +        // Prepare a browser page reload with a changed charset.
   1.857 +        window.BrowserCharsetReload();
   1.858 +      }
   1.859 +    },
   1.860 +    onCreated: function(aNode) {
   1.861 +      const kPanelId = "PanelUI-popup";
   1.862 +      let document = aNode.ownerDocument;
   1.863 +
   1.864 +      let updateButton = () => {
   1.865 +        if (this.maybeDisableMenu(document))
   1.866 +          aNode.setAttribute("disabled", "true");
   1.867 +        else
   1.868 +          aNode.removeAttribute("disabled");
   1.869 +      };
   1.870 +
   1.871 +      if (this.currentArea == CustomizableUI.AREA_PANEL) {
   1.872 +        let panel = document.getElementById(kPanelId);
   1.873 +        panel.addEventListener("popupshowing", updateButton);
   1.874 +      }
   1.875 +
   1.876 +      let listener = {
   1.877 +        onWidgetAdded: (aWidgetId, aArea) => {
   1.878 +          if (aWidgetId != this.id)
   1.879 +            return;
   1.880 +          if (aArea == CustomizableUI.AREA_PANEL) {
   1.881 +            let panel = document.getElementById(kPanelId);
   1.882 +            panel.addEventListener("popupshowing", updateButton);
   1.883 +          }
   1.884 +        },
   1.885 +        onWidgetRemoved: (aWidgetId, aPrevArea) => {
   1.886 +          if (aWidgetId != this.id)
   1.887 +            return;
   1.888 +          aNode.removeAttribute("disabled");
   1.889 +          if (aPrevArea == CustomizableUI.AREA_PANEL) {
   1.890 +            let panel = document.getElementById(kPanelId);
   1.891 +            panel.removeEventListener("popupshowing", updateButton);
   1.892 +          }
   1.893 +        },
   1.894 +        onWidgetInstanceRemoved: (aWidgetId, aDoc) => {
   1.895 +          if (aWidgetId != this.id || aDoc != document)
   1.896 +            return;
   1.897 +
   1.898 +          CustomizableUI.removeListener(listener);
   1.899 +          let panel = aDoc.getElementById(kPanelId);
   1.900 +          panel.removeEventListener("popupshowing", updateButton);
   1.901 +        }
   1.902 +      };
   1.903 +      CustomizableUI.addListener(listener);
   1.904 +      if (!this.charsetInfo) {
   1.905 +        this.charsetInfo = CharsetMenu.getData();
   1.906 +      }
   1.907 +    }
   1.908 +  }, {
   1.909 +    id: "email-link-button",
   1.910 +    tooltiptext: "email-link-button.tooltiptext3",
   1.911 +    onCommand: function(aEvent) {
   1.912 +      let win = aEvent.view;
   1.913 +      win.MailIntegration.sendLinkForWindow(win.content);
   1.914 +    }
   1.915 +  }];
   1.916 +
   1.917 +#ifdef XP_WIN
   1.918 +#ifdef MOZ_METRO
   1.919 +if (Services.metro && Services.metro.supported) {
   1.920 +  let widgetArgs = {tooltiptext: "switch-to-metro-button2.tooltiptext"};
   1.921 +  let brandShortName = BrandBundle.GetStringFromName("brandShortName");
   1.922 +  let metroTooltip = CustomizableUI.getLocalizedProperty(widgetArgs, "tooltiptext",
   1.923 +                                                         [brandShortName]);
   1.924 +  CustomizableWidgets.push({
   1.925 +    id: "switch-to-metro-button",
   1.926 +    label: "switch-to-metro-button2.label",
   1.927 +    tooltiptext: metroTooltip,
   1.928 +    defaultArea: CustomizableUI.AREA_PANEL,
   1.929 +    showInPrivateBrowsing: false, /* See bug 928068 */
   1.930 +    onCommand: function(aEvent) {
   1.931 +      let win = aEvent.view;
   1.932 +      if (win && typeof win.SwitchToMetro == "function") {
   1.933 +        win.SwitchToMetro();
   1.934 +      }
   1.935 +    }
   1.936 +  });
   1.937 +}
   1.938 +#endif
   1.939 +#endif
   1.940 +
   1.941 +#ifdef NIGHTLY_BUILD
   1.942 +/**
   1.943 + * The e10s button's purpose is to lower the barrier of entry
   1.944 + * for our Nightly testers to use e10s windows. We'll be removing it
   1.945 + * once remote tabs are enabled. This button should never ever make it
   1.946 + * to production. If it does, that'd be bad, and we should all feel bad.
   1.947 + */
   1.948 +if (Services.prefs.getBoolPref("browser.tabs.remote")) {
   1.949 +  let getCommandFunction = function(aOpenRemote) {
   1.950 +    return function(aEvent) {
   1.951 +      let win = aEvent.view;
   1.952 +      if (win && typeof win.OpenBrowserWindow == "function") {
   1.953 +        win.OpenBrowserWindow({remote: aOpenRemote});
   1.954 +      }
   1.955 +    };
   1.956 +  }
   1.957 +
   1.958 +  let openRemote = !Services.prefs.getBoolPref("browser.tabs.remote.autostart");
   1.959 +  // Like the XUL menuitem counterparts, we hard-code these strings in because
   1.960 +  // this button should never roll into production.
   1.961 +  let buttonLabel = openRemote ? "New e10s Window"
   1.962 +                               : "New Non-e10s Window";
   1.963 +
   1.964 +  CustomizableWidgets.push({
   1.965 +    id: "e10s-button",
   1.966 +    label: buttonLabel,
   1.967 +    tooltiptext: buttonLabel,
   1.968 +    defaultArea: CustomizableUI.AREA_PANEL,
   1.969 +    onCommand: getCommandFunction(openRemote),
   1.970 +  });
   1.971 +}
   1.972 +#endif

mercurial