Bug 1088660 - Improve the search bar UI to support one-off searches - improve discoverability of the search settings, r=felipe.

This commit is contained in:
Florian Quèze 2014-11-20 20:55:41 +01:00
parent 94833decfe
commit 13f2d62f6d
25 changed files with 344 additions and 63 deletions

View File

@ -3304,13 +3304,6 @@ const BrowserSearch = {
return;
}
// Append the URI and an appropriate title to the browser data.
// Use documentURIObject in the check for shouldLoadFavIcon so that we
// do the right thing with about:-style error pages. Bug 453442
var iconURL = null;
if (gBrowser.shouldLoadFavIcon(uri))
iconURL = uri.prePath + "/favicon.ico";
var hidden = false;
// If this engine (identified by title) is already in the list, add it
// to the list of hidden engines rather than to the main list.
@ -3323,7 +3316,8 @@ const BrowserSearch = {
engines.push({ uri: engine.href,
title: engine.title,
icon: iconURL });
get icon() { return browser.mIconURL; }
});
if (hidden)
browser.hiddenEngines = engines;
@ -7821,4 +7815,3 @@ let PanicButtonNotifier = {
popup.hidePopup();
},
};

View File

@ -957,30 +957,58 @@
<stylesheet src="chrome://browser/skin/searchbar.css"/>
</resources>
<content ignorekeys="true" level="top" consumeoutsideclicks="false">
<xul:hbox class="search-panel-header search-panel-current-engine">
<xul:hbox xbl:inherits="collapsed=showonlysettings"
class="search-panel-header search-panel-current-engine">
<xul:image class="searchbar-engine-image" xbl:inherits="src"/>
<xul:label anonid="searchbar-engine-name"/>
</xul:hbox>
<xul:tree anonid="tree" class="autocomplete-tree plain search-panel-tree" hidecolumnpicker="true" flex="1" seltype="single">
<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"/>
</xul:tree>
<xul:hbox anonid="search-panel-one-offs-header"
class="search-panel-header search-panel-current-input">
class="search-panel-header search-panel-current-input"
xbl:inherits="hidden=showonlysettings">
<xul:label anonid="searchbar-oneoffheader-before" value="Search for "/>
<xul:label anonid="searchbar-oneoffheader-searchtext" flex="1" crop="end" class="search-panel-input-value"/>
<xul:label anonid="searchbar-oneoffheader-after" flex="10000" value=" on:"/>
<xul:label anonid="searchbar-oneoffheader-after" flex="10000" value=" with:"/>
</xul:hbox>
<xul:description anonid="search-panel-one-offs" class="search-panel-one-offs"/>
<xul:description anonid="search-panel-one-offs"
class="search-panel-one-offs"
xbl:inherits="hidden=showonlysettings"/>
<xul:vbox anonid="add-engines"/>
<xul:button anonid="search-settings"
xbl:inherits="showonlysettings"
oncommand="openPreferences('paneSearch')"
class="search-setting-button search-panel-header"
label="Change Search Settings"/>
</content>
<handlers>
<handler event="popupshowing"><![CDATA[
// First handle deciding if we are showing the reduced version of the
// popup containing only the preferences button. We do this if the
// glass icon has been clicked if the text field is empty.
let searchbar = document.getElementById("searchbar");
let tree = document.getAnonymousElementByAttribute(this, "anonid",
"tree")
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...
tree.collapsed = true;
}
else {
this.removeAttribute("showonlysettings");
tree.collapsed = false;
}
// Show the current default engine in the top header of the panel.
let currentEngine = Services.search.currentEngine;
let uri = currentEngine.iconURI;
if (uri)
@ -989,12 +1017,16 @@
document.getAnonymousElementByAttribute(this, "anonid", "searchbar-engine-name")
.setAttribute("value", currentEngine.name + " Search");
// Update the 'Search for <keywords> with:" header.
let headerSearchText =
document.getAnonymousElementByAttribute(this, "anonid",
"searchbar-oneoffheader-searchtext");
let textbox = document.getElementById("searchbar").textbox;
let textbox = searchbar.textbox;
let self = this;
let keyPressHandler = function() {
headerSearchText.setAttribute("value", textbox.value);
if (textbox.value)
self.removeAttribute("showonlysettings");
};
textbox.addEventListener("keyup", keyPressHandler);
this.addEventListener("popuphiding", function hiding() {
@ -1003,9 +1035,42 @@
});
keyPressHandler();
// Handle opensearch items. This needs to be done before building the
// list of one off providers, as that code will return early if all the
// alternative engines are hidden.
let addEngineList =
document.getAnonymousElementByAttribute(this, "anonid", "add-engines");
while (addEngineList.firstChild)
addEngineList.firstChild.remove();
const kXULNS =
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
let addEngines = getBrowser().mCurrentBrowser.engines;
if (addEngines && addEngines.length > 0) {
const kBundleURI = "chrome://browser/locale/search.properties";
let bundle = Services.strings.createBundle(kBundleURI);
for (let engine of addEngines) {
let button = document.createElementNS(kXULNS, "button");
let label = bundle.formatStringFromName("cmd_addFoundEngine",
[engine.title], 1);
button.setAttribute("class", "addengine-item");
button.setAttribute("label", label);
button.setAttribute("pack", "start");
button.setAttribute("crop", "end");
button.setAttribute("tooltiptext", engine.uri);
button.setAttribute("uri", engine.uri);
if (engine.icon) {
let uri = PlacesUtils.getImageURLForResolution(window, engine.icon);
button.setAttribute("image", uri);
}
button.setAttribute("title", engine.title);
addEngineList.appendChild(button);
}
}
// Finally, build the list of one-off buttons.
let list = document.getAnonymousElementByAttribute(this, "anonid",
"search-panel-one-offs")
while (list.firstChild)
@ -1056,11 +1121,12 @@
let dummyItems = enginesPerRow - (engines.length % enginesPerRow || enginesPerRow);
for (let i = 0; i < engines.length; ++i) {
let engine = engines[i];
if (!engine.iconURI)
continue;
let button = document.createElementNS(kXULNS, "button");
let uri = PlacesUtils.getImageURLForResolution(window, engine.iconURI.spec);
button.setAttribute("label", engine.name);
let uri = "chrome://browser/skin/search-engine-placeholder.png";
if (engine.iconURI) {
uri = PlacesUtils.getImageURLForResolution(window, engine.iconURI.spec);
}
button.setAttribute("image", uri);
button.setAttribute("class", "searchbar-engine-one-off-item");
button.setAttribute("tooltiptext", engine.name);
@ -1116,6 +1182,23 @@
let searchbar = document.getElementById("searchbar");
searchbar.handleSearchCommand(event, button.engine);
]]></handler>
<handler event="command"><![CDATA[
let target = event.originalTarget;
if (target.classList.contains("addengine-item")) {
// On success, hide and reshow the panel to show the new engine.
let installCallback = {
onSuccess: function(engine) {
event.target.hidePopup();
BrowserSearch.searchBar.openSuggestionsPanel();
}
}
Services.search.addEngine(target.getAttribute("uri"),
Ci.nsISearchEngine.DATA_XML,
target.getAttribute("src"), false,
installCallback);
}
]]></handler>
</handlers>
</binding>

