diff --git a/browser/actors/PromptParent.sys.mjs b/browser/actors/PromptParent.sys.mjs index 9858a2662ce12..0339c14642004 100644 --- a/browser/actors/PromptParent.sys.mjs +++ b/browser/actors/PromptParent.sys.mjs @@ -26,7 +26,7 @@ XPCOMUtils.defineLazyPreferenceGetter( ); XPCOMUtils.defineLazyGetter(lazy, "gTabBrowserLocalization", function () { - return new Localization(["browser/tabbrowser.ftl"], true); + return new Localization(["browser/tabbrowser.ftl", "browser/waterfox.ftl"], true); }); /** diff --git a/browser/base/content/tabbrowser.js b/browser/base/content/tabbrowser.js index e501cce8ffe0c..9da985774437f 100644 --- a/browser/base/content/tabbrowser.js +++ b/browser/base/content/tabbrowser.js @@ -98,7 +98,7 @@ }); XPCOMUtils.defineLazyGetter(this, "tabLocalization", () => { return new Localization( - ["browser/tabbrowser.ftl", "branding/brand.ftl"], + ["browser/tabbrowser.ftl", "branding/brand.ftl", "browser/waterfox.ftl"], true ); }); @@ -3357,26 +3357,40 @@ // default to true: if it were false, we wouldn't get this far var warnOnClose = { value: true }; + let restoreSession; + let startupPref = Services.prefs.getIntPref("browser.startup.page"); + + // If we are set to anything other than restore session, + // leave its value. + if (startupPref != 3) { + console.log("Value of: " + startupPref); + restoreSession = { value: false }; + } else { + console.log("Value of: " + startupPref); + restoreSession = { value: true }; + } + // focus the window before prompting. // this will raise any minimized window, which will // make it obvious which window the prompt is for and will // solve the problem of windows "obscuring" the prompt. // see bug #350299 for more details window.focus(); - const [title, button, checkbox] = this.tabLocalization.formatValuesSync([ + const [title, button, checkbox, checkboxLabel2] = this.tabLocalization.formatValuesSync([ { id: "tabbrowser-confirm-close-tabs-title", args: { tabCount: tabsToClose }, }, { id: "tabbrowser-confirm-close-tabs-button" }, { id: "tabbrowser-confirm-close-tabs-checkbox" }, + { id: "tabbrowser-confirm-session-restore-checkbox" } ]); let flags = ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_0 + ps.BUTTON_TITLE_CANCEL * ps.BUTTON_POS_1; let checkboxLabel = aCloseTabs == this.closingTabsEnum.ALL ? checkbox : null; - var buttonPressed = ps.confirmEx( + var buttonPressed = ps.confirmEx2( window, title, null, @@ -3385,7 +3399,9 @@ null, null, checkboxLabel, - warnOnClose + warnOnClose, + checkboxLabel2, + restoreSession ); Services.telemetry.setEventRecordingEnabled("close_tab_warning", true); @@ -3432,6 +3448,16 @@ Services.prefs.setBoolPref(pref, false); } + if (buttonPressed == 0) { + if (!restoreSession.value) { + if (startupPref === 3) { + Services.prefs.setIntPref("browser.startup.page", 1); + } + } else if (restoreSession.value) { + Services.prefs.setIntPref("browser.startup.page", 3); + } + } + return reallyClose; }, diff --git a/browser/components/BrowserGlue.sys.mjs b/browser/components/BrowserGlue.sys.mjs index f9dad1e715c84..2107e99a5bdcd 100644 --- a/browser/components/BrowserGlue.sys.mjs +++ b/browser/components/BrowserGlue.sys.mjs @@ -3125,6 +3125,18 @@ BrowserGlue.prototype = { aQuitType = "quit"; } + let restoreSession; + let startupPref = Services.prefs.getIntPref("browser.startup.page"); + + // If we are set to anything other than restore session, + if (startupPref != 3) { + console.log("Value of: " + startupPref); + restoreSession = { value: false }; + } else { + console.log("Value of: " + startupPref); + restoreSession = { value: true }; + } + let win = lazy.BrowserWindowTracker.getTopWindow(); // Our prompt for quitting is most important, so replace others. @@ -3163,19 +3175,23 @@ BrowserGlue.prototype = { checkboxLabelId = "tabbrowser-confirm-close-tabs-checkbox"; } - const [title, buttonLabel, checkboxLabel] = + let checkboxLabelId2 = "tabbrowser-confirm-session-restore-checkbox"; + + const [title, buttonLabel, checkboxLabel, checkboxLabel2] = win.gBrowser.tabLocalization.formatMessagesSync([ titleId, buttonLabelId, checkboxLabelId, + checkboxLabelId2, ]); let warnOnClose = { value: true }; + let flags = Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0 + Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1; // buttonPressed will be 0 for closing, 1 for cancel (don't close/quit) - let buttonPressed = Services.prompt.confirmEx( + let buttonPressed = Services.prompt.confirmEx2( win, title.value, null, @@ -3184,7 +3200,9 @@ BrowserGlue.prototype = { null, null, checkboxLabel.value, - warnOnClose + warnOnClose, + checkboxLabel2.value, + restoreSession ); Services.telemetry.setEventRecordingEnabled("close_tab_warning", true); let warnCheckbox = warnOnClose.value ? "checked" : "unchecked"; @@ -3217,6 +3235,18 @@ BrowserGlue.prototype = { } } + // If we are set to anything other than restore session, + // leave its value. + if (buttonPressed == 0) { + if (!restoreSession.value) { + if (startupPref === 3) { + Services.prefs.setIntPref("browser.startup.page", 1); + } + } else if (restoreSession.value) { + Services.prefs.setIntPref("browser.startup.page", 3); + } + } + this._quitSource = "unknown"; aCancelQuit.data = buttonPressed != 0; diff --git a/netwerk/base/nsIPrompt.idl b/netwerk/base/nsIPrompt.idl index 9ceaa6b89244d..a0f31c041d708 100644 --- a/netwerk/base/nsIPrompt.idl +++ b/netwerk/base/nsIPrompt.idl @@ -79,6 +79,17 @@ interface nsIPrompt : nsISupports in wstring checkMsg, inout boolean checkValue); + int32_t confirmEx2(in wstring dialogTitle, + in wstring text, + in unsigned long buttonFlags, + in wstring button0Title, + in wstring button1Title, + in wstring button2Title, + in wstring checkMsg, + inout boolean checkValue, + in wstring checkMsg2, + inout boolean checkValue2); + boolean prompt(in wstring dialogTitle, in wstring text, inout wstring value, diff --git a/toolkit/components/prompts/content/commonDialog.js b/toolkit/components/prompts/content/commonDialog.js index a18b7cbd6cf57..a516bd16330fa 100644 --- a/toolkit/components/prompts/content/commonDialog.js +++ b/toolkit/components/prompts/content/commonDialog.js @@ -98,6 +98,7 @@ function commonDialogOnLoad() { infoTitle: document.getElementById("infoTitle"), infoIcon: document.getElementById("infoIcon"), checkbox: document.getElementById("checkbox"), + checkbox2: document.getElementById("checkbox2"), checkboxContainer: document.getElementById("checkboxContainer"), button3: dialog.getButton("extra2"), button2: dialog.getButton("extra1"), diff --git a/toolkit/components/prompts/content/commonDialog.xhtml b/toolkit/components/prompts/content/commonDialog.xhtml index 02e0749a9ef93..11c65e3d720a4 100644 --- a/toolkit/components/prompts/content/commonDialog.xhtml +++ b/toolkit/components/prompts/content/commonDialog.xhtml @@ -97,6 +97,7 @@
+
diff --git a/toolkit/components/prompts/src/CommonDialog.sys.mjs b/toolkit/components/prompts/src/CommonDialog.sys.mjs index a0812aa8eca21..752a4ed41e49d 100644 --- a/toolkit/components/prompts/src/CommonDialog.sys.mjs +++ b/toolkit/components/prompts/src/CommonDialog.sys.mjs @@ -33,6 +33,7 @@ CommonDialog.prototype = { * @param [commonDialogEl] - Dialog element from commonDialog.xhtml, * null for TabModalPrompts. */ + // eslint-disable-next-line complexity async onLoad(commonDialogEl = null) { let isEmbedded = !!commonDialogEl?.ownerGlobal.docShell.chromeEventHandler; @@ -73,6 +74,28 @@ CommonDialog.prototype = { this.iconClass = ["question-icon"]; this.soundID = Ci.nsISound.EVENT_CONFIRM_DIALOG_OPEN; break; + case "confirmEx2": + var numButtons2 = 0; + if (this.args.button0Label) { + numButtons2++; + } + if (this.args.button1Label) { + numButtons2++; + } + if (this.args.button2Label) { + numButtons2++; + } + if (this.args.button3Label) { + numButtons2++; + } + if (numButtons2 == 0) { + throw new Error("A dialog with no buttons? Can not haz."); + } + this.numButtons = numButtons2; + this.hasInputField = false; + this.iconClass = ["question-icon"]; + this.soundID = Ci.nsISound.EVENT_CONFIRM_DIALOG_OPEN; + break; case "prompt": this.numButtons = 2; this.iconClass = ["question-icon"]; @@ -190,6 +213,15 @@ CommonDialog.prototype = { this.ui.checkbox.checked = this.args.checked; } + let label2 = this.args.checkLabel2; + if (label2) { + // Only show the checkbox if label has a value. + this.ui.checkboxContainer.hidden = false; + this.ui.checkboxContainer.clientTop; // style flush to assure binding is attached + this.setLabelForNode(this.ui.checkbox2, label2); + this.ui.checkbox2.checked = this.args.checked2; + } + // set the icon let icon = this.ui.infoIcon; if (icon) { @@ -336,6 +368,10 @@ CommonDialog.prototype = { this.args.checked = this.ui.checkbox.checked; }, + onCheckbox2() { + this.args.checked2 = this.ui.checkbox2.checked; + }, + onButton0() { this.args.promptActive = false; this.args.ok = true; diff --git a/toolkit/components/prompts/src/Prompter.sys.mjs b/toolkit/components/prompts/src/Prompter.sys.mjs index fe44992378240..0a7cc1b736d32 100644 --- a/toolkit/components/prompts/src/Prompter.sys.mjs +++ b/toolkit/components/prompts/src/Prompter.sys.mjs @@ -306,6 +306,34 @@ Prompter.prototype = { ); }, + confirmEx2( + domWin, + title, + text, + flags, + button0, + button1, + button2, + checkLabel, + checkValue, + checkLabel2, + checkValue2 + ) { + let p = this.pickPrompter({ domWin }); + return p.confirmEx2( + title, + text, + flags, + button0, + button1, + button2, + checkLabel, + checkValue, + checkLabel2, + checkValue2 + ); + }, + /** * Puts up a dialog with up to 3 buttons and an optional, labeled checkbox. * @param {BrowsingContext} browsingContext - The browsing context the @@ -1467,6 +1495,66 @@ class ModalPrompter { return args.buttonNumClicked; } + confirmEx2( + title, + text, + flags, + button0, + button1, + button2, + checkLabel, + checkValue, + checkLabel2, + checkValue2, + extraArgs = {} + ) { + if (!title) { + title = InternalPromptUtils.getLocalizedString("Confirm"); + } + + let args = { + promptType: "confirmEx2", + title, + text, + checkLabel, + checked: this.async ? checkValue : checkValue.value, + checkLabel2, + checked2: this.async ? checkValue2 : checkValue2.value, + ok: false, + buttonNumClicked: 1, + ...extraArgs, + }; + + let [label0, label1, label2, defaultButtonNum, isDelayEnabled] = + InternalPromptUtils.confirmExHelper(flags, button0, button1, button2); + + args.defaultButtonNum = defaultButtonNum; + args.enableDelay = isDelayEnabled; + + if (label0) { + args.button0Label = label0; + if (label1) { + args.button1Label = label1; + if (label2) { + args.button2Label = label2; + } + } + } + + if (this.async) { + return this.openPromptAsync(args, result => ({ + checked: !!result.checked, + checked2: !!result.checked2, + buttonNumClicked: result.buttonNumClicked, + })); + } + + this.openPromptSync(args); + checkValue.value = args.checked; + checkValue2.value = args.checked2; + return args.buttonNumClicked; + } + nsIPrompt_prompt(title, text, value, checkLabel, checkValue) { if (!title) { title = InternalPromptUtils.getLocalizedString("Prompt"); diff --git a/toolkit/components/windowwatcher/nsIPromptService.idl b/toolkit/components/windowwatcher/nsIPromptService.idl index 9d910e0bcedfc..881434e719f56 100644 --- a/toolkit/components/windowwatcher/nsIPromptService.idl +++ b/toolkit/components/windowwatcher/nsIPromptService.idl @@ -333,6 +333,67 @@ interface nsIPromptService : nsISupports in wstring aButton2Title, in wstring aCheckMsg, inout boolean aCheckState); + + /** + * Puts up a dialog with up to 3 buttons and an optional, labeled checkbox. + * + * @param aParent + * The parent window or null. + * @param aDialogTitle + * Text to appear in the title of the dialog. + * @param aText + * Text to appear in the body of the dialog. + * @param aButtonFlags + * A combination of Button Flags. + * @param aButton0Title + * Used when button 0 uses TITLE_IS_STRING + * @param aButton1Title + * Used when button 1 uses TITLE_IS_STRING + * @param aButton2Title + * Used when button 2 uses TITLE_IS_STRING + * @param aCheckMsg + * Text to appear with the checkbox. Null if no checkbox. + * @param aCheckState + * Contains the initial checked state of the checkbox when this method + * is called and the final checked state after this method returns. + * @param aCheckMsg2 + * A second text to appear with the checkbox. Null if no checkbox. + * @param aCheckState2 + * Contains the initial checked state of the checkbox when this method + * is called and the final checked state after this method returns. + * + * @return index of the button pressed. + * + * Buttons are numbered 0 - 2. The implementation can decide whether the + * sequence goes from right to left or left to right. Button 0 is the + * default button unless one of the Button Default Flags is specified. + * + * A button may use a predefined title, specified by one of the Button Title + * Flags values. Each title value can be multiplied by a position value to + * assign the title to a particular button. If BUTTON_TITLE_IS_STRING is + * used for a button, the string parameter for that button will be used. If + * the value for a button position is zero, the button will not be shown. + * + * In general, aButtonFlags is constructed per the following example: + * + * aButtonFlags = (BUTTON_POS_0) * (BUTTON_TITLE_AAA) + + * (BUTTON_POS_1) * (BUTTON_TITLE_BBB) + + * BUTTON_POS_1_DEFAULT; + * + * where "AAA" and "BBB" correspond to one of the button titles. + */ + int32_t confirmEx2(in mozIDOMWindowProxy aParent, + in wstring aDialogTitle, + in wstring aText, + in unsigned long aButtonFlags, + in wstring aButton0Title, + in wstring aButton1Title, + in wstring aButton2Title, + in wstring aCheckMsg, + inout boolean aCheckState, + in wstring aCheckMsg2, + inout boolean aCheckState2); + /** * Like confirmEx, but with a BrowsingContext as parent. * diff --git a/waterfox/browser/locales/en-US/waterfox.ftl b/waterfox/browser/locales/en-US/waterfox.ftl index 20421900f4db4..963c3e416ec3e 100644 --- a/waterfox/browser/locales/en-US/waterfox.ftl +++ b/waterfox/browser/locales/en-US/waterfox.ftl @@ -258,4 +258,6 @@ telemetry-page-subtitle = Waterfox does not collect telemetry about your install telemetry-privacy-policy = Privacy Policy onboarding-grassroots-title = Supporting the grassroots -onboarding-grassroots-subtitle = Thank you for using Waterfox, an independent, grassroots browser. With your support, we’re building a sustainable alternative to the big players out there. \ No newline at end of file +onboarding-grassroots-subtitle = Thank you for using Waterfox, an independent, grassroots browser. With your support, we’re building a sustainable alternative to the big players out there. + +tabbrowser-confirm-session-restore-checkbox = Open previous windows and tabs \ No newline at end of file