/* 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"]){ //_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, { // 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 } }); (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; })(); }