Bug 605601 - when there are no (or few) awesomeresults, add search providers to list [r=mfinkle]
authorWesley Johnston <wjohnston@mozilla.com>
Wed, 03 Nov 2010 11:41:00 -0400
changeset 66950 59f8f569569c2f40cdbbae79bb61a3cf01ff0ad6
parent 66949 14e31eaaae662bcdf78dec9e90c44d9475b459c1
child 66951 2ec868f7ee8949b8ba6581e9b5aa50ec74d59e5f
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs605601
Bug 605601 - when there are no (or few) awesomeresults, add search providers to list [r=mfinkle]
mobile/app/mobile.js
mobile/chrome/content/bindings.xml
mobile/components/AutoCompleteCache.js
mobile/locales/en-US/chrome/browser.properties
mobile/themes/core/browser.css
--- a/mobile/app/mobile.js
+++ b/mobile/app/mobile.js
@@ -256,16 +256,17 @@ pref("browser.urlbar.filter.javascript",
 pref("browser.urlbar.maxRichResults", 24); // increased so we see more results when portrait
 pref("browser.urlbar.search.chunkSize", 1000);
 pref("browser.urlbar.search.timeout", 100);
 pref("browser.urlbar.restrict.history", "^");
 pref("browser.urlbar.restrict.bookmark", "*");
 pref("browser.urlbar.restrict.tag", "+");
 pref("browser.urlbar.match.title", "#");
 pref("browser.urlbar.match.url", "@");
+pref("browser.urlbar.autocomplete.search_threshold", 5);
 pref("browser.history.grouping", "day");
 pref("browser.history.showSessions", false);
 pref("browser.sessionhistory.max_entries", 50);
 pref("browser.history_expire_days", 180);
 pref("browser.history_expire_days_min", 90);
 pref("browser.history_expire_sites", 40000);
 pref("privacy.item.history", true);
 pref("browser.places.migratePostDataAnnotations", true);
--- a/mobile/chrome/content/bindings.xml
+++ b/mobile/chrome/content/bindings.xml
@@ -141,21 +141,21 @@
               linkURL: url
             }
           };
           ContextHelper.showPopup(data);
         ]]>
       </handler>
     </handlers>
     <content orient="vertical">
-      <xul:hbox class="autocomplete-item-container" align="top" xbl:inherits="favorite,remote" mousethrough="always">
+      <xul:hbox class="autocomplete-item-container" align="top" xbl:inherits="favorite,remote,search" mousethrough="always">
         <xul:image xbl:inherits="src"/>
         <xul:vbox flex="1">
           <xul:label class="autocomplete-item-label" crop="center" xbl:inherits="value"/>
-          <xul:label class="autocomplete-item-url" xbl:inherits="value=url" crop="center"/>
+          <xul:label class="autocomplete-item-subtitle" xbl:inherits="value=subtitle" crop="center"/>
         </xul:vbox>
         <xul:vbox align="end">
           <xul:label class="autocomplete-item-tags" value="" xbl:inherits="value=tags"/>
           <xul:label class="autocomplete-item-badge" value="" xbl:inherits="value=badge"/>
         </xul:vbox>
       </xul:hbox>
     </content>
   </binding>
@@ -309,16 +309,19 @@
           let items = this._items;
 
           // Need to iterate over all our existing entries at a minimum, to make
           // sure they're either updated or cleared out. We might also have to
           // add extra items.
           let matchCount = this._matchCount;
           let children = items.childNodes;
           let iterCount = Math.max(children.length, matchCount);
+
+          let searchSubtitle = Elements.browserBundle.stringBundle.formatStringFromName("opensearch.searchFor", [searchString], 1);
+
           for (let i = 0; i < iterCount; ++i) {
             let item = children.item(i);
 
             // Create an item if needed
             if (!item) {
               item = document.createElementNS(this._XULNS, "xul:autocompleteresult");
               items.appendChild(item);
             }
@@ -348,23 +351,30 @@
             item.setAttribute("tags", tags);
 
             let url = controller.getValueAt(i);
             item.setAttribute("value", title || url);
 
             // remove the badge only if the url has changed
             if (item._empty || item.getAttribute("url") != url) {
               item.setAttribute("url", url);
+              item.setAttribute("subtitle", url);
               item.removeAttribute("badge");
               item.removeAttribute("remote");
+              item.removeAttribute("search");
             }
 
             let isBookmark = ((type == "bookmark") || (type == "tag"));
             item.setAttribute("favorite", isBookmark);
             item.setAttribute("src", controller.getImageAt(i));
+            
+            if (type=="search") {
+              item.setAttribute("search", true);
+              item.setAttribute("subtitle", searchSubtitle);
+            }
 
             item._empty = false;
           }
 
           // Show the "no results" or "all bookmarks" entries as needed
           this._updateNoResultsItem(matchCount);
 
           // Make sure the list is scrolled to the top
@@ -383,16 +393,18 @@
             noResultsItem.className = "noresults";
             noResultsItem.setAttribute("value", "]]>&noResults.label;<![CDATA[");
             noResultsItem.removeAttribute("favorite");
             noResultsItem.removeAttribute("url");
             noResultsItem.removeAttribute("src");
             noResultsItem.removeAttribute("tags");
             noResultsItem.removeAttribute("badge");
             noResultsItem.removeAttribute("remote");
+            noResultsItem.removeAttribute("search");
+            noResultsItem.removeAttribute("subtitle");
           }
         ]]></body>
       </method>
 
       <method name="selectBy">
         <parameter name="aReverse"/>
         <parameter name="aPage"/>
         <body><![CDATA[
--- a/mobile/components/AutoCompleteCache.js
+++ b/mobile/components/AutoCompleteCache.js
@@ -50,16 +50,19 @@ const MODE_WRONLY   = 0x02;
 const MODE_CREATE   = 0x08;
 const MODE_APPEND   = 0x10;
 const MODE_TRUNCATE = 0x20;
 
 // Current cache version. This should be incremented if the format of the cache
 // file is modified.
 const CACHE_VERSION = 1;
 
+const RESULT_CACHE = 1;
+const RESULT_NEW = 2;
+
 // Lazily get the base Places AutoComplete Search
 XPCOMUtils.defineLazyGetter(this, "PACS", function() {
   return Components.classesByID["{d0272978-beab-4adc-a3d4-04b76acfa4e7}"]
                    .getService(Ci.nsIAutoCompleteSearch);
 });
 
 // Gets a directory from the directory service
 function getDir(aKey) {
@@ -85,17 +88,17 @@ var AutoCompleteUtils = {
     this.stop();
 
     // Flag that we're busy using the base places autocomplete search
     this.busy = true;
     PACS.startSearch(query, "", null, {
       onSearchResult: function(search, result) {
         // Let the listener know about the result right away
         if (typeof onResult == "function")
-          onResult(result);
+          onResult(result, RESULT_NEW);
 
         // Don't do any more processing if we're not completely done
         if (result.searchResult == result.RESULT_NOMATCH_ONGOING ||
             result.searchResult == result.RESULT_SUCCESS_ONGOING)
           return;
 
         // We must be done, so cache the results
         if (AutoCompleteUtils.query == query)
@@ -230,28 +233,50 @@ function AutoCompleteCache() {
   Services.obs.addObserver(this, "browser:purge-session-history", true);
 }
 
 AutoCompleteCache.prototype = {
   classID: Components.ID("{a65f9dca-62ab-4b36-a870-972927c78b56}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteSearch, Ci.nsIObserver, Ci.nsISupportsWeakReference]),
 
+  get _searchThreshold() {
+    delete this._searchCount;
+    return this._searchCount = Services.prefs.getIntPref("browser.urlbar.autocomplete.search_threshold");    
+  },
+
   startSearch: function(query, param, prev, listener) {
     let self = this;
-    let done = function(result) {
+    let done = function(result, aType) {
+      let showSearch = (result.matchCount < self._searchThreshold) && (aType == RESULT_NEW);
+
+      if (showSearch && (result.searchResult == Ci.nsIAutoCompleteResult.RESULT_SUCCESS ||
+                         result.searchResult == Ci.nsIAutoCompleteResult.RESULT_NOMATCH)) {
+        let engines = Services.search.getVisibleEngines();
+        try {
+          result.QueryInterface(Ci.nsIAutoCompleteSimpleResult);
+          if (engines.length > 0) {  
+            for (let i = 0; i < engines.length; i++) {
+              let url = engines[i].getSubmission(query).uri.spec;
+              result.appendMatch(url, engines[i].name, engines[i].iconURI.spec, "search");
+            }
+            result.setSearchResult(Ci.nsIAutoCompleteResult.RESULT_SUCCESS);
+          }
+        } catch(ex) {
+        }
+      }
       listener.onSearchResult(self, result);
     };
 
     // Strip out leading/trailing spaces
     query = query.trim();
 
     if (AutoCompleteUtils.query == query && AutoCompleteUtils.cache) {
       // On a cache-hit, give the results right away and fetch in the background
-      done(AutoCompleteUtils.cache);
+      done(AutoCompleteUtils.cache, RESULT_CACHE);
     } else {
       // Otherwise, fetch the result, cache it, and pass it on
       AutoCompleteUtils.fetch(query, done);
     }
 
     // Keep the cache warm
     AutoCompleteUtils.update();
   },
--- a/mobile/locales/en-US/chrome/browser.properties
+++ b/mobile/locales/en-US/chrome/browser.properties
@@ -184,16 +184,17 @@ homepage.custom2=Custom Page
 pageactions.saveas.pdf=Save As PDF
 pageactions.geo=Location
 pageactions.popup=Popups
 pageactions.offline-app=Offline Storage
 pageactions.password=Password
 
 # Open Search
 opensearch.searchWith=Search With:
+opensearch.searchFor=Search for "%S"
 
 # Mobile Sync
 # LOCALIZATION NOTE (sync.clientUpdate, sync.remoteUpdate):
 # #1 is the "application name"
 # #2 is the "version"
 sync.update.client=#1 #2 is not compatible with the latest version of Firefox Sync. Please update to the latest version.
 sync.update.remote=#1 #2 is not compatible with older versions of Firefox Sync. Please update Firefox on your other computer(s).
 sync.update.title=Firefox Sync
--- a/mobile/themes/core/browser.css
+++ b/mobile/themes/core/browser.css
@@ -677,57 +677,70 @@ placeitem[src=""] .bookmark-item-contain
   list-style-image: url(chrome://mozapps/skin/places/defaultFavicon.png);
 }
 
 .autocomplete-item-container > vbox > label,
 .bookmark-item-container > vbox > label {
   -moz-margin-start: 1px;
 }
 
-.autocomplete-item-container[favorite="true"] {
-  background: url(images/autocomplete-bookmarked-hdpi.png) no-repeat 100% 2px;
+.autocomplete-item-container[favorite="true"],
+.autocomplete-item-container[remote="true"],
+.autocomplete-item-container[search="true"] {
+  background-repeat: no-repeat;
+  background-position: 100% 2px;
   background-size: 24px 24px;
 }
 
+.autocomplete-item-container[favorite="true"] {
+  background-image: url("chrome://browser/skin/images/autocomplete-bookmarked-hdpi.png");
+}
+
 .autocomplete-item-container[remote="true"] {
-  background: url(images/autocomplete-desktop-hdpi.png) no-repeat 100% 2px;
-  background-size: 24px 24px;
+  background-image: url("chrome://browser/skin/images/autocomplete-desktop-hdpi.png");
+}
+
+.autocomplete-item-container[search="true"] {
+  background-image: url("chrome://browser/skin/images/search-glass-30.png");
 }
 
 .autocomplete-item-container[favorite="true"][remote="true"] {
-  background: url(images/autocomplete-bookmarked-hdpi.png) no-repeat 100% 2px, url(images/autocomplete-desktop-hdpi.png) no-repeat 94% 2px;
-  background-size: 24px 24px;
+  background-image: url("chrome://browser/skin/images/autocomplete-bookmarked-hdpi.png"),
+                    url("chrome://browser/skin/images/autocomplete-desktop-hdpi.png");
+  background-position: 100% 2px,
+                        94% 2px;
+  -moz-padding-end: 48px;
 }
 
-.autocomplete-item-container[favorite="true"]:-moz-locale-dir(rtl) {
-  background: url(images/autocomplete-bookmarked-hdpi.png) no-repeat left 2px;
-}
-
+.autocomplete-item-container[favorite="true"]:-moz-locale-dir(rtl),
 .autocomplete-item-container[remote="true"]:-moz-locale-dir(rtl) {
-  background: url(images/autocomplete-desktop-hdpi.png) no-repeat left 2px;
+  background-position: left 2px;
 }
 
 .autocomplete-item-container[favorite="true"][remote="true"]:-moz-locale-dir(rtl) {
-  background: url(images/autocomplete-bookmarked-hdpi.png) no-repeat left 2px, url(images/autocomplete-desktop-hdpi.png) no-repeat 6% 2px;
+  background-position: left 2px,
+                         6% 2px;
 }
 
-.autocomplete-item-url,
+.autocomplete-item-subtitle,
 .bookmark-item-url {
   color: blue;
   font-size: 18px !important;
   -moz-margin-end: 24px;
 }
 
 .autocomplete-item-container[favorite="true"] .autocomplete-item-label,
-.autocomplete-item-container[remote="true"] .autocomplete-item-label {
+.autocomplete-item-container[remote="true"] .autocomplete-item-label,
+.autocomplete-item-container[search="true"] .autocomplete-item-label {
   -moz-padding-end: 30px;
 }
 
-.autocomplete-item-container[favorite="true"][remote="true"] {
-  -moz-padding-end: 48px;
+.autocomplete-item-container[search="true"] .autocomplete-item-subtitle {
+  color: black;
+  font-size: smaller;
 }
 
 .autocomplete-item-tags,
 .bookmark-item-tags {
   content: attr(tags);
   font-size: 18px !important;
   font-weight: lighter;
   margin: 2px 0 4px 0;