diff options
Diffstat (limited to 'toolkit/components/jsdownloads/src/DownloadUIHelper.jsm')
-rw-r--r-- | toolkit/components/jsdownloads/src/DownloadUIHelper.jsm | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/toolkit/components/jsdownloads/src/DownloadUIHelper.jsm b/toolkit/components/jsdownloads/src/DownloadUIHelper.jsm new file mode 100644 index 000000000..f5102b4a8 --- /dev/null +++ b/toolkit/components/jsdownloads/src/DownloadUIHelper.jsm @@ -0,0 +1,243 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Provides functions to handle status and messages in the user interface. + */ + +"use strict"; + +this.EXPORTED_SYMBOLS = [ + "DownloadUIHelper", +]; + +// Globals + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/AppConstants.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "OS", + "resource://gre/modules/osfile.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Promise", + "resource://gre/modules/Promise.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Services", + "resource://gre/modules/Services.jsm"); + +const kStringBundleUrl = + "chrome://mozapps/locale/downloads/downloads.properties"; + +const kStringsRequiringFormatting = { + fileExecutableSecurityWarning: true, + cancelDownloadsOKTextMultiple: true, + quitCancelDownloadsAlertMsgMultiple: true, + quitCancelDownloadsAlertMsgMacMultiple: true, + offlineCancelDownloadsAlertMsgMultiple: true, + leavePrivateBrowsingWindowsCancelDownloadsAlertMsgMultiple2: true +}; + +// DownloadUIHelper + +/** + * Provides functions to handle status and messages in the user interface. + */ +this.DownloadUIHelper = { + /** + * Returns an object that can be used to display prompts related to downloads. + * + * The prompts may be either anchored to a specified window, or anchored to + * the most recently active window, for example if the prompt is displayed in + * response to global notifications that are not associated with any window. + * + * @param aParent + * If specified, should reference the nsIDOMWindow to which the prompts + * should be attached. If omitted, the prompts will be attached to the + * most recently active window. + * + * @return A DownloadPrompter object. + */ + getPrompter: function (aParent) + { + return new DownloadPrompter(aParent || null); + }, +}; + +/** + * Returns an object whose keys are the string names from the downloads string + * bundle, and whose values are either the translated strings or functions + * returning formatted strings. + */ +XPCOMUtils.defineLazyGetter(DownloadUIHelper, "strings", function () { + let strings = {}; + let sb = Services.strings.createBundle(kStringBundleUrl); + let enumerator = sb.getSimpleEnumeration(); + while (enumerator.hasMoreElements()) { + let string = enumerator.getNext().QueryInterface(Ci.nsIPropertyElement); + let stringName = string.key; + if (stringName in kStringsRequiringFormatting) { + strings[stringName] = function () { + // Convert "arguments" to a real array before calling into XPCOM. + return sb.formatStringFromName(stringName, + Array.slice(arguments, 0), + arguments.length); + }; + } else { + strings[stringName] = string.value; + } + } + return strings; +}); + +// DownloadPrompter + +/** + * Allows displaying prompts related to downloads. + * + * @param aParent + * The nsIDOMWindow to which prompts should be attached, or null to + * attach prompts to the most recently active window. + */ +this.DownloadPrompter = function (aParent) +{ + if (AppConstants.MOZ_B2G) { + // On B2G there is no prompter implementation. + this._prompter = null; + } else { + this._prompter = Services.ww.getNewPrompter(aParent); + } +} + +this.DownloadPrompter.prototype = { + /** + * Constants with the different type of prompts. + */ + ON_QUIT: "prompt-on-quit", + ON_OFFLINE: "prompt-on-offline", + ON_LEAVE_PRIVATE_BROWSING: "prompt-on-leave-private-browsing", + + /** + * nsIPrompt instance for displaying messages. + */ + _prompter: null, + + /** + * Displays a warning message box that informs that the specified file is + * executable, and asks whether the user wants to launch it. The user is + * given the option of disabling future instances of this warning. + * + * @param aPath + * String containing the full path to the file to be opened. + * + * @return {Promise} + * @resolves Boolean indicating whether the launch operation can continue. + * @rejects JavaScript exception. + */ + confirmLaunchExecutable: function (aPath) + { + const kPrefAlertOnEXEOpen = "browser.download.manager.alertOnEXEOpen"; + + try { + // Always launch in case we have no prompter implementation. + if (!this._prompter) { + return Promise.resolve(true); + } + + try { + if (!Services.prefs.getBoolPref(kPrefAlertOnEXEOpen)) { + return Promise.resolve(true); + } + } catch (ex) { + // If the preference does not exist, continue with the prompt. + } + + let leafName = OS.Path.basename(aPath); + + let s = DownloadUIHelper.strings; + let checkState = { value: false }; + let shouldLaunch = this._prompter.confirmCheck( + s.fileExecutableSecurityWarningTitle, + s.fileExecutableSecurityWarning(leafName, leafName), + s.fileExecutableSecurityWarningDontAsk, + checkState); + + if (shouldLaunch) { + Services.prefs.setBoolPref(kPrefAlertOnEXEOpen, !checkState.value); + } + + return Promise.resolve(shouldLaunch); + } catch (ex) { + return Promise.reject(ex); + } + }, + + /** + * Displays a warning message box that informs that there are active + * downloads, and asks whether the user wants to cancel them or not. + * + * @param aDownloadsCount + * The current downloads count. + * @param aPromptType + * The type of prompt notification depending on the observer. + * + * @return False to cancel the downloads and continue, true to abort the + * operation. + */ + confirmCancelDownloads: function DP_confirmCancelDownload(aDownloadsCount, + aPromptType) + { + // Always continue in case we have no prompter implementation, or if there + // are no active downloads. + if (!this._prompter || aDownloadsCount <= 0) { + return false; + } + + let s = DownloadUIHelper.strings; + let buttonFlags = (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_0) + + (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_1); + let okButton = aDownloadsCount > 1 ? s.cancelDownloadsOKTextMultiple(aDownloadsCount) + : s.cancelDownloadsOKText; + let title, message, cancelButton; + + switch (aPromptType) { + case this.ON_QUIT: + title = s.quitCancelDownloadsAlertTitle; + if (AppConstants.platform != "macosx") { + message = aDownloadsCount > 1 + ? s.quitCancelDownloadsAlertMsgMultiple(aDownloadsCount) + : s.quitCancelDownloadsAlertMsg; + cancelButton = s.dontQuitButtonWin; + } else { + message = aDownloadsCount > 1 + ? s.quitCancelDownloadsAlertMsgMacMultiple(aDownloadsCount) + : s.quitCancelDownloadsAlertMsgMac; + cancelButton = s.dontQuitButtonMac; + } + break; + case this.ON_OFFLINE: + title = s.offlineCancelDownloadsAlertTitle; + message = aDownloadsCount > 1 + ? s.offlineCancelDownloadsAlertMsgMultiple(aDownloadsCount) + : s.offlineCancelDownloadsAlertMsg; + cancelButton = s.dontGoOfflineButton; + break; + case this.ON_LEAVE_PRIVATE_BROWSING: + title = s.leavePrivateBrowsingCancelDownloadsAlertTitle; + message = aDownloadsCount > 1 + ? s.leavePrivateBrowsingWindowsCancelDownloadsAlertMsgMultiple2(aDownloadsCount) + : s.leavePrivateBrowsingWindowsCancelDownloadsAlertMsg2; + cancelButton = s.dontLeavePrivateBrowsingButton2; + break; + } + + let rv = this._prompter.confirmEx(title, message, buttonFlags, okButton, + cancelButton, null, null, {}); + return (rv == 1); + } +}; |