commit 803bf1178bc8c66a7166309abd680eef4af7a548
Author: Kathy Brade <brade(a)pearlcrescent.com>
Date: Tue Oct 31 10:06:32 2017 -0400
Bug 23262: implement integrated progress bar (Part 2)
Improve UX by greatly reducing the use of modal alert dialogs. In most
cases errors are now displayed using one of three techniques:
1. Via an overlaid error panel.
2. As a message on the progress panel (with a Reconfigure button).
3. On a standalone error page within the setup wizard.
Move "Restart Tor" to a separate panel.
Fix a problem where showAlert() would fail to display an alert: do not
try to use a hidden window as the parent for the alert.
Add a showOrHideElemById() utility function and use it.
---
src/chrome/content/localePicker.xul | 4 +-
src/chrome/content/network-settings-overlay.xul | 30 ++-
src/chrome/content/network-settings-wizard.xul | 35 +--
src/chrome/content/network-settings.js | 328 +++++++++++++++++-------
src/chrome/content/network-settings.xul | 94 +++----
src/chrome/skin/network-settings.css | 23 +-
src/components/tl-process.js | 61 +++--
src/components/tl-protocol.js | 11 +-
src/modules/tl-util.jsm | 34 ++-
9 files changed, 434 insertions(+), 186 deletions(-)
diff --git a/src/chrome/content/localePicker.xul b/src/chrome/content/localePicker.xul
index 2017baa..6030468 100644
--- a/src/chrome/content/localePicker.xul
+++ b/src/chrome/content/localePicker.xul
@@ -29,7 +29,7 @@
<hbox class="tbb-header" pack="center">
<image class="tbb-logo"/>
</hbox>
- <separator />
+ <separator/>
<vbox>
<label class="question">&torlauncher.localePicker.prompt;</label>
<separator/>
@@ -38,6 +38,6 @@
</wizardpage>
<hbox pack="start">
- <label id="forAssistance" />
+ <label id="forAssistance"/>
</hbox>
</wizard>
diff --git a/src/chrome/content/network-settings-overlay.xul b/src/chrome/content/network-settings-overlay.xul
index a709f0e..b49dbab 100644
--- a/src/chrome/content/network-settings-overlay.xul
+++ b/src/chrome/content/network-settings-overlay.xul
@@ -83,7 +83,7 @@
<hbox align="center">
<label value="&torsettings.firewall.allowedPorts;"
control="firewallAllowedPorts"/>
- <textbox id="firewallAllowedPorts" value="80,443" />
+ <textbox id="firewallAllowedPorts" value="80,443"/>
</hbox>
</groupbox>
@@ -136,13 +136,37 @@
<description id="progressPleaseWait"
hidden="true">&torprogress.pleaseWait;</description>
<progressmeter id="progressMeter" mode="determined" value="0"/>
- <description id="progressDesc"/>
+ <description id="progressDesc" errorElemId="message"/>
+ <label id="progressReconfigureLabel" hidden="true"
+ value="&torsettings.reconfigTor;"/>
</vbox>
</vbox>
+ <vbox id="restartContent">
+ <hbox pack="center">
+ <description id="restartPanelMessage" flex="1"/>
+ </hbox>
+ <separator/>
+ <hbox pack="center">
+ <button id="restartTorButton" label="&torsettings.restartTor;"
+ oncommand="onRestartTor()"/>
+ </hbox>
+ </vbox>
+
+ <vbox id="errorOverlayContent">
+ <hbox pack="center">
+ <description errorElemId="message" flex="1"/>
+ </hbox>
+ <separator/>
+ <hbox pack="center">
+ <button errorElemId="dismissButton" default="true"
+ oncommand="onDismissErrorOverlay()"/>
+ </hbox>
+ </vbox>
+
<panel id="copyLogFeedbackPanel" type="arrow" fade="slow"
onclick="closeCopyLogFeedbackPanel()">
- <description flex="1" />
+ <description flex="1"/>
</panel>
</overlay>
diff --git a/src/chrome/content/network-settings-wizard.xul b/src/chrome/content/network-settings-wizard.xul
index 97e846c..86c2e01 100644
--- a/src/chrome/content/network-settings-wizard.xul
+++ b/src/chrome/content/network-settings-wizard.xul
@@ -57,6 +57,10 @@
<separator/>
<vbox id="proxySettings"/>
</vbox>
+ <vbox id="configErrorOverlay" class="messagePanel" pack="center"
+ hidden="true">
+ <vbox id="errorOverlayContent"/>
+ </vbox>
</stack>
</wizardpage>
@@ -68,36 +72,37 @@
<vbox id="progressContent"/>
</wizardpage>
- <wizardpage pageid="startingTor" next="notUsed" torShowNavButtons="false">
+ <wizardpage pageid="startingTor" class="messagePanel" next="notUsed"
+ torShowNavButtons="false">
<hbox class="tbb-header" pack="center">
<image class="tbb-logo"/>
</hbox>
- <spring flex="1" />
+ <spring flex="1"/>
<hbox>
- <spring flex="1" />
+ <spring flex="1"/>
<description>&torsettings.startingTor;</description>
- <spring flex="1" />
+ <spring flex="1"/>
</hbox>
- <spring flex="1" />
+ <spring flex="1"/>
</wizardpage>
- <wizardpage pageid="restartPanel" next="notUsed"
+ <wizardpage pageid="restartPanel" class="messagePanel" next="notUsed"
pack="center" torShowNavButtons="false" onextra2="onCopyLog();">
<vbox id="restartContent"/>
</wizardpage>
- <wizardpage pageid="errorPanel" next="notUsed"
+ <wizardpage pageid="errorPanel" class="messagePanel" next="notUsed"
torShowNavButtons="false" onextra2="onCopyLog();">
- <spring flex="1" />
+ <spring flex="1"/>
<hbox pack="center">
<description errorElemId="message" flex="1"/>
</hbox>
<separator/>
<hbox pack="center">
<button errorElemId="reconfigButton" label="&torsettings.reconfigTor;"
- hidden="true" oncommand="onWizardReconfig()" />
+ hidden="true" oncommand="onWizardReconfig()"/>
</hbox>
- <spring flex="1" />
+ <spring flex="1"/>
</wizardpage>
<wizardpage pageid="discardSettings" next="notUsed" torShowNavButtons="false"
@@ -105,7 +110,7 @@
<hbox class="tbb-header" pack="center">
<image class="tbb-logo"/>
</hbox>
- <spring flex="1" />
+ <spring flex="1"/>
<hbox pack="center">
<description flex="1">&torsettings.discardSettings.prompt;</description>
</hbox>
@@ -114,9 +119,9 @@
<button id="discardSettingsGoBack" oncommand="showPanel();"/>
<separator/>
<button label="&torsettings.discardSettings.proceed;"
- oncommand="removeSettingsAndConnect()" />
+ oncommand="removeSettingsAndConnect()"/>
</hbox>
- <spring flex="1" />
+ <spring flex="1"/>
</wizardpage>
<wizardpage class="help" pageid="helpPanel" next="notUsed"
@@ -126,7 +131,7 @@
</wizardpage>
<hbox pack="start">
- <label id="forAssistance" />
+ <label id="forAssistance"/>
</hbox>
- <panel id="copyLogFeedbackPanel" />
+ <panel id="copyLogFeedbackPanel"/>
</wizard>
diff --git a/src/chrome/content/network-settings.js b/src/chrome/content/network-settings.js
index 2237c85..da48bab 100644
--- a/src/chrome/content/network-settings.js
+++ b/src/chrome/content/network-settings.js
@@ -217,7 +217,7 @@ function initDialog()
(status != gTorProcessService.kStatusRunning))
{
if (status == gTorProcessService.kStatusExited)
- showErrorMessage(true, null, false);
+ showRestartPanel();
else
showStartingTorPanel();
addObserver(kTorProcessReadyTopic);
@@ -395,7 +395,7 @@ function onWizardPageShow()
setTimeout(function() {
showOrHideButton("back", (val == "true"), false);
- // The "next" button is only used by the bridgeHelp wizard panel.
+ // The "next" button is only used by the help wizard panel.
let isShowingHelp = (wizardElem.currentPage.pageid == "helpPanel");
showOrHideButton("next", isShowingHelp, false);
}, 0);
@@ -500,6 +500,8 @@ function onShowProgressPanel()
}
+// resetProgressNavButtons() is called when moving away from the progress
+// panel entirely, and when an error is displayed within the progress panel.
function resetProgressNavButtons()
{
if (gShowProgressTimer)
@@ -521,6 +523,11 @@ var gObserver = {
(kTorLogHasWarnOrErrTopic == aTopic))
{
showCopyLogButton(true);
+ if (kTorBootstrapErrorTopic == aTopic)
+ {
+ stopTorBootstrap();
+ showErrorMessage(aSubject.wrappedJSObject, true);
+ }
return;
}
@@ -534,12 +541,12 @@ var gObserver = {
{
removeObserver(kTorProcessReadyTopic);
removeObserver(kTorProcessDidNotStartTopic);
- showErrorMessage(false, aData, false);
+ showErrorMessage(aSubject.wrappedJSObject, false);
}
else if (kTorProcessExitedTopic == aTopic)
{
removeObserver(kTorProcessExitedTopic);
- showErrorMessage(true, null, false);
+ showRestartPanel();
}
else if (kTorShowProgressPanelTopic == aTopic)
{
@@ -639,17 +646,11 @@ function readTorSettings()
if (!didSucceed)
{
// Unable to communicate with tor. Hide settings and display an error.
- showErrorMessage(false, null, false);
-
- setTimeout(function()
- {
- let details = TorLauncherUtil.getLocalizedString(
- "ensure_tor_is_running");
- let s = TorLauncherUtil.getFormattedLocalizedString(
- "failed_to_get_settings", [details], 1);
- TorLauncherUtil.showAlert(window, s);
- close();
- }, 0);
+ let details = TorLauncherUtil.getLocalizedString("ensure_tor_is_running");
+ let s = TorLauncherUtil.getFormattedLocalizedString(
+ "failed_to_get_settings", [details], 1);
+ let errorObj = { message: s };
+ showErrorMessage(errorObj, false);
}
TorLauncherLogger.log(2, "readTorSettings done; didSucceed: " + didSucceed);
@@ -728,49 +729,148 @@ function showStartingTorPanel()
}
-function showErrorMessage(aTorExited, aErrorMsg, aShowReconfigButton)
+function showErrorMessage(aErrorObj, aShowReconfigButton)
{
- var elem = document.getElementById("errorPanelMessage");
- var btn = document.getElementById("restartTorButton");
- if (aTorExited)
+ if (aErrorObj && aErrorObj.handled)
+ return;
+
+ // Determine our strategy for displaying this error message.
+ const kShowErrorInErrorPanel = 1;
+ const kShowErrorUsingErrorOverlay = 2;
+ const kShowErrorInProgressPanel = 3;
+ let errorStrategy = kShowErrorInErrorPanel;
+
+ let wizard = getWizard();
+ if (isShowingProgress() && aShowReconfigButton)
+ errorStrategy = kShowErrorInProgressPanel;
+ else if (!wizard || (wizard.currentPage.pageid == "configureSettings"))
+ errorStrategy = kShowErrorUsingErrorOverlay;
+
+ let errorContainer;
+ if (errorStrategy == kShowErrorUsingErrorOverlay)
+ errorContainer = getErrorOverlay();
+ else if (errorStrategy == kShowErrorInProgressPanel)
+ errorContainer = document.getElementById("progressContent");
+ else
+ errorContainer = wizard.getPageById("errorPanel");
+ if (!errorContainer)
+ return;
+
+ let messageElem = getFirstElementByErrorOverlayID(errorContainer, "message");
+ if (messageElem)
{
- // Show "Tor exited" message and "Restart Tor" button.
- aErrorMsg = TorLauncherUtil.getLocalizedString("tor_exited")
- + "\n\n" + TorLauncherUtil.getLocalizedString("tor_exited2");
+ let msg = "";
+ if (aErrorObj && aErrorObj.message)
+ {
+ msg = aErrorObj.message;
+ if (aErrorObj.details)
+ msg += "\n\n" + aErrorObj.details;
+ aErrorObj.handled = true;
+ }
+ messageElem.textContent = msg;
+ }
- if (btn)
- btn.removeAttribute("hidden");
- if (elem)
- elem.style.textAlign = "start";
+ if (errorStrategy == kShowErrorUsingErrorOverlay)
+ {
+ showOrHideDialogButtons(false);
+
+ let dismissBtn = getFirstElementByErrorOverlayID(errorContainer,
+ "dismissButton");
+ let bundle = Cc["@mozilla.org/intl/stringbundle;1"]
+ .getService(Ci.nsIStringBundleService)
+ .createBundle("chrome://global/locale/commonDialogs.properties");
+ dismissBtn.label = bundle.GetStringFromName("OK");
+ errorContainer.removeAttribute("hidden");
+ if (dismissBtn)
+ dismissBtn.focus();
}
- else
+ else if (errorStrategy == kShowErrorInProgressPanel)
{
- if (btn)
- btn.setAttribute("hidden", true);
- if (elem)
- elem.style.textAlign = "center";
+ // In this case, we always show a "Reconfigure" button.
+ errorContainer.setAttribute("isShowingReconfigure", "true");
+ let btnLabel = document.getElementById("progressReconfigureLabel");
+ if (wizard)
+ {
+ showOrHideElemById("progressPleaseWait", false);
+ resetProgressNavButtons(); // Show Quit and clear "show progress" timer.
+ overrideButtonLabel("finish", btnLabel.value);
+ }
+ else if (btnLabel)
+ {
+ // Network Settings window (non-wizard) case.
+ overrideButtonLabel("cancel", btnLabel.value);
+ }
}
+ else // if (errorStrategy == kShowErrorInErrorPanel)
+ {
+ let reconfigBtn = getFirstElementByErrorOverlayID(errorContainer,
+ "reconfigButton");
+ if (reconfigBtn)
+ {
+ if (aShowReconfigButton)
+ reconfigBtn.removeAttribute("hidden");
+ else
+ reconfigBtn.setAttribute("hidden", true);
+ }
+
+ // Navigate to the wizard error panel.
+ showPanel("errorPanel");
+ }
+
+ let haveErrorOrWarning = (gTorProcessService.TorBootstrapErrorOccurred ||
+ gProtocolSvc.TorLogHasWarnOrErr)
+ showCopyLogButton(haveErrorOrWarning);
+}
+
+
+function getErrorOverlay()
+{
+ return document.getElementById(getWizard() ? "configErrorOverlay"
+ : "errorOverlay");
+}
- if (elem)
- elem.textContent = (aErrorMsg) ? aErrorMsg : "";
- let reconfigBtn = document.getElementById("reconfigTorButton");
- if (reconfigBtn)
+function getFirstElementByErrorOverlayID(aContainer, aID)
+{
+ let nodeList = aContainer.getElementsByAttribute("errorElemId", aID);
+ return (nodeList && (nodeList.length > 0)) ? nodeList[0] : undefined;
+}
+
+
+function showRestartPanel()
+{
+ let elem = document.getElementById("restartPanelMessage");
+ if (elem)
{
- if (aShowReconfigButton)
- reconfigBtn.removeAttribute("hidden");
- else
- reconfigBtn.setAttribute("hidden", true);
+ elem.textContent = TorLauncherUtil.getLocalizedString("tor_exited")
+ + "\n\n" + TorLauncherUtil.getLocalizedString("tor_exited2");
}
- showPanel("errorPanel");
+ showPanel("restartPanel");
- var haveErrorOrWarning = (gTorProcessService.TorBootstrapErrorOccurred ||
+ let haveErrorOrWarning = (gTorProcessService.TorBootstrapErrorOccurred ||
gProtocolSvc.TorLogHasWarnOrErr)
showCopyLogButton(haveErrorOrWarning);
}
+function onDismissErrorOverlay()
+{
+ let errorOverlay = getErrorOverlay();
+ if (errorOverlay)
+ errorOverlay.setAttribute("hidden", true);
+
+ showOrHideDialogButtons(true);
+}
+
+
+function isShowingErrorOverlay()
+{
+ let errorOverlay = getErrorOverlay();
+ return errorOverlay && !errorOverlay.hasAttribute("hidden");
+}
+
+
function showCopyLogButton(aHaveErrorOrWarning)
{
let copyLogBtn = document.documentElement.getButton("extra2");
@@ -809,6 +909,29 @@ function restoreCopyLogVisibility()
}
+// Show or hide all of the buttons that are in the "footer" of the wizard or
+// Network Settings window.
+function showOrHideDialogButtons(aShow)
+{
+ let buttonContainer = document.getAnonymousElementByAttribute(
+ document.documentElement, "anonid", "buttons");
+ if (!buttonContainer)
+ {
+ // The wizard uses "Buttons" (capital 'B').
+ buttonContainer = document.getAnonymousElementByAttribute(
+ document.documentElement, "anonid", "Buttons");
+ }
+
+ if (buttonContainer)
+ {
+ if (aShow)
+ buttonContainer.removeAttribute("hidden");
+ else
+ buttonContainer.hidden = true;
+ }
+}
+
+
function showOrHideButton(aID, aShow, aFocus)
{
var btn = setButtonAttr(aID, "hidden", !aShow);
@@ -843,6 +966,19 @@ function setButtonAttr(aID, aAttr, aValue)
}
+function showOrHideElemById(aID, aShow)
+{
+ let elem = document.getElementById(aID);
+ if (elem)
+ {
+ if (aShow)
+ elem.removeAttribute("hidden");
+ else
+ elem.setAttribute("hidden", true);
+ }
+}
+
+
// Sets or removes aAttr for aID as well as optional aID+"Label" element.
function setBoolAttrForElemWithLabel(aID, aAttr, aValue)
{
@@ -1010,9 +1146,22 @@ function onCancel()
return false;
}
+ if (isShowingErrorOverlay())
+ {
+ onDismissErrorOverlay();
+ return false;
+ }
+
+ let wizard = getWizard();
+ if (!wizard && isShowingProgress())
+ {
+ onProgressCancelOrReconfigure(undefined);
+ return false;
+ }
+
// If this is a wizard (initial config or locale picker), the cancel
// button is "Quit"
- if (getWizard())
+ if (wizard)
{
try
{
@@ -1031,11 +1180,15 @@ function onCancel()
function onWizardFinish()
{
+ if (isShowingErrorOverlay())
+ {
+ onDismissErrorOverlay();
+ return false;
+ }
+
if (isShowingProgress())
{
- // When the progress panel is showing, the finish button is "Cancel"
- stopTorBootstrap();
- getWizard().rewind();
+ onProgressCancelOrReconfigure(getWizard());
return false;
}
else
@@ -1053,10 +1206,39 @@ function onNetworkSettingsFinish()
return false;
}
+ if (isShowingErrorOverlay())
+ {
+ onDismissErrorOverlay();
+ return false;
+ }
+
return applySettings(false);
}
+// When the progress panel is open, cancel stops bootstrapping... unless
+// we are showing an error, in which case the action is "Reconfigure".
+function onProgressCancelOrReconfigure(aWizard)
+{
+ let progressContent = document.getElementById("progressContent");
+ if (!progressContent ||
+ !progressContent.hasAttribute("isShowingReconfigure"))
+ {
+ stopTorBootstrap();
+ }
+
+ if (aWizard)
+ {
+ aWizard.rewind();
+ }
+ else
+ {
+ restoreButtonLabel("cancel");
+ showPanel(undefined); // return to the Network Settings main panel.
+ }
+}
+
+
function onCopyLog()
{
// Copy tor log messages to the system clipboard.
@@ -1107,12 +1289,8 @@ function onOpenHelp(aHelpContentID)
if (getWizard())
{
showOrHideButton("cancel", false, false);
- showOrHideButton("back", false, false);
overrideButtonLabelWithKey("next", "done");
- showOrHideButton("next", true, false);
- let forAssistance = document.getElementById("forAssistance");
- if (forAssistance)
- forAssistance.setAttribute("hidden", true);
+ showOrHideElemById("forAssistance", false);
}
else
{
@@ -1133,12 +1311,8 @@ function closeHelp()
if (wizardElem)
{
showOrHideButton("cancel", true, false);
- showOrHideButton("back", true, false);
- showOrHideButton("next", false, false);
restoreButtonLabel("next");
- var forAssistance = document.getElementById("forAssistance");
- if (forAssistance)
- forAssistance.removeAttribute("hidden");
+ showOrHideElemById("forAssistance", true);
helpPanel = wizardElem.currentPage;
}
else
@@ -1312,12 +1486,7 @@ function initBridgeSettings()
setElemValue(kUseBridgesCheckbox, useBridges);
- if (!canUseDefaultBridges)
- {
- var radioGroup = document.getElementById("bridgeTypeRadioGroup");
- if (radioGroup)
- radioGroup.setAttribute("hidden", true);
- }
+ showOrHideElemById("bridgeTypeRadioGroup", canUseDefaultBridges);
let radioID = (useDefault) ? "bridgeRadioDefault" : "bridgeRadioCustom";
let radio = document.getElementById(radioID);
@@ -1375,22 +1544,6 @@ function useSettings()
}
showProgressPanel();
-
-/* TODO2017: is this needed? Used to be after modal progress dlog was displayed
- let wizardElem = getWizard();
- if (!gTorProcessService.TorIsBootstrapDone && 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);
- }
- }
-*/
}
@@ -1416,12 +1569,12 @@ function stopTorBootstrap()
function showProgressPanel()
{
+ let progressContent = document.getElementById("progressContent");
+ if (progressContent)
+ progressContent.removeAttribute("isShowingReconfigure");
+
if (gIsInitialBootstrap)
- {
- let pleaseWait = document.getElementById("progressPleaseWait");
- if (pleaseWait)
- pleaseWait.removeAttribute("hidden");
- }
+ showOrHideElemById("progressPleaseWait", true);
// Clear the description to avoid displaying any old messages.
let desc = document.getElementById("progressDesc");
@@ -1555,7 +1708,7 @@ function isProxyConfigured()
function reportValidationError(aStrKey)
{
- showSaveSettingsAlert(TorLauncherUtil.getLocalizedString(aStrKey));
+ showSaveSettingsError(TorLauncherUtil.getLocalizedString(aStrKey));
}
@@ -1828,18 +1981,17 @@ function setConfAndReportErrors(aSettingsObj, aShowOnErrorPanelID)
} catch (e) {}
}
- showSaveSettingsAlert(errObj.details);
+ showSaveSettingsError(errObj.details);
}
return didSucceed;
}
-function showSaveSettingsAlert(aDetails)
+function showSaveSettingsError(aDetails)
{
- TorLauncherUtil.showSaveSettingsAlert(window, aDetails);
- showOrHideButton("extra2", true, false);
- gWizIsCopyLogBtnShowing = true;
+ let msg = TorLauncherUtil.getSaveSettingsErrorMessage(aDetails);
+ showErrorMessage({ message: msg }, true);
}
diff --git a/src/chrome/content/network-settings.xul b/src/chrome/content/network-settings.xul
index 1b5ced0..707990a 100644
--- a/src/chrome/content/network-settings.xul
+++ b/src/chrome/content/network-settings.xul
@@ -5,7 +5,7 @@
- vim: set sw=2 sts=2 ts=8 et syntax=xml:
-->
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://torlauncher/skin/network-settings.css"
type="text/css"?>
@@ -29,53 +29,53 @@
<script type="application/x-javascript"
src="chrome://torlauncher/content/network-settings.js"/>
- <deck id="deck" onselect="onDeckSelect();">
- <vbox id="settings">
- <vbox id="bridgeSettings"/>
- <separator orient="horizontal" class="thin"/>
- <vbox id="proxySettings"/>
+ <stack flex="1">
+ <vbox>
+ <deck id="deck" onselect="onDeckSelect();">
+ <vbox id="settings">
+ <vbox id="bridgeSettings"/>
+ <separator orient="horizontal" class="thin"/>
+ <vbox id="proxySettings"/>
+ <vbox>
+ <checkbox id="useFirewallPorts"
+ groupboxID="firewallSpecificSettings"
+ label="&torsettings.firewall.checkbox;"
+ oncommand="toggleElemUI(this)"/>
+ <groupbox id="firewallSpecificSettings"/>
+ </vbox>
+ </vbox>
- <vbox>
- <checkbox id="useFirewallPorts" groupboxID="firewallSpecificSettings"
- label="&torsettings.firewall.checkbox;"
- oncommand="toggleElemUI(this)"/>
- <groupbox id="firewallSpecificSettings" />
- </vbox>
- </vbox>
- <vbox id="startingTor">
- <spring flex="1" />
- <hbox>
- <spring flex="1" />
- <description>&torsettings.startingTor;</description>
- <spring flex="1" />
- </hbox>
- <spring flex="1" />
- </vbox>
- <vbox id="progressPanel">
- <vbox id="progressContent"/>
- </vbox>
- <vbox id="errorPanel">
- <spring flex="1" />
- <hbox>
- <spring flex="1" />
- <description id="errorPanelMessage" flex="1" />
- <spring flex="1" />
- </hbox>
- <separator/>
- <hbox>
- <spring flex="1" />
- <button id="restartTorButton" label="&torsettings.restartTor;" hidden="true"
- oncommand="onRestartTor()" />
- <spring flex="1" />
- </hbox>
- <spring flex="1" />
+ <vbox id="startingTor" class="messagePanel">
+ <spring flex="1"/>
+ <hbox>
+ <spring flex="1"/>
+ <description>&torsettings.startingTor;</description>
+ <spring flex="1"/>
+ </hbox>
+ <spring flex="1"/>
+ </vbox>
+
+ <vbox id="progressPanel">
+ <vbox id="progressContent"/>
+ </vbox>
+
+ <vbox id="helpPanel" class="help">
+ <vbox id="bridgeHelpContent" hidden="true"/>
+ <vbox id="proxyHelpContent" hidden="true"/>
+ </vbox>
+
+ <vbox id="restartPanel" class="messagePanel" pack="center">
+ <vbox id="restartContent"/>
+ </vbox>
+ </deck>
+
+ <spring flex="1"/>
+ <label id="forAssistance"/>
+ <panel id="copyLogFeedbackPanel"/>
</vbox>
- <vbox id="helpPanel" class="help">
- <vbox id="bridgeHelpContent" hidden="true"/>
- <vbox id="proxyHelpContent" hidden="true"/>
+
+ <vbox id="errorOverlay" class="messagePanel" pack="center" hidden="true">
+ <vbox id="errorOverlayContent"/>
</vbox>
- </deck>
- <spring flex="1" />
- <label id="forAssistance" />
- <panel id="copyLogFeedbackPanel" />
+ </stack>
</dialog>
diff --git a/src/chrome/skin/network-settings.css b/src/chrome/skin/network-settings.css
index 34b1b3e..259e38d 100644
--- a/src/chrome/skin/network-settings.css
+++ b/src/chrome/skin/network-settings.css
@@ -157,16 +157,31 @@ wizard.os-mac #bridgeList {
}
}
-wizardpage[pageid="startingTor"] description,
-wizardpage[pageid="errorPanel"] description,
-#errorPanel description,
-#startingTor description {
+#progressContent[isShowingReconfigure] description,
+.messagePanel description {
+ margin: 20px;
font-size: 120%;
font-weight: bold;
white-space: pre-wrap;
text-align: center;
}
+wizardpage[pageid="restartPanel"] description,
+#restartPanel description {
+ text-align: start;
+}
+
+#errorOverlayContent {
+ margin: 50px;
+ min-height: 12em;
+ background-color: rgba(251,251,251,1.0);
+ box-shadow: 0px 0px 50px rgba(0,0,0,0.9);
+}
+
+#errorOverlayContent button[errorElemId="dismissButton"] {
+ margin-bottom: 20px;
+}
+
#restartButton {
margin-top: 20px;
}
diff --git a/src/components/tl-process.js b/src/components/tl-process.js
index 6f07fdb..53c9919 100644
--- a/src/components/tl-process.js
+++ b/src/components/tl-process.js
@@ -50,6 +50,9 @@ TorProcessService.prototype =
kDefaultBridgesStatus_InUse: 1,
kDefaultBridgesStatus_BadConfig: 2,
+ kTorProcessDidNotStartTopic: "TorProcessDidNotStart",
+ kTorBootstrapErrorTopic: "TorBootstrapError",
+
// nsISupports implementation.
QueryInterface: function(aIID)
{
@@ -227,9 +230,8 @@ TorProcessService.prototype =
else if ((Date.now() - this.mTorProcessStartTime)
> this.kControlConnTimeoutMS)
{
- var s = TorLauncherUtil.getLocalizedString("tor_controlconn_failed");
- this.mObsSvc.notifyObservers(null, "TorProcessDidNotStart", s);
- TorLauncherUtil.showAlert(null, s);
+ let s = TorLauncherUtil.getLocalizedString("tor_controlconn_failed");
+ this._notifyUserOfError(s, null, this.kTorProcessDidNotStartTopic);
TorLauncherLogger.log(4, s);
}
else
@@ -373,7 +375,7 @@ TorProcessService.prototype =
var key = "unable_to_start_tor";
var err = TorLauncherUtil.getFormattedLocalizedString(key,
[details], 1);
- TorLauncherUtil.showAlert(null, err);
+ this._notifyUserOfError(err, null, this.kTorProcessDidNotStartTopic);
return;
}
@@ -461,7 +463,7 @@ TorProcessService.prototype =
var key = "error_bridge_bad_default_type";
var err = TorLauncherUtil.getFormattedLocalizedString(key,
[defaultBridgeType], 1);
- TorLauncherUtil.showAlert(null, err);
+ this._notifyUserOfError(err, null, null);
}
if (aForceDisableNetwork || TorLauncherUtil.shouldShowNetworkSettings ||
@@ -506,7 +508,7 @@ TorProcessService.prototype =
{
this.mTorProcessStatus = this.kStatusExited;
var s = TorLauncherUtil.getLocalizedString("tor_failed_to_start");
- TorLauncherUtil.showAlert(null, s);
+ this._notifyUserOfError(s, null, this.kTorProcessDidNotStartTopic);
TorLauncherLogger.safelog(4, "_startTor error: ", e);
}
}, // _startTor()
@@ -569,7 +571,7 @@ TorProcessService.prototype =
{
this.mTorProcessStatus = this.kStatusExited;
var s = TorLauncherUtil.getLocalizedString("tor_control_failed");
- TorLauncherUtil.showAlert(null, s);
+ this._notifyUserOfError(s, null, null);
TorLauncherLogger.safelog(4, "_controlTor error: ", e);
}
}, // controlTor()
@@ -619,11 +621,11 @@ TorProcessService.prototype =
{
this.mBootstrapErrorOccurred = true;
TorLauncherUtil.setBoolPref(this.kPrefPromptAtStartup, true);
- var phase = TorLauncherUtil.getLocalizedBootstrapStatus(aStatusObj,
+ let phase = TorLauncherUtil.getLocalizedBootstrapStatus(aStatusObj,
"TAG");
- var reason = TorLauncherUtil.getLocalizedBootstrapStatus(aStatusObj,
+ let reason = TorLauncherUtil.getLocalizedBootstrapStatus(aStatusObj,
"REASON");
- var details = TorLauncherUtil.getFormattedLocalizedString(
+ let details = TorLauncherUtil.getFormattedLocalizedString(
"tor_bootstrap_failed_details", [phase, reason], 2);
TorLauncherLogger.log(5, "Tor bootstrap error: [" + aStatusObj.TAG +
"/" + aStatusObj.REASON + "] " + details);
@@ -634,12 +636,8 @@ TorProcessService.prototype =
this.mLastTorWarningPhase = aStatusObj.TAG;
this.mLastTorWarningReason = aStatusObj.REASON;
- // Notify others that an error will be displayed.
- this.mObsSvc.notifyObservers(null, "TorBootstrapError", reason);
-
-// TODO2017: "route" error message to wizard or settings dialog if it is open
- var msg = TorLauncherUtil.getLocalizedString("tor_bootstrap_failed");
- TorLauncherUtil.showAlert(null, msg + "\n\n" + details);
+ let msg = TorLauncherUtil.getLocalizedString("tor_bootstrap_failed");
+ this._notifyUserOfError(msg, details, this.kTorBootstrapErrorTopic);
}
}
}
@@ -684,9 +682,14 @@ TorProcessService.prototype =
}
if (didSucceed)
+ {
this.mProtocolSvc.TorSendCommand("SAVECONF");
+ }
else
- TorLauncherUtil.showSaveSettingsAlert(null, errObj.details);
+ {
+ let msg = TorLauncherUtil.getSaveSettingsErrorMessage(errObj.details);
+ this._notifyUserOfError(msg, null, null);
+ }
},
_openLocalePicker: function()
@@ -752,6 +755,30 @@ TorProcessService.prototype =
return argsArray;
},
+ _notifyUserOfError: function(aMessage, aDetails, aNotifyTopic)
+ {
+ let errorObj = { handled: false, message: aMessage };
+ if (aDetails)
+ errorObj.details = aDetails;
+
+ if (aNotifyTopic)
+ {
+ // Give other code an opportunity to handle this error, e.g., if the
+ // network settings window is open, errors are displayed using an
+ // overlaid XUL element.
+ errorObj.wrappedJSObject = errorObj;
+ this.mObsSvc.notifyObservers(errorObj, aNotifyTopic, null);
+ }
+
+ if (!errorObj.handled)
+ {
+ let msg = aMessage;
+ if (aDetails)
+ msg += "\n\n" + aDetails;
+ TorLauncherUtil.showAlert(null, msg);
+ }
+ },
+
_getpid: function()
{
// Use nsIXULRuntime.processID if it is available.
diff --git a/src/components/tl-protocol.js b/src/components/tl-protocol.js
index d6323f4..68c6530 100644
--- a/src/components/tl-protocol.js
+++ b/src/components/tl-protocol.js
@@ -465,7 +465,7 @@ TorProtocolService.prototype =
// 250 OK
reply = this._parseReply(cmd, key, reply);
if (reply.lineArray)
- this._parseBootstrapStatus(reply.lineArray[0]);
+ this._parseBootstrapStatus(reply.lineArray[0], true);
},
// If successful, returns a JS object with these fields:
@@ -479,8 +479,10 @@ TorProtocolService.prototype =
// status.RECOMMENDATION -- string (optional)
// status.HOSTADDR -- string (optional)
// A "TorBootstrapStatus" notification is also sent.
+ // If aSuppressErrors is true, errors are ignored. This is used when we
+ // are handling the response to a "GETINFO status/bootstrap-phase" command.
// Returns null upon failure.
- _parseBootstrapStatus: function(aStatusMsg)
+ _parseBootstrapStatus: function(aStatusMsg, aSuppressErrors)
{
if (!aStatusMsg || (0 == aStatusMsg.length))
return null;
@@ -531,7 +533,8 @@ TorProtocolService.prototype =
}
// this._dumpObj("BootstrapStatus", statusObj);
- statusObj._errorOccurred = (("NOTICE" != statusObj.TYPE) &&
+ statusObj._errorOccurred = (!aSuppressErrors &&
+ ("NOTICE" != statusObj.TYPE) &&
("warn" == statusObj.RECOMMENDATION));
// Notify observers.
@@ -1519,7 +1522,7 @@ TorProtocolService.prototype =
}
break;
case "STATUS_CLIENT":
- this._parseBootstrapStatus(msg);
+ this._parseBootstrapStatus(msg, false);
break;
default:
this._dumpObj(eventType + "_event", aReply);
diff --git a/src/modules/tl-util.jsm b/src/modules/tl-util.jsm
index 2e45fd1..bb84bdf 100644
--- a/src/modules/tl-util.jsm
+++ b/src/modules/tl-util.jsm
@@ -50,9 +50,18 @@ let TorLauncherUtil = // Public
{
var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator);
- aParentWindow = wm.getMostRecentWindow("TorLauncher:NetworkSettings");
- if (!aParentWindow)
- aParentWindow = wm.getMostRecentWindow("navigator:browser");
+ let settingsWindow =
+ wm.getMostRecentWindow("TorLauncher:NetworkSettings");
+ if (TLUtilInternal._isWindowVisible(settingsWindow))
+ {
+ aParentWindow = settingsWindow;
+ }
+ else
+ {
+ let browserWindow = wm.getMostRecentWindow("navigator:browser");
+ if (TLUtilInternal._isWindowVisible(browserWindow))
+ aParentWindow = browserWindow;
+ }
}
var ps = Cc["@mozilla.org/embedcomp/prompt-service;1"]
@@ -106,14 +115,13 @@ let TorLauncherUtil = // Public
return false;
},
- showSaveSettingsAlert: function(aParentWindow, aDetails)
+ getSaveSettingsErrorMessage: function(aDetails)
{
if (!aDetails)
aDetails = TorLauncherUtil.getLocalizedString("ensure_tor_is_running");
- var s = TorLauncherUtil.getFormattedLocalizedString(
+ return TorLauncherUtil.getFormattedLocalizedString(
"failed_to_save_settings", [aDetails], 1);
- this.showAlert(aParentWindow, s);
},
// Localized Strings
@@ -846,6 +854,20 @@ let TLUtilInternal = // Private
return null;
}
},
+
+ _isWindowVisible: function(aWindow)
+ {
+ if (!aWindow)
+ return false;
+
+ try {
+ let winUtils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ return winUtils.isParentWindowMainWidgetVisible;
+ } catch(e) {}
+
+ return false;
+ },
};