зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1344924 - Contextual onboarding for search suggestions in the awesomebar. r=adw
Make the onboarding being opt-in or opt-out depending on the default value of the browser.urlbar.sugges.searches pref. In both cases respect userMadeSearchSuggestionChoice though, so we won't further nag users that made a choice already. MozReview-Commit-ID: D4rRMRbdMrW --HG-- rename : browser/base/content/test/urlbar/browser_urlbarSearchSuggestionsNotification.js => browser/base/content/test/urlbar/browser_urlbarSearchSuggestions_opt-in.js extra : rebase_source : 2eb22b5965734d9702b115bc653ce55174003221
This commit is contained in:
Родитель
f3c162e4e1
Коммит
33d0ed1409
|
@ -320,10 +320,11 @@ pref("browser.urlbar.suggest.bookmark", true);
|
|||
pref("browser.urlbar.suggest.openpage", true);
|
||||
pref("browser.urlbar.suggest.searches", false);
|
||||
pref("browser.urlbar.userMadeSearchSuggestionsChoice", false);
|
||||
// 4 here means the suggestion notification will be automatically
|
||||
// hidden the 4th day, so it will actually be shown on 3 different days.
|
||||
// The suggestion opt-in notification will be shown on 4 different days.
|
||||
pref("browser.urlbar.daysBeforeHidingSuggestionsPrompt", 4);
|
||||
pref("browser.urlbar.lastSuggestionsPromptDate", 20160601);
|
||||
// The suggestion opt-out hint will be hidden after being shown 4 times.
|
||||
pref("browser.urlbar.timesBeforeHidingSuggestionsHint", 4);
|
||||
|
||||
// Limit the number of characters sent to the current search engine to fetch
|
||||
// suggestions.
|
||||
|
|
|
@ -610,12 +610,12 @@ html|input.urlbar-input[textoverflow]:not([focused]) {
|
|||
transition: height 100ms;
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > hbox[anonid="search-suggestions-notification"] {
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"] {
|
||||
visibility: collapse;
|
||||
transition: margin-top 100ms;
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult.showSearchSuggestionsNotification > hbox[anonid="search-suggestions-notification"] {
|
||||
#PopupAutoCompleteRichResult.showSearchSuggestionsNotification > deck[anonid="search-suggestions-notification"] {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,11 @@ support-files =
|
|||
support-files =
|
||||
searchSuggestionEngine.xml
|
||||
searchSuggestionEngine.sjs
|
||||
[browser_urlbarSearchSuggestionsNotification.js]
|
||||
[browser_urlbarSearchSuggestions_opt-in.js]
|
||||
support-files =
|
||||
searchSuggestionEngine.xml
|
||||
searchSuggestionEngine.sjs
|
||||
[browser_urlbarSearchSuggestions_opt-out.js]
|
||||
support-files =
|
||||
searchSuggestionEngine.xml
|
||||
searchSuggestionEngine.sjs
|
||||
|
|
|
@ -25,11 +25,12 @@ add_task(async function searchSuggestions() {
|
|||
let oldCurrentEngine = Services.search.currentEngine;
|
||||
Services.search.currentEngine = engine;
|
||||
Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
|
||||
let suggestionsEnabled = Services.prefs.getBoolPref(SUGGEST_URLBAR_PREF);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
|
||||
registerCleanupFunction(function() {
|
||||
Services.search.currentEngine = oldCurrentEngine;
|
||||
Services.prefs.clearUserPref(SUGGEST_ALL_PREF);
|
||||
Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, suggestionsEnabled);
|
||||
});
|
||||
|
||||
await promiseAutocompleteResultPopup("foo");
|
||||
|
|
|
@ -3,12 +3,13 @@ const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
|
|||
|
||||
// Must run first.
|
||||
add_task(async function prepare() {
|
||||
let suggestionsEnabled = Services.prefs.getBoolPref(SUGGEST_URLBAR_PREF);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
|
||||
let engine = await promiseNewSearchEngine(TEST_ENGINE_BASENAME);
|
||||
let oldCurrentEngine = Services.search.currentEngine;
|
||||
Services.search.currentEngine = engine;
|
||||
registerCleanupFunction(async function() {
|
||||
Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, suggestionsEnabled);
|
||||
Services.search.currentEngine = oldCurrentEngine;
|
||||
|
||||
// Clicking suggestions causes visits to search results pages, so clear that
|
||||
|
|
|
@ -8,14 +8,19 @@ add_task(async function prepare() {
|
|||
let engine = await promiseNewSearchEngine(TEST_ENGINE_BASENAME);
|
||||
let oldCurrentEngine = Services.search.currentEngine;
|
||||
Services.search.currentEngine = engine;
|
||||
let defaults = Services.prefs.getDefaultBranch("browser.urlbar.");
|
||||
let searchSuggestionsDefault = defaults.getBoolPref("suggest.searches");
|
||||
defaults.setBoolPref("suggest.searches", false);
|
||||
let suggestionsEnabled = Services.prefs.getBoolPref(SUGGEST_URLBAR_PREF);
|
||||
registerCleanupFunction(async function() {
|
||||
defaults.setBoolPref("suggest.searches", searchSuggestionsDefault);
|
||||
Services.search.currentEngine = oldCurrentEngine;
|
||||
Services.prefs.clearUserPref(SUGGEST_ALL_PREF);
|
||||
Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, suggestionsEnabled);
|
||||
|
||||
// Disable the notification for future tests so it doesn't interfere with
|
||||
// them. clearUserPref() won't work because by default the pref is false.
|
||||
await setUserMadeChoicePref(true);
|
||||
Services.prefs.setBoolPref(CHOICE_PREF, true);
|
||||
|
||||
// Make sure the popup is closed for the next test.
|
||||
gURLBar.blur();
|
||||
|
@ -26,16 +31,14 @@ add_task(async function prepare() {
|
|||
add_task(async function focus() {
|
||||
// Focusing the urlbar used to open the popup in order to show the
|
||||
// notification, but it doesn't anymore. Make sure it does not.
|
||||
Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
|
||||
await setUserMadeChoicePref(false);
|
||||
setupVisibleNotification();
|
||||
gURLBar.blur();
|
||||
gURLBar.focus();
|
||||
Assert.ok(!gURLBar.popup.popupOpen, "popup should remain closed");
|
||||
});
|
||||
|
||||
add_task(async function dismissWithoutResults() {
|
||||
Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
|
||||
await setUserMadeChoicePref(false);
|
||||
setupVisibleNotification();
|
||||
gURLBar.blur();
|
||||
gURLBar.focus();
|
||||
let popupPromise = promisePopupShown(gURLBar.popup);
|
||||
|
@ -60,8 +63,7 @@ add_task(async function dismissWithoutResults() {
|
|||
});
|
||||
|
||||
add_task(async function dismissWithResults() {
|
||||
Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
|
||||
await setUserMadeChoicePref(false);
|
||||
setupVisibleNotification();
|
||||
gURLBar.blur();
|
||||
gURLBar.focus();
|
||||
await promiseAutocompleteResultPopup("foo");
|
||||
|
@ -84,8 +86,7 @@ add_task(async function dismissWithResults() {
|
|||
});
|
||||
|
||||
add_task(async function disable() {
|
||||
Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
|
||||
await setUserMadeChoicePref(false);
|
||||
setupVisibleNotification();
|
||||
gURLBar.blur();
|
||||
gURLBar.focus();
|
||||
await promiseAutocompleteResultPopup("foo");
|
||||
|
@ -103,9 +104,7 @@ add_task(async function disable() {
|
|||
});
|
||||
|
||||
add_task(async function enable() {
|
||||
Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, false);
|
||||
await setUserMadeChoicePref(false);
|
||||
setupVisibleNotification();
|
||||
gURLBar.blur();
|
||||
gURLBar.focus();
|
||||
await promiseAutocompleteResultPopup("foo");
|
||||
|
@ -131,6 +130,7 @@ add_task(async function enable() {
|
|||
add_task(async function privateWindow() {
|
||||
// Since suggestions are disabled in private windows, the notification should
|
||||
// not appear even when suggestions are otherwise enabled.
|
||||
setupVisibleNotification();
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow({ private: true });
|
||||
win.gURLBar.blur();
|
||||
win.gURLBar.focus();
|
||||
|
@ -143,9 +143,7 @@ add_task(async function privateWindow() {
|
|||
add_task(async function multipleWindows() {
|
||||
// Opening multiple windows, using their urlbars, and then dismissing the
|
||||
// notification in one should dismiss the notification in all.
|
||||
Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, false);
|
||||
await setUserMadeChoicePref(false);
|
||||
setupVisibleNotification();
|
||||
|
||||
gURLBar.focus();
|
||||
await promiseAutocompleteResultPopup("win1");
|
||||
|
@ -184,39 +182,19 @@ add_task(async function multipleWindows() {
|
|||
add_task(async function enableOutsideNotification() {
|
||||
// Setting the suggest.searches pref outside the notification (e.g., by
|
||||
// ticking the checkbox in the preferences window) should hide it.
|
||||
Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, false);
|
||||
await setUserMadeChoicePref(false);
|
||||
|
||||
setupVisibleNotification();
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
|
||||
gURLBar.focus();
|
||||
await promiseAutocompleteResultPopup("foo");
|
||||
assertVisible(false);
|
||||
});
|
||||
|
||||
/**
|
||||
* Setting the choice pref triggers a pref observer in the urlbar, which hides
|
||||
* the notification if it's present. This function returns a promise that's
|
||||
* resolved once the observer fires.
|
||||
*
|
||||
* @param userMadeChoice A boolean, the pref's new value.
|
||||
* @return A Promise that's resolved when the observer fires -- or, if the pref
|
||||
* is currently the given value, that's resolved immediately.
|
||||
*/
|
||||
function setUserMadeChoicePref(userMadeChoice) {
|
||||
return new Promise(resolve => {
|
||||
let currentUserMadeChoice = Services.prefs.getBoolPref(CHOICE_PREF);
|
||||
if (currentUserMadeChoice != userMadeChoice) {
|
||||
Services.prefs.addObserver(CHOICE_PREF, function obs(subj, topic, data) {
|
||||
Services.prefs.removeObserver(CHOICE_PREF, obs);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
Services.prefs.setBoolPref(CHOICE_PREF, userMadeChoice);
|
||||
if (currentUserMadeChoice == userMadeChoice) {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
function setupVisibleNotification() {
|
||||
Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
|
||||
// Toggle to reset the whichNotification cache.
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, false);
|
||||
Services.prefs.setBoolPref(CHOICE_PREF, false);
|
||||
}
|
||||
|
||||
function suggestionsPresent() {
|
|
@ -0,0 +1,118 @@
|
|||
// The order of the tests here matters!
|
||||
|
||||
const SUGGEST_ALL_PREF = "browser.search.suggest.enabled";
|
||||
const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
|
||||
const CHOICE_PREF = "browser.urlbar.userMadeSearchSuggestionsChoice";
|
||||
const TIMES_PREF = "browser.urlbar.timesBeforeHidingSuggestionsHint";
|
||||
const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
|
||||
|
||||
add_task(async function prepare() {
|
||||
let engine = await promiseNewSearchEngine(TEST_ENGINE_BASENAME);
|
||||
let oldCurrentEngine = Services.search.currentEngine;
|
||||
Services.search.currentEngine = engine;
|
||||
let defaults = Services.prefs.getDefaultBranch("browser.urlbar.");
|
||||
let searchSuggestionsDefault = defaults.getBoolPref("suggest.searches");
|
||||
defaults.setBoolPref("suggest.searches", true);
|
||||
let suggestionsEnabled = Services.prefs.getBoolPref(SUGGEST_URLBAR_PREF);
|
||||
let suggestionsChoice = Services.prefs.getBoolPref(CHOICE_PREF);
|
||||
Services.prefs.setBoolPref(CHOICE_PREF, false);
|
||||
registerCleanupFunction(async function() {
|
||||
defaults.setBoolPref("suggest.searches", searchSuggestionsDefault);
|
||||
Services.search.currentEngine = oldCurrentEngine;
|
||||
Services.prefs.clearUserPref(SUGGEST_ALL_PREF);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, suggestionsEnabled);
|
||||
Services.prefs.setBoolPref(CHOICE_PREF, suggestionsChoice);
|
||||
|
||||
// Make sure the popup is closed for the next test.
|
||||
gURLBar.blur();
|
||||
Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function focus() {
|
||||
// Focusing the urlbar should open the popup in order to show the
|
||||
// notification.
|
||||
setupVisibleHint();
|
||||
gURLBar.blur();
|
||||
let popupPromise = promisePopupShown(gURLBar.popup);
|
||||
gURLBar.focus();
|
||||
await popupPromise;
|
||||
Assert.ok(gURLBar.popup.popupOpen, "popup should be open");
|
||||
assertVisible(true);
|
||||
Assert.equal(gURLBar.popup._matchCount, 0, "popup should have no results");
|
||||
|
||||
// Start searching.
|
||||
EventUtils.synthesizeKey("r", {});
|
||||
EventUtils.synthesizeKey("n", {});
|
||||
EventUtils.synthesizeKey("d", {});
|
||||
await promiseSearchComplete();
|
||||
Assert.ok(suggestionsPresent());
|
||||
assertVisible(true);
|
||||
|
||||
// Check the Change Options link.
|
||||
let changeOptionsLink = document.getElementById("search-suggestions-change-settings");
|
||||
let prefsPromise = BrowserTestUtils.waitForLocationChange(gBrowser, "about:preferences#general-search");
|
||||
changeOptionsLink.click();
|
||||
await prefsPromise;
|
||||
Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
|
||||
});
|
||||
|
||||
|
||||
add_task(async function privateWindow() {
|
||||
// Since suggestions are disabled in private windows, the notification should
|
||||
// not appear even when suggestions are otherwise enabled.
|
||||
setupVisibleHint();
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow({ private: true });
|
||||
await promiseAutocompleteResultPopup("foo", win);
|
||||
assertVisible(false, win);
|
||||
win.gURLBar.blur();
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
add_task(async function enableOutsideNotification() {
|
||||
// Setting the suggest.searches pref outside the notification (e.g., by
|
||||
// ticking the checkbox in the preferences window) should hide it.
|
||||
setupVisibleHint();
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, false);
|
||||
await promiseAutocompleteResultPopup("foo");
|
||||
assertVisible(false);
|
||||
});
|
||||
|
||||
add_task(async function userMadeChoice() {
|
||||
// If the user made a choice already, he should not see the hint.
|
||||
setupVisibleHint();
|
||||
Services.prefs.setBoolPref(CHOICE_PREF, true);
|
||||
await promiseAutocompleteResultPopup("foo");
|
||||
assertVisible(false);
|
||||
});
|
||||
|
||||
function setupVisibleHint() {
|
||||
Services.prefs.clearUserPref(TIMES_PREF);
|
||||
Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
|
||||
// Toggle to reset the whichNotification cache.
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, false);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
|
||||
}
|
||||
|
||||
function suggestionsPresent() {
|
||||
let controller = gURLBar.popup.input.controller;
|
||||
let matchCount = controller.matchCount;
|
||||
for (let i = 0; i < matchCount; i++) {
|
||||
let url = controller.getValueAt(i);
|
||||
let mozActionMatch = url.match(/^moz-action:([^,]+),(.*)$/);
|
||||
if (mozActionMatch) {
|
||||
let [, type, paramStr] = mozActionMatch;
|
||||
let params = JSON.parse(paramStr);
|
||||
if (type == "searchengine" && "searchSuggestion" in params) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function assertVisible(visible, win = window) {
|
||||
let style =
|
||||
win.getComputedStyle(win.gURLBar.popup.searchSuggestionsNotification);
|
||||
Assert.equal(style.visibility, visible ? "visible" : "collapse");
|
||||
}
|
|
@ -7,13 +7,14 @@ const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
|
|||
|
||||
// Must run first.
|
||||
add_task(async function prepare() {
|
||||
let suggestionsEnabled = Services.prefs.getBoolPref(SUGGEST_URLBAR_PREF);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
|
||||
let engine = await promiseNewSearchEngine(TEST_ENGINE_BASENAME);
|
||||
let oldCurrentEngine = Services.search.currentEngine;
|
||||
Services.search.currentEngine = engine;
|
||||
|
||||
registerCleanupFunction(async function() {
|
||||
Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, suggestionsEnabled);
|
||||
Services.search.currentEngine = oldCurrentEngine;
|
||||
|
||||
// Clicking urlbar results causes visits to their associated pages, so clear
|
||||
|
|
|
@ -70,15 +70,18 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||
this._prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefService)
|
||||
.getBranch("browser.urlbar.");
|
||||
|
||||
this._prefs.addObserver("", this);
|
||||
|
||||
this._defaultPrefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefService)
|
||||
.getDefaultBranch("browser.urlbar.");
|
||||
|
||||
this.clickSelectsAll = this._prefs.getBoolPref("clickSelectsAll");
|
||||
this.doubleClickSelectsAll = this._prefs.getBoolPref("doubleClickSelectsAll");
|
||||
this.completeDefaultIndex = this._prefs.getBoolPref("autoFill");
|
||||
this.timeout = this._prefs.getIntPref("delay");
|
||||
this._formattingEnabled = this._prefs.getBoolPref("formatting.enabled");
|
||||
this._mayTrimURLs = this._prefs.getBoolPref("trimURLs");
|
||||
this._cacheUserMadeSearchSuggestionsChoice();
|
||||
this.inputField.controllers.insertControllerAt(0, this._copyCutController);
|
||||
this.inputField.addEventListener("paste", this);
|
||||
this.inputField.addEventListener("mousedown", this);
|
||||
|
@ -945,14 +948,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||
// binding's constructor.
|
||||
this._prefs.setBoolPref("searchSuggestionsChoice",
|
||||
this._prefs.getBoolPref("suggest.searches"));
|
||||
// fall-through.
|
||||
case "userMadeSearchSuggestionsChoice":
|
||||
this._cacheUserMadeSearchSuggestionsChoice();
|
||||
if (this._userMadeSearchSuggestionsChoice) {
|
||||
this.popup.searchSuggestionsNotificationWasDismissed(
|
||||
this._prefs.getBoolPref("suggest.searches")
|
||||
);
|
||||
}
|
||||
// Clear the cached value to allow changing conditions in tests.
|
||||
delete this._whichSearchSuggestionsNotification;
|
||||
break;
|
||||
case "trimURLs":
|
||||
this._mayTrimURLs = this._prefs.getBoolPref(aData);
|
||||
|
@ -1203,30 +1200,70 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||
]]></body>
|
||||
</method>
|
||||
|
||||
<field name="_userMadeSearchSuggestionsChoice"><![CDATA[
|
||||
false
|
||||
]]></field>
|
||||
|
||||
<method name="_cacheUserMadeSearchSuggestionsChoice">
|
||||
<body><![CDATA[
|
||||
this._userMadeSearchSuggestionsChoice =
|
||||
this._prefs.getBoolPref("userMadeSearchSuggestionsChoice") ||
|
||||
this._prefs.getBoolPref("suggest.searches");
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<property name="shouldShowSearchSuggestionsNotification" readonly="true">
|
||||
<property name="_userMadeSearchSuggestionsChoice" readonly="true">
|
||||
<getter><![CDATA[
|
||||
return !this._userMadeSearchSuggestionsChoice &&
|
||||
!this.inPrivateContext &&
|
||||
// When _urlbarFocused is true, tabbrowser would close the
|
||||
// popup if it's opened here, so don't show the notification.
|
||||
!gBrowser.selectedBrowser._urlbarFocused &&
|
||||
Services.prefs.getBoolPref("browser.search.suggest.enabled") &&
|
||||
this._prefs.getIntPref("daysBeforeHidingSuggestionsPrompt");
|
||||
return this._prefs.getBoolPref("userMadeSearchSuggestionsChoice") ||
|
||||
this._defaultPrefs.getBoolPref("suggest.searches") != this._prefs.getBoolPref("suggest.searches");
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<property name="whichSearchSuggestionsNotification" readonly="true">
|
||||
<getter><![CDATA[
|
||||
// Once we return "none" once, we'll always return "none".
|
||||
// If available, use the cached value, rather than running all of the
|
||||
// checks again at every locationbar focus.
|
||||
if (this._whichSearchSuggestionsNotification) {
|
||||
return this._whichSearchSuggestionsNotification;
|
||||
}
|
||||
|
||||
if (Services.prefs.getBoolPref("browser.search.suggest.enabled") &&
|
||||
!this.inPrivateContext &&
|
||||
// When _urlbarFocused is true, tabbrowser would close the
|
||||
// popup if it's opened here, so don't show the notification.
|
||||
!gBrowser.selectedBrowser._urlbarFocused &&
|
||||
// In any case, if the user made a choice we should not nag him.
|
||||
!this._userMadeSearchSuggestionsChoice) {
|
||||
let enabledByDefault = this._defaultPrefs.getBoolPref("suggest.searches");
|
||||
if (!enabledByDefault &&
|
||||
this._prefs.getIntPref("daysBeforeHidingSuggestionsPrompt")) {
|
||||
return "opt-in";
|
||||
}
|
||||
if (enabledByDefault &&
|
||||
// Has not been switched off.
|
||||
this._prefs.getBoolPref("suggest.searches") &&
|
||||
this._prefs.getIntPref("timesBeforeHidingSuggestionsHint")) {
|
||||
return "opt-out";
|
||||
}
|
||||
}
|
||||
return this._whichSearchSuggestionsNotification = "none";
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<method name="updateSearchSuggestionsNotificationImpressions">
|
||||
<parameter name="whichNotification"/>
|
||||
<body><![CDATA[
|
||||
if (whichNotification == "none") {
|
||||
throw new Error("Unexpected notification type");
|
||||
}
|
||||
|
||||
let useDays = whichNotification == "opt-in";
|
||||
let prefName = useDays ? "daysBeforeHidingSuggestionsPrompt"
|
||||
: "timesBeforeHidingSuggestionsHint";
|
||||
let remaining = this._prefs.getIntPref(prefName);
|
||||
if (remaining <= 0)
|
||||
return;
|
||||
|
||||
let now = new Date();
|
||||
let date = now.getFullYear() * 10000 + (now.getMonth() + 1) * 100 + now.getDate();
|
||||
|
||||
let previousDate = this._prefs.getIntPref("lastSuggestionsPromptDate");
|
||||
if (!useDays || previousDate != date) {
|
||||
this._prefs.setIntPref(prefName, remaining - 1);
|
||||
}
|
||||
this._prefs.setIntPref("lastSuggestionsPromptDate", date);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
</implementation>
|
||||
|
||||
<handlers>
|
||||
|
@ -1258,6 +1295,38 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||
if (this.getAttribute("pageproxystate") != "valid") {
|
||||
UpdatePopupNotificationsVisibility();
|
||||
}
|
||||
|
||||
// We may want to show the search suggestions hint.
|
||||
if (!gBrowser.selectedBrowser._urlbarFocused) {
|
||||
// We show the opt-out notification on every kind of focus to the urlbar
|
||||
// included opening a new tab, but we want to enforce at least one
|
||||
// notification when the user focuses it with the mouse.
|
||||
let whichNotification = this.whichSearchSuggestionsNotification;
|
||||
if (whichNotification == "opt-out" &&
|
||||
this._showSearchSuggestionNotificationOnMouseFocus === undefined) {
|
||||
this._showSearchSuggestionNotificationOnMouseFocus = true;
|
||||
}
|
||||
|
||||
// Check whether the focus change came from a user mouse action.
|
||||
let focusMethod = Services.focus.getLastFocusMethod(window);
|
||||
let mouseFocused = !!(focusMethod & Services.focus.FLAG_BYMOUSE);
|
||||
if (this._showSearchSuggestionNotificationOnMouseFocus &&
|
||||
mouseFocused) {
|
||||
// Force showing the opt-out notification.
|
||||
this._whichSearchSuggestionsNotification = whichNotification = "opt-out";
|
||||
}
|
||||
|
||||
if (whichNotification == "opt-out") {
|
||||
try {
|
||||
this.popup.openAutocompletePopup(this, this);
|
||||
} finally {
|
||||
if (mouseFocused) {
|
||||
delete this._whichSearchSuggestionsNotification;
|
||||
this._showSearchSuggestionNotificationOnMouseFocus = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></handler>
|
||||
|
||||
|
@ -1335,34 +1404,62 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||
|
||||
<content ignorekeys="true" level="top" consumeoutsideclicks="never"
|
||||
aria-owns="richlistbox">
|
||||
<xul:hbox anonid="search-suggestions-notification"
|
||||
<xul:deck anonid="search-suggestions-notification"
|
||||
align="center"
|
||||
role="alert"
|
||||
aria-describedby="search-suggestions-notification-text">
|
||||
<xul:description flex="1">
|
||||
&urlbar.searchSuggestionsNotification.question;
|
||||
<!-- Several things here are to make the label accessibile via an
|
||||
accesskey so that a11y doesn't suck: the accesskey, using an
|
||||
onclick handler instead of an href attribute, the control
|
||||
attribute, and having the control attribute refer to a valid ID
|
||||
that is the label itself. -->
|
||||
<xul:label id="search-suggestions-notification-learn-more"
|
||||
selectedIndex="0">
|
||||
<!-- OPT-IN -->
|
||||
<xul:hbox flex="1" align="center" anonid="search-suggestions-opt-in">
|
||||
<xul:description flex="1" id="search-suggestions-question">
|
||||
&urlbar.searchSuggestionsNotification.question;
|
||||
<!-- Several things here are to make the label accessibile via an
|
||||
accesskey so that a11y doesn't suck: the accesskey, using an
|
||||
onclick handler instead of an href attribute, the control
|
||||
attribute, and having the control attribute refer to a valid ID
|
||||
that is the label itself. -->
|
||||
<xul:label id="search-suggestions-learn-more"
|
||||
class="text-link"
|
||||
role="link"
|
||||
value="&urlbar.searchSuggestionsNotification.learnMore;"
|
||||
accesskey="&urlbar.searchSuggestionsNotification.learnMore.accesskey;"
|
||||
onclick="document.getBindingParent(this).openSearchSuggestionsNotificationLearnMoreURL();"
|
||||
control="search-suggestions-learn-more"/>
|
||||
</xul:description>
|
||||
<xul:button anonid="search-suggestions-notification-disable"
|
||||
label="&urlbar.searchSuggestionsNotification.disable;"
|
||||
accesskey="&urlbar.searchSuggestionsNotification.disable.accesskey;"
|
||||
onclick="document.getBindingParent(this).dismissSearchSuggestionsNotification(false);"/>
|
||||
<xul:button anonid="search-suggestions-notification-enable"
|
||||
label="&urlbar.searchSuggestionsNotification.enable;"
|
||||
accesskey="&urlbar.searchSuggestionsNotification.enable.accesskey;"
|
||||
onclick="document.getBindingParent(this).dismissSearchSuggestionsNotification(true);"/>
|
||||
</xul:hbox>
|
||||
<!-- OPT-OUT -->
|
||||
<xul:hbox flex="1" align="center" anonid="search-suggestions-opt-out">
|
||||
<xul:image class="ac-site-icon" type="searchengine"/>
|
||||
<xul:hbox anonid="search-suggestions-hint-typing">
|
||||
<xul:description class="ac-title-text">&brandShortName;</xul:description>
|
||||
</xul:hbox>
|
||||
<xul:hbox anonid="search-suggestions-hint-box" flex="1">
|
||||
<xul:description id="search-suggestions-hint">
|
||||
<html:span class="prefix">💡 &urlbar.searchSuggestionsNotification.hintPrefix;</html:span>
|
||||
<html:span>&urlbar.searchSuggestionsNotification.hint;</html:span>
|
||||
</xul:description>
|
||||
</xul:hbox>
|
||||
<xul:label id="search-suggestions-change-settings"
|
||||
class="text-link"
|
||||
role="link"
|
||||
value="&urlbar.searchSuggestionsNotification.learnMore;"
|
||||
accesskey="&urlbar.searchSuggestionsNotification.learnMore.accesskey;"
|
||||
onclick="document.getBindingParent(this).openSearchSuggestionsNotificationLearnMoreURL();"
|
||||
control="search-suggestions-notification-learn-more"/>
|
||||
</xul:description>
|
||||
<xul:button anonid="search-suggestions-notification-disable"
|
||||
label="&urlbar.searchSuggestionsNotification.disable;"
|
||||
accesskey="&urlbar.searchSuggestionsNotification.disable.accesskey;"
|
||||
onclick="document.getBindingParent(this).dismissSearchSuggestionsNotification(false);"/>
|
||||
<xul:button anonid="search-suggestions-notification-enable"
|
||||
label="&urlbar.searchSuggestionsNotification.enable;"
|
||||
accesskey="&urlbar.searchSuggestionsNotification.enable.accesskey;"
|
||||
onclick="document.getBindingParent(this).dismissSearchSuggestionsNotification(true);"/>
|
||||
</xul:hbox>
|
||||
#ifdef XP_WIN
|
||||
value="&urlbar.searchSuggestionsNotification.changeSettingsWin;"
|
||||
accesskey="&urlbar.searchSuggestionsNotification.changeSettingsWin.accesskey;"
|
||||
#else
|
||||
value="&urlbar.searchSuggestionsNotification.changeSettingsUnix;"
|
||||
accesskey="&urlbar.searchSuggestionsNotification.changeSettingsUnix.accesskey;"
|
||||
#endif
|
||||
onclick="openPreferences('general-search');"
|
||||
control="search-suggestions-change-settings"/>
|
||||
</xul:hbox>
|
||||
</xul:deck>
|
||||
<xul:richlistbox anonid="richlistbox" class="autocomplete-richlistbox"
|
||||
flex="1"/>
|
||||
<xul:hbox anonid="footer">
|
||||
|
@ -1377,6 +1474,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||
</content>
|
||||
|
||||
<implementation>
|
||||
<field name="DOMWindowUtils">
|
||||
window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
</field>
|
||||
|
||||
<field name="_maxResults">0</field>
|
||||
|
||||
<field name="_bundle" readonly="true">
|
||||
|
@ -1463,7 +1565,10 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||
Services.prefs.setBoolPref(
|
||||
"browser.urlbar.userMadeSearchSuggestionsChoice", true
|
||||
);
|
||||
// The input's pref observer will now hide the notification.
|
||||
// Hide the notification.
|
||||
this.searchSuggestionsNotificationWasDismissed(
|
||||
Services.prefs.getBoolPref("browser.urlbar.suggest.searches")
|
||||
);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -1551,29 +1656,6 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||
// to avoid impacting startup / new window performance
|
||||
aInput.popup.hidden = false;
|
||||
|
||||
let showNotification = aInput.shouldShowSearchSuggestionsNotification;
|
||||
if (showNotification) {
|
||||
let prefs = aInput._prefs;
|
||||
let now = new Date();
|
||||
let date = now.getFullYear() * 10000 + (now.getMonth() + 1) * 100 + now.getDate();
|
||||
let previousDate = prefs.getIntPref("lastSuggestionsPromptDate");
|
||||
if (previousDate < date) {
|
||||
let remainingDays =
|
||||
prefs.getIntPref("daysBeforeHidingSuggestionsPrompt") - 1;
|
||||
prefs.setIntPref("daysBeforeHidingSuggestionsPrompt",
|
||||
remainingDays);
|
||||
prefs.setIntPref("lastSuggestionsPromptDate", date);
|
||||
if (!remainingDays)
|
||||
showNotification = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (showNotification) {
|
||||
this._showSearchSuggestionsNotification();
|
||||
} else if (this.classList.contains("showSearchSuggestionsNotification")) {
|
||||
this._hideSearchSuggestionsNotification();
|
||||
}
|
||||
|
||||
this._openAutocompletePopup(aInput, aElement);
|
||||
]]>
|
||||
</body>
|
||||
|
@ -1634,12 +1716,25 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||
this.siteIconStart = undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
let whichNotification = aInput.whichSearchSuggestionsNotification;
|
||||
if (whichNotification != "none") {
|
||||
aInput.updateSearchSuggestionsNotificationImpressions(whichNotification);
|
||||
this._showSearchSuggestionsNotification(whichNotification, popupDirection);
|
||||
} else if (this.classList.contains("showSearchSuggestionsNotification")) {
|
||||
this._hideSearchSuggestionsNotification();
|
||||
}
|
||||
} catch (ex) {
|
||||
// Not critical for the urlbar functionality, just report the error.
|
||||
Components.utils.reportError(ex);
|
||||
}
|
||||
|
||||
// Position the popup below the navbar. To get the y-coordinate,
|
||||
// which is an offset from the bottom of the input, subtract the
|
||||
// bottom of the navbar from the buttom of the input.
|
||||
let yOffset =
|
||||
document.getElementById("nav-bar").getBoundingClientRect().bottom -
|
||||
aInput.getBoundingClientRect().bottom;
|
||||
this.DOMWindowUtils.getBoundsWithoutFlushing(document.getElementById("nav-bar")).bottom -
|
||||
this.DOMWindowUtils.getBoundsWithoutFlushing(aInput).bottom;
|
||||
this.openPopup(aElement, "after_start", 0, yOffset, false, false);
|
||||
]]></body>
|
||||
</method>
|
||||
|
@ -1653,8 +1748,36 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||
</method>
|
||||
|
||||
<method name="_showSearchSuggestionsNotification">
|
||||
<parameter name="whichNotification"/>
|
||||
<parameter name="popupDirection"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
let deckIndex = 0;
|
||||
if (whichNotification == "opt-out") {
|
||||
deckIndex = 1;
|
||||
|
||||
if (this.siteIconStart) {
|
||||
let rect = this.DOMWindowUtils.getBoundsWithoutFlushing(window.document.documentElement);
|
||||
let padding = popupDirection == "rtl" ? rect.right - this.siteIconStart
|
||||
: this.siteIconStart;
|
||||
this.searchSuggestionsNotification.style.paddingInlineStart = padding + "px";
|
||||
} else {
|
||||
this.searchSuggestionsNotification.style.removeProperty("padding-inline-start");
|
||||
}
|
||||
|
||||
// We want to animate the opt-out hint only once.
|
||||
if (!this._firstSearchSuggestionsNotification) {
|
||||
this._firstSearchSuggestionsNotification = true;
|
||||
this.searchSuggestionsNotification.setAttribute("animate", "true");
|
||||
}
|
||||
}
|
||||
this.searchSuggestionsNotification.setAttribute("selectedIndex", deckIndex);
|
||||
|
||||
let ariaDescElt = whichNotification == "opt-in" ?
|
||||
"search-suggestions-question" : "search-suggestions-hint";
|
||||
|
||||
this.searchSuggestionsNotification.setAttribute("aria-describedby", ariaDescElt);
|
||||
|
||||
// With the notification shown, the listbox's height can sometimes be
|
||||
// too small when it's flexed, as it normally is. Also, it can start
|
||||
// out slightly scrolled down. Both problems appear together, most
|
||||
|
@ -1704,6 +1827,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||
this.classList.remove("showSearchSuggestionsNotification");
|
||||
this.richlistbox.flex = 1;
|
||||
this.removeAttribute("dontanimate");
|
||||
this.searchSuggestionsNotification.removeAttribute("animate");
|
||||
if (this._matchCount) {
|
||||
// Update popup height.
|
||||
this._invalidate();
|
||||
|
|
|
@ -10,10 +10,11 @@
|
|||
|
||||
function setup() {
|
||||
const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
|
||||
let suggestionsEnabled = Services.prefs.getBoolPref(SUGGEST_URLBAR_PREF);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, false);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, suggestionsEnabled);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -60,12 +60,13 @@ function addSearchEngine(basename) {
|
|||
|
||||
async function prepareSearchEngine() {
|
||||
let oldCurrentEngine = Services.search.currentEngine;
|
||||
let suggestionsEnabled = Services.prefs.getBoolPref(SUGGEST_URLBAR_PREF);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
|
||||
let engine = await addSearchEngine(TEST_ENGINE_BASENAME);
|
||||
Services.search.currentEngine = engine;
|
||||
|
||||
registerCleanupFunction(async function() {
|
||||
Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, suggestionsEnabled);
|
||||
Services.search.currentEngine = oldCurrentEngine;
|
||||
|
||||
// Make sure the popup is closed for the next test.
|
||||
|
|
|
@ -419,7 +419,16 @@ These should match what Safari and other Apple applications use on OS X Lion. --
|
|||
<!ENTITY urlbar.searchSuggestionsNotification.enable "Yes">
|
||||
<!ENTITY urlbar.searchSuggestionsNotification.enable.accesskey "y">
|
||||
|
||||
<!--
|
||||
<!-- LOCALIZATION NOTE (urlbar.searchSuggestionsNotification.hintPrefix): Shown just before the suggestions opt-out hint. -->
|
||||
<!ENTITY urlbar.searchSuggestionsNotification.hintPrefix "Tip:">
|
||||
<!-- LOCALIZATION NOTE (urlbar.searchSuggestionsNotification.hint): 🔎 is the magnifier icon emoji, please don't change it. -->
|
||||
<!ENTITY urlbar.searchSuggestionsNotification.hint "Get help finding things! Look for the 🔎 next to search suggestions.">
|
||||
<!ENTITY urlbar.searchSuggestionsNotification.changeSettingsWin "Change Options…">
|
||||
<!ENTITY urlbar.searchSuggestionsNotification.changeSettingsWin.accesskey "C">
|
||||
<!ENTITY urlbar.searchSuggestionsNotification.changeSettingsUnix "Change Preferences…">
|
||||
<!ENTITY urlbar.searchSuggestionsNotification.changeSettingsUnix.accesskey "C">
|
||||
|
||||
<!--
|
||||
Comment duplicated from browser-sets.inc:
|
||||
|
||||
Search Command Key Logic works like this:
|
||||
|
|
|
@ -72,6 +72,7 @@ add_task(async function setup() {
|
|||
Services.search.moveEngine(engine, 0);
|
||||
|
||||
// Enable search suggestions in the urlbar.
|
||||
let suggestionsEnabled = Services.prefs.getBoolPref(SUGGEST_URLBAR_PREF);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
|
||||
|
||||
// Enable the urlbar one-off buttons.
|
||||
|
@ -96,7 +97,7 @@ add_task(async function setup() {
|
|||
Services.telemetry.canRecordExtended = oldCanRecord;
|
||||
Services.search.currentEngine = originalEngine;
|
||||
Services.search.removeEngine(engine);
|
||||
Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, suggestionsEnabled);
|
||||
Services.prefs.clearUserPref(ONEOFF_URLBAR_PREF);
|
||||
await PlacesTestUtils.clearHistory();
|
||||
Services.telemetry.setEventRecordingEnabled("navigation", false);
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
#PopupAutoCompleteRichResult > hbox[anonid="search-suggestions-notification"] {
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"] {
|
||||
border-bottom: 1px solid var(--panel-separator-color);
|
||||
background-color: hsla(210, 4%, 10%, 0.07);
|
||||
padding-inline-start: 0;
|
||||
padding-inline-end: 6px;
|
||||
min-height: 3em;
|
||||
}
|
||||
|
||||
/* Opt-in notification */
|
||||
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"] > hbox[anonid="search-suggestions-opt-in"] {
|
||||
padding: 6px 0;
|
||||
padding-inline-start: 44px;
|
||||
padding-inline-end: 6px;
|
||||
background-color: hsla(210, 4%, 10%, 0.07);
|
||||
background-image: url("chrome://browser/skin/info.svg");
|
||||
background-clip: padding-box;
|
||||
background-position: 20px center;
|
||||
|
@ -11,44 +18,146 @@
|
|||
background-size: 16px 16px;
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > hbox[anonid="search-suggestions-notification"]:-moz-locale-dir(rtl) {
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"] > hbox[anonid="search-suggestions-opt-in"]:-moz-locale-dir(rtl) {
|
||||
background-position: right 20px center;
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > hbox[anonid="search-suggestions-notification"] > description {
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"] > hbox[anonid="search-suggestions-opt-in"] > description {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > hbox[anonid="search-suggestions-notification"] > description > label.text-link {
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"] > hbox[anonid="search-suggestions-opt-in"] > description > label.text-link {
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > hbox[anonid="search-suggestions-notification"] > button {
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"] button {
|
||||
-moz-appearance: none;
|
||||
min-width: 80px;
|
||||
border-radius: 3px;
|
||||
padding: 4px 16px;
|
||||
margin: 0;
|
||||
margin-inline-start: 10px;
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > hbox[anonid="search-suggestions-notification"] > button[anonid="search-suggestions-notification-disable"] {
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"] button[anonid="search-suggestions-notification-disable"] {
|
||||
color: hsl(210, 0%, 38%);
|
||||
background-color: hsl(210, 0%, 88%);
|
||||
border: 1px solid hsl(210, 0%, 82%);
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > hbox[anonid="search-suggestions-notification"] > button[anonid="search-suggestions-notification-disable"]:hover {
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"] button[anonid="search-suggestions-notification-disable"]:hover {
|
||||
background-color: hsl(210, 0%, 84%);
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > hbox[anonid="search-suggestions-notification"] > button[anonid="search-suggestions-notification-enable"] {
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"] button[anonid="search-suggestions-notification-enable"] {
|
||||
color: white;
|
||||
background-color: hsl(93, 82%, 44%);
|
||||
border: 1px solid hsl(93, 82%, 44%);
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > hbox[anonid="search-suggestions-notification"] > button[anonid="search-suggestions-notification-enable"]:hover {
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"] button[anonid="search-suggestions-notification-enable"]:hover {
|
||||
background-color: hsl(93, 82%, 40%);
|
||||
}
|
||||
|
||||
/* Opt-out hint */
|
||||
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"] > hbox[anonid="search-suggestions-opt-out"] {
|
||||
font: message-box;
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"] hbox[anonid="search-suggestions-hint-box"] > description {
|
||||
margin: auto;
|
||||
padding: 4px 8px;
|
||||
background-color: #ffeebe;
|
||||
border: 1px solid #ffdf81;
|
||||
border-radius: 4px;
|
||||
color: #7d3500;
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"] hbox[anonid="search-suggestions-hint-box"] > description > html|span {
|
||||
unicode-bidi: embed;
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"] hbox[anonid="search-suggestions-hint-box"] > description > html|span.prefix {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"][animate] > hbox[anonid="search-suggestions-opt-out"] > .ac-site-icon {
|
||||
transform: scale(0);
|
||||
animation-name: search-suggestions-hint-grow;
|
||||
animation-duration: 500ms;
|
||||
animation-delay: 500ms;
|
||||
animation-iteration-count: 1;
|
||||
animation-timing-function: ease-in-out;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@keyframes search-suggestions-hint-grow {
|
||||
0% { transform: scale(0); }
|
||||
40% { transform: scale(1.5); }
|
||||
60% { transform: scale(1); }
|
||||
80% { transform: scale(1.25); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"][animate] hbox[anonid="search-suggestions-hint-typing"] > .ac-title-text {
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"][animate] hbox[anonid="search-suggestions-hint-typing"] {
|
||||
overflow: hidden;
|
||||
max-width: 8ch;
|
||||
width: 0;
|
||||
animation-name: search-suggestions-hint-typing;
|
||||
animation-duration: 500ms;
|
||||
animation-delay: 750ms;
|
||||
animation-iteration-count: 1;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@keyframes search-suggestions-hint-typing {
|
||||
from { width: 0; }
|
||||
to { width: 8ch; }
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"][animate] hbox[anonid="search-suggestions-hint-box"] {
|
||||
opacity: 0;
|
||||
animation-duration: 250ms;
|
||||
animation-delay: 1500ms;
|
||||
animation-iteration-count: 1;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
/* Margin-inline-start can't be animated yet */
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"][animate] hbox[anonid="search-suggestions-hint-box"]:-moz-locale-dir(ltr) {
|
||||
margin-left: 160px;
|
||||
animation-name: search-suggestions-hint-buildin-ltr;
|
||||
}
|
||||
|
||||
@keyframes search-suggestions-hint-buildin-ltr {
|
||||
from { margin-left: 160px; opacity: 0; }
|
||||
to { margin-left: 0; opacity: 1; }
|
||||
}
|
||||
|
||||
#PopupAutoCompleteRichResult > deck[anonid="search-suggestions-notification"][animate] hbox[anonid="search-suggestions-hint-box"]:-moz-locale-dir(rtl) {
|
||||
/* Should be margin-inline-start but that can't be animated yet */
|
||||
margin-right: 160px;
|
||||
animation-name: search-suggestions-hint-buildin-rtl;
|
||||
}
|
||||
|
||||
@keyframes search-suggestions-hint-buildin-rtl {
|
||||
from { margin-right: 160px; opacity: 0; }
|
||||
to { margin-right: 0; opacity: 1; }
|
||||
}
|
||||
|
||||
#search-suggestions-change-settings {
|
||||
opacity: 0;
|
||||
animation-name: search-suggestions-hint-fadein;
|
||||
animation-duration: 500ms;
|
||||
animation-delay: 1800ms;
|
||||
animation-iteration-count: 1;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@keyframes search-suggestions-hint-fadein {
|
||||
from { opacity: 0 }
|
||||
to { opacity: 1 }
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче