Source code

Revision control

Copy as Markdown

Other Tools

/* 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/. */
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
// This is redefined below, for strange and unfortunate reasons.
import { PromptUtils } from "resource://gre/modules/PromptUtils.sys.mjs";
import { BrowserUtils } from "resource://gre/modules/BrowserUtils.sys.mjs";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
ClipboardContextMenu: "resource://gre/modules/ClipboardContextMenu.sys.mjs",
});
const {
MODAL_TYPE_TAB,
MODAL_TYPE_CONTENT,
MODAL_TYPE_WINDOW,
MODAL_TYPE_INTERNAL_WINDOW,
} = Ci.nsIPrompt;
const COMMON_DIALOG = "chrome://global/content/commonDialog.xhtml";
const SELECT_DIALOG = "chrome://global/content/selectDialog.xhtml";
export function Prompter() {
// Note that EmbedPrompter clones this implementation.
}
/**
* Implements nsIPromptService and nsIPromptFactory
* @class Prompter
*/
Prompter.prototype = {
classID: Components.ID("{1c978d25-b37f-43a8-a2d6-0c7a239ead87}"),
QueryInterface: ChromeUtils.generateQI([
"nsIPromptFactory",
"nsIPromptService",
]),
/* ---------- private members ---------- */
pickPrompter(options) {
return new ModalPrompter(options);
},
/* ---------- nsIPromptFactory ---------- */
getPrompt(domWin, iid) {
// This is still kind of dumb; the C++ code delegated to login manager
// here, which in turn calls back into us via nsIPromptService.
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) {
console.error("nsPrompter: Delegation to password manager failed: ", e);
}
}
let p = new ModalPrompter({ domWin });
p.QueryInterface(iid);
return p;
},
/* ---------- nsIPromptService ---------- */
/**
* Puts up an alert dialog with an OK button.
* @param {mozIDOMWindowProxy} domWin - The parent window or null.
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
*/
alert(domWin, title, text) {
let p = this.pickPrompter({ domWin });
p.alert(title, text);
},
/**
* Puts up an alert dialog with an OK button.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
*/
alertBC(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType });
p.alert(...promptArgs);
},
/**
* Puts up an alert dialog with an OK button.
*
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @returns {Promise} A promise which resolves when the prompt is dismissed.
*/
asyncAlert(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType, async: true });
return p.alert(...promptArgs);
},
/**
* Puts up an alert dialog with an OK button and a labeled checkbox.
* @param {mozIDOMWindowProxy} domWin - The parent window or null.
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {String} checkLabel - Text to appear with the checkbox.
* @param {Object} checkValue - Contains the initial checked state of the
* checkbox when this method is called and the final checked state
* after this method returns.
*/
alertCheck(domWin, title, text, checkLabel, checkValue) {
let p = this.pickPrompter({ domWin });
p.alertCheck(title, text, checkLabel, checkValue);
},
/**
* Puts up an alert dialog with an OK button and a labeled checkbox.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {String} checkLabel - Text to appear with the checkbox.
* @param {Object} checkValue - Contains the initial checked state of the
* checkbox when this method is called and the final checked state
* after this method returns.
*/
alertCheckBC(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType });
p.alertCheck(...promptArgs);
},
/**
* Puts up an alert dialog with an OK button and a labeled checkbox.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {String} checkLabel - Text to appear with the checkbox.
* @param {Boolean} checkValue - The initial checked state of the checkbox.
* @returns {Promise<nsIPropertyBag<{ checked: Boolean }>>}
* A promise which resolves when the prompt is dismissed.
*/
asyncAlertCheck(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType, async: true });
return p.alertCheck(...promptArgs);
},
/**
* Puts up a dialog with OK and Cancel buttons.
* @param {mozIDOMWindowProxy} domWin - The parent window or null.
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @returns {Boolean} true for OK, false for Cancel.
*/
confirm(domWin, title, text) {
let p = this.pickPrompter({ domWin });
return p.confirm(title, text);
},
/**
* Puts up a dialog with OK and Cancel buttons.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @returns {Boolean} true for OK, false for Cancel.
*/
confirmBC(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType });
return p.confirm(...promptArgs);
},
/**
* Puts up a dialog with OK and Cancel buttons.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @returns {Promise<nsIPropertyBag<{ ok: Boolean }>>}
* A promise which resolves when the prompt is dismissed.
*/
asyncConfirm(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType, async: true });
return p.confirm(...promptArgs);
},
/**
* Puts up a dialog with OK and Cancel buttons and a labeled checkbox.
* @param {mozIDOMWindowProxy} domWin - The parent window or null.
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {String} checkLabel - Text to appear with the checkbox.
* @param {Object} checkValue - Contains the initial checked state of the
* checkbox when this method is called and the final checked state
* after this method returns.
*/
confirmCheck(domWin, title, text, checkLabel, checkValue) {
let p = this.pickPrompter({ domWin });
return p.confirmCheck(title, text, checkLabel, checkValue);
},
/**
* Puts up a dialog with OK and Cancel buttons and a labeled checkbox.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {String} checkLabel - Text to appear with the checkbox.
* @param {Object} checkValue - Contains the initial checked state of the
* checkbox when this method is called and the final checked state
* after this method returns.
* @returns {Boolean} true for OK, false for Cancel
*/
confirmCheckBC(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType });
return p.confirmCheck(...promptArgs);
},
/**
* Puts up a dialog with OK and Cancel buttons and a labeled checkbox.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {String} checkLabel - Text to appear with the checkbox.
* @param {Boolean} checkValue - The initial checked state of the checkbox.
* @returns {Promise<nsIPropertyBag<{ ok: Boolean, checked: Boolean }>>}
* A promise which resolves when the prompt is dismissed.
*/
asyncConfirmCheck(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType, async: true });
return p.confirmCheck(...promptArgs);
},
/**
* Puts up a dialog with up to 3 buttons and an optional, labeled checkbox.
*
* Buttons are numbered 0 - 2. Button 0 is the default button unless one of
* the Button Default Flags is specified.
*
* A button may use a predefined title, specified by one of the Button Title
* Flags values. Each title value can be multiplied by a position value to
* assign the title to a particular button. If BUTTON_TITLE_IS_STRING is
* used for a button, the string parameter for that button will be used. If
* the value for a button position is zero, the button will not be shown.
*
* In general, flags is constructed per the following example:
*
* flags = (BUTTON_POS_0) * (BUTTON_TITLE_AAA) +
* (BUTTON_POS_1) * (BUTTON_TITLE_BBB) +
* BUTTON_POS_1_DEFAULT;
*
* where "AAA" and "BBB" correspond to one of the button titles.
*
* @param {mozIDOMWindowProxy} domWin - The parent window or null.
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {Number} flags - A combination of Button Flags.
* @param {String} button0 - Used when button 0 uses TITLE_IS_STRING.
* @param {String} button1 - Used when button 1 uses TITLE_IS_STRING.
* @param {String} button2 - Used when button 2 uses TITLE_IS_STRING.
* @param {String} checkLabel - Text to appear with the checkbox.
* Null if no checkbox.
* @param {Object} checkValue - Contains the initial checked state of the
* checkbox when this method
* is called and the final checked state after this method returns.
* @returns {Number} The index of the button pressed.
*/
confirmEx(
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
);
},
/**
* Puts up a dialog with up to 3 buttons and an optional, labeled checkbox.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {Number} flags - A combination of Button Flags.
* @param {String} button0 - Used when button 0 uses TITLE_IS_STRING.
* @param {String} button1 - Used when button 1 uses TITLE_IS_STRING.
* @param {String} button2 - Used when button 2 uses TITLE_IS_STRING.
* @param {String} checkLabel - Text to appear with the checkbox.
* Null if no checkbox.
* @param {Object} checkValue - Contains the initial checked state of the
* checkbox when this method is called and the final checked state
* after this method returns.
* @returns {Number} The index of the button pressed.
*/
confirmExBC(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType });
return p.confirmEx(...promptArgs);
},
/**
* Puts up a dialog with up to 3 buttons and an optional, labeled checkbox.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {Number} flags - A combination of Button Flags.
* @param {String} button0 - Used when button 0 uses TITLE_IS_STRING.
* @param {String} button1 - Used when button 1 uses TITLE_IS_STRING.
* @param {String} button2 - Used when button 2 uses TITLE_IS_STRING.
* @param {String} checkLabel - Text to appear with the checkbox.
* Null if no checkbox.
* @param {Boolean} checkValue - The initial checked state of the checkbox.
* @param {Object} [extraArgs] - Extra arguments for the prompt metadata.
* @returns {Promise<nsIPropertyBag<{ buttonNumClicked: Number, checked: Boolean, isExtra1Secondary: Boolean }>>}
*/
asyncConfirmEx(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType, async: true });
return p.confirmEx(...promptArgs);
},
/**
* Puts up a dialog with an edit field and an optional, labeled checkbox.
* @param {mozIDOMWindowProxy} domWin - The parent window or null.
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {Object} value - Contains the default value for the dialog field
* when this method is called (null value is ok). Upon return, if
* the user pressed OK, then this parameter contains a newly
* allocated string value.
* Otherwise, the parameter's value is unmodified.
* @param {String} checkLabel - Text to appear with the checkbox.
* If null, check box will not be shown.
* @param {Object} checkValue - Contains the initial checked state of the
* checkbox when this method is called and the final checked state
* after this method returns.
* @returns {Boolean} true for OK, false for Cancel.
*/
prompt(domWin, title, text, value, checkLabel, checkValue) {
let p = this.pickPrompter({ domWin });
return p.nsIPrompt_prompt(title, text, value, checkLabel, checkValue);
},
/**
* Puts up a dialog with an edit field and an optional, labeled checkbox.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {Object} value - Contains the default value for the dialog field
* when this method is called (null value is ok). Upon return, if
* the user pressed OK, then this parameter contains a newly
* allocated string value.
* Otherwise, the parameter's value is unmodified.
* @param {String} checkLabel - Text to appear with the checkbox.
* If null, check box will not be shown.
* @param {Object} checkValue - Contains the initial checked state of the
* checkbox when this method is called and the final checked state
* after this method returns.
* @returns {Boolean} true for OK, false for Cancel.
*/
promptBC(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType });
return p.nsIPrompt_prompt(...promptArgs);
},
/**
* Puts up a dialog with an edit field and an optional, labeled checkbox.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {String} value - The default value for the dialog text field.
* @param {String} checkLabel - Text to appear with the checkbox.
* If null, check box will not be shown.
* @param {Boolean} checkValue - The initial checked state of the checkbox.
* @returns {Promise<nsIPropertyBag<{ ok: Boolean, checked: Boolean, value: String }>>}
* A promise which resolves when the prompt is dismissed.
*/
asyncPrompt(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType, async: true });
return p.nsIPrompt_prompt(...promptArgs);
},
/**
* Puts up a dialog with an edit field and a password field.
* @param {mozIDOMWindowProxy} domWin - The parent window or null.
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {Object} user - Contains the default value for the username
* field when this method is called (null value is ok).
* Upon return, if the user pressed OK, then this parameter contains
* a newly allocated string value. Otherwise, the parameter's value
* is unmodified.
* @param {Object} pass - Contains the default value for the password field
* when this method is called (null value is ok). Upon return, if the
* user pressed OK, this parameter contains a newly allocated string
* value. Otherwise, the parameter's value is unmodified.
* @returns {Boolean} true for OK, false for Cancel.
*/
promptUsernameAndPassword(domWin, title, text, user, pass) {
let p = this.pickPrompter({ domWin });
return p.nsIPrompt_promptUsernameAndPassword(null, title, text, user, pass);
},
/**
* Puts up a dialog with an edit field and a password field.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {Object} user - Contains the default value for the username
* field when this method is called (null value is ok).
* Upon return, if the user pressed OK, then this parameter contains
* a newly allocated string value. Otherwise, the parameter's value
* is unmodified.
* @param {Object} pass - Contains the default value for the password field
* when this method is called (null value is ok). Upon return, if the
* user pressed OK, this parameter contains a newly allocated string
* value. Otherwise, the parameter's value is unmodified.
* @returns {Boolean} true for OK, false for Cancel.
*/
promptUsernameAndPasswordBC(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType });
return p.nsIPrompt_promptUsernameAndPassword(null, ...promptArgs);
},
/**
* Puts up a dialog with an edit field and a password field.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {String} user - Default value for the username field.
* @param {String} pass - Contains the default value for the password field.
* @returns {Promise<nsIPropertyBag<{ ok: Boolean, user: String, pass: String }>>}
* A promise which resolves when the prompt is dismissed.
*/
asyncPromptUsernameAndPassword(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType, async: true });
return p.nsIPrompt_promptUsernameAndPassword(null, ...promptArgs);
},
/**
* Puts up a dialog with a password field.
* @param {mozIDOMWindowProxy} domWin - The parent window or null.
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {Object} pass - Contains the default value for the password field
* when this method is called (null value is ok). Upon return, if the
* user pressed OK, this parameter contains a newly allocated string
* value. Otherwise, the parameter's value is unmodified.
* @returns {Boolean} true for OK, false for Cancel.
*/
promptPassword(domWin, title, text, pass) {
let p = this.pickPrompter({ domWin });
return p.nsIPrompt_promptPassword(
null, // no channel.
title,
text,
pass
);
},
/**
* Puts up a dialog with a password field.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {Object} pass - Contains the default value for the password field
* when this method is called (null value is ok). Upon return, if the
* user pressed OK, this parameter contains a newly allocated string
* value. Otherwise, the parameter's value is unmodified.
* @returns {Boolean} true for OK, false for Cancel.
*/
promptPasswordBC(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType });
return p.nsIPrompt_promptPassword(null, ...promptArgs);
},
/**
* Puts up a dialog with a password field.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {String} pass - Contains the default value for the password field.
* @returns {Promise<nsIPropertyBag<{ ok: Boolean, pass: String }>>}
* A promise which resolves when the prompt is dismissed.
*/
asyncPromptPassword(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType, async: true });
return p.nsIPrompt_promptPassword(null, ...promptArgs);
},
/**
* Puts up a dialog box which has a list box of strings from which the user
* may make a single selection.
* @param {mozIDOMWindowProxy} domWin - The parent window or null.
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {String[]} list - The list of strings to display.
* @param {Object} selected - Contains the index of the selected item in the
* list when this method returns true.
* @returns {Boolean} true for OK, false for Cancel.
*/
select(domWin, title, text, list, selected) {
let p = this.pickPrompter({ domWin });
return p.select(title, text, list, selected);
},
/**
* Puts up a dialog box which has a list box of strings from which the user
* may make a single selection.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {String[]} list - The list of strings to display.
* @param {Object} selected - Contains the index of the selected item in the
* list when this method returns true.
* @returns {Boolean} true for OK, false for Cancel.
*/
selectBC(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType });
return p.select(...promptArgs);
},
/**
* Puts up a dialog box which has a list box of strings from which the user
* may make a single selection.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {String} title - Text to appear in the title of the dialog.
* @param {String} text - Text to appear in the body of the dialog.
* @param {String[]} list - The list of strings to display.
* @returns {Promise<nsIPropertyBag<{ selected: Number, ok: Boolean }>>}
* A promise which resolves when the prompt is dismissed.
*/
asyncSelect(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType, async: true });
return p.select(...promptArgs);
},
/**
* Requests a username and a password. Shows a dialog with username and
* password field, depending on flags also a domain field.
* @param {mozIDOMWindowProxy} domWin - The parent window or null.
* @param {nsIChannel} channel - The channel that requires authentication.
* @param {Number} level - Security level of the credential transmission.
* Any of nsIAuthPrompt2.<LEVEL_NONE|LEVEL_PW_ENCRYPTED|LEVEL_SECURE>
* @param {nsIAuthInformation} authInfo - Authentication information object.
* @returns {Boolean}
* true: Authentication can proceed using the values
* in the authInfo object.
* false: Authentication should be cancelled, usually because the
* user did not provide username/password.
*/
promptAuth(domWin, channel, level, authInfo) {
let p = this.pickPrompter({ domWin });
return p.promptAuth(channel, level, authInfo);
},
/**
* Requests a username and a password. Shows a dialog with username and
* password field, depending on flags also a domain field.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {nsIChannel} channel - The channel that requires authentication.
* @param {Number} level - Security level of the credential transmission.
* Any of nsIAuthPrompt2.<LEVEL_NONE|LEVEL_PW_ENCRYPTED|LEVEL_SECURE>
* @param {nsIAuthInformation} authInfo - Authentication information object.
* @returns {Boolean}
* true: Authentication can proceed using the values
* in the authInfo object.
* false: Authentication should be cancelled, usually because the
* user did not provide username/password.
*/
promptAuthBC(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType });
return p.promptAuth(...promptArgs);
},
/**
* Requests a username and a password. Shows a dialog with username and
* password field, depending on flags also a domain field.
* @param {BrowsingContext} browsingContext - The browsing context the
* prompt should be opened for.
* @param {Number} modalType - The modal type of the prompt.
* nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
* @param {nsIChannel} channel - The channel that requires authentication.
* @param {Number} level - Security level of the credential transmission.
* Any of nsIAuthPrompt2.<LEVEL_NONE|LEVEL_PW_ENCRYPTED|LEVEL_SECURE>
* @param {nsIAuthInformation} authInfo - Authentication information object.
* @returns {Promise<nsIPropertyBag<{ ok: Boolean }>>}
* A promise which resolves when the prompt is dismissed.
*/
asyncPromptAuth(browsingContext, modalType, ...promptArgs) {
let p = this.pickPrompter({ browsingContext, modalType, async: true });
return p.promptAuth(...promptArgs);
},
/**
* Displays a contextmenu to get user confirmation for clipboard read. Only
* one context menu can be opened at a time.
*
* @param {WindowContext} windowContext - The window context that initiates
* the clipboard operation.
* @returns {Promise<nsIPropertyBag<{ ok: Boolean }>>}
* A promise which resolves when the contextmenu is dismissed.
*/
confirmUserPaste() {
return lazy.ClipboardContextMenu.confirmUserPaste(...arguments);
},
};
// Common utils not specific to a particular prompter style.
var InternalPromptUtils = {
getLocalizedString(key, formatArgs) {
if (formatArgs) {
return this.strBundle.formatStringFromName(key, formatArgs);
}
return this.strBundle.GetStringFromName(key);
},
confirmExHelper(flags, button0, button1, button2) {
const BUTTON_DEFAULT_MASK = 0x03000000;
let defaultButtonNum = (flags & BUTTON_DEFAULT_MASK) >> 24;
let isDelayEnabled = flags & Ci.nsIPrompt.BUTTON_DELAY_ENABLE;
// Sanity check: If the flags indicate there should be no button0 then flags
// must contain BUTTON_NONE (notably, it must include BUTTON_NONE_ENABLE_BIT).
let allowNoButtons =
(flags & Ci.nsIPromptService.BUTTON_NONE) ==
Ci.nsIPromptService.BUTTON_NONE;
const NO_BUTTON0 =
Ci.nsIPrompt.BUTTON_POS_0 * Ci.nsIPrompt.BUTTON_TITLE_IS_STRING;
if (!allowNoButtons && !button0 && (flags & NO_BUTTON0) == NO_BUTTON0) {
throw new Error(
`Request for modal prompt with no buttons requires flags to be ` +
`BUTTON_NONE. Got ${flags}`
);
}
if (allowNoButtons && (button0 || button1 || button2)) {
throw new Error(
`Request for modal prompt with no buttons requires button names to be ` +
`null. Got ${button0}, ${button1}, ${button2}`
);
}
// 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 = this.getLocalizedString("OK");
break;
case Ci.nsIPrompt.BUTTON_TITLE_CANCEL:
buttonLabel = this.getLocalizedString("Cancel");
break;
case Ci.nsIPrompt.BUTTON_TITLE_YES:
buttonLabel = this.getLocalizedString("Yes");
break;
case Ci.nsIPrompt.BUTTON_TITLE_NO:
buttonLabel = this.getLocalizedString("No");
break;
case Ci.nsIPrompt.BUTTON_TITLE_SAVE:
buttonLabel = this.getLocalizedString("Save");
break;
case Ci.nsIPrompt.BUTTON_TITLE_DONT_SAVE:
buttonLabel = this.getLocalizedString("DontSave");
break;
case Ci.nsIPrompt.BUTTON_TITLE_REVERT:
buttonLabel = this.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,
allowNoButtons,
];
},
getAuthInfo(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(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(uri) {
return uri.scheme + "://" + uri.hostPort;
},
// Note: there's a similar implementation in the login manager.
getAuthTarget(aChannel, aAuthInfo) {
let displayHost, 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 new Error("proxy auth needs nsIProxiedChannel");
}
let info = aChannel.proxyInfo;
if (!info) {
throw new Error("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
);
displayHost =
"moz-proxy://" +
idnService.convertUTF8toACE(info.host) +
":" +
info.port;
realm = aAuthInfo.realm;
if (!realm) {
realm = displayHost;
}
return { realm, displayHost };
}
displayHost = this.getFormattedHostname(aChannel.URI);
let displayHostOnly = aChannel.URI.hostPort;
// 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 = displayHost;
}
return { realm, displayHostOnly, displayHost };
},
makeAuthMessage(prompt, channel, authInfo) {
if (prompt.modalType != MODAL_TYPE_TAB) {
return this._legacyMakeAuthMessage(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;
// We use the realm and displayHost only for proxy auth,
// and the displayHostOnly (hostPort) only for x-origin auth prompts.
// Otherwise we rely on the title of the dialog displaying the correct
// title.
let { displayHost, realm, displayHostOnly } = this.getAuthTarget(
channel,
authInfo
);
if (isProxy) {
// The realm is server-controlled. Trim it if it's very long, to
// avoid the dialog becoming unusable.
if (realm.length > 150) {
realm = realm.substring(0, 150);
// Append "..." (or localized equivalent).
realm += this.ellipsis;
}
return this.getLocalizedString("EnterLoginForProxy3", [
realm,
displayHost,
]);
}
if (isPassOnly) {
return this.getLocalizedString("EnterPasswordOnlyFor", [username]);
}
if (isCrossOrig) {
return this.getLocalizedString("EnterCredentialsCrossOrigin", [
displayHostOnly,
]);
}
return this.getLocalizedString("EnterCredentials");
},
_legacyMakeAuthMessage(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 = "";
}
// The realm is server-controlled. Trim it if it's very long, to
// avoid the dialog becoming unusable.
if (realm.length > 150) {
realm = realm.substring(0, 150);
// Append "..." (or localized equivalent).
realm += this.ellipsis;
}
let text;
if (isProxy) {
text = this.getLocalizedString("EnterLoginForProxy3", [
realm,
displayHost,
]);
} else if (isPassOnly) {
text = this.getLocalizedString("EnterPasswordFor", [
username,
displayHost,
]);
} else if (isCrossOrig) {
text = this.getLocalizedString("EnterUserPasswordForCrossOrigin2", [
displayHost,
]);
} else if (!realm) {
text = this.getLocalizedString("EnterUserPasswordFor2", [displayHost]);
} else {
text = this.getLocalizedString("EnterLoginForRealm3", [
realm,
displayHost,
]);
}
return text;
},
getBrandFullName() {
return this.brandBundle.GetStringFromName("brandFullName");
},
};
ChromeUtils.defineLazyGetter(InternalPromptUtils, "strBundle", function () {
let bundle = Services.strings.createBundle(
"chrome://global/locale/commonDialogs.properties"
);
if (!bundle) {
throw new Error("String bundle for Prompter not present!");
}
return bundle;
});
ChromeUtils.defineLazyGetter(InternalPromptUtils, "brandBundle", function () {
let bundle = Services.strings.createBundle(
"chrome://branding/locale/brand.properties"
);
if (!bundle) {
throw new Error("String bundle for branding not present!");
}
return bundle;
});
ChromeUtils.defineLazyGetter(InternalPromptUtils, "ellipsis", function () {
let ellipsis = "\u2026";
try {
ellipsis = Services.prefs.getComplexValue(
"intl.ellipsis",
Ci.nsIPrefLocalizedString
).data;
} catch (e) {}
return ellipsis;
});
class ModalPrompter {
constructor({
browsingContext = null,
domWin = null,
modalType = null,
async = false,
}) {
if (browsingContext && domWin) {
throw new Error("Pass either browsingContext or domWin");
}
if (domWin) {
// We have a domWin, get the associated browsing context
this.browsingContext = BrowsingContext.getFromWindow(domWin);
} else {
this.browsingContext = browsingContext;
}
if (
domWin &&
(!modalType || modalType == MODAL_TYPE_WINDOW) &&
!this.browsingContext?.isContent &&
this.browsingContext?.associatedWindow?.gDialogBox
) {
modalType = MODAL_TYPE_INTERNAL_WINDOW;
}
// Use given modal type or fallback to default
this.modalType = modalType || ModalPrompter.defaultModalType;
this.async = async;
this.QueryInterface = ChromeUtils.generateQI([
"nsIPrompt",
"nsIAuthPrompt",
"nsIAuthPrompt2",
"nsIWritablePropertyBag2",
]);
}
set modalType(modalType) {
// Setting modal type window is always allowed
if (modalType == MODAL_TYPE_WINDOW) {
this._modalType = modalType;
return;
}
// For content prompts for non-content windows, use window prompts:
if (modalType == MODAL_TYPE_CONTENT && !this.browsingContext?.isContent) {
this._modalType = MODAL_TYPE_WINDOW;
return;
}
// We can't use content / tab prompts if we don't have a suitable parent.
if (
!this.browsingContext?.isContent &&
modalType != MODAL_TYPE_INTERNAL_WINDOW
) {
// Only show this error if we're not about to fall back again and show a different one.
if (this.browsingContext?.associatedWindow?.gDialogBox) {
console.error(
"Prompter: Browser not available. Falling back to internal window prompt."
);
}
modalType = MODAL_TYPE_INTERNAL_WINDOW;
}
if (
modalType == MODAL_TYPE_INTERNAL_WINDOW &&
(this.browsingContext?.isContent ||
!this.browsingContext?.associatedWindow?.gDialogBox)
) {
console.error(
"Prompter: internal dialogs not available in this context. Falling back to window prompt."
);
modalType = MODAL_TYPE_WINDOW;
}
this._modalType = modalType;
}
get modalType() {
return this._modalType;
}
/* ---------- internal methods ---------- */
/**
* Synchronous wrapper around {@link ModalPrompter#openPrompt}
* @param {Object} args Prompt arguments. When prompt has been closed, they are updated to reflect the result state.
*/
openPromptSync(args) {
let closed = false;
this.openPrompt(args)
.then(returnedArgs => {
if (returnedArgs) {
for (let key in returnedArgs) {
args[key] = returnedArgs[key];
}
}
})
.finally(() => {
closed = true;
});
Services.tm.spinEventLoopUntilOrQuit(
"prompts/Prompter.sys.mjs:openPromptSync",
() => closed
);
}
async openPrompt(args) {
if (!this.browsingContext) {
// We don't have a browsing context, fallback to a window prompt.
args.modalType = MODAL_TYPE_WINDOW;
this.openWindowPrompt(null, args);
return args;
}
if (this._modalType == MODAL_TYPE_INTERNAL_WINDOW) {
await this.openInternalWindowPrompt(
this.browsingContext.associatedWindow,
args
);
return args;
}
// Select prompts are not part of CommonDialog
// and thus not supported as tab or content prompts yet. See Bug 1622817.
// Once they are integrated this override should be removed.
if (args.promptType == "select" && this.modalType !== MODAL_TYPE_WINDOW) {
console.error(
"Prompter: 'select' prompts do not support tab/content prompting. Falling back to window prompt."
);
args.modalType = MODAL_TYPE_WINDOW;
} else {
args.modalType = this.modalType;
}
const IS_CONTENT =
Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
let actor;
try {
if (IS_CONTENT) {
// When in the content, get the PromptChild actor.
actor =
this.browsingContext.window.windowGlobalChild.getActor("Prompt");
} else {
// When in the parent, get the PromptParent actor.
actor = this.browsingContext.currentWindowGlobal.getActor("Prompt");
}
} catch (_) {
// We can't get the prompt actor, fallback to window prompt.
let parentWin;
// If given a chrome BC we can try to get its window
if (!this.browsingContext.isContent && this.browsingContext.window) {
parentWin = this.browsingContext.window;
} else {
// Try to get the window which is the browsers parent
parentWin = this.browsingContext.top?.embedderElement?.ownerGlobal;
}
this.openWindowPrompt(parentWin, args);
return args;
}
/* For prompts with a channel, we want to show the origin requesting
* authentication. This is different from the prompt principal,
* which is based on the document loaded in the browsing context over
* which the prompt appears. So if page foo.com loads bar.com, and the
* latter asks for auth, we want that bar.com's origin, not foo.com.
* To avoid confusion, we use different properties
* (authOrigin / promptPrincipal) to track this information.
*/
if (args.channel) {
try {
// Bug 1767292: Display scheme if it is HTTP, otherwise omit it.
args.authOrigin = BrowserUtils.formatURIForDisplay(args.channel.URI, {
showInsecureHTTP: true,
});
} catch (ex) {
args.authOrigin = args.channel.URI.prePath;
}
args.isInsecureAuth = args.channel.URI.schemeIs("http");
// whether we are going to prompt the user for their credentials for a different base domain.
// When true, auth prompt spoofing protection mechanisms will be triggered (see bug 791594).
args.isTopLevelCrossDomainAuth = false;
// We don't support auth prompt spoofing protections for sub resources and window prompts
if (
args.modalType == MODAL_TYPE_TAB &&
args.channel.loadInfo.isTopLevelLoad
) {
// check if this is a request from a third party
try {
args.isTopLevelCrossDomainAuth =
this.browsingContext.currentWindowGlobal?.documentPrincipal?.isThirdPartyURI(
args.channel.URI
);
} catch (e) {
// isThirdPartyURI failes for about:/blob/data URIs
console.warn("nsPrompter: isThirdPartyURI failed: " + e);
}
}
} else {
args.promptPrincipal =
this.browsingContext.window?.document.nodePrincipal;
}
if (IS_CONTENT) {
let docShell = this.browsingContext.docShell;
let inPermitUnload = docShell?.docViewer?.inPermitUnload;
args.inPermitUnload = inPermitUnload;
let eventDetail = Cu.cloneInto(
{
tabPrompt: this.modalType != MODAL_TYPE_WINDOW,
inPermitUnload,
},
this.browsingContext.window
);
PromptUtils.fireDialogEvent(
this.browsingContext.window,
"DOMWillOpenModalDialog",
null,
eventDetail
);
// Put content window in the modal state while the prompt is open.
let windowUtils = this.browsingContext.window?.windowUtils;
if (windowUtils) {
windowUtils.enterModalState();
}
} else if (args.inPermitUnload) {
args.promptPrincipal =
this.browsingContext.currentWindowGlobal.documentPrincipal;
}
// It is technically possible for multiple prompts to be sent from a single
// BrowsingContext. See bug 1266353. We use a randomly generated UUID to
// differentiate between the different prompts.
let id = "id" + Services.uuid.generateUUID().toString();
args._remoteId = args.promptID ?? id;
let returnedArgs;
try {
if (IS_CONTENT) {
// If we're in the content process, send a message to the PromptParent
// window actor.
returnedArgs = await actor.sendQuery("Prompt:Open", args);
} else {
// If we're in the parent process we already have the parent actor.
// We can call its message handler directly.
returnedArgs = await actor.receiveMessage({
name: "Prompt:Open",
data: args,
});
}
if (returnedArgs?.promptAborted) {
throw Components.Exception(
"prompt aborted by user",
Cr.NS_ERROR_NOT_AVAILABLE
);
}
} finally {
if (IS_CONTENT) {
let windowUtils = this.browsingContext.window?.windowUtils;
if (windowUtils) {
windowUtils.leaveModalState();
}
PromptUtils.fireDialogEvent(
this.browsingContext.window,
"DOMModalDialogClosed"
);
}
}
return returnedArgs;
}
/**
* Open a window modal prompt
*
* 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.
* We try and find a window to use as the parent, but don't consider if that
* is visible before showing the prompt. parentWindow may still be null if
* there are _no_ windows open.
* @param {Window} [parentWindow] - The parent window for the prompt, may be
* null.
* @param {Object} args - Prompt options and return values.
*/
openWindowPrompt(parentWindow = null, args) {
let uri = args.promptType == "select" ? SELECT_DIALOG : COMMON_DIALOG;
let propBag = PromptUtils.objectToPropBag(args);
Services.ww.openWindow(
parentWindow || Services.ww.activeWindow,
uri,
"_blank",
"centerscreen,chrome,modal,titlebar",
propBag
);
PromptUtils.propBagToObject(propBag, args);
}
async openInternalWindowPrompt(parentWindow, args) {
if (!parentWindow?.gDialogBox) {
this.openWindowPrompt(parentWindow, args);
return;
}
let propBag = PromptUtils.objectToPropBag(args);
propBag.setProperty("async", this.async);
let uri = args.promptType == "select" ? SELECT_DIALOG : COMMON_DIALOG;
await parentWindow.gDialogBox.open(uri, propBag);
propBag.deleteProperty("async");
PromptUtils.propBagToObject(propBag, args);
}
/**
* Calls async prompt method and optionally runs promise chained task on
* result data. Converts result data to nsIPropertyBag.
* @param {Object} args - Prompt arguments.
* @param {Function} [task] - Function which is called with the modified
* prompt args object once the prompt has been closed. Must return a
* result object for the prompt caller.
* @returns {Promise<nsIPropertyBag>} - Resolves with a property bag holding the
* prompt result properties. Resolves once prompt has been closed.
*/
async openPromptAsync(args, task) {
let result = await this.openPrompt(args);
// If task is not defined, the prompt method does not return
// anything. In this case we can resolve without value.
if (!task) {
return undefined;
}
// Convert task result to nsIPropertyBag and resolve
let taskResult = task(result);
if (!(taskResult instanceof Object)) {
throw new Error("task must return object");
}
return PromptUtils.objectToPropBag(taskResult);
}
/*
* ---------- 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() {
// 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() {
// Both have 6 args, so use types.
if (typeof arguments[2] == "object") {
// Add the null channel:
let args = Array.from(arguments);
args.unshift(null);
return this.nsIPrompt_promptUsernameAndPassword.apply(this, args);
}
return this.nsIAuthPrompt_promptUsernameAndPassword.apply(this, arguments);
}
promptPassword() {
// Both have 5 args, so use types.
if (typeof arguments[2] == "object") {
// Add the null channel:
let args = Array.from(arguments);
args.unshift(null);
return this.nsIPrompt_promptPassword.apply(this, args);
}
return this.nsIAuthPrompt_promptPassword.apply(this, arguments);
}
/* ---------- nsIPrompt ---------- */
alert(title, text) {
if (!title) {
title = InternalPromptUtils.getLocalizedString("Alert");
}
let args = {
promptType: "alert",
title,
text,
};
if (this.async) {
return this.openPromptAsync(args);
}
return this.openPromptSync(args);
}
alertCheck(title, text, checkLabel, checkValue) {
if (!title) {
title = InternalPromptUtils.getLocalizedString("Alert");
}
// For sync calls checkValue is an XPCOM inout. XPCOM wraps primitves in
// objects for call by reference.
// The async version of this method uses call by value.
let checked = this.async ? checkValue : checkValue.value;
let args = {
promptType: "alertCheck",
title,
text,
checkLabel,
checked,
};
if (this.async) {
return this.openPromptAsync(args, result => ({
checked: result.checked,
}));
}
this.openPromptSync(args);
checkValue.value = args.checked;
return undefined;
}
confirm(title, text) {
if (!title) {
title = InternalPromptUtils.getLocalizedString("Confirm");
}
let args = {
promptType: "confirm",
title,
text,
ok: false,
};
if (this.async) {
return this.openPromptAsync(args, result => ({ ok: result.ok }));
}
this.openPromptSync(args);
return args.ok;
}
confirmCheck(title, text, checkLabel, checkValue) {
if (!title) {
title = InternalPromptUtils.getLocalizedString("ConfirmCheck");
}
let checked = this.async ? checkValue : checkValue.value;
let args = {
promptType: "confirmCheck",
title,
text,
checkLabel,
checked,
ok: false,
};
if (this.async) {
return this.openPromptAsync(args, result => ({
// Checkbox state always returned, even if cancel clicked.
checked: result.checked,
// Did user click Ok or Cancel?
ok: result.ok,
}));
}
this.openPromptSync(args);
checkValue.value = args.checked;
return args.ok;
}
confirmEx(
title,
text,
flags,
button0,
button1,
button2,
checkLabel,
checkValue,
extraArgs = {}
) {
if (!title) {
title = InternalPromptUtils.getLocalizedString("Confirm");
}
let args = {
promptType: "confirmEx",
title,
text,
checkLabel,
checked: this.async ? checkValue : checkValue.value,
ok: false,
buttonNumClicked: 1,
...extraArgs,
};
let [
label0,
label1,
label2,
defaultButtonNum,
isDelayEnabled,
allowNoButtons,
] = InternalPromptUtils.confirmExHelper(flags, button0, button1, button2);
args.defaultButtonNum = defaultButtonNum;
args.enableDelay = isDelayEnabled;
args.allowNoButtons = allowNoButtons;
if (label0) {
args.button0Label = label0;
if (label1) {
args.button1Label = label1;
if (label2) {
args.button2Label = label2;
}
}
}
if (flags & Ci.nsIPrompt.BUTTON_POS_1_IS_SECONDARY) {
args.isExtra1Secondary = true;
}
if (flags & Ci.nsIPrompt.SHOW_SPINNER) {
args.headerIconCSSValue = "url('chrome://global/skin/icons/loading.svg')";
}
if (this.async) {
return this.openPromptAsync(args, result => ({
checked: !!result.checked,
buttonNumClicked: result.buttonNumClicked,
isExtra1Secondary: result.isExtra1Secondary,
}));
}
this.openPromptSync(args);
checkValue.value = args.checked;
return args.buttonNumClicked;
}
nsIPrompt_prompt(title, text, value, checkLabel, checkValue) {
if (!title) {
title = InternalPromptUtils.getLocalizedString("Prompt");
}
let args = {
promptType: "prompt",
title,
text,
value: this.async ? value : value.value,
checkLabel,
checked: this.async ? checkValue : checkValue.value,
ok: false,
};
if (this.async) {
return this.openPromptAsync(args, result => ({
checked: !!result.checked,
value: result.value,
ok: result.ok,
}));
}
this.openPromptSync(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(channel, title, text, user, pass) {
if (!title) {
title = InternalPromptUtils.getLocalizedString(
"PromptUsernameAndPassword3",
[InternalPromptUtils.getBrandFullName()]
);
}
let args = {
channel,
promptType: "promptUserAndPass",
title,
text,
user: this.async ? user : user.value,
pass: this.async ? pass : pass.value,
button0Label: InternalPromptUtils.getLocalizedString("SignIn"),
ok: false,
};
if (this.async) {
return this.openPromptAsync(args, result => ({
user: result.user,
pass: result.pass,
ok: result.ok,
}));
}
this.openPromptSync(args);
// Did user click Ok or Cancel?
let ok = args.ok;
if (ok) {
user.value = args.user;
pass.value = args.pass;
}
return ok;
}
nsIPrompt_promptPassword(channel, title, text, pass) {
if (!title) {
title = InternalPromptUtils.getLocalizedString("PromptPassword3", [
InternalPromptUtils.getBrandFullName(),
]);
}
let args = {
channel,
promptType: "promptPassword",
title,
text,
pass: this.async ? pass : pass.value,
button0Label: InternalPromptUtils.getLocalizedString("SignIn"),
ok: false,
};
if (this.async) {
return this.openPromptAsync(args, result => ({
pass: result.pass,
ok: result.ok,
}));
}
this.openPromptSync(args);
// Did user click Ok or Cancel?
let ok = args.ok;
if (ok) {
pass.value = args.pass;
}
return ok;
}
select(title, text, list, selected) {
if (!title) {
title = InternalPromptUtils.getLocalizedString("Select");
}
let args = {
promptType: "select",
title,
text,
list,
selected: -1,
ok: false,
};
if (this.async) {
return this.openPromptAsync(args, result => ({
selected: result.selected,
ok: result.ok,
}));
}
this.openPromptSync(args);
// Did user click Ok or Cancel?
let ok = args.ok;
if (ok) {
selected.value = args.selected;
}
return ok;
}
/* ---------- nsIAuthPrompt ---------- */
nsIAuthPrompt_prompt(
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(
title,
text,
passwordRealm,
savePassword,
user,
pass
) {
// The passwordRealm and savePassword args were ignored by nsPrompt.cpp
return this.nsIPrompt_promptUsernameAndPassword(
null,
title,
text,
user,
pass
);
}
nsIAuthPrompt_promptPassword(title, text, passwordRealm, savePassword, pass) {
// The passwordRealm and savePassword args were ignored by nsPrompt.cpp,
// and we don't have a channel here.
return this.nsIPrompt_promptPassword(null, title, text, pass);
}
/* ---------- nsIAuthPrompt2 ---------- */
promptAuth(channel, level, authInfo) {
let message = InternalPromptUtils.makeAuthMessage(this, channel, authInfo);
let [username, password] = InternalPromptUtils.getAuthInfo(authInfo);
let userParam = this.async ? username : { value: username };
let passParam = this.async ? password : { value: password };
let result;
if (authInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD) {
result = this.nsIPrompt_promptPassword(channel, null, message, passParam);
} else {
result = this.nsIPrompt_promptUsernameAndPassword(
channel,
null,
message,
userParam,
passParam
);
}
// For the async case result is an nsIPropertyBag with prompt results.
if (this.async) {
return result.then(bag => {
let ok = bag.getProperty("ok");
if (ok) {
InternalPromptUtils.setAuthInfo(
authInfo,
bag.getProperty("user"),
bag.getProperty("pass")
);
}
return ok;
});
}
// For the sync case result is the "ok" boolean which indicates whether
// the user has confirmed the dialog.
if (result) {
InternalPromptUtils.setAuthInfo(
authInfo,
userParam.value,
passParam.value
);
}
return result;
}
asyncPromptAuth() {
// 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 Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
}
/* ---------- nsIWritablePropertyBag2 ---------- */
// Legacy way to set modal type when prompting via nsIPrompt.
// Please prompt via nsIPromptService. This will be removed in the future.
setPropertyAsUint32(name, value) {
if (name == "modalType") {
this.modalType = value;
} else {
throw Components.Exception("", Cr.NS_ERROR_ILLEGAL_VALUE);
}
}
}
XPCOMUtils.defineLazyPreferenceGetter(
ModalPrompter,
"defaultModalType",
"prompts.defaultModalType",
MODAL_TYPE_WINDOW
);
export function AuthPromptAdapterFactory() {}
AuthPromptAdapterFactory.prototype = {
classID: Components.ID("{6e134924-6c3a-4d86-81ac-69432dd971dc}"),
QueryInterface: ChromeUtils.generateQI(["nsIAuthPromptAdapterFactory"]),
/* ---------- nsIAuthPromptAdapterFactory ---------- */
createAdapter(oldPrompter) {
return new AuthPromptAdapter(oldPrompter);
},
};
// Takes an nsIAuthPrompt implementation, wraps it with a nsIAuthPrompt2 shell.
function AuthPromptAdapter(oldPrompter) {
this.oldPrompter = oldPrompter;
}
AuthPromptAdapter.prototype = {
QueryInterface: ChromeUtils.generateQI(["nsIAuthPrompt2"]),
oldPrompter: null,
/* ---------- nsIAuthPrompt2 ---------- */
promptAuth(channel, level, authInfo) {
let message = InternalPromptUtils.makeAuthMessage(
this.oldPrompter,
channel,
authInfo
);
let [username, password] = InternalPromptUtils.getAuthInfo(authInfo);
let userParam = { value: username };
let passParam = { value: password };
let { displayHost, realm } = InternalPromptUtils.getAuthTarget(
channel,
authInfo
);
let authTarget = displayHost + " (" + 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) {
InternalPromptUtils.setAuthInfo(
authInfo,
userParam.value,
passParam.value
);
}
return ok;
},
asyncPromptAuth() {
throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
},
};