Bug 1434751 - Add Restore Defaults button to Home
MozReview-Commit-ID: 5NRxEhPIImg
--- a/browser/components/preferences/in-content/home.js
+++ b/browser/components/preferences/in-content/home.js
@@ -27,21 +27,26 @@ Preferences.addAll([
{ id: "pref.browser.homepage.disable_button.restore_default", type: "bool" },
{ id: "browser.newtabpage.enabled", type: "bool" }
]);
const HOMEPAGE_OVERRIDE_KEY = "homepage_override";
const URL_OVERRIDES_TYPE = "url_overrides";
const NEW_TAB_KEY = "newTabURL";
-let gHomePane = {
+var gHomePane = {
HOME_MODE_FIREFOX_HOME: "0",
HOME_MODE_BLANK: "1",
HOME_MODE_CUSTOM: "2",
NEWTAB_ENABLED_PREF: "browser.newtabpage.enabled",
+ ACTIVITY_STREAM_PREF_BRANCH: "browser.newtabpage.activity-stream.",
+
+ get homePanePrefs() {
+ return Preferences.getAll().filter(pref => pref.id.includes(this.ACTIVITY_STREAM_PREF_BRANCH));
+ },
/**
* _handleNewTabOverrides: disables new tab settings UI. Called by
* an observer in ._watchNewTab that watches for new tab url changes
*/
async _handleNewTabOverrides() {
const isControlled = await handleControllingExtension(
URL_OVERRIDES_TYPE, NEW_TAB_KEY);
@@ -60,16 +65,33 @@ let gHomePane = {
};
Services.obs.addObserver(newTabObserver, "newtab-url-changed");
window.addEventListener("unload", () => {
Services.obs.removeObserver(newTabObserver, "newtab-url-changed");
});
},
/**
+ * Listen for all preferences changes on the Home Tab in order to show or
+ * hide the Restore Defaults button.
+ */
+ watchHomeTabPrefChange() {
+ const observer = () => this.toggleRestoreDefaultsBtn();
+ Services.prefs.addObserver(this.ACTIVITY_STREAM_PREF_BRANCH, observer);
+ Services.prefs.addObserver("browser.startup.homepage", observer);
+ Services.prefs.addObserver(this.NEWTAB_ENABLED_PREF, observer);
+
+ window.addEventListener("unload", () => {
+ Services.prefs.removeObserver(this.ACTIVITY_STREAM_PREF_BRANCH, observer);
+ Services.prefs.removeObserver("browser.startup.homepage", observer);
+ Services.prefs.removeObserver(this.NEWTAB_ENABLED_PREF, observer);
+ });
+ },
+
+ /**
* _renderCustomSettings: Hides or shows the UI for setting a custom
* homepage URL
* @param {obj} options
* @param {bool} options.shouldShow Should the custom UI be shown?
* @param {bool} options.isControlled Is an extension controlling the home page?
*/
_renderCustomSettings(options = {}) {
let {shouldShow, isControlled} = options;
@@ -349,31 +371,63 @@ let gHomePane = {
},
onCustomHomePageChange(event) {
const homePref = Preferences.get("browser.startup.homepage");
const value = event.target.value || homePref.defaultValue;
homePref.value = value;
},
+ /**
+ * Check all Home Tab preferences for user set values.
+ */
+ _changedHomeTabDefaultPrefs() {
+ const homeContentChanged = this.homePanePrefs.some(pref => pref.hasUserValue);
+ const homePref = Preferences.get("browser.startup.homepage");
+ const newtabPref = Preferences.get(this.NEWTAB_ENABLED_PREF);
+
+ return homeContentChanged ||
+ (homePref.value !== homePref.defaultValue) ||
+ newtabPref.hasUserValue;
+ },
+
+ /**
+ * Show the Restore Defaults button if any preference on the Home tab was
+ * changed, or hide it otherwise.
+ */
+ toggleRestoreDefaultsBtn() {
+ const btn = document.getElementById("restoreDefaultHomePageBtn");
+ const prefChanged = this._changedHomeTabDefaultPrefs();
+ btn.style.visibility = prefChanged ? "visible" : "hidden";
+ },
+
+ /**
+ * Set all prefs on the Home tab back to their default values.
+ */
+ restoreDefaultPrefsForHome() {
+ this.restoreDefaultHomePage();
+ this.homePanePrefs.forEach(pref => pref.value = pref.defaultValue);
+ },
+
init() {
// Event Listeners
document.getElementById("homeMode").addEventListener("command", this.onMenuChange.bind(this));
document.getElementById("homePageUrl").addEventListener("change", this.onCustomHomePageChange.bind(this));
document.getElementById("homePageUrl").addEventListener("input", this.onCustomHomePageInput.bind(this));
document.getElementById("useCurrentBtn").addEventListener("command", this.setHomePageToCurrent.bind(this));
document.getElementById("useBookmarkBtn").addEventListener("command", this.setHomePageToBookmark.bind(this));
- document.getElementById("restoreDefaultHomePageBtn").addEventListener("command", this.restoreDefaultHomePage.bind(this));
+ document.getElementById("restoreDefaultHomePageBtn").addEventListener("command", this.restoreDefaultPrefsForHome.bind(this));
this._updateUseCurrentButton();
window.addEventListener("focus", this._updateUseCurrentButton.bind(this));
// Extension/override-related events
this.watchNewTab();
document.getElementById("disableHomePageExtension").addEventListener("command",
makeDisableControllingExtension(PREF_SETTING_TYPE, 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
Services.obs.notifyObservers(window, "home-pane-loaded");
}
};
--- a/browser/components/preferences/in-content/home.xul
+++ b/browser/components/preferences/in-content/home.xul
@@ -6,29 +6,33 @@
<script type="application/javascript"
src="chrome://browser/content/preferences/in-content/home.js"/>
<hbox id="firefoxHomeCategory"
class="subcategory"
hidden="true"
data-category="paneHome">
- <label class="header-name" flex="1" data-l10n-id="pane-home-title" />
+ <hbox align="center" flex="1">
+ <hbox align="center" flex="1">
+ <label class="header-name" data-l10n-id="pane-home-title" />
+ </hbox>
+ <button id="restoreDefaultHomePageBtn"
+ class="homepage-button check-home-page-controlled"
+ data-preference-related="browser.startup.homepage"
+ data-l10n-id="home-restore-defaults"
+ preference="pref.browser.homepage.disable_button.restore_default"/>
+ </hbox>
</hbox>
<groupbox id="homepageGroup"
data-category="paneHome"
hidden="true">
<hbox>
- <caption flex="1" align="center"><label data-l10n-id="home-new-windows-tabs-header"/></caption>
- <button id="restoreDefaultHomePageBtn"
- class="homepage-button check-home-page-controlled"
- data-preference-related="browser.startup.homepage"
- data-l10n-id="home-restore-defaults"
- preference="pref.browser.homepage.disable_button.restore_default"/>
+ <caption><label data-l10n-id="home-new-windows-tabs-header"/></caption>
</hbox>
<description data-l10n-id="home-new-windows-tabs-description2" />
<vbox>
<hbox id="homepageAndNewWindowsOption">
<label control="homeMode" data-l10n-id="home-homepage-mode-label" flex="1" />
<vbox class="homepageMenuItemContainer" flex="1">
--- a/browser/components/preferences/in-content/tests/browser.ini
+++ b/browser/components/preferences/in-content/tests/browser.ini
@@ -89,8 +89,9 @@ support-files =
subdialog2.xul
[browser_sync_sanitize.js]
[browser_telemetry.js]
# Skip this test on Android as FHR and Telemetry are separate systems there.
skip-if = !healthreport || !telemetry || (os == 'linux' && debug) || (os == 'android')
[browser_containers_name_input.js]
run-if = nightly_build # Containers is enabled only on Nightly
[browser_fluent.js]
+[browser_hometab_restore_defaults.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/in-content/tests/browser_hometab_restore_defaults.js
@@ -0,0 +1,81 @@
+add_task(async function testRestoreDefaultsBtn() {
+ const before = SpecialPowers.Services.prefs.getStringPref("browser.newtabpage.activity-stream.feeds.section.topstories.options", "");
+
+ await SpecialPowers.pushPrefEnv({set: [
+ // Hide Pocket pref so we don't trigger network requests when we reset all preferences
+ ["browser.newtabpage.activity-stream.feeds.section.topstories.options", JSON.stringify(Object.assign({}, JSON.parse(before), {hidden: true}))],
+ // Set a user pref to false to force the Restore Defaults button to be visible
+ ["browser.newtabpage.activity-stream.feeds.topsites", false]
+ ]});
+
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:preferences#home", false);
+ let browser = tab.linkedBrowser;
+
+ await BrowserTestUtils.waitForCondition(() => ContentTask.spawn(browser, {},
+ () => content.document.getElementById("restoreDefaultHomePageBtn") !== null),
+ "Wait for the button to be added to the page");
+
+ await BrowserTestUtils.waitForCondition(() => ContentTask.spawn(browser, {},
+ () => content.document.querySelector("[data-subcategory='topsites'] checkbox") !== null),
+ "Wait for the preference checkbox to load");
+
+ await BrowserTestUtils.waitForCondition(() => ContentTask.spawn(browser, {},
+ () => content.document.getElementById("restoreDefaultHomePageBtn").hidden === false),
+ "Should show the Restore Defaults btn because pref is changed");
+
+ await ContentTask.spawn(browser, {}, () => content.document.getElementById("restoreDefaultHomePageBtn").click());
+
+ await BrowserTestUtils.waitForCondition(() => ContentTask.spawn(browser, {},
+ () => content.document.querySelector("[data-subcategory='topsites'] checkbox").checked),
+ "Should have checked preference");
+
+ await BrowserTestUtils.waitForCondition(() => ContentTask.spawn(browser, {},
+ () => content.document.getElementById("restoreDefaultHomePageBtn").style.visibility === "hidden"),
+ "Should not show the Restore Defaults btn if prefs were reset");
+
+ const topsitesPref = await SpecialPowers.Services.prefs.getBoolPref("browser.newtabpage.activity-stream.feeds.topsites");
+ Assert.ok(topsitesPref, "Topsites pref should have the default value");
+
+ await SpecialPowers.popPrefEnv();
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function testRestoreDefaultsBtn() {
+ const before = SpecialPowers.Services.prefs.getStringPref("browser.newtabpage.activity-stream.feeds.section.topstories.options", "");
+
+ await SpecialPowers.pushPrefEnv({set: [
+ // Hide Pocket pref so we don't trigger network requests when we reset all preferences
+ ["browser.newtabpage.activity-stream.feeds.section.topstories.options", JSON.stringify(Object.assign({}, JSON.parse(before), {hidden: true}))],
+ ]});
+
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:preferences#home", false);
+ let browser = tab.linkedBrowser;
+
+ await BrowserTestUtils.waitForCondition(() => ContentTask.spawn(browser, {},
+ () => content.document.querySelector("[data-subcategory='topsites'] checkbox") !== null),
+ "Wait for the preference checkbox to load");
+
+ const btnDefault = await ContentTask.spawn(browser, {}, () => content.document.getElementById("restoreDefaultHomePageBtn").style.visibility);
+ Assert.equal(btnDefault, "hidden", "When no prefs are changed button should not show up");
+
+ await BrowserTestUtils.waitForCondition(() => ContentTask.spawn(browser, {},
+ () => content.document.querySelector("[data-subcategory='topsites'] checkbox").checked),
+ "Should have checked preference");
+
+ // Uncheck a pref
+ await ContentTask.spawn(browser, {}, () => content.document.querySelector("[data-subcategory='topsites'] checkbox").click());
+
+ await BrowserTestUtils.waitForCondition(() => ContentTask.spawn(browser, {},
+ () => !content.document.querySelector("[data-subcategory='topsites'] checkbox").checked),
+ "Should have unchecked preference");
+
+ await BrowserTestUtils.waitForCondition(() => ContentTask.spawn(browser, {},
+ () => content.document.getElementById("restoreDefaultHomePageBtn").style.visibility === "visible"),
+ "Should show the Restore Defaults btn if prefs were changed");
+
+ // Reset the pref
+ await SpecialPowers.Services.prefs.clearUserPref("browser.newtabpage.activity-stream.feeds.topsites");
+
+ await SpecialPowers.popPrefEnv();
+ BrowserTestUtils.removeTab(tab);
+});
--- a/browser/extensions/activity-stream/lib/AboutPreferences.jsm
+++ b/browser/extensions/activity-stream/lib/AboutPreferences.jsm
@@ -119,17 +119,17 @@ this.AboutPreferences = class AboutPrefe
resolve(data);
}));
}
/**
* Render preferences to an about:preferences content window with the provided
* strings and preferences structure.
*/
- renderPreferences({document, Preferences}, strings, prefStructure) {
+ renderPreferences({document, Preferences, gHomePane}, strings, prefStructure) {
// Helper to create a new element and append it
const createAppend = (tag, parent) => parent.appendChild(
document.createElementNS(XUL_NS, tag));
// Helper to get strings and format with values if necessary
const formatString = id => {
if (typeof id !== "object") {
return strings[id] || id;
@@ -248,13 +248,16 @@ this.AboutPreferences = class AboutPrefe
// Add a checkbox pref for any nested preferences
nestedPrefs.forEach(nested => {
const subcheck = createAppend("checkbox", detailVbox);
subcheck.classList.add("indent");
subcheck.setAttribute("label", formatString(nested.titleString));
linkPref(subcheck, nested.name, "bool");
});
});
+
+ // Update the visibility of the Restore Defaults btn based on checked prefs
+ gHomePane.toggleRestoreDefaultsBtn();
}
};
this.PREFERENCES_LOADED_EVENT = PREFERENCES_LOADED_EVENT;
const EXPORTED_SYMBOLS = ["AboutPreferences", "PREFERENCES_LOADED_EVENT"];