]> git.wh0rd.org - tt-rss.git/blame - lib/dijit/dijit.js.uncompressed.js
implement basic feed output for register.php
[tt-rss.git] / lib / dijit / dijit.js.uncompressed.js
CommitLineData
2f01fe57
AD
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
14if(!dojo._hasResource["dojo.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
15dojo._hasResource["dojo.window"] = true;
16dojo.provide("dojo.window");
17
18dojo.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
29dojo.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
53dojo.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
151if(!dojo._hasResource["dijit._base.manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
152dojo._hasResource["dijit._base.manager"] = true;
153dojo.provide("dijit._base.manager");
154
155dojo.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
624if(!dojo._hasResource["dijit._base.focus"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
625dojo._hasResource["dijit._base.focus"] = true;
626dojo.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
644dojo.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
1131dojo.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
1143if(!dojo._hasResource["dojo.AdapterRegistry"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
1144dojo._hasResource["dojo.AdapterRegistry"] = true;
1145dojo.provide("dojo.AdapterRegistry");
1146
1147dojo.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
1180dojo.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
1243if(!dojo._hasResource["dijit._base.place"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
1244dojo._hasResource["dijit._base.place"] = true;
1245dojo.provide("dijit._base.place");
1246
1247
1248
1249
1250
1251dijit.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/*=====
1259dijit.__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
1271dijit.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
1310dijit._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
1386dijit.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/*=====
1442dijit.__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
1460dijit.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
1476dijit._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
1507dijit.placementRegistry= new dojo.AdapterRegistry();
1508dijit.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);
1514dijit.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
1521dijit.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
1534dijit.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
1582if(!dojo._hasResource["dijit._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
1583dojo._hasResource["dijit._base.window"] = true;
1584dojo.provide("dijit._base.window");
1585
1586
1587
1588dijit.getDocumentWindow = function(doc){
1589 return dojo.window.get(doc);
1590};
1591
1592}
1593
1594if(!dojo._hasResource["dijit._base.popup"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
1595dojo._hasResource["dijit._base.popup"] = true;
1596dojo.provide("dijit._base.popup");
1597
1598
1599
1600
1601
1602/*=====
1603dijit.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
1657dijit.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
1870dijit._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
1906dijit.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
1934dojo.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
1965if(!dojo._hasResource["dijit._base.scroll"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
1966dojo._hasResource["dijit._base.scroll"] = true;
1967dojo.provide("dijit._base.scroll");
1968
1969
1970
1971dijit.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
1981if(!dojo._hasResource["dojo.uacss"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
1982dojo._hasResource["dojo.uacss"] = true;
1983dojo.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
2049if(!dojo._hasResource["dijit._base.sniff"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2050dojo._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
2058dojo.provide("dijit._base.sniff");
2059
2060
2061
2062}
2063
2064if(!dojo._hasResource["dijit._base.typematic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2065dojo._hasResource["dijit._base.typematic"] = true;
2066dojo.provide("dijit._base.typematic");
2067
2068dijit.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
2248if(!dojo._hasResource["dijit._base.wai"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2249dojo._hasResource["dijit._base.wai"] = true;
2250dojo.provide("dijit._base.wai");
2251
2252dijit.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.
2292if(dojo.isIE || dojo.isMoz){ // NOTE: checking in Safari messes things up
2293 dojo._loaders.unshift(dijit.wai.onload);
2294}
2295
2296dojo.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
2399if(!dojo._hasResource["dijit._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2400dojo._hasResource["dijit._base"] = true;
2401dojo.provide("dijit._base");
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413}
2414
2415if(!dojo._hasResource["dojo.date.stamp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2416dojo._hasResource["dojo.date.stamp"] = true;
2417dojo.provide("dojo.date.stamp");
2418
2419// Methods to convert dates to or from a wire (string) format using well-known conventions
2420
2421dojo.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
2514dojo.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
2557if(!dojo._hasResource["dojo.parser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2558dojo._hasResource["dojo.parser"] = true;
2559dojo.provide("dojo.parser");
2560
2561
2562new Date("X"); // workaround for #11279, new Date("") == NaN
2563
2564dojo.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
3003if(!dojo._hasResource["dijit._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
3004dojo._hasResource["dijit._Widget"] = true;
3005dojo.provide("dijit._Widget");
3006
3007dojo.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.
3012dojo.connect(dojo, "_connect",
3013 function(/*dijit._Widget*/ widget, /*String*/ event){
3014 if(widget && dojo.isFunction(widget._onConnect)){
3015 widget._onConnect(event);
3016 }
3017 });
3018
3019dijit._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
3027dijit._lastKeyDownNode = null;
3028if(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
3046var _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
3065dojo.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
4201if(!dojo._hasResource["dojo.string"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
4202dojo._hasResource["dojo.string"] = true;
4203dojo.provide("dojo.string");
4204
4205/*=====
4206dojo.string = {
4207 // summary: String utilities for Dojo
4208};
4209=====*/
4210
4211dojo.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
4232dojo.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
4257dojo.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/*=====
4329dojo.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
4344dojo.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
4359if(!dojo._hasResource["dojo.cache"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
4360dojo._hasResource["dojo.cache"] = true;
4361dojo.provide("dojo.cache");
4362
4363/*=====
4364dojo.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
4480if(!dojo._hasResource["dijit._Templated"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
4481dojo._hasResource["dijit._Templated"] = true;
4482dojo.provide("dijit._Templated");
4483
4484
4485
4486
4487
4488
4489dojo.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
4746dijit._Templated._templateCache = {};
4747
4748dijit._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
4795if(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.)
4811dojo.extend(dijit._Widget,{
4812 dojoAttachEvent: "",
4813 dojoAttachPoint: "",
4814 waiRole: "",
4815 waiState:""
4816});
4817
4818}
4819
4820if(!dojo._hasResource["dijit._Container"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
4821dojo._hasResource["dijit._Container"] = true;
4822dojo.provide("dijit._Container");
4823
4824dojo.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
4957if(!dojo._hasResource["dijit._Contained"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
4958dojo._hasResource["dijit._Contained"] = true;
4959dojo.provide("dijit._Contained");
4960
4961dojo.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
5027if(!dojo._hasResource["dijit.layout._LayoutWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
5028dojo._hasResource["dijit.layout._LayoutWidget"] = true;
5029dojo.provide("dijit.layout._LayoutWidget");
5030
5031
5032
5033
5034
5035dojo.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
5215dijit.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
5308if(!dojo._hasResource["dijit._CssStateMixin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
5309dojo._hasResource["dijit._CssStateMixin"] = true;
5310dojo.provide("dijit._CssStateMixin");
5311
5312
5313dojo.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
5565if(!dojo._hasResource["dijit.form._FormWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
5566dojo._hasResource["dijit.form._FormWidget"] = true;
5567dojo.provide("dijit.form._FormWidget");
5568
5569
5570
5571
5572
5573
5574
5575dojo.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
5813dojo.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
5931if(!dojo._hasResource["dijit.dijit"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
5932dojo._hasResource["dijit.dijit"] = true;
5933dojo.provide("dijit.dijit");
5934
5935/*=====
5936dijit.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