-
-
Save mstriemer/442912a30cca4c2d27c25d8340c15eaf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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