Bug 1037091 - Add gear button with doorhanger configuration of newtab page [r=adw a=sylvestre]
authorEd Lee <edilee@mozilla.com>
Thu, 24 Jul 2014 17:20:03 -0700
changeset 217670 ec043dac15daa5d070e843865b5eb17f4c2f6dc3
parent 217669 ea4d28eac435f8bbc1ae7e84e72d4708902475d3
child 217671 24b8334087d662ba45ddcb89706864d9ff1f9c2f
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersadw, sylvestre
bugs1037091
milestone33.0a2
Bug 1037091 - Add gear button with doorhanger configuration of newtab page [r=adw a=sylvestre] Add new newtab control file for the customize functionality. Reuse existing panel styling of the search engine panel.
browser/base/content/newtab/customize.js
browser/base/content/newtab/newTab.css
browser/base/content/newtab/newTab.js
browser/base/content/newtab/newTab.xul
browser/base/content/newtab/page.js
browser/themes/shared/newtab/newTab.inc.css
new file mode 100644
--- /dev/null
+++ b/browser/base/content/newtab/customize.js
@@ -0,0 +1,67 @@
+#ifdef 0
+/* 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/. */
+#endif
+
+let gCustomize = {
+  _nodeIDSuffixes: [
+    "blank",
+    "button",
+    "classic",
+    "enhanced",
+    "panel",
+  ],
+
+  _nodes: {},
+
+  init: function() {
+    for (let idSuffix of this._nodeIDSuffixes) {
+      this._nodes[idSuffix] = document.getElementById("newtab-customize-" + idSuffix);
+    }
+
+    this._nodes.button.setAttribute("title", newTabString("customize.title"));
+    ["enhanced", "classic", "blank"].forEach(name => {
+      this._nodes[name].firstChild.textContent = newTabString("customize." + name);
+    });
+
+    this._nodes.button.addEventListener("click", e => this.showPanel());
+    this._nodes.blank.addEventListener("click", e => {
+      gAllPages.enabled = false;
+    });
+    this._nodes.classic.addEventListener("click", e => {
+      gAllPages.enabled = true;
+      gAllPages.enhanced = false;
+    });
+    this._nodes.enhanced.addEventListener("click", e => {
+      gAllPages.enabled = true;
+      gAllPages.enhanced = true;
+    });
+
+    this.updateSelected();
+  },
+
+  showPanel: function() {
+    let {button, panel} = this._nodes;
+    panel.openPopup(button);
+    button.setAttribute("active", true);
+    panel.addEventListener("popuphidden", function onHidden() {
+      panel.removeEventListener("popuphidden", onHidden);
+      button.removeAttribute("active");
+    });
+  },
+
+  updateSelected: function() {
+    let {enabled, enhanced} = gAllPages;
+    let selected = enabled ? enhanced ? "enhanced" : "classic" : "blank";
+    ["enhanced", "classic", "blank"].forEach(id => {
+      let node = this._nodes[id];
+      if (id == selected) {
+        node.setAttribute("selected", true);
+      }
+      else {
+        node.removeAttribute("selected");
+      }
+    });
+  },
+};
--- a/browser/base/content/newtab/newTab.css
+++ b/browser/base/content/newtab/newTab.css
@@ -33,25 +33,25 @@ input[type=button] {
   -moz-box-pack: center;
 }
 
 #newtab-undo-container[undo-disabled] {
   opacity: 0;
   pointer-events: none;
 }
 
-/* TOGGLE */
-#newtab-toggle {
+/* CUSTOMIZE */
+#newtab-customize-button {
   position: absolute;
-  top: 12px;
-  right: 12px;
+  top: 6px;
+  right: 6px;
 }
 
-#newtab-toggle:-moz-locale-dir(rtl) {
-  left: 12px;
+#newtab-customize-button:-moz-locale-dir(rtl) {
+  left: 6px;
   right: auto;
 }
 
 /* MARGINS */
 #newtab-vertical-margin {
   display: -moz-box;
   position: relative;
   -moz-box-flex: 1;
@@ -346,49 +346,54 @@ input[type=button] {
 }
 
 #newtab-search-text + #newtab-search-submit:hover:active {
   box-shadow: 0 1px 1px hsla(211,79%,6%,.1) inset,
               0 0 1px hsla(211,79%,6%,.2) inset;
   transition-duration: 0ms;
 }
 
