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 234099 d334f8d9129746203424293d20c2488e91f58ed3
parent 234098 4fb9368f8de1a1c1083765ba273587b4c1c82fb5
child 234100 eb8b2a6c5ea01628fceaacbebe7d90f738fdcef0
push id1
push usersledru@mozilla.com
push dateThu, 04 Dec 2014 17:57:20 +0000
reviewersMossop, gavin
bugs1101147
milestone35.0
Bug 1101147 - Update about:newtab search styling. r=Mossop 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
@@ -340,16 +340,29 @@ input[type=button] {
   border: 1px solid transparent;
   -moz-margin-end: 8px;
   background-repeat: no-repeat;
   background-position: center;
   background-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon);
   background-size: 26px 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[type="logo"] {
   background-size: 65px 26px;
   width: 77px; /* 65 image width + 6 left "padding" + 6 right "padding" */
 }
 
 #newtab-search-logo[type="favicon"] {
   background-size: 16px 16px;
 }
@@ -361,17 +374,17 @@ input[type=button] {
 #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,
@@ -385,17 +398,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,22 +3,33 @@
  * 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 () {
     let panel = this._nodes.panel;
     let logo = this._nodes.logo;
     panel.openPopup(logo);
@@ -115,16 +126,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;
@@ -191,38 +207,40 @@ let gSearch = {
     box.appendChild(label);
 
     return box;
   },
 
   _setCurrentEngine: function (engine) {
     this.currentEngineName = engine.name;
 
-    let type = "";
-    let uri;
-    let logoBuf = window.devicePixelRatio >= 2 ?
-                  engine.logo2xBuffer || engine.logoBuffer :
-                  engine.logoBuffer || engine.logo2xBuffer;
-    if (logoBuf) {
-      uri = URL.createObjectURL(new Blob([logoBuf]));
-      type = "logo";
-    }
-    else if (engine.iconBuffer) {
-      uri = this._getFaviconURIFromBuffer(engine.iconBuffer);
-      type = "favicon";
-    }
-    this._nodes.logo.setAttribute("type", type);
+    if (!this.useNewUI) {
+      let type = "";
+      let uri;
+      let logoBuf = window.devicePixelRatio >= 2 ?
+                    engine.logo2xBuffer || engine.logoBuffer :
+                    engine.logoBuffer || engine.logo2xBuffer;
+      if (logoBuf) {
+        uri = URL.createObjectURL(new Blob([logoBuf]));
+        type = "logo";
+      }
+      else if (engine.iconBuffer) {
+        uri = this._getFaviconURIFromBuffer(engine.iconBuffer);
+        type = "favicon";
+      }
+      this._nodes.logo.setAttribute("type", type);
 
-    if (uri) {
-      this._nodes.logo.style.backgroundImage = "url(" + uri + ")";
-      this._nodes.text.placeholder = "";
-    }
-    else {
-      this._nodes.logo.style.backgroundImage = "";
-      this._nodes.text.placeholder = engine.name;
+      if (uri) {
+        this._nodes.logo.style.backgroundImage = "url(" + uri + ")";
+        this._nodes.text.placeholder = "";
+      }
+      else {
+        this._nodes.logo.style.backgroundImage = "";
+        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
@@ -114,51 +114,22 @@ let runTaskifiedTests = Task.async(funct
   yield checkCurrentEngine(ENGINE_1X_2X_LOGO);
 
   // Click the logo to open the search panel.
   yield Promise.all([
     promisePanelShown(panel),
     promiseClick(logoImg()),
   ]);
 
-  // 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),
-  ]);
-
-  yield checkCurrentEngine(ENGINE_NO_LOGO);
-
-  // Switch back to the 1x-and-2x logo engine.
-  Services.search.currentEngine = logo1x2xEngine;
-  yield promiseSearchEvents(["CurrentEngine"]);
-  yield checkCurrentEngine(ENGINE_1X_2X_LOGO);
-
-  // Open the panel again.
-  yield Promise.all([
-    promisePanelShown(panel),
-    promiseClick(logoImg()),
-  ]);
-
-  // In the search panel, click the Manage Engines box.
   let manageBox = $("manage");
   ok(!!manageBox, "The Manage Engines box should be present in the document");
-  yield Promise.all([
-    promiseManagerOpen(),
-    promiseClick(manageBox),
-  ]);
+  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");
+
+  panel.hidePopup();
 
   // Add the engine that provides search suggestions and switch to it.
   let suggestionEngine = yield promiseNewSearchEngine(ENGINE_SUGGESTIONS);
   Services.search.currentEngine = suggestionEngine;
   yield promiseSearchEvents(["CurrentEngine"]);
   yield checkCurrentEngine(ENGINE_SUGGESTIONS);
 
   // Avoid intermittent failures.
@@ -335,52 +306,16 @@ let checkCurrentEngine = Task.async(func
   let engine = Services.search.currentEngine;
   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);
-
-  let expectedLogoPrefix = window.devicePixelRatio >= 2 ? logoPrefix2x : logoPrefix1x;
-
-  // Check that the right logo is set.
-  let logo = logoImg();
-  if (expectedLogoPrefix) {
-    let objectURL = logo.style.backgroundImage.match(/^url\("([^"]*)"\)$/)[1];
-    ok(objectURL, "ObjectURL should be there.");
-
-    let blob = yield objectURLToBlob(objectURL);
-    let base64 = yield blobToBase64(blob);
-
-    ok(base64.startsWith(expectedLogoPrefix), "Checking image prefix.");
-
-    let panel = searchPanel();
-    panel.openPopup(logo);
-    yield promisePanelShown(panel);
-
-    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);
-      }
-    }
-  }
-  else {
-    is(logo.style.backgroundImage, "", "backgroundImage should be empty");
-  }
 });
 
 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");
