Bug 1101147 - Update about:newtab search styling. r=Mossop a=gavin
authorFelipe Gomes <felipc@gmail.com>
Mon, 24 Nov 2014 08:40:22 -0200
changeset 226129 65fa22861cada0916d93a65fb39c661978f6cc74
parent 226128 27505b6035efa8bda2db8ce5e61af69e33a32b73
child 226130 6f2e20f76c83a5b241f59ca749b4c197e6f7882d
push id4171
push userfelipc@gmail.com
push dateMon, 24 Nov 2014 10:41:22 +0000
treeherdermozilla-beta@65fa22861cad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMossop, gavin
bugs1101147
milestone34.0
Bug 1101147 - Update about:newtab search styling. r=Mossop a=gavin Update about:newtab with the new search styling, controlled by the pref browser.search.showOneOffButtons. a=gavin
browser/base/content/newtab/newTab.css
browser/base/content/newtab/search.js
browser/base/content/test/newtab/browser_newtab_search.js
browser/modules/ContentSearch.jsm
browser/modules/test/browser_ContentSearch.js
--- a/browser/base/content/newtab/newTab.css
+++ b/browser/base/content/newtab/newTab.css
@@ -339,29 +339,43 @@ input[type=button] {
   height: 38px; /* 26 image height + 6 top "padding" + 6 bottom "padding" */
   border: 1px solid transparent;
   -moz-margin-end: 8px;
   background-repeat: no-repeat;
   background-position: center;
   background-size: 65px 26px;
 }
 
+#newtab-search-logo.magnifier {
+  width: 38px; /* 26 image width + 6 left "padding" + 6 right "padding" */
+  -moz-margin-end: 5px;
+  background-size: 26px;
+  background-image: url("chrome://browser/skin/magnifier.png");
+}
+
+@media not all and (max-resolution: 1dppx) {
+  #newtab-search-icon.magnifier {
+    background-image: url("chrome://browser/skin/magnifier@2x.png");
+  }
+}
+
+
 #newtab-search-logo[hidden] {
   display: none;
 }
 
 #newtab-search-logo[active],
 #newtab-search-logo:hover {
   background-color: #e9e9e9;
   border: 1px solid rgb(226, 227, 229);
   border-radius: 2.5px;
 }
 
 #newtab-search-text {
-  height: 38px;
+  height: 38px; /* same height as #newtab-search-logo */
   -moz-box-flex: 1;
 
   padding: 0 8px;
   background: hsla(0,0%,100%,.9) padding-box;
   border: 1px solid;
   border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
   box-shadow: 0 1px 0 hsla(210,65%,9%,.02) inset,
               0 0 2px hsla(210,65%,9%,.1) inset,
@@ -375,17 +389,17 @@ input[type=button] {
 }
 
 #newtab-search-text:focus,
 #newtab-search-text[autofocus] {
   border-color: hsla(206,100%,60%,.6) hsla(206,76%,52%,.6) hsla(204,100%,40%,.6);
 }
 
 #newtab-search-submit {
-  height: 38px;
+  height: 38px; /* same height as #newtab-search-logo */
   font-size: 13px !important;
 
   -moz-margin-start: -1px;
   background: linear-gradient(hsla(0,0%,100%,.8), hsla(0,0%,100%,.1)) padding-box;
   padding: 0 9px;
   border: 1px solid;
   border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
   -moz-border-start: 1px solid transparent;