View File

@ -12,4 +12,5 @@
.checkbox-icon {
-moz-margin-end: 8px;
max-width: 16px;
}

View File

@ -20,7 +20,8 @@ var gSearchPane = {
Services.search.getVisibleEngines().forEach(e => {
let item = list.appendItem(e.name);
item.setAttribute("class", "menuitem-iconic");
item.setAttribute("image", e.iconURI.spec);
if (e.iconURI)
item.setAttribute("image", e.iconURI.spec);
item.engine = e;
if (e.name == currentEngine)
list.selectedItem = item;
@ -49,7 +50,8 @@ var gSearchPane = {
item.setAttribute("label", e.name);
if (hiddenList.indexOf(e.name) == -1)
item.setAttribute("checked", "true");
item.setAttribute("src", e.iconURI.spec);
if (e.iconURI)
item.setAttribute("src", e.iconURI.spec);
richlistbox.appendChild(item);
});
},

View File

@ -9,11 +9,15 @@
window auto-sizing code work. */
}
#oneClickProvidersList {
height: 178px;
}
.checkbox-label-box {
-moz-box-align: center;
}
.checkbox-icon {
margin: 3px 3px;
max-width: 16px;
}

View File

@ -13,7 +13,8 @@ var gSearchPane = {
Services.search.getVisibleEngines().forEach(e => {
let item = list.appendItem(e.name);
item.setAttribute("class", "menuitem-iconic");
item.setAttribute("image", e.iconURI.spec);
if (e.iconURI)
item.setAttribute("image", e.iconURI.spec);
item.engine = e;
if (e.name == currentEngine)
list.selectedItem = item;
@ -42,7 +43,8 @@ var gSearchPane = {
item.setAttribute("label", e.name);
if (hiddenList.indexOf(e.name) == -1)
item.setAttribute("checked", "true");
item.setAttribute("src", e.iconURI.spec);
if (e.iconURI)
item.setAttribute("src", e.iconURI.spec);
richlistbox.appendChild(item);
});
},

View File

@ -552,13 +552,6 @@
// Speculatively connect to the current engine's search URI (and
// suggest URI, if different) to reduce request latency
this.currentEngine.speculativeConnect({window: window});
if (this._textbox.value && !this._textbox.open) {
this._textbox.showHistoryPopup();
// showHistoryPopup does a startSearch("") call, ensure the
// controller handles the text from the input box instead:
this._textbox.mController.handleText();
}
]]></handler>
</handlers>
</binding>
@ -643,10 +636,41 @@
.hidden = !this._textbox.value;
]]></body>
</method>
<method name="openSuggestionsPanel">
<parameter name="aShowOnlySettingsIfEmpty"/>
<body><![CDATA[
if (this._textbox.open)
return;
this._textbox.showHistoryPopup();
if (this._textbox.value) {
// showHistoryPopup does a startSearch("") call, ensure the
// controller handles the text from the input box instead:
this._textbox.mController.handleText();
}
else if (aShowOnlySettingsIfEmpty) {
this.setAttribute("showonlysettings", "true");
}
]]></body>
</method>
</implementation>
<handlers>
<handler event="input" action="this.updateGoButtonVisibility();"/>
<handler event="drop" action="this.updateGoButtonVisibility();"/>
<handler event="focus">
<![CDATA[
if (this._textbox.value)
this.openSuggestionsPanel();
]]></handler>
<handler event="click">
<![CDATA[
if (event.originalTarget.getAttribute("anonid") == "searchbar-search-button")
this.openSuggestionsPanel(true);
]]></handler>
</handlers>
</binding>
@ -884,6 +908,15 @@
if (!popup.popupOpen)
return;
if (aEvent.keyCode == KeyEvent.DOM_VK_DOWN &&
popup.hasAttribute("showonlysettings")) {
// If the suggestion tree is collapsed, don't let the down arrow
// key event reach the tree.
aEvent.preventDefault();
aEvent.stopPropagation();
return;
}
let list = document.getAnonymousElementByAttribute(popup, "anonid",
"search-panel-one-offs");
if (!list)

