mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-06-14 00:29:43 +00:00
958 lines
33 KiB
JavaScript
958 lines
33 KiB
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/. */
|
|
|
|
"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);
|
|
else
|
|
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 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("EnterLoginForProxy", [realm, displayHost]);
|
|
else if (isPassOnly)
|
|
text = PromptUtils.getLocalizedString("EnterPasswordFor", [username, displayHost]);
|
|
else if (!realm)
|
|
text = PromptUtils.getLocalizedString("EnterUserPasswordFor", [displayHost]);
|
|
else
|
|
text = PromptUtils.getLocalizedString("EnterLoginForRealm", [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);
|
|
else
|
|
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);
|
|
else
|
|
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);
|
|
else
|
|
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);
|