summaryrefslogtreecommitdiff
path: root/lib/dijit/_base/manager.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dijit/_base/manager.js')
-rw-r--r--lib/dijit/_base/manager.js718
1 files changed, 483 insertions, 235 deletions
diff --git a/lib/dijit/_base/manager.js b/lib/dijit/_base/manager.js
index d8d1cf6d5..e5f745622 100644
--- a/lib/dijit/_base/manager.js
+++ b/lib/dijit/_base/manager.js
@@ -1,245 +1,493 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
-if(!dojo._hasResource["dijit._base.manager"]){
-dojo._hasResource["dijit._base.manager"]=true;
+if(!dojo._hasResource["dijit._base.manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.manager"] = true;
dojo.provide("dijit._base.manager");
-dojo.declare("dijit.WidgetSet",null,{constructor:function(){
-this._hash={};
-this.length=0;
-},add:function(_1){
-if(this._hash[_1.id]){
-throw new Error("Tried to register widget with id=="+_1.id+" but that id is already registered");
-}
-this._hash[_1.id]=_1;
-this.length++;
-},remove:function(id){
-if(this._hash[id]){
-delete this._hash[id];
-this.length--;
-}
-},forEach:function(_2,_3){
-_3=_3||dojo.global;
-var i=0,id;
-for(id in this._hash){
-_2.call(_3,this._hash[id],i++,this._hash);
-}
-return this;
-},filter:function(_4,_5){
-_5=_5||dojo.global;
-var _6=new dijit.WidgetSet(),i=0,id;
-for(id in this._hash){
-var w=this._hash[id];
-if(_4.call(_5,w,i++,this._hash)){
-_6.add(w);
-}
-}
-return _6;
-},byId:function(id){
-return this._hash[id];
-},byClass:function(_7){
-var _8=new dijit.WidgetSet(),id,_9;
-for(id in this._hash){
-_9=this._hash[id];
-if(_9.declaredClass==_7){
-_8.add(_9);
-}
-}
-return _8;
-},toArray:function(){
-var ar=[];
-for(var id in this._hash){
-ar.push(this._hash[id]);
-}
-return ar;
-},map:function(_a,_b){
-return dojo.map(this.toArray(),_a,_b);
-},every:function(_c,_d){
-_d=_d||dojo.global;
-var x=0,i;
-for(i in this._hash){
-if(!_c.call(_d,this._hash[i],x++,this._hash)){
-return false;
-}
-}
-return true;
-},some:function(_e,_f){
-_f=_f||dojo.global;
-var x=0,i;
-for(i in this._hash){
-if(_e.call(_f,this._hash[i],x++,this._hash)){
-return true;
-}
-}
-return false;
-}});
-(function(){
-dijit.registry=new dijit.WidgetSet();
-var _10=dijit.registry._hash,_11=dojo.attr,_12=dojo.hasAttr,_13=dojo.style;
-dijit.byId=function(id){
-return typeof id=="string"?_10[id]:id;
-};
-var _14={};
-dijit.getUniqueId=function(_15){
-var id;
-do{
-id=_15+"_"+(_15 in _14?++_14[_15]:_14[_15]=0);
-}while(_10[id]);
-return dijit._scopeName=="dijit"?id:dijit._scopeName+"_"+id;
-};
-dijit.findWidgets=function(_16){
-var _17=[];
-function _18(_19){
-for(var _1a=_19.firstChild;_1a;_1a=_1a.nextSibling){
-if(_1a.nodeType==1){
-var _1b=_1a.getAttribute("widgetId");
-if(_1b){
-_17.push(_10[_1b]);
-}else{
-_18(_1a);
-}
-}
-}
-};
-_18(_16);
-return _17;
-};
-dijit._destroyAll=function(){
-dijit._curFocus=null;
-dijit._prevFocus=null;
-dijit._activeStack=[];
-dojo.forEach(dijit.findWidgets(dojo.body()),function(_1c){
-if(!_1c._destroyed){
-if(_1c.destroyRecursive){
-_1c.destroyRecursive();
-}else{
-if(_1c.destroy){
-_1c.destroy();
-}
-}
-}
-});
-};
-if(dojo.isIE){
-dojo.addOnWindowUnload(function(){
-dijit._destroyAll();
-});
-}
-dijit.byNode=function(_1d){
-return _10[_1d.getAttribute("widgetId")];
-};
-dijit.getEnclosingWidget=function(_1e){
-while(_1e){
-var id=_1e.getAttribute&&_1e.getAttribute("widgetId");
-if(id){
-return _10[id];
-}
-_1e=_1e.parentNode;
-}
-return null;
-};
-var _1f=(dijit._isElementShown=function(_20){
-var s=_13(_20);
-return (s.visibility!="hidden")&&(s.visibility!="collapsed")&&(s.display!="none")&&(_11(_20,"type")!="hidden");
-});
-dijit.hasDefaultTabStop=function(_21){
-switch(_21.nodeName.toLowerCase()){
-case "a":
-return _12(_21,"href");
-case "area":
-case "button":
-case "input":
-case "object":
-case "select":
-case "textarea":
-return true;
-case "iframe":
-if(dojo.isMoz){
-try{
-return _21.contentDocument.designMode=="on";
-}
-catch(err){
-return false;
-}
-}else{
-if(dojo.isWebKit){
-var doc=_21.contentDocument,_22=doc&&doc.body;
-return _22&&_22.contentEditable=="true";
-}else{
-try{
-doc=_21.contentWindow.document;
-_22=doc&&doc.body;
-return _22&&_22.firstChild&&_22.firstChild.contentEditable=="true";
-}
-catch(e){
-return false;
-}
-}
-}
-default:
-return _21.contentEditable=="true";
-}
-};
-var _23=(dijit.isTabNavigable=function(_24){
-if(_11(_24,"disabled")){
-return false;
-}else{
-if(_12(_24,"tabIndex")){
-return _11(_24,"tabIndex")>=0;
-}else{
-return dijit.hasDefaultTabStop(_24);
-}
-}
-});
-dijit._getTabNavigable=function(_25){
-var _26,_27,_28,_29,_2a,_2b;
-var _2c=function(_2d){
-dojo.query("> *",_2d).forEach(function(_2e){
-if((dojo.isIE&&_2e.scopeName!=="HTML")||!_1f(_2e)){
-return;
-}
-if(_23(_2e)){
-var _2f=_11(_2e,"tabIndex");
-if(!_12(_2e,"tabIndex")||_2f==0){
-if(!_26){
-_26=_2e;
-}
-_27=_2e;
-}else{
-if(_2f>0){
-if(!_28||_2f<_29){
-_29=_2f;
-_28=_2e;
-}
-if(!_2a||_2f>=_2b){
-_2b=_2f;
-_2a=_2e;
-}
-}
-}
-}
-if(_2e.nodeName.toUpperCase()!="SELECT"){
-_2c(_2e);
-}
+
+
+dojo.declare("dijit.WidgetSet", null, {
+ // summary:
+ // A set of widgets indexed by id. A default instance of this class is
+ // available as `dijit.registry`
+ //
+ // example:
+ // Create a small list of widgets:
+ // | var ws = new dijit.WidgetSet();
+ // | ws.add(dijit.byId("one"));
+ // | ws.add(dijit.byId("two"));
+ // | // destroy both:
+ // | ws.forEach(function(w){ w.destroy(); });
+ //
+ // example:
+ // Using dijit.registry:
+ // | dijit.registry.forEach(function(w){ /* do something */ });
+
+ constructor: function(){
+ this._hash = {};
+ this.length = 0;
+ },
+
+ add: function(/*dijit._Widget*/ widget){
+ // summary:
+ // Add a widget to this list. If a duplicate ID is detected, a error is thrown.
+ //
+ // widget: dijit._Widget
+ // Any dijit._Widget subclass.
+ if(this._hash[widget.id]){
+ throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered");
+ }
+ this._hash[widget.id] = widget;
+ this.length++;
+ },
+
+ remove: function(/*String*/ id){
+ // summary:
+ // Remove a widget from this WidgetSet. Does not destroy the widget; simply
+ // removes the reference.
+ if(this._hash[id]){
+ delete this._hash[id];
+ this.length--;
+ }
+ },
+
+ forEach: function(/*Function*/ func, /* Object? */thisObj){
+ // summary:
+ // Call specified function for each widget in this set.
+ //
+ // func:
+ // A callback function to run for each item. Is passed the widget, the index
+ // in the iteration, and the full hash, similar to `dojo.forEach`.
+ //
+ // thisObj:
+ // An optional scope parameter
+ //
+ // example:
+ // Using the default `dijit.registry` instance:
+ // | dijit.registry.forEach(function(widget){
+ // | console.log(widget.declaredClass);
+ // | });
+ //
+ // returns:
+ // Returns self, in order to allow for further chaining.
+
+ thisObj = thisObj || dojo.global;
+ var i = 0, id;
+ for(id in this._hash){
+ func.call(thisObj, this._hash[id], i++, this._hash);
+ }
+ return this; // dijit.WidgetSet
+ },
+
+ filter: function(/*Function*/ filter, /* Object? */thisObj){
+ // summary:
+ // Filter down this WidgetSet to a smaller new WidgetSet
+ // Works the same as `dojo.filter` and `dojo.NodeList.filter`
+ //
+ // filter:
+ // Callback function to test truthiness. Is passed the widget
+ // reference and the pseudo-index in the object.
+ //
+ // thisObj: Object?
+ // Option scope to use for the filter function.
+ //
+ // example:
+ // Arbitrary: select the odd widgets in this list
+ // | dijit.registry.filter(function(w, i){
+ // | return i % 2 == 0;
+ // | }).forEach(function(w){ /* odd ones */ });
+
+ thisObj = thisObj || dojo.global;
+ var res = new dijit.WidgetSet(), i = 0, id;
+ for(id in this._hash){
+ var w = this._hash[id];
+ if(filter.call(thisObj, w, i++, this._hash)){
+ res.add(w);
+ }
+ }
+ return res; // dijit.WidgetSet
+ },
+
+ byId: function(/*String*/ id){
+ // summary:
+ // Find a widget in this list by it's id.
+ // example:
+ // Test if an id is in a particular WidgetSet
+ // | var ws = new dijit.WidgetSet();
+ // | ws.add(dijit.byId("bar"));
+ // | var t = ws.byId("bar") // returns a widget
+ // | var x = ws.byId("foo"); // returns undefined
+
+ return this._hash[id]; // dijit._Widget
+ },
+
+ byClass: function(/*String*/ cls){
+ // summary:
+ // Reduce this widgetset to a new WidgetSet of a particular `declaredClass`
+ //
+ // cls: String
+ // The Class to scan for. Full dot-notated string.
+ //
+ // example:
+ // Find all `dijit.TitlePane`s in a page:
+ // | dijit.registry.byClass("dijit.TitlePane").forEach(function(tp){ tp.close(); });
+
+ var res = new dijit.WidgetSet(), id, widget;
+ for(id in this._hash){
+ widget = this._hash[id];
+ if(widget.declaredClass == cls){
+ res.add(widget);
+ }
+ }
+ return res; // dijit.WidgetSet
+},
+
+ toArray: function(){
+ // summary:
+ // Convert this WidgetSet into a true Array
+ //
+ // example:
+ // Work with the widget .domNodes in a real Array
+ // | dojo.map(dijit.registry.toArray(), function(w){ return w.domNode; });
+
+ var ar = [];
+ for(var id in this._hash){
+ ar.push(this._hash[id]);
+ }
+ return ar; // dijit._Widget[]
+},
+
+ map: function(/* Function */func, /* Object? */thisObj){
+ // summary:
+ // Create a new Array from this WidgetSet, following the same rules as `dojo.map`
+ // example:
+ // | var nodes = dijit.registry.map(function(w){ return w.domNode; });
+ //
+ // returns:
+ // A new array of the returned values.
+ return dojo.map(this.toArray(), func, thisObj); // Array
+ },
+
+ every: function(func, thisObj){
+ // summary:
+ // A synthetic clone of `dojo.every` acting explicitly on this WidgetSet
+ //
+ // func: Function
+ // A callback function run for every widget in this list. Exits loop
+ // when the first false return is encountered.
+ //
+ // thisObj: Object?
+ // Optional scope parameter to use for the callback
+
+ thisObj = thisObj || dojo.global;
+ var x = 0, i;
+ for(i in this._hash){
+ if(!func.call(thisObj, this._hash[i], x++, this._hash)){
+ return false; // Boolean
+ }
+ }
+ return true; // Boolean
+ },
+
+ some: function(func, thisObj){
+ // summary:
+ // A synthetic clone of `dojo.some` acting explictly on this WidgetSet
+ //
+ // func: Function
+ // A callback function run for every widget in this list. Exits loop
+ // when the first true return is encountered.
+ //
+ // thisObj: Object?
+ // Optional scope parameter to use for the callback
+
+ thisObj = thisObj || dojo.global;
+ var x = 0, i;
+ for(i in this._hash){
+ if(func.call(thisObj, this._hash[i], x++, this._hash)){
+ return true; // Boolean
+ }
+ }
+ return false; // Boolean
+ }
+
});
-};
-if(_1f(_25)){
-_2c(_25);
-}
-return {first:_26,last:_27,lowest:_28,highest:_2a};
-};
-dijit.getFirstInTabbingOrder=function(_30){
-var _31=dijit._getTabNavigable(dojo.byId(_30));
-return _31.lowest?_31.lowest:_31.first;
-};
-dijit.getLastInTabbingOrder=function(_32){
-var _33=dijit._getTabNavigable(dojo.byId(_32));
-return _33.last?_33.last:_33.highest;
-};
-dijit.defaultDuration=dojo.config["defaultDuration"]||200;
+
+(function(){
+
+ /*=====
+ dijit.registry = {
+ // summary:
+ // A list of widgets on a page.
+ // description:
+ // Is an instance of `dijit.WidgetSet`
+ };
+ =====*/
+ dijit.registry = new dijit.WidgetSet();
+
+ var hash = dijit.registry._hash,
+ attr = dojo.attr,
+ hasAttr = dojo.hasAttr,
+ style = dojo.style;
+
+ dijit.byId = function(/*String|dijit._Widget*/ id){
+ // summary:
+ // Returns a widget by it's id, or if passed a widget, no-op (like dojo.byId())
+ return typeof id == "string" ? hash[id] : id; // dijit._Widget
+ };
+
+ var _widgetTypeCtr = {};
+ dijit.getUniqueId = function(/*String*/widgetType){
+ // summary:
+ // Generates a unique id for a given widgetType
+
+ var id;
+ do{
+ id = widgetType + "_" +
+ (widgetType in _widgetTypeCtr ?
+ ++_widgetTypeCtr[widgetType] : _widgetTypeCtr[widgetType] = 0);
+ }while(hash[id]);
+ return dijit._scopeName == "dijit" ? id : dijit._scopeName + "_" + id; // String
+ };
+
+ dijit.findWidgets = function(/*DomNode*/ root){
+ // summary:
+ // Search subtree under root returning widgets found.
+ // Doesn't search for nested widgets (ie, widgets inside other widgets).
+
+ var outAry = [];
+
+ function getChildrenHelper(root){
+ for(var node = root.firstChild; node; node = node.nextSibling){
+ if(node.nodeType == 1){
+ var widgetId = node.getAttribute("widgetId");
+ if(widgetId){
+ var widget = hash[widgetId];
+ if(widget){ // may be null on page w/multiple dojo's loaded
+ outAry.push(widget);
+ }
+ }else{
+ getChildrenHelper(node);
+ }
+ }
+ }
+ }
+
+ getChildrenHelper(root);
+ return outAry;
+ };
+
+ dijit._destroyAll = function(){
+ // summary:
+ // Code to destroy all widgets and do other cleanup on page unload
+
+ // Clean up focus manager lingering references to widgets and nodes
+ dijit._curFocus = null;
+ dijit._prevFocus = null;
+ dijit._activeStack = [];
+
+ // Destroy all the widgets, top down
+ dojo.forEach(dijit.findWidgets(dojo.body()), function(widget){
+ // Avoid double destroy of widgets like Menu that are attached to <body>
+ // even though they are logically children of other widgets.
+ if(!widget._destroyed){
+ if(widget.destroyRecursive){
+ widget.destroyRecursive();
+ }else if(widget.destroy){
+ widget.destroy();
+ }
+ }
+ });
+ };
+
+ if(dojo.isIE){
+ // Only run _destroyAll() for IE because we think it's only necessary in that case,
+ // and because it causes problems on FF. See bug #3531 for details.
+ dojo.addOnWindowUnload(function(){
+ dijit._destroyAll();
+ });
+ }
+
+ dijit.byNode = function(/*DOMNode*/ node){
+ // summary:
+ // Returns the widget corresponding to the given DOMNode
+ return hash[node.getAttribute("widgetId")]; // dijit._Widget
+ };
+
+ dijit.getEnclosingWidget = function(/*DOMNode*/ node){
+ // summary:
+ // Returns the widget whose DOM tree contains the specified DOMNode, or null if
+ // the node is not contained within the DOM tree of any widget
+ while(node){
+ var id = node.getAttribute && node.getAttribute("widgetId");
+ if(id){
+ return hash[id];
+ }
+ node = node.parentNode;
+ }
+ return null;
+ };
+
+ var shown = (dijit._isElementShown = function(/*Element*/ elem){
+ var s = style(elem);
+ return (s.visibility != "hidden")
+ && (s.visibility != "collapsed")
+ && (s.display != "none")
+ && (attr(elem, "type") != "hidden");
+ });
+
+ dijit.hasDefaultTabStop = function(/*Element*/ elem){
+ // summary:
+ // Tests if element is tab-navigable even without an explicit tabIndex setting
+
+ // No explicit tabIndex setting, need to investigate node type
+ switch(elem.nodeName.toLowerCase()){
+ case "a":
+ // An <a> w/out a tabindex is only navigable if it has an href
+ return hasAttr(elem, "href");
+ case "area":
+ case "button":
+ case "input":
+ case "object":
+ case "select":
+ case "textarea":
+ // These are navigable by default
+ return true;
+ case "iframe":
+ // If it's an editor <iframe> then it's tab navigable.
+ var body;
+ try{
+ // non-IE
+ var contentDocument = elem.contentDocument;
+ if("designMode" in contentDocument && contentDocument.designMode == "on"){
+ return true;
+ }
+ body = contentDocument.body;
+ }catch(e1){
+ // contentWindow.document isn't accessible within IE7/8
+ // if the iframe.src points to a foreign url and this
+ // page contains an element, that could get focus
+ try{
+ body = elem.contentWindow.document.body;
+ }catch(e2){
+ return false;
+ }
+ }
+ return body.contentEditable == 'true' || (body.firstChild && body.firstChild.contentEditable == 'true');
+ default:
+ return elem.contentEditable == 'true';
+ }
+ };
+
+ var isTabNavigable = (dijit.isTabNavigable = function(/*Element*/ elem){
+ // summary:
+ // Tests if an element is tab-navigable
+
+ // TODO: convert (and rename method) to return effective tabIndex; will save time in _getTabNavigable()
+ if(attr(elem, "disabled")){
+ return false;
+ }else if(hasAttr(elem, "tabIndex")){
+ // Explicit tab index setting
+ return attr(elem, "tabIndex") >= 0; // boolean
+ }else{
+ // No explicit tabIndex setting, so depends on node type
+ return dijit.hasDefaultTabStop(elem);
+ }
+ });
+
+ dijit._getTabNavigable = function(/*DOMNode*/ root){
+ // summary:
+ // Finds descendants of the specified root node.
+ //
+ // description:
+ // Finds the following descendants of the specified root node:
+ // * the first tab-navigable element in document order
+ // without a tabIndex or with tabIndex="0"
+ // * the last tab-navigable element in document order
+ // without a tabIndex or with tabIndex="0"
+ // * the first element in document order with the lowest
+ // positive tabIndex value
+ // * the last element in document order with the highest
+ // positive tabIndex value
+ var first, last, lowest, lowestTabindex, highest, highestTabindex, radioSelected = {};
+ function radioName(node) {
+ // If this element is part of a radio button group, return the name for that group.
+ return node && node.tagName.toLowerCase() == "input" &&
+ node.type && node.type.toLowerCase() == "radio" &&
+ node.name && node.name.toLowerCase();
+ }
+ var walkTree = function(/*DOMNode*/parent){
+ dojo.query("> *", parent).forEach(function(child){
+ // Skip hidden elements, and also non-HTML elements (those in custom namespaces) in IE,
+ // since show() invokes getAttribute("type"), which crash on VML nodes in IE.
+ if((dojo.isIE && child.scopeName!=="HTML") || !shown(child)){
+ return;
+ }
+
+ if(isTabNavigable(child)){
+ var tabindex = attr(child, "tabIndex");
+ if(!hasAttr(child, "tabIndex") || tabindex == 0){
+ if(!first){ first = child; }
+ last = child;
+ }else if(tabindex > 0){
+ if(!lowest || tabindex < lowestTabindex){
+ lowestTabindex = tabindex;
+ lowest = child;
+ }
+ if(!highest || tabindex >= highestTabindex){
+ highestTabindex = tabindex;
+ highest = child;
+ }
+ }
+ var rn = radioName(child);
+ if(dojo.attr(child, "checked") && rn) {
+ radioSelected[rn] = child;
+ }
+ }
+ if(child.nodeName.toUpperCase() != 'SELECT'){
+ walkTree(child);
+ }
+ });
+ };
+ if(shown(root)){ walkTree(root) }
+ function rs(node) {
+ // substitute checked radio button for unchecked one, if there is a checked one with the same name.
+ return radioSelected[radioName(node)] || node;
+ }
+ return { first: rs(first), last: rs(last), lowest: rs(lowest), highest: rs(highest) };
+ }
+ dijit.getFirstInTabbingOrder = function(/*String|DOMNode*/ root){
+ // summary:
+ // Finds the descendant of the specified root node
+ // that is first in the tabbing order
+ var elems = dijit._getTabNavigable(dojo.byId(root));
+ return elems.lowest ? elems.lowest : elems.first; // DomNode
+ };
+
+ dijit.getLastInTabbingOrder = function(/*String|DOMNode*/ root){
+ // summary:
+ // Finds the descendant of the specified root node
+ // that is last in the tabbing order
+ var elems = dijit._getTabNavigable(dojo.byId(root));
+ return elems.last ? elems.last : elems.highest; // DomNode
+ };
+
+ /*=====
+ dojo.mixin(dijit, {
+ // defaultDuration: Integer
+ // The default animation speed (in ms) to use for all Dijit
+ // transitional animations, unless otherwise specified
+ // on a per-instance basis. Defaults to 200, overrided by
+ // `djConfig.defaultDuration`
+ defaultDuration: 200
+ });
+ =====*/
+
+ dijit.defaultDuration = dojo.config["defaultDuration"] || 200;
+
})();
+
}