[tbb-commits] [tor-launcher/master] Bug 11773: setup wizard UI flow improvements

gk at torproject.org gk at torproject.org
Wed Jan 20 20:38:30 UTC 2016


commit e18194b1622b4d8ef1b7a9674b63d1213e678199
Author: Kathy Brade <brade at pearlcrescent.com>
Date:   Wed Jan 20 11:42:12 2016 -0500

    Bug 11773: setup wizard UI flow improvements
    
    Add a new "Reconfigure" prompt that is displayed after
      bootstrapping fails. This makes it so users experience the
      same configuration sequence each time rather than forcing
      them to move backwards through the wizard pages.
    Add a new "Remove Settings and Connect" prompt that is
      displayed if the user clicks "Connect" while some bridge or
      proxy settings are present. This avoids a problem where old
      settings may be used without users being aware of them.
    Improve some of the configuration prompts and status text based
      on early feedback from UC Berkeley usability studies.
---
 src/chrome/content/network-settings-wizard.xul |   48 ++++++-
 src/chrome/content/network-settings.js         |  165 +++++++++++++++++++-----
 src/chrome/content/network-settings.xul        |    2 +-
 src/chrome/content/progress.js                 |    2 +
 src/chrome/locale/en/network-settings.dtd      |   15 ++-
 src/chrome/locale/en/progress.dtd              |    2 +-
 src/chrome/skin/network-settings.css           |    3 +-
 7 files changed, 189 insertions(+), 48 deletions(-)

diff --git a/src/chrome/content/network-settings-wizard.xul b/src/chrome/content/network-settings-wizard.xul
index 00c1682..56217c5 100644
--- a/src/chrome/content/network-settings-wizard.xul
+++ b/src/chrome/content/network-settings-wizard.xul
@@ -19,7 +19,7 @@
         windowtype="TorLauncher:NetworkSettings"
         persist="screenX screenY"
         buttonlabelextra2="&torsettings.copyLog;"
-        onwizardfinish="return applySettings();"
+        onwizardfinish="return applySettings(false);"
         onwizardcancel="return onCancel();"
         onload="initDialog();"
         onunload="deinitDialog();">
@@ -46,7 +46,8 @@
       <separator/>
       <label>&torSettings.connectPrompt2;</label>
       <label>&torSettings.connectPrompt3;</label>
-      <button label="&torSettings.connect;" oncommand="useSettings();"/>
+      <button label="&torSettings.connect;"
+              oncommand="onWizardFirstPanelConnect();"/>
       <separator class="tall"/>
       <label>&torSettings.configurePrompt1;</label>
       <label>&torSettings.configurePrompt2;</label>
@@ -74,7 +75,9 @@
           <radio id="bridgesRadioYes" label="&torSettings.yes;" />
           <radio id="bridgesRadioNo" label="&torSettings.no;" selected="true" />
         </radiogroup>
-        <description class="questionHelp">&torSettings.bridgeHelp;
+        <description class="questionHelp">&torSettings.bridgeExplanation1;
+        </description>
+        <description class="questionHelp">&torSettings.bridgeExplanation2;
         </description>
       </vbox>
     </hbox>
@@ -94,7 +97,8 @@
     <separator />
     <vbox>
       <label id="bridgeSettingsPrompt"
-             class="question">&torSettings.bridgeSettingsPrompt;</label>
+             class="question">&torSettings.bridgeSettingsPrompt; 
+&torsettings.useBridges.note;</label>
       <groupbox id="bridgeSpecificSettings" />
     </vbox>
   </wizardpage>
@@ -120,7 +124,9 @@
           <radio id="proxyRadioYes" label="&torSettings.yes;" />
           <radio id="proxyRadioNo" label="&torSettings.no;" selected="true" />
         </radiogroup>
-        <description class="questionHelp">&torSettings.proxyHelp;
+        <description class="questionHelp">&torSettings.proxyExplanation1;
+        </description>
+        <description class="questionHelp">&torSettings.proxyExplanation2;
         </description>
       </vbox>
     </hbox>
@@ -168,8 +174,36 @@
     <separator/>
     <hbox>
       <spring flex="1" />
