1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/jsdownloads/src/DownloadUIHelper.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,245 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/** 1.11 + * Provides functions to handle status and messages in the user interface. 1.12 + */ 1.13 + 1.14 +"use strict"; 1.15 + 1.16 +this.EXPORTED_SYMBOLS = [ 1.17 + "DownloadUIHelper", 1.18 +]; 1.19 + 1.20 +//////////////////////////////////////////////////////////////////////////////// 1.21 +//// Globals 1.22 + 1.23 +const Cc = Components.classes; 1.24 +const Ci = Components.interfaces; 1.25 +const Cu = Components.utils; 1.26 +const Cr = Components.results; 1.27 + 1.28 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.29 + 1.30 +XPCOMUtils.defineLazyModuleGetter(this, "OS", 1.31 + "resource://gre/modules/osfile.jsm"); 1.32 +XPCOMUtils.defineLazyModuleGetter(this, "Promise", 1.33 + "resource://gre/modules/Promise.jsm"); 1.34 +XPCOMUtils.defineLazyModuleGetter(this, "Services", 1.35 + "resource://gre/modules/Services.jsm"); 1.36 + 1.37 +const kStringBundleUrl = 1.38 + "chrome://mozapps/locale/downloads/downloads.properties"; 1.39 + 1.40 +const kStringsRequiringFormatting = { 1.41 + fileExecutableSecurityWarning: true, 1.42 + cancelDownloadsOKTextMultiple: true, 1.43 + quitCancelDownloadsAlertMsgMultiple: true, 1.44 + quitCancelDownloadsAlertMsgMacMultiple: true, 1.45 + offlineCancelDownloadsAlertMsgMultiple: true, 1.46 + leavePrivateBrowsingWindowsCancelDownloadsAlertMsgMultiple: true 1.47 +}; 1.48 + 1.49 +//////////////////////////////////////////////////////////////////////////////// 1.50 +//// DownloadUIHelper 1.51 + 1.52 +/** 1.53 + * Provides functions to handle status and messages in the user interface. 1.54 + */ 1.55 +this.DownloadUIHelper = { 1.56 + /** 1.57 + * Returns an object that can be used to display prompts related to downloads. 1.58 + * 1.59 + * The prompts may be either anchored to a specified window, or anchored to 1.60 + * the most recently active window, for example if the prompt is displayed in 1.61 + * response to global notifications that are not associated with any window. 1.62 + * 1.63 + * @param aParent 1.64 + * If specified, should reference the nsIDOMWindow to which the prompts 1.65 + * should be attached. If omitted, the prompts will be attached to the 1.66 + * most recently active window. 1.67 + * 1.68 + * @return A DownloadPrompter object. 1.69 + */ 1.70 + getPrompter: function (aParent) 1.71 + { 1.72 + return new DownloadPrompter(aParent || null); 1.73 + }, 1.74 +}; 1.75 + 1.76 +/** 1.77 + * Returns an object whose keys are the string names from the downloads string 1.78 + * bundle, and whose values are either the translated strings or functions 1.79 + * returning formatted strings. 1.80 + */ 1.81 +XPCOMUtils.defineLazyGetter(DownloadUIHelper, "strings", function () { 1.82 + let strings = {}; 1.83 + let sb = Services.strings.createBundle(kStringBundleUrl); 1.84 + let enumerator = sb.getSimpleEnumeration(); 1.85 + while (enumerator.hasMoreElements()) { 1.86 + let string = enumerator.getNext().QueryInterface(Ci.nsIPropertyElement); 1.87 + let stringName = string.key; 1.88 + if (stringName in kStringsRequiringFormatting) { 1.89 + strings[stringName] = function () { 1.90 + // Convert "arguments" to a real array before calling into XPCOM. 1.91 + return sb.formatStringFromName(stringName, 1.92 + Array.slice(arguments, 0), 1.93 + arguments.length); 1.94 + }; 1.95 + } else { 1.96 + strings[stringName] = string.value; 1.97 + } 1.98 + } 1.99 + return strings; 1.100 +}); 1.101 + 1.102 +//////////////////////////////////////////////////////////////////////////////// 1.103 +//// DownloadPrompter 1.104 + 1.105 +/** 1.106 + * Allows displaying prompts related to downloads. 1.107 + * 1.108 + * @param aParent 1.109 + * The nsIDOMWindow to which prompts should be attached, or null to 1.110 + * attach prompts to the most recently active window. 1.111 + */ 1.112 +this.DownloadPrompter = function (aParent) 1.113 +{ 1.114 +#ifdef MOZ_B2G 1.115 + // On B2G there is no prompter implementation. 1.116 + this._prompter = null; 1.117 +#else 1.118 + this._prompter = Services.ww.getNewPrompter(aParent); 1.119 +#endif 1.120 +} 1.121 + 1.122 +this.DownloadPrompter.prototype = { 1.123 + /** 1.124 + * Constants with the different type of prompts. 1.125 + */ 1.126 + ON_QUIT: "prompt-on-quit", 1.127 + ON_OFFLINE: "prompt-on-offline", 1.128 + ON_LEAVE_PRIVATE_BROWSING: "prompt-on-leave-private-browsing", 1.129 + 1.130 + /** 1.131 + * nsIPrompt instance for displaying messages. 1.132 + */ 1.133 + _prompter: null, 1.134 + 1.135 + /** 1.136 + * Displays a warning message box that informs that the specified file is 1.137 + * executable, and asks whether the user wants to launch it. The user is 1.138 + * given the option of disabling future instances of this warning. 1.139 + * 1.140 + * @param aPath 1.141 + * String containing the full path to the file to be opened. 1.142 + * 1.143 + * @return {Promise} 1.144 + * @resolves Boolean indicating whether the launch operation can continue. 1.145 + * @rejects JavaScript exception. 1.146 + */ 1.147 + confirmLaunchExecutable: function (aPath) 1.148 + { 1.149 + const kPrefAlertOnEXEOpen = "browser.download.manager.alertOnEXEOpen"; 1.150 + 1.151 + try { 1.152 + // Always launch in case we have no prompter implementation. 1.153 + if (!this._prompter) { 1.154 + return Promise.resolve(true); 1.155 + } 1.156 + 1.157 + try { 1.158 + if (!Services.prefs.getBoolPref(kPrefAlertOnEXEOpen)) { 1.159 + return Promise.resolve(true); 1.160 + } 1.161 + } catch (ex) { 1.162 + // If the preference does not exist, continue with the prompt. 1.163 + } 1.164 + 1.165 + let leafName = OS.Path.basename(aPath); 1.166 + 1.167 + let s = DownloadUIHelper.strings; 1.168 + let checkState = { value: false }; 1.169 + let shouldLaunch = this._prompter.confirmCheck( 1.170 + s.fileExecutableSecurityWarningTitle, 1.171 + s.fileExecutableSecurityWarning(leafName, leafName), 1.172 + s.fileExecutableSecurityWarningDontAsk, 1.173 + checkState); 1.174 + 1.175 + if (shouldLaunch) { 1.176 + Services.prefs.setBoolPref(kPrefAlertOnEXEOpen, !checkState.value); 1.177 + } 1.178 + 1.179 + return Promise.resolve(shouldLaunch); 1.180 + } catch (ex) { 1.181 + return Promise.reject(ex); 1.182 + } 1.183 + }, 1.184 + 1.185 + /** 1.186 + * Displays a warning message box that informs that there are active 1.187 + * downloads, and asks whether the user wants to cancel them or not. 1.188 + * 1.189 + * @param aDownloadsCount 1.190 + * The current downloads count. 1.191 + * @param aPromptType 1.192 + * The type of prompt notification depending on the observer. 1.193 + * 1.194 + * @return False to cancel the downloads and continue, true to abort the 1.195 + * operation. 1.196 + */ 1.197 + confirmCancelDownloads: function DP_confirmCancelDownload(aDownloadsCount, 1.198 + aPromptType) 1.199 + { 1.200 + // Always continue in case we have no prompter implementation, or if there 1.201 + // are no active downloads. 1.202 + if (!this._prompter || aDownloadsCount <= 0) { 1.203 + return false; 1.204 + } 1.205 + 1.206 + let s = DownloadUIHelper.strings; 1.207 + let buttonFlags = (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_0) + 1.208 + (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_1); 1.209 + let okButton = aDownloadsCount > 1 ? s.cancelDownloadsOKTextMultiple(aDownloadsCount) 1.210 + : s.cancelDownloadsOKText; 1.211 + let title, message, cancelButton; 1.212 + 1.213 + switch (aPromptType) { 1.214 + case this.ON_QUIT: 1.215 + title = s.quitCancelDownloadsAlertTitle; 1.216 +#ifndef XP_MACOSX 1.217 + message = aDownloadsCount > 1 1.218 + ? s.quitCancelDownloadsAlertMsgMultiple(aDownloadsCount) 1.219 + : s.quitCancelDownloadsAlertMsg; 1.220 + cancelButton = s.dontQuitButtonWin; 1.221 +#else 1.222 + message = aDownloadsCount > 1 1.223 + ? s.quitCancelDownloadsAlertMsgMacMultiple(aDownloadsCount) 1.224 + : s.quitCancelDownloadsAlertMsgMac; 1.225 + cancelButton = s.dontQuitButtonMac; 1.226 +#endif 1.227 + break; 1.228 + case this.ON_OFFLINE: 1.229 + title = s.offlineCancelDownloadsAlertTitle; 1.230 + message = aDownloadsCount > 1 1.231 + ? s.offlineCancelDownloadsAlertMsgMultiple(aDownloadsCount) 1.232 + : s.offlineCancelDownloadsAlertMsg; 1.233 + cancelButton = s.dontGoOfflineButton; 1.234 + break; 1.235 + case this.ON_LEAVE_PRIVATE_BROWSING: 1.236 + title = s.leavePrivateBrowsingCancelDownloadsAlertTitle; 1.237 + message = aDownloadsCount > 1 1.238 + ? s.leavePrivateBrowsingWindowsCancelDownloadsAlertMsgMultiple(aDownloadsCount) 1.239 + : s.leavePrivateBrowsingWindowsCancelDownloadsAlertMsg; 1.240 + cancelButton = s.dontLeavePrivateBrowsingButton; 1.241 + break; 1.242 + } 1.243 + 1.244 + let rv = this._prompter.confirmEx(title, message, buttonFlags, okButton, 1.245 + cancelButton, null, null, {}); 1.246 + return (rv == 1); 1.247 + } 1.248 +};