зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1390161 - Show that a WebExtension is managing the tracking protection setting, r=jaws,mstriemer
This adjusts both the new Tracking Protection UI and the old Tracking Protection UI on about:preferences to indicate when an extension is controlling Tracking Protection. It will disable the controls on about:preferences if an extension is in control, and provide a button to disable the extension. MozReview-Commit-ID: G04jWrS6Pr9 --HG-- extra : rebase_source : 4cdee73b00b74e25c074e62a872d7b50a984cf8f
This commit is contained in:
Родитель
dd155c0445
Коммит
31cb7a05fa
|
@ -37,7 +37,6 @@ const PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS =
|
|||
"browser.download.hide_plugins_without_extensions";
|
||||
|
||||
// Strings to identify ExtensionSettingsStore overrides
|
||||
const PREF_SETTING_TYPE = "prefs";
|
||||
const CONTAINERS_KEY = "privacy.containers";
|
||||
const HOMEPAGE_OVERRIDE_KEY = "homepage_override";
|
||||
const URL_OVERRIDES_TYPE = "url_overrides";
|
||||
|
|
|
@ -31,6 +31,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "formAutofillParent",
|
||||
"resource://formautofill/FormAutofillParent.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "trackingprotectionUiEnabled",
|
||||
"privacy.trackingprotection.ui.enabled");
|
||||
|
||||
var gLastHash = "";
|
||||
|
||||
var gCategoryInits = new Map();
|
||||
|
@ -418,11 +421,22 @@ function appendSearchKeywords(aId, keywords) {
|
|||
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 = {};
|
||||
|
@ -435,8 +449,17 @@ async function getControllingExtensionInfo(type, settingName) {
|
|||
return ExtensionSettingsStore.getSetting(type, settingName);
|
||||
}
|
||||
|
||||
function getControllingExtensionEl(settingName) {
|
||||
return document.getElementById(extensionControlledContentIds[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) {
|
||||
|
@ -453,7 +476,10 @@ async function handleControllingExtension(type, settingName) {
|
|||
extensionControlledIds[settingName] = info.id;
|
||||
showControllingExtension(settingName, addon);
|
||||
} else {
|
||||
if (extensionControlledIds[settingName] && !document.hidden) {
|
||||
let elements = getControllingExtensionEls(settingName);
|
||||
if (extensionControlledIds[settingName]
|
||||
&& !document.hidden
|
||||
&& elements.button) {
|
||||
showEnableExtensionMessage(settingName);
|
||||
} else {
|
||||
hideControllingExtension(settingName);
|
||||
|
@ -466,14 +492,15 @@ async function handleControllingExtension(type, settingName) {
|
|||
|
||||
async function showControllingExtension(settingName, addon) {
|
||||
// Tell the user what extension is controlling the setting.
|
||||
let extensionControlledContent = getControllingExtensionEl(settingName);
|
||||
extensionControlledContent.classList.remove("extension-controlled-disabled");
|
||||
let elements = getControllingExtensionEls(settingName);
|
||||
|
||||
elements.section.classList.remove("extension-controlled-disabled");
|
||||
const defaultIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
|
||||
let stringParts = document
|
||||
.getElementById("bundlePreferences")
|
||||
.getString(`extensionControlled.${settingName}`)
|
||||
.split("%S");
|
||||
let description = extensionControlledContent.querySelector("description");
|
||||
let description = elements.description;
|
||||
|
||||
// Remove the old content from the description.
|
||||
while (description.firstChild) {
|
||||
|
@ -489,38 +516,42 @@ async function showControllingExtension(settingName, addon) {
|
|||
description.appendChild(document.createTextNode(` ${addon.name}`));
|
||||
description.appendChild(document.createTextNode(stringParts[1]));
|
||||
|
||||
let disableButton = extensionControlledContent.querySelector("button");
|
||||
if (disableButton) {
|
||||
disableButton.hidden = false;
|
||||
if (elements.button) {
|
||||
elements.button.hidden = false;
|
||||
}
|
||||
|
||||
// Show the controlling extension row and hide the old label.
|
||||
extensionControlledContent.hidden = false;
|
||||
elements.section.hidden = false;
|
||||
}
|
||||
|
||||
function hideControllingExtension(settingName) {
|
||||
getControllingExtensionEl(settingName).hidden = true;
|
||||
let elements = getControllingExtensionEls(settingName);
|
||||
elements.section.hidden = true;
|
||||
if (elements.button) {
|
||||
elements.button.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
function showEnableExtensionMessage(settingName) {
|
||||
let extensionControlledContent = getControllingExtensionEl(settingName);
|
||||
extensionControlledContent.classList.add("extension-controlled-disabled");
|
||||
let elements = getControllingExtensionEls(settingName);
|
||||
|
||||
elements.button.hidden = true;
|
||||
elements.section.classList.add("extension-controlled-disabled");
|
||||
let icon = url => `<image src="${url}" class="extension-controlled-icon"/>`;
|
||||
let addonIcon = icon("chrome://mozapps/skin/extensions/extensionGeneric-16.svg");
|
||||
let toolbarIcon = icon("chrome://browser/skin/menu.svg");
|
||||
let message = document
|
||||
.getElementById("bundlePreferences")
|
||||
.getFormattedString("extensionControlled.enable", [addonIcon, toolbarIcon]);
|
||||
let description = extensionControlledContent.querySelector("description");
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
description.innerHTML = message;
|
||||
elements.description.innerHTML = message;
|
||||
let dismissButton = document.createElement("image");
|
||||
dismissButton.setAttribute("class", "extension-controlled-icon close-icon");
|
||||
dismissButton.addEventListener("click", function dismissHandler() {
|
||||
hideControllingExtension(settingName);
|
||||
dismissButton.removeEventListener("click", dismissHandler);
|
||||
});
|
||||
description.appendChild(dismissButton);
|
||||
elements.description.appendChild(dismissButton);
|
||||
}
|
||||
|
||||
function makeDisableControllingExtension(type, settingName) {
|
||||
|
|
|
@ -17,10 +17,17 @@ XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "SiteDataManager",
|
||||
"resource:///modules/SiteDataManager.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "trackingprotectionUiEnabled",
|
||||
"privacy.trackingprotection.ui.enabled");
|
||||
|
||||
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
|
||||
const PREF_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";
|
||||
|
||||
const TRACKING_PROTECTION_KEY = "websites.trackingProtectionMode";
|
||||
const TRACKING_PROTECTION_PREFS = ["privacy.trackingprotection.enabled",
|
||||
"privacy.trackingprotection.pbmode.enabled"];
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "AlertsServiceDND", function() {
|
||||
try {
|
||||
let alertsService = Cc["@mozilla.org/alerts-service;1"]
|
||||
|
@ -133,7 +140,7 @@ var gPrivacyPane = {
|
|||
* privacy.trackingprotection.ui.enabled pref, and linkify its Learn More link
|
||||
*/
|
||||
_initTrackingProtection() {
|
||||
if (!Services.prefs.getBoolPref("privacy.trackingprotection.ui.enabled")) {
|
||||
if (!trackingprotectionUiEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -153,9 +160,71 @@ var gPrivacyPane = {
|
|||
* Protection UI.
|
||||
*/
|
||||
_initTrackingProtectionPBM() {
|
||||
let link = document.getElementById("trackingProtectionPBMLearnMore");
|
||||
if (trackingprotectionUiEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
let link = document.getElementById("trackingProtectionLearnMore");
|
||||
let url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "tracking-protection-pbm";
|
||||
link.setAttribute("href", url);
|
||||
|
||||
this._updateTrackingProtectionUI();
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the tracking protection UI to deal with extension control.
|
||||
*/
|
||||
_updateTrackingProtectionUI() {
|
||||
let isLocked = TRACKING_PROTECTION_PREFS.some(
|
||||
pref => Services.prefs.prefIsLocked(pref));
|
||||
|
||||
function setInputsDisabledState(isControlled) {
|
||||
let disabled = isLocked || isControlled;
|
||||
if (trackingprotectionUiEnabled) {
|
||||
document.querySelectorAll("#trackingProtectionRadioGroup > radio")
|
||||
.forEach((element) => {
|
||||
element.disabled = disabled;
|
||||
});
|
||||
document.querySelector("#trackingProtectionDesc > label")
|
||||
.disabled = disabled;
|
||||
} else {
|
||||
document.getElementById("trackingProtectionPBM").disabled = disabled;
|
||||
document.getElementById("trackingProtectionPBMLabel")
|
||||
.disabled = disabled;
|
||||
}
|
||||
}
|
||||
|
||||
if (isLocked) {
|
||||
// An extension can't control this setting if either pref is locked.
|
||||
hideControllingExtension(TRACKING_PROTECTION_KEY);
|
||||
setInputsDisabledState(false);
|
||||
} else {
|
||||
handleControllingExtension(
|
||||
PREF_SETTING_TYPE,
|
||||
TRACKING_PROTECTION_KEY)
|
||||
.then(setInputsDisabledState);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set up handlers for showing and hiding controlling extension info
|
||||
* for tracking protection.
|
||||
*/
|
||||
_initTrackingProtectionExtensionControl() {
|
||||
let trackingProtectionObserver = {
|
||||
observe(subject, topic, data) {
|
||||
gPrivacyPane._updateTrackingProtectionUI();
|
||||
},
|
||||
};
|
||||
|
||||
for (let pref of TRACKING_PROTECTION_PREFS) {
|
||||
Services.prefs.addObserver(pref, trackingProtectionObserver);
|
||||
}
|
||||
window.addEventListener("unload", () => {
|
||||
for (let pref of TRACKING_PROTECTION_PREFS) {
|
||||
Services.prefs.removeObserver(pref, trackingProtectionObserver);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -183,6 +252,7 @@ var gPrivacyPane = {
|
|||
this.initAutoStartPrivateBrowsingReverter();
|
||||
this._initTrackingProtection();
|
||||
this._initTrackingProtectionPBM();
|
||||
this._initTrackingProtectionExtensionControl();
|
||||
this._initAutocomplete();
|
||||
|
||||
Preferences.get("privacy.sanitize.sanitizeOnShutdown").on("change",
|
||||
|
@ -227,6 +297,9 @@ var gPrivacyPane = {
|
|||
gPrivacyPane.showCookies);
|
||||
setEventListener("clearDataSettings", "command",
|
||||
gPrivacyPane.showClearPrivateDataSettings);
|
||||
setEventListener("disableTrackingProtectionExtension", "command",
|
||||
makeDisableControllingExtension(
|
||||
PREF_SETTING_TYPE, TRACKING_PROTECTION_KEY));
|
||||
setEventListener("trackingProtectionRadioGroup", "command",
|
||||
gPrivacyPane.trackingProtectionWritePrefs);
|
||||
setEventListener("trackingProtectionExceptions", "command",
|
||||
|
@ -419,6 +492,8 @@ var gPrivacyPane = {
|
|||
let pbmPref = Preferences.get("privacy.trackingprotection.pbmode.enabled");
|
||||
let radiogroup = document.getElementById("trackingProtectionRadioGroup");
|
||||
|
||||
this._updateTrackingProtectionUI();
|
||||
|
||||
// Global enable takes precedence over enabled in Private Browsing.
|
||||
if (enabledPref.value) {
|
||||
radiogroup.value = "always";
|
||||
|
|
|
@ -323,41 +323,55 @@
|
|||
<hbox align="start">
|
||||
<vbox flex="1">
|
||||
<description>
|
||||
&trackingProtection2.description;
|
||||
&trackingProtection3.description;
|
||||
<label id="trackingProtectionLearnMore" class="learnMore text-link">&trackingProtectionLearnMore2.label;</label>
|
||||
</description>
|
||||
</vbox>
|
||||
<spacer flex="1"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<vbox id="trackingProtectionBox" flex="1" hidden="true">
|
||||
<description id="trackingProtectionDesc"
|
||||
control="trackingProtectionRadioGroup">
|
||||
<label class="tail-with-learn-more">&trackingProtection2.radioGroupLabel;</label>
|
||||
<label id="trackingProtectionLearnMore" class="learnMore text-link">&trackingProtectionLearnMore.label;</label>
|
||||
</description>
|
||||
<radiogroup id="trackingProtectionRadioGroup" aria-labelledby="trackingProtectionDesc">
|
||||
<radio value="always"
|
||||
label="&trackingProtectionAlways.label;"
|
||||
accesskey="&trackingProtectionAlways.accesskey;"/>
|
||||
<radio value="private"
|
||||
label="&trackingProtectionPrivate.label;"
|
||||
accesskey="&trackingProtectionPrivate.accesskey;"/>
|
||||
<radio value="never"
|
||||
label="&trackingProtectionNever.label;"
|
||||
accesskey="&trackingProtectionNever.accesskey;"/>
|
||||
</radiogroup>
|
||||
<vbox>
|
||||
<hbox id="trackingProtectionExtensionContentLabel" align="center" hidden="true">
|
||||
<description control="disableTrackingProtectionExtension" flex="1"/>
|
||||
</hbox>
|
||||
<vbox>
|
||||
<description id="trackingProtectionDesc"
|
||||
control="trackingProtectionRadioGroup">
|
||||
<label>&trackingProtection3.radioGroupLabel;</label>
|
||||
</description>
|
||||
<radiogroup id="trackingProtectionRadioGroup" aria-labelledby="trackingProtectionDesc">
|
||||
<radio value="always"
|
||||
label="&trackingProtectionAlways.label;"
|
||||
accesskey="&trackingProtectionAlways.accesskey;"/>
|
||||
<radio value="private"
|
||||
label="&trackingProtectionPrivate.label;"
|
||||
accesskey="&trackingProtectionPrivate.accesskey;"/>
|
||||
<radio value="never"
|
||||
label="&trackingProtectionNever.label;"
|
||||
accesskey="&trackingProtectionNever.accesskey;"/>
|
||||
</radiogroup>
|
||||
</vbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
<vbox id="trackingProtectionPBMBox" flex="1">
|
||||
<hbox align="center">
|
||||
<hbox id="trackingProtectionPBMExtensionContentLabel" align="center" hidden="true">
|
||||
<description control="disableTrackingProtectionExtension" flex="1"/>
|
||||
</hbox>
|
||||
<hbox align="start">
|
||||
<checkbox id="trackingProtectionPBM"
|
||||
preference="privacy.trackingprotection.pbmode.enabled"
|
||||
accesskey="&trackingProtectionPBM6.accesskey;"/>
|
||||
<label flex="1">&trackingProtectionPBM6.label;<spacer class="tail-with-learn-more" /><label id="trackingProtectionPBMLearnMore"
|
||||
class="learnMore text-link">&trackingProtectionPBMLearnMore.label;</label>
|
||||
</label>
|
||||
<label id="trackingProtectionPBMLabel" flex="1">&trackingProtectionPBM6.label;</label>
|
||||
</hbox>
|
||||
</vbox>
|
||||
<vbox id="trackingProtectionAdvancedSettings">
|
||||
<hbox id="trackingProtectionExtensionContentButton" hidden="true">
|
||||
<button id="disableTrackingProtectionExtension"
|
||||
class="extension-controlled-button accessory-button"
|
||||
flex="1"
|
||||
label="&disableExtension.label;"/>
|
||||
</hbox>
|
||||
<!-- 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="trackingProtectionExceptions"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/* eslint-env webextensions */
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionSettingsStore",
|
||||
"resource://gre/modules/ExtensionSettingsStore.jsm");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
|
||||
|
@ -467,3 +469,138 @@ add_task(async function testExtensionControlledHomepageUninstalledAddon() {
|
|||
is(ExtensionSettingsStore.getSetting("prefs", "homepage_override"), null,
|
||||
"The ExtensionSettingsStore is left empty.");
|
||||
});
|
||||
|
||||
add_task(async function testExtensionControlledTrackingProtection() {
|
||||
const TP_UI_PREF = "privacy.trackingprotection.ui.enabled";
|
||||
const TP_PREF = "privacy.trackingprotection.enabled";
|
||||
const TP_DEFAULT = false;
|
||||
const EXTENSION_ID = "@set_tp";
|
||||
const CONTROLLED_LABEL_ID = {
|
||||
new: "trackingProtectionExtensionContentLabel",
|
||||
old: "trackingProtectionPBMExtensionContentLabel"
|
||||
};
|
||||
const CONTROLLED_BUTTON_ID = "trackingProtectionExtensionContentButton";
|
||||
|
||||
let tpEnabledPref = () => Services.prefs.getBoolPref(TP_PREF);
|
||||
|
||||
await SpecialPowers.pushPrefEnv(
|
||||
{"set": [[TP_PREF, TP_DEFAULT], [TP_UI_PREF, true]]});
|
||||
|
||||
function background() {
|
||||
browser.privacy.websites.trackingProtectionMode.set({value: "always"});
|
||||
}
|
||||
|
||||
function verifyState(isControlled) {
|
||||
is(tpEnabledPref(), isControlled, "TP pref is set to the expected value.");
|
||||
|
||||
let controlledLabel = doc.getElementById(CONTROLLED_LABEL_ID[uiType]);
|
||||
|
||||
is(controlledLabel.hidden, !isControlled, "The extension controlled row's visibility is as expected.");
|
||||
is(controlledButton.hidden, !isControlled, "The disable extension button's visibility is as expected.");
|
||||
if (isControlled) {
|
||||
let controlledDesc = controlledLabel.querySelector("description");
|
||||
// There are two spaces before "set_tp" because it's " <image /> set_tp".
|
||||
is(controlledDesc.textContent, "An extension, set_tp, is controlling tracking protection.",
|
||||
"The user is notified that an extension is controlling TP.");
|
||||
}
|
||||
|
||||
if (uiType === "new") {
|
||||
for (let element of doc.querySelectorAll("#trackingProtectionRadioGroup > radio")) {
|
||||
is(element.disabled, isControlled, "TP controls are enabled.");
|
||||
}
|
||||
is(doc.querySelector("#trackingProtectionDesc > label").disabled,
|
||||
isControlled,
|
||||
"TP control label is enabled.");
|
||||
} else {
|
||||
is(doc.getElementById("trackingProtectionPBM").disabled,
|
||||
isControlled,
|
||||
"TP control is enabled.");
|
||||
is(doc.getElementById("trackingProtectionPBMLabel").disabled,
|
||||
isControlled,
|
||||
"TP control label is enabled.");
|
||||
}
|
||||
}
|
||||
|
||||
async function disableViaClick() {
|
||||
let labelId = CONTROLLED_LABEL_ID[uiType];
|
||||
let controlledLabel = doc.getElementById(labelId);
|
||||
|
||||
let enableMessageShown = waitForEnableMessage(labelId);
|
||||
doc.getElementById("disableTrackingProtectionExtension").click();
|
||||
await enableMessageShown;
|
||||
|
||||
// The user is notified how to enable the extension.
|
||||
let controlledDesc = controlledLabel.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(labelId);
|
||||
controlledLabel.querySelector("image:last-of-type").click();
|
||||
await hidden;
|
||||
}
|
||||
|
||||
async function reEnableExtension(addon) {
|
||||
let controlledMessageShown = waitForMessageShown(CONTROLLED_LABEL_ID[uiType]);
|
||||
addon.userDisabled = false;
|
||||
await controlledMessageShown;
|
||||
}
|
||||
|
||||
let uiType = "new";
|
||||
|
||||
await openPreferencesViaOpenPreferencesAPI("panePrivacy", {leaveOpen: true});
|
||||
// eslint-disable-next-line mozilla/no-cpows-in-tests
|
||||
let doc = gBrowser.contentDocument;
|
||||
|
||||
is(gBrowser.currentURI.spec, "about:preferences#privacy",
|
||||
"#privacy should be in the URI for about:preferences");
|
||||
|
||||
let controlledButton = doc.getElementById(CONTROLLED_BUTTON_ID);
|
||||
|
||||
verifyState(false);
|
||||
|
||||
// Install an extension that sets Tracking Protection.
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
useAddonManager: "permanent",
|
||||
manifest: {
|
||||
name: "set_tp",
|
||||
applications: {gecko: {id: EXTENSION_ID}},
|
||||
permissions: ["privacy"],
|
||||
},
|
||||
background,
|
||||
});
|
||||
|
||||
let messageShown = waitForMessageShown(CONTROLLED_LABEL_ID[uiType]);
|
||||
await extension.startup();
|
||||
await messageShown;
|
||||
let addon = await AddonManager.getAddonByID(EXTENSION_ID);
|
||||
|
||||
verifyState(true);
|
||||
|
||||
await disableViaClick();
|
||||
|
||||
verifyState(false);
|
||||
|
||||
// Switch to the "old" Tracking Protection UI.
|
||||
uiType = "old";
|
||||
Services.prefs.setBoolPref(TP_UI_PREF, false);
|
||||
|
||||
verifyState(false);
|
||||
|
||||
await reEnableExtension(addon);
|
||||
|
||||
verifyState(true);
|
||||
|
||||
await disableViaClick();
|
||||
|
||||
verifyState(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);
|
||||
});
|
||||
|
|
|
@ -292,6 +292,10 @@ extensionControlled.defaultSearch = An extension, %S, has set your default searc
|
|||
# %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.enable):
|
||||
# %1$S is replaced with the icon for the add-ons menu.
|
||||
# %2$S is replaced with the icon for the toolbar menu.
|
||||
|
|
|
@ -3,15 +3,15 @@
|
|||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!ENTITY trackingProtectionHeader2.label "Tracking Protection">
|
||||
<!ENTITY trackingProtection2.description "Tracking is the collection of your browsing data across multiple websites. Tracking can be used to build a profile and display content based on your browsing and personal information.">
|
||||
<!ENTITY trackingProtection2.radioGroupLabel "Use Tracking Protection to block known trackers">
|
||||
<!ENTITY trackingProtection3.description "Tracking Protection blocks online trackers that collect your browsing data across multiple websites.">
|
||||
<!ENTITY trackingProtection3.radioGroupLabel "Use Tracking Protection to block known trackers">
|
||||
<!ENTITY trackingProtectionAlways.label "Always">
|
||||
<!ENTITY trackingProtectionAlways.accesskey "y">
|
||||
<!ENTITY trackingProtectionPrivate.label "Only in private windows">
|
||||
<!ENTITY trackingProtectionPrivate.accesskey "l">
|
||||
<!ENTITY trackingProtectionNever.label "Never">
|
||||
<!ENTITY trackingProtectionNever.accesskey "n">
|
||||
<!ENTITY trackingProtectionLearnMore.label "Learn more">
|
||||
<!ENTITY trackingProtectionLearnMore2.label "Learn more about Tracking Protection and your privacy">
|
||||
<!ENTITY trackingProtectionExceptions.label "Exceptions…">
|
||||
<!ENTITY trackingProtectionExceptions.accesskey "x">
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче