Bug 1728323 - Simplify extensionControlled and add missing fluent translation. r=mkmelin

We were missing lots of fluent ids that the previous code would have needed.

We only have extension control for proxy.settings, so this was simplified.

Differential Revision: https://phabricator.services.mozilla.com/D126094

--HG--
extra : amend_source : 07c340aa7c884f934792f008f5febeb6a37749b7
This commit is contained in:
Henry Wilkes 2021-09-23 13:03:58 +03:00
Родитель 339a2b6136
Коммит c97e8fad0c
5 изменённых файлов: 111 добавлений и 264 удалений

Просмотреть файл

@ -113,13 +113,8 @@ window.addEventListener(
);
document
.getElementById("disableProxyExtension")
.addEventListener(
"command",
makeDisableControllingExtension(PREF_SETTING_TYPE, PROXY_KEY).bind(
gConnectionsDialog
)
);
.getElementById("proxyExtensionDisable")
.addEventListener("click", disableControllingProxyExtension);
gConnectionsDialog.updateProxySettingsUI();
initializeProxyUI(gConnectionsDialog);
},
@ -433,11 +428,9 @@ var gConnectionsDialog = {
if (isLocked) {
// An extension can't control this setting if any pref is locked.
hideControllingExtension(PROXY_KEY);
hideControllingProxyExtension();
} else {
handleControllingExtension(PREF_SETTING_TYPE, PROXY_KEY).then(
setInputsDisabledState
);
handleControllingProxyExtension().then(setInputsDisabledState);
}
},

Просмотреть файл

@ -31,13 +31,19 @@
<script src="chrome://messenger/content/preferences/extensionControlled.js"/>
<script src="chrome://messenger/content/preferences/connection.js"/>
<hbox id="proxyExtensionContent"
align="start" hidden="true" class="extension-controlled">
<description control="disableProxyExtension" flex="1" />
<button id="disableProxyExtension"
class="extension-controlled-button accessory-button"
data-l10n-id="connection-disable-extension" />
</hbox>
<!-- Need a wrapper div within the xul:dialog, which otherwise does not give
- enough height for the flex display.
- REMOVE when we use HTML only. -->
<html:div>
<html:div id="proxyExtensionContent" hidden="hidden">
<html:p id="proxyExtensionDescription">
<html:img data-l10n-name="extension-icon" />
</html:p>
<html:button id="proxyExtensionDisable"
data-l10n-id="disable-extension-button">
</html:button>
</html:div>
</html:div>
<html:div>
<html:fieldset>

Просмотреть файл