+#newtab-customize-panel .panel-arrowcontent,
 #newtab-search-panel .panel-arrowcontent {
   -moz-padding-start: 0;
   -moz-padding-end: 0;
   padding-top: 0;
   padding-bottom: 0;
   background: rgb(248, 250, 251);
 }
 
+.newtab-customize-panel-item,
 .newtab-search-panel-engine {
   -moz-box-align: center;
   padding-top: 4px;
   padding-bottom: 4px;
   -moz-padding-start: 24px;
   -moz-padding-end: 24px;
 }
 
+.newtab-customize-panel-item:not(:last-child),
 .newtab-search-panel-engine:not(:last-child) {
   border-bottom: 1px solid #ccc;
 }
 
 .newtab-search-panel-engine > image {
   -moz-margin-end: 8px;
   width: 16px;
   height: 16px;
   list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
 }
 
+.newtab-customize-panel-item > label,
 .newtab-search-panel-engine > label {
   -moz-padding-start: 0;
   -moz-margin-start: 0;
   color: rgb(130, 132, 133);
 }
 
+.newtab-customize-panel-item[selected],
 .newtab-search-panel-engine[selected] {
   background: url("chrome://global/skin/menu/shared-menu-check.png") center left 4px no-repeat transparent;
 }
 
 .searchSuggestionTable {
   font: message-box;
   font-size: 16px;
 }
--- a/browser/base/content/newtab/newTab.js
+++ b/browser/base/content/newtab/newTab.js
@@ -30,17 +30,37 @@ let {
   gridPrefs: gGridPrefs
 } = NewTabUtils;
 
 XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() {
   return Services.strings.
     createBundle("chrome://browser/locale/newTab.properties");
 });
 
-function newTabString(name) gStringBundle.GetStringFromName('newtab.' + name);
+function newTabString(name, args) {
+  switch (name) {
+    case "customize.title":
+      return "Customize your New Tab page";
+
+    case "customize.enhanced":
+      return "Enhanced";
+
+    case "customize.classic":
+      return "Classic";
+
+    case "customize.blank":
+      return "Blank";
+  }
+
+  let stringName = "newtab." + name;
+  if (!args) {
+    return gStringBundle.GetStringFromName(stringName);
+  }
+  return gStringBundle.formatStringFromName(stringName, args, args.length);
+}
 
 function inPrivateBrowsingMode() {
   return PrivateBrowsingUtils.isWindowPrivate(window);
 }
 
 const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
 const XUL_NAMESPACE = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
@@ -52,11 +72,12 @@ const XUL_NAMESPACE = "http://www.mozill
 #include drag.js
 #include dragDataHelper.js
 #include drop.js
 #include dropTargetShim.js
 #include dropPreview.js
 #include updater.js
 #include undo.js
 #include search.js
+#include customize.js
 
 // Everything is loaded. Initialize the New Tab Page.
 gPage.init();
--- a/browser/base/content/newtab/newTab.xul
+++ b/browser/base/content/newtab/newTab.xul
@@ -30,16 +30,29 @@
 
   <xul:panel id="newtab-search-panel" orient="vertical" type="arrow"
              noautohide="true">
     <xul:hbox id="newtab-search-manage" class="newtab-search-panel-engine">
       <xul:label>&cmd_engineManager.label;</xul:label>
     </xul:hbox>
   </xul:panel>
 
+  <xul:panel id="newtab-customize-panel" orient="vertical" type="arrow"
+             noautohide="true">
+    <xul:hbox id="newtab-customize-enhanced" class="newtab-customize-panel-item">
+      <xul:label/>
+    </xul:hbox>
+    <xul:hbox id="newtab-customize-classic" class="newtab-customize-panel-item">
+      <xul:label/>
+    </xul:hbox>
+    <xul:hbox id="newtab-customize-blank" class="newtab-customize-panel-item">
+      <xul:label/>
+    </xul:hbox>
+  </xul:panel>
+
   <div id="newtab-scrollbox">
 
     <div id="newtab-vertical-margin">
 
       <div id="newtab-margin-top"/>
 
       <div id="newtab-margin-undo-container">
         <div id="newtab-undo-container" undo-disabled="true">
@@ -74,16 +87,17 @@
         </div>
 
         <div class="newtab-side-margin"/>
       </div>
 
       <div id="newtab-margin-bottom"/>
 
     </div>
