1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5"use strict";
6
7var EXPORTED_SYMBOLS = ["PromptCollection"];
8
9const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
10const { XPCOMUtils } = ChromeUtils.import(
11  "resource://gre/modules/XPCOMUtils.jsm"
12);
13
14/**
15 * Implements nsIPromptCollection
16 * @class PromptCollection
17 */
18class PromptCollection {
19  confirmRepost(browsingContext) {
20    let brandName;
21    try {
22      brandName = this.stringBundles.brand.GetStringFromName("brandShortName");
23    } catch (exception) {
24      // That's ok, we'll use a generic version of the prompt
25    }
26
27    let message;
28    let resendLabel;
29    try {
30      if (brandName) {
31        message = this.stringBundles.app.formatStringFromName(
32          "confirmRepostPrompt",
33          [brandName]
34        );
35      } else {
36        // Use a generic version of this prompt.
37        message = this.stringBundles.app.GetStringFromName(
38          "confirmRepostPrompt"
39        );
40      }
41      resendLabel = this.stringBundles.app.GetStringFromName(
42        "resendButton.label"
43      );
44    } catch (exception) {
45      Cu.reportError("Failed to get strings from appstrings.properties");
46      return false;
47    }
48
49    let contentViewer = browsingContext?.docShell?.contentViewer;
50    let modalType = contentViewer?.isTabModalPromptAllowed
51      ? Ci.nsIPromptService.MODAL_TYPE_CONTENT
52      : Ci.nsIPromptService.MODAL_TYPE_WINDOW;
53    let buttonFlags =
54      (Ci.nsIPromptService.BUTTON_TITLE_IS_STRING *
55        Ci.nsIPromptService.BUTTON_POS_0) |
56      (Ci.nsIPromptService.BUTTON_TITLE_CANCEL *
57        Ci.nsIPromptService.BUTTON_POS_1);
58    let buttonPressed = Services.prompt.confirmExBC(
59      browsingContext,
60      modalType,
61      null,
62      message,
63      buttonFlags,
64      resendLabel,
65      null,
66      null,
67      null,
68      {}
69    );
70
71    return buttonPressed === 0;
72  }
73
74  async asyncBeforeUnloadCheck(browsingContext) {
75    let title;
76    let message;
77    let leaveLabel;
78    let stayLabel;
79
80    try {
81      title = this.stringBundles.dom.GetStringFromName("OnBeforeUnloadTitle");
82      message = this.stringBundles.dom.GetStringFromName(
83        "OnBeforeUnloadMessage2"
84      );
85      leaveLabel = this.stringBundles.dom.GetStringFromName(
86        "OnBeforeUnloadLeaveButton"
87      );
88      stayLabel = this.stringBundles.dom.GetStringFromName(
89        "OnBeforeUnloadStayButton"
90      );
91    } catch (exception) {
92      Cu.reportError("Failed to get strings from dom.properties");
93      return false;
94    }
95
96    let contentViewer = browsingContext?.docShell?.contentViewer;
97
98    if (
99      (contentViewer && !contentViewer.isTabModalPromptAllowed) ||
100      !browsingContext.ancestorsAreCurrent
101    ) {
102      Cu.reportError("Can't prompt from inactive content viewer");
103      return true;
104    }
105
106    let buttonFlags =
107      Ci.nsIPromptService.BUTTON_POS_0_DEFAULT |
108      (Ci.nsIPromptService.BUTTON_TITLE_IS_STRING *
109        Ci.nsIPromptService.BUTTON_POS_0) |
110      (Ci.nsIPromptService.BUTTON_TITLE_IS_STRING *
111        Ci.nsIPromptService.BUTTON_POS_1);
112
113    let result = await Services.prompt.asyncConfirmEx(
114      browsingContext,
115      Services.prompt.MODAL_TYPE_CONTENT,
116      title,
117      message,
118      buttonFlags,
119      leaveLabel,
120      stayLabel,
121      null,
122      null,
123      false,
124      // Tell the prompt service that this is a permit unload prompt
125      // so that it can set the appropriate flag on the detail object
126      // of the events it dispatches.
127      { inPermitUnload: true }
128    );
129
130    return (
131      result.QueryInterface(Ci.nsIPropertyBag2).get("buttonNumClicked") == 0
132    );
133  }
134
135  confirmFolderUpload(browsingContext, directoryName) {
136    let title;
137    let message;
138    let acceptLabel;
139
140    try {
141      title = this.stringBundles.dom.GetStringFromName(
142        "FolderUploadPrompt.title"
143      );
144      message = this.stringBundles.dom.formatStringFromName(
145        "FolderUploadPrompt.message",
146        [directoryName]
147      );
148      acceptLabel = this.stringBundles.dom.GetStringFromName(
149        "FolderUploadPrompt.acceptButtonLabel"
150      );
151    } catch (exception) {
152      Cu.reportError("Failed to get strings from dom.properties");
153      return false;
154    }
155
156    let buttonFlags =
157      Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0 +
158      Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1 +
159      Services.prompt.BUTTON_POS_1_DEFAULT;
160
161    return (
162      Services.prompt.confirmExBC(
163        browsingContext,
164        Services.prompt.MODAL_TYPE_TAB,
165        title,
166        message,
167        buttonFlags,
168        acceptLabel,
169        null,
170        null,
171        null,
172        {}
173      ) === 0
174    );
175  }
176}
177
178const BUNDLES = {
179  dom: "chrome://global/locale/dom/dom.properties",
180  app: "chrome://global/locale/appstrings.properties",
181  brand: "chrome://branding/locale/brand.properties",
182};
183
184PromptCollection.prototype.stringBundles = {};
185
186for (const [bundleName, bundleUrl] of Object.entries(BUNDLES)) {
187  XPCOMUtils.defineLazyGetter(
188    PromptCollection.prototype.stringBundles,
189    bundleName,
190    function() {
191      let bundle = Services.strings.createBundle(bundleUrl);
192      if (!bundle) {
193        throw new Error("String bundle for dom not present!");
194      }
195      return bundle;
196    }
197  );
198}
199
200PromptCollection.prototype.QueryInterface = ChromeUtils.generateQI([
201  "nsIPromptCollection",
202]);
203