@ -11,11 +11,6 @@ ChromeUtils.defineModuleGetter(
"AddonManager",
"resource://gre/modules/AddonManager.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"DeferredTask",
@ -26,19 +21,7 @@ ChromeUtils.defineModuleGetter(
"ExtensionSettingsStore",
"resource://gre/modules/ExtensionSettingsStore.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"ExtensionPreferencesManager",
"resource://gre/modules/ExtensionPreferencesManager.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"Management",
"resource://gre/modules/Extension.jsm"
);
const PREF_SETTING_TYPE = "prefs";
const PROXY_KEY = "proxy.settings";
const API_PROXY_PREFS = [
"network.proxy.type",
"network.proxy.http",
@ -55,251 +38,88 @@ const API_PROXY_PREFS = [
"signon.autologin.proxy",
];
let extensionControlledContentIds = {
"privacy.containers": "browserContainersExtensionContent",
webNotificationsDisabled: "browserNotificationsPermissionExtensionContent",
"services.passwordSavingEnabled": "passwordManagerExtensionContent",
"proxy.settings": "proxyExtensionContent",
get "websites.trackingProtectionMode"() {
return {
button: "contentBlockingDisableTrackingProtectionExtension",
section: "contentBlockingTrackingProtectionExtensionContentLabel",
};
},
};
const extensionControlledL10nKeys = {
webNotificationsDisabled: "web-notifications",
"services.passwordSavingEnabled": "password-saving",
"privacy.containers": "privacy-containers",
"websites.trackingProtectionMode": "websites-content-blocking-all-trackers",
"proxy.settings": "proxy-config",
};
let extensionControlledIds = {};
/**
* Check if a pref is being managed by an extension.
*
* NOTE: We only currently handle proxy.settings.
*/
async function getControllingExtensionInfo(type, settingName) {
/**
* Get the addon extension that is controlling the proxy settings.
*
* @return - The found addon, or undefined if none was found.
*/
async function getControllingProxyExtensionAddon() {
await ExtensionSettingsStore.initialize();
return ExtensionSettingsStore.getSetting(type, settingName);
let id = ExtensionSettingsStore.getSetting("prefs", "proxy.settings")?.id;
if (id) {
return AddonManager.getAddonByID(id);
}
return undefined;
}
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.
/**
* Show or hide the proxy extension message depending on whether or not the
* proxy settings are controlled by an extension.
*
* @return {boolean} - Whether the proxy settings are controlled by an
* extension.
*/
async function handleControllingProxyExtension() {
let addon = await getControllingProxyExtensionAddon();
if (addon) {
extensionControlledIds[settingName] = addon.id;
showControllingExtension(settingName, addon);
showControllingProxyExtension(addon);
} else {
let elements = getControllingExtensionEls(settingName);
if (
extensionControlledIds[settingName] &&
!document.hidden &&
elements.button
) {
showEnableExtensionMessage(settingName);
} else {
hideControllingExtension(settingName);
hideControllingProxyExtension();
}
delete extensionControlledIds[settingName];
}
return !!addon;
}
function settingNameToL10nID(settingName) {
if (!extensionControlledL10nKeys.hasOwnProperty(settingName)) {
throw new Error(
`Unknown extension controlled setting name: ${settingName}`
/**
* Show the proxy extension message.
*
* @param {Object} addon - The addon extension that is currently controlling the
* proxy settings.
* @param {string} addon.name - The addon name.
* @param {string} [addon.iconUrl] - The addon icon source.
*/
function showControllingProxyExtension(addon) {
let description = document.getElementById("proxyExtensionDescription");
description
.querySelector("img")
.setAttribute(
"src",
addon.iconUrl || "chrome://mozapps/skin/extensions/extensionGeneric.svg"
);
}
return `extension-controlled-${extensionControlledL10nKeys[settingName]}`;
document.l10n.setAttributes(
description,
"proxy-settings-controlled-by-extension",
{ name: addon.name }
);
document.getElementById("proxyExtensionContent").hidden = false;
}
/**
* Set the localization data for the description of the controlling extension.
*
* The function alters the inner DOM structure of the fragment to, depending
* on the `addon` argument, remove the `<img/>` element or ensure it's
* set to the correct src.
* This allows Fluent DOM Overlays to localize the fragment.
*
* @param elem {Element}
* <description> element to be annotated
* @param addon {Object?}
* Addon object with meta information about the addon (or null)
* @param settingName {String}
* If `addon` is set this handled the name of the setting that will be used
* to fetch the l10n id for the given message.
* If `addon` is set to null, this will be the full l10n-id assigned to the
* element.
* Hide the proxy extension message.
*/
function setControllingExtensionDescription(elem, addon, settingName) {
const existingImg = elem.querySelector("img");
if (addon === null) {
// If the element has an image child element,
// remove it.
if (existingImg) {
existingImg.remove();
}
document.l10n.setAttributes(elem, settingName);
return;
}
const defaultIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
const src = addon.iconURL || defaultIcon;
if (!existingImg) {
// If an element doesn't have an image child
// node, add it.
let image = document.createElementNS("http://www.w3.org/1999/xhtml", "img");
image.setAttribute("src", src);
image.setAttribute("data-l10n-name", "icon");
image.classList.add("extension-controlled-icon");
elem.appendChild(image);
} else if (existingImg.getAttribute("src") !== src) {
existingImg.setAttribute("src", src);
}
const l10nId = settingNameToL10nID(settingName);
document.l10n.setAttributes(elem, l10nId, {
name: addon.name,
});
}
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;
setControllingExtensionDescription(description, addon, settingName);
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");
elements.description.textContent = "";
// We replace localization of the <description> with a DOM Fragment containing
// the enable-extension-enable message. That means a change from:
//
// <description data-l10n-id="..."/>
//
// to:
//
// <description>
// <img/>
// <label data-l10n-id="..."/>
// </description>
//
// We need to remove the l10n-id annotation from the <description> to prevent
// Fluent from overwriting the element in case of any retranslation.
elements.description.removeAttribute("data-l10n-id");
let icon = (url, name) => {
let img = document.createElementNS("http://www.w3.org/1999/xhtml", "img");
img.src = url;
img.setAttribute("data-l10n-name", name);
img.className = "extension-controlled-icon";
return img;
};
let label = document.createXULElement("label");
let addonIcon = icon(
"chrome://mozapps/skin/extensions/extensionGeneric.svg",
"addons-icon"
);
let toolbarIcon = icon("chrome://browser/skin/menu.svg", "menu-icon");
label.appendChild(addonIcon);
label.appendChild(toolbarIcon);
document.l10n.setAttributes(label, "extension-controlled-enable");
elements.description.appendChild(label);
let dismissButton = document.createXULElement("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() {
let { id } = await getControllingExtensionInfo(type, settingName);
let addon = await AddonManager.getAddonByID(id);
await addon.disable();
};
function hideControllingProxyExtension() {
document.getElementById("proxyExtensionContent").hidden = true;
}
/**
* Initialize listeners though the Management API to update the UI
* when an extension is controlling a pref.
* @param {string} type
* @param {string} prefId The unique id of the setting
* @param {HTMLElement} controlledElement
* Disable the addon extension that is currently controlling the proxy settings.
*/
async function initListenersForPrefChange(type, prefId, controlledElement) {
await Management.asyncLoadSettingsModules();
let managementObserver = async () => {
let managementControlled = await handleControllingExtension(type, prefId);
// Enterprise policy may have locked the pref, so we need to preserve that
controlledElement.disabled =
managementControlled || Services.prefs.prefIsLocked(prefId);
};
managementObserver();
Management.on(`extension-setting-changed:${prefId}`, managementObserver);
window.addEventListener("unload", () => {
Management.off(`extension-setting-changed:${prefId}`, managementObserver);
});
function disableControllingProxyExtension() {
getControllingProxyExtensionAddon().then(addon => addon?.disable());
}
/**
* Start listening to the proxy settings, and update the UI accordingly.
*
* @param {Object} container - The proxy container.
* @param {Function} container.updateProxySettingsUI - A callback to call
* whenever the proxy settings change.
*/
function initializeProxyUI(container) {
let deferredUpdate = new DeferredTask(() => {
container.updateProxySettingsUI();

Просмотреть файл

@ -25,8 +25,14 @@ connection-dialog-window =
*[other] width: 49em !important
}
connection-disable-extension =
.label = Disable Extension
disable-extension-button = Disable Extension
# Variables:
# $name (String) - The extension that is controlling the proxy settings.
#
# The extension-icon is the extension's icon, or a fallback image. It should be
# purely decoration for the actual extension name, with alt="".
proxy-settings-controlled-by-extension = An extension, <img data-l10n-name="extension-icon" alt="" /> { $name }, is controlling how { -brand-short-name } connects to the Internet.
connection-proxy-legend = Configure Proxies to Access the Internet

Просмотреть файл

@ -602,6 +602,28 @@ checkbox {
* Connection dialog
*/
#proxyExtensionContent:not([hidden]) {
display: flex;
align-items: center;
}
#proxyExtensionDescription {
margin-block: 0;
flex: 1 1 auto;
}
#proxyExtensionDescription > img {
height: 20px;
width: 20px;
vertical-align: text-bottom;
-moz-context-properties: fill;
fill: currentColor;
}
#proxyExtensionDisable {
flex: 0 0 auto;
}
#proxy-grid,
#dnsOverHttps-grid {
display: grid;