зеркало из https://github.com/mozilla/gecko-dev.git
411 строки
14 KiB
JavaScript
411 строки
14 KiB
JavaScript
/* 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/. */
|
|
|
|
"use strict";
|
|
|
|
/**
|
|
* This module exports the UrlbarPrefs singleton, which manages
|
|
* preferences for the urlbar.
|
|
*/
|
|
|
|
var EXPORTED_SYMBOLS = ["UrlbarPrefs"];
|
|
|
|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|
const { XPCOMUtils } = ChromeUtils.import(
|
|
"resource://gre/modules/XPCOMUtils.jsm"
|
|
);
|
|
|
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
|
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
|
|
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
|
|
});
|
|
|
|
const PREF_URLBAR_BRANCH = "browser.urlbar.";
|
|
|
|
// Prefs are defined as [pref name, default value] or [pref name, [default
|
|
// value, type]]. In the former case, the getter method name is inferred from
|
|
// the typeof the default value.
|
|
const PREF_URLBAR_DEFAULTS = new Map([
|
|
// "Autofill" is the name of the feature that automatically completes domains
|
|
// and URLs that the user has visited as the user is typing them in the urlbar
|
|
// textbox. If false, autofill will be disabled.
|
|
["autoFill", true],
|
|
|
|
// If true, the domains of the user's installed search engines will be
|
|
// autofilled even if the user hasn't actually visited them.
|
|
["autoFill.searchEngines", false],
|
|
|
|
// Affects the frecency threshold of the autofill algorithm. The threshold is
|
|
// the mean of all origin frecencies plus one standard deviation multiplied by
|
|
// this value. See UnifiedComplete.
|
|
["autoFill.stddevMultiplier", [0.0, "float"]],
|
|
|
|
// Whether using `ctrl` when hitting return/enter in the URL bar
|
|
// (or clicking 'go') should prefix 'www.' and suffix
|
|
// browser.fixup.alternate.suffix to the URL bar value prior to
|
|
// navigating.
|
|
["ctrlCanonizesURLs", true],
|
|
|
|
// Whether copying the entire URL from the location bar will put a human
|
|
// readable (percent-decoded) URL on the clipboard.
|
|
["decodeURLsOnCopy", false],
|
|
|
|
// The amount of time (ms) to wait after the user has stopped typing before
|
|
// fetching results. However, we ignore this for the very first result (the
|
|
// "heuristic" result). We fetch it as fast as possible.
|
|
["delay", 50],
|
|
|
|
// Some performance tests disable this because extending the urlbar needs
|
|
// layout information that we can't get before the first paint. (Or we could
|
|
// but this would mean flushing layout.)
|
|
["disableExtendForTests", false],
|
|
|
|
// Whether telemetry events should be recorded.
|
|
["eventTelemetry.enabled", false],
|
|
|
|
// When true, `javascript:` URLs are not included in search results.
|
|
["filter.javascript", true],
|
|
|
|
// Applies URL highlighting and other styling to the text in the urlbar input.
|
|
["formatting.enabled", false],
|
|
|
|
// Controls the composition of search results.
|
|
["matchBuckets", "suggestion:4,general:Infinity"],
|
|
|
|
// If the heuristic result is a search engine result, we use this instead of
|
|
// matchBuckets.
|
|
["matchBucketsSearch", ""],
|
|
|
|
// For search suggestion results, we truncate the user's search string to this
|
|
// number of characters before fetching results.
|
|
["maxCharsForSearchSuggestions", 20],
|
|
|
|
// May be removed in the future. Usually (when this pref is at its default of
|
|
// zero), search engine results do not include results from the user's local
|
|
// browser history. This value can be set to include such results.
|
|
["maxHistoricalSearchSuggestions", 0],
|
|
|
|
// The maximum number of results in the urlbar popup.
|
|
["maxRichResults", 10],
|
|
|
|
// Whether addresses and search results typed into the address bar
|
|
// should be opened in new tabs by default.
|
|
["openintab", false],
|
|
|
|
// Whether to open the urlbar view when the input field is focused by the user.
|
|
["openViewOnFocus", true],
|
|
|
|
// When true, URLs in the user's history that look like search result pages
|
|
// are styled to look like search engine results instead of the usual history
|
|
// results.
|
|
["restyleSearches", false],
|
|
|
|
// Hidden pref. Disables checks that prevent search tips being shown, thus
|
|
// showing them every time the newtab page or the default search engine
|
|
// homepage is opened.
|
|
["searchTips.test.ignoreShowLimits", false],
|
|
|
|
// Whether speculative connections should be enabled.
|
|
["speculativeConnect.enabled", true],
|
|
|
|
// Results will include the user's bookmarks when this is true.
|
|
["suggest.bookmark", true],
|
|
|
|
// Results will include the user's history when this is true.
|
|
["suggest.history", true],
|
|
|
|
// Results will include switch-to-tab results when this is true.
|
|
["suggest.openpage", true],
|
|
|
|
// Results will include search suggestions when this is true.
|
|
["suggest.searches", false],
|
|
|
|
// When using switch to tabs, if set to true this will move the tab into the
|
|
// active window.
|
|
["switchTabs.adoptIntoActiveWindow", false],
|
|
|
|
// The number of times the user has been shown the onboarding search tip.
|
|
["tipShownCount.searchTip_onboard", 0],
|
|
|
|
// The number of times the user has been shown the redirect search tip.
|
|
["tipShownCount.searchTip_redirect", 0],
|
|
|
|
// Remove redundant portions from URLs.
|
|
["trimURLs", true],
|
|
|
|
// Results will include a built-in set of popular domains when this is true.
|
|
["usepreloadedtopurls.enabled", true],
|
|
|
|
// After this many days from the profile creation date, the built-in set of
|
|
// popular domains will no longer be included in the results.
|
|
["usepreloadedtopurls.expire_days", 14],
|
|
|
|
// If true, we show actionable tips in the Urlbar when the user is searching
|
|
// for those actions.
|
|
["update1.interventions", true],
|
|
|
|
// If true, we show new users and those about to start an organic search a tip
|
|
// encouraging them to use the Urlbar.
|
|
["update1.searchTips", true],
|
|
|
|
// Whether the urlbar displays a permanent search button in design update 2.
|
|
["update2.searchButton", false],
|
|
]);
|
|
const PREF_OTHER_DEFAULTS = new Map([
|
|
["keyword.enabled", true],
|
|
["browser.search.suggest.enabled", true],
|
|
["browser.search.suggest.enabled.private", false],
|
|
["ui.popup.disable_autohide", false],
|
|
["browser.fixup.dns_first_for_single_words", false],
|
|
]);
|
|
|
|
// Maps preferences under browser.urlbar.suggest to behavior names, as defined
|
|
// in mozIPlacesAutoComplete.
|
|
const SUGGEST_PREF_TO_BEHAVIOR = {
|
|
history: "history",
|
|
bookmark: "bookmark",
|
|
openpage: "openpage",
|
|
searches: "search",
|
|
};
|
|
|
|
const PREF_TYPES = new Map([
|
|
["boolean", "Bool"],
|
|
["float", "Float"],
|
|
["number", "Int"],
|
|
["string", "Char"],
|
|
]);
|
|
|
|
// Buckets for result insertion.
|
|
// Every time a new result is returned, we go through each bucket in array order,
|
|
// and look for the first one having available space for the given result type.
|
|
// Each bucket is an array containing the following indices:
|
|
// 0: The result type of the acceptable entries.
|
|
// 1: available number of slots in this bucket.
|
|
// There are different matchBuckets definition for different contexts, currently
|
|
// a general one (matchBuckets) and a search one (matchBucketsSearch).
|
|
//
|
|
// First buckets. Anything with an Infinity frecency ends up here.
|
|
const DEFAULT_BUCKETS_BEFORE = [
|
|
[UrlbarUtils.RESULT_GROUP.HEURISTIC, 1],
|
|
[
|
|
UrlbarUtils.RESULT_GROUP.EXTENSION,
|
|
UrlbarUtils.MAXIMUM_ALLOWED_EXTENSION_MATCHES - 1,
|
|
],
|
|
];
|
|
// => USER DEFINED BUCKETS WILL BE INSERTED HERE <=
|
|
//
|
|
// Catch-all buckets. Anything remaining ends up here.
|
|
const DEFAULT_BUCKETS_AFTER = [
|
|
[UrlbarUtils.RESULT_GROUP.SUGGESTION, Infinity],
|
|
[UrlbarUtils.RESULT_GROUP.GENERAL, Infinity],
|
|
];
|
|
|
|
/**
|
|
* Preferences class. The exported object is a singleton instance.
|
|
*/
|
|
class Preferences {
|
|
/**
|
|
* Constructor
|
|
*/
|
|
constructor() {
|
|
this._map = new Map();
|
|
this.QueryInterface = ChromeUtils.generateQI([
|
|
Ci.nsIObserver,
|
|
Ci.nsISupportsWeakReference,
|
|
]);
|
|
Services.prefs.addObserver(PREF_URLBAR_BRANCH, this, true);
|
|
for (let pref of PREF_OTHER_DEFAULTS.keys()) {
|
|
Services.prefs.addObserver(pref, this, true);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the value for the preference with the given name.
|
|
* For preferences in the "browser.urlbar."" branch, the passed-in name
|
|
* should be relative to the branch. It's also possible to get prefs from the
|
|
* PREF_OTHER_DEFAULTS Map, specifying their full name.
|
|
*
|
|
* @param {string} pref
|
|
* The name of the preference to get.
|
|
* @returns {*} The preference value.
|
|
*/
|
|
get(pref) {
|
|
if (!this._map.has(pref)) {
|
|
this._map.set(pref, this._getPrefValue(pref));
|
|
}
|
|
return this._map.get(pref);
|
|
}
|
|
|
|
/**
|
|
* Sets the value for the preference with the given name.
|
|
* For preferences in the "browser.urlbar."" branch, the passed-in name
|
|
* should be relative to the branch. It's also possible to set prefs from the
|
|
* PREF_OTHER_DEFAULTS Map, specifying their full name.
|
|
*
|
|
* @param {string} pref
|
|
* The name of the preference to set.
|
|
* @param {*} value The preference value.
|
|
*/
|
|
set(pref, value) {
|
|
let { defaultValue, setter } = this._getPrefDescriptor(pref);
|
|
if (typeof value != typeof defaultValue) {
|
|
throw new Error(`Invalid value type ${typeof value} for pref ${pref}`);
|
|
}
|
|
setter(pref, value);
|
|
}
|
|
|
|
/**
|
|
* Observes preference changes.
|
|
*
|
|
* @param {nsISupports} subject
|
|
* @param {string} topic
|
|
* @param {string} data
|
|
*/
|
|
observe(subject, topic, data) {
|
|
let pref = data.replace(PREF_URLBAR_BRANCH, "");
|
|
if (!PREF_URLBAR_DEFAULTS.has(pref) && !PREF_OTHER_DEFAULTS.has(pref)) {
|
|
return;
|
|
}
|
|
this._map.delete(pref);
|
|
// Some prefs may influence others.
|
|
if (pref == "matchBuckets") {
|
|
this._map.delete("matchBucketsSearch");
|
|
}
|
|
if (pref.startsWith("suggest.")) {
|
|
this._map.delete("defaultBehavior");
|
|
this._map.delete("emptySearchDefaultBehavior");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the raw value of the given preference straight from Services.prefs.
|
|
*
|
|
* @param {string} pref
|
|
* The name of the preference to get.
|
|
* @returns {*} The raw preference value.
|
|
*/
|
|
_readPref(pref) {
|
|
let { defaultValue, getter } = this._getPrefDescriptor(pref);
|
|
return getter(pref, defaultValue);
|
|
}
|
|
|
|
/**
|
|
* Returns a validated and/or fixed-up value of the given preference. The
|
|
* value may be validated for correctness, or it might be converted into a
|
|
* different value that is easier to work with than the actual value stored in
|
|
* the preferences branch. Not all preferences require validation or fixup.
|
|
*
|
|
* The values returned from this method are the values that are made public by
|
|
* this module.
|
|
*
|
|
* @param {string} pref
|
|
* The name of the preference to get.
|
|
* @returns {*} The validated and/or fixed-up preference value.
|
|
*/
|
|
_getPrefValue(pref) {
|
|
switch (pref) {
|
|
case "matchBuckets": {
|
|
// Convert from pref char format to an array and add the default
|
|
// buckets.
|
|
let val = this._readPref(pref);
|
|
try {
|
|
val = PlacesUtils.convertMatchBucketsStringToArray(val);
|
|
} catch (ex) {
|
|
val = PlacesUtils.convertMatchBucketsStringToArray(
|
|
PREF_URLBAR_DEFAULTS.get(pref)
|
|
);
|
|
}
|
|
return [...DEFAULT_BUCKETS_BEFORE, ...val, ...DEFAULT_BUCKETS_AFTER];
|
|
}
|
|
case "matchBucketsSearch": {
|
|
// Convert from pref char format to an array and add the default
|
|
// buckets.
|
|
let val = this._readPref(pref);
|
|
if (val) {
|
|
// Convert from pref char format to an array and add the default
|
|
// buckets.
|
|
try {
|
|
val = PlacesUtils.convertMatchBucketsStringToArray(val);
|
|
return [
|
|
...DEFAULT_BUCKETS_BEFORE,
|
|
...val,
|
|
...DEFAULT_BUCKETS_AFTER,
|
|
];
|
|
} catch (ex) {
|
|
/* invalid format, will just return matchBuckets */
|
|
}
|
|
}
|
|
return this.get("matchBuckets");
|
|
}
|
|
case "defaultBehavior": {
|
|
let val = 0;
|
|
for (let type of Object.keys(SUGGEST_PREF_TO_BEHAVIOR)) {
|
|
let behavior = `BEHAVIOR_${SUGGEST_PREF_TO_BEHAVIOR[
|
|
type
|
|
].toUpperCase()}`;
|
|
val |=
|
|
this.get("suggest." + type) && Ci.mozIPlacesAutoComplete[behavior];
|
|
}
|
|
return val;
|
|
}
|
|
case "emptySearchDefaultBehavior": {
|
|
// Further restrictions to apply for "empty searches" (searching for
|
|
// ""). The empty behavior is typed history, if history is enabled.
|
|
// Otherwise, it is bookmarks, if they are enabled. If both history and
|
|
// bookmarks are disabled, it defaults to open pages.
|
|
let val = Ci.mozIPlacesAutoComplete.BEHAVIOR_RESTRICT;
|
|
if (this.get("suggest.history")) {
|
|
val |= Ci.mozIPlacesAutoComplete.BEHAVIOR_HISTORY;
|
|
} else if (this.get("suggest.bookmark")) {
|
|
val |= Ci.mozIPlacesAutoComplete.BEHAVIOR_BOOKMARK;
|
|
} else {
|
|
val |= Ci.mozIPlacesAutoComplete.BEHAVIOR_OPENPAGE;
|
|
}
|
|
return val;
|
|
}
|
|
}
|
|
return this._readPref(pref);
|
|
}
|
|
|
|
/**
|
|
* Returns a descriptor of the given preference.
|
|
* @param {string} pref The preference to examine.
|
|
* @returns {object} An object describing the pref with the following shape:
|
|
* { defaultValue, getter, setter }
|
|
*/
|
|
_getPrefDescriptor(pref) {
|
|
let branch = Services.prefs.getBranch(PREF_URLBAR_BRANCH);
|
|
let defaultValue = PREF_URLBAR_DEFAULTS.get(pref);
|
|
if (defaultValue === undefined) {
|
|
branch = Services.prefs;
|
|
defaultValue = PREF_OTHER_DEFAULTS.get(pref);
|
|
}
|
|
if (defaultValue === undefined) {
|
|
throw new Error("Trying to access an unknown pref " + pref);
|
|
}
|
|
|
|
let type;
|
|
if (!Array.isArray(defaultValue)) {
|
|
type = PREF_TYPES.get(typeof defaultValue);
|
|
} else {
|
|
if (defaultValue.length != 2) {
|
|
throw new Error("Malformed pref def: " + pref);
|
|
}
|
|
[defaultValue, type] = defaultValue;
|
|
type = PREF_TYPES.get(type);
|
|
}
|
|
if (!type) {
|
|
throw new Error("Unknown pref type: " + pref);
|
|
}
|
|
return {
|
|
defaultValue,
|
|
getter: branch[`get${type}Pref`],
|
|
// Float prefs are stored as Char.
|
|
setter: branch[`set${type == "Float" ? "Char" : type}Pref`],
|
|
};
|
|
}
|
|
}
|
|
|
|
var UrlbarPrefs = new Preferences();
|