Bug 1427350 - Part 1 - Use "autocomplete-rich-result-popup" instead of "autocomplete-result-popup" for the search bar. r=mak draft
authorPaolo Amadini <paolo.mozmail@amadzone.org>
Tue, 30 Jan 2018 13:28:01 +0000
changeset 748796 1fe623a4ead5f4305a94c906b2ede0c27fbf0aa4
parent 748783 9746e0a0a81cc089ff65e30ae902864846cd1b94
child 748797 a99eab40e439aa2664320da5112e423cb53c1187
push id97239
push userpaolo.mozmail@amadzone.org
push dateTue, 30 Jan 2018 13:46:26 +0000
reviewersmak
bugs1427350
milestone60.0a1
Bug 1427350 - Part 1 - Use "autocomplete-rich-result-popup" instead of "autocomplete-result-popup" for the search bar. r=mak MozReview-Commit-ID: AO926Wmhkbm
browser/base/content/browser.xul
browser/components/search/content/search.xml
browser/components/search/test/browser_426329.js
browser/components/search/test/browser_private_search_perwindowpb.js
browser/modules/test/browser/browser_UsageTelemetry_searchbar.js
browser/themes/linux/browser.css
browser/themes/osx/browser.css
browser/themes/shared/autocomplete.inc.css
browser/themes/shared/searchbar.inc.css
browser/themes/shared/urlbar-autocomplete.inc.css
browser/themes/windows/browser.css
toolkit/components/places/nsTaggingService.js
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -138,17 +138,20 @@
            id="PopupAutoComplete"
            noautofocus="true"
            hidden="true"
            overflowpadding="4"
            norolluponanchor="true"
            nomaxresults="true" />
 
     <!-- for search with one-off buttons -->
-    <panel type="autocomplete" id="PopupSearchAutoComplete" noautofocus="true" hidden="true"/>
+    <panel type="autocomplete-richlistbox"
+           id="PopupSearchAutoComplete"
+           noautofocus="true"
+           hidden="true" />
 
     <!-- for url bar autocomplete -->
     <panel type="autocomplete-richlistbox"
            id="PopupAutoCompleteRichResult"
            noautofocus="true"
            hidden="true"
            flip="none"
            level="parent"
--- a/browser/components/search/content/search.xml
+++ b/browser/components/search/content/search.xml
@@ -737,33 +737,36 @@
             popup.hidden = false;
 
             // Don't roll up on mouse click in the anchor for the search UI.
             if (popup.id == "PopupSearchAutoComplete") {
               popup.setAttribute("norolluponanchor", "true");
             }
 
             popup.mInput = this;
-            popup.view = this.controller.QueryInterface(Ci.nsITreeView);
-            popup.invalidate();
+            // clear any previous selection, see bugs 400671 and 488357
+            popup.selectedIndex = -1;
 
             popup.showCommentColumn = this.showCommentColumn;
             popup.showImageColumn = this.showImageColumn;
 
             document.popupNode = null;
 
             const isRTL = getComputedStyle(this, "").direction == "rtl";
 
             var outerRect = this.getBoundingClientRect();
             var innerRect = this.inputField.getBoundingClientRect();
             let width = isRTL ?
                         innerRect.right - outerRect.left :
                         outerRect.right - innerRect.left;
             popup.setAttribute("width", width > 100 ? width : 100);
 
+            // invalidate() depends on the width attribute
+            popup._invalidate();
+
             var yOffset = outerRect.bottom - innerRect.bottom;
             popup.openPopup(this.inputField, "after_start", 0, yOffset, false, false);
           }
         ]]></body>
       </method>
 
       <method name="openSearch">
         <body>
@@ -834,18 +837,18 @@
             return;
 
           // accel + up/down changes the default engine and shouldn't affect
           // the selection on the one-off buttons.
           if (aEvent.getModifierState("Accel"))
             return;
 
           let suggestionsHidden =
