Skip to content

Instantly share code, notes, and snippets.

@mstriemer
Last active April 9, 2020 16:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mstriemer/442912a30cca4c2d27c25d8340c15eaf to your computer and use it in GitHub Desktop.
Save mstriemer/442912a30cca4c2d27c25d8340c15eaf to your computer and use it in GitHub Desktop.
changeset: 605331:433996cb3310
tag: tip
parent: 605327:6c6c67870c37
user: Mark Striemer <mstriemer@mozilla.com>
date: Mon Feb 10 09:35:15 2020 -0600
summary: Bug 1595858 - Allow new tab selection when overridden
diff --git a/browser/components/preferences/in-content/home.inc.xhtml b/browser/components/preferences/in-content/home.inc.xhtml
--- a/browser/components/preferences/in-content/home.inc.xhtml
+++ b/browser/components/preferences/in-content/home.inc.xhtml
@@ -93,9 +93,9 @@
<hbox id="newTabsOption">
<label control="newTabMode" data-l10n-id="home-newtabs-mode-label" flex="1" />
- <menulist id="newTabMode"
- flex="1"
- preference="browser.newtabpage.enabled">
+ <!-- This can be set to an extension value which is managed outside of
+ Preferences so we need to handle setting the pref manually. -->
+ <menulist id="newTabMode" flex="1">
<menupopup>
<menuitem value="0" data-l10n-id="home-mode-choice-default" />
<menuitem value="1" data-l10n-id="home-mode-choice-blank" />
diff --git a/browser/components/preferences/in-content/home.js b/browser/components/preferences/in-content/home.js
--- a/browser/components/preferences/in-content/home.js
+++ b/browser/components/preferences/in-content/home.js
@@ -62,17 +62,92 @@ var gHomePane = {
return false;
},
+ async onNewTabChange() {
+ let value = document.getElementById("newTabMode").value;
+ dump(`onNewTabChange ${value}\n`);
+ if (["0", "1"].includes(value)) {
+ Services.prefs.setBoolPref(
+ this.NEWTAB_ENABLED_PREF,
+ value !== this.HOME_MODE_BLANK
+ );
+ ExtensionSettingsStore.select(null, URL_OVERRIDES_TYPE, NEW_TAB_KEY);
+ } else {
+ let addon = await AddonManager.getAddonByID(value);
+ if (addon && addon.isActive) {
+ let selectedAddon = ExtensionSettingsStore.getSetting(
+ URL_OVERRIDES_TYPE,
+ NEW_TAB_KEY
+ );
+ if (selectedAddon.id != addon.id) {
+ // This will trigger a callback which will call this function again.
+ // Make sure we only change the value if it needs to change.
+ ExtensionSettingsStore.select(
+ addon.id,
+ URL_OVERRIDES_TYPE,
+ NEW_TAB_KEY
+ );
+ }
+ }
+ }
+ },
+
/**
- * _handleNewTabOverrides: disables new tab settings UI. Called by
+ * _updateNewTabOverrides: disables new tab settings UI. Called by
* an observer in ._watchNewTab that watches for new tab url changes
*/
- async _handleNewTabOverrides() {
- const isControlled = await handleControllingExtension(
+ async _updateNewTabOverrides() {
+ let extensionOptions = await ExtensionSettingsStore.getAllSettings(
URL_OVERRIDES_TYPE,
NEW_TAB_KEY
);
- const el = document.getElementById("newTabMode");
- el.disabled = isControlled;
+ let addons = await AddonManager.getAddonsByIDs(
+ extensionOptions.map(a => a.id)
+ );
+
+ dump(`_updateNewTabOverrides ${AboutNewTab.newTabURL}\n`);
+
+ let select = document.getElementById("newTabMode");
+ let menupopup = select.querySelector("menupopup");
+ for (let addon of addons) {
+ let currentOption = select.querySelector(`[value="${addon.id}"]`);
+
+ if (!addon.isActive) {
+ // Skip any add-ons that are currently disabled.
+ if (currentOption) {
+ // Remove the old option if the add-on is now disabled.
+ //
+ // TODO: Test that disabling (or removing) an add-on that wasn't the
+ // active new tab add-on still gets cleaned up. This doesn't work
+ // since this is only run when the new tab URL changes.
+ currentOption.remove();
+ }
+ continue;
+ }
+
+ if (!currentOption) {
+ // Create an option for this add-on.
+ let option = document.createXULElement("menuitem");
+ option.value = addon.id;
+ option.label = addon.name;
+ menupopup.append(option);
+ option.querySelector("image").src = addon.iconURL;
+
+ let setting = extensionOptions.find(o => o.id == addon.id);
+ if (setting.value == AboutNewTab.newTabURL) {
+ dump(`Set newtab option to ${addon.id}\n`);
+ requestAnimationFrame(() => (select.value = addon.id));
+ }
+ }
+ }
+
+ switch (AboutNewTab.newTabURL) {
+ case "about:newtab":
+ select.value = 0;
+ break;
+ case "about:blank":
+ select.value = 1;
+ break;
+ }
},
/**
@@ -80,9 +155,12 @@ var gHomePane = {
* areas of the UI
*/
watchNewTab() {
- this._handleNewTabOverrides();
let newTabObserver = {
- observe: this._handleNewTabOverrides.bind(this),
+ observe: () => {
+ dump(`watchNewTab\n`);
+ this._updateNewTabOverrides();
+ this.onNewTabChange();
+ },
};
Services.obs.addObserver(newTabObserver, "newtab-url-changed");
window.addEventListener("unload", () => {
@@ -95,7 +173,9 @@ var gHomePane = {
* hide the Restore Defaults button.
*/
watchHomeTabPrefChange() {
- const observer = () => this.toggleRestoreDefaultsBtn();
+ const observer = () => {
+ this.toggleRestoreDefaultsBtn();
+ };
Services.prefs.addObserver(this.ACTIVITY_STREAM_PREF_BRANCH, observer);
Services.prefs.addObserver(this.HOMEPAGE_PREF, observer);
Services.prefs.addObserver(this.NEWTAB_ENABLED_PREF, observer);
@@ -284,17 +364,6 @@ var gHomePane = {
this._handleHomePageOverrides();
},
- syncFromNewTabPref() {
- const newtabPref = Preferences.get(this.NEWTAB_ENABLED_PREF);
- return newtabPref.value
- ? this.HOME_MODE_FIREFOX_HOME
- : this.HOME_MODE_BLANK;
- },
-
- syncToNewTabPref(value) {
- return value !== this.HOME_MODE_BLANK;
- },
-
onMenuChange(event) {
const { value } = event.target;
const startupPref = Preferences.get("browser.startup.page");
@@ -491,14 +560,13 @@ var gHomePane = {
document.getElementById("homePrefHidden"),
() => this.syncFromHomePref()
);
- Preferences.addSyncFromPrefListener(
- document.getElementById("newTabMode"),
- () => this.syncFromNewTabPref()
- );
- Preferences.addSyncToPrefListener(
- document.getElementById("newTabMode"),
- element => this.syncToNewTabPref(element.value)
- );
+
+ // Setup the add-on options for the new tab section before registering the
+ // listener.
+ this._updateNewTabOverrides();
+ document
+ .getElementById("newTabMode")
+ .addEventListener("select", () => this.onNewTabChange());
this._updateUseCurrentButton();
window.addEventListener("focus", this._updateUseCurrentButton.bind(this));
@@ -514,12 +582,6 @@ var gHomePane = {
HOMEPAGE_OVERRIDE_KEY
)
);
- document
- .getElementById("disableNewTabExtension")
- .addEventListener(
- "command",
- makeDisableControllingExtension(URL_OVERRIDES_TYPE, NEW_TAB_KEY)
- );
this.watchHomeTabPrefChange();
// Notify observers that the UI is now ready
diff --git a/browser/components/preferences/in-content/tests/browser_extension_controlled.js b/browser/components/preferences/in-content/tests/browser_extension_controlled.js
--- a/browser/components/preferences/in-content/tests/browser_extension_controlled.js
+++ b/browser/components/preferences/in-content/tests/browser_extension_controlled.js
@@ -457,6 +457,7 @@ add_task(async function testPrefLockedHo
});
add_task(async function testExtensionControlledNewTab() {
+ const ADDON_ID = "@set_newtab";
await openPreferencesViaOpenPreferencesAPI("paneHome", { leaveOpen: true });
let doc = gBrowser.contentDocument;
is(
@@ -465,62 +466,41 @@ add_task(async function testExtensionCon
"#home should be in the URI for about:preferences"
);
- let controlledContent = doc.getElementById("browserNewTabExtensionContent");
-
// The new tab is set to the default and message is hidden.
ok(!AboutNewTab.newTabURL.startsWith("moz-extension:"), "new tab is not set");
- is(controlledContent.hidden, true, "The extension controlled row is hidden");
+
+ let newTabMenuList = doc.getElementById("newTabMode");
// Install an extension that will set the new tab page.
- let promise = waitForMessageShown("browserNewTabExtensionContent");
+ let promise = BrowserTestUtils.waitForEvent(newTabMenuList, "select");
await installAddon("set_newtab.xpi");
await promise;
// The new tab page has been set by the extension and the user is notified.
- let controlledLabel = controlledContent.querySelector("description");
ok(
AboutNewTab.newTabURL.startsWith("moz-extension:"),
"new tab url is set by extension"
);
- Assert.deepEqual(
- doc.l10n.getAttributes(controlledLabel),
- {
- id: "extension-controlled-new-tab-url",
- args: {
- name: "set_newtab",
- },
- },
- "The user is notified that an extension is controlling the new tab page"
- );
- is(controlledContent.hidden, false, "The extension controlled row is hidden");
+ is(newTabMenuList.value, ADDON_ID, "New tab dropdown is set to the add-on");
// Disable the extension.
- doc.getElementById("disableNewTabExtension").click();
+ let addon = await AddonManager.getAddonByID(ADDON_ID);
+ // promise = BrowserTestUtils.waitForEvent(newTabMenuList, "select");
+ promise = TestUtils.waitForCondition(() => newTabMenuList.value == "0");
+ await addon.disable();
+ await promise;
// Verify the user is notified how to enable the extension.
- await waitForEnableMessage(controlledContent.id);
- is(
- doc.l10n.getAttributes(controlledLabel.querySelector("label")).id,
- "extension-controlled-enable",
- "The user is notified of how to enable the extension again"
- );
-
- // Verify the enable message can be dismissed.
- let hidden = waitForMessageHidden(controlledContent.id);
- let dismissButton = controlledLabel.querySelector("image:last-of-type");
- dismissButton.click();
- await hidden;
+ is(newTabMenuList.value, "0", "The add-on option is no longer selected");
// Ensure the New Tab page has been reset and there is no message.
ok(
!AboutNewTab.newTabURL.startsWith("moz-extension:"),
"new tab page is set back to default"
);
- is(controlledContent.hidden, true, "The extension controlled row is shown");
// Cleanup the tab and add-on.
BrowserTestUtils.removeTab(gBrowser.selectedTab);
- let addon = await AddonManager.getAddonByID("@set_newtab");
await addon.uninstall();
});
diff --git a/toolkit/components/extensions/ExtensionSettingsStore.jsm b/toolkit/components/extensions/ExtensionSettingsStore.jsm
--- a/toolkit/components/extensions/ExtensionSettingsStore.jsm
+++ b/toolkit/components/extensions/ExtensionSettingsStore.jsm
@@ -183,6 +183,25 @@ function getItem(type, key, id) {
return { key, initialValue: keyInfo.initialValue };
}
+function getAllItems(type, key) {
+ ensureType(type);
+
+ let keyInfo = _store.data[type][key];
+ if (!keyInfo) {
+ return [];
+ }
+
+ let items = keyInfo.precedenceList;
+ return items
+ ? items.map(item => ({
+ key,
+ value: item.value,
+ id: item.id,
+ enabled: item.enabled,
+ }))
+ : [];
+}
+
// Comparator used when sorting the precedence list.
function precedenceComparator(a, b) {
if (a.enabled && !b.enabled) {
@@ -536,6 +555,10 @@ var ExtensionSettingsStore = {
return getItem(type, key, id);
},
+ getAllSettings(type, key) {
+ return getAllItems(type, key);
+ },
+
/**
* Returns whether an extension currently has a stored setting for a given
* key.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment