Bug 1386018 - Show the extension controlling the default search engine r?jaws
MozReview-Commit-ID: 1tN7g8Zq6Y5
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -1,21 +1,16 @@
/* 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/. */
/* import-globals-from preferences.js */
/* import-globals-from ../../../../toolkit/mozapps/preferences/fontbuilder.js */
/* import-globals-from ../../../base/content/aboutDialog-appUpdater.js */
-XPCOMUtils.defineLazyModuleGetter(this, "ExtensionSettingsStore",
- "resource://gre/modules/ExtensionSettingsStore.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
- "resource://gre/modules/AddonManager.jsm");
-
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/Downloads.jsm");
Components.utils.import("resource://gre/modules/FileUtils.jsm");
Components.utils.import("resource:///modules/ShellService.jsm");
Components.utils.import("resource:///modules/TransientPrefs.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/AppConstants.jsm");
Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
@@ -255,21 +250,21 @@ var gMainPane = {
}
setEventListener("useCurrent", "command",
gMainPane.setHomePageToCurrent);
setEventListener("useBookmark", "command",
gMainPane.setHomePageToBookmark);
setEventListener("restoreDefaultHomePage", "command",
gMainPane.restoreDefaultHomePage);
setEventListener("disableHomePageExtension", "command",
- gMainPane.makeDisableControllingExtension("prefs", "homepage_override"));
+ makeDisableControllingExtension("prefs", "homepage_override"));
setEventListener("disableContainersExtension", "command",
- gMainPane.makeDisableControllingExtension("prefs", "privacy.containers"));
+ makeDisableControllingExtension("prefs", "privacy.containers"));
setEventListener("disableNewTabExtension", "command",
- gMainPane.makeDisableControllingExtension("url_overrides", "newTabURL"));
+ makeDisableControllingExtension("url_overrides", "newTabURL"));
setEventListener("chooseLanguage", "command",
gMainPane.showLanguages);
setEventListener("translationAttributionImage", "click",
gMainPane.openTranslationProviderAttribution);
setEventListener("translateButton", "command",
gMainPane.showTranslationExceptions);
setEventListener("font.language.group", "change",
gMainPane._rebuildFonts);
@@ -769,17 +764,17 @@ var gMainPane = {
let tabs = this._getTabsForHomePage();
if (tabs.length > 1)
useCurrent.label = useCurrent.getAttribute("label2");
else
useCurrent.label = useCurrent.getAttribute("label1");
// If the homepage is controlled by an extension then you can't use this.
- if (await getControllingExtensionId("prefs", "homepage_override")) {
+ if (await getControllingExtensionInfo("prefs", "homepage_override")) {
useCurrent.disabled = true;
return;
}
// In this case, the button's disabled state is set by preferences.xml.
let prefName = "pref.browser.homepage.disable_button.current_page";
if (document.getElementById(prefName).locked)
return;
@@ -817,24 +812,16 @@ var gMainPane = {
/**
* Restores the default home page as the user's home page.
*/
restoreDefaultHomePage() {
var homePage = document.getElementById("browser.startup.homepage");
homePage.value = homePage.defaultValue;
},
- makeDisableControllingExtension(type, settingName) {
- return async function disableExtension() {
- let id = await getControllingExtensionId(type, settingName);
- let addon = await AddonManager.getAddonByID(id);
- addon.userDisabled = true;
- };
- },
-
/**
* Utility function to enable/disable the button specified by aButtonID based
* on the value of the Boolean preference specified by aPreferenceID.
*/
updateButtons(aButtonID, aPreferenceID) {
var button = document.getElementById(aButtonID);
var preference = document.getElementById(aPreferenceID);
button.disabled = preference.value != true;
@@ -2655,79 +2642,16 @@ function getLocalHandlerApp(aFile) {
var localHandlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
createInstance(Ci.nsILocalHandlerApp);
localHandlerApp.name = getFileDisplayName(aFile);
localHandlerApp.executable = aFile;
return localHandlerApp;
}
-let extensionControlledContentIds = {
- "privacy.containers": "browserContainersExtensionContent",
- "homepage_override": "browserHomePageExtensionContent",
- "newTabURL": "browserNewTabExtensionContent",
-};
-
-/**
- * Check if a pref is being managed by an extension.
- */
-async function getControllingExtensionId(type, settingName) {
- await ExtensionSettingsStore.initialize();
- return ExtensionSettingsStore.getTopExtensionId(type, settingName);
-}
-
-function getControllingExtensionEl(settingName) {
- return document.getElementById(extensionControlledContentIds[settingName]);
-}
-
-async function handleControllingExtension(type, settingName) {
- let controllingExtensionId = await getControllingExtensionId(type, settingName);
-
- if (controllingExtensionId) {
- showControllingExtension(settingName, controllingExtensionId);
- } else {
- hideControllingExtension(settingName);
- }
-
- return !!controllingExtensionId;
-}
-
-async function showControllingExtension(settingName, extensionId) {
- let extensionControlledContent = getControllingExtensionEl(settingName);
- // Tell the user what extension is controlling the setting.
- let addon = await AddonManager.getAddonByID(extensionId);
- const defaultIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
- let stringParts = document
- .getElementById("bundlePreferences")
- .getString(`extensionControlled.${settingName}`)
- .split("%S");
- let description = extensionControlledContent.querySelector("description");
-
- // Remove the old content from the description.
- while (description.firstChild) {
- description.firstChild.remove();
- }
-
- // Populate the description.
- description.appendChild(document.createTextNode(stringParts[0]));
- let image = document.createElement("image");
- image.setAttribute("src", addon.iconURL || defaultIcon);
- image.classList.add("extension-controlled-icon");
- description.appendChild(image);
- description.appendChild(document.createTextNode(` ${addon.name}`));
- description.appendChild(document.createTextNode(stringParts[1]));
-
- // Show the controlling extension row and hide the old label.
- extensionControlledContent.hidden = false;
-}
-
-function hideControllingExtension(settingName) {
- getControllingExtensionEl(settingName).hidden = true;
-}
-
/**
* An enumeration of items in a JS array.
*
* FIXME: use ArrayConverter once it lands (bug 380839).
*
* @constructor
*/
function ArrayEnumerator(aItems) {
--- a/browser/components/preferences/in-content/preferences.js
+++ b/browser/components/preferences/in-content/preferences.js
@@ -18,16 +18,21 @@ var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
var Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/AppConstants.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ExtensionSettingsStore",
+ "resource://gre/modules/ExtensionSettingsStore.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
+ "resource://gre/modules/AddonManager.jsm");
+
var gLastHash = "";
var gCategoryInits = new Map();
function init_category_if_required(category) {
let categoryInfo = gCategoryInits.get(category);
if (!categoryInfo) {
throw "Unknown in-content prefs category! Can't init " + category;
}
@@ -352,8 +357,82 @@ function confirmRestartPrompt(aRestartTo
function appendSearchKeywords(aId, keywords) {
let element = document.getElementById(aId);
let searchKeywords = element.getAttribute("searchkeywords");
if (searchKeywords) {
keywords.push(searchKeywords);
}
element.setAttribute("searchkeywords", keywords.join(" "));
}
+
+let extensionControlledContentIds = {
+ "privacy.containers": "browserContainersExtensionContent",
+ "homepage_override": "browserHomePageExtensionContent",
+ "newTabURL": "browserNewTabExtensionContent",
+ "defaultSearch": "browserDefaultSearchExtensionContent",
+};
+
+/**
+ * Check if a pref is being managed by an extension.
+ */
+async function getControllingExtensionInfo(type, settingName) {
+ await ExtensionSettingsStore.initialize();
+ return ExtensionSettingsStore.getSetting(type, settingName);
+}
+
+function getControllingExtensionEl(settingName) {
+ return document.getElementById(extensionControlledContentIds[settingName]);
+}
+
+async function handleControllingExtension(type, settingName, {filter} = {}) {
+ let info = await getControllingExtensionInfo(type, settingName);
+ filter = filter || (() => true);
+ let isControlled = info && !!info.id && filter(info.value);
+
+ if (isControlled) {
+ showControllingExtension(settingName, info.id);
+ } else {
+ hideControllingExtension(settingName);
+ }
+
+ return isControlled;
+}
+
+async function showControllingExtension(settingName, extensionId) {
+ let extensionControlledContent = getControllingExtensionEl(settingName);
+ // Tell the user what extension is controlling the setting.
+ let addon = await AddonManager.getAddonByID(extensionId);
+ const defaultIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
+ let stringParts = document
+ .getElementById("bundlePreferences")
+ .getString(`extensionControlled.${settingName}`)
+ .split("%S");
+ let description = extensionControlledContent.querySelector("description");
+
+ // Remove the old content from the description.
+ while (description.firstChild) {
+ description.firstChild.remove();
+ }
+
+ // Populate the description.
+ description.appendChild(document.createTextNode(stringParts[0]));
+ let image = document.createElement("image");
+ image.setAttribute("src", addon.iconURL || defaultIcon);
+ image.classList.add("extension-controlled-icon");
+ description.appendChild(image);
+ description.appendChild(document.createTextNode(` ${addon.name}`));
+ description.appendChild(document.createTextNode(stringParts[1]));
+
+ // Show the controlling extension row and hide the old label.
+ extensionControlledContent.hidden = false;
+}
+
+function hideControllingExtension(settingName) {
+ getControllingExtensionEl(settingName).hidden = true;
+}
+
+function makeDisableControllingExtension(type, settingName) {
+ return async function disableExtension() {
+ let {id} = await getControllingExtensionInfo(type, settingName);
+ let addon = await AddonManager.getAddonByID(id);
+ addon.userDisabled = true;
+ };
+}
--- a/browser/components/preferences/in-content/search.js
+++ b/browser/components/preferences/in-content/search.js
@@ -2,19 +2,29 @@
* 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/. */
/* import-globals-from preferences.js */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
+ "resource://gre/modules/AddonManager.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ExtensionSettingsStore",
+ "resource://gre/modules/ExtensionSettingsStore.jsm");
const ENGINE_FLAVOR = "text/x-moz-search-engine";
+function handleControllingDefaultSearchExtension() {
+ return handleControllingExtension("default_search", "defaultSearch", {
+ filter: (value) => value == Services.search.currentEngine.name,
+ });
+}
+
var gEngineView = null;
var gSearchPane = {
/**
* Initialize autocomplete to ensure prefs are in sync.
*/
_initAutocomplete() {
@@ -92,16 +102,28 @@ var gSearchPane = {
item.setAttribute("class", "menuitem-iconic searchengine-menuitem menuitem-with-favicon");
if (e.iconURI) {
item.setAttribute("image", e.iconURI.spec);
}
item.engine = e;
if (e.name == currentEngine)
list.selectedItem = item;
});
+
+
+ handleControllingDefaultSearchExtension();
+ let searchEngineListener = {
+ observe(subject, topic, data) {
+ handleControllingDefaultSearchExtension();
+ },
+ };
+ Services.obs.addObserver(searchEngineListener, "browser-search-engine-modified");
+ window.addEventListener("unload", () => {
+ Services.obs.removeObserver(searchEngineListener, "browser-search-engine-modified");
+ });
},
handleEvent(aEvent) {
switch (aEvent.type) {
case "click":
if (aEvent.target.id != "engineChildren" &&
!aEvent.target.classList.contains("searchEngineAction")) {
let engineList = document.getElementById("engineList");
--- a/browser/components/preferences/in-content/search.xul
+++ b/browser/components/preferences/in-content/search.xul
@@ -39,24 +39,30 @@
<image class="searchBarImage searchBarShownImage" role="presentation"/>
</radiogroup>
</groupbox>
<!-- Default Search Engine -->
<groupbox id="defaultEngineGroup" data-category="paneSearch">
<caption><label>&defaultSearchEngine.label;</label></caption>
<description>&chooseYourDefaultSearchEngine2.label;</description>
+
+ <hbox id="browserDefaultSearchExtensionContent" align="center" hidden="true">
+ <description control="disableDefaultSearchExtension" flex="1"/>
+ </hbox>
+
<hbox>
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
<hbox>
<menulist id="defaultEngine">
<menupopup/>
</menulist>
</hbox>
</hbox>
+
<checkbox id="suggestionsInSearchFieldsCheckbox"
label="&provideSearchSuggestions.label;"
accesskey="&provideSearchSuggestions.accesskey;"
preference="browser.search.suggest.enabled"/>
<vbox class="indent">
<checkbox id="urlBarSuggestion" label="&showURLBarSuggestions2.label;"
accesskey="&showURLBarSuggestions2.accesskey;"
preference="browser.urlbar.suggest.searches"/>
new file mode 100644
index 0000000000000000000000000000000000000000..ed58428e2d97bb7ec9bcfdd2cdd2861faf50e507
GIT binary patch
literal 5227
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
--- a/browser/components/preferences/in-content/tests/browser.ini
+++ b/browser/components/preferences/in-content/tests/browser.ini
@@ -1,13 +1,14 @@
[DEFAULT]
support-files =
head.js
privacypane_tests_perwindow.js
site_data_test.html
+ addons/set_default_search.xpi
addons/set_homepage.xpi
addons/set_newtab.xpi
offline/offline.html
offline/manifest.appcache
[browser_applications_selection.js]
skip-if = os == 'linux' # bug 1382057
[browser_advanced_update.js]
--- a/browser/components/preferences/in-content/tests/browser_extension_controlled.js
+++ b/browser/components/preferences/in-content/tests/browser_extension_controlled.js
@@ -119,13 +119,50 @@ add_task(async function testExtensionCon
is(controlledContent.hidden, false, "The extension controlled row is hidden");
// Disable the extension.
doc.getElementById("disableNewTabExtension").click();
await waitForMessageHidden("browserNewTabExtensionContent");
ok(!aboutNewTabService.newTabURL.startsWith("moz-extension:"), "new tab page is set back to default");
+ is(controlledContent.hidden, true, "The extension controlled row is shown");
+
+ await BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
+
+add_task(async function testExtensionControlledDefaultSearch() {
+ await openPreferencesViaOpenPreferencesAPI("paneSearch", {leaveOpen: true});
+ let doc = gBrowser.contentDocument;
+ is(gBrowser.currentURI.spec, "about:preferences#search",
+ "#search should be in the URI for about:preferences");
+
+ let controlledContent = doc.getElementById("browserDefaultSearchExtensionContent");
+ let initialEngine = Services.search.currentEngine;
+
+ // Ensure the controlled content is hidden when not controlled.
+ is(controlledContent.hidden, true, "The extension controlled row is hidden");
+
+ // Install an extension that will set the default search engine.
+ await installAddon("set_default_search.xpi");
+
+ await waitForMessageShown("browserDefaultSearchExtensionContent");
+
+ // The default search engine has been set by the extension and the user is notified.
+ let controlledLabel = controlledContent.querySelector("description");
+ ok(initialEngine != Services.search.currentEngine, "The default engine has changed.");
+ // There are two spaces before "set_default_search" because it's " <image /> set_default_search".
+ is(controlledLabel.textContent,
+ "An extension, set_default_search, has set your default search engine.",
+ "The user is notified that an extension is controlling the default search engine");
+ is(controlledContent.hidden, false, "The extension controlled row is shown");
+
+ Services.search.currentEngine = initialEngine;
+
+ await waitForMessageHidden("browserDefaultSearchExtensionContent");
+
+ is(initialEngine, Services.search.currentEngine,
+ "default search engine is set back to default");
is(controlledContent.hidden, true, "The extension controlled row is hidden");
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
});
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -281,12 +281,17 @@ defaultContentProcessCount=%S (default)
# LOCALIZATION NOTE (extensionControlled.homepage_override):
# This string is shown to notify the user that their home page is being controlled by an extension.
extensionControlled.homepage_override = An extension, %S, controls your home page.
# LOCALIZATION NOTE (extensionControlled.newTabURL):
# This string is shown to notify the user that their new tab page is being controlled by an extension.
extensionControlled.newTabURL = An extension, %S, controls your New Tab page.
+# LOCALIZATION NOTE (extensionControlled.defaultSearch):
+# This string is shown to notify the user that the default search engine is being controlled
+# by an extension. %S is the icon and name of the extension.
+extensionControlled.defaultSearch = An extension, %S, has set your default search engine.
+
# LOCALIZATION NOTE (extensionControlled.privacy.containers):
# This string is shown to notify the user that Container Tabs are being enabled by an extension
# %S is the container addon controlling it
extensionControlled.privacy.containers = An extension, %S, requires Container Tabs.
--- a/toolkit/components/extensions/ExtensionPreferencesManager.jsm
+++ b/toolkit/components/extensions/ExtensionPreferencesManager.jsm
@@ -164,29 +164,16 @@ this.ExtensionPreferencesManager = {
*
* @returns {string|number|boolean} The default value of the preference.
*/
getDefaultValue(prefName) {
return defaultPreferences.get(prefName);
},
/**
- * Gets the id of the extension controlling a preference or null if it isn't
- * being controlled.
- *
- * @param {string} prefName The name of the preference.
- *
- * @returns {Promise} Resolves to the id of the extension, or null.
- */
- async getControllingExtensionId(prefName) {
- await ExtensionSettingsStore.initialize();
- return ExtensionSettingsStore.getTopExtensionId(STORE_TYPE, prefName);
- },
-
- /**
* Indicates that an extension would like to change the value of a previously
* defined setting.
*
* @param {Extension} extension
* The extension for which a setting is being set.
* @param {string} name
* The unique id of the setting.
* @param {any} value
--- a/toolkit/components/extensions/ExtensionSettingsStore.jsm
+++ b/toolkit/components/extensions/ExtensionSettingsStore.jsm
@@ -447,26 +447,16 @@ this.ExtensionSettingsStore = {
}
let addon = await AddonManager.getAddonByID(id);
return topItem.installDate > addon.installDate.valueOf() ?
"controlled_by_other_extensions" :
"controllable_by_this_extension";
},
- // Return the id of the controlling extension or null if no extension is
- // controlling this setting.
- getTopExtensionId(type, key) {
- let item = getTopItem(type, key);
- if (item) {
- return item.id;
- }
- return null;
- },
-
/**
* Test-only method to force reloading of the JSON file.
*
* Note that this method simply clears the local variable that stores the
* file, so the next time the file is accessed it will be reloaded.
*
* @returns {Promise}
* A promise that resolves once the settings store has been cleared.