-      <button id="restartTorButton" label="&torsettings.restartTor;" hidden="true"
-              oncommand="onRestartTor()" />
+      <button id="restartTorButton" label="&torsettings.restartTor;"
+              hidden="true" oncommand="onRestartTor()" />
+      <button id="reconfigTorButton" label="&torsettings.reconfigTor;"
+              hidden="true" oncommand="onWizardReconfig()" />
+      <spring flex="1" />
+    </hbox>
+    <spring flex="1" />
+  </wizardpage>
+
+  <wizardpage pageid="discardSettings" next="notUsed"
+              onpageshow="showWizardNavButtons(false);"
+              onextra2="onCopyLog();">
+    <hbox class="tbb-header">
+      <vbox class="tbb-logo-box" align="start">
+        <image class="tbb-logo" />
+      </vbox>
+    </hbox>
+    <spring flex="1" />
+    <hbox>
+      <spring flex="1" />
+      <description flex="1">&torsettings.discardSettings.prompt;</description>
+      <spring flex="1" />
+    </hbox>
+    <separator/>
+    <hbox>
+      <spring flex="1" />
+      <button id="discardSettingsGoBack" oncommand="showPanel();"/>
+      <separator/>
+      <button label="&torsettings.discardSettings.proceed;"
+              oncommand="removeSettingsAndConnect()" />
       <spring flex="1" />
     </hbox>
     <spring flex="1" />
diff --git a/src/chrome/content/network-settings.js b/src/chrome/content/network-settings.js
index 9d3cb60..d145f77 100644
--- a/src/chrome/content/network-settings.js
+++ b/src/chrome/content/network-settings.js
@@ -35,6 +35,8 @@ const kTorLogHasWarnOrErrTopic = "TorLogHasWarnOrErr";
 const kWizardProxyRadioGroup = "proxyRadioGroup";
 const kWizardUseBridgesRadioGroup = "useBridgesRadioGroup";
 
+const kWizardFirstPageID = "first";
+
 const kLocaleList = "localeList";
 const kUseProxyCheckbox = "useProxy";
 const kProxyTypeMenulist = "proxyType";
@@ -200,6 +202,12 @@ function initDialog()
       if (accessKey)
         helpBtn.setAttribute("accesskey", accessKey);
     }
+
+    // Set Discard Settings back button label to match the wizard Back button.
+    let wizardBackBtn = document.documentElement.getButton("back");
+    let backBtn = document.getElementById("discardSettingsGoBack");
+    if (wizardBackBtn && backBtn)
+      backBtn.label = wizardBackBtn.label;
   }
 
   initDefaultBridgeTypeMenu();
@@ -214,7 +222,7 @@ function initDialog()
      (status != gTorProcessService.kStatusRunning))
   {
     if (status == gTorProcessService.kStatusExited)
-      showErrorMessage(true, null);
+      showErrorMessage(true, null, false);
     else
       showStartingTorPanel();
     addObserver(kTorProcessReadyTopic);
@@ -384,6 +392,25 @@ function getWizard()
 }
 
 
