diff options
Diffstat (limited to 'toolkit/content/widgets/dialog.xml')
-rw-r--r-- | toolkit/content/widgets/dialog.xml | 448 |
1 files changed, 448 insertions, 0 deletions
diff --git a/toolkit/content/widgets/dialog.xml b/toolkit/content/widgets/dialog.xml new file mode 100644 index 000000000..d83570ac0 --- /dev/null +++ b/toolkit/content/widgets/dialog.xml @@ -0,0 +1,448 @@ +<?xml version="1.0"?> +<!-- 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/. --> + + +<bindings id="dialogBindings" + xmlns="http://www.mozilla.org/xbl" + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:xbl="http://www.mozilla.org/xbl"> + + <binding id="dialog" extends="chrome://global/content/bindings/general.xml#root-element"> + <resources> + <stylesheet src="chrome://global/skin/dialog.css"/> + </resources> + <content> + <xul:vbox class="box-inherit dialog-content-box" flex="1"> + <children/> + </xul:vbox> + + <xul:hbox class="dialog-button-box" anonid="buttons" + xbl:inherits="pack=buttonpack,align=buttonalign,dir=buttondir,orient=buttonorient" +#ifdef XP_UNIX + > + <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/> + <xul:button dlgtype="help" class="dialog-button" hidden="true"/> + <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/> + <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/> + <xul:spacer anonid="spacer" flex="1"/> + <xul:button dlgtype="cancel" class="dialog-button"/> + <xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/> +#else + pack="end"> + <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/> + <xul:spacer anonid="spacer" flex="1" hidden="true"/> + <xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/> + <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/> + <xul:button dlgtype="cancel" class="dialog-button"/> + <xul:button dlgtype="help" class="dialog-button" hidden="true"/> + <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/> +#endif + </xul:hbox> + </content> + + <implementation> + <field name="_mStrBundle">null</field> + <field name="_closeHandler">(function(event) { + if (!document.documentElement.cancelDialog()) + event.preventDefault(); + })</field> + + <property name="buttons" + onget="return this.getAttribute('buttons');" + onset="this._configureButtons(val); return val;"/> + + <property name="defaultButton"> + <getter> + <![CDATA[ + if (this.hasAttribute("defaultButton")) + return this.getAttribute("defaultButton"); + return "accept"; // default to the accept button + ]]> + </getter> + <setter> + <![CDATA[ + this._setDefaultButton(val); + return val; + ]]> + </setter> + </property> + + <method name="acceptDialog"> + <body> + <![CDATA[ + return this._doButtonCommand("accept"); + ]]> + </body> + </method> + + <method name="cancelDialog"> + <body> + <![CDATA[ + return this._doButtonCommand("cancel"); + ]]> + </body> + </method> + + <method name="getButton"> + <parameter name="aDlgType"/> + <body> + <![CDATA[ + return this._buttons[aDlgType]; + ]]> + </body> + </method> + + <method name="moveToAlertPosition"> + <body> + <![CDATA[ + // hack. we need this so the window has something like its final size + if (window.outerWidth == 1) { + dump("Trying to position a sizeless window; caller should have called sizeToContent() or sizeTo(). See bug 75649.\n"); + sizeToContent(); + } + + if (opener) { + var xOffset = (opener.outerWidth - window.outerWidth) / 2; + var yOffset = opener.outerHeight / 5; + + var newX = opener.screenX + xOffset; + var newY = opener.screenY + yOffset; + } else { + newX = (screen.availWidth - window.outerWidth) / 2; + newY = (screen.availHeight - window.outerHeight) / 2; + } + + // ensure the window is fully onscreen (if smaller than the screen) + if (newX < screen.availLeft) + newX = screen.availLeft + 20; + if ((newX + window.outerWidth) > (screen.availLeft + screen.availWidth)) + newX = (screen.availLeft + screen.availWidth) - window.outerWidth - 20; + + if (newY < screen.availTop) + newY = screen.availTop + 20; + if ((newY + window.outerHeight) > (screen.availTop + screen.availHeight)) + newY = (screen.availTop + screen.availHeight) - window.outerHeight - 60; + + window.moveTo( newX, newY ); + ]]> + </body> + </method> + + <method name="centerWindowOnScreen"> + <body> + <![CDATA[ + var xOffset = screen.availWidth/2 - window.outerWidth/2; + var yOffset = screen.availHeight/2 - window.outerHeight/2; + + xOffset = xOffset > 0 ? xOffset : 0; + yOffset = yOffset > 0 ? yOffset : 0; + window.moveTo(xOffset, yOffset); + ]]> + </body> + </method> + + <constructor> + <![CDATA[ + this._configureButtons(this.buttons); + + // listen for when window is closed via native close buttons + window.addEventListener("close", this._closeHandler, false); + + // for things that we need to initialize after onload fires + window.addEventListener("load", this.postLoadInit, false); + + window.moveToAlertPosition = this.moveToAlertPosition; + window.centerWindowOnScreen = this.centerWindowOnScreen; + ]]> + </constructor> + + <method name="postLoadInit"> + <parameter name="aEvent"/> + <body> + <![CDATA[ + function focusInit() { + const dialog = document.documentElement; + const defaultButton = dialog.getButton(dialog.defaultButton); + // give focus to the first focusable element in the dialog + if (!document.commandDispatcher.focusedElement) { + document.commandDispatcher.advanceFocusIntoSubtree(dialog); + + var focusedElt = document.commandDispatcher.focusedElement; + if (focusedElt) { + var initialFocusedElt = focusedElt; + while (focusedElt.localName == "tab" || + focusedElt.getAttribute("noinitialfocus") == "true") { + document.commandDispatcher.advanceFocusIntoSubtree(focusedElt); + focusedElt = document.commandDispatcher.focusedElement; + if (focusedElt == initialFocusedElt) + break; + } + + if (initialFocusedElt.localName == "tab") { + if (focusedElt.hasAttribute("dlgtype")) { + // We don't want to focus on anonymous OK, Cancel, etc. buttons, + // so return focus to the tab itself + initialFocusedElt.focus(); + } + } + else if (!/Mac/.test(navigator.platform) && + focusedElt.hasAttribute("dlgtype") && focusedElt != defaultButton) { + defaultButton.focus(); + } + } + } + + try { + if (defaultButton) + window.notifyDefaultButtonLoaded(defaultButton); + } catch (e) { } + } + + // Give focus after onload completes, see bug 103197. + setTimeout(focusInit, 0); + ]]> + </body> + </method> + + <property name="mStrBundle"> + <getter> + <![CDATA[ + if (!this._mStrBundle) { + // need to create string bundle manually instead of using <xul:stringbundle/> + // see bug 63370 for details + this._mStrBundle = Components.classes["@mozilla.org/intl/stringbundle;1"] + .getService(Components.interfaces.nsIStringBundleService) + .createBundle("chrome://global/locale/dialog.properties"); + } + return this._mStrBundle; + ]]></getter> + </property> + + <method name="_configureButtons"> + <parameter name="aButtons"/> + <body> + <![CDATA[ + // by default, get all the anonymous button elements + var buttons = {}; + this._buttons = buttons; + buttons.accept = document.getAnonymousElementByAttribute(this, "dlgtype", "accept"); + buttons.cancel = document.getAnonymousElementByAttribute(this, "dlgtype", "cancel"); + buttons.extra1 = document.getAnonymousElementByAttribute(this, "dlgtype", "extra1"); + buttons.extra2 = document.getAnonymousElementByAttribute(this, "dlgtype", "extra2"); + buttons.help = document.getAnonymousElementByAttribute(this, "dlgtype", "help"); + buttons.disclosure = document.getAnonymousElementByAttribute(this, "dlgtype", "disclosure"); + + // look for any overriding explicit button elements + var exBtns = this.getElementsByAttribute("dlgtype", "*"); + var dlgtype; + var i; + for (i = 0; i < exBtns.length; ++i) { + dlgtype = exBtns[i].getAttribute("dlgtype"); + buttons[dlgtype].hidden = true; // hide the anonymous button + buttons[dlgtype] = exBtns[i]; + } + + // add the label and oncommand handler to each button + for (dlgtype in buttons) { + var button = buttons[dlgtype]; + button.addEventListener("command", this._handleButtonCommand, true); + + // don't override custom labels with pre-defined labels on explicit buttons + if (!button.hasAttribute("label")) { + // dialog attributes override the default labels in dialog.properties + if (this.hasAttribute("buttonlabel"+dlgtype)) { + button.setAttribute("label", this.getAttribute("buttonlabel"+dlgtype)); + if (this.hasAttribute("buttonaccesskey"+dlgtype)) + button.setAttribute("accesskey", this.getAttribute("buttonaccesskey"+dlgtype)); + } else if (dlgtype != "extra1" && dlgtype != "extra2") { + button.setAttribute("label", this.mStrBundle.GetStringFromName("button-"+dlgtype)); + var accessKey = this.mStrBundle.GetStringFromName("accesskey-"+dlgtype); + if (accessKey) + button.setAttribute("accesskey", accessKey); + } + } + // allow specifying alternate icons in the dialog header + if (!button.hasAttribute("icon")) { + // if there's an icon specified, use that + if (this.hasAttribute("buttonicon"+dlgtype)) + button.setAttribute("icon", this.getAttribute("buttonicon"+dlgtype)); + // otherwise set defaults + else + switch (dlgtype) { + case "accept": + button.setAttribute("icon", "accept"); + break; + case "cancel": + button.setAttribute("icon", "cancel"); + break; + case "disclosure": + button.setAttribute("icon", "properties"); + break; + case "help": + button.setAttribute("icon", "help"); + break; + default: + break; + } + } + } + + // ensure that hitting enter triggers the default button command + this.defaultButton = this.defaultButton; + + // if there is a special button configuration, use it + if (aButtons) { + // expect a comma delimited list of dlgtype values + var list = aButtons.split(","); + + // mark shown dlgtypes as true + var shown = { accept: false, cancel: false, help: false, + disclosure: false, extra1: false, extra2: false }; + for (i = 0; i < list.length; ++i) + shown[list[i].replace(/ /g, "")] = true; + + // hide/show the buttons we want + for (dlgtype in buttons) + buttons[dlgtype].hidden = !shown[dlgtype]; + + // show the spacer on Windows only when the extra2 button is present + if (/Win/.test(navigator.platform)) { + var spacer = document.getAnonymousElementByAttribute(this, "anonid", "spacer"); + spacer.removeAttribute("hidden"); + spacer.setAttribute("flex", shown["extra2"]?"1":"0"); + } + } + ]]> + </body> + </method> + + <method name="_setDefaultButton"> + <parameter name="aNewDefault"/> + <body> + <![CDATA[ + // remove the default attribute from the previous default button, if any + var oldDefaultButton = this.getButton(this.defaultButton); + if (oldDefaultButton) + oldDefaultButton.removeAttribute("default"); + + var newDefaultButton = this.getButton(aNewDefault); + if (newDefaultButton) { + this.setAttribute("defaultButton", aNewDefault); + newDefaultButton.setAttribute("default", "true"); + } + else { + this.setAttribute("defaultButton", "none"); + if (aNewDefault != "none") + dump("invalid new default button: " + aNewDefault + ", assuming: none\n"); + } + ]]> + </body> + </method> + + <method name="_handleButtonCommand"> + <parameter name="aEvent"/> + <body> + <![CDATA[ + return document.documentElement._doButtonCommand( + aEvent.target.getAttribute("dlgtype")); + ]]> + </body> + </method> + + <method name="_doButtonCommand"> + <parameter name="aDlgType"/> + <body> + <![CDATA[ + var button = this.getButton(aDlgType); + if (!button.disabled) { + var noCancel = this._fireButtonEvent(aDlgType); + if (noCancel) { + if (aDlgType == "accept" || aDlgType == "cancel") { + var closingEvent = new CustomEvent("dialogclosing", { + bubbles: true, + detail: { button: aDlgType }, + }); + this.dispatchEvent(closingEvent); + window.close(); + } + } + return noCancel; + } + return true; + ]]> + </body> + </method> + + <method name="_fireButtonEvent"> + <parameter name="aDlgType"/> + <body> + <![CDATA[ + var event = document.createEvent("Events"); + event.initEvent("dialog"+aDlgType, true, true); + + // handle dom event handlers + var noCancel = this.dispatchEvent(event); + + // handle any xml attribute event handlers + var handler = this.getAttribute("ondialog"+aDlgType); + if (handler != "") { + var fn = new Function("event", handler); + var returned = fn(event); + if (returned == false) + noCancel = false; + } + + return noCancel; + ]]> + </body> + </method> + + <method name="_hitEnter"> + <parameter name="evt"/> + <body> + <![CDATA[ + if (evt.defaultPrevented) + return; + + var btn = this.getButton(this.defaultButton); + if (btn) + this._doButtonCommand(this.defaultButton); + ]]> + </body> + </method> + + </implementation> + + <handlers> + <handler event="keypress" keycode="VK_RETURN" + group="system" action="this._hitEnter(event);"/> + <handler event="keypress" keycode="VK_ESCAPE" group="system"> + if (!event.defaultPrevented) + this.cancelDialog(); + </handler> +#ifdef XP_MACOSX + <handler event="keypress" key="." modifiers="meta" phase="capturing" action="this.cancelDialog();"/> +#else + <handler event="focus" phase="capturing"> + var btn = this.getButton(this.defaultButton); + if (btn) + btn.setAttribute("default", event.originalTarget == btn || !(event.originalTarget instanceof Components.interfaces.nsIDOMXULButtonElement)); + </handler> +#endif + </handlers> + + </binding> + + <binding id="dialogheader"> + <resources> + <stylesheet src="chrome://global/skin/dialog.css"/> + </resources> + <content> + <xul:label class="dialogheader-title" xbl:inherits="value=title,crop" crop="right" flex="1"/> + <xul:label class="dialogheader-description" xbl:inherits="value=description"/> + </content> + </binding> + +</bindings> |