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