Bug 1434751 - Add Restore Defaults button to Home draft
authorAndrei Oprea <andrei.br92@gmail.com>
Tue, 03 Jul 2018 20:02:26 +0200
changeset 814123 d5e1d0b4cbe110c3fc1f853cdeac888b50972c5e
parent 813360 7d20e7fae1039720f92db1a3a72bc2c7424b5f98
push id115110
push userbmo:andrei.br92@gmail.com
push dateWed, 04 Jul 2018 14:55:56 +0000
bugs1434751
milestone63.0a1
Bug 1434751 - Add Restore Defaults button to Home MozReview-Commit-ID: 5NRxEhPIImg
browser/components/preferences/in-content/home.js
browser/components/preferences/in-content/home.xul
browser/components/preferences/in-content/tests/browser.ini
browser/components/preferences/in-content/tests/browser_hometab_restore_defaults.js
browser/extensions/activity-stream/lib/AboutPreferences.jsm
--- 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"];