commit 803bf1178bc8c66a7166309abd680eef4af7a548 Author: Kathy Brade brade@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; + }, };