]> git.wh0rd.org Git - tt-rss.git/blob - lib/dijit/Dialog.js.uncompressed.js
merge new hu_HU translation
[tt-rss.git] / lib / dijit / Dialog.js.uncompressed.js
1 require({cache:{
2 'url:dijit/templates/Dialog.html':"<div class=\"dijitDialog\" role=\"dialog\" aria-labelledby=\"${id}_title\">\n\t<div data-dojo-attach-point=\"titleBar\" class=\"dijitDialogTitleBar\">\n\t\t<span data-dojo-attach-point=\"titleNode\" class=\"dijitDialogTitle\" id=\"${id}_title\"\n\t\t\t\trole=\"heading\" level=\"1\"></span>\n\t\t<span data-dojo-attach-point=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" data-dojo-attach-event=\"ondijitclick: onCancel\" title=\"${buttonCancel}\" role=\"button\" tabIndex=\"-1\">\n\t\t\t<span data-dojo-attach-point=\"closeText\" class=\"closeText\" title=\"${buttonCancel}\">x</span>\n\t\t</span>\n\t</div>\n\t<div data-dojo-attach-point=\"containerNode\" class=\"dijitDialogPaneContent\"></div>\n</div>\n"}});
3 define("dijit/Dialog", [
4         "require",
5         "dojo/_base/array", // array.forEach array.indexOf array.map
6         "dojo/_base/connect", // connect._keypress
7         "dojo/_base/declare", // declare
8         "dojo/_base/Deferred", // Deferred
9         "dojo/dom", // dom.isDescendant
10         "dojo/dom-class", // domClass.add domClass.contains
11         "dojo/dom-geometry", // domGeometry.position
12         "dojo/dom-style", // domStyle.set
13         "dojo/_base/event", // event.stop
14         "dojo/_base/fx", // fx.fadeIn fx.fadeOut
15         "dojo/i18n", // i18n.getLocalization
16         "dojo/keys",
17         "dojo/_base/lang", // lang.mixin lang.hitch
18         "dojo/on",
19         "dojo/ready",
20         "dojo/sniff", // has("ie") has("opera") has("dijit-legacy-requires")
21         "dojo/window", // winUtils.getBox, winUtils.get
22         "dojo/dnd/Moveable", // Moveable
23         "dojo/dnd/TimedMoveable", // TimedMoveable
24         "./focus",
25         "./_base/manager",      // manager.defaultDuration
26         "./_Widget",
27         "./_TemplatedMixin",
28         "./_CssStateMixin",
29         "./form/_FormMixin",
30         "./_DialogMixin",
31         "./DialogUnderlay",
32         "./layout/ContentPane",
33         "dojo/text!./templates/Dialog.html",
34         "./main",                       // for back-compat, exporting dijit._underlay (remove in 2.0)
35         "dojo/i18n!./nls/common"
36 ], function(require, array, connect, declare, Deferred,
37                         dom, domClass, domGeometry, domStyle, event, fx, i18n, keys, lang, on, ready, has, winUtils,
38                         Moveable, TimedMoveable, focus, manager, _Widget, _TemplatedMixin, _CssStateMixin, _FormMixin, _DialogMixin,
39                         DialogUnderlay, ContentPane, template, dijit){
40
41         // module:
42         //              dijit/Dialog
43
44         /*=====
45         dijit._underlay = function(kwArgs){
46                 // summary:
47                 //              A shared instance of a `dijit.DialogUnderlay`
48                 //
49                 // description:
50                 //              A shared instance of a `dijit.DialogUnderlay` created and
51                 //              used by `dijit.Dialog`, though never created until some Dialog
52                 //              or subclass thereof is shown.
53         };
54         =====*/
55
56         var _DialogBase = declare("dijit._DialogBase", [_TemplatedMixin, _FormMixin, _DialogMixin, _CssStateMixin], {
57                 templateString: template,
58
59                 baseClass: "dijitDialog",
60
61                 cssStateNodes: {
62                         closeButtonNode: "dijitDialogCloseIcon"
63                 },
64
65                 // Map widget attributes to DOMNode attributes.
66                 _setTitleAttr: [
67                         { node: "titleNode", type: "innerHTML" },
68                         { node: "titleBar", type: "attribute" }
69                 ],
70
71                 // open: [readonly] Boolean
72                 //              True if Dialog is currently displayed on screen.
73                 open: false,
74
75                 // duration: Integer
76                 //              The time in milliseconds it takes the dialog to fade in and out
77                 duration: manager.defaultDuration,
78
79                 // refocus: Boolean
80                 //              A Toggle to modify the default focus behavior of a Dialog, which
81                 //              is to re-focus the element which had focus before being opened.
82                 //              False will disable refocusing. Default: true
83                 refocus: true,
84
85                 // autofocus: Boolean
86                 //              A Toggle to modify the default focus behavior of a Dialog, which
87                 //              is to focus on the first dialog element after opening the dialog.
88                 //              False will disable autofocusing. Default: true
89                 autofocus: true,
90
91                 // _firstFocusItem: [private readonly] DomNode
92                 //              The pointer to the first focusable node in the dialog.
93                 //              Set by `dijit/_DialogMixin._getFocusItems()`.
94                 _firstFocusItem: null,
95
96                 // _lastFocusItem: [private readonly] DomNode
97                 //              The pointer to which node has focus prior to our dialog.
98                 //              Set by `dijit/_DialogMixin._getFocusItems()`.
99                 _lastFocusItem: null,
100
101                 // doLayout: [protected] Boolean
102                 //              Don't change this parameter from the default value.
103                 //              This ContentPane parameter doesn't make sense for Dialog, since Dialog
104                 //              is never a child of a layout container, nor can you specify the size of
105                 //              Dialog in order to control the size of an inner widget.
106                 doLayout: false,
107
108                 // draggable: Boolean
109                 //              Toggles the moveable aspect of the Dialog. If true, Dialog
110                 //              can be dragged by it's title. If false it will remain centered
111                 //              in the viewport.
112                 draggable: true,
113
114                 _setDraggableAttr: function(/*Boolean*/ val){
115                         // Avoid _WidgetBase behavior of copying draggable attribute to this.domNode,
116                         // as that prevents text select on modern browsers (#14452)
117                         this._set("draggable", val);
118                 },
119
120                 // aria-describedby: String
121                 //              Allows the user to add an aria-describedby attribute onto the dialog. The value should
122                 //              be the id of the container element of text that describes the dialog purpose (usually
123                 //              the first text in the dialog).
124                 //      |       <div data-dojo-type="dijit/Dialog" aria-describedby="intro" .....>
125                 //      |               <div id="intro">Introductory text</div>
126                 //      |               <div>rest of dialog contents</div>
127                 //      |       </div>
128                 "aria-describedby": "",
129
130                 // maxRatio: Number
131                 //              Maximum size to allow the dialog to expand to, relative to viewport size
132                 maxRatio: 0.9,
133
134                 postMixInProperties: function(){
135                         var _nlsResources = i18n.getLocalization("dijit", "common");
136                         lang.mixin(this, _nlsResources);
137                         this.inherited(arguments);
138                 },
139
140                 postCreate: function(){
141                         domStyle.set(this.domNode, {
142                                 display: "none",
143                                 position:"absolute"
144                         });
145                         this.ownerDocumentBody.appendChild(this.domNode);
146
147                         this.inherited(arguments);
148
149                         this.connect(this, "onExecute", "hide");
150                         this.connect(this, "onCancel", "hide");
151                         this._modalconnects = [];
152                 },
153
154                 onLoad: function(){
155                         // summary:
156                         //              Called when data has been loaded from an href.
157                         //              Unlike most other callbacks, this function can be connected to (via `dojo.connect`)
158                         //              but should *not* be overridden.
159                         // tags:
160                         //              callback
161
162                         // when href is specified we need to reposition the dialog after the data is loaded
163                         // and find the focusable elements
164                         this._position();
165                         if(this.autofocus && DialogLevelManager.isTop(this)){
166                                 this._getFocusItems(this.domNode);
167                                 focus.focus(this._firstFocusItem);
168                         }
169                         this.inherited(arguments);
170                 },
171
172                 _onBlur: function(by){
173                         this.inherited(arguments);
174
175                         // If focus was accidentally removed from the dialog, such as if the user clicked a blank
176                         // area of the screen, or clicked the browser's address bar and then tabbed into the page,
177                         // then refocus.   Won't do anything if focus was removed because the Dialog was closed, or
178                         // because a new Dialog popped up on top of the old one.
179                         var refocus = lang.hitch(this, function(){
180                                 if(this.open && !this._destroyed && DialogLevelManager.isTop(this)){
181                                         this._getFocusItems(this.domNode);
182                                         focus.focus(this._firstFocusItem);
183                                 }
184                         });
185                         if(by == "mouse"){
186                                 // wait for mouse up, and then refocus dialog; otherwise doesn't work
187                                 on.once(this.ownerDocument, "mouseup", refocus);
188                         }else{
189                                 refocus();
190                         }
191                 },
192
193                 _endDrag: function(){
194                         // summary:
195                         //              Called after dragging the Dialog. Saves the position of the dialog in the viewport,
196                         //              and also adjust position to be fully within the viewport, so user doesn't lose access to handle
197                         var nodePosition = domGeometry.position(this.domNode),
198                                 viewport = winUtils.getBox(this.ownerDocument);
199                         nodePosition.y = Math.min(Math.max(nodePosition.y, 0), (viewport.h - nodePosition.h));
200                         nodePosition.x = Math.min(Math.max(nodePosition.x, 0), (viewport.w - nodePosition.w));
201                         this._relativePosition = nodePosition;
202                         this._position();
203                 },
204
205                 _setup: function(){
206                         // summary:
207                         //              Stuff we need to do before showing the Dialog for the first
208                         //              time (but we defer it until right beforehand, for
209                         //              performance reasons).
210                         // tags:
211                         //              private
212
213                         var node = this.domNode;
214
215                         if(this.titleBar && this.draggable){
216                                 this._moveable = new ((has("ie") == 6) ? TimedMoveable // prevent overload, see #5285
217                                         : Moveable)(node, { handle: this.titleBar });
218                                 this.connect(this._moveable, "onMoveStop", "_endDrag");
219                         }else{
220                                 domClass.add(node,"dijitDialogFixed");
221                         }
222
223                         this.underlayAttrs = {
224                                 dialogId: this.id,
225                                 "class": array.map(this["class"].split(/\s/), function(s){ return s+"_underlay"; }).join(" "),
226                                 ownerDocument: this.ownerDocument
227                         };
228                 },
229
230                 _size: function(){
231                         // summary:
232                         //              If necessary, shrink dialog contents so dialog fits in viewport
233                         // tags:
234                         //              private
235
236                         this._checkIfSingleChild();
237
238                         // If we resized the dialog contents earlier, reset them back to original size, so
239                         // that if the user later increases the viewport size, the dialog can display w/out a scrollbar.
240                         // Need to do this before the domGeometry.position(this.domNode) call below.
241                         if(this._singleChild){
242                                 if(typeof this._singleChildOriginalStyle != "undefined"){
243                                         this._singleChild.domNode.style.cssText = this._singleChildOriginalStyle;
244                                         delete this._singleChildOriginalStyle;
245                                 }
246                         }else{
247                                 domStyle.set(this.containerNode, {
248                                         width:"auto",
249                                         height:"auto"
250                                 });
251                         }
252
253                         var bb = domGeometry.position(this.domNode);
254
255                         // Get viewport size but then reduce it by a bit; Dialog should always have some space around it
256                         // to indicate that it's a popup.  This will also compensate for possible scrollbars on viewport.
257                         var viewport = winUtils.getBox(this.ownerDocument);
258                         viewport.w *= this.maxRatio;
259                         viewport.h *= this.maxRatio;
260
261                         if(bb.w >= viewport.w || bb.h >= viewport.h){
262                                 // Reduce size of dialog contents so that dialog fits in viewport
263
264                                 var containerSize = domGeometry.position(this.containerNode),
265                                         w = Math.min(bb.w, viewport.w) - (bb.w - containerSize.w),
266                                         h = Math.min(bb.h, viewport.h) - (bb.h - containerSize.h);
267
268                                 if(this._singleChild && this._singleChild.resize){
269                                         if(typeof this._singleChildOriginalStyle == "undefined"){
270                                                 this._singleChildOriginalStyle = this._singleChild.domNode.style.cssText;
271                                         }
272                                         this._singleChild.resize({w: w, h: h});
273                                 }else{
274                                         domStyle.set(this.containerNode, {
275                                                 width: w + "px",
276                                                 height: h + "px",
277                                                 overflow: "auto",
278                                                 position: "relative"    // workaround IE bug moving scrollbar or dragging dialog
279                                         });
280                                 }
281                         }else{
282                                 if(this._singleChild && this._singleChild.resize){
283                                         this._singleChild.resize();
284                                 }
285                         }
286                 },
287
288                 _position: function(){
289                         // summary:
290                         //              Position modal dialog in the viewport. If no relative offset
291                         //              in the viewport has been determined (by dragging, for instance),
292                         //              center the node. Otherwise, use the Dialog's stored relative offset,
293                         //              and position the node to top: left: values based on the viewport.
294                         if(!domClass.contains(this.ownerDocumentBody, "dojoMove")){     // don't do anything if called during auto-scroll
295                                 var node = this.domNode,
296                                         viewport = winUtils.getBox(this.ownerDocument),
297                                         p = this._relativePosition,
298                                         bb = p ? null : domGeometry.position(node),
299                                         l = Math.floor(viewport.l + (p ? p.x : (viewport.w - bb.w) / 2)),
300                                         t = Math.floor(viewport.t + (p ? p.y : (viewport.h - bb.h) / 2))
301                                 ;
302                                 domStyle.set(node,{
303                                         left: l + "px",
304                                         top: t + "px"
305                                 });
306                         }
307                 },
308
309                 _onKey: function(/*Event*/ evt){
310                         // summary:
311                         //              Handles the keyboard events for accessibility reasons
312                         // tags:
313                         //              private
314
315                         if(evt.charOrCode){
316                                 var node = evt.target;
317                                 if(evt.charOrCode === keys.TAB){
318                                         this._getFocusItems(this.domNode);
319                                 }
320                                 var singleFocusItem = (this._firstFocusItem == this._lastFocusItem);
321                                 // see if we are shift-tabbing from first focusable item on dialog
322                                 if(node == this._firstFocusItem && evt.shiftKey && evt.charOrCode === keys.TAB){
323                                         if(!singleFocusItem){
324                                                 focus.focus(this._lastFocusItem); // send focus to last item in dialog
325                                         }
326                                         event.stop(evt);
327                                 }else if(node == this._lastFocusItem && evt.charOrCode === keys.TAB && !evt.shiftKey){
328                                         if(!singleFocusItem){
329                                                 focus.focus(this._firstFocusItem); // send focus to first item in dialog
330                                         }
331                                         event.stop(evt);
332                                 }else{
333                                         // see if the key is for the dialog
334                                         while(node){
335                                                 if(node == this.domNode || domClass.contains(node, "dijitPopup")){
336                                                         if(evt.charOrCode == keys.ESCAPE){
337                                                                 this.onCancel();
338                                                         }else{
339                                                                 return; // just let it go
340                                                         }
341                                                 }
342                                                 node = node.parentNode;
343                                         }
344                                         // this key is for the disabled document window
345                                         if(evt.charOrCode !== keys.TAB){ // allow tabbing into the dialog for a11y
346                                                 event.stop(evt);
347                                         // opera won't tab to a div
348                                         }else if(!has("opera")){
349                                                 try{
350                                                         this._firstFocusItem.focus();
351                                                 }catch(e){ /*squelch*/ }
352                                         }
353                                 }
354                         }
355                 },
356
357                 show: function(){
358                         // summary:
359                         //              Display the dialog
360                         // returns: dojo/_base/Deferred
361                         //              Deferred object that resolves when the display animation is complete
362
363                         if(this.open){ return; }
364
365                         if(!this._started){
366                                 this.startup();
367                         }
368
369                         // first time we show the dialog, there's some initialization stuff to do
370                         if(!this._alreadyInitialized){
371                                 this._setup();
372                                 this._alreadyInitialized=true;
373                         }
374
375                         if(this._fadeOutDeferred){
376                                 this._fadeOutDeferred.cancel();
377                         }
378
379                         // Recenter Dialog if user scrolls browser.  Connecting to document doesn't work on IE, need to use window.
380                         var win = winUtils.get(this.ownerDocument);
381                         this._modalconnects.push(on(win, "scroll", lang.hitch(this, "resize")));
382
383                         this._modalconnects.push(on(this.domNode, connect._keypress, lang.hitch(this, "_onKey")));
384
385                         domStyle.set(this.domNode, {
386                                 opacity:0,
387                                 display:""
388                         });
389
390                         this._set("open", true);
391                         this._onShow(); // lazy load trigger
392
393                         this._size();
394                         this._position();
395
396                         // fade-in Animation object, setup below
397                         var fadeIn;
398
399                         this._fadeInDeferred = new Deferred(lang.hitch(this, function(){
400                                 fadeIn.stop();
401                                 delete this._fadeInDeferred;
402                         }));
403
404                         fadeIn = fx.fadeIn({
405                                 node: this.domNode,
406                                 duration: this.duration,
407                                 beforeBegin: lang.hitch(this, function(){
408                                         DialogLevelManager.show(this, this.underlayAttrs);
409                                 }),
410                                 onEnd: lang.hitch(this, function(){
411                                         if(this.autofocus && DialogLevelManager.isTop(this)){
412                                                 // find focusable items each time dialog is shown since if dialog contains a widget the
413                                                 // first focusable items can change
414                                                 this._getFocusItems(this.domNode);
415                                                 focus.focus(this._firstFocusItem);
416                                         }
417                                         this._fadeInDeferred.resolve(true);
418                                         delete this._fadeInDeferred;
419                                 })
420                         }).play();
421
422                         return this._fadeInDeferred;
423                 },
424
425                 hide: function(){
426                         // summary:
427                         //              Hide the dialog
428                         // returns: dojo/_base/Deferred
429                         //              Deferred object that resolves when the hide animation is complete
430
431                         // If we haven't been initialized yet then we aren't showing and we can just return.
432                         // Likewise if we are already hidden, or are currently fading out.
433                         if(!this._alreadyInitialized || !this.open){
434                                 return;
435                         }
436                         if(this._fadeInDeferred){
437                                 this._fadeInDeferred.cancel();
438                         }
439
440                         // fade-in Animation object, setup below
441                         var fadeOut;
442
443                         this._fadeOutDeferred = new Deferred(lang.hitch(this, function(){
444                                 fadeOut.stop();
445                                 delete this._fadeOutDeferred;
446                         }));
447                         // fire onHide when the promise resolves.
448                         this._fadeOutDeferred.then(lang.hitch(this, 'onHide'));
449
450                         fadeOut = fx.fadeOut({
451                                 node: this.domNode,
452                                 duration: this.duration,
453                                 onEnd: lang.hitch(this, function(){
454                                         this.domNode.style.display = "none";
455                                         DialogLevelManager.hide(this);
456                                         this._fadeOutDeferred.resolve(true);
457                                         delete this._fadeOutDeferred;
458                                 })
459                          }).play();
460
461                         if(this._scrollConnected){
462                                 this._scrollConnected = false;
463                         }
464                         var h;
465                         while(h = this._modalconnects.pop()){
466                                 h.remove();
467                         }
468
469                         if(this._relativePosition){
470                                 delete this._relativePosition;
471                         }
472                         this._set("open", false);
473
474                         return this._fadeOutDeferred;
475                 },
476
477                 resize: function(){
478                         // summary:
479                         //              Called when viewport scrolled or size changed.  Position the Dialog and the underlay.
480                         // tags:
481                         //              private
482                         if(this.domNode.style.display != "none"){
483                                 if(DialogUnderlay._singleton){  // avoid race condition during show()
484                                         DialogUnderlay._singleton.layout();
485                                 }
486                                 this._position();
487                                 this._size();
488                         }
489                 },
490
491                 destroy: function(){
492                         if(this._fadeInDeferred){
493                                 this._fadeInDeferred.cancel();
494                         }
495                         if(this._fadeOutDeferred){
496                                 this._fadeOutDeferred.cancel();
497                         }
498                         if(this._moveable){
499                                 this._moveable.destroy();
500                         }
501                         var h;
502                         while(h = this._modalconnects.pop()){
503                                 h.remove();
504                         }
505
506                         DialogLevelManager.hide(this);
507
508                         this.inherited(arguments);
509                 }
510         });
511
512         var Dialog = declare("dijit.Dialog", [ContentPane, _DialogBase], {
513                 // summary:
514                 //              A modal dialog Widget.
515                 // description:
516                 //              Pops up a modal dialog window, blocking access to the screen
517                 //              and also graying out the screen Dialog is extended from
518                 //              ContentPane so it supports all the same parameters (href, etc.).
519                 // example:
520                 // |    <div data-dojo-type="dijit/Dialog" data-dojo-props="href: 'test.html'"></div>
521                 // example:
522                 // |    var foo = new Dialog({ title: "test dialog", content: "test content" };
523                 // |    foo.placeAt(win.body());
524                 // |    foo.startup();
525         });
526         Dialog._DialogBase = _DialogBase;       // for monkey patching and dojox/widget/DialogSimple
527
528         var DialogLevelManager = Dialog._DialogLevelManager = {
529                 // summary:
530                 //              Controls the various active "levels" on the page, starting with the
531                 //              stuff initially visible on the page (at z-index 0), and then having an entry for
532                 //              each Dialog shown.
533
534                 _beginZIndex: 950,
535
536                 show: function(/*dijit/_WidgetBase*/ dialog, /*Object*/ underlayAttrs){
537                         // summary:
538                         //              Call right before fade-in animation for new dialog.
539                         //              Saves current focus, displays/adjusts underlay for new dialog,
540                         //              and sets the z-index of the dialog itself.
541                         //
542                         //              New dialog will be displayed on top of all currently displayed dialogs.
543                         //
544                         //              Caller is responsible for setting focus in new dialog after the fade-in
545                         //              animation completes.
546
547                         // Save current focus
548                         ds[ds.length-1].focus = focus.curNode;
549
550                         // Display the underlay, or if already displayed then adjust for this new dialog
551                         // TODO: one underlay per document (based on dialog.ownerDocument)
552                         var underlay = DialogUnderlay._singleton;
553                         if(!underlay || underlay._destroyed){
554                                 underlay = dijit._underlay = DialogUnderlay._singleton = new DialogUnderlay(underlayAttrs);
555                         }else{
556                                 underlay.set(dialog.underlayAttrs);
557                         }
558
559                         // Set z-index a bit above previous dialog
560                         var zIndex = ds[ds.length-1].dialog ? ds[ds.length-1].zIndex + 2 : Dialog._DialogLevelManager._beginZIndex;
561                         if(ds.length == 1){     // first dialog
562                                 underlay.show();
563                         }
564                         domStyle.set(DialogUnderlay._singleton.domNode, 'zIndex', zIndex - 1);
565
566                         // Dialog
567                         domStyle.set(dialog.domNode, 'zIndex', zIndex);
568
569                         ds.push({dialog: dialog, underlayAttrs: underlayAttrs, zIndex: zIndex});
570                 },
571
572                 hide: function(/*dijit/_WidgetBase*/ dialog){
573                         // summary:
574                         //              Called when the specified dialog is hidden/destroyed, after the fade-out
575                         //              animation ends, in order to reset page focus, fix the underlay, etc.
576                         //              If the specified dialog isn't open then does nothing.
577                         //
578                         //              Caller is responsible for either setting display:none on the dialog domNode,
579                         //              or calling dijit/popup.hide(), or removing it from the page DOM.
580
581                         if(ds[ds.length-1].dialog == dialog){
582                                 // Removing the top (or only) dialog in the stack, return focus
583                                 // to previous dialog
584
585                                 ds.pop();
586
587                                 var pd = ds[ds.length-1];       // the new active dialog (or the base page itself)
588
589                                 // Adjust underlay, unless the underlay widget has already been destroyed
590                                 // because we are being called during page unload (when all widgets are destroyed)
591                                 if(!DialogUnderlay._singleton._destroyed){
592                                         if(ds.length == 1){
593                                                 // Returning to original page.  Hide the underlay.
594                                                 DialogUnderlay._singleton.hide();
595                                         }else{
596                                                 // Popping back to previous dialog, adjust underlay.
597                                                 domStyle.set(DialogUnderlay._singleton.domNode, 'zIndex', pd.zIndex - 1);
598                                                 DialogUnderlay._singleton.set(pd.underlayAttrs);
599                                         }
600                                 }
601
602                                 // Adjust focus
603                                 if(dialog.refocus){
604                                         // If we are returning control to a previous dialog but for some reason
605                                         // that dialog didn't have a focused field, set focus to first focusable item.
606                                         // This situation could happen if two dialogs appeared at nearly the same time,
607                                         // since a dialog doesn't set it's focus until the fade-in is finished.
608                                         var focus = pd.focus;
609                                         if(pd.dialog && (!focus || !dom.isDescendant(focus, pd.dialog.domNode))){
610                                                 pd.dialog._getFocusItems(pd.dialog.domNode);
611                                                 focus = pd.dialog._firstFocusItem;
612                                         }
613
614                                         if(focus){
615                                                 // Refocus the button that spawned the Dialog.   This will fail in corner cases including
616                                                 // page unload on IE, because the dijit/form/Button that launched the Dialog may get destroyed
617                                                 // before this code runs.  (#15058)
618                                                 try{
619                                                         focus.focus();
620                                                 }catch(e){}
621                                         }
622                                 }
623                         }else{
624                                 // Removing a dialog out of order (#9944, #10705).
625                                 // Don't need to mess with underlay or z-index or anything.
626                                 var idx = array.indexOf(array.map(ds, function(elem){return elem.dialog}), dialog);
627                                 if(idx != -1){
628                                         ds.splice(idx, 1);
629                                 }
630                         }
631                 },
632
633                 isTop: function(/*dijit/_WidgetBase*/ dialog){
634                         // summary:
635                         //              Returns true if specified Dialog is the top in the task
636                         return ds[ds.length-1].dialog == dialog;
637                 }
638         };
639
640         // Stack representing the various active "levels" on the page, starting with the
641         // stuff initially visible on the page (at z-index 0), and then having an entry for
642         // each Dialog shown.
643         // Each element in stack has form {
644         //              dialog: dialogWidget,
645         //              focus: returnFromGetFocus(),
646         //              underlayAttrs: attributes to set on underlay (when this widget is active)
647         // }
648         var ds = Dialog._dialogStack = [
649                 {dialog: null, focus: null, underlayAttrs: null}        // entry for stuff at z-index: 0
650         ];
651
652         // Back compat w/1.6, remove for 2.0
653         if(has("dijit-legacy-requires")){
654                 ready(0, function(){
655                         var requires = ["dijit/TooltipDialog"];
656                         require(requires);      // use indirection so modules not rolled into a build
657                 });
658         }
659
660         return Dialog;
661 });