author | Gurzau Raul <rgurzau@mozilla.com> |
Tue, 06 Feb 2018 22:03:23 +0200 | |
changeset 402577 | 87b9333134d1ed8833dda6514d729de3930dc54b |
parent 402576 | 853e25b18469df0f72b116a481d7c19d74c63640 |
child 402578 | aa124ca6eabb9ddf2a30d51e431166a69ca9209d |
child 402623 | 6b88557d1e500c8d21fa57e6f48642a5d72a3c09 |
push id | 33392 |
push user | rgurzau@mozilla.com |
push date | Tue, 06 Feb 2018 21:53:12 +0000 |
treeherder | mozilla-central@aa124ca6eabb [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 1429593 |
milestone | 60.0a1 |
backs out | 9dfaa0724a424dfa146159d388f8fbd0a70bce28 20829d727fdfd30a97a127310aa78867cd97acf0 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/components/preferences/connection.js +++ b/browser/components/preferences/connection.js @@ -1,16 +1,15 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */ /* 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 ../../base/content/utilityOverlay.js */ /* import-globals-from ../../../toolkit/content/preferencesBindings.js */ -/* import-globals-from in-content/extensionControlled.js */ Preferences.addAll([ { id: "network.proxy.type", type: "int" }, { id: "network.proxy.http", type: "string" }, { id: "network.proxy.http_port", type: "int" }, { id: "network.proxy.ftp", type: "string" }, { id: "network.proxy.ftp_port", type: "int" }, { id: "network.proxy.ssl", type: "string" }, @@ -32,24 +31,16 @@ Preferences.addAll([ { id: "network.proxy.backup.socks_port", type: "int" }, ]); window.addEventListener("DOMContentLoaded", () => { Preferences.get("network.proxy.type").on("change", gConnectionsDialog.proxyTypeChanged.bind(gConnectionsDialog)); Preferences.get("network.proxy.socks_version").on("change", gConnectionsDialog.updateDNSPref.bind(gConnectionsDialog)); - - document - .getElementById("disableProxyExtension") - .addEventListener( - "command", makeDisableControllingExtension( - PREF_SETTING_TYPE, PROXY_KEY).bind(gConnectionsDialog)); - gConnectionsDialog.updateProxySettingsUI(); - initializeProxyUI(gConnectionsDialog); }, { once: true, capture: true }); var gConnectionsDialog = { beforeAccept() { var proxyTypePref = Preferences.get("network.proxy.type"); if (proxyTypePref.value == 2) { this.doAutoconfigURLFixup(); return true; @@ -231,45 +222,10 @@ var gConnectionsDialog = { return undefined; }, readHTTPProxyPort() { var shareProxiesPref = Preferences.get("network.proxy.share_proxy_settings"); if (shareProxiesPref.value) this.updateProtocolPrefs(); return undefined; - }, - - getProxyControls() { - let controlGroup = document.getElementById("networkProxyType"); - return [ - ...controlGroup.querySelectorAll(":scope > radio"), - ...controlGroup.querySelectorAll("label"), - ...controlGroup.querySelectorAll("textbox"), - ...controlGroup.querySelectorAll("checkbox"), - ...document.querySelectorAll("#networkProxySOCKSVersion > radio"), - ...document.querySelectorAll("#ConnectionsDialogPane > checkbox"), - ]; - }, - - // Update the UI to show/hide the extension controlled message for - // proxy settings. - async updateProxySettingsUI() { - let isLocked = API_PROXY_PREFS.some( - pref => Services.prefs.prefIsLocked(pref)); - - function setInputsDisabledState(isControlled) { - let disabled = isLocked || isControlled; - for (let element of gConnectionsDialog.getProxyControls()) { - element.disabled = disabled; - } - } - - if (isLocked) { - // An extension can't control this setting if any pref is locked. - hideControllingExtension(PROXY_KEY); - setInputsDisabledState(false); - } else { - handleControllingExtension(PREF_SETTING_TYPE, PROXY_KEY) - .then(setInputsDisabledState); - } } };
--- a/browser/components/preferences/connection.xul +++ b/browser/components/preferences/connection.xul @@ -4,18 +4,16 @@ - 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/. --> <!DOCTYPE dialog [ <!ENTITY % preferencesDTD SYSTEM "chrome://global/locale/preferences.dtd"> %preferencesDTD; <!ENTITY % connectionDTD SYSTEM "chrome://browser/locale/preferences/connection.dtd"> %connectionDTD; - <!ENTITY % mainDTD SYSTEM "chrome://browser/locale/preferences/main.dtd"> - %mainDTD; ]> <?xml-stylesheet href="chrome://global/skin/"?> <?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?> <dialog id="ConnectionsDialog" type="child" class="prefwindow" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" title="&connectionsDialog.title;" @@ -32,37 +30,28 @@ #ifdef XP_MACOSX style="width: &window.macWidth2; !important;"> #else style="width: &window.width2; !important;"> #endif <script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/> <script type="application/javascript" src="chrome://global/content/preferencesBindings.js"/> - <script type="application/javascript" src="chrome://browser/content/preferences/in-content/extensionControlled.js"/> <keyset> <key key="&windowClose.key;" modifiers="accel" oncommand="Preferences.close(event)"/> </keyset> <vbox id="ConnectionsDialogPane" class="prefpane largeDialogContainer"> - <stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences/preferences.properties"/> - <stringbundle id="bundleBrand" src="chrome://branding/locale/brand.properties"/> + <stringbundle id="preferencesBundle" src="chrome://browser/locale/preferences/preferences.properties"/> <script type="application/javascript" src="chrome://browser/content/preferences/connection.js"/> - <hbox id="proxyExtensionContent" align="top" hidden="true"> - <description control="disableProxyExtension" flex="1" /> - <button id="disableProxyExtension" - class="extension-controlled-button accessory-button" - label="&disableExtension.label;" /> - </hbox> - <groupbox> - <caption><label>&proxyTitle.label2;</label></caption> + <caption><label>&proxyTitle.label;</label></caption> <radiogroup id="networkProxyType" preference="network.proxy.type" onsyncfrompreference="return gConnectionsDialog.readProxyType();"> <radio value="0" label="&noProxyTypeRadio.label;" accesskey="&noProxyTypeRadio.accesskey;"/> <radio value="4" label="&WPADTypeRadio.label;" accesskey="&WPADTypeRadio.accesskey;"/> <radio value="5" label="&systemTypeRadio.label;" accesskey="&systemTypeRadio.accesskey;" id="systemPref" hidden="true"/> <radio value="1" label="&manualTypeRadio2.label;" accesskey="&manualTypeRadio2.accesskey;"/> <grid class="indent" flex="1">
deleted file mode 100644 --- a/browser/components/preferences/in-content/extensionControlled.js +++ /dev/null @@ -1,221 +0,0 @@ -/* - 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 */ - -"use strict"; - -ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); - -ChromeUtils.defineModuleGetter(this, "AddonManager", - "resource://gre/modules/AddonManager.jsm"); -ChromeUtils.defineModuleGetter(this, "BrowserUtils", - "resource://gre/modules/BrowserUtils.jsm"); -ChromeUtils.defineModuleGetter(this, "DeferredTask", - "resource://gre/modules/DeferredTask.jsm"); -ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore", - "resource://gre/modules/ExtensionSettingsStore.jsm"); - -XPCOMUtils.defineLazyPreferenceGetter(this, "trackingprotectionUiEnabled", - "privacy.trackingprotection.ui.enabled"); - -const PREF_SETTING_TYPE = "prefs"; -const PROXY_KEY = "proxyConfig"; -const API_PROXY_PREFS = [ - "network.proxy.type", - "network.proxy.http", - "network.proxy.http_port", - "network.proxy.share_proxy_settings", - "network.proxy.ftp", - "network.proxy.ftp_port", - "network.proxy.ssl", - "network.proxy.ssl_port", - "network.proxy.socks", - "network.proxy.socks_port", - "network.proxy.socks_version", - "network.proxy.socks_remote_dns", - "network.proxy.no_proxies_on", - "network.proxy.autoconfig_url", - "signon.autologin.proxy", -]; - -let extensionControlledContentIds = { - "privacy.containers": "browserContainersExtensionContent", - "homepage_override": "browserHomePageExtensionContent", - "newTabURL": "browserNewTabExtensionContent", - "defaultSearch": "browserDefaultSearchExtensionContent", - "proxyConfig": "proxyExtensionContent", - get "websites.trackingProtectionMode"() { - return { - button: "trackingProtectionExtensionContentButton", - section: - trackingprotectionUiEnabled ? - "trackingProtectionExtensionContentLabel" : - "trackingProtectionPBMExtensionContentLabel", - }; - } -}; - -function getExtensionControlledArgs(settingName) { - switch (settingName) { - case "proxyConfig": - return [document.getElementById("bundleBrand").getString("brandShortName")]; - default: - return []; - } -} - -let extensionControlledIds = {}; - -/** - * Check if a pref is being managed by an extension. - */ -async function getControllingExtensionInfo(type, settingName) { - await ExtensionSettingsStore.initialize(); - return ExtensionSettingsStore.getSetting(type, settingName); -} - -function getControllingExtensionEls(settingName) { - let idInfo = extensionControlledContentIds[settingName]; - let section = document.getElementById(idInfo.section || idInfo); - let button = idInfo.button ? - document.getElementById(idInfo.button) : - section.querySelector("button"); - return { - section, - button, - description: section.querySelector("description"), - }; -} - -async function getControllingExtension(type, settingName) { - let info = await getControllingExtensionInfo(type, settingName); - let addon = info && info.id - && await AddonManager.getAddonByID(info.id); - return addon; -} - -async function handleControllingExtension(type, settingName) { - let addon = await getControllingExtension(type, settingName); - - // Sometimes the ExtensionSettingsStore gets in a bad state where it thinks - // an extension is controlling a setting but the extension has been uninstalled - // outside of the regular lifecycle. If the extension isn't currently installed - // then we should treat the setting as not being controlled. - // See https://bugzilla.mozilla.org/show_bug.cgi?id=1411046 for an example. - if (addon) { - extensionControlledIds[settingName] = addon.id; - showControllingExtension(settingName, addon); - } else { - let elements = getControllingExtensionEls(settingName); - if (extensionControlledIds[settingName] - && !document.hidden - && elements.button) { - showEnableExtensionMessage(settingName); - } else { - hideControllingExtension(settingName); - } - delete extensionControlledIds[settingName]; - } - - return !!addon; -} - -function getControllingExtensionFragment(settingName, addon, ...extraArgs) { - let msg = document.getElementById("bundlePreferences") - .getString(`extensionControlled.${settingName}`); - let image = document.createElement("image"); - const defaultIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg"; - image.setAttribute("src", addon.iconURL || defaultIcon); - image.classList.add("extension-controlled-icon"); - let addonBit = document.createDocumentFragment(); - addonBit.appendChild(image); - addonBit.appendChild(document.createTextNode(" " + addon.name)); - return BrowserUtils.getLocalizedFragment(document, msg, addonBit, ...extraArgs); -} - -async function showControllingExtension(settingName, addon) { - // Tell the user what extension is controlling the setting. - let elements = getControllingExtensionEls(settingName); - let extraArgs = getExtensionControlledArgs(settingName); - - elements.section.classList.remove("extension-controlled-disabled"); - let description = elements.description; - - // Remove the old content from the description. - while (description.firstChild) { - description.firstChild.remove(); - } - - let fragment = getControllingExtensionFragment( - settingName, addon, ...extraArgs); - description.appendChild(fragment); - - if (elements.button) { - elements.button.hidden = false; - } - - // Show the controlling extension row and hide the old label. - elements.section.hidden = false; -} - -function hideControllingExtension(settingName) { - let elements = getControllingExtensionEls(settingName); - elements.section.hidden = true; - if (elements.button) { - elements.button.hidden = true; - } -} - -function showEnableExtensionMessage(settingName) { - let elements = getControllingExtensionEls(settingName); - - elements.button.hidden = true; - elements.section.classList.add("extension-controlled-disabled"); - let icon = url => { - let img = document.createElement("image"); - img.src = url; - img.className = "extension-controlled-icon"; - return img; - }; - let addonIcon = icon("chrome://mozapps/skin/extensions/extensionGeneric-16.svg"); - let toolbarIcon = icon("chrome://browser/skin/menu.svg"); - let message = document.getElementById("bundlePreferences") - .getString("extensionControlled.enable"); - let frag = BrowserUtils.getLocalizedFragment(document, message, addonIcon, toolbarIcon); - elements.description.innerHTML = ""; - elements.description.appendChild(frag); - let dismissButton = document.createElement("image"); - dismissButton.setAttribute("class", "extension-controlled-icon close-icon"); - dismissButton.addEventListener("click", function dismissHandler() { - hideControllingExtension(settingName); - dismissButton.removeEventListener("click", dismissHandler); - }); - elements.description.appendChild(dismissButton); -} - -function makeDisableControllingExtension(type, settingName) { - return async function disableExtension() { - let {id} = await getControllingExtensionInfo(type, settingName); - let addon = await AddonManager.getAddonByID(id); - addon.userDisabled = true; - }; -} - -function initializeProxyUI(container) { - let deferredUpdate = new DeferredTask(() => { - container.updateProxySettingsUI(); - }, 10); - let proxyObserver = { - observe: (subject, topic, data) => { - if (API_PROXY_PREFS.includes(data)) { - deferredUpdate.arm(); - } - }, - }; - Services.prefs.addObserver("", proxyObserver); - window.addEventListener("unload", () => { - Services.prefs.removeObserver("", proxyObserver); - }); -}
--- a/browser/components/preferences/in-content/findInPage.js +++ b/browser/components/preferences/in-content/findInPage.js @@ -1,13 +1,12 @@ /* 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 extensionControlled.js */ /* import-globals-from preferences.js */ var gSearchResultsPane = { listSearchTooltips: new Set(), listSearchMenuitemIndicators: new Set(), searchInput: null, inited: false,
--- a/browser/components/preferences/in-content/jar.mn +++ b/browser/components/preferences/in-content/jar.mn @@ -1,15 +1,14 @@ # 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/. browser.jar: content/browser/preferences/in-content/preferences.js - content/browser/preferences/in-content/extensionControlled.js * content/browser/preferences/in-content/preferences.xul content/browser/preferences/in-content/subdialogs.js content/browser/preferences/in-content/main.js content/browser/preferences/in-content/search.js content/browser/preferences/in-content/privacy.js content/browser/preferences/in-content/containers.js content/browser/preferences/in-content/sync.js
--- a/browser/components/preferences/in-content/main.js +++ b/browser/components/preferences/in-content/main.js @@ -1,13 +1,12 @@ /* 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 extensionControlled.js */ /* import-globals-from preferences.js */ /* import-globals-from ../../../../toolkit/mozapps/preferences/fontbuilder.js */ /* import-globals-from ../../../base/content/aboutDialog-appUpdater.js */ ChromeUtils.import("resource://gre/modules/Services.jsm"); ChromeUtils.import("resource://gre/modules/Downloads.jsm"); ChromeUtils.import("resource://gre/modules/FileUtils.jsm"); ChromeUtils.import("resource:///modules/ShellService.jsm"); @@ -363,23 +362,16 @@ var gMainPane = { handleControllingExtension(URL_OVERRIDES_TYPE, NEW_TAB_KEY); }, }; Services.obs.addObserver(newTabObserver, "newtab-url-changed"); window.addEventListener("unload", () => { Services.obs.removeObserver(newTabObserver, "newtab-url-changed"); }); - let connectionSettingsLink = document.getElementById("connectionSettingsLearnMore"); - let connectionSettingsUrl = Services.urlFormatter.formatURLPref("app.support.baseURL") + - "prefs-connection-settings"; - connectionSettingsLink.setAttribute("href", connectionSettingsUrl); - this.updateProxySettingsUI(); - initializeProxyUI(gMainPane); - if (AppConstants.platform == "win") { // Functionality for "Show tabs in taskbar" on Windows 7 and up. try { let ver = parseFloat(Services.sysinfo.getProperty("version")); let showTabsInTaskbar = document.getElementById("showTabsInTaskbar"); showTabsInTaskbar.hidden = ver < 6.1; } catch (ex) { } } @@ -1093,38 +1085,17 @@ var gMainPane = { gSubDialog.open("chrome://browser/content/preferences/colors.xul", "resizable=no"); }, // NETWORK /** * Displays a dialog in which proxy settings may be changed. */ showConnections() { - gSubDialog.open("chrome://browser/content/preferences/connection.xul", - null, null, this.updateProxySettingsUI.bind(this)); - }, - - // Update the UI to show the proper description depending on whether an - // extension is in control or not. - async updateProxySettingsUI() { - let controllingExtension = await getControllingExtension(PREF_SETTING_TYPE, PROXY_KEY); - let fragment = controllingExtension ? - getControllingExtensionFragment(PROXY_KEY, controllingExtension, this._brandShortName) : - BrowserUtils.getLocalizedFragment( - document, - this._prefsBundle.getString("connectionDesc.label"), - this._brandShortName); - let description = document.getElementById("connectionSettingsDescription"); - - // Remove the old content from the description. - while (description.firstChild) { - description.firstChild.remove(); - } - - description.appendChild(fragment); + gSubDialog.open("chrome://browser/content/preferences/connection.xul"); }, checkBrowserContainers(event) { let checkbox = document.getElementById("browserContainersCheckbox"); if (checkbox.checked) { Services.prefs.setBoolPref("privacy.userContext.enabled", true); return; }
--- a/browser/components/preferences/in-content/main.xul +++ b/browser/components/preferences/in-content/main.xul @@ -744,25 +744,17 @@ <label class="header-name" flex="1">&networkProxy.label;</label> </hbox> <!-- Network Proxy--> <groupbox id="connectionGroup" data-category="paneGeneral" hidden="true"> <caption class="search-header" hidden="true"><label>&networkProxy.label;</label></caption> <hbox align="center"> - <hbox align="center" flex="1"> - <description id="connectionSettingsDescription" control="connectionSettings"></description> - <spacer width="5"/> - <label id="connectionSettingsLearnMore" class="learnMore text-link"> - &connectionSettingsLearnMore.label; - </label> - <separator orient="vertical"/> - </hbox> - + <description flex="1" control="connectionSettings">&connectionDesc.label;</description> <!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. --> <hbox> <button id="connectionSettings" class="accessory-button" icon="network" label="&connectionSettings.label;" accesskey="&connectionSettings.accesskey;" searchkeywords="&connectionsDialog.title;
--- a/browser/components/preferences/in-content/preferences.js +++ b/browser/components/preferences/in-content/preferences.js @@ -15,22 +15,32 @@ "use strict"; var Cc = Components.classes; var Ci = Components.interfaces; var Cu = Components.utils; var Cr = Components.results; +ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); ChromeUtils.import("resource://gre/modules/Services.jsm"); ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); +ChromeUtils.defineModuleGetter(this, "AddonManager", + "resource://gre/modules/AddonManager.jsm"); +ChromeUtils.defineModuleGetter(this, "BrowserUtils", + "resource://gre/modules/BrowserUtils.jsm"); +ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore", + "resource://gre/modules/ExtensionSettingsStore.jsm"); ChromeUtils.defineModuleGetter(this, "formAutofillParent", "resource://formautofill/FormAutofillParent.jsm"); +XPCOMUtils.defineLazyPreferenceGetter(this, "trackingprotectionUiEnabled", + "privacy.trackingprotection.ui.enabled"); + 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; } @@ -407,8 +417,153 @@ 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(" ")); } + +const PREF_SETTING_TYPE = "prefs"; + +let extensionControlledContentIds = { + "privacy.containers": "browserContainersExtensionContent", + "homepage_override": "browserHomePageExtensionContent", + "newTabURL": "browserNewTabExtensionContent", + "defaultSearch": "browserDefaultSearchExtensionContent", + get "websites.trackingProtectionMode"() { + return { + button: "trackingProtectionExtensionContentButton", + section: + trackingprotectionUiEnabled ? + "trackingProtectionExtensionContentLabel" : + "trackingProtectionPBMExtensionContentLabel", + }; + } +}; + +let extensionControlledIds = {}; + +/** + * Check if a pref is being managed by an extension. + */ +async function getControllingExtensionInfo(type, settingName) { + await ExtensionSettingsStore.initialize(); + return ExtensionSettingsStore.getSetting(type, settingName); +} + +function getControllingExtensionEls(settingName) { + let idInfo = extensionControlledContentIds[settingName]; + let section = document.getElementById(idInfo.section || idInfo); + let button = idInfo.button ? + document.getElementById(idInfo.button) : + section.querySelector("button"); + return { + section, + button, + description: section.querySelector("description"), + }; +} + +async function handleControllingExtension(type, settingName) { + let info = await getControllingExtensionInfo(type, settingName); + let addon = info && info.id + && await AddonManager.getAddonByID(info.id); + + // Sometimes the ExtensionSettingsStore gets in a bad state where it thinks + // an extension is controlling a setting but the extension has been uninstalled + // outside of the regular lifecycle. If the extension isn't currently installed + // then we should treat the setting as not being controlled. + // See https://bugzilla.mozilla.org/show_bug.cgi?id=1411046 for an example. + if (addon) { + extensionControlledIds[settingName] = info.id; + showControllingExtension(settingName, addon); + } else { + let elements = getControllingExtensionEls(settingName); + if (extensionControlledIds[settingName] + && !document.hidden + && elements.button) { + showEnableExtensionMessage(settingName); + } else { + hideControllingExtension(settingName); + } + delete extensionControlledIds[settingName]; + } + + return !!addon; +} + +async function showControllingExtension(settingName, addon) { + // Tell the user what extension is controlling the setting. + let elements = getControllingExtensionEls(settingName); + + elements.section.classList.remove("extension-controlled-disabled"); + let description = elements.description; + + // Remove the old content from the description. + while (description.firstChild) { + description.firstChild.remove(); + } + + // Populate the description. + let msg = document.getElementById("bundlePreferences") + .getString(`extensionControlled.${settingName}`); + let image = document.createElement("image"); + const defaultIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg"; + image.setAttribute("src", addon.iconURL || defaultIcon); + image.classList.add("extension-controlled-icon"); + let addonBit = document.createDocumentFragment(); + addonBit.appendChild(image); + addonBit.appendChild(document.createTextNode(" " + addon.name)); + let fragment = BrowserUtils.getLocalizedFragment(document, msg, addonBit); + description.appendChild(fragment); + + if (elements.button) { + elements.button.hidden = false; + } + + // Show the controlling extension row and hide the old label. + elements.section.hidden = false; +} + +function hideControllingExtension(settingName) { + let elements = getControllingExtensionEls(settingName); + elements.section.hidden = true; + if (elements.button) { + elements.button.hidden = true; + } +} + +function showEnableExtensionMessage(settingName) { + let elements = getControllingExtensionEls(settingName); + + elements.button.hidden = true; + elements.section.classList.add("extension-controlled-disabled"); + let icon = url => { + let img = document.createElement("image"); + img.src = url; + img.className = "extension-controlled-icon"; + return img; + }; + let addonIcon = icon("chrome://mozapps/skin/extensions/extensionGeneric-16.svg"); + let toolbarIcon = icon("chrome://browser/skin/menu.svg"); + let message = document.getElementById("bundlePreferences") + .getString("extensionControlled.enable"); + let frag = BrowserUtils.getLocalizedFragment(document, message, addonIcon, toolbarIcon); + elements.description.innerHTML = ""; + elements.description.appendChild(frag); + let dismissButton = document.createElement("image"); + dismissButton.setAttribute("class", "extension-controlled-icon close-icon"); + dismissButton.addEventListener("click", function dismissHandler() { + hideControllingExtension(settingName); + dismissButton.removeEventListener("click", dismissHandler); + }); + elements.description.appendChild(dismissButton); +} + +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/preferences.xul +++ b/browser/components/preferences/in-content/preferences.xul @@ -103,18 +103,16 @@ href="chrome://browser/skin/settings.svg"/> <script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/> <script type="application/javascript" src="chrome://global/content/preferencesBindings.js"/> <script type="application/javascript" src="chrome://browser/content/preferences/in-content/preferences.js"/> - <script type="application/javascript" - src="chrome://browser/content/preferences/in-content/extensionControlled.js"/> <script src="chrome://browser/content/preferences/in-content/findInPage.js"/> <script src="chrome://browser/content/preferences/in-content/subdialogs.js"/> <stringbundle id="bundleBrand" src="chrome://branding/locale/brand.properties"/> <stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences/preferences.properties"/> <stringbundle id="pkiBundle"
--- a/browser/components/preferences/in-content/privacy.js +++ b/browser/components/preferences/in-content/privacy.js @@ -1,13 +1,12 @@ /* 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 extensionControlled.js */ /* import-globals-from preferences.js */ /* FIXME: ESlint globals workaround should be removed once bug 1395426 gets fixed */ /* globals DownloadUtils, LoadContextInfo */ ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); ChromeUtils.import("resource://gre/modules/PluralForm.jsm");
--- a/browser/components/preferences/in-content/search.js +++ b/browser/components/preferences/in-content/search.js @@ -1,13 +1,12 @@ /* 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 extensionControlled.js */ /* import-globals-from preferences.js */ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); ChromeUtils.defineModuleGetter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm"); ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore", "resource://gre/modules/ExtensionSettingsStore.jsm");
--- a/browser/components/preferences/in-content/tests/browser_extension_controlled.js +++ b/browser/components/preferences/in-content/tests/browser_extension_controlled.js @@ -1,18 +1,15 @@ /* eslint-env webextensions */ -const PROXY_PREF = "network.proxy.type"; - ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore", "resource://gre/modules/ExtensionSettingsStore.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService", "@mozilla.org/browser/aboutnewtab-service;1", "nsIAboutNewTabService"); -XPCOMUtils.defineLazyPreferenceGetter(this, "proxyType", PROXY_PREF); const TEST_DIR = gTestPath.substr(0, gTestPath.lastIndexOf("/")); const CHROME_URL_ROOT = TEST_DIR + "/"; function getSupportsFile(path) { let cr = Cc["@mozilla.org/chrome/chrome-registry;1"] .getService(Ci.nsIChromeRegistry); let uri = Services.io.newURI(CHROME_URL_ROOT + path); @@ -46,47 +43,36 @@ function waitForMutation(target, opts, c observer.disconnect(); resolve(); } }); observer.observe(target, opts); }); } -function waitForMessageChange(element, cb, opts = { attributes: true, attributeFilter: ["hidden"] }) { - return waitForMutation(element, opts, cb); +function waitForMessageChange(id, cb, opts = { attributes: true, attributeFilter: ["hidden"] }) { + // eslint-disable-next-line mozilla/no-cpows-in-tests + return waitForMutation(gBrowser.contentDocument.getElementById(id), opts, cb); } -// eslint-disable-next-line mozilla/no-cpows-in-tests -function getElement(id, doc = gBrowser.contentDocument) { - return doc.getElementById(id); -} - -function waitForMessageHidden(messageId, doc) { - return waitForMessageChange(getElement(messageId, doc), target => target.hidden); +function waitForMessageHidden(messageId) { + return waitForMessageChange(messageId, target => target.hidden); } -function waitForMessageShown(messageId, doc) { - return waitForMessageChange(getElement(messageId, doc), target => !target.hidden); +function waitForMessageShown(messageId) { + return waitForMessageChange(messageId, target => !target.hidden); } -function waitForEnableMessage(messageId, doc) { +function waitForEnableMessage(messageId) { return waitForMessageChange( - getElement(messageId, doc), + messageId, target => target.classList.contains("extension-controlled-disabled"), { attributeFilter: ["class"], attributes: true }); } -function waitForMessageContent(messageId, content, doc) { - return waitForMessageChange( - getElement(messageId, doc), - target => target.textContent === content, - { childList: true }); -} - add_task(async function testExtensionControlledHomepage() { await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true}); // eslint-disable-next-line mozilla/no-cpows-in-tests let doc = gBrowser.contentDocument; is(gBrowser.currentURI.spec, "about:preferences#general", "#general should be in the URI for about:preferences"); let homepagePref = () => Services.prefs.getCharPref("browser.startup.homepage"); let originalHomepagePref = homepagePref(); @@ -101,17 +87,17 @@ add_task(async function testExtensionCon // Install an extension that will set the homepage. await installAddon("set_homepage.xpi"); await waitForMessageShown("browserHomePageExtensionContent"); // The homepage has been set by the extension, the user is notified and it isn't editable. let controlledLabel = controlledContent.querySelector("description"); is(homepagePref(), extensionHomepage, "homepage is set by extension"); // There are two spaces before "set_homepage" because it's " <image /> set_homepage". - is(controlledLabel.textContent, "An extension, set_homepage, is controlling your home page.", + is(controlledLabel.textContent, "An extension, set_homepage, controls your home page.", "The user is notified that an extension is controlling the homepage"); is(controlledContent.hidden, false, "The extension controlled row is hidden"); is(doc.getElementById("browserHomePage").disabled, true, "The homepage input is disabled"); // Disable the extension. let enableMessageShown = waitForEnableMessage(controlledContent.id); doc.getElementById("disableHomePageExtension").click(); await enableMessageShown; @@ -291,17 +277,17 @@ add_task(async function testExtensionCon await installAddon("set_newtab.xpi"); await waitForMessageShown("browserNewTabExtensionContent"); // The new tab page has been set by the extension and the user is notified. let controlledLabel = controlledContent.querySelector("description"); ok(aboutNewTabService.newTabURL.startsWith("moz-extension:"), "new tab url is set by extension"); // There are two spaces before "set_newtab" because it's " <image /> set_newtab". - is(controlledLabel.textContent, "An extension, set_newtab, is controlling your New Tab page.", + is(controlledLabel.textContent, "An extension, set_newtab, controls your New Tab page.", "The user is notified that an extension is controlling the new tab page"); is(controlledContent.hidden, false, "The extension controlled row is hidden"); // Disable the extension. doc.getElementById("disableNewTabExtension").click(); // Verify the user is notified how to enable the extension. await waitForEnableMessage(controlledContent.id); @@ -613,198 +599,8 @@ add_task(async function testExtensionCon // ExtensionPreferencesManager to clean up properly. // TODO: BUG 1408226 await reEnableExtension(addon); await extension.unload(); await BrowserTestUtils.removeTab(gBrowser.selectedTab); }); - -add_task(async function testExtensionControlledProxyConfig() { - const proxySvc = Ci.nsIProtocolProxyService; - const PROXY_DEFAULT = proxySvc.PROXYCONFIG_SYSTEM; - const EXTENSION_ID = "@set_proxy"; - const CONTROLLED_SECTION_ID = "proxyExtensionContent"; - const CONTROLLED_BUTTON_ID = "disableProxyExtension"; - const CONNECTION_SETTINGS_DESC_ID = "connectionSettingsDescription"; - const PANEL_URL = "chrome://browser/content/preferences/connection.xul"; - - await SpecialPowers.pushPrefEnv({"set": [[PROXY_PREF, PROXY_DEFAULT]]}); - - function background() { - browser.browserSettings.proxyConfig.set({value: {proxyType: "none"}}); - } - - function expectedConnectionSettingsMessage(doc, isControlled) { - let brandShortName = doc.getElementById("bundleBrand").getString("brandShortName"); - return isControlled ? - `An extension, set_proxy, is controlling how ${brandShortName} connects to the internet.` : - `Configure how ${brandShortName} connects to the internet.`; - } - - function connectionSettingsMessagePromise(doc, isControlled) { - return waitForMessageContent( - CONNECTION_SETTINGS_DESC_ID, - expectedConnectionSettingsMessage(doc, isControlled) - ); - } - - function verifyState(doc, isControlled) { - let isPanel = doc.getElementById(CONTROLLED_BUTTON_ID); - let brandShortName = doc.getElementById("bundleBrand").getString("brandShortName"); - is(proxyType === proxySvc.PROXYCONFIG_DIRECT, isControlled, - "Proxy pref is set to the expected value."); - - if (isPanel) { - let controlledSection = doc.getElementById(CONTROLLED_SECTION_ID); - - is(controlledSection.hidden, !isControlled, "The extension controlled row's visibility is as expected."); - if (isPanel) { - is(doc.getElementById(CONTROLLED_BUTTON_ID).hidden, !isControlled, - "The disable extension button's visibility is as expected."); - } - if (isControlled) { - let controlledDesc = controlledSection.querySelector("description"); - // There are two spaces before "set_proxy" because it's " <image /> set_proxy". - is(controlledDesc.textContent, `An extension, set_proxy, is controlling how ${brandShortName} connects to the internet.`, - "The user is notified that an extension is controlling proxy settings."); - } - function getProxyControls() { - let controlGroup = doc.getElementById("networkProxyType"); - return [ - ...controlGroup.querySelectorAll(":scope > radio"), - ...controlGroup.querySelectorAll("label"), - ...controlGroup.querySelectorAll("textbox"), - ...controlGroup.querySelectorAll("checkbox"), - ...doc.querySelectorAll("#networkProxySOCKSVersion > radio"), - ...doc.querySelectorAll("#ConnectionsDialogPane > checkbox"), - ]; - } - let controlState = isControlled ? "disabled" : "enabled"; - for (let element of getProxyControls()) { - is(element.disabled, isControlled, `Proxy controls are ${controlState}.`); - } - } else { - is(doc.getElementById(CONNECTION_SETTINGS_DESC_ID).textContent, - expectedConnectionSettingsMessage(doc, isControlled), - "The connection settings description is as expected."); - } - } - - async function disableViaClick() { - let sectionId = CONTROLLED_SECTION_ID; - let controlledSection = panelDoc.getElementById(sectionId); - - let enableMessageShown = waitForEnableMessage(sectionId, panelDoc); - panelDoc.getElementById(CONTROLLED_BUTTON_ID).click(); - await enableMessageShown; - - // The user is notified how to enable the extension. - let controlledDesc = controlledSection.querySelector("description"); - is(controlledDesc.textContent, "To enable the extension go to Add-ons in the menu.", - "The user is notified of how to enable the extension again"); - - // The user can dismiss the enable instructions. - let hidden = waitForMessageHidden(sectionId, panelDoc); - controlledSection.querySelector("image:last-of-type").click(); - return hidden; - } - - async function reEnableExtension(addon) { - let messageChanged = connectionSettingsMessagePromise(mainDoc, true); - addon.userDisabled = false; - await messageChanged; - } - - async function openProxyPanel() { - let panel = await openAndLoadSubDialog(PANEL_URL); - let closingPromise = waitForEvent(panel.document.documentElement, "dialogclosing"); - ok(panel, "Proxy panel opened."); - return {panel, closingPromise}; - } - - async function closeProxyPanel(panelObj) { - panelObj.panel.document.documentElement.cancelDialog(); - let panelClosingEvent = await panelObj.closingPromise; - ok(panelClosingEvent, "Proxy panel closed."); - } - - await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true}); - // eslint-disable-next-line mozilla/no-cpows-in-tests - let mainDoc = gBrowser.contentDocument; - - is(gBrowser.currentURI.spec, "about:preferences#general", - "#general should be in the URI for about:preferences"); - - verifyState(mainDoc, false); - - // Open the connections panel. - let panelObj = await openProxyPanel(); - let panelDoc = panelObj.panel.document; - - verifyState(panelDoc, false); - - await closeProxyPanel(panelObj); - - verifyState(mainDoc, false); - - // Install an extension that sets Tracking Protection. - let extension = ExtensionTestUtils.loadExtension({ - useAddonManager: "permanent", - manifest: { - name: "set_proxy", - applications: {gecko: {id: EXTENSION_ID}}, - permissions: ["browserSettings"], - }, - background, - }); - - let messageChanged = connectionSettingsMessagePromise(mainDoc, true); - await extension.startup(); - await messageChanged; - let addon = await AddonManager.getAddonByID(EXTENSION_ID); - - verifyState(mainDoc, true); - messageChanged = connectionSettingsMessagePromise(mainDoc, false); - - panelObj = await openProxyPanel(); - panelDoc = panelObj.panel.document; - - verifyState(panelDoc, true); - - await disableViaClick(); - - verifyState(panelDoc, false); - - await closeProxyPanel(panelObj); - await messageChanged; - - verifyState(mainDoc, false); - - await reEnableExtension(addon); - - verifyState(mainDoc, true); - messageChanged = connectionSettingsMessagePromise(mainDoc, false); - - panelObj = await openProxyPanel(); - panelDoc = panelObj.panel.document; - - verifyState(panelDoc, true); - - await disableViaClick(); - - verifyState(panelDoc, false); - - await closeProxyPanel(panelObj); - await messageChanged; - - verifyState(mainDoc, false); - - // Enable the extension so we get the UNINSTALL event, which is needed by - // ExtensionPreferencesManager to clean up properly. - // TODO: BUG 1408226 - await reEnableExtension(addon); - - await extension.unload(); - - await BrowserTestUtils.removeTab(gBrowser.selectedTab); -});
--- a/browser/locales/en-US/chrome/browser/preferences/advanced.dtd +++ b/browser/locales/en-US/chrome/browser/preferences/advanced.dtd @@ -40,17 +40,17 @@ available. --> <!ENTITY alwaysSubmitCrashReports1.label "Allow &brandShortName; to send crash reports to Mozilla"> <!ENTITY alwaysSubmitCrashReports1.accesskey "c"> <!ENTITY crashReporterLearnMore.label "Learn more"> <!ENTITY networkTab.label "Network"> <!ENTITY networkProxy.label "Network Proxy"> -<!ENTITY connectionSettingsLearnMore.label "Learn more"> +<!ENTITY connectionDesc.label "Configure how &brandShortName; connects to the Internet"> <!ENTITY connectionSettings.label "Settingsā¦"> <!ENTITY connectionSettings.accesskey "e"> <!ENTITY httpCache.label "Cached Web Content"> <!-- Site Data section manages sites using Storage API and is under Network --> <!ENTITY siteData.label "Site Data"> <!ENTITY clearSiteData.label "Clear All Data">
--- a/browser/locales/en-US/chrome/browser/preferences/connection.dtd +++ b/browser/locales/en-US/chrome/browser/preferences/connection.dtd @@ -2,17 +2,17 @@ - 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/. --> <!ENTITY connectionsDialog.title "Connection Settings"> <!ENTITY window.width2 "49em"> <!ENTITY window.macWidth2 "44em"> -<!ENTITY proxyTitle.label2 "Configure Proxy Access to the Internet"> +<!ENTITY proxyTitle.label "Configure Proxies to Access the Internet"> <!ENTITY noProxyTypeRadio.label "No proxy"> <!ENTITY noProxyTypeRadio.accesskey "y"> <!ENTITY systemTypeRadio.label "Use system proxy settings"> <!ENTITY systemTypeRadio.accesskey "u"> <!ENTITY WPADTypeRadio.label "Auto-detect proxy settings for this network"> <!ENTITY WPADTypeRadio.accesskey "w"> <!ENTITY manualTypeRadio2.label "Manual proxy configuration"> <!ENTITY manualTypeRadio2.accesskey "m">
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties +++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties @@ -270,43 +270,33 @@ searchResults.needHelp3=Need help? Visit # LOCALIZATION NOTE (searchResults.needHelpSupportLink): %S will be replaced with the browser name. searchResults.needHelpSupportLink=%S Support # LOCALIZATION NOTE %S is the default value of the `dom.ipc.processCount` pref. 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, is controlling your home page. +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, is controlling your New Tab page. +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. # LOCALIZATION NOTE (extensionControlled.websites.trackingProtectionMode): # This string is shown to notify the user that their tracking protection preferences are being controlled by an extension. extensionControlled.websites.trackingProtectionMode = An extension, %S, is controlling tracking protection. -# LOCALIZATION NOTE (extensionControlled.proxyConfig): -# This string is shown to notify the user that their proxy configuration preferences are being controlled by an extension. -# %1$S is the icon and name of the extension. -# %2$S is the brandShortName from brand.properties (for example "Nightly") -extensionControlled.proxyConfig = An extension, %1$S, is controlling how %2$S connects to the internet. - # LOCALIZATION NOTE (extensionControlled.enable): # %1$S is replaced with the icon for the add-ons menu. # %2$S is replaced with the icon for the toolbar menu. # This string is shown to notify the user how to enable an extension that they disabled. extensionControlled.enable = To enable the extension go to %1$S Add-ons in the %2$S menu. - -# LOCALIZATION NOTE (connectionDesc.label): -# %S is the brandShortName from brand.properties (for example "Nightly") -connectionDesc.label = Configure how %S connects to the internet.