Project

General

Profile

Statistics
| Revision:

root / trunk / web / dojo / dijit / dijit.js.uncompressed.js @ 11

History | View | Annotate | Download (194 KB)

1
/*
2
        Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
3
        Available via Academic Free License >= 2.1 OR the modified BSD license.
4
        see: http://dojotoolkit.org/license for details
5
*/
6

    
7
/*
8
        This is an optimized version of Dojo, built for deployment and not for
9
        development. To get sources and documentation, please visit:
10

11
                http://dojotoolkit.org
12
*/
13

    
14
if(!dojo._hasResource["dojo.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
15
dojo._hasResource["dojo.window"] = true;
16
dojo.provide("dojo.window");
17

    
18
dojo.window.getBox = function(){
19
        // summary:
20
        //                Returns the dimensions and scroll position of the viewable area of a browser window
21

    
22
        var scrollRoot = (dojo.doc.compatMode == 'BackCompat') ? dojo.body() : dojo.doc.documentElement;
23

    
24
        // get scroll position
25
        var scroll = dojo._docScroll(); // scrollRoot.scrollTop/Left should work
26
        return { w: scrollRoot.clientWidth, h: scrollRoot.clientHeight, l: scroll.x, t: scroll.y };
27
};
28

    
29
dojo.window.get = function(doc){
30
        // summary:
31
        //                 Get window object associated with document doc
32

    
33
        // In some IE versions (at least 6.0), document.parentWindow does not return a
34
        // reference to the real window object (maybe a copy), so we must fix it as well
35
        // We use IE specific execScript to attach the real window reference to
36
        // document._parentWindow for later use
37
        if(dojo.isIE && window !== document.parentWindow){
38
                /*
39
                In IE 6, only the variable "window" can be used to connect events (others
40
                may be only copies).
41
                */
42
                doc.parentWindow.execScript("document._parentWindow = window;", "Javascript");
43
                //to prevent memory leak, unset it after use
44
                //another possibility is to add an onUnload handler which seems overkill to me (liucougar)
45
                var win = doc._parentWindow;
46
                doc._parentWindow = null;
47
                return win;        //        Window
48
        }
49

    
50
        return doc.parentWindow || doc.defaultView;        //        Window
51
};
52

    
53
dojo.window.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
54
        // summary:
55
        //                Scroll the passed node into view, if it is not already.
56
        
57
        // don't rely on node.scrollIntoView working just because the function is there
58

    
59
        try{ // catch unexpected/unrecreatable errors (#7808) since we can recover using a semi-acceptable native method
60
                node = dojo.byId(node);
61
                var doc = node.ownerDocument || dojo.doc,
62
                        body = doc.body || dojo.body(),
63
                        html = doc.documentElement || body.parentNode,
64
                        isIE = dojo.isIE, isWK = dojo.isWebKit;
65
                // if an untested browser, then use the native method
66
                if((!(dojo.isMoz || isIE || isWK || dojo.isOpera) || node == body || node == html) && (typeof node.scrollIntoView != "undefined")){
67
                        node.scrollIntoView(false); // short-circuit to native if possible
68
                        return;
69
                }
70
                var backCompat = doc.compatMode == 'BackCompat',
71
                        clientAreaRoot = backCompat? body : html,
72
                        scrollRoot = isWK ? body : clientAreaRoot,
73
                        rootWidth = clientAreaRoot.clientWidth,
74
                        rootHeight = clientAreaRoot.clientHeight,
75
                        rtl = !dojo._isBodyLtr(),
76
                        nodePos = pos || dojo.position(node),
77
                        el = node.parentNode,
78
                        isFixed = function(el){
79
                                return ((isIE <= 6 || (isIE && backCompat))? false : (dojo.style(el, 'position').toLowerCase() == "fixed"));
80
                        };
81
                if(isFixed(node)){ return; } // nothing to do
82

    
83
                while(el){
84
                        if(el == body){ el = scrollRoot; }
85
                        var elPos = dojo.position(el),
86
                                fixedPos = isFixed(el);
87
        
88
                        if(el == scrollRoot){
89
                                elPos.w = rootWidth; elPos.h = rootHeight;
90
                                if(scrollRoot == html && isIE && rtl){ elPos.x += scrollRoot.offsetWidth-elPos.w; } // IE workaround where scrollbar causes negative x
91
                                if(elPos.x < 0 || !isIE){ elPos.x = 0; } // IE can have values > 0
92
                                if(elPos.y < 0 || !isIE){ elPos.y = 0; }
93
                        }else{
94
                                var pb = dojo._getPadBorderExtents(el);
95
                                elPos.w -= pb.w; elPos.h -= pb.h; elPos.x += pb.l; elPos.y += pb.t;
96
                        }
97
        
98
                        if(el != scrollRoot){ // body, html sizes already have the scrollbar removed
99
                                var clientSize = el.clientWidth,
100
                                        scrollBarSize = elPos.w - clientSize;
101
                                if(clientSize > 0 && scrollBarSize > 0){
102
                                        elPos.w = clientSize;
103
                                        if(isIE && rtl){ elPos.x += scrollBarSize; }
104
                                }
105
                                clientSize = el.clientHeight;
106
                                scrollBarSize = elPos.h - clientSize;
107
                                if(clientSize > 0 && scrollBarSize > 0){
108
                                        elPos.h = clientSize;
109
                                }
110
                        }
111
                        if(fixedPos){ // bounded by viewport, not parents
112
                                if(elPos.y < 0){
113
                                        elPos.h += elPos.y; elPos.y = 0;
114
                                }
115
                                if(elPos.x < 0){
116
                                        elPos.w += elPos.x; elPos.x = 0;
117
                                }
118
                                if(elPos.y + elPos.h > rootHeight){
119
                                        elPos.h = rootHeight - elPos.y;
120
                                }
121
                                if(elPos.x + elPos.w > rootWidth){
122
                                        elPos.w = rootWidth - elPos.x;
123
                                }
124
                        }
125
                        // calculate overflow in all 4 directions
126
                        var l = nodePos.x - elPos.x, // beyond left: < 0
127
                                t = nodePos.y - Math.max(elPos.y, 0), // beyond top: < 0
128
                                r = l + nodePos.w - elPos.w, // beyond right: > 0
129
                                bot = t + nodePos.h - elPos.h; // beyond bottom: > 0
130
                        if(r * l > 0){
131
                                var s = Math[l < 0? "max" : "min"](l, r);
132
                                nodePos.x += el.scrollLeft;
133
                                el.scrollLeft += (isIE >= 8 && !backCompat && rtl)? -s : s;
134
                                nodePos.x -= el.scrollLeft;
135
                        }
136
                        if(bot * t > 0){
137
                                nodePos.y += el.scrollTop;
138
                                el.scrollTop += Math[t < 0? "max" : "min"](t, bot);
139
                                nodePos.y -= el.scrollTop;
140
                        }
141
                        el = (el != scrollRoot) && !fixedPos && el.parentNode;
142
                }        
143
        }catch(error){
144
                console.error('scrollIntoView: ' + error);
145
                node.scrollIntoView(false);
146
        }
147
};
148

    
149
}
150

    
151
if(!dojo._hasResource["dijit._base.manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
152
dojo._hasResource["dijit._base.manager"] = true;
153
dojo.provide("dijit._base.manager");
154

    
155
dojo.declare("dijit.WidgetSet", null, {
156
        // summary:
157
        //                A set of widgets indexed by id. A default instance of this class is
158
        //                available as `dijit.registry`
159
        //
160
        // example:
161
        //                Create a small list of widgets:
162
        //                |        var ws = new dijit.WidgetSet();
163
        //                |        ws.add(dijit.byId("one"));
164
        //                |         ws.add(dijit.byId("two"));
165
        //                |        // destroy both:
166
        //                |        ws.forEach(function(w){ w.destroy(); });
167
        //
168
        // example:
169
        //                Using dijit.registry:
170
        //                |        dijit.registry.forEach(function(w){ /* do something */ });
171

    
172
        constructor: function(){
173
                this._hash = {};
174
                this.length = 0;
175
        },
176

    
177
        add: function(/*dijit._Widget*/ widget){
178
                // summary:
179
                //                Add a widget to this list. If a duplicate ID is detected, a error is thrown.
180
                //
181
                // widget: dijit._Widget
182
                //                Any dijit._Widget subclass.
183
                if(this._hash[widget.id]){
184
                        throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered");
185
                }
186
                this._hash[widget.id] = widget;
187
                this.length++;
188
        },
189

    
190
        remove: function(/*String*/ id){
191
                // summary:
192
                //                Remove a widget from this WidgetSet. Does not destroy the widget; simply
193
                //                removes the reference.
194
                if(this._hash[id]){
195
                        delete this._hash[id];
196
                        this.length--;
197
                }
198
        },
199

    
200
        forEach: function(/*Function*/ func, /* Object? */thisObj){
201
                // summary:
202
                //                Call specified function for each widget in this set.
203
                //
204
                // func:
205
                //                A callback function to run for each item. Is passed the widget, the index
206
                //                in the iteration, and the full hash, similar to `dojo.forEach`.
207
                //
208
                // thisObj:
209
                //                An optional scope parameter
210
                //
211
                // example:
212
                //                Using the default `dijit.registry` instance:
213
                //                |        dijit.registry.forEach(function(widget){
214
                //                |                console.log(widget.declaredClass);
215
                //                |        });
216
                //
217
                // returns:
218
                //                Returns self, in order to allow for further chaining.
219

    
220
                thisObj = thisObj || dojo.global;
221
                var i = 0, id;
222
                for(id in this._hash){
223
                        func.call(thisObj, this._hash[id], i++, this._hash);
224
                }
225
                return this;        // dijit.WidgetSet
226
        },
227

    
228
        filter: function(/*Function*/ filter, /* Object? */thisObj){
229
                // summary:
230
                //                Filter down this WidgetSet to a smaller new WidgetSet
231
                //                Works the same as `dojo.filter` and `dojo.NodeList.filter`
232
                //
233
                // filter:
234
                //                Callback function to test truthiness. Is passed the widget
235
                //                reference and the pseudo-index in the object.
236
                //
237
                // thisObj: Object?
238
                //                Option scope to use for the filter function.
239
                //
240
                // example:
241
                //                Arbitrary: select the odd widgets in this list
242
                //                |        dijit.registry.filter(function(w, i){
243
                //                |                return i % 2 == 0;
244
                //                |        }).forEach(function(w){ /* odd ones */ });
245

    
246
                thisObj = thisObj || dojo.global;
247
                var res = new dijit.WidgetSet(), i = 0, id;
248
                for(id in this._hash){
249
                        var w = this._hash[id];
250
                        if(filter.call(thisObj, w, i++, this._hash)){
251
                                res.add(w);
252
                        }
253
                }
254
                return res; // dijit.WidgetSet
255
        },
256

    
257
        byId: function(/*String*/ id){
258
                // summary:
259
                //                Find a widget in this list by it's id.
260
                // example:
261
                //                Test if an id is in a particular WidgetSet
262
                //                | var ws = new dijit.WidgetSet();
263
                //                | ws.add(dijit.byId("bar"));
264
                //                | var t = ws.byId("bar") // returns a widget
265
                //                | var x = ws.byId("foo"); // returns undefined
266

    
267
                return this._hash[id];        // dijit._Widget
268
        },
269

    
270
        byClass: function(/*String*/ cls){
271
                // summary:
272
                //                Reduce this widgetset to a new WidgetSet of a particular `declaredClass`
273
                //
274
                // cls: String
275
                //                The Class to scan for. Full dot-notated string.
276
                //
277
                // example:
278
                //                Find all `dijit.TitlePane`s in a page:
279
                //                |        dijit.registry.byClass("dijit.TitlePane").forEach(function(tp){ tp.close(); });
280

    
281
                var res = new dijit.WidgetSet(), id, widget;
282
                for(id in this._hash){
283
                        widget = this._hash[id];
284
                        if(widget.declaredClass == cls){
285
                                res.add(widget);
286
                        }
287
                 }
288
                 return res; // dijit.WidgetSet
289
},
290

    
291
        toArray: function(){
292
                // summary:
293
                //                Convert this WidgetSet into a true Array
294
                //
295
                // example:
296
                //                Work with the widget .domNodes in a real Array
297
                //                |        dojo.map(dijit.registry.toArray(), function(w){ return w.domNode; });
298

    
299
                var ar = [];
300
                for(var id in this._hash){
301
                        ar.push(this._hash[id]);
302
                }
303
                return ar;        // dijit._Widget[]
304
},
305

    
306
        map: function(/* Function */func, /* Object? */thisObj){
307
                // summary:
308
                //                Create a new Array from this WidgetSet, following the same rules as `dojo.map`
309
                // example:
310
                //                |        var nodes = dijit.registry.map(function(w){ return w.domNode; });
311
                //
312
                // returns:
313
                //                A new array of the returned values.
314
                return dojo.map(this.toArray(), func, thisObj); // Array
315
        },
316

    
317
        every: function(func, thisObj){
318
                // summary:
319
                //                 A synthetic clone of `dojo.every` acting explicitly on this WidgetSet
320
                //
321
                // func: Function
322
                //                A callback function run for every widget in this list. Exits loop
323
                //                when the first false return is encountered.
324
                //
325
                // thisObj: Object?
326
                //                Optional scope parameter to use for the callback
327

    
328
                thisObj = thisObj || dojo.global;
329
                var x = 0, i;
330
                for(i in this._hash){
331
                        if(!func.call(thisObj, this._hash[i], x++, this._hash)){
332
                                return false; // Boolean
333
                        }
334
                }
335
                return true; // Boolean
336
        },
337

    
338
        some: function(func, thisObj){
339
                // summary:
340
                //                 A synthetic clone of `dojo.some` acting explictly on this WidgetSet
341
                //
342
                // func: Function
343
                //                A callback function run for every widget in this list. Exits loop
344
                //                when the first true return is encountered.
345
                //
346
                // thisObj: Object?
347
                //                Optional scope parameter to use for the callback
348

    
349
                thisObj = thisObj || dojo.global;
350
                var x = 0, i;
351
                for(i in this._hash){
352
                        if(func.call(thisObj, this._hash[i], x++, this._hash)){
353
                                return true; // Boolean
354
                        }
355
                }
356
                return false; // Boolean
357
        }
358

    
359
});
360

    
361
(function(){
362

    
363
        /*=====
364
        dijit.registry = {
365
                // summary:
366
                //                A list of widgets on a page.
367
                // description:
368
                //                Is an instance of `dijit.WidgetSet`
369
        };
370
        =====*/
371
        dijit.registry = new dijit.WidgetSet();
372

    
373
        var hash = dijit.registry._hash,
374
                attr = dojo.attr,
375
                hasAttr = dojo.hasAttr,
376
                style = dojo.style;
377

    
378
        dijit.byId = function(/*String|dijit._Widget*/ id){
379
                // summary:
380
                //                Returns a widget by it's id, or if passed a widget, no-op (like dojo.byId())
381
                return typeof id == "string" ? hash[id] : id; // dijit._Widget
382
        };
383

    
384
        var _widgetTypeCtr = {};
385
        dijit.getUniqueId = function(/*String*/widgetType){
386
                // summary:
387
                //                Generates a unique id for a given widgetType
388
        
389
                var id;
390
                do{
391
                        id = widgetType + "_" +
392
                                (widgetType in _widgetTypeCtr ?
393
                                        ++_widgetTypeCtr[widgetType] : _widgetTypeCtr[widgetType] = 0);
394
                }while(hash[id]);
395
                return dijit._scopeName == "dijit" ? id : dijit._scopeName + "_" + id; // String
396
        };
397
        
398
        dijit.findWidgets = function(/*DomNode*/ root){
399
                // summary:
400
                //                Search subtree under root returning widgets found.
401
                //                Doesn't search for nested widgets (ie, widgets inside other widgets).
402
        
403
                var outAry = [];
404
        
405
                function getChildrenHelper(root){
406
                        for(var node = root.firstChild; node; node = node.nextSibling){
407
                                if(node.nodeType == 1){
408
                                        var widgetId = node.getAttribute("widgetId");
409
                                        if(widgetId){
410
                                                outAry.push(hash[widgetId]);
411
                                        }else{
412
                                                getChildrenHelper(node);
413
                                        }
414
                                }
415
                        }
416
                }
417
        
418
                getChildrenHelper(root);
419
                return outAry;
420
        };
421
        
422
        dijit._destroyAll = function(){
423
                // summary:
424
                //                Code to destroy all widgets and do other cleanup on page unload
425
        
426
                // Clean up focus manager lingering references to widgets and nodes
427
                dijit._curFocus = null;
428
                dijit._prevFocus = null;
429
                dijit._activeStack = [];
430
        
431
                // Destroy all the widgets, top down
432
                dojo.forEach(dijit.findWidgets(dojo.body()), function(widget){
433
                        // Avoid double destroy of widgets like Menu that are attached to <body>
434
                        // even though they are logically children of other widgets.
435
                        if(!widget._destroyed){
436
                                if(widget.destroyRecursive){
437
                                        widget.destroyRecursive();
438
                                }else if(widget.destroy){
439
                                        widget.destroy();
440
                                }
441
                        }
442
                });
443
        };
444
        
445
        if(dojo.isIE){
446
                // Only run _destroyAll() for IE because we think it's only necessary in that case,
447
                // and because it causes problems on FF.  See bug #3531 for details.
448
                dojo.addOnWindowUnload(function(){
449
                        dijit._destroyAll();
450
                });
451
        }
452
        
453
        dijit.byNode = function(/*DOMNode*/ node){
454
                // summary:
455
                //                Returns the widget corresponding to the given DOMNode
456
                return hash[node.getAttribute("widgetId")]; // dijit._Widget
457
        };
458
        
459
        dijit.getEnclosingWidget = function(/*DOMNode*/ node){
460
                // summary:
461
                //                Returns the widget whose DOM tree contains the specified DOMNode, or null if
462
                //                the node is not contained within the DOM tree of any widget
463
                while(node){
464
                        var id = node.getAttribute && node.getAttribute("widgetId");
465
                        if(id){
466
                                return hash[id];
467
                        }
468
                        node = node.parentNode;
469
                }
470
                return null;
471
        };
472

    
473
        var shown = (dijit._isElementShown = function(/*Element*/ elem){
474
                var s = style(elem);
475
                return (s.visibility != "hidden")
476
                        && (s.visibility != "collapsed")
477
                        && (s.display != "none")
478
                        && (attr(elem, "type") != "hidden");
479
        });
480
        
481
        dijit.hasDefaultTabStop = function(/*Element*/ elem){
482
                // summary:
483
                //                Tests if element is tab-navigable even without an explicit tabIndex setting
484
        
485
                // No explicit tabIndex setting, need to investigate node type
486
                switch(elem.nodeName.toLowerCase()){
487
                        case "a":
488
                                // An <a> w/out a tabindex is only navigable if it has an href
489
                                return hasAttr(elem, "href");
490
                        case "area":
491
                        case "button":
492
                        case "input":
493
                        case "object":
494
                        case "select":
495
                        case "textarea":
496
                                // These are navigable by default
497
                                return true;
498
                        case "iframe":
499
                                // If it's an editor <iframe> then it's tab navigable.
500
                                //TODO: feature detect "designMode" in elem.contentDocument?
501
                                if(dojo.isMoz){
502
                                        try{
503
                                                return elem.contentDocument.designMode == "on";
504
                                        }catch(err){
505
                                                return false;
506
                                        }
507
                                }else if(dojo.isWebKit){
508
                                        var doc = elem.contentDocument,
509
                                                body = doc && doc.body;
510
                                        return body && body.contentEditable == 'true';
511
                                }else{
512
                                        // contentWindow.document isn't accessible within IE7/8
513
                                        // if the iframe.src points to a foreign url and this
514
                                        // page contains an element, that could get focus
515
                                        try{
516
                                                doc = elem.contentWindow.document;
517
                                                body = doc && doc.body;
518
                                                return body && body.firstChild && body.firstChild.contentEditable == 'true';
519
                                        }catch(e){
520
                                                return false;
521
                                        }
522
                                }
523
                        default:
524
                                return elem.contentEditable == 'true';
525
                }
526
        };
527
        
528
        var isTabNavigable = (dijit.isTabNavigable = function(/*Element*/ elem){
529
                // summary:
530
                //                Tests if an element is tab-navigable
531
        
532
                // TODO: convert (and rename method) to return effective tabIndex; will save time in _getTabNavigable()
533
                if(attr(elem, "disabled")){
534
                        return false;
535
                }else if(hasAttr(elem, "tabIndex")){
536
                        // Explicit tab index setting
537
                        return attr(elem, "tabIndex") >= 0; // boolean
538
                }else{
539
                        // No explicit tabIndex setting, so depends on node type
540
                        return dijit.hasDefaultTabStop(elem);
541
                }
542
        });
543

    
544
        dijit._getTabNavigable = function(/*DOMNode*/ root){
545
                // summary:
546
                //                Finds descendants of the specified root node.
547
                //
548
                // description:
549
                //                Finds the following descendants of the specified root node:
550
                //                * the first tab-navigable element in document order
551
                //                  without a tabIndex or with tabIndex="0"
552
                //                * the last tab-navigable element in document order
553
                //                  without a tabIndex or with tabIndex="0"
554
                //                * the first element in document order with the lowest
555
                //                  positive tabIndex value
556
                //                * the last element in document order with the highest
557
                //                  positive tabIndex value
558
                var first, last, lowest, lowestTabindex, highest, highestTabindex;
559
                var walkTree = function(/*DOMNode*/parent){
560
                        dojo.query("> *", parent).forEach(function(child){
561
                                // Skip hidden elements, and also non-HTML elements (those in custom namespaces) in IE,
562
                                // since show() invokes getAttribute("type"), which crash on VML nodes in IE.
563
                                if((dojo.isIE && child.scopeName!=="HTML") || !shown(child)){
564
                                        return;
565
                                }
566

    
567
                                if(isTabNavigable(child)){
568
                                        var tabindex = attr(child, "tabIndex");
569
                                        if(!hasAttr(child, "tabIndex") || tabindex == 0){
570
                                                if(!first){ first = child; }
571
                                                last = child;
572
                                        }else if(tabindex > 0){
573
                                                if(!lowest || tabindex < lowestTabindex){
574
                                                        lowestTabindex = tabindex;
575
                                                        lowest = child;
576
                                                }
577
                                                if(!highest || tabindex >= highestTabindex){
578
                                                        highestTabindex = tabindex;
579
                                                        highest = child;
580
                                                }
581
                                        }
582
                                }
583
                                if(child.nodeName.toUpperCase() != 'SELECT'){
584
                                        walkTree(child);
585
                                }
586
                        });
587
                };
588
                if(shown(root)){ walkTree(root) }
589
                return { first: first, last: last, lowest: lowest, highest: highest };
590
        }
591
        dijit.getFirstInTabbingOrder = function(/*String|DOMNode*/ root){
592
                // summary:
593
                //                Finds the descendant of the specified root node
594
                //                that is first in the tabbing order
595
                var elems = dijit._getTabNavigable(dojo.byId(root));
596
                return elems.lowest ? elems.lowest : elems.first; // DomNode
597
        };
598
        
599
        dijit.getLastInTabbingOrder = function(/*String|DOMNode*/ root){
600
                // summary:
601
                //                Finds the descendant of the specified root node
602
                //                that is last in the tabbing order
603
                var elems = dijit._getTabNavigable(dojo.byId(root));
604
                return elems.last ? elems.last : elems.highest; // DomNode
605
        };
606
        
607
        /*=====
608
        dojo.mixin(dijit, {
609
                // defaultDuration: Integer
610
                //                The default animation speed (in ms) to use for all Dijit
611
                //                transitional animations, unless otherwise specified
612
                //                on a per-instance basis. Defaults to 200, overrided by
613
                //                `djConfig.defaultDuration`
614
                defaultDuration: 200
615
        });
616
        =====*/
617
        
618
        dijit.defaultDuration = dojo.config["defaultDuration"] || 200;
619

    
620
})();
621

    
622
}
623

    
624
if(!dojo._hasResource["dijit._base.focus"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
625
dojo._hasResource["dijit._base.focus"] = true;
626
dojo.provide("dijit._base.focus");
627

    
628

    
629
        // for dijit.isTabNavigable()
630

    
631
// summary:
632
//                These functions are used to query or set the focus and selection.
633
//
634
//                Also, they trace when widgets become activated/deactivated,
635
//                so that the widget can fire _onFocus/_onBlur events.
636
//                "Active" here means something similar to "focused", but
637
//                "focus" isn't quite the right word because we keep track of
638
//                a whole stack of "active" widgets.  Example: ComboButton --> Menu -->
639
//                MenuItem.  The onBlur event for ComboButton doesn't fire due to focusing
640
//                on the Menu or a MenuItem, since they are considered part of the
641
//                ComboButton widget.  It only happens when focus is shifted
642
//                somewhere completely different.
643

    
644
dojo.mixin(dijit, {
645
        // _curFocus: DomNode
646
        //                Currently focused item on screen
647
        _curFocus: null,
648

    
649
        // _prevFocus: DomNode
650
        //                Previously focused item on screen
651
        _prevFocus: null,
652

    
653
        isCollapsed: function(){
654
                // summary:
655
                //                Returns true if there is no text selected
656
                return dijit.getBookmark().isCollapsed;
657
        },
658

    
659
        getBookmark: function(){
660
                // summary:
661
                //                Retrieves a bookmark that can be used with moveToBookmark to return to the same range
662
                var bm, rg, tg, sel = dojo.doc.selection, cf = dijit._curFocus;
663

    
664
                if(dojo.global.getSelection){
665
                        //W3C Range API for selections.
666
                        sel = dojo.global.getSelection();
667
                        if(sel){
668
                                if(sel.isCollapsed){
669
                                        tg = cf? cf.tagName : "";
670
                                        if(tg){
671
                                                //Create a fake rangelike item to restore selections.
672
                                                tg = tg.toLowerCase();
673
                                                if(tg == "textarea" ||
674
                                                                (tg == "input" && (!cf.type || cf.type.toLowerCase() == "text"))){
675
                                                        sel = {
676
                                                                start: cf.selectionStart,
677
                                                                end: cf.selectionEnd,
678
                                                                node: cf,
679
                                                                pRange: true
680
                                                        };
681
                                                        return {isCollapsed: (sel.end <= sel.start), mark: sel}; //Object.
682
                                                }
683
                                        }
684
                                        bm = {isCollapsed:true};
685
                                }else{
686
                                        rg = sel.getRangeAt(0);
687
                                        bm = {isCollapsed: false, mark: rg.cloneRange()};
688
                                }
689
                        }
690
                }else if(sel){
691
                        // If the current focus was a input of some sort and no selection, don't bother saving
692
                        // a native bookmark.  This is because it causes issues with dialog/page selection restore.
693
                        // So, we need to create psuedo bookmarks to work with.
694
                        tg = cf ? cf.tagName : "";
695
                        tg = tg.toLowerCase();
696
                        if(cf && tg && (tg == "button" || tg == "textarea" || tg == "input")){
697
                                if(sel.type && sel.type.toLowerCase() == "none"){
698
                                        return {
699
                                                isCollapsed: true,
700
                                                mark: null
701
                                        }
702
                                }else{
703
                                        rg = sel.createRange();
704
                                        return {
705
                                                isCollapsed: rg.text && rg.text.length?false:true,
706
                                                mark: {
707
                                                        range: rg,
708
                                                        pRange: true
709
                                                }
710
                                        };
711
                                }
712
                        }
713
                        bm = {};
714

    
715
                        //'IE' way for selections.
716
                        try{
717
                                // createRange() throws exception when dojo in iframe
718
                                //and nothing selected, see #9632
719
                                rg = sel.createRange();
720
                                bm.isCollapsed = !(sel.type == 'Text' ? rg.htmlText.length : rg.length);
721
                        }catch(e){
722
                                bm.isCollapsed = true;
723
                                return bm;
724
                        }
725
                        if(sel.type.toUpperCase() == 'CONTROL'){
726
                                if(rg.length){
727
                                        bm.mark=[];
728
                                        var i=0,len=rg.length;
729
                                        while(i<len){
730
                                                bm.mark.push(rg.item(i++));
731
                                        }
732
                                }else{
733
                                        bm.isCollapsed = true;
734
                                        bm.mark = null;
735
                                }
736
                        }else{
737
                                bm.mark = rg.getBookmark();
738
                        }
739
                }else{
740
                        console.warn("No idea how to store the current selection for this browser!");
741
                }
742
                return bm; // Object
743
        },
744

    
745
        moveToBookmark: function(/*Object*/bookmark){
746
                // summary:
747
                //                Moves current selection to a bookmark
748
                // bookmark:
749
                //                This should be a returned object from dijit.getBookmark()
750

    
751
                var _doc = dojo.doc,
752
                        mark = bookmark.mark;
753
                if(mark){
754
                        if(dojo.global.getSelection){
755
                                //W3C Rangi API (FF, WebKit, Opera, etc)
756
                                var sel = dojo.global.getSelection();
757
                                if(sel && sel.removeAllRanges){
758
                                        if(mark.pRange){
759
                                                var r = mark;
760
                                                var n = r.node;
761
                                                n.selectionStart = r.start;
762
                                                n.selectionEnd = r.end;
763
                                        }else{
764
                                                sel.removeAllRanges();
765
                                                sel.addRange(mark);
766
                                        }
767
                                }else{
768
                                        console.warn("No idea how to restore selection for this browser!");
769
                                }
770
                        }else if(_doc.selection && mark){
771
                                //'IE' way.
772
                                var rg;
773
                                if(mark.pRange){
774
                                        rg = mark.range;
775
                                }else if(dojo.isArray(mark)){
776
                                        rg = _doc.body.createControlRange();
777
                                        //rg.addElement does not have call/apply method, so can not call it directly
778
                                        //rg is not available in "range.addElement(item)", so can't use that either
779
                                        dojo.forEach(mark, function(n){
780
                                                rg.addElement(n);
781
                                        });
782
                                }else{
783
                                        rg = _doc.body.createTextRange();
784
                                        rg.moveToBookmark(mark);
785
                                }
786
                                rg.select();
787
                        }
788
                }
789
        },
790

    
791
        getFocus: function(/*Widget?*/ menu, /*Window?*/ openedForWindow){
792
                // summary:
793
                //                Called as getFocus(), this returns an Object showing the current focus
794
                //                and selected text.
795
                //
796
                //                Called as getFocus(widget), where widget is a (widget representing) a button
797
                //                that was just pressed, it returns where focus was before that button
798
                //                was pressed.   (Pressing the button may have either shifted focus to the button,
799
                //                or removed focus altogether.)   In this case the selected text is not returned,
800
                //                since it can't be accurately determined.
801
                //
802
                // menu: dijit._Widget or {domNode: DomNode} structure
803
                //                The button that was just pressed.  If focus has disappeared or moved
804
                //                to this button, returns the previous focus.  In this case the bookmark
805
                //                information is already lost, and null is returned.
806
                //
807
                // openedForWindow:
808
                //                iframe in which menu was opened
809
                //
810
                // returns:
811
                //                A handle to restore focus/selection, to be passed to `dijit.focus`
812
                var node = !dijit._curFocus || (menu && dojo.isDescendant(dijit._curFocus, menu.domNode)) ? dijit._prevFocus : dijit._curFocus;
813
                return {
814
                        node: node,
815
                        bookmark: (node == dijit._curFocus) && dojo.withGlobal(openedForWindow || dojo.global, dijit.getBookmark),
816
                        openedForWindow: openedForWindow
817
                }; // Object
818
        },
819

    
820
        focus: function(/*Object || DomNode */ handle){
821
                // summary:
822
                //                Sets the focused node and the selection according to argument.
823
                //                To set focus to an iframe's content, pass in the iframe itself.
824
                // handle:
825
                //                object returned by get(), or a DomNode
826

    
827
                if(!handle){ return; }
828

    
829
                var node = "node" in handle ? handle.node : handle,                // because handle is either DomNode or a composite object
830
                        bookmark = handle.bookmark,
831
                        openedForWindow = handle.openedForWindow,
832
                        collapsed = bookmark ? bookmark.isCollapsed : false;
833

    
834
                // Set the focus
835
                // Note that for iframe's we need to use the <iframe> to follow the parentNode chain,
836
                // but we need to set focus to iframe.contentWindow
837
                if(node){
838
                        var focusNode = (node.tagName.toLowerCase() == "iframe") ? node.contentWindow : node;
839
                        if(focusNode && focusNode.focus){
840
                                try{
841
                                        // Gecko throws sometimes if setting focus is impossible,
842
                                        // node not displayed or something like that
843
                                        focusNode.focus();
844
                                }catch(e){/*quiet*/}
845
                        }
846
                        dijit._onFocusNode(node);
847
                }
848

    
849
                // set the selection
850
                // do not need to restore if current selection is not empty
851
                // (use keyboard to select a menu item) or if previous selection was collapsed
852
                // as it may cause focus shift (Esp in IE).
853
                if(bookmark && dojo.withGlobal(openedForWindow || dojo.global, dijit.isCollapsed) && !collapsed){
854
                        if(openedForWindow){
855
                                openedForWindow.focus();
856
                        }
857
                        try{
858
                                dojo.withGlobal(openedForWindow || dojo.global, dijit.moveToBookmark, null, [bookmark]);
859
                        }catch(e2){
860
                                /*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */
861
                        }
862
                }
863
        },
864

    
865
        // _activeStack: dijit._Widget[]
866
        //                List of currently active widgets (focused widget and it's ancestors)
867
        _activeStack: [],
868

    
869
        registerIframe: function(/*DomNode*/ iframe){
870
                // summary:
871
                //                Registers listeners on the specified iframe so that any click
872
                //                or focus event on that iframe (or anything in it) is reported
873
                //                as a focus/click event on the <iframe> itself.
874
                // description:
875
                //                Currently only used by editor.
876
                // returns:
877
                //                Handle to pass to unregisterIframe()
878
                return dijit.registerWin(iframe.contentWindow, iframe);
879
        },
880

    
881
        unregisterIframe: function(/*Object*/ handle){
882
                // summary:
883
                //                Unregisters listeners on the specified iframe created by registerIframe.
884
                //                After calling be sure to delete or null out the handle itself.
885
                // handle:
886
                //                Handle returned by registerIframe()
887

    
888
                dijit.unregisterWin(handle);
889
        },
890

    
891
        registerWin: function(/*Window?*/targetWindow, /*DomNode?*/ effectiveNode){
892
                // summary:
893
                //                Registers listeners on the specified window (either the main
894
                //                window or an iframe's window) to detect when the user has clicked somewhere
895
                //                or focused somewhere.
896
                // description:
897
                //                Users should call registerIframe() instead of this method.
898
                // targetWindow:
899
                //                If specified this is the window associated with the iframe,
900
                //                i.e. iframe.contentWindow.
901
                // effectiveNode:
902
                //                If specified, report any focus events inside targetWindow as
903
                //                an event on effectiveNode, rather than on evt.target.
904
                // returns:
905
                //                Handle to pass to unregisterWin()
906

    
907
                // TODO: make this function private in 2.0; Editor/users should call registerIframe(),
908

    
909
                var mousedownListener = function(evt){
910
                        dijit._justMouseDowned = true;
911
                        setTimeout(function(){ dijit._justMouseDowned = false; }, 0);
912
                        
913
                        // workaround weird IE bug where the click is on an orphaned node
914
                        // (first time clicking a Select/DropDownButton inside a TooltipDialog)
915
                        if(dojo.isIE && evt && evt.srcElement && evt.srcElement.parentNode == null){
916
                                return;
917
                        }
918

    
919
                        dijit._onTouchNode(effectiveNode || evt.target || evt.srcElement, "mouse");
920
                };
921
                //dojo.connect(targetWindow, "onscroll", ???);
922

    
923
                // Listen for blur and focus events on targetWindow's document.
924
                // IIRC, I'm using attachEvent() rather than dojo.connect() because focus/blur events don't bubble
925
                // through dojo.connect(), and also maybe to catch the focus events early, before onfocus handlers
926
                // fire.
927
                // Connect to <html> (rather than document) on IE to avoid memory leaks, but document on other browsers because
928
                // (at least for FF) the focus event doesn't fire on <html> or <body>.
929
                var doc = dojo.isIE ? targetWindow.document.documentElement : targetWindow.document;
930
                if(doc){
931
                        if(dojo.isIE){
932
                                doc.attachEvent('onmousedown', mousedownListener);
933
                                var activateListener = function(evt){
934
                                        // IE reports that nodes like <body> have gotten focus, even though they have tabIndex=-1,
935
                                        // Should consider those more like a mouse-click than a focus....
936
                                        if(evt.srcElement.tagName.toLowerCase() != "#document" &&
937
                                                dijit.isTabNavigable(evt.srcElement)){
938
                                                dijit._onFocusNode(effectiveNode || evt.srcElement);
939
                                        }else{
940
                                                dijit._onTouchNode(effectiveNode || evt.srcElement);
941
                                        }
942
                                };
943
                                doc.attachEvent('onactivate', activateListener);
944
                                var deactivateListener =  function(evt){
945
                                        dijit._onBlurNode(effectiveNode || evt.srcElement);
946
                                };
947
                                doc.attachEvent('ondeactivate', deactivateListener);
948

    
949
                                return function(){
950
                                        doc.detachEvent('onmousedown', mousedownListener);
951
                                        doc.detachEvent('onactivate', activateListener);
952
                                        doc.detachEvent('ondeactivate', deactivateListener);
953
                                        doc = null;        // prevent memory leak (apparent circular reference via closure)
954
                                };
955
                        }else{
956
                                doc.addEventListener('mousedown', mousedownListener, true);
957
                                var focusListener = function(evt){
958
                                        dijit._onFocusNode(effectiveNode || evt.target);
959
                                };
960
                                doc.addEventListener('focus', focusListener, true);
961
                                var blurListener = function(evt){
962
                                        dijit._onBlurNode(effectiveNode || evt.target);
963
                                };
964
                                doc.addEventListener('blur', blurListener, true);
965

    
966
                                return function(){
967
                                        doc.removeEventListener('mousedown', mousedownListener, true);
968
                                        doc.removeEventListener('focus', focusListener, true);
969
                                        doc.removeEventListener('blur', blurListener, true);
970
                                        doc = null;        // prevent memory leak (apparent circular reference via closure)
971
                                };
972
                        }
973
                }
974
        },
975

    
976
        unregisterWin: function(/*Handle*/ handle){
977
                // summary:
978
                //                Unregisters listeners on the specified window (either the main
979
                //                window or an iframe's window) according to handle returned from registerWin().
980
                //                After calling be sure to delete or null out the handle itself.
981

    
982
                // Currently our handle is actually a function
983
                handle && handle();
984
        },
985

    
986
        _onBlurNode: function(/*DomNode*/ node){
987
                // summary:
988
                //                 Called when focus leaves a node.
989
                //                Usually ignored, _unless_ it *isn't* follwed by touching another node,
990
                //                which indicates that we tabbed off the last field on the page,
991
                //                in which case every widget is marked inactive
992
                dijit._prevFocus = dijit._curFocus;
993
                dijit._curFocus = null;
994

    
995
                if(dijit._justMouseDowned){
996
                        // the mouse down caused a new widget to be marked as active; this blur event
997
                        // is coming late, so ignore it.
998
                        return;
999
                }
1000

    
1001
                // if the blur event isn't followed by a focus event then mark all widgets as inactive.
1002
                if(dijit._clearActiveWidgetsTimer){
1003
                        clearTimeout(dijit._clearActiveWidgetsTimer);
1004
                }
1005
                dijit._clearActiveWidgetsTimer = setTimeout(function(){
1006
                        delete dijit._clearActiveWidgetsTimer;
1007
                        dijit._setStack([]);
1008
                        dijit._prevFocus = null;
1009
                }, 100);
1010
        },
1011

    
1012
        _onTouchNode: function(/*DomNode*/ node, /*String*/ by){
1013
                // summary:
1014
                //                Callback when node is focused or mouse-downed
1015
                // node:
1016
                //                The node that was touched.
1017
                // by:
1018
                //                "mouse" if the focus/touch was caused by a mouse down event
1019

    
1020
                // ignore the recent blurNode event
1021
                if(dijit._clearActiveWidgetsTimer){
1022
                        clearTimeout(dijit._clearActiveWidgetsTimer);
1023
                        delete dijit._clearActiveWidgetsTimer;
1024
                }
1025

    
1026
                // compute stack of active widgets (ex: ComboButton --> Menu --> MenuItem)
1027
                var newStack=[];
1028
                try{
1029
                        while(node){
1030
                                var popupParent = dojo.attr(node, "dijitPopupParent");
1031
                                if(popupParent){
1032
                                        node=dijit.byId(popupParent).domNode;
1033
                                }else if(node.tagName && node.tagName.toLowerCase() == "body"){
1034
                                        // is this the root of the document or just the root of an iframe?
1035
                                        if(node === dojo.body()){
1036
                                                // node is the root of the main document
1037
                                                break;
1038
                                        }
1039
                                        // otherwise, find the iframe this node refers to (can't access it via parentNode,
1040
                                        // need to do this trick instead). window.frameElement is supported in IE/FF/Webkit
1041
                                        node=dojo.window.get(node.ownerDocument).frameElement;
1042
                                }else{
1043
                                        // if this node is the root node of a widget, then add widget id to stack,
1044
                                        // except ignore clicks on disabled widgets (actually focusing a disabled widget still works,
1045
                                        // to support MenuItem)
1046
                                        var id = node.getAttribute && node.getAttribute("widgetId"),
1047
                                                widget = id && dijit.byId(id);
1048
                                        if(widget && !(by == "mouse" && widget.get("disabled"))){
1049
                                                newStack.unshift(id);
1050
                                        }
1051
                                        node=node.parentNode;
1052
                                }
1053
                        }
1054
                }catch(e){ /* squelch */ }
1055

    
1056
                dijit._setStack(newStack, by);
1057
        },
1058

    
1059
        _onFocusNode: function(/*DomNode*/ node){
1060
                // summary:
1061
                //                Callback when node is focused
1062

    
1063
                if(!node){
1064
                        return;
1065
                }
1066

    
1067
                if(node.nodeType == 9){
1068
                        // Ignore focus events on the document itself.  This is here so that
1069
                        // (for example) clicking the up/down arrows of a spinner
1070
                        // (which don't get focus) won't cause that widget to blur. (FF issue)
1071
                        return;
1072
                }
1073

    
1074
                dijit._onTouchNode(node);
1075

    
1076
                if(node == dijit._curFocus){ return; }
1077
                if(dijit._curFocus){
1078
                        dijit._prevFocus = dijit._curFocus;
1079
                }
1080
                dijit._curFocus = node;
1081
                dojo.publish("focusNode", [node]);
1082
        },
1083

    
1084
        _setStack: function(/*String[]*/ newStack, /*String*/ by){
1085
                // summary:
1086
                //                The stack of active widgets has changed.  Send out appropriate events and records new stack.
1087
                // newStack:
1088
                //                array of widget id's, starting from the top (outermost) widget
1089
                // by:
1090
                //                "mouse" if the focus/touch was caused by a mouse down event
1091

    
1092
                var oldStack = dijit._activeStack;
1093
                dijit._activeStack = newStack;
1094

    
1095
                // compare old stack to new stack to see how many elements they have in common
1096
                for(var nCommon=0; nCommon<Math.min(oldStack.length, newStack.length); nCommon++){
1097
                        if(oldStack[nCommon] != newStack[nCommon]){
1098
                                break;
1099
                        }
1100
                }
1101

    
1102
                var widget;
1103
                // for all elements that have gone out of focus, send blur event
1104
                for(var i=oldStack.length-1; i>=nCommon; i--){
1105
                        widget = dijit.byId(oldStack[i]);
1106
                        if(widget){
1107
                                widget._focused = false;
1108
                                widget._hasBeenBlurred = true;
1109
                                if(widget._onBlur){
1110
                                        widget._onBlur(by);
1111
                                }
1112
                                dojo.publish("widgetBlur", [widget, by]);
1113
                        }
1114
                }
1115

    
1116
                // for all element that have come into focus, send focus event
1117
                for(i=nCommon; i<newStack.length; i++){
1118
                        widget = dijit.byId(newStack[i]);
1119
                        if(widget){
1120
                                widget._focused = true;
1121
                                if(widget._onFocus){
1122
                                        widget._onFocus(by);
1123
                                }
1124
                                dojo.publish("widgetFocus", [widget, by]);
1125
                        }
1126
                }
1127
        }
1128
});
1129

    
1130
// register top window and all the iframes it contains
1131
dojo.addOnLoad(function(){
1132
        var handle = dijit.registerWin(window);
1133
        if(dojo.isIE){
1134
                dojo.addOnWindowUnload(function(){
1135
                        dijit.unregisterWin(handle);
1136
                        handle = null;
1137
                })
1138
        }
1139
});
1140

    
1141
}
1142

    
1143
if(!dojo._hasResource["dojo.AdapterRegistry"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
1144
dojo._hasResource["dojo.AdapterRegistry"] = true;
1145
dojo.provide("dojo.AdapterRegistry");
1146

    
1147
dojo.AdapterRegistry = function(/*Boolean?*/ returnWrappers){
1148
        //        summary:
1149
        //                A registry to make contextual calling/searching easier.
1150
        //        description:
1151
        //                Objects of this class keep list of arrays in the form [name, check,
1152
        //                wrap, directReturn] that are used to determine what the contextual
1153
        //                result of a set of checked arguments is. All check/wrap functions
1154
        //                in this registry should be of the same arity.
1155
        //        example:
1156
        //        |        // create a new registry
1157
        //        |        var reg = new dojo.AdapterRegistry();
1158
        //        |        reg.register("handleString",
1159
        //        |                dojo.isString,
1160
        //        |                function(str){
1161
        //        |                        // do something with the string here
1162
        //        |                }
1163
        //        |        );
1164
        //        |        reg.register("handleArr",
1165
        //        |                dojo.isArray,
1166
        //        |                function(arr){
1167
        //        |                        // do something with the array here
1168
        //        |                }
1169
        //        |        );
1170
        //        |
1171
        //        |        // now we can pass reg.match() *either* an array or a string and
1172
        //        |        // the value we pass will get handled by the right function
1173
        //        |        reg.match("someValue"); // will call the first function
1174
        //        |        reg.match(["someValue"]); // will call the second
1175

    
1176
        this.pairs = [];
1177
        this.returnWrappers = returnWrappers || false; // Boolean
1178
}
1179

    
1180
dojo.extend(dojo.AdapterRegistry, {
1181
        register: function(/*String*/ name, /*Function*/ check, /*Function*/ wrap, /*Boolean?*/ directReturn, /*Boolean?*/ override){
1182
                //        summary: 
1183
                //                register a check function to determine if the wrap function or
1184
                //                object gets selected
1185
                //        name:
1186
                //                a way to identify this matcher.
1187
                //        check:
1188
                //                a function that arguments are passed to from the adapter's
1189
                //                match() function.  The check function should return true if the
1190
                //                given arguments are appropriate for the wrap function.
1191
                //        directReturn:
1192
                //                If directReturn is true, the value passed in for wrap will be
1193
                //                returned instead of being called. Alternately, the
1194
                //                AdapterRegistry can be set globally to "return not call" using
1195
                //                the returnWrappers property. Either way, this behavior allows
1196
                //                the registry to act as a "search" function instead of a
1197
                //                function interception library.
1198
                //        override:
1199
                //                If override is given and true, the check function will be given
1200
                //                highest priority. Otherwise, it will be the lowest priority
1201
                //                adapter.
1202
                this.pairs[((override) ? "unshift" : "push")]([name, check, wrap, directReturn]);
1203
        },
1204

    
1205
        match: function(/* ... */){
1206
                // summary:
1207
                //                Find an adapter for the given arguments. If no suitable adapter
1208
                //                is found, throws an exception. match() accepts any number of
1209
                //                arguments, all of which are passed to all matching functions
1210
                //                from the registered pairs.
1211
                for(var i = 0; i < this.pairs.length; i++){
1212
                        var pair = this.pairs[i];
1213
                        if(pair[1].apply(this, arguments)){
1214
                                if((pair[3])||(this.returnWrappers)){
1215
                                        return pair[2];
1216
                                }else{
1217
                                        return pair[2].apply(this, arguments);
1218
                                }
1219
                        }
1220
                }
1221
                throw new Error("No match found");
1222
        },
1223

    
1224
        unregister: function(name){
1225
                // summary: Remove a named adapter from the registry
1226

    
1227
                // FIXME: this is kind of a dumb way to handle this. On a large
1228
                // registry this will be slow-ish and we can use the name as a lookup
1229
                // should we choose to trade memory for speed.
1230
                for(var i = 0; i < this.pairs.length; i++){
1231
                        var pair = this.pairs[i];
1232
                        if(pair[0] == name){
1233
                                this.pairs.splice(i, 1);
1234
                                return true;
1235
                        }
1236
                }
1237
                return false;
1238
        }
1239
});
1240

    
1241
}
1242

    
1243
if(!dojo._hasResource["dijit._base.place"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
1244
dojo._hasResource["dijit._base.place"] = true;
1245
dojo.provide("dijit._base.place");
1246

    
1247

    
1248

    
1249

    
1250

    
1251
dijit.getViewport = function(){
1252
        // summary:
1253
        //                Returns the dimensions and scroll position of the viewable area of a browser window
1254

    
1255
        return dojo.window.getBox();
1256
};
1257

    
1258
/*=====
1259
dijit.__Position = function(){
1260
        // x: Integer
1261
        //                horizontal coordinate in pixels, relative to document body
1262
        // y: Integer
1263
        //                vertical coordinate in pixels, relative to document body
1264

1265
        thix.x = x;
1266
        this.y = y;
1267
}
1268
=====*/
1269

    
1270

    
1271
dijit.placeOnScreen = function(
1272
        /* DomNode */                        node,
1273
        /* dijit.__Position */        pos,
1274
        /* String[] */                        corners,
1275
        /* dijit.__Position? */        padding){
1276
        // summary:
1277
        //                Positions one of the node's corners at specified position
1278
        //                such that node is fully visible in viewport.
1279
        // description:
1280
        //                NOTE: node is assumed to be absolutely or relatively positioned.
1281
        //        pos:
1282
        //                Object like {x: 10, y: 20}
1283
        //        corners:
1284
        //                Array of Strings representing order to try corners in, like ["TR", "BL"].
1285
        //                Possible values are:
1286
        //                        * "BL" - bottom left
1287
        //                        * "BR" - bottom right
1288
        //                        * "TL" - top left
1289
        //                        * "TR" - top right
1290
        //        padding:
1291
        //                set padding to put some buffer around the element you want to position.
1292
        // example:
1293
        //                Try to place node's top right corner at (10,20).
1294
        //                If that makes node go (partially) off screen, then try placing
1295
        //                bottom left corner at (10,20).
1296
        //        |        placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"])
1297

    
1298
        var choices = dojo.map(corners, function(corner){
1299
                var c = { corner: corner, pos: {x:pos.x,y:pos.y} };
1300
                if(padding){
1301
                        c.pos.x += corner.charAt(1) == 'L' ? padding.x : -padding.x;
1302
                        c.pos.y += corner.charAt(0) == 'T' ? padding.y : -padding.y;
1303
                }
1304
                return c;
1305
        });
1306

    
1307
        return dijit._place(node, choices);
1308
}
1309

    
1310
dijit._place = function(/*DomNode*/ node, /* Array */ choices, /* Function */ layoutNode){
1311
        // summary:
1312
        //                Given a list of spots to put node, put it at the first spot where it fits,
1313
        //                of if it doesn't fit anywhere then the place with the least overflow
1314
        // choices: Array
1315
        //                Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} }
1316
        //                Above example says to put the top-left corner of the node at (10,20)
1317
        // layoutNode: Function(node, aroundNodeCorner, nodeCorner)
1318
        //                for things like tooltip, they are displayed differently (and have different dimensions)
1319
        //                based on their orientation relative to the parent.   This adjusts the popup based on orientation.
1320

    
1321
        // get {x: 10, y: 10, w: 100, h:100} type obj representing position of
1322
        // viewport over document
1323
        var view = dojo.window.getBox();
1324

    
1325
        // This won't work if the node is inside a <div style="position: relative">,
1326
        // so reattach it to dojo.doc.body.   (Otherwise, the positioning will be wrong
1327
        // and also it might get cutoff)
1328
        if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){
1329
                dojo.body().appendChild(node);
1330
        }
1331

    
1332
        var best = null;
1333
        dojo.some(choices, function(choice){
1334
                var corner = choice.corner;
1335
                var pos = choice.pos;
1336

    
1337
                // configure node to be displayed in given position relative to button
1338
                // (need to do this in order to get an accurate size for the node, because
1339
                // a tooltips size changes based on position, due to triangle)
1340
                if(layoutNode){
1341
                        layoutNode(node, choice.aroundCorner, corner);
1342
                }
1343

    
1344
                // get node's size
1345
                var style = node.style;
1346
                var oldDisplay = style.display;
1347
                var oldVis = style.visibility;
1348
                style.visibility = "hidden";
1349
                style.display = "";
1350
                var mb = dojo.marginBox(node);
1351
                style.display = oldDisplay;
1352
                style.visibility = oldVis;
1353

    
1354
                // coordinates and size of node with specified corner placed at pos,
1355
                // and clipped by viewport
1356
                var startX = Math.max(view.l, corner.charAt(1) == 'L' ? pos.x : (pos.x - mb.w)),
1357
                        startY = Math.max(view.t, corner.charAt(0) == 'T' ? pos.y : (pos.y - mb.h)),
1358
                        endX = Math.min(view.l + view.w, corner.charAt(1) == 'L' ? (startX + mb.w) : pos.x),
1359
                        endY = Math.min(view.t + view.h, corner.charAt(0) == 'T' ? (startY + mb.h) : pos.y),
1360
                        width = endX - startX,
1361
                        height = endY - startY,
1362
                        overflow = (mb.w - width) + (mb.h - height);
1363

    
1364
                if(best == null || overflow < best.overflow){
1365
                        best = {
1366
                                corner: corner,
1367
                                aroundCorner: choice.aroundCorner,
1368
                                x: startX,
1369
                                y: startY,
1370
                                w: width,
1371
                                h: height,
1372
                                overflow: overflow
1373
                        };
1374
                }
1375
                return !overflow;
1376
        });
1377

    
1378
        node.style.left = best.x + "px";
1379
        node.style.top = best.y + "px";
1380
        if(best.overflow && layoutNode){
1381
                layoutNode(node, best.aroundCorner, best.corner);
1382
        }
1383
        return best;
1384
}
1385

    
1386
dijit.placeOnScreenAroundNode = function(
1387
        /* DomNode */                node,
1388
        /* DomNode */                aroundNode,
1389
        /* Object */                aroundCorners,
1390
        /* Function? */                layoutNode){
1391

    
1392
        // summary:
1393
        //                Position node adjacent or kitty-corner to aroundNode
1394
        //                such that it's fully visible in viewport.
1395
        //
1396
        // description:
1397
        //                Place node such that corner of node touches a corner of
1398
        //                aroundNode, and that node is fully visible.
1399
        //
1400
        // aroundCorners:
1401
        //                Ordered list of pairs of corners to try matching up.
1402
        //                Each pair of corners is represented as a key/value in the hash,
1403
        //                where the key corresponds to the aroundNode's corner, and
1404
        //                the value corresponds to the node's corner:
1405
        //
1406
        //        |        { aroundNodeCorner1: nodeCorner1, aroundNodeCorner2: nodeCorner2, ...}
1407
        //
1408
        //                The following strings are used to represent the four corners:
1409
        //                        * "BL" - bottom left
1410
        //                        * "BR" - bottom right
1411
        //                        * "TL" - top left
1412
        //                        * "TR" - top right
1413
        //
1414
        // layoutNode: Function(node, aroundNodeCorner, nodeCorner)
1415
        //                For things like tooltip, they are displayed differently (and have different dimensions)
1416
        //                based on their orientation relative to the parent.   This adjusts the popup based on orientation.
1417
        //
1418
        // example:
1419
        //        |        dijit.placeOnScreenAroundNode(node, aroundNode, {'BL':'TL', 'TR':'BR'});
1420
        //                This will try to position node such that node's top-left corner is at the same position
1421
        //                as the bottom left corner of the aroundNode (ie, put node below
1422
        //                aroundNode, with left edges aligned).  If that fails it will try to put
1423
        //                 the bottom-right corner of node where the top right corner of aroundNode is
1424
        //                (ie, put node above aroundNode, with right edges aligned)
1425
        //
1426

    
1427
        // get coordinates of aroundNode
1428
        aroundNode = dojo.byId(aroundNode);
1429
        var oldDisplay = aroundNode.style.display;
1430
        aroundNode.style.display="";
1431
        // #3172: use the slightly tighter border box instead of marginBox
1432
        var aroundNodePos = dojo.position(aroundNode, true);
1433
        aroundNode.style.display=oldDisplay;
1434

    
1435
        // place the node around the calculated rectangle
1436
        return dijit._placeOnScreenAroundRect(node,
1437
                aroundNodePos.x, aroundNodePos.y, aroundNodePos.w, aroundNodePos.h,        // rectangle
1438
                aroundCorners, layoutNode);
1439
};
1440

    
1441
/*=====
1442
dijit.__Rectangle = function(){
1443
        // x: Integer
1444
        //                horizontal offset in pixels, relative to document body
1445
        // y: Integer
1446
        //                vertical offset in pixels, relative to document body
1447
        // width: Integer
1448
        //                width in pixels
1449
        // height: Integer
1450
        //                height in pixels
1451

1452
        this.x = x;
1453
        this.y = y;
1454
        this.width = width;
1455
        this.height = height;
1456
}
1457
=====*/
1458

    
1459

    
1460
dijit.placeOnScreenAroundRectangle = function(
1461
        /* DomNode */                        node,
1462
        /* dijit.__Rectangle */        aroundRect,
1463
        /* Object */                        aroundCorners,
1464
        /* Function */                        layoutNode){
1465

    
1466
        // summary:
1467
        //                Like dijit.placeOnScreenAroundNode(), except that the "around"
1468
        //                parameter is an arbitrary rectangle on the screen (x, y, width, height)
1469
        //                instead of a dom node.
1470

    
1471
        return dijit._placeOnScreenAroundRect(node,
1472
                aroundRect.x, aroundRect.y, aroundRect.width, aroundRect.height,        // rectangle
1473
                aroundCorners, layoutNode);
1474
};
1475

    
1476
dijit._placeOnScreenAroundRect = function(
1477
        /* DomNode */                node,
1478
        /* Number */                x,
1479
        /* Number */                y,
1480
        /* Number */                width,
1481
        /* Number */                height,
1482
        /* Object */                aroundCorners,
1483
        /* Function */                layoutNode){
1484

    
1485
        // summary:
1486
        //                Like dijit.placeOnScreenAroundNode(), except it accepts coordinates
1487
        //                of a rectangle to place node adjacent to.
1488

    
1489
        // TODO: combine with placeOnScreenAroundRectangle()
1490

    
1491
        // Generate list of possible positions for node
1492
        var choices = [];
1493
        for(var nodeCorner in aroundCorners){
1494
                choices.push( {
1495
                        aroundCorner: nodeCorner,
1496
                        corner: aroundCorners[nodeCorner],
1497
                        pos: {
1498
                                x: x + (nodeCorner.charAt(1) == 'L' ? 0 : width),
1499
                                y: y + (nodeCorner.charAt(0) == 'T' ? 0 : height)
1500
                        }
1501
                });
1502
        }
1503

    
1504
        return dijit._place(node, choices, layoutNode);
1505
};
1506

    
1507
dijit.placementRegistry= new dojo.AdapterRegistry();
1508
dijit.placementRegistry.register("node",
1509
        function(n, x){
1510
                return typeof x == "object" &&
1511
                        typeof x.offsetWidth != "undefined" && typeof x.offsetHeight != "undefined";
1512
        },
1513
        dijit.placeOnScreenAroundNode);
1514
dijit.placementRegistry.register("rect",
1515
        function(n, x){
1516
                return typeof x == "object" &&
1517
                        "x" in x && "y" in x && "width" in x && "height" in x;
1518
        },
1519
        dijit.placeOnScreenAroundRectangle);
1520

    
1521
dijit.placeOnScreenAroundElement = function(
1522
        /* DomNode */                node,
1523
        /* Object */                aroundElement,
1524
        /* Object */                aroundCorners,
1525
        /* Function */                layoutNode){
1526

    
1527
        // summary:
1528
        //                Like dijit.placeOnScreenAroundNode(), except it accepts an arbitrary object
1529
        //                for the "around" argument and finds a proper processor to place a node.
1530

    
1531
        return dijit.placementRegistry.match.apply(dijit.placementRegistry, arguments);
1532
};
1533

    
1534
dijit.getPopupAroundAlignment = function(/*Array*/ position, /*Boolean*/ leftToRight){
1535
        // summary:
1536
        //                Transforms the passed array of preferred positions into a format suitable for passing as the aroundCorners argument to dijit.placeOnScreenAroundElement.
1537
        //
1538
        // position: String[]
1539
        //                This variable controls the position of the drop down.
1540
        //                It's an array of strings with the following values:
1541
        //
1542
        //                        * before: places drop down to the left of the target node/widget, or to the right in
1543
        //                          the case of RTL scripts like Hebrew and Arabic
1544
        //                        * after: places drop down to the right of the target node/widget, or to the left in
1545
        //                          the case of RTL scripts like Hebrew and Arabic
1546
        //                        * above: drop down goes above target node
1547
        //                        * below: drop down goes below target node
1548
        //
1549
        //                The list is positions is tried, in order, until a position is found where the drop down fits
1550
        //                within the viewport.
1551
        //
1552
        // leftToRight: Boolean
1553
        //                Whether the popup will be displaying in leftToRight mode.
1554
        //
1555
        var align = {};
1556
        dojo.forEach(position, function(pos){
1557
                switch(pos){
1558
                        case "after":
1559
                                align[leftToRight ? "BR" : "BL"] = leftToRight ? "BL" : "BR";
1560
                                break;
1561
                        case "before":
1562
                                align[leftToRight ? "BL" : "BR"] = leftToRight ? "BR" : "BL";
1563
                                break;
1564
                        case "below":
1565
                                // first try to align left borders, next try to align right borders (or reverse for RTL mode)
1566
                                align[leftToRight ? "BL" : "BR"] = leftToRight ? "TL" : "TR";
1567
                                align[leftToRight ? "BR" : "BL"] = leftToRight ? "TR" : "TL";
1568
                                break;
1569
                        case "above":
1570
                        default:
1571
                                // first try to align left borders, next try to align right borders (or reverse for RTL mode)
1572
                                align[leftToRight ? "TL" : "TR"] = leftToRight ? "BL" : "BR";
1573
                                align[leftToRight ? "TR" : "TL"] = leftToRight ? "BR" : "BL";
1574
                                break;
1575
                }
1576
        });
1577
        return align;
1578
};
1579

    
1580
}
1581

    
1582
if(!dojo._hasResource["dijit._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
1583
dojo._hasResource["dijit._base.window"] = true;
1584
dojo.provide("dijit._base.window");
1585

    
1586

    
1587

    
1588
dijit.getDocumentWindow = function(doc){
1589
        return dojo.window.get(doc);
1590
};
1591

    
1592
}
1593

    
1594
if(!dojo._hasResource["dijit._base.popup"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
1595
dojo._hasResource["dijit._base.popup"] = true;
1596
dojo.provide("dijit._base.popup");
1597

    
1598

    
1599

    
1600

    
1601

    
1602
/*=====
1603
dijit.popup.__OpenArgs = function(){
1604
        // popup: Widget
1605
        //                widget to display
1606
        // parent: Widget
1607
        //                the button etc. that is displaying this popup
1608
        // around: DomNode
1609
        //                DOM node (typically a button); place popup relative to this node.  (Specify this *or* "x" and "y" parameters.)
1610
        // x: Integer
1611
        //                Absolute horizontal position (in pixels) to place node at.  (Specify this *or* "around" parameter.)
1612
        // y: Integer
1613
        //                Absolute vertical position (in pixels) to place node at.  (Specify this *or* "around" parameter.)
1614
        // orient: Object|String
1615
        //                When the around parameter is specified, orient should be an
1616
        //                ordered list of tuples of the form (around-node-corner, popup-node-corner).
1617
        //                dijit.popup.open() tries to position the popup according to each tuple in the list, in order,
1618
        //                until the popup appears fully within the viewport.
1619
        //
1620
        //                The default value is {BL:'TL', TL:'BL'}, which represents a list of two tuples:
1621
        //                        1. (BL, TL)
1622
        //                        2. (TL, BL)
1623
        //                where BL means "bottom left" and "TL" means "top left".
1624
        //                So by default, it first tries putting the popup below the around node, left-aligning them,
1625
        //                and then tries to put it above the around node, still left-aligning them.   Note that the
1626
        //                default is horizontally reversed when in RTL mode.
1627
        //
1628
        //                When an (x,y) position is specified rather than an around node, orient is either
1629
        //                "R" or "L".  R (for right) means that it tries to put the popup to the right of the mouse,
1630
        //                specifically positioning the popup's top-right corner at the mouse position, and if that doesn't
1631
        //                fit in the viewport, then it tries, in order, the bottom-right corner, the top left corner,
1632
        //                and the top-right corner.
1633
        // onCancel: Function
1634
        //                callback when user has canceled the popup by
1635
        //                        1. hitting ESC or
1636
        //                        2. by using the popup widget's proprietary cancel mechanism (like a cancel button in a dialog);
1637
        //                           i.e. whenever popupWidget.onCancel() is called, args.onCancel is called
1638
        // onClose: Function
1639
        //                callback whenever this popup is closed
1640
        // onExecute: Function
1641
        //                callback when user "executed" on the popup/sub-popup by selecting a menu choice, etc. (top menu only)
1642
        // padding: dijit.__Position
1643
        //                adding a buffer around the opening position. This is only useful when around is not set.
1644
        this.popup = popup;
1645
        this.parent = parent;
1646
        this.around = around;
1647
        this.x = x;
1648
        this.y = y;
1649
        this.orient = orient;
1650
        this.onCancel = onCancel;
1651
        this.onClose = onClose;
1652
        this.onExecute = onExecute;
1653
        this.padding = padding;
1654
}
1655
=====*/
1656

    
1657
dijit.popup = {
1658
        // summary:
1659
        //                This singleton is used to show/hide widgets as popups.
1660

    
1661
        // _stack: dijit._Widget[]
1662
        //                Stack of currently popped up widgets.
1663
        //                (someone opened _stack[0], and then it opened _stack[1], etc.)
1664
        _stack: [],
1665
        
1666
        // _beginZIndex: Number
1667
        //                Z-index of the first popup.   (If first popup opens other
1668
        //                popups they get a higher z-index.)
1669
        _beginZIndex: 1000,
1670

    
1671
        _idGen: 1,
1672

    
1673
        moveOffScreen: function(/*DomNode*/ node){
1674
                // summary:
1675
                //                Initialization for nodes that will be used as popups
1676
                //
1677
                // description:
1678
                //                Puts node inside a wrapper <div>, and
1679
                //                positions wrapper div off screen, but not display:none, so that
1680
                //                the widget doesn't appear in the page flow and/or cause a blank
1681
                //                area at the bottom of the viewport (making scrollbar longer), but
1682
                //                initialization of contained widgets works correctly
1683

    
1684
                var wrapper = node.parentNode;
1685

    
1686
                // Create a wrapper widget for when this node (in the future) will be used as a popup.
1687
                // This is done early because of IE bugs where creating/moving DOM nodes causes focus
1688
                // to go wonky, see tests/robot/Toolbar.html to reproduce
1689
                if(!wrapper || !dojo.hasClass(wrapper, "dijitPopup")){
1690
                        wrapper = dojo.create("div",{
1691
                                "class":"dijitPopup",
1692
                                style:{
1693
                                        visibility:"hidden",
1694
                                        top: "-9999px"
1695
                                }
1696
                        }, dojo.body());
1697
                        dijit.setWaiRole(wrapper, "presentation");
1698
                        wrapper.appendChild(node);
1699
                }
1700

    
1701

    
1702
                var s = node.style;
1703
                s.display = "";
1704
                s.visibility = "";
1705
                s.position = "";
1706
                s.top = "0px";
1707

    
1708
                dojo.style(wrapper, {
1709
                        visibility: "hidden",
1710
                        // prevent transient scrollbar causing misalign (#5776), and initial flash in upper left (#10111)
1711
                        top: "-9999px"
1712
                });
1713
        },
1714

    
1715
        getTopPopup: function(){
1716
                // summary:
1717
                //                Compute the closest ancestor popup that's *not* a child of another popup.
1718
                //                Ex: For a TooltipDialog with a button that spawns a tree of menus, find the popup of the button.
1719
                var stack = this._stack;
1720
                for(var pi=stack.length-1; pi > 0 && stack[pi].parent === stack[pi-1].widget; pi--){
1721
                        /* do nothing, just trying to get right value for pi */
1722
                }
1723
                return stack[pi];
1724
        },
1725

    
1726
        open: function(/*dijit.popup.__OpenArgs*/ args){
1727
                // summary:
1728
                //                Popup the widget at the specified position
1729
                //
1730
                // example:
1731
                //                opening at the mouse position
1732
                //                |                dijit.popup.open({popup: menuWidget, x: evt.pageX, y: evt.pageY});
1733
                //
1734
                // example:
1735
                //                opening the widget as a dropdown
1736
                //                |                dijit.popup.open({parent: this, popup: menuWidget, around: this.domNode, onClose: function(){...}});
1737
                //
1738
                //                Note that whatever widget called dijit.popup.open() should also listen to its own _onBlur callback
1739
                //                (fired from _base/focus.js) to know that focus has moved somewhere else and thus the popup should be closed.
1740

    
1741
                var stack = this._stack,
1742
                        widget = args.popup,
1743
                        orient = args.orient || (
1744
                                (args.parent ? args.parent.isLeftToRight() : dojo._isBodyLtr()) ?
1745
                                {'BL':'TL', 'BR':'TR', 'TL':'BL', 'TR':'BR'} :
1746
                                {'BR':'TR', 'BL':'TL', 'TR':'BR', 'TL':'BL'}
1747
                        ),
1748
                        around = args.around,
1749
                        id = (args.around && args.around.id) ? (args.around.id+"_dropdown") : ("popup_"+this._idGen++);
1750

    
1751

    
1752
                // The wrapper may have already been created, but in case it wasn't, create here
1753
                var wrapper = widget.domNode.parentNode;
1754
                if(!wrapper || !dojo.hasClass(wrapper, "dijitPopup")){
1755
                        this.moveOffScreen(widget.domNode);
1756
                        wrapper = widget.domNode.parentNode;
1757
                }
1758

    
1759
                dojo.attr(wrapper, {
1760
                        id: id,
1761
                        style: {
1762
                                zIndex: this._beginZIndex + stack.length
1763
                        },
1764
                        "class": "dijitPopup " + (widget.baseClass || widget["class"] || "").split(" ")[0] +"Popup",
1765
                        dijitPopupParent: args.parent ? args.parent.id : ""
1766
                });
1767

    
1768
                if(dojo.isIE || dojo.isMoz){
1769
                        var iframe = wrapper.childNodes[1];
1770
                        if(!iframe){
1771
                                iframe = new dijit.BackgroundIframe(wrapper);
1772
                        }
1773
                }
1774

    
1775
                // position the wrapper node and make it visible
1776
                var best = around ?
1777
                        dijit.placeOnScreenAroundElement(wrapper, around, orient, widget.orient ? dojo.hitch(widget, "orient") : null) :
1778
                        dijit.placeOnScreen(wrapper, args, orient == 'R' ? ['TR','BR','TL','BL'] : ['TL','BL','TR','BR'], args.padding);
1779

    
1780
                wrapper.style.visibility = "visible";
1781
                widget.domNode.style.visibility = "visible";        // counteract effects from _HasDropDown
1782

    
1783
                var handlers = [];
1784

    
1785
                // provide default escape and tab key handling
1786
                // (this will work for any widget, not just menu)
1787
                handlers.push(dojo.connect(wrapper, "onkeypress", this, function(evt){
1788
                        if(evt.charOrCode == dojo.keys.ESCAPE && args.onCancel){
1789
                                dojo.stopEvent(evt);
1790
                                args.onCancel();
1791
                        }else if(evt.charOrCode === dojo.keys.TAB){
1792
                                dojo.stopEvent(evt);
1793
                                var topPopup = this.getTopPopup();
1794
                                if(topPopup && topPopup.onCancel){
1795
                                        topPopup.onCancel();
1796
                                }
1797
                        }
1798
                }));
1799

    
1800
                // watch for cancel/execute events on the popup and notify the caller
1801
                // (for a menu, "execute" means clicking an item)
1802
                if(widget.onCancel){
1803
                        handlers.push(dojo.connect(widget, "onCancel", args.onCancel));
1804
                }
1805

    
1806
                handlers.push(dojo.connect(widget, widget.onExecute ? "onExecute" : "onChange", this, function(){
1807
                        var topPopup = this.getTopPopup();
1808
                        if(topPopup && topPopup.onExecute){
1809
                                topPopup.onExecute();
1810
                        }
1811
                }));
1812

    
1813
                stack.push({
1814
                        wrapper: wrapper,
1815
                        iframe: iframe,
1816
                        widget: widget,
1817
                        parent: args.parent,
1818
                        onExecute: args.onExecute,
1819
                        onCancel: args.onCancel,
1820
                         onClose: args.onClose,
1821
                        handlers: handlers
1822
                });
1823

    
1824
                if(widget.onOpen){
1825
                        // TODO: in 2.0 standardize onShow() (used by StackContainer) and onOpen() (used here)
1826
                        widget.onOpen(best);
1827
                }
1828

    
1829
                return best;
1830
        },
1831

    
1832
        close: function(/*dijit._Widget*/ popup){
1833
                // summary:
1834
                //                Close specified popup and any popups that it parented
1835

    
1836
                var stack = this._stack;
1837

    
1838
                // Basically work backwards from the top of the stack closing popups
1839
                // until we hit the specified popup, but IIRC there was some issue where closing
1840
                // a popup would cause others to close too.  Thus if we are trying to close B in [A,B,C]
1841
                // closing C might close B indirectly and then the while() condition will run where stack==[A]...
1842
                // so the while condition is constructed defensively.
1843
                while(dojo.some(stack, function(elem){return elem.widget == popup;})){
1844
                        var top = stack.pop(),
1845
                                wrapper = top.wrapper,
1846
                                iframe = top.iframe,
1847
                                widget = top.widget,
1848
                                onClose = top.onClose;
1849

    
1850
                        if(widget.onClose){
1851
                                // TODO: in 2.0 standardize onHide() (used by StackContainer) and onClose() (used here)
1852
                                widget.onClose();
1853
                        }
1854
                        dojo.forEach(top.handlers, dojo.disconnect);
1855

    
1856
                        // Move the widget plus it's wrapper off screen, unless it has already been destroyed in above onClose() etc.
1857
                        if(widget && widget.domNode){
1858
                                this.moveOffScreen(widget.domNode);
1859
                        }else{
1860
                                dojo.destroy(wrapper);
1861
                        }
1862
                        
1863
                        if(onClose){
1864
                                onClose();
1865
                        }
1866
                }
1867
        }
1868
};
1869

    
1870
dijit._frames = new function(){
1871
        // summary:
1872
        //                cache of iframes
1873
        var queue = [];
1874

    
1875
        this.pop = function(){
1876
                var iframe;
1877
                if(queue.length){
1878
                        iframe = queue.pop();
1879
                        iframe.style.display="";
1880
                }else{
1881
                        if(dojo.isIE){
1882
                                var burl = dojo.config["dojoBlankHtmlUrl"] || (dojo.moduleUrl("dojo", "resources/blank.html")+"") || "javascript:\"\"";
1883
                                var html="<iframe src='" + burl + "'"
1884
                                        + " style='position: absolute; left: 0px; top: 0px;"
1885
                                        + "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
1886
                                iframe = dojo.doc.createElement(html);
1887
                        }else{
1888
                                 iframe = dojo.create("iframe");
1889
                                iframe.src = 'javascript:""';
1890
                                iframe.className = "dijitBackgroundIframe";
1891
                                dojo.style(iframe, "opacity", 0.1);
1892
                        }
1893
                        iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didnt work.
1894
                        dijit.setWaiRole(iframe,"presentation");
1895
                }
1896
                return iframe;
1897
        };
1898

    
1899
        this.push = function(iframe){
1900
                iframe.style.display="none";
1901
                queue.push(iframe);
1902
        }
1903
}();
1904

    
1905

    
1906
dijit.BackgroundIframe = function(/* DomNode */node){
1907
        // summary:
1908
        //                For IE/FF z-index schenanigans. id attribute is required.
1909
        //
1910
        // description:
1911
        //                new dijit.BackgroundIframe(node)
1912
        //                        Makes a background iframe as a child of node, that fills
1913
        //                        area (and position) of node
1914

    
1915
        if(!node.id){ throw new Error("no id"); }
1916
        if(dojo.isIE || dojo.isMoz){
1917
                var iframe = dijit._frames.pop();
1918
                node.appendChild(iframe);
1919
                if(dojo.isIE<7){
1920
                        this.resize(node);
1921
                        this._conn = dojo.connect(node, 'onresize', this, function(){
1922
                                this.resize(node);
1923
                        });
1924
                }else{
1925
                        dojo.style(iframe, {
1926
                                width: '100%',
1927
                                height: '100%'
1928
                        });
1929
                }
1930
                this.iframe = iframe;
1931
        }
1932
};
1933

    
1934
dojo.extend(dijit.BackgroundIframe, {
1935
        resize: function(node){
1936
                // summary:
1937
                //                 resize the iframe so its the same size as node
1938
                // description:
1939
                //                this function is a no-op in all browsers except
1940
                //                IE6, which does not support 100% width/height 
1941
                //                of absolute positioned iframes
1942
                if(this.iframe && dojo.isIE<7){
1943
                        dojo.style(this.iframe, {
1944
                                width: node.offsetWidth + 'px',
1945
                                height: node.offsetHeight + 'px'
1946
                        });
1947
                }
1948
        },
1949
        destroy: function(){
1950
                // summary:
1951
                //                destroy the iframe
1952
                if(this._conn){
1953
                        dojo.disconnect(this._conn);
1954
                        this._conn = null;
1955
                }
1956
                if(this.iframe){
1957
                        dijit._frames.push(this.iframe);
1958
                        delete this.iframe;
1959
                }
1960
        }
1961
});
1962

    
1963
}
1964

    
1965
if(!dojo._hasResource["dijit._base.scroll"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
1966
dojo._hasResource["dijit._base.scroll"] = true;
1967
dojo.provide("dijit._base.scroll");
1968

    
1969

    
1970

    
1971
dijit.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
1972
        // summary:
1973
        //                Scroll the passed node into view, if it is not already.
1974
        //                Deprecated, use `dojo.window.scrollIntoView` instead.
1975
        
1976
        dojo.window.scrollIntoView(node, pos);
1977
};
1978

    
1979
}
1980

    
1981
if(!dojo._hasResource["dojo.uacss"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
1982
dojo._hasResource["dojo.uacss"] = true;
1983
dojo.provide("dojo.uacss");
1984

    
1985
(function(){
1986
        // summary:
1987
        //                Applies pre-set CSS classes to the top-level HTML node, based on:
1988
        //                         - browser (ex: dj_ie)
1989
        //                        - browser version (ex: dj_ie6)
1990
        //                        - box model (ex: dj_contentBox)
1991
        //                        - text direction (ex: dijitRtl)
1992
        //
1993
        //                In addition, browser, browser version, and box model are
1994
        //                combined with an RTL flag when browser text is RTL.  ex: dj_ie-rtl.
1995

    
1996
        var d = dojo,
1997
                html = d.doc.documentElement,
1998
                ie = d.isIE,
1999
                opera = d.isOpera,
2000
                maj = Math.floor,
2001
                ff = d.isFF,
2002
                boxModel = d.boxModel.replace(/-/,''),
2003

    
2004
                classes = {
2005
                        dj_ie: ie,
2006
                        dj_ie6: maj(ie) == 6,
2007
                        dj_ie7: maj(ie) == 7,
2008
                        dj_ie8: maj(ie) == 8,
2009
                        dj_quirks: d.isQuirks,
2010
                        dj_iequirks: ie && d.isQuirks,
2011

    
2012
                        // NOTE: Opera not supported by dijit
2013
                        dj_opera: opera,
2014

    
2015
                        dj_khtml: d.isKhtml,
2016

    
2017
                        dj_webkit: d.isWebKit,
2018
                        dj_safari: d.isSafari,
2019
                        dj_chrome: d.isChrome,
2020

    
2021
                        dj_gecko: d.isMozilla,
2022
                        dj_ff3: maj(ff) == 3
2023
                }; // no dojo unsupported browsers
2024

    
2025
        classes["dj_" + boxModel] = true;
2026

    
2027
        // apply browser, browser version, and box model class names
2028
        var classStr = "";
2029
        for(var clz in classes){
2030
                if(classes[clz]){
2031
                        classStr += clz + " ";
2032
                }
2033
        }
2034
        html.className = d.trim(html.className + " " + classStr);
2035

    
2036
        // If RTL mode, then add dj_rtl flag plus repeat existing classes with -rtl extension.
2037
        // We can't run the code below until the <body> tag has loaded (so we can check for dir=rtl).  
2038
        // Unshift() is to run sniff code before the parser.
2039
        dojo._loaders.unshift(function(){
2040
                if(!dojo._isBodyLtr()){
2041
                        var rtlClassStr = "dj_rtl dijitRtl " + classStr.replace(/ /g, "-rtl ")
2042
                        html.className = d.trim(html.className + " " + rtlClassStr);
2043
                }
2044
        });
2045
})();
2046

    
2047
}
2048

    
2049
if(!dojo._hasResource["dijit._base.sniff"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2050
dojo._hasResource["dijit._base.sniff"] = true;
2051
// summary:
2052
//                Applies pre-set CSS classes to the top-level HTML node, see
2053
//                `dojo.uacss` for details.
2054
//
2055
//                Simply doing a require on this module will
2056
//                establish this CSS.  Modified version of Morris' CSS hack.
2057

    
2058
dojo.provide("dijit._base.sniff");
2059

    
2060

    
2061

    
2062
}
2063

    
2064
if(!dojo._hasResource["dijit._base.typematic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2065
dojo._hasResource["dijit._base.typematic"] = true;
2066
dojo.provide("dijit._base.typematic");
2067

    
2068
dijit.typematic = {
2069
        // summary:
2070
        //                These functions are used to repetitively call a user specified callback
2071
        //                method when a specific key or mouse click over a specific DOM node is
2072
        //                held down for a specific amount of time.
2073
        //                Only 1 such event is allowed to occur on the browser page at 1 time.
2074

    
2075
        _fireEventAndReload: function(){
2076
                this._timer = null;
2077
                this._callback(++this._count, this._node, this._evt);
2078
                
2079
                // Schedule next event, timer is at most minDelay (default 10ms) to avoid
2080
                // browser overload (particularly avoiding starving DOH robot so it never gets to send a mouseup)
2081
                this._currentTimeout = Math.max(
2082
                        this._currentTimeout < 0 ? this._initialDelay :
2083
                                (this._subsequentDelay > 1 ? this._subsequentDelay : Math.round(this._currentTimeout * this._subsequentDelay)),
2084
                        this._minDelay);
2085
                this._timer = setTimeout(dojo.hitch(this, "_fireEventAndReload"), this._currentTimeout);
2086
        },
2087

    
2088
        trigger: function(/*Event*/ evt, /*Object*/ _this, /*DOMNode*/ node, /*Function*/ callback, /*Object*/ obj, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
2089
                // summary:
2090
                //                Start a timed, repeating callback sequence.
2091
                //                If already started, the function call is ignored.
2092
                //                This method is not normally called by the user but can be
2093
                //                when the normal listener code is insufficient.
2094
                // evt:
2095
                //                key or mouse event object to pass to the user callback
2096
                // _this:
2097
                //                pointer to the user's widget space.
2098
                // node:
2099
                //                the DOM node object to pass the the callback function
2100
                // callback:
2101
                //                function to call until the sequence is stopped called with 3 parameters:
2102
                // count:
2103
                //                integer representing number of repeated calls (0..n) with -1 indicating the iteration has stopped
2104
                // node:
2105
                //                the DOM node object passed in
2106
                // evt:
2107
                //                key or mouse event object
2108
                // obj:
2109
                //                user space object used to uniquely identify each typematic sequence
2110
                // subsequentDelay (optional):
2111
                //                if > 1, the number of milliseconds until the 3->n events occur
2112
                //                or else the fractional time multiplier for the next event's delay, default=0.9
2113
                // initialDelay (optional):
2114
                //                the number of milliseconds until the 2nd event occurs, default=500ms
2115
                // minDelay (optional):
2116
                //                the maximum delay in milliseconds for event to fire, default=10ms
2117
                if(obj != this._obj){
2118
                        this.stop();
2119
                        this._initialDelay = initialDelay || 500;
2120
                        this._subsequentDelay = subsequentDelay || 0.90;
2121
                        this._minDelay = minDelay || 10;
2122
                        this._obj = obj;
2123
                        this._evt = evt;
2124
                        this._node = node;
2125
                        this._currentTimeout = -1;
2126
                        this._count = -1;
2127
                        this._callback = dojo.hitch(_this, callback);
2128
                        this._fireEventAndReload();
2129
                        this._evt = dojo.mixin({faux: true}, evt);
2130
                }
2131
        },
2132

    
2133
        stop: function(){
2134
                // summary:
2135
                //                Stop an ongoing timed, repeating callback sequence.
2136
                if(this._timer){
2137
                        clearTimeout(this._timer);
2138
                        this._timer = null;
2139
                }
2140
                if(this._obj){
2141
                        this._callback(-1, this._node, this._evt);
2142
                        this._obj = null;
2143
                }
2144
        },
2145

    
2146
        addKeyListener: function(/*DOMNode*/ node, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
2147
                // summary:
2148
                //                Start listening for a specific typematic key.
2149
                //                See also the trigger method for other parameters.
2150
                // keyObject:
2151
                //                an object defining the key to listen for:
2152
                //                 charOrCode:
2153
                //                        the printable character (string) or keyCode (number) to listen for.
2154
                //                 keyCode:
2155
                //                        (deprecated - use charOrCode) the keyCode (number) to listen for (implies charCode = 0).
2156
                //                 charCode:
2157
                //                        (deprecated - use charOrCode) the charCode (number) to listen for.
2158
                //                 ctrlKey:
2159
                //                        desired ctrl key state to initiate the callback sequence:
2160
                //                        - pressed (true)
2161
                //                        - released (false)
2162
                //                        - either (unspecified)
2163
                //                 altKey:
2164
                //                        same as ctrlKey but for the alt key
2165
                //                 shiftKey:
2166
                //                        same as ctrlKey but for the shift key
2167
                // returns:
2168
                //                an array of dojo.connect handles
2169
                if(keyObject.keyCode){
2170
                        keyObject.charOrCode = keyObject.keyCode;
2171
                        dojo.deprecated("keyCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0");
2172
                }else if(keyObject.charCode){
2173
                        keyObject.charOrCode = String.fromCharCode(keyObject.charCode);
2174
                        dojo.deprecated("charCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0");
2175
                }
2176
                return [
2177
                        dojo.connect(node, "onkeypress", this, function(evt){
2178
                                if(evt.charOrCode == keyObject.charOrCode &&
2179
                                (keyObject.ctrlKey === undefined || keyObject.ctrlKey == evt.ctrlKey) &&
2180
                                (keyObject.altKey === undefined || keyObject.altKey == evt.altKey) &&
2181
                                (keyObject.metaKey === undefined || keyObject.metaKey == (evt.metaKey || false)) && // IE doesn't even set metaKey
2182
                                (keyObject.shiftKey === undefined || keyObject.shiftKey == evt.shiftKey)){
2183
                                        dojo.stopEvent(evt);
2184
                                        dijit.typematic.trigger(evt, _this, node, callback, keyObject, subsequentDelay, initialDelay, minDelay);
2185
                                }else if(dijit.typematic._obj == keyObject){
2186
                                        dijit.typematic.stop();
2187
                                }
2188
                        }),
2189
                        dojo.connect(node, "onkeyup", this, function(evt){
2190
                                if(dijit.typematic._obj == keyObject){
2191
                                        dijit.typematic.stop();
2192
                                }
2193
                        })
2194
                ];
2195
        },
2196

    
2197
        addMouseListener: function(/*DOMNode*/ node, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
2198
                // summary:
2199
                //                Start listening for a typematic mouse click.
2200
                //                See the trigger method for other parameters.
2201
                // returns:
2202
                //                an array of dojo.connect handles
2203
                var dc = dojo.connect;
2204
                return [
2205
                        dc(node, "mousedown", this, function(evt){
2206
                                dojo.stopEvent(evt);
2207
                                dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay);
2208
                        }),
2209
                        dc(node, "mouseup", this, function(evt){
2210
                                dojo.stopEvent(evt);
2211
                                dijit.typematic.stop();
2212
                        }),
2213
                        dc(node, "mouseout", this, function(evt){
2214
                                dojo.stopEvent(evt);
2215
                                dijit.typematic.stop();
2216
                        }),
2217
                        dc(node, "mousemove", this, function(evt){
2218
                                evt.preventDefault();
2219
                        }),
2220
                        dc(node, "dblclick", this, function(evt){
2221
                                dojo.stopEvent(evt);
2222
                                if(dojo.isIE){
2223
                                        dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay);
2224
                                        setTimeout(dojo.hitch(this, dijit.typematic.stop), 50);
2225
                                }
2226
                        })
2227
                ];
2228
        },
2229

    
2230
        addListener: function(/*Node*/ mouseNode, /*Node*/ keyNode, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
2231
                // summary:
2232
                //                Start listening for a specific typematic key and mouseclick.
2233
                //                This is a thin wrapper to addKeyListener and addMouseListener.
2234
                //                See the addMouseListener and addKeyListener methods for other parameters.
2235
                // mouseNode:
2236
                //                the DOM node object to listen on for mouse events.
2237
                // keyNode:
2238
                //                the DOM node object to listen on for key events.
2239
                // returns:
2240
                //                an array of dojo.connect handles
2241
                return this.addKeyListener(keyNode, keyObject, _this, callback, subsequentDelay, initialDelay, minDelay).concat(
2242
                        this.addMouseListener(mouseNode, _this, callback, subsequentDelay, initialDelay, minDelay));
2243
        }
2244
};
2245

    
2246
}
2247

    
2248
if(!dojo._hasResource["dijit._base.wai"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2249
dojo._hasResource["dijit._base.wai"] = true;
2250
dojo.provide("dijit._base.wai");
2251

    
2252
dijit.wai = {
2253
        onload: function(){
2254
                // summary:
2255
                //                Detects if we are in high-contrast mode or not
2256

    
2257
                // This must be a named function and not an anonymous
2258
                // function, so that the widget parsing code can make sure it
2259
                // registers its onload function after this function.
2260
                // DO NOT USE "this" within this function.
2261

    
2262
                // create div for testing if high contrast mode is on or images are turned off
2263
                var div = dojo.create("div",{
2264
                        id: "a11yTestNode",
2265
                        style:{
2266
                                cssText:'border: 1px solid;'
2267
                                        + 'border-color:red green;'
2268
                                        + 'position: absolute;'
2269
                                        + 'height: 5px;'
2270
                                        + 'top: -999px;'
2271
                                        + 'background-image: url("' + (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")) + '");'
2272
                        }
2273
                }, dojo.body());
2274

    
2275
                // test it
2276
                var cs = dojo.getComputedStyle(div);
2277
                if(cs){
2278
                        var bkImg = cs.backgroundImage;
2279
                        var needsA11y = (cs.borderTopColor == cs.borderRightColor) || (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)" ));
2280
                        dojo[needsA11y ? "addClass" : "removeClass"](dojo.body(), "dijit_a11y");
2281
                        if(dojo.isIE){
2282
                                div.outerHTML = "";                // prevent mixed-content warning, see http://support.microsoft.com/kb/925014
2283
                        }else{
2284
                                dojo.body().removeChild(div);
2285
                        }
2286
                }
2287
        }
2288
};
2289

    
2290
// Test if computer is in high contrast mode.
2291
// Make sure the a11y test runs first, before widgets are instantiated.
2292
if(dojo.isIE || dojo.isMoz){        // NOTE: checking in Safari messes things up
2293
        dojo._loaders.unshift(dijit.wai.onload);
2294
}
2295

    
2296
dojo.mixin(dijit, {
2297
        _XhtmlRoles: /banner|contentinfo|definition|main|navigation|search|note|secondary|seealso/,
2298

    
2299
        hasWaiRole: function(/*Element*/ elem, /*String*/ role){
2300
                // summary:
2301
                //                Determines if an element has a particular non-XHTML role.
2302
                // returns:
2303
                //                True if elem has the specific non-XHTML role attribute and false if not.
2304
                //                 For backwards compatibility if role parameter not provided,
2305
                //                 returns true if has non XHTML role
2306
                var waiRole = this.getWaiRole(elem);
2307
                return role ? (waiRole.indexOf(role) > -1) : (waiRole.length > 0);
2308
        },
2309

    
2310
        getWaiRole: function(/*Element*/ elem){
2311
                // summary:
2312
                //                Gets the non-XHTML role for an element (which should be a wai role).
2313
                // returns:
2314
                //                The non-XHTML role of elem or an empty string if elem
2315
                //                does not have a role.
2316
                 return dojo.trim((dojo.attr(elem, "role") || "").replace(this._XhtmlRoles,"").replace("wairole:",""));
2317
        },
2318

    
2319
        setWaiRole: function(/*Element*/ elem, /*String*/ role){
2320
                // summary:
2321
                //                Sets the role on an element.
2322
                // description:
2323
                //                Replace existing role attribute with new role.
2324
                //                If elem already has an XHTML role, append this role to XHTML role
2325
                //                and remove other ARIA roles.
2326

    
2327
                var curRole = dojo.attr(elem, "role") || "";
2328
                if(!this._XhtmlRoles.test(curRole)){
2329
                        dojo.attr(elem, "role", role);
2330
                }else{
2331
                        if((" "+ curRole +" ").indexOf(" " + role + " ") < 0){
2332
                                var clearXhtml = dojo.trim(curRole.replace(this._XhtmlRoles, ""));
2333
                                var cleanRole = dojo.trim(curRole.replace(clearXhtml, ""));
2334
                                dojo.attr(elem, "role", cleanRole + (cleanRole ? ' ' : '') + role);
2335
                        }
2336
                }
2337
        },
2338

    
2339
        removeWaiRole: function(/*Element*/ elem, /*String*/ role){
2340
                // summary:
2341
                //                Removes the specified non-XHTML role from an element.
2342
                //                 Removes role attribute if no specific role provided (for backwards compat.)
2343

    
2344
                var roleValue = dojo.attr(elem, "role");
2345
                if(!roleValue){ return; }
2346
                if(role){
2347
                        var t = dojo.trim((" " + roleValue + " ").replace(" " + role + " ", " "));
2348
                        dojo.attr(elem, "role", t);
2349
                }else{
2350
                        elem.removeAttribute("role");
2351
                }
2352
        },
2353

    
2354
        hasWaiState: function(/*Element*/ elem, /*String*/ state){
2355
                // summary:
2356
                //                Determines if an element has a given state.
2357
                // description:
2358
                //                Checks for an attribute called "aria-"+state.
2359
                // returns:
2360
                //                true if elem has a value for the given state and
2361
                //                false if it does not.
2362

    
2363
                return elem.hasAttribute ? elem.hasAttribute("aria-"+state) : !!elem.getAttribute("aria-"+state);
2364
        },
2365

    
2366
        getWaiState: function(/*Element*/ elem, /*String*/ state){
2367
                // summary:
2368
                //                Gets the value of a state on an element.
2369
                // description:
2370
                //                Checks for an attribute called "aria-"+state.
2371
                // returns:
2372
                //                The value of the requested state on elem
2373
                //                or an empty string if elem has no value for state.
2374

    
2375
                return elem.getAttribute("aria-"+state) || "";
2376
        },
2377

    
2378
        setWaiState: function(/*Element*/ elem, /*String*/ state, /*String*/ value){
2379
                // summary:
2380
                //                Sets a state on an element.
2381
                // description:
2382
                //                Sets an attribute called "aria-"+state.
2383

    
2384
                elem.setAttribute("aria-"+state, value);
2385
        },
2386

    
2387
        removeWaiState: function(/*Element*/ elem, /*String*/ state){
2388
                // summary:
2389
                //                Removes a state from an element.
2390
                // description:
2391
                //                Sets an attribute called "aria-"+state.
2392

    
2393
                elem.removeAttribute("aria-"+state);
2394
        }
2395
});
2396

    
2397
}
2398

    
2399
if(!dojo._hasResource["dijit._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2400
dojo._hasResource["dijit._base"] = true;
2401
dojo.provide("dijit._base");
2402

    
2403

    
2404

    
2405

    
2406

    
2407

    
2408

    
2409

    
2410

    
2411

    
2412

    
2413
}
2414

    
2415
if(!dojo._hasResource["dojo.date.stamp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2416
dojo._hasResource["dojo.date.stamp"] = true;
2417
dojo.provide("dojo.date.stamp");
2418

    
2419
// Methods to convert dates to or from a wire (string) format using well-known conventions
2420

    
2421
dojo.date.stamp.fromISOString = function(/*String*/formattedString, /*Number?*/defaultTime){
2422
        //        summary:
2423
        //                Returns a Date object given a string formatted according to a subset of the ISO-8601 standard.
2424
        //
2425
        //        description:
2426
        //                Accepts a string formatted according to a profile of ISO8601 as defined by
2427
        //                [RFC3339](http://www.ietf.org/rfc/rfc3339.txt), except that partial input is allowed.
2428
        //                Can also process dates as specified [by the W3C](http://www.w3.org/TR/NOTE-datetime)
2429
        //                The following combinations are valid:
2430
        //
2431
        //                        * dates only
2432
        //                        |        * yyyy
2433
        //                        |        * yyyy-MM
2434
        //                        |        * yyyy-MM-dd
2435
        //                         * times only, with an optional time zone appended
2436
        //                        |        * THH:mm
2437
        //                        |        * THH:mm:ss
2438
        //                        |        * THH:mm:ss.SSS
2439
        //                         * and "datetimes" which could be any combination of the above
2440
        //
2441
        //                timezones may be specified as Z (for UTC) or +/- followed by a time expression HH:mm
2442
        //                Assumes the local time zone if not specified.  Does not validate.  Improperly formatted
2443
        //                input may return null.  Arguments which are out of bounds will be handled
2444
        //                 by the Date constructor (e.g. January 32nd typically gets resolved to February 1st)
2445
        //                Only years between 100 and 9999 are supported.
2446
        //
2447
          //        formattedString:
2448
        //                A string such as 2005-06-30T08:05:00-07:00 or 2005-06-30 or T08:05:00
2449
        //
2450
        //        defaultTime:
2451
        //                Used for defaults for fields omitted in the formattedString.
2452
        //                Uses 1970-01-01T00:00:00.0Z by default.
2453

    
2454
        if(!dojo.date.stamp._isoRegExp){
2455
                dojo.date.stamp._isoRegExp =
2456
//TODO: could be more restrictive and check for 00-59, etc.
2457
                        /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(.\d+)?)?((?:[+-](\d{2}):(\d{2}))|Z)?)?$/;
2458
        }
2459

    
2460
        var match = dojo.date.stamp._isoRegExp.exec(formattedString),
2461
                result = null;
2462

    
2463
        if(match){
2464
                match.shift();
2465
                if(match[1]){match[1]--;} // Javascript Date months are 0-based
2466
                if(match[6]){match[6] *= 1000;} // Javascript Date expects fractional seconds as milliseconds
2467

    
2468
                if(defaultTime){
2469
                        // mix in defaultTime.  Relatively expensive, so use || operators for the fast path of defaultTime === 0
2470
                        defaultTime = new Date(defaultTime);
2471
                        dojo.forEach(dojo.map(["FullYear", "Month", "Date", "Hours", "Minutes", "Seconds", "Milliseconds"], function(prop){
2472
                                return defaultTime["get" + prop]();
2473
                        }), function(value, index){
2474
                                match[index] = match[index] || value;
2475
                        });
2476
                }
2477
                result = new Date(match[0]||1970, match[1]||0, match[2]||1, match[3]||0, match[4]||0, match[5]||0, match[6]||0); //TODO: UTC defaults
2478
                if(match[0] < 100){
2479
                        result.setFullYear(match[0] || 1970);
2480
                }
2481

    
2482
                var offset = 0,
2483
                        zoneSign = match[7] && match[7].charAt(0);
2484
                if(zoneSign != 'Z'){
2485
                        offset = ((match[8] || 0) * 60) + (Number(match[9]) || 0);
2486
                        if(zoneSign != '-'){ offset *= -1; }
2487
                }
2488
                if(zoneSign){
2489
                        offset -= result.getTimezoneOffset();
2490
                }
2491
                if(offset){
2492
                        result.setTime(result.getTime() + offset * 60000);
2493
                }
2494
        }
2495

    
2496
        return result; // Date or null
2497
}
2498

    
2499
/*=====
2500
        dojo.date.stamp.__Options = function(){
2501
                //        selector: String
2502
                //                "date" or "time" for partial formatting of the Date object.
2503
                //                Both date and time will be formatted by default.
2504
                //        zulu: Boolean
2505
                //                if true, UTC/GMT is used for a timezone
2506
                //        milliseconds: Boolean
2507
                //                if true, output milliseconds
2508
                this.selector = selector;
2509
                this.zulu = zulu;
2510
                this.milliseconds = milliseconds;
2511
        }
2512
=====*/
2513

    
2514
dojo.date.stamp.toISOString = function(/*Date*/dateObject, /*dojo.date.stamp.__Options?*/options){
2515
        //        summary:
2516
        //                Format a Date object as a string according a subset of the ISO-8601 standard
2517
        //
2518
        //        description:
2519
        //                When options.selector is omitted, output follows [RFC3339](http://www.ietf.org/rfc/rfc3339.txt)
2520
        //                The local time zone is included as an offset from GMT, except when selector=='time' (time without a date)
2521
        //                Does not check bounds.  Only years between 100 and 9999 are supported.
2522
        //
2523
        //        dateObject:
2524
        //                A Date object
2525

    
2526
        var _ = function(n){ return (n < 10) ? "0" + n : n; };
2527
        options = options || {};
2528
        var formattedDate = [],
2529
                getter = options.zulu ? "getUTC" : "get",
2530
                date = "";
2531
        if(options.selector != "time"){
2532
                var year = dateObject[getter+"FullYear"]();
2533
                date = ["0000".substr((year+"").length)+year, _(dateObject[getter+"Month"]()+1), _(dateObject[getter+"Date"]())].join('-');
2534
        }
2535
        formattedDate.push(date);
2536
        if(options.selector != "date"){
2537
                var time = [_(dateObject[getter+"Hours"]()), _(dateObject[getter+"Minutes"]()), _(dateObject[getter+"Seconds"]())].join(':');
2538
                var millis = dateObject[getter+"Milliseconds"]();
2539
                if(options.milliseconds){
2540
                        time += "."+ (millis < 100 ? "0" : "") + _(millis);
2541
                }
2542
                if(options.zulu){
2543
                        time += "Z";
2544
                }else if(options.selector != "time"){
2545
                        var timezoneOffset = dateObject.getTimezoneOffset();
2546
                        var absOffset = Math.abs(timezoneOffset);
2547
                        time += (timezoneOffset > 0 ? "-" : "+") + 
2548
                                _(Math.floor(absOffset/60)) + ":" + _(absOffset%60);
2549
                }
2550
                formattedDate.push(time);
2551
        }
2552
        return formattedDate.join('T'); // String
2553
}
2554

    
2555
}
2556

    
2557
if(!dojo._hasResource["dojo.parser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2558
dojo._hasResource["dojo.parser"] = true;
2559
dojo.provide("dojo.parser");
2560

    
2561

    
2562
new Date("X"); // workaround for #11279, new Date("") == NaN
2563

    
2564
dojo.parser = new function(){
2565
        // summary: The Dom/Widget parsing package
2566

    
2567
        var d = dojo;
2568
        this._attrName = d._scopeName + "Type";
2569
        this._query = "[" + this._attrName + "]";
2570

    
2571
        function val2type(/*Object*/ value){
2572
                // summary:
2573
                //                Returns name of type of given value.
2574

    
2575
                if(d.isString(value)){ return "string"; }
2576
                if(typeof value == "number"){ return "number"; }
2577
                if(typeof value == "boolean"){ return "boolean"; }
2578
                if(d.isFunction(value)){ return "function"; }
2579
                if(d.isArray(value)){ return "array"; } // typeof [] == "object"
2580
                if(value instanceof Date) { return "date"; } // assume timestamp
2581
                if(value instanceof d._Url){ return "url"; }
2582
                return "object";
2583
        }
2584

    
2585
        function str2obj(/*String*/ value, /*String*/ type){
2586
                // summary:
2587
                //                Convert given string value to given type
2588
                switch(type){
2589
                        case "string":
2590
                                return value;
2591
                        case "number":
2592
                                return value.length ? Number(value) : NaN;
2593
                        case "boolean":
2594
                                // for checked/disabled value might be "" or "checked".  interpret as true.
2595
                                return typeof value == "boolean" ? value : !(value.toLowerCase()=="false");
2596
                        case "function":
2597
                                if(d.isFunction(value)){
2598
                                        // IE gives us a function, even when we say something like onClick="foo"
2599
                                        // (in which case it gives us an invalid function "function(){ foo }"). 
2600
                                        //  Therefore, convert to string
2601
                                        value=value.toString();
2602
                                        value=d.trim(value.substring(value.indexOf('{')+1, value.length-1));
2603
                                }
2604
                                try{
2605
                                        if(value === "" || value.search(/[^\w\.]+/i) != -1){
2606
                                                // The user has specified some text for a function like "return x+5"
2607
                                                return new Function(value);
2608
                                        }else{
2609
                                                // The user has specified the name of a function like "myOnClick"
2610
                                                // or a single word function "return"
2611
                                                return d.getObject(value, false) || new Function(value);
2612
                                        }
2613
                                }catch(e){ return new Function(); }
2614
                        case "array":
2615
                                return value ? value.split(/\s*,\s*/) : [];
2616
                        case "date":
2617
                                switch(value){
2618
                                        case "": return new Date("");        // the NaN of dates
2619
                                        case "now": return new Date();        // current date
2620
                                        default: return d.date.stamp.fromISOString(value);
2621
                                }
2622
                        case "url":
2623
                                return d.baseUrl + value;
2624
                        default:
2625
                                return d.fromJson(value);
2626
                }
2627
        }
2628

    
2629
        var instanceClasses = {
2630
                // map from fully qualified name (like "dijit.Button") to structure like
2631
                // { cls: dijit.Button, params: {label: "string", disabled: "boolean"} }
2632
        };
2633

    
2634
        // Widgets like BorderContainer add properties to _Widget via dojo.extend().
2635
        // If BorderContainer is loaded after _Widget's parameter list has been cached,
2636
        // we need to refresh that parameter list (for _Widget and all widgets that extend _Widget).
2637
        dojo.connect(dojo, "extend", function(){
2638
                instanceClasses = {};
2639
        });
2640

    
2641
        function getClassInfo(/*String*/ className){
2642
                // className:
2643
                //                fully qualified name (like "dijit.form.Button")
2644
                // returns:
2645
                //                structure like
2646
                //                        { 
2647
                //                                cls: dijit.Button, 
2648
                //                                params: { label: "string", disabled: "boolean"}
2649
                //                        }
2650

    
2651
                if(!instanceClasses[className]){
2652
                        // get pointer to widget class
2653
                        var cls = d.getObject(className);
2654
                        if(!cls){ return null; }                // class not defined [yet]
2655

    
2656
                        var proto = cls.prototype;
2657
        
2658
                        // get table of parameter names & types
2659
                        var params = {}, dummyClass = {};
2660
                        for(var name in proto){
2661
                                if(name.charAt(0)=="_"){ continue; }         // skip internal properties
2662
                                if(name in dummyClass){ continue; }                // skip "constructor" and "toString"
2663
                                var defVal = proto[name];
2664
                                params[name]=val2type(defVal);
2665
                        }
2666

    
2667
                        instanceClasses[className] = { cls: cls, params: params };
2668
                }
2669
                return instanceClasses[className];
2670
        }
2671

    
2672
        this._functionFromScript = function(script){
2673
                var preamble = "";
2674
                var suffix = "";
2675
                var argsStr = script.getAttribute("args");
2676
                if(argsStr){
2677
                        d.forEach(argsStr.split(/\s*,\s*/), function(part, idx){
2678
                                preamble += "var "+part+" = arguments["+idx+"]; ";
2679
                        });
2680
                }
2681
                var withStr = script.getAttribute("with");
2682
                if(withStr && withStr.length){
2683
                        d.forEach(withStr.split(/\s*,\s*/), function(part){
2684
                                preamble += "with("+part+"){";
2685
                                suffix += "}";
2686
                        });
2687
                }
2688
                return new Function(preamble+script.innerHTML+suffix);
2689
        }
2690

    
2691
        this.instantiate = function(/* Array */nodes, /* Object? */mixin, /* Object? */args){
2692
                // summary:
2693
                //                Takes array of nodes, and turns them into class instances and
2694
                //                potentially calls a startup method to allow them to connect with
2695
                //                any children.
2696
                // nodes: Array
2697
                //                Array of nodes or objects like
2698
                //        |                {
2699
                //        |                        type: "dijit.form.Button",
2700
                //        |                        node: DOMNode,
2701
                //        |                        scripts: [ ... ],        // array of <script type="dojo/..."> children of node
2702
                //        |                        inherited: { ... }        // settings inherited from ancestors like dir, theme, etc.
2703
                //        |                }
2704
                // mixin: Object?
2705
                //                An object that will be mixed in with each node in the array.
2706
                //                Values in the mixin will override values in the node, if they
2707
                //                exist.
2708
                // args: Object?
2709
                //                An object used to hold kwArgs for instantiation.
2710
                //                Supports 'noStart' and inherited.
2711
                var thelist = [], dp = dojo.parser;
2712
                mixin = mixin||{};
2713
                args = args||{};
2714
                
2715
                d.forEach(nodes, function(obj){
2716
                        if(!obj){ return; }
2717

    
2718
                        // Get pointers to DOMNode, dojoType string, and clsInfo (metadata about the dojoType), etc.s
2719
                        var node, type, clsInfo, clazz, scripts;
2720
                        if(obj.node){
2721
                                // new format of nodes[] array, object w/lots of properties pre-computed for me
2722
                                node = obj.node;
2723
                                type = obj.type;
2724
                                clsInfo = obj.clsInfo || (type && getClassInfo(type));
2725
                                clazz = clsInfo && clsInfo.cls;
2726
                                scripts = obj.scripts;
2727
                        }else{
2728
                                // old (backwards compatible) format of nodes[] array, simple array of DOMNodes
2729
                                node = obj;
2730
                                type = dp._attrName in mixin ? mixin[dp._attrName] : node.getAttribute(dp._attrName);
2731
                                clsInfo = type && getClassInfo(type);
2732
                                clazz = clsInfo && clsInfo.cls;
2733
                                scripts = (clazz && (clazz._noScript || clazz.prototype._noScript) ? [] : 
2734
                                                        d.query("> script[type^='dojo/']", node));
2735
                        }
2736
                        if(!clsInfo){
2737
                                throw new Error("Could not load class '" + type);
2738
                        }
2739

    
2740
                        // Setup hash to hold parameter settings for this widget.   Start with the parameter
2741
                        // settings inherited from ancestors ("dir" and "lang").
2742
                        // Inherited setting may later be overridden by explicit settings on node itself.
2743
                        var params = {},
2744
                                attributes = node.attributes;
2745
                        if(args.defaults){
2746
                                // settings for the document itself (or whatever subtree is being parsed)
2747
                                dojo.mixin(params, args.defaults);
2748
                        }
2749
                        if(obj.inherited){
2750
                                // settings from dir=rtl or lang=... on a node above this node
2751
                                dojo.mixin(params, obj.inherited);
2752
                        }
2753

    
2754
                        // read parameters (ie, attributes) specified on DOMNode
2755
                        // clsInfo.params lists expected params like {"checked": "boolean", "n": "number"}
2756
                        for(var name in clsInfo.params){
2757
                                var item = name in mixin?{value:mixin[name],specified:true}:attributes.getNamedItem(name);
2758
                                if(!item || (!item.specified && (!dojo.isIE || name.toLowerCase()!="value"))){ continue; }
2759
                                var value = item.value;
2760
                                // Deal with IE quirks for 'class' and 'style'
2761
                                switch(name){
2762
                                case "class":
2763
                                        value = "className" in mixin?mixin.className:node.className;
2764
                                        break;
2765
                                case "style":
2766
                                        value = "style" in mixin?mixin.style:(node.style && node.style.cssText); // FIXME: Opera?
2767
                                }
2768
                                var _type = clsInfo.params[name];
2769
                                if(typeof value == "string"){
2770
                                        params[name] = str2obj(value, _type);
2771
                                }else{
2772
                                        params[name] = value;
2773
                                }
2774
                        }
2775

    
2776
                        // Process <script type="dojo/*"> script tags
2777
                        // <script type="dojo/method" event="foo"> tags are added to params, and passed to
2778
                        // the widget on instantiation.
2779
                        // <script type="dojo/method"> tags (with no event) are executed after instantiation
2780
                        // <script type="dojo/connect" event="foo"> tags are dojo.connected after instantiation
2781
                        // note: dojo/* script tags cannot exist in self closing widgets, like <input />
2782
                        var connects = [],        // functions to connect after instantiation
2783
                                calls = [];                // functions to call after instantiation
2784

    
2785
                        d.forEach(scripts, function(script){
2786
                                node.removeChild(script);
2787
                                var event = script.getAttribute("event"),
2788
                                        type = script.getAttribute("type"),
2789
                                        nf = d.parser._functionFromScript(script);
2790
                                if(event){
2791
                                        if(type == "dojo/connect"){
2792
                                                connects.push({event: event, func: nf});
2793
                                        }else{
2794
                                                params[event] = nf;
2795
                                        }
2796
                                }else{
2797
                                        calls.push(nf);
2798
                                }
2799
                        });
2800

    
2801
                        var markupFactory = clazz.markupFactory || clazz.prototype && clazz.prototype.markupFactory;
2802
                        // create the instance
2803
                        var instance = markupFactory ? markupFactory(params, node, clazz) : new clazz(params, node);
2804
                        thelist.push(instance);
2805

    
2806
                        // map it to the JS namespace if that makes sense
2807
                        var jsname = node.getAttribute("jsId");
2808
                        if(jsname){
2809
                                d.setObject(jsname, instance);
2810
                        }
2811

    
2812
                        // process connections and startup functions
2813
                        d.forEach(connects, function(connect){
2814
                                d.connect(instance, connect.event, null, connect.func);
2815
                        });
2816
                        d.forEach(calls, function(func){
2817
                                func.call(instance);
2818
                        });
2819
                });
2820

    
2821
                // Call startup on each top level instance if it makes sense (as for
2822
                // widgets).  Parent widgets will recursively call startup on their
2823
                // (non-top level) children
2824
                if(!mixin._started){
2825
                        // TODO: for 2.0, when old instantiate() API is desupported, store parent-child
2826
                        // relationships in the nodes[] array so that no getParent() call is needed.
2827
                        // Note that will  require a parse() call from ContentPane setting a param that the
2828
                        // ContentPane is the parent widget (so that the parse doesn't call startup() on the
2829
                        // ContentPane's children)
2830
                        d.forEach(thelist, function(instance){
2831
                                if(        !args.noStart && instance  && 
2832
                                        instance.startup &&
2833
                                        !instance._started && 
2834
                                        (!instance.getParent || !instance.getParent())
2835
                                ){
2836
                                        instance.startup();
2837
                                }
2838
                        });
2839
                }
2840
                return thelist;
2841
        };
2842

    
2843
        this.parse = function(/*DomNode?*/ rootNode, /* Object? */ args){
2844
                // summary:
2845
                //                Scan the DOM for class instances, and instantiate them.
2846
                //
2847
                // description:
2848
                //                Search specified node (or root node) recursively for class instances,
2849
                //                and instantiate them Searches for
2850
                //                dojoType="qualified.class.name"
2851
                //
2852
                // rootNode: DomNode?
2853
                //                A default starting root node from which to start the parsing. Can be
2854
                //                omitted, defaulting to the entire document. If omitted, the `args`
2855
                //                object can be passed in this place. If the `args` object has a 
2856
                //                `rootNode` member, that is used.
2857
                //
2858
                // args:
2859
                //                a kwArgs object passed along to instantiate()
2860
                //                
2861
                //                        * noStart: Boolean?
2862
                //                                when set will prevent the parser from calling .startup()
2863
                //                                when locating the nodes. 
2864
                //                        * rootNode: DomNode?
2865
                //                                identical to the function's `rootNode` argument, though
2866
                //                                allowed to be passed in via this `args object. 
2867
                //                        * inherited: Object
2868
                //                                Hash possibly containing dir and lang settings to be applied to
2869
                //                                parsed widgets, unless there's another setting on a sub-node that overrides
2870
                //
2871
                //
2872
                // example:
2873
                //                Parse all widgets on a page:
2874
                //        |                dojo.parser.parse();
2875
                //
2876
                // example:
2877
                //                Parse all classes within the node with id="foo"
2878
                //        |                dojo.parser.parse(dojo.byId(foo));
2879
                //
2880
                // example:
2881
                //                Parse all classes in a page, but do not call .startup() on any 
2882
                //                child
2883
                //        |                dojo.parser.parse({ noStart: true })
2884
                //
2885
                // example:
2886
                //                Parse all classes in a node, but do not call .startup()
2887
                //        |                dojo.parser.parse(someNode, { noStart:true });
2888
                //        |                // or
2889
                //         |                dojo.parser.parse({ noStart:true, rootNode: someNode });
2890

    
2891
                // determine the root node based on the passed arguments.
2892
                var root;
2893
                if(!args && rootNode && rootNode.rootNode){
2894
                        args = rootNode;
2895
                        root = args.rootNode;
2896
                }else{
2897
                        root = rootNode;
2898
                }
2899

    
2900
                var attrName = this._attrName;
2901
                function scan(parent, list){
2902
                        // summary:
2903
                        //                Parent is an Object representing a DOMNode, with or without a dojoType specified.
2904
                        //                Scan parent's children looking for nodes with dojoType specified, storing in list[].
2905
                        //                If parent has a dojoType, also collects <script type=dojo/*> children and stores in parent.scripts[].
2906
                        // parent: Object
2907
                        //                Object representing the parent node, like
2908
                        //        |        {
2909
                        //        |                node: DomNode,                         // scan children of this node
2910
                        //        |                inherited: {dir: "rtl"},        // dir/lang setting inherited from above node
2911
                        //        |
2912
                        //        |                // attributes only set if node has dojoType specified
2913
                        //        |                scripts: [],                        // empty array, put <script type=dojo/*> in here
2914
                        //        |                clsInfo: { cls: dijit.form.Button, ...}
2915
                        //        |        }
2916
                        // list: DomNode[]
2917
                        //                Output array of objects (same format as parent) representing nodes to be turned into widgets
2918

    
2919
                        // Effective dir and lang settings on parent node, either set directly or inherited from grandparent
2920
                        var inherited = dojo.clone(parent.inherited);
2921
                        dojo.forEach(["dir", "lang"], function(name){
2922
                                var val = parent.node.getAttribute(name);
2923
                                if(val){
2924
                                        inherited[name] = val;
2925
                                }
2926
                        });
2927

    
2928
                        // if parent is a widget, then search for <script type=dojo/*> tags and put them in scripts[].
2929
                        var scripts = parent.scripts;
2930

    
2931
                        // unless parent is a widget with the stopParser flag set, continue search for dojoType, recursively
2932
                        var recurse = !parent.clsInfo || !parent.clsInfo.cls.prototype.stopParser;
2933

    
2934
                        // scan parent's children looking for dojoType and <script type=dojo/*>
2935
                        for(var child = parent.node.firstChild; child; child = child.nextSibling){
2936
                                if(child.nodeType == 1){
2937
                                        var type = recurse && child.getAttribute(attrName);
2938
                                        if(type){
2939
                                                // if dojoType specified, add to output array of nodes to instantiate
2940
                                                var params = {
2941
                                                        "type": type,
2942
                                                        clsInfo: getClassInfo(type),        // note: won't find classes declared via dojo.Declaration
2943
                                                        node: child,
2944
                                                        scripts: [], // <script> nodes that are parent's children
2945
                                                        inherited: inherited // dir & lang attributes inherited from parent
2946
                                                };
2947
                                                list.push(params);
2948

    
2949
                                                // Recurse, collecting <script type="dojo/..."> children, and also looking for
2950
                                                // descendant nodes with dojoType specified (unless the widget has the stopParser flag),
2951
                                                scan(params, list);
2952
                                        }else if(scripts && child.nodeName.toLowerCase() == "script"){
2953
                                                // if <script type="dojo/...">, save in scripts[]
2954
                                                type = child.getAttribute("type");
2955
                                                if (type && /^dojo\//i.test(type)) {
2956
                                                        scripts.push(child);
2957
                                                }
2958
                                        }else if(recurse){
2959
                                                // Recurse, looking for grandchild nodes with dojoType specified
2960
                                                scan({
2961
                                                        node: child,
2962
                                                        inherited: inherited
2963
                                                }, list);
2964
                                        }
2965
                                }
2966
                        }
2967
                }
2968

    
2969
                // Make list of all nodes on page w/dojoType specified
2970
                var list = [];
2971
                scan({
2972
                        node: root ? dojo.byId(root) : dojo.body(),
2973
                        inherited: (args && args.inherited) || {
2974
                                dir: dojo._isBodyLtr() ? "ltr" : "rtl"
2975
                        }
2976
                }, list);
2977

    
2978
                // go build the object instances
2979
                return this.instantiate(list, null, args); // Array
2980
        };
2981
}();
2982

    
2983
//Register the parser callback. It should be the first callback
2984
//after the a11y test.
2985

    
2986
(function(){
2987
        var parseRunner = function(){ 
2988
                if(dojo.config.parseOnLoad){
2989
                        dojo.parser.parse(); 
2990
                }
2991
        };
2992

    
2993
        // FIXME: need to clobber cross-dependency!!
2994
        if(dojo.exists("dijit.wai.onload") && (dijit.wai.onload === dojo._loaders[0])){
2995
                dojo._loaders.splice(1, 0, parseRunner);
2996
        }else{
2997
                dojo._loaders.unshift(parseRunner);
2998
        }
2999
})();
3000

    
3001
}
3002

    
3003
if(!dojo._hasResource["dijit._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
3004
dojo._hasResource["dijit._Widget"] = true;
3005
dojo.provide("dijit._Widget");
3006

    
3007
dojo.require( "dijit._base" );
3008

    
3009

    
3010
// This code is to assist deferring dojo.connect() calls in widgets (connecting to events on the widgets'
3011
// DOM nodes) until someone actually needs to monitor that event.
3012
dojo.connect(dojo, "_connect",
3013
        function(/*dijit._Widget*/ widget, /*String*/ event){
3014
                if(widget && dojo.isFunction(widget._onConnect)){
3015
                        widget._onConnect(event);
3016
                }
3017
        });
3018

    
3019
dijit._connectOnUseEventHandler = function(/*Event*/ event){};
3020

    
3021
// Keep track of where the last keydown event was, to help avoid generating
3022
// spurious ondijitclick events when:
3023
// 1. focus is on a <button> or <a>
3024
// 2. user presses then releases the ENTER key
3025
// 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler
3026
// 4. onkeyup event fires, causing the ondijitclick handler to fire
3027
dijit._lastKeyDownNode = null;
3028
if(dojo.isIE){
3029
        (function(){
3030
                var keydownCallback = function(evt){
3031
                        dijit._lastKeyDownNode = evt.srcElement;
3032
                };
3033
                dojo.doc.attachEvent('onkeydown', keydownCallback);
3034
                dojo.addOnWindowUnload(function(){
3035
                        dojo.doc.detachEvent('onkeydown', keydownCallback);
3036
                });
3037
        })();
3038
}else{
3039
        dojo.doc.addEventListener('keydown', function(evt){
3040
                dijit._lastKeyDownNode = evt.target;
3041
        }, true);
3042
}
3043

    
3044
(function(){
3045

    
3046
var _attrReg = {},        // cached results from getSetterAttributes
3047
        getSetterAttributes = function(widget){
3048
                // summary:
3049
                //                Returns list of attributes with custom setters for specified widget
3050
                var dc = widget.declaredClass;
3051
                if(!_attrReg[dc]){
3052
                        var r = [],
3053
                                attrs,
3054
                                proto = widget.constructor.prototype;
3055
                        for(var fxName in proto){
3056
                                if(dojo.isFunction(proto[fxName]) && (attrs = fxName.match(/^_set([a-zA-Z]*)Attr$/)) && attrs[1]){
3057
                                        r.push(attrs[1].charAt(0).toLowerCase() + attrs[1].substr(1));
3058
                                }
3059
                        }
3060
                        _attrReg[dc] = r;
3061
                }
3062
                return _attrReg[dc] || [];        // String[]
3063
        };
3064

    
3065
dojo.declare("dijit._Widget", null, {
3066
        // summary:
3067
        //                Base class for all Dijit widgets.
3068

    
3069
        // id: [const] String
3070
        //                A unique, opaque ID string that can be assigned by users or by the
3071
        //                system. If the developer passes an ID which is known not to be
3072
        //                unique, the specified ID is ignored and the system-generated ID is
3073
        //                used instead.
3074
        id: "",
3075

    
3076
        // lang: [const] String
3077
        //                Rarely used.  Overrides the default Dojo locale used to render this widget,
3078
        //                as defined by the [HTML LANG](http://www.w3.org/TR/html401/struct/dirlang.html#adef-lang) attribute.
3079
        //                Value must be among the list of locales specified during by the Dojo bootstrap,
3080
        //                formatted according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt) (like en-us).
3081
        lang: "",
3082

    
3083
        // dir: [const] String
3084
        //                Bi-directional support, as defined by the [HTML DIR](http://www.w3.org/TR/html401/struct/dirlang.html#adef-dir)
3085
        //                attribute. Either left-to-right "ltr" or right-to-left "rtl".  If undefined, widgets renders in page's
3086
        //                default direction.
3087
        dir: "",
3088

    
3089
        // class: String
3090
        //                HTML class attribute
3091
        "class": "",
3092

    
3093
        // style: String||Object
3094
        //                HTML style attributes as cssText string or name/value hash
3095
        style: "",
3096

    
3097
        // title: String
3098
        //                HTML title attribute.
3099
        //
3100
        //                For form widgets this specifies a tooltip to display when hovering over
3101
        //                the widget (just like the native HTML title attribute).
3102
        //
3103
        //                For TitlePane or for when this widget is a child of a TabContainer, AccordionContainer,
3104
        //                etc., it's used to specify the tab label, accordion pane title, etc.
3105
        title: "",
3106

    
3107
        // tooltip: String
3108
        //                When this widget's title attribute is used to for a tab label, accordion pane title, etc.,
3109
        //                this specifies the tooltip to appear when the mouse is hovered over that text.
3110
        tooltip: "",
3111

    
3112
        // baseClass: [protected] String
3113
        //                Root CSS class of the widget (ex: dijitTextBox), used to construct CSS classes to indicate
3114
        //                widget state.
3115
        baseClass: "",
3116

    
3117
        // srcNodeRef: [readonly] DomNode
3118
        //                pointer to original DOM node
3119
        srcNodeRef: null,
3120

    
3121
        // domNode: [readonly] DomNode
3122
        //                This is our visible representation of the widget! Other DOM
3123
        //                Nodes may by assigned to other properties, usually through the
3124
        //                template system's dojoAttachPoint syntax, but the domNode
3125
        //                property is the canonical "top level" node in widget UI.
3126
        domNode: null,
3127

    
3128
        // containerNode: [readonly] DomNode
3129
        //                Designates where children of the source DOM node will be placed.
3130
        //                "Children" in this case refers to both DOM nodes and widgets.
3131
        //                For example, for myWidget:
3132
        //
3133
        //                |        <div dojoType=myWidget>
3134
        //                |                <b> here's a plain DOM node
3135
        //                |                <span dojoType=subWidget>and a widget</span>
3136
        //                |                <i> and another plain DOM node </i>
3137
        //                |        </div>
3138
        //
3139
        //                containerNode would point to:
3140
        //
3141
        //                |                <b> here's a plain DOM node
3142
        //                |                <span dojoType=subWidget>and a widget</span>
3143
        //                |                <i> and another plain DOM node </i>
3144
        //
3145
        //                In templated widgets, "containerNode" is set via a
3146
        //                dojoAttachPoint assignment.
3147
        //
3148
        //                containerNode must be defined for any widget that accepts innerHTML
3149
        //                (like ContentPane or BorderContainer or even Button), and conversely
3150
        //                is null for widgets that don't, like TextBox.
3151
        containerNode: null,
3152

    
3153
/*=====
3154
        // _started: Boolean
3155
        //                startup() has completed.
3156
        _started: false,
3157
=====*/
3158

    
3159
        // attributeMap: [protected] Object
3160
        //                attributeMap sets up a "binding" between attributes (aka properties)
3161
        //                of the widget and the widget's DOM.
3162
        //                Changes to widget attributes listed in attributeMap will be
3163
        //                reflected into the DOM.
3164
        //
3165
        //                For example, calling attr('title', 'hello')
3166
        //                on a TitlePane will automatically cause the TitlePane's DOM to update
3167
        //                with the new title.
3168
        //
3169
        //                attributeMap is a hash where the key is an attribute of the widget,
3170
        //                and the value reflects a binding to a:
3171
        //
3172
        //                - DOM node attribute
3173
        // |                focus: {node: "focusNode", type: "attribute"}
3174
        //                 Maps this.focus to this.focusNode.focus
3175
        //
3176
        //                - DOM node innerHTML
3177
        //        |                title: { node: "titleNode", type: "innerHTML" }
3178
        //                Maps this.title to this.titleNode.innerHTML
3179
        //
3180
        //                - DOM node innerText
3181
        //        |                title: { node: "titleNode", type: "innerText" }
3182
        //                Maps this.title to this.titleNode.innerText
3183
        //
3184
        //                - DOM node CSS class
3185
        // |                myClass: { node: "domNode", type: "class" }
3186
        //                Maps this.myClass to this.domNode.className
3187
        //
3188
        //                If the value is an array, then each element in the array matches one of the
3189
        //                formats of the above list.
3190
        //
3191
        //                There are also some shorthands for backwards compatibility:
3192
        //                - string --> { node: string, type: "attribute" }, for example:
3193
        //        |        "focusNode" ---> { node: "focusNode", type: "attribute" }
3194
        //                - "" --> { node: "domNode", type: "attribute" }
3195
        attributeMap: {id:"", dir:"", lang:"", "class":"", style:"", title:""},
3196

    
3197
        // _deferredConnects: [protected] Object
3198
        //                attributeMap addendum for event handlers that should be connected only on first use
3199
        _deferredConnects: {
3200
                onClick: "",
3201
                onDblClick: "",
3202
                onKeyDown: "",
3203
                onKeyPress: "",
3204
                onKeyUp: "",
3205
                onMouseMove: "",
3206
                onMouseDown: "",
3207
                onMouseOut: "",
3208
                onMouseOver: "",
3209
                onMouseLeave: "",
3210
                onMouseEnter: "",
3211
                onMouseUp: ""
3212
        },
3213

    
3214
        onClick: dijit._connectOnUseEventHandler,
3215
        /*=====
3216
        onClick: function(event){
3217
                // summary:
3218
                //                Connect to this function to receive notifications of mouse click events.
3219
                // event:
3220
                //                mouse Event
3221
                // tags:
3222
                //                callback
3223
        },
3224
        =====*/
3225
        onDblClick: dijit._connectOnUseEventHandler,
3226
        /*=====
3227
        onDblClick: function(event){
3228
                // summary:
3229
                //                Connect to this function to receive notifications of mouse double click events.
3230
                // event:
3231
                //                mouse Event
3232
                // tags:
3233
                //                callback
3234
        },
3235
        =====*/
3236
        onKeyDown: dijit._connectOnUseEventHandler,
3237
        /*=====
3238
        onKeyDown: function(event){
3239
                // summary:
3240
                //                Connect to this function to receive notifications of keys being pressed down.
3241
                // event:
3242
                //                key Event
3243
                // tags:
3244
                //                callback
3245
        },
3246
        =====*/
3247
        onKeyPress: dijit._connectOnUseEventHandler,
3248
        /*=====
3249
        onKeyPress: function(event){
3250
                // summary:
3251
                //                Connect to this function to receive notifications of printable keys being typed.
3252
                // event:
3253
                //                key Event
3254
                // tags:
3255
                //                callback
3256
        },
3257
        =====*/
3258
        onKeyUp: dijit._connectOnUseEventHandler,
3259
        /*=====
3260
        onKeyUp: function(event){
3261
                // summary:
3262
                //                Connect to this function to receive notifications of keys being released.
3263
                // event:
3264
                //                key Event
3265
                // tags:
3266
                //                callback
3267
        },
3268
        =====*/
3269
        onMouseDown: dijit._connectOnUseEventHandler,
3270
        /*=====
3271
        onMouseDown: function(event){
3272
                // summary:
3273
                //                Connect to this function to receive notifications of when the mouse button is pressed down.
3274
                // event:
3275
                //                mouse Event
3276
                // tags:
3277
                //                callback
3278
        },
3279
        =====*/
3280
        onMouseMove: dijit._connectOnUseEventHandler,
3281
        /*=====
3282
        onMouseMove: function(event){
3283
                // summary:
3284
                //                Connect to this function to receive notifications of when the mouse moves over nodes contained within this widget.
3285
                // event:
3286
                //                mouse Event
3287
                // tags:
3288
                //                callback
3289
        },
3290
        =====*/
3291
        onMouseOut: dijit._connectOnUseEventHandler,
3292
        /*=====
3293
        onMouseOut: function(event){
3294
                // summary:
3295
                //                Connect to this function to receive notifications of when the mouse moves off of nodes contained within this widget.
3296
                // event:
3297
                //                mouse Event
3298
                // tags:
3299
                //                callback
3300
        },
3301
        =====*/
3302
        onMouseOver: dijit._connectOnUseEventHandler,
3303
        /*=====
3304
        onMouseOver: function(event){
3305
                // summary:
3306
                //                Connect to this function to receive notifications of when the mouse moves onto nodes contained within this widget.
3307
                // event:
3308
                //                mouse Event
3309
                // tags:
3310
                //                callback
3311
        },
3312
        =====*/
3313
        onMouseLeave: dijit._connectOnUseEventHandler,
3314
        /*=====
3315
        onMouseLeave: function(event){
3316
                // summary:
3317
                //                Connect to this function to receive notifications of when the mouse moves off of this widget.
3318
                // event:
3319
                //                mouse Event
3320
                // tags:
3321
                //                callback
3322
        },
3323
        =====*/
3324
        onMouseEnter: dijit._connectOnUseEventHandler,
3325
        /*=====
3326
        onMouseEnter: function(event){
3327
                // summary:
3328
                //                Connect to this function to receive notifications of when the mouse moves onto this widget.
3329
                // event:
3330
                //                mouse Event
3331
                // tags:
3332
                //                callback
3333
        },
3334
        =====*/
3335
        onMouseUp: dijit._connectOnUseEventHandler,
3336
        /*=====
3337
        onMouseUp: function(event){
3338
                // summary:
3339
                //                Connect to this function to receive notifications of when the mouse button is released.
3340
                // event:
3341
                //                mouse Event
3342
                // tags:
3343
                //                callback
3344
        },
3345
        =====*/
3346

    
3347
        // Constants used in templates
3348

    
3349
        // _blankGif: [protected] String
3350
        //                Path to a blank 1x1 image.
3351
        //                Used by <img> nodes in templates that really get their image via CSS background-image.
3352
        _blankGif: (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")).toString(),
3353

    
3354
        //////////// INITIALIZATION METHODS ///////////////////////////////////////
3355

    
3356
        postscript: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){
3357
                // summary:
3358
                //                Kicks off widget instantiation.  See create() for details.
3359
                // tags:
3360
                //                private
3361
                this.create(params, srcNodeRef);
3362
        },
3363

    
3364
        create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){
3365
                // summary:
3366
                //                Kick off the life-cycle of a widget
3367
                // params:
3368
                //                Hash of initialization parameters for widget, including
3369
                //                scalar values (like title, duration etc.) and functions,
3370
                //                typically callbacks like onClick.
3371
                // srcNodeRef:
3372
                //                If a srcNodeRef (DOM node) is specified:
3373
                //                        - use srcNodeRef.innerHTML as my contents
3374
                //                        - if this is a behavioral widget then apply behavior
3375
                //                          to that srcNodeRef
3376
                //                        - otherwise, replace srcNodeRef with my generated DOM
3377
                //                          tree
3378
                // description:
3379
                //                Create calls a number of widget methods (postMixInProperties, buildRendering, postCreate,
3380
                //                etc.), some of which of you'll want to override. See http://docs.dojocampus.org/dijit/_Widget
3381
                //                for a discussion of the widget creation lifecycle.
3382
                //
3383
                //                Of course, adventurous developers could override create entirely, but this should
3384
                //                only be done as a last resort.
3385
                // tags:
3386
                //                private
3387

    
3388
                // store pointer to original DOM tree
3389
                this.srcNodeRef = dojo.byId(srcNodeRef);
3390

    
3391
                // For garbage collection.  An array of handles returned by Widget.connect()
3392
                // Each handle returned from Widget.connect() is an array of handles from dojo.connect()
3393
                this._connects = [];
3394

    
3395
                // For garbage collection.  An array of handles returned by Widget.subscribe()
3396
                // The handle returned from Widget.subscribe() is the handle returned from dojo.subscribe()
3397
                this._subscribes = [];
3398

    
3399
                // To avoid double-connects, remove entries from _deferredConnects
3400
                // that have been setup manually by a subclass (ex, by dojoAttachEvent).
3401
                // If a subclass has redefined a callback (ex: onClick) then assume it's being
3402
                // connected to manually.
3403
                this._deferredConnects = dojo.clone(this._deferredConnects);
3404
                for(var attr in this.attributeMap){
3405
                        delete this._deferredConnects[attr]; // can't be in both attributeMap and _deferredConnects
3406
                }
3407
                for(attr in this._deferredConnects){
3408
                        if(this[attr] !== dijit._connectOnUseEventHandler){
3409
                                delete this._deferredConnects[attr];        // redefined, probably dojoAttachEvent exists
3410
                        }
3411
                }
3412

    
3413
                //mixin our passed parameters
3414
                if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; }
3415
                if(params){
3416
                        this.params = params;
3417
                        dojo.mixin(this,params);
3418
                }
3419
                this.postMixInProperties();
3420

    
3421
                // generate an id for the widget if one wasn't specified
3422
                // (be sure to do this before buildRendering() because that function might
3423
                // expect the id to be there.)
3424
                if(!this.id){
3425
                        this.id = dijit.getUniqueId(this.declaredClass.replace(/\./g,"_"));
3426
                }
3427
                dijit.registry.add(this);
3428

    
3429
                this.buildRendering();
3430

    
3431
                if(this.domNode){
3432
                        // Copy attributes listed in attributeMap into the [newly created] DOM for the widget.
3433
                        this._applyAttributes();
3434

    
3435
                        var source = this.srcNodeRef;
3436
                        if(source && source.parentNode){
3437
                                source.parentNode.replaceChild(this.domNode, source);
3438
                        }
3439

    
3440
                        // If the developer has specified a handler as a widget parameter
3441
                        // (ex: new Button({onClick: ...})
3442
                        // then naturally need to connect from DOM node to that handler immediately,
3443
                        for(attr in this.params){
3444
                                this._onConnect(attr);
3445
                        }
3446
                }
3447

    
3448
                if(this.domNode){
3449
                        this.domNode.setAttribute("widgetId", this.id);
3450
                }
3451
                this.postCreate();
3452

    
3453
                // If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC.
3454
                if(this.srcNodeRef && !this.srcNodeRef.parentNode){
3455
                        delete this.srcNodeRef;
3456
                }
3457

    
3458
                this._created = true;
3459
        },
3460

    
3461
        _applyAttributes: function(){
3462
                // summary:
3463
                //                Step during widget creation to copy all widget attributes to the
3464
                //                DOM as per attributeMap and _setXXXAttr functions.
3465
                // description:
3466
                //                Skips over blank/false attribute values, unless they were explicitly specified
3467
                //                as parameters to the widget, since those are the default anyway,
3468
                //                and setting tabIndex="" is different than not setting tabIndex at all.
3469
                //
3470
                //                It processes the attributes in the attribute map first, and then
3471
                //                it goes through and processes the attributes for the _setXXXAttr
3472
                //                functions that have been specified
3473
                // tags:
3474
                //                private
3475
                var condAttrApply = function(attr, scope){
3476
                        if((scope.params && attr in scope.params) || scope[attr]){
3477
                                scope.set(attr, scope[attr]);
3478
                        }
3479
                };
3480

    
3481
                // Do the attributes in attributeMap
3482
                for(var attr in this.attributeMap){
3483
                        condAttrApply(attr, this);
3484
                }
3485

    
3486
                // And also any attributes with custom setters
3487
                dojo.forEach(getSetterAttributes(this), function(a){
3488
                        if(!(a in this.attributeMap)){
3489
                                condAttrApply(a, this);
3490
                        }
3491
                }, this);
3492
        },
3493

    
3494
        postMixInProperties: function(){
3495
                // summary:
3496
                //                Called after the parameters to the widget have been read-in,
3497
                //                but before the widget template is instantiated. Especially
3498
                //                useful to set properties that are referenced in the widget
3499
                //                template.
3500
                // tags:
3501
                //                protected
3502
        },
3503

    
3504
        buildRendering: function(){
3505
                // summary:
3506
                //                Construct the UI for this widget, setting this.domNode
3507
                // description:
3508
                //                Most widgets will mixin `dijit._Templated`, which implements this
3509
                //                method.
3510
                // tags:
3511
                //                protected
3512
                this.domNode = this.srcNodeRef || dojo.create('div');
3513
        },
3514

    
3515
        postCreate: function(){
3516
                // summary:
3517
                //                Processing after the DOM fragment is created
3518
                // description:
3519
                //                Called after the DOM fragment has been created, but not necessarily
3520
                //                added to the document.  Do not include any operations which rely on
3521
                //                node dimensions or placement.
3522
                // tags:
3523
                //                protected
3524

    
3525
                // baseClass is a single class name or occasionally a space-separated list of names.
3526
                // Add those classes to the DOMNod.  If RTL mode then also add with Rtl suffix.                
3527
                if(this.baseClass){
3528
                        var classes = this.baseClass.split(" ");
3529
                        if(!this.isLeftToRight()){
3530
                                classes = classes.concat( dojo.map(classes, function(name){ return name+"Rtl"; }));
3531
                        }
3532
                        dojo.addClass(this.domNode, classes);
3533
                }
3534
        },
3535

    
3536
        startup: function(){
3537
                // summary:
3538
                //                Processing after the DOM fragment is added to the document
3539
                // description:
3540
                //                Called after a widget and its children have been created and added to the page,
3541
                //                and all related widgets have finished their create() cycle, up through postCreate().
3542
                //                This is useful for composite widgets that need to control or layout sub-widgets.
3543
                //                Many layout widgets can use this as a wiring phase.
3544
                this._started = true;
3545
        },
3546

    
3547
        //////////// DESTROY FUNCTIONS ////////////////////////////////
3548

    
3549
        destroyRecursive: function(/*Boolean?*/ preserveDom){
3550
                // summary:
3551
                //                 Destroy this widget and its descendants
3552
                // description:
3553
                //                This is the generic "destructor" function that all widget users
3554
                //                 should call to cleanly discard with a widget. Once a widget is
3555
                //                 destroyed, it is removed from the manager object.
3556
                // preserveDom:
3557
                //                If true, this method will leave the original DOM structure
3558
                //                alone of descendant Widgets. Note: This will NOT work with
3559
                //                dijit._Templated widgets.
3560

    
3561
                this._beingDestroyed = true;
3562
                this.destroyDescendants(preserveDom);
3563
                this.destroy(preserveDom);
3564
        },
3565

    
3566
        destroy: function(/*Boolean*/ preserveDom){
3567
                // summary:
3568
                //                 Destroy this widget, but not its descendants.
3569
                //                This method will, however, destroy internal widgets such as those used within a template.
3570
                // preserveDom: Boolean
3571
                //                If true, this method will leave the original DOM structure alone.
3572
                //                Note: This will not yet work with _Templated widgets
3573

    
3574
                this._beingDestroyed = true;
3575
                this.uninitialize();
3576
                var d = dojo,
3577
                        dfe = d.forEach,
3578
                        dun = d.unsubscribe;
3579
                dfe(this._connects, function(array){
3580
                        dfe(array, d.disconnect);
3581
                });
3582
                dfe(this._subscribes, function(handle){
3583
                        dun(handle);
3584
                });
3585

    
3586
                // destroy widgets created as part of template, etc.
3587
                dfe(this._supportingWidgets || [], function(w){
3588
                        if(w.destroyRecursive){
3589
                                w.destroyRecursive();
3590
                        }else if(w.destroy){
3591
                                w.destroy();
3592
                        }
3593
                });
3594

    
3595
                this.destroyRendering(preserveDom);
3596
                dijit.registry.remove(this.id);
3597
                this._destroyed = true;
3598
        },
3599

    
3600
        destroyRendering: function(/*Boolean?*/ preserveDom){
3601
                // summary:
3602
                //                Destroys the DOM nodes associated with this widget
3603
                // preserveDom:
3604
                //                If true, this method will leave the original DOM structure alone
3605
                //                during tear-down. Note: this will not work with _Templated
3606
                //                widgets yet.
3607
                // tags:
3608
                //                protected
3609

    
3610
                if(this.bgIframe){
3611
                        this.bgIframe.destroy(preserveDom);
3612
                        delete this.bgIframe;
3613
                }
3614

    
3615
                if(this.domNode){
3616
                        if(preserveDom){
3617
                                dojo.removeAttr(this.domNode, "widgetId");
3618
                        }else{
3619
                                dojo.destroy(this.domNode);
3620
                        }
3621
                        delete this.domNode;
3622
                }
3623

    
3624
                if(this.srcNodeRef){
3625
                        if(!preserveDom){
3626
                                dojo.destroy(this.srcNodeRef);
3627
                        }
3628
                        delete this.srcNodeRef;
3629
                }
3630
        },
3631

    
3632
        destroyDescendants: function(/*Boolean?*/ preserveDom){
3633
                // summary:
3634
                //                Recursively destroy the children of this widget and their
3635
                //                descendants.
3636
                // preserveDom:
3637
                //                If true, the preserveDom attribute is passed to all descendant
3638
                //                widget's .destroy() method. Not for use with _Templated
3639
                //                widgets.
3640

    
3641
                // get all direct descendants and destroy them recursively
3642
                dojo.forEach(this.getChildren(), function(widget){
3643
                        if(widget.destroyRecursive){
3644
                                widget.destroyRecursive(preserveDom);
3645
                        }
3646
                });
3647
        },
3648

    
3649

    
3650
        uninitialize: function(){
3651
                // summary:
3652
                //                Stub function. Override to implement custom widget tear-down
3653
                //                behavior.
3654
                // tags:
3655
                //                protected
3656
                return false;
3657
        },
3658

    
3659
        ////////////////// MISCELLANEOUS METHODS ///////////////////
3660

    
3661
        onFocus: function(){
3662
                // summary:
3663
                //                Called when the widget becomes "active" because
3664
                //                it or a widget inside of it either has focus, or has recently
3665
                //                been clicked.
3666
                // tags:
3667
                //                callback
3668
        },
3669

    
3670
        onBlur: function(){
3671
                // summary:
3672
                //                Called when the widget stops being "active" because
3673
                //                focus moved to something outside of it, or the user
3674
                //                clicked somewhere outside of it, or the widget was
3675
                //                hidden.
3676
                // tags:
3677
                //                callback
3678
        },
3679

    
3680
        _onFocus: function(e){
3681
                // summary:
3682
                //                This is where widgets do processing for when they are active,
3683
                //                such as changing CSS classes.  See onFocus() for more details.
3684
                // tags:
3685
                //                protected
3686
                this.onFocus();
3687
        },
3688

    
3689
        _onBlur: function(){
3690
                // summary:
3691
                //                This is where widgets do processing for when they stop being active,
3692
                //                such as changing CSS classes.  See onBlur() for more details.
3693
                // tags:
3694
                //                protected
3695
                this.onBlur();
3696
        },
3697

    
3698
        _onConnect: function(/*String*/ event){
3699
                // summary:
3700
                //                Called when someone connects to one of my handlers.
3701
                //                "Turn on" that handler if it isn't active yet.
3702
                //
3703
                //                This is also called for every single initialization parameter
3704
                //                so need to do nothing for parameters like "id".
3705
                // tags:
3706
                //                private
3707
                if(event in this._deferredConnects){
3708
                        var mapNode = this[this._deferredConnects[event] || 'domNode'];
3709
                        this.connect(mapNode, event.toLowerCase(), event);
3710
                        delete this._deferredConnects[event];
3711
                }
3712
        },
3713

    
3714
        _setClassAttr: function(/*String*/ value){
3715
                // summary:
3716
                //                Custom setter for the CSS "class" attribute
3717
                // tags:
3718
                //                protected
3719
                var mapNode = this[this.attributeMap["class"] || 'domNode'];
3720
                dojo.removeClass(mapNode, this["class"])
3721
                this["class"] = value;
3722
                dojo.addClass(mapNode, value);
3723
        },
3724

    
3725
        _setStyleAttr: function(/*String||Object*/ value){
3726
                // summary:
3727
                //                Sets the style attribut of the widget according to value,
3728
                //                which is either a hash like {height: "5px", width: "3px"}
3729
                //                or a plain string
3730
                // description:
3731
                //                Determines which node to set the style on based on style setting
3732
                //                in attributeMap.
3733
                // tags:
3734
                //                protected
3735

    
3736
                var mapNode = this[this.attributeMap.style || 'domNode'];
3737

    
3738
                // Note: technically we should revert any style setting made in a previous call
3739
                // to his method, but that's difficult to keep track of.
3740

    
3741
                if(dojo.isObject(value)){
3742
                        dojo.style(mapNode, value);
3743
                }else{
3744
                        if(mapNode.style.cssText){
3745
                                mapNode.style.cssText += "; " + value;
3746
                        }else{
3747
                                mapNode.style.cssText = value;
3748
                        }
3749
                }
3750

    
3751
                this.style = value;
3752
        },
3753

    
3754
        setAttribute: function(/*String*/ attr, /*anything*/ value){
3755
                // summary:
3756
                //                Deprecated.  Use set() instead.
3757
                // tags:
3758
                //                deprecated
3759
                dojo.deprecated(this.declaredClass+"::setAttribute(attr, value) is deprecated. Use set() instead.", "", "2.0");
3760
                this.set(attr, value);
3761
        },
3762

    
3763
        _attrToDom: function(/*String*/ attr, /*String*/ value){
3764
                // summary:
3765
                //                Reflect a widget attribute (title, tabIndex, duration etc.) to
3766
                //                the widget DOM, as specified in attributeMap.
3767
                //
3768
                // description:
3769
                //                Also sets this["attr"] to the new value.
3770
                //                Note some attributes like "type"
3771
                //                cannot be processed this way as they are not mutable.
3772
                //
3773
                // tags:
3774
                //                private
3775

    
3776
                var commands = this.attributeMap[attr];
3777
                dojo.forEach(dojo.isArray(commands) ? commands : [commands], function(command){
3778

    
3779
                        // Get target node and what we are doing to that node
3780
                        var mapNode = this[command.node || command || "domNode"];        // DOM node
3781
                        var type = command.type || "attribute";        // class, innerHTML, innerText, or attribute
3782

    
3783
                        switch(type){
3784
                                case "attribute":
3785
                                        if(dojo.isFunction(value)){ // functions execute in the context of the widget
3786
                                                value = dojo.hitch(this, value);
3787
                                        }
3788

    
3789
                                        // Get the name of the DOM node attribute; usually it's the same
3790
                                        // as the name of the attribute in the widget (attr), but can be overridden.
3791
                                        // Also maps handler names to lowercase, like onSubmit --> onsubmit
3792
                                        var attrName = command.attribute ? command.attribute :
3793
                                                (/^on[A-Z][a-zA-Z]*$/.test(attr) ? attr.toLowerCase() : attr);
3794

    
3795
                                        dojo.attr(mapNode, attrName, value);
3796
                                        break;
3797
                                case "innerText":
3798
                                        mapNode.innerHTML = "";
3799
                                        mapNode.appendChild(dojo.doc.createTextNode(value));
3800
                                        break;
3801
                                case "innerHTML":
3802
                                        mapNode.innerHTML = value;
3803
                                        break;
3804
                                case "class":
3805
                                        dojo.removeClass(mapNode, this[attr]);
3806
                                        dojo.addClass(mapNode, value);
3807
                                        break;
3808
                        }
3809
                }, this);
3810
                this[attr] = value;
3811
        },
3812

    
3813
        attr: function(/*String|Object*/name, /*Object?*/value){
3814
                // summary:
3815
                //                Set or get properties on a widget instance.
3816
                //        name:
3817
                //                The property to get or set. If an object is passed here and not
3818
                //                a string, its keys are used as names of attributes to be set
3819
                //                and the value of the object as values to set in the widget.
3820
                //        value:
3821
                //                Optional. If provided, attr() operates as a setter. If omitted,
3822
                //                the current value of the named property is returned.
3823
                // description:
3824
                //                This method is deprecated, use get() or set() directly.
3825

    
3826
                // Print deprecation warning but only once per calling function
3827
                if(dojo.config.isDebug){
3828
                        var alreadyCalledHash = arguments.callee._ach || (arguments.callee._ach = {}),
3829
                                caller = (arguments.callee.caller || "unknown caller").toString();
3830
                        if(!alreadyCalledHash[caller]){
3831
                                dojo.deprecated(this.declaredClass + "::attr() is deprecated. Use get() or set() instead, called from " +
3832
                                caller, "", "2.0");
3833
                                alreadyCalledHash[caller] = true;
3834
                        }
3835
                }
3836

    
3837
                var args = arguments.length;
3838
                if(args >= 2 || typeof name === "object"){ // setter
3839
                        return this.set.apply(this, arguments);
3840
                }else{ // getter
3841
                        return this.get(name);
3842
                }
3843
        },
3844
        
3845
        get: function(name){
3846
                // summary:
3847
                //                Get a property from a widget.
3848
                //        name:
3849
                //                The property to get.
3850
                // description:
3851
                //                Get a named property from a widget. The property may
3852
                //                potentially be retrieved via a getter method. If no getter is defined, this
3853
                //                 just retrieves the object's property.  
3854
                //                 For example, if the widget has a properties "foo"
3855
                //                and "bar" and a method named "_getFooAttr", calling:
3856
                //        |        myWidget.get("foo");
3857
                //                would be equivalent to writing:
3858
                //        |        widget._getFooAttr();
3859
                //                and:
3860
                //        |        myWidget.get("bar");
3861
                //                would be equivalent to writing:
3862
                //        |        widget.bar;
3863
                var names = this._getAttrNames(name);
3864
                return this[names.g] ? this[names.g]() : this[name];
3865
        },
3866
        
3867
        set: function(name, value){
3868
                // summary:
3869
                //                Set a property on a widget
3870
                //        name:
3871
                //                The property to set. 
3872
                //        value:
3873
                //                The value to set in the property.
3874
                // description:
3875
                //                Sets named properties on a widget which may potentially be handled by a 
3876
                //                 setter in the widget.
3877
                //                 For example, if the widget has a properties "foo"
3878
                //                and "bar" and a method named "_setFooAttr", calling:
3879
                //        |        myWidget.set("foo", "Howdy!");
3880
                //                would be equivalent to writing:
3881
                //        |        widget._setFooAttr("Howdy!");
3882
                //                and:
3883
                //        |        myWidget.set("bar", 3);
3884
                //                would be equivalent to writing:
3885
                //        |        widget.bar = 3;
3886
                //
3887
                //        set() may also be called with a hash of name/value pairs, ex:
3888
                //        |        myWidget.set({
3889
                //        |                foo: "Howdy",
3890
                //        |                bar: 3
3891
                //        |        })
3892
                //        This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
3893

    
3894
                if(typeof name === "object"){
3895
                        for(var x in name){
3896
                                this.set(x, name[x]); 
3897
                        }
3898
                        return this;
3899
                }
3900
                var names = this._getAttrNames(name);
3901
                if(this[names.s]){
3902
                        // use the explicit setter
3903
                        var result = this[names.s].apply(this, Array.prototype.slice.call(arguments, 1));
3904
                }else{
3905
                        // if param is specified as DOM node attribute, copy it
3906
                        if(name in this.attributeMap){
3907
                                this._attrToDom(name, value);
3908
                        }
3909
                        var oldValue = this[name];
3910
                        // FIXME: what about function assignments? Any way to connect() here?
3911
                        this[name] = value;
3912
                }
3913
                return result || this;
3914
        },
3915
        
3916
        _attrPairNames: {},                // shared between all widgets
3917
        _getAttrNames: function(name){
3918
                // summary:
3919
                //                Helper function for get() and set().
3920
                //                Caches attribute name values so we don't do the string ops every time.
3921
                // tags:
3922
                //                private
3923

    
3924
                var apn = this._attrPairNames;
3925
                if(apn[name]){ return apn[name]; }
3926
                var uc = name.charAt(0).toUpperCase() + name.substr(1);
3927
                return (apn[name] = {
3928
                        n: name+"Node",
3929
                        s: "_set"+uc+"Attr",
3930
                        g: "_get"+uc+"Attr"
3931
                });
3932
        },
3933

    
3934
        toString: function(){
3935
                // summary:
3936
                //                Returns a string that represents the widget
3937
                // description:
3938
                //                When a widget is cast to a string, this method will be used to generate the
3939
                //                output. Currently, it does not implement any sort of reversible
3940
                //                serialization.
3941
                return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String
3942
        },
3943

    
3944
        getDescendants: function(){
3945
                // summary:
3946
                //                Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode.
3947
                //                This method should generally be avoided as it returns widgets declared in templates, which are
3948
                //                supposed to be internal/hidden, but it's left here for back-compat reasons.
3949

    
3950
                return this.containerNode ? dojo.query('[widgetId]', this.containerNode).map(dijit.byNode) : []; // dijit._Widget[]
3951
        },
3952

    
3953
        getChildren: function(){
3954
                // summary:
3955
                //                Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode.
3956
                //                Does not return nested widgets, nor widgets that are part of this widget's template.
3957
                return this.containerNode ? dijit.findWidgets(this.containerNode) : []; // dijit._Widget[]
3958
        },
3959

    
3960
        // nodesWithKeyClick: [private] String[]
3961
        //                List of nodes that correctly handle click events via native browser support,
3962
        //                and don't need dijit's help
3963
        nodesWithKeyClick: ["input", "button"],
3964

    
3965
        connect: function(
3966
                        /*Object|null*/ obj,
3967
                        /*String|Function*/ event,
3968
                        /*String|Function*/ method){
3969
                // summary:
3970
                //                Connects specified obj/event to specified method of this object
3971
                //                and registers for disconnect() on widget destroy.
3972
                // description:
3973
                //                Provide widget-specific analog to dojo.connect, except with the
3974
                //                implicit use of this widget as the target object.
3975
                //                This version of connect also provides a special "ondijitclick"
3976
                //                event which triggers on a click or space or enter keyup
3977
                // returns:
3978
                //                A handle that can be passed to `disconnect` in order to disconnect before
3979
                //                the widget is destroyed.
3980
                // example:
3981
                //        |        var btn = new dijit.form.Button();
3982
                //        |        // when foo.bar() is called, call the listener we're going to
3983
                //        |        // provide in the scope of btn
3984
                //        |        btn.connect(foo, "bar", function(){
3985
                //        |                console.debug(this.toString());
3986
                //        |        });
3987
                // tags:
3988
                //                protected
3989

    
3990
                var d = dojo,
3991
                        dc = d._connect,
3992
                        handles = [];
3993
                if(event == "ondijitclick"){
3994
                        // add key based click activation for unsupported nodes.
3995
                        // do all processing onkey up to prevent spurious clicks
3996
                        // for details see comments at top of this file where _lastKeyDownNode is defined
3997
                        if(dojo.indexOf(this.nodesWithKeyClick, obj.nodeName.toLowerCase()) == -1){ // is NOT input or button
3998
                                var m = d.hitch(this, method);
3999
                                handles.push(
4000
                                        dc(obj, "onkeydown", this, function(e){
4001
                                                //console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode));
4002
                                                if((e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) &&
4003
                                                        !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){
4004
                                                        // needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work
4005
                                                        dijit._lastKeyDownNode = e.target;
4006
                                                        e.preventDefault();                // stop event to prevent scrolling on space key in IE
4007
                                                }
4008
                                         }),
4009
                                        dc(obj, "onkeyup", this, function(e){
4010
                                                //console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode));
4011
                                                if( (e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) &&
4012
                                                        e.target === dijit._lastKeyDownNode &&
4013
                                                        !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){
4014
                                                                //need reset here or have problems in FF when focus returns to trigger element after closing popup/alert
4015
                                                                dijit._lastKeyDownNode = null;
4016
                                                                return m(e);
4017
                                                }
4018
                                        })
4019
                                );
4020
                        }
4021
                        event = "onclick";
4022
                }
4023
                handles.push(dc(obj, event, this, method));
4024

    
4025
                this._connects.push(handles);
4026
                return handles;                // _Widget.Handle
4027
        },
4028

    
4029
        disconnect: function(/* _Widget.Handle */ handles){
4030
                // summary:
4031
                //                Disconnects handle created by `connect`.
4032
                //                Also removes handle from this widget's list of connects.
4033
                // tags:
4034
                //                protected
4035
                for(var i=0; i<this._connects.length; i++){
4036
                        if(this._connects[i] == handles){
4037
                                dojo.forEach(handles, dojo.disconnect);
4038
                                this._connects.splice(i, 1);
4039
                                return;
4040
                        }
4041
                }
4042
        },
4043

    
4044
        subscribe: function(
4045
                        /*String*/ topic,
4046
                        /*String|Function*/ method){
4047
                // summary:
4048
                //                Subscribes to the specified topic and calls the specified method
4049
                //                of this object and registers for unsubscribe() on widget destroy.
4050
                // description:
4051
                //                Provide widget-specific analog to dojo.subscribe, except with the
4052
                //                implicit use of this widget as the target object.
4053
                // example:
4054
                //        |        var btn = new dijit.form.Button();
4055
                //        |        // when /my/topic is published, this button changes its label to
4056
                //        |   // be the parameter of the topic.
4057
                //        |        btn.subscribe("/my/topic", function(v){
4058
                //        |                this.set("label", v);
4059
                //        |        });
4060
                var d = dojo,
4061
                        handle = d.subscribe(topic, this, method);
4062

    
4063
                // return handles for Any widget that may need them
4064
                this._subscribes.push(handle);
4065
                return handle;
4066
        },
4067

    
4068
        unsubscribe: function(/*Object*/ handle){
4069
                // summary:
4070
                //                Unsubscribes handle created by this.subscribe.
4071
                //                Also removes handle from this widget's list of subscriptions
4072
                for(var i=0; i<this._subscribes.length; i++){
4073
                        if(this._subscribes[i] == handle){
4074
                                dojo.unsubscribe(handle);
4075
                                this._subscribes.splice(i, 1);
4076
                                return;
4077
                        }
4078
                }
4079
        },
4080

    
4081
        isLeftToRight: function(){
4082
                // summary:
4083
                //                Return this widget's explicit or implicit orientation (true for LTR, false for RTL)
4084
                // tags:
4085
                //                protected
4086
                return this.dir ? (this.dir == "ltr") : dojo._isBodyLtr(); //Boolean
4087
        },
4088

    
4089
        isFocusable: function(){
4090
                // summary:
4091
                //                Return true if this widget can currently be focused
4092
                //                and false if not
4093
                return this.focus && (dojo.style(this.domNode, "display") != "none");
4094
        },
4095

    
4096
        placeAt: function(/* String|DomNode|_Widget */reference, /* String?|Int? */position){
4097
                // summary:
4098
                //                Place this widget's domNode reference somewhere in the DOM based
4099
                //                on standard dojo.place conventions, or passing a Widget reference that
4100
                //                contains and addChild member.
4101
                //
4102
                // description:
4103
                //                A convenience function provided in all _Widgets, providing a simple
4104
                //                shorthand mechanism to put an existing (or newly created) Widget
4105
                //                somewhere in the dom, and allow chaining.
4106
                //
4107
                // reference:
4108
                //                The String id of a domNode, a domNode reference, or a reference to a Widget posessing
4109
                //                an addChild method.
4110
                //
4111
                // position:
4112
                //                If passed a string or domNode reference, the position argument
4113
                //                accepts a string just as dojo.place does, one of: "first", "last",
4114
                //                "before", or "after".
4115
                //
4116
                //                If passed a _Widget reference, and that widget reference has an ".addChild" method,
4117
                //                it will be called passing this widget instance into that method, supplying the optional
4118
                //                position index passed.
4119
                //
4120
                // returns:
4121
                //                dijit._Widget
4122
                //                Provides a useful return of the newly created dijit._Widget instance so you
4123
                //                can "chain" this function by instantiating, placing, then saving the return value
4124
                //                to a variable.
4125
                //
4126
                // example:
4127
                // |         // create a Button with no srcNodeRef, and place it in the body:
4128
                // |         var button = new dijit.form.Button({ label:"click" }).placeAt(dojo.body());
4129
                // |         // now, 'button' is still the widget reference to the newly created button
4130
                // |         dojo.connect(button, "onClick", function(e){ console.log('click'); });
4131
                //
4132
                // example:
4133
                // |        // create a button out of a node with id="src" and append it to id="wrapper":
4134
                // |         var button = new dijit.form.Button({},"src").placeAt("wrapper");
4135
                //
4136
                // example:
4137
                // |        // place a new button as the first element of some div
4138
                // |        var button = new dijit.form.Button({ label:"click" }).placeAt("wrapper","first");
4139
                //
4140
                // example:
4141
                // |        // create a contentpane and add it to a TabContainer
4142
                // |        var tc = dijit.byId("myTabs");
4143
                // |        new dijit.layout.ContentPane({ href:"foo.html", title:"Wow!" }).placeAt(tc)
4144

    
4145
                if(reference.declaredClass && reference.addChild){
4146
                        reference.addChild(this, position);
4147
                }else{
4148
                        dojo.place(this.domNode, reference, position);
4149
                }
4150
                return this;
4151
        },
4152

    
4153
        _onShow: function(){
4154
                // summary:
4155
                //                Internal method called when this widget is made visible.
4156
                //                See `onShow` for details.
4157
                this.onShow();
4158
        },
4159

    
4160
        onShow: function(){
4161
                // summary:
4162
                //                Called when this widget becomes the selected pane in a
4163
                //                `dijit.layout.TabContainer`, `dijit.layout.StackContainer`,
4164
                //                `dijit.layout.AccordionContainer`, etc.
4165
                //
4166
                //                Also called to indicate display of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
4167
                // tags:
4168
                //                callback
4169
        },
4170

    
4171
        onHide: function(){
4172
                // summary:
4173
                        //                Called when another widget becomes the selected pane in a
4174
                        //                `dijit.layout.TabContainer`, `dijit.layout.StackContainer`,
4175
                        //                `dijit.layout.AccordionContainer`, etc.
4176
                        //
4177
                        //                Also called to indicate hide of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
4178
                        // tags:
4179
                        //                callback
4180
        },
4181

    
4182
        onClose: function(){
4183
                // summary:
4184
                //                Called when this widget is being displayed as a popup (ex: a Calendar popped
4185
                //                up from a DateTextBox), and it is hidden.
4186
                //                This is called from the dijit.popup code, and should not be called directly.
4187
                //
4188
                //                Also used as a parameter for children of `dijit.layout.StackContainer` or subclasses.
4189
                //                Callback if a user tries to close the child.   Child will be closed if this function returns true.
4190
                // tags:
4191
                //                extension
4192

    
4193
                return true;                // Boolean
4194
        }
4195
});
4196

    
4197
})();
4198

    
4199
}
4200

    
4201
if(!dojo._hasResource["dojo.string"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
4202
dojo._hasResource["dojo.string"] = true;
4203
dojo.provide("dojo.string");
4204

    
4205
/*=====
4206
dojo.string = { 
4207
        // summary: String utilities for Dojo
4208
};
4209
=====*/
4210

    
4211
dojo.string.rep = function(/*String*/str, /*Integer*/num){
4212
        //        summary:
4213
        //                Efficiently replicate a string `n` times.
4214
        //        str:
4215
        //                the string to replicate
4216
        //        num:
4217
        //                number of times to replicate the string
4218
        
4219
        if(num <= 0 || !str){ return ""; }
4220
        
4221
        var buf = [];
4222
        for(;;){
4223
                if(num & 1){
4224
                        buf.push(str);
4225
                }
4226
                if(!(num >>= 1)){ break; }
4227
                str += str;
4228
        }
4229
        return buf.join("");        // String
4230
};
4231

    
4232
dojo.string.pad = function(/*String*/text, /*Integer*/size, /*String?*/ch, /*Boolean?*/end){
4233
        //        summary:
4234
        //                Pad a string to guarantee that it is at least `size` length by
4235
        //                filling with the character `ch` at either the start or end of the
4236
        //                string. Pads at the start, by default.
4237
        //        text:
4238
        //                the string to pad
4239
        //        size:
4240
        //                length to provide padding
4241
        //        ch:
4242
        //                character to pad, defaults to '0'
4243
        //        end:
4244
        //                adds padding at the end if true, otherwise pads at start
4245
        //        example:
4246
        //        |        // Fill the string to length 10 with "+" characters on the right.  Yields "Dojo++++++".
4247
        //        |        dojo.string.pad("Dojo", 10, "+", true);
4248

    
4249
        if(!ch){
4250
                ch = '0';
4251
        }
4252
        var out = String(text),
4253
                pad = dojo.string.rep(ch, Math.ceil((size - out.length) / ch.length));
4254
        return end ? out + pad : pad + out;        // String
4255
};
4256

    
4257
dojo.string.substitute = function(        /*String*/                template, 
4258
                                                                        /*Object|Array*/map, 
4259
                                                                        /*Function?*/        transform, 
4260
                                                                        /*Object?*/                thisObject){
4261
        //        summary:
4262
        //                Performs parameterized substitutions on a string. Throws an
4263
        //                exception if any parameter is unmatched.
4264
        //        template: 
4265
        //                a string with expressions in the form `${key}` to be replaced or
4266
        //                `${key:format}` which specifies a format function. keys are case-sensitive. 
4267
        //        map:
4268
        //                hash to search for substitutions
4269
        //        transform: 
4270
        //                a function to process all parameters before substitution takes
4271
        //                place, e.g. mylib.encodeXML
4272
        //        thisObject: 
4273
        //                where to look for optional format function; default to the global
4274
        //                namespace
4275
        //        example:
4276
        //                Substitutes two expressions in a string from an Array or Object
4277
        //        |        // returns "File 'foo.html' is not found in directory '/temp'."
4278
        //        |        // by providing substitution data in an Array
4279
        //        |        dojo.string.substitute(
4280
        //        |                "File '${0}' is not found in directory '${1}'.",
4281
        //        |                ["foo.html","/temp"]
4282
        //        |        );
4283
        //        |
4284
        //        |        // also returns "File 'foo.html' is not found in directory '/temp'."
4285
        //        |        // but provides substitution data in an Object structure.  Dotted
4286
        //        |        // notation may be used to traverse the structure.
4287
        //        |        dojo.string.substitute(
4288
        //        |                "File '${name}' is not found in directory '${info.dir}'.",
4289
        //        |                { name: "foo.html", info: { dir: "/temp" } }
4290
        //        |        );
4291
        //        example:
4292
        //                Use a transform function to modify the values:
4293
        //        |        // returns "file 'foo.html' is not found in directory '/temp'."
4294
        //        |        dojo.string.substitute(
4295
        //        |                "${0} is not found in ${1}.",
4296
        //        |                ["foo.html","/temp"],
4297
        //        |                function(str){
4298
        //        |                        // try to figure out the type
4299
        //        |                        var prefix = (str.charAt(0) == "/") ? "directory": "file";
4300
        //        |                        return prefix + " '" + str + "'";
4301
        //        |                }
4302
        //        |        );
4303
        //        example:
4304
        //                Use a formatter
4305
        //        |        // returns "thinger -- howdy"
4306
        //        |        dojo.string.substitute(
4307
        //        |                "${0:postfix}", ["thinger"], null, {
4308
        //        |                        postfix: function(value, key){
4309
        //        |                                return value + " -- howdy";
4310
        //        |                        }
4311
        //        |                }
4312
        //        |        );
4313

    
4314
        thisObject = thisObject || dojo.global;
4315
        transform = transform ? 
4316
                dojo.hitch(thisObject, transform) : function(v){ return v; };
4317

    
4318
        return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g,
4319
                function(match, key, format){
4320
                        var value = dojo.getObject(key, false, map);
4321
                        if(format){
4322
                                value = dojo.getObject(format, false, thisObject).call(thisObject, value, key);
4323
                        }
4324
                        return transform(value, key).toString();
4325
                }); // String
4326
};
4327

    
4328
/*=====
4329
dojo.string.trim = function(str){
4330
        //        summary:
4331
        //                Trims whitespace from both sides of the string
4332
        //        str: String
4333
        //                String to be trimmed
4334
        //        returns: String
4335
        //                Returns the trimmed string
4336
        //        description:
4337
        //                This version of trim() was taken from [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript).
4338
        //                The short yet performant version of this function is dojo.trim(),
4339
        //                which is part of Dojo base.  Uses String.prototype.trim instead, if available.
4340
        return "";        // String
4341
}
4342
=====*/
4343

    
4344
dojo.string.trim = String.prototype.trim ?
4345
        dojo.trim : // aliasing to the native function
4346
        function(str){
4347
                str = str.replace(/^\s+/, '');
4348
                for(var i = str.length - 1; i >= 0; i--){
4349
                        if(/\S/.test(str.charAt(i))){
4350
                                str = str.substring(0, i + 1);
4351
                                break;
4352
                        }
4353
                }
4354
                return str;
4355
        };
4356

    
4357
}
4358

    
4359
if(!dojo._hasResource["dojo.cache"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
4360
dojo._hasResource["dojo.cache"] = true;
4361
dojo.provide("dojo.cache");
4362

    
4363
/*=====
4364
dojo.cache = { 
4365
        // summary:
4366
        //                 A way to cache string content that is fetchable via `dojo.moduleUrl`.
4367
};
4368
=====*/
4369

    
4370
(function(){
4371
        var cache = {};
4372
        dojo.cache = function(/*String||Object*/module, /*String*/url, /*String||Object?*/value){
4373
                // summary:
4374
                //                 A getter and setter for storing the string content associated with the
4375
                //                 module and url arguments.
4376
                // description:
4377
                //                 module and url are used to call `dojo.moduleUrl()` to generate a module URL.
4378
                //                 If value is specified, the cache value for the moduleUrl will be set to
4379
                //                 that value. Otherwise, dojo.cache will fetch the moduleUrl and store it
4380
                //                 in its internal cache and return that cached value for the URL. To clear
4381
                //                 a cache value pass null for value. Since XMLHttpRequest (XHR) is used to fetch the
4382
                //                 the URL contents, only modules on the same domain of the page can use this capability.
4383
                //                 The build system can inline the cache values though, to allow for xdomain hosting.
4384
                // module: String||Object
4385
                //                 If a String, the module name to use for the base part of the URL, similar to module argument
4386
                //                 to `dojo.moduleUrl`. If an Object, something that has a .toString() method that
4387
                //                 generates a valid path for the cache item. For example, a dojo._Url object.
4388
                // url: String
4389
                //                 The rest of the path to append to the path derived from the module argument. If
4390
                //                 module is an object, then this second argument should be the "value" argument instead.
4391
                // value: String||Object?
4392
                //                 If a String, the value to use in the cache for the module/url combination.
4393
                //                 If an Object, it can have two properties: value and sanitize. The value property
4394
                //                 should be the value to use in the cache, and sanitize can be set to true or false,
4395
                //                 to indicate if XML declarations should be removed from the value and if the HTML
4396
                //                 inside a body tag in the value should be extracted as the real value. The value argument
4397
                //                 or the value property on the value argument are usually only used by the build system
4398
                //                 as it inlines cache content.
4399
                //        example:
4400
                //                To ask dojo.cache to fetch content and store it in the cache (the dojo["cache"] style
4401
                //                 of call is used to avoid an issue with the build system erroneously trying to intern
4402
                //                 this example. To get the build system to intern your dojo.cache calls, use the
4403
                //                 "dojo.cache" style of call):
4404
                //                 |        //If template.html contains "<h1>Hello</h1>" that will be
4405
                //                 |        //the value for the text variable.
4406
                //                |        var text = dojo["cache"]("my.module", "template.html");
4407
                //        example:
4408
                //                To ask dojo.cache to fetch content and store it in the cache, and sanitize the input
4409
                //                  (the dojo["cache"] style of call is used to avoid an issue with the build system 
4410
                //                 erroneously trying to intern this example. To get the build system to intern your
4411
                //                 dojo.cache calls, use the "dojo.cache" style of call):
4412
                //                 |        //If template.html contains "<html><body><h1>Hello</h1></body></html>", the
4413
                //                 |        //text variable will contain just "<h1>Hello</h1>".
4414
                //                |        var text = dojo["cache"]("my.module", "template.html", {sanitize: true});
4415
                //        example:
4416
                //                Same example as previous, but demostrates how an object can be passed in as
4417
                //                the first argument, then the value argument can then be the second argument.
4418
                //                 |        //If template.html contains "<html><body><h1>Hello</h1></body></html>", the
4419
                //                 |        //text variable will contain just "<h1>Hello</h1>".
4420
                //                |        var text = dojo["cache"](new dojo._Url("my/module/template.html"), {sanitize: true});
4421

    
4422
                //Module could be a string, or an object that has a toString() method
4423
                //that will return a useful path. If it is an object, then the "url" argument
4424
                //will actually be the value argument.
4425
                if(typeof module == "string"){
4426
                        var pathObj = dojo.moduleUrl(module, url);
4427
                }else{
4428
                        pathObj = module;
4429
                        value = url;
4430
                }
4431
                var key = pathObj.toString();
4432

    
4433
                var val = value;
4434
                if(value != undefined && !dojo.isString(value)){
4435
                        val = ("value" in value ? value.value : undefined);
4436
                }
4437

    
4438
                var sanitize = value && value.sanitize ? true : false;
4439

    
4440
                if(typeof val == "string"){
4441
                        //We have a string, set cache value
4442
                        val = cache[key] = sanitize ? dojo.cache._sanitize(val) : val;
4443
                }else if(val === null){
4444
                        //Remove cached value
4445
                        delete cache[key];
4446
                }else{
4447
                        //Allow cache values to be empty strings. If key property does
4448
                        //not exist, fetch it.
4449
                        if(!(key in cache)){
4450
                                val = dojo._getText(key);
4451
                                cache[key] = sanitize ? dojo.cache._sanitize(val) : val;
4452
                        }
4453
                        val = cache[key];
4454
                }
4455
                return val; //String
4456
        };
4457

    
4458
        dojo.cache._sanitize = function(/*String*/val){
4459
                // summary: 
4460
                //                Strips <?xml ...?> declarations so that external SVG and XML
4461
                //                 documents can be added to a document without worry. Also, if the string
4462
                //                is an HTML document, only the part inside the body tag is returned.
4463
                // description:
4464
                //                 Copied from dijit._Templated._sanitizeTemplateString.
4465
                if(val){
4466
                        val = val.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
4467
                        var matches = val.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
4468
                        if(matches){
4469
                                val = matches[1];
4470
                        }
4471
                }else{
4472
                        val = "";
4473
                }
4474
                return val; //String
4475
        };
4476
})();
4477

    
4478
}
4479

    
4480
if(!dojo._hasResource["dijit._Templated"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
4481
dojo._hasResource["dijit._Templated"] = true;
4482
dojo.provide("dijit._Templated");
4483

    
4484

    
4485

    
4486

    
4487

    
4488

    
4489
dojo.declare("dijit._Templated",
4490
        null,
4491
        {
4492
                // summary:
4493
                //                Mixin for widgets that are instantiated from a template
4494

    
4495
                // templateString: [protected] String
4496
                //                A string that represents the widget template. Pre-empts the
4497
                //                templatePath. In builds that have their strings "interned", the
4498
                //                templatePath is converted to an inline templateString, thereby
4499
                //                preventing a synchronous network call.
4500
                //
4501
                //                Use in conjunction with dojo.cache() to load from a file.
4502
                templateString: null,
4503

    
4504
                // templatePath: [protected deprecated] String
4505
                //                Path to template (HTML file) for this widget relative to dojo.baseUrl.
4506
                //                Deprecated: use templateString with dojo.cache() instead.
4507
                templatePath: null,
4508

    
4509
                // widgetsInTemplate: [protected] Boolean
4510
                //                Should we parse the template to find widgets that might be
4511
                //                declared in markup inside it?  False by default.
4512
                widgetsInTemplate: false,
4513

    
4514
                // skipNodeCache: [protected] Boolean
4515
                //                If using a cached widget template node poses issues for a
4516
                //                particular widget class, it can set this property to ensure
4517
                //                that its template is always re-built from a string
4518
                _skipNodeCache: false,
4519

    
4520
                // _earlyTemplatedStartup: Boolean
4521
                //                A fallback to preserve the 1.0 - 1.3 behavior of children in
4522
                //                templates having their startup called before the parent widget
4523
                //                fires postCreate. Defaults to 'false', causing child widgets to
4524
                //                have their .startup() called immediately before a parent widget
4525
                //                .startup(), but always after the parent .postCreate(). Set to
4526
                //                'true' to re-enable to previous, arguably broken, behavior.
4527
                _earlyTemplatedStartup: false,
4528

    
4529
                // _attachPoints: [private] String[]
4530
                //                List of widget attribute names associated with dojoAttachPoint=... in the
4531
                //                template, ex: ["containerNode", "labelNode"]
4532
/*=====
4533
                 _attachPoints: [],
4534
 =====*/
4535

    
4536
                constructor: function(){
4537
                        this._attachPoints = [];
4538
                },
4539

    
4540
                _stringRepl: function(tmpl){
4541
                        // summary:
4542
                        //                Does substitution of ${foo} type properties in template string
4543
                        // tags:
4544
                        //                private
4545
                        var className = this.declaredClass, _this = this;
4546
                        // Cache contains a string because we need to do property replacement
4547
                        // do the property replacement
4548
                        return dojo.string.substitute(tmpl, this, function(value, key){
4549
                                if(key.charAt(0) == '!'){ value = dojo.getObject(key.substr(1), false, _this); }
4550
                                if(typeof value == "undefined"){ throw new Error(className+" template:"+key); } // a debugging aide
4551
                                if(value == null){ return ""; }
4552

    
4553
                                // Substitution keys beginning with ! will skip the transform step,
4554
                                // in case a user wishes to insert unescaped markup, e.g. ${!foo}
4555
                                return key.charAt(0) == "!" ? value :
4556
                                        // Safer substitution, see heading "Attribute values" in
4557
                                        // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
4558
                                        value.toString().replace(/"/g,"&quot;"); //TODO: add &amp? use encodeXML method?
4559
                        }, this);
4560
                },
4561

    
4562
                // method over-ride
4563
                buildRendering: function(){
4564
                        // summary:
4565
                        //                Construct the UI for this widget from a template, setting this.domNode.
4566
                        // tags:
4567
                        //                protected
4568

    
4569
                        // Lookup cached version of template, and download to cache if it
4570
                        // isn't there already.  Returns either a DomNode or a string, depending on
4571
                        // whether or not the template contains ${foo} replacement parameters.
4572
                        var cached = dijit._Templated.getCachedTemplate(this.templatePath, this.templateString, this._skipNodeCache);
4573

    
4574
                        var node;
4575
                        if(dojo.isString(cached)){
4576
                                node = dojo._toDom(this._stringRepl(cached));
4577
                                if(node.nodeType != 1){
4578
                                        // Flag common problems such as templates with multiple top level nodes (nodeType == 11)
4579
                                        throw new Error("Invalid template: " + cached);
4580
                                }
4581
                        }else{
4582
                                // if it's a node, all we have to do is clone it
4583
                                node = cached.cloneNode(true);
4584
                        }
4585

    
4586
                        this.domNode = node;
4587

    
4588
                        // recurse through the node, looking for, and attaching to, our
4589
                        // attachment points and events, which should be defined on the template node.
4590
                        this._attachTemplateNodes(node);
4591

    
4592
                        if(this.widgetsInTemplate){
4593
                                // Make sure dojoType is used for parsing widgets in template.
4594
                                // The dojo.parser.query could be changed from multiversion support.
4595
                                var parser = dojo.parser, qry, attr;
4596
                                if(parser._query != "[dojoType]"){
4597
                                        qry = parser._query;
4598
                                        attr = parser._attrName;
4599
                                        parser._query = "[dojoType]";
4600
                                        parser._attrName = "dojoType";
4601
                                }
4602

    
4603
                                // Store widgets that we need to start at a later point in time
4604
                                var cw = (this._startupWidgets = dojo.parser.parse(node, {
4605
                                        noStart: !this._earlyTemplatedStartup,
4606
                                        inherited: {dir: this.dir, lang: this.lang}
4607
                                }));
4608

    
4609
                                // Restore the query.
4610
                                if(qry){
4611
                                        parser._query = qry;
4612
                                        parser._attrName = attr;
4613
                                }
4614

    
4615
                                this._supportingWidgets = dijit.findWidgets(node);
4616

    
4617
                                this._attachTemplateNodes(cw, function(n,p){
4618
                                        return n[p];
4619
                                });
4620
                        }
4621

    
4622
                        this._fillContent(this.srcNodeRef);
4623
                },
4624

    
4625
                _fillContent: function(/*DomNode*/ source){
4626
                        // summary:
4627
                        //                Relocate source contents to templated container node.
4628
                        //                this.containerNode must be able to receive children, or exceptions will be thrown.
4629
                        // tags:
4630
                        //                protected
4631
                        var dest = this.containerNode;
4632
                        if(source && dest){
4633
                                while(source.hasChildNodes()){
4634
                                        dest.appendChild(source.firstChild);
4635
                                }
4636
                        }
4637
                },
4638

    
4639
                _attachTemplateNodes: function(rootNode, getAttrFunc){
4640
                        // summary:
4641
                        //                Iterate through the template and attach functions and nodes accordingly.
4642
                        // description:
4643
                        //                Map widget properties and functions to the handlers specified in
4644
                        //                the dom node and it's descendants. This function iterates over all
4645
                        //                nodes and looks for these properties:
4646
                        //                        * dojoAttachPoint
4647
                        //                        * dojoAttachEvent
4648
                        //                        * waiRole
4649
                        //                        * waiState
4650
                        // rootNode: DomNode|Array[Widgets]
4651
                        //                the node to search for properties. All children will be searched.
4652
                        // getAttrFunc: Function?
4653
                        //                a function which will be used to obtain property for a given
4654
                        //                DomNode/Widget
4655
                        // tags:
4656
                        //                private
4657

    
4658
                        getAttrFunc = getAttrFunc || function(n,p){ return n.getAttribute(p); };
4659

    
4660
                        var nodes = dojo.isArray(rootNode) ? rootNode : (rootNode.all || rootNode.getElementsByTagName("*"));
4661
                        var x = dojo.isArray(rootNode) ? 0 : -1;
4662
                        for(; x<nodes.length; x++){
4663
                                var baseNode = (x == -1) ? rootNode : nodes[x];
4664
                                if(this.widgetsInTemplate && getAttrFunc(baseNode, "dojoType")){
4665
                                        continue;
4666
                                }
4667
                                // Process dojoAttachPoint
4668
                                var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint");
4669
                                if(attachPoint){
4670
                                        var point, points = attachPoint.split(/\s*,\s*/);
4671
                                        while((point = points.shift())){
4672
                                                if(dojo.isArray(this[point])){
4673
                                                        this[point].push(baseNode);
4674
                                                }else{
4675
                                                        this[point]=baseNode;
4676
                                                }
4677
                                                this._attachPoints.push(point);
4678
                                        }
4679
                                }
4680

    
4681
                                // Process dojoAttachEvent
4682
                                var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent");
4683
                                if(attachEvent){
4684
                                        // NOTE: we want to support attributes that have the form
4685
                                        // "domEvent: nativeEvent; ..."
4686
                                        var event, events = attachEvent.split(/\s*,\s*/);
4687
                                        var trim = dojo.trim;
4688
                                        while((event = events.shift())){
4689
                                                if(event){
4690
                                                        var thisFunc = null;
4691
                                                        if(event.indexOf(":") != -1){
4692
                                                                // oh, if only JS had tuple assignment
4693
                                                                var funcNameArr = event.split(":");
4694
                                                                event = trim(funcNameArr[0]);
4695
                                                                thisFunc = trim(funcNameArr[1]);
4696
                                                        }else{
4697
                                                                event = trim(event);
4698
                                                        }
4699
                                                        if(!thisFunc){
4700
                                                                thisFunc = event;
4701
                                                        }
4702
                                                        this.connect(baseNode, event, thisFunc);
4703
                                                }
4704
                                        }
4705
                                }
4706

    
4707
                                // waiRole, waiState
4708
                                var role = getAttrFunc(baseNode, "waiRole");
4709
                                if(role){
4710
                                        dijit.setWaiRole(baseNode, role);
4711
                                }
4712
                                var values = getAttrFunc(baseNode, "waiState");
4713
                                if(values){
4714
                                        dojo.forEach(values.split(/\s*,\s*/), function(stateValue){
4715
                                                if(stateValue.indexOf('-') != -1){
4716
                                                        var pair = stateValue.split('-');
4717
                                                        dijit.setWaiState(baseNode, pair[0], pair[1]);
4718
                                                }
4719
                                        });
4720
                                }
4721
                        }
4722
                },
4723

    
4724
                startup: function(){
4725
                        dojo.forEach(this._startupWidgets, function(w){
4726
                                if(w && !w._started && w.startup){
4727
                                        w.startup();
4728
                                }
4729
                        });
4730
                        this.inherited(arguments);
4731
                },
4732

    
4733
                destroyRendering: function(){
4734
                        // Delete all attach points to prevent IE6 memory leaks.
4735
                        dojo.forEach(this._attachPoints, function(point){
4736
                                delete this[point];
4737
                        }, this);
4738
                        this._attachPoints = [];
4739

    
4740
                        this.inherited(arguments);
4741
                }
4742
        }
4743
);
4744

    
4745
// key is either templatePath or templateString; object is either string or DOM tree
4746
dijit._Templated._templateCache = {};
4747

    
4748
dijit._Templated.getCachedTemplate = function(templatePath, templateString, alwaysUseString){
4749
        // summary:
4750
        //                Static method to get a template based on the templatePath or
4751
        //                templateString key
4752
        // templatePath: String||dojo.uri.Uri
4753
        //                The URL to get the template from.
4754
        // templateString: String?
4755
        //                a string to use in lieu of fetching the template from a URL. Takes precedence
4756
        //                over templatePath
4757
        // returns: Mixed
4758
        //                Either string (if there are ${} variables that need to be replaced) or just
4759
        //                a DOM tree (if the node can be cloned directly)
4760

    
4761
        // is it already cached?
4762
        var tmplts = dijit._Templated._templateCache;
4763
        var key = templateString || templatePath;
4764
        var cached = tmplts[key];
4765
        if(cached){
4766
                try{
4767
                        // if the cached value is an innerHTML string (no ownerDocument) or a DOM tree created within the current document, then use the current cached value
4768
                        if(!cached.ownerDocument || cached.ownerDocument == dojo.doc){
4769
                                // string or node of the same document
4770
                                return cached;
4771
                        }
4772
                }catch(e){ /* squelch */ } // IE can throw an exception if cached.ownerDocument was reloaded
4773
                dojo.destroy(cached);
4774
        }
4775

    
4776
        // If necessary, load template string from template path
4777
        if(!templateString){
4778
                templateString = dojo.cache(templatePath, {sanitize: true});
4779
        }
4780
        templateString = dojo.string.trim(templateString);
4781

    
4782
        if(alwaysUseString || templateString.match(/\$\{([^\}]+)\}/g)){
4783
                // there are variables in the template so all we can do is cache the string
4784
                return (tmplts[key] = templateString); //String
4785
        }else{
4786
                // there are no variables in the template so we can cache the DOM tree
4787
                var node = dojo._toDom(templateString);
4788
                if(node.nodeType != 1){
4789
                        throw new Error("Invalid template: " + templateString);
4790
                }
4791
                return (tmplts[key] = node); //Node
4792
        }
4793
};
4794

    
4795
if(dojo.isIE){
4796
        dojo.addOnWindowUnload(function(){
4797
                var cache = dijit._Templated._templateCache;
4798
                for(var key in cache){
4799
                        var value = cache[key];
4800
                        if(typeof value == "object"){ // value is either a string or a DOM node template
4801
                                dojo.destroy(value);
4802
                        }
4803
                        delete cache[key];
4804
                }
4805
        });
4806
}
4807

    
4808
// These arguments can be specified for widgets which are used in templates.
4809
// Since any widget can be specified as sub widgets in template, mix it
4810
// into the base widget class.  (This is a hack, but it's effective.)
4811
dojo.extend(dijit._Widget,{
4812
        dojoAttachEvent: "",
4813
        dojoAttachPoint: "",
4814
        waiRole: "",
4815
        waiState:""
4816
});
4817

    
4818
}
4819

    
4820
if(!dojo._hasResource["dijit._Container"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
4821
dojo._hasResource["dijit._Container"] = true;
4822
dojo.provide("dijit._Container");
4823

    
4824
dojo.declare("dijit._Container",
4825
        null,
4826
        {
4827
                // summary:
4828
                //                Mixin for widgets that contain a set of widget children.
4829
                // description:
4830
                //                Use this mixin for widgets that needs to know about and
4831
                //                keep track of their widget children. Suitable for widgets like BorderContainer
4832
                //                and TabContainer which contain (only) a set of child widgets.
4833
                //
4834
                //                It's not suitable for widgets like ContentPane
4835
                //                which contains mixed HTML (plain DOM nodes in addition to widgets),
4836
                //                and where contained widgets are not necessarily directly below
4837
                //                this.containerNode.   In that case calls like addChild(node, position)
4838
                //                wouldn't make sense.
4839

    
4840
                // isContainer: [protected] Boolean
4841
                //                Indicates that this widget acts as a "parent" to the descendant widgets.
4842
                //                When the parent is started it will call startup() on the child widgets.
4843
                //                See also `isLayoutContainer`.
4844
                isContainer: true,
4845

    
4846
                buildRendering: function(){
4847
                        this.inherited(arguments);
4848
                        if(!this.containerNode){
4849
                                // all widgets with descendants must set containerNode
4850
                                         this.containerNode = this.domNode;
4851
                        }
4852
                },
4853

    
4854
                addChild: function(/*dijit._Widget*/ widget, /*int?*/ insertIndex){
4855
                        // summary:
4856
                        //                Makes the given widget a child of this widget.
4857
                        // description:
4858
                        //                Inserts specified child widget's dom node as a child of this widget's
4859
                        //                container node, and possibly does other processing (such as layout).
4860

    
4861
                        var refNode = this.containerNode;
4862
                        if(insertIndex && typeof insertIndex == "number"){
4863
                                var children = this.getChildren();
4864
                                if(children && children.length >= insertIndex){
4865
                                        refNode = children[insertIndex-1].domNode;
4866
                                        insertIndex = "after";
4867
                                }
4868
                        }
4869
                        dojo.place(widget.domNode, refNode, insertIndex);
4870

    
4871
                        // If I've been started but the child widget hasn't been started,
4872
                        // start it now.  Make sure to do this after widget has been
4873
                        // inserted into the DOM tree, so it can see that it's being controlled by me,
4874
                        // so it doesn't try to size itself.
4875
                        if(this._started && !widget._started){
4876
                                widget.startup();
4877
                        }
4878
                },
4879

    
4880
                removeChild: function(/*Widget or int*/ widget){
4881
                        // summary:
4882
                        //                Removes the passed widget instance from this widget but does
4883
                        //                not destroy it.  You can also pass in an integer indicating
4884
                        //                the index within the container to remove
4885

    
4886
                        if(typeof widget == "number" && widget > 0){
4887
                                widget = this.getChildren()[widget];
4888
                        }
4889

    
4890
                        if(widget){
4891
                                var node = widget.domNode;
4892
                                if(node && node.parentNode){
4893
                                        node.parentNode.removeChild(node); // detach but don't destroy
4894
                                }
4895
                        }
4896
                },
4897

    
4898
                hasChildren: function(){
4899
                        // summary:
4900
                        //                Returns true if widget has children, i.e. if this.containerNode contains something.
4901
                        return this.getChildren().length > 0;        // Boolean
4902
                },
4903

    
4904
                destroyDescendants: function(/*Boolean*/ preserveDom){
4905
                        // summary:
4906
                        //      Destroys all the widgets inside this.containerNode,
4907
                        //      but not this widget itself
4908
                        dojo.forEach(this.getChildren(), function(child){ child.destroyRecursive(preserveDom); });
4909
                },
4910

    
4911
                _getSiblingOfChild: function(/*dijit._Widget*/ child, /*int*/ dir){
4912
                        // summary:
4913
                        //                Get the next or previous widget sibling of child
4914
                        // dir:
4915
                        //                if 1, get the next sibling
4916
                        //                if -1, get the previous sibling
4917
                        // tags:
4918
                        //      private
4919
                        var node = child.domNode,
4920
                                which = (dir>0 ? "nextSibling" : "previousSibling");
4921
                        do{
4922
                                node = node[which];
4923
                        }while(node && (node.nodeType != 1 || !dijit.byNode(node)));
4924
                        return node && dijit.byNode(node);        // dijit._Widget
4925
                },
4926

    
4927
                getIndexOfChild: function(/*dijit._Widget*/ child){
4928
                        // summary:
4929
                        //                Gets the index of the child in this container or -1 if not found
4930
                        return dojo.indexOf(this.getChildren(), child);        // int
4931
                },
4932

    
4933
                startup: function(){
4934
                        // summary:
4935
                        //                Called after all the widgets have been instantiated and their
4936
                        //                dom nodes have been inserted somewhere under dojo.doc.body.
4937
                        //
4938
                        //                Widgets should override this method to do any initialization
4939
                        //                dependent on other widgets existing, and then call
4940
                        //                this superclass method to finish things off.
4941
                        //
4942
                        //                startup() in subclasses shouldn't do anything
4943
                        //                size related because the size of the widget hasn't been set yet.
4944

    
4945
                        if(this._started){ return; }
4946

    
4947
                        // Startup all children of this widget
4948
                        dojo.forEach(this.getChildren(), function(child){ child.startup(); });
4949

    
4950
                        this.inherited(arguments);
4951
                }
4952
        }
4953
);
4954

    
4955
}
4956

    
4957
if(!dojo._hasResource["dijit._Contained"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
4958
dojo._hasResource["dijit._Contained"] = true;
4959
dojo.provide("dijit._Contained");
4960

    
4961
dojo.declare("dijit._Contained",
4962
                null,
4963
                {
4964
                        // summary:
4965
                        //                Mixin for widgets that are children of a container widget
4966
                        //
4967
                        // example:
4968
                        // |         // make a basic custom widget that knows about it's parents
4969
                        // |        dojo.declare("my.customClass",[dijit._Widget,dijit._Contained],{});
4970

    
4971
                        getParent: function(){
4972
                                // summary:
4973
                                //                Returns the parent widget of this widget, assuming the parent
4974
                                //                specifies isContainer
4975
                                var parent = dijit.getEnclosingWidget(this.domNode.parentNode);
4976
                                return parent && parent.isContainer ? parent : null;
4977
                        },
4978

    
4979
                        _getSibling: function(/*String*/ which){
4980
                                // summary:
4981
                                //      Returns next or previous sibling
4982
                                // which:
4983
                                //      Either "next" or "previous"
4984
                                // tags:
4985
                                //      private
4986
                                var node = this.domNode;
4987
                                do{
4988
                                        node = node[which+"Sibling"];
4989
                                }while(node && node.nodeType != 1);
4990
                                return node && dijit.byNode(node);        // dijit._Widget
4991
                        },
4992

    
4993
                        getPreviousSibling: function(){
4994
                                // summary:
4995
                                //                Returns null if this is the first child of the parent,
4996
                                //                otherwise returns the next element sibling to the "left".
4997

    
4998
                                return this._getSibling("previous"); // dijit._Widget
4999
                        },
5000

    
5001
                        getNextSibling: function(){
5002
                                // summary:
5003
                                //                Returns null if this is the last child of the parent,
5004
                                //                otherwise returns the next element sibling to the "right".
5005

    
5006
                                return this._getSibling("next"); // dijit._Widget
5007
                        },
5008

    
5009
                        getIndexInParent: function(){
5010
                                // summary:
5011
                                //                Returns the index of this widget within its container parent.
5012
                                //                It returns -1 if the parent does not exist, or if the parent
5013
                                //                is not a dijit._Container
5014

    
5015
                                var p = this.getParent();
5016
                                if(!p || !p.getIndexOfChild){
5017
                                        return -1; // int
5018
                                }
5019
                                return p.getIndexOfChild(this); // int
5020
                        }
5021
                }
5022
        );
5023

    
5024

    
5025
}
5026

    
5027
if(!dojo._hasResource["dijit.layout._LayoutWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
5028
dojo._hasResource["dijit.layout._LayoutWidget"] = true;
5029
dojo.provide("dijit.layout._LayoutWidget");
5030

    
5031

    
5032

    
5033

    
5034

    
5035
dojo.declare("dijit.layout._LayoutWidget",
5036
        [dijit._Widget, dijit._Container, dijit._Contained],
5037
        {
5038
                // summary:
5039
                //                Base class for a _Container widget which is responsible for laying out its children.
5040
                //                Widgets which mixin this code must define layout() to manage placement and sizing of the children.
5041

    
5042
                // baseClass: [protected extension] String
5043
                //                This class name is applied to the widget's domNode
5044
                //                and also may be used to generate names for sub nodes,
5045
                //                for example dijitTabContainer-content.
5046
                baseClass: "dijitLayoutContainer",
5047

    
5048
                // isLayoutContainer: [protected] Boolean
5049
                //                Indicates that this widget is going to call resize() on its
5050
                //                children widgets, setting their size, when they become visible.
5051
                isLayoutContainer: true,
5052

    
5053
                postCreate: function(){
5054
                        dojo.addClass(this.domNode, "dijitContainer");
5055

    
5056
                        this.inherited(arguments);
5057
                },
5058

    
5059
                startup: function(){
5060
                        // summary:
5061
                        //                Called after all the widgets have been instantiated and their
5062
                        //                dom nodes have been inserted somewhere under dojo.doc.body.
5063
                        //
5064
                        //                Widgets should override this method to do any initialization
5065
                        //                dependent on other widgets existing, and then call
5066
                        //                this superclass method to finish things off.
5067
                        //
5068
                        //                startup() in subclasses shouldn't do anything
5069
                        //                size related because the size of the widget hasn't been set yet.
5070

    
5071
                        if(this._started){ return; }
5072

    
5073
                        // Need to call inherited first - so that child widgets get started
5074
                        // up correctly
5075
                        this.inherited(arguments);
5076

    
5077
                        // If I am a not being controlled by a parent layout widget...
5078
                        var parent = this.getParent && this.getParent()
5079
                        if(!(parent && parent.isLayoutContainer)){
5080
                                // Do recursive sizing and layout of all my descendants
5081
                                // (passing in no argument to resize means that it has to glean the size itself)
5082
                                this.resize();
5083

    
5084
                                // Since my parent isn't a layout container, and my style *may be* width=height=100%
5085
                                // or something similar (either set directly or via a CSS class),
5086
                                // monitor when my size changes so that I can re-layout.
5087
                                // For browsers where I can't directly monitor when my size changes,
5088
                                // monitor when the viewport changes size, which *may* indicate a size change for me.
5089
                                this.connect(dojo.isIE ? this.domNode : dojo.global, 'onresize', function(){
5090
                                        // Using function(){} closure to ensure no arguments to resize.
5091
                                        this.resize();
5092
                                });
5093
                        }
5094
                },
5095

    
5096
                resize: function(changeSize, resultSize){
5097
                        // summary:
5098
                        //                Call this to resize a widget, or after its size has changed.
5099
                        // description:
5100
                        //                Change size mode:
5101
                        //                        When changeSize is specified, changes the marginBox of this widget
5102
                        //                        and forces it to relayout its contents accordingly.
5103
                        //                        changeSize may specify height, width, or both.
5104
                        //
5105
                        //                        If resultSize is specified it indicates the size the widget will
5106
                        //                        become after changeSize has been applied.
5107
                        //
5108
                        //                Notification mode:
5109
                        //                        When changeSize is null, indicates that the caller has already changed
5110
                        //                        the size of the widget, or perhaps it changed because the browser
5111
                        //                        window was resized.  Tells widget to relayout its contents accordingly.
5112
                        //
5113
                        //                        If resultSize is also specified it indicates the size the widget has
5114
                        //                        become.
5115
                        //
5116
                        //                In either mode, this method also:
5117
                        //                        1. Sets this._borderBox and this._contentBox to the new size of
5118
                        //                                the widget.  Queries the current domNode size if necessary.
5119
                        //                        2. Calls layout() to resize contents (and maybe adjust child widgets).
5120
                        //
5121
                        // changeSize: Object?
5122
                        //                Sets the widget to this margin-box size and position.
5123
                        //                May include any/all of the following properties:
5124
                        //        |        {w: int, h: int, l: int, t: int}
5125
                        //
5126
                        // resultSize: Object?
5127
                        //                The margin-box size of this widget after applying changeSize (if
5128
                        //                changeSize is specified).  If caller knows this size and
5129
                        //                passes it in, we don't need to query the browser to get the size.
5130
                        //        |        {w: int, h: int}
5131

    
5132
                        var node = this.domNode;
5133

    
5134
                        // set margin box size, unless it wasn't specified, in which case use current size
5135
                        if(changeSize){
5136
                                dojo.marginBox(node, changeSize);
5137

    
5138
                                // set offset of the node
5139
                                if(changeSize.t){ node.style.top = changeSize.t + "px"; }
5140
                                if(changeSize.l){ node.style.left = changeSize.l + "px"; }
5141
                        }
5142

    
5143
                        // If either height or width wasn't specified by the user, then query node for it.
5144
                        // But note that setting the margin box and then immediately querying dimensions may return
5145
                        // inaccurate results, so try not to depend on it.
5146
                        var mb = resultSize || {};
5147
                        dojo.mixin(mb, changeSize || {});        // changeSize overrides resultSize
5148
                        if( !("h" in mb) || !("w" in mb) ){
5149
                                mb = dojo.mixin(dojo.marginBox(node), mb);        // just use dojo.marginBox() to fill in missing values
5150
                        }
5151

    
5152
                        // Compute and save the size of my border box and content box
5153
                        // (w/out calling dojo.contentBox() since that may fail if size was recently set)
5154
                        var cs = dojo.getComputedStyle(node);
5155
                        var me = dojo._getMarginExtents(node, cs);
5156
                        var be = dojo._getBorderExtents(node, cs);
5157
                        var bb = (this._borderBox = {
5158
                                w: mb.w - (me.w + be.w),
5159
                                h: mb.h - (me.h + be.h)
5160
                        });
5161
                        var pe = dojo._getPadExtents(node, cs);
5162
                        this._contentBox = {
5163
                                l: dojo._toPixelValue(node, cs.paddingLeft),
5164
                                t: dojo._toPixelValue(node, cs.paddingTop),
5165
                                w: bb.w - pe.w,
5166
                                h: bb.h - pe.h
5167
                        };
5168

    
5169
                        // Callback for widget to adjust size of its children
5170
                        this.layout();
5171
                },
5172

    
5173
                layout: function(){
5174
                        // summary:
5175
                        //                Widgets override this method to size and position their contents/children.
5176
                        //                When this is called this._contentBox is guaranteed to be set (see resize()).
5177
                        //
5178
                        //                This is called after startup(), and also when the widget's size has been
5179
                        //                changed.
5180
                        // tags:
5181
                        //                protected extension
5182
                },
5183

    
5184
                _setupChild: function(/*dijit._Widget*/child){
5185
                        // summary:
5186
                        //                Common setup for initial children and children which are added after startup
5187
                        // tags:
5188
                        //                protected extension
5189

    
5190
                        dojo.addClass(child.domNode, this.baseClass+"-child");
5191
                        if(child.baseClass){
5192
                                dojo.addClass(child.domNode, this.baseClass+"-"+child.baseClass);
5193
                        }
5194
                },
5195

    
5196
                addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
5197
                        // Overrides _Container.addChild() to call _setupChild()
5198
                        this.inherited(arguments);
5199
                        if(this._started){
5200
                                this._setupChild(child);
5201
                        }
5202
                },
5203

    
5204
                removeChild: function(/*dijit._Widget*/ child){
5205
                        // Overrides _Container.removeChild() to remove class added by _setupChild()
5206
                        dojo.removeClass(child.domNode, this.baseClass+"-child");
5207
                        if(child.baseClass){
5208
                                dojo.removeClass(child.domNode, this.baseClass+"-"+child.baseClass);
5209
                        }
5210
                        this.inherited(arguments);
5211
                }
5212
        }
5213
);
5214

    
5215
dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
5216
        // summary:
5217
        //                Given the margin-box size of a node, return its content box size.
5218
        //                Functions like dojo.contentBox() but is more reliable since it doesn't have
5219
        //                to wait for the browser to compute sizes.
5220
        var cs = dojo.getComputedStyle(node);
5221
        var me = dojo._getMarginExtents(node, cs);
5222
        var pb = dojo._getPadBorderExtents(node, cs);
5223
        return {
5224
                l: dojo._toPixelValue(node, cs.paddingLeft),
5225
                t: dojo._toPixelValue(node, cs.paddingTop),
5226
                w: mb.w - (me.w + pb.w),
5227
                h: mb.h - (me.h + pb.h)
5228
        };
5229
};
5230

    
5231
(function(){
5232
        var capitalize = function(word){
5233
                return word.substring(0,1).toUpperCase() + word.substring(1);
5234
        };
5235

    
5236
        var size = function(widget, dim){
5237
                // size the child
5238
                widget.resize ? widget.resize(dim) : dojo.marginBox(widget.domNode, dim);
5239

    
5240
                // record child's size, but favor our own numbers when we have them.
5241
                // the browser lies sometimes
5242
                dojo.mixin(widget, dojo.marginBox(widget.domNode));
5243
                dojo.mixin(widget, dim);
5244
        };
5245

    
5246
        dijit.layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Object[]*/ children){
5247
                // summary
5248
                //                Layout a bunch of child dom nodes within a parent dom node
5249
                // container:
5250
                //                parent node
5251
                // dim:
5252
                //                {l, t, w, h} object specifying dimensions of container into which to place children
5253
                // children:
5254
                //                an array like [ {domNode: foo, layoutAlign: "bottom" }, {domNode: bar, layoutAlign: "client"} ]
5255

    
5256
                // copy dim because we are going to modify it
5257
                dim = dojo.mixin({}, dim);
5258

    
5259
                dojo.addClass(container, "dijitLayoutContainer");
5260

    
5261
                // Move "client" elements to the end of the array for layout.  a11y dictates that the author
5262
                // needs to be able to put them in the document in tab-order, but this algorithm requires that
5263
                // client be last.
5264
                children = dojo.filter(children, function(item){ return item.layoutAlign != "client"; })
5265
                        .concat(dojo.filter(children, function(item){ return item.layoutAlign == "client"; }));
5266

    
5267
                // set positions/sizes
5268
                dojo.forEach(children, function(child){
5269
                        var elm = child.domNode,
5270
                                pos = child.layoutAlign;
5271

    
5272
                        // set elem to upper left corner of unused space; may move it later
5273
                        var elmStyle = elm.style;
5274
                        elmStyle.left = dim.l+"px";
5275
                        elmStyle.top = dim.t+"px";
5276
                        elmStyle.bottom = elmStyle.right = "auto";
5277

    
5278
                        dojo.addClass(elm, "dijitAlign" + capitalize(pos));
5279

    
5280
                        // set size && adjust record of remaining space.
5281
                        // note that setting the width of a <div> may affect its height.
5282
                        if(pos == "top" || pos == "bottom"){
5283
                                size(child, { w: dim.w });
5284
                                dim.h -= child.h;
5285
                                if(pos == "top"){
5286
                                        dim.t += child.h;
5287
                                }else{
5288
                                        elmStyle.top = dim.t + dim.h + "px";
5289
                                }
5290
                        }else if(pos == "left" || pos == "right"){
5291
                                size(child, { h: dim.h });
5292
                                dim.w -= child.w;
5293
                                if(pos == "left"){
5294
                                        dim.l += child.w;
5295
                                }else{
5296
                                        elmStyle.left = dim.l + dim.w + "px";
5297
                                }
5298
                        }else if(pos == "client"){
5299
                                size(child, dim);
5300
                        }
5301
                });
5302
        };
5303

    
5304
})();
5305

    
5306
}
5307

    
5308
if(!dojo._hasResource["dijit._CssStateMixin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
5309
dojo._hasResource["dijit._CssStateMixin"] = true;
5310
dojo.provide("dijit._CssStateMixin");
5311

    
5312

    
5313
dojo.declare("dijit._CssStateMixin", [], {
5314
        // summary:
5315
        //                Mixin for widgets to set CSS classes on the widget DOM nodes depending on hover/mouse press/focus
5316
        //                state changes, and also higher-level state changes such becoming disabled or selected.
5317
        //
5318
        // description:
5319
        //                By mixing this class into your widget, and setting the this.baseClass attribute, it will automatically
5320
        //                maintain CSS classes on the widget root node (this.domNode) depending on hover,
5321
        //                active, focus, etc. state.   Ex: with a baseClass of dijitButton, it will apply the classes
5322
        //                dijitButtonHovered and dijitButtonActive, as the user moves the mouse over the widget and clicks it.
5323
        //
5324
        //                It also sets CSS like dijitButtonDisabled based on widget semantic state.
5325
        //
5326
        //                By setting the cssStateNodes attribute, a widget can also track events on subnodes (like buttons
5327
        //                within the widget).
5328

    
5329
        // cssStateNodes: [protected] Object
5330
        //                List of sub-nodes within the widget that need CSS classes applied on mouse hover/press and focus
5331
        //.
5332
        //                Each entry in the hash is a an attachpoint names (like "upArrowButton") mapped to a CSS class names
5333
        //                (like "dijitUpArrowButton"). Example:
5334
        //        |                {
5335
        //        |                        "upArrowButton": "dijitUpArrowButton",
5336
        //        |                        "downArrowButton": "dijitDownArrowButton"
5337
        //        |                }
5338
        //                The above will set the CSS class dijitUpArrowButton to the this.upArrowButton DOMNode when it
5339
        //                is hovered, etc.
5340
        cssStateNodes: {},
5341

    
5342
        postCreate: function(){
5343
                this.inherited(arguments);
5344

    
5345
                // Automatically monitor mouse events (essentially :hover and :active) on this.domNode
5346
                dojo.forEach(["onmouseenter", "onmouseleave", "onmousedown"], function(e){
5347
                        this.connect(this.domNode, e, "_cssMouseEvent");
5348
                }, this);
5349
                
5350
                // Monitoring changes to disabled, readonly, etc. state, and update CSS class of root node
5351
                this.connect(this, "set", function(name, value){
5352
                        if(arguments.length >= 2 && {disabled: true, readOnly: true, checked:true, selected:true}[name]){
5353
                                this._setStateClass();
5354
                        }
5355
                });
5356

    
5357
                // The widget coming in/out of the focus change affects it's state
5358
                dojo.forEach(["_onFocus", "_onBlur"], function(ap){
5359
                        this.connect(this, ap, "_setStateClass");
5360
                }, this);
5361

    
5362
                // Events on sub nodes within the widget
5363
                for(var ap in this.cssStateNodes){
5364
                        this._trackMouseState(this[ap], this.cssStateNodes[ap]);
5365
                }
5366
                // Set state initially; there's probably no hover/active/focus state but widget might be
5367
                // disabled/readonly so we want to set CSS classes for those conditions.
5368
                this._setStateClass();
5369
        },
5370

    
5371
        _cssMouseEvent: function(/*Event*/ event){
5372
                // summary:
5373
                //        Sets _hovering and _active properties depending on mouse state,
5374
                //        then calls _setStateClass() to set appropriate CSS classes for this.domNode.
5375

    
5376
                if(!this.disabled){
5377
                        switch(event.type){
5378
                                case "mouseenter":
5379
                                case "mouseover":        // generated on non-IE browsers even though we connected to mouseenter
5380
                                        this._hovering = true;
5381
                                        this._active = this._mouseDown;
5382
                                        break;
5383

    
5384
                                case "mouseleave":
5385
                                case "mouseout":        // generated on non-IE browsers even though we connected to mouseleave
5386
                                        this._hovering = false;
5387
                                        this._active = false;
5388
                                        break;
5389

    
5390
                                case "mousedown" :
5391
                                        this._active = true;
5392
                                        this._mouseDown = true;
5393
                                        // Set a global event to handle mouseup, so it fires properly
5394
                                        // even if the cursor leaves this.domNode before the mouse up event.
5395
                                        // Alternately could set active=false on mouseout.
5396
                                        var mouseUpConnector = this.connect(dojo.body(), "onmouseup", function(){
5397
                                                this._active = false;
5398
                                                this._mouseDown = false;
5399
                                                this._setStateClass();
5400
                                                this.disconnect(mouseUpConnector);
5401
                                        });
5402
                                        break;
5403
                        }
5404
                        this._setStateClass();
5405
                }
5406
        },
5407

    
5408
        _setStateClass: function(){
5409
                // summary:
5410
                //                Update the visual state of the widget by setting the css classes on this.domNode
5411
                //                (or this.stateNode if defined) by combining this.baseClass with
5412
                //                various suffixes that represent the current widget state(s).
5413
                //
5414
                // description:
5415
                //                In the case where a widget has multiple
5416
                //                states, it sets the class based on all possible
5417
                //                 combinations.  For example, an invalid form widget that is being hovered
5418
                //                will be "dijitInput dijitInputInvalid dijitInputHover dijitInputInvalidHover".
5419
                //
5420
                //                The widget may have one or more of the following states, determined
5421
                //                by this.state, this.checked, this.valid, and this.selected:
5422
                //                        - Error - ValidationTextBox sets this.state to "Error" if the current input value is invalid
5423
                //                        - Checked - ex: a checkmark or a ToggleButton in a checked state, will have this.checked==true
5424
                //                        - Selected - ex: currently selected tab will have this.selected==true
5425
                //
5426
                //                In addition, it may have one or more of the following states,
5427
                //                based on this.disabled and flags set in _onMouse (this._active, this._hovering, this._focused):
5428
                //                        - Disabled        - if the widget is disabled
5429
                //                        - Active                - if the mouse (or space/enter key?) is being pressed down
5430
                //                        - Focused                - if the widget has focus
5431
                //                        - Hover                - if the mouse is over the widget
5432

    
5433
                // Compute new set of classes
5434
                var newStateClasses = this.baseClass.split(" ");
5435

    
5436
                function multiply(modifier){
5437
                        newStateClasses = newStateClasses.concat(dojo.map(newStateClasses, function(c){ return c+modifier; }), "dijit"+modifier);
5438
                }
5439

    
5440
                if(!this.isLeftToRight()){
5441
                        // For RTL mode we need to set an addition class like dijitTextBoxRtl.
5442
                        multiply("Rtl");
5443
                }
5444

    
5445
                if(this.checked){
5446
                        multiply("Checked");
5447
                }
5448
                if(this.state){
5449
                        multiply(this.state);
5450
                }
5451
                if(this.selected){
5452
                        multiply("Selected");
5453
                }
5454

    
5455
                if(this.disabled){
5456
                        multiply("Disabled");
5457
                }else if(this.readOnly){
5458
                        multiply("ReadOnly");
5459
                }else{
5460
                        if(this._active){
5461
                                multiply("Active");
5462
                        }else if(this._hovering){
5463
                                multiply("Hover");
5464
                        }
5465
                }
5466

    
5467
                if(this._focused){
5468
                        multiply("Focused");
5469
                }
5470

    
5471
                // Remove old state classes and add new ones.
5472
                // For performance concerns we only write into domNode.className once.
5473
                var tn = this.stateNode || this.domNode,
5474
                        classHash = {};        // set of all classes (state and otherwise) for node
5475

    
5476
                dojo.forEach(tn.className.split(" "), function(c){ classHash[c] = true; });
5477

    
5478
                if("_stateClasses" in this){
5479
                        dojo.forEach(this._stateClasses, function(c){ delete classHash[c]; });
5480
                }
5481

    
5482
                dojo.forEach(newStateClasses, function(c){ classHash[c] = true; });
5483

    
5484
                var newClasses = [];
5485
                for(var c in classHash){
5486
                        newClasses.push(c);
5487
                }
5488
                tn.className = newClasses.join(" ");
5489

    
5490
                this._stateClasses = newStateClasses;
5491
        },
5492

    
5493
        _trackMouseState: function(/*DomNode*/ node, /*String*/ clazz){
5494
                // summary:
5495
                //                Track mouse/focus events on specified node and set CSS class on that node to indicate
5496
                //                current state.   Usually not called directly, but via cssStateNodes attribute.
5497
                // description:
5498
                //                Given class=foo, will set the following CSS class on the node
5499
                //                        - fooActive: if the user is currently pressing down the mouse button while over the node
5500
                //                        - fooHover: if the user is hovering the mouse over the node, but not pressing down a button
5501
                //                        - fooFocus: if the node is focused
5502
                //
5503
                //                Note that it won't set any classes if the widget is disabled.
5504
                // node: DomNode
5505
                //                Should be a sub-node of the widget, not the top node (this.domNode), since the top node
5506
                //                is handled specially and automatically just by mixing in this class.
5507
                // clazz: String
5508
                //                CSS class name (ex: dijitSliderUpArrow).
5509

    
5510
                // Current state of node (initially false)
5511
                // NB: setting specifically to false because dojo.toggleClass() needs true boolean as third arg
5512
                var hovering=false, active=false, focused=false;
5513

    
5514
                var self = this,
5515
                        cn = dojo.hitch(this, "connect", node);
5516

    
5517
                function setClass(){
5518
                        var disabled = ("disabled" in self && self.disabled) || ("readonly" in self && self.readonly);
5519
                        dojo.toggleClass(node, clazz+"Hover", hovering && !active && !disabled);
5520
                        dojo.toggleClass(node, clazz+"Active", active && !disabled);
5521
                        dojo.toggleClass(node, clazz+"Focused", focused && !disabled);
5522
                }
5523

    
5524
                // Mouse
5525
                cn("onmouseenter", function(){
5526
                        hovering = true;
5527
                        setClass();
5528
                });
5529
                cn("onmouseleave", function(){
5530
                        hovering = false;
5531
                        active = false;
5532
                        setClass();
5533
                });
5534
                cn("onmousedown", function(){
5535
                        active = true;
5536
                        setClass();
5537
                });
5538
                cn("onmouseup", function(){
5539
                        active = false;
5540
                        setClass();
5541
                });
5542

    
5543
                // Focus
5544
                cn("onfocus", function(){
5545
                        focused = true;
5546
                        setClass();
5547
                });
5548
                cn("onblur", function(){
5549
                        focused = false;
5550
                        setClass();
5551
                });
5552

    
5553
                // Just in case widget is enabled/disabled while it has focus/hover/active state.
5554
                // Maybe this is overkill.
5555
                this.connect(this, "set", function(name, value){
5556
                        if(name == "disabled" || name == "readOnly"){
5557
                                setClass();
5558
                        }
5559
                });
5560
        }
5561
});
5562

    
5563
}
5564

    
5565
if(!dojo._hasResource["dijit.form._FormWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
5566
dojo._hasResource["dijit.form._FormWidget"] = true;
5567
dojo.provide("dijit.form._FormWidget");
5568

    
5569

    
5570

    
5571

    
5572

    
5573

    
5574

    
5575
dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated, dijit._CssStateMixin],
5576
        {
5577
        // summary:
5578
        //                Base class for widgets corresponding to native HTML elements such as <checkbox> or <button>,
5579
        //                which can be children of a <form> node or a `dijit.form.Form` widget.
5580
        //
5581
        // description:
5582
        //                Represents a single HTML element.
5583
        //                All these widgets should have these attributes just like native HTML input elements.
5584
        //                You can set them during widget construction or afterwards, via `dijit._Widget.attr`.
5585
        //
5586
        //                They also share some common methods.
5587

    
5588
        // name: String
5589
        //                Name used when submitting form; same as "name" attribute or plain HTML elements
5590
        name: "",
5591

    
5592
        // alt: String
5593
        //                Corresponds to the native HTML <input> element's attribute.
5594
        alt: "",
5595

    
5596
        // value: String
5597
        //                Corresponds to the native HTML <input> element's attribute.
5598
        value: "",
5599

    
5600
        // type: String
5601
        //                Corresponds to the native HTML <input> element's attribute.
5602
        type: "text",
5603

    
5604
        // tabIndex: Integer
5605
        //                Order fields are traversed when user hits the tab key
5606
        tabIndex: "0",
5607

    
5608
        // disabled: Boolean
5609
        //                Should this widget respond to user input?
5610
        //                In markup, this is specified as "disabled='disabled'", or just "disabled".
5611
        disabled: false,
5612

    
5613
        // intermediateChanges: Boolean
5614
        //                Fires onChange for each value change or only on demand
5615
        intermediateChanges: false,
5616

    
5617
        // scrollOnFocus: Boolean
5618
        //                On focus, should this widget scroll into view?
5619
        scrollOnFocus: true,
5620

    
5621
        // These mixins assume that the focus node is an INPUT, as many but not all _FormWidgets are.
5622
        attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
5623
                value: "focusNode",
5624
                id: "focusNode",
5625
                tabIndex: "focusNode",
5626
                alt: "focusNode",
5627
                title: "focusNode"
5628
        }),
5629

    
5630
        postMixInProperties: function(){
5631
                // Setup name=foo string to be referenced from the template (but only if a name has been specified)
5632
                // Unfortunately we can't use attributeMap to set the name due to IE limitations, see #8660
5633
                // Regarding escaping, see heading "Attribute values" in
5634
                // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
5635
                this.nameAttrSetting = this.name ? ('name="' + this.name.replace(/'/g, "&quot;") + '"') : '';
5636
                this.inherited(arguments);
5637
        },
5638

    
5639
        postCreate: function(){
5640
                this.inherited(arguments);
5641
                this.connect(this.domNode, "onmousedown", "_onMouseDown");
5642
        },
5643

    
5644
        _setDisabledAttr: function(/*Boolean*/ value){
5645
                this.disabled = value;
5646
                dojo.attr(this.focusNode, 'disabled', value);
5647
                if(this.valueNode){
5648
                        dojo.attr(this.valueNode, 'disabled', value);
5649
                }
5650
                dijit.setWaiState(this.focusNode, "disabled", value);
5651

    
5652
                if(value){
5653
                        // reset these, because after the domNode is disabled, we can no longer receive
5654
                        // mouse related events, see #4200
5655
                        this._hovering = false;
5656
                        this._active = false;
5657

    
5658
                        // clear tab stop(s) on this widget's focusable node(s)  (ComboBox has two focusable nodes)
5659
                        var attachPointNames = "tabIndex" in this.attributeMap ? this.attributeMap.tabIndex : "focusNode";
5660
                        dojo.forEach(dojo.isArray(attachPointNames) ? attachPointNames : [attachPointNames], function(attachPointName){
5661
                                var node = this[attachPointName];
5662
                                // complex code because tabIndex=-1 on a <div> doesn't work on FF
5663
                                if(dojo.isWebKit || dijit.hasDefaultTabStop(node)){        // see #11064 about webkit bug
5664
                                        node.setAttribute('tabIndex', "-1");
5665
                                }else{
5666
                                        node.removeAttribute('tabIndex');                                
5667
                                }
5668
                        }, this);
5669
                }else{
5670
                        this.focusNode.setAttribute('tabIndex', this.tabIndex);
5671
                }
5672
        },
5673

    
5674
        setDisabled: function(/*Boolean*/ disabled){
5675
                // summary:
5676
                //                Deprecated.   Use set('disabled', ...) instead.
5677
                dojo.deprecated("setDisabled("+disabled+") is deprecated. Use set('disabled',"+disabled+") instead.", "", "2.0");
5678
                this.set('disabled', disabled);
5679
        },
5680

    
5681
        _onFocus: function(e){
5682
                if(this.scrollOnFocus){
5683
                        dojo.window.scrollIntoView(this.domNode);
5684
                }
5685
                this.inherited(arguments);
5686
        },
5687

    
5688
        isFocusable: function(){
5689
                // summary:
5690
                //                Tells if this widget is focusable or not.   Used internally by dijit.
5691
                // tags:
5692
                //                protected
5693
                return !this.disabled && !this.readOnly && this.focusNode && (dojo.style(this.domNode, "display") != "none");
5694
        },
5695

    
5696
        focus: function(){
5697
                // summary:
5698
                //                Put focus on this widget
5699
                dijit.focus(this.focusNode);
5700
        },
5701

    
5702
        compare: function(/*anything*/val1, /*anything*/val2){
5703
                // summary:
5704
                //                Compare 2 values (as returned by attr('value') for this widget).
5705
                // tags:
5706
                //                protected
5707
                if(typeof val1 == "number" && typeof val2 == "number"){
5708
                        return (isNaN(val1) && isNaN(val2)) ? 0 : val1 - val2;
5709
                }else if(val1 > val2){
5710
                        return 1;
5711
                }else if(val1 < val2){
5712
                        return -1;
5713
                }else{
5714
                        return 0;
5715
                }
5716
        },
5717

    
5718
        onChange: function(newValue){
5719
                // summary:
5720
                //                Callback when this widget's value is changed.
5721
                // tags:
5722
                //                callback
5723
        },
5724

    
5725
        // _onChangeActive: [private] Boolean
5726
        //                Indicates that changes to the value should call onChange() callback.
5727
        //                This is false during widget initialization, to avoid calling onChange()
5728
        //                when the initial value is set.
5729
        _onChangeActive: false,
5730

    
5731
        _handleOnChange: function(/*anything*/ newValue, /* Boolean? */ priorityChange){
5732
                // summary:
5733
                //                Called when the value of the widget is set.  Calls onChange() if appropriate
5734
                // newValue:
5735
                //                the new value
5736
                // priorityChange:
5737
                //                For a slider, for example, dragging the slider is priorityChange==false,
5738
                //                but on mouse up, it's priorityChange==true.  If intermediateChanges==true,
5739
                //                onChange is only called form priorityChange=true events.
5740
                // tags:
5741
                //                private
5742
                this._lastValue = newValue;
5743
                if(this._lastValueReported == undefined && (priorityChange === null || !this._onChangeActive)){
5744
                        // this block executes not for a change, but during initialization,
5745
                        // and is used to store away the original value (or for ToggleButton, the original checked state)
5746
                        this._resetValue = this._lastValueReported = newValue;
5747
                }
5748
                if((this.intermediateChanges || priorityChange || priorityChange === undefined) &&
5749
                        ((typeof newValue != typeof this._lastValueReported) ||
5750
                                this.compare(newValue, this._lastValueReported) != 0)){
5751
                        this._lastValueReported = newValue;
5752
                        if(this._onChangeActive){
5753
                                if(this._onChangeHandle){
5754
                                        clearTimeout(this._onChangeHandle);
5755
                                }
5756
                                // setTimout allows hidden value processing to run and
5757
                                // also the onChange handler can safely adjust focus, etc
5758
                                this._onChangeHandle = setTimeout(dojo.hitch(this,
5759
                                        function(){
5760
                                                this._onChangeHandle = null;
5761
                                                this.onChange(newValue);
5762
                                        }), 0); // try to collapse multiple onChange's fired faster than can be processed
5763
                        }
5764
                }
5765
        },
5766

    
5767
        create: function(){
5768
                // Overrides _Widget.create()
5769
                this.inherited(arguments);
5770
                this._onChangeActive = true;
5771
        },
5772

    
5773
        destroy: function(){
5774
                if(this._onChangeHandle){ // destroy called before last onChange has fired
5775
                        clearTimeout(this._onChangeHandle);
5776
                        this.onChange(this._lastValueReported);
5777
                }
5778
                this.inherited(arguments);
5779
        },
5780

    
5781
        setValue: function(/*String*/ value){
5782
                // summary:
5783
                //                Deprecated.   Use set('value', ...) instead.
5784
                dojo.deprecated("dijit.form._FormWidget:setValue("+value+") is deprecated.  Use set('value',"+value+") instead.", "", "2.0");
5785
                this.set('value', value);
5786
        },
5787

    
5788
        getValue: function(){
5789
                // summary:
5790
                //                Deprecated.   Use get('value') instead.
5791
                dojo.deprecated(this.declaredClass+"::getValue() is deprecated. Use get('value') instead.", "", "2.0");
5792
                return this.get('value');
5793
        },
5794
        
5795
        _onMouseDown: function(e){
5796
                // If user clicks on the button, even if the mouse is released outside of it,
5797
                // this button should get focus (to mimics native browser buttons).
5798
                // This is also needed on chrome because otherwise buttons won't get focus at all,
5799
                // which leads to bizarre focus restore on Dialog close etc.
5800
                if(!e.ctrlKey && this.isFocusable()){ // !e.ctrlKey to ignore right-click on mac
5801
                        // Set a global event to handle mouseup, so it fires properly
5802
                        // even if the cursor leaves this.domNode before the mouse up event.
5803
                        var mouseUpConnector = this.connect(dojo.body(), "onmouseup", function(){
5804
                                if (this.isFocusable()) {
5805
                                        this.focus();
5806
                                }
5807
                                this.disconnect(mouseUpConnector);
5808
                        });
5809
                }
5810
        }
5811
});
5812

    
5813
dojo.declare("dijit.form._FormValueWidget", dijit.form._FormWidget,
5814
{
5815
        // summary:
5816
        //                Base class for widgets corresponding to native HTML elements such as <input> or <select> that have user changeable values.
5817
        // description:
5818
        //                Each _FormValueWidget represents a single input value, and has a (possibly hidden) <input> element,
5819
        //                to which it serializes it's input value, so that form submission (either normal submission or via FormBind?)
5820
        //                works as expected.
5821

    
5822
        // Don't attempt to mixin the 'type', 'name' attributes here programatically -- they must be declared
5823
        // directly in the template as read by the parser in order to function. IE is known to specifically
5824
        // require the 'name' attribute at element creation time.   See #8484, #8660.
5825
        // TODO: unclear what that {value: ""} is for; FormWidget.attributeMap copies value to focusNode,
5826
        // so maybe {value: ""} is so the value *doesn't* get copied to focusNode?
5827
        // Seems like we really want value removed from attributeMap altogether
5828
        // (although there's no easy way to do that now)
5829

    
5830
        // readOnly: Boolean
5831
        //                Should this widget respond to user input?
5832
        //                In markup, this is specified as "readOnly".
5833
        //                Similar to disabled except readOnly form values are submitted.
5834
        readOnly: false,
5835

    
5836
        attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
5837
                value: "",
5838
                readOnly: "focusNode"
5839
        }),
5840

    
5841
        _setReadOnlyAttr: function(/*Boolean*/ value){
5842
                this.readOnly = value;
5843
                dojo.attr(this.focusNode, 'readOnly', value);
5844
                dijit.setWaiState(this.focusNode, "readonly", value);
5845
        },
5846

    
5847
        postCreate: function(){
5848
                this.inherited(arguments);
5849

    
5850
                if(dojo.isIE){ // IE won't stop the event with keypress
5851
                        this.connect(this.focusNode || this.domNode, "onkeydown", this._onKeyDown);
5852
                }
5853
                // Update our reset value if it hasn't yet been set (because this.set()
5854
                // is only called when there *is* a value)
5855
                if(this._resetValue === undefined){
5856
                        this._resetValue = this.value;
5857
                }
5858
        },
5859

    
5860
        _setValueAttr: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){
5861
                // summary:
5862
                //                Hook so attr('value', value) works.
5863
                // description:
5864
                //                Sets the value of the widget.
5865
                //                If the value has changed, then fire onChange event, unless priorityChange
5866
                //                is specified as null (or false?)
5867
                this.value = newValue;
5868
                this._handleOnChange(newValue, priorityChange);
5869
        },
5870

    
5871
        _getValueAttr: function(){
5872
                // summary:
5873
                //                Hook so attr('value') works.
5874
                return this._lastValue;
5875
        },
5876

    
5877
        undo: function(){
5878
                // summary:
5879
                //                Restore the value to the last value passed to onChange
5880
                this._setValueAttr(this._lastValueReported, false);
5881
        },
5882

    
5883
        reset: function(){
5884
                // summary:
5885
                //                Reset the widget's value to what it was at initialization time
5886
                this._hasBeenBlurred = false;
5887
                this._setValueAttr(this._resetValue, true);
5888
        },
5889

    
5890
        _onKeyDown: function(e){
5891
                if(e.keyCode == dojo.keys.ESCAPE && !(e.ctrlKey || e.altKey || e.metaKey)){
5892
                        var te;
5893
                        if(dojo.isIE){
5894
                                e.preventDefault(); // default behavior needs to be stopped here since keypress is too late
5895
                                te = document.createEventObject();
5896
                                te.keyCode = dojo.keys.ESCAPE;
5897
                                te.shiftKey = e.shiftKey;
5898
                                e.srcElement.fireEvent('onkeypress', te);
5899
                        }
5900
                }
5901
        },
5902

    
5903
        _layoutHackIE7: function(){
5904
                // summary:
5905
                //                Work around table sizing bugs on IE7 by forcing redraw
5906

    
5907
                if(dojo.isIE == 7){ // fix IE7 layout bug when the widget is scrolled out of sight
5908
                        var domNode = this.domNode;
5909
                        var parent = domNode.parentNode;
5910
                        var pingNode = domNode.firstChild || domNode; // target node most unlikely to have a custom filter
5911
                        var origFilter = pingNode.style.filter; // save custom filter, most likely nothing
5912
                        var _this = this;
5913
                        while(parent && parent.clientHeight == 0){ // search for parents that haven't rendered yet
5914
                                (function ping(){
5915
                                        var disconnectHandle = _this.connect(parent, "onscroll",
5916
                                                function(e){
5917
                                                        _this.disconnect(disconnectHandle); // only call once
5918
                                                        pingNode.style.filter = (new Date()).getMilliseconds(); // set to anything that's unique
5919
                                                        setTimeout(function(){ pingNode.style.filter = origFilter }, 0); // restore custom filter, if any
5920
                                                }
5921
                                        );
5922
                                })();
5923
                                parent = parent.parentNode;
5924
                        }
5925
                }
5926
        }
5927
});
5928

    
5929
}
5930

    
5931
if(!dojo._hasResource["dijit.dijit"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
5932
dojo._hasResource["dijit.dijit"] = true;
5933
dojo.provide("dijit.dijit");
5934

    
5935
/*=====
5936
dijit.dijit = {
5937
        // summary:
5938
        //                A roll-up for common dijit methods
5939
        // description:
5940
        //        A rollup file for the build system including the core and common
5941
        //        dijit files.
5942
        //
5943
        // example:
5944
        // | <script type="text/javascript" src="js/dojo/dijit/dijit.js"></script>
5945
        //
5946
};
5947
=====*/
5948

    
5949
// All the stuff in _base (these are the function that are guaranteed available without an explicit dojo.require)
5950

    
5951

    
5952
// And some other stuff that we tend to pull in all the time anyway
5953

    
5954

    
5955

    
5956

    
5957

    
5958

    
5959

    
5960
}
5961