-    <input id="newtab-toggle" type="button"/>
+
+    <input id="newtab-customize-button" type="button"/>
   </div>
 
   <xul:script type="text/javascript;version=1.8"
               src="chrome://browser/content/newtab/newTab.js"/>
   <xul:script type="text/javascript;version=1.8"
               src="chrome://browser/content/searchSuggestionUI.js"/>
 </xul:window>
--- a/browser/base/content/newtab/page.js
+++ b/browser/base/content/newtab/page.js
@@ -36,23 +36,28 @@ let gPage = {
     }
 
     // Check if the new tab feature is enabled.
     let enabled = gAllPages.enabled;
     if (enabled)
       this._init();
 
     this._updateAttributes(enabled);
+
+    // Initialize customize controls.
+    gCustomize.init();
   },
 
   /**
    * Listens for notifications specific to this page.
    */
   observe: function Page_observe(aSubject, aTopic, aData) {
     if (aTopic == "nsPref:changed") {
+      gCustomize.updateSelected();
+
       let enabled = gAllPages.enabled;
       this._updateAttributes(enabled);
 
       // Update thumbnails to the new enhanced setting
       if (aData == "browser.newtabpage.enhanced") {
         this.update();
       }
 
@@ -132,55 +137,44 @@ let gPage = {
   },
 
   /**
    * Updates the 'page-disabled' attributes of the respective DOM nodes.
    * @param aValue Whether the New Tab Page is enabled or not.
    */
   _updateAttributes: function Page_updateAttributes(aValue) {
     // Set the nodes' states.
-    let nodeSelector = "#newtab-scrollbox, #newtab-toggle, #newtab-grid, #newtab-search-container";
+    let nodeSelector = "#newtab-scrollbox, #newtab-grid, #newtab-search-container";
     for (let node of document.querySelectorAll(nodeSelector)) {
       if (aValue)
         node.removeAttribute("page-disabled");
       else
         node.setAttribute("page-disabled", "true");
     }
 
     // Enables/disables the control and link elements.
     let inputSelector = ".newtab-control, .newtab-link";
     for (let input of document.querySelectorAll(inputSelector)) {
       if (aValue) 
         input.removeAttribute("tabindex");
       else
         input.setAttribute("tabindex", "-1");
     }
-
-    // Update the toggle button's title.
-    let toggle = document.getElementById("newtab-toggle");
-    toggle.setAttribute("title", newTabString(aValue ? "hide" : "show"));
   },
 
   /**
    * Handles all page events.
    */
   handleEvent: function Page_handleEvent(aEvent) {
     switch (aEvent.type) {
       case "unload":
         gAllPages.unregister(this);
         break;
       case "click":
         let {button, target} = aEvent;
-        if (target.id == "newtab-toggle") {
-          if (button == 0) {
-            gAllPages.enabled = !gAllPages.enabled;
-          }
-          break;
-        }
-
         // Go up ancestors until we find a Site or not
         while (target) {
           if (target.hasOwnProperty("_newtabSite")) {
             target._newtabSite.onClick(aEvent);
             break;
           }
           target = target.parentNode;
         }
--- a/browser/themes/shared/newtab/newTab.inc.css
+++ b/browser/themes/shared/newtab/newTab.inc.css
@@ -53,34 +53,27 @@
   padding: 0;
   border: none;
 }
 
 #newtab-undo-close-button:-moz-focusring {
   outline: 1px dotted;
 }
 
-/* TOGGLE */
-#newtab-toggle {
-  width: 16px;
-  height: 16px;
-  padding: 0;
+/* CUSTOMIZE */
+#newtab-customize-button {
+  background-color: transparent;
+  background-image: -moz-image-rect(url(chrome://browser/skin/newtab/controls.svg), 0, 32, 32, 0);
   border: none;
-  background: -216px 0 transparent url(chrome://browser/skin/newtab/controls.png);
+  height: 32px;
+  width: 32px;
 }
 
-#newtab-toggle[page-disabled] {
-  background-position: -232px 0;
-}
-
-@media (min-resolution: 2dppx) {
-  #newtab-toggle {
-    background-image: url(chrome://browser/skin/newtab/controls@2x.png);
-    background-size: 296px;
-  }
+#newtab-customize-button:-moz-any(:hover, :active, [active]) {
+  background-image: -moz-image-rect(url(chrome://browser/skin/newtab/controls.svg), 0, 64, 32, 32);
 }
 
 /* CELLS */
 .newtab-cell {
   background-color: rgba(255,255,255,.2);
   border-radius: 12px;
 }