-            popup.tree.getAttribute("collapsed") == "true";
-          let numItems = suggestionsHidden ? 0 : this.popup.view.rowCount;
+            popup.richlistbox.getAttribute("collapsed") == "true";
+          let numItems = suggestionsHidden ? 0 : this.popup._matchCount;
           this.popup.oneOffButtons.handleKeyPress(aEvent, numItems, true);
         ]]></body>
       </method>
 
       <!-- nsIController -->
       <field name="searchbarController" readonly="true"><![CDATA[({
         _self: this,
         supportsCommand(aCommand) {
@@ -922,36 +925,29 @@
           document.getBindingParent(this).openSuggestionsPanel();
         }
       ]]>
       </handler>
 
     </handlers>
   </binding>
 
-  <binding id="browser-search-autocomplete-result-popup" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete-result-popup">
+  <binding id="browser-search-autocomplete-result-popup" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete-rich-result-popup">
     <resources>
       <stylesheet src="chrome://browser/content/search/searchbarBindings.css"/>
       <stylesheet src="chrome://browser/skin/searchbar.css"/>
     </resources>
     <content ignorekeys="true" level="top" consumeoutsideclicks="never">
       <xul:hbox anonid="searchbar-engine" xbl:inherits="showonlysettings"
                 class="search-panel-header search-panel-current-engine">
         <xul:image class="searchbar-engine-image" xbl:inherits="src"/>
         <xul:label anonid="searchbar-engine-name" flex="1" crop="end"
                    role="presentation"/>
       </xul:hbox>
-      <xul:tree anonid="tree" flex="1"
-                class="autocomplete-tree plain search-panel-tree"
-                hidecolumnpicker="true" seltype="single">
-        <xul:treecols anonid="treecols">
-          <xul:treecol id="treecolAutoCompleteValue" class="autocomplete-treecol" flex="1" overflow="true"/>
-        </xul:treecols>
-        <xul:treechildren class="autocomplete-treebody searchbar-treebody" noSelectOnMouseMove="true"/>
-      </xul:tree>
+      <xul:richlistbox anonid="richlistbox" class="autocomplete-richlistbox search-panel-tree" flex="1"/>
       <xul:vbox anonid="search-one-off-buttons" class="search-one-offs"/>
     </content>
     <implementation>
       <method name="openAutocompletePopup">
         <parameter name="aInput"/>
         <parameter name="aElement"/>
         <body><![CDATA[
           // initially the panel is hidden
@@ -971,17 +967,17 @@
             return;
 
           var controller = this.view.QueryInterface(Components.interfaces.nsIAutoCompleteController);
 
           var searchBar = BrowserSearch.searchBar;
           var popupForSearchBar = searchBar && searchBar.textbox == this.mInput;
           if (popupForSearchBar) {
             searchBar.telemetrySearchDetails = {
-              index: controller.selection.currentIndex,
+              index: this.selectedIndex,
               kind: "mouse"
             };
           }
 
           // Check for unmodified left-click, and use default behavior
           if (aEvent.button == 0 && !aEvent.shiftKey && !aEvent.ctrlKey &&
               !aEvent.altKey && !aEvent.metaKey) {
             controller.handleEnter(true, aEvent);
@@ -1109,24 +1105,24 @@
         // glass icon has been clicked if the text field is empty.
         let searchbar = document.getElementById("searchbar");
         if (searchbar.hasAttribute("showonlysettings")) {
           searchbar.removeAttribute("showonlysettings");
           this.setAttribute("showonlysettings", "true");
 
           // Setting this with an xbl-inherited attribute gets overridden the
           // second time the user clicks the glass icon for some reason...
-          this.tree.collapsed = true;
+          this.richlistbox.collapsed = true;
         } else {
           this.removeAttribute("showonlysettings");
-          // Uncollapse as long as we have a tree with a view which has >= 1 row.
+          // Uncollapse as long as we have a view which has >= 1 row.
           // The autocomplete binding itself will take care of uncollapsing later,
           // if we currently have no rows but end up having some in the future
           // when the search string changes
-          this.tree.collapsed = !this.tree.view || !this.tree.view.rowCount;
+          this.richlistbox.collapsed = (this._matchCount == 0);
         }
 
         // Show the current default engine in the top header of the panel.
         this.updateHeader();
       ]]></handler>
 
       <handler event="popuphiding"><![CDATA[
         this._isHiding = true;
--- a/browser/components/search/test/browser_426329.js
+++ b/browser/components/search/test/browser_426329.js
@@ -28,26 +28,20 @@ function simulateClick(aEvent, aTarget) 
 function checkMenuEntries(expectedValues) {
   var actualValues = getMenuEntries();
   is(actualValues.length, expectedValues.length, "Checking length of expected menu");
   for (var i = 0; i < expectedValues.length; i++)
     is(actualValues[i], expectedValues[i], "Checking menu entry #" + i);
 }
 
 function getMenuEntries() {
-  var entries = [];
-  var autocompleteMenu = searchBar.textbox.popup;
   // Could perhaps pull values directly from the controller, but it seems
-  // more reliable to test the values that are actually in the tree?
-  var column = autocompleteMenu.tree.columns[0];
-  var numRows = autocompleteMenu.tree.view.rowCount;
-  for (var i = 0; i < numRows; i++) {
-    entries.push(autocompleteMenu.tree.view.getValueAt(i, column));
-  }
-  return entries;
+  // more reliable to test the values that are actually in the richlistbox?
+  return Array.map(searchBar.textbox.popup.richlistbox.children,
+                   item => item.getAttribute("ac-value"));
 }
 
 function countEntries(name, value) {
   return new Promise(resolve => {
     let count = 0;
     let obj = name && value ? {fieldname: name, value} : {};
     FormHistory.count(obj,
                       { handleResult(result) { count = result; },
--- a/browser/components/search/test/browser_private_search_perwindowpb.js
+++ b/browser/components/search/test/browser_private_search_perwindowpb.js
@@ -58,19 +58,13 @@ add_task(async function() {
   searchBar.value = "";
 
   windowsToClose.forEach(function(win) {
     win.close();
   });
 });
 
 function getMenuEntries(searchBar) {
-  let entries = [];
-  let autocompleteMenu = searchBar.textbox.popup;
   // Could perhaps pull values directly from the controller, but it seems
-  // more reliable to test the values that are actually in the tree?
-  let column = autocompleteMenu.tree.columns[0];
-  let numRows = autocompleteMenu.tree.view.rowCount;
-  for (let i = 0; i < numRows; i++) {
-    entries.push(autocompleteMenu.tree.view.getValueAt(i, column));
-  }
-  return entries;
+  // more reliable to test the values that are actually in the richlistbox?
+  return Array.map(searchBar.textbox.popup.richlistbox.children,
+                   item => item.getAttribute("ac-value"));
 }
--- a/browser/modules/test/browser/browser_UsageTelemetry_searchbar.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry_searchbar.js
@@ -35,37 +35,23 @@ let searchInSearchbar = async function(i
 
 /**
  * Click one of the entries in the search suggestion popup.
  *
  * @param {String} entryName
  *        The name of the elemet to click on.
  */
 function clickSearchbarSuggestion(entryName) {
-  let popup = BrowserSearch.searchBar.textbox.popup;
-  let column = popup.tree.columns[0];
-
-  for (let rowID = 0; rowID < popup.tree.view.rowCount; rowID++) {
-    const suggestion = popup.tree.view.getValueAt(rowID, column);
-    if (suggestion !== entryName) {
-      continue;
-    }
+  let richlistbox = BrowserSearch.searchBar.textbox.popup.richlistbox;
+  let richlistitem = Array.prototype.find.call(richlistbox.children,
+                     item => item.getAttribute("ac-value") == entryName);
 
-    // Make sure the suggestion is visible, just in case.
-    let tbo = popup.tree.treeBoxObject;
-    tbo.ensureRowIsVisible(rowID);
-    // Calculate the click coordinates.
-    let rect = tbo.getCoordsForCellItem(rowID, column, "text");
-    let x = rect.x + rect.width / 2;
-    let y = rect.y + rect.height / 2;
-    // Simulate the click.
-    EventUtils.synthesizeMouse(popup.tree.body, x, y, {},
-                               popup.tree.ownerGlobal);
-    break;
-  }
+  // Make sure the suggestion is visible and simulate the click.
+  richlistbox.ensureElementIsVisible(richlistitem);
+  EventUtils.synthesizeMouseAtCenter(richlistitem, {});
 }
 
 add_task(async function setup() {
   await SpecialPowers.pushPrefEnv({ set: [
     ["browser.search.widget.inNavBar", true],
   ]});
 
   // Create two new search engines. Mark one as the default engine, so
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -454,30 +454,16 @@ html|span.ac-emphasize-text-url {
   fill: #b2b2b2;
 }
 
 .ac-type-icon[type=switchtab][selected],
 .ac-type-icon[type=remotetab][selected] {
   fill: white;
 }
 
-.autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
-  color: GrayText;
-}
-
-.autocomplete-treebody::-moz-tree-cell-text(suggesthint, treecolAutoCompleteComment),
-.autocomplete-treebody::-moz-tree-cell-text(suggestfirst, treecolAutoCompleteComment) {
-  color: GrayText;
-  font-size: smaller;
-}
-
-.autocomplete-treebody::-moz-tree-cell(suggesthint) {
-  border-top: 1px solid GrayText;
-}
-
 /* Bookmarking panel */
 #editBookmarkPanelStarIcon {
   list-style-image: url("chrome://browser/skin/places/starred48.png");
   width: 48px;
   height: 48px;
 }
 
 #editBookmarkPanelTitle {
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -414,31 +414,16 @@ html|span.ac-emphasize-text-url {
   fill: #b2b2b2;
 }
 
 .ac-type-icon[type=switchtab][selected],
 .ac-type-icon[type=remotetab][selected] {
   fill: white;
 }
 
-.autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
-  color: GrayText;
-}
-
-.autocomplete-treebody::-moz-tree-cell-text(suggesthint, treecolAutoCompleteComment),
-.autocomplete-treebody::-moz-tree-cell-text(suggestfirst, treecolAutoCompleteComment)
-{
-  color: GrayText;
-  font-size: smaller;
-}
-
-.autocomplete-treebody::-moz-tree-cell(suggesthint) {
-  border-top: 1px solid GrayText;
-}
-
 #BMB_bookmarksPopup[side="top"],
 #BMB_bookmarksPopup[side="bottom"] {
   margin-left: -26px;
   margin-right: -26px;
 }
 
 #BMB_bookmarksPopup[side="left"],
 #BMB_bookmarksPopup[side="right"] {
--- a/browser/themes/shared/autocomplete.inc.css
+++ b/browser/themes/shared/autocomplete.inc.css
@@ -25,23 +25,21 @@
 }
 
 #PopupAutoComplete > richlistbox {
   padding: 0;
 }
 
 /* Popup states */
 
-.autocomplete-richlistitem:hover,
-treechildren.searchbar-treebody::-moz-tree-row(hover) {
+.autocomplete-richlistitem:hover {
   background-color: var(--arrowpanel-dimmed);
 }
 
-.autocomplete-richlistitem[selected],
-treechildren.searchbar-treebody::-moz-tree-row(selected) {
+.autocomplete-richlistitem[selected] {
   background-color: Highlight;
   color: HighlightText;
 }
 
 /* Login form autocompletion */
 #PopupAutoComplete > richlistbox > richlistitem[originaltype="login"] > .ac-site-icon {
   display: initial;
   list-style-image: url(chrome://browser/skin/notification-icons/login.svg);
--- a/browser/themes/shared/searchbar.inc.css
+++ b/browser/themes/shared/searchbar.inc.css
@@ -193,37 +193,41 @@
 }
 
 .addengine-item[type=menu] > .toolbarbutton-menu-dropmarker {
   display: -moz-box;
   -moz-appearance: menuarrow !important;
   list-style-image: none;
 }
 
-.search-panel-tree > .autocomplete-treebody::-moz-tree-cell {
-  border-top: none !important;
+.search-panel-tree > .autocomplete-richlistitem {
+  padding: 1px;
 }
 
-.search-panel-tree > .autocomplete-treebody::-moz-tree-image {
-  padding-inline-start: 2px;
-  padding-inline-end: 2px;
+.search-panel-tree > .autocomplete-richlistitem > .ac-type-icon {
   width: 14px;
   height: 14px;
 }
 
-.search-panel-tree > .autocomplete-treebody::-moz-tree-image(fromhistory) {
+.search-panel-tree > .autocomplete-richlistitem[originaltype="fromhistory"] > .ac-type-icon {
   list-style-image: url("chrome://browser/skin/history.svg");
   -moz-context-properties: fill;
   fill: graytext;
 }
 
-.search-panel-tree > .autocomplete-treebody::-moz-tree-image(fromhistory, selected) {
+.search-panel-tree > .autocomplete-richlistitem[originaltype="fromhistory"][selected] > .ac-type-icon {
   fill: HighlightText;
 }
 
+.search-panel-tree > .autocomplete-richlistitem > .ac-site-icon,
+.search-panel-tree > .autocomplete-richlistitem > .ac-separator,
+.search-panel-tree > .autocomplete-richlistitem > .ac-url {
+  display: none;
+}
+
 .search-setting-button {
   -moz-appearance: none;
   margin: 0;
   min-height: 32px;
 }
 
 .search-setting-button:hover,
 .search-setting-button[selected] {
--- a/browser/themes/shared/urlbar-autocomplete.inc.css
+++ b/browser/themes/shared/urlbar-autocomplete.inc.css
@@ -1,18 +1,14 @@
 %if 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
 
-#treecolAutoCompleteImage {
-  max-width: 36px;
-}
-
 #PopupAutoCompleteRichResult .autocomplete-richlistbox {
   padding: 4px 3px;
 }
 
 #PopupAutoCompleteRichResult .autocomplete-richlistitem {
   min-height: 30px;
   font: message-box;
   border-radius: 2px;
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -702,31 +702,16 @@ html|span.ac-emphasize-text-url {
   fill: #b2b2b2;
 }
 
 .ac-type-icon[type=switchtab][selected],
 .ac-type-icon[type=remotetab][selected] {
   fill: white;
 }
 
-.autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
-  color: GrayText;
-}
-
-.autocomplete-treebody::-moz-tree-cell-text(suggesthint, treecolAutoCompleteComment),
-.autocomplete-treebody::-moz-tree-cell-text(suggestfirst, treecolAutoCompleteComment)
-{
-  color: GrayText;
-  font-size: smaller;
-}
-
-.autocomplete-treebody::-moz-tree-cell(suggesthint) {
-  border-top: 1px solid GrayText;
-}
-
 /* bookmarking panel */
 
 #editBookmarkPanelStarIcon {
   list-style-image: url("chrome://browser/skin/places/starred48.png");
   width: 48px;
   height: 48px;
 }
 
--- a/toolkit/components/places/nsTaggingService.js
+++ b/toolkit/components/places/nsTaggingService.js
@@ -536,23 +536,17 @@ TagAutoCompleteResult.prototype = {
   getCommentAt: function PTACR_getCommentAt(index) {
     return this._comments[index];
   },
 
   /**
    * Get the style hint for the result at the given index
    */
   getStyleAt: function PTACR_getStyleAt(index) {
-    if (!this._comments[index])
-      return null; // not a category label, so no special styling
-
-    if (index == 0)
-      return "suggestfirst"; // category label on first line of results
-
-    return "suggesthint"; // category label on any other line of results
+    return null;
   },
 
   /**
    * Get the image for the result at the given index
    */
   getImageAt: function PTACR_getImageAt(index) {
     return null;
   },