summaryrefslogtreecommitdiffstats
path: root/toolkit/components/downloads/DownloadUIHelper.sys.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/downloads/DownloadUIHelper.sys.mjs')
-rw-r--r--toolkit/components/downloads/DownloadUIHelper.sys.mjs240
1 files changed, 240 insertions, 0 deletions
diff --git a/toolkit/components/downloads/DownloadUIHelper.sys.mjs b/toolkit/components/downloads/DownloadUIHelper.sys.mjs
new file mode 100644
index 0000000000..0d1d0e0a31
--- /dev/null
+++ b/toolkit/components/downloads/DownloadUIHelper.sys.mjs
@@ -0,0 +1,240 @@
+/* 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.
+ */
+
+import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
+
+const lazy = {};
+
+// BrowserWindowTracker and PrivateBrowsingUtils are only used when opening downloaded files into a browser window
+ChromeUtils.defineESModuleGetters(lazy, {
+ BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs",
+ PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
+});
+
+ChromeUtils.defineLazyGetter(
+ lazy,
+ "l10n",
+ () => new Localization(["toolkit/downloads/downloadUI.ftl"], true)
+);
+
+/**
+ * Provides functions to handle status and messages in the user interface.
+ */
+export var 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(aParent) {
+ return new DownloadPrompter(aParent || null);
+ },
+
+ /**
+ * Open the given file as a file: URI in the active window
+ *
+ * @param nsIFile file The downloaded file
+ * @param options.chromeWindow Optional chrome window where we could open the file URI
+ * @param options.openWhere String indicating how to open the URI.
+ * One of "window", "tab", "tabshifted"
+ * @param options.isPrivate Open in private window or not
+ * @param options.browsingContextId BrowsingContext ID of the initiating document
+ * @param options.userContextId UserContextID of the initiating document
+ */
+ loadFileIn(
+ file,
+ {
+ chromeWindow: browserWin,
+ openWhere = "tab",
+ isPrivate,
+ userContextId = 0,
+ browsingContextId = 0,
+ } = {}
+ ) {
+ let fileURI = Services.io.newFileURI(file);
+ let allowPrivate =
+ isPrivate || lazy.PrivateBrowsingUtils.permanentPrivateBrowsing;
+
+ if (
+ !browserWin ||
+ browserWin.document.documentElement.getAttribute("windowtype") !==
+ "navigator:browser"
+ ) {
+ // we'll need a private window for a private download, or if we're in private-only mode
+ // but otherwise we want to open files in a non-private window
+ browserWin = lazy.BrowserWindowTracker.getTopWindow({
+ private: allowPrivate,
+ });
+ }
+ // if there is no suitable browser window, we'll need to open one and ignore any other `openWhere` value
+ // this can happen if the library dialog is the only open window
+ if (!browserWin) {
+ // There is no browser window open, so open a new one.
+ let args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
+ let strURI = Cc["@mozilla.org/supports-string;1"].createInstance(
+ Ci.nsISupportsString
+ );
+ strURI.data = fileURI.spec;
+ args.appendElement(strURI);
+ let features = "chrome,dialog=no,all";
+ if (isPrivate) {
+ features += ",private";
+ }
+ browserWin = Services.ww.openWindow(
+ null,
+ AppConstants.BROWSER_CHROME_URL,
+ null,
+ features,
+ args
+ );
+ return;
+ }
+
+ // a browser window will have the helpers from utilityOverlay.js
+ let browsingContext = browserWin?.BrowsingContext.get(browsingContextId);
+ browserWin.openTrustedLinkIn(fileURI.spec, openWhere, {
+ triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+ private: isPrivate,
+ userContextId,
+ openerBrowser: browsingContext?.top?.embedderElement,
+ });
+ },
+};
+
+/**
+ * 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.
+ */
+var DownloadPrompter = function (aParent) {
+ this._prompter = Services.ww.getNewPrompter(aParent);
+};
+
+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.
+ *
+ * @param path
+ * String containing the full path to the file to be opened.
+ *
+ * @resolves Boolean indicating whether the launch operation can continue.
+ */
+ async confirmLaunchExecutable(path) {
+ const kPrefSkipConfirm = "browser.download.skipConfirmLaunchExecutable";
+
+ // Always launch in case we have no prompter implementation.
+ if (!this._prompter) {
+ return true;
+ }
+
+ try {
+ if (Services.prefs.getBoolPref(kPrefSkipConfirm)) {
+ return true;
+ }
+ } catch (ex) {
+ // If the preference does not exist, continue with the prompt.
+ }
+
+ const title = lazy.l10n.formatValueSync(
+ "download-ui-file-executable-security-warning-title"
+ );
+ const message = lazy.l10n.formatValueSync(
+ "download-ui-file-executable-security-warning",
+ { executable: PathUtils.filename(path) }
+ );
+ return this._prompter.confirm(title, message);
+ },
+
+ /**
+ * 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 message, cancelButton;
+
+ switch (aPromptType) {
+ case this.ON_QUIT:
+ message =
+ AppConstants.platform == "macosx"
+ ? "download-ui-confirm-quit-cancel-downloads-mac"
+ : "download-ui-confirm-quit-cancel-downloads";
+ cancelButton = "download-ui-dont-quit-button";
+ break;
+
+ case this.ON_OFFLINE:
+ message = "download-ui-confirm-offline-cancel-downloads";
+ cancelButton = "download-ui-dont-go-offline-button";
+ break;
+
+ case this.ON_LEAVE_PRIVATE_BROWSING:
+ message =
+ "download-ui-confirm-leave-private-browsing-windows-cancel-downloads";
+ cancelButton = "download-ui-dont-leave-private-browsing-button";
+ break;
+ }
+
+ const buttonFlags =
+ Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_0 +
+ Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_1;
+
+ let rv = this._prompter.confirmEx(
+ lazy.l10n.formatValueSync("download-ui-confirm-title"),
+ lazy.l10n.formatValueSync(message, { downloadsCount: aDownloadsCount }),
+ buttonFlags,
+ lazy.l10n.formatValueSync("download-ui-cancel-downloads-ok", {
+ downloadsCount: aDownloadsCount,
+ }),
+ lazy.l10n.formatValueSync(cancelButton),
+ null,
+ null,
+ {}
+ );
+ return rv == 1;
+ },
+};