--- a/browser/base/content/newtab/search.js
+++ b/browser/base/content/newtab/search.js
@@ -3,31 +3,38 @@
  * 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 gSearch = {
 
   currentEngineName: null,
 
+  get useNewUI() {
+    let newUI = Services.prefs.getBoolPref("browser.search.showOneOffButtons");
+    delete this.useNewUI;
+    this.useNewUI = newUI;
+    return newUI;
+  },
+
   init: function () {
     for (let idSuffix of this._nodeIDSuffixes) {
       this._nodes[idSuffix] =
         document.getElementById("newtab-search-" + idSuffix);
     }
 
+    if (this.useNewUI) {
+      this._nodes.logo.classList.add("magnifier");
+    }
+
     window.addEventListener("ContentSearchService", this);
     this._send("GetState");
   },
 
   showPanel: function () {
-    if (!Services.prefs.getBoolPref("browser.search.showOneOffButtons")) {
-      return;
-    }
-
     let panel = this._nodes.panel;
     let logo = this._nodes.logo;
     panel.openPopup(logo);
     logo.setAttribute("active", "true");
     panel.addEventListener("popuphidden", function onHidden() {
       panel.removeEventListener("popuphidden", onHidden);
       logo.removeAttribute("active");
     });
@@ -108,16 +115,21 @@ let gSearch = {
       detail: {
         type: type,
         data: data,
       },
     }));
   },
 
   _setUpPanel: function () {
+    // The new search UI only contains the "manage" engine entry in the panel
+    if (this.useNewUI) {
+      return;
+    }
+
     // Build the panel if necessary.
     if (this._newEngines) {
       this._buildPanel(this._newEngines);
       delete this._newEngines;
     }
 
     // Set the selected states of the engines.
     let panel = this._nodes.panel;
@@ -179,28 +191,30 @@ let gSearch = {
     box.appendChild(label);
 
     return box;
   },
 
   _setCurrentEngine: function (engine) {
     this.currentEngineName = engine.name;
 
-    // Set the logo.
-    let logoBuf = window.devicePixelRatio == 2 ? engine.logo2xBuffer :
-                  engine.logoBuffer || engine.logo2xBuffer;
-    if (logoBuf) {
-      this._nodes.logo.hidden = false;
-      let uri = URL.createObjectURL(new Blob([logoBuf]));
-      this._nodes.logo.style.backgroundImage = "url(" + uri + ")";
-      this._nodes.text.placeholder = "";
-    }
-    else {
-      this._nodes.logo.hidden = true;
-      this._nodes.text.placeholder = engine.name;
+    if (!this.useNewUI) {
+      // Set the logo.
+      let logoBuf = window.devicePixelRatio == 2 ? engine.logo2xBuffer :
+                    engine.logoBuffer || engine.logo2xBuffer;
+      if (logoBuf) {
+        this._nodes.logo.hidden = false;
+        let uri = URL.createObjectURL(new Blob([logoBuf]));
+        this._nodes.logo.style.backgroundImage = "url(" + uri + ")";
+        this._nodes.text.placeholder = "";
+      }
+      else {
+        this._nodes.logo.hidden = true;
+        this._nodes.text.placeholder = engine.name;
+      }
     }
 
     // Set up the suggestion controller.
     if (!this._suggestionController) {
       let parent = document.getElementById("newtab-scrollbox");
       this._suggestionController =
         new SearchSuggestionUIController(this._nodes.text, parent,
                                          () => this.search());
--- a/browser/base/content/test/newtab/browser_newtab_search.js
+++ b/browser/base/content/test/newtab/browser_newtab_search.js
@@ -101,47 +101,21 @@ function runTests() {
   yield checkCurrentEngine(ENGINE_1X_2X_LOGO, true, true);
 
   // Click the logo to open the search panel.
   yield Promise.all([
     promisePanelShown(panel),
     promiseClick(logoImg()),
   ]).then(TestRunner.next);
 
-  // In the search panel, click the no-logo engine.  It should become the
-  // current engine.
-  let noLogoBox = null;
-  for (let box of panel.childNodes) {
-    if (box.getAttribute("engine") == noLogoEngine.name) {
-      noLogoBox = box;
-      break;
-    }
-  }
-  ok(noLogoBox, "Search panel should contain the no-logo engine");
-  yield Promise.all([
-    promiseSearchEvents(["CurrentEngine"]),
-    promiseClick(noLogoBox),
-  ]).then(TestRunner.next);
-
-  yield checkCurrentEngine(ENGINE_NO_LOGO, false, false);
-
-  // Switch back to the 1x-and-2x logo engine.
-  Services.search.currentEngine = logo1x2xEngine;
-  yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
-  yield checkCurrentEngine(ENGINE_1X_2X_LOGO, true, true);
-
-  // Open the panel again.
-  yield Promise.all([
-    promisePanelShown(panel),
-    promiseClick(logoImg()),
-  ]).then(TestRunner.next);
-
-  // In the search panel, click the Manage Engines box.
   let manageBox = $("manage");
   ok(!!manageBox, "The Manage Engines box should be present in the document");
+  is(panel.childNodes.length, 1, "Search panel should only contain the Manage Engines entry");
+  is(panel.childNodes[0], manageBox, "Search panel should contain the Manage Engines entry");
+
   yield Promise.all([
     promiseManagerOpen(),
     promiseClick(manageBox),
   ]).then(TestRunner.next);
 
   // Add the engine that provides search suggestions and switch to it.
   let suggestionEngine = null;
   yield promiseNewSearchEngine(ENGINE_SUGGESTIONS, 0).then(engine => {
@@ -314,68 +288,17 @@ function checkCurrentEngine(basename, ha
   ok(engine.name.contains(basename),
      "Sanity check: current engine: engine.name=" + engine.name +
      " basename=" + basename);
 
   // gSearch.currentEngineName
   is(gSearch().currentEngineName, engine.name,
      "currentEngineName: " + engine.name);
 
-  // search bar logo
-  let logoURI = null;
-  if (window.devicePixelRatio == 2) {
-    if (has2xLogo) {
-      logoURI = engine.getIconURLBySize(...LOGO_2X_DPI_SIZE);
-      ok(!!logoURI, "Sanity check: engine should have 2x logo");
-    }
-  }
-  else {
-    if (has1xLogo) {
-      logoURI = engine.getIconURLBySize(...LOGO_1X_DPI_SIZE);
-      ok(!!logoURI, "Sanity check: engine should have 1x logo");
-    }
-    else if (has2xLogo) {
-      logoURI = engine.getIconURLBySize(...LOGO_2X_DPI_SIZE);
-      ok(!!logoURI, "Sanity check: engine should have 2x logo");
-    }
-  }
-  let logo = logoImg();
-  is(logo.hidden, !logoURI,
-     "Logo should be visible iff engine has a logo: " + engine.name);
-  if (logoURI) {
-    // The URLs of blobs created with the same ArrayBuffer are different, so
-    // just check that the URI is a blob URI.
-    ok(/^url\("blob:/.test(logo.style.backgroundImage), "Logo URI"); //"
-  }
-
-  if (logo.hidden) {
-    executeSoon(TestRunner.next);
-    return;
-  }
-
-  // "selected" attributes of engines in the panel
-  let panel = searchPanel();
-  promisePanelShown(panel).then(() => {
-    panel.hidePopup();
-    for (let engineBox of panel.childNodes) {
-      let engineName = engineBox.getAttribute("engine");
-      if (engineName == engine.name) {
-        is(engineBox.getAttribute("selected"), "true",
-           "Engine box's selected attribute should be true for " +
-           "selected engine: " + engineName);
-      }
-      else {
-        ok(!engineBox.hasAttribute("selected"),
-           "Engine box's selected attribute should be absent for " +
-           "non-selected engine: " + engineName);
-      }
-    }
-    TestRunner.next();
-  });
-  panel.openPopup(logo);
+  executeSoon(TestRunner.next);
 }
 
 function promisePanelShown(panel) {
   let deferred = Promise.defer();
   info("Waiting for popupshown");
   panel.addEventListener("popupshown", function onEvent() {
     panel.removeEventListener("popupshown", onEvent);
     is(panel.state, "open", "Panel state");
@@ -399,22 +322,24 @@ function promiseManagerOpen() {
   let deferred = Promise.defer();
   let winWatcher = Cc["@mozilla.org/embedcomp/window-watcher;1"].
                    getService(Ci.nsIWindowWatcher);
   winWatcher.registerNotification(function onWin(subj, topic, data) {
     if (topic == "domwindowopened" && subj instanceof Ci.nsIDOMWindow) {
       subj.addEventListener("load", function onLoad() {
         subj.removeEventListener("load", onLoad);
         if (subj.document.documentURI ==
-            "chrome://browser/content/search/engineManager.xul") {
+            "chrome://browser/content/preferences/preferences.xul") {
           winWatcher.unregisterNotification(onWin);
-          ok(true, "Observed search manager window opened");
+          ok(true, "Observed Preferences window opened");
           is(subj.opener, gWindow,
-             "Search engine manager opener should be the chrome browser " +
+             "Preferences window opener should be the chrome browser " +
              "window containing the newtab page");
+          is(subj.document.documentElement.currentPane.id, "paneSearch",
+             "Preferences window should be opened in the Search pane");
           executeSoon(() => {
             subj.close();
             deferred.resolve();
           });
         }
       });
     }
   });
--- a/browser/modules/ContentSearch.jsm
+++ b/browser/modules/ContentSearch.jsm
@@ -201,16 +201,22 @@ this.ContentSearch = {
 
   _onMessageSetCurrentEngine: function (msg, data) {
     Services.search.currentEngine = Services.search.getEngineByName(data);
     return Promise.resolve();
   },
 
   _onMessageManageEngines: function (msg, data) {
     let browserWin = msg.target.ownerDocument.defaultView;
+
+    if (Services.prefs.getBoolPref("browser.search.showOneOffButtons")) {
+      browserWin.openPreferences("paneSearch");
+      return Promise.resolve();
+    }
+
     let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].
              getService(Components.interfaces.nsIWindowMediator);
     let window = wm.getMostRecentWindow("Browser:SearchManager");
 
     if (window) {
       window.focus()
     }
     else {
--- a/browser/modules/test/browser_ContentSearch.js
+++ b/browser/modules/test/browser_ContentSearch.js
@@ -74,21 +74,23 @@ add_task(function* ManageEngines() {
   let deferred = Promise.defer();
   let winWatcher = Cc["@mozilla.org/embedcomp/window-watcher;1"].
                    getService(Ci.nsIWindowWatcher);
   winWatcher.registerNotification(function onOpen(subj, topic, data) {
     if (topic == "domwindowopened" && subj instanceof Ci.nsIDOMWindow) {
       subj.addEventListener("load", function onLoad() {
         subj.removeEventListener("load", onLoad);
         if (subj.document.documentURI ==
-            "chrome://browser/content/search/engineManager.xul") {
+            "chrome://browser/content/preferences/preferences.xul") {
           winWatcher.unregisterNotification(onOpen);
-          ok(true, "Observed search manager window open");
+          ok(true, "Observed Preferences window open");
           is(subj.opener, window,
-             "Search engine manager opener should be this chrome window");
+             "Preferences window opener should be this chrome window");
+          is(subj.document.documentElement.currentPane.id, "paneSearch",
+             "Preferences window should be opened in the Search pane");
           subj.close();
           deferred.resolve();
         }
       });
     }
   });
   info("Waiting for search engine manager window to open...");
   yield deferred.promise;