summaryrefslogtreecommitdiffstats
path: root/toolkit/components/prompts/src/nsPrompter.js
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /toolkit/components/prompts/src/nsPrompter.js
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'toolkit/components/prompts/src/nsPrompter.js')
-rw-r--r--toolkit/components/prompts/src/nsPrompter.js958
1 files changed, 958 insertions, 0 deletions
diff --git a/toolkit/components/prompts/src/nsPrompter.js b/toolkit/components/prompts/src/nsPrompter.js
new file mode 100644
index 000000000..26efe28cc
--- /dev/null
+++ b/toolkit/components/prompts/src/nsPrompter.js
@@ -0,0 +1,958 @@
+/* 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/. */
+
+"use strict";
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cr = Components.results;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/SharedPromptUtils.jsm");
+
+function Prompter() {
+ // Note that EmbedPrompter clones this implementation.
+}
+
+Prompter.prototype = {
+ classID : Components.ID("{1c978d25-b37f-43a8-a2d6-0c7a239ead87}"),
+ QueryInterface : XPCOMUtils.generateQI([Ci.nsIPromptFactory, Ci.nsIPromptService, Ci.nsIPromptService2]),
+
+
+ /* ---------- private members ---------- */
+
+ pickPrompter : function (domWin) {
+ return new ModalPrompter(domWin);
+ },
+
+
+ /* ---------- nsIPromptFactory ---------- */
+
+
+ getPrompt : function (domWin, iid) {
+ // This is still kind of dumb; the C++ code delegated to login manager
+ // here, which in turn calls back into us via nsIPromptService2.
+ if (iid.equals(Ci.nsIAuthPrompt2) || iid.equals(Ci.nsIAuthPrompt)) {
+ try {
+ let pwmgr = Cc["@mozilla.org/passwordmanager/authpromptfactory;1"].
+ getService(Ci.nsIPromptFactory);
+ return pwmgr.getPrompt(domWin, iid);
+ } catch (e) {
+ Cu.reportError("nsPrompter: Delegation to password manager failed: " + e);
+ }
+ }
+
+ let p = new ModalPrompter(domWin);
+ p.QueryInterface(iid);
+ return p;
+ },
+
+
+ /* ---------- nsIPromptService ---------- */
+
+
+ alert : function (domWin, title, text) {
+ let p = this.pickPrompter(domWin);
+ p.alert(title, text);
+ },
+
+ alertCheck : function (domWin, title, text, checkLabel, checkValue) {
+ let p = this.pickPrompter(domWin);
+ p.alertCheck(title, text, checkLabel, checkValue);
+ },
+
+ confirm : function (domWin, title, text) {
+ let p = this.pickPrompter(domWin);
+ return p.confirm(title, text);
+ },
+
+ confirmCheck : function (domWin, title, text, checkLabel, checkValue) {
+ let p = this.pickPrompter(domWin);
+ return p.confirmCheck(title, text, checkLabel, checkValue);
+ },
+
+ confirmEx : function (domWin, title, text, flags, button0, button1, button2, checkLabel, checkValue) {
+ let p = this.pickPrompter(domWin);
+ return p.confirmEx(title, text, flags, button0, button1, button2, checkLabel, checkValue);
+ },
+
+ prompt : function (domWin, title, text, value, checkLabel, checkValue) {
+ let p = this.pickPrompter(domWin);
+ return p.nsIPrompt_prompt(title, text, value, checkLabel, checkValue);
+ },
+
+ promptUsernameAndPassword : function (domWin, title, text, user, pass, checkLabel, checkValue) {
+ let p = this.pickPrompter(domWin);
+ return p.nsIPrompt_promptUsernameAndPassword(title, text, user, pass, checkLabel, checkValue);
+ },
+
+ promptPassword : function (domWin, title, text, pass, checkLabel, checkValue) {
+ let p = this.pickPrompter(domWin);
+ return p.nsIPrompt_promptPassword(title, text, pass, checkLabel, checkValue);
+ },
+
+ select : function (domWin, title, text, count, list, selected) {
+ let p = this.pickPrompter(domWin);
+ return p.select(title, text, count, list, selected);
+ },
+
+
+ /* ---------- nsIPromptService2 ---------- */
+
+
+ promptAuth : function (domWin, channel, level, authInfo, checkLabel, checkValue) {
+ let p = this.pickPrompter(domWin);
+ return p.promptAuth(channel, level, authInfo, checkLabel, checkValue);
+ },
+
+ asyncPromptAuth : function (domWin, channel, callback, context, level, authInfo, checkLabel, checkValue) {
+ let p = this.pickPrompter(domWin);
+ return p.asyncPromptAuth(channel, callback, context, level, authInfo, checkLabel, checkValue);
+ },
+
+};
+
+
+// Common utils not specific to a particular prompter style.
+var PromptUtilsTemp = {
+ __proto__ : PromptUtils,
+
+ getLocalizedString : function (key, formatArgs) {
+ if (formatArgs)
+ return this.strBundle.formatStringFromName(key, formatArgs, formatArgs.length);
+ return this.strBundle.GetStringFromName(key);
+ },
+
+ confirmExHelper : function (flags, button0, button1, button2) {
+ const BUTTON_DEFAULT_MASK = 0x03000000;
+ let defaultButtonNum = (flags & BUTTON_DEFAULT_MASK) >> 24;
+ let isDelayEnabled = (flags & Ci.nsIPrompt.BUTTON_DELAY_ENABLE);
+
+ // Flags can be used to select a specific pre-defined button label or
+ // a caller-supplied string (button0/button1/button2). If no flags are
+ // set for a button, then the button won't be shown.
+ let argText = [button0, button1, button2];
+ let buttonLabels = [null, null, null];
+ for (let i = 0; i < 3; i++) {
+ let buttonLabel;
+ switch (flags & 0xff) {
+ case Ci.nsIPrompt.BUTTON_TITLE_OK:
+ buttonLabel = PromptUtils.getLocalizedString("OK");
+ break;
+ case Ci.nsIPrompt.BUTTON_TITLE_CANCEL:
+ buttonLabel = PromptUtils.getLocalizedString("Cancel");
+ break;
+ case Ci.nsIPrompt.BUTTON_TITLE_YES:
+ buttonLabel = PromptUtils.getLocalizedString("Yes");
+ break;
+ case Ci.nsIPrompt.BUTTON_TITLE_NO:
+ buttonLabel = PromptUtils.getLocalizedString("No");
+ break;
+ case Ci.nsIPrompt.BUTTON_TITLE_SAVE:
+ buttonLabel = PromptUtils.getLocalizedString("Save");
+ break;
+ case Ci.nsIPrompt.BUTTON_TITLE_DONT_SAVE:
+ buttonLabel = PromptUtils.getLocalizedString("DontSave");
+ break;
+ case Ci.nsIPrompt.BUTTON_TITLE_REVERT:
+ buttonLabel = PromptUtils.getLocalizedString("Revert");
+ break;
+ case Ci.nsIPrompt.BUTTON_TITLE_IS_STRING:
+ buttonLabel = argText[i];
+ break;
+ }
+ if (buttonLabel)
+ buttonLabels[i] = buttonLabel;
+ flags >>= 8;
+ }
+
+ return [buttonLabels[0], buttonLabels[1], buttonLabels[2], defaultButtonNum, isDelayEnabled];
+ },
+
+ getAuthInfo : function (authInfo) {
+ let username, password;
+
+ let flags = authInfo.flags;
+ if (flags & Ci.nsIAuthInformation.NEED_DOMAIN && authInfo.domain)
+ username = authInfo.domain + "\\" + authInfo.username;
+ else
+ username = authInfo.username;
+
+ password = authInfo.password;
+
+ return [username, password];
+ },
+
+ setAuthInfo : function (authInfo, username, password) {
+ let flags = authInfo.flags;
+ if (flags & Ci.nsIAuthInformation.NEED_DOMAIN) {
+ // Domain is separated from username by a backslash
+ let idx = username.indexOf("\\");
+ if (idx == -1) {
+ authInfo.username = username;
+ } else {
+ authInfo.domain = username.substring(0, idx);
+ authInfo.username = username.substring(idx+1);
+ }
+ } else {
+ authInfo.username = username;
+ }
+ authInfo.password = password;
+ },
+
+ /**
+ * Strip out things like userPass and path for display.
+ */
+ getFormattedHostname : function (uri) {
+ return uri.scheme + "://" + uri.hostPort;
+ },
+
+ // Copied from login manager
+ getAuthTarget : function (aChannel, aAuthInfo) {
+ let hostname, realm;
+
+ // If our proxy is demanding authentication, don't use the
+ // channel's actual destination.
+ if (aAuthInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) {
+ if (!(aChannel instanceof Ci.nsIProxiedChannel))
+ throw "proxy auth needs nsIProxiedChannel";
+
+ let info = aChannel.proxyInfo;
+ if (!info)
+ throw "proxy auth needs nsIProxyInfo";
+
+ // Proxies don't have a scheme, but we'll use "moz-proxy://"
+ // so that it's more obvious what the login is for.
+ let idnService = Cc["@mozilla.org/network/idn-service;1"].
+ getService(Ci.nsIIDNService);
+ hostname = "moz-proxy://" +
+ idnService.convertUTF8toACE(info.host) +
+ ":" + info.port;
+ realm = aAuthInfo.realm;
+ if (!realm)
+ realm = hostname;
+
+ return [hostname, realm];
+ }
+
+ hostname = this.getFormattedHostname(aChannel.URI);
+
+ // If a HTTP WWW-Authenticate header specified a realm, that value
+ // will be available here. If it wasn't set or wasn't HTTP, we'll use
+ // the formatted hostname instead.
+ realm = aAuthInfo.realm;
+ if (!realm)
+ realm = hostname;
+
+ return [hostname, realm];
+ },
+
+
+ makeAuthMessage : function (channel, authInfo) {
+ let isProxy = (authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY);
+ let isPassOnly = (authInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD);
+ let isCrossOrig = (authInfo.flags &
+ Ci.nsIAuthInformation.CROSS_ORIGIN_SUB_RESOURCE);
+
+ let username = authInfo.username;
+ let [displayHost, realm] = this.getAuthTarget(channel, authInfo);
+
+ // Suppress "the site says: $realm" when we synthesized a missing realm.
+ if (!authInfo.realm && !isProxy)
+ realm = "";
+
+ // Trim obnoxiously long realms.
+ if (realm.length > 150) {
+ realm = realm.substring(0, 150);
+ // Append "..." (or localized equivalent).
+ realm += this.ellipsis;
+ }
+
+ let text;
+ if (isProxy) {
+ text = PromptUtils.getLocalizedString("EnterLoginForProxy3", [realm, displayHost]);
+ } else if (isPassOnly) {
+ text = PromptUtils.getLocalizedString("EnterPasswordFor", [username, displayHost]);
+ } else if (isCrossOrig) {
+ text = PromptUtils.getLocalizedString("EnterUserPasswordForCrossOrigin2", [displayHost]);
+ } else if (!realm) {
+ text = PromptUtils.getLocalizedString("EnterUserPasswordFor2", [displayHost]);
+ } else {
+ text = PromptUtils.getLocalizedString("EnterLoginForRealm3", [realm, displayHost]);
+ }
+
+ return text;
+ },
+
+ getTabModalPrompt : function (domWin) {
+ var promptBox = null;
+
+ try {
+ // Get the topmost window, in case we're in a frame.
+ var promptWin = domWin.top;
+
+ // Get the chrome window for the content window we're using.
+ // (Unwrap because we need a non-IDL property below.)
+ var chromeWin = promptWin.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShell)
+ .chromeEventHandler.ownerDocument
+ .defaultView.wrappedJSObject;
+
+ if (chromeWin.getTabModalPromptBox)
+ promptBox = chromeWin.getTabModalPromptBox(promptWin);
+ } catch (e) {
+ // If any errors happen, just assume no tabmodal prompter.
+ }
+
+ return promptBox;
+ },
+};
+
+PromptUtils = PromptUtilsTemp;
+
+XPCOMUtils.defineLazyGetter(PromptUtils, "strBundle", function () {
+ let bunService = Cc["@mozilla.org/intl/stringbundle;1"].
+ getService(Ci.nsIStringBundleService);
+ let bundle = bunService.createBundle("chrome://global/locale/commonDialogs.properties");
+ if (!bundle)
+ throw "String bundle for Prompter not present!";
+ return bundle;
+});
+
+XPCOMUtils.defineLazyGetter(PromptUtils, "ellipsis", function () {
+ let ellipsis = "\u2026";
+ try {
+ ellipsis = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
+ } catch (e) { }
+ return ellipsis;
+});
+
+
+
+function openModalWindow(domWin, uri, args) {
+ // There's an implied contract that says modal prompts should still work
+ // when no "parent" window is passed for the dialog (eg, the "Master
+ // Password" dialog does this). These prompts must be shown even if there
+ // are *no* visible windows at all.
+ // There's also a requirement for prompts to be blocked if a window is
+ // passed and that window is hidden (eg, auth prompts are supressed if the
+ // passed window is the hidden window).
+ // See bug 875157 comment 30 for more...
+ if (domWin) {
+ // a domWin was passed, so we can apply the check for it being hidden.
+ let winUtils = domWin.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+
+ if (winUtils && !winUtils.isParentWindowMainWidgetVisible) {
+ throw Components.Exception("Cannot call openModalWindow on a hidden window",
+ Cr.NS_ERROR_NOT_AVAILABLE);
+ }
+ } else {
+ // We try and find a window to use as the parent, but don't consider
+ // if that is visible before showing the prompt.
+ domWin = Services.ww.activeWindow;
+ // domWin may still be null here if there are _no_ windows open.
+ }
+ // Note that we don't need to fire DOMWillOpenModalDialog and
+ // DOMModalDialogClosed events here, wwatcher's OpenWindowInternal
+ // will do that. Similarly for enterModalState / leaveModalState.
+
+ Services.ww.openWindow(domWin, uri, "_blank", "centerscreen,chrome,modal,titlebar", args);
+}
+
+function openTabPrompt(domWin, tabPrompt, args) {
+ let docShell = domWin.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDocShell);
+ let inPermitUnload = docShell.contentViewer && docShell.contentViewer.inPermitUnload;
+ let eventDetail = Cu.cloneInto({tabPrompt: true, inPermitUnload}, domWin);
+ PromptUtils.fireDialogEvent(domWin, "DOMWillOpenModalDialog", null, eventDetail);
+
+ let winUtils = domWin.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ winUtils.enterModalState();
+
+ let frameMM = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIContentFrameMessageManager);
+ frameMM.QueryInterface(Ci.nsIDOMEventTarget);
+
+ // We provide a callback so the prompt can close itself. We don't want to
+ // wait for this event loop to return... Otherwise the presence of other
+ // prompts on the call stack would in this dialog appearing unresponsive
+ // until the other prompts had been closed.
+ let callbackInvoked = false;
+ let newPrompt;
+ function onPromptClose(forceCleanup) {
+ if (!newPrompt && !forceCleanup)
+ return;
+ callbackInvoked = true;
+ if (newPrompt)
+ tabPrompt.removePrompt(newPrompt);
+
+ frameMM.removeEventListener("pagehide", pagehide, true);
+
+ winUtils.leaveModalState();
+
+ PromptUtils.fireDialogEvent(domWin, "DOMModalDialogClosed");
+ }
+
+ frameMM.addEventListener("pagehide", pagehide, true);
+ function pagehide(e) {
+ // Check whether the event relates to our window or its ancestors
+ let window = domWin;
+ let eventWindow = e.target.defaultView;
+ while (window != eventWindow && window.parent != window) {
+ window = window.parent;
+ }
+ if (window != eventWindow) {
+ return;
+ }
+ frameMM.removeEventListener("pagehide", pagehide, true);
+
+ if (newPrompt) {
+ newPrompt.abortPrompt();
+ }
+ }
+
+ try {
+ let topPrincipal = domWin.top.document.nodePrincipal;
+ let promptPrincipal = domWin.document.nodePrincipal;
+ args.showAlertOrigin = topPrincipal.equals(promptPrincipal);
+ args.promptActive = true;
+
+ newPrompt = tabPrompt.appendPrompt(args, onPromptClose);
+
+ // TODO since we don't actually open a window, need to check if
+ // there's other stuff in nsWindowWatcher::OpenWindowInternal
+ // that we might need to do here as well.
+
+ let thread = Services.tm.currentThread;
+ while (args.promptActive)
+ thread.processNextEvent(true);
+ delete args.promptActive;
+
+ if (args.promptAborted)
+ throw Components.Exception("prompt aborted by user", Cr.NS_ERROR_NOT_AVAILABLE);
+ } finally {
+ // If the prompt unexpectedly failed to invoke the callback, do so here.
+ if (!callbackInvoked)
+ onPromptClose(true);
+ }
+}
+
+function openRemotePrompt(domWin, args, tabPrompt) {
+ let docShell = domWin.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDocShell);
+ let messageManager = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsITabChild)
+ .messageManager;
+
+ let inPermitUnload = docShell.contentViewer && docShell.contentViewer.inPermitUnload;
+ let eventDetail = Cu.cloneInto({tabPrompt, inPermitUnload}, domWin);
+ PromptUtils.fireDialogEvent(domWin, "DOMWillOpenModalDialog", null, eventDetail);
+
+ let winUtils = domWin.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ winUtils.enterModalState();
+ let closed = false;
+
+ let frameMM = docShell.getInterface(Ci.nsIContentFrameMessageManager);
+ frameMM.QueryInterface(Ci.nsIDOMEventTarget);
+
+ // It should be hard or impossible to cause a window to create multiple
+ // prompts, but just in case, give our prompt an ID.
+ let id = "id" + Cc["@mozilla.org/uuid-generator;1"]
+ .getService(Ci.nsIUUIDGenerator).generateUUID().toString();
+
+ messageManager.addMessageListener("Prompt:Close", function listener(message) {
+ if (message.data._remoteId !== id) {
+ return;
+ }
+
+ messageManager.removeMessageListener("Prompt:Close", listener);
+ frameMM.removeEventListener("pagehide", pagehide, true);
+
+ winUtils.leaveModalState();
+ PromptUtils.fireDialogEvent(domWin, "DOMModalDialogClosed");
+
+ // Copy the response from the closed prompt into our args, it will be
+ // read by our caller.
+ if (message.data) {
+ for (let key in message.data) {
+ args[key] = message.data[key];
+ }
+ }
+
+ // Exit our nested event loop when we unwind.
+ closed = true;
+ });
+
+ frameMM.addEventListener("pagehide", pagehide, true);
+ function pagehide(e) {
+ // Check whether the event relates to our window or its ancestors
+ let window = domWin;
+ let eventWindow = e.target.defaultView;
+ while (window != eventWindow && window.parent != window) {
+ window = window.parent;
+ }
+ if (window != eventWindow) {
+ return;
+ }
+ frameMM.removeEventListener("pagehide", pagehide, true);
+ messageManager.sendAsyncMessage("Prompt:ForceClose", { _remoteId: id });
+ }
+
+ let topPrincipal = domWin.top.document.nodePrincipal;
+ let promptPrincipal = domWin.document.nodePrincipal;
+ args.promptPrincipal = promptPrincipal;
+ args.showAlertOrigin = topPrincipal.equals(promptPrincipal);
+ args.inPermitUnload = inPermitUnload;
+
+ args._remoteId = id;
+
+ messageManager.sendAsyncMessage("Prompt:Open", args, {});
+
+ let thread = Services.tm.currentThread;
+ while (!closed) {
+ thread.processNextEvent(true);
+ }
+}
+
+function ModalPrompter(domWin) {
+ this.domWin = domWin;
+}
+ModalPrompter.prototype = {
+ domWin : null,
+ /*
+ * Default to not using a tab-modal prompt, unless the caller opts in by
+ * QIing to nsIWritablePropertyBag and setting the value of this property
+ * to true.
+ */
+ allowTabModal : false,
+
+ QueryInterface : XPCOMUtils.generateQI([Ci.nsIPrompt, Ci.nsIAuthPrompt,
+ Ci.nsIAuthPrompt2,
+ Ci.nsIWritablePropertyBag2]),
+
+
+ /* ---------- internal methods ---------- */
+
+
+ openPrompt : function (args) {
+ // Check pref, if false/missing do not ever allow tab-modal prompts.
+ const prefName = "prompts.tab_modal.enabled";
+ let prefValue = false;
+ if (Services.prefs.getPrefType(prefName) == Services.prefs.PREF_BOOL)
+ prefValue = Services.prefs.getBoolPref(prefName);
+
+ let allowTabModal = this.allowTabModal && prefValue;
+
+ if (allowTabModal && this.domWin) {
+ if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
+ openRemotePrompt(this.domWin, args, true);
+ return;
+ }
+
+ let tabPrompt = PromptUtils.getTabModalPrompt(this.domWin);
+ if (tabPrompt) {
+ openTabPrompt(this.domWin, tabPrompt, args);
+ return;
+ }
+ }
+
+ // If we can't do a tab modal prompt, fallback to using a window-modal dialog.
+ const COMMON_DIALOG = "chrome://global/content/commonDialog.xul";
+ const SELECT_DIALOG = "chrome://global/content/selectDialog.xul";
+
+ let uri = (args.promptType == "select") ? SELECT_DIALOG : COMMON_DIALOG;
+
+ if (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) {
+ args.uri = uri;
+ openRemotePrompt(this.domWin, args);
+ return;
+ }
+
+ let propBag = PromptUtils.objectToPropBag(args);
+ openModalWindow(this.domWin, uri, propBag);
+ PromptUtils.propBagToObject(propBag, args);
+ },
+
+
+
+ /*
+ * ---------- interface disambiguation ----------
+ *
+ * nsIPrompt and nsIAuthPrompt share 3 method names with slightly
+ * different arguments. All but prompt() have the same number of
+ * arguments, so look at the arg types to figure out how we're being
+ * called. :-(
+ */
+ prompt : function() {
+ // also, the nsIPrompt flavor has 5 args instead of 6.
+ if (typeof arguments[2] == "object")
+ return this.nsIPrompt_prompt.apply(this, arguments);
+ return this.nsIAuthPrompt_prompt.apply(this, arguments);
+ },
+
+ promptUsernameAndPassword : function() {
+ // Both have 6 args, so use types.
+ if (typeof arguments[2] == "object")
+ return this.nsIPrompt_promptUsernameAndPassword.apply(this, arguments);
+ return this.nsIAuthPrompt_promptUsernameAndPassword.apply(this, arguments);
+ },
+
+ promptPassword : function() {
+ // Both have 5 args, so use types.
+ if (typeof arguments[2] == "object")
+ return this.nsIPrompt_promptPassword.apply(this, arguments);
+ return this.nsIAuthPrompt_promptPassword.apply(this, arguments);
+ },
+
+
+ /* ---------- nsIPrompt ---------- */
+
+
+ alert : function (title, text) {
+ if (!title)
+ title = PromptUtils.getLocalizedString("Alert");
+
+ let args = {
+ promptType: "alert",
+ title: title,
+ text: text,
+ };
+
+ this.openPrompt(args);
+ },
+
+ alertCheck : function (title, text, checkLabel, checkValue) {
+ if (!title)
+ title = PromptUtils.getLocalizedString("Alert");
+
+ let args = {
+ promptType: "alertCheck",
+ title: title,
+ text: text,
+ checkLabel: checkLabel,
+ checked: checkValue.value,
+ };
+
+ this.openPrompt(args);
+
+ // Checkbox state always returned, even if cancel clicked.
+ checkValue.value = args.checked;
+ },
+
+ confirm : function (title, text) {
+ if (!title)
+ title = PromptUtils.getLocalizedString("Confirm");
+
+ let args = {
+ promptType: "confirm",
+ title: title,
+ text: text,
+ ok: false,
+ };
+
+ this.openPrompt(args);
+
+ // Did user click Ok or Cancel?
+ return args.ok;
+ },
+
+ confirmCheck : function (title, text, checkLabel, checkValue) {
+ if (!title)
+ title = PromptUtils.getLocalizedString("ConfirmCheck");
+
+ let args = {
+ promptType: "confirmCheck",
+ title: title,
+ text: text,
+ checkLabel: checkLabel,
+ checked: checkValue.value,
+ ok: false,
+ };
+
+ this.openPrompt(args);
+
+ // Checkbox state always returned, even if cancel clicked.
+ checkValue.value = args.checked;
+
+ // Did user click Ok or Cancel?
+ return args.ok;
+ },
+
+ confirmEx : function (title, text, flags, button0, button1, button2,
+ checkLabel, checkValue) {
+
+ if (!title)
+ title = PromptUtils.getLocalizedString("Confirm");
+
+ let args = {
+ promptType: "confirmEx",
+ title: title,
+ text: text,
+ checkLabel: checkLabel,
+ checked: checkValue.value,
+ ok: false,
+ buttonNumClicked: 1,
+ };
+
+ let [label0, label1, label2, defaultButtonNum, isDelayEnabled] =
+ PromptUtils.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;
+ }
+ }
+ }
+
+ this.openPrompt(args);
+
+ // Checkbox state always returned, even if cancel clicked.
+ checkValue.value = args.checked;
+
+ // Get the number of the button the user clicked.
+ return args.buttonNumClicked;
+ },
+
+ nsIPrompt_prompt : function (title, text, value, checkLabel, checkValue) {
+ if (!title)
+ title = PromptUtils.getLocalizedString("Prompt");
+
+ let args = {
+ promptType: "prompt",
+ title: title,
+ text: text,
+ value: value.value,
+ checkLabel: checkLabel,
+ checked: checkValue.value,
+ ok: false,
+ };
+
+ this.openPrompt(args);
+
+ // Did user click Ok or Cancel?
+ let ok = args.ok;
+ if (ok) {
+ checkValue.value = args.checked;
+ value.value = args.value;
+ }
+
+ return ok;
+ },
+
+ nsIPrompt_promptUsernameAndPassword : function (title, text, user, pass, checkLabel, checkValue) {
+ if (!title)
+ title = PromptUtils.getLocalizedString("PromptUsernameAndPassword2");
+
+ let args = {
+ promptType: "promptUserAndPass",
+ title: title,
+ text: text,
+ user: user.value,
+ pass: pass.value,
+ checkLabel: checkLabel,
+ checked: checkValue.value,
+ ok: false,
+ };
+
+ this.openPrompt(args);
+
+ // Did user click Ok or Cancel?
+ let ok = args.ok;
+ if (ok) {
+ checkValue.value = args.checked;
+ user.value = args.user;
+ pass.value = args.pass;
+ }
+
+ return ok;
+ },
+
+ nsIPrompt_promptPassword : function (title, text, pass, checkLabel, checkValue) {
+ if (!title)
+ title = PromptUtils.getLocalizedString("PromptPassword2");
+
+ let args = {
+ promptType: "promptPassword",
+ title: title,
+ text: text,
+ pass: pass.value,
+ checkLabel: checkLabel,
+ checked: checkValue.value,
+ ok: false,
+ }
+
+ this.openPrompt(args);
+
+ // Did user click Ok or Cancel?
+ let ok = args.ok;
+ if (ok) {
+ checkValue.value = args.checked;
+ pass.value = args.pass;
+ }
+
+ return ok;
+ },
+
+ select : function (title, text, count, list, selected) {
+ if (!title)
+ title = PromptUtils.getLocalizedString("Select");
+
+ let args = {
+ promptType: "select",
+ title: title,
+ text: text,
+ list: list,
+ selected: -1,
+ ok: false,
+ };
+
+ this.openPrompt(args);
+
+ // Did user click Ok or Cancel?
+ let ok = args.ok;
+ if (ok)
+ selected.value = args.selected;
+
+ return ok;
+ },
+
+
+ /* ---------- nsIAuthPrompt ---------- */
+
+
+ nsIAuthPrompt_prompt : function (title, text, passwordRealm, savePassword, defaultText, result) {
+ // The passwordRealm and savePassword args were ignored by nsPrompt.cpp
+ if (defaultText)
+ result.value = defaultText;
+ return this.nsIPrompt_prompt(title, text, result, null, {});
+ },
+
+ nsIAuthPrompt_promptUsernameAndPassword : function (title, text, passwordRealm, savePassword, user, pass) {
+ // The passwordRealm and savePassword args were ignored by nsPrompt.cpp
+ return this.nsIPrompt_promptUsernameAndPassword(title, text, user, pass, null, {});
+ },
+
+ nsIAuthPrompt_promptPassword : function (title, text, passwordRealm, savePassword, pass) {
+ // The passwordRealm and savePassword args were ignored by nsPrompt.cpp
+ return this.nsIPrompt_promptPassword(title, text, pass, null, {});
+ },
+
+
+ /* ---------- nsIAuthPrompt2 ---------- */
+
+
+ promptAuth : function (channel, level, authInfo, checkLabel, checkValue) {
+ let message = PromptUtils.makeAuthMessage(channel, authInfo);
+
+ let [username, password] = PromptUtils.getAuthInfo(authInfo);
+
+ let userParam = { value: username };
+ let passParam = { value: password };
+
+ let ok;
+ if (authInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD)
+ ok = this.nsIPrompt_promptPassword(null, message, passParam, checkLabel, checkValue);
+ else
+ ok = this.nsIPrompt_promptUsernameAndPassword(null, message, userParam, passParam, checkLabel, checkValue);
+
+ if (ok)
+ PromptUtils.setAuthInfo(authInfo, userParam.value, passParam.value);
+ return ok;
+ },
+
+ asyncPromptAuth : function (channel, callback, context, level, authInfo, checkLabel, checkValue) {
+ // Nothing calls this directly; netwerk ends up going through
+ // nsIPromptService::GetPrompt, which delegates to login manager.
+ // Login manger handles the async bits itself, and only calls out
+ // promptAuth, never asyncPromptAuth.
+ //
+ // Bug 565582 will change this.
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+
+ /* ---------- nsIWritablePropertyBag2 ---------- */
+
+ // Only a partial implementation, for one specific use case...
+
+ setPropertyAsBool : function(name, value) {
+ if (name == "allowTabModal")
+ this.allowTabModal = value;
+ else
+ throw Cr.NS_ERROR_ILLEGAL_VALUE;
+ },
+};
+
+
+function AuthPromptAdapterFactory() {
+}
+AuthPromptAdapterFactory.prototype = {
+ classID : Components.ID("{6e134924-6c3a-4d86-81ac-69432dd971dc}"),
+ QueryInterface : XPCOMUtils.generateQI([Ci.nsIAuthPromptAdapterFactory]),
+
+ /* ---------- nsIAuthPromptAdapterFactory ---------- */
+
+ createAdapter : function (oldPrompter) {
+ return new AuthPromptAdapter(oldPrompter);
+ }
+};
+
+
+// Takes an nsIAuthPrompt implementation, wraps it with a nsIAuthPrompt2 shell.
+function AuthPromptAdapter(oldPrompter) {
+ this.oldPrompter = oldPrompter;
+}
+AuthPromptAdapter.prototype = {
+ QueryInterface : XPCOMUtils.generateQI([Ci.nsIAuthPrompt2]),
+ oldPrompter : null,
+
+ /* ---------- nsIAuthPrompt2 ---------- */
+
+ promptAuth : function (channel, level, authInfo, checkLabel, checkValue) {
+ let message = PromptUtils.makeAuthMessage(channel, authInfo);
+
+ let [username, password] = PromptUtils.getAuthInfo(authInfo);
+ let userParam = { value: username };
+ let passParam = { value: password };
+
+ let [host, realm] = PromptUtils.getAuthTarget(channel, authInfo);
+ let authTarget = host + " (" + realm + ")";
+
+ let ok;
+ if (authInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD)
+ ok = this.oldPrompter.promptPassword(null, message, authTarget, Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, passParam);
+ else
+ ok = this.oldPrompter.promptUsernameAndPassword(null, message, authTarget, Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, userParam, passParam);
+
+ if (ok)
+ PromptUtils.setAuthInfo(authInfo, userParam.value, passParam.value);
+ return ok;
+ },
+
+ asyncPromptAuth : function (channel, callback, context, level, authInfo, checkLabel, checkValue) {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ }
+};
+
+
+// Wrapper using the old embedding contractID, since it's already common in
+// the addon ecosystem.
+function EmbedPrompter() {
+}
+EmbedPrompter.prototype = new Prompter();
+EmbedPrompter.prototype.classID = Components.ID("{7ad1b327-6dfa-46ec-9234-f2a620ea7e00}");
+
+var component = [Prompter, EmbedPrompter, AuthPromptAdapterFactory];
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory(component);