dojo.provide("dijit._base.manager"); 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 = {}; }, add: function(/*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; }, remove: function(/*String*/ id){ // summary: // Remove a widget from this WidgetSet. Does not destroy the widget; simply // removes the reference. delete this._hash[id]; }, forEach: function(/*Function*/ func){ // summary: // Call specified function for each widget in this set. // // func: // A callback function to run for each item. Is passed a the widget. // // example: // Using the default `dijit.registry` instance: // | dijit.registry.forEach(function(widget){ // | console.log(widget.declaredClass); // | }); for(var id in this._hash){ func(this._hash[id]); } }, filter: function(/*Function*/ filter){ // 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. // // example: // Arbitrary: select the odd widgets in this list // | var i = 0; // | dijit.registry.filter(function(w){ // | return ++i % 2 == 0; // | }).forEach(function(w){ /* odd ones */ }); var res = new dijit.WidgetSet(); this.forEach(function(widget){ if(filter(widget)){ res.add(widget); } }); 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 // // example: // Find all titlePane's in a page: // | dijit.registry.byClass("dijit.TitlePane").forEach(function(tp){ tp.close(); }); return this.filter(function(widget){ return widget.declaredClass==cls; }); // dijit.WidgetSet } }); /*===== dijit.registry = { // summary: A list of widgets on a page. // description: Is an instance of `dijit.WidgetSet` }; =====*/ dijit.registry = new dijit.WidgetSet(); dijit._widgetTypeCtr = {}; dijit.getUniqueId = function(/*String*/widgetType){ // summary: Generates a unique id for a given widgetType var id; do{ id = widgetType + "_" + (widgetType in dijit._widgetTypeCtr ? ++dijit._widgetTypeCtr[widgetType] : dijit._widgetTypeCtr[widgetType] = 0); }while(dijit.byId(id)); return id; // String }; dijit.findWidgets = function(/*DomNode*/ root){ // summary: // Search subtree under root, putting found widgets in outAry. // Doesn't search for nested widgets (ie, widgets inside other widgets) var outAry = []; function getChildrenHelper(root){ var list = dojo.isIE ? root.children : root.childNodes, i = 0, node; while(node = list[i++]){ if(node.nodeType != 1){ continue; } var widgetId = node.getAttribute("widgetId"); if(widgetId){ var widget = dijit.byId(widgetId); outAry.push(widget); }else{ getChildrenHelper(node); } } } getChildrenHelper(root); return outAry; }; if(dojo.isIE){ // Only run this 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(){ dojo.forEach(dijit.findWidgets(dojo.body()), function(widget){ if(widget.destroyRecursive){ widget.destroyRecursive(); }else if(widget.destroy){ widget.destroy(); } }); }); } dijit.byId = function(/*String|Widget*/id){ // summary: // Returns a widget by it's id, or if passed a widget, no-op (like dojo.byId()) return (dojo.isString(id)) ? dijit.registry.byId(id) : id; // Widget }; dijit.byNode = function(/* DOMNode */ node){ // summary: // Returns the widget corresponding to the given DOMNode return dijit.registry.byId(node.getAttribute("widgetId")); // 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){ if(node.getAttribute && node.getAttribute("widgetId")){ return dijit.registry.byId(node.getAttribute("widgetId")); } node = node.parentNode; } return null; }; // elements that are tab-navigable if they have no tabindex value set // (except for "a", which must have an href attribute) dijit._tabElements = { area: true, button: true, input: true, object: true, select: true, textarea: true }; dijit._isElementShown = function(/*Element*/elem){ var style = dojo.style(elem); return (style.visibility != "hidden") && (style.visibility != "collapsed") && (style.display != "none") && (dojo.attr(elem, "type") != "hidden"); } dijit.isTabNavigable = function(/*Element*/elem){ // summary: // Tests if an element is tab-navigable if(dojo.hasAttr(elem, "disabled")){ return false; } var hasTabindex = dojo.hasAttr(elem, "tabindex"); var tabindex = dojo.attr(elem, "tabindex"); if(hasTabindex && tabindex >= 0) { return true; // boolean } var name = elem.nodeName.toLowerCase(); if(((name == "a" && dojo.hasAttr(elem, "href")) || dijit._tabElements[name]) && (!hasTabindex || tabindex >= 0)){ return true; // boolean } return false; // boolean }; 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; var walkTree = function(/*DOMNode*/parent){ dojo.query("> *", parent).forEach(function(child){ var isShown = dijit._isElementShown(child); if(isShown && dijit.isTabNavigable(child)){ var tabindex = dojo.attr(child, "tabindex"); if(!dojo.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; } } } if(isShown && child.nodeName.toUpperCase() != 'SELECT'){ walkTree(child) } }); }; if(dijit._isElementShown(root)){ walkTree(root) } return { first: first, last: last, lowest: lowest, highest: 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: 300 }); =====*/ dijit.defaultDuration = dojo.config["defaultDuration"] || 200;