зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1410412 implement browser setting onChange event r=zombie
Differential Revision: https://phabricator.services.mozilla.com/D51324 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
f17dad37f7
Коммит
4c534e5697
|
@ -225,17 +225,17 @@ this.urlbar = class extends ExtensionAPI {
|
||||||
},
|
},
|
||||||
}).api(),
|
}).api(),
|
||||||
|
|
||||||
openViewOnFocus: getSettingsAPI(
|
openViewOnFocus: getSettingsAPI({
|
||||||
context.extension.id,
|
context,
|
||||||
"openViewOnFocus",
|
name: "openViewOnFocus",
|
||||||
() => UrlbarPrefs.get("openViewOnFocus")
|
callback: () => UrlbarPrefs.get("openViewOnFocus"),
|
||||||
),
|
}),
|
||||||
|
|
||||||
engagementTelemetry: getSettingsAPI(
|
engagementTelemetry: getSettingsAPI({
|
||||||
context.extension.id,
|
context,
|
||||||
"engagementTelemetry",
|
name: "engagementTelemetry",
|
||||||
() => UrlbarPrefs.get("eventTelemetry.enabled")
|
callback: () => UrlbarPrefs.get("eventTelemetry.enabled"),
|
||||||
),
|
}),
|
||||||
|
|
||||||
contextualTip: {
|
contextualTip: {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
|
|
||||||
var EXPORTED_SYMBOLS = ["ExtensionPreferencesManager"];
|
var EXPORTED_SYMBOLS = ["ExtensionPreferencesManager"];
|
||||||
|
|
||||||
|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
const { Management } = ChromeUtils.import(
|
const { Management } = ChromeUtils.import(
|
||||||
"resource://gre/modules/Extension.jsm",
|
"resource://gre/modules/Extension.jsm",
|
||||||
null
|
null
|
||||||
|
@ -41,6 +43,17 @@ ChromeUtils.defineModuleGetter(
|
||||||
"Preferences",
|
"Preferences",
|
||||||
"resource://gre/modules/Preferences.jsm"
|
"resource://gre/modules/Preferences.jsm"
|
||||||
);
|
);
|
||||||
|
ChromeUtils.defineModuleGetter(
|
||||||
|
this,
|
||||||
|
"ExtensionCommon",
|
||||||
|
"resource://gre/modules/ExtensionCommon.jsm"
|
||||||
|
);
|
||||||
|
|
||||||
|
const { ExtensionUtils } = ChromeUtils.import(
|
||||||
|
"resource://gre/modules/ExtensionUtils.jsm"
|
||||||
|
);
|
||||||
|
|
||||||
|
const { ExtensionError } = ExtensionUtils;
|
||||||
|
|
||||||
XPCOMUtils.defineLazyGetter(this, "defaultPreferences", function() {
|
XPCOMUtils.defineLazyGetter(this, "defaultPreferences", function() {
|
||||||
return new Preferences({ defaultBranch: true });
|
return new Preferences({ defaultBranch: true });
|
||||||
|
@ -52,12 +65,12 @@ Management.on("uninstall", (type, { id }) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Management.on("disable", (type, id) => {
|
Management.on("disable", (type, id) => {
|
||||||
this.ExtensionPreferencesManager.disableAll(id);
|
ExtensionPreferencesManager.disableAll(id);
|
||||||
});
|
});
|
||||||
|
|
||||||
Management.on("startup", async (type, extension) => {
|
Management.on("startup", async (type, extension) => {
|
||||||
if (extension.startupReason == "ADDON_ENABLE") {
|
if (extension.startupReason == "ADDON_ENABLE") {
|
||||||
this.ExtensionPreferencesManager.enableAll(extension.id);
|
ExtensionPreferencesManager.enableAll(extension.id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
/* eslint-enable mozilla/balanced-listeners */
|
/* eslint-enable mozilla/balanced-listeners */
|
||||||
|
@ -115,6 +128,8 @@ function settingsUpdate(initialValue) {
|
||||||
/**
|
/**
|
||||||
* Loops through a set of prefs, either setting or resetting them.
|
* Loops through a set of prefs, either setting or resetting them.
|
||||||
*
|
*
|
||||||
|
* @param {string} name
|
||||||
|
* The api name of the setting.
|
||||||
* @param {Object} setting
|
* @param {Object} setting
|
||||||
* An object that represents a setting, which will have a setCallback
|
* An object that represents a setting, which will have a setCallback
|
||||||
* property. If a onPrefsChanged function is provided it will be called
|
* property. If a onPrefsChanged function is provided it will be called
|
||||||
|
@ -123,7 +138,7 @@ function settingsUpdate(initialValue) {
|
||||||
* An object that represents an item handed back from the setting store
|
* An object that represents an item handed back from the setting store
|
||||||
* from which the new pref values can be calculated.
|
* from which the new pref values can be calculated.
|
||||||
*/
|
*/
|
||||||
function setPrefs(setting, item) {
|
function setPrefs(name, setting, item) {
|
||||||
let prefs = item.initialValue || setting.setCallback(item.value);
|
let prefs = item.initialValue || setting.setCallback(item.value);
|
||||||
let changed = false;
|
let changed = false;
|
||||||
for (let pref of setting.prefNames) {
|
for (let pref of setting.prefNames) {
|
||||||
|
@ -140,6 +155,7 @@ function setPrefs(setting, item) {
|
||||||
if (changed && typeof setting.onPrefsChanged == "function") {
|
if (changed && typeof setting.onPrefsChanged == "function") {
|
||||||
setting.onPrefsChanged(item);
|
setting.onPrefsChanged(item);
|
||||||
}
|
}
|
||||||
|
Management.emit(`extension-setting-changed:${name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -181,7 +197,7 @@ async function processSetting(id, name, action) {
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
setPrefs(setting, item);
|
setPrefs(name, setting, item);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -243,7 +259,7 @@ this.ExtensionPreferencesManager = {
|
||||||
settingsUpdate.bind(setting)
|
settingsUpdate.bind(setting)
|
||||||
);
|
);
|
||||||
if (item) {
|
if (item) {
|
||||||
setPrefs(setting, item);
|
setPrefs(name, setting, item);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -399,18 +415,18 @@ this.ExtensionPreferencesManager = {
|
||||||
/**
|
/**
|
||||||
* Returns an API object with get/set/clear used for a setting.
|
* Returns an API object with get/set/clear used for a setting.
|
||||||
*
|
*
|
||||||
* @param {string} extensionId
|
* @param {string|object} extensionId or params object
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
* The unique id of the setting.
|
* The unique id of the setting.
|
||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
* The function that retreives the current setting from prefs.
|
* The function that retreives the current setting from prefs.
|
||||||
* @param {string} storeType
|
* @param {string} storeType
|
||||||
* The name of the store in ExtensionSettingsStore.
|
* The name of the store in ExtensionSettingsStore.
|
||||||
* Defaults to STORE_TYPE.
|
* Defaults to STORE_TYPE.
|
||||||
* @param {boolean} readOnly
|
* @param {boolean} readOnly
|
||||||
* @param {Function} validate
|
* @param {Function} validate
|
||||||
* Utility function for any specific validation, such as checking
|
* Utility function for any specific validation, such as checking
|
||||||
* for supported platform. Function should throw an error if necessary.
|
* for supported platform. Function should throw an error if necessary.
|
||||||
*
|
*
|
||||||
* @returns {object} API object with get/set/clear methods
|
* @returns {object} API object with get/set/clear methods
|
||||||
*/
|
*/
|
||||||
|
@ -422,7 +438,70 @@ this.ExtensionPreferencesManager = {
|
||||||
readOnly = false,
|
readOnly = false,
|
||||||
validate = () => {}
|
validate = () => {}
|
||||||
) {
|
) {
|
||||||
return {
|
if (arguments.length > 1) {
|
||||||
|
Services.console.logStringMessage(
|
||||||
|
`ExtensionPreferencesManager.getSettingsAPI for ${name} should be updated to use a single paramater object.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return ExtensionPreferencesManager._getSettingsAPI(
|
||||||
|
arguments.length === 1
|
||||||
|
? extensionId
|
||||||
|
: {
|
||||||
|
extensionId,
|
||||||
|
name,
|
||||||
|
callback,
|
||||||
|
storeType,
|
||||||
|
readOnly,
|
||||||
|
validate,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an API object with get/set/clear used for a setting.
|
||||||
|
*
|
||||||
|
* @param {object} params The params object contains the following:
|
||||||
|
* {BaseContext} context
|
||||||
|
* {string} extensionId, optional to support old API
|
||||||
|
* {string} name
|
||||||
|
* The unique id of the setting.
|
||||||
|
* {Function} callback
|
||||||
|
* The function that retreives the current setting from prefs.
|
||||||
|
* {string} storeType
|
||||||
|
* The name of the store in ExtensionSettingsStore.
|
||||||
|
* Defaults to STORE_TYPE.
|
||||||
|
* {boolean} readOnly
|
||||||
|
* {Function} validate
|
||||||
|
* Utility function for any specific validation, such as checking
|
||||||
|
* for supported platform. Function should throw an error if necessary.
|
||||||
|
*
|
||||||
|
* @returns {object} API object with get/set/clear methods
|
||||||
|
*/
|
||||||
|
_getSettingsAPI(params) {
|
||||||
|
let {
|
||||||
|
extensionId,
|
||||||
|
context,
|
||||||
|
name,
|
||||||
|
callback,
|
||||||
|
storeType,
|
||||||
|
readOnly = false,
|
||||||
|
onChange,
|
||||||
|
validate = () => {},
|
||||||
|
} = params;
|
||||||
|
if (!extensionId) {
|
||||||
|
extensionId = context.extension.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkScope = details => {
|
||||||
|
let { scope } = details;
|
||||||
|
if (scope && scope !== "regular") {
|
||||||
|
throw new ExtensionError(
|
||||||
|
`Firefox does not support the ${scope} settings scope.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let settingsAPI = {
|
||||||
async get(details) {
|
async get(details) {
|
||||||
validate();
|
validate();
|
||||||
let levelOfControl = details.incognito
|
let levelOfControl = details.incognito
|
||||||
|
@ -443,6 +522,7 @@ this.ExtensionPreferencesManager = {
|
||||||
},
|
},
|
||||||
set(details) {
|
set(details) {
|
||||||
validate();
|
validate();
|
||||||
|
checkScope(details);
|
||||||
if (!readOnly) {
|
if (!readOnly) {
|
||||||
return ExtensionPreferencesManager.setSetting(
|
return ExtensionPreferencesManager.setSetting(
|
||||||
extensionId,
|
extensionId,
|
||||||
|
@ -454,11 +534,44 @@ this.ExtensionPreferencesManager = {
|
||||||
},
|
},
|
||||||
clear(details) {
|
clear(details) {
|
||||||
validate();
|
validate();
|
||||||
|
checkScope(details);
|
||||||
if (!readOnly) {
|
if (!readOnly) {
|
||||||
return ExtensionPreferencesManager.removeSetting(extensionId, name);
|
return ExtensionPreferencesManager.removeSetting(extensionId, name);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
onChange,
|
||||||
};
|
};
|
||||||
|
// Any caller using the old call signature will not have passed
|
||||||
|
// context to us. This should only be experimental addons in the
|
||||||
|
// wild.
|
||||||
|
if (onChange === undefined && context) {
|
||||||
|
// Some settings that are read-only may not have called addSetting, in
|
||||||
|
// which case we have no way to listen on the pref changes.
|
||||||
|
let setting = settingsMap.get(name);
|
||||||
|
if (!setting) {
|
||||||
|
Services.console.logStringMessage(
|
||||||
|
`ExtensionPreferencesManager API ${name} created but addSetting was not called.`
|
||||||
|
);
|
||||||
|
return settingsAPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
settingsAPI.onChange = new ExtensionCommon.EventManager({
|
||||||
|
context,
|
||||||
|
name: `${name}.onChange`,
|
||||||
|
register: fire => {
|
||||||
|
let listener = async () => {
|
||||||
|
fire.async({
|
||||||
|
details: await settingsAPI.get({}),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Management.on(`extension-setting-changed:${name}`, listener);
|
||||||
|
return () => {
|
||||||
|
Management.off(`extension-setting-changed:${name}`, listener);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}).api();
|
||||||
|
}
|
||||||
|
return settingsAPI;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -78,6 +78,14 @@ ExtensionPreferencesManager.addSetting("contextMenuShowEvent", {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ExtensionPreferencesManager.addSetting(HOMEPAGE_OVERRIDE_SETTING, {
|
||||||
|
prefNames: [HOMEPAGE_URL_PREF],
|
||||||
|
|
||||||
|
setCallback() {
|
||||||
|
throw new Error("Unable to set read-only setting");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
ExtensionPreferencesManager.addSetting("ftpProtocolEnabled", {
|
ExtensionPreferencesManager.addSetting("ftpProtocolEnabled", {
|
||||||
prefNames: ["network.ftp.enabled"],
|
prefNames: ["network.ftp.enabled"],
|
||||||
|
|
||||||
|
@ -161,47 +169,53 @@ this.browserSettings = class extends ExtensionAPI {
|
||||||
let { extension } = context;
|
let { extension } = context;
|
||||||
return {
|
return {
|
||||||
browserSettings: {
|
browserSettings: {
|
||||||
allowPopupsForUserEvents: getSettingsAPI(
|
allowPopupsForUserEvents: getSettingsAPI({
|
||||||
extension.id,
|
context,
|
||||||
"allowPopupsForUserEvents",
|
name: "allowPopupsForUserEvents",
|
||||||
() => {
|
callback() {
|
||||||
return Services.prefs.getCharPref("dom.popup_allowed_events") != "";
|
return Services.prefs.getCharPref("dom.popup_allowed_events") != "";
|
||||||
}
|
},
|
||||||
),
|
|
||||||
cacheEnabled: getSettingsAPI(extension.id, "cacheEnabled", () => {
|
|
||||||
return (
|
|
||||||
Services.prefs.getBoolPref("browser.cache.disk.enable") &&
|
|
||||||
Services.prefs.getBoolPref("browser.cache.memory.enable")
|
|
||||||
);
|
|
||||||
}),
|
}),
|
||||||
closeTabsByDoubleClick: getSettingsAPI(
|
cacheEnabled: getSettingsAPI({
|
||||||
extension.id,
|
context,
|
||||||
"closeTabsByDoubleClick",
|
name: "cacheEnabled",
|
||||||
() => {
|
callback() {
|
||||||
|
return (
|
||||||
|
Services.prefs.getBoolPref("browser.cache.disk.enable") &&
|
||||||
|
Services.prefs.getBoolPref("browser.cache.memory.enable")
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
closeTabsByDoubleClick: getSettingsAPI({
|
||||||
|
context,
|
||||||
|
name: "closeTabsByDoubleClick",
|
||||||
|
callback() {
|
||||||
return Services.prefs.getBoolPref(
|
return Services.prefs.getBoolPref(
|
||||||
"browser.tabs.closeTabByDblclick"
|
"browser.tabs.closeTabByDblclick"
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
undefined,
|
validate() {
|
||||||
false,
|
|
||||||
() => {
|
|
||||||
if (AppConstants.platform == "android") {
|
if (AppConstants.platform == "android") {
|
||||||
throw new ExtensionError(
|
throw new ExtensionError(
|
||||||
`android is not a supported platform for the closeTabsByDoubleClick setting.`
|
`android is not a supported platform for the closeTabsByDoubleClick setting.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
contextMenuShowEvent: Object.assign(
|
contextMenuShowEvent: Object.assign(
|
||||||
getSettingsAPI(extension.id, "contextMenuShowEvent", () => {
|
getSettingsAPI({
|
||||||
if (AppConstants.platform === "win") {
|
context,
|
||||||
return "mouseup";
|
name: "contextMenuShowEvent",
|
||||||
}
|
callback() {
|
||||||
let prefValue = Services.prefs.getBoolPref(
|
if (AppConstants.platform === "win") {
|
||||||
"ui.context_menus.after_mouseup",
|
return "mouseup";
|
||||||
null
|
}
|
||||||
);
|
let prefValue = Services.prefs.getBoolPref(
|
||||||
return prefValue ? "mouseup" : "mousedown";
|
"ui.context_menus.after_mouseup",
|
||||||
|
null
|
||||||
|
);
|
||||||
|
return prefValue ? "mouseup" : "mousedown";
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
set: details => {
|
set: details => {
|
||||||
|
@ -227,94 +241,121 @@ this.browserSettings = class extends ExtensionAPI {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
ftpProtocolEnabled: getSettingsAPI(
|
ftpProtocolEnabled: getSettingsAPI({
|
||||||
extension.id,
|
context,
|
||||||
"ftpProtocolEnabled",
|
name: "ftpProtocolEnabled",
|
||||||
() => {
|
callback() {
|
||||||
return Services.prefs.getBoolPref("network.ftp.enabled");
|
return Services.prefs.getBoolPref("network.ftp.enabled");
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
homepageOverride: getSettingsAPI(
|
homepageOverride: getSettingsAPI({
|
||||||
extension.id,
|
context,
|
||||||
HOMEPAGE_OVERRIDE_SETTING,
|
name: HOMEPAGE_OVERRIDE_SETTING,
|
||||||
() => {
|
callback() {
|
||||||
return Services.prefs.getStringPref(HOMEPAGE_URL_PREF);
|
return Services.prefs.getStringPref(HOMEPAGE_URL_PREF);
|
||||||
},
|
},
|
||||||
undefined,
|
readOnly: true,
|
||||||
true
|
|
||||||
),
|
|
||||||
imageAnimationBehavior: getSettingsAPI(
|
|
||||||
extension.id,
|
|
||||||
"imageAnimationBehavior",
|
|
||||||
() => {
|
|
||||||
return Services.prefs.getCharPref("image.animation_mode");
|
|
||||||
}
|
|
||||||
),
|
|
||||||
newTabPosition: getSettingsAPI(extension.id, "newTabPosition", () => {
|
|
||||||
if (Services.prefs.getBoolPref("browser.tabs.insertAfterCurrent")) {
|
|
||||||
return "afterCurrent";
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
Services.prefs.getBoolPref("browser.tabs.insertRelatedAfterCurrent")
|
|
||||||
) {
|
|
||||||
return "relatedAfterCurrent";
|
|
||||||
}
|
|
||||||
return "atEnd";
|
|
||||||
}),
|
}),
|
||||||
newTabPageOverride: getSettingsAPI(
|
imageAnimationBehavior: getSettingsAPI({
|
||||||
extension.id,
|
context,
|
||||||
NEW_TAB_OVERRIDE_SETTING,
|
name: "imageAnimationBehavior",
|
||||||
() => {
|
callback() {
|
||||||
|
return Services.prefs.getCharPref("image.animation_mode");
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
newTabPosition: getSettingsAPI({
|
||||||
|
context,
|
||||||
|
name: "newTabPosition",
|
||||||
|
callback() {
|
||||||
|
if (Services.prefs.getBoolPref("browser.tabs.insertAfterCurrent")) {
|
||||||
|
return "afterCurrent";
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
Services.prefs.getBoolPref(
|
||||||
|
"browser.tabs.insertRelatedAfterCurrent"
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return "relatedAfterCurrent";
|
||||||
|
}
|
||||||
|
return "atEnd";
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
newTabPageOverride: getSettingsAPI({
|
||||||
|
context,
|
||||||
|
name: NEW_TAB_OVERRIDE_SETTING,
|
||||||
|
callback() {
|
||||||
return aboutNewTabService.newTabURL;
|
return aboutNewTabService.newTabURL;
|
||||||
},
|
},
|
||||||
URL_STORE_TYPE,
|
storeType: URL_STORE_TYPE,
|
||||||
true
|
readOnly: true,
|
||||||
),
|
onChange: new ExtensionCommon.EventManager({
|
||||||
openBookmarksInNewTabs: getSettingsAPI(
|
context,
|
||||||
extension.id,
|
name: `${NEW_TAB_OVERRIDE_SETTING}.onChange`,
|
||||||
"openBookmarksInNewTabs",
|
register: fire => {
|
||||||
() => {
|
let listener = (text, id) => {
|
||||||
|
fire.async({
|
||||||
|
details: {
|
||||||
|
levelOfControl: "not_controllable",
|
||||||
|
value: aboutNewTabService.newTabURL,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Services.obs.addObserver(listener, "newtab-url-changed");
|
||||||
|
return () => {
|
||||||
|
Services.obs.removeObserver(listener, "newtab-url-changed");
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}).api(),
|
||||||
|
}),
|
||||||
|
openBookmarksInNewTabs: getSettingsAPI({
|
||||||
|
context,
|
||||||
|
name: "openBookmarksInNewTabs",
|
||||||
|
callback() {
|
||||||
return Services.prefs.getBoolPref(
|
return Services.prefs.getBoolPref(
|
||||||
"browser.tabs.loadBookmarksInTabs"
|
"browser.tabs.loadBookmarksInTabs"
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
openSearchResultsInNewTabs: getSettingsAPI(
|
openSearchResultsInNewTabs: getSettingsAPI({
|
||||||
extension.id,
|
context,
|
||||||
"openSearchResultsInNewTabs",
|
name: "openSearchResultsInNewTabs",
|
||||||
() => {
|
callback() {
|
||||||
return Services.prefs.getBoolPref("browser.search.openintab");
|
return Services.prefs.getBoolPref("browser.search.openintab");
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
openUrlbarResultsInNewTabs: getSettingsAPI(
|
openUrlbarResultsInNewTabs: getSettingsAPI({
|
||||||
extension.id,
|
context,
|
||||||
"openUrlbarResultsInNewTabs",
|
name: "openUrlbarResultsInNewTabs",
|
||||||
() => {
|
callback() {
|
||||||
return Services.prefs.getBoolPref("browser.urlbar.openintab");
|
return Services.prefs.getBoolPref("browser.urlbar.openintab");
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
webNotificationsDisabled: getSettingsAPI(
|
webNotificationsDisabled: getSettingsAPI({
|
||||||
extension.id,
|
context,
|
||||||
"webNotificationsDisabled",
|
name: "webNotificationsDisabled",
|
||||||
() => {
|
callback() {
|
||||||
let prefValue = Services.prefs.getIntPref(
|
let prefValue = Services.prefs.getIntPref(
|
||||||
"permissions.default.desktop-notification",
|
"permissions.default.desktop-notification",
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
return prefValue === PERM_DENY_ACTION;
|
return prefValue === PERM_DENY_ACTION;
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
overrideDocumentColors: Object.assign(
|
overrideDocumentColors: Object.assign(
|
||||||
getSettingsAPI(extension.id, "overrideDocumentColors", () => {
|
getSettingsAPI({
|
||||||
let prefValue = Services.prefs.getIntPref(
|
context,
|
||||||
"browser.display.document_color_use"
|
name: "overrideDocumentColors",
|
||||||
);
|
callback() {
|
||||||
if (prefValue === 1) {
|
let prefValue = Services.prefs.getIntPref(
|
||||||
return "never";
|
"browser.display.document_color_use"
|
||||||
} else if (prefValue === 2) {
|
);
|
||||||
return "always";
|
if (prefValue === 1) {
|
||||||
}
|
return "never";
|
||||||
return "high-contrast-only";
|
} else if (prefValue === 2) {
|
||||||
|
return "always";
|
||||||
|
}
|
||||||
|
return "high-contrast-only";
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
set: details => {
|
set: details => {
|
||||||
|
@ -344,12 +385,16 @@ this.browserSettings = class extends ExtensionAPI {
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
useDocumentFonts: Object.assign(
|
useDocumentFonts: Object.assign(
|
||||||
getSettingsAPI(extension.id, "useDocumentFonts", () => {
|
getSettingsAPI({
|
||||||
return (
|
context,
|
||||||
Services.prefs.getIntPref(
|
name: "useDocumentFonts",
|
||||||
"browser.display.use_document_fonts"
|
callback() {
|
||||||
) !== 0
|
return (
|
||||||
);
|
Services.prefs.getIntPref(
|
||||||
|
"browser.display.use_document_fonts"
|
||||||
|
) !== 0
|
||||||
|
);
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
set: details => {
|
set: details => {
|
||||||
|
|
|
@ -104,15 +104,14 @@ this.captivePortal = class extends ExtensionAPI {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
}).api(),
|
}).api(),
|
||||||
canonicalURL: getSettingsAPI(
|
canonicalURL: getSettingsAPI({
|
||||||
context.extension.id,
|
context,
|
||||||
"captiveURL",
|
name: "captiveURL",
|
||||||
() => {
|
callback() {
|
||||||
return Services.prefs.getStringPref("captivedetect.canonicalURL");
|
return Services.prefs.getStringPref("captivedetect.canonicalURL");
|
||||||
},
|
},
|
||||||
undefined,
|
readOnly: true,
|
||||||
true
|
}),
|
||||||
),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,7 @@ ChromeUtils.defineModuleGetter(
|
||||||
var { ExtensionPreferencesManager } = ChromeUtils.import(
|
var { ExtensionPreferencesManager } = ChromeUtils.import(
|
||||||
"resource://gre/modules/ExtensionPreferencesManager.jsm"
|
"resource://gre/modules/ExtensionPreferencesManager.jsm"
|
||||||
);
|
);
|
||||||
|
var { getSettingsAPI } = ExtensionPreferencesManager;
|
||||||
var { ExtensionError } = ExtensionUtils;
|
|
||||||
|
|
||||||
const cookieSvc = Ci.nsICookieService;
|
const cookieSvc = Ci.nsICookieService;
|
||||||
|
|
||||||
|
@ -28,42 +27,6 @@ const cookieBehaviorValues = new Map([
|
||||||
["reject_trackers", cookieSvc.BEHAVIOR_REJECT_TRACKER],
|
["reject_trackers", cookieSvc.BEHAVIOR_REJECT_TRACKER],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const checkScope = scope => {
|
|
||||||
if (scope && scope !== "regular") {
|
|
||||||
throw new ExtensionError(
|
|
||||||
`Firefox does not support the ${scope} settings scope.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getPrivacyAPI = (extension, name, callback) => {
|
|
||||||
return {
|
|
||||||
async get(details) {
|
|
||||||
return {
|
|
||||||
levelOfControl: details.incognito
|
|
||||||
? "not_controllable"
|
|
||||||
: await ExtensionPreferencesManager.getLevelOfControl(
|
|
||||||
extension.id,
|
|
||||||
name
|
|
||||||
),
|
|
||||||
value: await callback(),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
set(details) {
|
|
||||||
checkScope(details.scope);
|
|
||||||
return ExtensionPreferencesManager.setSetting(
|
|
||||||
extension.id,
|
|
||||||
name,
|
|
||||||
details.value
|
|
||||||
);
|
|
||||||
},
|
|
||||||
clear(details) {
|
|
||||||
checkScope(details.scope);
|
|
||||||
return ExtensionPreferencesManager.removeSetting(extension.id, name);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add settings objects for supported APIs to the preferences manager.
|
// Add settings objects for supported APIs to the preferences manager.
|
||||||
ExtensionPreferencesManager.addSetting("network.networkPredictionEnabled", {
|
ExtensionPreferencesManager.addSetting("network.networkPredictionEnabled", {
|
||||||
prefNames: [
|
prefNames: [
|
||||||
|
@ -217,14 +180,13 @@ ExtensionPreferencesManager.addSetting("websites.trackingProtectionMode", {
|
||||||
|
|
||||||
this.privacy = class extends ExtensionAPI {
|
this.privacy = class extends ExtensionAPI {
|
||||||
getAPI(context) {
|
getAPI(context) {
|
||||||
let { extension } = context;
|
|
||||||
return {
|
return {
|
||||||
privacy: {
|
privacy: {
|
||||||
network: {
|
network: {
|
||||||
networkPredictionEnabled: getPrivacyAPI(
|
networkPredictionEnabled: getSettingsAPI({
|
||||||
extension,
|
context,
|
||||||
"network.networkPredictionEnabled",
|
name: "network.networkPredictionEnabled",
|
||||||
() => {
|
callback() {
|
||||||
return (
|
return (
|
||||||
Preferences.get("network.predictor.enabled") &&
|
Preferences.get("network.predictor.enabled") &&
|
||||||
Preferences.get("network.prefetch-next") &&
|
Preferences.get("network.prefetch-next") &&
|
||||||
|
@ -232,19 +194,19 @@ this.privacy = class extends ExtensionAPI {
|
||||||
0 &&
|
0 &&
|
||||||
!Preferences.get("network.dns.disablePrefetch")
|
!Preferences.get("network.dns.disablePrefetch")
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
peerConnectionEnabled: getPrivacyAPI(
|
peerConnectionEnabled: getSettingsAPI({
|
||||||
extension,
|
context,
|
||||||
"network.peerConnectionEnabled",
|
name: "network.peerConnectionEnabled",
|
||||||
() => {
|
callback() {
|
||||||
return Preferences.get("media.peerconnection.enabled");
|
return Preferences.get("media.peerconnection.enabled");
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
webRTCIPHandlingPolicy: getPrivacyAPI(
|
webRTCIPHandlingPolicy: getSettingsAPI({
|
||||||
extension,
|
context,
|
||||||
"network.webRTCIPHandlingPolicy",
|
name: "network.webRTCIPHandlingPolicy",
|
||||||
() => {
|
callback() {
|
||||||
if (Preferences.get("media.peerconnection.ice.proxy_only")) {
|
if (Preferences.get("media.peerconnection.ice.proxy_only")) {
|
||||||
return "proxy_only";
|
return "proxy_only";
|
||||||
}
|
}
|
||||||
|
@ -270,25 +232,25 @@ this.privacy = class extends ExtensionAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
return "default";
|
return "default";
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
},
|
},
|
||||||
|
|
||||||
services: {
|
services: {
|
||||||
passwordSavingEnabled: getPrivacyAPI(
|
passwordSavingEnabled: getSettingsAPI({
|
||||||
extension,
|
context,
|
||||||
"services.passwordSavingEnabled",
|
name: "services.passwordSavingEnabled",
|
||||||
() => {
|
callback() {
|
||||||
return Preferences.get("signon.rememberSignons");
|
return Preferences.get("signon.rememberSignons");
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
},
|
},
|
||||||
|
|
||||||
websites: {
|
websites: {
|
||||||
cookieConfig: getPrivacyAPI(
|
cookieConfig: getSettingsAPI({
|
||||||
extension,
|
context,
|
||||||
"websites.cookieConfig",
|
name: "websites.cookieConfig",
|
||||||
() => {
|
callback() {
|
||||||
let prefValue = Preferences.get("network.cookie.cookieBehavior");
|
let prefValue = Preferences.get("network.cookie.cookieBehavior");
|
||||||
return {
|
return {
|
||||||
behavior: Array.from(cookieBehaviorValues.entries()).find(
|
behavior: Array.from(cookieBehaviorValues.entries()).find(
|
||||||
|
@ -298,40 +260,40 @@ this.privacy = class extends ExtensionAPI {
|
||||||
Preferences.get("network.cookie.lifetimePolicy") ===
|
Preferences.get("network.cookie.lifetimePolicy") ===
|
||||||
cookieSvc.ACCEPT_SESSION,
|
cookieSvc.ACCEPT_SESSION,
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
firstPartyIsolate: getPrivacyAPI(
|
firstPartyIsolate: getSettingsAPI({
|
||||||
extension,
|
context,
|
||||||
"websites.firstPartyIsolate",
|
name: "websites.firstPartyIsolate",
|
||||||
() => {
|
callback() {
|
||||||
return Preferences.get("privacy.firstparty.isolate");
|
return Preferences.get("privacy.firstparty.isolate");
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
hyperlinkAuditingEnabled: getPrivacyAPI(
|
hyperlinkAuditingEnabled: getSettingsAPI({
|
||||||
extension,
|
context,
|
||||||
"websites.hyperlinkAuditingEnabled",
|
name: "websites.hyperlinkAuditingEnabled",
|
||||||
() => {
|
callback() {
|
||||||
return Preferences.get("browser.send_pings");
|
return Preferences.get("browser.send_pings");
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
referrersEnabled: getPrivacyAPI(
|
referrersEnabled: getSettingsAPI({
|
||||||
extension,
|
context,
|
||||||
"websites.referrersEnabled",
|
name: "websites.referrersEnabled",
|
||||||
() => {
|
callback() {
|
||||||
return Preferences.get("network.http.sendRefererHeader") !== 0;
|
return Preferences.get("network.http.sendRefererHeader") !== 0;
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
resistFingerprinting: getPrivacyAPI(
|
resistFingerprinting: getSettingsAPI({
|
||||||
extension,
|
context,
|
||||||
"websites.resistFingerprinting",
|
name: "websites.resistFingerprinting",
|
||||||
() => {
|
callback() {
|
||||||
return Preferences.get("privacy.resistFingerprinting");
|
return Preferences.get("privacy.resistFingerprinting");
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
trackingProtectionMode: getPrivacyAPI(
|
trackingProtectionMode: getSettingsAPI({
|
||||||
extension,
|
context,
|
||||||
"websites.trackingProtectionMode",
|
name: "websites.trackingProtectionMode",
|
||||||
() => {
|
callback() {
|
||||||
if (Preferences.get("privacy.trackingprotection.enabled")) {
|
if (Preferences.get("privacy.trackingprotection.enabled")) {
|
||||||
return "always";
|
return "always";
|
||||||
} else if (
|
} else if (
|
||||||
|
@ -340,8 +302,8 @@ this.privacy = class extends ExtensionAPI {
|
||||||
return "private_browsing";
|
return "private_browsing";
|
||||||
}
|
}
|
||||||
return "never";
|
return "never";
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -173,10 +173,10 @@ this.proxy = class extends ExtensionAPI {
|
||||||
}).api(),
|
}).api(),
|
||||||
|
|
||||||
settings: Object.assign(
|
settings: Object.assign(
|
||||||
getSettingsAPI(
|
getSettingsAPI({
|
||||||
extension.id,
|
context,
|
||||||
"proxy.settings",
|
name: "proxy.settings",
|
||||||
() => {
|
callback() {
|
||||||
let prefValue = Services.prefs.getIntPref("network.proxy.type");
|
let prefValue = Services.prefs.getIntPref("network.proxy.type");
|
||||||
let proxyConfig = {
|
let proxyConfig = {
|
||||||
proxyType: Array.from(PROXY_TYPES_MAP.entries()).find(
|
proxyType: Array.from(PROXY_TYPES_MAP.entries()).find(
|
||||||
|
@ -214,16 +214,14 @@ this.proxy = class extends ExtensionAPI {
|
||||||
return proxyConfig;
|
return proxyConfig;
|
||||||
},
|
},
|
||||||
// proxy.settings is unsupported on android.
|
// proxy.settings is unsupported on android.
|
||||||
undefined,
|
validate() {
|
||||||
false,
|
|
||||||
() => {
|
|
||||||
if (AppConstants.platform == "android") {
|
if (AppConstants.platform == "android") {
|
||||||
throw new ExtensionError(
|
throw new ExtensionError(
|
||||||
`proxy.settings is not supported on android.`
|
`proxy.settings is not supported on android.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
),
|
}),
|
||||||
{
|
{
|
||||||
set: details => {
|
set: details => {
|
||||||
if (AppConstants.platform === "android") {
|
if (AppConstants.platform === "android") {
|
||||||
|
|
|
@ -133,7 +133,6 @@
|
||||||
"name": "onChange",
|
"name": "onChange",
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"description": "Fired after the setting changes.",
|
"description": "Fired after the setting changes.",
|
||||||
"unsupported": true,
|
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|
|
@ -40,8 +40,20 @@ add_task(async function test_browser_settings() {
|
||||||
};
|
};
|
||||||
|
|
||||||
async function background() {
|
async function background() {
|
||||||
|
let listeners = new Set([]);
|
||||||
browser.test.onMessage.addListener(async (msg, apiName, value) => {
|
browser.test.onMessage.addListener(async (msg, apiName, value) => {
|
||||||
let apiObj = browser.browserSettings[apiName];
|
let apiObj = browser.browserSettings[apiName];
|
||||||
|
// Don't add more than one listner per apiName. We leave the
|
||||||
|
// listener to ensure we do not get more calls than we expect.
|
||||||
|
if (!listeners.has(apiName)) {
|
||||||
|
apiObj.onChange.addListener(details => {
|
||||||
|
browser.test.sendMessage("onChange", {
|
||||||
|
details: details.details,
|
||||||
|
setting: apiName,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
listeners.add(apiName);
|
||||||
|
}
|
||||||
let result = await apiObj.set({ value });
|
let result = await apiObj.set({ value });
|
||||||
if (msg === "set") {
|
if (msg === "set") {
|
||||||
browser.test.assertTrue(result, "set returns true.");
|
browser.test.assertTrue(result, "set returns true.");
|
||||||
|
@ -79,6 +91,13 @@ add_task(async function test_browser_settings() {
|
||||||
async function testSetting(setting, value, expected, expectedValue = value) {
|
async function testSetting(setting, value, expected, expectedValue = value) {
|
||||||
extension.sendMessage("set", setting, value);
|
extension.sendMessage("set", setting, value);
|
||||||
let data = await extension.awaitMessage("settingData");
|
let data = await extension.awaitMessage("settingData");
|
||||||
|
let dataChange = await extension.awaitMessage("onChange");
|
||||||
|
equal(setting, dataChange.setting, "onChange fired");
|
||||||
|
equal(
|
||||||
|
data.value,
|
||||||
|
dataChange.details.value,
|
||||||
|
"onChange fired with correct value"
|
||||||
|
);
|
||||||
deepEqual(
|
deepEqual(
|
||||||
data.value,
|
data.value,
|
||||||
expectedValue,
|
expectedValue,
|
||||||
|
@ -174,12 +193,12 @@ add_task(async function test_browser_settings() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await testSetting("ftpProtocolEnabled", true, {
|
|
||||||
"network.ftp.enabled": true,
|
|
||||||
});
|
|
||||||
await testSetting("ftpProtocolEnabled", false, {
|
await testSetting("ftpProtocolEnabled", false, {
|
||||||
"network.ftp.enabled": false,
|
"network.ftp.enabled": false,
|
||||||
});
|
});
|
||||||
|
await testSetting("ftpProtocolEnabled", true, {
|
||||||
|
"network.ftp.enabled": true,
|
||||||
|
});
|
||||||
|
|
||||||
await testSetting("newTabPosition", "afterCurrent", {
|
await testSetting("newTabPosition", "afterCurrent", {
|
||||||
"browser.tabs.insertRelatedAfterCurrent": false,
|
"browser.tabs.insertRelatedAfterCurrent": false,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче