|
|
1 <?xml version="1.0"?>
2
3 <bindings id="dialogBindings"
4 xmlns="http://www.mozilla.org/xbl"
5 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
6 xmlns:xbl="http://www.mozilla.org/xbl">
7
8 <binding id="dialog-base">
9 <resources>
10 <stylesheet src="chrome://global/skin/dialog.css"/>
11 </resources>
12 </binding>
13
14 <binding id="dialog" extends="chrome://global/content/bindings/dialog.xml#dialog-base">
15 <content>
16 <xul:vbox class="box-inherit dialog-content-box" flex="1">
17 <children/>
18 </xul:vbox>
19
20 <xul:hbox class="dialog-button-box" anonid="buttons"
21 xbl:inherits="pack=buttonpack,align=buttonalign,dir=buttondir,orient=buttonorient"
22 #ifdef XP_UNIX
23 >
24 <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
25 <xul:button dlgtype="help" class="dialog-button" hidden="true"/>
26 <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
27 <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
28 <xul:spacer anonid="spacer" flex="1"/>
29 <xul:button dlgtype="cancel" class="dialog-button"/>
30 <xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/>
31 #else
32 pack="end">
33 <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
34 <xul:spacer anonid="spacer" flex="1" hidden="true"/>
35 <xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/>
36 <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
37 <xul:button dlgtype="cancel" class="dialog-button"/>
38 <xul:button dlgtype="help" class="dialog-button" hidden="true"/>
39 <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
40 #endif
41 </xul:hbox>
42 </content>
43
44 <implementation>
45 <field name="_mStrBundle">null</field>
46 <field name="_closeHandler">(function(event) {
47 if (!document.documentElement.cancelDialog())
48 event.preventDefault();
49 })</field>
50
51 <property name="buttons"
52 onget="return this.getAttribute('buttons');"
53 onset="this._configureButtons(val); return val;"/>
54
55 <property name="defaultButton">
56 <getter>
57 <![CDATA[
58 if (this.hasAttribute("defaultButton"))
59 return this.getAttribute("defaultButton");
60 else // default to the accept button
61 return "accept";
62 ]]>
63 </getter>
64 <setter>
65 <![CDATA[
66 this._setDefaultButton(val);
67 return val;
68 ]]>
69 </setter>
70 </property>
71
72 <method name="acceptDialog">
73 <body>
74 <![CDATA[
75 return this._doButtonCommand("accept");
76 ]]>
77 </body>
78 </method>
79
80 <method name="cancelDialog">
81 <body>
82 <![CDATA[
83 return this._doButtonCommand("cancel");
84 ]]>
85 </body>
86 </method>
87
88 <method name="getButton">
89 <parameter name="aDlgType"/>
90 <body>
91 <![CDATA[
92 return this._buttons[aDlgType];
93 ]]>
94 </body>
95 </method>
96
97 <method name="moveToAlertPosition">
98 <body>
99 <![CDATA[
100 // hack. we need this so the window has something like its final size
101 if (window.outerWidth == 1) {
102 dump("Trying to position a sizeless window; caller should have called sizeToContent() or sizeTo(). See bug 75649.\n");
103 sizeToContent();
104 }
105
106 var xOffset = (opener.outerWidth - window.outerWidth) / 2;
107 var yOffset = opener.outerHeight / 5;
108
109 var newX = opener.screenX + xOffset;
110 var newY = opener.screenY + yOffset;
111
112 // ensure the window is fully onscreen (if smaller than the screen)
113 if (newX < screen.availLeft)
114 newX = screen.availLeft + 20;
115 if ((newX + window.outerWidth) > (screen.availLeft + screen.availWidth))
116 newX = (screen.availLeft + screen.availWidth) - window.outerWidth - 20;
117
118 if (newY < screen.availTop)
119 newY = screen.availTop + 20;
120 if ((newY + window.outerHeight) > (screen.availTop + screen.availHeight))
121 newY = (screen.availTop + screen.availHeight) - window.outerHeight - 60;
122
123 window.moveTo( newX, newY );
124 ]]>
125 </body>
126 </method>
127
128 <method name="centerWindowOnScreen">
129 <body>
130 <![CDATA[
131 var xOffset = screen.availWidth/2 - window.outerWidth/2;
132 var yOffset = screen.availHeight/2 - window.outerHeight/2; //(opener.outerHeight *2)/10;
133
134 xOffset = xOffset > 0 ? xOffset : 0;
135 yOffset = yOffset > 0 ? yOffset : 0;
136 window.moveTo(xOffset, yOffset);
137 ]]>
138 </body>
139 </method>
140
141 <constructor>
142 <![CDATA[
143 this._configureButtons(this.buttons);
144
145 // listen for when window is closed via native close buttons
146 window.addEventListener("close", this._closeHandler, false);
147
148 // for things that we need to initialize after onload fires
149 window.addEventListener("load", this.postLoadInit, false);
150
151 window.moveToAlertPosition = this.moveToAlertPosition;
152 window.centerWindowOnScreen = this.centerWindowOnScreen;
153 ]]>
154 </constructor>
155
156 <method name="postLoadInit">
157 <parameter name="aEvent"/>
158 <body>
159 <![CDATA[
160 function focusInit() {
161 // give focus to the first focusable element in the dialog
162 if (!document.commandDispatcher.focusedElement) {
163 document.commandDispatcher.advanceFocusIntoSubtree(document.documentElement);
164 var focusedElt = document.commandDispatcher.focusedElement;
165 if (focusedElt) {
166 if (focusedElt.localName == 'tab') {
167 // Move focus into the tab
168 document.commandDispatcher.advanceFocusIntoSubtree(focusedElt);
169 if (document.commandDispatcher.focusedElement.hasAttribute("dlgtype")) {
170 // We don't want to focus on anonymous OK, Cancel, etc. buttons,
171 // so return focus to the tab itself
172 focusedElt.focus();
173 }
174 }
175 #ifndef XP_MACOSX
176 else {
177 const dialog = document.documentElement;
178 const defaultButton = dialog.getButton(dialog.defaultButton);
179 if (focusedElt.hasAttribute("dlgtype") && focusedElt != defaultButton)
180 defaultButton.focus();
181 }
182 #endif
183 }
184 }
185 }
186
187 // Give focus after onload completes, see bug 103197.
188 setTimeout(focusInit, 0);
189 ]]>
190 </body>
191 </method>
192
193 <property name="mStrBundle">
194 <getter>
195 <![CDATA[
196 if (!this._mStrBundle) {
197 // need to create string bundle manually instead of using <xul:stringbundle/>
198 // see bug 63370 for details
199 var localeService = Components.classes["@mozilla.org/intl/nslocaleservice;1"]
200 .getService(Components.interfaces.nsILocaleService);
201 var stringBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"]
202 .getService(Components.interfaces.nsIStringBundleService);
203 var bundleURL = "chrome://global/locale/dialog.properties";
204 this._mStrBundle = stringBundleService.createBundle(bundleURL, localeService.getApplicationLocale());
205 }
206 return this._mStrBundle;
207 ]]></getter>
208 </property>
209
210 <method name="_configureButtons">
211 <parameter name="aButtons"/>
212 <body>
213 <![CDATA[
214 // by default, get all the anonymous button elements
215 var buttons = {};
216 this._buttons = buttons;
217 buttons.accept = document.getAnonymousElementByAttribute(this, "dlgtype", "accept");
218 buttons.cancel = document.getAnonymousElementByAttribute(this, "dlgtype", "cancel");
219 buttons.extra1 = document.getAnonymousElementByAttribute(this, "dlgtype", "extra1");
220 buttons.extra2 = document.getAnonymousElementByAttribute(this, "dlgtype", "extra2");
221 buttons.help = document.getAnonymousElementByAttribute(this, "dlgtype", "help");
222 buttons.disclosure = document.getAnonymousElementByAttribute(this, "dlgtype", "disclosure");
223
224 // look for any overriding explicit button elements
225 var exBtns = this.getElementsByAttribute("dlgtype", "*");
226 var dlgtype;
227 var i;
228 for (i = 0; i < exBtns.length; ++i) {
229 dlgtype = exBtns[i].getAttribute("dlgtype");
230 buttons[dlgtype].hidden = true; // hide the anonymous button
231 buttons[dlgtype] = exBtns[i];
232 }
233
234 // add the label and oncommand handler to each button
235 for (dlgtype in buttons) {
236 var button = buttons[dlgtype];
237 button.addEventListener("command", this._handleButtonCommand, true);
238
239 // don't override custom labels with pre-defined labels on explicit buttons
240 if (!button.hasAttribute("label")) {
241 // dialog attributes override the default labels in dialog.properties
242 if (this.hasAttribute("buttonlabel"+dlgtype)) {
243 button.setAttribute("label", this.getAttribute("buttonlabel"+dlgtype));
244 if (this.hasAttribute("buttonaccesskey"+dlgtype))
245 button.setAttribute("accesskey", this.getAttribute("buttonaccesskey"+dlgtype));
246 } else if (dlgtype != "extra1" && dlgtype != "extra2") {
247 button.setAttribute("label", this.mStrBundle.GetStringFromName("button-"+dlgtype));
248 var accessKey = this.mStrBundle.GetStringFromName("accesskey-"+dlgtype);
249 if (accessKey)
250 button.setAttribute("accesskey", accessKey);
251 }
252 }
253 // allow specifying alternate icons in the dialog header
254 if (!button.hasAttribute("icon")) {
255 // if there's an icon specified, use that
256 if (this.hasAttribute("buttonicon"+dlgtype))
257 button.setAttribute("icon", this.getAttribute("buttonicon"+dlgtype));
258 // otherwise set defaults
259 else
260 switch (dlgtype) {
261 case "accept":
262 button.setAttribute("icon","accept");
263 break;
264 case "cancel":
265 button.setAttribute("icon","cancel");
266 break;
267 case "disclosue":
268 button.setAttribute("icon","properties");
269 break;
270 case "help":
271 button.setAttribute("icon","help");
272 break;
273 default:
274 break;
275 }
276 }
277 }
278
279 // ensure that hitting enter triggers the default button command
280 this.defaultButton = this.defaultButton;
281
282 // if there is a special button configuration, use it
283 if (aButtons) {
284 // expect a comma delimited list of dlgtype values
285 var list = aButtons.split(",");
286
287 // mark shown dlgtypes as true
288 var shown = { accept: false, cancel: false, help: false,
289 disclosure: false, extra1: false, extra2: false };
290 for (i = 0; i < list.length; ++i)
291 shown[list[i].replace(/ /g, "")] = true;
292
293 // hide/show the buttons we want
294 for (dlgtype in buttons)
295 buttons[dlgtype].hidden = !shown[dlgtype];
296
297 #ifdef XP_WIN
298 # show the spacer on Windows only when the extra2 button is present
299 var spacer = document.getAnonymousElementByAttribute(this, "anonid", "spacer");
300 spacer.removeAttribute("hidden");
301 spacer.setAttribute("flex", shown["extra2"]?"1":"0");
302 #endif
303
304 }
305 ]]>
306 </body>
307 </method>
308
309 <method name="_setDefaultButton">
310 <parameter name="aNewDefault"/>
311 <body>
312 <![CDATA[
313 // remove the default attribute from the previous default button, if any
314 var oldDefaultButton = this.getButton(this.defaultButton);
315 if (oldDefaultButton)
316 oldDefaultButton.removeAttribute("default");
317
318 var newDefaultButton = this.getButton(aNewDefault);
319 if (newDefaultButton) {
320 this.setAttribute("defaultButton", aNewDefault);
321 newDefaultButton.setAttribute("default", "true");
322 }
323 else {
324 this.setAttribute("defaultButton", "none");
325 if (aNewDefault != "none")
326 dump("invalid new default button: " + aNewDefault + ", assuming: none\n");
327 }
328 ]]>
329 </body>
330 </method>
331
332 <method name="_handleButtonCommand">
333 <parameter name="aEvent"/>
334 <body>
335 <![CDATA[
336 return document.documentElement._doButtonCommand(
337 aEvent.target.getAttribute("dlgtype"));
338 ]]>
339 </body>
340 </method>
341
342 <method name="_doButtonCommand">
343 <parameter name="aDlgType"/>
344 <body>
345 <![CDATA[
346 var button = this.getButton(aDlgType);
347 if (!button.disabled) {
348 var noCancel = this._fireButtonEvent(aDlgType);
349 if (noCancel) {
350 if (aDlgType == "accept" || aDlgType == "cancel")
351 window.close();
352 }
353 return noCancel;
354 }
355 return true;
356 ]]>
357 </body>
358 </method>
359
360 <method name="_fireButtonEvent">
361 <parameter name="aDlgType"/>
362 <body>
363 <![CDATA[
364 var event = document.createEvent("Events");
365 event.initEvent("dialog"+aDlgType, true, true);
366
367 // handle dom event handlers
368 var noCancel = this.dispatchEvent(event);
369
370 // handle any xml attribute event handlers
371 var handler = this.getAttribute("ondialog"+aDlgType);
372 if (handler != "") {
373 var fn = new Function("event", handler);
374 var returned = fn(event);
375 if (returned == false)
376 noCancel = false;
377 }
378
379 return noCancel;
380 ]]>
381 </body>
382 </method>
383
384 <method name="_hitEnter">
385 <parameter name="evt"/>
386 <body>
387 <![CDATA[
388 if (evt.getPreventDefault())
389 return;
390
391 var btn = this.getButton(this.defaultButton);
392 if (btn)
393 this._doButtonCommand(this.defaultButton);
394 ]]>
395 </body>
396 </method>
397
398 </implementation>
399
400 <handlers>
401 <handler event="keypress" keycode="VK_ENTER"
402 group="system" action="this._hitEnter(event);"/>
403 <handler event="keypress" keycode="VK_RETURN"
404 group="system" action="this._hitEnter(event);"/>
405 <handler event="keypress" keycode="VK_ESCAPE" group="system">
406 if (!event.getPreventDefault())
407 this.cancelDialog();
408 </handler>
409 #ifdef XP_MACOSX
410 <handler event="keypress" key="." modifiers="meta" phase="capturing" action="this.cancelDialog();"/>
411 #else
412 <handler event="focus" phase="capturing">
413 var btn = this.getButton(this.defaultButton);
414 if (btn)
415 btn.setAttribute("default", event.originalTarget == btn || !(event.originalTarget instanceof Components.interfaces.nsIDOMXULButtonElement));
416 </handler>
417 #endif
418 </handlers>
419
420 </binding>
421
422 <binding id="dialogheader" extends="chrome://global/content/bindings/dialog.xml#dialog-base">
423 <content>
424 <xul:label class="dialogheader-title" xbl:inherits="value=title,crop" crop="right" flex="1"/>
425 <xul:label class="dialogheader-description" xbl:inherits="value=description"/>
426 </content>
427 </binding>
428
429 </bindings>
430