mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 575485 - Refactor commonDialog code into a sharable JSM (Part 3, JSM). r=gavin, a=beltzner
This commit is contained in:
parent
7c7936c1a3
commit
a6bc82164a
@ -45,112 +45,56 @@ const Cc = Components.classes;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/CommonDialog.jsm");
|
||||
|
||||
let gArgs, promptType, numButtons, iconClass, soundID, hasInputField = true;
|
||||
let gDelayExpired = false, gBlurred = false;
|
||||
let propBag, args, Dialog;
|
||||
|
||||
function earlyInit() {
|
||||
// This is called before onload fires, so we can't be certain that any elements
|
||||
// in the document have their bindings ready, so don't call any methods/properties
|
||||
// here on xul elements that come from xbl bindings.
|
||||
|
||||
gArgs = window.arguments[0].QueryInterface(Ci.nsIWritablePropertyBag2)
|
||||
.QueryInterface(Ci.nsIWritablePropertyBag);
|
||||
|
||||
promptType = gArgs.getProperty("promptType");
|
||||
|
||||
switch (promptType) {
|
||||
case "alert":
|
||||
case "alertCheck":
|
||||
hasInputField = false;
|
||||
numButtons = 1;
|
||||
iconClass = "alert-icon";
|
||||
soundID = Ci.nsISound.EVENT_ALERT_DIALOG_OPEN;
|
||||
break;
|
||||
case "confirmCheck":
|
||||
case "confirm":
|
||||
hasInputField = false;
|
||||
numButtons = 2;
|
||||
iconClass = "question-icon";
|
||||
soundID = Ci.nsISound.EVENT_CONFIRM_DIALOG_OPEN;
|
||||
break;
|
||||
case "confirmEx":
|
||||
numButtons = 0;
|
||||
if (gArgs.hasKey("button0Label"))
|
||||
numButtons++;
|
||||
if (gArgs.hasKey("button1Label"))
|
||||
numButtons++;
|
||||
if (gArgs.hasKey("button2Label"))
|
||||
numButtons++;
|
||||
if (gArgs.hasKey("button3Label"))
|
||||
numButtons++;
|
||||
if (numButtons == 0)
|
||||
throw "A dialog with no buttons? Can not haz.";
|
||||
hasInputField = false;
|
||||
iconClass = "question-icon";
|
||||
soundID = Ci.nsISound.EVENT_CONFIRM_DIALOG_OPEN;
|
||||
break;
|
||||
case "prompt":
|
||||
numButtons = 2;
|
||||
iconClass = "question-icon";
|
||||
soundID = Ci.nsISound.EVENT_PROMPT_DIALOG_OPEN;
|
||||
initTextbox("login", gArgs.getProperty("value"));
|
||||
// Clear the label, since this isn't really a username prompt.
|
||||
document.getElementById("loginLabel").setAttribute("value", "");
|
||||
break;
|
||||
case "promptUserAndPass":
|
||||
numButtons = 2;
|
||||
iconClass = "authentication-icon question-icon";
|
||||
soundID = Ci.nsISound.EVENT_PROMPT_DIALOG_OPEN;
|
||||
initTextbox("login", gArgs.getProperty("user"));
|
||||
initTextbox("password1", gArgs.getProperty("pass"));
|
||||
break;
|
||||
case "promptPassword":
|
||||
numButtons = 2;
|
||||
iconClass = "authentication-icon question-icon";
|
||||
soundID = Ci.nsISound.EVENT_PROMPT_DIALOG_OPEN;
|
||||
initTextbox("password1", gArgs.getProperty("pass"));
|
||||
// Clear the label, since the message presumably indicates its purpose.
|
||||
document.getElementById("password1Label").setAttribute("value", "");
|
||||
break;
|
||||
default:
|
||||
Cu.reportError("commonDialog opened for unknown type: " + promptType);
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
|
||||
function initTextbox(aName, aValue) {
|
||||
document.getElementById(aName + "Container").hidden = false;
|
||||
document.getElementById(aName + "Textbox").setAttribute("value", aValue);
|
||||
}
|
||||
|
||||
function setLabelForNode(aNode, aLabel) {
|
||||
// This is for labels which may contain embedded access keys.
|
||||
// If we end in (&X) where X represents the access key, optionally preceded
|
||||
// by spaces and/or followed by the ':' character, store the access key and
|
||||
// remove the access key placeholder + leading spaces from the label.
|
||||
// Otherwise a character preceded by one but not two &s is the access key.
|
||||
// Store it and remove the &.
|
||||
|
||||
// Note that if you change the following code, see the comment of
|
||||
// nsTextBoxFrame::UpdateAccessTitle.
|
||||
var accessKey = null;
|
||||
if (/ *\(\&([^&])\)(:)?$/.test(aLabel)) {
|
||||
aLabel = RegExp.leftContext + RegExp.$2;
|
||||
accessKey = RegExp.$1;
|
||||
} else if (/^(.*[^&])?\&(([^&]).*$)/.test(aLabel)) {
|
||||
aLabel = RegExp.$1 + RegExp.$2;
|
||||
accessKey = RegExp.$3;
|
||||
function commonDialogOnLoad() {
|
||||
propBag = window.arguments[0].QueryInterface(Ci.nsIWritablePropertyBag2)
|
||||
.QueryInterface(Ci.nsIWritablePropertyBag);
|
||||
// Convert to a JS object
|
||||
args = {};
|
||||
let propEnum = propBag.enumerator;
|
||||
while (propEnum.hasMoreElements()) {
|
||||
let prop = propEnum.getNext().QueryInterface(Ci.nsIProperty);
|
||||
args[prop.name] = prop.value;
|
||||
}
|
||||
|
||||
// && is the magic sequence to embed an & in your label.
|
||||
aLabel = aLabel.replace(/\&\&/g, "&");
|
||||
aNode.label = aLabel;
|
||||
let dialog = document.documentElement;
|
||||
|
||||
// XXXjag bug 325251
|
||||
// Need to set this after aNode.setAttribute("value", aLabel);
|
||||
if (accessKey)
|
||||
aNode.accessKey = accessKey;
|
||||
let ui = {
|
||||
loginContainer : document.getElementById("loginContainer"),
|
||||
loginTextbox : document.getElementById("loginTextbox"),
|
||||
loginLabel : document.getElementById("loginLabel"),
|
||||
password1Container : document.getElementById("password1Container"),
|
||||
password1Textbox : document.getElementById("password1Textbox"),
|
||||
password1Label : document.getElementById("password1Label"),
|
||||
infoBody : document.getElementById("info.body"),
|
||||
infoTitle : document.getElementById("info.title"),
|
||||
infoIcon : document.getElementById("info.icon"),
|
||||
checkbox : document.getElementById("checkbox"),
|
||||
checkboxContainer : document.getElementById("checkboxContainer"),
|
||||
button3 : dialog.getButton("extra2"),
|
||||
button2 : dialog.getButton("extra1"),
|
||||
button1 : dialog.getButton("cancel"),
|
||||
button0 : dialog.getButton("accept"),
|
||||
focusTarget : window,
|
||||
};
|
||||
|
||||
// limit the dialog to the screen width
|
||||
document.getElementById("filler").maxWidth = screen.availWidth;
|
||||
Services.obs.addObserver(softkbObserver, "softkb-change", false);
|
||||
|
||||
Dialog = new CommonDialog(args, ui);
|
||||
Dialog.onLoad(dialog);
|
||||
window.getAttention();
|
||||
}
|
||||
|
||||
function commonDialogOnUnload() {
|
||||
Services.obs.removeObserver(softkbObserver, "softkb-change");
|
||||
// Convert args back into property bag
|
||||
for (let propName in args)
|
||||
propBag.setProperty(propName, args[propName]);
|
||||
}
|
||||
|
||||
function softkbObserver(subject, topic, data) {
|
||||
@ -163,179 +107,3 @@ function softkbObserver(subject, topic, data) {
|
||||
window.moveTo(left, top);
|
||||
}
|
||||
}
|
||||
|
||||
function commonDialogOnLoad() {
|
||||
// limit the dialog to the screen width
|
||||
document.getElementById("filler").maxWidth = screen.availWidth;
|
||||
|
||||
// set the document title
|
||||
let title = gArgs.getProperty("title");
|
||||
document.title = title;
|
||||
// OS X doesn't have a title on modal dialogs, this is hidden on other platforms.
|
||||
document.getElementById("info.title").appendChild(document.createTextNode(title));
|
||||
|
||||
Services.obs.addObserver(softkbObserver, "softkb-change", false);
|
||||
|
||||
// Set button labels and visibility
|
||||
let dialog = document.documentElement;
|
||||
switch (numButtons) {
|
||||
case 4:
|
||||
setLabelForNode(dialog.getButton("extra2"), gArgs.getProperty("button3Label"));
|
||||
dialog.getButton("extra2").hidden = false;
|
||||
// fall through
|
||||
case 3:
|
||||
setLabelForNode(dialog.getButton("extra1"), gArgs.getProperty("button2Label"));
|
||||
dialog.getButton("extra1").hidden = false;
|
||||
// fall through
|
||||
case 2:
|
||||
if (gArgs.hasKey("button1Label"))
|
||||
setLabelForNode(dialog.getButton("cancel"), gArgs.getProperty("button1Label"));
|
||||
break;
|
||||
|
||||
case 1:
|
||||
dialog.getButton("cancel").hidden = true;
|
||||
break;
|
||||
}
|
||||
if (gArgs.hasKey("button0Label"))
|
||||
setLabelForNode(dialog.getButton("accept"), gArgs.getProperty("button0Label"));
|
||||
|
||||
// display the main text
|
||||
// Bug 317334 - crop string length as a workaround.
|
||||
let croppedMessage = gArgs.getProperty("text").substr(0, 10000);
|
||||
document.getElementById("info.body").appendChild(document.createTextNode(croppedMessage));
|
||||
|
||||
if (gArgs.hasKey("checkLabel")) {
|
||||
let label = gArgs.getProperty("checkLabel")
|
||||
// Only show the checkbox if label has a value.
|
||||
if (label) {
|
||||
document.getElementById("checkboxContainer").hidden = false;
|
||||
let checkboxElement = document.getElementById("checkbox");
|
||||
setLabelForNode(checkboxElement, label);
|
||||
checkboxElement.checked = gArgs.getProperty("checked");
|
||||
}
|
||||
}
|
||||
|
||||
// set the icon
|
||||
document.getElementById("info.icon").className += " " + iconClass;
|
||||
|
||||
// set default result to cancelled
|
||||
gArgs.setProperty("ok", false);
|
||||
gArgs.setProperty("buttonNumClicked", 1);
|
||||
|
||||
|
||||
// If there are no input fields on the dialog, select the default button.
|
||||
// Otherwise, select the appropriate input field.
|
||||
if (!hasInputField) {
|
||||
let dlgButtons = ['accept', 'cancel', 'extra1', 'extra2'];
|
||||
|
||||
// Set the default button and focus it on non-OS X systems
|
||||
let b = 0;
|
||||
if (gArgs.hasKey("defaultButtonNum"))
|
||||
b = gArgs.getProperty("defaultButtonNum");
|
||||
let dButton = dlgButtons[b];
|
||||
// XXX shouldn't we set the default even when a textbox is focused?
|
||||
dialog.defaultButton = dButton;
|
||||
#ifndef XP_MACOSX
|
||||
dialog.getButton(dButton).focus();
|
||||
#endif
|
||||
} else {
|
||||
if (promptType == "promptPassword")
|
||||
document.getElementById("password1Textbox").select();
|
||||
else
|
||||
document.getElementById("loginTextbox").select();
|
||||
}
|
||||
|
||||
if (gArgs.hasKey("enableDelay") && gArgs.getProperty("enableDelay")) {
|
||||
let delayInterval = Services.prefs.getIntPref("security.dialog_enable_delay");
|
||||
setButtonsEnabledState(dialog, false);
|
||||
setTimeout(function () {
|
||||
// Don't automatically enable the buttons if we're not in the foreground
|
||||
if (!gBlurred)
|
||||
setButtonsEnabledState(dialog, true);
|
||||
gDelayExpired = true;
|
||||
}, delayInterval);
|
||||
|
||||
addEventListener("blur", commonDialogBlur, false);
|
||||
addEventListener("focus", commonDialogFocus, false);
|
||||
}
|
||||
|
||||
window.getAttention();
|
||||
|
||||
// play sound
|
||||
try {
|
||||
if (soundID) {
|
||||
Cc["@mozilla.org/sound;1"].
|
||||
createInstance(Ci.nsISound).
|
||||
playEventSound(soundID);
|
||||
}
|
||||
} catch (e) { }
|
||||
|
||||
Services.obs.notifyObservers(window, "common-dialog-loaded", null);
|
||||
}
|
||||
|
||||
function setButtonsEnabledState(dialog, enabled) {
|
||||
dialog.getButton("accept").disabled = !enabled;
|
||||
dialog.getButton("extra1").disabled = !enabled;
|
||||
dialog.getButton("extra2").disabled = !enabled;
|
||||
}
|
||||
|
||||
function commonDialogOnUnload() {
|
||||
Services.obs.removeObserver(softkbObserver, "softkb-change");
|
||||
}
|
||||
|
||||
function commonDialogBlur(aEvent) {
|
||||
if (aEvent.target != document)
|
||||
return;
|
||||
gBlurred = true;
|
||||
let dialog = document.documentElement;
|
||||
setButtonsEnabledState(dialog, false);
|
||||
}
|
||||
|
||||
function commonDialogFocus(aEvent) {
|
||||
if (aEvent.target != document)
|
||||
return;
|
||||
gBlurred = false;
|
||||
let dialog = document.documentElement;
|
||||
// When refocusing the window, don't enable the buttons unless the countdown
|
||||
// delay has expired.
|
||||
if (gDelayExpired)
|
||||
setTimeout(setButtonsEnabledState, 250, dialog, true);
|
||||
}
|
||||
|
||||
function onCheckboxClick(aCheckboxElement) {
|
||||
gArgs.setProperty("checked", aCheckboxElement.checked);
|
||||
}
|
||||
|
||||
function commonDialogOnAccept() {
|
||||
gArgs.setProperty("ok", true);
|
||||
gArgs.setProperty("buttonNumClicked", 0);
|
||||
|
||||
let username = document.getElementById("loginTextbox").value;
|
||||
let password = document.getElementById("password1Textbox").value;
|
||||
|
||||
// Return textfield values
|
||||
switch (promptType) {
|
||||
case "prompt":
|
||||
gArgs.setProperty("value", username);
|
||||
break;
|
||||
case "promptUserAndPass":
|
||||
gArgs.setProperty("user", username);
|
||||
gArgs.setProperty("pass", password);
|
||||
break;
|
||||
case "promptPassword":
|
||||
gArgs.setProperty("pass", password);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function commonDialogOnExtra1() {
|
||||
// .setProperty("ok", true)?
|
||||
gArgs.setProperty("buttonNumClicked", 2);
|
||||
window.close();
|
||||
}
|
||||
|
||||
function commonDialogOnExtra2() {
|
||||
// .setProperty("ok", true)?
|
||||
gArgs.setProperty("buttonNumClicked", 3);
|
||||
window.close();
|
||||
}
|
||||
|
@ -11,9 +11,10 @@
|
||||
aria-describedby="info.body"
|
||||
onload="commonDialogOnLoad();"
|
||||
onunload="commonDialogOnUnload();"
|
||||
ondialogaccept="return commonDialogOnAccept();"
|
||||
ondialogextra1="return commonDialogOnExtra1();"
|
||||
ondialogextra2="return commonDialogOnExtra2();"
|
||||
ondialogaccept="Dialog.onButton0(); return true;"
|
||||
ondialogcancel="Dialog.onButton1(); return true;"
|
||||
ondialogextra1="Dialog.onButton2(); window.close();"
|
||||
ondialogextra2="Dialog.onButton3(); window.close();"
|
||||
buttonpack="center">
|
||||
|
||||
<script type="application/javascript" src="chrome://global/content/commonDialog.js"/>
|
||||
@ -75,16 +76,9 @@
|
||||
</row>
|
||||
<row id="checkboxContainer" hidden="true">
|
||||
<spacer/>
|
||||
<checkbox id="checkbox" oncommand="onCheckboxClick(this);"/>
|
||||
<checkbox id="checkbox" oncommand="Dialog.onCheckbox()"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
|
||||
|
||||
<!-- This method is called inline because it may unset hidden="true" on the
|
||||
above boxes, causing their frames to be build and bindings to load.
|
||||
So, by calling this inline, we guarantee the textboxes and checkboxes
|
||||
above will have their bindings before initButtons is called, and the
|
||||
dialog will be intrinsically sized correctly. -->
|
||||
<script type="application/javascript">earlyInit();</script>
|
||||
</dialog>
|
||||
|
350
toolkit/components/prompts/src/CommonDialog.jsm
Normal file
350
toolkit/components/prompts/src/CommonDialog.jsm
Normal file
@ -0,0 +1,350 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is CommonDialog.jsm code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Justin Dolske <dolske@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
var EXPORTED_SYMBOLS = ["CommonDialog"];
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
const Cc = Components.classes;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
|
||||
function CommonDialog(args, ui) {
|
||||
this.args = args;
|
||||
this.ui = ui;
|
||||
}
|
||||
|
||||
CommonDialog.prototype = {
|
||||
args : null,
|
||||
ui : null,
|
||||
|
||||
hasInputField : true,
|
||||
numButtons : undefined,
|
||||
iconClass : undefined,
|
||||
soundID : undefined,
|
||||
focusTimer : null,
|
||||
|
||||
onLoad : function(xulDialog) {
|
||||
switch (this.args.promptType) {
|
||||
case "alert":
|
||||
case "alertCheck":
|
||||
this.hasInputField = false;
|
||||
this.numButtons = 1;
|
||||
this.iconClass = ["alert-icon"];
|
||||
this.soundID = Ci.nsISound.EVENT_ALERT_DIALOG_OPEN;
|
||||
break;
|
||||
case "confirmCheck":
|
||||
case "confirm":
|
||||
this.hasInputField = false;
|
||||
this.numButtons = 2;
|
||||
this.iconClass = ["question-icon"];
|
||||
this.soundID = Ci.nsISound.EVENT_CONFIRM_DIALOG_OPEN;
|
||||
break;
|
||||
case "confirmEx":
|
||||
var numButtons = 0;
|
||||
if (this.args.button0Label)
|
||||
numButtons++;
|
||||
if (this.args.button1Label)
|
||||
numButtons++;
|
||||
if (this.args.button2Label)
|
||||
numButtons++;
|
||||
if (this.args.button3Label)
|
||||
numButtons++;
|
||||
if (numButtons == 0)
|
||||
throw "A dialog with no buttons? Can not haz.";
|
||||
this.numButtons = numButtons;
|
||||
this.hasInputField = false;
|
||||
this.iconClass = ["question-icon"];
|
||||
this.soundID = Ci.nsISound.EVENT_CONFIRM_DIALOG_OPEN;
|
||||
break;
|
||||
case "prompt":
|
||||
this.numButtons = 2;
|
||||
this.iconClass = ["question-icon"];
|
||||
this.soundID = Ci.nsISound.EVENT_PROMPT_DIALOG_OPEN;
|
||||
this.initTextbox("login", this.args.value);
|
||||
// Clear the label, since this isn't really a username prompt.
|
||||
this.ui.loginLabel.setAttribute("value", "");
|
||||
break;
|
||||
case "promptUserAndPass":
|
||||
this.numButtons = 2;
|
||||
this.iconClass = ["authentication-icon", "question-icon"];
|
||||
this.soundID = Ci.nsISound.EVENT_PROMPT_DIALOG_OPEN;
|
||||
this.initTextbox("login", this.args.user);
|
||||
this.initTextbox("password1", this.args.pass);
|
||||
break;
|
||||
case "promptPassword":
|
||||
this.numButtons = 2;
|
||||
this.iconClass = ["authentication-icon", "question-icon"];
|
||||
this.soundID = Ci.nsISound.EVENT_PROMPT_DIALOG_OPEN;
|
||||
this.initTextbox("password1", this.args.pass);
|
||||
// Clear the label, since the message presumably indicates its purpose.
|
||||
this.ui.password1Label.setAttribute("value", "");
|
||||
break;
|
||||
default:
|
||||
Cu.reportError("commonDialog opened for unknown type: " + this.args.promptType);
|
||||
throw "unknown dialog type";
|
||||
}
|
||||
|
||||
// set the document title
|
||||
let title = this.args.title;
|
||||
// OS X doesn't have a title on modal dialogs, this is hidden on other platforms.
|
||||
let infoTitle = this.ui.infoTitle;
|
||||
infoTitle.appendChild(infoTitle.ownerDocument.createTextNode(title));
|
||||
if (xulDialog)
|
||||
xulDialog.ownerDocument.title = title;
|
||||
|
||||
// Set button labels and visibility
|
||||
//
|
||||
// This assumes that button0 defaults to a visible "ok" button, and
|
||||
// button1 defaults to a visible "cancel" button. The other 2 buttons
|
||||
// have no default labels (and are hidden).
|
||||
switch (this.numButtons) {
|
||||
case 4:
|
||||
this.setLabelForNode(this.ui.button3, this.args.button3Label);
|
||||
this.ui.button3.hidden = false;
|
||||
// fall through
|
||||
case 3:
|
||||
this.setLabelForNode(this.ui.button2, this.args.button2Label);
|
||||
this.ui.button2.hidden = false;
|
||||
// fall through
|
||||
case 2:
|
||||
// Defaults to a visible "cancel" button
|
||||
if (this.args.button1Label)
|
||||
this.setLabelForNode(this.ui.button1, this.args.button1Label);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
this.ui.button1.hidden = true;
|
||||
break;
|
||||
}
|
||||
// Defaults to a visible "ok" button
|
||||
if (this.args.button0Label)
|
||||
this.setLabelForNode(this.ui.button0, this.args.button0Label);
|
||||
|
||||
// display the main text
|
||||
// Bug 317334 - crop string length as a workaround.
|
||||
let croppedMessage = this.args.text.substr(0, 10000);
|
||||
let infoBody = this.ui.infoBody;
|
||||
infoBody.appendChild(infoBody.ownerDocument.createTextNode(croppedMessage));
|
||||
|
||||
let label = this.args.checkLabel;
|
||||
if (label) {
|
||||
// Only show the checkbox if label has a value.
|
||||
this.ui.checkboxContainer.hidden = false;
|
||||
this.setLabelForNode(this.ui.checkbox, label);
|
||||
this.ui.checkbox.checked = this.args.checked;
|
||||
}
|
||||
|
||||
// set the icon
|
||||
let icon = this.ui.infoIcon;
|
||||
this.iconClass.forEach(function(el,idx,arr) icon.classList.add(el));
|
||||
|
||||
// set default result to cancelled
|
||||
this.args.ok = false;
|
||||
this.args.buttonNumClicked = 1;
|
||||
|
||||
|
||||
// If there are no input fields on the dialog, select the default button.
|
||||
// Otherwise, select the appropriate input field.
|
||||
// XXX shouldn't we set an unfocused default even when a textbox is focused?
|
||||
if (!this.hasInputField) {
|
||||
// Set the default button (and focus it on non-OS X systems)
|
||||
let b = 0;
|
||||
if (this.args.defaultButtonNum)
|
||||
b = this.args.defaultButtonNum;
|
||||
let button = this.ui["button" + b];
|
||||
if (xulDialog) {
|
||||
xulDialog.defaultButton = ['accept', 'cancel', 'extra1', 'extra2'][b];
|
||||
let isOSX = ("nsILocalFileMac" in Components.interfaces);
|
||||
if (!isOSX)
|
||||
button.focus();
|
||||
}
|
||||
// TODO:
|
||||
// else
|
||||
// (tabmodal prompts need to set a default button for Enter to act upon)
|
||||
} else {
|
||||
if (this.args.promptType == "promptPassword")
|
||||
this.ui.password1Textbox.select();
|
||||
else
|
||||
this.ui.loginTextbox.select();
|
||||
}
|
||||
|
||||
if (this.args.enableDelay) {
|
||||
this.setButtonsEnabledState(false);
|
||||
// Use a longer, pref-controlled delay when the dialog is first opened.
|
||||
let delayTime = Services.prefs.getIntPref("security.dialog_enable_delay");
|
||||
this.startOnFocusDelay(delayTime);
|
||||
let self = this;
|
||||
this.ui.focusTarget.addEventListener("blur", function(e) { self.onBlur(e); }, false);
|
||||
this.ui.focusTarget.addEventListener("focus", function(e) { self.onFocus(e); }, false);
|
||||
}
|
||||
|
||||
// play sound
|
||||
try {
|
||||
if (this.soundID) {
|
||||
Cc["@mozilla.org/sound;1"].
|
||||
createInstance(Ci.nsISound).
|
||||
playEventSound(soundID);
|
||||
}
|
||||
} catch (e) { }
|
||||
|
||||
if (xulDialog)
|
||||
Services.obs.notifyObservers(xulDialog.ownerDocument.defaultView, "common-dialog-loaded", null);
|
||||
// TODO:
|
||||
// else
|
||||
// (notify using what as the subject?)
|
||||
},
|
||||
|
||||
setLabelForNode: function(aNode, aLabel) {
|
||||
// This is for labels which may contain embedded access keys.
|
||||
// If we end in (&X) where X represents the access key, optionally preceded
|
||||
// by spaces and/or followed by the ':' character, store the access key and
|
||||
// remove the access key placeholder + leading spaces from the label.
|
||||
// Otherwise a character preceded by one but not two &s is the access key.
|
||||
// Store it and remove the &.
|
||||
|
||||
// Note that if you change the following code, see the comment of
|
||||
// nsTextBoxFrame::UpdateAccessTitle.
|
||||
var accessKey = null;
|
||||
if (/ *\(\&([^&])\)(:)?$/.test(aLabel)) {
|
||||
aLabel = RegExp.leftContext + RegExp.$2;
|
||||
accessKey = RegExp.$1;
|
||||
} else if (/^(.*[^&])?\&(([^&]).*$)/.test(aLabel)) {
|
||||
aLabel = RegExp.$1 + RegExp.$2;
|
||||
accessKey = RegExp.$3;
|
||||
}
|
||||
|
||||
// && is the magic sequence to embed an & in your label.
|
||||
aLabel = aLabel.replace(/\&\&/g, "&");
|
||||
aNode.label = aLabel;
|
||||
|
||||
// XXXjag bug 325251
|
||||
// Need to set this after aNode.setAttribute("value", aLabel);
|
||||
if (accessKey)
|
||||
aNode.accessKey = accessKey;
|
||||
},
|
||||
|
||||
|
||||
initTextbox : function (aName, aValue) {
|
||||
this.ui[aName + "Container"].hidden = false;
|
||||
this.ui[aName + "Textbox"].setAttribute("value", aValue);
|
||||
},
|
||||
|
||||
setButtonsEnabledState : function(enabled) {
|
||||
this.ui.button0.disabled = !enabled;
|
||||
// button1 (cancel) remains enabled.
|
||||
this.ui.button2.disabled = !enabled;
|
||||
this.ui.button3.disabled = !enabled;
|
||||
},
|
||||
|
||||
onBlur : function (aEvent) {
|
||||
if (aEvent.target != this.ui.focusTarget)
|
||||
return;
|
||||
this.setButtonsEnabledState(false);
|
||||
|
||||
// If we blur while waiting to enable the buttons, just cancel the
|
||||
// timer to ensure the delay doesn't fire while not focused.
|
||||
if (this.focusTimer) {
|
||||
this.focusTimer.cancel();
|
||||
this.focusTimer = null;
|
||||
}
|
||||
},
|
||||
|
||||
onFocus : function (aEvent) {
|
||||
if (aEvent.target != this.ui.focusTarget)
|
||||
return;
|
||||
this.startOnFocusDelay();
|
||||
},
|
||||
|
||||
startOnFocusDelay : function(delayTime) {
|
||||
// Shouldn't already have a timer, but just in case...
|
||||
if (this.focusTimer)
|
||||
return;
|
||||
// If no delay specified, use 250ms. (This is the normal case for when
|
||||
// after the dialog has been opened and focus shifts.)
|
||||
if (!delayTime)
|
||||
delayTime = 250;
|
||||
let self = this;
|
||||
this.focusTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
this.focusTimer.initWithCallback(function() { self.onFocusTimeout(); },
|
||||
delayTime, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
},
|
||||
|
||||
onFocusTimeout : function() {
|
||||
this.focusTimer = null;
|
||||
this.setButtonsEnabledState(true);
|
||||
},
|
||||
|
||||
onCheckbox : function() {
|
||||
this.args.checked = this.ui.checkbox.checked;
|
||||
},
|
||||
|
||||
onButton0 : function() {
|
||||
this.args.ok = true;
|
||||
this.args.buttonNumClicked = 0;
|
||||
|
||||
let username = this.ui.loginTextbox.value;
|
||||
let password = this.ui.password1Textbox.value;
|
||||
|
||||
// Return textfield values
|
||||
switch (this.args.promptType) {
|
||||
case "prompt":
|
||||
this.args.value = username;
|
||||
break;
|
||||
case "promptUserAndPass":
|
||||
this.args.user = username;
|
||||
this.args.pass = password;
|
||||
break;
|
||||
case "promptPassword":
|
||||
this.args.pass = password;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
onButton1 : function() {
|
||||
this.args.buttonNumClicked = 1;
|
||||
},
|
||||
|
||||
onButton2 : function() {
|
||||
this.args.buttonNumClicked = 2;
|
||||
},
|
||||
|
||||
onButton3 : function() {
|
||||
this.args.buttonNumClicked = 3;
|
||||
},
|
||||
};
|
@ -48,4 +48,8 @@ EXTRA_COMPONENTS = \
|
||||
nsPrompter.manifest \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_JS_MODULES = \
|
||||
CommonDialog.jsm \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -24,6 +24,20 @@ let prompter = Cc["@mozilla.org/embedcomp/prompt-service;1"].
|
||||
getService(Ci.nsIPromptService2);
|
||||
let ioService = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
let pollTimer;
|
||||
|
||||
function pollDialog(dialog) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
if (dialog.getButton("accept").disabled)
|
||||
return;
|
||||
|
||||
ok(true, "dialog button is enabled now");
|
||||
pollTimer.cancel();
|
||||
pollTimer = null;
|
||||
dialog.acceptDialog();
|
||||
didDialog = true;
|
||||
}
|
||||
|
||||
function checkExpectedState(doc, state) {
|
||||
let msg = doc.getElementById("info.body").textContent;
|
||||
@ -654,6 +668,27 @@ function handleDialog(doc, testNum) {
|
||||
checkExpectedState(doc, state);
|
||||
break;
|
||||
|
||||
case 30:
|
||||
// ConfirmEx (with delay, ok)
|
||||
state = {
|
||||
msg : "This is the confirmEx delay text.",
|
||||
title : "TestTitle",
|
||||
iconClass : "question-icon",
|
||||
textHidden : true,
|
||||
passHidden : true,
|
||||
checkHidden : true,
|
||||
textValue : "",
|
||||
passValue : "",
|
||||
checkMsg : "",
|
||||
checked : false,
|
||||
};
|
||||
is(dialog.getButton("accept").label, "OK", "Checking accept-button label");
|
||||
is(dialog.getButton("cancel").label, "Cancel", "Checking cancel-button label");
|
||||
is(dialog.getButton("accept").disabled, true, "Checking accept-button is disabled");
|
||||
is(dialog.getButton("cancel").disabled, false, "Checking cancel-button isn't disabled ");
|
||||
checkExpectedState(doc, state);
|
||||
break;
|
||||
|
||||
|
||||
case 100:
|
||||
// PromptAuth (no realm, ok, with checkbox)
|
||||
@ -711,6 +746,14 @@ function handleDialog(doc, testNum) {
|
||||
|
||||
if (testNum == 28) {
|
||||
dialog._doButtonCommand("extra1");
|
||||
} else if (testNum == 30) {
|
||||
// Buttons are disabled at the moment, poll until they're reenabled.
|
||||
// Can't use setInterval here, because the window's in a modal state
|
||||
// and thus DOM events are suppressed.
|
||||
pollTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
pollTimer.initWithCallback(function() { pollDialog(dialog); },
|
||||
100, Ci.nsITimer.TYPE_REPEATING_SLACK);
|
||||
return;
|
||||
} else {
|
||||
if (clickOK)
|
||||
dialog.acceptDialog();
|
||||
@ -1049,6 +1092,15 @@ prompter.alert(null, "TestTitle", "This is the alert text.");
|
||||
ok(didDialog, "handleDialog was invoked");
|
||||
|
||||
|
||||
// ===== test 30 =====
|
||||
// ConfirmEx (delay, ok)
|
||||
testNum++;
|
||||
startCallbackTimer();
|
||||
flags = (Ci.nsIPromptService.STD_OK_CANCEL_BUTTONS | Ci.nsIPromptService.BUTTON_DELAY_ENABLE);
|
||||
clickedButton = prompter.confirmEx(window, "TestTitle", "This is the confirmEx delay text.", flags, null, null, null, null, {});
|
||||
is(clickedButton, 0, "checked expected button num click");
|
||||
ok(didDialog, "handleDialog was invoked");
|
||||
|
||||
// promptAuth already tested via password manager but do a few specific things here.
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user