@@ -394,41 +329,16 @@ function promiseClick(node) {
   let win = getContentWindow();
   SimpleTest.waitForFocus(() => {
     EventUtils.synthesizeMouseAtCenter(node, {}, win);
     deferred.resolve();
   }, win);
   return deferred.promise;
 }
 
-function promiseManagerOpen() {
-  info("Waiting for the search manager window to open...");
-  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") {
-          winWatcher.unregisterNotification(onWin);
-          ok(true, "Observed search manager window opened");
-          is(subj.opener, gWindow,
-             "Search engine manager opener should be the chrome browser " +
-             "window containing the newtab page");
-          subj.close();
-          deferred.resolve();
-        }
-      });
-    }
-  });
-  return deferred.promise;
-}
-
 function searchPanel() {
   return $("panel");
 }
 
 function logoImg() {
   return $("logo");
 }
 
--- a/browser/modules/ContentSearch.jsm
+++ b/browser/modules/ContentSearch.jsm
@@ -214,16 +214,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
@@ -61,44 +61,16 @@ add_task(function* SetCurrentEngine() {
   Services.search.currentEngine = oldCurrentEngine;
   msg = yield waitForTestMsg("CurrentEngine");
   checkMsg(msg, {
     type: "CurrentEngine",
     data: yield currentEngineObj(oldCurrentEngine),
   });
 });
 
-add_task(function* ManageEngines() {
-  yield addTab();
-  gMsgMan.sendAsyncMessage(TEST_MSG, {
-    type: "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") {
-          winWatcher.unregisterNotification(onOpen);
-          ok(true, "Observed search manager window open");
-          is(subj.opener, window,
-             "Search engine manager opener should be this chrome window");
-          subj.close();
-          deferred.resolve();
-        }
-      });
-    }
-  });
-  info("Waiting for search engine manager window to open...");
-  yield deferred.promise;
-});
-
 add_task(function* modifyEngine() {
   yield addTab();
   let engine = Services.search.currentEngine;
   let oldAlias = engine.alias;
   engine.alias = "ContentSearchTest";
   let msg = yield waitForTestMsg("CurrentState");
   checkMsg(msg, {
     type: "CurrentState",