Bug 1448971 - Replace "when Firefox starts" section in about:preferences#general with checkbox draft
authork88hudson <k88hudson@gmail.com>
Wed, 04 Apr 2018 12:28:22 -0400
changeset 786362 4f1c6daf4ec855544d83826a7fa906de6aaff132
parent 786291 8d4cf28964f6956cd22d8710b316456e2c7c848d
push id107439
push userbmo:khudson@mozilla.com
push dateMon, 23 Apr 2018 00:32:34 +0000
bugs1448971
milestone61.0a1
Bug 1448971 - Replace "when Firefox starts" section in about:preferences#general with checkbox MozReview-Commit-ID: JHL20S5gZq2
browser/components/enterprisepolicies/tests/browser/browser_policy_set_homepage.js
browser/components/preferences/in-content/home.js
browser/components/preferences/in-content/main.js
browser/components/preferences/in-content/main.xul
browser/components/preferences/in-content/tests/browser_search_subdialogs_within_preferences_1.js
browser/locales/en-US/browser/preferences/preferences.ftl
browser/themes/shared/incontentprefs/preferences.inc.css
--- a/browser/components/enterprisepolicies/tests/browser/browser_policy_set_homepage.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_set_homepage.js
@@ -20,30 +20,34 @@ async function check_homepage({expectedU
   is(Services.prefs.prefIsLocked("browser.startup.page"), locked,
      "Lock status of browser.startup.page should match expected");
 
   // Test that UI is disabled when the Locked property is enabled
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:preferences");
   await ContentTask.spawn(tab.linkedBrowser, {expectedURL, expectedPageVal, locked},
                           // eslint-disable-next-line no-shadow
                           async function({expectedURL, expectedPageVal, locked}) {
-    let startupPageRadioGroup = content.document.getElementById("browserStartupPage");
-    is(startupPageRadioGroup.disabled, locked,
-       "Disabled status of start page radio group should match expected");
-    is(startupPageRadioGroup.value, expectedPageVal,
-       "Value of start page radio group should match expected");
+    let browserRestoreSessionCheckbox = content.document.getElementById("browserRestoreSession");
+    is(browserRestoreSessionCheckbox.disabled, locked,
+       "Disabled status of session restore status should match expected");
+    let shouldBeChecked = expectedPageVal === 3;
+    is(browserRestoreSessionCheckbox.checked, shouldBeChecked,
+       "Session restore status checkbox should be: " + (shouldBeChecked ? "checked" : "unchecked"));
 
     content.document.getElementById("category-home").click();
 
     let homepageTextbox = content.document.getElementById("homePageUrl");
     // Unfortunately this test does not work because the new UI does not fill
     // default values into the URL box at the moment.
     // is(homepageTextbox.value, expectedURL,
     //    "Homepage URL should match expected");
 
+    // Wait for rendering to be finished
+    await ContentTaskUtils.waitForCondition(() => content.document.getElementById("useCurrentBtn").disabled === locked);
+
     is(homepageTextbox.disabled, locked,
        "Homepage URL text box disabled status should match expected");
     is(content.document.getElementById("homeMode").disabled, locked,
        "Home mode drop down disabled status should match expected");
     is(content.document.getElementById("useCurrentBtn").disabled, locked,
        "\"Use current page\" button disabled status should match expected");
     is(content.document.getElementById("useBookmarkBtn").disabled, locked,
       "\"Use bookmark\" button disabled status should match expected");
--- a/browser/components/preferences/in-content/home.js
+++ b/browser/components/preferences/in-content/home.js
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
  /* import-globals-from extensionControlled.js */
  /* import-globals-from preferences.js */
+ /* import-globals-from main.js */
 
  // HOME PAGE
 
  /*
    * Preferences:
    *
    * browser.startup.homepage
    * - the user's home page, as a string; if the home page is a set of tabs,
@@ -62,48 +63,77 @@ let gHomePane = {
     window.addEventListener("unload", () => {
       Services.obs.removeObserver(newTabObserver, "newtab-url-changed");
     });
   },
 
   /**
    * _renderCustomSettings: Hides or shows the UI for setting a custom
    * homepage URL
-   * @param {bool} shouldShow Should the custom UI be shown?
+   * @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(shouldShow) {
+  _renderCustomSettings(options = {}) {
+    let {shouldShow, isControlled} = options;
     const customSettingsContainerEl = document.getElementById("customSettings");
     const customUrlEl = document.getElementById("homePageUrl");
-    const isHomepageCustom = !this._isHomePageDefaultValue() && !this._isHomePageBlank();
-    if (typeof shouldShow === "undefined") shouldShow = isHomepageCustom;
+    const homePref = Preferences.get("browser.startup.homepage");
 
+    const isHomePageCustom = isControlled || (!this._isHomePageDefaultValue() && !this.isHomePageBlank());
+    if (typeof shouldShow === "undefined") {
+      shouldShow = isHomePageCustom;
+    }
     customSettingsContainerEl.hidden = !shouldShow;
-    if (isHomepageCustom) {
-      customUrlEl.value = Preferences.get("browser.startup.homepage").value;
+
+    // We can't use isHomePageDefaultValue and isHomePageBlank here because we want to disregard the blank
+    // possibility triggered by the browser.startup.page being 0.
+    let newValue;
+    if (homePref.value !== homePref.defaultValue && homePref.value !== "about:blank") {
+      newValue = homePref.value;
     } else {
-      customUrlEl.value = "";
+      newValue = "";
+    }
+    if (customUrlEl.value !== newValue) {
+      customUrlEl.value = newValue;
     }
   },
 
   /**
    * _isHomePageDefaultValue
+   * @param {bool} isControlled Is an extension controlling the home page?
    * @returns {bool} Is the homepage set to the default pref value?
    */
   _isHomePageDefaultValue() {
+    const startupPref = Preferences.get("browser.startup.page");
     const homePref = Preferences.get("browser.startup.homepage");
-    return homePref.value === homePref.defaultValue;
+    return startupPref.value !== gMainPane.STARTUP_PREF_BLANK && homePref.value === homePref.defaultValue;
   },
 
   /**
-   * _isHomePageBlank
+   * isHomePageBlank
    * @returns {bool} Is the homepage set to about:blank?
    */
-  _isHomePageBlank() {
+  isHomePageBlank() {
+    const startupPref = Preferences.get("browser.startup.page");
     const homePref = Preferences.get("browser.startup.homepage");
-    return homePref.value === "about:blank" || homePref.value === "";
+    return homePref.value === "about:blank" || homePref.value === "" || startupPref.value === gMainPane.STARTUP_PREF_BLANK;
+  },
+  /**
+   * isHomePageControlled
+   * @resolves {bool} Is the homepage being controlled by an extension?
+   * @returns {Promise}
+   */
+  isHomePageControlled() {
+    const homePref = Preferences.get("browser.startup.homepage");
+    if (homePref.locked) {
+      return Promise.resolve(false);
+    }
+    return handleControllingExtension(
+      PREF_SETTING_TYPE, HOMEPAGE_OVERRIDE_KEY, "extensionControlled.homepage_override2");
   },
 
   /**
    * _isTabAboutPreferences: Is a given tab set to about:preferences?
    * @param {Element} aTab A tab element
    * @returns {bool} Is the linkedBrowser of aElement set to about:preferences?
    */
   _isTabAboutPreferences(aTab) {
@@ -124,27 +154,33 @@ let gHomePane = {
       tabs = tabs.filter(tab => !this._isTabAboutPreferences(tab));
       // XXX: Bug 1441637 - Fix tabbrowser to report tab.closing before it blurs it
       tabs = tabs.filter(tab => !tab.closing);
     }
 
     return tabs;
   },
 
-  _renderHomepageMode() {
+  _renderHomepageMode(isControlled) {
     const isDefault = this._isHomePageDefaultValue();
-    const isBlank = this._isHomePageBlank();
+    const isBlank = this.isHomePageBlank();
     const el = document.getElementById("homeMode");
+    let newValue;
 
-    if (isDefault) {
-      el.value = this.HOME_MODE_FIREFOX_HOME;
+    if (isControlled) {
+      newValue = this.HOME_MODE_CUSTOM;
+    } else if (isDefault) {
+      newValue = this.HOME_MODE_FIREFOX_HOME;
     } else if (isBlank) {
-      el.value = this.HOME_MODE_BLANK;
+      newValue = this.HOME_MODE_BLANK;
     } else {
-      el.value = this.HOME_MODE_CUSTOM;
+      newValue = this.HOME_MODE_CUSTOM;
+    }
+    if (el.value !== newValue) {
+      el.value = newValue;
     }
   },
 
   _setInputDisabledStates(isControlled) {
     let tabCount = this._getTabsForHomePage().length;
 
     // Disable or enable the inputs based on if this is controlled by an extension.
     document.querySelectorAll(".check-home-page-controlled")
@@ -167,25 +203,24 @@ let gHomePane = {
 
   async _handleHomePageOverrides() {
     const homePref = Preferences.get("browser.startup.homepage");
     if (homePref.locked) {
       // An extension can't control these settings if they're locked.
       hideControllingExtension(HOMEPAGE_OVERRIDE_KEY);
       this._setInputDisabledStates(false);
     } else {
-      // Asynchronously update the extension controlled UI.
-      const isHomePageControlled = await handleControllingExtension(
-        PREF_SETTING_TYPE, HOMEPAGE_OVERRIDE_KEY, "extensionControlled.homepage_override2");
-      this._setInputDisabledStates(isHomePageControlled);
+      const isControlled = await this.isHomePageControlled();
+      this._setInputDisabledStates(isControlled);
+      this._renderCustomSettings({isControlled});
+      this._renderHomepageMode(isControlled);
     }
   },
 
   syncFromHomePref() {
-    // Set the "Use Current Page(s)" button's text and enabled state.
     this._updateUseCurrentButton();
     this._renderCustomSettings();
     this._renderHomepageMode();
     this._handleHomePageOverrides();
   },
 
   syncFromNewTabPref() {
     const newtabPref = Preferences.get(this.NEWTAB_ENABLED_PREF);
@@ -193,34 +228,39 @@ let gHomePane = {
   },
 
   syncToNewTabPref(value) {
     return value !== this.HOME_MODE_BLANK;
   },
 
   onMenuChange(event) {
     const {value} = event.target;
+    const startupPref = Preferences.get("browser.startup.page");
     const homePref = Preferences.get("browser.startup.homepage");
+
     switch (value) {
       case this.HOME_MODE_FIREFOX_HOME:
+        if (startupPref.value === gMainPane.STARTUP_PREF_BLANK) {
+          startupPref.value = gMainPane.STARTUP_PREF_HOMEPAGE;
+        }
         if (homePref.value !== homePref.defaultValue) {
           homePref.value = homePref.defaultValue;
         } else {
-          this._renderCustomSettings(false);
+          this._renderCustomSettings({shouldShow: false});
         }
         break;
       case this.HOME_MODE_BLANK:
         if (homePref.value !== "about:blank") {
           homePref.value = "about:blank";
         } else {
-          this._renderCustomSettings(false);
+          this._renderCustomSettings({shouldShow: false});
         }
         break;
       case this.HOME_MODE_CUSTOM:
-        this._renderCustomSettings(true);
+        this._renderCustomSettings({shouldShow: true});
         break;
     }
   },
 
   /**
    * Switches the "Use Current Page" button between its singular and plural
    * forms.
    */
@@ -232,18 +272,19 @@ let gHomePane = {
 
     // If the homepage is controlled by an extension then you can't use this.
     if (await getControllingExtensionInfo(PREF_SETTING_TYPE, HOMEPAGE_OVERRIDE_KEY)) {
       return;
     }
 
     // In this case, the button's disabled state is set by preferences.xml.
     let prefName = "pref.browser.homepage.disable_button.current_page";
-    if (Preferences.get(prefName).locked)
+    if (Preferences.get(prefName).locked) {
       return;
+    }
 
     useCurrent.disabled = tabCount < 1;
   },
 
   /**
    * Sets the home page to the URL(s) of any currently opened tab(s),
    * updating about:preferences#home UI to reflect this.
    */
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -252,16 +252,20 @@ var gMainPane = {
   _visibleTypes: [],
 
   // A count of the number of times each visible type description appears.
   // We use these counts to determine whether or not to annotate descriptions
   // with their types to distinguish duplicate descriptions from each other.
   // A hash of integer counts, indexed by string description.
   _visibleTypeDescriptionCount: {},
 
+  // browser.startup.page values
+  STARTUP_PREF_BLANK: 0,
+  STARTUP_PREF_HOMEPAGE: 1,
+  STARTUP_PREF_RESTORE_SESSION: 3,
 
   // Convenience & Performance Shortcuts
 
   get _brandShortName() {
     delete this._brandShortName;
     return this._brandShortName = document.getElementById("bundleBrand").getString("brandShortName");
   },
 
@@ -339,18 +343,16 @@ var gMainPane = {
 
     let defaultPerformancePref =
       Preferences.get("browser.preferences.defaultPerformanceSettings.enabled");
     defaultPerformancePref.on("change", () => {
       this.updatePerformanceSettingsBox({ duringChangeEvent: true });
     });
     this.updatePerformanceSettingsBox({ duringChangeEvent: false });
 
-    this.updateBrowserStartupLastSession();
-
     let connectionSettingsLink = document.getElementById("connectionSettingsLearnMore");
     let connectionSettingsUrl = Services.urlFormatter.formatURLPref("app.support.baseURL") +
                                 "prefs-connection-settings";
     connectionSettingsLink.setAttribute("href", connectionSettingsUrl);
     this.updateProxySettingsUI();
     initializeProxyUI(gMainPane);
 
     if (AppConstants.platform == "win") {
@@ -366,18 +368,28 @@ var gMainPane = {
     // &brandShortName;" warnings provide options for not showing these
     // warnings again. When the user disabled them, we provide checkboxes to
     // re-enable the warnings.
     if (!TransientPrefs.prefShouldBeVisible("browser.tabs.warnOnClose"))
       document.getElementById("warnCloseMultiple").hidden = true;
     if (!TransientPrefs.prefShouldBeVisible("browser.tabs.warnOnOpen"))
       document.getElementById("warnOpenMany").hidden = true;
 
+    // Startup pref
+    setEventListener("browserRestoreSession", "command",
+      gMainPane.onBrowserRestoreSessionChange);
+    gMainPane.updateBrowserStartupUI = gMainPane.updateBrowserStartupUI.bind(gMainPane);
     Preferences.get("browser.privatebrowsing.autostart").on("change",
-      gMainPane.updateBrowserStartupLastSession.bind(gMainPane));
+      gMainPane.updateBrowserStartupUI);
+    Preferences.get("browser.startup.page").on("change",
+      gMainPane.updateBrowserStartupUI);
+    Preferences.get("browser.startup.homepage").on("change",
+      gMainPane.updateBrowserStartupUI);
+    gMainPane.updateBrowserStartupUI();
+
     if (AppConstants.HAVE_SHELL_SERVICE) {
       setEventListener("setDefaultButton", "command",
         gMainPane.setDefaultBrowser);
     }
     setEventListener("disableContainersExtension", "command",
                      makeDisableControllingExtension(PREF_SETTING_TYPE, CONTAINERS_KEY));
     setEventListener("chooseLanguage", "command",
       gMainPane.showLanguages);
@@ -703,17 +715,17 @@ var gMainPane = {
 
   // HOME PAGE
   /*
    * Preferences:
    *
    * browser.startup.page
    * - what page(s) to show when the user starts the application, as an integer:
    *
-   *     0: a blank page
+   *     0: a blank page (DEPRECATED - this can be set via browser.startup.homepage)
    *     1: the home page (as set by the browser.startup.homepage pref)
    *     2: the last page the user visited (DEPRECATED)
    *     3: windows and tabs from the last session (a.k.a. session restore)
    *
    *   The deprecated option is not exposed in UI; however, if the user has it
    *   selected and doesn't change the UI for this preference, the deprecated
    *   option is preserved.
    */
@@ -728,30 +740,49 @@ var gMainPane = {
     button.disabled = !preference.value;
     return undefined;
   },
 
   /**
    * Hide/show the "Show my windows and tabs from last time" option based
    * on the value of the browser.privatebrowsing.autostart pref.
    */
-  updateBrowserStartupLastSession() {
-    let pbAutoStartPref = Preferences.get("browser.privatebrowsing.autostart");
-    let startupPref = Preferences.get("browser.startup.page");
-    let group = document.getElementById("browserStartupPage");
-    let option = document.getElementById("browserStartupLastSession");
-    if (pbAutoStartPref.value) {
-      option.setAttribute("disabled", "true");
-      if (option.selected) {
-        group.selectedItem = document.getElementById("browserStartupHomePage");
+  updateBrowserStartupUI() {
+    const pbAutoStartPref = Preferences.get("browser.privatebrowsing.autostart");
+    const startupPref = Preferences.get("browser.startup.page");
+
+    let newValue;
+    let checkbox = document.getElementById("browserRestoreSession");
+    if (pbAutoStartPref.value || startupPref.locked) {
+      checkbox.setAttribute("disabled", "true");
+      newValue = false;
+    } else {
+      checkbox.removeAttribute("disabled");
+      newValue = startupPref.value === this.STARTUP_PREF_RESTORE_SESSION;
+    }
+    if (checkbox.checked !== newValue) {
+      checkbox.checked = newValue;
+    }
+  },
+
+  onBrowserRestoreSessionChange(event) {
+    const value = event.target.checked;
+    const startupPref = Preferences.get("browser.startup.page");
+    let newValue;
+
+    if (value) {
+      // We need to restore the blank homepage setting in our other pref
+      if (startupPref.value === this.STARTUP_PREF_BLANK) {
+        Preferences.get("browser.startup.homepage").value = "about:blank";
       }
+      newValue = this.STARTUP_PREF_RESTORE_SESSION;
     } else {
-      option.removeAttribute("disabled");
-      startupPref.updateElements(); // select the correct radio in the startup group
+      newValue = this.STARTUP_PREF_HOMEPAGE;
     }
+    startupPref.value = newValue;
   },
 
   // TABS
 
   /*
    * Preferences:
    *
    * browser.link.open_newwindow - int
--- a/browser/components/preferences/in-content/main.xul
+++ b/browser/components/preferences/in-content/main.xul
@@ -38,16 +38,21 @@
       <deck id="getStarted">
         <label class="text-link" data-l10n-id="get-started-not-logged-in"/>
         <label class="text-link" data-l10n-id="get-started-configured"/>
       </deck>
     </hbox>
   </vbox>
 #endif
 
+  <vbox id="startupPageBox">
+    <checkbox id="browserRestoreSession"
+              data-l10n-id="startup-restore-previous-session"/>
+  </vbox>
+
 #ifdef HAVE_SHELL_SERVICE
   <vbox id="defaultBrowserBox">
     <checkbox id="alwaysCheckDefault" preference="browser.shell.checkDefaultBrowser"
               data-l10n-id="always-check-default"/>
     <deck id="setDefaultPane">
       <hbox align="center" class="indent">
         <image class="face-sad"/>
         <label id="isNotDefaultLabel" flex="1" data-l10n-id="is-not-default"/>
@@ -59,33 +64,16 @@
       <hbox align="center" class="indent">
         <image class="face-smile"/>
         <label id="isDefaultLabel" flex="1" data-l10n-id="is-default"/>
       </hbox>
     </deck>
   </vbox>
 #endif
 
-  <vbox id="startupPageBox">
-    <label data-l10n-id="startup-page"
-           control="browserStartupPage"/>
-    <radiogroup id="browserStartupPage"
-                preference="browser.startup.page">
-      <radio data-l10n-id="startup-user-homepage"
-             value="1"
-             id="browserStartupHomePage"/>
-      <radio data-l10n-id="startup-blank-page"
-             value="0"
-             id="browserStartupBlank"/>
-      <radio data-l10n-id="startup-prev-session"
-             value="3"
-             id="browserStartupLastSession"/>
-    </radiogroup>
-
-  </vbox>
 </groupbox>
 
 <!-- Tab preferences -->
 <groupbox data-category="paneGeneral"
           hidden="true">
     <caption><label data-l10n-id="tabs-group-header"/></caption>
 
     <checkbox id="ctrlTabRecentlyUsedOrder" data-l10n-id="ctrl-tab-recently-used-order"
--- a/browser/components/preferences/in-content/tests/browser_search_subdialogs_within_preferences_1.js
+++ b/browser/components/preferences/in-content/tests/browser_search_subdialogs_within_preferences_1.js
@@ -9,17 +9,24 @@ add_task(async function() {
 
 /**
  * Test for searching for the "Set Home Page" subdialog.
  */
 add_task(async function() {
   await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
 
   // Set custom URL so bookmark button will be shown on the page (otherwise it is hidden)
-  await SpecialPowers.pushPrefEnv({"set": [["browser.startup.homepage", "about:robots"]]});
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["browser.startup.homepage", "about:robots"],
+    ["browser.startup.page", 1]
+  ]});
+
+  // Wait for Activity Stream to add its panels
+  await BrowserTestUtils.waitForCondition(() => ContentTask.spawn(gBrowser.selectedTab.linkedBrowser, {},
+    async () => content.document.getElementById("homeContentsGroup")));
 
   await evaluateSearchResults("Set Home Page", "homepageGroup");
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 /**
  * Test for searching for the "Languages" subdialog.
  */
--- a/browser/locales/en-US/browser/preferences/preferences.ftl
+++ b/browser/locales/en-US/browser/preferences/preferences.ftl
@@ -107,26 +107,20 @@ always-check-default =
 
 is-default = { -brand-short-name } is currently your default browser
 is-not-default = { -brand-short-name } is not your default browser
 
 set-as-my-default-browser =
     .label = Make Default…
     .accesskey = D
 
-startup-page = When { -brand-short-name } starts
+startup-restore-previous-session =
+    .label = Restore previous session
     .accesskey = s
 
-startup-user-homepage =
-    .label = Show your home page
-startup-blank-page =
-    .label = Show a blank page
-startup-prev-session =
-    .label = Show your windows and tabs from last time
-
 disable-extension =
     .label = Disable Extension
 
 tabs-group-header = Tabs
 
 ctrl-tab-recently-used-order =
     .label = Ctrl+Tab cycles through tabs in recently used order
     .accesskey = T
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -175,20 +175,16 @@ button > hbox > label {
 }
 
 /* General Pane */
 
 #isDefaultLabel {
   font-weight: 600;
 }
 
-#startupPageBox {
-  padding-top: 32px;
-}
-
 .extension-controlled-icon {
   height: 20px;
   margin: 2px 0 6px;
   vertical-align: middle;
   width: 20px;
 }
 
 .extension-controlled-disabled {
@@ -239,18 +235,17 @@ button > hbox > label {
 #updateDeck > hbox > label {
   -moz-box-flex: 1;
 }
 
 #manualLink {
   margin-inline-start: 6px !important;
 }
 
-#updateRadioGroup > radio,
-#browserStartupPage > radio {
+#updateRadioGroup > radio {
   height: 30px;
   margin: 2px 0;
 }
 
 #filter {
   margin: 4px 0 8px;
 }