View File

@ -141,6 +141,7 @@ function* prepareTest() {
searchBar.removeEventListener("focus", onFocus);
deferred.resolve();
});
gURLBar.focus();
searchBar.focus();
} else {
deferred.resolve();

View File

@ -62,7 +62,11 @@ browser.jar:
skin/classic/browser/privatebrowsing-mask.png
skin/classic/browser/reload-stop-go.png
skin/classic/browser/searchbar.css
skin/classic/browser/search-pref.png (../shared/search-pref.png)
skin/classic/browser/search-pref.png (../shared/search/search-pref.png)
skin/classic/browser/search-indicator.png (../shared/search/search-indicator.png)
skin/classic/browser/search-indicator-add-engine.png (../shared/search/search-indicator-add-engine.png)
skin/classic/browser/search-engine-placeholder.png (../shared/search/search-engine-placeholder.png)
skin/classic/browser/badge-add-engine.png (../shared/search/badge-add-engine.png)
skin/classic/browser/Secure.png
skin/classic/browser/Security-broken.png
skin/classic/browser/setDesktopBackground.css

View File

@ -77,8 +77,17 @@ menuitem[cmd="cmd_clearhistory"][disabled] {
}
.searchbar-search-button {
list-style-image: url("chrome://global/skin/icons/Search-glass.png");
-moz-image-region: rect(0px 16px 16px 0px);
list-style-image: url("chrome://browser/skin/search-indicator.png");
-moz-image-region: rect(0, 20px, 20px, 0);
margin: -2px -2px;
}
.searchbar-search-button:hover {
-moz-image-region: rect(0, 40px, 20px, 20px);
}
.searchbar-search-button:hover:active {
-moz-image-region: rect(0, 60px, 20px, 40px);
}
searchbar[oneoffui] .search-go-button {
@ -172,6 +181,40 @@ searchbar[oneoffui] .search-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon
height: 16px;
}
.addengine-item {
-moz-appearance: none;
font-size: 10px;
height: 32px;
margin: 0 0;
padding: 0 10px;
}
.addengine-item > .button-box {
-moz-box-pack: start;
}
.addengine-item:first-of-type {
border-top: 1px solid #ccc;
}
.addengine-item:hover {
background-color: Highlight;
}
.addengine-item > .button-box > .button-icon {
width: 16px;
}
.addengine-item > .button-box > .button-text {
-moz-box-flex: 1;
text-align: start;
-moz-padding-start: 10px;
}
.addengine-item:not([image]) {
list-style-image: url("chrome://browser/skin/search-engine-placeholder.png");
}
searchbar[oneoffui] .searchbar-engine-button {
display: none;
}
@ -195,11 +238,6 @@ searchbar[oneoffui] .searchbar-engine-button {
}
.search-setting-button:hover {
background-color: hsla(210,4%,10%,.07);
}
.search-setting-button:hover:active {
outline: 1px solid hsla(210,4%,10%,.12);
background-color: hsla(210,4%,10%,.12);
box-shadow: 0 1px 0 hsla(210,4%,10%,.05) inset;
background-color: #d3d3d3;
border-top-color: #bdbebe;
}

View File

@ -100,7 +100,15 @@ browser.jar:
skin/classic/browser/searchbar.css
skin/classic/browser/Search.png
skin/classic/browser/Search@2x.png
skin/classic/browser/search-pref.png (../shared/search-pref.png)
skin/classic/browser/search-pref.png (../shared/search/search-pref.png)
skin/classic/browser/search-indicator.png (../shared/search/search-indicator.png)
skin/classic/browser/search-indicator@2x.png (../shared/search/search-indicator@2x.png)
skin/classic/browser/search-indicator-add-engine.png (../shared/search/search-indicator-add-engine.png)
skin/classic/browser/search-indicator-add-engine@2x.png (../shared/search/search-indicator-add-engine@2x.png)
skin/classic/browser/search-engine-placeholder.png (../shared/search/search-engine-placeholder.png)
skin/classic/browser/search-engine-placeholder@2x.png (../shared/search/search-engine-placeholder@2x.png)
skin/classic/browser/badge-add-engine.png (../shared/search/badge-add-engine.png)
skin/classic/browser/badge-add-engine@2x.png (../shared/search/badge-add-engine@2x.png)
skin/classic/browser/Secure-Glyph.png
skin/classic/browser/Secure-Glyph@2x.png
skin/classic/browser/slowStartup-16.png

View File

@ -53,11 +53,24 @@
-moz-padding-end: 4px;
}
.searchbar-search-button,
.search-go-button {
list-style-image: url("chrome://browser/skin/Search.png");
}
.searchbar-search-button {
list-style-image: url("chrome://browser/skin/search-indicator.png");
-moz-image-region: rect(0, 20px, 20px, 0);
margin: 0 -3px;
}
.searchbar-search-button:hover {
-moz-image-region: rect(0, 40px, 20px, 20px);
}
.searchbar-search-button:hover:active {
-moz-image-region: rect(0, 60px, 20px, 40px);
}
searchbar[oneoffui] .search-go-button {
list-style-image: url("chrome://browser/skin/reload-stop-go.png");
-moz-image-region: rect(0, 42px, 14px, 28px);
@ -81,12 +94,25 @@ searchbar[oneoffui] .search-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon
width: 7px;
}
.search-go-button,
.searchbar-search-button {
.search-go-button {
list-style-image: url("chrome://browser/skin/Search@2x.png");
width: 14px;
}
.searchbar-search-button {
list-style-image: url("chrome://browser/skin/search-indicator@2x.png");
width: 20px;
-moz-image-region: rect(0, 40px, 40px, 0);
}
.searchbar-search-button:hover {
-moz-image-region: rect(0, 80px, 40px, 40px);
}
.searchbar-search-button:hover:active {
-moz-image-region: rect(0, 120px, 40px, 80px);
}
searchbar[oneoffui] .search-go-button {
list-style-image: url("chrome://browser/skin/reload-stop-go@2x.png");
-moz-image-region: rect(0, 84px, 28px, 56px);
@ -166,6 +192,46 @@ searchbar[oneoffui] .search-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon
height: 16px;
}
.addengine-item {
-moz-appearance: none;
font-size: 10px;
height: 32px;
margin: 0 0;
padding: 0 10px;
}
.addengine-item > .button-box {
-moz-box-pack: start;
}
.addengine-item:first-of-type {
border-top: 1px solid #ccc;
}
.addengine-item:hover {
background-color: Highlight;
}
.addengine-item > .button-box > .button-icon {
width: 16px;
}
.addengine-item > .button-box > .button-text {
-moz-box-flex: 1;
text-align: start;
-moz-padding-start: 10px;
}
.addengine-item:not([image]) {
list-style-image: url("chrome://browser/skin/search-engine-placeholder.png");
}
@media (min-resolution: 2dppx) {
.addengine-item:not([image]) {
list-style-image: url("chrome://browser/skin/search-engine-placeholder@2x.png");
}
}
searchbar[oneoffui] .searchbar-engine-button {
display: none;
}
@ -185,12 +251,11 @@ searchbar[oneoffui] .searchbar-engine-button {
min-height: 32px;
}
.search-setting-button:hover {
background-color: hsla(210,4%,10%,.07);
.search-setting-button[showonlysettings] {
border-radius: 4px;
}
.search-setting-button:hover:active {
outline: 1px solid hsla(210,4%,10%,.12);
background-color: hsla(210,4%,10%,.12);
box-shadow: 0 1px 0 hsla(210,4%,10%,.05) inset;
.search-setting-button:hover {
background-color: #d3d3d3;
border-top-color: #bdbebe;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 888 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -77,7 +77,11 @@ browser.jar:
skin/classic/browser/reload-stop-go.png
skin/classic/browser/searchbar.css
skin/classic/browser/searchbar-dropdown-arrow.png
skin/classic/browser/search-pref.png (../shared/search-pref.png)
skin/classic/browser/search-pref.png (../shared/search/search-pref.png)
skin/classic/browser/search-indicator.png (../shared/search/search-indicator.png)
skin/classic/browser/search-indicator-add-engine.png (../shared/search/search-indicator-add-engine.png)
skin/classic/browser/search-engine-placeholder.png (../shared/search/search-engine-placeholder.png)
skin/classic/browser/badge-add-engine.png (../shared/search/badge-add-engine.png)
skin/classic/browser/Secure24.png
skin/classic/browser/setDesktopBackground.css
skin/classic/browser/slowStartup-16.png
@ -512,7 +516,11 @@ browser.jar:
skin/classic/aero/browser/reload-stop-go.png
skin/classic/aero/browser/searchbar.css
skin/classic/aero/browser/searchbar-dropdown-arrow.png (searchbar-dropdown-arrow-aero.png)
skin/classic/aero/browser/search-pref.png (../shared/search-pref.png)
skin/classic/aero/browser/search-pref.png (../shared/search/search-pref.png)
skin/classic/aero/browser/search-indicator.png (../shared/search/search-indicator.png)
skin/classic/aero/browser/search-indicator-add-engine.png (../shared/search/search-indicator-add-engine.png)
skin/classic/aero/browser/search-engine-placeholder.png (../shared/search/search-engine-placeholder.png)
skin/classic/aero/browser/badge-add-engine.png (../shared/search/badge-add-engine.png)
skin/classic/aero/browser/Secure24.png (Secure24-aero.png)
skin/classic/aero/browser/setDesktopBackground.css
skin/classic/aero/browser/slowStartup-16.png

View File

@ -88,8 +88,17 @@
}
.searchbar-search-button {
list-style-image: url("chrome://global/skin/icons/Search-glass.png");
-moz-image-region: rect(0px 16px 16px 0px);
list-style-image: url("chrome://browser/skin/search-indicator.png");
-moz-image-region: rect(0, 20px, 20px, 0);
margin: -2px -2px;
}
.searchbar-search-button:hover {
-moz-image-region: rect(0, 40px, 20px, 20px);
}
.searchbar-search-button:hover:active {
-moz-image-region: rect(0, 60px, 20px, 40px);
}
searchbar[oneoffui] .search-go-button {
@ -181,6 +190,40 @@ searchbar[oneoffui] .search-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon
height: 16px;
}
.addengine-item {
-moz-appearance: none;
font-size: 10px;
height: 32px;
margin: 0 0;
padding: 0 10px;
}
.addengine-item > .button-box {
-moz-box-pack: start;
}
.addengine-item:first-of-type {
border-top: 1px solid #ccc;
}
.addengine-item:hover {
background-color: Highlight;
}
.addengine-item > .button-box > .button-icon {
width: 16px;
}
.addengine-item > .button-box > .button-text {
-moz-box-flex: 1;
text-align: start;
-moz-padding-start: 10px;
}
.addengine-item:not([image]) {
list-style-image: url("chrome://browser/skin/search-engine-placeholder.png");
}
searchbar[oneoffui] .searchbar-engine-button {
display: none;
}
@ -204,11 +247,6 @@ searchbar[oneoffui] .searchbar-engine-button {
}
.search-setting-button:hover {
background-color: hsla(210,4%,10%,.07);
}
.search-setting-button:hover:active {
outline: 1px solid hsla(210,4%,10%,.12);
background-color: hsla(210,4%,10%,.12);
box-shadow: 0 1px 0 hsla(210,4%,10%,.05) inset;
background-color: #d3d3d3;
border-top-color: #bdbebe;
}

View File

@ -73,8 +73,9 @@ SuggestAutoComplete.prototype = {
finalComments = finalComments.concat(comments);
}
// If no result, add the search term so that the panel is shown anyway.
if (!finalResults.length) {
// If no result, add the search term so that the panel of the new UI is shown anyway.
if (!finalResults.length &&
Services.prefs.getBoolPref("browser.search.showOneOffButtons")) {
finalResults.push(results.term);
finalComments.push("");
}