+function onWizardFirstPanelConnect()
+{
+  // If the user configured bridge or proxy settings, prompt before
+  // discarding their data.
+  if (isBridgeConfigured() || isProxyConfigured())
+    showPanel("discardSettings");
+  else
+    removeSettingsAndConnect()
+}
+
+
+function removeSettingsAndConnect()
+{
+  applySettings(true);  // Use default settings.
+  if (!gIsBootstrapComplete)
+    readTorSettings();  // Ensure UI matches the settings that were used.
+}
+
+
 function onWizardConfigure()
 {
   getWizard().advance("bridges");
@@ -497,12 +524,12 @@ var gObserver = {
     {
       removeObserver(kTorProcessReadyTopic);
       removeObserver(kTorProcessDidNotStartTopic);
-      showErrorMessage(false, aData);
+      showErrorMessage(false, aData, false);
     }
     else if (kTorProcessExitedTopic == aTopic)
     {
       removeObserver(kTorProcessExitedTopic);
-      showErrorMessage(true, null);
+      showErrorMessage(true, null, false);
     }
     else if (kTorOpenProgressTopic == aTopic)
     {
@@ -560,7 +587,7 @@ function readTorSettings()
   if (!didSucceed)
   {
     // Unable to communicate with tor.  Hide settings and display an error.
-    showErrorMessage(false, null);
+    showErrorMessage(false, null, false);
 
     setTimeout(function()
         {
@@ -581,7 +608,7 @@ function showPanel(aPanelID)
 {
   var wizard = getWizard();
   if (!aPanelID)
-    aPanelID = (wizard) ? "first" : "settings";
+    aPanelID = (wizard) ? kWizardFirstPageID : "settings";
 
   var deckElem = document.getElementById("deck");
   if (deckElem)
@@ -589,7 +616,7 @@ function showPanel(aPanelID)
   else if (wizard.currentPage.pageid != aPanelID)
     wizard.goTo(aPanelID);
 
-  if (wizard && (aPanelID == "first"))
+  if (wizard && (aPanelID == kWizardFirstPageID))
     setTimeout( function() { showWizardNavButtons(false); }, 0);
 
   showOrHideButton("accept", (aPanelID == "settings"), true);
@@ -627,7 +654,7 @@ function showStartingTorPanel()
 }
 
 
-function showErrorMessage(aTorExited, aErrorMsg)
+function showErrorMessage(aTorExited, aErrorMsg, aShowReconfigButton)
 {
   var elem = document.getElementById("errorPanelMessage");
   var btn = document.getElementById("restartTorButton");
@@ -653,6 +680,15 @@ function showErrorMessage(aTorExited, aErrorMsg)
   if (elem)
     elem.textContent = (aErrorMsg) ? aErrorMsg : "";
 
+  let reconfigBtn = document.getElementById("reconfigTorButton");
+  if (reconfigBtn)
+  {
+    if (aShowReconfigButton)
+      reconfigBtn.removeAttribute("hidden");
+    else
+      reconfigBtn.setAttribute("hidden", true);
+  }
+
   showPanel("errorPanel");
 
   var haveWizard = (getWizard() != null);
@@ -856,6 +892,17 @@ function onRestartTor()
 }
 
 
+function onWizardReconfig()
+{
+  showPanel(kWizardFirstPageID);
+  onWizardConfigure();
+  // Because a similar delayed call is used to hide the buttons when the
+  // first wizard page is displayed, we use setTimeout() here to ensure
+  // that the navigation buttons are visible.
+  window.setTimeout(function() { showWizardNavButtons(true); }, 0);
+}
+
+
 function onCancel()
 {
   if (gRestoreAfterHelpPanelID) // Is help open?
@@ -927,7 +974,9 @@ function onOpenHelp()
       forAssistance.setAttribute("hidden", true);
   }
   else
+  {
     overrideButtonLabel("cancel", "done");
+  }
 }
 
 
@@ -948,7 +997,9 @@ function closeHelp()
       forAssistance.removeAttribute("hidden");
   }
   else
+  {
     restoreButtonLabel("cancel");
+  }
 
   showPanel(gRestoreAfterHelpPanelID);
   gRestoreAfterHelpPanelID = null;
@@ -1130,15 +1181,16 @@ function initBridgeSettings()
 
 
 // Returns true if settings were successfully applied.
-function applySettings()
+function applySettings(aUseDefaults)
 {
   TorLauncherLogger.log(2, "applySettings ---------------------" +
                              "----------------------------------------------");
   var didSucceed = false;
   try
   {
-    didSucceed = applyBridgeSettings() &&
-                 applyProxySettings() && applyFirewallSettings();
+    didSucceed = applyBridgeSettings(aUseDefaults) &&
+                 applyProxySettings(aUseDefaults) &&
+                 applyFirewallSettings(aUseDefaults);
   }
   catch (e) { TorLauncherLogger.safelog(4, "Error in applySettings: ", e); }
 
@@ -1164,10 +1216,26 @@ function useSettings()
   if (!gIsBootstrapComplete)
     openProgressDialog();
 
+  let wizardElem = getWizard();
   if (gIsBootstrapComplete)
+  {
     close();
+  }
+  else if (wizardElem)
+  {
+    // If the user went down the "Configure" path and another error (e.g.,
+    // Tor Exited) has not already been shown, display a generic message
+    // with a "Reconfigure" button.
+    let pageid = wizardElem.currentPage.pageid;
+    if ((pageid != kWizardFirstPageID) && (pageid != "errorPanel"))
+    {
+      let msg = TorLauncherUtil.getLocalizedString("tor_bootstrap_failed");
+      showErrorMessage(false, msg, true);
+    }
+  }
 }
 
+
 function openProgressDialog()
 {
   var chromeURL = "chrome://torlauncher/content/progress.xul";
@@ -1184,9 +1252,10 @@ function onProgressDialogClose(aBootstrapCompleted)
 
 
 // Returns true if settings were successfully applied.
-function applyProxySettings()
+function applyProxySettings(aUseDefaults)
 {
-  var settings = getAndValidateProxySettings();
+  let settings = aUseDefaults ? getDefaultProxySettings()
+                              : getAndValidateProxySettings();
   if (!settings)
     return false;
 
@@ -1194,34 +1263,40 @@ function applyProxySettings()
 }
 
 
-// Return a settings object if successful and null if not.
-function getAndValidateProxySettings()
+function getDefaultProxySettings()
 {
-  // TODO: validate user-entered data.  See Vidalia's NetworkPage::save()
-
-  var settings = {};
+  let settings = {};
   settings[kTorConfKeySocks4Proxy] = null;
   settings[kTorConfKeySocks5Proxy] = null;
   settings[kTorConfKeySocks5ProxyUsername] = null;
   settings[kTorConfKeySocks5ProxyPassword] = null;
   settings[kTorConfKeyHTTPSProxy] = null;
   settings[kTorConfKeyHTTPSProxyAuthenticator] = null;
+  return settings;
+}
+
+
+// Return a settings object if successful and null if not.
+function getAndValidateProxySettings()
+{
+  var settings = getDefaultProxySettings();
 
+  // TODO: validate user-entered data.  See Vidalia's NetworkPage::save()
   var proxyType, proxyAddrPort, proxyUsername, proxyPassword;
   if (isProxyConfigured())
   {
-    proxyAddrPort = createColonStr(getElemValue(kProxyAddr, null),
-                                   getElemValue(kProxyPort, null));
-    if (!proxyAddrPort)
+    proxyType = getElemValue(kProxyTypeMenulist, null);
+    if (!proxyType)
     {
-      reportValidationError("error_proxy_addr_missing");
+      reportValidationError("error_proxy_type_missing");
       return null;
     }
 
-    proxyType = getElemValue(kProxyTypeMenulist, null);
-    if (!proxyType)
+    proxyAddrPort = createColonStr(getElemValue(kProxyAddr, null),
+                                   getElemValue(kProxyPort, null));
+    if (!proxyAddrPort)
     {
-      reportValidationError("error_proxy_type_missing");
+      reportValidationError("error_proxy_addr_missing");
       return null;
     }
 
@@ -1268,10 +1343,16 @@ function reportValidationError(aStrKey)
 
 
 // Returns true if settings were successfully applied.
-function applyFirewallSettings()
+function applyFirewallSettings(aUseDefaults)
 {
-  var settings = (getWizard()) ? getAutoFirewallSettings()
-                               : getAndValidateFirewallSettings();
+  let settings;
+  if (aUseDefaults)
+    settings = getDefaultFirewallSettings();
+  else if (getWizard())
+    settings = getAutoFirewallSettings();
+  else
+    settings = getAndValidateFirewallSettings();
+
   if (!settings)
     return false;
 
@@ -1296,6 +1377,12 @@ function getAndValidateFirewallSettings()
 }
 
 
+function getDefaultFirewallSettings()
+{
+  return constructFirewallSettings(undefined);
+}
+
+
 // Return a settings object if successful and null if not.
 // Only used for the wizard.
 function getAutoFirewallSettings()
@@ -1386,9 +1473,10 @@ function initDefaultBridgeTypeMenu()
 
 
 // Returns true if settings were successfully applied.
-function applyBridgeSettings()
+function applyBridgeSettings(aUseDefaults)
 {
-  var settings = getAndValidateBridgeSettings();
+  let settings = (aUseDefaults) ? getDefaultBridgeSettings()
+                                : getAndValidateBridgeSettings();
   if (!settings)
     return false;
 
@@ -1396,13 +1484,19 @@ function applyBridgeSettings()
 }
 
 
-// Return a settings object if successful and null if not.
-function getAndValidateBridgeSettings()
+function getDefaultBridgeSettings()
 {
-  var settings = {};
+  let settings = {};
   settings[kTorConfKeyUseBridges] = null;
   settings[kTorConfKeyBridgeList] = null;
+  return settings;
+}
 
+
+// Return a settings object if successful and null if not.
+function getAndValidateBridgeSettings()
+{
+  var settings = getDefaultBridgeSettings();
   var useBridges = isBridgeConfigured();
   var defaultBridgeType;
   var bridgeList;
@@ -1432,8 +1526,9 @@ function getAndValidateBridgeSettings()
     }
   }
 
-  // Since it returns a filterd list of bridges, TorLauncherUtil.defaultBridges
-  // must be called after setting the kPrefDefaultBridgeType pref.
+  // Since it returns a filtered list of bridges,
+  // TorLauncherUtil.defaultBridges must be called after setting the
+  // kPrefDefaultBridgeType pref.
   TorLauncherUtil.setCharPref(kPrefDefaultBridgeType, defaultBridgeType);
   if (defaultBridgeType)
     bridgeList = TorLauncherUtil.defaultBridges;
@@ -1651,7 +1746,9 @@ function parseColonStr(aStr)
     rv[1] = aStr.substring(idx + 1);
   }
   else
+  {
     rv[0] = aStr;
+  }
 
   return rv;
 }
diff --git a/src/chrome/content/network-settings.xul b/src/chrome/content/network-settings.xul
index 9fffbec..727e7f6 100644
--- a/src/chrome/content/network-settings.xul
+++ b/src/chrome/content/network-settings.xul
@@ -20,7 +20,7 @@
         persist="screenX screenY"
         buttons="accept,cancel,extra2,help"
         buttonlabelextra2="&torsettings.copyLog;"
-        ondialogaccept="return applySettings();"
+        ondialogaccept="return applySettings(false);"
         ondialogcancel="return onCancel();"
         ondialogextra2="onCopyLog();"
         ondialoghelp="onOpenHelp();"
diff --git a/src/chrome/content/progress.js b/src/chrome/content/progress.js
index b44dca5..48362e7 100644
--- a/src/chrome/content/progress.js
+++ b/src/chrome/content/progress.js
@@ -170,6 +170,8 @@ var gObserver = {
       // TODO: provide a way to access tor log e.g., leave this dialog open
       //       and display the open settings button or provide a way to do
       //       that from our error alerts.
+      if (kTorBootstrapErrorTopic == aTopic)
+        stopTorBootstrap();
       cleanup();
       window.close();
     }
diff --git a/src/chrome/locale/en/network-settings.dtd b/src/chrome/locale/en/network-settings.dtd
index b193750..75ece3b 100644
--- a/src/chrome/locale/en/network-settings.dtd
+++ b/src/chrome/locale/en/network-settings.dtd
@@ -13,26 +13,32 @@
 
 <!ENTITY torSettings.firstQuestion "Which of the following best describes your situation?">
 <!ENTITY torSettings.configurePrompt1 "This computer's Internet connection is censored or proxied.">
-<!ENTITY torSettings.configurePrompt2 "I need to configure bridge or local proxy settings.">
+<!ENTITY torSettings.configurePrompt2 "I need to configure bridge or local proxy settings before I connect to the Tor network.">
 <!ENTITY torSettings.configure "Configure">
-<!ENTITY torSettings.connectPrompt2 "I would like to connect directly to the Tor network.">
+<!ENTITY torSettings.connectPrompt2 "I would like to make a direct connection to the Tor network.">
 <!ENTITY torSettings.connectPrompt3 "This will work in most situations.">
 <!ENTITY torSettings.connect "Connect">
 
 <!ENTITY torSettings.proxyPageTitle "Local Proxy Configuration">
 <!ENTITY torSettings.proxyQuestion "Does this computer need to use a local proxy to access the Internet?">
 <!-- see https://www.torproject.org/docs/proxychain.html.en -->
-<!ENTITY torSettings.proxyHelp "If you are not sure how to answer this question, look at the Internet settings in another browser to see whether it is configured to use a local proxy.">
+<!ENTITY torSettings.proxyExplanation1 "In most cases a local proxy is not needed, but it may be required when connecting through a company, school, or university network.">
+<!ENTITY torSettings.proxyExplanation2 "If you are not sure how to answer this question, look at the Internet settings in another browser or check your system's network settings to see whether a local proxy is needed.">
 <!ENTITY torSettings.enterProxy "Enter the proxy settings.">
 <!ENTITY torSettings.bridgePageTitle "Tor Bridges Configuration">
 <!ENTITY torSettings.bridgeQuestion "Does your Internet Service Provider (ISP) block or otherwise censor connections to the Tor Network?">
-<!ENTITY torSettings.bridgeHelp "If you are not sure how to answer this question, choose No.  If you choose Yes, you will be asked to configure Tor Bridges, which are unlisted relays that make it more difficult to block connections to the Tor Network.">
+<!ENTITY torSettings.bridgeExplanation1 "If you are not sure how to answer this question, choose No (if you are unable to connect to the Tor network without a bridge, you can add one later).">
+<!ENTITY torSettings.bridgeExplanation2 "If you choose Yes, you will be asked to configure Tor Bridges, which are unlisted relays that make it more difficult to block connections to the Tor Network.">
 <!ENTITY torSettings.bridgeSettingsPrompt "You may use the provided set of bridges or you may obtain and enter a custom set of bridges.">
 
 <!-- Other: -->
 
 <!ENTITY torsettings.startingTor "Waiting for Tor to start…">
 <!ENTITY torsettings.restartTor "Restart Tor">
+<!ENTITY torsettings.reconfigTor "Reconfigure">
+
+<!ENTITY torsettings.discardSettings.prompt "You have configured Tor bridges or you have entered local proxy settings.  To make a direct connection to the Tor network, these settings must be removed.">
+<!ENTITY torsettings.discardSettings.proceed "Remove Settings and Connect">
 
 <!ENTITY torsettings.optional "Optional">
 
@@ -50,6 +56,7 @@
 <!ENTITY torsettings.firewall.allowedPorts "Allowed Ports:">
 <!ENTITY torsettings.useBridges.checkbox "My Internet Service Provider (ISP) blocks connections to the Tor network">
 <!ENTITY torsettings.useBridges.default "Connect with provided bridges">
+<!ENTITY torsettings.useBridges.note "Each type of bridge uses a different method to avoid censorship.  If one bridge does not work, try again using a different one.">
 <!ENTITY torsettings.useBridges.type "Transport type:">
 <!ENTITY torsettings.useBridges.custom "Enter custom bridges">
 <!ENTITY torsettings.useBridges.label "Enter one or more bridge relays (one per line).">
diff --git a/src/chrome/locale/en/progress.dtd b/src/chrome/locale/en/progress.dtd
index ebd9cef..9ac9ad7 100644
--- a/src/chrome/locale/en/progress.dtd
+++ b/src/chrome/locale/en/progress.dtd
@@ -1,4 +1,4 @@
 <!ENTITY torprogress.dialog.title "Tor Status">
 <!ENTITY torprogress.openSettings "Open Settings">
 <!ENTITY torprogress.heading "Connecting to the Tor network">
-<!ENTITY torprogress.pleaseWait "Please wait while we establish a connection to the Tor network.">
+<!ENTITY torprogress.pleaseWait "Please wait while we establish a connection to the Tor network.  This may take several minutes.">
diff --git a/src/chrome/skin/network-settings.css b/src/chrome/skin/network-settings.css
index 610ab26..20d3528 100644
--- a/src/chrome/skin/network-settings.css
+++ b/src/chrome/skin/network-settings.css
@@ -72,7 +72,7 @@ separator.tall {
 }
 
 .questionHelp {
-  margin-right: 20px;
+  margin: 0px 0px 12px 20px;
 }
 
 .instructions {
@@ -109,6 +109,7 @@ wizard#TorLauncherLocalePicker button[dlgtype="next"] {
   font-weight: bold;
 }
 
+#bridgeNote,
 #bridgeDefaultEntry,
 #bridgeCustomEntry {
   margin-left: 1.8em;



More information about the tbb-commits mailing list