]> git.wh0rd.org - tt-rss.git/blobdiff - lib/dojo/tt-rss-layer.js.uncompressed.js
upgrade Dojo to 1.6.1
[tt-rss.git] / lib / dojo / tt-rss-layer.js.uncompressed.js
index fa2e12157d1ee24882fbcd79c0908e2959f89ec7..81d4302df951f3fda13007b8dddd4c1b1a167fe4 100644 (file)
@@ -1,5 +1,5 @@
 /*
-       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
 */
@@ -16,6 +16,8 @@ if(!dojo._hasResource["dojo.date.stamp"]){ //_hasResource checks added by build.
 dojo._hasResource["dojo.date.stamp"] = true;
 dojo.provide("dojo.date.stamp");
 
+dojo.getObject("date.stamp", true, dojo);
+
 // Methods to convert dates to or from a wire (string) format using well-known conventions
 
 dojo.date.stamp.fromISOString = function(/*String*/formattedString, /*Number?*/defaultTime){
@@ -94,7 +96,7 @@ dojo.date.stamp.fromISOString = function(/*String*/formattedString, /*Number?*/d
        }
 
        return result; // Date or null
-}
+};
 
 /*=====
        dojo.date.stamp.__Options = function(){
@@ -144,13 +146,13 @@ dojo.date.stamp.toISOString = function(/*Date*/dateObject, /*dojo.date.stamp.__O
                }else if(options.selector != "time"){
                        var timezoneOffset = dateObject.getTimezoneOffset();
                        var absOffset = Math.abs(timezoneOffset);
-                       time += (timezoneOffset > 0 ? "-" : "+") + 
+                       time += (timezoneOffset > 0 ? "-" : "+") +
                                _(Math.floor(absOffset/60)) + ":" + _(absOffset%60);
                }
                formattedDate.push(time);
        }
        return formattedDate.join('T'); // String
-}
+};
 
 }
 
@@ -159,14 +161,14 @@ dojo._hasResource["dojo.parser"] = true;
 dojo.provide("dojo.parser");
 
 
+
 new Date("X"); // workaround for #11279, new Date("") == NaN
 
 dojo.parser = new function(){
-       // summary: The Dom/Widget parsing package
+       // summary:
+       //              The Dom/Widget parsing package
 
        var d = dojo;
-       this._attrName = d._scopeName + "Type";
-       this._query = "[" + this._attrName + "]";
 
        function val2type(/*Object*/ value){
                // summary:
@@ -191,13 +193,13 @@ dojo.parser = new function(){
                        case "number":
                                return value.length ? Number(value) : NaN;
                        case "boolean":
-                               // for checked/disabled value might be "" or "checked".  interpret as true.
+                               // for checked/disabled value might be "" or "checked".  interpret as true.
                                return typeof value == "boolean" ? value : !(value.toLowerCase()=="false");
                        case "function":
                                if(d.isFunction(value)){
                                        // IE gives us a function, even when we say something like onClick="foo"
-                                       // (in which case it gives us an invalid function "function(){ foo }"). 
-                                       //  Therefore, convert to string
+                                       // (in which case it gives us an invalid function "function(){ foo }").
+                                       //      Therefore, convert to string
                                        value=value.toString();
                                        value=d.trim(value.substring(value.indexOf('{')+1, value.length-1));
                                }
@@ -226,7 +228,7 @@ dojo.parser = new function(){
                }
        }
 
-       var instanceClasses = {
+       var dummyClass = {}, instanceClasses = {
                // map from fully qualified name (like "dijit.Button") to structure like
                // { cls: dijit.Button, params: {label: "string", disabled: "boolean"} }
        };
@@ -234,45 +236,70 @@ dojo.parser = new function(){
        // Widgets like BorderContainer add properties to _Widget via dojo.extend().
        // If BorderContainer is loaded after _Widget's parameter list has been cached,
        // we need to refresh that parameter list (for _Widget and all widgets that extend _Widget).
-       dojo.connect(dojo, "extend", function(){
+       // TODO: remove this in 2.0, when we stop caching parameters.
+       d.connect(d, "extend", function(){
                instanceClasses = {};
        });
 
-       function getClassInfo(/*String*/ className){
+       function getProtoInfo(cls, params){
+               // cls: A prototype
+               //              The prototype of the class to check props on
+               // params: Object
+               //              The parameters object to mix found parameters onto.
+               for(var name in cls){
+                       if(name.charAt(0)=="_"){ continue; }    // skip internal properties
+                       if(name in dummyClass){ continue; }             // skip "constructor" and "toString"
+                       params[name] = val2type(cls[name]);
+               }
+               return params;
+       }
+
+       function getClassInfo(/*String*/ className, /*Boolean*/ skipParamsLookup){
+               // summary:
+               //              Maps a widget name string like "dijit.form.Button" to the widget constructor itself,
+               //              and a list of that widget's parameters and their types
                // className:
                //              fully qualified name (like "dijit.form.Button")
                // returns:
                //              structure like
-               //                      { 
-               //                              cls: dijit.Button, 
+               //                      {
+               //                              cls: dijit.Button,
                //                              params: { label: "string", disabled: "boolean"}
                //                      }
 
-               if(!instanceClasses[className]){
+               var c = instanceClasses[className];
+               if(!c){
                        // get pointer to widget class
-                       var cls = d.getObject(className);
+                       var cls = d.getObject(className), params = null;
                        if(!cls){ return null; }                // class not defined [yet]
-
-                       var proto = cls.prototype;
-       
-                       // get table of parameter names & types
-                       var params = {}, dummyClass = {};
-                       for(var name in proto){
-                               if(name.charAt(0)=="_"){ continue; }    // skip internal properties
-                               if(name in dummyClass){ continue; }             // skip "constructor" and "toString"
-                               var defVal = proto[name];
-                               params[name]=val2type(defVal);
+                       if(!skipParamsLookup){ // from fastpath, we don't need to lookup the attrs on the proto because they are explicit
+                               params = getProtoInfo(cls.prototype, {})
                        }
-
-                       instanceClasses[className] = { cls: cls, params: params };
+                       c = { cls: cls, params: params };
+                       
+               }else if(!skipParamsLookup && !c.params){
+                       // if we're calling getClassInfo and have a cls proto, but no params info, scan that cls for params now
+                       // and update the pointer in instanceClasses[className]. This happens when a widget appears in another
+                       // widget's template which still uses dojoType, but an instance of the widget appears prior with a data-dojo-type,
+                       // skipping this lookup the first time.
+                       c.params = getProtoInfo(c.cls.prototype, {});
                }
-               return instanceClasses[className];
+               
+               return c;
        }
 
-       this._functionFromScript = function(script){
+       this._functionFromScript = function(script, attrData){
+               // summary:
+               //              Convert a <script type="dojo/method" args="a, b, c"> ... </script>
+               //              into a function
+               // script: DOMNode
+               //              The <script> DOMNode
+               // attrData: String
+               //              For HTML5 compliance, searches for attrData + "args" (typically
+               //              "data-dojo-args") instead of "args"
                var preamble = "";
                var suffix = "";
-               var argsStr = script.getAttribute("args");
+               var argsStr = (script.getAttribute(attrData + "args") || script.getAttribute("args"));
                if(argsStr){
                        d.forEach(argsStr.split(/\s*,\s*/), function(part, idx){
                                preamble += "var "+part+" = arguments["+idx+"]; ";
@@ -286,7 +313,7 @@ dojo.parser = new function(){
                        });
                }
                return new Function(preamble+script.innerHTML+suffix);
-       }
+       };
 
        this.instantiate = function(/* Array */nodes, /* Object? */mixin, /* Object? */args){
                // summary:
@@ -307,69 +334,106 @@ dojo.parser = new function(){
                //              exist.
                // args: Object?
                //              An object used to hold kwArgs for instantiation.
-               //              Supports 'noStart' and inherited.
-               var thelist = [], dp = dojo.parser;
+               //              See parse.args argument for details.
+
+               var thelist = [],
                mixin = mixin||{};
                args = args||{};
-               
+
+               // TODO: for 2.0 default to data-dojo- regardless of scopeName (or maybe scopeName won't exist in 2.0)
+               var attrName = (args.scope || d._scopeName) + "Type",   // typically "dojoType"
+                       attrData = "data-" + (args.scope || d._scopeName) + "-";        // typically "data-dojo-"
+
                d.forEach(nodes, function(obj){
                        if(!obj){ return; }
 
-                       // Get pointers to DOMNode, dojoType string, and clsInfo (metadata about the dojoType), etc.s
-                       var node, type, clsInfo, clazz, scripts;
+                       // Get pointers to DOMNode, dojoType string, and clsInfo (metadata about the dojoType), etc.
+                       var node, type, clsInfo, clazz, scripts, fastpath;
                        if(obj.node){
                                // new format of nodes[] array, object w/lots of properties pre-computed for me
                                node = obj.node;
                                type = obj.type;
-                               clsInfo = obj.clsInfo || (type && getClassInfo(type));
+                               fastpath = obj.fastpath;
+                               clsInfo = obj.clsInfo || (type && getClassInfo(type, fastpath));
                                clazz = clsInfo && clsInfo.cls;
                                scripts = obj.scripts;
                        }else{
-                               // old (backwards compatible) format of nodes[] array, simple array of DOMNodes
+                               // old (backwards compatible) format of nodes[] array, simple array of DOMNodes. no fastpath/data-dojo-type support here.
                                node = obj;
-                               type = dp._attrName in mixin ? mixin[dp._attrName] : node.getAttribute(dp._attrName);
+                               type = attrName in mixin ? mixin[attrName] : node.getAttribute(attrName);
                                clsInfo = type && getClassInfo(type);
                                clazz = clsInfo && clsInfo.cls;
-                               scripts = (clazz && (clazz._noScript || clazz.prototype._noScript) ? [] : 
+                               scripts = (clazz && (clazz._noScript || clazz.prototype._noScript) ? [] :
                                                        d.query("> script[type^='dojo/']", node));
                        }
                        if(!clsInfo){
                                throw new Error("Could not load class '" + type);
                        }
 
-                       // Setup hash to hold parameter settings for this widget.   Start with the parameter
+                       // Setup hash to hold parameter settings for this widget.       Start with the parameter
                        // settings inherited from ancestors ("dir" and "lang").
                        // Inherited setting may later be overridden by explicit settings on node itself.
-                       var params = {},
-                               attributes = node.attributes;
+                       var params = {};
+                               
                        if(args.defaults){
                                // settings for the document itself (or whatever subtree is being parsed)
-                               dojo.mixin(params, args.defaults);
+                               d._mixin(params, args.defaults);
                        }
                        if(obj.inherited){
                                // settings from dir=rtl or lang=... on a node above this node
-                               dojo.mixin(params, obj.inherited);
+                               d._mixin(params, obj.inherited);
                        }
+                       
+                       // mix things found in data-dojo-props into the params
+                       if(fastpath){
+                               var extra = node.getAttribute(attrData + "props");
+                               if(extra && extra.length){
+                                       try{
+                                               extra = d.fromJson.call(args.propsThis, "{" + extra + "}");
+                                               d._mixin(params, extra);
+                                       }catch(e){
+                                               // give the user a pointer to their invalid parameters. FIXME: can we kill this in production?
+                                               throw new Error(e.toString() + " in data-dojo-props='" + extra + "'");
+                                       }
+                               }
 
-                       // read parameters (ie, attributes) specified on DOMNode
-                       // clsInfo.params lists expected params like {"checked": "boolean", "n": "number"}
-                       for(var name in clsInfo.params){
-                               var item = name in mixin?{value:mixin[name],specified:true}:attributes.getNamedItem(name);
-                               if(!item || (!item.specified && (!dojo.isIE || name.toLowerCase()!="value"))){ continue; }
-                               var value = item.value;
-                               // Deal with IE quirks for 'class' and 'style'
-                               switch(name){
-                               case "class":
-                                       value = "className" in mixin?mixin.className:node.className;
-                                       break;
-                               case "style":
-                                       value = "style" in mixin?mixin.style:(node.style && node.style.cssText); // FIXME: Opera?
+                               // For the benefit of _Templated, check if node has data-dojo-attach-point/data-dojo-attach-event
+                               // and mix those in as though they were parameters
+                               var attachPoint = node.getAttribute(attrData + "attach-point");
+                               if(attachPoint){
+                                       params.dojoAttachPoint = attachPoint;
                                }
-                               var _type = clsInfo.params[name];
-                               if(typeof value == "string"){
-                                       params[name] = str2obj(value, _type);
-                               }else{
-                                       params[name] = value;
+                               var attachEvent = node.getAttribute(attrData + "attach-event");
+                               if(attachEvent){
+                                       params.dojoAttachEvent = attachEvent;
+                               }
+                               dojo.mixin(params, mixin);
+                       }else{
+                               // FIXME: we need something like "deprecateOnce()" to throw dojo.deprecation for something.
+                               // remove this logic in 2.0
+                               // read parameters (ie, attributes) specified on DOMNode
+
+                               var attributes = node.attributes;
+
+                               // clsInfo.params lists expected params like {"checked": "boolean", "n": "number"}
+                               for(var name in clsInfo.params){
+                                       var item = name in mixin ? { value:mixin[name], specified:true } : attributes.getNamedItem(name);
+                                       if(!item || (!item.specified && (!dojo.isIE || name.toLowerCase()!="value"))){ continue; }
+                                       var value = item.value;
+                                       // Deal with IE quirks for 'class' and 'style'
+                                       switch(name){
+                                       case "class":
+                                               value = "className" in mixin ? mixin.className : node.className;
+                                               break;
+                                       case "style":
+                                               value = "style" in mixin ? mixin.style : (node.style && node.style.cssText); // FIXME: Opera?
+                                       }
+                                       var _type = clsInfo.params[name];
+                                       if(typeof value == "string"){
+                                               params[name] = str2obj(value, _type);
+                                       }else{
+                                               params[name] = value;
+                                       }
                                }
                        }
 
@@ -384,9 +448,10 @@ dojo.parser = new function(){
 
                        d.forEach(scripts, function(script){
                                node.removeChild(script);
-                               var event = script.getAttribute("event"),
+                               // FIXME: drop event="" support in 2.0. use data-dojo-event="" instead
+                               var event = (script.getAttribute(attrData + "event") || script.getAttribute("event")),
                                        type = script.getAttribute("type"),
-                                       nf = d.parser._functionFromScript(script);
+                                       nf = d.parser._functionFromScript(script, attrData);
                                if(event){
                                        if(type == "dojo/connect"){
                                                connects.push({event: event, func: nf});
@@ -404,7 +469,8 @@ dojo.parser = new function(){
                        thelist.push(instance);
 
                        // map it to the JS namespace if that makes sense
-                       var jsname = node.getAttribute("jsId");
+                       // FIXME: in 2.0, drop jsId support. use data-dojo-id instead
+                       var jsname = (node.getAttribute(attrData + "id") || node.getAttribute("jsId"));
                        if(jsname){
                                d.setObject(jsname, instance);
                        }
@@ -428,9 +494,9 @@ dojo.parser = new function(){
                        // ContentPane is the parent widget (so that the parse doesn't call startup() on the
                        // ContentPane's children)
                        d.forEach(thelist, function(instance){
-                               if(     !args.noStart && instance  && 
-                                       instance.startup &&
-                                       !instance._started && 
+                               if( !args.noStart && instance  &&
+                                       dojo.isFunction(instance.startup) &&
+                                       !instance._started &&
                                        (!instance.getParent || !instance.getParent())
                                ){
                                        instance.startup();
@@ -440,34 +506,57 @@ dojo.parser = new function(){
                return thelist;
        };
 
-       this.parse = function(/*DomNode?*/ rootNode, /* Object? */ args){
+       this.parse = function(rootNode, args){
                // summary:
                //              Scan the DOM for class instances, and instantiate them.
                //
                // description:
                //              Search specified node (or root node) recursively for class instances,
-               //              and instantiate them Searches for
-               //              dojoType="qualified.class.name"
+               //              and instantiate them. Searches for either data-dojo-type="Class" or
+               //              dojoType="Class" where "Class" is a a fully qualified class name,
+               //              like `dijit.form.Button`
+               //
+               //              Using `data-dojo-type`:
+               //              Attributes using can be mixed into the parameters used to instantitate the
+               //              Class by using a `data-dojo-props` attribute on the node being converted.
+               //              `data-dojo-props` should be a string attribute to be converted from JSON.
+               //
+               //              Using `dojoType`:
+               //              Attributes are read from the original domNode and converted to appropriate
+               //              types by looking up the Class prototype values. This is the default behavior
+               //              from Dojo 1.0 to Dojo 1.5. `dojoType` support is deprecated, and will
+               //              go away in Dojo 2.0.
                //
                // rootNode: DomNode?
                //              A default starting root node from which to start the parsing. Can be
                //              omitted, defaulting to the entire document. If omitted, the `args`
-               //              object can be passed in this place. If the `args` object has a 
+               //              object can be passed in this place. If the `args` object has a
                //              `rootNode` member, that is used.
                //
-               // args:
+               // args: Object
                //              a kwArgs object passed along to instantiate()
-               //              
+               //
                //                      * noStart: Boolean?
                //                              when set will prevent the parser from calling .startup()
-               //                              when locating the nodes. 
+               //                              when locating the nodes.
                //                      * rootNode: DomNode?
                //                              identical to the function's `rootNode` argument, though
-               //                              allowed to be passed in via this `args object. 
+               //                              allowed to be passed in via this `args object.
+               //                      * template: Boolean
+               //                              If true, ignores ContentPane's stopParser flag and parses contents inside of
+               //                              a ContentPane inside of a template.   This allows dojoAttachPoint on widgets/nodes
+               //                              nested inside the ContentPane to work.
                //                      * inherited: Object
                //                              Hash possibly containing dir and lang settings to be applied to
                //                              parsed widgets, unless there's another setting on a sub-node that overrides
-               //
+               //                      * scope: String
+               //                              Root for attribute names to search for.   If scopeName is dojo,
+               //                              will search for data-dojo-type (or dojoType).   For backwards compatibility
+               //                              reasons defaults to dojo._scopeName (which is "dojo" except when
+               //                              multi-version support is used, when it will be something like dojo16, dojo20, etc.)
+               //                      * propsThis: Object
+               //                              If specified, "this" referenced from data-dojo-props will refer to propsThis.
+               //                              Intended for use from the widgets-in-template feature of `dijit._Templated`
                //
                // example:
                //              Parse all widgets on a page:
@@ -475,10 +564,10 @@ dojo.parser = new function(){
                //
                // example:
                //              Parse all classes within the node with id="foo"
-               //      |               dojo.parser.parse(dojo.byId(foo));
+               //      |               dojo.parser.parse(dojo.byId('foo'));
                //
                // example:
-               //              Parse all classes in a page, but do not call .startup() on any 
+               //              Parse all classes in a page, but do not call .startup() on any
                //              child
                //      |               dojo.parser.parse({ noStart: true })
                //
@@ -486,7 +575,7 @@ dojo.parser = new function(){
                //              Parse all classes in a node, but do not call .startup()
                //      |               dojo.parser.parse(someNode, { noStart:true });
                //      |               // or
-               //      |               dojo.parser.parse({ noStart:true, rootNode: someNode });
+               //      |               dojo.parser.parse({ noStart:true, rootNode: someNode });
 
                // determine the root node based on the passed arguments.
                var root;
@@ -496,8 +585,12 @@ dojo.parser = new function(){
                }else{
                        root = rootNode;
                }
+               root = root ? dojo.byId(root) : dojo.body();
+               args = args || {};
+
+               var attrName = (args.scope || d._scopeName) + "Type",           // typically "dojoType"
+                       attrData = "data-" + (args.scope || d._scopeName) + "-";        // typically "data-dojo-"
 
-               var attrName = this._attrName;
                function scan(parent, list){
                        // summary:
                        //              Parent is an Object representing a DOMNode, with or without a dojoType specified.
@@ -506,7 +599,7 @@ dojo.parser = new function(){
                        // parent: Object
                        //              Object representing the parent node, like
                        //      |       {
-                       //      |               node: DomNode,                  // scan children of this node
+                       //      |               node: DomNode,                  // scan children of this node
                        //      |               inherited: {dir: "rtl"},        // dir/lang setting inherited from above node
                        //      |
                        //      |               // attributes only set if node has dojoType specified
@@ -519,6 +612,7 @@ dojo.parser = new function(){
                        // Effective dir and lang settings on parent node, either set directly or inherited from grandparent
                        var inherited = dojo.clone(parent.inherited);
                        dojo.forEach(["dir", "lang"], function(name){
+                               // TODO: what if this is a widget and dir/lang are declared in data-dojo-props?
                                var val = parent.node.getAttribute(name);
                                if(val){
                                        inherited[name] = val;
@@ -526,20 +620,31 @@ dojo.parser = new function(){
                        });
 
                        // if parent is a widget, then search for <script type=dojo/*> tags and put them in scripts[].
-                       var scripts = parent.scripts;
+                       var scripts = parent.clsInfo && !parent.clsInfo.cls.prototype._noScript ? parent.scripts : null;
 
                        // unless parent is a widget with the stopParser flag set, continue search for dojoType, recursively
-                       var recurse = !parent.clsInfo || !parent.clsInfo.cls.prototype.stopParser;
+                       var recurse = (!parent.clsInfo || !parent.clsInfo.cls.prototype.stopParser) || (args && args.template);
 
                        // scan parent's children looking for dojoType and <script type=dojo/*>
                        for(var child = parent.node.firstChild; child; child = child.nextSibling){
                                if(child.nodeType == 1){
-                                       var type = recurse && child.getAttribute(attrName);
+                                       // FIXME: desupport dojoType in 2.0. use data-dojo-type instead
+                                       var type, html5 = recurse && child.getAttribute(attrData + "type");
+                                       if(html5){
+                                               type = html5;
+                                       }else{
+                                               // fallback to backward compatible mode, using dojoType. remove in 2.0
+                                               type = recurse && child.getAttribute(attrName);
+                                       }
+                                       
+                                       var fastpath = html5 == type;
+
                                        if(type){
-                                               // if dojoType specified, add to output array of nodes to instantiate
+                                               // if dojoType/data-dojo-type specified, add to output array of nodes to instantiate
                                                var params = {
                                                        "type": type,
-                                                       clsInfo: getClassInfo(type),    // note: won't find classes declared via dojo.Declaration
+                                                       fastpath: fastpath,
+                                                       clsInfo: getClassInfo(type, fastpath), // note: won't find classes declared via dojo.Declaration
                                                        node: child,
                                                        scripts: [], // <script> nodes that are parent's children
                                                        inherited: inherited // dir & lang attributes inherited from parent
@@ -552,7 +657,7 @@ dojo.parser = new function(){
                                        }else if(scripts && child.nodeName.toLowerCase() == "script"){
                                                // if <script type="dojo/...">, save in scripts[]
                                                type = child.getAttribute("type");
-                                               if (type && /^dojo\//i.test(type)) {
+                                               if (type && /^dojo\/\w/i.test(type)) {
                                                        scripts.push(child);
                                                }
                                        }else if(recurse){
@@ -566,17 +671,24 @@ dojo.parser = new function(){
                        }
                }
 
+               // Ignore bogus entries in inherited hash like {dir: ""}
+               var inherited = {};
+               if(args && args.inherited){
+                       for(var key in args.inherited){
+                               if(args.inherited[key]){ inherited[key] = args.inherited[key]; }
+                       }
+               }
+
                // Make list of all nodes on page w/dojoType specified
                var list = [];
                scan({
-                       node: root ? dojo.byId(root) : dojo.body(),
-                       inherited: (args && args.inherited) || {
-                               dir: dojo._isBodyLtr() ? "ltr" : "rtl"
-                       }
+                       node: root,
+                       inherited: inherited
                }, list);
 
                // go build the object instances
-               return this.instantiate(list, null, args); // Array
+               var mixin = args && args.template ? {template: true} : null;
+               return this.instantiate(list, mixin, args); // Array
        };
 }();
 
@@ -584,14 +696,14 @@ dojo.parser = new function(){
 //after the a11y test.
 
 (function(){
-       var parseRunner = function(){ 
+       var parseRunner = function(){
                if(dojo.config.parseOnLoad){
-                       dojo.parser.parse(); 
+                       dojo.parser.parse();
                }
        };
 
        // FIXME: need to clobber cross-dependency!!
-       if(dojo.exists("dijit.wai.onload") && (dijit.wai.onload === dojo._loaders[0])){
+       if(dojo.getObject("dijit.wai.onload") === dojo._loaders[0]){
                dojo._loaders.splice(1, 0, parseRunner);
        }else{
                dojo._loaders.unshift(parseRunner);
@@ -604,6 +716,8 @@ if(!dojo._hasResource["dojo.window"]){ //_hasResource checks added by build. Do
 dojo._hasResource["dojo.window"] = true;
 dojo.provide("dojo.window");
 
+dojo.getObject("window", true, dojo);
+
 dojo.window.getBox = function(){
        // summary:
        //              Returns the dimensions and scroll position of the viewable area of a browser window
@@ -657,7 +771,9 @@ dojo.window.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
                        return;
                }
                var backCompat = doc.compatMode == 'BackCompat',
-                       clientAreaRoot = backCompat? body : html,
+                       clientAreaRoot = (isIE >= 9 && node.ownerDocument.parentWindow.frameElement)
+                               ? ((html.clientHeight > 0 && html.clientWidth > 0 && (body.clientHeight == 0 || body.clientWidth == 0 || body.clientHeight > html.clientHeight || body.clientWidth > html.clientWidth)) ? html : body)
+                               : (backCompat ? body : html),
                        scrollRoot = isWK ? body : clientAreaRoot,
                        rootWidth = clientAreaRoot.clientWidth,
                        rootHeight = clientAreaRoot.clientHeight,
@@ -682,14 +798,11 @@ dojo.window.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
                        }else{
                                var pb = dojo._getPadBorderExtents(el);
                                elPos.w -= pb.w; elPos.h -= pb.h; elPos.x += pb.l; elPos.y += pb.t;
-                       }
-       
-                       if(el != scrollRoot){ // body, html sizes already have the scrollbar removed
                                var clientSize = el.clientWidth,
                                        scrollBarSize = elPos.w - clientSize;
                                if(clientSize > 0 && scrollBarSize > 0){
                                        elPos.w = clientSize;
-                                       if(isIE && rtl){ elPos.x += scrollBarSize; }
+                                       elPos.x += (rtl && (isIE || el.clientLeft > pb.l/*Chrome*/)) ? scrollBarSize : 0;
                                }
                                clientSize = el.clientHeight;
                                scrollBarSize = elPos.h - clientSize;
@@ -718,8 +831,9 @@ dojo.window.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
                                bot = t + nodePos.h - elPos.h; // beyond bottom: > 0
                        if(r * l > 0){
                                var s = Math[l < 0? "max" : "min"](l, r);
+                               if(rtl && ((isIE == 8 && !backCompat) || isIE >= 9)){ s = -s; }
                                nodePos.x += el.scrollLeft;
-                               el.scrollLeft += (isIE >= 8 && !backCompat && rtl)? -s : s;
+                               el.scrollLeft += s;
                                nodePos.x -= el.scrollLeft;
                        }
                        if(bot * t > 0){
@@ -728,7 +842,7 @@ dojo.window.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
                                nodePos.y -= el.scrollTop;
                        }
                        el = (el != scrollRoot) && !fixedPos && el.parentNode;
-               }       
+               }
        }catch(error){
                console.error('scrollIntoView: ' + error);
                node.scrollIntoView(false);
@@ -741,6 +855,7 @@ if(!dojo._hasResource["dijit._base.manager"]){ //_hasResource checks added by bu
 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
@@ -996,7 +1111,10 @@ dojo.declare("dijit.WidgetSet", null, {
                                if(node.nodeType == 1){
                                        var widgetId = node.getAttribute("widgetId");
                                        if(widgetId){
-                                               outAry.push(hash[widgetId]);
+                                               var widget = hash[widgetId];
+                                               if(widget){     // may be null on page w/multiple dojo's loaded
+                                                       outAry.push(widget);
+                                               }
                                        }else{
                                                getChildrenHelper(node);
                                        }
@@ -1086,29 +1204,25 @@ dojo.declare("dijit.WidgetSet", null, {
                                return true;
                        case "iframe":
                                // If it's an editor <iframe> then it's tab navigable.
-                               //TODO: feature detect "designMode" in elem.contentDocument?
-                               if(dojo.isMoz){
-                                       try{
-                                               return elem.contentDocument.designMode == "on";
-                                       }catch(err){
-                                               return false;
+                               var body;
+                               try{
+                                       // non-IE
+                                       var contentDocument = elem.contentDocument;
+                                       if("designMode" in contentDocument && contentDocument.designMode == "on"){
+                                               return true;
                                        }
-                               }else if(dojo.isWebKit){
-                                       var doc = elem.contentDocument,
-                                               body = doc && doc.body;
-                                       return body && body.contentEditable == 'true';
-                               }else{
+                                       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{
-                                               doc = elem.contentWindow.document;
-                                               body = doc && doc.body;
-                                               return body && body.firstChild && body.firstChild.contentEditable == 'true';
-                                       }catch(e){
+                                               body = elem.contentWindow.document.body;
+                                       }catch(e2){
                                                return false;
                                        }
                                }
+                               return body.contentEditable == 'true' || (body.firstChild && body.firstChild.contentEditable == 'true');
                        default:
                                return elem.contentEditable == 'true';
                }
@@ -1144,7 +1258,13 @@ dojo.declare("dijit.WidgetSet", null, {
                //                positive tabIndex value
                //              * the last element in document order with the highest
                //                positive tabIndex value
-               var first, last, lowest, lowestTabindex, highest, highestTabindex;
+               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,
@@ -1168,6 +1288,10 @@ dojo.declare("dijit.WidgetSet", null, {
                                                        highest = child;
                                                }
                                        }
+                                       var rn = radioName(child);
+                                       if(dojo.attr(child, "checked") && rn) {
+                                               radioSelected[rn] = child;
+                                       }
                                }
                                if(child.nodeName.toUpperCase() != 'SELECT'){
                                        walkTree(child);
@@ -1175,7 +1299,11 @@ dojo.declare("dijit.WidgetSet", null, {
                        });
                };
                if(shown(root)){ walkTree(root) }
-               return { first: first, last: last, lowest: lowest, highest: highest };
+               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:
@@ -1215,7 +1343,7 @@ dojo._hasResource["dijit._base.focus"] = true;
 dojo.provide("dijit._base.focus");
 
 
-       // for dijit.isTabNavigable()
+
 
 // summary:
 //             These functions are used to query or set the focus and selection.
@@ -1271,6 +1399,9 @@ dojo.mixin(dijit, {
                                                }
                                        }
                                        bm = {isCollapsed:true};
+                                       if(sel.rangeCount){
+                                               bm.mark = sel.getRangeAt(0).cloneRange();
+                                       }
                                }else{
                                        rg = sel.getRangeAt(0);
                                        bm = {isCollapsed: false, mark: rg.cloneRange()};
@@ -1518,7 +1649,7 @@ dojo.mixin(dijit, {
                var doc = dojo.isIE ? targetWindow.document.documentElement : targetWindow.document;
                if(doc){
                        if(dojo.isIE){
-                               doc.attachEvent('onmousedown', mousedownListener);
+                               targetWindow.document.body.attachEvent('onmousedown', mousedownListener);
                                var activateListener = function(evt){
                                        // IE reports that nodes like <body> have gotten focus, even though they have tabIndex=-1,
                                        // Should consider those more like a mouse-click than a focus....
@@ -1536,13 +1667,13 @@ dojo.mixin(dijit, {
                                doc.attachEvent('ondeactivate', deactivateListener);
 
                                return function(){
-                                       doc.detachEvent('onmousedown', mousedownListener);
+                                       targetWindow.document.detachEvent('onmousedown', mousedownListener);
                                        doc.detachEvent('onactivate', activateListener);
                                        doc.detachEvent('ondeactivate', deactivateListener);
                                        doc = null;     // prevent memory leak (apparent circular reference via closure)
                                };
                        }else{
-                               doc.addEventListener('mousedown', mousedownListener, true);
+                               doc.body.addEventListener('mousedown', mousedownListener, true);
                                var focusListener = function(evt){
                                        dijit._onFocusNode(effectiveNode || evt.target);
                                };
@@ -1553,7 +1684,7 @@ dojo.mixin(dijit, {
                                doc.addEventListener('blur', blurListener, true);
 
                                return function(){
-                                       doc.removeEventListener('mousedown', mousedownListener, true);
+                                       doc.body.removeEventListener('mousedown', mousedownListener, true);
                                        doc.removeEventListener('focus', focusListener, true);
                                        doc.removeEventListener('blur', blurListener, true);
                                        doc = null;     // prevent memory leak (apparent circular reference via closure)
@@ -1694,6 +1825,7 @@ dojo.mixin(dijit, {
                        widget = dijit.byId(oldStack[i]);
                        if(widget){
                                widget._focused = false;
+                               widget.set("focused", false);
                                widget._hasBeenBlurred = true;
                                if(widget._onBlur){
                                        widget._onBlur(by);
@@ -1707,6 +1839,7 @@ dojo.mixin(dijit, {
                        widget = dijit.byId(newStack[i]);
                        if(widget){
                                widget._focused = true;
+                               widget.set("focused", true);
                                if(widget._onFocus){
                                        widget._onFocus(by);
                                }
@@ -1733,6 +1866,7 @@ if(!dojo._hasResource["dojo.AdapterRegistry"]){ //_hasResource checks added by b
 dojo._hasResource["dojo.AdapterRegistry"] = true;
 dojo.provide("dojo.AdapterRegistry");
 
+
 dojo.AdapterRegistry = function(/*Boolean?*/ returnWrappers){
        //      summary:
        //              A registry to make contextual calling/searching easier.
@@ -1764,11 +1898,11 @@ dojo.AdapterRegistry = function(/*Boolean?*/ returnWrappers){
 
        this.pairs = [];
        this.returnWrappers = returnWrappers || false; // Boolean
-}
+};
 
 dojo.extend(dojo.AdapterRegistry, {
        register: function(/*String*/ name, /*Function*/ check, /*Function*/ wrap, /*Boolean?*/ directReturn, /*Boolean?*/ override){
-               //      summary: 
+               //      summary:
                //              register a check function to determine if the wrap function or
                //              object gets selected
                //      name:
@@ -1836,7 +1970,6 @@ dojo.provide("dijit._base.place");
 
 
 
-
 dijit.getViewport = function(){
        // summary:
        //              Returns the dimensions and scroll position of the viewable area of a browser window
@@ -1896,16 +2029,22 @@ dijit.placeOnScreen = function(
        return dijit._place(node, choices);
 }
 
-dijit._place = function(/*DomNode*/ node, /* Array */ choices, /* Function */ layoutNode){
+dijit._place = function(/*DomNode*/ node, choices, layoutNode, /*Object*/ aroundNodeCoords){
        // summary:
        //              Given a list of spots to put node, put it at the first spot where it fits,
        //              of if it doesn't fit anywhere then the place with the least overflow
        // choices: Array
        //              Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} }
        //              Above example says to put the top-left corner of the node at (10,20)
-       // layoutNode: Function(node, aroundNodeCorner, nodeCorner)
+       // layoutNode: Function(node, aroundNodeCorner, nodeCorner, size)
        //              for things like tooltip, they are displayed differently (and have different dimensions)
        //              based on their orientation relative to the parent.   This adjusts the popup based on orientation.
+       //              It also passes in the available size for the popup, which is useful for tooltips to
+       //              tell them that their width is limited to a certain amount.   layoutNode() may return a value expressing
+       //              how much the popup had to be modified to fit into the available space.   This is used to determine
+       //              what the best placement is.
+       // aroundNodeCoords: Object
+       //              Size of aroundNode, ex: {w: 200, h: 50}
 
        // get {x: 10, y: 10, w: 100, h:100} type obj representing position of
        // viewport over document
@@ -1922,12 +2061,20 @@ dijit._place = function(/*DomNode*/ node, /* Array */ choices, /* Function */ la
        dojo.some(choices, function(choice){
                var corner = choice.corner;
                var pos = choice.pos;
+               var overflow = 0;
+
+               // calculate amount of space available given specified position of node
+               var spaceAvailable = {
+                       w: corner.charAt(1) == 'L' ? (view.l + view.w) - pos.x : pos.x - view.l,
+                       h: corner.charAt(1) == 'T' ? (view.t + view.h) - pos.y : pos.y - view.t
+               };
 
                // configure node to be displayed in given position relative to button
                // (need to do this in order to get an accurate size for the node, because
-               // a tooltips size changes based on position, due to triangle)
+               // a tooltip's size changes based on position, due to triangle)
                if(layoutNode){
-                       layoutNode(node, choice.aroundCorner, corner);
+                       var res = layoutNode(node, choice.aroundCorner, corner, spaceAvailable, aroundNodeCoords);
+                       overflow = typeof res == "undefined" ? 0 : res;
                }
 
                // get node's size
@@ -1947,8 +2094,9 @@ dijit._place = function(/*DomNode*/ node, /* Array */ choices, /* Function */ la
                        endX = Math.min(view.l + view.w, corner.charAt(1) == 'L' ? (startX + mb.w) : pos.x),
                        endY = Math.min(view.t + view.h, corner.charAt(0) == 'T' ? (startY + mb.h) : pos.y),
                        width = endX - startX,
-                       height = endY - startY,
-                       overflow = (mb.w - width) + (mb.h - height);
+                       height = endY - startY;
+
+               overflow += (mb.w - width) + (mb.h - height);
 
                if(best == null || overflow < best.overflow){
                        best = {
@@ -1958,17 +2106,32 @@ dijit._place = function(/*DomNode*/ node, /* Array */ choices, /* Function */ la
                                y: startY,
                                w: width,
                                h: height,
-                               overflow: overflow
+                               overflow: overflow,
+                               spaceAvailable: spaceAvailable
                        };
                }
+               
                return !overflow;
        });
 
-       node.style.left = best.x + "px";
-       node.style.top = best.y + "px";
+       // In case the best position is not the last one we checked, need to call
+       // layoutNode() again.
        if(best.overflow && layoutNode){
-               layoutNode(node, best.aroundCorner, best.corner);
+               layoutNode(node, best.aroundCorner, best.corner, best.spaceAvailable, aroundNodeCoords);
        }
+
+       // And then position the node.   Do this last, after the layoutNode() above
+       // has sized the node, due to browser quirks when the viewport is scrolled
+       // (specifically that a Tooltip will shrink to fit as though the window was
+       // scrolled to the left).
+       //
+       // In RTL mode, set style.right rather than style.left so in the common case,
+       // window resizes move the popup along with the aroundNode.
+       var l = dojo._isBodyLtr(),
+               s = node.style;
+       s.top = best.y + "px";
+       s[l ? "left" : "right"] = (l ? best.x : view.w - best.x - best.w) + "px";
+       
        return best;
 }
 
@@ -2015,11 +2178,7 @@ dijit.placeOnScreenAroundNode = function(
 
        // get coordinates of aroundNode
        aroundNode = dojo.byId(aroundNode);
-       var oldDisplay = aroundNode.style.display;
-       aroundNode.style.display="";
-       // #3172: use the slightly tighter border box instead of marginBox
        var aroundNodePos = dojo.position(aroundNode, true);
-       aroundNode.style.display=oldDisplay;
 
        // place the node around the calculated rectangle
        return dijit._placeOnScreenAroundRect(node,
@@ -2090,7 +2249,7 @@ dijit._placeOnScreenAroundRect = function(
                });
        }
 
-       return dijit._place(node, choices, layoutNode);
+       return dijit._place(node, choices, layoutNode, {w: width, h: height});
 };
 
 dijit.placementRegistry= new dojo.AdapterRegistry();
@@ -2150,11 +2309,17 @@ dijit.getPopupAroundAlignment = function(/*Array*/ position, /*Boolean*/ leftToR
                        case "before":
                                align[leftToRight ? "BL" : "BR"] = leftToRight ? "BR" : "BL";
                                break;
+                       case "below-alt":
+                               leftToRight = !leftToRight;
+                               // fall through
                        case "below":
                                // first try to align left borders, next try to align right borders (or reverse for RTL mode)
                                align[leftToRight ? "BL" : "BR"] = leftToRight ? "TL" : "TR";
                                align[leftToRight ? "BR" : "BL"] = leftToRight ? "TR" : "TL";
                                break;
+                       case "above-alt":
+                               leftToRight = !leftToRight;
+                               // fall through
                        case "above":
                        default:
                                // first try to align left borders, next try to align right borders (or reverse for RTL mode)
@@ -2259,48 +2424,77 @@ dijit.popup = {
 
        _idGen: 1,
 
-       moveOffScreen: function(/*DomNode*/ node){
+       _createWrapper: function(/*Widget || DomNode*/ widget){
                // summary:
-               //              Initialization for nodes that will be used as popups
-               //
-               // description:
-               //              Puts node inside a wrapper <div>, and
-               //              positions wrapper div off screen, but not display:none, so that
-               //              the widget doesn't appear in the page flow and/or cause a blank
-               //              area at the bottom of the viewport (making scrollbar longer), but
-               //              initialization of contained widgets works correctly
-
-               var wrapper = node.parentNode;
-
-               // Create a wrapper widget for when this node (in the future) will be used as a popup.
-               // This is done early because of IE bugs where creating/moving DOM nodes causes focus
-               // to go wonky, see tests/robot/Toolbar.html to reproduce
-               if(!wrapper || !dojo.hasClass(wrapper, "dijitPopup")){
+               //              Initialization for widgets that will be used as popups.
+               //              Puts widget inside a wrapper DIV (if not already in one),
+               //              and returns pointer to that wrapper DIV.
+
+               var wrapper = widget.declaredClass ? widget._popupWrapper : (widget.parentNode && dojo.hasClass(widget.parentNode, "dijitPopup")),
+                       node = widget.domNode || widget;
+
+               if(!wrapper){
+                       // Create wrapper <div> for when this widget [in the future] will be used as a popup.
+                       // This is done early because of IE bugs where creating/moving DOM nodes causes focus
+                       // to go wonky, see tests/robot/Toolbar.html to reproduce
                        wrapper = dojo.create("div",{
                                "class":"dijitPopup",
-                               style:{
-                                       visibility:"hidden",
-                                       top: "-9999px"
-                               }
+                               style:{ display: "none"},
+                               role: "presentation"
                        }, dojo.body());
-                       dijit.setWaiRole(wrapper, "presentation");
                        wrapper.appendChild(node);
+
+                       var s = node.style;
+                       s.display = "";
+                       s.visibility = "";
+                       s.position = "";
+                       s.top = "0px";
+
+                       if(widget.declaredClass){               // TODO: in 2.0 change signature to always take widget, then remove if()
+                               widget._popupWrapper = wrapper;
+                               dojo.connect(widget, "destroy", function(){
+                                       dojo.destroy(wrapper);
+                                       delete widget._popupWrapper;
+                               });
+                       }
                }
+               
+               return wrapper;
+       },
 
+       moveOffScreen: function(/*Widget || DomNode*/ widget){
+               // summary:
+               //              Moves the popup widget off-screen.
+               //              Do not use this method to hide popups when not in use, because
+               //              that will create an accessibility issue: the offscreen popup is
+               //              still in the tabbing order.
 
-               var s = node.style;
-               s.display = "";
-               s.visibility = "";
-               s.position = "";
-               s.top = "0px";
+               // Create wrapper if not already there
+               var wrapper = this._createWrapper(widget);
 
                dojo.style(wrapper, {
                        visibility: "hidden",
-                       // prevent transient scrollbar causing misalign (#5776), and initial flash in upper left (#10111)
-                       top: "-9999px"
+                       top: "-9999px",         // prevent transient scrollbar causing misalign (#5776), and initial flash in upper left (#10111)
+                       display: ""
                });
        },
 
+       hide: function(/*dijit._Widget*/ widget){
+               // summary:
+               //              Hide this popup widget (until it is ready to be shown).
+               //              Initialization for widgets that will be used as popups
+               //
+               //              Also puts widget inside a wrapper DIV (if not already in one)
+               //
+               //              If popup widget needs to layout it should
+               //              do so when it is made visible, and popup._onShow() is called.
+
+               // Create wrapper if not already there
+               var wrapper = this._createWrapper(widget);
+
+               dojo.style(wrapper, "display", "none");
+       },
+               
        getTopPopup: function(){
                // summary:
                //              Compute the closest ancestor popup that's *not* a child of another popup.
@@ -2337,14 +2531,17 @@ dijit.popup = {
                        around = args.around,
                        id = (args.around && args.around.id) ? (args.around.id+"_dropdown") : ("popup_"+this._idGen++);
 
-
-               // The wrapper may have already been created, but in case it wasn't, create here
-               var wrapper = widget.domNode.parentNode;
-               if(!wrapper || !dojo.hasClass(wrapper, "dijitPopup")){
-                       this.moveOffScreen(widget.domNode);
-                       wrapper = widget.domNode.parentNode;
+               // If we are opening a new popup that isn't a child of a currently opened popup, then
+               // close currently opened popup(s).   This should happen automatically when the old popups
+               // gets the _onBlur() event, except that the _onBlur() event isn't reliable on IE, see [22198].
+               while(stack.length && (!args.parent || !dojo.isDescendant(args.parent.domNode, stack[stack.length-1].widget.domNode))){
+                       dijit.popup.close(stack[stack.length-1].widget);
                }
 
+               // Get pointer to popup wrapper, and create wrapper if it doesn't exist
+               var wrapper = this._createWrapper(widget);
+
+
                dojo.attr(wrapper, {
                        id: id,
                        style: {
@@ -2355,9 +2552,9 @@ dijit.popup = {
                });
 
                if(dojo.isIE || dojo.isMoz){
-                       var iframe = wrapper.childNodes[1];
-                       if(!iframe){
-                               iframe = new dijit.BackgroundIframe(wrapper);
+                       if(!widget.bgIframe){
+                               // setting widget.bgIframe triggers cleanup in _Widget.destroy()
+                               widget.bgIframe = new dijit.BackgroundIframe(wrapper);
                        }
                }
 
@@ -2366,6 +2563,7 @@ dijit.popup = {
                        dijit.placeOnScreenAroundElement(wrapper, around, orient, widget.orient ? dojo.hitch(widget, "orient") : null) :
                        dijit.placeOnScreen(wrapper, args, orient == 'R' ? ['TR','BR','TL','BL'] : ['TL','BL','TR','BR'], args.padding);
 
+               wrapper.style.display = "";
                wrapper.style.visibility = "visible";
                widget.domNode.style.visibility = "visible";    // counteract effects from _HasDropDown
 
@@ -2400,8 +2598,6 @@ dijit.popup = {
                }));
 
                stack.push({
-                       wrapper: wrapper,
-                       iframe: iframe,
                        widget: widget,
                        parent: args.parent,
                        onExecute: args.onExecute,
@@ -2418,9 +2614,10 @@ dijit.popup = {
                return best;
        },
 
-       close: function(/*dijit._Widget*/ popup){
+       close: function(/*dijit._Widget?*/ popup){
                // summary:
-               //              Close specified popup and any popups that it parented
+               //              Close specified popup and any popups that it parented.
+               //              If no popup is specified, closes all popups.
 
                var stack = this._stack;
 
@@ -2429,10 +2626,9 @@ dijit.popup = {
                // a popup would cause others to close too.  Thus if we are trying to close B in [A,B,C]
                // closing C might close B indirectly and then the while() condition will run where stack==[A]...
                // so the while condition is constructed defensively.
-               while(dojo.some(stack, function(elem){return elem.widget == popup;})){
+               while((popup && dojo.some(stack, function(elem){return elem.widget == popup;})) ||
+                       (!popup && stack.length)){
                        var top = stack.pop(),
-                               wrapper = top.wrapper,
-                               iframe = top.iframe,
                                widget = top.widget,
                                onClose = top.onClose;
 
@@ -2442,11 +2638,9 @@ dijit.popup = {
                        }
                        dojo.forEach(top.handlers, dojo.disconnect);
 
-                       // Move the widget plus it's wrapper off screen, unless it has already been destroyed in above onClose() etc.
+                       // Hide the widget and it's wrapper unless it has already been destroyed in above onClose() etc.
                        if(widget && widget.domNode){
-                               this.moveOffScreen(widget.domNode);
-                       }else{
-                               dojo.destroy(wrapper);
+                               this.hide(widget);
                        }
                         
                        if(onClose){
@@ -2456,9 +2650,12 @@ dijit.popup = {
        }
 };
 
+// TODO: remove dijit._frames, it isn't being used much, since popups never release their
+// iframes (see [22236])
 dijit._frames = new function(){
        // summary:
        //              cache of iframes
+
        var queue = [];
 
        this.pop = function(){
@@ -2467,7 +2664,7 @@ dijit._frames = new function(){
                        iframe = queue.pop();
                        iframe.style.display="";
                }else{
-                       if(dojo.isIE){
+                       if(dojo.isIE < 9){
                                var burl = dojo.config["dojoBlankHtmlUrl"] || (dojo.moduleUrl("dojo", "resources/blank.html")+"") || "javascript:\"\"";
                                var html="<iframe src='" + burl + "'"
                                        + " style='position: absolute; left: 0px; top: 0px;"
@@ -2479,7 +2676,7 @@ dijit._frames = new function(){
                                iframe.className = "dijitBackgroundIframe";
                                dojo.style(iframe, "opacity", 0.1);
                        }
-                       iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didnt work.
+                       iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didn't work.
                        dijit.setWaiRole(iframe,"presentation");
                }
                return iframe;
@@ -2492,7 +2689,7 @@ dijit._frames = new function(){
 }();
 
 
-dijit.BackgroundIframe = function(/* DomNode */node){
+dijit.BackgroundIframe = function(/*DomNode*/ node){
        // summary:
        //              For IE/FF z-index schenanigans. id attribute is required.
        //
@@ -2503,9 +2700,9 @@ dijit.BackgroundIframe = function(/* DomNode */node){
 
        if(!node.id){ throw new Error("no id"); }
        if(dojo.isIE || dojo.isMoz){
-               var iframe = dijit._frames.pop();
+               var iframe = (this.iframe = dijit._frames.pop());
                node.appendChild(iframe);
-               if(dojo.isIE<7){
+               if(dojo.isIE<7 || dojo.isQuirks){
                        this.resize(node);
                        this._conn = dojo.connect(node, 'onresize', this, function(){
                                this.resize(node);
@@ -2516,19 +2713,15 @@ dijit.BackgroundIframe = function(/* DomNode */node){
                                height: '100%'
                        });
                }
-               this.iframe = iframe;
        }
 };
 
 dojo.extend(dijit.BackgroundIframe, {
        resize: function(node){
                // summary:
-               //              resize the iframe so its the same size as node
-               // description:
-               //              this function is a no-op in all browsers except
-               //              IE6, which does not support 100% width/height 
-               //              of absolute positioned iframes
-               if(this.iframe && dojo.isIE<7){
+               //              Resize the iframe so it's the same size as node.
+               //              Needed on IE6 and IE/quirks because height:100% doesn't work right.
+               if(this.iframe){
                        dojo.style(this.iframe, {
                                width: node.offsetWidth + 'px',
                                height: node.offsetHeight + 'px'
@@ -2571,6 +2764,7 @@ if(!dojo._hasResource["dojo.uacss"]){ //_hasResource checks added by build. Do n
 dojo._hasResource["dojo.uacss"] = true;
 dojo.provide("dojo.uacss");
 
+
 (function(){
        // summary:
        //              Applies pre-set CSS classes to the top-level HTML node, based on:
@@ -2595,6 +2789,7 @@ dojo.provide("dojo.uacss");
                        dj_ie6: maj(ie) == 6,
                        dj_ie7: maj(ie) == 7,
                        dj_ie8: maj(ie) == 8,
+                       dj_ie9: maj(ie) == 9,
                        dj_quirks: d.isQuirks,
                        dj_iequirks: ie && d.isQuirks,
 
@@ -2623,7 +2818,7 @@ dojo.provide("dojo.uacss");
        html.className = d.trim(html.className + " " + classStr);
 
        // If RTL mode, then add dj_rtl flag plus repeat existing classes with -rtl extension.
-       // We can't run the code below until the <body> tag has loaded (so we can check for dir=rtl).  
+       // We can't run the code below until the <body> tag has loaded (so we can check for dir=rtl).
        // Unshift() is to run sniff code before the parser.
        dojo._loaders.unshift(function(){
                if(!dojo._isBodyLtr()){
@@ -2637,6 +2832,10 @@ dojo.provide("dojo.uacss");
 
 if(!dojo._hasResource["dijit._base.sniff"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
 dojo._hasResource["dijit._base.sniff"] = true;
+dojo.provide("dijit._base.sniff");
+
+
+
 // summary:
 //             Applies pre-set CSS classes to the top-level HTML node, see
 //             `dojo.uacss` for details.
@@ -2644,16 +2843,13 @@ dojo._hasResource["dijit._base.sniff"] = true;
 //             Simply doing a require on this module will
 //             establish this CSS.  Modified version of Morris' CSS hack.
 
-dojo.provide("dijit._base.sniff");
-
-
-
 }
 
 if(!dojo._hasResource["dijit._base.typematic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
 dojo._hasResource["dijit._base.typematic"] = true;
 dojo.provide("dijit._base.typematic");
 
+
 dijit.typematic = {
        // summary:
        //              These functions are used to repetitively call a user specified callback
@@ -2838,6 +3034,7 @@ if(!dojo._hasResource["dijit._base.wai"]){ //_hasResource checks added by build.
 dojo._hasResource["dijit._base.wai"] = true;
 dojo.provide("dijit._base.wai");
 
+
 dijit.wai = {
        onload: function(){
                // summary:
@@ -2883,26 +3080,24 @@ if(dojo.isIE || dojo.isMoz){    // NOTE: checking in Safari messes things up
 }
 
 dojo.mixin(dijit, {
-       _XhtmlRoles: /banner|contentinfo|definition|main|navigation|search|note|secondary|seealso/,
-
-       hasWaiRole: function(/*Element*/ elem, /*String*/ role){
+       hasWaiRole: function(/*Element*/ elem, /*String?*/ role){
                // summary:
-               //              Determines if an element has a particular non-XHTML role.
+               //              Determines if an element has a particular role.
                // returns:
-               //              True if elem has the specific non-XHTML role attribute and false if not.
+               //              True if elem has the specific role attribute and false if not.
                //              For backwards compatibility if role parameter not provided,
-               //              returns true if has non XHTML role
+               //              returns true if has a role
                var waiRole = this.getWaiRole(elem);
                return role ? (waiRole.indexOf(role) > -1) : (waiRole.length > 0);
        },
 
        getWaiRole: function(/*Element*/ elem){
                // summary:
-               //              Gets the non-XHTML role for an element (which should be a wai role).
+               //              Gets the role for an element (which should be a wai role).
                // returns:
-               //              The non-XHTML role of elem or an empty string if elem
+               //              The role of elem or an empty string if elem
                //              does not have a role.
-                return dojo.trim((dojo.attr(elem, "role") || "").replace(this._XhtmlRoles,"").replace("wairole:",""));
+                return dojo.trim((dojo.attr(elem, "role") || "").replace("wairole:",""));
        },
 
        setWaiRole: function(/*Element*/ elem, /*String*/ role){
@@ -2910,24 +3105,13 @@ dojo.mixin(dijit, {
                //              Sets the role on an element.
                // description:
                //              Replace existing role attribute with new role.
-               //              If elem already has an XHTML role, append this role to XHTML role
-               //              and remove other ARIA roles.
 
-               var curRole = dojo.attr(elem, "role") || "";
-               if(!this._XhtmlRoles.test(curRole)){
                        dojo.attr(elem, "role", role);
-               }else{
-                       if((" "+ curRole +" ").indexOf(" " + role + " ") < 0){
-                               var clearXhtml = dojo.trim(curRole.replace(this._XhtmlRoles, ""));
-                               var cleanRole = dojo.trim(curRole.replace(clearXhtml, ""));
-                               dojo.attr(elem, "role", cleanRole + (cleanRole ? ' ' : '') + role);
-                       }
-               }
        },
 
        removeWaiRole: function(/*Element*/ elem, /*String*/ role){
                // summary:
-               //              Removes the specified non-XHTML role from an element.
+               //              Removes the specified role from an element.
                //              Removes role attribute if no specific role provided (for backwards compat.)
 
                var roleValue = dojo.attr(elem, "role");
@@ -2999,73 +3183,157 @@ dojo.provide("dijit._base");
 
 
 
-}
 
-if(!dojo._hasResource["dijit._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dijit._Widget"] = true;
-dojo.provide("dijit._Widget");
+}
 
-dojo.require( "dijit._base" );
+if(!dojo._hasResource["dojo.Stateful"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.Stateful"] = true;
+dojo.provide("dojo.Stateful");
 
 
-// This code is to assist deferring dojo.connect() calls in widgets (connecting to events on the widgets'
-// DOM nodes) until someone actually needs to monitor that event.
-dojo.connect(dojo, "_connect",
-       function(/*dijit._Widget*/ widget, /*String*/ event){
-               if(widget && dojo.isFunction(widget._onConnect)){
-                       widget._onConnect(event);
+dojo.declare("dojo.Stateful", null, {
+       // summary:
+       //              Base class for objects that provide named properties with optional getter/setter
+       //              control and the ability to watch for property changes
+       // example:
+       //      |       var obj = new dojo.Stateful();
+       //      |       obj.watch("foo", function(){
+       //      |               console.log("foo changed to " + this.get("foo"));
+       //      |       });
+       //      |       obj.set("foo","bar");
+       postscript: function(mixin){
+               if(mixin){
+                       dojo.mixin(this, mixin);
                }
-       });
-
-dijit._connectOnUseEventHandler = function(/*Event*/ event){};
-
-// Keep track of where the last keydown event was, to help avoid generating
-// spurious ondijitclick events when:
-// 1. focus is on a <button> or <a>
-// 2. user presses then releases the ENTER key
-// 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler
-// 4. onkeyup event fires, causing the ondijitclick handler to fire
-dijit._lastKeyDownNode = null;
-if(dojo.isIE){
-       (function(){
-               var keydownCallback = function(evt){
-                       dijit._lastKeyDownNode = evt.srcElement;
+       },
+       
+       get: function(/*String*/name){
+               // summary:
+               //              Get a property on a Stateful instance.
+               //      name:
+               //              The property to get.
+               // description:
+               //              Get a named property on a Stateful object. The property may
+               //              potentially be retrieved via a getter method in subclasses. In the base class
+               //              this just retrieves the object's property.
+               //              For example:
+               //      |       stateful = new dojo.Stateful({foo: 3});
+               //      |       stateful.get("foo") // returns 3
+               //      |       stateful.foo // returns 3
+               
+               return this[name];
+       },
+       set: function(/*String*/name, /*Object*/value){
+               // summary:
+               //              Set a property on a Stateful instance
+               //      name:
+               //              The property to set.
+               //      value:
+               //              The value to set in the property.
+               // description:
+               //              Sets named properties on a stateful object and notifies any watchers of
+               //              the property. A programmatic setter may be defined in subclasses.
+               //              For example:
+               //      |       stateful = new dojo.Stateful();
+               //      |       stateful.watch(function(name, oldValue, value){
+               //      |               // this will be called on the set below
+               //      |       }
+               //      |       stateful.set(foo, 5);
+               //
+               //      set() may also be called with a hash of name/value pairs, ex:
+               //      |       myObj.set({
+               //      |               foo: "Howdy",
+               //      |               bar: 3
+               //      |       })
+               //      This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
+               if(typeof name === "object"){
+                       for(var x in name){
+                               this.set(x, name[x]);
+                       }
+                       return this;
+               }
+               var oldValue = this[name];
+               this[name] = value;
+               if(this._watchCallbacks){
+                       this._watchCallbacks(name, oldValue, value);
+               }
+               return this;
+       },
+       watch: function(/*String?*/name, /*Function*/callback){
+               // summary:
+               //              Watches a property for changes
+               //      name:
+               //              Indicates the property to watch. This is optional (the callback may be the
+               //              only parameter), and if omitted, all the properties will be watched
+               // returns:
+               //              An object handle for the watch. The unwatch method of this object
+               //              can be used to discontinue watching this property:
+               //              |       var watchHandle = obj.watch("foo", callback);
+               //              |       watchHandle.unwatch(); // callback won't be called now
+               //      callback:
+               //              The function to execute when the property changes. This will be called after
+               //              the property has been changed. The callback will be called with the |this|
+               //              set to the instance, the first argument as the name of the property, the
+               //              second argument as the old value and the third argument as the new value.
+               
+               var callbacks = this._watchCallbacks;
+               if(!callbacks){
+                       var self = this;
+                       callbacks = this._watchCallbacks = function(name, oldValue, value, ignoreCatchall){
+                               var notify = function(propertyCallbacks){
+                                       if(propertyCallbacks){
+                        propertyCallbacks = propertyCallbacks.slice();
+                                               for(var i = 0, l = propertyCallbacks.length; i < l; i++){
+                                                       try{
+                                                               propertyCallbacks[i].call(self, name, oldValue, value);
+                                                       }catch(e){
+                                                               console.error(e);
+                                                       }
+                                               }
+                                       }
+                               };
+                               notify(callbacks['_' + name]);
+                               if(!ignoreCatchall){
+                                       notify(callbacks["*"]); // the catch-all
+                               }
+                       }; // we use a function instead of an object so it will be ignored by JSON conversion
+               }
+               if(!callback && typeof name === "function"){
+                       callback = name;
+                       name = "*";
+               }else{
+                       // prepend with dash to prevent name conflicts with function (like "name" property)
+                       name = '_' + name;
+               }
+               var propertyCallbacks = callbacks[name];
+               if(typeof propertyCallbacks !== "object"){
+                       propertyCallbacks = callbacks[name] = [];
+               }
+               propertyCallbacks.push(callback);
+               return {
+                       unwatch: function(){
+                               propertyCallbacks.splice(dojo.indexOf(propertyCallbacks, callback), 1);
+                       }
                };
-               dojo.doc.attachEvent('onkeydown', keydownCallback);
-               dojo.addOnWindowUnload(function(){
-                       dojo.doc.detachEvent('onkeydown', keydownCallback);
-               });
-       })();
-}else{
-       dojo.doc.addEventListener('keydown', function(evt){
-               dijit._lastKeyDownNode = evt.target;
-       }, true);
+       }
+       
+});
+
 }
 
-(function(){
+if(!dojo._hasResource["dijit._WidgetBase"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._WidgetBase"] = true;
+dojo.provide("dijit._WidgetBase");
+
+
 
-var _attrReg = {},     // cached results from getSetterAttributes
-       getSetterAttributes = function(widget){
-               // summary:
-               //              Returns list of attributes with custom setters for specified widget
-               var dc = widget.declaredClass;
-               if(!_attrReg[dc]){
-                       var r = [],
-                               attrs,
-                               proto = widget.constructor.prototype;
-                       for(var fxName in proto){
-                               if(dojo.isFunction(proto[fxName]) && (attrs = fxName.match(/^_set([a-zA-Z]*)Attr$/)) && attrs[1]){
-                                       r.push(attrs[1].charAt(0).toLowerCase() + attrs[1].substr(1));
-                               }
-                       }
-                       _attrReg[dc] = r;
-               }
-               return _attrReg[dc] || [];      // String[]
-       };
 
-dojo.declare("dijit._Widget", null, {
+(function(){
+
+dojo.declare("dijit._WidgetBase", dojo.Stateful, {
        // summary:
-       //              Base class for all Dijit widgets.
+       //              Future base class for all Dijit widgets.
+       //              _Widget extends this class adding support for various features needed by desktop.
 
        // id: [const] String
        //              A unique, opaque ID string that can be assigned by users or by the
@@ -3163,7 +3431,7 @@ dojo.declare("dijit._Widget", null, {
        //              Changes to widget attributes listed in attributeMap will be
        //              reflected into the DOM.
        //
-       //              For example, calling attr('title', 'hello')
+       //              For example, calling set('title', 'hello')
        //              on a TitlePane will automatically cause the TitlePane's DOM to update
        //              with the new title.
        //
@@ -3195,166 +3463,14 @@ dojo.declare("dijit._Widget", null, {
        //              - "" --> { node: "domNode", type: "attribute" }
        attributeMap: {id:"", dir:"", lang:"", "class":"", style:"", title:""},
 
-       // _deferredConnects: [protected] Object
-       //              attributeMap addendum for event handlers that should be connected only on first use
-       _deferredConnects: {
-               onClick: "",
-               onDblClick: "",
-               onKeyDown: "",
-               onKeyPress: "",
-               onKeyUp: "",
-               onMouseMove: "",
-               onMouseDown: "",
-               onMouseOut: "",
-               onMouseOver: "",
-               onMouseLeave: "",
-               onMouseEnter: "",
-               onMouseUp: ""
-       },
+       // _blankGif: [protected] String
+       //              Path to a blank 1x1 image.
+       //              Used by <img> nodes in templates that really get their image via CSS background-image.
+       _blankGif: (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")).toString(),
 
-       onClick: dijit._connectOnUseEventHandler,
-       /*=====
-       onClick: function(event){
-               // summary:
-               //              Connect to this function to receive notifications of mouse click events.
-               // event:
-               //              mouse Event
-               // tags:
-               //              callback
-       },
-       =====*/
-       onDblClick: dijit._connectOnUseEventHandler,
-       /*=====
-       onDblClick: function(event){
-               // summary:
-               //              Connect to this function to receive notifications of mouse double click events.
-               // event:
-               //              mouse Event
-               // tags:
-               //              callback
-       },
-       =====*/
-       onKeyDown: dijit._connectOnUseEventHandler,
-       /*=====
-       onKeyDown: function(event){
-               // summary:
-               //              Connect to this function to receive notifications of keys being pressed down.
-               // event:
-               //              key Event
-               // tags:
-               //              callback
-       },
-       =====*/
-       onKeyPress: dijit._connectOnUseEventHandler,
-       /*=====
-       onKeyPress: function(event){
-               // summary:
-               //              Connect to this function to receive notifications of printable keys being typed.
-               // event:
-               //              key Event
-               // tags:
-               //              callback
-       },
-       =====*/
-       onKeyUp: dijit._connectOnUseEventHandler,
-       /*=====
-       onKeyUp: function(event){
-               // summary:
-               //              Connect to this function to receive notifications of keys being released.
-               // event:
-               //              key Event
-               // tags:
-               //              callback
-       },
-       =====*/
-       onMouseDown: dijit._connectOnUseEventHandler,
-       /*=====
-       onMouseDown: function(event){
-               // summary:
-               //              Connect to this function to receive notifications of when the mouse button is pressed down.
-               // event:
-               //              mouse Event
-               // tags:
-               //              callback
-       },
-       =====*/
-       onMouseMove: dijit._connectOnUseEventHandler,
-       /*=====
-       onMouseMove: function(event){
-               // summary:
-               //              Connect to this function to receive notifications of when the mouse moves over nodes contained within this widget.
-               // event:
-               //              mouse Event
-               // tags:
-               //              callback
-       },
-       =====*/
-       onMouseOut: dijit._connectOnUseEventHandler,
-       /*=====
-       onMouseOut: function(event){
-               // summary:
-               //              Connect to this function to receive notifications of when the mouse moves off of nodes contained within this widget.
-               // event:
-               //              mouse Event
-               // tags:
-               //              callback
-       },
-       =====*/
-       onMouseOver: dijit._connectOnUseEventHandler,
-       /*=====
-       onMouseOver: function(event){
-               // summary:
-               //              Connect to this function to receive notifications of when the mouse moves onto nodes contained within this widget.
-               // event:
-               //              mouse Event
-               // tags:
-               //              callback
-       },
-       =====*/
-       onMouseLeave: dijit._connectOnUseEventHandler,
-       /*=====
-       onMouseLeave: function(event){
-               // summary:
-               //              Connect to this function to receive notifications of when the mouse moves off of this widget.
-               // event:
-               //              mouse Event
-               // tags:
-               //              callback
-       },
-       =====*/
-       onMouseEnter: dijit._connectOnUseEventHandler,
-       /*=====
-       onMouseEnter: function(event){
-               // summary:
-               //              Connect to this function to receive notifications of when the mouse moves onto this widget.
-               // event:
-               //              mouse Event
-               // tags:
-               //              callback
-       },
-       =====*/
-       onMouseUp: dijit._connectOnUseEventHandler,
-       /*=====
-       onMouseUp: function(event){
-               // summary:
-               //              Connect to this function to receive notifications of when the mouse button is released.
-               // event:
-               //              mouse Event
-               // tags:
-               //              callback
-       },
-       =====*/
-
-       // Constants used in templates
-
-       // _blankGif: [protected] String
-       //              Path to a blank 1x1 image.
-       //              Used by <img> nodes in templates that really get their image via CSS background-image.
-       _blankGif: (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")).toString(),
-
-       //////////// INITIALIZATION METHODS ///////////////////////////////////////
-
-       postscript: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){
+       //////////// INITIALIZATION METHODS ///////////////////////////////////////
+
+       postscript: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){
                // summary:
                //              Kicks off widget instantiation.  See create() for details.
                // tags:
@@ -3397,25 +3513,11 @@ dojo.declare("dijit._Widget", null, {
                // The handle returned from Widget.subscribe() is the handle returned from dojo.subscribe()
                this._subscribes = [];
 
-               // To avoid double-connects, remove entries from _deferredConnects
-               // that have been setup manually by a subclass (ex, by dojoAttachEvent).
-               // If a subclass has redefined a callback (ex: onClick) then assume it's being
-               // connected to manually.
-               this._deferredConnects = dojo.clone(this._deferredConnects);
-               for(var attr in this.attributeMap){
-                       delete this._deferredConnects[attr]; // can't be in both attributeMap and _deferredConnects
-               }
-               for(attr in this._deferredConnects){
-                       if(this[attr] !== dijit._connectOnUseEventHandler){
-                               delete this._deferredConnects[attr];    // redefined, probably dojoAttachEvent exists
-                       }
-               }
-
-               //mixin our passed parameters
+               // mix in our passed parameters
                if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; }
                if(params){
                        this.params = params;
-                       dojo.mixin(this,params);
+                       dojo._mixin(this, params);
                }
                this.postMixInProperties();
 
@@ -3431,22 +3533,22 @@ dojo.declare("dijit._Widget", null, {
 
                if(this.domNode){
                        // Copy attributes listed in attributeMap into the [newly created] DOM for the widget.
+                       // Also calls custom setters for all attributes with custom setters.
                        this._applyAttributes();
 
+                       // If srcNodeRef was specified, then swap out original srcNode for this widget's DOM tree.
+                       // For 2.0, move this after postCreate().  postCreate() shouldn't depend on the
+                       // widget being attached to the DOM since it isn't when a widget is created programmatically like
+                       // new MyWidget({}).   See #11635.
                        var source = this.srcNodeRef;
-                       if(source && source.parentNode){
+                       if(source && source.parentNode && this.domNode !== source){
                                source.parentNode.replaceChild(this.domNode, source);
                        }
-
-                       // If the developer has specified a handler as a widget parameter
-                       // (ex: new Button({onClick: ...})
-                       // then naturally need to connect from DOM node to that handler immediately,
-                       for(attr in this.params){
-                               this._onConnect(attr);
-                       }
                }
 
                if(this.domNode){
+                       // Note: for 2.0 may want to rename widgetId to dojo._scopeName + "_widgetId",
+                       // assuming that dojo._scopeName even exists in 2.0
                        this.domNode.setAttribute("widgetId", this.id);
                }
                this.postCreate();
@@ -3485,13 +3587,30 @@ dojo.declare("dijit._Widget", null, {
                }
 
                // And also any attributes with custom setters
-               dojo.forEach(getSetterAttributes(this), function(a){
+               dojo.forEach(this._getSetterAttributes(), function(a){
                        if(!(a in this.attributeMap)){
                                condAttrApply(a, this);
                        }
                }, this);
        },
 
+       _getSetterAttributes: function(){
+               // summary:
+               //              Returns list of attributes with custom setters for this widget
+               var ctor = this.constructor;
+               if(!ctor._setterAttrs){
+                       var r = (ctor._setterAttrs = []),
+                               attrs,
+                               proto = ctor.prototype;
+                       for(var fxName in proto){
+                               if(dojo.isFunction(proto[fxName]) && (attrs = fxName.match(/^_set([a-zA-Z]*)Attr$/)) && attrs[1]){
+                                       r.push(attrs[1].charAt(0).toLowerCase() + attrs[1].substr(1));
+                               }
+                       }
+               }
+               return ctor._setterAttrs;       // String[]
+       },
+
        postMixInProperties: function(){
                // summary:
                //              Called after the parameters to the widget have been read-in,
@@ -3510,7 +3629,22 @@ dojo.declare("dijit._Widget", null, {
                //              method.
                // tags:
                //              protected
-               this.domNode = this.srcNodeRef || dojo.create('div');
+
+               if(!this.domNode){
+                       // Create root node if it wasn't created by _Templated
+                       this.domNode = this.srcNodeRef || dojo.create('div');
+               }
+
+               // baseClass is a single class name or occasionally a space-separated list of names.
+               // Add those classes to the DOMNode.  If RTL mode then also add with Rtl suffix.
+               // TODO: make baseClass custom setter
+               if(this.baseClass){
+                       var classes = this.baseClass.split(" ");
+                       if(!this.isLeftToRight()){
+                               classes = classes.concat( dojo.map(classes, function(name){ return name+"Rtl"; }));
+                       }
+                       dojo.addClass(this.domNode, classes);
+               }
        },
 
        postCreate: function(){
@@ -3522,16 +3656,6 @@ dojo.declare("dijit._Widget", null, {
                //              node dimensions or placement.
                // tags:
                //              protected
-
-               // baseClass is a single class name or occasionally a space-separated list of names.
-               // Add those classes to the DOMNod.  If RTL mode then also add with Rtl suffix.         
-               if(this.baseClass){
-                       var classes = this.baseClass.split(" ");
-                       if(!this.isLeftToRight()){
-                               classes = classes.concat( dojo.map(classes, function(name){ return name+"Rtl"; }));
-                       }
-                       dojo.addClass(this.domNode, classes);
-               }
        },
 
        startup: function(){
@@ -3647,7 +3771,6 @@ dojo.declare("dijit._Widget", null, {
                });
        },
 
-
        uninitialize: function(){
                // summary:
                //              Stub function. Override to implement custom widget tear-down
@@ -3657,60 +3780,7 @@ dojo.declare("dijit._Widget", null, {
                return false;
        },
 
-       ////////////////// MISCELLANEOUS METHODS ///////////////////
-
-       onFocus: function(){
-               // summary:
-               //              Called when the widget becomes "active" because
-               //              it or a widget inside of it either has focus, or has recently
-               //              been clicked.
-               // tags:
-               //              callback
-       },
-
-       onBlur: function(){
-               // summary:
-               //              Called when the widget stops being "active" because
-               //              focus moved to something outside of it, or the user
-               //              clicked somewhere outside of it, or the widget was
-               //              hidden.
-               // tags:
-               //              callback
-       },
-
-       _onFocus: function(e){
-               // summary:
-               //              This is where widgets do processing for when they are active,
-               //              such as changing CSS classes.  See onFocus() for more details.
-               // tags:
-               //              protected
-               this.onFocus();
-       },
-
-       _onBlur: function(){
-               // summary:
-               //              This is where widgets do processing for when they stop being active,
-               //              such as changing CSS classes.  See onBlur() for more details.
-               // tags:
-               //              protected
-               this.onBlur();
-       },
-
-       _onConnect: function(/*String*/ event){
-               // summary:
-               //              Called when someone connects to one of my handlers.
-               //              "Turn on" that handler if it isn't active yet.
-               //
-               //              This is also called for every single initialization parameter
-               //              so need to do nothing for parameters like "id".
-               // tags:
-               //              private
-               if(event in this._deferredConnects){
-                       var mapNode = this[this._deferredConnects[event] || 'domNode'];
-                       this.connect(mapNode, event.toLowerCase(), event);
-                       delete this._deferredConnects[event];
-               }
-       },
+       ////////////////// GET/SET, CUSTOM SETTERS, ETC. ///////////////////
 
        _setClassAttr: function(/*String*/ value){
                // summary:
@@ -3718,14 +3788,13 @@ dojo.declare("dijit._Widget", null, {
                // tags:
                //              protected
                var mapNode = this[this.attributeMap["class"] || 'domNode'];
-               dojo.removeClass(mapNode, this["class"])
-               this["class"] = value;
-               dojo.addClass(mapNode, value);
+               dojo.replaceClass(mapNode, value, this["class"]);
+               this._set("class", value);
        },
 
        _setStyleAttr: function(/*String||Object*/ value){
                // summary:
-               //              Sets the style attribut of the widget according to value,
+               //              Sets the style attribute of the widget according to value,
                //              which is either a hash like {height: "5px", width: "3px"}
                //              or a plain string
                // description:
@@ -3749,25 +3818,13 @@ dojo.declare("dijit._Widget", null, {
                        }
                }
 
-               this.style = value;
-       },
-
-       setAttribute: function(/*String*/ attr, /*anything*/ value){
-               // summary:
-               //              Deprecated.  Use set() instead.
-               // tags:
-               //              deprecated
-               dojo.deprecated(this.declaredClass+"::setAttribute(attr, value) is deprecated. Use set() instead.", "", "2.0");
-               this.set(attr, value);
+               this._set("style", value);
        },
 
        _attrToDom: function(/*String*/ attr, /*String*/ value){
                // summary:
                //              Reflect a widget attribute (title, tabIndex, duration etc.) to
                //              the widget DOM, as specified in attributeMap.
-               //
-               // description:
-               //              Also sets this["attr"] to the new value.
                //              Note some attributes like "type"
                //              cannot be processed this way as they are not mutable.
                //
@@ -3803,47 +3860,13 @@ dojo.declare("dijit._Widget", null, {
                                        mapNode.innerHTML = value;
                                        break;
                                case "class":
-                                       dojo.removeClass(mapNode, this[attr]);
-                                       dojo.addClass(mapNode, value);
+                                       dojo.replaceClass(mapNode, value, this[attr]);
                                        break;
                        }
                }, this);
-               this[attr] = value;
        },
 
-       attr: function(/*String|Object*/name, /*Object?*/value){
-               // summary:
-               //              Set or get properties on a widget instance.
-               //      name:
-               //              The property to get or set. If an object is passed here and not
-               //              a string, its keys are used as names of attributes to be set
-               //              and the value of the object as values to set in the widget.
-               //      value:
-               //              Optional. If provided, attr() operates as a setter. If omitted,
-               //              the current value of the named property is returned.
-               // description:
-               //              This method is deprecated, use get() or set() directly.
-
-               // Print deprecation warning but only once per calling function
-               if(dojo.config.isDebug){
-                       var alreadyCalledHash = arguments.callee._ach || (arguments.callee._ach = {}),
-                               caller = (arguments.callee.caller || "unknown caller").toString();
-                       if(!alreadyCalledHash[caller]){
-                               dojo.deprecated(this.declaredClass + "::attr() is deprecated. Use get() or set() instead, called from " +
-                               caller, "", "2.0");
-                               alreadyCalledHash[caller] = true;
-                       }
-               }
-
-               var args = arguments.length;
-               if(args >= 2 || typeof name === "object"){ // setter
-                       return this.set.apply(this, arguments);
-               }else{ // getter
-                       return this.get(name);
-               }
-       },
-       
-       get: function(name){
+       get: function(name){
                // summary:
                //              Get a property from a widget.
                //      name:
@@ -3851,7 +3874,7 @@ dojo.declare("dijit._Widget", null, {
                // description:
                //              Get a named property from a widget. The property may
                //              potentially be retrieved via a getter method. If no getter is defined, this
-               //              just retrieves the object's property.  
+               //              just retrieves the object's property.
                //              For example, if the widget has a properties "foo"
                //              and "bar" and a method named "_getFooAttr", calling:
                //      |       myWidget.get("foo");
@@ -3869,11 +3892,11 @@ dojo.declare("dijit._Widget", null, {
                // summary:
                //              Set a property on a widget
                //      name:
-               //              The property to set. 
+               //              The property to set.
                //      value:
                //              The value to set in the property.
                // description:
-               //              Sets named properties on a widget which may potentially be handled by a 
+               //              Sets named properties on a widget which may potentially be handled by a
                //              setter in the widget.
                //              For example, if the widget has a properties "foo"
                //              and "bar" and a method named "_setFooAttr", calling:
@@ -3894,7 +3917,7 @@ dojo.declare("dijit._Widget", null, {
 
                if(typeof name === "object"){
                        for(var x in name){
-                               this.set(x, name[x]); 
+                               this.set(x, name[x]);
                        }
                        return this;
                }
@@ -3907,9 +3930,7 @@ dojo.declare("dijit._Widget", null, {
                        if(name in this.attributeMap){
                                this._attrToDom(name, value);
                        }
-                       var oldValue = this[name];
-                       // FIXME: what about function assignments? Any way to connect() here?
-                       this[name] = value;
+                       this._set(name, value);
                }
                return result || this;
        },
@@ -3932,6 +3953,17 @@ dojo.declare("dijit._Widget", null, {
                });
        },
 
+       _set: function(/*String*/ name, /*anything*/ value){
+               // summary:
+               //              Helper function to set new value for specified attribute, and call handlers
+               //              registered with watch() if the value has changed.
+               var oldValue = this[name];
+               this[name] = value;
+               if(this._watchCallbacks && this._created && value !== oldValue){
+                       this._watchCallbacks(name, oldValue, value);
+               }
+       },
+
        toString: function(){
                // summary:
                //              Returns a string that represents the widget
@@ -3958,11 +3990,6 @@ dojo.declare("dijit._Widget", null, {
                return this.containerNode ? dijit.findWidgets(this.containerNode) : []; // dijit._Widget[]
        },
 
-       // nodesWithKeyClick: [private] String[]
-       //              List of nodes that correctly handle click events via native browser support,
-       //              and don't need dijit's help
-       nodesWithKeyClick: ["input", "button"],
-
        connect: function(
                        /*Object|null*/ obj,
                        /*String|Function*/ event,
@@ -3973,8 +4000,8 @@ dojo.declare("dijit._Widget", null, {
                // description:
                //              Provide widget-specific analog to dojo.connect, except with the
                //              implicit use of this widget as the target object.
-               //              This version of connect also provides a special "ondijitclick"
-               //              event which triggers on a click or space or enter keyup
+               //              Events connected with `this.connect` are disconnected upon
+               //              destruction.
                // returns:
                //              A handle that can be passed to `disconnect` in order to disconnect before
                //              the widget is destroyed.
@@ -3988,41 +4015,7 @@ dojo.declare("dijit._Widget", null, {
                // tags:
                //              protected
 
-               var d = dojo,
-                       dc = d._connect,
-                       handles = [];
-               if(event == "ondijitclick"){
-                       // add key based click activation for unsupported nodes.
-                       // do all processing onkey up to prevent spurious clicks
-                       // for details see comments at top of this file where _lastKeyDownNode is defined
-                       if(dojo.indexOf(this.nodesWithKeyClick, obj.nodeName.toLowerCase()) == -1){ // is NOT input or button
-                               var m = d.hitch(this, method);
-                               handles.push(
-                                       dc(obj, "onkeydown", this, function(e){
-                                               //console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode));
-                                               if((e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) &&
-                                                       !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){
-                                                       // needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work
-                                                       dijit._lastKeyDownNode = e.target;
-                                                       e.preventDefault();             // stop event to prevent scrolling on space key in IE
-                                               }
-                                       }),
-                                       dc(obj, "onkeyup", this, function(e){
-                                               //console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode));
-                                               if( (e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) &&
-                                                       e.target === dijit._lastKeyDownNode &&
-                                                       !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){
-                                                               //need reset here or have problems in FF when focus returns to trigger element after closing popup/alert
-                                                               dijit._lastKeyDownNode = null;
-                                                               return m(e);
-                                               }
-                                       })
-                               );
-                       }
-                       event = "onclick";
-               }
-               handles.push(dc(obj, event, this, method));
-
+               var handles = [dojo._connect(obj, event, this, method)];
                this._connects.push(handles);
                return handles;         // _Widget.Handle
        },
@@ -4058,8 +4051,7 @@ dojo.declare("dijit._Widget", null, {
                //      |       btn.subscribe("/my/topic", function(v){
                //      |               this.set("label", v);
                //      |       });
-               var d = dojo,
-                       handle = d.subscribe(topic, this, method);
+               var handle = dojo.subscribe(topic, this, method);
 
                // return handles for Any widget that may need them
                this._subscribes.push(handle);
@@ -4087,13 +4079,6 @@ dojo.declare("dijit._Widget", null, {
                return this.dir ? (this.dir == "ltr") : dojo._isBodyLtr(); //Boolean
        },
 
-       isFocusable: function(){
-               // summary:
-               //              Return true if this widget can currently be focused
-               //              and false if not
-               return this.focus && (dojo.style(this.domNode, "display") != "none");
-       },
-
        placeAt: function(/* String|DomNode|_Widget */reference, /* String?|Int? */position){
                // summary:
                //              Place this widget's domNode reference somewhere in the DOM based
@@ -4149,49 +4134,6 @@ dojo.declare("dijit._Widget", null, {
                        dojo.place(this.domNode, reference, position);
                }
                return this;
-       },
-
-       _onShow: function(){
-               // summary:
-               //              Internal method called when this widget is made visible.
-               //              See `onShow` for details.
-               this.onShow();
-       },
-
-       onShow: function(){
-               // summary:
-               //              Called when this widget becomes the selected pane in a
-               //              `dijit.layout.TabContainer`, `dijit.layout.StackContainer`,
-               //              `dijit.layout.AccordionContainer`, etc.
-               //
-               //              Also called to indicate display of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
-               // tags:
-               //              callback
-       },
-
-       onHide: function(){
-               // summary:
-                       //              Called when another widget becomes the selected pane in a
-                       //              `dijit.layout.TabContainer`, `dijit.layout.StackContainer`,
-                       //              `dijit.layout.AccordionContainer`, etc.
-                       //
-                       //              Also called to indicate hide of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
-                       // tags:
-                       //              callback
-       },
-
-       onClose: function(){
-               // summary:
-               //              Called when this widget is being displayed as a popup (ex: a Calendar popped
-               //              up from a DateTextBox), and it is hidden.
-               //              This is called from the dijit.popup code, and should not be called directly.
-               //
-               //              Also used as a parameter for children of `dijit.layout.StackContainer` or subclasses.
-               //              Callback if a user tries to close the child.   Child will be closed if this function returns true.
-               // tags:
-               //              extension
-
-               return true;            // Boolean
        }
 });
 
@@ -4199,146 +4141,634 @@ dojo.declare("dijit._Widget", null, {
 
 }
 
-if(!dojo._hasResource["dojo.string"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo.string"] = true;
-dojo.provide("dojo.string");
+if(!dojo._hasResource["dijit._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._Widget"] = true;
+dojo.provide("dijit._Widget");
 
-/*=====
-dojo.string = { 
-       // summary: String utilities for Dojo
-};
-=====*/
 
-dojo.string.rep = function(/*String*/str, /*Integer*/num){
-       //      summary:
-       //              Efficiently replicate a string `n` times.
-       //      str:
-       //              the string to replicate
-       //      num:
-       //              number of times to replicate the string
-       
-       if(num <= 0 || !str){ return ""; }
-       
-       var buf = [];
-       for(;;){
-               if(num & 1){
-                       buf.push(str);
-               }
-               if(!(num >>= 1)){ break; }
-               str += str;
-       }
-       return buf.join("");    // String
-};
 
-dojo.string.pad = function(/*String*/text, /*Integer*/size, /*String?*/ch, /*Boolean?*/end){
-       //      summary:
-       //              Pad a string to guarantee that it is at least `size` length by
-       //              filling with the character `ch` at either the start or end of the
-       //              string. Pads at the start, by default.
-       //      text:
-       //              the string to pad
-       //      size:
-       //              length to provide padding
-       //      ch:
-       //              character to pad, defaults to '0'
-       //      end:
-       //              adds padding at the end if true, otherwise pads at start
-       //      example:
-       //      |       // Fill the string to length 10 with "+" characters on the right.  Yields "Dojo++++++".
-       //      |       dojo.string.pad("Dojo", 10, "+", true);
 
-       if(!ch){
-               ch = '0';
-       }
-       var out = String(text),
-               pad = dojo.string.rep(ch, Math.ceil((size - out.length) / ch.length));
-       return end ? out + pad : pad + out;     // String
-};
 
-dojo.string.substitute = function(     /*String*/              template, 
-                                                                       /*Object|Array*/map, 
-                                                                       /*Function?*/   transform, 
-                                                                       /*Object?*/             thisObject){
-       //      summary:
-       //              Performs parameterized substitutions on a string. Throws an
-       //              exception if any parameter is unmatched.
-       //      template: 
-       //              a string with expressions in the form `${key}` to be replaced or
-       //              `${key:format}` which specifies a format function. keys are case-sensitive. 
-       //      map:
-       //              hash to search for substitutions
-       //      transform: 
-       //              a function to process all parameters before substitution takes
-       //              place, e.g. mylib.encodeXML
-       //      thisObject: 
-       //              where to look for optional format function; default to the global
-       //              namespace
-       //      example:
-       //              Substitutes two expressions in a string from an Array or Object
-       //      |       // returns "File 'foo.html' is not found in directory '/temp'."
-       //      |       // by providing substitution data in an Array
-       //      |       dojo.string.substitute(
-       //      |               "File '${0}' is not found in directory '${1}'.",
-       //      |               ["foo.html","/temp"]
-       //      |       );
-       //      |
-       //      |       // also returns "File 'foo.html' is not found in directory '/temp'."
-       //      |       // but provides substitution data in an Object structure.  Dotted
-       //      |       // notation may be used to traverse the structure.
-       //      |       dojo.string.substitute(
-       //      |               "File '${name}' is not found in directory '${info.dir}'.",
-       //      |               { name: "foo.html", info: { dir: "/temp" } }
-       //      |       );
-       //      example:
-       //              Use a transform function to modify the values:
-       //      |       // returns "file 'foo.html' is not found in directory '/temp'."
-       //      |       dojo.string.substitute(
-       //      |               "${0} is not found in ${1}.",
-       //      |               ["foo.html","/temp"],
-       //      |               function(str){
-       //      |                       // try to figure out the type
-       //      |                       var prefix = (str.charAt(0) == "/") ? "directory": "file";
-       //      |                       return prefix + " '" + str + "'";
-       //      |               }
-       //      |       );
-       //      example:
-       //              Use a formatter
-       //      |       // returns "thinger -- howdy"
-       //      |       dojo.string.substitute(
-       //      |               "${0:postfix}", ["thinger"], null, {
-       //      |                       postfix: function(value, key){
-       //      |                               return value + " -- howdy";
-       //      |                       }
-       //      |               }
-       //      |       );
+////////////////// DEFERRED CONNECTS ///////////////////
 
-       thisObject = thisObject || dojo.global;
-       transform = transform ? 
-               dojo.hitch(thisObject, transform) : function(v){ return v; };
+// This code is to assist deferring dojo.connect() calls in widgets (connecting to events on the widgets'
+// DOM nodes) until someone actually needs to monitor that event.
+dojo.connect(dojo, "_connect",
+       function(/*dijit._Widget*/ widget, /*String*/ event){
+               if(widget && dojo.isFunction(widget._onConnect)){
+                       widget._onConnect(event);
+               }
+       });
 
-       return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g,
-               function(match, key, format){
-                       var value = dojo.getObject(key, false, map);
-                       if(format){
-                               value = dojo.getObject(format, false, thisObject).call(thisObject, value, key);
-                       }
-                       return transform(value, key).toString();
-               }); // String
-};
+dijit._connectOnUseEventHandler = function(/*Event*/ event){};
 
-/*=====
-dojo.string.trim = function(str){
-       //      summary:
-       //              Trims whitespace from both sides of the string
-       //      str: String
-       //              String to be trimmed
-       //      returns: String
-       //              Returns the trimmed string
-       //      description:
-       //              This version of trim() was taken from [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript).
-       //              The short yet performant version of this function is dojo.trim(),
-       //              which is part of Dojo base.  Uses String.prototype.trim instead, if available.
-       return "";      // String
+////////////////// ONDIJITCLICK SUPPORT ///////////////////
+
+// Keep track of where the last keydown event was, to help avoid generating
+// spurious ondijitclick events when:
+// 1. focus is on a <button> or <a>
+// 2. user presses then releases the ENTER key
+// 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler
+// 4. onkeyup event fires, causing the ondijitclick handler to fire
+dijit._lastKeyDownNode = null;
+if(dojo.isIE){
+       (function(){
+               var keydownCallback = function(evt){
+                       dijit._lastKeyDownNode = evt.srcElement;
+               };
+               dojo.doc.attachEvent('onkeydown', keydownCallback);
+               dojo.addOnWindowUnload(function(){
+                       dojo.doc.detachEvent('onkeydown', keydownCallback);
+               });
+       })();
+}else{
+       dojo.doc.addEventListener('keydown', function(evt){
+               dijit._lastKeyDownNode = evt.target;
+       }, true);
+}
+
+(function(){
+
+dojo.declare("dijit._Widget", dijit._WidgetBase, {
+       // summary:
+       //              Base class for all Dijit widgets.
+       //
+       //              Extends _WidgetBase, adding support for:
+       //                      - deferred connections
+       //                              A call like dojo.connect(myWidget, "onMouseMove", func)
+       //                              will essentially do a dojo.connect(myWidget.domNode, "onMouseMove", func)
+       //                      - ondijitclick
+       //                              Support new dojoAttachEvent="ondijitclick: ..." that is triggered by a mouse click or a SPACE/ENTER keypress
+       //                      - focus related functions
+       //                              In particular, the onFocus()/onBlur() callbacks.   Driven internally by
+       //                              dijit/_base/focus.js.
+       //                      - deprecated methods
+       //                      - onShow(), onHide(), onClose()
+       //
+       //              Also, by loading code in dijit/_base, turns on:
+       //                      - browser sniffing (putting browser id like .dj_ie on <html> node)
+       //                      - high contrast mode sniffing (add .dijit_a11y class to <body> if machine is in high contrast mode)
+       
+
+       ////////////////// DEFERRED CONNECTS ///////////////////
+
+       // _deferredConnects: [protected] Object
+       //              attributeMap addendum for event handlers that should be connected only on first use
+       _deferredConnects: {
+               onClick: "",
+               onDblClick: "",
+               onKeyDown: "",
+               onKeyPress: "",
+               onKeyUp: "",
+               onMouseMove: "",
+               onMouseDown: "",
+               onMouseOut: "",
+               onMouseOver: "",
+               onMouseLeave: "",
+               onMouseEnter: "",
+               onMouseUp: ""
+       },
+
+       onClick: dijit._connectOnUseEventHandler,
+       /*=====
+       onClick: function(event){
+               // summary:
+               //              Connect to this function to receive notifications of mouse click events.
+               // event:
+               //              mouse Event
+               // tags:
+               //              callback
+       },
+       =====*/
+       onDblClick: dijit._connectOnUseEventHandler,
+       /*=====
+       onDblClick: function(event){
+               // summary:
+               //              Connect to this function to receive notifications of mouse double click events.
+               // event:
+               //              mouse Event
+               // tags:
+               //              callback
+       },
+       =====*/
+       onKeyDown: dijit._connectOnUseEventHandler,
+       /*=====
+       onKeyDown: function(event){
+               // summary:
+               //              Connect to this function to receive notifications of keys being pressed down.
+               // event:
+               //              key Event
+               // tags:
+               //              callback
+       },
+       =====*/
+       onKeyPress: dijit._connectOnUseEventHandler,
+       /*=====
+       onKeyPress: function(event){
+               // summary:
+               //              Connect to this function to receive notifications of printable keys being typed.
+               // event:
+               //              key Event
+               // tags:
+               //              callback
+       },
+       =====*/
+       onKeyUp: dijit._connectOnUseEventHandler,
+       /*=====
+       onKeyUp: function(event){
+               // summary:
+               //              Connect to this function to receive notifications of keys being released.
+               // event:
+               //              key Event
+               // tags:
+               //              callback
+       },
+       =====*/
+       onMouseDown: dijit._connectOnUseEventHandler,
+       /*=====
+       onMouseDown: function(event){
+               // summary:
+               //              Connect to this function to receive notifications of when the mouse button is pressed down.
+               // event:
+               //              mouse Event
+               // tags:
+               //              callback
+       },
+       =====*/
+       onMouseMove: dijit._connectOnUseEventHandler,
+       /*=====
+       onMouseMove: function(event){
+               // summary:
+               //              Connect to this function to receive notifications of when the mouse moves over nodes contained within this widget.
+               // event:
+               //              mouse Event
+               // tags:
+               //              callback
+       },
+       =====*/
+       onMouseOut: dijit._connectOnUseEventHandler,
+       /*=====
+       onMouseOut: function(event){
+               // summary:
+               //              Connect to this function to receive notifications of when the mouse moves off of nodes contained within this widget.
+               // event:
+               //              mouse Event
+               // tags:
+               //              callback
+       },
+       =====*/
+       onMouseOver: dijit._connectOnUseEventHandler,
+       /*=====
+       onMouseOver: function(event){
+               // summary:
+               //              Connect to this function to receive notifications of when the mouse moves onto nodes contained within this widget.
+               // event:
+               //              mouse Event
+               // tags:
+               //              callback
+       },
+       =====*/
+       onMouseLeave: dijit._connectOnUseEventHandler,
+       /*=====
+       onMouseLeave: function(event){
+               // summary:
+               //              Connect to this function to receive notifications of when the mouse moves off of this widget.
+               // event:
+               //              mouse Event
+               // tags:
+               //              callback
+       },
+       =====*/
+       onMouseEnter: dijit._connectOnUseEventHandler,
+       /*=====
+       onMouseEnter: function(event){
+               // summary:
+               //              Connect to this function to receive notifications of when the mouse moves onto this widget.
+               // event:
+               //              mouse Event
+               // tags:
+               //              callback
+       },
+       =====*/
+       onMouseUp: dijit._connectOnUseEventHandler,
+       /*=====
+       onMouseUp: function(event){
+               // summary:
+               //              Connect to this function to receive notifications of when the mouse button is released.
+               // event:
+               //              mouse Event
+               // tags:
+               //              callback
+       },
+       =====*/
+
+       create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){
+               // To avoid double-connects, remove entries from _deferredConnects
+               // that have been setup manually by a subclass (ex, by dojoAttachEvent).
+               // If a subclass has redefined a callback (ex: onClick) then assume it's being
+               // connected to manually.
+               this._deferredConnects = dojo.clone(this._deferredConnects);
+               for(var attr in this.attributeMap){
+                       delete this._deferredConnects[attr]; // can't be in both attributeMap and _deferredConnects
+               }
+               for(attr in this._deferredConnects){
+                       if(this[attr] !== dijit._connectOnUseEventHandler){
+                               delete this._deferredConnects[attr];    // redefined, probably dojoAttachEvent exists
+                       }
+               }
+
+               this.inherited(arguments);
+
+               if(this.domNode){
+                       // If the developer has specified a handler as a widget parameter
+                       // (ex: new Button({onClick: ...})
+                       // then naturally need to connect from DOM node to that handler immediately,
+                       for(attr in this.params){
+                               this._onConnect(attr);
+                       }
+               }
+       },
+
+       _onConnect: function(/*String*/ event){
+               // summary:
+               //              Called when someone connects to one of my handlers.
+               //              "Turn on" that handler if it isn't active yet.
+               //
+               //              This is also called for every single initialization parameter
+               //              so need to do nothing for parameters like "id".
+               // tags:
+               //              private
+               if(event in this._deferredConnects){
+                       var mapNode = this[this._deferredConnects[event] || 'domNode'];
+                       this.connect(mapNode, event.toLowerCase(), event);
+                       delete this._deferredConnects[event];
+               }
+       },
+
+       ////////////////// FOCUS RELATED ///////////////////
+       // _onFocus() and _onBlur() are called by the focus manager
+
+       // focused: [readonly] Boolean
+       //              This widget or a widget it contains has focus, or is "active" because
+       //              it was recently clicked.
+       focused: false,
+
+       isFocusable: function(){
+               // summary:
+               //              Return true if this widget can currently be focused
+               //              and false if not
+               return this.focus && (dojo.style(this.domNode, "display") != "none");
+       },
+
+       onFocus: function(){
+               // summary:
+               //              Called when the widget becomes "active" because
+               //              it or a widget inside of it either has focus, or has recently
+               //              been clicked.
+               // tags:
+               //              callback
+       },
+
+       onBlur: function(){
+               // summary:
+               //              Called when the widget stops being "active" because
+               //              focus moved to something outside of it, or the user
+               //              clicked somewhere outside of it, or the widget was
+               //              hidden.
+               // tags:
+               //              callback
+       },
+
+       _onFocus: function(e){
+               // summary:
+               //              This is where widgets do processing for when they are active,
+               //              such as changing CSS classes.  See onFocus() for more details.
+               // tags:
+               //              protected
+               this.onFocus();
+       },
+
+       _onBlur: function(){
+               // summary:
+               //              This is where widgets do processing for when they stop being active,
+               //              such as changing CSS classes.  See onBlur() for more details.
+               // tags:
+               //              protected
+               this.onBlur();
+       },
+
+       ////////////////// DEPRECATED METHODS ///////////////////
+
+       setAttribute: function(/*String*/ attr, /*anything*/ value){
+               // summary:
+               //              Deprecated.  Use set() instead.
+               // tags:
+               //              deprecated
+               dojo.deprecated(this.declaredClass+"::setAttribute(attr, value) is deprecated. Use set() instead.", "", "2.0");
+               this.set(attr, value);
+       },
+
+       attr: function(/*String|Object*/name, /*Object?*/value){
+               // summary:
+               //              Set or get properties on a widget instance.
+               //      name:
+               //              The property to get or set. If an object is passed here and not
+               //              a string, its keys are used as names of attributes to be set
+               //              and the value of the object as values to set in the widget.
+               //      value:
+               //              Optional. If provided, attr() operates as a setter. If omitted,
+               //              the current value of the named property is returned.
+               // description:
+               //              This method is deprecated, use get() or set() directly.
+
+               // Print deprecation warning but only once per calling function
+               if(dojo.config.isDebug){
+                       var alreadyCalledHash = arguments.callee._ach || (arguments.callee._ach = {}),
+                               caller = (arguments.callee.caller || "unknown caller").toString();
+                       if(!alreadyCalledHash[caller]){
+                               dojo.deprecated(this.declaredClass + "::attr() is deprecated. Use get() or set() instead, called from " +
+                               caller, "", "2.0");
+                               alreadyCalledHash[caller] = true;
+                       }
+               }
+
+               var args = arguments.length;
+               if(args >= 2 || typeof name === "object"){ // setter
+                       return this.set.apply(this, arguments);
+               }else{ // getter
+                       return this.get(name);
+               }
+       },
+       
+       ////////////////// ONDIJITCLICK SUPPORT ///////////////////
+
+       // nodesWithKeyClick: [private] String[]
+       //              List of nodes that correctly handle click events via native browser support,
+       //              and don't need dijit's help
+       nodesWithKeyClick: ["input", "button"],
+
+       connect: function(
+                       /*Object|null*/ obj,
+                       /*String|Function*/ event,
+                       /*String|Function*/ method){
+               // summary:
+               //              Connects specified obj/event to specified method of this object
+               //              and registers for disconnect() on widget destroy.
+               // description:
+               //              Provide widget-specific analog to dojo.connect, except with the
+               //              implicit use of this widget as the target object.
+               //              This version of connect also provides a special "ondijitclick"
+               //              event which triggers on a click or space or enter keyup.
+               //              Events connected with `this.connect` are disconnected upon
+               //              destruction.
+               // returns:
+               //              A handle that can be passed to `disconnect` in order to disconnect before
+               //              the widget is destroyed.
+               // example:
+               //      |       var btn = new dijit.form.Button();
+               //      |       // when foo.bar() is called, call the listener we're going to
+               //      |       // provide in the scope of btn
+               //      |       btn.connect(foo, "bar", function(){
+               //      |               console.debug(this.toString());
+               //      |       });
+               // tags:
+               //              protected
+
+               var d = dojo,
+                       dc = d._connect,
+                       handles = this.inherited(arguments, [obj, event == "ondijitclick" ? "onclick" : event, method]);
+
+               if(event == "ondijitclick"){
+                       // add key based click activation for unsupported nodes.
+                       // do all processing onkey up to prevent spurious clicks
+                       // for details see comments at top of this file where _lastKeyDownNode is defined
+                       if(d.indexOf(this.nodesWithKeyClick, obj.nodeName.toLowerCase()) == -1){ // is NOT input or button
+                               var m = d.hitch(this, method);
+                               handles.push(
+                                       dc(obj, "onkeydown", this, function(e){
+                                               //console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode));
+                                               if((e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) &&
+                                                       !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){
+                                                       // needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work
+                                                       dijit._lastKeyDownNode = e.target;
+                                                       
+                                                       // Stop event to prevent scrolling on space key in IE.
+                                                       // But don't do this for _HasDropDown because it surpresses the onkeypress
+                                                       // event needed to open the drop down when the user presses the SPACE key.
+                                                       if(!("openDropDown" in this && obj == this._buttonNode)){
+                                                               e.preventDefault();
+                                                       }
+                                               }
+                                       }),
+                                       dc(obj, "onkeyup", this, function(e){
+                                               //console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode));
+                                               if( (e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) &&
+                                                       e.target == dijit._lastKeyDownNode &&   // === breaks greasemonkey
+                                                       !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){
+                                                               //need reset here or have problems in FF when focus returns to trigger element after closing popup/alert
+                                                               dijit._lastKeyDownNode = null;
+                                                               return m(e);
+                                               }
+                                       })
+                               );
+                       }
+               }
+
+               return handles;         // _Widget.Handle
+       },
+
+       ////////////////// MISCELLANEOUS METHODS ///////////////////
+
+       _onShow: function(){
+               // summary:
+               //              Internal method called when this widget is made visible.
+               //              See `onShow` for details.
+               this.onShow();
+       },
+
+       onShow: function(){
+               // summary:
+               //              Called when this widget becomes the selected pane in a
+               //              `dijit.layout.TabContainer`, `dijit.layout.StackContainer`,
+               //              `dijit.layout.AccordionContainer`, etc.
+               //
+               //              Also called to indicate display of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
+               // tags:
+               //              callback
+       },
+
+       onHide: function(){
+               // summary:
+                       //              Called when another widget becomes the selected pane in a
+                       //              `dijit.layout.TabContainer`, `dijit.layout.StackContainer`,
+                       //              `dijit.layout.AccordionContainer`, etc.
+                       //
+                       //              Also called to indicate hide of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
+                       // tags:
+                       //              callback
+       },
+
+       onClose: function(){
+               // summary:
+               //              Called when this widget is being displayed as a popup (ex: a Calendar popped
+               //              up from a DateTextBox), and it is hidden.
+               //              This is called from the dijit.popup code, and should not be called directly.
+               //
+               //              Also used as a parameter for children of `dijit.layout.StackContainer` or subclasses.
+               //              Callback if a user tries to close the child.   Child will be closed if this function returns true.
+               // tags:
+               //              extension
+
+               return true;            // Boolean
+       }
+});
+
+})();
+
+}
+
+if(!dojo._hasResource["dojo.string"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.string"] = true;
+dojo.provide("dojo.string");
+
+dojo.getObject("string", true, dojo);
+
+/*=====
+dojo.string = {
+       // summary: String utilities for Dojo
+};
+=====*/
+
+dojo.string.rep = function(/*String*/str, /*Integer*/num){
+       //      summary:
+       //              Efficiently replicate a string `n` times.
+       //      str:
+       //              the string to replicate
+       //      num:
+       //              number of times to replicate the string
+       
+       if(num <= 0 || !str){ return ""; }
+       
+       var buf = [];
+       for(;;){
+               if(num & 1){
+                       buf.push(str);
+               }
+               if(!(num >>= 1)){ break; }
+               str += str;
+       }
+       return buf.join("");    // String
+};
+
+dojo.string.pad = function(/*String*/text, /*Integer*/size, /*String?*/ch, /*Boolean?*/end){
+       //      summary:
+       //              Pad a string to guarantee that it is at least `size` length by
+       //              filling with the character `ch` at either the start or end of the
+       //              string. Pads at the start, by default.
+       //      text:
+       //              the string to pad
+       //      size:
+       //              length to provide padding
+       //      ch:
+       //              character to pad, defaults to '0'
+       //      end:
+       //              adds padding at the end if true, otherwise pads at start
+       //      example:
+       //      |       // Fill the string to length 10 with "+" characters on the right.  Yields "Dojo++++++".
+       //      |       dojo.string.pad("Dojo", 10, "+", true);
+
+       if(!ch){
+               ch = '0';
+       }
+       var out = String(text),
+               pad = dojo.string.rep(ch, Math.ceil((size - out.length) / ch.length));
+       return end ? out + pad : pad + out;     // String
+};
+
+dojo.string.substitute = function(     /*String*/              template,
+                                                                       /*Object|Array*/map,
+                                                                       /*Function?*/   transform,
+                                                                       /*Object?*/             thisObject){
+       //      summary:
+       //              Performs parameterized substitutions on a string. Throws an
+       //              exception if any parameter is unmatched.
+       //      template:
+       //              a string with expressions in the form `${key}` to be replaced or
+       //              `${key:format}` which specifies a format function. keys are case-sensitive.
+       //      map:
+       //              hash to search for substitutions
+       //      transform:
+       //              a function to process all parameters before substitution takes
+       //              place, e.g. mylib.encodeXML
+       //      thisObject:
+       //              where to look for optional format function; default to the global
+       //              namespace
+       //      example:
+       //              Substitutes two expressions in a string from an Array or Object
+       //      |       // returns "File 'foo.html' is not found in directory '/temp'."
+       //      |       // by providing substitution data in an Array
+       //      |       dojo.string.substitute(
+       //      |               "File '${0}' is not found in directory '${1}'.",
+       //      |               ["foo.html","/temp"]
+       //      |       );
+       //      |
+       //      |       // also returns "File 'foo.html' is not found in directory '/temp'."
+       //      |       // but provides substitution data in an Object structure.  Dotted
+       //      |       // notation may be used to traverse the structure.
+       //      |       dojo.string.substitute(
+       //      |               "File '${name}' is not found in directory '${info.dir}'.",
+       //      |               { name: "foo.html", info: { dir: "/temp" } }
+       //      |       );
+       //      example:
+       //              Use a transform function to modify the values:
+       //      |       // returns "file 'foo.html' is not found in directory '/temp'."
+       //      |       dojo.string.substitute(
+       //      |               "${0} is not found in ${1}.",
+       //      |               ["foo.html","/temp"],
+       //      |               function(str){
+       //      |                       // try to figure out the type
+       //      |                       var prefix = (str.charAt(0) == "/") ? "directory": "file";
+       //      |                       return prefix + " '" + str + "'";
+       //      |               }
+       //      |       );
+       //      example:
+       //              Use a formatter
+       //      |       // returns "thinger -- howdy"
+       //      |       dojo.string.substitute(
+       //      |               "${0:postfix}", ["thinger"], null, {
+       //      |                       postfix: function(value, key){
+       //      |                               return value + " -- howdy";
+       //      |                       }
+       //      |               }
+       //      |       );
+
+       thisObject = thisObject || dojo.global;
+       transform = transform ?
+               dojo.hitch(thisObject, transform) : function(v){ return v; };
+
+       return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g,
+               function(match, key, format){
+                       var value = dojo.getObject(key, false, map);
+                       if(format){
+                               value = dojo.getObject(format, false, thisObject).call(thisObject, value, key);
+                       }
+                       return transform(value, key).toString();
+               }); // String
+};
+
+/*=====
+dojo.string.trim = function(str){
+       //      summary:
+       //              Trims whitespace from both sides of the string
+       //      str: String
+       //              String to be trimmed
+       //      returns: String
+       //              Returns the trimmed string
+       //      description:
+       //              This version of trim() was taken from [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript).
+       //              The short yet performant version of this function is dojo.trim(),
+       //              which is part of Dojo base.  Uses String.prototype.trim instead, if available.
+       return "";      // String
 }
 =====*/
 
@@ -4361,14 +4791,14 @@ if(!dojo._hasResource["dojo.cache"]){ //_hasResource checks added by build. Do n
 dojo._hasResource["dojo.cache"] = true;
 dojo.provide("dojo.cache");
 
+
 /*=====
-dojo.cache = { 
+dojo.cache = {
        // summary:
        //              A way to cache string content that is fetchable via `dojo.moduleUrl`.
 };
 =====*/
 
-(function(){
        var cache = {};
        dojo.cache = function(/*String||Object*/module, /*String*/url, /*String||Object?*/value){
                // summary:
@@ -4407,7 +4837,7 @@ dojo.cache = {
                //              |       var text = dojo["cache"]("my.module", "template.html");
                //      example:
                //              To ask dojo.cache to fetch content and store it in the cache, and sanitize the input
-               //               (the dojo["cache"] style of call is used to avoid an issue with the build system 
+               //               (the dojo["cache"] style of call is used to avoid an issue with the build system
                //              erroneously trying to intern this example. To get the build system to intern your
                //              dojo.cache calls, use the "dojo.cache" style of call):
                //              |       //If template.html contains "<html><body><h1>Hello</h1></body></html>", the
@@ -4457,7 +4887,7 @@ dojo.cache = {
        };
 
        dojo.cache._sanitize = function(/*String*/val){
-               // summary: 
+               // summary:
                //              Strips <?xml ...?> declarations so that external SVG and XML
                //              documents can be added to a document without worry. Also, if the string
                //              is an HTML document, only the part inside the body tag is returned.
@@ -4474,7 +4904,6 @@ dojo.cache = {
                }
                return val; //String
        };
-})();
 
 }
 
@@ -4527,15 +4956,23 @@ dojo.declare("dijit._Templated",
                //              'true' to re-enable to previous, arguably broken, behavior.
                _earlyTemplatedStartup: false,
 
+/*=====
                // _attachPoints: [private] String[]
                //              List of widget attribute names associated with dojoAttachPoint=... in the
                //              template, ex: ["containerNode", "labelNode"]
-/*=====
                _attachPoints: [],
  =====*/
 
+/*=====
+               // _attachEvents: [private] Handle[]
+               //              List of connections associated with dojoAttachEvent=... in the
+               //              template
+               _attachEvents: [],
+ =====*/
+
                constructor: function(){
                        this._attachPoints = [];
+                       this._attachEvents = [];
                },
 
                _stringRepl: function(tmpl){
@@ -4560,7 +4997,6 @@ dojo.declare("dijit._Templated",
                        }, this);
                },
 
-               // method over-ride
                buildRendering: function(){
                        // summary:
                        //              Construct the UI for this widget from a template, setting this.domNode.
@@ -4586,33 +5022,24 @@ dojo.declare("dijit._Templated",
 
                        this.domNode = node;
 
+                       // Call down to _Widget.buildRendering() to get base classes assigned
+                       // TODO: change the baseClass assignment to attributeMap
+                       this.inherited(arguments);
+
                        // recurse through the node, looking for, and attaching to, our
                        // attachment points and events, which should be defined on the template node.
                        this._attachTemplateNodes(node);
 
                        if(this.widgetsInTemplate){
-                               // Make sure dojoType is used for parsing widgets in template.
-                               // The dojo.parser.query could be changed from multiversion support.
-                               var parser = dojo.parser, qry, attr;
-                               if(parser._query != "[dojoType]"){
-                                       qry = parser._query;
-                                       attr = parser._attrName;
-                                       parser._query = "[dojoType]";
-                                       parser._attrName = "dojoType";
-                               }
-
                                // Store widgets that we need to start at a later point in time
                                var cw = (this._startupWidgets = dojo.parser.parse(node, {
                                        noStart: !this._earlyTemplatedStartup,
-                                       inherited: {dir: this.dir, lang: this.lang}
+                                       template: true,
+                                       inherited: {dir: this.dir, lang: this.lang},
+                                       propsThis: this,        // so data-dojo-props of widgets in the template can reference "this" to refer to me
+                                       scope: "dojo"   // even in multi-version mode templates use dojoType/data-dojo-type
                                }));
 
-                               // Restore the query.
-                               if(qry){
-                                       parser._query = qry;
-                                       parser._attrName = attr;
-                               }
-
                                this._supportingWidgets = dijit.findWidgets(node);
 
                                this._attachTemplateNodes(cw, function(n,p){
@@ -4640,6 +5067,8 @@ dojo.declare("dijit._Templated",
                _attachTemplateNodes: function(rootNode, getAttrFunc){
                        // summary:
                        //              Iterate through the template and attach functions and nodes accordingly.
+                       //              Alternately, if rootNode is an array of widgets, then will process dojoAttachPoint
+                       //              etc. for those widgets.
                        // description:
                        //              Map widget properties and functions to the handlers specified in
                        //              the dom node and it's descendants. This function iterates over all
@@ -4662,11 +5091,11 @@ dojo.declare("dijit._Templated",
                        var x = dojo.isArray(rootNode) ? 0 : -1;
                        for(; x<nodes.length; x++){
                                var baseNode = (x == -1) ? rootNode : nodes[x];
-                               if(this.widgetsInTemplate && getAttrFunc(baseNode, "dojoType")){
+                               if(this.widgetsInTemplate && (getAttrFunc(baseNode, "dojoType") || getAttrFunc(baseNode, "data-dojo-type"))){
                                        continue;
                                }
                                // Process dojoAttachPoint
-                               var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint");
+                               var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint") || getAttrFunc(baseNode, "data-dojo-attach-point");
                                if(attachPoint){
                                        var point, points = attachPoint.split(/\s*,\s*/);
                                        while((point = points.shift())){
@@ -4680,7 +5109,7 @@ dojo.declare("dijit._Templated",
                                }
 
                                // Process dojoAttachEvent
-                               var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent");
+                               var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent") || getAttrFunc(baseNode, "data-dojo-attach-event");;
                                if(attachEvent){
                                        // NOTE: we want to support attributes that have the form
                                        // "domEvent: nativeEvent; ..."
@@ -4700,12 +5129,13 @@ dojo.declare("dijit._Templated",
                                                        if(!thisFunc){
                                                                thisFunc = event;
                                                        }
-                                                       this.connect(baseNode, event, thisFunc);
+                                                       this._attachEvents.push(this.connect(baseNode, event, thisFunc));
                                                }
                                        }
                                }
 
                                // waiRole, waiState
+                               // TODO: remove this in 2.0, templates are now using role=... and aria-XXX=... attributes directicly
                                var role = getAttrFunc(baseNode, "waiRole");
                                if(role){
                                        dijit.setWaiRole(baseNode, role);
@@ -4738,6 +5168,10 @@ dojo.declare("dijit._Templated",
                        }, this);
                        this._attachPoints = [];
 
+                       // And same for event handlers
+                       dojo.forEach(this._attachEvents, this.disconnect, this);
+                       this._attachEvents = [];
+                       
                        this.inherited(arguments);
                }
        }
@@ -4822,6 +5256,7 @@ if(!dojo._hasResource["dijit._Container"]){ //_hasResource checks added by build
 dojo._hasResource["dijit._Container"] = true;
 dojo.provide("dijit._Container");
 
+
 dojo.declare("dijit._Container",
        null,
        {
@@ -4884,7 +5319,7 @@ dojo.declare("dijit._Container",
                        //              not destroy it.  You can also pass in an integer indicating
                        //              the index within the container to remove
 
-                       if(typeof widget == "number" && widget > 0){
+                       if(typeof widget == "number"){
                                widget = this.getChildren()[widget];
                        }
 
@@ -4959,6 +5394,7 @@ if(!dojo._hasResource["dijit._Contained"]){ //_hasResource checks added by build
 dojo._hasResource["dijit._Contained"] = true;
 dojo.provide("dijit._Contained");
 
+
 dojo.declare("dijit._Contained",
                null,
                {
@@ -5022,7 +5458,6 @@ dojo.declare("dijit._Contained",
                }
        );
 
-
 }
 
 if(!dojo._hasResource["dijit.layout._LayoutWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
@@ -5051,10 +5486,9 @@ dojo.declare("dijit.layout._LayoutWidget",
                //              children widgets, setting their size, when they become visible.
                isLayoutContainer: true,
 
-               postCreate: function(){
-                       dojo.addClass(this.domNode, "dijitContainer");
-
+               buildRendering: function(){
                        this.inherited(arguments);
+                       dojo.addClass(this.domNode, "dijitContainer");
                },
 
                startup: function(){
@@ -5188,10 +5622,9 @@ dojo.declare("dijit.layout._LayoutWidget",
                        // tags:
                        //              protected extension
 
-                       dojo.addClass(child.domNode, this.baseClass+"-child");
-                       if(child.baseClass){
-                               dojo.addClass(child.domNode, this.baseClass+"-"+child.baseClass);
-                       }
+                       var cls = this.baseClass + "-child "
+                               + (child.baseClass ? this.baseClass + "-" + child.baseClass : "");
+                       dojo.addClass(child.domNode, cls);
                },
 
                addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
@@ -5204,10 +5637,11 @@ dojo.declare("dijit.layout._LayoutWidget",
 
                removeChild: function(/*dijit._Widget*/ child){
                        // Overrides _Container.removeChild() to remove class added by _setupChild()
-                       dojo.removeClass(child.domNode, this.baseClass+"-child");
-                       if(child.baseClass){
-                               dojo.removeClass(child.domNode, this.baseClass+"-"+child.baseClass);
-                       }
+                       var cls = this.baseClass + "-child"
+                                       + (child.baseClass ?
+                                               " " + this.baseClass + "-" + child.baseClass : "");
+                       dojo.removeClass(child.domNode, cls);
+                       
                        this.inherited(arguments);
                }
        }
@@ -5236,15 +5670,22 @@ dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
 
        var size = function(widget, dim){
                // size the child
-               widget.resize ? widget.resize(dim) : dojo.marginBox(widget.domNode, dim);
+               var newSize = widget.resize ? widget.resize(dim) : dojo.marginBox(widget.domNode, dim);
 
-               // record child's size, but favor our own numbers when we have them.
-               // the browser lies sometimes
-               dojo.mixin(widget, dojo.marginBox(widget.domNode));
-               dojo.mixin(widget, dim);
+               // record child's size
+               if(newSize){
+                       // if the child returned it's new size then use that
+                       dojo.mixin(widget, newSize);
+               }else{
+                       // otherwise, call marginBox(), but favor our own numbers when we have them.
+                       // the browser lies sometimes
+                       dojo.mixin(widget, dojo.marginBox(widget.domNode));
+                       dojo.mixin(widget, dim);
+               }
        };
 
-       dijit.layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Object[]*/ children){
+       dijit.layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Widget[]*/ children,
+                       /*String?*/ changedRegionId, /*Number?*/ changedRegionSize){
                // summary
                //              Layout a bunch of child dom nodes within a parent dom node
                // container:
@@ -5252,7 +5693,16 @@ dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
                // dim:
                //              {l, t, w, h} object specifying dimensions of container into which to place children
                // children:
-               //              an array like [ {domNode: foo, layoutAlign: "bottom" }, {domNode: bar, layoutAlign: "client"} ]
+               //              an array of Widgets or at least objects containing:
+               //                      * domNode: pointer to DOM node to position
+               //                      * region or layoutAlign: position to place DOM node
+               //                      * resize(): (optional) method to set size of node
+               //                      * id: (optional) Id of widgets, referenced from resize object, below.
+               // changedRegionId:
+               //              If specified, the slider for the region with the specified id has been dragged, and thus
+               //              the region's height or width should be adjusted according to changedRegionSize
+               // changedRegionSize:
+               //              See changedRegionId.
 
                // copy dim because we are going to modify it
                dim = dojo.mixin({}, dim);
@@ -5261,27 +5711,37 @@ dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
 
                // Move "client" elements to the end of the array for layout.  a11y dictates that the author
                // needs to be able to put them in the document in tab-order, but this algorithm requires that
-               // client be last.
-               children = dojo.filter(children, function(item){ return item.layoutAlign != "client"; })
-                       .concat(dojo.filter(children, function(item){ return item.layoutAlign == "client"; }));
+               // client be last.    TODO: move these lines to LayoutContainer?   Unneeded other places I think.
+               children = dojo.filter(children, function(item){ return item.region != "center" && item.layoutAlign != "client"; })
+                       .concat(dojo.filter(children, function(item){ return item.region == "center" || item.layoutAlign == "client"; }));
 
                // set positions/sizes
                dojo.forEach(children, function(child){
                        var elm = child.domNode,
-                               pos = child.layoutAlign;
+                               pos = (child.region || child.layoutAlign);
 
                        // set elem to upper left corner of unused space; may move it later
                        var elmStyle = elm.style;
                        elmStyle.left = dim.l+"px";
                        elmStyle.top = dim.t+"px";
-                       elmStyle.bottom = elmStyle.right = "auto";
+                       elmStyle.position = "absolute";
 
                        dojo.addClass(elm, "dijitAlign" + capitalize(pos));
 
+                       // Size adjustments to make to this child widget
+                       var sizeSetting = {};
+
+                       // Check for optional size adjustment due to splitter drag (height adjustment for top/bottom align
+                       // panes and width adjustment for left/right align panes.
+                       if(changedRegionId && changedRegionId == child.id){
+                               sizeSetting[child.region == "top" || child.region == "bottom" ? "h" : "w"] = changedRegionSize;
+                       }
+
                        // set size && adjust record of remaining space.
                        // note that setting the width of a <div> may affect its height.
                        if(pos == "top" || pos == "bottom"){
-                               size(child, { w: dim.w });
+                               sizeSetting.w = dim.w;
+                               size(child, sizeSetting);
                                dim.h -= child.h;
                                if(pos == "top"){
                                        dim.t += child.h;
@@ -5289,14 +5749,15 @@ dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
                                        elmStyle.top = dim.t + dim.h + "px";
                                }
                        }else if(pos == "left" || pos == "right"){
-                               size(child, { h: dim.h });
+                               sizeSetting.h = dim.h;
+                               size(child, sizeSetting);
                                dim.w -= child.w;
                                if(pos == "left"){
                                        dim.l += child.w;
                                }else{
                                        elmStyle.left = dim.l + dim.w + "px";
                                }
-                       }else if(pos == "client"){
+                       }else if(pos == "client" || pos == "center"){
                                size(child, dim);
                        }
                });
@@ -5340,7 +5801,19 @@ dojo.declare("dijit._CssStateMixin", [], {
        //              is hovered, etc.
        cssStateNodes: {},
 
-       postCreate: function(){
+       // hovering: [readonly] Boolean
+       //              True if cursor is over this widget
+       hovering: false,
+       
+       // active: [readonly] Boolean
+       //              True if mouse was pressed while over this widget, and hasn't been released yet
+       active: false,
+
+       _applyAttributes: function(){
+               // This code would typically be in postCreate(), but putting in _applyAttributes() for
+               // performance: so the class changes happen before DOM is inserted into the document.
+               // Change back to postCreate() in 2.0.  See #11635.
+
                this.inherited(arguments);
 
                // Automatically monitor mouse events (essentially :hover and :active) on this.domNode
@@ -5349,15 +5822,8 @@ dojo.declare("dijit._CssStateMixin", [], {
                }, this);
                
                // Monitoring changes to disabled, readonly, etc. state, and update CSS class of root node
-               this.connect(this, "set", function(name, value){
-                       if(arguments.length >= 2 && {disabled: true, readOnly: true, checked:true, selected:true}[name]){
-                               this._setStateClass();
-                       }
-               });
-
-               // The widget coming in/out of the focus change affects it's state
-               dojo.forEach(["_onFocus", "_onBlur"], function(ap){
-                       this.connect(this, ap, "_setStateClass");
+               dojo.forEach(["disabled", "readOnly", "checked", "selected", "focused", "state", "hovering", "active"], function(attr){
+                       this.watch(attr, dojo.hitch(this, "_setStateClass"));
                }, this);
 
                // Events on sub nodes within the widget
@@ -5365,44 +5831,42 @@ dojo.declare("dijit._CssStateMixin", [], {
                        this._trackMouseState(this[ap], this.cssStateNodes[ap]);
                }
                // Set state initially; there's probably no hover/active/focus state but widget might be
-               // disabled/readonly so we want to set CSS classes for those conditions.
+               // disabled/readonly/checked/selected so we want to set CSS classes for those conditions.
                this._setStateClass();
        },
 
        _cssMouseEvent: function(/*Event*/ event){
                // summary:
-               //      Sets _hovering and _active properties depending on mouse state,
-               //      then calls _setStateClass() to set appropriate CSS classes for this.domNode.
+               //      Sets hovering and active properties depending on mouse state,
+               //      which triggers _setStateClass() to set appropriate CSS classes for this.domNode.
 
                if(!this.disabled){
                        switch(event.type){
                                case "mouseenter":
                                case "mouseover":       // generated on non-IE browsers even though we connected to mouseenter
-                                       this._hovering = true;
-                                       this._active = this._mouseDown;
+                                       this._set("hovering", true);
+                                       this._set("active", this._mouseDown);
                                        break;
 
                                case "mouseleave":
                                case "mouseout":        // generated on non-IE browsers even though we connected to mouseleave
-                                       this._hovering = false;
-                                       this._active = false;
+                                       this._set("hovering", false);
+                                       this._set("active", false);
                                        break;
 
                                case "mousedown" :
-                                       this._active = true;
+                                       this._set("active", true);
                                        this._mouseDown = true;
                                        // Set a global event to handle mouseup, so it fires properly
                                        // even if the cursor leaves this.domNode before the mouse up event.
                                        // Alternately could set active=false on mouseout.
                                        var mouseUpConnector = this.connect(dojo.body(), "onmouseup", function(){
-                                               this._active = false;
                                                this._mouseDown = false;
-                                               this._setStateClass();
+                                               this._set("active", false);
                                                this.disconnect(mouseUpConnector);
                                        });
                                        break;
                        }
-                       this._setStateClass();
                }
        },
 
@@ -5421,11 +5885,12 @@ dojo.declare("dijit._CssStateMixin", [], {
                //              The widget may have one or more of the following states, determined
                //              by this.state, this.checked, this.valid, and this.selected:
                //                      - Error - ValidationTextBox sets this.state to "Error" if the current input value is invalid
+               //                      - Incomplete - ValidationTextBox sets this.state to "Incomplete" if the current input value is not finished yet
                //                      - Checked - ex: a checkmark or a ToggleButton in a checked state, will have this.checked==true
                //                      - Selected - ex: currently selected tab will have this.selected==true
                //
                //              In addition, it may have one or more of the following states,
-               //              based on this.disabled and flags set in _onMouse (this._active, this._hovering, this._focused):
+               //              based on this.disabled and flags set in _onMouse (this.active, this.hovering) and from focus manager (this.focused):
                //                      - Disabled      - if the widget is disabled
                //                      - Active                - if the mouse (or space/enter key?) is being pressed down
                //                      - Focused               - if the widget has focus
@@ -5458,9 +5923,9 @@ dojo.declare("dijit._CssStateMixin", [], {
                }else if(this.readOnly){
                        multiply("ReadOnly");
                }else{
-                       if(this._active){
+                       if(this.active){
                                multiply("Active");
-                       }else if(this._hovering){
+                       }else if(this.hovering){
                                multiply("Hover");
                        }
                }
@@ -5553,11 +6018,8 @@ dojo.declare("dijit._CssStateMixin", [], {
 
                // Just in case widget is enabled/disabled while it has focus/hover/active state.
                // Maybe this is overkill.
-               this.connect(this, "set", function(name, value){
-                       if(name == "disabled" || name == "readOnly"){
-                               setClass();
-                       }
-               });
+               this.watch("disabled", setClass);
+               this.watch("readOnly", setClass);
        }
 });
 
@@ -5572,7 +6034,6 @@ dojo.provide("dijit.form._FormWidget");
 
 
 
-
 dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated, dijit._CssStateMixin],
        {
        // summary:
@@ -5586,7 +6047,7 @@ dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated, dijit._
        //
        //              They also share some common methods.
 
-       // name: String
+       // name: [const] String
        //              Name used when submitting form; same as "name" attribute or plain HTML elements
        name: "",
 
@@ -5643,7 +6104,7 @@ dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated, dijit._
        },
 
        _setDisabledAttr: function(/*Boolean*/ value){
-               this.disabled = value;
+               this._set("disabled", value);
                dojo.attr(this.focusNode, 'disabled', value);
                if(this.valueNode){
                        dojo.attr(this.valueNode, 'disabled', value);
@@ -5653,8 +6114,8 @@ dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated, dijit._
                if(value){
                        // reset these, because after the domNode is disabled, we can no longer receive
                        // mouse related events, see #4200
-                       this._hovering = false;
-                       this._active = false;
+                       this._set("hovering", false);
+                       this._set("active", false);
 
                        // clear tab stop(s) on this widget's focusable node(s)  (ComboBox has two focusable nodes)
                        var attachPointNames = "tabIndex" in this.attributeMap ? this.attributeMap.tabIndex : "focusNode";
@@ -5664,17 +6125,19 @@ dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated, dijit._
                                if(dojo.isWebKit || dijit.hasDefaultTabStop(node)){     // see #11064 about webkit bug
                                        node.setAttribute('tabIndex', "-1");
                                }else{
-                                       node.removeAttribute('tabIndex');                               
+                                       node.removeAttribute('tabIndex');
                                }
                        }, this);
                }else{
-                       this.focusNode.setAttribute('tabIndex', this.tabIndex);
+                       if(this.tabIndex != ""){
+                               this.focusNode.setAttribute('tabIndex', this.tabIndex);
+                       }
                }
        },
 
        setDisabled: function(/*Boolean*/ disabled){
                // summary:
-               //              Deprecated.   Use set('disabled', ...) instead.
+               //              Deprecated.  Use set('disabled', ...) instead.
                dojo.deprecated("setDisabled("+disabled+") is deprecated. Use set('disabled',"+disabled+") instead.", "", "2.0");
                this.set('disabled', disabled);
        },
@@ -5688,21 +6151,23 @@ dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated, dijit._
 
        isFocusable: function(){
                // summary:
-               //              Tells if this widget is focusable or not.   Used internally by dijit.
+               //              Tells if this widget is focusable or not.  Used internally by dijit.
                // tags:
                //              protected
-               return !this.disabled && !this.readOnly && this.focusNode && (dojo.style(this.domNode, "display") != "none");
+               return !this.disabled && this.focusNode && (dojo.style(this.domNode, "display") != "none");
        },
 
        focus: function(){
                // summary:
                //              Put focus on this widget
-               dijit.focus(this.focusNode);
+               if(!this.disabled){
+                       dijit.focus(this.focusNode);
+               }
        },
 
-       compare: function(/*anything*/val1, /*anything*/val2){
+       compare: function(/*anything*/ val1, /*anything*/ val2){
                // summary:
-               //              Compare 2 values (as returned by attr('value') for this widget).
+               //              Compare 2 values (as returned by get('value') for this widget).
                // tags:
                //              protected
                if(typeof val1 == "number" && typeof val2 == "number"){
@@ -5729,27 +6194,28 @@ dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated, dijit._
        //              when the initial value is set.
        _onChangeActive: false,
 
-       _handleOnChange: function(/*anything*/ newValue, /* Boolean? */ priorityChange){
+       _handleOnChange: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){
                // summary:
                //              Called when the value of the widget is set.  Calls onChange() if appropriate
                // newValue:
                //              the new value
                // priorityChange:
                //              For a slider, for example, dragging the slider is priorityChange==false,
-               //              but on mouse up, it's priorityChange==true.  If intermediateChanges==true,
+               //              but on mouse up, it's priorityChange==true.  If intermediateChanges==false,
                //              onChange is only called form priorityChange=true events.
                // tags:
                //              private
-               this._lastValue = newValue;
                if(this._lastValueReported == undefined && (priorityChange === null || !this._onChangeActive)){
                        // this block executes not for a change, but during initialization,
                        // and is used to store away the original value (or for ToggleButton, the original checked state)
                        this._resetValue = this._lastValueReported = newValue;
                }
-               if((this.intermediateChanges || priorityChange || priorityChange === undefined) &&
-                       ((typeof newValue != typeof this._lastValueReported) ||
-                               this.compare(newValue, this._lastValueReported) != 0)){
+               this._pendingOnChange = this._pendingOnChange
+                       || (typeof newValue != typeof this._lastValueReported)
+                       || (this.compare(newValue, this._lastValueReported) != 0);
+               if((this.intermediateChanges || priorityChange || priorityChange === undefined) && this._pendingOnChange){
                        this._lastValueReported = newValue;
+                       this._pendingOnChange = false;
                        if(this._onChangeActive){
                                if(this._onChangeHandle){
                                        clearTimeout(this._onChangeHandle);
@@ -5781,14 +6247,14 @@ dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated, dijit._
 
        setValue: function(/*String*/ value){
                // summary:
-               //              Deprecated.   Use set('value', ...) instead.
+               //              Deprecated.  Use set('value', ...) instead.
                dojo.deprecated("dijit.form._FormWidget:setValue("+value+") is deprecated.  Use set('value',"+value+") instead.", "", "2.0");
                this.set('value', value);
        },
 
        getValue: function(){
                // summary:
-               //              Deprecated.   Use get('value') instead.
+               //              Deprecated.  Use get('value') instead.
                dojo.deprecated(this.declaredClass+"::getValue() is deprecated. Use get('value') instead.", "", "2.0");
                return this.get('value');
        },
@@ -5798,7 +6264,7 @@ dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated, dijit._
                // this button should get focus (to mimics native browser buttons).
                // This is also needed on chrome because otherwise buttons won't get focus at all,
                // which leads to bizarre focus restore on Dialog close etc.
-               if(!e.ctrlKey && this.isFocusable()){ // !e.ctrlKey to ignore right-click on mac
+               if(!e.ctrlKey && dojo.mouseButtons.isLeft(e) && this.isFocusable()){ // !e.ctrlKey to ignore right-click on mac
                        // Set a global event to handle mouseup, so it fires properly
                        // even if the cursor leaves this.domNode before the mouse up event.
                        var mouseUpConnector = this.connect(dojo.body(), "onmouseup", function(){
@@ -5822,7 +6288,7 @@ dojo.declare("dijit.form._FormValueWidget", dijit.form._FormWidget,
 
        // Don't attempt to mixin the 'type', 'name' attributes here programatically -- they must be declared
        // directly in the template as read by the parser in order to function. IE is known to specifically
-       // require the 'name' attribute at element creation time.   See #8484, #8660.
+       // require the 'name' attribute at element creation time.  See #8484, #8660.
        // TODO: unclear what that {value: ""} is for; FormWidget.attributeMap copies value to focusNode,
        // so maybe {value: ""} is so the value *doesn't* get copied to focusNode?
        // Seems like we really want value removed from attributeMap altogether
@@ -5840,39 +6306,40 @@ dojo.declare("dijit.form._FormValueWidget", dijit.form._FormWidget,
        }),
 
        _setReadOnlyAttr: function(/*Boolean*/ value){
-               this.readOnly = value;
                dojo.attr(this.focusNode, 'readOnly', value);
                dijit.setWaiState(this.focusNode, "readonly", value);
+               this._set("readOnly", value);
        },
 
        postCreate: function(){
                this.inherited(arguments);
 
-               if(dojo.isIE){ // IE won't stop the event with keypress
+               if(dojo.isIE < 9 || (dojo.isIE && dojo.isQuirks)){ // IE won't stop the event with keypress
                        this.connect(this.focusNode || this.domNode, "onkeydown", this._onKeyDown);
                }
                // Update our reset value if it hasn't yet been set (because this.set()
                // is only called when there *is* a value)
                if(this._resetValue === undefined){
-                       this._resetValue = this.value;
+                       this._lastValueReported = this._resetValue = this.value;
                }
        },
 
-       _setValueAttr: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){
+       _setValueAttr: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){
                // summary:
-               //              Hook so attr('value', value) works.
+               //              Hook so set('value', value) works.
                // description:
                //              Sets the value of the widget.
                //              If the value has changed, then fire onChange event, unless priorityChange
                //              is specified as null (or false?)
-               this.value = newValue;
                this._handleOnChange(newValue, priorityChange);
        },
 
-       _getValueAttr: function(){
+       _handleOnChange: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){
                // summary:
-               //              Hook so attr('value') works.
-               return this._lastValue;
+               //              Called when the value of the widget has changed.  Saves the new value in this.value,
+               //              and calls onChange() if appropriate.   See _FormWidget._handleOnChange() for details.
+               this._set("value", newValue);
+               this.inherited(arguments);
        },
 
        undo: function(){
@@ -5933,6 +6400,14 @@ if(!dojo._hasResource["dijit.dijit"]){ //_hasResource checks added by build. Do
 dojo._hasResource["dijit.dijit"] = true;
 dojo.provide("dijit.dijit");
 
+
+
+
+
+
+
+
+
 /*=====
 dijit.dijit = {
        // summary:
@@ -5949,21 +6424,15 @@ dijit.dijit = {
 
 // All the stuff in _base (these are the function that are guaranteed available without an explicit dojo.require)
 
-
 // And some other stuff that we tend to pull in all the time anyway
 
-
-
-
-
-
-
 }
 
 if(!dojo._hasResource["dojo.fx.Toggler"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
 dojo._hasResource["dojo.fx.Toggler"] = true;
 dojo.provide("dojo.fx.Toggler");
 
+
 dojo.declare("dojo.fx.Toggler", null, {
        // summary:
        //              A simple `dojo.Animation` toggler API.
@@ -5971,16 +6440,16 @@ dojo.declare("dojo.fx.Toggler", null, {
        // description:
        //              class constructor for an animation toggler. It accepts a packed
        //              set of arguments about what type of animation to use in each
-       //              direction, duration, etc. All available members are mixed into 
-       //              these animations from the constructor (for example, `node`, 
-       //              `showDuration`, `hideDuration`). 
+       //              direction, duration, etc. All available members are mixed into
+       //              these animations from the constructor (for example, `node`,
+       //              `showDuration`, `hideDuration`).
        //
        // example:
        //      |       var t = new dojo.fx.Toggler({
        //      |               node: "nodeId",
        //      |               showDuration: 500,
        //      |               // hideDuration will default to "200"
-       //      |               showFunc: dojo.fx.wipeIn, 
+       //      |               showFunc: dojo.fx.wipeIn,
        //      |               // hideFunc will default to "fadeOut"
        //      |       });
        //      |       t.show(100); // delay showing for 100ms
@@ -5995,7 +6464,7 @@ dojo.declare("dojo.fx.Toggler", null, {
        //              The function that returns the `dojo.Animation` to show the node
        showFunc: dojo.fadeIn,
 
-       // hideFunc: Function   
+       // hideFunc: Function
        //              The function that returns the `dojo.Animation` to hide the node
        hideFunc: dojo.fadeOut,
 
@@ -6011,7 +6480,7 @@ dojo.declare("dojo.fx.Toggler", null, {
        // time show/hide are called if we're stopped somewhere in the
        // middle.
        // FIXME: also would be nice to specify individual showArgs/hideArgs mixed into
-       // each animation individually. 
+       // each animation individually.
        // FIXME: also would be nice to have events from the animations exposed/bridged
 
        /*=====
@@ -6064,7 +6533,9 @@ dojo.declare("dojo.fx.Toggler", null, {
 if(!dojo._hasResource["dojo.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
 dojo._hasResource["dojo.fx"] = true;
 dojo.provide("dojo.fx");
- // FIXME: remove this back-compat require in 2.0 
+
+
+
 /*=====
 dojo.fx = {
        // summary: Effects library on top of Base animations
@@ -6072,7 +6543,7 @@ dojo.fx = {
 =====*/
 (function(){
        
-       var d = dojo, 
+       var d = dojo,
                _baseObj = {
                        _fire: function(evt, args){
                                if(this[evt]){
@@ -6191,14 +6662,14 @@ dojo.fx = {
        d.extend(_chain, _baseObj);
 
        dojo.fx.chain = function(/*dojo.Animation[]*/ animations){
-               // summary: 
+               // summary:
                //              Chain a list of `dojo.Animation`s to run in sequence
                //
                // description:
                //              Return a `dojo.Animation` which will play all passed
                //              `dojo.Animation` instances in sequence, firing its own
                //              synthesized events simulating a single animation. (eg:
-               //              onEnd of this animation means the end of the chain, 
+               //              onEnd of this animation means the end of the chain,
                //              not the individual animations within)
                //
                // example:
@@ -6226,7 +6697,7 @@ dojo.fx = {
                
                this._pseudoAnimation = new d.Animation({curve: [0, 1], duration: this.duration});
                var self = this;
-               d.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop", "onEnd"], 
+               d.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop", "onEnd"],
                        function(evt){
                                self._connects.push(d.connect(self._pseudoAnimation, evt,
                                        function(){ self._fire(evt, arguments); }
@@ -6284,11 +6755,11 @@ dojo.fx = {
        d.extend(_combine, _baseObj);
 
        dojo.fx.combine = function(/*dojo.Animation[]*/ animations){
-               // summary: 
+               // summary:
                //              Combine a list of `dojo.Animation`s to run in parallel
                //
                // description:
-               //              Combine an array of `dojo.Animation`s to run in parallel, 
+               //              Combine an array of `dojo.Animation`s to run in parallel,
                //              providing a new `dojo.Animation` instance encompasing each
                //              animation, firing standard animation events.
                //
@@ -6359,17 +6830,17 @@ dojo.fx = {
                        }
                }, args));
 
-               d.connect(anim, "onEnd", function(){ 
+               d.connect(anim, "onEnd", function(){
                        s.height = "auto";
                        s.overflow = o;
                });
 
                return anim; // dojo.Animation
-       }
+       };
 
        dojo.fx.wipeOut = function(/*Object*/ args){
                // summary:
-               //              Shrink a node to nothing and hide it. 
+               //              Shrink a node to nothing and hide it.
                //
                // description:
                //              Returns an animation that will shrink node defined in "args"
@@ -6378,7 +6849,7 @@ dojo.fx = {
                // args: Object
                //              A hash-map of standard `dojo.Animation` constructor properties
                //              (such as easing: node: duration: and so on)
-               // 
+               //
                // example:
                //      |       dojo.fx.wipeOut({ node:"someId" }).play()
                
@@ -6404,14 +6875,14 @@ dojo.fx = {
                });
 
                return anim; // dojo.Animation
-       }
+       };
 
        dojo.fx.slideTo = function(/*Object*/ args){
                // summary:
                //              Slide a node to a new top/left position
                //
                // description:
-               //              Returns an animation that will slide "node" 
+               //              Returns an animation that will slide "node"
                //              defined in args Object from its current position to
                //              the position defined by (args.left, args.top).
                //
@@ -6423,7 +6894,7 @@ dojo.fx = {
                // example:
                //      |       dojo.fx.slideTo({ node: node, left:"40", top:"50", units:"px" }).play()
 
-               var node = args.node = d.byId(args.node), 
+               var node = args.node = d.byId(args.node),
                        top = null, left = null;
 
                var init = (function(n){
@@ -6453,7 +6924,7 @@ dojo.fx = {
                d.connect(anim, "beforeBegin", anim, init);
 
                return anim; // dojo.Animation
-       }
+       };
 
 })();
 
@@ -6464,6 +6935,7 @@ dojo._hasResource["dojo.NodeList-fx"] = true;
 dojo.provide("dojo.NodeList-fx");
 
 
+
 /*=====
 dojo["NodeList-fx"] = {
        // summary: Adds dojo.fx animation support to dojo.query()
@@ -6479,7 +6951,7 @@ dojo.extend(dojo.NodeList, {
                                dojo.mixin(tmpArgs, args);
                                return obj[method](tmpArgs);
                        })
-               ); 
+               );
                return args.auto ? a.play() && this : a; // dojo.Animation|dojo.NodeList
        },
 
@@ -6488,7 +6960,7 @@ dojo.extend(dojo.NodeList, {
                //              wipe in all elements of this NodeList via `dojo.fx.wipeIn`
                //
                //      args: Object?
-               //              Additional dojo.Animation arguments to mix into this set with the addition of 
+               //              Additional dojo.Animation arguments to mix into this set with the addition of
                //              an `auto` parameter.
                //
                //      returns: dojo.Animation|dojo.NodeList
@@ -6512,7 +6984,7 @@ dojo.extend(dojo.NodeList, {
                //              wipe out all elements of this NodeList via `dojo.fx.wipeOut`
                //
                //      args: Object?
-               //              Additional dojo.Animation arguments to mix into this set with the addition of 
+               //              Additional dojo.Animation arguments to mix into this set with the addition of
                //              an `auto` parameter.
                //
                //      returns: dojo.Animation|dojo.NodeList
@@ -6531,7 +7003,7 @@ dojo.extend(dojo.NodeList, {
                //              slide all elements of the node list to the specified place via `dojo.fx.slideTo`
                //
                //      args: Object?
-               //              Additional dojo.Animation arguments to mix into this set with the addition of 
+               //              Additional dojo.Animation arguments to mix into this set with the addition of
                //              an `auto` parameter.
                //
                //      returns: dojo.Animation|dojo.NodeList
@@ -6554,7 +7026,7 @@ dojo.extend(dojo.NodeList, {
                //              fade in all elements of this NodeList via `dojo.fadeIn`
                //
                //      args: Object?
-               //              Additional dojo.Animation arguments to mix into this set with the addition of 
+               //              Additional dojo.Animation arguments to mix into this set with the addition of
                //              an `auto` parameter.
                //
                //      returns: dojo.Animation|dojo.NodeList
@@ -6573,7 +7045,7 @@ dojo.extend(dojo.NodeList, {
                //              fade out all elements of this NodeList via `dojo.fadeOut`
                //
                //      args: Object?
-               //              Additional dojo.Animation arguments to mix into this set with the addition of 
+               //              Additional dojo.Animation arguments to mix into this set with the addition of
                //              an `auto` parameter.
                //
                //      returns: dojo.Animation|dojo.NodeList
@@ -6609,14 +7081,14 @@ dojo.extend(dojo.NodeList, {
                //      example:
                //      |       dojo.query(".zork").animateProperty({
                //      |               duration: 500,
-               //      |               properties: { 
+               //      |               properties: {
                //      |                       color:          { start: "black", end: "white" },
-               //      |                       left:           { end: 300 } 
-               //      |               } 
+               //      |                       left:           { end: 300 }
+               //      |               }
                //      |       }).play();
                //
                //      example:
-               //      |       dojo.query(".grue").animateProperty({ 
+               //      |       dojo.query(".grue").animateProperty({
                //      |               auto:true,
                //      |               properties: {
                //      |                       height:240
@@ -6625,9 +7097,9 @@ dojo.extend(dojo.NodeList, {
                return this._anim(dojo, "animateProperty", args); // dojo.Animation|dojo.NodeList
        },
 
-       anim: function( /*Object*/                      properties, 
-                                       /*Integer?*/            duration, 
-                                       /*Function?*/           easing, 
+       anim: function( /*Object*/                      properties,
+                                       /*Integer?*/            duration,
+                                       /*Function?*/           easing,
                                        /*Function?*/           onEnd,
                                        /*Integer?*/            delay){
                //      summary:
@@ -6635,8 +7107,8 @@ dojo.extend(dojo.NodeList, {
                //              The returned animation object will already be playing when it
                //              is returned. See the docs for `dojo.anim` for full details.
                //      properties: Object
-               //              the properties to animate. does NOT support the `auto` parameter like other 
-               //              NodeList-fx methods. 
+               //              the properties to animate. does NOT support the `auto` parameter like other
+               //              NodeList-fx methods.
                //      duration: Integer?
                //              Optional. The time to run the animations for
                //      easing: Function?
@@ -6661,7 +7133,7 @@ dojo.extend(dojo.NodeList, {
                                        easing: easing
                                });
                        })
-               ); 
+               );
                if(onEnd){
                        dojo.connect(canim, "onEnd", onEnd);
                }
@@ -6675,6 +7147,8 @@ if(!dojo._hasResource["dojo.colors"]){ //_hasResource checks added by build. Do
 dojo._hasResource["dojo.colors"] = true;
 dojo.provide("dojo.colors");
 
+dojo.getObject("colors", true, dojo);
+
 //TODO: this module appears to break naming conventions
 
 /*=====
@@ -6721,9 +7195,9 @@ dojo.colors = {
                                var H = ((parseFloat(c[0]) % 360) + 360) % 360 / 360,
                                        S = parseFloat(c[1]) / 100,
                                        L = parseFloat(c[2]) / 100,
-                                       // calculate rgb according to the algorithm 
-                                       // recommended by the CSS3 Color Module 
-                                       m2 = L <= 0.5 ? L * (S + 1) : L + S - L * S, 
+                                       // calculate rgb according to the algorithm
+                                       // recommended by the CSS3 Color Module
+                                       m2 = L <= 0.5 ? L * (S + 1) : L + S - L * S,
                                        m1 = 2 * L - m2;
                                a = [
                                        hue2rgb(m1, m2, H + 1 / 3) * 256,
@@ -6905,13 +7379,16 @@ if(!dojo._hasResource["dojo.i18n"]){ //_hasResource checks added by build. Do no
 dojo._hasResource["dojo.i18n"] = true;
 dojo.provide("dojo.i18n");
 
+dojo.getObject("i18n", true, dojo);
+
 /*=====
 dojo.i18n = {
        // summary: Utility classes to enable loading of resources for internationalization (i18n)
 };
 =====*/
 
-dojo.i18n.getLocalization = function(/*String*/packageName, /*String*/bundleName, /*String?*/locale){
+// when using a real AMD loader, dojo.i18n.getLocalization is already defined by dojo/lib/backCompat
+dojo.i18n.getLocalization = dojo.i18n.getLocalization || function(/*String*/packageName, /*String*/bundleName, /*String?*/locale){
        //      summary:
        //              Returns an Object containing the localization for a given resource
        //              bundle in a package, matching the specified locale.
@@ -6939,7 +7416,7 @@ dojo.i18n.getLocalization = function(/*String*/packageName, /*String*/bundleName
        // look for nearest locale match
        var elements = locale.split('-');
        var module = [packageName,"nls",bundleName].join('.');
-       var bundle = dojo._loadedModules[module];
+               var bundle = dojo._loadedModules[module];
        if(bundle){
                var localization;
                for(var i = elements.length; i > 0; i--){
@@ -6989,7 +7466,7 @@ dojo.i18n._requireLocalization = function(/*String*/moduleName, /*String*/bundle
 
        var targetLocale = dojo.i18n.normalizeLocale(locale);
        var bundlePackage = [moduleName, "nls", bundleName].join(".");
-       // NOTE: 
+       // NOTE:
        //              When loading these resources, the packaging does not match what is
        //              on disk.  This is an implementation detail, as this is just a
        //              private data structure to hold the loaded resources.  e.g.
@@ -6999,7 +7476,7 @@ dojo.i18n._requireLocalization = function(/*String*/moduleName, /*String*/bundle
        //              in memory it is more logical and efficient to store in a different
        //              order.  Locales cannot use dashes, since the resulting path will
        //              not evaluate as valid JS, so we translate them to underscores.
-       
+
        //Find the best-match locale to load if we have available flat locales.
        var bestLocale = "";
        if(availableFlatLocales){
@@ -7016,7 +7493,7 @@ dojo.i18n._requireLocalization = function(/*String*/moduleName, /*String*/bundle
                }
                if(!bestLocale){
                        bestLocale = "ROOT";
-               }               
+               }
        }
 
        //See if the desired locale is already loaded.
@@ -7048,6 +7525,7 @@ dojo.i18n._requireLocalization = function(/*String*/moduleName, /*String*/bundle
                                module.push(bundleName);
                                var filespec = module.join("/") + '.js';
                                loaded = dojo._loadPath(filespec, null, function(hash){
+                                       hash = hash.root || hash;
                                        // Use singleton with prototype to point to parent bundle, then mix-in result from loadPath
                                        var clazz = function(){};
                                        clazz.prototype = parent;
@@ -7062,7 +7540,7 @@ dojo.i18n._requireLocalization = function(/*String*/moduleName, /*String*/bundle
                        }else{
                                bundle[jsLoc] = parent;
                        }
-                       
+
                        if(availableFlatLocales){
                                //Stop the locale path searching if we know the availableFlatLocales, since
                                //the first call to this function will load the only bundle that is needed.
@@ -7080,8 +7558,8 @@ dojo.i18n._requireLocalization = function(/*String*/moduleName, /*String*/bundle
 
 (function(){
        // If other locales are used, dojo.requireLocalization should load them as
-       // well, by default. 
-       // 
+       // well, by default.
+       //
        // Override dojo.requireLocalization to do load the default bundle, then
        // iterate through the extraLocale list and load those translations as
        // well, unless a particular locale was requested.
@@ -7158,6 +7636,7 @@ dojo._hasResource["dijit._PaletteMixin"] = true;
 dojo.provide("dijit._PaletteMixin");
 
 
+
 dojo.declare("dijit._PaletteMixin",
        [dijit._CssStateMixin],
        {
@@ -7184,23 +7663,23 @@ dojo.declare("dijit._PaletteMixin",
        //              Index of the currently selected cell. Initially, none selected
        _selectedCell: -1,
 
+/*=====
        // _currentFocus: [private] DomNode
        //              The currently focused cell (if the palette itself has focus), or otherwise
        //              the cell to be focused when the palette itself gets focus.
        //              Different from value, which represents the selected (i.e. clicked) cell.
-/*=====
        _currentFocus: null,
 =====*/
 
+/*=====
        // _xDim: [protected] Integer
        //              This is the number of cells horizontally across.
-/*=====
        _xDim: null,
 =====*/
 
+/*=====
        // _yDim: [protected] Integer
        //              This is the number of cells vertically down.
-/*=====
        _yDim: null,
 =====*/
 
@@ -7217,7 +7696,7 @@ dojo.declare("dijit._PaletteMixin",
        //       dyeClass should implements dijit.Dye interface
        dyeClass: '',
 
-       _preparePalette: function(choices, titles) {
+       _preparePalette: function(choices, titles, dyeClassObj) {
                // summary:
                //              Subclass must call _preparePalette() from postCreate(), passing in the tooltip
                //              for each cell
@@ -7225,18 +7704,20 @@ dojo.declare("dijit._PaletteMixin",
                //              id's for each cell of the palette, used to create Dye JS object for each cell
                // titles: String[]
                //              Localized tooltip for each cell
+               // dyeClassObj: Constructor?
+               //              If specified, use this constructor rather than this.dyeClass
 
                this._cells = [];
                var url = this._blankGif;
                
-               var dyeClassObj = dojo.getObject(this.dyeClass);
+               dyeClassObj = dyeClassObj || dojo.getObject(this.dyeClass);
 
                for(var row=0; row < choices.length; row++){
                        var rowNode = dojo.create("tr", {tabIndex: "-1"}, this.gridNode);
                        for(var col=0; col < choices[row].length; col++){
                                var value = choices[row][col];
                                if(value){
-                                       var cellObject = new dyeClassObj(value);
+                                       var cellObject = new dyeClassObj(value, row, col);
                                        
                                        var cellNode = dojo.create("td", {
                                                "class": this.cellClass,
@@ -7316,7 +7797,7 @@ dojo.declare("dijit._PaletteMixin",
                // tags:
                //              private
 
-               var target = evt.currentTarget, 
+               var target = evt.currentTarget,
                        value = this._getDye(target).getValue();
 
                // First focus the clicked cell, and then send onChange() notification.
@@ -7326,8 +7807,8 @@ dojo.declare("dijit._PaletteMixin",
                // Use setTimeout because IE doesn't like changing focus inside of an event handler.
                this._setCurrent(target);
                setTimeout(dojo.hitch(this, function(){
-                       dijit.focus(target);            
-                       this._setValueAttr(value, true);                
+                       dijit.focus(target);
+                       this._setValueAttr(value, true);
                }));
 
                // workaround bug where hover class is not removed on popup because the popup is
@@ -7371,8 +7852,7 @@ dojo.declare("dijit._PaletteMixin",
                //              Optional parameter used to tell the select whether or not to fire
                //              onChange event.
                
-               // clear old value and selected cell
-               this.value = null;
+               // clear old selected cell
                if(this._selectedCell >= 0){
                        dojo.removeClass(this._cells[this._selectedCell].node, "dijitPaletteCellSelected");
                }
@@ -7383,18 +7863,18 @@ dojo.declare("dijit._PaletteMixin",
                        for(var i = 0; i < this._cells.length; i++){
                                if(value == this._cells[i].dye.getValue()){
                                        this._selectedCell = i;
-                                       this.value = value;
-
                                        dojo.addClass(this._cells[i].node, "dijitPaletteCellSelected");
-
-                                       if(priorityChange || priorityChange === undefined){
-                                               this.onChange(value);
-                                       }
-
                                        break;
                                }
                        }
                }
+               
+               // record new value, or null if no matching cell
+               this._set("value", this._selectedCell >= 0 ? value : null);
+
+               if(priorityChange || priorityChange === undefined){
+                       this.onChange(value);
+               }
        },
 
        onChange: function(value){
@@ -7444,7 +7924,7 @@ dojo.declare("dijit.Dye",
                // summary:
                //              Interface for the JS Object associated with a palette cell (i.e. DOMNode)
 
-               constructor: function(alias){
+               constructor: function(alias, row, col){
                        // summary:
                        //              Initialize according to value or alias like "white"
                        // alias: String
@@ -7483,7 +7963,6 @@ dojo.provide("dijit.ColorPalette");
 
 
 
-
 dojo.declare("dijit.ColorPalette",
        [dijit._Widget, dijit._Templated, dijit._PaletteMixin],
        {
@@ -7501,7 +7980,7 @@ dojo.declare("dijit.ColorPalette",
        // |    picker.startup();
 
 
-       // palette: String
+       // palette: [const] String
        //              Size of grid, either "7x10" or "3x4".
        palette: "7x10",
 
@@ -7523,65 +8002,88 @@ dojo.declare("dijit.ColorPalette",
                        ["gray", "red", "purple", "black"]]
        },
 
-       // _imagePaths: [protected] Map
-       //              This is stores the path to the palette images
-       _imagePaths: {
-               "7x10": dojo.moduleUrl("dijit.themes", "a11y/colors7x10.png"),
-               "3x4": dojo.moduleUrl("dijit.themes", "a11y/colors3x4.png"),
-               "7x10-rtl": dojo.moduleUrl("dijit.themes", "a11y/colors7x10-rtl.png"),
-               "3x4-rtl": dojo.moduleUrl("dijit.themes", "a11y/colors3x4-rtl.png")
-       },
-
        // templateString: String
        //              The template of this widget.
-       templateString: dojo.cache("dijit", "templates/ColorPalette.html", "<div class=\"dijitInline dijitColorPalette\">\n\t<img class=\"dijitColorPaletteUnder\" dojoAttachPoint=\"imageNode\" waiRole=\"presentation\" alt=\"\"/>\n\t<table class=\"dijitPaletteTable\" cellSpacing=\"0\" cellPadding=\"0\">\n\t\t<tbody dojoAttachPoint=\"gridNode\"></tbody>\n\t</table>\n</div>\n"),
+       templateString: dojo.cache("dijit", "templates/ColorPalette.html", "<div class=\"dijitInline dijitColorPalette\">\n\t<table class=\"dijitPaletteTable\" cellSpacing=\"0\" cellPadding=\"0\">\n\t\t<tbody dojoAttachPoint=\"gridNode\"></tbody>\n\t</table>\n</div>\n"),
 
        baseClass: "dijitColorPalette",
 
-       dyeClass: 'dijit._Color',
-
        buildRendering: function(){
                // Instantiate the template, which makes a skeleton into which we'll insert a bunch of
                // <img> nodes
-
                this.inherited(arguments);
 
-               this.imageNode.setAttribute("src", this._imagePaths[this.palette + (this.isLeftToRight() ? "" : "-rtl")].toString());
-
-               var i18nColorNames = dojo.i18n.getLocalization("dojo", "colors", this.lang);
+               // Creates <img> nodes in each cell of the template.
+               // Pass in "customized" dijit._Color constructor for specified palette and high-contrast vs. normal mode
                this._preparePalette(
                        this._palettes[this.palette],
-                       i18nColorNames
+                       dojo.i18n.getLocalization("dojo", "colors", this.lang),
+                       dojo.declare(dijit._Color, {
+                               hc: dojo.hasClass(dojo.body(), "dijit_a11y"),
+                               palette: this.palette
+                       })
                );
        }
 });
 
-dojo.declare("dijit._Color", dojo.Color,
+dojo.declare("dijit._Color", dojo.Color, {
        // summary:
        //              Object associated with each cell in a ColorPalette palette.
        //              Implements dijit.Dye.
-       {
-               constructor: function(/*String*/alias){
-                       this._alias = alias;
-                       this.setColor(dojo.Color.named[alias]);
-               },
 
-               getValue: function(){
-                       // summary:
-                       //              Note that although dijit._Color is initialized with a value like "white" getValue() always
-                       //              returns a hex value
-                       return this.toHex();
-               },
+       // Template for each cell in normal (non-high-contrast mode).  Each cell contains a wrapper
+       // node for showing the border (called dijitPaletteImg for back-compat), and dijitColorPaletteSwatch
+       // for showing the color.
+       template:
+               "<span class='dijitInline dijitPaletteImg'>" +
+                       "<img src='${blankGif}' alt='${alt}' class='dijitColorPaletteSwatch' style='background-color: ${color}'/>" +
+               "</span>",
+
+       // Template for each cell in high contrast mode.  Each cell contains an image with the whole palette,
+       // but scrolled and clipped to show the correct color only
+       hcTemplate:
+               "<span class='dijitInline dijitPaletteImg' style='position: relative; overflow: hidden; height: 12px; width: 14px;'>" +
+                       "<img src='${image}' alt='${alt}' style='position: absolute; left: ${left}px; top: ${top}px; ${size}'/>" +
+               "</span>",
 
-               fillCell: function(/*DOMNode*/ cell, /*String*/ blankGif){
-                       dojo.create("img", {
-                               src: blankGif,
-                               "class": "dijitPaletteImg",
-                               alt: this._alias
-                       }, cell);
-               }
+       // _imagePaths: [protected] Map
+       //              This is stores the path to the palette images used for high-contrast mode display
+       _imagePaths: {
+               "7x10": dojo.moduleUrl("dijit.themes", "a11y/colors7x10.png"),
+               "3x4": dojo.moduleUrl("dijit.themes", "a11y/colors3x4.png")
+       },
+
+       constructor: function(/*String*/alias, /*Number*/ row, /*Number*/ col){
+               this._alias = alias;
+               this._row = row;
+               this._col = col;
+               this.setColor(dojo.Color.named[alias]);
+       },
+
+       getValue: function(){
+               // summary:
+               //              Note that although dijit._Color is initialized with a value like "white" getValue() always
+               //              returns a hex value
+               return this.toHex();
+       },
+
+       fillCell: function(/*DOMNode*/ cell, /*String*/ blankGif){
+               var html = dojo.string.substitute(this.hc ? this.hcTemplate : this.template, {
+                       // substitution variables for normal mode
+                       color: this.toHex(),
+                       blankGif: blankGif,
+                       alt: this._alias,
+                       
+                       // variables used for high contrast mode
+                       image: this._imagePaths[this.palette].toString(),
+                       left: this._col * -20 - 5,
+                       top: this._row * -20 - 5,
+                       size: this.palette == "7x10" ? "height: 145px; width: 206px" : "height: 64px; width: 86px"
+               });
+
+               dojo.place(html, cell);
        }
-);
+});
 
 }
 
@@ -7589,6 +8091,8 @@ if(!dojo._hasResource["dojo.dnd.common"]){ //_hasResource checks added by build.
 dojo._hasResource["dojo.dnd.common"] = true;
 dojo.provide("dojo.dnd.common");
 
+dojo.getObject("dnd", true, dojo);
+
 dojo.dnd.getCopyKeyState = dojo.isCopyKey;
 
 dojo.dnd._uniqueId = 0;
@@ -7620,25 +8124,10 @@ if(!dojo._hasResource["dojo.dnd.autoscroll"]){ //_hasResource checks added by bu
 dojo._hasResource["dojo.dnd.autoscroll"] = true;
 dojo.provide("dojo.dnd.autoscroll");
 
-dojo.dnd.getViewport = function(){
-       // summary:
-       //              Returns a viewport size (visible part of the window)
-
-       // TODO: remove this when getViewport() moved to dojo core, see #7028
-
-       // FIXME: need more docs!!
-       var d = dojo.doc, dd = d.documentElement, w = window, b = dojo.body();
-       if(dojo.isMozilla){
-               return {w: dd.clientWidth, h: w.innerHeight};   // Object
-       }else if(!dojo.isOpera && w.innerWidth){
-               return {w: w.innerWidth, h: w.innerHeight};             // Object
-       }else if (!dojo.isOpera && dd && dd.clientWidth){
-               return {w: dd.clientWidth, h: dd.clientHeight}; // Object
-       }else if (b.clientWidth){
-               return {w: b.clientWidth, h: b.clientHeight};   // Object
-       }
-       return null;    // Object
-};
+
+dojo.getObject("dnd", true, dojo);
+
+dojo.dnd.getViewport = dojo.window.getBox;
 
 dojo.dnd.V_TRIGGER_AUTOSCROLL = 32;
 dojo.dnd.H_TRIGGER_AUTOSCROLL = 32;
@@ -7654,7 +8143,7 @@ dojo.dnd.autoScroll = function(e){
        //              onmousemove event
 
        // FIXME: needs more docs!
-       var v = dojo.dnd.getViewport(), dx = 0, dy = 0;
+       var v = dojo.window.getBox(), dx = 0, dy = 0;
        if(e.clientX < dojo.dnd.H_TRIGGER_AUTOSCROLL){
                dx = -dojo.dnd.H_AUTOSCROLL_VALUE;
        }else if(e.clientX > v.w - dojo.dnd.H_TRIGGER_AUTOSCROLL){
@@ -7685,14 +8174,15 @@ dojo.dnd.autoScrollNodes = function(e){
                        if(s.overflow.toLowerCase() in dojo.dnd._validOverflow){
                                var b = dojo._getContentBox(n, s), t = dojo.position(n, true);
                                //console.log(b.l, b.t, t.x, t.y, n.scrollLeft, n.scrollTop);
-                               var w = Math.min(dojo.dnd.H_TRIGGER_AUTOSCROLL, b.w / 2), 
+                               var w = Math.min(dojo.dnd.H_TRIGGER_AUTOSCROLL, b.w / 2),
                                        h = Math.min(dojo.dnd.V_TRIGGER_AUTOSCROLL, b.h / 2),
                                        rx = e.pageX - t.x, ry = e.pageY - t.y, dx = 0, dy = 0;
                                if(dojo.isWebKit || dojo.isOpera){
-                                       // FIXME: this code should not be here, it should be taken into account 
+                                       // FIXME: this code should not be here, it should be taken into account
                                        // either by the event fixing code, or the dojo.position()
                                        // FIXME: this code doesn't work on Opera 9.5 Beta
-                                       rx += dojo.body().scrollLeft, ry += dojo.body().scrollTop;
+                                       rx += dojo.body().scrollLeft;
+                                       ry += dojo.body().scrollTop;
                                }
                                if(rx > 0 && rx < b.w){
                                        if(rx < w){
@@ -7736,7 +8226,7 @@ dojo.provide("dojo.dnd.Mover");
 dojo.declare("dojo.dnd.Mover", null, {
        constructor: function(node, e, host){
                // summary:
-               //              an object, which makes a node follow the mouse. 
+               //              an object which makes a node follow the mouse, or touch-drag on touch devices.
                //              Used as a default mover, and as a base class for custom movers.
                // node: Node
                //              a node (or node's id) to be moved
@@ -7747,17 +8237,27 @@ dojo.declare("dojo.dnd.Mover", null, {
                //              object which implements the functionality of the move,
                //              and defines proper events (onMoveStart and onMoveStop)
                this.node = dojo.byId(node);
-               this.marginBox = {l: e.pageX, t: e.pageY};
+               var pos = e.touches ? e.touches[0] : e;
+               this.marginBox = {l: pos.pageX, t: pos.pageY};
                this.mouseButton = e.button;
-               var h = this.host = host, d = node.ownerDocument, 
-                       firstEvent = dojo.connect(d, "onmousemove", this, "onFirstMove");
+               var h = (this.host = host), d = node.ownerDocument;
                this.events = [
+                       // At the start of a drag, onFirstMove is called, and then the following two
+                       // connects are disconnected
+                       dojo.connect(d, "onmousemove", this, "onFirstMove"),
+                       dojo.connect(d, "ontouchmove", this, "onFirstMove"),
+
+                       // These are called continually during the drag
                        dojo.connect(d, "onmousemove", this, "onMouseMove"),
+                       dojo.connect(d, "ontouchmove", this, "onMouseMove"),
+
+                       // And these are called at the end of the drag
                        dojo.connect(d, "onmouseup",   this, "onMouseUp"),
+                       dojo.connect(d, "ontouchend", this, "onMouseUp"),
+
                        // cancel text selection and text dragging
                        dojo.connect(d, "ondragstart",   dojo.stopEvent),
-                       dojo.connect(d.body, "onselectstart", dojo.stopEvent),
-                       firstEvent
+                       dojo.connect(d.body, "onselectstart", dojo.stopEvent)
                ];
                // notify that the move has started
                if(h && h.onMoveStart){
@@ -7767,17 +8267,18 @@ dojo.declare("dojo.dnd.Mover", null, {
        // mouse event processors
        onMouseMove: function(e){
                // summary:
-               //              event processor for onmousemove
+               //              event processor for onmousemove/ontouchmove
                // e: Event
-               //              mouse event
+               //              mouse/touch event
                dojo.dnd.autoScroll(e);
-               var m = this.marginBox;
-               this.host.onMove(this, {l: m.l + e.pageX, t: m.t + e.pageY}, e);
+               var m = this.marginBox,
+                       pos = e.touches ? e.touches[0] : e;
+               this.host.onMove(this, {l: m.l + pos.pageX, t: m.t + pos.pageY}, e);
                dojo.stopEvent(e);
        },
        onMouseUp: function(e){
-               if(dojo.isWebKit && dojo.isMac && this.mouseButton == 2 ? 
-                               e.button == 0 : this.mouseButton == e.button){
+               if(dojo.isWebKit && dojo.isMac && this.mouseButton == 2 ?
+                               e.button == 0 : this.mouseButton == e.button){ // TODO Should condition be met for touch devices, too?
                        this.destroy();
                }
                dojo.stopEvent(e);
@@ -7785,7 +8286,7 @@ dojo.declare("dojo.dnd.Mover", null, {
        // utilities
        onFirstMove: function(e){
                // summary:
-               //              makes the node absolute; it is meant to be called only once. 
+               //              makes the node absolute; it is meant to be called only once.
                //              relative and absolutely positioned nodes are assumed to use pixel units
                var s = this.node.style, l, t, h = this.host;
                switch(s.position){
@@ -7805,7 +8306,7 @@ dojo.declare("dojo.dnd.Mover", null, {
                                // space into account - so we need to subtract the combined
                                // padding and margin.  We use getComputedStyle and
                                // _getMarginBox/_getContentBox to avoid the extra lookup of
-                               // the computed style. 
+                               // the computed style.
                                var b = dojo.doc.body;
                                var bs = dojo.getComputedStyle(b);
                                var bm = dojo._getMarginBox(b, bs);
@@ -7819,7 +8320,10 @@ dojo.declare("dojo.dnd.Mover", null, {
                if(h && h.onFirstMove){
                        h.onFirstMove(this, e);
                }
-               dojo.disconnect(this.events.pop());
+               
+               // Disconnect onmousemove and ontouchmove events that call this function
+               dojo.disconnect(this.events.shift());
+               dojo.disconnect(this.events.shift());
        },
        destroy: function(){
                // summary:
@@ -7886,6 +8390,7 @@ dojo.declare("dojo.dnd.Moveable", null, {
                this.mover = params.mover ? params.mover : dojo.dnd.Mover;
                this.events = [
                        dojo.connect(this.handle, "onmousedown", this, "onMouseDown"),
+                       dojo.connect(this.handle, "ontouchstart", this, "onMouseDown"),
                        // cancel text selection and text dragging
                        dojo.connect(this.handle, "ondragstart",   this, "onSelectStart"),
                        dojo.connect(this.handle, "onselectstart", this, "onSelectStart")
@@ -7908,17 +8413,20 @@ dojo.declare("dojo.dnd.Moveable", null, {
        // mouse event processors
        onMouseDown: function(e){
                // summary:
-               //              event processor for onmousedown, creates a Mover for the node
+               //              event processor for onmousedown/ontouchstart, creates a Mover for the node
                // e: Event
-               //              mouse event
+               //              mouse/touch event
                if(this.skip && dojo.dnd.isFormElement(e)){ return; }
                if(this.delay){
                        this.events.push(
                                dojo.connect(this.handle, "onmousemove", this, "onMouseMove"),
-                               dojo.connect(this.handle, "onmouseup", this, "onMouseUp")
+                               dojo.connect(this.handle, "ontouchmove", this, "onMouseMove"),
+                               dojo.connect(this.handle, "onmouseup", this, "onMouseUp"),
+                               dojo.connect(this.handle, "ontouchend", this, "onMouseUp")
                        );
-                       this._lastX = e.pageX;
-                       this._lastY = e.pageY;
+                       var pos = e.touches ? e.touches[0] : e;
+                       this._lastX = pos.pageX;
+                       this._lastY = pos.pageY;
                }else{
                        this.onDragDetected(e);
                }
@@ -7926,10 +8434,11 @@ dojo.declare("dojo.dnd.Moveable", null, {
        },
        onMouseMove: function(e){
                // summary:
-               //              event processor for onmousemove, used only for delayed drags
+               //              event processor for onmousemove/ontouchmove, used only for delayed drags
                // e: Event
-               //              mouse event
-               if(Math.abs(e.pageX - this._lastX) > this.delay || Math.abs(e.pageY - this._lastY) > this.delay){
+               //              mouse/touch event
+               var pos = e.touches ? e.touches[0] : e;
+               if(Math.abs(pos.pageX - this._lastX) > this.delay || Math.abs(pos.pageY - this._lastY) > this.delay){
                        this.onMouseUp(e);
                        this.onDragDetected(e);
                }
@@ -7966,8 +8475,8 @@ dojo.declare("dojo.dnd.Moveable", null, {
                // summary:
                //              called before every move operation
                dojo.publish("/dnd/move/start", [mover]);
-               dojo.addClass(dojo.body(), "dojoMove"); 
-               dojo.addClass(this.node, "dojoMoveItem"); 
+               dojo.addClass(dojo.body(), "dojoMove");
+               dojo.addClass(this.node, "dojoMoveItem");
        },
        onMoveStop: function(/* dojo.dnd.Mover */ mover){
                // summary:
@@ -8059,7 +8568,7 @@ dojo.declare("dojo.dnd.move.constrainedMoveable", dojo.dnd.Moveable, {
                c.r = c.l + c.w;
                c.b = c.t + c.h;
                if(this.within){
-                       var mb = dojo.marginBox(mover.node);
+                       var mb = dojo._getMarginSize(mover.node);
                        c.r -= mb.w;
                        c.b -= mb.h;
                }
@@ -8069,8 +8578,12 @@ dojo.declare("dojo.dnd.move.constrainedMoveable", dojo.dnd.Moveable, {
                //              called during every move notification;
                //              should actually move the node; can be overwritten.
                var c = this.constraintBox, s = mover.node.style;
-               s.left = (leftTop.l < c.l ? c.l : c.r < leftTop.l ? c.r : leftTop.l) + "px";
-               s.top  = (leftTop.t < c.t ? c.t : c.b < leftTop.t ? c.b : leftTop.t) + "px";
+               this.onMoving(mover, leftTop);
+               leftTop.l = leftTop.l < c.l ? c.l : c.r < leftTop.l ? c.r : leftTop.l;
+               leftTop.t = leftTop.t < c.t ? c.t : c.b < leftTop.t ? c.b : leftTop.t;
+               s.left = leftTop.l + "px";
+               s.top  = leftTop.t + "px";
+               this.onMoved(mover, leftTop);
        }
 });
 
@@ -8132,8 +8645,8 @@ dojo.declare("dojo.dnd.move.parentConstrainedMoveable", dojo.dnd.move.constraine
                //              an optional object with parameters
                var area = params && params.area;
                this.constraints = function(){
-                       var n = this.node.parentNode, 
-                               s = dojo.getComputedStyle(n), 
+                       var n = this.node.parentNode,
+                               s = dojo.getComputedStyle(n),
                                mb = dojo._getMarginBox(n, s);
                        if(area == "margin"){
                                return mb;      // Object
@@ -8155,100 +8668,6 @@ dojo.declare("dojo.dnd.move.parentConstrainedMoveable", dojo.dnd.move.constraine
        }
 });
 
-// WARNING: below are obsolete objects, instead of custom movers use custom moveables (above)
-
-dojo.dnd.move.constrainedMover = function(fun, within){
-       // summary:
-       //              returns a constrained version of dojo.dnd.Mover
-       // description:
-       //              this function produces n object, which will put a constraint on 
-       //              the margin box of dragged object in absolute coordinates
-       // fun: Function
-       //              called on drag, and returns a constraint box
-       // within: Boolean
-       //              if true, constraints the whole dragged object withtin the rectangle, 
-       //              otherwise the constraint is applied to the left-top corner
-
-       dojo.deprecated("dojo.dnd.move.constrainedMover, use dojo.dnd.move.constrainedMoveable instead");
-       var mover = function(node, e, notifier){
-               dojo.dnd.Mover.call(this, node, e, notifier);
-       };
-       dojo.extend(mover, dojo.dnd.Mover.prototype);
-       dojo.extend(mover, {
-               onMouseMove: function(e){
-                       // summary: event processor for onmousemove
-                       // e: Event: mouse event
-                       dojo.dnd.autoScroll(e);
-                       var m = this.marginBox, c = this.constraintBox,
-                               l = m.l + e.pageX, t = m.t + e.pageY;
-                       l = l < c.l ? c.l : c.r < l ? c.r : l;
-                       t = t < c.t ? c.t : c.b < t ? c.b : t;
-                       this.host.onMove(this, {l: l, t: t});
-               },
-               onFirstMove: function(){
-                       // summary: called once to initialize things; it is meant to be called only once
-                       dojo.dnd.Mover.prototype.onFirstMove.call(this);
-                       var c = this.constraintBox = fun.call(this);
-                       c.r = c.l + c.w;
-                       c.b = c.t + c.h;
-                       if(within){
-                               var mb = dojo.marginBox(this.node);
-                               c.r -= mb.w;
-                               c.b -= mb.h;
-                       }
-               }
-       });
-       return mover;   // Object
-};
-
-dojo.dnd.move.boxConstrainedMover = function(box, within){
-       // summary:
-       //              a specialization of dojo.dnd.constrainedMover, which constrains to the specified box
-       // box: Object
-       //              a constraint box (l, t, w, h)
-       // within: Boolean
-       //              if true, constraints the whole dragged object withtin the rectangle, 
-       //              otherwise the constraint is applied to the left-top corner
-
-       dojo.deprecated("dojo.dnd.move.boxConstrainedMover, use dojo.dnd.move.boxConstrainedMoveable instead");
-       return dojo.dnd.move.constrainedMover(function(){ return box; }, within);       // Object
-};
-
-dojo.dnd.move.parentConstrainedMover = function(area, within){
-       // summary:
-       //              a specialization of dojo.dnd.constrainedMover, which constrains to the parent node
-       // area: String
-       //              "margin" to constrain within the parent's margin box, "border" for the border box,
-       //              "padding" for the padding box, and "content" for the content box; "content" is the default value.
-       // within: Boolean
-       //              if true, constraints the whole dragged object within the rectangle, 
-       //              otherwise the constraint is applied to the left-top corner
-
-       dojo.deprecated("dojo.dnd.move.parentConstrainedMover, use dojo.dnd.move.parentConstrainedMoveable instead");
-       var fun = function(){
-               var n = this.node.parentNode, 
-                       s = dojo.getComputedStyle(n), 
-                       mb = dojo._getMarginBox(n, s);
-               if(area == "margin"){
-                       return mb;      // Object
-               }
-               var t = dojo._getMarginExtents(n, s);
-               mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
-               if(area == "border"){
-                       return mb;      // Object
-               }
-               t = dojo._getBorderExtents(n, s);
-               mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
-               if(area == "padding"){
-                       return mb;      // Object
-               }
-               t = dojo._getPadExtents(n, s);
-               mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
-               return mb;      // Object
-       };
-       return dojo.dnd.move.constrainedMover(fun, within);     // Object
-};
-
 // patching functions one level up for compatibility
 
 dojo.dnd.constrainedMover = dojo.dnd.move.constrainedMover;
@@ -8279,7 +8698,7 @@ dojo.declare("dojo.dnd.__TimedMoveableArgs", [dojo.dnd.__MoveableArgs], {
        dojo.declare("dojo.dnd.TimedMoveable", dojo.dnd.Moveable, {
                // summary:
                //              A specialized version of Moveable to support an FPS throttling.
-               //              This class puts an upper restriction on FPS, which may reduce 
+               //              This class puts an upper restriction on FPS, which may reduce
                //              the CPU load. The additional parameter "timeout" regulates
                //              the delay before actually moving the moveable object.
                
@@ -8338,8 +8757,7 @@ dojo.provide("dijit.form._FormMixin");
 
 
 
-dojo.declare("dijit.form._FormMixin", null,
-       {
+dojo.declare("dijit.form._FormMixin", null, {
        // summary:
        //              Mixin for containers of form widgets (i.e. widgets that represent a single value
        //              and can be children of a <form> node or dijit.form.Form widget)
@@ -8350,10 +8768,10 @@ dojo.declare("dijit.form._FormMixin", null,
        //              form widgets
 
 /*=====
-    // value: Object
+       // value: Object
        //              Name/value hash for each child widget with a name and value.
        //              Child widgets without names are not part of the hash.
-       // 
+       //
        //              If there are multiple child widgets w/the same name, value is an array,
        //              unless they are radio buttons in which case value is a scalar (since only
        //              one radio button can be checked at a time).
@@ -8364,6 +8782,12 @@ dojo.declare("dijit.form._FormMixin", null,
        //      |       { name: "John Smith", interests: ["sports", "movies"] }
 =====*/
 
+       // state: [readonly] String
+       //              Will be "Error" if one or more of the child widgets has an invalid value,
+       //              "Incomplete" if not all of the required child widgets are filled in.  Otherwise, "",
+       //              which indicates that the form is ready to be submitted.
+       state: "",
+
        //      TODO:
        //      * Repeater
        //      * better handling for arrays.  Often form elements have names with [] like
@@ -8382,11 +8806,11 @@ dojo.declare("dijit.form._FormMixin", null,
                validate: function(){
                        // summary:
                        //              returns if the form is valid - same as isValid - but
-                       //                      provides a few additional (ui-specific) features.
-                       //                      1 - it will highlight any sub-widgets that are not
-                       //                              valid
-                       //                      2 - it will call focus() on the first invalid
-                       //                              sub-widget
+                       //              provides a few additional (ui-specific) features.
+                       //              1 - it will highlight any sub-widgets that are not
+                       //                      valid
+                       //              2 - it will call focus() on the first invalid
+                       //                      sub-widget
                        var didFocus = false;
                        return dojo.every(dojo.map(this.getDescendants(), function(widget){
                                // Need to set this so that "required" widgets get their
@@ -8407,9 +8831,9 @@ dojo.declare("dijit.form._FormMixin", null,
                        dojo.deprecated(this.declaredClass+"::setValues() is deprecated. Use set('value', val) instead.", "", "2.0");
                        return this.set('value', val);
                },
-               _setValueAttr: function(/*object*/obj){
+               _setValueAttr: function(/*Object*/ obj){
                        // summary:
-                       //              Fill in form values from according to an Object (in the format returned by attr('value'))
+                       //              Fill in form values from according to an Object (in the format returned by get('value'))
 
                        // generate map from name --> [list of widgets with that name]
                        var map = { };
@@ -8487,7 +8911,7 @@ dojo.declare("dijit.form._FormMixin", null,
                                        return;         // like "continue"
                                }
 
-                               // TODO: widget values (just call attr('value', ...) on the widget)
+                               // TODO: widget values (just call set('value', ...) on the widget)
 
                                // TODO: maybe should call dojo.getNodeProp() instead
                                switch(element.type){
@@ -8519,6 +8943,9 @@ dojo.declare("dijit.form._FormMixin", null,
                                }
                        });
                        */
+                       
+                       // Note: no need to call this._set("value", ...) as the child updates will trigger onChange events
+                       // which I am monitoring.
                },
 
                getValues: function(){
@@ -8527,17 +8954,18 @@ dojo.declare("dijit.form._FormMixin", null,
                },
                _getValueAttr: function(){
                        // summary:
-                       //              Returns Object representing form values.
+                       //              Returns Object representing form values.   See description of `value` for details.
                        // description:
-                       //              Returns name/value hash for each form element.
-                       //              If there are multiple elements w/the same name, value is an array,
-                       //              unless they are radio buttons in which case value is a scalar since only
-                       //              one can be checked at a time.
+
+                       // The value is updated into this.value every time a child has an onChange event,
+                       // so in the common case this function could just return this.value.   However,
+                       // that wouldn't work when:
                        //
-                       //              If the name is a dot separated list (like a.b.c.d), creates a nested structure.
-                       //              Only works on widget form elements.
-                       // example:
-                       //              | { name: "John Smith", interests: ["sports", "movies"] }
+                       // 1. User presses return key to submit a form.  That doesn't fire an onchange event,
+                       // and even if it did it would come too late due to the setTimout(..., 0) in _handleOnChange()
+                       //
+                       // 2. app for some reason calls this.get("value") while the user is typing into a
+                       // form field.   Not sure if that case needs to be supported or not.
 
                        // get widget values
                        var obj = { };
@@ -8545,7 +8973,7 @@ dojo.declare("dijit.form._FormMixin", null,
                                var name = widget.name;
                                if(!name || widget.disabled){ return; }
 
-                               // Single value widget (checkbox, radio, or plain <input> type widget
+                               // Single value widget (checkbox, radio, or plain <input> type widget)
                                var value = widget.get('value');
 
                                // Store widget's value(s) as a scalar, except for checkboxes which are automatically arrays
@@ -8648,98 +9076,132 @@ dojo.declare("dijit.form._FormMixin", null,
                        return obj;
                },
 
-               // TODO: ComboBox might need time to process a recently input value.  This should be async?
                isValid: function(){
                        // summary:
-                       //              Returns true if all of the widgets are valid
+                       //              Returns true if all of the widgets are valid.
+                       //              Deprecated, will be removed in 2.0.  Use get("state") instead.
 
-                       // This also populate this._invalidWidgets[] array with list of invalid widgets...
-                       // TODO: put that into separate function?   It's confusing to have that as a side effect
-                       // of a method named isValid().
-
-                       this._invalidWidgets = dojo.filter(this.getDescendants(), function(widget){
-                               return !widget.disabled && widget.isValid && !widget.isValid();
-                       });
-                       return !this._invalidWidgets.length;
+                       return this.state == "";
                },
 
-
                onValidStateChange: function(isValid){
                        // summary:
                        //              Stub function to connect to if you want to do something
                        //              (like disable/enable a submit button) when the valid
                        //              state changes on the form as a whole.
+                       //
+                       //              Deprecated.  Will be removed in 2.0.  Use watch("state", ...) instead.
                },
 
-               _widgetChange: function(widget){
+               _getState: function(){
                        // summary:
-                       //              Connected to a widget's onChange function - update our
-                       //              valid state, if needed.
-                       var isValid = this._lastValidState;
-                       if(!widget || this._lastValidState === undefined){
-                               // We have passed a null widget, or we haven't been validated
-                               // yet - let's re-check all our children
-                               // This happens when we connect (or reconnect) our children
-                               isValid = this.isValid();
-                               if(this._lastValidState === undefined){
-                                       // Set this so that we don't fire an onValidStateChange
-                                       // the first time
-                                       this._lastValidState = isValid;
-                               }
-                       }else if(widget.isValid){
-                               this._invalidWidgets = dojo.filter(this._invalidWidgets || [], function(w){
-                                       return (w != widget);
-                               }, this);
-                               if(!widget.isValid() && !widget.get("disabled")){
-                                       this._invalidWidgets.push(widget);
-                               }
-                               isValid = (this._invalidWidgets.length === 0);
-                       }
-                       if(isValid !== this._lastValidState){
-                               this._lastValidState = isValid;
-                               this.onValidStateChange(isValid);
-                       }
+                       //              Compute what this.state should be based on state of children
+                       var states = dojo.map(this._descendants, function(w){
+                               return w.get("state") || "";
+                       });
+
+                       return dojo.indexOf(states, "Error") >= 0 ? "Error" :
+                               dojo.indexOf(states, "Incomplete") >= 0 ? "Incomplete" : "";
                },
 
-               connectChildren: function(){
+               disconnectChildren: function(){
                        // summary:
-                       //              Connects to the onChange function of all children to
-                       //              track valid state changes.  You can call this function
-                       //              directly, ex. in the event that you programmatically
-                       //              add a widget to the form *after* the form has been
+                       //              Remove connections to monitor changes to children's value, error state, and disabled state,
+                       //              in order to update Form.value and Form.state.
+                       dojo.forEach(this._childConnections || [], dojo.hitch(this, "disconnect"));
+                       dojo.forEach(this._childWatches || [], function(w){ w.unwatch(); });
+               },
+
+               connectChildren: function(/*Boolean*/ inStartup){
+                       // summary:
+                       //              Setup connections to monitor changes to children's value, error state, and disabled state,
+                       //              in order to update Form.value and Form.state.
+                       //
+                       //              You can call this function directly, ex. in the event that you
+                       //              programmatically add a widget to the form *after* the form has been
                        //              initialized.
-                       dojo.forEach(this._changeConnections, dojo.hitch(this, "disconnect"));
+
                        var _this = this;
 
-                       // we connect to validate - so that it better reflects the states
-                       // of the widgets - also, we only connect if it has a validate
-                       // function (to avoid too many unneeded connections)
-                       var conns = (this._changeConnections = []);
-                       dojo.forEach(dojo.filter(this.getDescendants(),
+                       // Remove old connections, if any
+                       this.disconnectChildren();
+
+                       this._descendants = this.getDescendants();
+
+                       // (Re)set this.value and this.state.   Send watch() notifications but not on startup.
+                       var set = inStartup ? function(name, val){ _this[name] = val; } : dojo.hitch(this, "_set");
+                       set("value", this.get("value"));
+                       set("state", this._getState());
+
+                       // Monitor changes to error state and disabled state in order to update
+                       // Form.state
+                       var conns = (this._childConnections = []),
+                               watches = (this._childWatches = []);
+                       dojo.forEach(dojo.filter(this._descendants,
                                function(item){ return item.validate; }
                        ),
                        function(widget){
-                               // We are interested in whenever the widget is validated - or
-                               // whenever the disabled attribute on that widget is changed
-                               conns.push(_this.connect(widget, "validate",
-                                                                       dojo.hitch(_this, "_widgetChange", widget)));
-                               conns.push(_this.connect(widget, "_setDisabledAttr",
-                                                                       dojo.hitch(_this, "_widgetChange", widget)));
+                               // We are interested in whenever the widget changes validity state - or
+                               // whenever the disabled attribute on that widget is changed.
+                               dojo.forEach(["state", "disabled"], function(attr){
+                                       watches.push(widget.watch(attr, function(attr, oldVal, newVal){
+                                               _this.set("state", _this._getState());
+                                       }));
+                               });
                        });
 
-                       // Call the widget change function to update the valid state, in
-                       // case something is different now.
-                       this._widgetChange(null);
+                       // And monitor calls to child.onChange so we can update this.value
+                       var onChange = function(){
+                               // summary:
+                               //              Called when child's value or disabled state changes
+                               
+                               // Use setTimeout() to collapse value changes in multiple children into a single
+                               // update to my value.   Multiple updates will occur on:
+                               //      1. Form.set()
+                               //      2. Form.reset()
+                               //      3. user selecting a radio button (which will de-select another radio button,
+                               //               causing two onChange events)
+                               if(_this._onChangeDelayTimer){
+                                       clearTimeout(_this._onChangeDelayTimer);
+                               }
+                               _this._onChangeDelayTimer = setTimeout(function(){
+                                       delete _this._onChangeDelayTimer;
+                                       _this._set("value", _this.get("value"));
+                               }, 10);
+                       };
+                       dojo.forEach(
+                               dojo.filter(this._descendants, function(item){ return item.onChange; } ),
+                               function(widget){
+                                       // When a child widget's value changes,
+                                       // the efficient thing to do is to just update that one attribute in this.value,
+                                       // but that gets a little complicated when a checkbox is checked/unchecked
+                                       // since this.value["checkboxName"] contains an array of all the checkboxes w/the same name.
+                                       // Doing simple thing for now.
+                                       conns.push(_this.connect(widget, "onChange", onChange));
+
+                                       // Disabling/enabling a child widget should remove it's value from this.value.
+                                       // Again, this code could be more efficient, doing simple thing for now.
+                                       watches.push(widget.watch("disabled", onChange));
+                               }
+                       );
                },
 
                startup: function(){
                        this.inherited(arguments);
-                       // Initialize our valid state tracking.  Needs to be done in startup
-                       // because it's not guaranteed that our children are initialized
-                       // yet.
-                       this._changeConnections = [];
-                       this.connectChildren();
+
+                       // Initialize value and valid/invalid state tracking.  Needs to be done in startup()
+                       // so that children are initialized.
+                       this.connectChildren(true);
+
+                       // Make state change call onValidStateChange(), will be removed in 2.0
+                       this.watch("state", function(attr, oldVal, newVal){ this.onValidStateChange(newVal == ""); });
+               },
+
+               destroy: function(){
+                       this.disconnectChildren();
+                       this.inherited(arguments);
                }
+
        });
 
 }
@@ -8802,22 +9264,16 @@ dojo.declare("dijit._DialogMixin", null,
                        this.execute(this.get('value'));
                },
 
-               _getFocusItems: function(/*Node*/ dialogNode){
+               _getFocusItems: function(){
                        // summary:
-                       //              Find focusable Items each time a dialog is opened,
-                       //              setting _firstFocusItem and _lastFocusItem
+                       //              Finds focusable items in dialog,
+                       //              and sets this._firstFocusItem and this._lastFocusItem
                        // tags:
                        //              protected
 
-                       var elems = dijit._getTabNavigable(dojo.byId(dialogNode));
-                       this._firstFocusItem = elems.lowest || elems.first || dialogNode;
+                       var elems = dijit._getTabNavigable(this.containerNode);
+                       this._firstFocusItem = elems.lowest || elems.first || this.closeButtonNode || this.domNode;
                        this._lastFocusItem = elems.last || elems.highest || this._firstFocusItem;
-                       if(dojo.isMoz && this._firstFocusItem.tagName.toLowerCase() == "input" &&
-                                       dojo.getNodeProp(this._firstFocusItem, "type").toLowerCase() == "file"){
-                               // FF doesn't behave well when first element is input type=file, set first focusable to dialog container
-                               dojo.attr(dialogNode, "tabIndex", "0");
-                               this._firstFocusItem = dialogNode;
-                       }
                }
        }
 );
@@ -8832,7 +9288,6 @@ dojo.provide("dijit.DialogUnderlay");
 
 
 
-
 dojo.declare(
        "dijit.DialogUnderlay",
        [dijit._Widget, dijit._Templated],
@@ -8851,87 +9306,337 @@ dojo.declare(
                //              In the case of `dijit.Dialog`, this id is based on the id of the Dialog,
                //              suffixed with _underlay.
 
-               // Template has two divs; outer div is used for fade-in/fade-out, and also to hold background iframe.
-               // Inner div has opacity specified in CSS file.
-               templateString: "<div class='dijitDialogUnderlayWrapper'><div class='dijitDialogUnderlay' dojoAttachPoint='node'></div></div>",
+               // Template has two divs; outer div is used for fade-in/fade-out, and also to hold background iframe.
+               // Inner div has opacity specified in CSS file.
+               templateString: "<div class='dijitDialogUnderlayWrapper'><div class='dijitDialogUnderlay' dojoAttachPoint='node'></div></div>",
+
+               // Parameters on creation or updatable later
+
+               // dialogId: String
+               //              Id of the dialog.... DialogUnderlay's id is based on this id
+               dialogId: "",
+
+               // class: String
+               //              This class name is used on the DialogUnderlay node, in addition to dijitDialogUnderlay
+               "class": "",
+
+               attributeMap: { id: "domNode" },
+
+               _setDialogIdAttr: function(id){
+                       dojo.attr(this.node, "id", id + "_underlay");
+                       this._set("dialogId", id);
+               },
+
+               _setClassAttr: function(clazz){
+                       this.node.className = "dijitDialogUnderlay " + clazz;
+                       this._set("class", clazz);
+               },
+
+               postCreate: function(){
+                       // summary:
+                       //              Append the underlay to the body
+                       dojo.body().appendChild(this.domNode);
+               },
+
+               layout: function(){
+                       // summary:
+                       //              Sets the background to the size of the viewport
+                       //
+                       // description:
+                       //              Sets the background to the size of the viewport (rather than the size
+                       //              of the document) since we need to cover the whole browser window, even
+                       //              if the document is only a few lines long.
+                       // tags:
+                       //              private
+
+                       var is = this.node.style,
+                               os = this.domNode.style;
+
+                       // hide the background temporarily, so that the background itself isn't
+                       // causing scrollbars to appear (might happen when user shrinks browser
+                       // window and then we are called to resize)
+                       os.display = "none";
+
+                       // then resize and show
+                       var viewport = dojo.window.getBox();
+                       os.top = viewport.t + "px";
+                       os.left = viewport.l + "px";
+                       is.width = viewport.w + "px";
+                       is.height = viewport.h + "px";
+                       os.display = "block";
+               },
+
+               show: function(){
+                       // summary:
+                       //              Show the dialog underlay
+                       this.domNode.style.display = "block";
+                       this.layout();
+                       this.bgIframe = new dijit.BackgroundIframe(this.domNode);
+               },
+
+               hide: function(){
+                       // summary:
+                       //              Hides the dialog underlay
+                       this.bgIframe.destroy();
+                       delete this.bgIframe;
+                       this.domNode.style.display = "none";
+               }
+       }
+);
+
+}
+
+if(!dojo._hasResource["dijit.layout._ContentPaneResizeMixin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout._ContentPaneResizeMixin"] = true;
+dojo.provide("dijit.layout._ContentPaneResizeMixin");
+
+
+
+
+dojo.declare("dijit.layout._ContentPaneResizeMixin", null, {
+       // summary:
+       //              Resize() functionality of ContentPane.   If there's a single layout widget
+       //              child then it will call resize() with the same dimensions as the ContentPane.
+       //              Otherwise just calls resize on each child.
+       //
+       //              Also implements basic startup() functionality, where starting the parent
+       //              will start the children
+
+       // doLayout: Boolean
+       //              - false - don't adjust size of children
+       //              - true - if there is a single visible child widget, set it's size to
+       //                              however big the ContentPane is
+       doLayout: true,
+
+       // isContainer: [protected] Boolean
+       //              Indicates that this widget acts as a "parent" to the descendant widgets.
+       //              When the parent is started it will call startup() on the child widgets.
+       //              See also `isLayoutContainer`.
+       isContainer: true,
+
+       // isLayoutContainer: [protected] Boolean
+       //              Indicates that this widget will call resize() on it's child widgets
+       //              when they become visible.
+       isLayoutContainer: true,
+
+       _startChildren: function(){
+               // summary:
+               //              Call startup() on all children including non _Widget ones like dojo.dnd.Source objects
+
+               // This starts all the widgets
+               dojo.forEach(this.getChildren(), function(child){
+                       child.startup();
+                       child._started = true;
+               });
+       },
+
+       startup: function(){
+               // summary:
+               //              See `dijit.layout._LayoutWidget.startup` for description.
+               //              Although ContentPane doesn't extend _LayoutWidget, it does implement
+               //              the same API.
+
+               if(this._started){ return; }
+
+               var parent = dijit._Contained.prototype.getParent.call(this);
+               this._childOfLayoutWidget = parent && parent.isLayoutContainer;
+
+               // I need to call resize() on my child/children (when I become visible), unless
+               // I'm the child of a layout widget in which case my parent will call resize() on me and I'll do it then.
+               this._needLayout = !this._childOfLayoutWidget;
+
+               this.inherited(arguments);
+
+               this._startChildren();
+
+               if(this._isShown()){
+                       this._onShow();
+               }
+
+               if(!this._childOfLayoutWidget){
+                       // If my parent isn't a layout container, since my style *may be* width=height=100%
+                       // or something similar (either set directly or via a CSS class),
+                       // monitor when my size changes so that I can re-layout.
+                       // For browsers where I can't directly monitor when my size changes,
+                       // monitor when the viewport changes size, which *may* indicate a size change for me.
+                       this.connect(dojo.isIE ? this.domNode : dojo.global, 'onresize', function(){
+                               // Using function(){} closure to ensure no arguments to resize.
+                               this._needLayout = !this._childOfLayoutWidget;
+                               this.resize();
+                       });
+               }
+       },
+
+       _checkIfSingleChild: function(){
+               // summary:
+               //              Test if we have exactly one visible widget as a child,
+               //              and if so assume that we are a container for that widget,
+               //              and should propagate startup() and resize() calls to it.
+               //              Skips over things like data stores since they aren't visible.
+
+               var childNodes = dojo.query("> *", this.containerNode).filter(function(node){
+                               return node.tagName !== "SCRIPT"; // or a regexp for hidden elements like script|area|map|etc..
+                       }),
+                       childWidgetNodes = childNodes.filter(function(node){
+                               return dojo.hasAttr(node, "data-dojo-type") || dojo.hasAttr(node, "dojoType") || dojo.hasAttr(node, "widgetId");
+                       }),
+                       candidateWidgets = dojo.filter(childWidgetNodes.map(dijit.byNode), function(widget){
+                               return widget && widget.domNode && widget.resize;
+                       });
+
+               if(
+                       // all child nodes are widgets
+                       childNodes.length == childWidgetNodes.length &&
+
+                       // all but one are invisible (like dojo.data)
+                       candidateWidgets.length == 1
+               ){
+                       this._singleChild = candidateWidgets[0];
+               }else{
+                       delete this._singleChild;
+               }
+
+               // So we can set overflow: hidden to avoid a safari bug w/scrollbars showing up (#9449)
+               dojo.toggleClass(this.containerNode, this.baseClass + "SingleChild", !!this._singleChild);
+       },
+
+       resize: function(changeSize, resultSize){
+               // summary:
+               //              See `dijit.layout._LayoutWidget.resize` for description.
+               //              Although ContentPane doesn't extend _LayoutWidget, it does implement
+               //              the same API.
+
+               // For the TabContainer --> BorderContainer --> ContentPane case, _onShow() is
+               // never called, so resize() is our trigger to do the initial href download (see [20099]).
+               // However, don't load href for closed TitlePanes.
+               if(!this._wasShown && this.open !== false){
+                       this._onShow();
+               }
 
-               // Parameters on creation or updatable later
+               this._resizeCalled = true;
 
-               // dialogId: String
-               //              Id of the dialog.... DialogUnderlay's id is based on this id
-               dialogId: "",
+               this._scheduleLayout(changeSize, resultSize);
+       },
 
-               // class: String
-               //              This class name is used on the DialogUnderlay node, in addition to dijitDialogUnderlay
-               "class": "",
+       _scheduleLayout: function(changeSize, resultSize){
+               // summary:
+               //              Resize myself, and call resize() on each of my child layout widgets, either now
+               //              (if I'm currently visible) or when I become visible
+               if(this._isShown()){
+                       this._layout(changeSize, resultSize);
+               }else{
+                       this._needLayout = true;
+                       this._changeSize = changeSize;
+                       this._resultSize = resultSize;
+               }
+       },
 
-               attributeMap: { id: "domNode" },
+       _layout: function(changeSize, resultSize){
+               // summary:
+               //              Resize myself according to optional changeSize/resultSize parameters, like a layout widget.
+               //              Also, since I am a Container widget, each of my children expects me to
+               //              call resize() or layout() on them.
+               //
+               //              Should be called on initialization and also whenever we get new content
+               //              (from an href, or from set('content', ...))... but deferred until
+               //              the ContentPane is visible
 
-               _setDialogIdAttr: function(id){
-                       dojo.attr(this.node, "id", id + "_underlay");
-               },
+               // Set margin box size, unless it wasn't specified, in which case use current size.
+               if(changeSize){
+                       dojo.marginBox(this.domNode, changeSize);
+               }
 
-               _setClassAttr: function(clazz){
-                       this.node.className = "dijitDialogUnderlay " + clazz;
-               },
+               // Compute content box size of containerNode in case we [later] need to size our single child.
+               var cn = this.containerNode;
+               if(cn === this.domNode){
+                       // If changeSize or resultSize was passed to this method and this.containerNode ==
+                       // this.domNode then we can compute the content-box size without querying the node,
+                       // which is more reliable (similar to LayoutWidget.resize) (see for example #9449).
+                       var mb = resultSize || {};
+                       dojo.mixin(mb, changeSize || {}); // changeSize overrides resultSize
+                       if(!("h" in mb) || !("w" in mb)){
+                               mb = dojo.mixin(dojo.marginBox(cn), mb); // just use dojo.marginBox() to fill in missing values
+                       }
+                       this._contentBox = dijit.layout.marginBox2contentBox(cn, mb);
+               }else{
+                       this._contentBox = dojo.contentBox(cn);
+               }
 
-               postCreate: function(){
-                       // summary:
-                       //              Append the underlay to the body
-                       dojo.body().appendChild(this.domNode);
-               },
+               this._layoutChildren();
 
-               layout: function(){
-                       // summary:
-                       //              Sets the background to the size of the viewport
-                       //
-                       // description:
-                       //              Sets the background to the size of the viewport (rather than the size
-                       //              of the document) since we need to cover the whole browser window, even
-                       //              if the document is only a few lines long.
-                       // tags:
-                       //              private
+               delete this._needLayout;
+       },
+       
+       _layoutChildren: function(){
+               // Call _checkIfSingleChild() again in case app has manually mucked w/the content
+               // of the ContentPane (rather than changing it through the set("content", ...) API.
+               if(this.doLayout){
+                       this._checkIfSingleChild();
+               }
 
-                       var is = this.node.style,
-                               os = this.domNode.style;
+               if(this._singleChild && this._singleChild.resize){
+                       var cb = this._contentBox || dojo.contentBox(this.containerNode);
 
-                       // hide the background temporarily, so that the background itself isn't
-                       // causing scrollbars to appear (might happen when user shrinks browser
-                       // window and then we are called to resize)
-                       os.display = "none";
+                       // note: if widget has padding this._contentBox will have l and t set,
+                       // but don't pass them to resize() or it will doubly-offset the child
+                       this._singleChild.resize({w: cb.w, h: cb.h});
+               }else{
+                       // All my child widgets are independently sized (rather than matching my size),
+                       // but I still need to call resize() on each child to make it layout.
+                       dojo.forEach(this.getChildren(), function(widget){
+                               if(widget.resize){
+                                       widget.resize();
+                               }
+                       });
+               }
+       },
 
-                       // then resize and show
-                       var viewport = dojo.window.getBox();
-                       os.top = viewport.t + "px";
-                       os.left = viewport.l + "px";
-                       is.width = viewport.w + "px";
-                       is.height = viewport.h + "px";
-                       os.display = "block";
-               },
+       _isShown: function(){
+               // summary:
+               //              Returns true if the content is currently shown.
+               // description:
+               //              If I am a child of a layout widget then it actually returns true if I've ever been visible,
+               //              not whether I'm currently visible, since that's much faster than tracing up the DOM/widget
+               //              tree every call, and at least solves the performance problem on page load by deferring loading
+               //              hidden ContentPanes until they are first shown
 
-               show: function(){
-                       // summary:
-                       //              Show the dialog underlay
-                       this.domNode.style.display = "block";
-                       this.layout();
-                       this.bgIframe = new dijit.BackgroundIframe(this.domNode);
-               },
+               if(this._childOfLayoutWidget){
+                       // If we are TitlePane, etc - we return that only *IF* we've been resized
+                       if(this._resizeCalled && "open" in this){
+                               return this.open;
+                       }
+                       return this._resizeCalled;
+               }else if("open" in this){
+                       return this.open;               // for TitlePane, etc.
+               }else{
+                       var node = this.domNode, parent = this.domNode.parentNode;
+                       return (node.style.display != 'none') && (node.style.visibility != 'hidden') && !dojo.hasClass(node, "dijitHidden") &&
+                                       parent && parent.style && (parent.style.display != 'none');
+               }
+       },
 
-               hide: function(){
-                       // summary:
-                       //              Hides the dialog underlay
-                       this.bgIframe.destroy();
-                       this.domNode.style.display = "none";
-               },
+       _onShow: function(){
+               // summary:
+               //              Called when the ContentPane is made visible
+               // description:
+               //              For a plain ContentPane, this is called on initialization, from startup().
+               //              If the ContentPane is a hidden pane of a TabContainer etc., then it's
+               //              called whenever the pane is made visible.
+               //
+               //              Does layout/resize of child widget(s)
 
-               uninitialize: function(){
-                       if(this.bgIframe){
-                               this.bgIframe.destroy();
-                       }
-                       this.inherited(arguments);
+               if(this._needLayout){
+                       // If a layout has been scheduled for when we become visible, do it now
+                       this._layout(this._changeSize, this._resultSize);
                }
+
+               this.inherited(arguments);
+
+               // Need to keep track of whether ContentPane has been shown (which is different than
+               // whether or not it's currently visible).
+               this._wasShown = true;
        }
-);
+});
 
 }
 
@@ -8939,24 +9644,25 @@ if(!dojo._hasResource["dojo.html"]){ //_hasResource checks added by build. Do no
 dojo._hasResource["dojo.html"] = true;
 dojo.provide("dojo.html");
 
-// the parser might be needed..
 
+dojo.getObject("html", true, dojo);
+
+// the parser might be needed..
 (function(){ // private scope, sort of a namespace
 
        // idCounter is incremented with each instantiation to allow asignment of a unique id for tracking, logging purposes
-       var idCounter = 0, 
+       var idCounter = 0,
                d = dojo;
        
        dojo.html._secureForInnerHtml = function(/*String*/ cont){
                // summary:
                //              removes !DOCTYPE and title elements from the html string.
-               // 
+               //
                //              khtml is picky about dom faults, you can't attach a style or <title> node as child of body
                //              must go into head, so we need to cut out those tags
                //      cont:
                //              An html string for insertion into the dom
-               //      
+               //
                return cont.replace(/(?:\s*<!DOCTYPE\s[^>]+>|<title[^>]*>[\s\S]*?<\/title>)/ig, ""); // String
        };
 
@@ -8976,7 +9682,7 @@ dojo.provide("dojo.html");
                //      node:
                //              the parent element
                //      content:
-               //              the content to be set on the parent element. 
+               //              the content to be set on the parent element.
                //              This can be an html string, a node reference or a NodeList, dojo.NodeList, Array or other enumerable list of nodes
                
                // always empty
@@ -9002,7 +9708,7 @@ dojo.provide("dojo.html");
        };
 
        // we wrap up the content-setting operation in a object
-       dojo.declare("dojo.html._ContentSetter", null, 
+       dojo.declare("dojo.html._ContentSetter", null,
                {
                        // node: DomNode|String
                        //              An node which will be the parent element that we set content into
@@ -9013,11 +9719,11 @@ dojo.provide("dojo.html");
                        content: "",
                        
                        // id: String?
-                       //              Usually only used internally, and auto-generated with each instance 
+                       //              Usually only used internally, and auto-generated with each instance
                        id: "",
 
                        // cleanContent: Boolean
-                       //              Should the content be treated as a full html document, 
+                       //              Should the content be treated as a full html document,
                        //              and the real content stripped of <html>, <body> wrapper before injection
                        cleanContent: false,
                        
@@ -9028,6 +9734,17 @@ dojo.provide("dojo.html");
                        // parseContent: Boolean
                        //              Should the node by passed to the parser after the new content is set
                        parseContent: false,
+
+                       // parserScope: String
+                       //              Flag passed to parser.  Root for attribute names to search for.   If scopeName is dojo,
+                       //              will search for data-dojo-type (or dojoType).  For backwards compatibility
+                       //              reasons defaults to dojo._scopeName (which is "dojo" except when
+                       //              multi-version support is used, when it will be something like dojo16, dojo20, etc.)
+                       parserScope: dojo._scopeName,
+
+                       // startup: Boolean
+                       //              Start the child widgets after parsing them.   Only obeyed if parseContent is true.
+                       startup: true,
                        
                        // lifecyle methods
                        constructor: function(/* Object */params, /* String|DomNode */node){
@@ -9045,14 +9762,14 @@ dojo.provide("dojo.html");
                                if(!this.id){
                                        this.id = [
                                                "Setter",
-                                               (node) ? node.id || node.tagName : "", 
+                                               (node) ? node.id || node.tagName : "",
                                                idCounter++
                                        ].join("_");
                                }
                        },
                        set: function(/* String|DomNode|NodeList? */ cont, /* Object? */ params){
                                // summary:
-                               //              front-end to the set-content sequence 
+                               //              front-end to the set-content sequence
                                //      cont:
                                //              An html string, node or enumerable list of nodes for insertion into the dom
                                //              If not provided, the object's content property will be used
@@ -9072,9 +9789,9 @@ dojo.provide("dojo.html");
                        },
                        setContent: function(){
                                // summary:
-                               //              sets the content on the node 
+                               //              sets the content on the node
 
-                               var node = this.node; 
+                               var node = this.node;
                                if(!node) {
                                    // can't proceed
                                        throw new Error(this.declaredClass + ": setContent given no node");
@@ -9086,7 +9803,7 @@ dojo.provide("dojo.html");
                                        // like for instance if domNode is a UL and we try append a DIV
        
                                        // FIXME: need to allow the user to provide a content error message string
-                                       var errMess = this.onContentError(e); 
+                                       var errMess = this.onContentError(e);
                                        try{
                                                node.innerHTML = errMess;
                                        }catch(e){
@@ -9102,7 +9819,7 @@ dojo.provide("dojo.html");
                                //      cleanly empty out existing content
 
                                // destroy any widgets from a previous run
-                               // NOTE: if you dont want this you'll need to empty 
+                               // NOTE: if you dont want this you'll need to empty
                                // the parseResults array property yourself to avoid bad things happenning
                                if(this.parseResults && this.parseResults.length) {
                                        dojo.forEach(this.parseResults, function(w) {
@@ -9112,17 +9829,17 @@ dojo.provide("dojo.html");
                                        });
                                        delete this.parseResults;
                                }
-                               // this is fast, but if you know its already empty or safe, you could 
+                               // this is fast, but if you know its already empty or safe, you could
                                // override empty to skip this step
                                dojo.html._emptyNode(this.node);
                        },
        
                        onBegin: function(){
                                // summary
-                               //              Called after instantiation, but before set(); 
-                               //              It allows modification of any of the object properties 
+                               //              Called after instantiation, but before set();
+                               //              It allows modification of any of the object properties
                                //              - including the node and content provided - before the set operation actually takes place
-                               //              This default implementation checks for cleanContent and extractContent flags to 
+                               //              This default implementation checks for cleanContent and extractContent flags to
                                //              optionally pre-process html string content
                                var cont = this.content;
        
@@ -9160,21 +9877,21 @@ dojo.provide("dojo.html");
                                // summary
                                //              manually reset the Setter instance if its being re-used for example for another set()
                                // description
-                               //              tearDown() is not called automatically. 
+                               //              tearDown() is not called automatically.
                                //              In normal use, the Setter instance properties are simply allowed to fall out of scope
                                //              but the tearDown method can be called to explicitly reset this instance.
-                               delete this.parseResults; 
-                               delete this.node; 
-                               delete this.content; 
+                               delete this.parseResults;
+                               delete this.node;
+                               delete this.content;
                        },
   
                        onContentError: function(err){
-                               return "Error occured setting content: " + err; 
+                               return "Error occured setting content: " + err;
                        },
                        
                        _mixin: function(params){
                                // mix properties/methods into the instance
-                               // TODO: the intention with tearDown is to put the Setter's state 
+                               // TODO: the intention with tearDown is to put the Setter's state
                                // back to that of the original constructor (vs. deleting/resetting everything regardless of ctor params)
                                // so we could do something here to move the original properties aside for later restoration
                                var empty = {}, key;
@@ -9182,21 +9899,28 @@ dojo.provide("dojo.html");
                                        if(key in empty){ continue; }
                                        // TODO: here's our opportunity to mask the properties we dont consider configurable/overridable
                                        // .. but history shows we'll almost always guess wrong
-                                       this[key] = params[key]; 
+                                       this[key] = params[key];
                                }
                        },
                        _parse: function(){
-                               // summary: 
+                               // summary:
                                //              runs the dojo parser over the node contents, storing any results in this.parseResults
                                //              Any errors resulting from parsing are passed to _onError for handling
 
                                var rootNode = this.node;
                                try{
                                        // store the results (widgets, whatever) for potential retrieval
+                                       var inherited = {};
+                                       dojo.forEach(["dir", "lang", "textDir"], function(name){
+                                               if(this[name]){
+                                                       inherited[name] = this[name];
+                                               }
+                                       }, this);
                                        this.parseResults = dojo.parser.parse({
                                                rootNode: rootNode,
-                                               dir: this.dir,
-                                               lang: this.lang
+                                               noStart: !this.startup,
+                                               inherited: inherited,
+                                               scope: this.parserScope
                                        });
                                }catch(e){
                                        this._onError('Content', e, "Error parsing in _ContentSetter#"+this.id);
@@ -9229,29 +9953,29 @@ dojo.provide("dojo.html");
                        //      node:
                        //              the parent element that will receive the content
                        //      cont:
-                       //              the content to be set on the parent element. 
+                       //              the content to be set on the parent element.
                        //              This can be an html string, a node reference or a NodeList, dojo.NodeList, Array or other enumerable list of nodes
-                       //      params: 
+                       //      params:
                        //              Optional flags/properties to configure the content-setting. See dojo.html._ContentSetter
                        //      example:
                        //              A safe string/node/nodelist content replacement/injection with hooks for extension
-                       //              Example Usage: 
-                       //              dojo.html.set(node, "some string"); 
-                       //              dojo.html.set(node, contentNode, {options}); 
-                       //              dojo.html.set(node, myNode.childNodes, {options}); 
+                       //              Example Usage:
+                       //              dojo.html.set(node, "some string");
+                       //              dojo.html.set(node, contentNode, {options});
+                       //              dojo.html.set(node, myNode.childNodes, {options});
                if(undefined == cont){
                        console.warn("dojo.html.set: no cont argument provided, using empty string");
                        cont = "";
-               }       
+               }
                if(!params){
                        // simple and fast
                        return dojo.html._setNodeContent(node, cont, true);
-               }else{ 
+               }else{
                        // more options but slower
                        // note the arguments are reversed in order, to match the convention for instantiation via the parser
-                       var op = new dojo.html._ContentSetter(dojo.mixin( 
-                                       params, 
-                                       { content: cont, node: node } 
+                       var op = new dojo.html._ContentSetter(dojo.mixin(
+                                       params,
+                                       { content: cont, node: node }
                        ));
                        return op.set();
                }
@@ -9266,35 +9990,39 @@ dojo.provide("dijit.layout.ContentPane");
 
 
 
-       // for dijit.layout.marginBox2contentBox()
-
-
 
 
 
 
 dojo.declare(
-       "dijit.layout.ContentPane", dijit._Widget,
+       "dijit.layout.ContentPane", [dijit._Widget, dijit.layout._ContentPaneResizeMixin],
 {
        // summary:
-       //              A widget that acts as a container for mixed HTML and widgets, and includes an Ajax interface
+       //              A widget containing an HTML fragment, specified inline
+       //              or by uri.  Fragment may include widgets.
+       //
        // description:
-       //              A widget that can be used as a stand alone widget
-       //              or as a base class for other widgets.
+       //              This widget embeds a document fragment in the page, specified
+       //              either by uri, javascript generated markup or DOM reference.
+       //              Any widgets within this content are instantiated and managed,
+       //              but laid out according to the HTML structure.  Unlike IFRAME,
+       //              ContentPane embeds a document fragment as would be found
+       //              inside the BODY tag of a full HTML document.  It should not
+       //              contain the HTML, HEAD, or BODY tags.
+       //              For more advanced functionality with scripts and
+       //              stylesheets, see dojox.layout.ContentPane.  This widget may be
+       //              used stand alone or as a base class for other widgets.
+       //              ContentPane is useful as a child of other layout containers
+       //              such as BorderContainer or TabContainer, but note that those
+       //              widgets can contain any widget as a child.
        //
-       //              Handles replacement of document fragment using either external uri or javascript
-       //              generated markup or DOM content, instantiating widgets within that content.
-       //              Don't confuse it with an iframe, it only needs/wants document fragments.
-       //              It's useful as a child of LayoutContainer, SplitContainer, or TabContainer.
-       //              But note that those classes can contain any widget as a child.
        // example:
        //              Some quick samples:
-       //              To change the innerHTML use .set('content', '<b>new content</b>')
+       //              To change the innerHTML: cp.set('content', '<b>new content</b>')
        //
-       //              Or you can send it a NodeList, .set('content', dojo.query('div [class=selected]', userSelection))
-       //              please note that the nodes in NodeList will copied, not moved
+       //              Or you can send it a NodeList: cp.set('content', dojo.query('div [class=selected]', userSelection))
        //
-       //              To do a ajax update use .set('href', url)
+       //              To do an ajax update: cp.set('href', url)
 
        // href: String
        //              The href of the content that displays now.
@@ -9306,7 +10034,7 @@ dojo.declare(
 /*=====
        // content: String || DomNode || NodeList || dijit._Widget
        //              The innerHTML of the ContentPane.
-       //              Note that the initialization parameter / argument to attr("content", ...)
+       //              Note that the initialization parameter / argument to set("content", ...)
        //              can be a String, DomNode, Nodelist, or _Widget.
        content: "",
 =====*/
@@ -9320,6 +10048,13 @@ dojo.declare(
        //              Parse content and create the widgets, if any.
        parseOnLoad: true,
 
+       // parserScope: String
+       //              Flag passed to parser.  Root for attribute names to search for.   If scopeName is dojo,
+       //              will search for data-dojo-type (or dojoType).  For backwards compatibility
+       //              reasons defaults to dojo._scopeName (which is "dojo" except when
+       //              multi-version support is used, when it will be something like dojo16, dojo20, etc.)
+       parserScope: dojo._scopeName,
+
        // preventCache: Boolean
        //              Prevent caching of data from href's by appending a timestamp to the href.
        preventCache: false,
@@ -9343,7 +10078,7 @@ dojo.declare(
        // isLoaded: [readonly] Boolean
        //              True if the ContentPane has data in it, either specified
        //              during initialization (via href or inline content), or set
-       //              via attr('content', ...) / attr('href', ...)
+       //              via set('content', ...) / set('href', ...)
        //
        //              False if it doesn't have any content, or if ContentPane is
        //              still in the process of downloading href.
@@ -9351,35 +10086,19 @@ dojo.declare(
 
        baseClass: "dijitContentPane",
 
-       // doLayout: Boolean
-       //              - false - don't adjust size of children
-       //              - true - if there is a single visible child widget, set it's size to
-       //                              however big the ContentPane is
-       doLayout: true,
-
        // ioArgs: Object
        //              Parameters to pass to xhrGet() request, for example:
        // |    <div dojoType="dijit.layout.ContentPane" href="./bar" ioArgs="{timeout: 500}">
        ioArgs: {},
 
-       // isContainer: [protected] Boolean
-       //              Indicates that this widget acts as a "parent" to the descendant widgets.
-       //              When the parent is started it will call startup() on the child widgets.
-       //              See also `isLayoutContainer`.
-       isContainer: true,
-
-       // isLayoutContainer: [protected] Boolean
-       //              Indicates that this widget will call resize() on it's child widgets
-       //              when they become visible.
-       isLayoutContainer: true,
-
        // onLoadDeferred: [readonly] dojo.Deferred
-       //              This is the `dojo.Deferred` returned by attr('href', ...) and refresh().
+       //              This is the `dojo.Deferred` returned by set('href', ...) and refresh().
        //              Calling onLoadDeferred.addCallback() or addErrback() registers your
-       //              callback to be called only once, when the prior attr('href', ...) call or
+       //              callback to be called only once, when the prior set('href', ...) call or
        //              the initial href parameter to the constructor finishes loading.
        //
-       //              This is different than an onLoad() handler which gets called any time any href is loaded.
+       //              This is different than an onLoad() handler which gets called any time any href
+       //              or content is loaded.
        onLoadDeferred: null,
 
        // Override _Widget's attributeMap because we don't want the title attribute (used to specify
@@ -9389,99 +10108,71 @@ dojo.declare(
                title: []
        }),
 
+       // Flag to parser that I'll parse my contents, so it shouldn't.
+       stopParser: true,
+
+       // template: [private] Boolean
+       //              Flag from the parser that this ContentPane is inside a template
+       //              so the contents are pre-parsed.
+       // (TODO: this declaration can be commented out in 2.0)
+       template: false,
+
+       create: function(params, srcNodeRef){
+               // Convert a srcNodeRef argument into a content parameter, so that the original contents are
+               // processed in the same way as contents set via set("content", ...), calling the parser etc.
+               // Avoid modifying original params object since that breaks NodeList instantiation, see #11906.
+               if((!params || !params.template) && srcNodeRef && !("href" in params) && !("content" in params)){
+                       var df = dojo.doc.createDocumentFragment();
+                       srcNodeRef = dojo.byId(srcNodeRef)
+                       while(srcNodeRef.firstChild){
+                               df.appendChild(srcNodeRef.firstChild);
+                       }
+                       params = dojo.delegate(params, {content: df});
+               }
+               this.inherited(arguments, [params, srcNodeRef]);
+       },
+
        postMixInProperties: function(){
                this.inherited(arguments);
                var messages = dojo.i18n.getLocalization("dijit", "loading", this.lang);
                this.loadingMessage = dojo.string.substitute(this.loadingMessage, messages);
                this.errorMessage = dojo.string.substitute(this.errorMessage, messages);
-
-               // Detect if we were initialized with data
-               if(!this.href && this.srcNodeRef && this.srcNodeRef.innerHTML){
-                       this.isLoaded = true;
-               }
        },
 
        buildRendering: function(){
-               // Overrides Widget.buildRendering().
-               // Since we have no template we need to set this.containerNode ourselves.
-               // For subclasses of ContentPane do have a template, does nothing.
                this.inherited(arguments);
+
+               // Since we have no template we need to set this.containerNode ourselves, to make getChildren() work.
+               // For subclasses of ContentPane that do have a template, does nothing.
                if(!this.containerNode){
-                       // make getDescendants() work
                        this.containerNode = this.domNode;
                }
-       },
 
-       postCreate: function(){
                // remove the title attribute so it doesn't show up when hovering
-               // over a node
+               // over a node  (TODO: remove in 2.0, no longer needed after #11490)
                this.domNode.title = "";
 
                if(!dojo.attr(this.domNode,"role")){
                        dijit.setWaiRole(this.domNode, "group");
                }
-
-               dojo.addClass(this.domNode, this.baseClass);
        },
 
-       startup: function(){
+       _startChildren: function(){
                // summary:
-               //              See `dijit.layout._LayoutWidget.startup` for description.
-               //              Although ContentPane doesn't extend _LayoutWidget, it does implement
-               //              the same API.
-               if(this._started){ return; }
-
-               var parent = dijit._Contained.prototype.getParent.call(this);
-               this._childOfLayoutWidget = parent && parent.isLayoutContainer;
-
-               // I need to call resize() on my child/children (when I become visible), unless
-               // I'm the child of a layout widget in which case my parent will call resize() on me and I'll do it then.
-               this._needLayout = !this._childOfLayoutWidget;
-
-               if(this.isLoaded){
-                       dojo.forEach(this.getChildren(), function(child){
-                               child.startup();
-                       });
-               }
-
-               if(this._isShown() || this.preload){
-                       this._onShow();
-               }
+               //              Call startup() on all children including non _Widget ones like dojo.dnd.Source objects
 
+               // This starts all the widgets
                this.inherited(arguments);
-       },
-
-       _checkIfSingleChild: function(){
-               // summary:
-               //              Test if we have exactly one visible widget as a child,
-               //              and if so assume that we are a container for that widget,
-               //              and should propogate startup() and resize() calls to it.
-               //              Skips over things like data stores since they aren't visible.
-
-               var childNodes = dojo.query("> *", this.containerNode).filter(function(node){
-                               return node.tagName !== "SCRIPT"; // or a regexp for hidden elements like script|area|map|etc..
-                       }),
-                       childWidgetNodes = childNodes.filter(function(node){
-                               return dojo.hasAttr(node, "dojoType") || dojo.hasAttr(node, "widgetId");
-                       }),
-                       candidateWidgets = dojo.filter(childWidgetNodes.map(dijit.byNode), function(widget){
-                               return widget && widget.domNode && widget.resize;
-                       });
-
-               if(
-                       // all child nodes are widgets
-                       childNodes.length == childWidgetNodes.length &&
-
-                       // all but one are invisible (like dojo.data)
-                       candidateWidgets.length == 1
-               ){
-                       this._singleChild = candidateWidgets[0];
-               }else{
-                       delete this._singleChild;
-               }
 
-               // So we can set overflow: hidden to avoid a safari bug w/scrollbars showing up (#9449)
-               dojo.toggleClass(this.containerNode, this.baseClass + "SingleChild", !!this._singleChild);
+               // And this catches stuff like dojo.dnd.Source
+               if(this._contentSetter){
+                       dojo.forEach(this._contentSetter.parseResults, function(obj){
+                               if(!obj._started && !obj._destroyed && dojo.isFunction(obj.startup)){
+                                       obj.startup();
+                                       obj._started = true;
+                               }
+                       }, this);
+               }
        },
 
        setHref: function(/*String|Uri*/ href){
@@ -9492,23 +10183,25 @@ dojo.declare(
        },
        _setHrefAttr: function(/*String|Uri*/ href){
                // summary:
-               //              Hook so attr("href", ...) works.
+               //              Hook so set("href", ...) works.
                // description:
                //              Reset the (external defined) content of this pane and replace with new url
                //              Note: It delays the download until widget is shown if preload is false.
                //      href:
                //              url to the page you want to get, must be within the same domain as your mainpage
 
-               // Cancel any in-flight requests (an attr('href') will cancel any in-flight attr('href', ...))
+               // Cancel any in-flight requests (a set('href', ...) will cancel any in-flight set('href', ...))
                this.cancel();
 
                this.onLoadDeferred = new dojo.Deferred(dojo.hitch(this, "cancel"));
+               this.onLoadDeferred.addCallback(dojo.hitch(this, "onLoad"));
 
-               this.href = href;
+               this._set("href", href);
 
                // _setHrefAttr() is called during creation and by the user, after creation.
-               // only in the second case do we actually load the URL; otherwise it's done in startup()
-               if(this._created && (this.preload || this._isShown())){
+               // Assuming preload == false, only in the second case do we actually load the URL;
+               // otherwise it's done in startup(), and only if this widget is shown.
+               if(this.preload || (this._created && this._isShown())){
                        this._load();
                }else{
                        // Set flag to indicate that href needs to be loaded the next time the
@@ -9527,7 +10220,7 @@ dojo.declare(
        },
        _setContentAttr: function(/*String|DomNode|Nodelist*/data){
                // summary:
-               //              Hook to make attr("content", ...) work.
+               //              Hook to make set("content", ...) work.
                //              Replaces old content with data content, include style classes from old content
                //      data:
                //              the new Content may be String, DomNode or NodeList
@@ -9537,24 +10230,30 @@ dojo.declare(
 
                // clear href so we can't run refresh and clear content
                // refresh should only work if we downloaded the content
-               this.href = "";
+               this._set("href", "");
 
-               // Cancel any in-flight requests (an attr('content') will cancel any in-flight attr('href', ...))
+               // Cancel any in-flight requests (a set('content', ...) will cancel any in-flight set('href', ...))
                this.cancel();
 
                // Even though user is just setting content directly, still need to define an onLoadDeferred
                // because the _onLoadHandler() handler is still getting called from setContent()
                this.onLoadDeferred = new dojo.Deferred(dojo.hitch(this, "cancel"));
+               if(this._created){
+                       // For back-compat reasons, call onLoad() for set('content', ...)
+                       // calls but not for content specified in srcNodeRef (ie: <div dojoType=ContentPane>...</div>)
+                       // or as initialization parameter (ie: new ContentPane({content: ...})
+                       this.onLoadDeferred.addCallback(dojo.hitch(this, "onLoad"));
+               }
 
                this._setContent(data || "");
 
-               this._isDownloaded = false; // mark that content is from a attr('content') not an attr('href')
+               this._isDownloaded = false; // mark that content is from a set('content') not a set('href')
 
                return this.onLoadDeferred;     // dojo.Deferred
        },
        _getContentAttr: function(){
                // summary:
-               //              Hook to make attr("content") work
+               //              Hook to make get("content") work
                return this.containerNode.innerHTML;
        },
 
@@ -9587,69 +10286,6 @@ dojo.declare(
                this.inherited(arguments);
        },
 
-       resize: function(changeSize, resultSize){
-               // summary:
-               //              See `dijit.layout._LayoutWidget.resize` for description.
-               //              Although ContentPane doesn't extend _LayoutWidget, it does implement
-               //              the same API.
-
-               // For the TabContainer --> BorderContainer --> ContentPane case, _onShow() is
-               // never called, so resize() is our trigger to do the initial href download.
-               if(!this._wasShown){
-                       this._onShow();
-               }
-
-               this._resizeCalled = true;
-
-               // Set margin box size, unless it wasn't specified, in which case use current size.
-               if(changeSize){
-                       dojo.marginBox(this.domNode, changeSize);
-               }
-
-               // Compute content box size of containerNode in case we [later] need to size our single child.
-               var cn = this.containerNode;
-               if(cn === this.domNode){
-                       // If changeSize or resultSize was passed to this method and this.containerNode ==
-                       // this.domNode then we can compute the content-box size without querying the node,
-                       // which is more reliable (similar to LayoutWidget.resize) (see for example #9449).
-                       var mb = resultSize || {};
-                       dojo.mixin(mb, changeSize || {}); // changeSize overrides resultSize
-                       if(!("h" in mb) || !("w" in mb)){
-                               mb = dojo.mixin(dojo.marginBox(cn), mb); // just use dojo.marginBox() to fill in missing values
-                       }
-                       this._contentBox = dijit.layout.marginBox2contentBox(cn, mb);
-               }else{
-                       this._contentBox = dojo.contentBox(cn);
-               }
-
-               // Make my children layout, or size my single child widget
-               this._layoutChildren();
-       },
-
-       _isShown: function(){
-               // summary:
-               //              Returns true if the content is currently shown.
-               // description:
-               //              If I am a child of a layout widget then it actually returns true if I've ever been visible,
-               //              not whether I'm currently visible, since that's much faster than tracing up the DOM/widget
-               //              tree every call, and at least solves the performance problem on page load by deferring loading
-               //              hidden ContentPanes until they are first shown
-
-               if(this._childOfLayoutWidget){
-                       // If we are TitlePane, etc - we return that only *IF* we've been resized
-                       if(this._resizeCalled && "open" in this){
-                               return this.open;
-                       }
-                       return this._resizeCalled;
-               }else if("open" in this){
-                       return this.open;               // for TitlePane, etc.
-               }else{
-                       // TODO: with _childOfLayoutWidget check maybe this branch no longer necessary?
-                       var node = this.domNode;
-                       return (node.style.display != 'none') && (node.style.visibility != 'hidden') && !dojo.hasClass(node, "dijitHidden");
-               }
-       },
-
        _onShow: function(){
                // summary:
                //              Called when the ContentPane is made visible
@@ -9661,26 +10297,15 @@ dojo.declare(
                //              Does necessary processing, including href download and layout/resize of
                //              child widget(s)
 
+               this.inherited(arguments);
+
                if(this.href){
                        if(!this._xhrDfd && // if there's an href that isn't already being loaded
                                (!this.isLoaded || this._hrefChanged || this.refreshOnShow)
                        ){
-                               this.refresh();
-                       }
-               }else{
-                       // If we are the child of a layout widget then the layout widget will call resize() on
-                       // us, and then we will size our child/children.   Otherwise, we need to do it now.
-                       if(!this._childOfLayoutWidget && this._needLayout){
-                               // If a layout has been scheduled for when we become visible, do it now
-                               this._layoutChildren();
+                               return this.refresh();  // If child has an href, promise that fires when the load is complete
                        }
                }
-
-               this.inherited(arguments);
-
-               // Need to keep track of whether ContentPane has been shown (which is different than
-               // whether or not it's currently visible).
-               this._wasShown = true;
        },
 
        refresh: function(){
@@ -9695,8 +10320,9 @@ dojo.declare(
                this.cancel();
 
                this.onLoadDeferred = new dojo.Deferred(dojo.hitch(this, "cancel"));
+               this.onLoadDeferred.addCallback(dojo.hitch(this, "onLoad"));
                this._load();
-               return this.onLoadDeferred;
+               return this.onLoadDeferred;             // If child has an href, promise that fires when refresh is complete
        },
 
        _load: function(){
@@ -9746,10 +10372,9 @@ dojo.declare(
        _onLoadHandler: function(data){
                // summary:
                //              This is called whenever new content is being loaded
-               this.isLoaded = true;
+               this._set("isLoaded", true);
                try{
                        this.onLoadDeferred.callback(data);
-                       this.onLoad(data);
                }catch(e){
                        console.error('Error '+this.widgetId+' running custom onLoad code: ' + e.message);
                }
@@ -9758,7 +10383,7 @@ dojo.declare(
        _onUnloadHandler: function(){
                // summary:
                //              This is called whenever the content is being unloaded
-               this.isLoaded = false;
+               this._set("isLoaded", false);
                try{
                        this.onUnload();
                }catch(e){
@@ -9804,7 +10429,7 @@ dojo.declare(
                delete this._singleChild;
        },
 
-       _setContent: function(cont, isFakeContent){
+       _setContent: function(/*String|DocumentFragment*/ cont, /*Boolean*/ isFakeContent){
                // summary:
                //              Insert the content into the container node
 
@@ -9839,31 +10464,31 @@ dojo.declare(
                        cleanContent: this.cleanContent,
                        extractContent: this.extractContent,
                        parseContent: this.parseOnLoad,
+                       parserScope: this.parserScope,
+                       startup: false,
                        dir: this.dir,
                        lang: this.lang
                }, this._contentSetterParams || {});
 
-               dojo.mixin(setter, setterParams);
-
-               setter.set( (dojo.isObject(cont) && cont.domNode) ? cont.domNode : cont );
+               setter.set( (dojo.isObject(cont) && cont.domNode) ? cont.domNode : cont, setterParams );
 
                // setter params must be pulled afresh from the ContentPane each time
                delete this._contentSetterParams;
 
-               if(!isFakeContent){
-                       // Startup each top level child widget (and they will start their children, recursively)
-                       dojo.forEach(this.getChildren(), function(child){
-                               // The parser has already called startup on all widgets *without* a getParent() method
-                               if(!this.parseOnLoad || child.getParent){
-                                       child.startup();
-                               }
-                       }, this);
+               if(this.doLayout){
+                       this._checkIfSingleChild();
+               }
 
-                       // Call resize() on each of my child layout widgets,
-                       // or resize() on my single child layout widget...
-                       // either now (if I'm currently visible)
-                       // or when I become visible
-                       this._scheduleLayout();
+               if(!isFakeContent){
+                       if(this._started){
+                               // Startup each top level child widget (and they will start their children, recursively)
+                               this._startChildren();
+       
+                               // Call resize() on each of my child layout widgets,
+                               // or resize() on my single child layout widget...
+                               // either now (if I'm currently visible) or when I become visible
+                               this._scheduleLayout();
+                       }
 
                        this._onLoadHandler(cont);
                }
@@ -9873,7 +10498,7 @@ dojo.declare(
                this.onLoadDeferred.errback(err);
 
                // shows user the string that is returned by on[type]Error
-               // overide on[type]Error and return your own string to customize
+               // override on[type]Error and return your own string to customize
                var errText = this['on' + type + 'Error'].call(this, err);
                if(consoleText){
                        console.error(consoleText, err);
@@ -9882,48 +10507,6 @@ dojo.declare(
                }
        },
 
-       _scheduleLayout: function(){
-               // summary:
-               //              Call resize() on each of my child layout widgets, either now
-               //              (if I'm currently visible) or when I become visible
-               if(this._isShown()){
-                       this._layoutChildren();
-               }else{
-                       this._needLayout = true;
-               }
-       },
-
-       _layoutChildren: function(){
-               // summary:
-               //              Since I am a Container widget, each of my children expects me to
-               //              call resize() or layout() on them.
-               // description:
-               //              Should be called on initialization and also whenever we get new content
-               //              (from an href, or from attr('content', ...))... but deferred until
-               //              the ContentPane is visible
-
-               if(this.doLayout){
-                       this._checkIfSingleChild();
-               }
-
-               if(this._singleChild && this._singleChild.resize){
-                       var cb = this._contentBox || dojo.contentBox(this.containerNode);
-
-                       // note: if widget has padding this._contentBox will have l and t set,
-                       // but don't pass them to resize() or it will doubly-offset the child
-                       this._singleChild.resize({w: cb.w, h: cb.h});
-               }else{
-                       // All my child widgets are independently sized (rather than matching my size),
-                       // but I still need to call resize() on each child to make it layout.
-                       dojo.forEach(this.getChildren(), function(widget){
-                               if(widget.resize){
-                                       widget.resize();
-                               }
-                       });
-               }
-               delete this._needLayout;
-       },
-
        // EVENT's, should be overide-able
        onLoad: function(data){
                // summary:
@@ -10035,12 +10618,16 @@ dojo.declare(
                        //              Set by `dijit._DialogMixin._getFocusItems`.
                        _lastFocusItem: null,
 
-                       templateString: dojo.cache("dijit", "templates/TooltipDialog.html", "<div waiRole=\"presentation\">\n\t<div class=\"dijitTooltipContainer\" waiRole=\"presentation\">\n\t\t<div class =\"dijitTooltipContents dijitTooltipFocusNode\" dojoAttachPoint=\"containerNode\" tabindex=\"-1\" waiRole=\"dialog\"></div>\n\t</div>\n\t<div class=\"dijitTooltipConnector\" waiRole=\"presentation\"></div>\n</div>\n"),
+                       templateString: dojo.cache("dijit", "templates/TooltipDialog.html", "<div role=\"presentation\" tabIndex=\"-1\">\n\t<div class=\"dijitTooltipContainer\" role=\"presentation\">\n\t\t<div class =\"dijitTooltipContents dijitTooltipFocusNode\" dojoAttachPoint=\"containerNode\" role=\"dialog\"></div>\n\t</div>\n\t<div class=\"dijitTooltipConnector\" role=\"presentation\"></div>\n</div>\n"),
+
+                       _setTitleAttr: function(/*String*/ title){
+                               this.containerNode.title = title;
+                               this._set("title", title)
+                       },
 
                        postCreate: function(){
                                this.inherited(arguments);
                                this.connect(this.containerNode, "onkeypress", "_onKey");
-                               this.containerNode.title = this.title;
                        },
 
                        orient: function(/*DomNode*/ node, /*String*/ aroundCorner, /*String*/ corner){
@@ -10050,13 +10637,19 @@ dojo.declare(
                                //              directly.
                                // tags:
                                //              protected
-                               var c = this._currentOrientClass;
-                               if(c){
-                                       dojo.removeClass(this.domNode, c);
-                               }
-                               c = "dijitTooltipAB"+(corner.charAt(1) == 'L'?"Left":"Right")+" dijitTooltip"+(corner.charAt(0) == 'T' ? "Below" : "Above");
-                               dojo.addClass(this.domNode, c);
-                               this._currentOrientClass = c;
+                               var newC = "dijitTooltipAB" + (corner.charAt(1) == 'L' ? "Left" : "Right")
+                                               + " dijitTooltip"
+                                               + (corner.charAt(0) == 'T' ? "Below" : "Above");
+                               
+                               dojo.replaceClass(this.domNode, newC, this._currentOrientClass || "");
+                               this._currentOrientClass = newC;
+                       },
+
+                       focus: function(){
+                               // summary:
+                               //              Focus on first field
+                               this._getFocusItems(this.containerNode);
+                               dijit.focus(this._firstFocusItem);
                        },
 
                        onOpen: function(/*Object*/ pos){
@@ -10068,11 +10661,6 @@ dojo.declare(
 
                                this.orient(this.domNode,pos.aroundCorner, pos.corner);
                                this._onShow(); // lazy load trigger
-
-                               if(this.autofocus){
-                                       this._getFocusItems(this.containerNode);
-                                       dijit.focus(this._firstFocusItem);
-                               }
                        },
 
                        onClose: function(){
@@ -10141,6 +10729,8 @@ dojo.provide("dijit.Dialog");
 
 
 
+// dijit/TooltipDialog required for back-compat.  TODO: remove in 2.0
+
 /*=====
 dijit._underlay = function(kwArgs){
        // summary:
@@ -10152,7 +10742,6 @@ dijit._underlay = function(kwArgs){
        //              or subclass thereof is shown.
 };
 =====*/
-
 dojo.declare(
        "dijit._DialogBase",
        [dijit._Templated, dijit.form._FormMixin, dijit._DialogMixin, dijit._CssStateMixin],
@@ -10173,7 +10762,7 @@ dojo.declare(
                // |    dojo.body().appendChild(foo.domNode);
                // |    foo.startup();
 
-               templateString: dojo.cache("dijit", "templates/Dialog.html", "<div class=\"dijitDialog\" tabindex=\"-1\" waiRole=\"dialog\" waiState=\"labelledby-${id}_title\">\n\t<div dojoAttachPoint=\"titleBar\" class=\"dijitDialogTitleBar\">\n\t<span dojoAttachPoint=\"titleNode\" class=\"dijitDialogTitle\" id=\"${id}_title\"></span>\n\t<span dojoAttachPoint=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" dojoAttachEvent=\"onclick: onCancel\" title=\"${buttonCancel}\">\n\t\t<span dojoAttachPoint=\"closeText\" class=\"closeText\" title=\"${buttonCancel}\">x</span>\n\t</span>\n\t</div>\n\t\t<div dojoAttachPoint=\"containerNode\" class=\"dijitDialogPaneContent\"></div>\n</div>\n"),
+               templateString: dojo.cache("dijit", "templates/Dialog.html", "<div class=\"dijitDialog\" role=\"dialog\" aria-labelledby=\"${id}_title\">\n\t<div dojoAttachPoint=\"titleBar\" class=\"dijitDialogTitleBar\">\n\t<span dojoAttachPoint=\"titleNode\" class=\"dijitDialogTitle\" id=\"${id}_title\"></span>\n\t<span dojoAttachPoint=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" dojoAttachEvent=\"ondijitclick: onCancel\" title=\"${buttonCancel}\" role=\"button\" tabIndex=\"-1\">\n\t\t<span dojoAttachPoint=\"closeText\" class=\"closeText\" title=\"${buttonCancel}\">x</span>\n\t</span>\n\t</div>\n\t\t<div dojoAttachPoint=\"containerNode\" class=\"dijitDialogPaneContent\"></div>\n</div>\n"),
                
                baseClass: "dijitDialog",
                
@@ -10189,7 +10778,7 @@ dojo.declare(
                        "aria-describedby":""
                }),
 
-               // open: Boolean
+               // open: [readonly] Boolean
                //              True if Dialog is currently displayed on screen.
                open: false,
 
@@ -10209,12 +10798,12 @@ dojo.declare(
                //              False will disable autofocusing. Default: true
                autofocus: true,
 
-               // _firstFocusItem: [private] [readonly] DomNode
+               // _firstFocusItem: [private readonly] DomNode
                //              The pointer to the first focusable node in the dialog.
                //              Set by `dijit._DialogMixin._getFocusItems`.
                _firstFocusItem: null,
 
-               // _lastFocusItem: [private] [readonly] DomNode
+               // _lastFocusItem: [private readonly] DomNode
                //              The pointer to which node has focus prior to our dialog.
                //              Set by `dijit._DialogMixin._getFocusItems`.
                _lastFocusItem: null,
@@ -10266,14 +10855,14 @@ dojo.declare(
                        // summary:
                        //              Called when data has been loaded from an href.
                        //              Unlike most other callbacks, this function can be connected to (via `dojo.connect`)
-                       //              but should *not* be overriden.
+                       //              but should *not* be overridden.
                        // tags:
                        //              callback
 
                        // when href is specified we need to reposition the dialog after the data is loaded
                        // and find the focusable elements
                        this._position();
-                       if(this.autofocus){
+                       if(this.autofocus && dijit._DialogLevelManager.isTop(this)){
                                this._getFocusItems(this.domNode);
                                dijit.focus(this._firstFocusItem);
                        }
@@ -10304,7 +10893,7 @@ dojo.declare(
                                this._moveable = (dojo.isIE == 6) ?
                                        new dojo.dnd.TimedMoveable(node, { handle: this.titleBar }) :   // prevent overload, see #5285
                                        new dojo.dnd.Moveable(node, { handle: this.titleBar, timeout: 0 });
-                               dojo.subscribe("/dnd/move/stop",this,"_endDrag");
+                               this._dndListener = dojo.subscribe("/dnd/move/stop",this,"_endDrag");
                        }else{
                                dojo.addClass(node,"dijitDialogFixed");
                        }
@@ -10313,95 +10902,6 @@ dojo.declare(
                                dialogId: this.id,
                                "class": dojo.map(this["class"].split(/\s/), function(s){ return s+"_underlay"; }).join(" ")
                        };
-
-                       this._fadeIn = dojo.fadeIn({
-                               node: node,
-                               duration: this.duration,
-                               beforeBegin: dojo.hitch(this, function(){
-                                       var underlay = dijit._underlay;
-                                       if(!underlay){
-                                               underlay = dijit._underlay = new dijit.DialogUnderlay(this.underlayAttrs);
-                                       }else{
-                                               underlay.set(this.underlayAttrs);
-                                       }
-
-                                       var ds = dijit._dialogStack,
-                                               zIndex = 948 + ds.length*2;
-                                       if(ds.length == 1){     // first dialog
-                                               underlay.show();
-                                       }
-                                       dojo.style(dijit._underlay.domNode, 'zIndex', zIndex);
-                                       dojo.style(this.domNode, 'zIndex', zIndex + 1);
-                               }),
-                               onEnd: dojo.hitch(this, function(){
-                                       if(this.autofocus){
-                                               // find focusable Items each time dialog is shown since if dialog contains a widget the
-                                               // first focusable items can change
-                                               this._getFocusItems(this.domNode);
-                                               dijit.focus(this._firstFocusItem);
-                                       }
-                               })
-                        });
-
-                       this._fadeOut = dojo.fadeOut({
-                               node: node,
-                               duration: this.duration,
-                               onEnd: dojo.hitch(this, function(){
-                                       node.style.display = "none";
-
-                                       // Restore the previous dialog in the stack, or if this is the only dialog
-                                       // then restore to original page
-                                       var ds = dijit._dialogStack;
-                                       if(ds.length == 0){
-                                               dijit._underlay.hide();
-                                       }else{
-                                               dojo.style(dijit._underlay.domNode, 'zIndex', 948 + ds.length*2);
-                                               dijit._underlay.set(ds[ds.length-1].underlayAttrs);
-                                       }
-
-                                       // Restore focus to wherever it was before this dialog was displayed
-                                       if(this.refocus){
-                                               var focus = this._savedFocus;
-
-                                               // If we are returning control to a previous dialog but for some reason
-                                               // that dialog didn't have a focused field, set focus to first focusable item.
-                                               // This situation could happen if two dialogs appeared at nearly the same time,
-                                               // since a dialog doesn't set it's focus until the fade-in is finished.
-                                               if(ds.length > 0){
-                                                       var pd = ds[ds.length-1];
-                                                       if(!dojo.isDescendant(focus.node, pd.domNode)){
-                                                               pd._getFocusItems(pd.domNode);
-                                                               focus = pd._firstFocusItem;
-                                                       }
-                                               }
-
-                                               dijit.focus(focus);
-                                       }
-                               })
-                        });
-               },
-
-               uninitialize: function(){
-                       var wasPlaying = false;
-                       if(this._fadeIn && this._fadeIn.status() == "playing"){
-                               wasPlaying = true;
-                               this._fadeIn.stop();
-                       }
-                       if(this._fadeOut && this._fadeOut.status() == "playing"){
-                               wasPlaying = true;
-                               this._fadeOut.stop();
-                       }
-                       
-                       // Hide the underlay, unless the underlay widget has already been destroyed
-                       // because we are being called during page unload (when all widgets are destroyed)
-                       if((this.open || wasPlaying) && !dijit._underlay._destroyed){
-                               dijit._underlay.hide();
-                       }
-
-                       if(this._moveable){
-                               this._moveable.destroy();
-                       }
-                       this.inherited(arguments);
                },
 
                _size: function(){
@@ -10427,7 +10927,7 @@ dojo.declare(
                                });
                        }
 
-                       var mb = dojo.marginBox(this.domNode);
+                       var mb = dojo._getMarginSize(this.domNode);
                        var viewport = dojo.window.getBox();
                        if(mb.w >= viewport.w || mb.h >= viewport.h){
                                // Reduce size of dialog contents so that dialog fits in viewport
@@ -10482,12 +10982,6 @@ dojo.declare(
                        // tags:
                        //              private
 
-                       var ds = dijit._dialogStack;
-                       if(ds[ds.length-1] != this){
-                               // console.debug(this.id + ': skipping because', this, 'is not the active dialog');
-                               return;
-                       }
-
                        if(evt.charOrCode){
                                var dk = dojo.keys;
                                var node = evt.target;
@@ -10534,16 +11028,23 @@ dojo.declare(
                show: function(){
                        // summary:
                        //              Display the dialog
+                       // returns: dojo.Deferred
+                       //              Deferred object that resolves when the display animation is complete
+
                        if(this.open){ return; }
 
+                       if(!this._started){
+                               this.startup();
+                       }
+
                        // first time we show the dialog, there's some initialization stuff to do
                        if(!this._alreadyInitialized){
                                this._setup();
                                this._alreadyInitialized=true;
                        }
 
-                       if(this._fadeOut.status() == "playing"){
-                               this._fadeOut.stop();
+                       if(this._fadeOutDeferred){
+                               this._fadeOutDeferred.cancel();
                        }
 
                        this._modalconnects.push(dojo.connect(window, "onscroll", this, "layout"));
@@ -10558,43 +11059,81 @@ dojo.declare(
                                        this._oldViewport = viewport;
                                }
                        }));
-                       this._modalconnects.push(dojo.connect(dojo.doc.documentElement, "onkeypress", this, "_onKey"));
+                       this._modalconnects.push(dojo.connect(this.domNode, "onkeypress", this, "_onKey"));
 
                        dojo.style(this.domNode, {
                                opacity:0,
                                display:""
                        });
 
-                       this.open = true;
+                       this._set("open", true);
                        this._onShow(); // lazy load trigger
 
                        this._size();
                        this._position();
-                       dijit._dialogStack.push(this);
-                       this._fadeIn.play();
 
-                       this._savedFocus = dijit.getFocus(this);
+                       // fade-in Animation object, setup below
+                       var fadeIn;
+
+                       this._fadeInDeferred = new dojo.Deferred(dojo.hitch(this, function(){
+                               fadeIn.stop();
+                               delete this._fadeInDeferred;
+                       }));
+
+                       fadeIn = dojo.fadeIn({
+                               node: this.domNode,
+                               duration: this.duration,
+                               beforeBegin: dojo.hitch(this, function(){
+                                       dijit._DialogLevelManager.show(this, this.underlayAttrs);
+                               }),
+                               onEnd: dojo.hitch(this, function(){
+                                       if(this.autofocus && dijit._DialogLevelManager.isTop(this)){
+                                               // find focusable items each time dialog is shown since if dialog contains a widget the
+                                               // first focusable items can change
+                                               this._getFocusItems(this.domNode);
+                                               dijit.focus(this._firstFocusItem);
+                                       }
+                                       this._fadeInDeferred.callback(true);
+                                       delete this._fadeInDeferred;
+                               })
+                       }).play();
+                       
+                       return this._fadeInDeferred;
                },
 
                hide: function(){
                        // summary:
                        //              Hide the dialog
+                       // returns: dojo.Deferred
+                       //              Deferred object that resolves when the hide animation is complete
 
                        // if we haven't been initialized yet then we aren't showing and we can just return
-                       // or if we aren't the active dialog, don't allow us to close yet
-                       var ds = dijit._dialogStack;
-                       if(!this._alreadyInitialized || this != ds[ds.length-1]){
+                       if(!this._alreadyInitialized){
                                return;
                        }
-
-                       if(this._fadeIn.status() == "playing"){
-                               this._fadeIn.stop();
+                       if(this._fadeInDeferred){
+                               this._fadeInDeferred.cancel();
                        }
 
-                       // throw away current active dialog from stack -- making the previous dialog or the node on the original page active
-                       ds.pop();
+                       // fade-in Animation object, setup below
+                       var fadeOut;
+
+                       this._fadeOutDeferred = new dojo.Deferred(dojo.hitch(this, function(){
+                               fadeOut.stop();
+                               delete this._fadeOutDeferred;
+                       }));
 
-                       this._fadeOut.play();
+                       fadeOut = dojo.fadeOut({
+                               node: this.domNode,
+                               duration: this.duration,
+                               onEnd: dojo.hitch(this, function(){
+                                       this.domNode.style.display = "none";
+                                       dijit._DialogLevelManager.hide(this);
+                                       this.onHide();
+                                       this._fadeOutDeferred.callback(true);
+                                       delete this._fadeOutDeferred;
+                               })
+                        }).play();
 
                        if(this._scrollConnected){
                                this._scrollConnected = false;
@@ -10605,9 +11144,9 @@ dojo.declare(
                        if(this._relativePosition){
                                delete this._relativePosition;
                        }
-                       this.open = false;
+                       this._set("open", false);
 
-                       this.onHide();
+                       return this._fadeOutDeferred;
                },
 
                layout: function(){
@@ -10619,31 +11158,161 @@ dojo.declare(
                                if(dijit._underlay){    // avoid race condition during show()
                                        dijit._underlay.layout();
                                }
-                               this._position();
+                               this._position();
+                       }
+               },
+
+               destroy: function(){
+                       if(this._fadeInDeferred){
+                               this._fadeInDeferred.cancel();
+                       }
+                       if(this._fadeOutDeferred){
+                               this._fadeOutDeferred.cancel();
+                       }
+                       if(this._moveable){
+                               this._moveable.destroy();
+                       }
+                       if(this._dndListener){
+                               dojo.unsubscribe(this._dndListener);
+                       }
+                       dojo.forEach(this._modalconnects, dojo.disconnect);
+
+                       dijit._DialogLevelManager.hide(this);
+
+                       this.inherited(arguments);
+               }
+       }
+);
+
+dojo.declare(
+       "dijit.Dialog",
+       [dijit.layout.ContentPane, dijit._DialogBase],
+       {}
+);
+
+dijit._DialogLevelManager = {
+       // summary:
+       //              Controls the various active "levels" on the page, starting with the
+       //              stuff initially visible on the page (at z-index 0), and then having an entry for
+       //              each Dialog shown.
+
+       show: function(/*dijit._Widget*/ dialog, /*Object*/ underlayAttrs){
+               // summary:
+               //              Call right before fade-in animation for new dialog.
+               //              Saves current focus, displays/adjusts underlay for new dialog,
+               //              and sets the z-index of the dialog itself.
+               //
+               //              New dialog will be displayed on top of all currently displayed dialogs.
+               //
+               //              Caller is responsible for setting focus in new dialog after the fade-in
+               //              animation completes.
+
+               var ds = dijit._dialogStack;
+
+               // Save current focus
+               ds[ds.length-1].focus = dijit.getFocus(dialog);
+
+               // Display the underlay, or if already displayed then adjust for this new dialog
+               var underlay = dijit._underlay;
+               if(!underlay || underlay._destroyed){
+                       underlay = dijit._underlay = new dijit.DialogUnderlay(underlayAttrs);
+               }else{
+                       underlay.set(dialog.underlayAttrs);
+               }
+
+               // Set z-index a bit above previous dialog
+               var zIndex = ds[ds.length-1].dialog ? ds[ds.length-1].zIndex + 2 : 950;
+               if(ds.length == 1){     // first dialog
+                       underlay.show();
+               }
+               dojo.style(dijit._underlay.domNode, 'zIndex', zIndex - 1);
+
+               // Dialog
+               dojo.style(dialog.domNode, 'zIndex', zIndex);
+
+               ds.push({dialog: dialog, underlayAttrs: underlayAttrs, zIndex: zIndex});
+       },
+
+       hide: function(/*dijit._Widget*/ dialog){
+               // summary:
+               //              Called when the specified dialog is hidden/destroyed, after the fade-out
+               //              animation ends, in order to reset page focus, fix the underlay, etc.
+               //              If the specified dialog isn't open then does nothing.
+               //
+               //              Caller is responsible for either setting display:none on the dialog domNode,
+               //              or calling dijit.popup.hide(), or removing it from the page DOM.
+
+               var ds = dijit._dialogStack;
+
+               if(ds[ds.length-1].dialog == dialog){
+                       // Removing the top (or only) dialog in the stack, return focus
+                       // to previous dialog
+
+                       ds.pop();
+
+                       var pd = ds[ds.length-1];       // the new active dialog (or the base page itself)
+
+                       // Adjust underlay
+                       if(ds.length == 1){
+                               // Returning to original page.
+                               // Hide the underlay, unless the underlay widget has already been destroyed
+                               // because we are being called during page unload (when all widgets are destroyed)
+                               if(!dijit._underlay._destroyed){
+                                       dijit._underlay.hide();
+                               }
+                       }else{
+                               // Popping back to previous dialog, adjust underlay
+                               dojo.style(dijit._underlay.domNode, 'zIndex', pd.zIndex - 1);
+                               dijit._underlay.set(pd.underlayAttrs);
+                       }
+
+                       // Adjust focus
+                       if(dialog.refocus){
+                               // If we are returning control to a previous dialog but for some reason
+                               // that dialog didn't have a focused field, set focus to first focusable item.
+                               // This situation could happen if two dialogs appeared at nearly the same time,
+                               // since a dialog doesn't set it's focus until the fade-in is finished.
+                               var focus = pd.focus;
+                               if(!focus || (pd.dialog && !dojo.isDescendant(focus.node, pd.dialog.domNode))){
+                                       pd.dialog._getFocusItems(pd.dialog.domNode);
+                                       focus = pd.dialog._firstFocusItem;
+                               }
+       
+                               try{
+                                       dijit.focus(focus);
+                               }catch(e){
+                                       /* focus() will fail if user opened the dialog by clicking a non-focusable element */
+                               }
                        }
-               },
-
-               destroy: function(){
-                       dojo.forEach(this._modalconnects, dojo.disconnect);
-                       if(this.refocus && this.open){
-                               setTimeout(dojo.hitch(dijit,"focus",this._savedFocus), 25);
+               }else{
+                       // Removing a dialog out of order (#9944, #10705).
+                       // Don't need to mess with underlay or z-index or anything.
+                       var idx = dojo.indexOf(dojo.map(ds, function(elem){return elem.dialog}), dialog);
+                       if(idx != -1){
+                               ds.splice(idx, 1);
                        }
-                       this.inherited(arguments);
                }
-       }
-);
-
-dojo.declare(
-       "dijit.Dialog",
-       [dijit.layout.ContentPane, dijit._DialogBase],
-       {}
-);
-
-// Stack of currenctly displayed dialogs, layered on top of each other
-dijit._dialogStack = [];
+       },
 
-// For back-compat.  TODO: remove in 2.0
+       isTop: function(/*dijit._Widget*/ dialog){
+               // summary:
+               //              Returns true if specified Dialog is the top in the task
+               var ds = dijit._dialogStack;
+               return ds[ds.length-1].dialog == dialog;
+       }
+};
 
+// Stack representing the various active "levels" on the page, starting with the
+// stuff initially visible on the page (at z-index 0), and then having an entry for
+// each Dialog shown.
+// Each element in stack has form {
+//             dialog: dialogWidget,
+//             focus: returnFromGetFocus(),
+//             underlayAttrs: attributes to set on underlay (when this widget is active)
+// }
+dijit._dialogStack = [
+       {dialog: null, focus: null, underlayAttrs: null}        // entry for stuff at z-index: 0
+];
 
 }
 
@@ -10653,7 +11322,6 @@ dojo.provide("dijit._HasDropDown");
 
 
 
-
 dojo.declare("dijit._HasDropDown",
        null,
        {
@@ -10702,8 +11370,9 @@ dojo.declare("dijit._HasDropDown",
                forceWidth: false,
 
                // maxHeight: [protected] Integer
-               //              The max height for our dropdown.  Set to 0 for no max height.
-               //              any dropdown taller than this will have scrollbars
+               //              The max height for our dropdown.
+               //              Any dropdown taller than this will have scrollbars.
+               //              Set to 0 for no max height, or -1 to limit height to available space in viewport
                maxHeight: 0,
 
                // dropDownPosition: [const] String[]
@@ -10733,6 +11402,8 @@ dojo.declare("dijit._HasDropDown",
 
                        if(this.disabled || this.readOnly){ return; }
 
+                       dojo.stopEvent(e);
+
                        this._docHandler = this.connect(dojo.doc, "onmouseup", "_onDropDownMouseUp");
 
                        this.toggleDropDown();
@@ -10786,7 +11457,7 @@ dojo.declare("dijit._HasDropDown",
                                        }
                                }
                        }
-                       if(this._opened && dropDown.focus){
+                       if(this._opened && dropDown.focus && dropDown.autoFocus !== false){
                                // Focus the dropdown widget - do it on a delay so that we
                                // don't steal our own focus.
                                window.setTimeout(dojo.hitch(dropDown, "focus"), 1);
@@ -10797,27 +11468,14 @@ dojo.declare("dijit._HasDropDown",
                        // the drop down was already opened on mousedown/keydown; just need to call stopEvent()
                        if(this._stopClickEvents){
                                dojo.stopEvent(e);
-                       }                       
+                       }
                },
 
-               _setupDropdown: function(){
-                       // summary:
-                       //              set up nodes and connect our mouse and keypress events
+               buildRendering: function(){
+                       this.inherited(arguments);
+
                        this._buttonNode = this._buttonNode || this.focusNode || this.domNode;
                        this._popupStateNode = this._popupStateNode || this.focusNode || this._buttonNode;
-                       this._aroundNode = this._aroundNode || this.domNode;
-                       this.connect(this._buttonNode, "onmousedown", "_onDropDownMouseDown");
-                       this.connect(this._buttonNode, "onclick", "_onDropDownClick");
-                       this.connect(this._buttonNode, "onkeydown", "_onDropDownKeydown");
-                       this.connect(this._buttonNode, "onkeyup", "_onKey");
-
-                       // If we have a _setStateClass function (which happens when
-                       // we are a form widget), then we need to connect our open/close
-                       // functions to it
-                       if(this._setStateClass){
-                               this.connect(this, "openDropDown", "_setStateClass");
-                               this.connect(this, "closeDropDown", "_setStateClass");
-                       }
 
                        // Add a class to the "dijitDownArrowButton" type class to _buttonNode so theme can set direction of arrow
                        // based on where drop down will normally appear
@@ -10833,11 +11491,18 @@ dojo.declare("dijit._HasDropDown",
                },
 
                postCreate: function(){
-                       this._setupDropdown();
+                       // summary:
+                       //              set up nodes and connect our mouse and keypress events
+
                        this.inherited(arguments);
+
+                       this.connect(this._buttonNode, "onmousedown", "_onDropDownMouseDown");
+                       this.connect(this._buttonNode, "onclick", "_onDropDownClick");
+                       this.connect(this.focusNode, "onkeypress", "_onKey");
+                       this.connect(this.focusNode, "onkeyup", "_onKeyUp");
                },
 
-               destroyDescendants: function(){
+               destroy: function(){
                        if(this.dropDown){
                                // Destroy the drop down, unless it's already been destroyed.  This can happen because
                                // the drop down is a direct child of <body> even though it's logically my child.
@@ -10849,27 +11514,43 @@ dojo.declare("dijit._HasDropDown",
                        this.inherited(arguments);
                },
 
-               _onDropDownKeydown: function(/*Event*/ e){
-                       if(e.keyCode == dojo.keys.DOWN_ARROW || e.keyCode == dojo.keys.ENTER || e.keyCode == dojo.keys.SPACE){
-                               e.preventDefault();     // stop IE screen jump
-                       }
-               },
-
                _onKey: function(/*Event*/ e){
                        // summary:
                        //              Callback when the user presses a key while focused on the button node
 
                        if(this.disabled || this.readOnly){ return; }
-                       var d = this.dropDown;
+
+                       var d = this.dropDown, target = e.target;
                        if(d && this._opened && d.handleKey){
-                               if(d.handleKey(e) === false){ return; }
+                               if(d.handleKey(e) === false){
+                                       /* false return code means that the drop down handled the key */
+                                       dojo.stopEvent(e);
+                                       return;
+                               }
                        }
-                       if(d && this._opened && e.keyCode == dojo.keys.ESCAPE){
-                               this.toggleDropDown();
-                       }else if(d && !this._opened && 
-                                       (e.keyCode == dojo.keys.DOWN_ARROW || e.keyCode == dojo.keys.ENTER || e.keyCode == dojo.keys.SPACE)){
+                       if(d && this._opened && e.charOrCode == dojo.keys.ESCAPE){
+                               this.closeDropDown();
+                               dojo.stopEvent(e);
+                       }else if(!this._opened &&
+                                       (e.charOrCode == dojo.keys.DOWN_ARROW ||
+                                               ( (e.charOrCode == dojo.keys.ENTER || e.charOrCode == " ") &&
+                                                 //ignore enter and space if the event is for a text input
+                                                 ((target.tagName || "").toLowerCase() !== 'input' ||
+                                                    (target.type && target.type.toLowerCase() !== 'text'))))){
+                               // Toggle the drop down, but wait until keyup so that the drop down doesn't
+                               // get a stray keyup event, or in the case of key-repeat (because user held
+                               // down key for too long), stray keydown events
+                               this._toggleOnKeyUp = true;
+                               dojo.stopEvent(e);
+                       }
+               },
+
+               _onKeyUp: function(){
+                       if(this._toggleOnKeyUp){
+                               delete this._toggleOnKeyUp;
                                this.toggleDropDown();
-                               if(d.focus){
+                               var d = this.dropDown;  // drop down may not exist until toggleDropDown() call
+                               if(d && d.focus){
                                        setTimeout(dojo.hitch(d, "focus"), 1);
                                }
                        }
@@ -10879,8 +11560,14 @@ dojo.declare("dijit._HasDropDown",
                        // summary:
                        //              Called magically when focus has shifted away from this widget and it's dropdown
 
-                       this.closeDropDown();
-                       // don't focus on button.  the user has explicitly focused on something else.
+                       // Don't focus on button if the user has explicitly focused on something else (happens
+                       // when user clicks another control causing the current popup to close)..
+                       // But if focus is inside of the drop down then reset focus to me, because IE doesn't like
+                       // it when you display:none a node with focus.
+                       var focusMe = dijit._curFocus && this.dropDown && dojo.isDescendant(dijit._curFocus, this.dropDown.domNode);
+
+                       this.closeDropDown(focusMe);
+
                        this.inherited(arguments);
                },
 
@@ -10897,7 +11584,8 @@ dojo.declare("dijit._HasDropDown",
                loadDropDown: function(/* Function */ loadCallback){
                        // summary:
                        //              Loads the data for the dropdown, and at some point, calls
-                       //              the given callback
+                       //              the given callback.   This is basically a callback when the
+                       //              user presses the down arrow button to open the drop down.
                        // tags:
                        //              protected
 
@@ -10906,14 +11594,13 @@ dojo.declare("dijit._HasDropDown",
 
                toggleDropDown: function(){
                        // summary:
+                       //              Callback when the user presses the down arrow button or presses
+                       //              the down arrow key to open/close the drop down.
                        //              Toggle the drop-down widget; if it is up, close it, if not, open it
                        // tags:
                        //              protected
 
                        if(this.disabled || this.readOnly){ return; }
-                       this.focus();
-                       var dropDown = this.dropDown;
-                       if(!dropDown){ return; }
                        if(!this._opened){
                                // If we aren't loaded, load it first so there isn't a flicker
                                if(!this.isLoaded()){
@@ -10929,14 +11616,17 @@ dojo.declare("dijit._HasDropDown",
 
                openDropDown: function(){
                        // summary:
-                       //              Opens the dropdown for this widget - it returns the
-                       //              return value of dijit.popup.open
+                       //              Opens the dropdown for this widget.   To be called only when this.dropDown
+                       //              has been created and is ready to display (ie, it's data is loaded).
+                       // returns:
+                       //              return value of dijit.popup.open()
                        // tags:
                        //              protected
 
-                       var dropDown = this.dropDown;
-                       var ddNode = dropDown.domNode;
-                       var self = this;
+                       var dropDown = this.dropDown,
+                               ddNode = dropDown.domNode,
+                               aroundNode = this._aroundNode || this.domNode,
+                               self = this;
 
                        // Prepare our popup's height and honor maxHeight if it exists.
 
@@ -10944,8 +11634,7 @@ dojo.declare("dijit._HasDropDown",
                        // ie, dependent on how much space is available (BK)
 
                        if(!this._preparedNode){
-                               dijit.popup.moveOffScreen(ddNode);
-                               this._preparedNode = true;                      
+                               this._preparedNode = true;
                                // Check if we have explicitly set width and height on the dropdown widget dom node
                                if(ddNode.style.width){
                                        this._explicitDDWidth = true;
@@ -10969,29 +11658,44 @@ dojo.declare("dijit._HasDropDown",
                                }
                                dojo.style(ddNode, myStyle);
                                
+                               // Figure out maximum height allowed (if there is a height restriction)
+                               var maxHeight = this.maxHeight;
+                               if(maxHeight == -1){
+                                       // limit height to space available in viewport either above or below my domNode
+                                       // (whichever side has more room)
+                                       var viewport = dojo.window.getBox(),
+                                               position = dojo.position(aroundNode, false);
+                                       maxHeight = Math.floor(Math.max(position.y, viewport.h - (position.y + position.h)));
+                               }
+
+                               // Attach dropDown to DOM and make make visibility:hidden rather than display:none
+                               // so we call startup() and also get the size
+                               if(dropDown.startup && !dropDown._started){
+                                       dropDown.startup();
+                               }
+
+                               dijit.popup.moveOffScreen(dropDown);
                                // Get size of drop down, and determine if vertical scroll bar needed
-                               var mb = dojo.marginBox(ddNode);
-                               var overHeight = (this.maxHeight && mb.h > this.maxHeight);
+                               var mb = dojo._getMarginSize(ddNode);
+                               var overHeight = (maxHeight && mb.h > maxHeight);
                                dojo.style(ddNode, {
                                        overflowX: "hidden",
                                        overflowY: overHeight ? "auto" : "hidden"
                                });
                                if(overHeight){
-                                       mb.h = this.maxHeight;
+                                       mb.h = maxHeight;
                                        if("w" in mb){
                                                mb.w += 16;     // room for vertical scrollbar
                                        }
                                }else{
                                        delete mb.h;
                                }
-                               delete mb.t;
-                               delete mb.l;
 
                                // Adjust dropdown width to match or be larger than my width
                                if(this.forceWidth){
-                                       mb.w = this.domNode.offsetWidth;
+                                       mb.w = aroundNode.offsetWidth;
                                }else if(this.autoWidth){
-                                       mb.w = Math.max(mb.w, this.domNode.offsetWidth);
+                                       mb.w = Math.max(mb.w, aroundNode.offsetWidth);
                                }else{
                                        delete mb.w;
                                }
@@ -11007,7 +11711,7 @@ dojo.declare("dijit._HasDropDown",
                        var retVal = dijit.popup.open({
                                parent: this,
                                popup: dropDown,
-                               around: this._aroundNode,
+                               around: aroundNode,
                                orient: dijit.getPopupAroundAlignment((this.dropDownPosition && this.dropDownPosition.length) ? this.dropDownPosition : ["below"],this.isLeftToRight()),
                                onExecute: function(){
                                        self.closeDropDown(true);
@@ -11019,13 +11723,12 @@ dojo.declare("dijit._HasDropDown",
                                        dojo.attr(self._popupStateNode, "popupActive", false);
                                        dojo.removeClass(self._popupStateNode, "dijitHasDropDownOpen");
                                        self._opened = false;
-                                       self.state = "";
                                }
                        });
                        dojo.attr(this._popupStateNode, "popupActive", "true");
                        dojo.addClass(self._popupStateNode, "dijitHasDropDownOpen");
                        this._opened=true;
-                       this.state="Opened";
+
                        // TODO: set this.checked and call setStateClass(), to affect button look while drop down is shown
                        return retVal;
                },
@@ -11033,6 +11736,8 @@ dojo.declare("dijit._HasDropDown",
                closeDropDown: function(/*Boolean*/ focus){
                        // summary:
                        //              Closes the drop down on this widget
+                       // focus:
+                       //              If true, refocuses the button widget
                        // tags:
                        //              protected
 
@@ -11040,7 +11745,6 @@ dojo.declare("dijit._HasDropDown",
                                if(focus){ this.focus(); }
                                dijit.popup.close(this.dropDown);
                                this._opened = false;
-                               this.state = "";
                        }
                }
 
@@ -11099,14 +11803,12 @@ dojo.declare("dijit.form.Button",
 
        baseClass: "dijitButton",
 
-       templateString: dojo.cache("dijit.form", "templates/Button.html", "<span class=\"dijit dijitReset dijitInline\"\n\t><span class=\"dijitReset dijitInline dijitButtonNode\"\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"titleNode,focusNode\"\n\t\t\twaiRole=\"button\" waiState=\"labelledby-${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\"></span\n\t\t\t><span class=\"dijitReset dijitToggleButtonIconChar\">&#x25CF;</span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t\tdojoAttachPoint=\"containerNode\"\n\t\t\t></span\n\t\t></span\n\t></span\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\n\t\tdojoAttachPoint=\"valueNode\"\n/></span>\n"),
+       templateString: dojo.cache("dijit.form", "templates/Button.html", "<span class=\"dijit dijitReset dijitInline\"\n\t><span class=\"dijitReset dijitInline dijitButtonNode\"\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"titleNode,focusNode\"\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\"></span\n\t\t\t><span class=\"dijitReset dijitToggleButtonIconChar\">&#x25CF;</span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t\tdojoAttachPoint=\"containerNode\"\n\t\t\t></span\n\t\t></span\n\t></span\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\" tabIndex=\"-1\"\n\t\tdojoAttachPoint=\"valueNode\"\n/></span>\n"),
 
        attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
-               value: "valueNode",
-               iconClass: { node: "iconNode", type: "class" }
+               value: "valueNode"
        }),
 
-
        _onClick: function(/*Event*/ e){
                // summary:
                //              Internal function to handle click actions
@@ -11136,25 +11838,26 @@ dojo.declare("dijit.form.Button",
                }
        },
 
+       buildRendering: function(){
+               this.inherited(arguments);
+               dojo.setSelectable(this.focusNode, false);
+       },
+
        _fillContent: function(/*DomNode*/ source){
                // Overrides _Templated._fillContent().
                // If button label is specified as srcNodeRef.innerHTML rather than
                // this.params.label, handle it here.
+               // TODO: remove the method in 2.0, parser will do it all for me
                if(source && (!this.params || !("label" in this.params))){
                        this.set('label', source.innerHTML);
                }
        },
 
-       postCreate: function(){
-               dojo.setSelectable(this.focusNode, false);
-               this.inherited(arguments);
-       },
-
        _setShowLabelAttr: function(val){
                if(this.containerNode){
                        dojo.toggleClass(this.containerNode, "dijitDisplayNone", !val);
                }
-               this.showLabel = val;
+               this._set("showLabel", val);
        },
 
        onClick: function(/*Event*/ e){
@@ -11180,13 +11883,24 @@ dojo.declare("dijit.form.Button",
 
        _setLabelAttr: function(/*String*/ content){
                // summary:
-               //              Hook for attr('label', ...) to work.
+               //              Hook for set('label', ...) to work.
                // description:
                //              Set the label (text) of the button; takes an HTML string.
-               this.containerNode.innerHTML = this.label = content;
+               this._set("label", content);
+               this.containerNode.innerHTML = content;
                if(this.showLabel == false && !this.params.title){
                        this.titleNode.title = dojo.trim(this.containerNode.innerText || this.containerNode.textContent || '');
                }
+       },
+
+       _setIconClassAttr: function(/*String*/ val){
+               // Custom method so that icon node is hidden when not in use, to avoid excess padding/margin
+               // appearing around it (even if it's a 0x0 sized <img> node)
+
+               var oldVal = this.iconClass || "dijitNoIcon",
+                       newVal = val || "dijitNoIcon";
+               dojo.replaceClass(this.iconNode, newVal, oldVal);
+               this._set("iconClass", val);
        }
 });
 
@@ -11207,7 +11921,7 @@ dojo.declare("dijit.form.DropDownButton", [dijit.form.Button, dijit._Container,
 
        baseClass : "dijitDropDownButton",
 
-       templateString: dojo.cache("dijit.form", "templates/DropDownButton.html", "<span class=\"dijit dijitReset dijitInline\"\n\t><span class='dijitReset dijitInline dijitButtonNode'\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\" dojoAttachPoint=\"_buttonNode\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"focusNode,titleNode,_arrowWrapperNode\"\n\t\t\twaiRole=\"button\" waiState=\"haspopup-true,labelledby-${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\"\n\t\t\t\tdojoAttachPoint=\"iconNode\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tdojoAttachPoint=\"containerNode,_popupStateNode\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonInner\"></span\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonChar\">&#9660;</span\n\t\t></span\n\t></span\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\n\t\tdojoAttachPoint=\"valueNode\"\n/></span>\n"),
+       templateString: dojo.cache("dijit.form", "templates/DropDownButton.html", "<span class=\"dijit dijitReset dijitInline\"\n\t><span class='dijitReset dijitInline dijitButtonNode'\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\" dojoAttachPoint=\"_buttonNode\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"focusNode,titleNode,_arrowWrapperNode\"\n\t\t\trole=\"button\" aria-haspopup=\"true\" aria-labelledby=\"${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\"\n\t\t\t\tdojoAttachPoint=\"iconNode\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tdojoAttachPoint=\"containerNode,_popupStateNode\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonInner\"></span\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonChar\">&#9660;</span\n\t\t></span\n\t></span\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\" tabIndex=\"-1\"\n\t\tdojoAttachPoint=\"valueNode\"\n/></span>\n"),
 
        _fillContent: function(){
                // Overrides Button._fillContent().
@@ -11232,12 +11946,14 @@ dojo.declare("dijit.form.DropDownButton", [dijit.form.Button, dijit._Container,
 
                // the child widget from srcNodeRef is the dropdown widget.  Insert it in the page DOM,
                // make it invisible, and store a reference to pass to the popup code.
-               if(!this.dropDown){
+               if(!this.dropDown && this.dropDownContainer){
                        var dropDownNode = dojo.query("[widgetId]", this.dropDownContainer)[0];
                        this.dropDown = dijit.byNode(dropDownNode);
                        delete this.dropDownContainer;
                }
-               dijit.popup.moveOffScreen(this.dropDown.domNode);
+               if(this.dropDown){
+                       dijit.popup.hide(this.dropDown);
+               }
 
                this.inherited(arguments);
        },
@@ -11246,7 +11962,7 @@ dojo.declare("dijit.form.DropDownButton", [dijit.form.Button, dijit._Container,
                // Returns whether or not we are loaded - if our dropdown has an href,
                // then we want to check that.
                var dropDown = this.dropDown;
-               return (!dropDown.href || dropDown.isLoaded);
+               return (!!dropDown && (!dropDown.href || dropDown.isLoaded));
        },
 
        loadDropDown: function(){
@@ -11288,7 +12004,7 @@ dojo.declare("dijit.form.ComboButton", dijit.form.DropDownButton, {
        // |    dojo.body().appendChild(button1.domNode);
        //
 
-       templateString: dojo.cache("dijit.form", "templates/ComboButton.html", "<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tcellspacing='0' cellpadding='0' waiRole=\"presentation\"\n\t><tbody waiRole=\"presentation\"><tr waiRole=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonNode\" dojoAttachPoint=\"buttonNode\" dojoAttachEvent=\"ondijitclick:_onButtonClick,onkeypress:_onButtonKeyPress\"\n\t\t><div id=\"${id}_button\" class=\"dijitReset dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"titleNode\"\n\t\t\twaiRole=\"button\" waiState=\"labelledby-${id}_label\"\n\t\t\t><div class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\" waiRole=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitInline dijitButtonText\" id=\"${id}_label\" dojoAttachPoint=\"containerNode\" waiRole=\"presentation\"></div\n\t\t></div\n\t\t></td\n\t\t><td id=\"${id}_arrow\" class='dijitReset dijitRight dijitButtonNode dijitArrowButton'\n\t\t\tdojoAttachPoint=\"_popupStateNode,focusNode,_buttonNode\"\n\t\t\tdojoAttachEvent=\"onkeypress:_onArrowKeyPress\"\n\t\t\ttitle=\"${optionsTitle}\"\n\t\t\twaiRole=\"button\" waiState=\"haspopup-true\"\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" waiRole=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" waiRole=\"presentation\">&#9660;</div\n\t\t></td\n\t\t><td style=\"display:none !important;\"\n\t\t\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" dojoAttachPoint=\"valueNode\"\n\t\t/></td></tr></tbody\n></table>\n"),
+       templateString: dojo.cache("dijit.form", "templates/ComboButton.html", "<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tcellspacing='0' cellpadding='0' role=\"presentation\"\n\t><tbody role=\"presentation\"><tr role=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonNode\" dojoAttachPoint=\"buttonNode\" dojoAttachEvent=\"ondijitclick:_onButtonClick,onkeypress:_onButtonKeyPress\"\n\t\t><div id=\"${id}_button\" class=\"dijitReset dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"titleNode\"\n\t\t\trole=\"button\" aria-labelledby=\"${id}_label\"\n\t\t\t><div class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\" role=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitInline dijitButtonText\" id=\"${id}_label\" dojoAttachPoint=\"containerNode\" role=\"presentation\"></div\n\t\t></div\n\t\t></td\n\t\t><td id=\"${id}_arrow\" class='dijitReset dijitRight dijitButtonNode dijitArrowButton'\n\t\t\tdojoAttachPoint=\"_popupStateNode,focusNode,_buttonNode\"\n\t\t\tdojoAttachEvent=\"onkeypress:_onArrowKeyPress\"\n\t\t\ttitle=\"${optionsTitle}\"\n\t\t\trole=\"button\" aria-haspopup=\"true\"\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" role=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" role=\"presentation\">&#9660;</div\n\t\t></td\n\t\t><td style=\"display:none !important;\"\n\t\t\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" dojoAttachPoint=\"valueNode\"\n\t\t/></td></tr></tbody\n></table>\n"),
 
        attributeMap: dojo.mixin(dojo.clone(dijit.form.Button.prototype.attributeMap), {
                id: "",
@@ -11336,8 +12052,9 @@ dojo.declare("dijit.form.ComboButton", dijit.form.DropDownButton, {
                //              otherwise on arrow node
                // position:
                //              "start" or "end"
-               
-               dijit.focus(position == "start" ? this.titleNode : this._popupStateNode);
+               if(!this.disabled){
+                       dijit.focus(position == "start" ? this.titleNode : this._popupStateNode);
+               }
        }
 });
 
@@ -11363,8 +12080,8 @@ dojo.declare("dijit.form.ToggleButton", dijit.form.Button, {
                this.set('checked', !this.checked);
        },
 
-       _setCheckedAttr: function(/*Boolean*/ value, /* Boolean? */ priorityChange){
-               this.checked = value;
+       _setCheckedAttr: function(/*Boolean*/ value, /*Boolean?*/ priorityChange){
+               this._set("checked", value);
                dojo.attr(this.focusNode || this.domNode, "checked", value);
                dijit.setWaiState(this.focusNode || this.domNode, "pressed", value);
                this._handleOnChange(value, priorityChange);
@@ -11372,7 +12089,7 @@ dojo.declare("dijit.form.ToggleButton", dijit.form.Button, {
 
        setChecked: function(/*Boolean*/ checked){
                // summary:
-               //              Deprecated.   Use set('checked', true/false) instead.
+               //              Deprecated.  Use set('checked', true/false) instead.
                dojo.deprecated("setChecked("+checked+") is deprecated. Use set('checked',"+checked+") instead.", "", "2.0");
                this.set('checked', checked);
        },
@@ -11395,6 +12112,8 @@ dojo._hasResource["dijit.form.ToggleButton"] = true;
 dojo.provide("dijit.form.ToggleButton");
 
 
+
+
 }
 
 if(!dojo._hasResource["dijit.form.CheckBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
@@ -11424,26 +12143,26 @@ dojo.declare(
                //              In case 2, the regular html inputs are invisible but still used by
                //              the user. They are turned quasi-invisible and overlay the background-image.
 
-               templateString: dojo.cache("dijit.form", "templates/CheckBox.html", "<div class=\"dijit dijitReset dijitInline\" waiRole=\"presentation\"\n\t><input\n\t \t${!nameAttrSetting} type=\"${type}\" ${checkedAttrSetting}\n\t\tclass=\"dijitReset dijitCheckBoxInput\"\n\t\tdojoAttachPoint=\"focusNode\"\n\t \tdojoAttachEvent=\"onclick:_onClick\"\n/></div>\n"),
+               templateString: dojo.cache("dijit.form", "templates/CheckBox.html", "<div class=\"dijit dijitReset dijitInline\" role=\"presentation\"\n\t><input\n\t \t${!nameAttrSetting} type=\"${type}\" ${checkedAttrSetting}\n\t\tclass=\"dijitReset dijitCheckBoxInput\"\n\t\tdojoAttachPoint=\"focusNode\"\n\t \tdojoAttachEvent=\"onclick:_onClick\"\n/></div>\n"),
 
                baseClass: "dijitCheckBox",
 
                // type: [private] String
                //              type attribute on <input> node.
-               //              Overrides `dijit.form.Button.type`.   Users should not change this value.
+               //              Overrides `dijit.form.Button.type`.  Users should not change this value.
                type: "checkbox",
 
                // value: String
                //              As an initialization parameter, equivalent to value field on normal checkbox
                //              (if checked, the value is passed as the value when form is submitted).
                //
-               //              However, attr('value') will return either the string or false depending on
+               //              However, get('value') will return either the string or false depending on
                //              whether or not the checkbox is checked.
                //
-               //              attr('value', string) will check the checkbox and change the value to the
+               //              set('value', string) will check the checkbox and change the value to the
                //              specified string
                //
-               //              attr('value', boolean) will change the checked state.
+               //              set('value', boolean) will change the checked state.
                value: "on",
 
                // readOnly: Boolean
@@ -11452,22 +12171,22 @@ dojo.declare(
                //              Similar to disabled except readOnly form values are submitted.
                readOnly: false,
                
-               // the attributeMap should inherit from dijit.form._FormWidget.prototype.attributeMap 
+               // the attributeMap should inherit from dijit.form._FormWidget.prototype.attributeMap
                // instead of ToggleButton as the icon mapping has no meaning for a CheckBox
                attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
                        readOnly: "focusNode"
                }),
 
                _setReadOnlyAttr: function(/*Boolean*/ value){
-                       this.readOnly = value;
+                       this._set("readOnly", value);
                        dojo.attr(this.focusNode, 'readOnly', value);
                        dijit.setWaiState(this.focusNode, "readonly", value);
                },
 
-               _setValueAttr: function(/*String or Boolean*/ newValue, /*Boolean*/ priorityChange){
+               _setValueAttr: function(/*String|Boolean*/ newValue, /*Boolean*/ priorityChange){
                        // summary:
                        //              Handler for value= attribute to constructor, and also calls to
-                       //              attr('value', val).
+                       //              set('value', val).
                        // description:
                        //              During initialization, just saves as attribute to the <input type=checkbox>.
                        //
@@ -11477,7 +12196,7 @@ dojo.declare(
                        //              specified as "value" when the CheckBox was constructed (ex: <input
                        //              dojoType="dijit.CheckBox" value="chicken">)
                        if(typeof newValue == "string"){
-                               this.value = newValue;
+                               this._set("value", newValue);
                                dojo.attr(this.focusNode, 'value', newValue);
                                newValue = true;
                        }
@@ -11487,7 +12206,7 @@ dojo.declare(
                },
                _getValueAttr: function(){
                        // summary:
-                       //              Hook so attr('value') works.
+                       //              Hook so get('value') works.
                        // description:
                        //              If the CheckBox is checked, returns the value attribute.
                        //              Otherwise returns false.
@@ -11524,7 +12243,7 @@ dojo.declare(
                        this.set('checked', this.params.checked || false);
 
                        // Handle unlikely event that the <input type=checkbox> value attribute has changed
-                       this.value = this.params.value || "on";
+                       this._set("value", this.params.value || "on");
                        dojo.attr(this.focusNode, 'value', this.value);
                },
 
@@ -11547,6 +12266,7 @@ dojo.declare(
                        //              Internal function to handle click actions - need to check
                        //              readOnly, since button no longer does that check.
                        if(this.readOnly){
+                               dojo.stopEvent(e);
                                return false;
                        }
                        return this.inherited(arguments);
@@ -11600,12 +12320,15 @@ dojo.provide("dijit.form.DropDownButton");
 
 
 
+
 }
 
 if(!dojo._hasResource["dojo.regexp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
 dojo._hasResource["dojo.regexp"] = true;
 dojo.provide("dojo.regexp");
 
+dojo.getObject("regexp", true, dojo);
+
 /*=====
 dojo.regexp = {
        // summary: Regular expressions and Builder resources
@@ -11624,7 +12347,7 @@ dojo.regexp.escapeString = function(/*String*/str, /*String?*/except){
                }
                return "\\" + ch;
        }); // String
-}
+};
 
 dojo.regexp.buildGroupRE = function(/*Object|Array*/arr, /*Function*/re, /*Boolean?*/nonCapture){
        //      summary:
@@ -11639,7 +12362,7 @@ dojo.regexp.buildGroupRE = function(/*Object|Array*/arr, /*Function*/re, /*Boole
        //              A single value or an array of values.
        // re:
        //              A function. Takes one parameter and converts it to a regular
-       //              expression. 
+       //              expression.
        // nonCapture:
        //              If true, uses non-capturing match, otherwise matches are retained
        //              by regular expression. Defaults to false
@@ -11658,16 +12381,16 @@ dojo.regexp.buildGroupRE = function(/*Object|Array*/arr, /*Function*/re, /*Boole
 
         // join the REs as alternatives in a RE group.
        return dojo.regexp.group(b.join("|"), nonCapture); // String
-}
+};
 
 dojo.regexp.group = function(/*String*/expression, /*Boolean?*/nonCapture){
        // summary:
        //              adds group match to expression
        // nonCapture:
        //              If true, uses non-capturing match, otherwise matches are retained
-       //              by regular expression. 
+       //              by regular expression.
        return "(" + (nonCapture ? "?:":"") + expression + ")"; // String
-}
+};
 
 }
 
@@ -11675,11 +12398,13 @@ if(!dojo._hasResource["dojo.data.util.sorter"]){ //_hasResource checks added by
 dojo._hasResource["dojo.data.util.sorter"] = true;
 dojo.provide("dojo.data.util.sorter");
 
-dojo.data.util.sorter.basicComparator = function(      /*anything*/ a, 
+dojo.getObject("data.util.sorter", true, dojo);
+
+dojo.data.util.sorter.basicComparator = function(      /*anything*/ a,
                                                                                                        /*anything*/ b){
-       //      summary:  
+       //      summary:
        //              Basic comparision function that compares if an item is greater or less than another item
-       //      description:  
+       //      description:
        //              returns 1 if a > b, -1 if a < b, 0 if equal.
        //              'null' values (null, undefined) are treated as larger values so that they're pushed to the end of the list.
        //              And compared to each other, null is equivalent to undefined.
@@ -11696,18 +12421,18 @@ dojo.data.util.sorter.basicComparator = function(     /*anything*/ a,
                b = undefined;
        }
        if(a == b){
-               r = 0; 
+               r = 0;
        }else if(a > b || a == null){
-               r = 1; 
+               r = 1;
        }
        return r; //int {-1,0,1}
 };
 
 dojo.data.util.sorter.createSortFunction = function(   /* attributes array */sortSpec,
                                                                                                                /*dojo.data.core.Read*/ store){
-       //      summary:  
+       //      summary:
        //              Helper function to generate the sorting function based off the list of sort attributes.
-       //      description:  
+       //      description:
        //              The sort function creation will look for a property on the store called 'comparatorMap'.  If it exists
        //              it will look in the mapping for comparisons function for the attributes.  If one is found, it will
        //              use it instead of the basic comparator, which is typically used for strings, ints, booleans, and dates.
@@ -11749,7 +12474,7 @@ dojo.data.util.sorter.createSortFunction = function(    /* attributes array */sortS
                                }
                                comp = map[attr] || bc;
                        }
-                       sortFunctions.push(createSortFunction(attr, 
+                       sortFunctions.push(createSortFunction(attr,
                                dir, comp, store));
                }
        }
@@ -11761,7 +12486,7 @@ dojo.data.util.sorter.createSortFunction = function(    /* attributes array */sortS
                                return ret;//int
                        }
                }
-               return 0; //int  
+               return 0; //int
        }; // Function
 };
 
@@ -11772,30 +12497,32 @@ dojo._hasResource["dojo.data.util.simpleFetch"] = true;
 dojo.provide("dojo.data.util.simpleFetch");
 
 
+dojo.getObject("data.util.simpleFetch", true, dojo);
+
 dojo.data.util.simpleFetch.fetch = function(/* Object? */ request){
        //      summary:
        //              The simpleFetch mixin is designed to serve as a set of function(s) that can
-       //              be mixed into other datastore implementations to accelerate their development.  
-       //              The simpleFetch mixin should work well for any datastore that can respond to a _fetchItems() 
+       //              be mixed into other datastore implementations to accelerate their development.
+       //              The simpleFetch mixin should work well for any datastore that can respond to a _fetchItems()
        //              call by returning an array of all the found items that matched the query.  The simpleFetch mixin
        //              is not designed to work for datastores that respond to a fetch() call by incrementally
        //              loading items, or sequentially loading partial batches of the result
-       //              set.  For datastores that mixin simpleFetch, simpleFetch 
+       //              set.  For datastores that mixin simpleFetch, simpleFetch
        //              implements a fetch method that automatically handles eight of the fetch()
        //              arguments -- onBegin, onItem, onComplete, onError, start, count, sort and scope
        //              The class mixing in simpleFetch should not implement fetch(),
-       //              but should instead implement a _fetchItems() method.  The _fetchItems() 
-       //              method takes three arguments, the keywordArgs object that was passed 
+       //              but should instead implement a _fetchItems() method.  The _fetchItems()
+       //              method takes three arguments, the keywordArgs object that was passed
        //              to fetch(), a callback function to be called when the result array is
        //              available, and an error callback to be called if something goes wrong.
        //              The _fetchItems() method should ignore any keywordArgs parameters for
-       //              start, count, onBegin, onItem, onComplete, onError, sort, and scope.  
+       //              start, count, onBegin, onItem, onComplete, onError, sort, and scope.
        //              The _fetchItems() method needs to correctly handle any other keywordArgs
-       //              parameters, including the query parameter and any optional parameters 
-       //              (such as includeChildren).  The _fetchItems() method should create an array of 
-       //              result items and pass it to the fetchHandler along with the original request object 
-       //              -- or, the _fetchItems() method may, if it wants to, create an new request object 
-       //              with other specifics about the request that are specific to the datastore and pass 
+       //              parameters, including the query parameter and any optional parameters
+       //              (such as includeChildren).  The _fetchItems() method should create an array of
+       //              result items and pass it to the fetchHandler along with the original request object
+       //              -- or, the _fetchItems() method may, if it wants to, create an new request object
+       //              with other specifics about the request that are specific to the datastore and pass
        //              that as the request object to the handler.
        //
        //              For more information on this specific function, see dojo.data.api.Read.fetch()
@@ -11862,12 +12589,14 @@ if(!dojo._hasResource["dojo.data.util.filter"]){ //_hasResource checks added by
 dojo._hasResource["dojo.data.util.filter"] = true;
 dojo.provide("dojo.data.util.filter");
 
+dojo.getObject("data.util.filter", true, dojo);
+
 dojo.data.util.filter.patternToRegExp = function(/*String*/pattern, /*boolean?*/ ignoreCase){
-       //      summary:  
+       //      summary:
        //              Helper function to convert a simple pattern to a regular expression for matching.
        //      description:
        //              Returns a regular expression object that conforms to the defined conversion rules.
-       //              For example:  
+       //              For example:
        //                      ca*   -> /^ca.*$/
        //                      *ca*  -> /^.*ca.*$/
        //                      *c\*a*  -> /^.*c\*a.*$/
@@ -11879,7 +12608,7 @@ dojo.data.util.filter.patternToRegExp = function(/*String*/pattern, /*boolean?*/
        //                      * Means match anything, so ca* means match anything starting with ca
        //                      ? Means match single character.  So, b?b will match to bob and bab, and so on.
        //              \ is an escape character.  So for example, \* means do not treat * as a match, but literal character *.
-       //                              To use a \ as a character in the string, it must be escaped.  So in the pattern it should be 
+       //                              To use a \ as a character in the string, it must be escaped.  So in the pattern it should be
        //                              represented by \\ to be treated as an ordinary \ character instead of an escape.
        //
        //      ignoreCase:
@@ -11957,20 +12686,20 @@ dojo.declare(
                //              Converts the first character of each word to uppercase if true.
                propercase: false,
 
-               //      maxLength: String
+               // maxLength: String
                //              HTML INPUT tag maxLength declaration.
                maxLength: "",
 
-               //      selectOnClick: [const] Boolean
+               // selectOnClick: [const] Boolean
                //              If true, all text will be selected when focused with mouse
                selectOnClick: false,
 
-               //      placeHolder: String
+               // placeHolder: String
                //              Defines a hint to help users fill out the input field (as defined in HTML 5).
                //              This should only contain plain text (no html markup).
                placeHolder: "",
                
-               templateString: dojo.cache("dijit.form", "templates/TextBox.html", "<div class=\"dijit dijitReset dijitInline dijitLeft\" id=\"widget_${id}\" waiRole=\"presentation\"\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n"),
+               templateString: dojo.cache("dijit.form", "templates/TextBox.html", "<div class=\"dijit dijitReset dijitInline dijitLeft\" id=\"widget_${id}\" role=\"presentation\"\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n"),
                _singleNodeTemplate: '<input class="dijit dijitReset dijitLeft dijitInputField" dojoAttachPoint="textbox,focusNode" autocomplete="off" type="${type}" ${!nameAttrSetting} />',
 
                _buttonInputDisabled: dojo.isIE ? "disabled" : "", // allows IE to disallow focus, but Firefox cannot be disabled for mousedown events
@@ -11983,14 +12712,14 @@ dojo.declare(
                
                postMixInProperties: function(){
                        var type = this.type.toLowerCase();
-                       if(this.templateString.toLowerCase() == "input" || ((type == "hidden" || type == "file") && this.templateString == dijit.form.TextBox.prototype.templateString)){
+                       if(this.templateString && this.templateString.toLowerCase() == "input" || ((type == "hidden" || type == "file") && this.templateString == dijit.form.TextBox.prototype.templateString)){
                                this.templateString = this._singleNodeTemplate;
                        }
                        this.inherited(arguments);
                },
 
                _setPlaceHolderAttr: function(v){
-                       this.placeHolder = v;
+                       this._set("placeHolder", v);
                        if(!this._phspan){
                                this._attachPoints.push('_phspan');
                                /* dijitInputField class gives placeHolder same padding as the input field
@@ -12013,7 +12742,7 @@ dojo.declare(
 
                _getValueAttr: function(){
                        // summary:
-                       //              Hook so attr('value') works as we like.
+                       //              Hook so get('value') works as we like.
                        // description:
                        //              For `dijit.form.TextBox` this basically returns the value of the <input>.
                        //
@@ -12026,7 +12755,7 @@ dojo.declare(
 
                _setValueAttr: function(value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
                        // summary:
-                       //              Hook so attr('value', ...) works.
+                       //              Hook so set('value', ...) works.
                        //
                        // description:
                        //              Sets the value of the widget to "value" which can be of
@@ -12057,6 +12786,7 @@ dojo.declare(
                        }
                        if(formattedValue != null && formattedValue != undefined && ((typeof formattedValue) != "number" || !isNaN(formattedValue)) && this.textbox.value != formattedValue){
                                this.textbox.value = formattedValue;
+                               this._set("displayedValue", this.get("displayedValue"));
                        }
 
                        this._updatePlaceHolder();
@@ -12069,7 +12799,7 @@ dojo.declare(
                //              (ex: Kentucky) and the serialized value (ex: KY) are different,
                //              this represents the displayed value.
                //
-               //              Setting 'displayedValue' through attr('displayedValue', ...)
+               //              Setting 'displayedValue' through set('displayedValue', ...)
                //              updates 'value', and vice-versa.  Otherwise 'value' is updated
                //              from 'displayedValue' periodically, like onBlur etc.
                //
@@ -12080,7 +12810,7 @@ dojo.declare(
 
                getDisplayedValue: function(){
                        // summary:
-                       //              Deprecated.   Use set('displayedValue') instead.
+                       //              Deprecated.  Use get('displayedValue') instead.
                        // tags:
                        //              deprecated
                        dojo.deprecated(this.declaredClass+"::getDisplayedValue() is deprecated. Use set('displayedValue') instead.", "", "2.0");
@@ -12089,7 +12819,7 @@ dojo.declare(
 
                _getDisplayedValueAttr: function(){
                        // summary:
-                       //              Hook so attr('displayedValue') works.
+                       //              Hook so get('displayedValue') works.
                        // description:
                        //              Returns the displayed value (what the user sees on the screen),
                        //              after filtering (ie, trimming spaces etc.).
@@ -12098,21 +12828,24 @@ dojo.declare(
                        //              is different from the serialized value that's actually
                        //              sent to the server (see dijit.form.ValidationTextBox.serialize)
 
+                       // TODO: maybe we should update this.displayedValue on every keystroke so that we don't need
+                       // this method
+                       // TODO: this isn't really the displayed value when the user is typing
                        return this.filter(this.textbox.value);
                },
 
-               setDisplayedValue: function(/*String*/value){
+               setDisplayedValue: function(/*String*/ value){
                        // summary:
-                       //              Deprecated.   Use set('displayedValue', ...) instead.
+                       //              Deprecated.  Use set('displayedValue', ...) instead.
                        // tags:
                        //              deprecated
                        dojo.deprecated(this.declaredClass+"::setDisplayedValue() is deprecated. Use set('displayedValue', ...) instead.", "", "2.0");
                        this.set('displayedValue', value);
                },
 
-               _setDisplayedValueAttr: function(/*String*/value){
+               _setDisplayedValueAttr: function(/*String*/ value){
                        // summary:
-                       //              Hook so attr('displayedValue', ...) works.
+                       //              Hook so set('displayedValue', ...) works.
                        // description:
                        //              Sets the value of the visual element to the string "value".
                        //              The widget value is also set to a corresponding,
@@ -12120,11 +12853,18 @@ dojo.declare(
 
                        if(value === null || value === undefined){ value = '' }
                        else if(typeof value != "string"){ value = String(value) }
+
                        this.textbox.value = value;
-                       this._setValueAttr(this.get('value'), undefined, value);
+
+                       // sets the serialized value to something corresponding to specified displayedValue
+                       // (if possible), and also updates the textbox.value, for example converting "123"
+                       // to "123.00"
+                       this._setValueAttr(this.get('value'), undefined);
+
+                       this._set("displayedValue", this.get('displayedValue'));
                },
 
-               format: function(/* String */ value, /* Object */ constraints){
+               format: function(/*String*/ value, /*Object*/ constraints){
                        // summary:
                        //              Replacable function to convert a value to a properly formatted string.
                        // tags:
@@ -12132,7 +12872,7 @@ dojo.declare(
                        return ((value == null || value == undefined) ? "" : (value.toString ? value.toString() : value));
                },
 
-               parse: function(/* String */ value, /* Object */ constraints){
+               parse: function(/*String*/ value, /*Object*/ constraints){
                        // summary:
                        //              Replacable function to convert a formatted string to a value
                        // tags:
@@ -12166,12 +12906,15 @@ dojo.declare(
                                setTimeout(function(){ _this._handleOnChange(_this.get('value'), false); }, 0);
                        }
                        this._refreshState();
+
+                       // In case someone is watch()'ing for changes to displayedValue
+                       this._set("displayedValue", this.get("displayedValue"));
                },
 
                postCreate: function(){
-                       // setting the value here is needed since value="" in the template causes "undefined"
-                       // and setting in the DOM (instead of the JS object) helps with form reset actions
                        if(dojo.isIE){ // IE INPUT tag fontFamily has to be set directly using STYLE
+                               // the setTimeout gives IE a chance to render the TextBox and to deal with font inheritance
+                               setTimeout(dojo.hitch(this, function(){
                                var s = dojo.getComputedStyle(this.domNode);
                                if(s){
                                        var ff = s.fontFamily;
@@ -12184,16 +12927,22 @@ dojo.declare(
                                                }
                                        }
                                }
+                               }), 0);
                        }
-                       this.textbox.setAttribute("value", this.textbox.value); // DOM and JS values shuld be the same
+
+                       // setting the value here is needed since value="" in the template causes "undefined"
+                       // and setting in the DOM (instead of the JS object) helps with form reset actions
+                       this.textbox.setAttribute("value", this.textbox.value); // DOM and JS values should be the same
+
                        this.inherited(arguments);
+
                        if(dojo.isMoz || dojo.isOpera){
-                               this.connect(this.textbox, "oninput", this._onInput);
+                               this.connect(this.textbox, "oninput", "_onInput");
                        }else{
-                               this.connect(this.textbox, "onkeydown", this._onInput);
-                               this.connect(this.textbox, "onkeyup", this._onInput);
-                               this.connect(this.textbox, "onpaste", this._onInput);
-                               this.connect(this.textbox, "oncut", this._onInput);
+                               this.connect(this.textbox, "onkeydown", "_onInput");
+                               this.connect(this.textbox, "onkeyup", "_onInput");
+                               this.connect(this.textbox, "onpaste", "_onInput");
+                               this.connect(this.textbox, "oncut", "_onInput");
                        }
                },
 
@@ -12205,8 +12954,8 @@ dojo.declare(
                        // description:
                        //              For MappedTextBox subclasses, this is called twice
                        //                      - once with the display value
-                       //                      - once the value as set/returned by attr('value', ...)
-                       //              and attr('value'), ex: a Number for NumberTextBox.
+                       //                      - once the value as set/returned by set('value', ...)
+                       //              and get('value'), ex: a Number for NumberTextBox.
                        //
                        //              In the latter case it does corrections like converting null to NaN.  In
                        //              the former case the NumberTextBox.filter() method calls this.inherited()
@@ -12284,8 +13033,11 @@ dojo.declare(
 
                        this._updatePlaceHolder();
                        
-                       this._refreshState();
+                       // call this.inherited() before refreshState(), since this.inherited() will possibly scroll the viewport
+                       // (to scroll the TextBox into view), which will affect how _refreshState() positions the tooltip
                        this.inherited(arguments);
+
+                       this._refreshState();
                },
 
                reset: function(){
@@ -12297,7 +13049,7 @@ dojo.declare(
        }
 );
 
-dijit.selectInputText = function(/*DomNode*/element, /*Number?*/ start, /*Number?*/ stop){
+dijit.selectInputText = function(/*DomNode*/ element, /*Number?*/ start, /*Number?*/ stop){
        // summary:
        //              Select text in the input element argument, from start (default 0), to stop (default end).
 
@@ -12310,14 +13062,12 @@ dijit.selectInputText = function(/*DomNode*/element, /*Number?*/ start, /*Number
        dijit.focus(element);
        if(_document["selection"] && dojo.body()["createTextRange"]){ // IE
                if(element.createTextRange){
-                       var range = element.createTextRange();
-                       with(range){
-                               collapse(true);
-                               moveStart("character", -99999); // move to 0
-                               moveStart("character", start); // delta from 0 is the correct position
-                               moveEnd("character", stop-start);
-                               select();
-                       }
+                       var r = element.createTextRange();
+                       r.collapse(true);
+                       r.moveStart("character", -99999); // move to 0
+                       r.moveStart("character", start); // delta from 0 is the correct position
+                       r.moveEnd("character", stop-start);
+                       r.select();
                }
        }else if(_window["getSelection"]){
                if(element.setSelectionRange){
@@ -12351,7 +13101,7 @@ dojo.declare(
                //              Milliseconds to fade in/fade out
                duration: dijit.defaultDuration,
 
-               templateString: dojo.cache("dijit", "templates/Tooltip.html", "<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\">\n\t<div class=\"dijitTooltipContainer dijitTooltipContents\" dojoAttachPoint=\"containerNode\" waiRole='alert'></div>\n\t<div class=\"dijitTooltipConnector\"></div>\n</div>\n"),
+               templateString: dojo.cache("dijit", "templates/Tooltip.html", "<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\"\n\t><div class=\"dijitTooltipContainer dijitTooltipContents\" dojoAttachPoint=\"containerNode\" role='alert'></div\n\t><div class=\"dijitTooltipConnector\" dojoAttachPoint=\"connectorNode\"></div\n></div>\n"),
 
                postCreate: function(){
                        dojo.body().appendChild(this.domNode);
@@ -12361,7 +13111,6 @@ dojo.declare(
                        // Setup fade-in and fade-out functions.
                        this.fadeIn = dojo.fadeIn({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onShow") });
                        this.fadeOut = dojo.fadeOut({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onHide") });
-
                },
 
                show: function(/*String*/ innerHTML, /*DomNode*/ aroundNode, /*String[]?*/ position, /*Boolean*/ rtl){
@@ -12373,6 +13122,9 @@ dojo.declare(
                                return;
                        }
 
+                       // reset width; it may have been set by orient() on a previous tooltip show()
+                       this.domNode.width = "auto";
+
                        if(this.fadeOut.status() == "playing"){
                                // previous tooltip is being hidden; wait until the hide completes then show new one
                                this._onDeck=arguments;
@@ -12389,12 +13141,17 @@ dojo.declare(
                        this.aroundNode = aroundNode;
                },
 
-               orient: function(/* DomNode */ node, /* String */ aroundCorner, /* String */ tooltipCorner){
+               orient: function(/*DomNode*/ node, /*String*/ aroundCorner, /*String*/ tooltipCorner, /*Object*/ spaceAvailable, /*Object*/ aroundNodeCoords){
                        // summary:
                        //              Private function to set CSS for tooltip node based on which position it's in.
-                       //              This is called by the dijit popup code.
+                       //              This is called by the dijit popup code.   It will also reduce the tooltip's
+                       //              width to whatever width is available
                        // tags:
                        //              protected
+                       this.connectorNode.style.top = ""; //reset to default
+                       
+                       //Adjust the spaceAvailable width, without changing the spaceAvailable object
+                       var tooltipSpaceAvaliableWidth = spaceAvailable.w - this.connectorNode.offsetWidth;
 
                        node.className = "dijitTooltip " +
                                {
@@ -12405,6 +13162,52 @@ dojo.declare(
                                        "BR-BL": "dijitTooltipRight",
                                        "BL-BR": "dijitTooltipLeft"
                                }[aroundCorner + "-" + tooltipCorner];
+                               
+                       // reduce tooltip's width to the amount of width available, so that it doesn't overflow screen
+                       this.domNode.style.width = "auto";
+                       var size = dojo.contentBox(this.domNode);
+                       
+                       var width = Math.min((Math.max(tooltipSpaceAvaliableWidth,1)), size.w);
+                       var widthWasReduced = width < size.w;
+                       
+                       this.domNode.style.width = width+"px";
+                                               
+                       //Adjust width for tooltips that have a really long word or a nowrap setting
+                       if(widthWasReduced){
+                               this.containerNode.style.overflow = "auto"; //temp change to overflow to detect if our tooltip needs to be wider to support the content
+                               var scrollWidth = this.containerNode.scrollWidth;
+                               this.containerNode.style.overflow = "visible"; //change it back
+                               if(scrollWidth > width){
+                                       scrollWidth = scrollWidth + dojo.style(this.domNode,"paddingLeft") + dojo.style(this.domNode,"paddingRight");
+                                       this.domNode.style.width = scrollWidth + "px";
+                               }
+                       }
+                       
+                       // Reposition the tooltip connector.
+                       if(tooltipCorner.charAt(0) == 'B' && aroundCorner.charAt(0) == 'B'){
+                               var mb = dojo.marginBox(node);
+                               var tooltipConnectorHeight = this.connectorNode.offsetHeight;
+                               if(mb.h > spaceAvailable.h){
+                                       // The tooltip starts at the top of the page and will extend past the aroundNode
+                                       var aroundNodePlacement = spaceAvailable.h - (aroundNodeCoords.h / 2) - (tooltipConnectorHeight / 2);
+                                       this.connectorNode.style.top = aroundNodePlacement + "px";
+                                       this.connectorNode.style.bottom = "";
+                               }else{
+                                       // Align center of connector with center of aroundNode, except don't let bottom
+                                       // of connector extend below bottom of tooltip content, or top of connector
+                                       // extend past top of tooltip content
+                                       this.connectorNode.style.bottom = Math.min(
+                                               Math.max(aroundNodeCoords.h/2 - tooltipConnectorHeight/2, 0),
+                                               mb.h - tooltipConnectorHeight) + "px";
+                                       this.connectorNode.style.top = "";
+                               }
+                       }else{
+                               // reset the tooltip back to the defaults
+                               this.connectorNode.style.top = "";
+                               this.connectorNode.style.bottom = "";
+                       }
+                       
+                       return Math.max(0, size.w - tooltipSpaceAvaliableWidth);
                },
 
                _onShow: function(){
@@ -12421,6 +13224,7 @@ dojo.declare(
                hide: function(aroundNode){
                        // summary:
                        //              Hide the tooltip
+
                        if(this._onDeck && this._onDeck[1] == aroundNode){
                                // this hide request is for a show() that hasn't even started yet;
                                // just cancel the pending show()
@@ -12487,69 +13291,70 @@ dojo.declare(
                //              the tooltip is displayed.
                showDelay: 400,
 
-               // connectId: [const] String[]
-               //              Id's of domNodes to attach the tooltip to.
-               //              When user hovers over any of the specified dom nodes, the tooltip will appear.
-               //
-               //              Note: Currently connectId can only be specified on initialization, it cannot
-               //              be changed via attr('connectId', ...)
-               //
-               //              Note: in 2.0 this will be renamed to connectIds for less confusion.
+               // connectId: String|String[]
+               //              Id of domNode(s) to attach the tooltip to.
+               //              When user hovers over specified dom node, the tooltip will appear.
                connectId: [],
 
                // position: String[]
                //              See description of `dijit.Tooltip.defaultPosition` for details on position parameter.
                position: [],
 
-               constructor: function(){
-                       // Map id's of nodes I'm connected to to a list of the this.connect() handles
-                       this._nodeConnectionsById = {};
-               },
+               _setConnectIdAttr: function(/*String*/ newId){
+                       // summary:
+                       //              Connect to node(s) (specified by id)
 
-               _setConnectIdAttr: function(newIds){
-                       for(var oldId in this._nodeConnectionsById){
-                               this.removeTarget(oldId);
-                       }
-                       dojo.forEach(dojo.isArrayLike(newIds) ? newIds : [newIds], this.addTarget, this);
-               },
+                       // Remove connections to old nodes (if there are any)
+                       dojo.forEach(this._connections || [], function(nested){
+                               dojo.forEach(nested, dojo.hitch(this, "disconnect"));
+                       }, this);
 
-               _getConnectIdAttr: function(){
-                       var ary = [];
-                       for(var id in this._nodeConnectionsById){
-                               ary.push(id);
-                       }
-                       return ary;
+                       // Make connections to nodes in newIds.
+                       var ary = dojo.isArrayLike(newId) ? newId : (newId ? [newId] : []);
+                       this._connections = dojo.map(ary, function(id){
+                               var node = dojo.byId(id);
+                               return node ? [
+                                       this.connect(node, "onmouseenter", "_onTargetMouseEnter"),
+                                       this.connect(node, "onmouseleave", "_onTargetMouseLeave"),
+                                       this.connect(node, "onfocus", "_onTargetFocus"),
+                                       this.connect(node, "onblur", "_onTargetBlur")
+                               ] : [];
+                       }, this);
+       
+                       this._set("connectId", newId);
+
+                       this._connectIds = ary; // save as array
                },
 
-               addTarget: function(/*DOMNODE || String*/ id){
+               addTarget: function(/*DOMNODE || String*/ node){
                        // summary:
-                       //              Attach tooltip to specified node, if it's not already connected
-                       var node = dojo.byId(id);
-                       if(!node){ return; }
-                       if(node.id in this._nodeConnectionsById){ return; }//Already connected
-
-                       this._nodeConnectionsById[node.id] = [
-                               this.connect(node, "onmouseenter", "_onTargetMouseEnter"),
-                               this.connect(node, "onmouseleave", "_onTargetMouseLeave"),
-                               this.connect(node, "onfocus", "_onTargetFocus"),
-                               this.connect(node, "onblur", "_onTargetBlur")
-                       ];
+                       //              Attach tooltip to specified node if it's not already connected
+
+                       // TODO: remove in 2.0 and just use set("connectId", ...) interface
+
+                       var id = node.id || node;
+                       if(dojo.indexOf(this._connectIds, id) == -1){
+                               this.set("connectId", this._connectIds.concat(id));
+                       }
                },
 
                removeTarget: function(/*DOMNODE || String*/ node){
                        // summary:
                        //              Detach tooltip from specified node
 
-                       // map from DOMNode back to plain id string
-                       var id = node.id || node;
-
-                       if(id in this._nodeConnectionsById){
-                               dojo.forEach(this._nodeConnectionsById[id], this.disconnect, this);
-                               delete this._nodeConnectionsById[id];
+                       // TODO: remove in 2.0 and just use set("connectId", ...) interface
+                       
+                       var id = node.id || node,       // map from DOMNode back to plain id string
+                               idx = dojo.indexOf(this._connectIds, id);
+                       if(idx >= 0){
+                               // remove id (modifies original this._connectIds but that's OK in this case)
+                               this._connectIds.splice(idx, 1);
+                               this.set("connectId", this._connectIds);
                        }
                },
 
-               postCreate: function(){
+               buildRendering: function(){
+                       this.inherited(arguments);
                        dojo.addClass(this.domNode,"dijitTooltipData");
                },
 
@@ -12716,8 +13521,6 @@ dojo.provide("dijit.form.ValidationTextBox");
 
 
 
-
-
 /*=====
        dijit.form.ValidationTextBox.__Constraints = function(){
                // locale: String
@@ -12738,7 +13541,7 @@ dojo.declare(
                // tags:
                //              protected
 
-               templateString: dojo.cache("dijit.form", "templates/ValidationTextBox.html", "<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\n\tid=\"widget_${id}\" waiRole=\"presentation\"\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&Chi; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n"),
+               templateString: dojo.cache("dijit.form", "templates/ValidationTextBox.html", "<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\n\tid=\"widget_${id}\" role=\"presentation\"\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n"),
                baseClass: "dijitTextBox dijitValidationTextBox",
 
                // required: Boolean
@@ -12747,6 +13550,7 @@ dojo.declare(
 
                // promptMessage: String
                //              If defined, display this hint string immediately on focus to the textbox, if empty.
+               //              Also displays if the textbox value is Incomplete (not yet valid but will be with additional input).
                //              Think of this like a tooltip that tells the user what to do, not an error message
                //              that tells the user what they've done wrong.
                //
@@ -12765,6 +13569,12 @@ dojo.declare(
                //              Set to "" to use the invalidMessage instead.
                missingMessage: "$_unset_$",
 
+               // message: String
+               //              Currently error/prompt message.
+               //              When using the default tooltip implementation, this will only be
+               //              displayed when the field is focused.
+               message: "",
+
                // constraints: dijit.form.ValidationTextBox.__Constraints
                //              user-defined object needed to pass parameters to the validator functions
                constraints: {},
@@ -12774,7 +13584,7 @@ dojo.declare(
                //              Do not specify both regExp and regExpGen
                regExp: ".*",
 
-               regExpGen: function(/*dijit.form.ValidationTextBox.__Constraints*/constraints){
+               regExpGen: function(/*dijit.form.ValidationTextBox.__Constraints*/ constraints){
                        // summary:
                        //              Overridable function used to generate regExp when dependent on constraints.
                        //              Do not specify both regExp and regExpGen.
@@ -12784,7 +13594,7 @@ dojo.declare(
                },
 
                // state: [readonly] String
-               //              Shows current state (ie, validation result) of input (Normal, Warning, or Error)
+               //              Shows current state (ie, validation result) of input (""=Normal, Incomplete, or Error)
                state: "",
 
                // tooltipPosition: String[]
@@ -12793,12 +13603,12 @@ dojo.declare(
 
                _setValueAttr: function(){
                        // summary:
-                       //              Hook so attr('value', ...) works.
+                       //              Hook so set('value', ...) works.
                        this.inherited(arguments);
                        this.validate(this._focused);
                },
 
-               validator: function(/*anything*/value, /*dijit.form.ValidationTextBox.__Constraints*/constraints){
+               validator: function(/*anything*/ value, /*dijit.form.ValidationTextBox.__Constraints*/ constraints){
                        // summary:
                        //              Overridable function used to validate the text input against the regular expression.
                        // tags:
@@ -12827,7 +13637,7 @@ dojo.declare(
                _isEmpty: function(value){
                        // summary:
                        //              Checks for whitespace
-                       return /^\s*$/.test(value); // Boolean
+                       return (this.trim ? /^\s*$/ : /^$/).test(value); // Boolean
                },
 
                getErrorMessage: function(/*Boolean*/ isFocused){
@@ -12858,37 +13668,32 @@ dojo.declare(
                        var isValid = this.disabled || this.isValid(isFocused);
                        if(isValid){ this._maskValidSubsetError = true; }
                        var isEmpty = this._isEmpty(this.textbox.value);
-                       var isValidSubset = !isValid && !isEmpty && isFocused && this._isValidSubset();
-                       this.state = ((isValid || ((!this._hasBeenBlurred || isFocused) && isEmpty) || isValidSubset) && this._maskValidSubsetError) ? "" : "Error";
-                       if(this.state == "Error"){ this._maskValidSubsetError = isFocused; } // we want the error to show up afer a blur and refocus
-                       this._setStateClass();
+                       var isValidSubset = !isValid && isFocused && this._isValidSubset();
+                       this._set("state", isValid ? "" : (((((!this._hasBeenBlurred || isFocused) && isEmpty) || isValidSubset) && this._maskValidSubsetError) ? "Incomplete" : "Error"));
                        dijit.setWaiState(this.focusNode, "invalid", isValid ? "false" : "true");
-                       if(isFocused){
-                               if(this.state == "Error"){
-                                       message = this.getErrorMessage(true);
-                               }else{
-                                       message = this.getPromptMessage(true); // show the prompt whever there's no error
-                               }
-                               this._maskValidSubsetError = true; // since we're focused, always mask warnings
+
+                       if(this.state == "Error"){
+                               this._maskValidSubsetError = isFocused && isValidSubset; // we want the error to show up after a blur and refocus
+                               message = this.getErrorMessage(isFocused);
+                       }else if(this.state == "Incomplete"){
+                               message = this.getPromptMessage(isFocused); // show the prompt whenever the value is not yet complete
+                               this._maskValidSubsetError = !this._hasBeenBlurred || isFocused; // no Incomplete warnings while focused
+                       }else if(isEmpty){
+                               message = this.getPromptMessage(isFocused); // show the prompt whenever there's no error and no text
                        }
-                       this.displayMessage(message);
+                       this.set("message", message);
+
                        return isValid;
                },
 
-               // _message: String
-               //              Currently displayed message
-               _message: "",
-
                displayMessage: function(/*String*/ message){
                        // summary:
                        //              Overridable method to display validation errors/hints.
                        //              By default uses a tooltip.
                        // tags:
                        //              extension
-                       if(this._message == message){ return; }
-                       this._message = message;
                        dijit.hideTooltip(this.domNode);
-                       if(message){
+                       if(message && this._focused){
                                dijit.showTooltip(message, this.domNode, this.tooltipPosition, !this.isLeftToRight());
                        }
                },
@@ -12905,11 +13710,11 @@ dojo.declare(
                        this.constraints = {};
                },
 
-               _setConstraintsAttr: function(/* Object */ constraints){
+               _setConstraintsAttr: function(/*Object*/ constraints){
                        if(!constraints.locale && this.lang){
                                constraints.locale = this.lang;
                        }
-                       this.constraints = constraints;
+                       this._set("constraints", constraints);
                        this._computePartialRE();
                },
 
@@ -12966,11 +13771,16 @@ dojo.declare(
                },
 
                _setRequiredAttr: function(/*Boolean*/ value){
-                       this.required = value;
+                       this._set("required", value);
                        dijit.setWaiState(this.focusNode, "required", value);
                        this._refreshState();
                },
 
+               _setMessageAttr: function(/*String*/ message){
+                       this._set("message", message);
+                       this.displayMessage(message);
+               },
+
                reset:function(){
                        // Overrides dijit.form.TextBox.reset() by also
                        // hiding errors about partial matches
@@ -12979,7 +13789,10 @@ dojo.declare(
                },
 
                _onBlur: function(){
+                       // the message still exists but for back-compat, and to erase the tooltip
+                       // (if the message is being displayed as a tooltip), call displayMessage('')
                        this.displayMessage('');
+
                        this.inherited(arguments);
                }
        }
@@ -13010,9 +13823,9 @@ dojo.declare(
                        this.nameAttrSetting = "";
                },
 
-               serialize: function(/*anything*/val, /*Object?*/options){
+               serialize: function(/*anything*/ val, /*Object?*/ options){
                        // summary:
-                       //              Overridable function used to convert the attr('value') result to a canonical
+                       //              Overridable function used to convert the get('value') result to a canonical
                        //              (non-localized) string.  For example, will print dates in ISO format, and
                        //              numbers the same way as they are represented in javascript.
                        // tags:
@@ -13044,10 +13857,10 @@ dojo.declare(
                        // (as opposed to the displayed value).
                        // Passing in name as markup rather than calling dojo.create() with an attrs argument
                        // to make dojo.query(input[name=...]) work on IE. (see #8660)
-                       this.valueNode = dojo.place("<input type='hidden'" + (this.name ? " name='" + this.name + "'" : "") + ">", this.textbox, "after");
+                       this.valueNode = dojo.place("<input type='hidden'" + (this.name ? " name='" + this.name.replace(/'/g, "&quot;") + "'" : "") + "/>", this.textbox, "after");
                },
 
-               reset:function(){
+               reset: function(){
                        // Overrides `dijit.form.ValidationTextBox.reset` to
                        // reset the hidden textbox value to ''
                        this.valueNode.value = '';
@@ -13151,7 +13964,7 @@ dojo.declare(
                        }
                },
 
-               _setConstraintsAttr: function(/* Object */ constraints){
+               _setConstraintsAttr: function(/*Object*/ constraints){
                        this.inherited(arguments);
                        if(this.focusNode){ // not set when called from postMixInProperties
                                if(this.constraints.min !== undefined){
@@ -13169,7 +13982,7 @@ dojo.declare(
 
                _setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange){
                        // summary:
-                       //              Hook so attr('value', ...) works.
+                       //              Hook so set('value', ...) works.
 
                        dijit.setWaiState(this.focusNode, "valuenow", value);
                        this.inherited(arguments);
@@ -13193,10 +14006,9 @@ dojo.provide("dijit.form.ComboBox");
 
 
 
-
 dojo.declare(
        "dijit.form.ComboBoxMixin",
-       null,
+       dijit._HasDropDown,
        {
                // summary:
                //              Implements the base functionality for `dijit.form.ComboBox`/`dijit.form.FilteringSelect`
@@ -13215,14 +14027,14 @@ dojo.declare(
                //              Specifies number of search results per page (before hitting "next" button)
                pageSize: Infinity,
 
-               // store: Object
+               // store: [const] Object
                //              Reference to data provider object used by this ComboBox
                store: null,
 
                // fetchProperties: Object
                //              Mixin to the dojo.data store's fetch.
                //              For example, to set the sort order of the ComboBox menu, pass:
-               //      |       { sort: {attribute:"name",descending: true} }
+               //      |       { sort: [{attribute:"name",descending: true}] }
                //              To override the default queryOptions so that deep=false, do:
                //      |       { queryOptions: {ignoreCase: true, deep: false} }
                fetchProperties:{},
@@ -13275,7 +14087,7 @@ dojo.declare(
                //              This specifies what query ComboBox/FilteringSelect sends to the data store,
                //              based on what the user has typed.  Changing this expression will modify
                //              whether the drop down shows only exact matches, a "starting with" match,
-               //              etc.   Use it in conjunction with highlightMatch.
+               //              etc.  Use it in conjunction with highlightMatch.
                //              dojo.data query expression pattern.
                //              `${0}` will be substituted for the user text.
                //              `*` is used for wildcards.
@@ -13286,21 +14098,32 @@ dojo.declare(
                //              Set true if the ComboBox/FilteringSelect should ignore case when matching possible items
                ignoreCase: true,
 
-               // hasDownArrow: [const] Boolean
+               // hasDownArrow: Boolean
                //              Set this textbox to have a down arrow button, to display the drop down list.
                //              Defaults to true.
                hasDownArrow: true,
 
-               templateString: dojo.cache("dijit.form", "templates/ComboBox.html", "<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\n\tid=\"widget_${id}\"\n\tdojoAttachPoint=\"comboNode\" waiRole=\"combobox\"\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\n\t\tdojoAttachPoint=\"downArrowNode\" waiRole=\"presentation\"\n\t\tdojoAttachEvent=\"onmousedown:_onArrowMouseDown\"\n\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t\t\t${_buttonInputDisabled}\n\t/></div\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&Chi; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type=\"text\" autocomplete=\"off\"\n\t\t\tdojoAttachEvent=\"onkeypress:_onKeyPress,compositionend\"\n\t\t\tdojoAttachPoint=\"textbox,focusNode\" waiRole=\"textbox\" waiState=\"haspopup-true,autocomplete-list\"\n\t/></div\n></div>\n"),
+               templateString: dojo.cache("dijit.form", "templates/DropDownBox.html", "<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\n\tid=\"widget_${id}\"\n\trole=\"combobox\"\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\n\t\tdojoAttachPoint=\"_buttonNode, _popupStateNode\" role=\"presentation\"\n\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t\t\t${_buttonInputDisabled}\n\t/></div\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&#935; \" type=\"text\" tabIndex=\"-1\" readonly=\"readonly\" role=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type=\"text\" autocomplete=\"off\"\n\t\t\tdojoAttachPoint=\"textbox,focusNode\" role=\"textbox\" aria-haspopup=\"true\"\n\t/></div\n></div>\n"),
 
                baseClass: "dijitTextBox dijitComboBox",
 
+               // dropDownClass: [protected extension] String
+               //              Name of the dropdown widget class used to select a date/time.
+               //              Subclasses should specify this.
+               dropDownClass: "dijit.form._ComboBoxMenu",
+
                // Set classes like dijitDownArrowButtonHover depending on
                // mouse action over button node
                cssStateNodes: {
-                       "downArrowNode": "dijitDownArrowButton"
+                       "_buttonNode": "dijitDownArrowButton"
                },
 
+               // Flags to _HasDropDown to limit height of drop down to make it fit in viewport
+               maxHeight: -1,
+
+               // For backwards compatibility let onClick events propagate, even clicks on the down arrow button
+               _stopClickEvents: false,
+
                _getCaretPos: function(/*DomNode*/ element){
                        // khtml 3.5.2 has selection* methods as does webkit nightlies from 2005-06-22
                        var pos = 0;
@@ -13317,7 +14140,7 @@ dojo.declare(
                                tr.move("character",0);
                                ntr.move("character",0);
                                try{
-                                       // If control doesnt have focus, you get an exception.
+                                       // If control doesn't have focus, you get an exception.
                                        // Seems to happen on reverse-tab, but can also happen on tab (seems to be a race condition - only happens sometimes).
                                        // There appears to be no workaround for this - googled for quite a while.
                                        ntr.setEndPoint("EndToEnd", tr);
@@ -13338,7 +14161,7 @@ dojo.declare(
                        // Additional code to set disabled state of ComboBox node.
                        // Overrides _FormValueWidget._setDisabledAttr() or ValidationTextBox._setDisabledAttr().
                        this.inherited(arguments);
-                       dijit.setWaiState(this.comboNode, "disabled", value);
+                       dijit.setWaiState(this.domNode, "disabled", value);
                },
 
                _abortQuery: function(){
@@ -13358,29 +14181,39 @@ dojo.declare(
                        //              Handles paste events
                        if(!this.searchTimer && (evt.type == 'paste'/*IE|WebKit*/ || evt.type == 'input'/*Firefox*/) && this._lastInput != this.textbox.value){
                                this.searchTimer = setTimeout(dojo.hitch(this, function(){
-                                       this._onKeyPress({charOrCode: 229}); // fake IME key to cause a search
+                                       this._onKey({charOrCode: 229}); // fake IME key to cause a search
                                }), 100); // long delay that will probably be preempted by keyboard input
                        }
                        this.inherited(arguments);
                },
 
-               _onKeyPress: function(/*Event*/ evt){
+               _onKey: function(/*Event*/ evt){
                        // summary:
                        //              Handles keyboard events
+
                        var key = evt.charOrCode;
+
                        // except for cutting/pasting case - ctrl + x/v
                        if(evt.altKey || ((evt.ctrlKey || evt.metaKey) && (key != 'x' && key != 'v')) || key == dojo.keys.SHIFT){
                                return; // throw out weird key combinations and spurious events
                        }
+                       
                        var doSearch = false;
-                       var searchFunction = "_startSearchFromInput";
-                       var pw = this._popupWidget;
+                       var pw = this.dropDown;
                        var dk = dojo.keys;
                        var highlighted = null;
                        this._prev_key_backspace = false;
                        this._abortQuery();
-                       if(this._isShowingNow){
-                               pw.handleKey(key);
+
+                       // _HasDropDown will do some of the work:
+                       //              1. when drop down is not yet shown:
+                       //                      - if user presses the down arrow key, call loadDropDown()
+                       //              2. when drop down is already displayed:
+                       //                      - on ESC key, call closeDropDown()
+                       //                      - otherwise, call dropDown.handleKey() to process the keystroke
+                       this.inherited(arguments);
+
+                       if(this._opened){
                                highlighted = pw.getHighlightedOption();
                        }
                        switch(key){
@@ -13388,10 +14221,9 @@ dojo.declare(
                                case dk.DOWN_ARROW:
                                case dk.PAGE_UP:
                                case dk.UP_ARROW:
-                                       if(!this._isShowingNow){
-                                               doSearch = true;
-                                               searchFunction = "_startSearchAll";
-                                       }else{
+                                       // Keystroke caused ComboBox_menu to move to a different item.
+                                       // Copy new item to <input> box.
+                                       if(this._opened){
                                                this._announceOption(highlighted);
                                        }
                                        dojo.stopEvent(evt);
@@ -13418,8 +14250,12 @@ dojo.declare(
                                                this._setCaretPos(this.focusNode, this.focusNode.value.length); // move cursor to end and cancel highlighting
                                        }
                                        // default case:
+                                       // if enter pressed while drop down is open, or for FilteringSelect,
+                                       // if we are in the middle of a query to convert a directly typed in value to an item,
                                        // prevent submit, but allow event to bubble
+                                       if(this._opened || this._fetchHandle){
                                        evt.preventDefault();
+                                       }
                                        // fall through
 
                                case dk.TAB:
@@ -13435,29 +14271,24 @@ dojo.declare(
                                        if(highlighted){
                                                this._selectOption();
                                        }
-                                       if(this._isShowingNow){
+                                       if(this._opened){
                                                this._lastQuery = null; // in case results come back later
-                                               this._hideResultList();
+                                               this.closeDropDown();
                                        }
                                        break;
 
                                case ' ':
                                        if(highlighted){
+                                               // user is effectively clicking a choice in the drop down menu
                                                dojo.stopEvent(evt);
                                                this._selectOption();
-                                               this._hideResultList();
+                                               this.closeDropDown();
                                        }else{
+                                               // user typed a space into the input box, treat as normal character
                                                doSearch = true;
                                        }
                                        break;
 
-                               case dk.ESCAPE:
-                                       if(this._isShowingNow){
-                                               dojo.stopEvent(evt);
-                                               this._hideResultList();
-                                       }
-                                       break;
-
                                case dk.DELETE:
                                case dk.BACKSPACE:
                                        this._prev_key_backspace = true;
@@ -13467,15 +14298,14 @@ dojo.declare(
                                default:
                                        // Non char keys (F1-F12 etc..)  shouldn't open list.
                                        // Ascii characters and IME input (Chinese, Japanese etc.) should.
-                                       // On IE and safari, IME input produces keycode == 229, and we simulate
-                                       // it on firefox by attaching to compositionend event (see compositionend method)
+                                       //IME input produces keycode == 229.
                                        doSearch = typeof key == 'string' || key == 229;
                        }
                        if(doSearch){
                                // need to wait a tad before start search so that the event
                                // bubbles through DOM and we have value visible
                                this.item = undefined; // undefined means item needs to be set
-                               this.searchTimer = setTimeout(dojo.hitch(this, searchFunction),1);
+                               this.searchTimer = setTimeout(dojo.hitch(this, "_startSearchFromInput"),1);
                        }
                },
 
@@ -13511,6 +14341,12 @@ dojo.declare(
                },
 
                _openResultList: function(/*Object*/ results, /*Object*/ dataObject){
+                       // summary:
+                       //              Callback when a search completes.
+                       // description:
+                       //              1. generates drop-down list and calls _showResultList() to display it
+                       //              2. if this result list is from user pressing "more choices"/"previous choices"
+                       //                      then tell screen reader to announce new option
                        this._fetchHandle = null;
                        if(     this.disabled ||
                                this.readOnly ||
@@ -13518,13 +14354,13 @@ dojo.declare(
                        ){
                                return;
                        }
-                       this._popupWidget.clearResultList();
-                       if(!results.length && !this._maxOptions){ // this condition needs to match !this._isvalid set in FilteringSelect::_openResultList
-                               this._hideResultList();
+                       var wasSelected = this.dropDown._highlighted_option && dojo.hasClass(this.dropDown._highlighted_option, "dijitMenuItemSelected");
+                       this.dropDown.clearResultList();
+                       if(!results.length && !this._maxOptions){ // if no results and not just the previous choices button
+                               this.closeDropDown();
                                return;
                        }
 
-
                        // Fill in the textbox with the first item from the drop down list,
                        // and highlight the characters that were auto-completed. For
                        // example, if user typed "CA" and the drop down list appeared, the
@@ -13532,7 +14368,7 @@ dojo.declare(
                        // highlighted.
 
                        dataObject._maxOptions = this._maxOptions;
-                       var nodes = this._popupWidget.createOptions(
+                       var nodes = this.dropDown.createOptions(
                                results,
                                dataObject,
                                dojo.hitch(this, "_getMenuLabelFromItem")
@@ -13546,12 +14382,14 @@ dojo.declare(
                        //              shouting the next choice
                        if(dataObject.direction){
                                if(1 == dataObject.direction){
-                                       this._popupWidget.highlightFirstOption();
+                                       this.dropDown.highlightFirstOption();
                                }else if(-1 == dataObject.direction){
-                                       this._popupWidget.highlightLastOption();
+                                       this.dropDown.highlightLastOption();
+                               }
+                               if(wasSelected){
+                                       this._announceOption(this.dropDown.getHighlightedOption());
                                }
-                               this._announceOption(this._popupWidget.getHighlightedOption());
-                       }else if(this.autoComplete && !this._prev_key_backspace /*&& !dataObject.direction*/
+                       }else if(this.autoComplete && !this._prev_key_backspace
                                // when the user clicks the arrow button to show the full list,
                                // startSearch looks for "*".
                                // it does not make sense to autocomplete
@@ -13562,62 +14400,42 @@ dojo.declare(
                },
 
                _showResultList: function(){
-                       this._hideResultList();
+                       // summary:
+                       //              Display the drop down if not already displayed, or if it is displayed, then
+                       //              reposition it if necessary (reposition may be necessary if drop down's height changed).
+
+                       this.closeDropDown(true);
+
                        // hide the tooltip
                        this.displayMessage("");
 
-                       // Position the list and if it's too big to fit on the screen then
-                       // size it to the maximum possible height
-                       // Our dear friend IE doesnt take max-height so we need to
-                       // calculate that on our own every time
-
-                       // TODO: want to redo this, see
-                       //              http://trac.dojotoolkit.org/ticket/3272
-                       //      and
-                       //              http://trac.dojotoolkit.org/ticket/4108
-
-
-                       // natural size of the list has changed, so erase old
-                       // width/height settings, which were hardcoded in a previous
-                       // call to this function (via dojo.marginBox() call)
-                       dojo.style(this._popupWidget.domNode, {width: "", height: ""});
-
-                       var best = this.open();
-                       // #3212:
-                       //              only set auto scroll bars if necessary prevents issues with
-                       //              scroll bars appearing when they shouldn't when node is made
-                       //              wider (fractional pixels cause this)
-                       var popupbox = dojo.marginBox(this._popupWidget.domNode);
-                       this._popupWidget.domNode.style.overflow =
-                               ((best.h == popupbox.h) && (best.w == popupbox.w)) ? "hidden" : "auto";
-                       // #4134:
-                       //              borrow TextArea scrollbar test so content isn't covered by
-                       //              scrollbar and horizontal scrollbar doesn't appear
-                       var newwidth = best.w;
-                       if(best.h < this._popupWidget.domNode.scrollHeight){
-                               newwidth += 16;
-                       }
-                       dojo.marginBox(this._popupWidget.domNode, {
-                               h: best.h,
-                               w: Math.max(newwidth, this.domNode.offsetWidth)
-                       });
+                       this.openDropDown();
+
+                       dijit.setWaiState(this.domNode, "expanded", "true");
+               },
+
+               loadDropDown: function(/*Function*/ callback){
+                       // Overrides _HasDropDown.loadDropDown().
+                       // This is called when user has pressed button icon or pressed the down arrow key
+                       // to open the drop down.
                        
-                       // If we increased the width of drop down to match the width of ComboBox.domNode,
-                       // then need to reposition the drop down (wrapper) so (all of) the drop down still
-                       // appears underneath the ComboBox.domNode
-                       if(newwidth < this.domNode.offsetWidth){
-                               this._popupWidget.domNode.parentNode.style.left = dojo.position(this.domNode, true).x + "px";
-                       }
+                       this._startSearchAll();
+               },
 
-                       dijit.setWaiState(this.comboNode, "expanded", "true");
+               isLoaded: function(){
+                       // signal to _HasDropDown that it needs to call loadDropDown() to load the
+                       // drop down asynchronously before displaying it
+                       return false;
                },
 
-               _hideResultList: function(){
+               closeDropDown: function(){
+                       // Overrides _HasDropDown.closeDropDown().  Closes the drop down (assuming that it's open).
+                       // This method is the callback when the user types ESC or clicking
+                       // the button icon while the drop down is open.  It's also called by other code.
                        this._abortQuery();
-                       if(this._isShowingNow){
-                               dijit.popup.close(this._popupWidget);
-                               this._isShowingNow=false;
-                               dijit.setWaiState(this.comboNode, "expanded", "false");
+                       if(this._opened){
+                               this.inherited(arguments);
+                               dijit.setWaiState(this.domNode, "expanded", "false");
                                dijit.removeWaiState(this.focusNode,"activedescendant");
                        }
                },
@@ -13629,7 +14447,7 @@ dojo.declare(
                        //              if value is now more choices or previous choices, revert
                        //              the value
                        var newvalue = this.get('displayedValue');
-                       var pw = this._popupWidget;
+                       var pw = this.dropDown;
                        if(pw && (
                                newvalue == pw._messages["previousMessage"] ||
                                newvalue == pw._messages["nextMessage"]
@@ -13651,23 +14469,25 @@ dojo.declare(
                _onBlur: function(){
                        // summary:
                        //              Called magically when focus has shifted away from this widget and it's drop down
-                       this._hideResultList();
+                       this.closeDropDown();
                        this.inherited(arguments);
                },
 
                _setItemAttr: function(/*item*/ item, /*Boolean?*/ priorityChange, /*String?*/ displayedValue){
                        // summary:
-                       //              Set the displayed valued in the input box, and the hidden value
-                       //              that gets submitted, based on a dojo.data store item.
+                       //              Set the displayed valued in the input box, and the hidden value
+                       //              that gets submitted, based on a dojo.data store item.
                        // description:
-                       //              Users shouldn't call this function; they should be calling
-                       //              attr('item', value)
+                       //              Users shouldn't call this function; they should be calling
+                       //              set('item', value)
                        // tags:
-                       //              private
-                       if(!displayedValue){ displayedValue = this.labelFunc(item, this.store); }
-                       this.value = this._getValueField() != this.searchAttr? this.store.getIdentity(item) : displayedValue;
-                       this.item = item;
-                       dijit.form.ComboBox.superclass._setValueAttr.call(this, this.value, priorityChange, displayedValue);
+                       //              private
+                       if(!displayedValue){
+                               displayedValue = this.store.getValue(item, this.searchAttr);
+                       }
+                       var value = this._getValueField() != this.searchAttr? this.store.getIdentity(item) : displayedValue;
+                       this._set("item", item);
+                       dijit.form.ComboBox.superclass._setValueAttr.call(this, value, priorityChange, displayedValue);
                },
 
                _announceOption: function(/*Node*/ node){
@@ -13681,13 +14501,13 @@ dojo.declare(
                        }
                        // pull the text value from the item attached to the DOM node
                        var newValue;
-                       if(node == this._popupWidget.nextButton ||
-                               node == this._popupWidget.previousButton){
+                       if(node == this.dropDown.nextButton ||
+                               node == this.dropDown.previousButton){
                                newValue = node.innerHTML;
                                this.item = undefined;
                                this.value = '';
                        }else{
-                               newValue = this.labelFunc(node.item, this.store);
+                               newValue = this.store.getValue(node.item, this.searchAttr).toString();
                                this.set('item', node.item, false, newValue);
                        }
                        // get the text that the user manually entered (cut off autocompleted text)
@@ -13704,28 +14524,11 @@ dojo.declare(
                        if(evt){
                                this._announceOption(evt.target);
                        }
-                       this._hideResultList();
+                       this.closeDropDown();
                        this._setCaretPos(this.focusNode, this.focusNode.value.length);
                        dijit.form._FormValueWidget.prototype._setValueAttr.call(this, this.value, true); // set this.value and fire onChange
                },
 
-               _onArrowMouseDown: function(evt){
-                       // summary:
-                       //              Callback when arrow is clicked
-                       if(this.disabled || this.readOnly){
-                               return;
-                       }
-                       dojo.stopEvent(evt);
-                       this.focus();
-                       if(this._isShowingNow){
-                               this._hideResultList();
-                       }else{
-                               // forces full population of results, if they click
-                               // on the arrow it means they want to see more options
-                               this._startSearchAll();
-                       }
-               },
-
                _startSearchAll: function(){
                        this._startSearch('');
                },
@@ -13739,9 +14542,13 @@ dojo.declare(
                },
 
                _startSearch: function(/*String*/ key){
-                       if(!this._popupWidget){
-                               var popupId = this.id + "_popup";
-                               this._popupWidget = new dijit.form._ComboBoxMenu({
+                       // summary:
+                       //              Starts a search for elements matching key (key=="" means to return all items),
+                       //              and calls _openResultList() when the search completes, to display the results.
+                       if(!this.dropDown){
+                               var popupId = this.id + "_popup",
+                               dropDownConstructor = dojo.getObject(this.dropDownClass, false);
+                               this.dropDown = new dropDownConstructor({
                                        onChange: dojo.hitch(this, this._selectOption),
                                        id: popupId,
                                        dir: this.dir
@@ -13770,7 +14577,7 @@ dojo.declare(
                                        onError: function(errText){
                                                _this._fetchHandle = null;
                                                console.error('dijit.form.ComboBox: ' + errText);
-                                               dojo.hitch(_this, "_hideResultList")();
+                                               _this.closeDropDown();
                                        },
                                        start: 0,
                                        count: this.pageSize
@@ -13785,8 +14592,9 @@ dojo.declare(
                                        //              reader knows which menu option to shout
                                        dataObject.direction = direction;
                                        this._fetchHandle = this.store.fetch(dataObject);
+                                       this.focus();
                                };
-                               this._nextSearch = this._popupWidget.onPage = dojo.hitch(this, nextSearch, this._fetchHandle);
+                               this._nextSearch = this.dropDown.onPage = dojo.hitch(this, nextSearch, this._fetchHandle);
                        }, query, this), this.searchDelay);
                },
 
@@ -13795,29 +14603,12 @@ dojo.declare(
                },
 
                _getValueField: function(){
-                       // summmary:
+                       // summary:
                        //              Helper for postMixInProperties() to set this.value based on data inlined into the markup.
                        //              Returns the attribute name in the item (in dijit.form._ComboBoxDataStore) to use as the value.
                        return this.searchAttr;
                },
 
-               /////////////// Event handlers /////////////////////
-
-               // FIXME: For 2.0, rename to "_compositionEnd"
-               compositionend: function(/*Event*/ evt){
-                       // summary:
-                       //              When inputting characters using an input method, such as
-                       //              Asian languages, it will generate this event instead of
-                       //              onKeyDown event.
-                       //              Note: this event is only triggered in FF (not in IE/safari)
-                       // tags:
-                       //              private
-
-                       // 229 is the code produced by IE and safari while pressing keys during
-                       // IME input mode
-                       this._onKeyPress({charOrCode: 229});
-               },
-
                //////////// INITIALIZATION METHODS ///////////////////////////////////////
 
                constructor: function(){
@@ -13841,13 +14632,14 @@ dojo.declare(
                                // by the selected attribute of an option tag
                                // IE6 does not set value, Opera sets value = selectedIndex
                                if(!("value" in this.params)){
-                                       var item = this.store.fetchSelectedItem();
+                                       var item = (this.item = this.store.fetchSelectedItem());
                                        if(item){
                                                var valueField = this._getValueField();
-                                               this.value = valueField != this.searchAttr? this.store.getValue(item, valueField) : this.labelFunc(item, this.store);
+                                               this.value = this.store.getValue(item, valueField);
                                        }
                                }
                        }
+
                        this.inherited(arguments);
                },
 
@@ -13857,32 +14649,24 @@ dojo.declare(
                        // tags:
                        //              protected
 
-                       if(!this.hasDownArrow){
-                               this.downArrowNode.style.display = "none";
-                       }
-
                        // find any associated label element and add to ComboBox node.
                        var label=dojo.query('label[for="'+this.id+'"]');
                        if(label.length){
                                label[0].id = (this.id+"_label");
-                               var cn=this.comboNode;
-                               dijit.setWaiState(cn, "labelledby", label[0].id);
+                               dijit.setWaiState(this.domNode, "labelledby", label[0].id);
 
                        }
                        this.inherited(arguments);
                },
 
-               uninitialize: function(){
-                       if(this._popupWidget && !this._popupWidget._destroyed){
-                               this._hideResultList();
-                               this._popupWidget.destroy();
-                       }
-                       this.inherited(arguments);
+               _setHasDownArrowAttr: function(val){
+                       this.hasDownArrow = val;
+                       this._buttonNode.style.display = val ? "" : "none";
                },
 
                _getMenuLabelFromItem: function(/*Item*/ item){
-                       var label = this.labelAttr? this.store.getValue(item, this.labelAttr) : this.labelFunc(item, this.store);
-                       var labelType = this.labelType;
+                       var label = this.labelFunc(item, this.store),
+                               labelType = this.labelType;
                        // If labelType is not "text" we don't want to screw any markup ot whatever.
                        if(this.highlightMatch != "none" && this.labelType == "text" && this._lastInput){
                                label = this.doHighlight(label, this._escapeHtml(this._lastInput));
@@ -13891,24 +14675,27 @@ dojo.declare(
                        return {html: labelType == "html", label: label};
                },
 
-               doHighlight: function(/*String*/label, /*String*/find){
+               doHighlight: function(/*String*/ label, /*String*/ find){
                        // summary:
                        //              Highlights the string entered by the user in the menu.  By default this
-                       //              highlights the first occurence found. Override this method
-                       //              to implement your custom highlighing.
+                       //              highlights the first occurrence found. Override this method
+                       //              to implement your custom highlighting.
                        // tags:
                        //              protected
 
-                       // Add greedy when this.highlightMatch == "all"
-                       var modifiers = "i"+(this.highlightMatch == "all"?"g":"");
-                       var escapedLabel = this._escapeHtml(label);
+                       var
+                               // Add (g)lobal modifier when this.highlightMatch == "all" and (i)gnorecase when this.ignoreCase == true
+                               modifiers = (this.ignoreCase ? "i" : "") + (this.highlightMatch == "all" ? "g" : ""),
+                               i = this.queryExpr.indexOf("${0}");
                        find = dojo.regexp.escapeString(find); // escape regexp special chars
-                       var ret = escapedLabel.replace(new RegExp("(^|\\s)("+ find +")", modifiers),
-                                       '$1<span class="dijitComboBoxHighlightMatch">$2</span>');
-                       return ret;// returns String, (almost) valid HTML (entities encoded)
+                       return this._escapeHtml(label).replace(
+                               // prepend ^ when this.queryExpr == "${0}*" and append $ when this.queryExpr == "*${0}"
+                               new RegExp((i == 0 ? "^" : "") + "("+ find +")" + (i == (this.queryExpr.length - 4) ? "$" : ""), modifiers),
+                               '<span class="dijitComboBoxHighlightMatch">$1</span>'
+                       ); // returns String, (almost) valid HTML (entities encoded)
                },
 
-               _escapeHtml: function(/*string*/str){
+               _escapeHtml: function(/*String*/ str){
                        // TODO Should become dojo.html.entities(), when exists use instead
                        // summary:
                        //              Adds escape sequences for special characters in XML: &<>"'
@@ -13917,19 +14704,6 @@ dojo.declare(
                        return str; // string
                },
 
-               open: function(){
-                       // summary:
-                       //              Opens the drop down menu.  TODO: rename to _open.
-                       // tags:
-                       //              private
-                       this._isShowingNow=true;
-                       return dijit.popup.open({
-                               popup: this._popupWidget,
-                               around: this.domNode,
-                               parent: this
-                       });
-               },
-
                reset: function(){
                        // Overrides the _FormWidget.reset().
                        // Additionally reset the .item (to clean up).
@@ -13939,15 +14713,15 @@ dojo.declare(
 
                labelFunc: function(/*item*/ item, /*dojo.data.store*/ store){
                        // summary:
-                       //              Computes the label to display based on the dojo.data store item.
+                       //              Computes the label to display based on the dojo.data store item.
                        // returns:
-                       //              The label that the ComboBox should display
+                       //              The label that the ComboBox should display
                        // tags:
-                       //              private
+                       //              private
 
                        // Use toString() because XMLStore returns an XMLItem whereas this
                        // method is expected to return a String (#9354)
-                       return store.getValue(item, this.searchAttr).toString(); // String
+                       return store.getValue(item, this.labelAttr || this.searchAttr).toString(); // String
                }
        }
 );
@@ -13961,9 +14735,9 @@ dojo.declare(
                // tags:
                //              private
 
-               templateString: "<ul class='dijitReset dijitMenu' dojoAttachEvent='onmousedown:_onMouseDown,onmouseup:_onMouseUp,onmouseover:_onMouseOver,onmouseout:_onMouseOut' tabIndex='-1' style='overflow: \"auto\"; overflow-x: \"hidden\";'>"
-                               +"<li class='dijitMenuItem dijitMenuPreviousButton' dojoAttachPoint='previousButton' waiRole='option'></li>"
-                               +"<li class='dijitMenuItem dijitMenuNextButton' dojoAttachPoint='nextButton' waiRole='option'></li>"
+               templateString: "<ul class='dijitReset dijitMenu' dojoAttachEvent='onmousedown:_onMouseDown,onmouseup:_onMouseUp,onmouseover:_onMouseOver,onmouseout:_onMouseOut' style='overflow: \"auto\"; overflow-x: \"hidden\";'>"
+                               +"<li class='dijitMenuItem dijitMenuPreviousButton' dojoAttachPoint='previousButton' role='option'></li>"
+                               +"<li class='dijitMenuItem dijitMenuNextButton' dojoAttachPoint='nextButton' role='option'></li>"
                        +"</ul>",
 
                // _messages: Object
@@ -13973,8 +14747,16 @@ dojo.declare(
                baseClass: "dijitComboBoxMenu",
 
                postMixInProperties: function(){
+                       this.inherited(arguments);
                        this._messages = dojo.i18n.getLocalization("dijit.form", "ComboBox", this.lang);
+               },
+
+               buildRendering: function(){
                        this.inherited(arguments);
+
+                       // fill in template with i18n messages
+                       this.previousButton.innerHTML = this._messages["previousMessage"];
+                       this.nextButton.innerHTML = this._messages["nextMessage"];
                },
 
                _setValueAttr: function(/*Object*/ value){
@@ -13997,13 +14779,6 @@ dojo.declare(
                        //              callback
                },
 
-               postCreate: function(){
-                       // fill in template with i18n messages
-                       this.previousButton.innerHTML = this._messages["previousMessage"];
-                       this.nextButton.innerHTML = this._messages["nextMessage"];
-                       this.inherited(arguments);
-               },
-
                onClose: function(){
                        // summary:
                        //              Callback from dijit.popup code to this widget, notifying it that it closed
@@ -14017,9 +14792,11 @@ dojo.declare(
                        //              Creates an option to appear on the popup menu subclassed by
                        //              `dijit.form.FilteringSelect`.
 
+                       var menuitem = dojo.create("li", {
+                               "class": "dijitReset dijitMenuItem" +(this.isLeftToRight() ? "" : " dijitMenuItemRtl"),
+                               role: "option"
+                       });
                        var labelObject = labelFunc(item);
-                       var menuitem = dojo.doc.createElement("li");
-                       dijit.setWaiRole(menuitem, "option");
                        if(labelObject.html){
                                menuitem.innerHTML = labelObject.label;
                        }else{
@@ -14056,8 +14833,6 @@ dojo.declare(
                        //              iterate over cache nondestructively
                        dojo.forEach(results, function(item, i){
                                var menuitem = this._createOption(item, labelFunc);
-                               menuitem.className = "dijitReset dijitMenuItem" +
-                                       (this.isLeftToRight() ? "" : " dijitMenuItemRtl");
                                dojo.attr(menuitem, "id", this.id + i);
                                this.domNode.insertBefore(menuitem, this.nextButton);
                        }, this);
@@ -14090,6 +14865,7 @@ dojo.declare(
                        while(this.domNode.childNodes.length>2){
                                this.domNode.removeChild(this.domNode.childNodes[this.domNode.childNodes.length-2]);
                        }
+                       this._blurOptionNode();
                },
 
                _onMouseDown: function(/*Event*/ evt){
@@ -14098,10 +14874,14 @@ dojo.declare(
 
                _onMouseUp: function(/*Event*/ evt){
                        if(evt.target === this.domNode || !this._highlighted_option){
+                               // !this._highlighted_option check to prevent immediate selection when menu appears on top
+                               // of <input>, see #9898.  Note that _HasDropDown also has code to prevent this.
                                return;
                        }else if(evt.target == this.previousButton){
+                               this._blurOptionNode();
                                this.onPage(-1);
                        }else if(evt.target == this.nextButton){
+                               this._blurOptionNode();
                                this.onPage(1);
                        }else{
                                var tgt = evt.target;
@@ -14268,20 +15048,25 @@ dojo.declare(
                        return (ho && ho.parentNode) ? ho : null;
                },
 
-               handleKey: function(key){
-                       switch(key){
+               handleKey: function(evt){
+                       // summary:
+                       //              Handle keystroke event forwarded from ComboBox, returning false if it's
+                       //              a keystroke I recognize and process, true otherwise.
+                       switch(evt.charOrCode){
                                case dojo.keys.DOWN_ARROW:
                                        this._highlightNextOption();
-                                       break;
+                                       return false;
                                case dojo.keys.PAGE_DOWN:
                                        this.pageDown();
-                                       break;
+                                       return false;
                                case dojo.keys.UP_ARROW:
                                        this._highlightPrevOption();
-                                       break;
+                                       return false;
                                case dojo.keys.PAGE_UP:
                                        this.pageUp();
-                                       break;
+                                       return false;
+                               default:
+                                       return true;
                        }
                }
        }
@@ -14309,10 +15094,10 @@ dojo.declare(
 
                _setValueAttr: function(/*String*/ value, /*Boolean?*/ priorityChange, /*String?*/ displayedValue){
                        // summary:
-                       //              Hook so attr('value', value) works.
+                       //              Hook so set('value', value) works.
                        // description:
                        //              Sets the value of the select.
-                       this.item = null; // value not looked up in store
+                       this._set("item", null); // value not looked up in store
                        if(!value){ value = ''; } // null translates to blank
                        dijit.form.ValidationTextBox.prototype._setValueAttr.call(this, value, priorityChange, displayedValue);
                }
@@ -14356,13 +15141,13 @@ dojo.declare("dijit.form._ComboBoxDataStore", null, {
 
        },
 
-       getValue: function(     /* item */ item,
-                                               /* attribute-name-string */ attribute,
-                                               /* value? */ defaultValue){
+       getValue: function(     /*item*/ item,
+                                               /*attribute-name-string*/ attribute,
+                                               /*value?*/ defaultValue){
                return (attribute == "value") ? item.value : (item.innerText || item.textContent || '');
        },
 
-       isItemLoaded: function(/* anything */ something){
+       isItemLoaded: function(/*anything*/ something){
                return true;
        },
 
@@ -14370,9 +15155,9 @@ dojo.declare("dijit.form._ComboBoxDataStore", null, {
                return {"dojo.data.api.Read": true, "dojo.data.api.Identity": true};
        },
 
-       _fetchItems: function(  /* Object */ args,
-                                                       /* Function */ findCallback,
-                                                       /* Function */ errorCallback){
+       _fetchItems: function(  /*Object*/ args,
+                                                       /*Function*/ findCallback,
+                                                       /*Function*/ errorCallback){
                // summary:
                //              See dojo.data.util.simpleFetch.fetch()
                if(!args.query){ args.query = {}; }
@@ -14388,19 +15173,19 @@ dojo.declare("dijit.form._ComboBoxDataStore", null, {
                findCallback(items, args);
        },
 
-       close: function(/*dojo.data.api.Request || args || null */ request){
+       close: function(/*dojo.data.api.Request || args || null*/ request){
                return;
        },
 
-       getLabel: function(/* item */ item){
+       getLabel: function(/*item*/ item){
                return item.innerHTML;
        },
 
-       getIdentity: function(/* item */ item){
+       getIdentity: function(/*item*/ item){
                return dojo.attr(item, "value");
        },
 
-       fetchItemByIdentity: function(/* Object */ args){
+       fetchItemByIdentity: function(/*Object*/ args){
                // summary:
                //              Given the identity of an item, this method returns the item that has
                //              that identity through the onItem callback.
@@ -14468,17 +15253,19 @@ dojo.declare(
                //                      - List can be specified either as a static list or via a javascript
                //                              function (that can get the list from a server)
 
-               _isvalid: true,
-
                // required: Boolean
                //              True (default) if user is required to enter a value into this field.
                required: true,
 
                _lastDisplayedValue: "",
 
+               _isValidSubset: function(){
+                       return this._opened;
+               },
+
                isValid: function(){
                        // Overrides ValidationTextBox.isValid()
-                       return this._isvalid || (!this.required && this.get('displayedValue') == ""); // #5974
+                       return this.item || (!this.required && this.get('displayedValue') == ""); // #5974
                },
 
                _refreshState: function(){
@@ -14487,12 +15274,12 @@ dojo.declare(
                        }
                },
 
-               _callbackSetLabel: function(    /*Array*/ result,
+               _callbackSetLabel: function(
+                                               /*Array*/ result,
                                                /*Object*/ dataObject,
                                                /*Boolean?*/ priorityChange){
                        // summary:
-                       //              Callback function that dynamically sets the label of the
-                       //              ComboBox
+                       //              Callback from dojo.data after lookup of user entered value finishes
 
                        // setValue does a synchronous lookup,
                        // so it calls _callbackSetLabel directly,
@@ -14502,35 +15289,38 @@ dojo.declare(
                                return;
                        }
                        if(!result.length){
-                               //#3268: do nothing on bad input
+                               //#3268: don't modify display value on bad input
                                //#3285: change CSS to indicate error
                                this.valueNode.value = "";
                                dijit.form.TextBox.superclass._setValueAttr.call(this, "", priorityChange || (priorityChange === undefined && !this._focused));
-                               this._isvalid = false;
+                               this._set("item", null);
                                this.validate(this._focused);
-                               this.item = null;
                        }else{
                                this.set('item', result[0], priorityChange);
                        }
                },
 
                _openResultList: function(/*Object*/ results, /*Object*/ dataObject){
+                       // Callback when a data store query completes.
                        // Overrides ComboBox._openResultList()
 
                        // #3285: tap into search callback to see if user's query resembles a match
                        if(dataObject.query[this.searchAttr] != this._lastQuery){
                                return;
                        }
+                       dijit.form.ComboBoxMixin.prototype._openResultList.apply(this, arguments);
+
                        if(this.item === undefined){ // item == undefined for keyboard search
-                               this._isvalid = results.length != 0 || this._maxOptions != 0; // result.length==0 && maxOptions != 0 implies the nextChoices item selected but then the datastore returned 0 more entries
+                               // If the search returned no items that means that the user typed
+                               // in something invalid (and they can't make it valid by typing more characters),
+                               // so flag the FilteringSelect as being in an invalid state
                                this.validate(true);
                        }
-                       dijit.form.ComboBoxMixin.prototype._openResultList.apply(this, arguments);
                },
 
                _getValueAttr: function(){
                        // summary:
-                       //              Hook for attr('value') to work.
+                       //              Hook for get('value') to work.
 
                        // don't get the textbox value but rather the previously set hidden value.
                        // Use this.valueNode.value which isn't always set for other MappedTextBox widgets until blur
@@ -14544,7 +15334,7 @@ dojo.declare(
 
                _setValueAttr: function(/*String*/ value, /*Boolean?*/ priorityChange){
                        // summary:
-                       //              Hook so attr('value', value) works.
+                       //              Hook so set('value', value) works.
                        // description:
                        //              Sets the value of the select.
                        //              Also sets the label to the corresponding value by reverse lookup.
@@ -14572,10 +15362,9 @@ dojo.declare(
                        //              that gets submitted, based on a dojo.data store item.
                        // description:
                        //              Users shouldn't call this function; they should be calling
-                       //              attr('item', value)
+                       //              set('item', value)
                        // tags:
                        //              private
-                       this._isvalid = true;
                        this.inherited(arguments);
                        this.valueNode.value = this.value;
                        this._lastDisplayedValue = this.textbox.value;
@@ -14587,30 +15376,38 @@ dojo.declare(
 
                _setDisplayedValueAttr: function(/*String*/ label, /*Boolean?*/ priorityChange){
                        // summary:
-                       //              Hook so attr('displayedValue', label) works.
+                       //              Hook so set('displayedValue', label) works.
                        // description:
                        //              Sets textbox to display label. Also performs reverse lookup
-                       //              to set the hidden value.
+                       //              to set the hidden value.  label should corresponding to item.searchAttr.
 
-                       // When this is called during initialization it'll ping the datastore
-                       // for reverse lookup, and when that completes (after an XHR request)
-                       // will call setValueAttr()... but that shouldn't trigger an onChange()
-                       // event, even when it happens after creation has finished
+                       if(label == null){ label = ''; }
+
+                       // This is called at initialization along with every custom setter.
+                       // Usually (or always?) the call can be ignored.   If it needs to be
+                       // processed then at least make sure that the XHR request doesn't trigger an onChange()
+                       // event, even if it returns after creation has finished
                        if(!this._created){
+                               if(!("displayedValue" in this.params)){
+                                       return;
+                               }
                                priorityChange = false;
                        }
 
+                       // Do a reverse lookup to map the specified displayedValue to the hidden value.
+                       // Note that if there's a custom labelFunc() this code
                        if(this.store){
-                               this._hideResultList();
+                               this.closeDropDown();
                                var query = dojo.clone(this.query); // #6196: populate query with user-specifics
                                // escape meta characters of dojo.data.util.filter.patternToRegExp().
                                this._lastQuery = query[this.searchAttr] = this._getDisplayQueryString(label);
-                               // if the label is not valid, the callback will never set it,
-                               // so the last valid value will get the warning textbox set the
+                               // If the label is not valid, the callback will never set it,
+                               // so the last valid value will get the warning textbox.   Set the
                                // textbox value now so that the impending warning will make
                                // sense to the user
                                this.textbox.value = label;
                                this._lastDisplayedValue = label;
+                               this._set("displayedValue", label);     // for watch("displayedValue") notification
                                var _this = this;
                                var fetch = {
                                        query: query,
@@ -14633,11 +15430,6 @@ dojo.declare(
                        }
                },
 
-               postMixInProperties: function(){
-                       this.inherited(arguments);
-                       this._isvalid = !this.required;
-               },
-
                undo: function(){
                        this.set('displayedValue', this._lastDisplayedValue);
                }
@@ -14654,9 +15446,10 @@ dojo.provide("dijit.form.Form");
 
 
 
+
 dojo.declare(
        "dijit.form.Form",
-       [dijit._Widget, dijit._Templated, dijit.form._FormMixin],
+       [dijit._Widget, dijit._Templated, dijit.form._FormMixin, dijit.layout._ContentPaneResizeMixin],
        {
                // summary:
                //              Widget corresponding to HTML form tag, for validation and serialization
@@ -14740,7 +15533,7 @@ dojo.declare(
 
                postCreate: function(){
                        // IE tries to hide encType
-                       // TODO: this code should be in parser, not here.
+                       // TODO: remove in 2.0, no longer necessary with data-dojo-params
                        if(dojo.isIE && this.srcNodeRef && this.srcNodeRef.attributes){
                                var item = this.srcNodeRef.attributes.getNamedItem('encType');
                                if(item && !item.specified && (typeof item.value == "string")){
@@ -14761,8 +15554,8 @@ dojo.declare(
                                preventDefault: function(){ // not IE
                                                        this.returnValue = false;
                                                },
-                               stopPropagation: function(){}, 
-                               currentTarget: e ? e.target : this.domNode, 
+                               stopPropagation: function(){},
+                               currentTarget: e ? e.target : this.domNode,
                                target: e ? e.target : this.domNode
                        };
                        // if return value is not exactly false, and haven't called preventDefault(), then reset
@@ -14801,7 +15594,7 @@ dojo.declare(
                        }
                },
 
-               onSubmit: function(/*Event?*/e){
+               onSubmit: function(/*Event?*/ e){
                        // summary:
                        //              Callback when user submits the form.
                        // description:
@@ -14833,6 +15626,7 @@ dojo._hasResource["dijit.form.RadioButton"] = true;
 dojo.provide("dijit.form.RadioButton");
 
 
+
 // TODO: for 2.0, move the RadioButton code into this file
 
 }
@@ -14851,7 +15645,7 @@ dijit.form.__SelectOption = function(){
        //              place a separator at that location
        // label: String
        //              The label for our option.  It can contain html tags.
-       //  selected: Boolean
+       // selected: Boolean
        //              Whether or not we are a selected option
        // disabled: Boolean
        //              Whether or not this specific option is disabled
@@ -14869,13 +15663,13 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
        //              This also provides the mechanism for reading the elements from
        //              a store, if desired.
 
-       // multiple: Boolean
+       // multiple: [const] Boolean
        //              Whether or not we are multi-valued
        multiple: false,
 
        // options: dijit.form.__SelectOption[]
        //              The set of options for our select item.  Roughly corresponds to
-       //      the html <option> tag.
+       //              the html <option> tag.
        options: null,
 
        // store: dojo.data.api.Identity
@@ -14897,20 +15691,20 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
        //              iterated over (i.e. to filter even futher what you want to add)
        onFetch: null,
 
-       // sortByLabel: boolean
+       // sortByLabel: Boolean
        //              Flag to sort the options returned from a store by the label of
        //              the store.
        sortByLabel: true,
 
 
-       // loadChildrenOnOpen: boolean
+       // loadChildrenOnOpen: Boolean
        //              By default loadChildren is called when the items are fetched from the
        //              store.  This property allows delaying loadChildren (and the creation
-       //              of the options/menuitems) until the user opens the click the button.
-       //              dropdown
+       //              of the options/menuitems) until the user clicks the button to open the
+       //              dropdown.
        loadChildrenOnOpen: false,
 
-       getOptions: function(/* anything */ valueOrIdx){
+       getOptions: function(/*anything*/ valueOrIdx){
                // summary:
                //              Returns a given option (or options).
                // valueOrIdx:
@@ -14976,7 +15770,7 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
                return null; // null
        },
 
-       addOption: function(/* dijit.form.__SelectOption, dijit.form.__SelectOption[] */ option){
+       addOption: function(/*dijit.form.__SelectOption|dijit.form.__SelectOption[]*/ option){
                // summary:
                //              Adds an option or options to the end of the select.  If value
                //              of the option is empty or missing, a separator is created instead.
@@ -14991,7 +15785,7 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
                this._loadChildren();
        },
 
-       removeOption: function(/* string, dijit.form.__SelectOption, number, or array */ valueOrIdx){
+       removeOption: function(/*String|dijit.form.__SelectOption|Number|Array*/ valueOrIdx){
                // summary:
                //              Removes the given option or options.  You can remove by string
                //              (in which case the value is removed), number (in which case the
@@ -15006,7 +15800,7 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
                        // that case, we don't want to blow up...
                        if(i){
                                this.options = dojo.filter(this.options, function(node, idx){
-                                       return (node.value !== i.value);
+                                       return (node.value !== i.value || node.label !== i.label);
                                });
                                this._removeOptionItem(i);
                        }
@@ -15014,7 +15808,7 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
                this._loadChildren();
        },
 
-       updateOption: function(/* dijit.form.__SelectOption, dijit.form.__SelectOption[] */ newOption){
+       updateOption: function(/*dijit.form.__SelectOption|dijit.form.__SelectOption[]*/ newOption){
                // summary:
                //              Updates the values of the given option.  The option to update
                //              is matched based on the value of the entered option.  Passing
@@ -15030,9 +15824,9 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
                this._loadChildren();
        },
 
-       setStore: function(/* dojo.data.api.Identity */ store,
-                                               /* anything? */ selectedValue,
-                                               /* Object? */ fetchArgs){
+       setStore: function(/*dojo.data.api.Identity*/ store,
+                                               /*anything?*/ selectedValue,
+                                               /*Object?*/ fetchArgs){
                // summary:
                //              Sets the store you would like to use with this select widget.
                //              The selected value is the value of the new store to set.  This
@@ -15059,7 +15853,7 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
                                        dojo.connect(store, "onSet", this, "_onSetItem")
                                ];
                        }
-                       this.store = store;
+                       this._set("store", store);
                }
 
                // Turn off change notifications while we make all these changes
@@ -15072,48 +15866,52 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
 
                // Add our new options
                if(store){
-                       var cb = function(items){
-                               if(this.sortByLabel && !fetchArgs.sort && items.length){
-                                       items.sort(dojo.data.util.sorter.createSortFunction([{
-                                               attribute: store.getLabelAttributes(items[0])[0]
-                                       }], store));
-                               }
-
-                               if(fetchArgs.onFetch){
-                                       items = fetchArgs.onFetch(items);
-                               }
-                               // TODO: Add these guys as a batch, instead of separately
-                               dojo.forEach(items, function(i){
-                                       this._addOptionForItem(i);
-                               }, this);
-
-                               // Set our value (which might be undefined), and then tweak
-                               // it to send a change event with the real value
-                               this._loadingStore = false;
-                               this.set("value", (("_pendingValue" in this) ? this._pendingValue : selectedValue));
-                               delete this._pendingValue;
-
-                               if(!this.loadChildrenOnOpen){
-                                       this._loadChildren();
-                               }else{
-                                       this._pseudoLoadChildren(items);
-                               }
-                               this._fetchedWith = opts;
-                               this._lastValueReported = this.multiple ? [] : null;
-                               this._onChangeActive = true;
-                               this.onSetStore();
-                               this._handleOnChange(this.value);
-                       };
-                       var opts = dojo.mixin({onComplete:cb, scope: this}, fetchArgs);
                        this._loadingStore = true;
-                       store.fetch(opts);
+                       store.fetch(dojo.delegate(fetchArgs, {
+                               onComplete: function(items, opts){
+                                       if(this.sortByLabel && !fetchArgs.sort && items.length){
+                                               items.sort(dojo.data.util.sorter.createSortFunction([{
+                                                       attribute: store.getLabelAttributes(items[0])[0]
+                                               }], store));
+                                       }
+       
+                                       if(fetchArgs.onFetch){
+                                                       items = fetchArgs.onFetch.call(this, items, opts);
+                                       }
+                                       // TODO: Add these guys as a batch, instead of separately
+                                       dojo.forEach(items, function(i){
+                                               this._addOptionForItem(i);
+                                       }, this);
+       
+                                       // Set our value (which might be undefined), and then tweak
+                                       // it to send a change event with the real value
+                                       this._loadingStore = false;
+                                               this.set("value", "_pendingValue" in this ? this._pendingValue : selectedValue);
+                                       delete this._pendingValue;
+       
+                                       if(!this.loadChildrenOnOpen){
+                                               this._loadChildren();
+                                       }else{
+                                               this._pseudoLoadChildren(items);
+                                       }
+                                       this._fetchedWith = opts;
+                                       this._lastValueReported = this.multiple ? [] : null;
+                                       this._onChangeActive = true;
+                                       this.onSetStore();
+                                       this._handleOnChange(this.value);
+                               },
+                               scope: this
+                       }));
                }else{
                        delete this._fetchedWith;
                }
                return oStore;  // dojo.data.api.Identity
        },
 
-       _setValueAttr: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){
+       // TODO: implement set() and watch() for store and query, although not sure how to handle
+       // setting them individually rather than together (as in setStore() above)
+
+       _setValueAttr: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){
                // summary:
                //              set the value of the widget.
                //              If a string is passed, then we set our value from looking it up.
@@ -15149,7 +15947,7 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
                var val = dojo.map(newValue, function(i){ return i.value; }),
                        disp = dojo.map(newValue, function(i){ return i.label; });
 
-               this.value = this.multiple ? val : val[0];
+               this._set("value", this.multiple ? val : val[0]);
                this._setDisplay(this.multiple ? disp : disp[0]);
                this._updateSelection();
                this._handleOnChange(this.value, priorityChange);
@@ -15173,23 +15971,10 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
                return this.multiple ? ret : ret[0];
        },
 
-       _getValueDeprecated: false, // remove when _FormWidget:getValue is removed
-       getValue: function(){
-               // summary:
-               //              get the value of the widget.
-               return this._lastValue;
-       },
-
-       undo: function(){
-               // summary:
-               //              restore the value to the last value passed to onChange
-               this._setValueAttr(this._lastValueReported, false);
-       },
-
        _loadChildren: function(){
                // summary:
                //              Loads the children represented by this widget's options.
-               //              reset the menu to make it "populatable on the next click
+               //              reset the menu to make it populatable on the next click
                if(this._loadingStore){ return; }
                dojo.forEach(this._getChildren(), function(child){
                        child.destroyRecursive();
@@ -15204,7 +15989,7 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
        _updateSelection: function(){
                // summary:
                //              Sets the "selected" class on the item for styling purposes
-               this.value = this._getValueFromOpts();
+               this._set("value", this._getValueFromOpts());
                var val = this.value;
                if(!dojo.isArray(val)){
                        val = [val];
@@ -15218,7 +16003,6 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
                                dijit.setWaiState(child.domNode, "selected", isSelected);
                        }, this);
                }
-               this._handleOnChange(this.value);
        },
 
        _getValueFromOpts: function(){
@@ -15249,17 +16033,17 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
        },
 
        // Internal functions to call when we have store notifications come in
-       _onNewItem: function(/* item */ item, /* Object? */ parentInfo){
+       _onNewItem: function(/*item*/ item, /*Object?*/ parentInfo){
                if(!parentInfo || !parentInfo.parent){
                        // Only add it if we are top-level
                        this._addOptionForItem(item);
                }
        },
-       _onDeleteItem: function(/* item */ item){
+       _onDeleteItem: function(/*item*/ item){
                var store = this.store;
                this.removeOption(store.getIdentity(item));
        },
-       _onSetItem: function(/* item */ item){
+       _onSetItem: function(/*item*/ item){
                this.updateOption(this._getOptionObjForItem(item));
        },
 
@@ -15274,7 +16058,7 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
                return {value: value, label: label, item:item}; // dijit.form.__SelectOption
        },
 
-       _addOptionForItem: function(/* item */ item){
+       _addOptionForItem: function(/*item*/ item){
                // summary:
                //              Creates (and adds) the option for the given item
                var store = this.store;
@@ -15290,13 +16074,18 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
                this.addOption(newOpt);
        },
 
-       constructor: function(/* Object */ keywordArgs){
+       constructor: function(/*Object*/ keywordArgs){
                // summary:
                //              Saves off our value, if we have an initial one set so we
                //              can use it if we have a store as well (see startup())
                this._oValue = (keywordArgs || {}).value || null;
        },
 
+       buildRendering: function(){
+               this.inherited(arguments);
+               dojo.setSelectable(this.focusNode, false);
+       },
+
        _fillContent: function(){
                // summary:
                //              Loads our options and sets up our dropdown correctly.  We
@@ -15309,16 +16098,21 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
                                                        if(node.getAttribute("type") === "separator"){
                                                                return { value: "", label: "", selected: false, disabled: false };
                                                        }
-                                                       return { value: node.getAttribute("value"),
+                                                       return {
+                                                               value: (node.getAttribute("data-" + dojo._scopeName + "-value") || node.getAttribute("value")),
                                                                                label: String(node.innerHTML),
+                                                               // FIXME: disabled and selected are not valid on complex markup children (which is why we're
+                                                               // looking for data-dojo-value above.  perhaps we should data-dojo-props="" this whole thing?)
+                                                               // decide before 1.6
                                                                                selected: node.getAttribute("selected") || false,
-                                                                               disabled: node.getAttribute("disabled") || false };
+                                                               disabled: node.getAttribute("disabled") || false
+                                                       };
                                                }, this) : [];
                }
                if(!this.value){
-                       this.value = this._getValueFromOpts();
+                       this._set("value", this._getValueFromOpts());
                }else if(this.multiple && typeof this.value == "string"){
-                       this.value = this.value.split(",");
+                       this_set("value", this.value.split(","));
                }
        },
 
@@ -15326,7 +16120,6 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
                // summary:
                //              sets up our event handling that we need for functioning
                //              as a select
-               dojo.setSelectable(this.focusNode, false);
                this.inherited(arguments);
 
                // Make our event connections for updating state
@@ -15362,7 +16155,7 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
                this.inherited(arguments);
        },
 
-       _addOptionItem: function(/* dijit.form.__SelectOption */ option){
+       _addOptionItem: function(/*dijit.form.__SelectOption*/ option){
                // summary:
                //              User-overridable function which, for the given option, adds an
                //              item to the select.  If the option doesn't have a value, then a
@@ -15370,7 +16163,7 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
                //              in the created option widget.
        },
 
-       _removeOptionItem: function(/* dijit.form.__SelectOption */ option){
+       _removeOptionItem: function(/*dijit.form.__SelectOption*/ option){
                // summary:
                //              User-overridable function which, for the given option, removes
                //              its item from the select.
@@ -15396,7 +16189,7 @@ dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
                return this.getOptions(this.get("value"));
        },
 
-       _pseudoLoadChildren: function(/* item[] */ items){
+       _pseudoLoadChildren: function(/*item[]*/ items){
                // summary:
                //              a function that will "fake" loading children, if needed, and
                //              if we have set to not load children until the widget opens.
@@ -15419,6 +16212,7 @@ dojo._hasResource["dijit._KeyNavContainer"] = true;
 dojo.provide("dijit._KeyNavContainer");
 
 
+
 dojo.declare("dijit._KeyNavContainer",
        dijit._Container,
        {
@@ -15460,6 +16254,8 @@ dojo.declare("dijit._KeyNavContainer",
                        var next = dojo.hitch(this, this.focusNext);
                        dojo.forEach(prevKeyCodes, function(code){ keyCodes[code] = prev; });
                        dojo.forEach(nextKeyCodes, function(code){ keyCodes[code] = next; });
+                       keyCodes[dojo.keys.HOME] = dojo.hitch(this, "focusFirstChild");
+                       keyCodes[dojo.keys.END] = dojo.hitch(this, "focusLastChild");
                        this.connect(this.domNode, "onkeypress", "_onContainerKeypress");
                        this.connect(this.domNode, "onfocus", "_onContainerFocus");
                },
@@ -15496,6 +16292,17 @@ dojo.declare("dijit._KeyNavContainer",
                        }
                },
 
+               focusLastChild: function(){
+                       // summary:
+                       //              Focus the last focusable child in the container.
+                       // tags:
+                       //              protected
+                       var child = this._getLastFocusableChild();
+                       if(child){ // edge case: Menu could be empty or hidden
+                               this.focusChild(child);
+                       }
+               },
+
                focusNext: function(){
                        // summary:
                        //              Focus the next widget
@@ -15529,15 +16336,16 @@ dojo.declare("dijit._KeyNavContainer",
                        if(this.focusedChild && widget !== this.focusedChild){
                                this._onChildBlur(this.focusedChild);
                        }
+                       widget.set("tabIndex", this.tabIndex);  // for IE focus outline to appear, must set tabIndex before focs
                        widget.focus(last ? "end" : "start");
-                       this.focusedChild = widget;
+                       this._set("focusedChild", widget);
                },
 
                _startupChild: function(/*dijit._Widget*/ widget){
                        // summary:
                        //              Setup for each child widget
                        // description:
-                       //              Sets tabIndex=-1 on each child, so that the tab key will 
+                       //              Sets tabIndex=-1 on each child, so that the tab key will
                        //              leave the container rather than visiting each child.
                        // tags:
                        //              private
@@ -15618,6 +16426,12 @@ dojo.declare("dijit._KeyNavContainer",
                        return this._getNextFocusableChild(null, 1);    // dijit._Widget
                },
 
+               _getLastFocusableChild: function(){
+                       // summary:
+                       //              Returns last child that can be focused
+                       return this._getNextFocusableChild(null, -1);   // dijit._Widget
+               },
+
                _getNextFocusableChild: function(child, dir){
                        // summary:
                        //              Returns the next or previous focusable child, compared
@@ -15665,7 +16479,7 @@ dojo.declare("dijit.MenuItem",
 
                // Make 3 columns
                // icon, label, and expand arrow (BiDi-dependent) indicating sub-menu
-               templateString: dojo.cache("dijit", "templates/MenuItem.html", "<tr class=\"dijitReset dijitMenuItem\" dojoAttachPoint=\"focusNode\" waiRole=\"menuitem\" tabIndex=\"-1\"\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" waiRole=\"presentation\">\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon dijitMenuItemIcon\" dojoAttachPoint=\"iconNode\"/>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" dojoAttachPoint=\"containerNode\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" dojoAttachPoint=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" waiRole=\"presentation\">\n\t\t<div dojoAttachPoint=\"arrowWrapper\" style=\"visibility: hidden\">\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuExpand\"/>\n\t\t\t<span class=\"dijitMenuExpandA11y\">+</span>\n\t\t</div>\n\t</td>\n</tr>\n"),
+               templateString: dojo.cache("dijit", "templates/MenuItem.html", "<tr class=\"dijitReset dijitMenuItem\" dojoAttachPoint=\"focusNode\" role=\"menuitem\" tabIndex=\"-1\"\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon dijitMenuItemIcon\" dojoAttachPoint=\"iconNode\"/>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" dojoAttachPoint=\"containerNode\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" dojoAttachPoint=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\">\n\t\t<div dojoAttachPoint=\"arrowWrapper\" style=\"visibility: hidden\">\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuExpand\"/>\n\t\t\t<span class=\"dijitMenuExpandA11y\">+</span>\n\t\t</div>\n\t</td>\n</tr>\n"),
 
                attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
                        label: { node: "containerNode", type: "innerHTML" },
@@ -15702,9 +16516,8 @@ dojo.declare("dijit.MenuItem",
                        }
                },
 
-               postCreate: function(){
+               buildRendering: function(){
                        this.inherited(arguments);
-                       dojo.setSelectable(this.domNode, false);
                        var label = this.id+"_text";
                        dojo.attr(this.containerNode, "id", label);
                        if(this.accelKeyNode){
@@ -15712,6 +16525,7 @@ dojo.declare("dijit.MenuItem",
                                label += " " + this.id + "_accel";
                        }
                        dijit.setWaiState(this.domNode, "labelledby", label);
+                       dojo.setSelectable(this.domNode, false);
                },
 
                _onHover: function(){
@@ -15734,11 +16548,10 @@ dojo.declare("dijit.MenuItem",
                        // then unselect it
                        this.getParent().onItemUnhover(this);
 
-                       // _onUnhover() is called when the menu is hidden (collapsed), due to clicking
-                       // a MenuItem and having it execut.  When that happens, FF and IE don't generate
-                       // an onmouseout event for the MenuItem, so give _CssStateMixin some help
-                       this._hovering = false;
-                       this._setStateClass();
+                       // When menu is hidden (collapsed) due to clicking a MenuItem and having it execute,
+                       // FF and IE don't generate an onmouseout event for the MenuItem.
+                       // So, help out _CssStateMixin in this case.
+                       this._set("hovering", false);
                },
 
                _onClick: function(evt){
@@ -15823,19 +16636,21 @@ dojo.declare("dijit.MenuItem",
                        // summary:
                        //              Hook for attr('disabled', ...) to work.
                        //              Enable or disable this menu item.
-                       this.disabled = value;
+
                        dijit.setWaiState(this.focusNode, 'disabled', value ? 'true' : 'false');
+                       this._set("disabled", value);
                },
                _setAccelKeyAttr: function(/*String*/ value){
                        // summary:
                        //              Hook for attr('accelKey', ...) to work.
                        //              Set accelKey on this menu item.
-                       this.accelKey=value;
 
                        this.accelKeyNode.style.display=value?"":"none";
                        this.accelKeyNode.innerHTML=value;
                        //have to use colSpan to make it work in IE
                        dojo.attr(this.containerNode,'colSpan',value?"1":"2");
+                       
+                       this._set("accelKey", value);
                }
        });
 
@@ -15907,7 +16722,6 @@ dojo.declare("dijit.PopupMenuItem",
                }
        });
 
-
 }
 
 if(!dojo._hasResource["dijit.CheckedMenuItem"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
@@ -15922,7 +16736,7 @@ dojo.declare("dijit.CheckedMenuItem",
                // summary:
                //              A checkbox-like menu item for toggling on and off
 
-               templateString: dojo.cache("dijit", "templates/CheckedMenuItem.html", "<tr class=\"dijitReset dijitMenuItem\" dojoAttachPoint=\"focusNode\" waiRole=\"menuitemcheckbox\" tabIndex=\"-1\"\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" waiRole=\"presentation\">\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuItemIcon dijitCheckedMenuItemIcon\" dojoAttachPoint=\"iconNode\"/>\n\t\t<span class=\"dijitCheckedMenuItemIconChar\">&#10003;</span>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" dojoAttachPoint=\"containerNode,labelNode\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" dojoAttachPoint=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" waiRole=\"presentation\">&nbsp;</td>\n</tr>\n"),
+               templateString: dojo.cache("dijit", "templates/CheckedMenuItem.html", "<tr class=\"dijitReset dijitMenuItem\" dojoAttachPoint=\"focusNode\" role=\"menuitemcheckbox\" tabIndex=\"-1\"\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" role=\"presentation\">\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuItemIcon dijitCheckedMenuItemIcon\" dojoAttachPoint=\"iconNode\"/>\n\t\t<span class=\"dijitCheckedMenuItemIconChar\">&#10003;</span>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" dojoAttachPoint=\"containerNode,labelNode\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" dojoAttachPoint=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" role=\"presentation\">&nbsp;</td>\n</tr>\n"),
 
                // checked: Boolean
                //              Our checked state
@@ -15933,7 +16747,7 @@ dojo.declare("dijit.CheckedMenuItem",
                        //              Sets the class and state for the check box.
                        dojo.toggleClass(this.domNode, "dijitCheckedMenuItemChecked", checked);
                        dijit.setWaiState(this.domNode, "checked", checked);
-                       this.checked = checked;
+                       this._set("checked", checked);
                },
 
                onChange: function(/*Boolean*/ checked){
@@ -15974,7 +16788,8 @@ dojo.declare("dijit.MenuSeparator",
 
                templateString: dojo.cache("dijit", "templates/MenuSeparator.html", "<tr class=\"dijitMenuSeparator\">\n\t<td class=\"dijitMenuSeparatorIconCell\">\n\t\t<div class=\"dijitMenuSeparatorTop\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n\t<td colspan=\"3\" class=\"dijitMenuSeparatorLabelCell\">\n\t\t<div class=\"dijitMenuSeparatorTop dijitMenuSeparatorLabel\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n</tr>\n"),
 
-               postCreate: function(){
+               buildRendering: function(){
+                       this.inherited(arguments);
                        dojo.setSelectable(this.domNode, false);
                },
 
@@ -15988,7 +16803,6 @@ dojo.declare("dijit.MenuSeparator",
                }
        });
 
-
 }
 
 if(!dojo._hasResource["dijit.Menu"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
@@ -16001,6 +16815,11 @@ dojo.provide("dijit.Menu");
 
 
 
+
+
+
+// "dijit/MenuItem", "dijit/PopupMenuItem", "dijit/CheckedMenuItem", "dijit/MenuSeparator" for Back-compat (TODO: remove in 2.0)
+
 dojo.declare("dijit._MenuBase",
        [dijit._Widget, dijit._Templated, dijit._KeyNavContainer],
 {
@@ -16277,8 +17096,7 @@ dojo.declare("dijit._MenuBase",
                //              menus (similar to TAB navigation) but the menu is not active
                //              (ie no dropdown) until an item is clicked.
                this.isActive = true;
-               dojo.addClass(this.domNode, "dijitMenuActive");
-               dojo.removeClass(this.domNode, "dijitMenuPassive");
+               dojo.replaceClass(this.domNode, "dijitMenuActive", "dijitMenuPassive");
        },
 
        onOpen: function(/*Event*/ e){
@@ -16297,8 +17115,7 @@ dojo.declare("dijit._MenuBase",
                // summary:
                //              Mark this menu's state as inactive.
                this.isActive = false; // don't do this in _onBlur since the state is pending-close until we get here
-               dojo.removeClass(this.domNode, "dijitMenuActive");
-               dojo.addClass(this.domNode, "dijitMenuPassive");
+               dojo.replaceClass(this.domNode, "dijitMenuPassive", "dijitMenuActive");
        },
 
        onClose: function(){
@@ -16321,16 +17138,25 @@ dojo.declare("dijit._MenuBase",
                // tags:
                //              private
                this._stopPopupTimer();
-               if(this.focusedChild){ // unhighlight the focused item
-                       this.focusedChild._setSelected(false);
-                       this.focusedChild._onUnhover();
-                       this.focusedChild = null;
-               }
+
+               var fromItem = this.focusedChild && this.focusedChild.from_item;
+
                if(this.currentPopup){
+                       // If focus is on my child menu then move focus to me,
+                       // because IE doesn't like it when you display:none a node with focus
+                       if(dijit._curFocus && dojo.isDescendant(dijit._curFocus, this.currentPopup.domNode)){
+                               this.focusedChild.focusNode.focus();
+                       }
                        // Close all popups that are open and descendants of this menu
                        dijit.popup.close(this.currentPopup);
                        this.currentPopup = null;
                }
+
+               if(this.focusedChild){ // unhighlight the focused item
+                       this.focusedChild._setSelected(false);
+                       this.focusedChild._onUnhover();
+                       this.focusedChild = null;
+               }
        },
 
        _onItemFocus: function(/*MenuItem*/ item){
@@ -16381,7 +17207,7 @@ dojo.declare("dijit.Menu",
                this._bindings = [];
        },
 
-       templateString: dojo.cache("dijit", "templates/Menu.html", "<table class=\"dijit dijitMenu dijitMenuPassive dijitReset dijitMenuTable\" waiRole=\"menu\" tabIndex=\"${tabIndex}\" dojoAttachEvent=\"onkeypress:_onKeyPress\" cellspacing=0>\n\t<tbody class=\"dijitReset\" dojoAttachPoint=\"containerNode\"></tbody>\n</table>\n"),
+       templateString: dojo.cache("dijit", "templates/Menu.html", "<table class=\"dijit dijitMenu dijitMenuPassive dijitReset dijitMenuTable\" role=\"menu\" tabIndex=\"${tabIndex}\" dojoAttachEvent=\"onkeypress:_onKeyPress\" cellspacing=\"0\">\n\t<tbody class=\"dijitReset\" dojoAttachPoint=\"containerNode\"></tbody>\n</table>\n"),
 
        baseClass: "dijitMenu",
 
@@ -16408,7 +17234,7 @@ dojo.declare("dijit.Menu",
                        this.bindDomNode(dojo.body());
                }else{
                        // TODO: should have _setTargetNodeIds() method to handle initialization and a possible
-                       // later attr('targetNodeIds', ...) call.   There's also a problem that targetNodeIds[]
+                       // later set('targetNodeIds', ...) call.   There's also a problem that targetNodeIds[]
                        // gets stale after calls to bindDomNode()/unBindDomNode() as it still is just the original list (see #9610)
                        dojo.forEach(this.targetNodeIds, this.bindDomNode, this);
                }
@@ -16521,7 +17347,7 @@ dojo.declare("dijit.Menu",
                                                this._scheduleOpen(evt.target, iframe); // no coords - open near target node
                                        }
                                })
-                       ];      
+                       ];
                });
                binding.connects = cn ? doConnects(cn) : [];
 
@@ -16687,13 +17513,6 @@ dojo.declare("dijit.Menu",
 }
 );
 
-// Back-compat (TODO: remove in 2.0)
-
-
-
-
-
-
 }
 
 if(!dojo._hasResource["dijit.form.Select"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
@@ -16706,7 +17525,6 @@ dojo.provide("dijit.form.Select");
 
 
 
-
 dojo.declare("dijit.form._SelectMenu", dijit.Menu, {
        // summary:
        //              An internally-used menu for dropdown that allows us a vertical scrollbar
@@ -16727,6 +17545,16 @@ dojo.declare("dijit.form._SelectMenu", dijit.Menu, {
                dijit.setWaiRole(n,"presentation");
                n.appendChild(o);
        },
+
+       postCreate: function(){
+               // summary:
+               //              stop mousemove from selecting text on IE to be consistent with other browsers
+
+               this.inherited(arguments);
+
+               this.connect(this.domNode, "onmousemove", dojo.stopEvent);
+       },
+
        resize: function(/*Object*/ mb){
                // summary:
                //              Overridden so that we are able to handle resizing our
@@ -16755,7 +17583,7 @@ dojo.declare("dijit.form.Select", [dijit.form._FormSelectWidget, dijit._HasDropD
 
        baseClass: "dijitSelect",
 
-       templateString: dojo.cache("dijit.form", "templates/Select.html", "<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tdojoAttachPoint=\"_buttonNode,tableNode,focusNode\" cellspacing='0' cellpadding='0'\n\twaiRole=\"combobox\" waiState=\"haspopup-true\"\n\t><tbody waiRole=\"presentation\"><tr waiRole=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonContents dijitButtonNode\" waiRole=\"presentation\"\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"  dojoAttachPoint=\"containerNode,_popupStateNode\"></span\n\t\t\t><input type=\"hidden\" ${!nameAttrSetting} dojoAttachPoint=\"valueNode\" value=\"${value}\" waiState=\"hidden-true\"\n\t\t/></td><td class=\"dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton\"\n\t\t\t\tdojoAttachPoint=\"titleNode\" waiRole=\"presentation\"\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" waiRole=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" waiRole=\"presentation\">&#9660;</div\n\t\t></td\n\t></tr></tbody\n></table>\n"),
+       templateString: dojo.cache("dijit.form", "templates/Select.html", "<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tdojoAttachPoint=\"_buttonNode,tableNode,focusNode\" cellspacing='0' cellpadding='0'\n\trole=\"combobox\" aria-haspopup=\"true\"\n\t><tbody role=\"presentation\"><tr role=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonContents dijitButtonNode\" role=\"presentation\"\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"  dojoAttachPoint=\"containerNode,_popupStateNode\"></span\n\t\t\t><input type=\"hidden\" ${!nameAttrSetting} dojoAttachPoint=\"valueNode\" value=\"${value}\" aria-hidden=\"true\"\n\t\t/></td><td class=\"dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton\"\n\t\t\t\tdojoAttachPoint=\"titleNode\" role=\"presentation\"\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" role=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" role=\"presentation\">&#9660;</div\n\t\t></td\n\t></tr></tbody\n></table>\n"),
 
        // attributeMap: Object
        //              Add in our style to be applied to the focus node
@@ -16769,13 +17597,17 @@ dojo.declare("dijit.form.Select", [dijit.form._FormSelectWidget, dijit._HasDropD
        //              Shows current state (ie, validation result) of input (Normal, Warning, or Error)
        state: "",
 
+       // message: String
+       //              Currently displayed error/prompt message
+       message: "",
+
        //      tooltipPosition: String[]
        //              See description of dijit.Tooltip.defaultPosition for details on this parameter.
        tooltipPosition: [],
 
        // emptyLabel: string
        //              What to display in an "empty" dropdown
-       emptyLabel: "",
+       emptyLabel: "&nbsp;",
 
        // _isLoaded: Boolean
        //              Whether or not we have been loaded
@@ -16789,11 +17621,11 @@ dojo.declare("dijit.form.Select", [dijit.form._FormSelectWidget, dijit._HasDropD
                // summary:
                //              Set the value to be the first, or the selected index
                this.inherited(arguments);
+               // set value from selected option
                if(this.options.length && !this.value && this.srcNodeRef){
-                       var si = this.srcNodeRef.selectedIndex;
-                       this.value = this.options[si != -1 ? si : 0].value;
+                       var si = this.srcNodeRef.selectedIndex || 0; // || 0 needed for when srcNodeRef is not a SELECT
+                       this.value = this.options[si >= 0 ? si : 0].value;
                }
-
                // Create the dropDown widget
                this.dropDown = new dijit.form._SelectMenu({id: this.id + "_menu"});
                dojo.addClass(this.dropDown.domNode, this.baseClass + "Menu");
@@ -16803,7 +17635,7 @@ dojo.declare("dijit.form.Select", [dijit.form._FormSelectWidget, dijit._HasDropD
                // summary:
                //              For the given option, return the menu item that should be
                //              used to display it.  This can be overridden as needed
-               if(!option.value){
+               if(!option.value && !option.label){
                        // We are a separator (no label set for it)
                        return new dijit.MenuSeparator();
                }else{
@@ -16811,7 +17643,7 @@ dojo.declare("dijit.form.Select", [dijit.form._FormSelectWidget, dijit._HasDropD
                        var click = dojo.hitch(this, "_setValueAttr", option);
                        var item = new dijit.MenuItem({
                                option: option,
-                               label: option.label,
+                               label: option.label || this.emptyLabel,
                                onClick: click,
                                disabled: option.disabled || false
                        });
@@ -16865,7 +17697,6 @@ dojo.declare("dijit.form.Select", [dijit.form._FormSelectWidget, dijit._HasDropD
                        this._updateSelection();
                }
 
-               var len = this.options.length;
                this._isLoaded = false;
                this._childrenLoaded = true;
 
@@ -16883,10 +17714,9 @@ dojo.declare("dijit.form.Select", [dijit.form._FormSelectWidget, dijit._HasDropD
        _setDisplay: function(/*String*/ newDisplay){
                // summary:
                //              sets the display for the given value (or values)
-               this.containerNode.innerHTML = '<span class="dijitReset dijitInline ' + this.baseClass + 'Label">' +
-                                       (newDisplay || this.emptyLabel || "&nbsp;") +
-                                       '</span>';
-               dijit.setWaiState(this.focusNode, "valuetext", (newDisplay || this.emptyLabel || "&nbsp;") );
+               var lbl = newDisplay || this.emptyLabel;
+               this.containerNode.innerHTML = '<span class="dijitReset dijitInline ' + this.baseClass + 'Label">' + lbl + '</span>';
+               dijit.setWaiState(this.focusNode, "valuetext", lbl);
        },
 
        validate: function(/*Boolean*/ isFocused){
@@ -16898,12 +17728,11 @@ dojo.declare("dijit.form.Select", [dijit.form._FormSelectWidget, dijit._HasDropD
                //              set the value.
                
                var isValid = this.isValid(isFocused);
-               this.state = isValid ? "" : "Error";
-               this._setStateClass();
+               this._set("state", isValid ? "" : "Error");
                dijit.setWaiState(this.focusNode, "invalid", isValid ? "false" : "true");
                var message = isValid ? "" : this._missingMsg;
-               if(this._message !== message){
-                       this._message = message;
+               if(this.message !== message){
+                       this._set("message", message);
                        dijit.hideTooltip(this.domNode);
                        if(message){
                                dijit.showTooltip(message, this.domNode, this.tooltipPosition, !this.isLeftToRight());
@@ -16914,9 +17743,9 @@ dojo.declare("dijit.form.Select", [dijit.form._FormSelectWidget, dijit._HasDropD
 
        isValid: function(/*Boolean*/ isFocused){
                // summary:
-               //              Whether or not this is a valid value.   The only way a Select
+               //              Whether or not this is a valid value.  The only way a Select
                //              can be invalid is when it's required but nothing is selected.
-               return (!this.required || !(/^\s*$/.test(this.value)));
+               return (!this.required || this.value === 0 || !(/^\s*$/.test(this.value || ""))); // handle value is null or undefined
        },
 
        reset: function(){
@@ -16924,9 +17753,8 @@ dojo.declare("dijit.form.Select", [dijit.form._FormSelectWidget, dijit._HasDropD
                //              Overridden so that the state will be cleared.
                this.inherited(arguments);
                dijit.hideTooltip(this.domNode);
-               this.state = "";
-               this._setStateClass();
-               delete this._message;
+               this._set("state", "");
+               this._set("message", "")
        },
 
        postMixInProperties: function(){
@@ -16938,10 +17766,17 @@ dojo.declare("dijit.form.Select", [dijit.form._FormSelectWidget, dijit._HasDropD
        },
 
        postCreate: function(){
+               // summary:
+               //              stop mousemove from selecting text on IE to be consistent with other browsers
+
                this.inherited(arguments);
-               if(this.tableNode.style.width){
-                       dojo.addClass(this.domNode, this.baseClass + "FixedWidth");
-               }
+
+               this.connect(this.domNode, "onmousemove", dojo.stopEvent);
+       },
+
+       _setStyleAttr: function(/*String||Object*/ value){
+               this.inherited(arguments);
+               dojo.toggleClass(this.domNode, this.baseClass + "FixedWidth", !!this.tableNode.style.width);
        },
 
        isLoaded: function(){
@@ -17017,12 +17852,20 @@ dojo.declare("dijit.form.SimpleTextarea",
 
        postMixInProperties: function(){
                // Copy value from srcNodeRef, unless user specified a value explicitly (or there is no srcNodeRef)
+               // TODO: parser will handle this in 2.0
                if(!this.value && this.srcNodeRef){
                        this.value = this.srcNodeRef.value;
                }
                this.inherited(arguments);
        },
 
+       buildRendering: function(){
+               this.inherited(arguments);
+               if(dojo.isIE && this.cols){ // attribute selectors is not supported in IE6
+                       dojo.addClass(this.textbox, "dijitTextAreaCols");
+               }
+       },
+
        filter: function(/*String*/ value){
                // Override TextBox.filter to deal with newlines... specifically (IIRC) this is for IE which writes newlines
                // as \r\n instead of just \n
@@ -17032,13 +17875,6 @@ dojo.declare("dijit.form.SimpleTextarea",
                return this.inherited(arguments);
        },
 
-       postCreate: function(){
-               this.inherited(arguments);
-               if(dojo.isIE && this.cols){ // attribute selectors is not supported in IE6
-                       dojo.addClass(this.textbox, "dijitTextAreaCols");
-               }
-       },
-
        _previousValue: "",
        _onInput: function(/*Event?*/ e){
                // Override TextBox._onInput() to enforce maxLength restriction
@@ -17086,8 +17922,6 @@ dojo.provide("dijit.InlineEditBox");
 
 
 
-
-
 dojo.declare("dijit.InlineEditBox",
        dijit._Widget,
        {
@@ -17131,12 +17965,12 @@ dojo.declare("dijit.InlineEditBox",
        //              rather than plain text (ex: `dijit.Editor`)
        renderAsHtml: false,
 
-       // editor: String
-       //              Class name for Editor widget
+       // editor: String|Function
+       //              Class name (or reference to the Class) for Editor widget
        editor: "dijit.form.TextBox",
 
-       // editorWrapper: String
-       //              Class name for widget that wraps the editor widget, displaying save/cancel
+       // editorWrapper: String|Function
+       //              Class name (or reference to the Class) for widget that wraps the editor widget, displaying save/cancel
        //              buttons.
        editorWrapper: "dijit._InlineEditor",
 
@@ -17144,6 +17978,10 @@ dojo.declare("dijit.InlineEditBox",
        //              Set of parameters for editor, like {required: true}
        editorParams: {},
 
+       // disabled: Boolean
+       //              If true, clicking the InlineEditBox to edit it will have no effect.
+       disabled: false,
+
        onChange: function(value){
                // summary:
                //              Set this handler to be notified of changes to value.
@@ -17226,7 +18064,6 @@ dojo.declare("dijit.InlineEditBox",
                // summary:
                //              Hook to make set("disabled", ...) work.
                //              Set disabled state of widget.
-               this.disabled = disabled;
                dijit.setWaiState(this.domNode, "disabled", disabled);
                if(disabled){
                        this.displayNode.removeAttribute("tabIndex");
@@ -17234,6 +18071,7 @@ dojo.declare("dijit.InlineEditBox",
                        this.displayNode.setAttribute("tabIndex", 0);
                }
                dojo.toggleClass(this.displayNode, "dijitInlineEditBoxDisplayModeDisabled", disabled);
+               this._set("disabled", disabled);
        },
 
        _onMouseOver: function(){
@@ -17291,7 +18129,7 @@ dojo.declare("dijit.InlineEditBox",
                        var placeholder = dojo.create("span", null, this.domNode, "before");
 
                        // Create the editor wrapper (the thing that holds the editor widget and the save/cancel buttons)
-                       var ewc = dojo.getObject(this.editorWrapper);
+                       var ewc = typeof this.editorWrapper == "string" ? dojo.getObject(this.editorWrapper) : this.editorWrapper;
                        this.wrapperWidget = new ewc({
                                value: this.value,
                                buttonSave: this.buttonSave,
@@ -17305,6 +18143,9 @@ dojo.declare("dijit.InlineEditBox",
                                save: dojo.hitch(this, "save"),
                                cancel: dojo.hitch(this, "cancel")
                        }, placeholder);
+                       if(!this._started){
+                               this.startup();
+                       }
                }
                var ww = this.wrapperWidget;
 
@@ -17350,7 +18191,7 @@ dojo.declare("dijit.InlineEditBox",
        },
 
        destroy: function(){
-               if(this.wrapperWidget){
+               if(this.wrapperWidget && !this.wrapperWidget._destroyed){
                        this.wrapperWidget.destroy();
                        delete this.wrapperWidget;
                }
@@ -17387,9 +18228,6 @@ dojo.declare("dijit.InlineEditBox",
                var value = ww.getValue();
                this.set('value', value); // display changed, formatted value
 
-               // tell the world that we have changed
-               setTimeout(dojo.hitch(this, "onChange", value), 0); // setTimeout prevents browser freeze for long-running event handlers
-
                this._showText(focus); // set focus as needed
        },
 
@@ -17407,11 +18245,15 @@ dojo.declare("dijit.InlineEditBox",
                //              Hook to make set("value", ...) work.
                //              Inserts specified HTML value into this node, or an "input needed" character if node is blank.
 
-               this.value = val = dojo.trim(val);
-               if(!this.renderAsHtml){
-                       val = val.replace(/&/gm, "&amp;").replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/"/gm, "&quot;").replace(/\n/g, "<br>");
+               val = dojo.trim(val);
+               var renderVal = this.renderAsHtml ? val : val.replace(/&/gm, "&amp;").replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/"/gm, "&quot;").replace(/\n/g, "<br>");
+               this.displayNode.innerHTML = renderVal || this.noValueIndicator;
+               this._set("value", val);
+
+               if(this._started){
+                       // tell the world that we have changed
+                       setTimeout(dojo.hitch(this, "onChange", val), 0); // setTimeout prevents browser freeze for long-running event handlers
                }
-               this.displayNode.innerHTML = val || this.noValueIndicator;
        },
 
        getValue: function(){
@@ -17456,7 +18298,7 @@ dojo.declare(
        // value: String
        //              Value as an HTML string or plain text string, depending on renderAsHTML flag
 
-       templateString: dojo.cache("dijit", "templates/InlineEditBox.html", "<span dojoAttachPoint=\"editNode\" waiRole=\"presentation\" style=\"position: absolute; visibility:hidden\" class=\"dijitReset dijitInline\"\n\tdojoAttachEvent=\"onkeypress: _onKeyPress\"\n\t><span dojoAttachPoint=\"editorPlaceholder\"></span\n\t><span dojoAttachPoint=\"buttonContainer\"\n\t\t><button class='saveButton' dojoAttachPoint=\"saveButton\" dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:save\" label=\"${buttonSave}\"></button\n\t\t><button class='cancelButton' dojoAttachPoint=\"cancelButton\" dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:cancel\" label=\"${buttonCancel}\"></button\n\t></span\n></span>\n"),
+       templateString: dojo.cache("dijit", "templates/InlineEditBox.html", "<span data-dojo-attach-point=\"editNode\" role=\"presentation\" style=\"position: absolute; visibility:hidden\" class=\"dijitReset dijitInline\"\n\tdata-dojo-attach-event=\"onkeypress: _onKeyPress\"\n\t><span data-dojo-attach-point=\"editorPlaceholder\"></span\n\t><span data-dojo-attach-point=\"buttonContainer\"\n\t\t><button data-dojo-type=\"dijit.form.Button\" data-dojo-props=\"label: '${buttonSave}', 'class': 'saveButton'\"\n\t\t\tdata-dojo-attach-point=\"saveButton\" data-dojo-attach-event=\"onClick:save\"></button\n\t\t><button data-dojo-type=\"dijit.form.Button\"  data-dojo-props=\"label: '${buttonCancel}', 'class': 'cancelButton'\"\n\t\t\tdata-dojo-attach-point=\"cancelButton\" data-dojo-attach-event=\"onClick:cancel\"></button\n\t></span\n></span>\n"),
        widgetsInTemplate: true,
 
        postMixInProperties: function(){
@@ -17467,9 +18309,11 @@ dojo.declare(
                }, this);
        },
 
-       postCreate: function(){
+       buildRendering: function(){
+               this.inherited(arguments);
+
                // Create edit widget in place in the template
-               var cls = dojo.getObject(this.editor);
+               var cls = typeof this.editor == "string" ? dojo.getObject(this.editor) : this.editor;
 
                // Copy the style from the source
                // Don't copy ALL properties though, just the necessary/applicable ones.
@@ -17504,13 +18348,21 @@ dojo.declare(
                        lang: this.lang
                });
                editorParams[ "displayedValue" in cls.prototype ? "displayedValue" : "value"] = this.value;
-               var ew = (this.editWidget = new cls(editorParams, this.editorPlaceholder));
+               this.editWidget = new cls(editorParams, this.editorPlaceholder);
 
                if(this.inlineEditBox.autoSave){
                        // Remove the save/cancel buttons since saving is done by simply tabbing away or
                        // selecting a value from the drop down list
                        dojo.destroy(this.buttonContainer);
+               }
+       },
+
+       postCreate: function(){
+               this.inherited(arguments);
+
+               var ew = this.editWidget;
 
+               if(this.inlineEditBox.autoSave){
                        // Selecting a value from a drop down list causes an onChange event and then we save
                        this.connect(ew, "onChange", "_onChange");
 
@@ -17520,7 +18372,7 @@ dojo.declare(
                        this.connect(ew, "onKeyPress", "_onKeyPress");
                }else{
                        // If possible, enable/disable save button based on whether the user has changed the value
-                       if("intermediateChanges" in cls.prototype){
+                       if("intermediateChanges" in ew){
                                ew.set("intermediateChanges", true);
                                this.connect(ew, "onChange", "_onIntermediateChange");
                                this.saveButton.set("disabled", true);
@@ -17670,7 +18522,7 @@ dojo.__cookieProps = function(){
 
 
 dojo.cookie = function(/*String*/name, /*String?*/value, /*dojo.__cookieProps?*/props){
-       //      summary: 
+       //      summary:
        //              Get or set a cookie.
        //      description:
        //              If one argument is passed, returns the value of the cookie
@@ -17679,17 +18531,17 @@ dojo.cookie = function(/*String*/name, /*String?*/value, /*dojo.__cookieProps?*/
        //              Name of the cookie
        //      value:
        //              Value for the cookie
-       //      props: 
+       //      props:
        //              Properties for the cookie
        //      example:
        //              set a cookie with the JSON-serialized contents of an object which
        //              will expire 5 days from now:
        //      |       dojo.cookie("configObj", dojo.toJson(config), { expires: 5 });
-       //      
+       //
        //      example:
        //              de-serialize a cookie back into a JavaScript object:
        //      |       var config = dojo.fromJson(dojo.cookie("configObj"));
-       //      
+       //
        //      example:
        //              delete a cookie:
        //      |       dojo.cookie("configObj", null, {expires: -1});
@@ -17701,7 +18553,7 @@ dojo.cookie = function(/*String*/name, /*String?*/value, /*dojo.__cookieProps?*/
                props = props || {};
 // FIXME: expires=0 seems to disappear right away, not on close? (FF3)  Change docs?
                var exp = props.expires;
-               if(typeof exp == "number"){ 
+               if(typeof exp == "number"){
                        var d = new Date();
                        d.setTime(d.getTime() + exp*24*60*60*1000);
                        exp = props.expires = d;
@@ -17722,7 +18574,7 @@ dojo.cookie = function(/*String*/name, /*String?*/value, /*dojo.__cookieProps?*/
 dojo.cookie.isSupported = function(){
        //      summary:
        //              Use to determine if the current browser supports cookies or not.
-       //              
+       //
        //              Returns true if user allows cookies.
        //              Returns false if user doesn't allow cookies.
 
@@ -17758,7 +18610,7 @@ dojo.declare(
                        //              Monitors the specified StackContainer, and whenever a page is
                        //              added, deleted, or selected, updates itself accordingly.
 
-                       templateString: "<span wairole='tablist' dojoAttachEvent='onkeypress' class='dijitStackController'></span>",
+                       templateString: "<span role='tablist' dojoAttachEvent='onkeypress' class='dijitStackController'></span>",
 
                        // containerId: [const] String
                        //              The id of the page container that I point to
@@ -17768,11 +18620,19 @@ dojo.declare(
                        //              The name of the button widget to create to correspond to each page
                        buttonWidget: "dijit.layout._StackButton",
 
-                       postCreate: function(){
-                               dijit.setWaiRole(this.domNode, "tablist");
-
+                       constructor: function(){
                                this.pane2button = {};          // mapping from pane id to buttons
-                               this.pane2handles = {};         // mapping from pane id to this.connect() handles
+                               this.pane2connects = {};        // mapping from pane id to this.connect() handles
+                               this.pane2watches = {};         // mapping from pane id to watch() handles
+                       },
+
+                       buildRendering: function(){
+                               this.inherited(arguments);
+                               dijit.setWaiRole(this.domNode, "tablist");      // TODO: unneeded?   it's in template above.
+                       },
+
+                       postCreate: function(){
+                               this.inherited(arguments);
 
                                // Listen to notifications from StackContainer
                                this.subscribe(this.containerId+"-startup", "onStartup");
@@ -17822,22 +18682,25 @@ dojo.declare(
                                        title: page.tooltip
                                });
                                dijit.setWaiState(button.focusNode,"selected", "false");
-                               this.pane2handles[page.id] = [
-                                       this.connect(page, 'set', function(name, value){
-                                               var buttonAttr = {
-                                                       title: 'label',
-                                                       showTitle: 'showLabel',
-                                                       iconClass: 'iconClass',
-                                                       closable: 'closeButton',
-                                                       tooltip: 'title'
-                                               }[name];
-                                               if(buttonAttr){
-                                                       button.set(buttonAttr, value);
-                                               }
-                                       }),
+
+
+                               // map from page attribute to corresponding tab button attribute
+                               var pageAttrList = ["title", "showTitle", "iconClass", "closable", "tooltip"],
+                                       buttonAttrList = ["label", "showLabel", "iconClass", "closeButton", "title"];
+
+                               // watch() so events like page title changes are reflected in tab button
+                               this.pane2watches[page.id] = dojo.map(pageAttrList, function(pageAttr, idx){
+                                       return page.watch(pageAttr, function(name, oldVal, newVal){
+                                               button.set(buttonAttrList[idx], newVal);
+                                       });
+                               });
+                                       
+                               // connections so that clicking a tab button selects the corresponding page
+                               this.pane2connects[page.id] = [
                                        this.connect(button, 'onClick', dojo.hitch(this,"onButtonClick", page)),
                                        this.connect(button, 'onClickCloseButton', dojo.hitch(this,"onCloseButtonClick", page))
                                ];
+
                                this.addChild(button, insertIndex);
                                this.pane2button[page.id] = button;
                                page.controlButton = button;    // this value might be overwritten if two tabs point to same container
@@ -17860,8 +18723,13 @@ dojo.declare(
                                //              private
 
                                if(this._currentChild === page){ this._currentChild = null; }
-                               dojo.forEach(this.pane2handles[page.id], this.disconnect, this);
-                               delete this.pane2handles[page.id];
+
+                               // disconnect/unwatch connections/watches related to page being removed
+                               dojo.forEach(this.pane2connects[page.id], dojo.hitch(this, "disconnect"));
+                               delete this.pane2connects[page.id];
+                               dojo.forEach(this.pane2watches[page.id], function(w){ w.unwatch(); });
+                               delete this.pane2watches[page.id];
+
                                var button = this.pane2button[page.id];
                                if(button){
                                        this.removeChild(button);
@@ -17963,6 +18831,14 @@ dojo.declare(
                                                case k.PAGE_DOWN:
                                                        if(e.ctrlKey){ forward = true; }
                                                        break;
+                                               case k.HOME:
+                                               case k.END:
+                                                       var children = this.getChildren();
+                                                       if(children && children.length){
+                                                               children[e.charOrCode == k.HOME ? 0 : children.length-1].onClick();
+                                                       }
+                                                       dojo.stopEvent(e);
+                                                       break;
                                                case k.DELETE:
                                                        if(this._currentChild.closable){
                                                                this.onCloseButtonClick(this._currentChild);
@@ -17982,7 +18858,7 @@ dojo.declare(
                                                                }
                                                        }
                                        }
-                                       // handle page navigation
+                                       // handle next/previous page navigation (left/right arrow, etc.)
                                        if(forward !== null){
                                                this.adjacent(forward).onClick();
                                                dojo.stopEvent(e);
@@ -18016,9 +18892,9 @@ dojo.declare("dijit.layout._StackButton",
                // Probably we should be calling this.startupKeyNavChildren() instead.
                tabIndex: "-1",
 
-               postCreate: function(/*Event*/ evt){
-                       dijit.setWaiRole((this.focusNode || this.domNode), "tab");
+               buildRendering: function(/*Event*/ evt){
                        this.inherited(arguments);
+                       dijit.setWaiRole((this.focusNode || this.domNode), "tab");
                },
 
                onClick: function(/*Event*/ evt){
@@ -18040,7 +18916,6 @@ dojo.declare("dijit.layout._StackButton",
                }
        });
 
-
 }
 
 if(!dojo._hasResource["dijit.layout.StackContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
@@ -18052,6 +18927,7 @@ dojo.provide("dijit.layout.StackContainer");
 
 
 
+
 dojo.declare(
        "dijit.layout.StackContainer",
        dijit.layout._LayoutWidget,
@@ -18085,10 +18961,14 @@ dojo.declare(
        selectedChildWidget: null,
 =====*/
 
-       postCreate: function(){
+       buildRendering: function(){
                this.inherited(arguments);
                dojo.addClass(this.domNode, "dijitLayoutContainer");
                dijit.setWaiRole(this.containerNode, "tabpanel");
+       },
+
+       postCreate: function(){
+               this.inherited(arguments);
                this.connect(this.domNode, "onkeypress", this._onKeyPress);
        },
 
@@ -18144,8 +19024,7 @@ dojo.declare(
 
                this.inherited(arguments);
 
-               dojo.removeClass(child.domNode, "dijitVisible");
-               dojo.addClass(child.domNode, "dijitHidden");
+               dojo.replaceClass(child.domNode, "dijitHidden", "dijitVisible");
 
                // remove the title attribute so it doesn't show up when i hover
                // over a node
@@ -18218,17 +19097,19 @@ dojo.declare(
 
                if(this.selectedChildWidget != page){
                        // Deselect old page and select new one
-                       this._transition(page, this.selectedChildWidget, animate);
-                       this.selectedChildWidget = page;
+                       var d = this._transition(page, this.selectedChildWidget, animate);
+                       this._set("selectedChildWidget", page);
                        dojo.publish(this.id+"-selectChild", [page]);
 
                        if(this.persist){
                                dojo.cookie(this.id + "_selectedChild", this.selectedChildWidget.id);
                        }
                }
+
+               return d;               // If child has an href, promise that fires when the child's href finishes loading
        },
 
-       _transition: function(/*dijit._Widget*/newWidget, /*dijit._Widget*/oldWidget){
+       _transition: function(/*dijit._Widget*/ newWidget, /*dijit._Widget*/ oldWidget, /*Boolean*/ animate){
                // summary:
                //              Hide the old widget and display the new widget.
                //              Subclasses should override this.
@@ -18237,7 +19118,7 @@ dojo.declare(
                if(oldWidget){
                        this._hideChild(oldWidget);
                }
-               this._showChild(newWidget);
+               var d = this._showChild(newWidget);
 
                // Size the new widget, in case this is the first time it's being shown,
                // or I have been resized since the last time it was shown.
@@ -18251,6 +19132,8 @@ dojo.declare(
                                newWidget.resize();
                        }
                }
+
+               return d;       // If child has an href, promise that fires when the child's href finishes loading
        },
 
        _adjacent: function(/*Boolean*/ forward){
@@ -18265,13 +19148,13 @@ dojo.declare(
        forward: function(){
                // summary:
                //              Advance to next page.
-               this.selectChild(this._adjacent(true), true);
+               return this.selectChild(this._adjacent(true), true);
        },
 
        back: function(){
                // summary:
                //              Go back to previous page.
-               this.selectChild(this._adjacent(false), true);
+               return this.selectChild(this._adjacent(false), true);
        },
 
        _onKeyPress: function(e){
@@ -18289,24 +19172,24 @@ dojo.declare(
                // summary:
                //              Show the specified child by changing it's CSS, and call _onShow()/onShow() so
                //              it can do any updates it needs regarding loading href's etc.
+               // returns:
+               //              Promise that fires when page has finished showing, or true if there's no href
                var children = this.getChildren();
                page.isFirstChild = (page == children[0]);
                page.isLastChild = (page == children[children.length-1]);
-               page.selected = true;
+               page._set("selected", true);
 
-               dojo.removeClass(page.domNode, "dijitHidden");
-               dojo.addClass(page.domNode, "dijitVisible");
+               dojo.replaceClass(page.domNode, "dijitVisible", "dijitHidden");
 
-               page._onShow();
+               return page._onShow() || true;
        },
 
        _hideChild: function(/*dijit._Widget*/ page){
                // summary:
                //              Hide the specified child by changing it's CSS, and call _onHide() so
                //              it's notified.
-               page.selected=false;
-               dojo.removeClass(page.domNode, "dijitVisible");
-               dojo.addClass(page.domNode, "dijitHidden");
+               page._set("selected", false);
+               dojo.replaceClass(page.domNode, "dijitHidden", "dijitVisible");
 
                page.onHide();
        },
@@ -18325,7 +19208,7 @@ dojo.declare(
                }
        },
 
-       destroyDescendants: function(/*Boolean*/preserveDom){
+       destroyDescendants: function(/*Boolean*/ preserveDom){
                dojo.forEach(this.getChildren(), function(child){
                        this.removeChild(child);
                        child.destroyRecursive(preserveDom);
@@ -18336,7 +19219,6 @@ dojo.declare(
 // For back-compat, remove for 2.0
 
 
-
 // These arguments can be specified for the children of a StackContainer.
 // Since any widget can be specified as a StackContainer child, mix them
 // into the base widget class.  (This is a hack, but it's effective.)
@@ -18401,8 +19283,28 @@ dojo.provide("dijit.layout.AccordionContainer");
 
 
 
+//dojo.require("dijit.layout.AccordionPane "); // for back compat, remove for 2.0
 
-       // for back compat, remove for 2.0
+// Design notes:
+//
+// An AccordionContainer is a StackContainer, but each child (typically ContentPane)
+// is wrapped in a _AccordionInnerContainer.   This is hidden from the caller.
+//
+// The resulting markup will look like:
+//
+//     <div class=dijitAccordionContainer>
+//             <div class=dijitAccordionInnerContainer>        (one pane)
+//                             <div class=dijitAccordionTitle>         (title bar) ... </div>
+//                             <div class=dijtAccordionChildWrapper>   (content pane) </div>
+//             </div>
+//     </div>
+//
+// Normally the dijtAccordionChildWrapper is hidden for all but one child (the shown
+// child), so the space for the content pane is all the title bars + the one dijtAccordionChildWrapper,
+// which on claro has a 1px border plus a 2px bottom margin.
+//
+// During animation there are two dijtAccordionChildWrapper's shown, so we need
+// to compensate for that.
 
 dojo.declare(
        "dijit.layout.AccordionContainer",
@@ -18428,17 +19330,18 @@ dojo.declare(
                //              The name of the widget used to display the title of each pane
                buttonWidget: "dijit.layout._AccordionButton",
 
+/*=====
                // _verticalSpace: Number
                //              Pixels of space available for the open pane
                //              (my content box size minus the cumulative size of all the title bars)
                _verticalSpace: 0,
-
+=====*/
                baseClass: "dijitAccordionContainer",
 
-               postCreate: function(){
-                       this.domNode.style.overflow = "hidden";
+               buildRendering: function(){
                        this.inherited(arguments);
-                       dijit.setWaiRole(this.domNode, "tablist");
+                       this.domNode.style.overflow = "hidden";         // TODO: put this in dijit.css
+                       dijit.setWaiRole(this.domNode, "tablist");      // TODO: put this in template
                },
 
                startup: function(){
@@ -18452,20 +19355,6 @@ dojo.declare(
                        }
                },
 
-               _getTargetHeight: function(/* Node */ node){
-                       // summary:
-                       //              For the given node, returns the height that should be
-                       //              set to achieve our vertical space (subtract any padding
-                       //              we may have).
-                       //
-                       //              This is used by the animations.
-                       //
-                       //              TODO: I don't think this works correctly in IE quirks when an elements
-                       //              style.height including padding and borders
-                       var cs = dojo.getComputedStyle(node);
-                       return Math.max(this._verticalSpace - dojo._getPadBorderExtents(node, cs).h - dojo._getMarginExtents(node, cs).h, 0);
-               },
-
                layout: function(){
                        // Implement _LayoutWidget.layout() virtual method.
                        // Set the height of the open pane based on what room remains.
@@ -18474,25 +19363,31 @@ dojo.declare(
                        
                        if(!openPane){ return;}
 
-                       var openPaneContainer = openPane._wrapperWidget.domNode,
-                               openPaneContainerMargin = dojo._getMarginExtents(openPaneContainer),
-                               openPaneContainerPadBorder = dojo._getPadBorderExtents(openPaneContainer),
+                       // space taken up by title, plus wrapper div (with border/margin) for open pane
+                       var wrapperDomNode = openPane._wrapperWidget.domNode,
+                               wrapperDomNodeMargin = dojo._getMarginExtents(wrapperDomNode),
+                               wrapperDomNodePadBorder = dojo._getPadBorderExtents(wrapperDomNode),
+                               wrapperContainerNode = openPane._wrapperWidget.containerNode,
+                               wrapperContainerNodeMargin = dojo._getMarginExtents(wrapperContainerNode),
+                               wrapperContainerNodePadBorder = dojo._getPadBorderExtents(wrapperContainerNode),
                                mySize = this._contentBox;
 
                        // get cumulative height of all the unselected title bars
                        var totalCollapsedHeight = 0;
                        dojo.forEach(this.getChildren(), function(child){
                    if(child != openPane){
-                                       totalCollapsedHeight += dojo.marginBox(child._wrapperWidget.domNode).h;
+                                       totalCollapsedHeight += dojo._getMarginSize(child._wrapperWidget.domNode).h;
                                }
                        });
-                       this._verticalSpace = mySize.h - totalCollapsedHeight - openPaneContainerMargin.h 
-                               - openPaneContainerPadBorder.h - openPane._buttonWidget.getTitleHeight();
+                       this._verticalSpace = mySize.h - totalCollapsedHeight - wrapperDomNodeMargin.h
+                               - wrapperDomNodePadBorder.h - wrapperContainerNodeMargin.h - wrapperContainerNodePadBorder.h
+                               - openPane._buttonWidget.getTitleHeight();
 
                        // Memo size to make displayed child
                        this._containerContentBox = {
                                h: this._verticalSpace,
-                               w: this._contentBox.w - openPaneContainerMargin.w - openPaneContainerPadBorder.w
+                               w: this._contentBox.w - wrapperDomNodeMargin.w - wrapperDomNodePadBorder.w
+                                       - wrapperContainerNodeMargin.w - wrapperContainerNodePadBorder.w
                        };
 
                        if(openPane){
@@ -18516,7 +19411,7 @@ dojo.declare(
                        this.inherited(arguments);
                },
 
-               addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){  
+               addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
                        if(this._started){
                                // Adding a child to a started Accordion is complicated because children have
                                // wrapper widgets.  Default code path (calling this.inherited()) would add
@@ -18532,7 +19427,7 @@ dojo.declare(
                                // Then stick the wrapper widget around the child widget
                                this._setupChild(child);
 
-                               // Code below copied from StackContainer        
+                               // Code below copied from StackContainer
                                dojo.publish(this.id+"-addChild", [child, insertIndex]);
                                this.layout();
                                if(!this.selectedChildWidget){
@@ -18548,9 +19443,15 @@ dojo.declare(
                removeChild: function(child){
                        // Overrides _LayoutWidget.removeChild().
 
-                       // destroy wrapper widget first, before StackContainer.getChildren() call
-                       child._wrapperWidget.destroy();
-                       delete child._wrapperWidget;
+                       // Destroy wrapper widget first, before StackContainer.getChildren() call.
+                       // Replace wrapper widget with true child widget (ContentPane etc.).
+                       // This step only happens if the AccordionContainer has been started; otherwise there's no wrapper.
+                       if(child._wrapperWidget){
+                               dojo.place(child.domNode, child._wrapperWidget.domNode, "after");
+                               child._wrapperWidget.destroy();
+                               delete child._wrapperWidget;
+                       }
+
                        dojo.removeClass(child.domNode, "dijitHidden");
 
                        this.inherited(arguments);
@@ -18564,23 +19465,53 @@ dojo.declare(
                },
 
                destroy: function(){
+                       if(this._animation){
+                               this._animation.stop();
+                       }
                        dojo.forEach(this.getChildren(), function(child){
-                               child._wrapperWidget.destroy();
+                               // If AccordionContainer has been started, then each child has a wrapper widget which
+                               // also needs to be destroyed.
+                               if(child._wrapperWidget){
+                                       child._wrapperWidget.destroy();
+                               }else{
+                                       child.destroyRecursive();
+                               }
                        });
                        this.inherited(arguments);
                },
 
-               _transition: function(/*dijit._Widget?*/newWidget, /*dijit._Widget?*/oldWidget, /*Boolean*/ animate){
+               _showChild: function(child){
+                       // Override StackContainer._showChild() to set visibility of _wrapperWidget.containerNode
+                       child._wrapperWidget.containerNode.style.display="block";
+                       return this.inherited(arguments);
+               },
+
+               _hideChild: function(child){
+                       // Override StackContainer._showChild() to set visibility of _wrapperWidget.containerNode
+                       child._wrapperWidget.containerNode.style.display="none";
+                       this.inherited(arguments);
+               },
+
+               _transition: function(/*dijit._Widget?*/ newWidget, /*dijit._Widget?*/ oldWidget, /*Boolean*/ animate){
                        // Overrides StackContainer._transition() to provide sliding of title bars etc.
 
-//TODO: should be able to replace this with calls to slideIn/slideOut
-                       if(this._inTransition){ return; }
-                       var animations = [];
-                       var paneHeight = this._verticalSpace;
+                       if(dojo.isIE < 8){
+                               // workaround animation bugs by not animating; not worth supporting animation for IE6 & 7
+                               animate = false;
+                       }
+
+                       if(this._animation){
+                               // there's an in-progress animation.  speedily end it so we can do the newly requested one
+                               this._animation.stop(true);
+                               delete this._animation;
+                       }
+
+                       var self = this;
+
                        if(newWidget){
                                newWidget._wrapperWidget.set("selected", true);
 
-                               this._showChild(newWidget);     // prepare widget to be slid in
+                               var d = this._showChild(newWidget);     // prepare widget to be slid in
 
                                // Size the new widget, in case this is the first time it's being shown,
                                // or I have been resized since the last time it was shown.
@@ -18588,74 +19519,51 @@ dojo.declare(
                                if(this.doLayout && newWidget.resize){
                                        newWidget.resize(this._containerContentBox);
                                }
-
-                               var newContents = newWidget.domNode;
-                               dojo.addClass(newContents, "dijitVisible");
-                               dojo.removeClass(newContents, "dijitHidden");
-                               
-                               if(animate){
-                                       var newContentsOverflow = newContents.style.overflow;
-                                       newContents.style.overflow = "hidden";
-                                       animations.push(dojo.animateProperty({
-                                               node: newContents,
-                                               duration: this.duration,
-                                               properties: {
-                                                       height: { start: 1, end: this._getTargetHeight(newContents) }
-                                               },
-                                               onEnd: function(){
-                                                       newContents.style.overflow = newContentsOverflow;
-
-                                                       // Kick IE to workaround layout bug, see #11415
-                                                       if(dojo.isIE){
-                                                               setTimeout(function(){
-                                                                       dojo.removeClass(newContents.parentNode, "dijitAccordionInnerContainerFocused");
-                                                                       setTimeout(function(){
-                                                                               dojo.addClass(newContents.parentNode, "dijitAccordionInnerContainerFocused");
-                                                                       }, 0);
-                                                               }, 0);
-                                                       }
-                                               }
-                                       }));
-                               }
                        }
+
                        if(oldWidget){
                                oldWidget._wrapperWidget.set("selected", false);
-                               var oldContents = oldWidget.domNode;
-                               if(animate){
-                                       var oldContentsOverflow = oldContents.style.overflow;
-                                       oldContents.style.overflow = "hidden";
-                                       animations.push(dojo.animateProperty({
-                                               node: oldContents,
-                                               duration: this.duration,
-                                               properties: {
-                                                       height: { start: this._getTargetHeight(oldContents), end: 1 }
-                                               },
-                                               onEnd: function(){
-                                                       dojo.addClass(oldContents, "dijitHidden");
-                                                       dojo.removeClass(oldContents, "dijitVisible");
-                                                       oldContents.style.overflow = oldContentsOverflow;
-                                                       if(oldWidget.onHide){
-                                                               oldWidget.onHide();
-                                                       }
-                                               }
-                                       }));
-                               }else{
-                                       dojo.addClass(oldContents, "dijitHidden");
-                                       dojo.removeClass(oldContents, "dijitVisible");
-                                       if(oldWidget.onHide){
-                                               oldWidget.onHide();
-                                       }
+                               if(!animate){
+                                       this._hideChild(oldWidget);
                                }
                        }
 
                        if(animate){
-                               this._inTransition = true;
-                               var combined = dojo.fx.combine(animations);
-                               combined.onEnd = dojo.hitch(this, function(){
-                                       delete this._inTransition;
+                               var newContents = newWidget._wrapperWidget.containerNode,
+                                       oldContents = oldWidget._wrapperWidget.containerNode;
+
+                               // During the animation we will be showing two dijitAccordionChildWrapper nodes at once,
+                               // which on claro takes up 4px extra space (compared to stable AccordionContainer).
+                               // Have to compensate for that by immediately shrinking the pane being closed.
+                               var wrapperContainerNode = newWidget._wrapperWidget.containerNode,
+                                       wrapperContainerNodeMargin = dojo._getMarginExtents(wrapperContainerNode),
+                                       wrapperContainerNodePadBorder = dojo._getPadBorderExtents(wrapperContainerNode),
+                                       animationHeightOverhead = wrapperContainerNodeMargin.h + wrapperContainerNodePadBorder.h;
+
+                               oldContents.style.height = (self._verticalSpace - animationHeightOverhead) + "px";
+
+                               this._animation = new dojo.Animation({
+                                       node: newContents,
+                                       duration: this.duration,
+                                       curve: [1, this._verticalSpace - animationHeightOverhead - 1],
+                                       onAnimate: function(value){
+                                               value = Math.floor(value);      // avoid fractional values
+                                               newContents.style.height = value + "px";
+                                               oldContents.style.height = (self._verticalSpace - animationHeightOverhead - value) + "px";
+                                       },
+                                       onEnd: function(){
+                                               delete self._animation;
+                                               newContents.style.height = "auto";
+                                               oldWidget._wrapperWidget.containerNode.style.display = "none";
+                                               oldContents.style.height = "auto";
+                                               self._hideChild(oldWidget);
+                                       }
                                });
-                               combined.play();
-                       }                       
+                               this._animation.onStop = this._animation.onEnd;
+                               this._animation.play();
+                       }
+
+                       return d;       // If child has an href, promise that fires when the widget has finished loading
                },
 
                // note: we are treating the container as controller here
@@ -18666,10 +19574,7 @@ dojo.declare(
                        //              This is called from a handler on AccordionContainer.domNode
                        //              (setup in StackContainer), and is also called directly from
                        //              the click handler for accordion labels
-                       if(this._inTransition || this.disabled || e.altKey || !(fromTitle || e.ctrlKey)){
-                               if(this._inTransition){
-                                       dojo.stopEvent(e);
-                               }
+                       if(this.disabled || e.altKey || !(fromTitle || e.ctrlKey)){
                                return;
                        }
                        var k = dojo.keys,
@@ -18694,16 +19599,17 @@ dojo.declare("dijit.layout._AccordionInnerContainer",
                //              When other widgets are added as children to an AccordionContainer they are wrapped in
                //              this widget.
                
+/*=====
                // buttonWidget: String
                //              Name of class to use to instantiate title
                //              (Wish we didn't have a separate widget for just the title but maintaining it
                //              for backwards compatibility, is it worth it?)
-/*=====
                 buttonWidget: null,
 =====*/
+
+/*=====
                // contentWidget: dijit._Widget
                //              Pointer to the real child widget
-/*=====
                contentWidget: null,
 =====*/
 
@@ -18713,7 +19619,15 @@ dojo.declare("dijit.layout._AccordionInnerContainer",
                isContainer: true,
                isLayoutContainer: true,
 
-               buildRendering: function(){                     
+               buildRendering: function(){
+                       // Builds a template like:
+                       //      <div class=dijitAccordionInnerContainer>
+                       //              Button
+                       //              <div class=dijitAccordionChildWrapper>
+                       //                      ContentPane
+                       //              </div>
+                       //      </div>
+
                        // Create wrapper div, placed where the child is now
                        this.domNode = dojo.place("<div class='" + this.baseClass + "'>", this.contentWidget.domNode, "after");
                        
@@ -18731,22 +19645,32 @@ dojo.declare("dijit.layout._AccordionInnerContainer",
                                parent: this.parent
                        })).placeAt(this.domNode);
                        
-                       // and then the actual content widget (changing it from prior-sibling to last-child)
-                       dojo.place(this.contentWidget.domNode, this.domNode);
+                       // and then the actual content widget (changing it from prior-sibling to last-child),
+                       // wrapped by a <div class=dijitAccordionChildWrapper>
+                       this.containerNode = dojo.place("<div class='dijitAccordionChildWrapper' style='display:none'>", this.domNode);
+                       dojo.place(this.contentWidget.domNode, this.containerNode);
                },
 
                postCreate: function(){
                        this.inherited(arguments);
-                       this.connect(this.contentWidget, 'set', function(name, value){
-                               var mappedName = {title: "label", tooltip: "title", iconClass: "iconClass"}[name];
-                               if(mappedName){
-                                       this.button.set(mappedName, value);
-                               }
-                       }, this);
+
+                       // Map changes in content widget's title etc. to changes in the button
+                       var button = this.button;
+                       this._contentWidgetWatches = [
+                               this.contentWidget.watch('title', dojo.hitch(this, function(name, oldValue, newValue){
+                                       button.set("label", newValue);
+                               })),
+                               this.contentWidget.watch('tooltip', dojo.hitch(this, function(name, oldValue, newValue){
+                                       button.set("title", newValue);
+                               })),
+                               this.contentWidget.watch('iconClass', dojo.hitch(this, function(name, oldValue, newValue){
+                                       button.set("iconClass", newValue);
+                               }))
+                       ];
                },
 
                _setSelectedAttr: function(/*Boolean*/ isSelected){
-                       this.selected = isSelected;
+                       this._set("selected", isSelected);
                        this.button.set("selected", isSelected);
                        if(isSelected){
                                var cw = this.contentWidget;
@@ -18761,7 +19685,9 @@ dojo.declare("dijit.layout._AccordionInnerContainer",
 
                destroy: function(){
                        this.button.destroyRecursive();
-                       
+
+                       dojo.forEach(this._contentWidgetWatches || [], function(w){ w.unwatch(); });
+
                        delete this.contentWidget._buttonWidget;
                        delete this.contentWidget._wrapperWidget;
 
@@ -18783,7 +19709,7 @@ dojo.declare("dijit.layout._AccordionButton",
        // tags:
        //              private
 
-       templateString: dojo.cache("dijit.layout", "templates/AccordionButton.html", "<div dojoAttachEvent='onclick:_onTitleClick' class='dijitAccordionTitle'>\n\t<div dojoAttachPoint='titleNode,focusNode' dojoAttachEvent='onkeypress:_onTitleKeyPress'\n\t\t\tclass='dijitAccordionTitleFocus' wairole=\"tab\" waiState=\"expanded-false\"\n\t\t><span class='dijitInline dijitAccordionArrow' waiRole=\"presentation\"></span\n\t\t><span class='arrowTextUp' waiRole=\"presentation\">+</span\n\t\t><span class='arrowTextDown' waiRole=\"presentation\">-</span\n\t\t><img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" dojoAttachPoint='iconNode' style=\"vertical-align: middle\" waiRole=\"presentation\"/>\n\t\t<span waiRole=\"presentation\" dojoAttachPoint='titleTextNode' class='dijitAccordionText'></span>\n\t</div>\n</div>\n"),
+       templateString: dojo.cache("dijit.layout", "templates/AccordionButton.html", "<div dojoAttachEvent='onclick:_onTitleClick' class='dijitAccordionTitle'>\n\t<div dojoAttachPoint='titleNode,focusNode' dojoAttachEvent='onkeypress:_onTitleKeyPress'\n\t\t\tclass='dijitAccordionTitleFocus' role=\"tab\" aria-expanded=\"false\"\n\t\t><span class='dijitInline dijitAccordionArrow' role=\"presentation\"></span\n\t\t><span class='arrowTextUp' role=\"presentation\">+</span\n\t\t><span class='arrowTextDown' role=\"presentation\">-</span\n\t\t><img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" dojoAttachPoint='iconNode' style=\"vertical-align: middle\" role=\"presentation\"/>\n\t\t<span role=\"presentation\" dojoAttachPoint='titleTextNode' class='dijitAccordionText'></span>\n\t</div>\n</div>\n"),
        attributeMap: dojo.mixin(dojo.clone(dijit.layout.ContentPane.prototype.attributeMap), {
                label: {node: "titleTextNode", type: "innerHTML" },
                title: {node: "titleTextNode", type: "attribute", attribute: "title"},
@@ -18800,18 +19726,18 @@ dojo.declare("dijit.layout._AccordionButton",
                return this.parent;
        },
 
-       postCreate: function(){
+       buildRendering: function(){
                this.inherited(arguments);
-               dojo.setSelectable(this.domNode, false);
-               var titleTextNodeId = dojo.attr(this.domNode,'id').replace(' ','_');
+               var titleTextNodeId = this.id.replace(' ','_');
                dojo.attr(this.titleTextNode, "id", titleTextNodeId+"_title");
                dijit.setWaiState(this.focusNode, "labelledby", dojo.attr(this.titleTextNode, "id"));
+               dojo.setSelectable(this.domNode, false);
        },
 
        getTitleHeight: function(){
                // summary:
                //              Returns the height of the title dom node.
-               return dojo.marginBox(this.domNode).h;  // Integer
+               return dojo._getMarginSize(this.domNode).h;     // Integer
        },
 
        // TODO: maybe the parent should set these methods directly rather than forcing the code
@@ -18820,10 +19746,8 @@ dojo.declare("dijit.layout._AccordionButton",
                // summary:
                //              Callback when someone clicks my title.
                var parent = this.getParent();
-               if(!parent._inTransition){
                        parent.selectChild(this.contentWidget, true);
                        dijit.focus(this.focusNode);
-               }
        },
 
        _onTitleKeyPress: function(/*Event*/ evt){
@@ -18831,7 +19755,7 @@ dojo.declare("dijit.layout._AccordionButton",
        },
 
        _setSelectedAttr: function(/*Boolean*/ isSelected){
-               this.selected = isSelected;
+               this._set("selected", isSelected);
                dijit.setWaiState(this.focusNode, "expanded", isSelected);
                dijit.setWaiState(this.focusNode, "selected", isSelected);
                this.focusNode.setAttribute("tabIndex", isSelected ? "0" : "-1");
@@ -18847,6 +19771,7 @@ dojo.provide("dijit.layout.BorderContainer");
 
 
 
+
 dojo.declare(
        "dijit.layout.BorderContainer",
        dijit.layout._LayoutWidget,
@@ -18862,19 +19787,21 @@ dojo.declare(
        //              include optional splitters (splitter="true") to make them resizable by the user.  The remaining
        //              space is designated for the center region.
        //
-       //              NOTE: Splitters must not be more than 50 pixels in width.
-       //
        //              The outer size must be specified on the BorderContainer node.  Width must be specified for the sides
        //              and height for the top and bottom, respectively.  No dimensions should be specified on the center;
        //              it will fill the remaining space.  Regions named "leading" and "trailing" may be used just like
        //              "left" and "right" except that they will be reversed in right-to-left environments.
        //
+       //              For complex layouts, multiple children can be specified for a single region.   In this case, the
+       //              layoutPriority flag on the children determines which child is closer to the edge (low layoutPriority)
+       //              and which child is closer to the center (high layoutPriority).   layoutPriority can also be used
+       //              instead of the design attribute to conrol layout precedence of horizontal vs. vertical panes.
        // example:
        // |    <div dojoType="dijit.layout.BorderContainer" design="sidebar" gutters="false"
        // |            style="width: 400px; height: 300px;">
-       // |            <div dojoType="ContentPane" region="top">header text</div>
-       // |            <div dojoType="ContentPane" region="right" splitter="true" style="width: 200px;">table of contents</div>
-       // |            <div dojoType="ContentPane" region="center">client area</div>
+       // |            <div dojoType="dijit.layout.ContentPane" region="top">header text</div>
+       // |            <div dojoType="dijit.layout.ContentPane" region="right" splitter="true" style="width: 200px;">table of contents</div>
+       // |            <div dojoType="dijit.layout.ContentPane" region="center">client area</div>
        // |    </div>
 
        // design: String
@@ -18884,13 +19811,13 @@ dojo.declare(
        //                      - "sidebar" where the left and right sides extend from top to bottom.
        design: "headline",
 
-       // gutters: Boolean
+       // gutters: [const] Boolean
        //              Give each pane a border and margin.
        //              Margin determined by domNode.paddingLeft.
        //              When false, only resizable panes have a gutter (i.e. draggable splitter) for resizing.
        gutters: true,
 
-       // liveSplitters: Boolean
+       // liveSplitters: [const] Boolean
        //              Specifies whether splitters resize as you drag (true) or only upon mouseup (false)
        liveSplitters: true,
 
@@ -18913,13 +19840,6 @@ dojo.declare(
                this.inherited(arguments);
        },
 
-       postCreate: function(){
-               this.inherited(arguments);
-
-               this._splitters = {};
-               this._splitterThickness = {};
-       },
-
        startup: function(){
                if(this._started){ return; }
                dojo.forEach(this.getChildren(), this._setupChild, this);
@@ -18939,14 +19859,10 @@ dojo.declare(
                        if(region == "leading"){ region = ltr ? "left" : "right"; }
                        if(region == "trailing"){ region = ltr ? "right" : "left"; }
 
-                       //FIXME: redundant?
-                       this["_"+region] = child.domNode;
-                       this["_"+region+"Widget"] = child;
-
                        // Create draggable splitter for resizing pane,
                        // or alternately if splitter=false but BorderContainer.gutters=true then
                        // insert dummy div just for spacing
-                       if((child.splitter || this.gutters) && !this._splitters[region]){
+                       if(region != "center" && (child.splitter || this.gutters) && !child._splitterWidget){
                                var _Splitter = dojo.getObject(child.splitter ? this._splitterClass : "dijit.layout._Gutter");
                                var splitter = new _Splitter({
                                        id: child.id + "_splitter",
@@ -18956,24 +19872,19 @@ dojo.declare(
                                        live: this.liveSplitters
                                });
                                splitter.isSplitter = true;
-                               this._splitters[region] = splitter.domNode;
-                               dojo.place(this._splitters[region], child.domNode, "after");
+                               child._splitterWidget = splitter;
+
+                               dojo.place(splitter.domNode, child.domNode, "after");
 
-                               // Splitters arent added as Contained children, so we need to call startup explicitly
+                               // Splitters aren't added as Contained children, so we need to call startup explicitly
                                splitter.startup();
                        }
-                       child.region = region;
+                       child.region = region;  // TODO: technically wrong since it overwrites "trailing" with "left" etc.
                }
        },
 
-       _computeSplitterThickness: function(region){
-               this._splitterThickness[region] = this._splitterThickness[region] ||
-                       dojo.marginBox(this._splitters[region])[(/top|bottom/.test(region) ? 'h' : 'w')];
-       },
-
        layout: function(){
                // Implement _LayoutWidget.layout() virtual method.
-               for(var region in this._splitters){ this._computeSplitterThickness(region); }
                this._layoutChildren();
        },
 
@@ -18987,20 +19898,29 @@ dojo.declare(
 
        removeChild: function(/*dijit._Widget*/ child){
                // Override _LayoutWidget.removeChild().
+
                var region = child.region;
-               var splitter = this._splitters[region];
+               var splitter = child._splitterWidget
                if(splitter){
-                       dijit.byNode(splitter).destroy();
-                       delete this._splitters[region];
-                       delete this._splitterThickness[region];
+                       splitter.destroy();
+                       delete child._splitterWidget;
                }
                this.inherited(arguments);
-               delete this["_"+region];
-               delete this["_" +region+"Widget"];
+               
                if(this._started){
                        this._layoutChildren();
                }
+               // Clean up whatever style changes we made to the child pane.
+               // Unclear how height and width should be handled.
                dojo.removeClass(child.domNode, this.baseClass+"Pane");
+               dojo.style(child.domNode, {
+                       top: "auto",
+                       bottom: "auto",
+                       left: "auto",
+                       right: "auto",
+                       position: "static"
+               });
+               dojo.style(child.domNode, region == "top" || region == "bottom" ? "width" : "height", "auto");
        },
 
        getChildren: function(){
@@ -19010,11 +19930,15 @@ dojo.declare(
                });
        },
 
+       // TODO: remove in 2.0
        getSplitter: function(/*String*/region){
                // summary:
                //              Returns the widget responsible for rendering the splitter associated with region
-               var splitter = this._splitters[region];
-               return splitter ? dijit.byNode(splitter) : null;
+               // tags:
+               //              deprecated
+               return dojo.filter(this.getChildren(), function(child){
+                       return child.region == region;
+               })[0]._splitterWidget;
        },
 
        resize: function(newSize, currentSize){
@@ -19035,7 +19959,7 @@ dojo.declare(
                this.inherited(arguments);
        },
 
-       _layoutChildren: function(/*String?*/changedRegion, /*Number?*/ changedRegionSize){
+       _layoutChildren: function(/*String?*/ changedChildId, /*Number?*/ changedChildSize){
                // summary:
                //              This is the main routine for setting size/position of each child.
                // description:
@@ -19045,11 +19969,10 @@ dojo.declare(
                //              With changedRegion specified (as "left", "top", "bottom", or "right"),
                //              it changes that region's width/height to changedRegionSize and
                //              then resizes other regions that were affected.
-               // changedRegion:
-               //              The region should be changed because splitter was dragged.
-               //              "left", "right", "top", or "bottom".
-               // changedRegionSize:
-               //              The new width/height (in pixels) to make changedRegion
+               // changedChildId:
+               //              Id of the child which should be resized because splitter was dragged.
+               // changedChildSize:
+               //              The new width/height (in pixels) to make specified child
 
                if(!this._borderBox || !this._borderBox.h){
                        // We are currently hidden, or we haven't been sized by our parent yet.
@@ -19057,196 +19980,63 @@ dojo.declare(
                        return;
                }
 
-               var sidebarLayout = (this.design == "sidebar");
-               var topHeight = 0, bottomHeight = 0, leftWidth = 0, rightWidth = 0;
-               var topStyle = {}, leftStyle = {}, rightStyle = {}, bottomStyle = {},
-                       centerStyle = (this._center && this._center.style) || {};
-
-               var changedSide = /left|right/.test(changedRegion);
-
-               var layoutSides = !changedRegion || (!changedSide && !sidebarLayout);
-               var layoutTopBottom = !changedRegion || (changedSide && sidebarLayout);
-
-               // Ask browser for width/height of side panes.
-               // Would be nice to cache this but height can change according to width
-               // (because words wrap around).  I don't think width will ever change though
-               // (except when the user drags a splitter).
-               if(this._top){
-                       topStyle = (changedRegion == "top" || layoutTopBottom) && this._top.style;
-                       topHeight = changedRegion == "top" ? changedRegionSize : dojo.marginBox(this._top).h;
-               }
-               if(this._left){
-                       leftStyle = (changedRegion == "left" || layoutSides) && this._left.style;
-                       leftWidth = changedRegion == "left" ? changedRegionSize : dojo.marginBox(this._left).w;
-               }
-               if(this._right){
-                       rightStyle = (changedRegion == "right" || layoutSides) && this._right.style;
-                       rightWidth = changedRegion == "right" ? changedRegionSize : dojo.marginBox(this._right).w;
-               }
-               if(this._bottom){
-                       bottomStyle = (changedRegion == "bottom" || layoutTopBottom) && this._bottom.style;
-                       bottomHeight = changedRegion == "bottom" ? changedRegionSize : dojo.marginBox(this._bottom).h;
-               }
-
-               var splitters = this._splitters;
-               var topSplitter = splitters.top, bottomSplitter = splitters.bottom,
-                       leftSplitter = splitters.left, rightSplitter = splitters.right;
-               var splitterThickness = this._splitterThickness;
-               var topSplitterThickness = splitterThickness.top || 0,
-                       leftSplitterThickness = splitterThickness.left || 0,
-                       rightSplitterThickness = splitterThickness.right || 0,
-                       bottomSplitterThickness = splitterThickness.bottom || 0;
-
-               // Check for race condition where CSS hasn't finished loading, so
-               // the splitter width == the viewport width (#5824)
-               if(leftSplitterThickness > 50 || rightSplitterThickness > 50){
-                       setTimeout(dojo.hitch(this, function(){
-                               // Results are invalid.  Clear them out.
-                               this._splitterThickness = {};
-
-                               for(var region in this._splitters){
-                                       this._computeSplitterThickness(region);
+               // Generate list of wrappers of my children in the order that I want layoutChildren()
+               // to process them (i.e. from the outside to the inside)
+               var wrappers = dojo.map(this.getChildren(), function(child, idx){
+                       return {
+                               pane: child,
+                               weight: [
+                                       child.region == "center" ? Infinity : 0,
+                                       child.layoutPriority,
+                                       (this.design == "sidebar" ? 1 : -1) * (/top|bottom/.test(child.region) ? 1 : -1),
+                                       idx
+                               ]
+                       };
+               }, this);
+               wrappers.sort(function(a, b){
+                       var aw = a.weight, bw = b.weight;
+                       for(var i=0; i<aw.length; i++){
+                               if(aw[i] != bw[i]){
+                                       return aw[i] - bw[i];
                                }
-                               this._layoutChildren();
-                       }), 50);
-                       return false;
-               }
-
-               var pe = this.pe;
-
-               var splitterBounds = {
-                       left: (sidebarLayout ? leftWidth + leftSplitterThickness: 0) + pe.l + "px",
-                       right: (sidebarLayout ? rightWidth + rightSplitterThickness: 0) + pe.r + "px"
-               };
-
-               if(topSplitter){
-                       dojo.mixin(topSplitter.style, splitterBounds);
-                       topSplitter.style.top = topHeight + pe.t + "px";
-               }
-
-               if(bottomSplitter){
-                       dojo.mixin(bottomSplitter.style, splitterBounds);
-                       bottomSplitter.style.bottom = bottomHeight + pe.b + "px";
-               }
-
-               splitterBounds = {
-                       top: (sidebarLayout ? 0 : topHeight + topSplitterThickness) + pe.t + "px",
-                       bottom: (sidebarLayout ? 0 : bottomHeight + bottomSplitterThickness) + pe.b + "px"
-               };
-
-               if(leftSplitter){
-                       dojo.mixin(leftSplitter.style, splitterBounds);
-                       leftSplitter.style.left = leftWidth + pe.l + "px";
-               }
-
-               if(rightSplitter){
-                       dojo.mixin(rightSplitter.style, splitterBounds);
-                       rightSplitter.style.right = rightWidth + pe.r + "px";
-               }
-
-               dojo.mixin(centerStyle, {
-                       top: pe.t + topHeight + topSplitterThickness + "px",
-                       left: pe.l + leftWidth + leftSplitterThickness + "px",
-                       right: pe.r + rightWidth + rightSplitterThickness + "px",
-                       bottom: pe.b + bottomHeight + bottomSplitterThickness + "px"
+                       }
+                       return 0;
                });
 
-               var bounds = {
-                       top: sidebarLayout ? pe.t + "px" : centerStyle.top,
-                       bottom: sidebarLayout ? pe.b + "px" : centerStyle.bottom
-               };
-               dojo.mixin(leftStyle, bounds);
-               dojo.mixin(rightStyle, bounds);
-               leftStyle.left = pe.l + "px"; rightStyle.right = pe.r + "px"; topStyle.top = pe.t + "px"; bottomStyle.bottom = pe.b + "px";
-               if(sidebarLayout){
-                       topStyle.left = bottomStyle.left = leftWidth + leftSplitterThickness + pe.l + "px";
-                       topStyle.right = bottomStyle.right = rightWidth + rightSplitterThickness + pe.r + "px";
-               }else{
-                       topStyle.left = bottomStyle.left = pe.l + "px";
-                       topStyle.right = bottomStyle.right = pe.r + "px";
-               }
-
-               // More calculations about sizes of panes
-               var containerHeight = this._borderBox.h - pe.t - pe.b,
-                       middleHeight = containerHeight - ( topHeight + topSplitterThickness + bottomHeight + bottomSplitterThickness),
-                       sidebarHeight = sidebarLayout ? containerHeight : middleHeight;
-
-               var containerWidth = this._borderBox.w - pe.l - pe.r,
-                       middleWidth = containerWidth - (leftWidth + leftSplitterThickness + rightWidth + rightSplitterThickness),
-                       sidebarWidth = sidebarLayout ? middleWidth : containerWidth;
+               // Make new list, combining the externally specified children with splitters and gutters
+               var childrenAndSplitters = [];
+               dojo.forEach(wrappers, function(wrapper){
+                       var pane = wrapper.pane;
+                       childrenAndSplitters.push(pane);
+                       if(pane._splitterWidget){
+                               childrenAndSplitters.push(pane._splitterWidget);
+                       }
+               });
 
-               // New margin-box size of each pane
+               // Compute the box in which to lay out my children
                var dim = {
-                       top:    { w: sidebarWidth, h: topHeight },
-                       bottom: { w: sidebarWidth, h: bottomHeight },
-                       left:   { w: leftWidth, h: sidebarHeight },
-                       right:  { w: rightWidth, h: sidebarHeight },
-                       center: { h: middleHeight, w: middleWidth }
+                       l: this.pe.l,
+                       t: this.pe.t,
+                       w: this._borderBox.w - this.pe.w,
+                       h: this._borderBox.h - this.pe.h
                };
 
-               if(changedRegion){
-                       // Respond to splitter drag event by changing changedRegion's width or height
-                       var child = this["_" + changedRegion + "Widget"],
-                               mb = {};
-                               mb[ /top|bottom/.test(changedRegion) ? "h" : "w"] = changedRegionSize;
-                       child.resize ? child.resize(mb, dim[child.region]) : dojo.marginBox(child.domNode, mb);
-               }
+               // Layout the children, possibly changing size due to a splitter drag
+               dijit.layout.layoutChildren(this.domNode, dim, childrenAndSplitters,
+                       changedChildId, changedChildSize);
+       },
 
-               // Nodes in IE<8 don't respond to t/l/b/r, and TEXTAREA doesn't respond in any browser
-               var janky = dojo.isIE < 8 || (dojo.isIE && dojo.isQuirks) || dojo.some(this.getChildren(), function(child){
-                       return child.domNode.tagName == "TEXTAREA" || child.domNode.tagName == "INPUT";
+       destroyRecursive: function(){
+               // Destroy splitters first, while getChildren() still works
+               dojo.forEach(this.getChildren(), function(child){
+                       var splitter = child._splitterWidget;
+                       if(splitter){
+                               splitter.destroy();
+                       }
+                       delete child._splitterWidget;
                });
-               if(janky){
-                       // Set the size of the children the old fashioned way, by setting
-                       // CSS width and height
-
-                       var resizeWidget = function(widget, changes, result){
-                               if(widget){
-                                       (widget.resize ? widget.resize(changes, result) : dojo.marginBox(widget.domNode, changes));
-                               }
-                       };
-
-                       if(leftSplitter){ leftSplitter.style.height = sidebarHeight; }
-                       if(rightSplitter){ rightSplitter.style.height = sidebarHeight; }
-                       resizeWidget(this._leftWidget, {h: sidebarHeight}, dim.left);
-                       resizeWidget(this._rightWidget, {h: sidebarHeight}, dim.right);
-
-                       if(topSplitter){ topSplitter.style.width = sidebarWidth; }
-                       if(bottomSplitter){ bottomSplitter.style.width = sidebarWidth; }
-                       resizeWidget(this._topWidget, {w: sidebarWidth}, dim.top);
-                       resizeWidget(this._bottomWidget, {w: sidebarWidth}, dim.bottom);
-
-                       resizeWidget(this._centerWidget, dim.center);
-               }else{
-                       // Calculate which panes need a notification that their size has been changed
-                       // (we've already set style.top/bottom/left/right on those other panes).
-                       var notifySides = !changedRegion || (/top|bottom/.test(changedRegion) && this.design != "sidebar"),
-                               notifyTopBottom = !changedRegion || (/left|right/.test(changedRegion) && this.design == "sidebar"),
-                               notifyList = {
-                                       center: true,
-                                       left: notifySides,
-                                       right: notifySides,
-                                       top: notifyTopBottom,
-                                       bottom: notifyTopBottom
-                               };
-                       
-                       // Send notification to those panes that have changed size
-                       dojo.forEach(this.getChildren(), function(child){
-                               if(child.resize && notifyList[child.region]){
-                                       child.resize(null, dim[child.region]);
-                               }
-                       }, this);
-               }
-       },
 
-       destroy: function(){
-               for(var region in this._splitters){
-                       var splitter = this._splitters[region];
-                       dijit.byNode(splitter).destroy();
-                       dojo.destroy(splitter);
-               }
-               delete this._splitters;
-               delete this._splitterThickness;
+               // Then destroy the real children, and myself
                this.inherited(arguments);
        }
 });
@@ -19261,6 +20051,12 @@ dojo.extend(dijit._Widget, {
        //              See the `dijit.layout.BorderContainer` description for details.
        region: '',
 
+       // layoutPriority: [const] Number
+       //              Parameter for children of `dijit.layout.BorderContainer`.
+       //              Children with a higher layoutPriority will be placed closer to the BorderContainer center,
+       //              between children with a lower layoutPriority.
+       layoutPriority: 0,
+
        // splitter: [const] Boolean
        //              Parameter for child of `dijit.layout.BorderContainer` where region != "center".
        //              If true, enables user to resize the widget by putting a draggable splitter between
@@ -19278,8 +20074,6 @@ dojo.extend(dijit._Widget, {
        maxSize: Infinity
 });
 
-
-
 dojo.declare("dijit.layout._Splitter", [ dijit._Widget, dijit._Templated ],
 {
        // summary:
@@ -19299,7 +20093,7 @@ dojo.declare("dijit.layout._Splitter", [ dijit._Widget, dijit._Templated ],
        //              Pointer to the pane associated with this splitter
        child: null,
 
-       // region: String
+       // region: [const] String
        //              Region of pane associated with this splitter.
        //              "top", "bottom", "left", "right".
        region: null,
@@ -19310,18 +20104,21 @@ dojo.declare("dijit.layout._Splitter", [ dijit._Widget, dijit._Templated ],
        //              otherwise, the size doesn't change until you drop the splitter (by mouse-up)
        live: true,
 
-       templateString: '<div class="dijitSplitter" dojoAttachEvent="onkeypress:_onKeyPress,onmousedown:_startDrag,onmouseenter:_onMouse,onmouseleave:_onMouse" tabIndex="0" waiRole="separator"><div class="dijitSplitterThumb"></div></div>',
+       templateString: '<div class="dijitSplitter" dojoAttachEvent="onkeypress:_onKeyPress,onmousedown:_startDrag,onmouseenter:_onMouse,onmouseleave:_onMouse" tabIndex="0" role="separator"><div class="dijitSplitterThumb"></div></div>',
 
-       postCreate: function(){
+       postMixInProperties: function(){
                this.inherited(arguments);
-               this.horizontal = /top|bottom/.test(this.region);
-               dojo.addClass(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V"));
-//             dojo.addClass(this.child.domNode, "dijitSplitterPane");
-//             dojo.setSelectable(this.domNode, false); //TODO is this necessary?
 
+               this.horizontal = /top|bottom/.test(this.region);
                this._factor = /top|left/.test(this.region) ? 1 : -1;
-
                this._cookieName = this.container.id + "_" + this.region;
+       },
+
+       buildRendering: function(){
+               this.inherited(arguments);
+
+               dojo.addClass(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V"));
+
                if(this.container.persist){
                        // restore old size
                        var persistSize = dojo.cookie(this._cookieName);
@@ -19333,23 +20130,14 @@ dojo.declare("dijit.layout._Splitter", [ dijit._Widget, dijit._Templated ],
 
        _computeMaxSize: function(){
                // summary:
-               //              Compute the maximum size that my corresponding pane can be set to
+               //              Return the maximum size that my corresponding pane can be set to
 
                var dim = this.horizontal ? 'h' : 'w',
-                       thickness = this.container._splitterThickness[this.region];
-                       
-               // Get DOMNode of opposite pane, if an opposite pane exists.
-               // Ex: if I am the _Splitter for the left pane, then get the right pane.
-               var flip = {left:'right', right:'left', top:'bottom', bottom:'top', leading:'trailing', trailing:'leading'},
-                       oppNode = this.container["_" + flip[this.region]];
-               
-               // I can expand up to the edge of the opposite pane, or if there's no opposite pane, then to
-               // edge of BorderContainer
-               var available = dojo.contentBox(this.container.domNode)[dim] -
-                               (oppNode ? dojo.marginBox(oppNode)[dim] : 0) -
-                               20 - thickness * 2;
+                       childSize = dojo.marginBox(this.child.domNode)[dim],
+                       center = dojo.filter(this.container.getChildren(), function(child){ return child.region == "center";})[0],
+                       spaceAvailable = dojo.marginBox(center.domNode)[dim];   // can expand until center is crushed to 0
 
-               return Math.min(this.child.maxSize, available);
+               return Math.min(this.child.maxSize, childSize + spaceAvailable);
        },
 
        _startDrag: function(e){
@@ -19368,28 +20156,26 @@ dojo.declare("dijit.layout._Splitter", [ dijit._Widget, dijit._Templated ],
                        dojo.addClass(this.domNode, "dijitSplitterShadow");
                        dojo.place(this.fake, this.domNode, "after");
                }
-               dojo.addClass(this.domNode, "dijitSplitterActive");
-               dojo.addClass(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V") + "Active");
+               dojo.addClass(this.domNode, "dijitSplitterActive dijitSplitter" + (this.horizontal ? "H" : "V") + "Active");
                if(this.fake){
-                       dojo.removeClass(this.fake, "dijitSplitterHover");
-                       dojo.removeClass(this.fake, "dijitSplitter" + (this.horizontal ? "H" : "V") + "Hover");
+                       dojo.removeClass(this.fake, "dijitSplitterHover dijitSplitter" + (this.horizontal ? "H" : "V") + "Hover");
                }
 
                //Performance: load data info local vars for onmousevent function closure
                var factor = this._factor,
-                       max = this._computeMaxSize(),
-                       min = this.child.minSize || 20,
                        isHorizontal = this.horizontal,
                        axis = isHorizontal ? "pageY" : "pageX",
                        pageStart = e[axis],
                        splitterStyle = this.domNode.style,
                        dim = isHorizontal ? 'h' : 'w',
                        childStart = dojo.marginBox(this.child.domNode)[dim],
+                       max = this._computeMaxSize(),
+                       min = this.child.minSize || 20,
                        region = this.region,
-                       splitterStart = parseInt(this.domNode.style[region], 10),
+                       splitterAttr = region == "top" || region == "bottom" ? "top" : "left",  // style attribute of splitter to adjust
+                       splitterStart = parseInt(splitterStyle[splitterAttr], 10),
                        resize = this._resize,
-                       childNode = this.child.domNode,
-                       layoutFunc = dojo.hitch(this.container, this.container._layoutChildren),
+                       layoutFunc = dojo.hitch(this.container, "_layoutChildren", this.child.id),
                        de = dojo.doc;
 
                this._handlers = (this._handlers || []).concat([
@@ -19399,9 +20185,10 @@ dojo.declare("dijit.layout._Splitter", [ dijit._Widget, dijit._Templated ],
                                        boundChildSize = Math.max(Math.min(childSize, max), min);
 
                                if(resize || forceResize){
-                                       layoutFunc(region, boundChildSize);
+                                       layoutFunc(boundChildSize);
                                }
-                               splitterStyle[region] = factor * delta + splitterStart + (boundChildSize - childSize) + "px";
+                               // TODO: setting style directly (usually) sets content box size, need to set margin box size
+                               splitterStyle[splitterAttr] = delta + splitterStart + factor*(boundChildSize - childSize) + "px";
                        }),
                        dojo.connect(de, "ondragstart", dojo.stopEvent),
                        dojo.connect(dojo.body(), "onselectstart", dojo.stopEvent),
@@ -19422,9 +20209,8 @@ dojo.declare("dijit.layout._Splitter", [ dijit._Widget, dijit._Templated ],
                                dojo.removeClass(this.cover, "dijitSplitterCoverActive");
                        }
                        if(this.fake){ dojo.destroy(this.fake); }
-                       dojo.removeClass(this.domNode, "dijitSplitterActive");
-                       dojo.removeClass(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V") + "Active");
-                       dojo.removeClass(this.domNode, "dijitSplitterShadow");
+                       dojo.removeClass(this.domNode, "dijitSplitterActive dijitSplitter"
+                               + (this.horizontal ? "H" : "V") + "Active dijitSplitterShadow");
                        this._drag(e); //TODO: redundant with onmousemove?
                        this._drag(e, true);
                }finally{
@@ -19458,8 +20244,8 @@ dojo.declare("dijit.layout._Splitter", [ dijit._Widget, dijit._Templated ],
 //                             this.inherited(arguments);
                                return;
                }
-               var childSize = dojo.marginBox(this.child.domNode)[ horizontal ? 'h' : 'w' ] + this._factor * tick;
-               this.container._layoutChildren(this.region, Math.max(Math.min(childSize, this._computeMaxSize()), this.child.minSize));
+               var childSize = dojo._getMarginSize(this.child.domNode)[ horizontal ? 'h' : 'w' ] + this._factor * tick;
+               this.container._layoutChildren(this.child.id, Math.max(Math.min(childSize, this._computeMaxSize()), this.child.minSize));
                dojo.stopEvent(e);
        },
 
@@ -19473,7 +20259,7 @@ dojo.declare("dijit.layout._Splitter", [ dijit._Widget, dijit._Templated ],
        }
 });
 
-dojo.declare("dijit.layout._Gutter", [dijit._Widget, dijit._Templated ],
+dojo.declare("dijit.layout._Gutter", [dijit._Widget, dijit._Templated],
 {
        // summary:
        //              Just a spacer div to separate side pane from center pane.
@@ -19484,10 +20270,15 @@ dojo.declare("dijit.layout._Gutter", [dijit._Widget, dijit._Templated ],
        // tags:
        //              private
 
-       templateString: '<div class="dijitGutter" waiRole="presentation"></div>',
+       templateString: '<div class="dijitGutter" role="presentation"></div>',
 
-       postCreate: function(){
+       postMixInProperties: function(){
+               this.inherited(arguments);
                this.horizontal = /top|bottom/.test(this.region);
+       },
+
+       buildRendering: function(){
+               this.inherited(arguments);
                dojo.addClass(this.domNode, "dijitGutter" + (this.horizontal ? "H" : "V"));
        }
 });
@@ -19519,12 +20310,12 @@ dojo.declare("dijit.layout._TabContainerBase",
 
        baseClass: "dijitTabContainer",
 
-       // tabStrip: Boolean
+       // tabStrip: [const] Boolean
        //              Defines whether the tablist gets an extra class for layouting, putting a border/shading
-       //              around the set of tabs.
+       //              around the set of tabs.   Not supported by claro theme.
        tabStrip: false,
 
-       // nested: Boolean
+       // nested: [const] Boolean
        //              If true, use styling for a TabContainer nested inside another TabContainer.
        //              For tundra etc., makes tabs look like links, and hides the outer
        //              border since the outer TabContainer already has a border.
@@ -19541,7 +20332,7 @@ dojo.declare("dijit.layout._TabContainerBase",
                this.inherited(arguments);
        },
 
-       postCreate: function(){
+       buildRendering: function(){
                this.inherited(arguments);
 
                // Create the tab list that will have a tab (a.k.a. tab button) for each tab panel
@@ -19608,7 +20399,12 @@ dojo.declare("dijit.layout._TabContainerBase",
                }else{
                        // just layout the tab controller, so it can position left/right buttons etc.
                        if(this.tablist.resize){
-                               this.tablist.resize({w: dojo.contentBox(this.domNode).w});
+                               //make the tabs zero width so that they don't interfere with width calc, then reset
+                               var s = this.tablist.domNode.style;
+                               s.width="0";
+                               var width = dojo.contentBox(this.domNode).w;
+                               s.width="";
+                               this.tablist.resize({w: width});
                        }
 
                        // and call resize() on the selected pane just to tell it that it's been made visible
@@ -19626,7 +20422,6 @@ dojo.declare("dijit.layout._TabContainerBase",
        }
 });
 
-
 }
 
 if(!dojo._hasResource["dijit.layout.TabController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
@@ -19635,10 +20430,10 @@ dojo.provide("dijit.layout.TabController");
 
 
 
-// Menu is used for an accessible close button, would be nice to have a lighter-weight solution
 
 
 
+// Menu is used for an accessible close button, would be nice to have a lighter-weight solution
 
 
 dojo.declare("dijit.layout.TabController",
@@ -19654,7 +20449,7 @@ dojo.declare("dijit.layout.TabController",
        // tags:
        //              private
 
-       templateString: "<div wairole='tablist' dojoAttachEvent='onkeypress:onkeypress'></div>",
+       templateString: "<div role='tablist' dojoAttachEvent='onkeypress:onkeypress'></div>",
 
        // tabPosition: String
        //              Defines where tabs go relative to the content.
@@ -19704,32 +20499,16 @@ dojo.declare("dijit.layout._TabButton",
                closeNode: "dijitTabCloseButton"
        },
 
-       templateString: dojo.cache("dijit.layout", "templates/_TabButton.html", "<div waiRole=\"presentation\" dojoAttachPoint=\"titleNode\" dojoAttachEvent='onclick:onClick'>\n    <div waiRole=\"presentation\" class='dijitTabInnerDiv' dojoAttachPoint='innerDiv'>\n        <div waiRole=\"presentation\" class='dijitTabContent' dojoAttachPoint='tabContent'>\n        \t<div waiRole=\"presentation\" dojoAttachPoint='focusNode'>\n\t\t        <img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" dojoAttachPoint='iconNode' />\n\t\t        <span dojoAttachPoint='containerNode' class='tabLabel'></span>\n\t\t        <span class=\"dijitInline dijitTabCloseButton dijitTabCloseIcon\" dojoAttachPoint='closeNode'\n\t\t        \t\tdojoAttachEvent='onclick: onClickCloseButton' waiRole=\"presentation\">\n\t\t            <span dojoAttachPoint='closeText' class='dijitTabCloseText'>x</span\n\t\t        ></span>\n\t\t\t</div>\n        </div>\n    </div>\n</div>\n"),
+       templateString: dojo.cache("dijit.layout", "templates/_TabButton.html", "<div role=\"presentation\" dojoAttachPoint=\"titleNode\" dojoAttachEvent='onclick:onClick'>\n    <div role=\"presentation\" class='dijitTabInnerDiv' dojoAttachPoint='innerDiv'>\n        <div role=\"presentation\" class='dijitTabContent' dojoAttachPoint='tabContent'>\n        \t<div role=\"presentation\" dojoAttachPoint='focusNode'>\n\t\t        <img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon dijitTabButtonIcon\" dojoAttachPoint='iconNode' />\n\t\t        <span dojoAttachPoint='containerNode' class='tabLabel'></span>\n\t\t        <span class=\"dijitInline dijitTabCloseButton dijitTabCloseIcon\" dojoAttachPoint='closeNode'\n\t\t        \t\tdojoAttachEvent='onclick: onClickCloseButton' role=\"presentation\">\n\t\t            <span dojoAttachPoint='closeText' class='dijitTabCloseText'>[x]</span\n\t\t        ></span>\n\t\t\t</div>\n        </div>\n    </div>\n</div>\n"),
 
        // Override _FormWidget.scrollOnFocus.
        // Don't scroll the whole tab container into view when the button is focused.
        scrollOnFocus: false,
 
-       postMixInProperties: function(){
-               // Override blank iconClass from Button to do tab height adjustment on IE6,
-               // to make sure that tabs with and w/out close icons are same height
-               if(!this.iconClass){
-                       this.iconClass = "dijitTabButtonIcon";
-               }
-       },
-
-       postCreate: function(){
+       buildRendering: function(){
                this.inherited(arguments);
-               dojo.setSelectable(this.containerNode, false);
 
-               // If a custom icon class has not been set for the
-               // tab icon, set its width to one pixel. This ensures
-               // that the height styling of the tab is maintained,
-               // as it is based on the height of the icon.
-               // TODO: I still think we can just set dijitTabButtonIcon to 1px in CSS <Bill>
-               if(this.iconNode.className == "dijitTabButtonIcon"){
-                       dojo.style(this.iconNode, "width", "1px");
-               }
+               dojo.setSelectable(this.containerNode, false);
        },
 
        startup: function(){
@@ -19743,8 +20522,10 @@ dojo.declare("dijit.layout._TabButton",
                }, 1);
        },
 
-       _setCloseButtonAttr: function(disp){
-               this.closeButton = disp;
+       _setCloseButtonAttr: function(/*Boolean*/ disp){
+               // summary:
+               //              Hide/show close button
+               this._set("closeButton", disp);
                dojo.toggleClass(this.innerDiv, "dijitClosable", disp);
                this.closeNode.style.display = disp ? "" : "none";
                if(disp){
@@ -19776,16 +20557,16 @@ dojo.declare("dijit.layout._TabButton",
        },
        _setLabelAttr: function(/*String*/ content){
                // summary:
-               //              Hook for attr('label', ...) to work.
+               //              Hook for set('label', ...) to work.
                // description:
                //              takes an HTML string.
-               //              Inherited ToggleButton implementation will Set the label (text) of the button; 
+               //              Inherited ToggleButton implementation will Set the label (text) of the button;
                //              Need to set the alt attribute of icon on tab buttons if no label displayed
-                       this.inherited(arguments);
-                       if(this.showLabel == false && !this.params.title){
-                               this.iconNode.alt = dojo.trim(this.containerNode.innerText || this.containerNode.textContent || '');
-                       }
-               },
+               this.inherited(arguments);
+               if(this.showLabel == false && !this.params.title){
+                       this.iconNode.alt = dojo.trim(this.containerNode.innerText || this.containerNode.textContent || '');
+               }
+       },
 
        destroy: function(){
                if(this._closeMenu){
@@ -19805,6 +20586,8 @@ dojo.provide("dijit.layout.ScrollingTabController");
 
 
 
+
+
 dojo.declare("dijit.layout.ScrollingTabController",
        dijit.layout.TabController,
        {
@@ -19816,9 +20599,9 @@ dojo.declare("dijit.layout.ScrollingTabController",
        // tags:
        //              private
 
-       templateString: dojo.cache("dijit.layout", "templates/ScrollingTabController.html", "<div class=\"dijitTabListContainer-${tabPosition}\" style=\"visibility:hidden\">\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_menuBtn\" iconClass=\"dijitTabStripMenuIcon\"\n\t\t\tdojoAttachPoint=\"_menuBtn\" showLabel=false>&#9660;</div>\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_leftBtn\" iconClass=\"dijitTabStripSlideLeftIcon\"\n\t\t\tdojoAttachPoint=\"_leftBtn\" dojoAttachEvent=\"onClick: doSlideLeft\" showLabel=false>&#9664;</div>\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_rightBtn\" iconClass=\"dijitTabStripSlideRightIcon\"\n\t\t\tdojoAttachPoint=\"_rightBtn\" dojoAttachEvent=\"onClick: doSlideRight\" showLabel=false>&#9654;</div>\n\t<div class='dijitTabListWrapper' dojoAttachPoint='tablistWrapper'>\n\t\t<div wairole='tablist' dojoAttachEvent='onkeypress:onkeypress'\n\t\t\t\tdojoAttachPoint='containerNode' class='nowrapTabStrip'></div>\n\t</div>\n</div>\n"),
+       templateString: dojo.cache("dijit.layout", "templates/ScrollingTabController.html", "<div class=\"dijitTabListContainer-${tabPosition}\" style=\"visibility:hidden\">\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerMenuButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_menuBtn\" containerId=\"${containerId}\" iconClass=\"dijitTabStripMenuIcon\"\n\t\t\tdropDownPosition=\"below-alt, above-alt\"\n\t\t\tdojoAttachPoint=\"_menuBtn\" showLabel=\"false\">&#9660;</div>\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_leftBtn\" iconClass=\"dijitTabStripSlideLeftIcon\"\n\t\t\tdojoAttachPoint=\"_leftBtn\" dojoAttachEvent=\"onClick: doSlideLeft\" showLabel=\"false\">&#9664;</div>\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_rightBtn\" iconClass=\"dijitTabStripSlideRightIcon\"\n\t\t\tdojoAttachPoint=\"_rightBtn\" dojoAttachEvent=\"onClick: doSlideRight\" showLabel=\"false\">&#9654;</div>\n\t<div class='dijitTabListWrapper' dojoAttachPoint='tablistWrapper'>\n\t\t<div role='tablist' dojoAttachEvent='onkeypress:onkeypress'\n\t\t\t\tdojoAttachPoint='containerNode' class='nowrapTabStrip'></div>\n\t</div>\n</div>\n"),
 
-       // useMenu:[const] Boolean
+       // useMenu: [const] Boolean
        //              True if a menu should be used to select tabs when they are too
        //              wide to fit the TabContainer, false otherwise.
        useMenu: true,
@@ -19828,7 +20611,7 @@ dojo.declare("dijit.layout.ScrollingTabController",
        //              wide to fit the TabContainer, false otherwise.
        useSlider: true,
 
-       // tabStripClass: String
+       // tabStripClass: [const] String
        //              The css class to apply to the tab strip, if it is visible.
        tabStripClass: "",
 
@@ -19844,7 +20627,7 @@ dojo.declare("dijit.layout.ScrollingTabController",
                "class": "containerNode"
        }),
 
-       postCreate: function(){
+       buildRendering: function(){
                this.inherited(arguments);
                var n = this.domNode;
 
@@ -19874,41 +20657,18 @@ dojo.declare("dijit.layout.ScrollingTabController",
 
        onAddChild: function(page, insertIndex){
                this.inherited(arguments);
-               var menuItem;
-               if(this.useMenu){
-                       var containerId = this.containerId;
-                       menuItem = new dijit.MenuItem({
-                               id: page.id + "_stcMi",
-                               label: page.title,
-                               dir: page.dir,
-                               lang: page.lang,
-                               onClick: dojo.hitch(this, function(){
-                                       var container = dijit.byId(containerId);
-                                       container.selectChild(page);
-                               })
-                       });
-                       this._menuChildren[page.id] = menuItem;
-                       this._menu.addChild(menuItem, insertIndex);
-               }
 
-               // update the menuItem label when the button label is updated
-               this.pane2handles[page.id].push(
-                       this.connect(this.pane2button[page.id], "set", function(name, value){
-                               if(this._postStartup){
-                                       if(name == "label"){
-                                               if(menuItem){
-                                                       menuItem.set(name, value);
-                                               }
-       
-                                               // The changed label will have changed the width of the
-                                               // buttons, so do a resize
-                                               if(this._dim){
-                                                       this.resize(this._dim);
-                                               }
+               // changes to the tab button label or iconClass will have changed the width of the
+               // buttons, so do a resize
+               dojo.forEach(["label", "iconClass"], function(attr){
+                       this.pane2watches[page.id].push(
+                               this.pane2button[page.id].watch(attr, dojo.hitch(this, function(name, oldValue, newValue){
+                                       if(this._postStartup && this._dim){
+                                               this.resize(this._dim);
                                        }
-                               }
-                       })
-               );
+                               }))
+                       );
+               }, this);
 
                // Increment the width of the wrapper when a tab is added
                // This makes sure that the buttons never wrap.
@@ -19925,13 +20685,6 @@ dojo.declare("dijit.layout.ScrollingTabController",
                        this._selectedTab = null;
                }
 
-               // delete menu entry corresponding to pane that was removed from TabContainer
-               if(this.useMenu && page && page.id && this._menuChildren[page.id]){
-                       this._menu.removeChild(this._menuChildren[page.id]);
-                       this._menuChildren[page.id].destroy();
-                       delete this._menuChildren[page.id];
-               }
-
                this.inherited(arguments);
        },
 
@@ -19939,7 +20692,6 @@ dojo.declare("dijit.layout.ScrollingTabController",
                // summary:
                //              Creates the buttons used to scroll to view tabs that
                //              may not be visible if the TabContainer is too narrow.
-               this._menuChildren = {};
 
                // Make a list of the buttons to display when the tab labels become
                // wider than the TabContainer, and hide the other buttons.
@@ -19948,26 +20700,13 @@ dojo.declare("dijit.layout.ScrollingTabController",
                this._buttons = dojo.query("> .tabStripButton", this.domNode).filter(function(btn){
                        if((this.useMenu && btn == this._menuBtn.domNode) ||
                                (this.useSlider && (btn == this._rightBtn.domNode || btn == this._leftBtn.domNode))){
-                               this._btnWidth += dojo.marginBox(btn).w;
+                               this._btnWidth += dojo._getMarginSize(btn).w;
                                return true;
                        }else{
                                dojo.style(btn, "display", "none");
                                return false;
                        }
                }, this);
-
-               if(this.useMenu){
-                       // Create the menu that is used to select tabs.
-                       this._menu = new dijit.Menu({
-                               id: this.id + "_menu",
-                               dir: this.dir,
-                               lang: this.lang,
-                               targetNodeIds: [this._menuBtn.domNode],
-                               leftClickToOpen: true,
-                               refocus: false  // selecting a menu item sets focus to a TabButton
-                       });
-                       this._supportingWidgets.push(this._menu);
-               }
        },
 
        _getTabsWidth: function(){
@@ -20037,6 +20776,10 @@ dojo.declare("dijit.layout.ScrollingTabController",
                this._setButtonClass(this._getScroll());
                
                this._postResize = true;
+
+               // Return my size so layoutChildren() can use it.
+               // Also avoids IE9 layout glitch on browser resize when scroll buttons present
+               return {h: this._contentBox.h, w: dim.w};
        },
 
        _getScroll: function(){
@@ -20139,7 +20882,7 @@ dojo.declare("dijit.layout.ScrollingTabController",
                return pos;
        },
 
-       createSmoothScroll : function(x){
+       createSmoothScroll: function(x){
                // summary:
                //              Creates a dojo._Animation object that smoothly scrolls the tab list
                //              either to a fixed horizontal pixel value, or to the selected tab.
@@ -20185,7 +20928,7 @@ dojo.declare("dijit.layout.ScrollingTabController",
                return anim; // dojo._Animation
        },
 
-       _getBtnNode: function(e){
+       _getBtnNode: function(/*Event*/ e){
                // summary:
                //              Gets a button DOM node from a mouse click event.
                // e:
@@ -20197,7 +20940,7 @@ dojo.declare("dijit.layout.ScrollingTabController",
                return n;
        },
 
-       doSlideRight: function(e){
+       doSlideRight: function(/*Event*/ e){
                // summary:
                //              Scrolls the menu to the right.
                // e:
@@ -20205,7 +20948,7 @@ dojo.declare("dijit.layout.ScrollingTabController",
                this.doSlide(1, this._getBtnNode(e));
        },
 
-       doSlideLeft: function(e){
+       doSlideLeft: function(/*Event*/ e){
                // summary:
                //              Scrolls the menu to the left.
                // e:
@@ -20213,7 +20956,7 @@ dojo.declare("dijit.layout.ScrollingTabController",
                this.doSlide(-1,this._getBtnNode(e));
        },
 
-       doSlide: function(direction, node){
+       doSlide: function(/*Number*/ direction, /*DomNode*/ node){
                // summary:
                //              Scrolls the tab list to the left or right by 75% of the widget width.
                // direction:
@@ -20232,7 +20975,7 @@ dojo.declare("dijit.layout.ScrollingTabController",
                this.createSmoothScroll(to).play();
        },
 
-       _setButtonClass: function(scroll){
+       _setButtonClass: function(/*Number*/ scroll){
                // summary:
                //              Disables the left scroll button if the tabs are scrolled all the way to the left,
                //              or the right scroll button in the opposite case.
@@ -20245,18 +20988,71 @@ dojo.declare("dijit.layout.ScrollingTabController",
        }
 });
 
-dojo.declare("dijit.layout._ScrollingTabControllerButton",
-       dijit.form.Button,
-       {
-               baseClass: "dijitTab tabStripButton",
 
-               templateString: dojo.cache("dijit.layout", "templates/_ScrollingTabControllerButton.html", "<div dojoAttachEvent=\"onclick:_onButtonClick\">\n\t<div waiRole=\"presentation\" class=\"dijitTabInnerDiv\" dojoattachpoint=\"innerDiv,focusNode\">\n\t\t<div waiRole=\"presentation\" class=\"dijitTabContent dijitButtonContents\" dojoattachpoint=\"tabContent\">\n\t\t\t<img waiRole=\"presentation\" alt=\"\" src=\"${_blankGif}\" class=\"dijitTabStripIcon\" dojoAttachPoint=\"iconNode\"/>\n\t\t\t<span dojoAttachPoint=\"containerNode,titleNode\" class=\"dijitButtonText\"></span>\n\t\t</div>\n\t</div>\n</div>\n"),
+dojo.declare("dijit.layout._ScrollingTabControllerButtonMixin", null, {
+       baseClass: "dijitTab tabStripButton",
+
+       templateString: dojo.cache("dijit.layout", "templates/_ScrollingTabControllerButton.html", "<div dojoAttachEvent=\"onclick:_onButtonClick\">\n\t<div role=\"presentation\" class=\"dijitTabInnerDiv\" dojoattachpoint=\"innerDiv,focusNode\">\n\t\t<div role=\"presentation\" class=\"dijitTabContent dijitButtonContents\" dojoattachpoint=\"tabContent\">\n\t\t\t<img role=\"presentation\" alt=\"\" src=\"${_blankGif}\" class=\"dijitTabStripIcon\" dojoAttachPoint=\"iconNode\"/>\n\t\t\t<span dojoAttachPoint=\"containerNode,titleNode\" class=\"dijitButtonText\"></span>\n\t\t</div>\n\t</div>\n</div>\n"),
 
                // Override inherited tabIndex: 0 from dijit.form.Button, because user shouldn't be
                // able to tab to the left/right/menu buttons
-               tabIndex: "-1"
+       tabIndex: "",
+
+       // Similarly, override FormWidget.isFocusable() because clicking a button shouldn't focus it
+       // either (this override avoids focus() call in FormWidget.js)
+       isFocusable: function(){ return false; }
+});
+
+dojo.declare("dijit.layout._ScrollingTabControllerButton",
+       [dijit.form.Button, dijit.layout._ScrollingTabControllerButtonMixin]);
+
+dojo.declare(
+       "dijit.layout._ScrollingTabControllerMenuButton",
+       [dijit.form.Button, dijit._HasDropDown, dijit.layout._ScrollingTabControllerButtonMixin],
+{
+       // id of the TabContainer itself
+       containerId: "",
+
+       // -1 so user can't tab into the button, but so that button can still be focused programatically.
+       // Because need to move focus to the button (or somewhere) before the menu is hidden or IE6 will crash.
+       tabIndex: "-1",
+
+       isLoaded: function(){
+               // recreate menu every time, in case the TabContainer's list of children (or their icons/labels) have changed
+               return false;
+       },
+
+       loadDropDown: function(callback){
+               this.dropDown = new dijit.Menu({
+                       id: this.containerId + "_menu",
+                       dir: this.dir,
+                       lang: this.lang
+               });
+               var container = dijit.byId(this.containerId);
+               dojo.forEach(container.getChildren(), function(page){
+                       var menuItem = new dijit.MenuItem({
+                               id: page.id + "_stcMi",
+                               label: page.title,
+                               iconClass: page.iconClass,
+                               dir: page.dir,
+                               lang: page.lang,
+                               onClick: function(){
+                                       container.selectChild(page);
+                               }
+                       });
+                       this.dropDown.addChild(menuItem);
+               }, this);
+               callback();
+       },
+
+       closeDropDown: function(/*Boolean*/ focus){
+               this.inherited(arguments);
+               if(this.dropDown){
+                       this.dropDown.destroyRecursive();
+                       delete this.dropDown;
+               }
        }
-);
+});
 
 }
 
@@ -20328,7 +21124,6 @@ dojo.declare("dijit.layout.TabContainer",
                }
 });
 
-
 }
 
 if(!dojo._hasResource["dojo.number"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
@@ -20339,7 +21134,7 @@ dojo.provide("dojo.number");
 
 
 
-
+dojo.getObject("number", true, dojo);
 
 /*=====
 dojo.number = {
@@ -20444,7 +21239,7 @@ dojo.number._applyPattern = function(/*Number*/value, /*String*/pattern, /*dojo.
        if(options.fractional === false){ options.places = 0; }
        return pattern.replace(numberPatternRE,
                dojo.number._formatAbsolute(value, numberPattern[0], {decimal: decimal, group: group, places: options.places, round: options.round}));
-}
+};
 
 dojo.number.round = function(/*Number*/value, /*Number?*/places, /*Number?*/increment){
        //      summary:
@@ -20470,7 +21265,7 @@ dojo.number.round = function(/*Number*/value, /*Number?*/places, /*Number?*/incr
        //              10.75
        var factor = 10 / (increment || 10);
        return (factor * +value).toFixed(places) / factor; // Number
-}
+};
 
 if((0.9).toFixed() == 0){
        // (isIE) toFixed() bug workaround: Rounding fails on IE when most significant digit
@@ -20483,7 +21278,7 @@ if((0.9).toFixed() == 0){
                                d = 0;
                        }
                        return round(v, p, m) + (v > 0 ? d : -d);
-               }
+               };
        })();
 }
 
@@ -20506,7 +21301,7 @@ dojo.number.__FormatAbsoluteOptions = function(){
 =====*/
 
 dojo.number._formatAbsolute = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatAbsoluteOptions?*/options){
-       // summary: 
+       // summary:
        //              Apply numeric pattern to absolute value using options. Gives no
        //              consideration to local customs.
        // value:
@@ -20621,7 +21416,7 @@ dojo.number.regexp = function(/*dojo.number.__RegexpOptions?*/options){
        //              Returns regular expression with positive and negative match, group
        //              and decimal separators
        return dojo.number._parseInfo(options).regexp; // String
-}
+};
 
 dojo.number._parseInfo = function(/*Object?*/options){
        options = options || {};
@@ -20709,7 +21504,7 @@ dojo.number._parseInfo = function(/*Object?*/options){
 
        // normalize whitespace and return
        return {regexp: re.replace(/[\xa0 ]/g, "[\\s\\xa0]"), group: group, decimal: decimal, factor: factor}; // Object
-}
+};
 
 /*=====
 dojo.number.__ParseOptions = function(){
@@ -20820,10 +21615,10 @@ dojo.number._realNumberRegexp = function(/*dojo.number.__RealNumberRegexpFlags?*
                        var re = "";
                        if(q && (flags.places!==0)){
                                re = "\\" + flags.decimal;
-                               if(flags.places == Infinity){ 
-                                       re = "(?:" + re + "\\d+)?"; 
+                               if(flags.places == Infinity){
+                                       re = "(?:" + re + "\\d+)?";
                                }else{
-                                       re += "\\d{" + flags.places + "}"; 
+                                       re += "\\d{" + flags.places + "}";
                                }
                        }
                        return re;
@@ -20832,3403 +21627,3569 @@ dojo.number._realNumberRegexp = function(/*dojo.number.__RealNumberRegexpFlags?*
        );
 
        var exponentRE = dojo.regexp.buildGroupRE(flags.exponent,
-               function(q){ 
+               function(q){
                        if(q){ return "([eE]" + dojo.number._integerRegexp({ signed: flags.eSigned}) + ")"; }
-                       return ""; 
+                       return "";
                }
        );
 
-       var realRE = integerRE + decimalRE;
-       // allow for decimals without integers, e.g. .25
-       if(decimalRE){realRE = "(?:(?:"+ realRE + ")|(?:" + decimalRE + "))";}
-       return realRE + exponentRE; // String
-};
+       var realRE = integerRE + decimalRE;
+       // allow for decimals without integers, e.g. .25
+       if(decimalRE){realRE = "(?:(?:"+ realRE + ")|(?:" + decimalRE + "))";}
+       return realRE + exponentRE; // String
+};
+
+/*=====
+dojo.number.__IntegerRegexpFlags = function(){
+       //      signed: Boolean?
+       //              The leading plus-or-minus sign. Can be true, false, or `[true,false]`.
+       //              Default is `[true, false]`, (i.e. will match if it is signed
+       //              or unsigned).
+       //      separator: String?
+       //              The character used as the thousands separator. Default is no
+       //              separator. For more than one symbol use an array, e.g. `[",", ""]`,
+       //              makes ',' optional.
+       //      groupSize: Number?
+       //              group size between separators
+       //      groupSize2: Number?
+       //              second grouping, where separators 2..n have a different interval than the first separator (for India)
+       this.signed = signed;
+       this.separator = separator;
+       this.groupSize = groupSize;
+       this.groupSize2 = groupSize2;
+}
+=====*/
+
+dojo.number._integerRegexp = function(/*dojo.number.__IntegerRegexpFlags?*/flags){
+       // summary:
+       //              Builds a regular expression that matches an integer
+
+       // assign default values to missing parameters
+       flags = flags || {};
+       if(!("signed" in flags)){ flags.signed = [true, false]; }
+       if(!("separator" in flags)){
+               flags.separator = "";
+       }else if(!("groupSize" in flags)){
+               flags.groupSize = 3;
+       }
+
+       var signRE = dojo.regexp.buildGroupRE(flags.signed,
+               function(q){ return q ? "[-+]" : ""; },
+               true
+       );
+
+       var numberRE = dojo.regexp.buildGroupRE(flags.separator,
+               function(sep){
+                       if(!sep){
+                               return "(?:\\d+)";
+                       }
+
+                       sep = dojo.regexp.escapeString(sep);
+                       if(sep == " "){ sep = "\\s"; }
+                       else if(sep == "\xa0"){ sep = "\\s\\xa0"; }
+
+                       var grp = flags.groupSize, grp2 = flags.groupSize2;
+                       //TODO: should we continue to enforce that numbers with separators begin with 1-9?  See #6933
+                       if(grp2){
+                               var grp2RE = "(?:0|[1-9]\\d{0," + (grp2-1) + "}(?:[" + sep + "]\\d{" + grp2 + "})*[" + sep + "]\\d{" + grp + "})";
+                               return ((grp-grp2) > 0) ? "(?:" + grp2RE + "|(?:0|[1-9]\\d{0," + (grp-1) + "}))" : grp2RE;
+                       }
+                       return "(?:0|[1-9]\\d{0," + (grp-1) + "}(?:[" + sep + "]\\d{" + grp + "})*)";
+               },
+               true
+       );
+
+       return signRE + numberRE; // String
+};
+
+}
+
+if(!dojo._hasResource["dijit.ProgressBar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.ProgressBar"] = true;
+dojo.provide("dijit.ProgressBar");
+
+
+
+
+
+
+dojo.declare("dijit.ProgressBar", [dijit._Widget, dijit._Templated], {
+       // summary:
+       //              A progress indication widget, showing the amount completed
+       //              (often the percentage completed) of a task.
+       //
+       // example:
+       // |    <div dojoType="ProgressBar"
+       // |             places="0"
+       // |             value="..." maximum="...">
+       // |    </div>
+
+       // progress: [const] String (Percentage or Number)
+       //              Number or percentage indicating amount of task completed.
+       //              Deprecated.   Use "value" instead.
+       progress: "0",
+
+       // value: String (Percentage or Number)
+       //              Number or percentage indicating amount of task completed.
+       //              With "%": percentage value, 0% <= progress <= 100%, or
+       //              without "%": absolute value, 0 <= progress <= maximum.
+       //              Infinity means that the progress bar is indeterminate.
+       value: "",
+
+       // maximum: [const] Float
+       //              Max sample number
+       maximum: 100,
+
+       // places: [const] Number
+       //              Number of places to show in values; 0 by default
+       places: 0,
+
+       // indeterminate: [const] Boolean
+       //              If false: show progress value (number or percentage).
+       //              If true: show that a process is underway but that the amount completed is unknown.
+       //              Deprecated.   Use "value" instead.
+       indeterminate: false,
+
+       // label: String?
+       //              Label on progress bar.   Defaults to percentage for determinate progress bar and
+       //              blank for indeterminate progress bar.
+       label:"",
+
+       // name: String
+       //              this is the field name (for a form) if set. This needs to be set if you want to use
+       //              this widget in a dijit.form.Form widget (such as dijit.Dialog)
+       name: '',
+
+       templateString: dojo.cache("dijit", "templates/ProgressBar.html", "<div class=\"dijitProgressBar dijitProgressBarEmpty\" role=\"progressbar\"\n\t><div  dojoAttachPoint=\"internalProgress\" class=\"dijitProgressBarFull\"\n\t\t><div class=\"dijitProgressBarTile\" role=\"presentation\"></div\n\t\t><span style=\"visibility:hidden\">&nbsp;</span\n\t></div\n\t><div dojoAttachPoint=\"labelNode\" class=\"dijitProgressBarLabel\" id=\"${id}_label\"></div\n\t><img dojoAttachPoint=\"indeterminateHighContrastImage\" class=\"dijitProgressBarIndeterminateHighContrastImage\" alt=\"\"\n/></div>\n"),
+
+       // _indeterminateHighContrastImagePath: [private] dojo._URL
+       //              URL to image to use for indeterminate progress bar when display is in high contrast mode
+       _indeterminateHighContrastImagePath:
+               dojo.moduleUrl("dijit", "themes/a11y/indeterminate_progress.gif"),
+
+       postMixInProperties: function(){
+               this.inherited(arguments);
+               if(!("value" in this.params)){
+                       this.value = this.indeterminate ? Infinity : this.progress;
+               }
+       },
+
+       buildRendering: function(){
+               this.inherited(arguments);
+               this.indeterminateHighContrastImage.setAttribute("src",
+                       this._indeterminateHighContrastImagePath.toString());
+               this.update();
+       },
+
+       update: function(/*Object?*/attributes){
+               // summary:
+               //              Internal method to change attributes of ProgressBar, similar to set(hash).  Users should call
+               //              set("value", ...) rather than calling this method directly.
+               // attributes:
+               //              May provide progress and/or maximum properties on this parameter;
+               //              see attribute specs for details.
+               // example:
+               //      |       myProgressBar.update({'indeterminate': true});
+               //      |       myProgressBar.update({'progress': 80});
+               //      |       myProgressBar.update({'indeterminate': true, label:"Loading ..." })
+               // tags:
+               //              private
+
+               // TODO: deprecate this method and use set() instead
+
+               dojo.mixin(this, attributes || {});
+               var tip = this.internalProgress, ap = this.domNode;
+               var percent = 1;
+               if(this.indeterminate){
+                       dijit.removeWaiState(ap, "valuenow");
+                       dijit.removeWaiState(ap, "valuemin");
+                       dijit.removeWaiState(ap, "valuemax");
+               }else{
+                       if(String(this.progress).indexOf("%") != -1){
+                               percent = Math.min(parseFloat(this.progress)/100, 1);
+                               this.progress = percent * this.maximum;
+                       }else{
+                               this.progress = Math.min(this.progress, this.maximum);
+                               percent = this.progress / this.maximum;
+                       }
+
+                       dijit.setWaiState(ap, "describedby", this.labelNode.id);
+                       dijit.setWaiState(ap, "valuenow", this.progress);
+                       dijit.setWaiState(ap, "valuemin", 0);
+                       dijit.setWaiState(ap, "valuemax", this.maximum);
+               }
+               this.labelNode.innerHTML = this.report(percent);
+
+               dojo.toggleClass(this.domNode, "dijitProgressBarIndeterminate", this.indeterminate);
+               tip.style.width = (percent * 100) + "%";
+               this.onChange();
+       },
+
+       _setValueAttr: function(v){
+               this._set("value", v);
+               if(v == Infinity){
+                       this.update({indeterminate:true});
+               }else{
+                       this.update({indeterminate:false, progress:v});
+               }
+       },
+
+       _setLabelAttr: function(label){
+               this._set("label", label);
+               this.update();
+       },
+
+       _setIndeterminateAttr: function(indeterminate){
+               // Deprecated, use set("value", ...) instead
+               this.indeterminate = indeterminate;
+               this.update();
+       },
+
+       report: function(/*float*/percent){
+               // summary:
+               //              Generates message to show inside progress bar (normally indicating amount of task completed).
+               //              May be overridden.
+               // tags:
+               //              extension
+
+               return this.label ? this.label :
+                               (this.indeterminate ? "&nbsp;" : dojo.number.format(percent, { type: "percent", places: this.places, locale: this.lang }));
+       },
+
+       onChange: function(){
+               // summary:
+               //              Callback fired when progress updates.
+               // tags:
+               //              extension
+       }
+});
+
+}
+
+if(!dojo._hasResource["dijit.ToolbarSeparator"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.ToolbarSeparator"] = true;
+dojo.provide("dijit.ToolbarSeparator");
+
+
+
+
+dojo.declare("dijit.ToolbarSeparator",
+               [ dijit._Widget, dijit._Templated ],
+               {
+               // summary:
+               //              A spacer between two `dijit.Toolbar` items
+               templateString: '<div class="dijitToolbarSeparator dijitInline" role="presentation"></div>',
+               buildRendering: function(){
+                       this.inherited(arguments);
+                       dojo.setSelectable(this.domNode, false);
+               },
+               isFocusable: function(){
+                       // summary:
+                       //              This widget isn't focusable, so pass along that fact.
+                       // tags:
+                       //              protected
+                       return false;
+               }
+
+       });
+
+}
+
+if(!dojo._hasResource["dijit.Toolbar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.Toolbar"] = true;
+dojo.provide("dijit.Toolbar");
+
+
+
+
+
+
+// Note: require of ToolbarSeparator is for back-compat, remove for 2.0
+
+dojo.declare("dijit.Toolbar",
+       [dijit._Widget, dijit._Templated, dijit._KeyNavContainer],
+       {
+       // summary:
+       //              A Toolbar widget, used to hold things like `dijit.Editor` buttons
+
+       templateString:
+               '<div class="dijit" role="toolbar" tabIndex="${tabIndex}" dojoAttachPoint="containerNode">' +
+               //      '<table style="table-layout: fixed" class="dijitReset dijitToolbarTable">' + // factor out style
+               //              '<tr class="dijitReset" dojoAttachPoint="containerNode"></tr>'+
+               //      '</table>' +
+               '</div>',
+
+       baseClass: "dijitToolbar",
 
-/*=====
-dojo.number.__IntegerRegexpFlags = function(){
-       //      signed: Boolean?
-       //              The leading plus-or-minus sign. Can be true, false, or `[true,false]`.
-       //              Default is `[true, false]`, (i.e. will match if it is signed
-       //              or unsigned).
-       //      separator: String?
-       //              The character used as the thousands separator. Default is no
-       //              separator. For more than one symbol use an array, e.g. `[",", ""]`,
-       //              makes ',' optional.
-       //      groupSize: Number?
-       //              group size between separators
-       //      groupSize2: Number?
-       //              second grouping, where separators 2..n have a different interval than the first separator (for India)
-       this.signed = signed;
-       this.separator = separator;
-       this.groupSize = groupSize;
-       this.groupSize2 = groupSize2;
-}
-=====*/
+       postCreate: function(){
+               this.inherited(arguments);
 
-dojo.number._integerRegexp = function(/*dojo.number.__IntegerRegexpFlags?*/flags){
-       // summary: 
-       //              Builds a regular expression that matches an integer
+               this.connectKeyNavHandlers(
+                       this.isLeftToRight() ? [dojo.keys.LEFT_ARROW] : [dojo.keys.RIGHT_ARROW],
+                       this.isLeftToRight() ? [dojo.keys.RIGHT_ARROW] : [dojo.keys.LEFT_ARROW]
+               );
+       },
 
-       // assign default values to missing parameters
-       flags = flags || {};
-       if(!("signed" in flags)){ flags.signed = [true, false]; }
-       if(!("separator" in flags)){
-               flags.separator = "";
-       }else if(!("groupSize" in flags)){
-               flags.groupSize = 3;
+       startup: function(){
+               if(this._started){ return; }
+
+               this.startupKeyNavChildren();
+
+               this.inherited(arguments);
        }
+}
+);
 
-       var signRE = dojo.regexp.buildGroupRE(flags.signed,
-               function(q){ return q ? "[-+]" : ""; },
-               true
-       );
+}
 
-       var numberRE = dojo.regexp.buildGroupRE(flags.separator,
-               function(sep){
-                       if(!sep){
-                               return "(?:\\d+)";
-                       }
+if(!dojo._hasResource["dojo.DeferredList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.DeferredList"] = true;
+dojo.provide("dojo.DeferredList");
 
-                       sep = dojo.regexp.escapeString(sep);
-                       if(sep == " "){ sep = "\\s"; }
-                       else if(sep == "\xa0"){ sep = "\\s\\xa0"; }
 
-                       var grp = flags.groupSize, grp2 = flags.groupSize2;
-                       //TODO: should we continue to enforce that numbers with separators begin with 1-9?  See #6933
-                       if(grp2){
-                               var grp2RE = "(?:0|[1-9]\\d{0," + (grp2-1) + "}(?:[" + sep + "]\\d{" + grp2 + "})*[" + sep + "]\\d{" + grp + "})";
-                               return ((grp-grp2) > 0) ? "(?:" + grp2RE + "|(?:0|[1-9]\\d{0," + (grp-1) + "}))" : grp2RE;
+dojo.DeferredList = function(/*Array*/ list, /*Boolean?*/ fireOnOneCallback, /*Boolean?*/ fireOnOneErrback, /*Boolean?*/ consumeErrors, /*Function?*/ canceller){
+       // summary:
+       //              Provides event handling for a group of Deferred objects.
+       // description:
+       //              DeferredList takes an array of existing deferreds and returns a new deferred of its own
+       //              this new deferred will typically have its callback fired when all of the deferreds in
+       //              the given list have fired their own deferreds.  The parameters `fireOnOneCallback` and
+       //              fireOnOneErrback, will fire before all the deferreds as appropriate
+       //
+       //      list:
+       //              The list of deferreds to be synchronizied with this DeferredList
+       //      fireOnOneCallback:
+       //              Will cause the DeferredLists callback to be fired as soon as any
+       //              of the deferreds in its list have been fired instead of waiting until
+       //              the entire list has finished
+       //      fireonOneErrback:
+       //              Will cause the errback to fire upon any of the deferreds errback
+       //      canceller:
+       //              A deferred canceller function, see dojo.Deferred
+       var resultList = [];
+       dojo.Deferred.call(this);
+       var self = this;
+       if(list.length === 0 && !fireOnOneCallback){
+               this.resolve([0, []]);
+       }
+       var finished = 0;
+       dojo.forEach(list, function(item, i){
+               item.then(function(result){
+                       if(fireOnOneCallback){
+                               self.resolve([i, result]);
+                       }else{
+                               addResult(true, result);
                        }
-                       return "(?:0|[1-9]\\d{0," + (grp-1) + "}(?:[" + sep + "]\\d{" + grp + "})*)";
-               },
-               true
-       );
+               },function(error){
+                       if(fireOnOneErrback){
+                               self.reject(error);
+                       }else{
+                               addResult(false, error);
+                       }
+                       if(consumeErrors){
+                               return null;
+                       }
+                       throw error;
+               });
+               function addResult(succeeded, result){
+                       resultList[i] = [succeeded, result];
+                       finished++;
+                       if(finished === list.length){
+                               self.resolve(resultList);
+                       }
+                       
+               }
+       });
+};
+dojo.DeferredList.prototype = new dojo.Deferred();
 
-       return signRE + numberRE; // String
-}
+dojo.DeferredList.prototype.gatherResults= function(deferredList){
+       // summary:
+       //      Gathers the results of the deferreds for packaging
+       //      as the parameters to the Deferred Lists' callback
 
-}
+       var d = new dojo.DeferredList(deferredList, false, true, false);
+       d.addCallback(function(results){
+               var ret = [];
+               dojo.forEach(results, function(result){
+                       ret.push(result[1]);
+               });
+               return ret;
+       });
+       return d;
+};
 
-if(!dojo._hasResource["dijit.ProgressBar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dijit.ProgressBar"] = true;
-dojo.provide("dijit.ProgressBar");
+}
 
+if(!dojo._hasResource["dijit.tree.TreeStoreModel"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.tree.TreeStoreModel"] = true;
+dojo.provide("dijit.tree.TreeStoreModel");
 
 
+dojo.declare(
+               "dijit.tree.TreeStoreModel",
+               null,
+       {
+               // summary:
+               //              Implements dijit.Tree.model connecting to a store with a single
+               //              root item.  Any methods passed into the constructor will override
+               //              the ones defined here.
 
+               // store: dojo.data.Store
+               //              Underlying store
+               store: null,
 
+               // childrenAttrs: String[]
+               //              One or more attribute names (attributes in the dojo.data item) that specify that item's children
+               childrenAttrs: ["children"],
 
+               // newItemIdAttr: String
+               //              Name of attribute in the Object passed to newItem() that specifies the id.
+               //
+               //              If newItemIdAttr is set then it's used when newItem() is called to see if an
+               //              item with the same id already exists, and if so just links to the old item
+               //              (so that the old item ends up with two parents).
+               //
+               //              Setting this to null or "" will make every drop create a new item.
+               newItemIdAttr: "id",
 
-dojo.declare("dijit.ProgressBar", [dijit._Widget, dijit._Templated], {
-       // summary:
-       //              A progress indication widget, showing the amount completed
-       //              (often the percentage completed) of a task.
-       //
-       // example:
-       // |    <div dojoType="ProgressBar"
-       // |             places="0"
-       // |             progress="..." maximum="...">
-       // |    </div>
-       //
-       // description:
-       //              Note that the progress bar is updated via (a non-standard)
-       //              update() method, rather than via attr() like other widgets.
+               // labelAttr: String
+               //              If specified, get label for tree node from this attribute, rather
+               //              than by calling store.getLabel()
+               labelAttr: "",
 
-       // progress: [const] String (Percentage or Number)
-       //              Number or percentage indicating amount of task completed.
-       //              With "%": percentage value, 0% <= progress <= 100%, or
-       //              without "%": absolute value, 0 <= progress <= maximum
-       // TODO: rename to value for 2.0
-       progress: "0",
+               // root: [readonly] dojo.data.Item
+               //              Pointer to the root item (read only, not a parameter)
+               root: null,
 
-       // maximum: [const] Float
-       //              Max sample number
-       maximum: 100,
+               // query: anything
+               //              Specifies datastore query to return the root item for the tree.
+               //              Must only return a single item.   Alternately can just pass in pointer
+               //              to root item.
+               // example:
+               //      |       {id:'ROOT'}
+               query: null,
 
-       // places: [const] Number
-       //              Number of places to show in values; 0 by default
-       places: 0,
+               // deferItemLoadingUntilExpand: Boolean
+               //              Setting this to true will cause the TreeStoreModel to defer calling loadItem on nodes
+               //              until they are expanded. This allows for lazying loading where only one
+               //              loadItem (and generally one network call, consequently) per expansion
+               //              (rather than one for each child).
+               //              This relies on partial loading of the children items; each children item of a
+               //              fully loaded item should contain the label and info about having children.
+               deferItemLoadingUntilExpand: false,
 
-       // indeterminate: [const] Boolean
-       //              If false: show progress value (number or percentage).
-       //              If true: show that a process is underway but that the amount completed is unknown.
-       indeterminate: false,
+               constructor: function(/* Object */ args){
+                       // summary:
+                       //              Passed the arguments listed above (store, etc)
+                       // tags:
+                       //              private
 
-       // name: String
-       //              this is the field name (for a form) if set. This needs to be set if you want to use
-       //              this widget in a dijit.form.Form widget (such as dijit.Dialog)
-       name: '',
+                       dojo.mixin(this, args);
 
-       templateString: dojo.cache("dijit", "templates/ProgressBar.html", "<div class=\"dijitProgressBar dijitProgressBarEmpty\"\n\t><div waiRole=\"progressbar\" dojoAttachPoint=\"internalProgress\" class=\"dijitProgressBarFull\"\n\t\t><div class=\"dijitProgressBarTile\"></div\n\t\t><span style=\"visibility:hidden\">&nbsp;</span\n\t></div\n\t><div dojoAttachPoint=\"label\" class=\"dijitProgressBarLabel\" id=\"${id}_label\">&nbsp;</div\n\t><img dojoAttachPoint=\"indeterminateHighContrastImage\" class=\"dijitProgressBarIndeterminateHighContrastImage\" alt=\"\"\n/></div>\n"),
+                       this.connects = [];
 
-       // _indeterminateHighContrastImagePath: [private] dojo._URL
-       //              URL to image to use for indeterminate progress bar when display is in high contrast mode
-       _indeterminateHighContrastImagePath:
-               dojo.moduleUrl("dijit", "themes/a11y/indeterminate_progress.gif"),
+                       var store = this.store;
+                       if(!store.getFeatures()['dojo.data.api.Identity']){
+                               throw new Error("dijit.Tree: store must support dojo.data.Identity");
+                       }
 
-       // public functions
-       postCreate: function(){
-               this.inherited(arguments);
-               this.indeterminateHighContrastImage.setAttribute("src",
-                       this._indeterminateHighContrastImagePath.toString());
-               this.update();
-       },
+                       // if the store supports Notification, subscribe to the notification events
+                       if(store.getFeatures()['dojo.data.api.Notification']){
+                               this.connects = this.connects.concat([
+                                       dojo.connect(store, "onNew", this, "onNewItem"),
+                                       dojo.connect(store, "onDelete", this, "onDeleteItem"),
+                                       dojo.connect(store, "onSet", this, "onSetItem")
+                               ]);
+                       }
+               },
 
-       update: function(/*Object?*/attributes){
-               // summary:
-               //              Change attributes of ProgressBar, similar to attr(hash).
-               //
-               // attributes:
-               //              May provide progress and/or maximum properties on this parameter;
-               //              see attribute specs for details.
-               //
-               // example:
-               //      |       myProgressBar.update({'indeterminate': true});
-               //      |       myProgressBar.update({'progress': 80});
+               destroy: function(){
+                       dojo.forEach(this.connects, dojo.disconnect);
+                       // TODO: should cancel any in-progress processing of getRoot(), getChildren()
+               },
 
-               // TODO: deprecate this method and use set() instead
+               // =======================================================================
+               // Methods for traversing hierarchy
 
-               dojo.mixin(this, attributes || {});
-               var tip = this.internalProgress;
-               var percent = 1, classFunc;
-               if(this.indeterminate){
-                       classFunc = "addClass";
-                       dijit.removeWaiState(tip, "valuenow");
-                       dijit.removeWaiState(tip, "valuemin");
-                       dijit.removeWaiState(tip, "valuemax");
-               }else{
-                       classFunc = "removeClass";
-                       if(String(this.progress).indexOf("%") != -1){
-                               percent = Math.min(parseFloat(this.progress)/100, 1);
-                               this.progress = percent * this.maximum;
+               getRoot: function(onItem, onError){
+                       // summary:
+                       //              Calls onItem with the root item for the tree, possibly a fabricated item.
+                       //              Calls onError on error.
+                       if(this.root){
+                               onItem(this.root);
                        }else{
-                               this.progress = Math.min(this.progress, this.maximum);
-                               percent = this.progress / this.maximum;
+                               this.store.fetch({
+                                       query: this.query,
+                                       onComplete: dojo.hitch(this, function(items){
+                                               if(items.length != 1){
+                                                       throw new Error(this.declaredClass + ": query " + dojo.toJson(this.query) + " returned " + items.length +
+                                                               " items, but must return exactly one item");
+                                               }
+                                               this.root = items[0];
+                                               onItem(this.root);
+                                       }),
+                                       onError: onError
+                               });
                        }
-                       var text = this.report(percent);
-                       this.label.firstChild.nodeValue = text;
-                       dijit.setWaiState(tip, "describedby", this.label.id);
-                       dijit.setWaiState(tip, "valuenow", this.progress);
-                       dijit.setWaiState(tip, "valuemin", 0);
-                       dijit.setWaiState(tip, "valuemax", this.maximum);
-               }
-               dojo[classFunc](this.domNode, "dijitProgressBarIndeterminate");
-               tip.style.width = (percent * 100) + "%";
-               this.onChange();
-       },
-
-       _setValueAttr: function(v){
-               if(v == Infinity){
-                       this.update({indeterminate:true});
-               }else{
-                       this.update({indeterminate:false, progress:v});
-               }
-       },
+               },
 
-       _getValueAttr: function(){
-               return this.progress;
-       },
+               mayHaveChildren: function(/*dojo.data.Item*/ item){
+                       // summary:
+                       //              Tells if an item has or may have children.  Implementing logic here
+                       //              avoids showing +/- expando icon for nodes that we know don't have children.
+                       //              (For efficiency reasons we may not want to check if an element actually
+                       //              has children until user clicks the expando node)
+                       return dojo.some(this.childrenAttrs, function(attr){
+                               return this.store.hasAttribute(item, attr);
+                       }, this);
+               },
 
-       report: function(/*float*/percent){
-               // summary:
-               //              Generates message to show inside progress bar (normally indicating amount of task completed).
-               //              May be overridden.
-               // tags:
-               //              extension
+               getChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ onComplete, /*function*/ onError){
+                       // summary:
+                       //              Calls onComplete() with array of child items of given parent item, all loaded.
 
-               return dojo.number.format(percent, { type: "percent", places: this.places, locale: this.lang });
-       },
+                       var store = this.store;
+                       if(!store.isItemLoaded(parentItem)){
+                               // The parent is not loaded yet, we must be in deferItemLoadingUntilExpand
+                               // mode, so we will load it and just return the children (without loading each
+                               // child item)
+                               var getChildren = dojo.hitch(this, arguments.callee);
+                               store.loadItem({
+                                       item: parentItem,
+                                       onItem: function(parentItem){
+                                               getChildren(parentItem, onComplete, onError);
+                                       },
+                                       onError: onError
+                               });
+                               return;
+                       }
+                       // get children of specified item
+                       var childItems = [];
+                       for(var i=0; i<this.childrenAttrs.length; i++){
+                               var vals = store.getValues(parentItem, this.childrenAttrs[i]);
+                               childItems = childItems.concat(vals);
+                       }
 
-       onChange: function(){
-               // summary:
-               //              Callback fired when progress updates.
-               // tags:
-               //              progress
-       }
-});
+                       // count how many items need to be loaded
+                       var _waitCount = 0;
+                       if(!this.deferItemLoadingUntilExpand){
+                               dojo.forEach(childItems, function(item){ if(!store.isItemLoaded(item)){ _waitCount++; } });
+                       }
 
-}
+                       if(_waitCount == 0){
+                               // all items are already loaded (or we aren't loading them).  proceed...
+                               onComplete(childItems);
+                       }else{
+                               // still waiting for some or all of the items to load
+                               dojo.forEach(childItems, function(item, idx){
+                                       if(!store.isItemLoaded(item)){
+                                               store.loadItem({
+                                                       item: item,
+                                                       onItem: function(item){
+                                                               childItems[idx] = item;
+                                                               if(--_waitCount == 0){
+                                                                       // all nodes have been loaded, send them to the tree
+                                                                       onComplete(childItems);
+                                                               }
+                                                       },
+                                                       onError: onError
+                                               });
+                                       }
+                               });
+                       }
+               },
 
-if(!dojo._hasResource["dijit.ToolbarSeparator"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dijit.ToolbarSeparator"] = true;
-dojo.provide("dijit.ToolbarSeparator");
+               // =======================================================================
+               // Inspecting items
 
+               isItem: function(/* anything */ something){
+                       return this.store.isItem(something);    // Boolean
+               },
 
+               fetchItemByIdentity: function(/* object */ keywordArgs){
+                       this.store.fetchItemByIdentity(keywordArgs);
+               },
 
+               getIdentity: function(/* item */ item){
+                       return this.store.getIdentity(item);    // Object
+               },
 
-dojo.declare("dijit.ToolbarSeparator",
-               [ dijit._Widget, dijit._Templated ],
-               {
-               // summary:
-               //              A spacer between two `dijit.Toolbar` items
-               templateString: '<div class="dijitToolbarSeparator dijitInline" waiRole="presentation"></div>',
-               postCreate: function(){ dojo.setSelectable(this.domNode, false); },
-               isFocusable: function(){
+               getLabel: function(/*dojo.data.Item*/ item){
                        // summary:
-                       //              This widget isn't focusable, so pass along that fact.
-                       // tags:
-                       //              protected
-                       return false;
-               }
-
-       });
-
+                       //              Get the label for an item
+                       if(this.labelAttr){
+                               return this.store.getValue(item,this.labelAttr);        // String
+                       }else{
+                               return this.store.getLabel(item);       // String
+                       }
+               },
 
+               // =======================================================================
+               // Write interface
 
-}
+               newItem: function(/* dojo.dnd.Item */ args, /*Item*/ parent, /*int?*/ insertIndex){
+                       // summary:
+                       //              Creates a new item.   See `dojo.data.api.Write` for details on args.
+                       //              Used in drag & drop when item from external source dropped onto tree.
+                       // description:
+                       //              Developers will need to override this method if new items get added
+                       //              to parents with multiple children attributes, in order to define which
+                       //              children attribute points to the new item.
 
-if(!dojo._hasResource["dijit.Toolbar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dijit.Toolbar"] = true;
-dojo.provide("dijit.Toolbar");
+                       var pInfo = {parent: parent, attribute: this.childrenAttrs[0]}, LnewItem;
 
+                       if(this.newItemIdAttr && args[this.newItemIdAttr]){
+                               // Maybe there's already a corresponding item in the store; if so, reuse it.
+                               this.fetchItemByIdentity({identity: args[this.newItemIdAttr], scope: this, onItem: function(item){
+                                       if(item){
+                                               // There's already a matching item in store, use it
+                                               this.pasteItem(item, null, parent, true, insertIndex);
+                                       }else{
+                                               // Create new item in the tree, based on the drag source.
+                                               LnewItem=this.store.newItem(args, pInfo);
+                                               if (LnewItem && (insertIndex!=undefined)){
+                                                       // Move new item to desired position
+                                                       this.pasteItem(LnewItem, parent, parent, false, insertIndex);
+                                               }
+                                       }
+                               }});
+                       }else{
+                               // [as far as we know] there is no id so we must assume this is a new item
+                               LnewItem=this.store.newItem(args, pInfo);
+                               if (LnewItem && (insertIndex!=undefined)){
+                                       // Move new item to desired position
+                                       this.pasteItem(LnewItem, parent, parent, false, insertIndex);
+                               }
+                       }
+               },
 
+               pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){
+                       // summary:
+                       //              Move or copy an item from one parent item to another.
+                       //              Used in drag & drop
+                       var store = this.store,
+                               parentAttr = this.childrenAttrs[0];     // name of "children" attr in parent item
 
+                       // remove child from source item, and record the attribute that child occurred in
+                       if(oldParentItem){
+                               dojo.forEach(this.childrenAttrs, function(attr){
+                                       if(store.containsValue(oldParentItem, attr, childItem)){
+                                               if(!bCopy){
+                                                       var values = dojo.filter(store.getValues(oldParentItem, attr), function(x){
+                                                               return x != childItem;
+                                                       });
+                                                       store.setValues(oldParentItem, attr, values);
+                                               }
+                                               parentAttr = attr;
+                                       }
+                               });
+                       }
 
+                       // modify target item's children attribute to include this item
+                       if(newParentItem){
+                               if(typeof insertIndex == "number"){
+                                       // call slice() to avoid modifying the original array, confusing the data store
+                                       var childItems = store.getValues(newParentItem, parentAttr).slice();
+                                       childItems.splice(insertIndex, 0, childItem);
+                                       store.setValues(newParentItem, parentAttr, childItems);
+                               }else{
+                                       store.setValues(newParentItem, parentAttr,
+                                               store.getValues(newParentItem, parentAttr).concat(childItem));
+                               }
+                       }
+               },
 
-dojo.declare("dijit.Toolbar",
-       [dijit._Widget, dijit._Templated, dijit._KeyNavContainer],
-       {
-       // summary:
-       //              A Toolbar widget, used to hold things like `dijit.Editor` buttons
+               // =======================================================================
+               // Callbacks
 
-       templateString:
-               '<div class="dijit" waiRole="toolbar" tabIndex="${tabIndex}" dojoAttachPoint="containerNode">' +
-               //      '<table style="table-layout: fixed" class="dijitReset dijitToolbarTable">' + // factor out style
-               //              '<tr class="dijitReset" dojoAttachPoint="containerNode"></tr>'+
-               //      '</table>' +
-               '</div>',
+               onChange: function(/*dojo.data.Item*/ item){
+                       // summary:
+                       //              Callback whenever an item has changed, so that Tree
+                       //              can update the label, icon, etc.   Note that changes
+                       //              to an item's children or parent(s) will trigger an
+                       //              onChildrenChange() so you can ignore those changes here.
+                       // tags:
+                       //              callback
+               },
 
-       baseClass: "dijitToolbar",
+               onChildrenChange: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
+                       // summary:
+                       //              Callback to do notifications about new, updated, or deleted items.
+                       // tags:
+                       //              callback
+               },
 
-       postCreate: function(){
-               this.connectKeyNavHandlers(
-                       this.isLeftToRight() ? [dojo.keys.LEFT_ARROW] : [dojo.keys.RIGHT_ARROW],
-                       this.isLeftToRight() ? [dojo.keys.RIGHT_ARROW] : [dojo.keys.LEFT_ARROW]
-               );
-               this.inherited(arguments);
-       },
+               onDelete: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
+                       // summary:
+                       //              Callback when an item has been deleted.
+                       // description:
+                       //              Note that there will also be an onChildrenChange() callback for the parent
+                       //              of this item.
+                       // tags:
+                       //              callback
+               },
 
-       startup: function(){
-               if(this._started){ return; }
+               // =======================================================================
+               // Events from data store
 
-               this.startupKeyNavChildren();
+               onNewItem: function(/* dojo.data.Item */ item, /* Object */ parentInfo){
+                       // summary:
+                       //              Handler for when new items appear in the store, either from a drop operation
+                       //              or some other way.   Updates the tree view (if necessary).
+                       // description:
+                       //              If the new item is a child of an existing item,
+                       //              calls onChildrenChange() with the new list of children
+                       //              for that existing item.
+                       //
+                       // tags:
+                       //              extension
 
-               this.inherited(arguments);
-       }
-}
-);
+                       // We only care about the new item if it has a parent that corresponds to a TreeNode
+                       // we are currently displaying
+                       if(!parentInfo){
+                               return;
+                       }
 
-// For back-compat, remove for 2.0
+                       // Call onChildrenChange() on parent (ie, existing) item with new list of children
+                       // In the common case, the new list of children is simply parentInfo.newValue or
+                       // [ parentInfo.newValue ], although if items in the store has multiple
+                       // child attributes (see `childrenAttr`), then it's a superset of parentInfo.newValue,
+                       // so call getChildren() to be sure to get right answer.
+                       this.getChildren(parentInfo.item, dojo.hitch(this, function(children){
+                               this.onChildrenChange(parentInfo.item, children);
+                       }));
+               },
 
+               onDeleteItem: function(/*Object*/ item){
+                       // summary:
+                       //              Handler for delete notifications from underlying store
+                       this.onDelete(item);
+               },
 
-}
+               onSetItem: function(/* item */ item,
+                                               /* attribute-name-string */ attribute,
+                                               /* object | array */ oldValue,
+                                               /* object | array */ newValue){
+                       // summary:
+                       //              Updates the tree view according to changes in the data store.
+                       // description:
+                       //              Handles updates to an item's children by calling onChildrenChange(), and
+                       //              other updates to an item by calling onChange().
+                       //
+                       //              See `onNewItem` for more details on handling updates to an item's children.
+                       // tags:
+                       //              extension
 
-if(!dojo._hasResource["dojo.DeferredList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo.DeferredList"] = true;
-dojo.provide("dojo.DeferredList");
-dojo.DeferredList = function(/*Array*/ list, /*Boolean?*/ fireOnOneCallback, /*Boolean?*/ fireOnOneErrback, /*Boolean?*/ consumeErrors, /*Function?*/ canceller){
-       // summary:
-       //              Provides event handling for a group of Deferred objects.
-       // description:
-       //              DeferredList takes an array of existing deferreds and returns a new deferred of its own
-       //              this new deferred will typically have its callback fired when all of the deferreds in
-       //              the given list have fired their own deferreds.  The parameters `fireOnOneCallback` and
-       //              fireOnOneErrback, will fire before all the deferreds as appropriate
-       //
-       //      list:
-       //              The list of deferreds to be synchronizied with this DeferredList
-       //      fireOnOneCallback:
-       //              Will cause the DeferredLists callback to be fired as soon as any
-       //              of the deferreds in its list have been fired instead of waiting until
-       //              the entire list has finished
-       //      fireonOneErrback:
-       //              Will cause the errback to fire upon any of the deferreds errback
-       //      canceller:
-       //              A deferred canceller function, see dojo.Deferred
-       var resultList = [];
-       dojo.Deferred.call(this);
-       var self = this;
-       if(list.length === 0 && !fireOnOneCallback){
-               this.resolve([0, []]);
-       }
-       var finished = 0;
-       dojo.forEach(list, function(item, i){
-               item.then(function(result){
-                       if(fireOnOneCallback){
-                               self.resolve([i, result]);
-                       }else{
-                               addResult(true, result);
-                       }
-               },function(error){
-                       if(fireOnOneErrback){
-                               self.reject(error);
+                       if(dojo.indexOf(this.childrenAttrs, attribute) != -1){
+                               // item's children list changed
+                               this.getChildren(item, dojo.hitch(this, function(children){
+                                       // See comments in onNewItem() about calling getChildren()
+                                       this.onChildrenChange(item, children);
+                               }));
                        }else{
-                               addResult(false, error);
-                       }
-                       if(consumeErrors){
-                               return null;
-                       }
-                       throw error;
-               });
-               function addResult(succeeded, result){
-                       resultList[i] = [succeeded, result];
-                       finished++;
-                       if(finished === list.length){
-                               self.resolve(resultList);
+                               // item's label/icon/etc. changed.
+                               this.onChange(item);
                        }
-                       
                }
        });
-};
-dojo.DeferredList.prototype = new dojo.Deferred();
-
-dojo.DeferredList.prototype.gatherResults= function(deferredList){
-       // summary:     
-       //      Gathers the results of the deferreds for packaging
-       //      as the parameters to the Deferred Lists' callback
-
-       var d = new dojo.DeferredList(deferredList, false, true, false);
-       d.addCallback(function(results){
-               var ret = [];
-               dojo.forEach(results, function(result){
-                       ret.push(result[1]);
-               });
-               return ret;
-       });
-       return d;
-};
 
 }
 
-if(!dojo._hasResource["dijit.tree.TreeStoreModel"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dijit.tree.TreeStoreModel"] = true;
-dojo.provide("dijit.tree.TreeStoreModel");
-
-dojo.declare(
-               "dijit.tree.TreeStoreModel",
-               null,
-       {
-               // summary:
-               //              Implements dijit.Tree.model connecting to a store with a single
-               //              root item.  Any methods passed into the constructor will override
-               //              the ones defined here.
-
-               // store: dojo.data.Store
-               //              Underlying store
-               store: null,
-
-               // childrenAttrs: String[]
-               //              One or more attribute names (attributes in the dojo.data item) that specify that item's children
-               childrenAttrs: ["children"],
+if(!dojo._hasResource["dijit.tree.ForestStoreModel"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.tree.ForestStoreModel"] = true;
+dojo.provide("dijit.tree.ForestStoreModel");
 
-               // newItemIdAttr: String
-               //              Name of attribute in the Object passed to newItem() that specifies the id.
-               //
-               //              If newItemIdAttr is set then it's used when newItem() is called to see if an
-               //              item with the same id already exists, and if so just links to the old item
-               //              (so that the old item ends up with two parents).
-               //
-               //              Setting this to null or "" will make every drop create a new item.
-               newItemIdAttr: "id",
 
-               // labelAttr: String
-               //              If specified, get label for tree node from this attribute, rather
-               //              than by calling store.getLabel()
-               labelAttr: "",
 
-               // root: [readonly] dojo.data.Item
-               //              Pointer to the root item (read only, not a parameter)
-               root: null,
+dojo.declare("dijit.tree.ForestStoreModel", dijit.tree.TreeStoreModel, {
+       // summary:
+       //              Interface between a dijit.Tree and a dojo.data store that doesn't have a root item,
+       //              a.k.a. a store that has multiple "top level" items.
+       //
+       // description
+       //              Use this class to wrap a dojo.data store, making all the items matching the specified query
+       //              appear as children of a fabricated "root item".  If no query is specified then all the
+       //              items returned by fetch() on the underlying store become children of the root item.
+       //              This class allows dijit.Tree to assume a single root item, even if the store doesn't have one.
+       //
+       //              When using this class the developer must override a number of methods according to their app and
+       //              data, including:
+       //                      - onNewRootItem
+       //                      - onAddToRoot
+       //                      - onLeaveRoot
+       //                      - onNewItem
+       //                      - onSetItem
 
-               // query: anything
-               //              Specifies datastore query to return the root item for the tree.
-               //              Must only return a single item.   Alternately can just pass in pointer
-               //              to root item.
-               // example:
-               //      |       {id:'ROOT'}
-               query: null,
+       // Parameters to constructor
 
-               // deferItemLoadingUntilExpand: Boolean
-               //              Setting this to true will cause the TreeStoreModel to defer calling loadItem on nodes
-               //              until they are expanded. This allows for lazying loading where only one
-               //              loadItem (and generally one network call, consequently) per expansion
-               //              (rather than one for each child).
-               //              This relies on partial loading of the children items; each children item of a
-               //              fully loaded item should contain the label and info about having children.
-               deferItemLoadingUntilExpand: false,
+       // rootId: String
+       //              ID of fabricated root item
+       rootId: "$root$",
 
-               constructor: function(/* Object */ args){
-                       // summary:
-                       //              Passed the arguments listed above (store, etc)
-                       // tags:
-                       //              private
+       // rootLabel: String
+       //              Label of fabricated root item
+       rootLabel: "ROOT",
 
-                       dojo.mixin(this, args);
+       // query: String
+       //              Specifies the set of children of the root item.
+       // example:
+       //      |       {type:'continent'}
+       query: null,
 
-                       this.connects = [];
+       // End of parameters to constructor
 
-                       var store = this.store;
-                       if(!store.getFeatures()['dojo.data.api.Identity']){
-                               throw new Error("dijit.Tree: store must support dojo.data.Identity");
-                       }
+       constructor: function(params){
+               // summary:
+               //              Sets up variables, etc.
+               // tags:
+               //              private
 
-                       // if the store supports Notification, subscribe to the notification events
-                       if(store.getFeatures()['dojo.data.api.Notification']){
-                               this.connects = this.connects.concat([
-                                       dojo.connect(store, "onNew", this, "onNewItem"),
-                                       dojo.connect(store, "onDelete", this, "onDeleteItem"),
-                                       dojo.connect(store, "onSet", this, "onSetItem")
-                               ]);
-                       }
-               },
+               // Make dummy root item
+               this.root = {
+                       store: this,
+                       root: true,
+                       id: params.rootId,
+                       label: params.rootLabel,
+                       children: params.rootChildren   // optional param
+               };
+       },
 
-               destroy: function(){
-                       dojo.forEach(this.connects, dojo.disconnect);
-                       // TODO: should cancel any in-progress processing of getRoot(), getChildren()
-               },
+       // =======================================================================
+       // Methods for traversing hierarchy
 
-               // =======================================================================
-               // Methods for traversing hierarchy
+       mayHaveChildren: function(/*dojo.data.Item*/ item){
+               // summary:
+               //              Tells if an item has or may have children.  Implementing logic here
+               //              avoids showing +/- expando icon for nodes that we know don't have children.
+               //              (For efficiency reasons we may not want to check if an element actually
+               //              has children until user clicks the expando node)
+               // tags:
+               //              extension
+               return item === this.root || this.inherited(arguments);
+       },
 
-               getRoot: function(onItem, onError){
-                       // summary:
-                       //              Calls onItem with the root item for the tree, possibly a fabricated item.
-                       //              Calls onError on error.
-                       if(this.root){
-                               onItem(this.root);
+       getChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ callback, /*function*/ onError){
+               // summary:
+               //              Calls onComplete() with array of child items of given parent item, all loaded.
+               if(parentItem === this.root){
+                       if(this.root.children){
+                               // already loaded, just return
+                               callback(this.root.children);
                        }else{
                                this.store.fetch({
                                        query: this.query,
                                        onComplete: dojo.hitch(this, function(items){
-                                               if(items.length != 1){
-                                                       throw new Error(this.declaredClass + ": query " + dojo.toJson(this.query) + " returned " + items.length +
-                                                               " items, but must return exactly one item");
-                                               }
-                                               this.root = items[0];
-                                               onItem(this.root);
+                                               this.root.children = items;
+                                               callback(items);
                                        }),
                                        onError: onError
                                });
                        }
-               },
-
-               mayHaveChildren: function(/*dojo.data.Item*/ item){
-                       // summary:
-                       //              Tells if an item has or may have children.  Implementing logic here
-                       //              avoids showing +/- expando icon for nodes that we know don't have children.
-                       //              (For efficiency reasons we may not want to check if an element actually
-                       //              has children until user clicks the expando node)
-                       return dojo.some(this.childrenAttrs, function(attr){
-                               return this.store.hasAttribute(item, attr);
-                       }, this);
-               },
+               }else{
+                       this.inherited(arguments);
+               }
+       },
 
-               getChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ onComplete, /*function*/ onError){
-                       // summary:
-                       //              Calls onComplete() with array of child items of given parent item, all loaded.
+       // =======================================================================
+       // Inspecting items
 
-                       var store = this.store;
-                       if(!store.isItemLoaded(parentItem)){
-                               // The parent is not loaded yet, we must be in deferItemLoadingUntilExpand
-                               // mode, so we will load it and just return the children (without loading each
-                               // child item)
-                               var getChildren = dojo.hitch(this, arguments.callee);
-                               store.loadItem({
-                                       item: parentItem,
-                                       onItem: function(parentItem){
-                                               getChildren(parentItem, onComplete, onError);
-                                       },
-                                       onError: onError
-                               });
-                               return;
-                       }
-                       // get children of specified item
-                       var childItems = [];
-                       for(var i=0; i<this.childrenAttrs.length; i++){
-                               var vals = store.getValues(parentItem, this.childrenAttrs[i]);
-                               childItems = childItems.concat(vals);
-                       }
+       isItem: function(/* anything */ something){
+               return (something === this.root) ? true : this.inherited(arguments);
+       },
 
-                       // count how many items need to be loaded
-                       var _waitCount = 0;
-                       if(!this.deferItemLoadingUntilExpand){
-                               dojo.forEach(childItems, function(item){ if(!store.isItemLoaded(item)){ _waitCount++; } });
+       fetchItemByIdentity: function(/* object */ keywordArgs){
+               if(keywordArgs.identity == this.root.id){
+                       var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
+                       if(keywordArgs.onItem){
+                               keywordArgs.onItem.call(scope, this.root);
                        }
+               }else{
+                       this.inherited(arguments);
+               }
+       },
 
-                       if(_waitCount == 0){
-                               // all items are already loaded (or we aren't loading them).  proceed...
-                               onComplete(childItems);
-                       }else{
-                               // still waiting for some or all of the items to load
-                               dojo.forEach(childItems, function(item, idx){
-                                       if(!store.isItemLoaded(item)){
-                                               store.loadItem({
-                                                       item: item,
-                                                       onItem: function(item){
-                                                               childItems[idx] = item;
-                                                               if(--_waitCount == 0){
-                                                                       // all nodes have been loaded, send them to the tree
-                                                                       onComplete(childItems);
-                                                               }
-                                                       },
-                                                       onError: onError
-                                               });
-                                       }
-                               });
-                       }
-               },
+       getIdentity: function(/* item */ item){
+               return (item === this.root) ? this.root.id : this.inherited(arguments);
+       },
 
-               // =======================================================================
-               // Inspecting items
+       getLabel: function(/* item */ item){
+               return  (item === this.root) ? this.root.label : this.inherited(arguments);
+       },
 
-               isItem: function(/* anything */ something){
-                       return this.store.isItem(something);    // Boolean
-               },
+       // =======================================================================
+       // Write interface
 
-               fetchItemByIdentity: function(/* object */ keywordArgs){
-                       this.store.fetchItemByIdentity(keywordArgs);
-               },
+       newItem: function(/* dojo.dnd.Item */ args, /*Item*/ parent, /*int?*/ insertIndex){
+               // summary:
+               //              Creates a new item.   See dojo.data.api.Write for details on args.
+               //              Used in drag & drop when item from external source dropped onto tree.
+               if(parent === this.root){
+                       this.onNewRootItem(args);
+                       return this.store.newItem(args);
+               }else{
+                       return this.inherited(arguments);
+               }
+       },
 
-               getIdentity: function(/* item */ item){
-                       return this.store.getIdentity(item);    // Object
-               },
+       onNewRootItem: function(args){
+               // summary:
+               //              User can override this method to modify a new element that's being
+               //              added to the root of the tree, for example to add a flag like root=true
+       },
 
-               getLabel: function(/*dojo.data.Item*/ item){
-                       // summary:
-                       //              Get the label for an item
-                       if(this.labelAttr){
-                               return this.store.getValue(item,this.labelAttr);        // String
-                       }else{
-                               return this.store.getLabel(item);       // String
+       pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){
+               // summary:
+               //              Move or copy an item from one parent item to another.
+               //              Used in drag & drop
+               if(oldParentItem === this.root){
+                       if(!bCopy){
+                               // It's onLeaveRoot()'s responsibility to modify the item so it no longer matches
+                               // this.query... thus triggering an onChildrenChange() event to notify the Tree
+                               // that this element is no longer a child of the root node
+                               this.onLeaveRoot(childItem);
                        }
-               },
-
-               // =======================================================================
-               // Write interface
-
-               newItem: function(/* dojo.dnd.Item */ args, /*Item*/ parent, /*int?*/ insertIndex){
-                       // summary:
-                       //              Creates a new item.   See `dojo.data.api.Write` for details on args.
-                       //              Used in drag & drop when item from external source dropped onto tree.
-                       // description:
-                       //              Developers will need to override this method if new items get added
-                       //              to parents with multiple children attributes, in order to define which
-                       //              children attribute points to the new item.
-
-                       var pInfo = {parent: parent, attribute: this.childrenAttrs[0], insertIndex: insertIndex};
+               }
+               dijit.tree.TreeStoreModel.prototype.pasteItem.call(this, childItem,
+                       oldParentItem === this.root ? null : oldParentItem,
+                       newParentItem === this.root ? null : newParentItem,
+                       bCopy,
+                       insertIndex
+               );
+               if(newParentItem === this.root){
+                       // It's onAddToRoot()'s responsibility to modify the item so it matches
+                       // this.query... thus triggering an onChildrenChange() event to notify the Tree
+                       // that this element is now a child of the root node
+                       this.onAddToRoot(childItem);
+               }
+       },
 
-                       if(this.newItemIdAttr && args[this.newItemIdAttr]){
-                               // Maybe there's already a corresponding item in the store; if so, reuse it.
-                               this.fetchItemByIdentity({identity: args[this.newItemIdAttr], scope: this, onItem: function(item){
-                                       if(item){
-                                               // There's already a matching item in store, use it
-                                               this.pasteItem(item, null, parent, true, insertIndex);
-                                       }else{
-                                               // Create new item in the tree, based on the drag source.
-                                               this.store.newItem(args, pInfo);
-                                       }
-                               }});
-                       }else{
-                               // [as far as we know] there is no id so we must assume this is a new item
-                               this.store.newItem(args, pInfo);
-                       }
-               },
+       // =======================================================================
+       // Handling for top level children
 
-               pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){
-                       // summary:
-                       //              Move or copy an item from one parent item to another.
-                       //              Used in drag & drop
-                       var store = this.store,
-                               parentAttr = this.childrenAttrs[0];     // name of "children" attr in parent item
+       onAddToRoot: function(/* item */ item){
+               // summary:
+               //              Called when item added to root of tree; user must override this method
+               //              to modify the item so that it matches the query for top level items
+               // example:
+               //      |       store.setValue(item, "root", true);
+               // tags:
+               //              extension
+               console.log(this, ": item ", item, " added to root");
+       },
 
-                       // remove child from source item, and record the attribute that child occurred in
-                       if(oldParentItem){
-                               dojo.forEach(this.childrenAttrs, function(attr){
-                                       if(store.containsValue(oldParentItem, attr, childItem)){
-                                               if(!bCopy){
-                                                       var values = dojo.filter(store.getValues(oldParentItem, attr), function(x){
-                                                               return x != childItem;
-                                                       });
-                                                       store.setValues(oldParentItem, attr, values);
-                                               }
-                                               parentAttr = attr;
-                                       }
-                               });
-                       }
+       onLeaveRoot: function(/* item */ item){
+               // summary:
+               //              Called when item removed from root of tree; user must override this method
+               //              to modify the item so it doesn't match the query for top level items
+               // example:
+               //      |       store.unsetAttribute(item, "root");
+               // tags:
+               //              extension
+               console.log(this, ": item ", item, " removed from root");
+       },
 
-                       // modify target item's children attribute to include this item
-                       if(newParentItem){
-                               if(typeof insertIndex == "number"){
-                                       // call slice() to avoid modifying the original array, confusing the data store
-                                       var childItems = store.getValues(newParentItem, parentAttr).slice();
-                                       childItems.splice(insertIndex, 0, childItem);
-                                       store.setValues(newParentItem, parentAttr, childItems);
-                               }else{
-                                       store.setValues(newParentItem, parentAttr,
-                                               store.getValues(newParentItem, parentAttr).concat(childItem));
-                               }
-                       }
-               },
+       // =======================================================================
+       // Events from data store
 
-               // =======================================================================
-               // Callbacks
+       _requeryTop: function(){
+               // reruns the query for the children of the root node,
+               // sending out an onSet notification if those children have changed
+               var oldChildren = this.root.children || [];
+               this.store.fetch({
+                       query: this.query,
+                       onComplete: dojo.hitch(this, function(newChildren){
+                               this.root.children = newChildren;
 
-               onChange: function(/*dojo.data.Item*/ item){
-                       // summary:
-                       //              Callback whenever an item has changed, so that Tree
-                       //              can update the label, icon, etc.   Note that changes
-                       //              to an item's children or parent(s) will trigger an
-                       //              onChildrenChange() so you can ignore those changes here.
-                       // tags:
-                       //              callback
-               },
+                               // If the list of children or the order of children has changed...
+                               if(oldChildren.length != newChildren.length ||
+                                       dojo.some(oldChildren, function(item, idx){ return newChildren[idx] != item;})){
+                                       this.onChildrenChange(this.root, newChildren);
+                               }
+                       })
+               });
+       },
 
-               onChildrenChange: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
-                       // summary:
-                       //              Callback to do notifications about new, updated, or deleted items.
-                       // tags:
-                       //              callback
-               },
+       onNewItem: function(/* dojo.data.Item */ item, /* Object */ parentInfo){
+               // summary:
+               //              Handler for when new items appear in the store.  Developers should override this
+               //              method to be more efficient based on their app/data.
+               // description:
+               //              Note that the default implementation requeries the top level items every time
+               //              a new item is created, since any new item could be a top level item (even in
+               //              addition to being a child of another item, since items can have multiple parents).
+               //
+               //              If developers can detect which items are possible top level items (based on the item and the
+               //              parentInfo parameters), they should override this method to only call _requeryTop() for top
+               //              level items.  Often all top level items have parentInfo==null, but
+               //              that will depend on which store you use and what your data is like.
+               // tags:
+               //              extension
+               this._requeryTop();
 
-               onDelete: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
-                       // summary:
-                       //              Callback when an item has been deleted.
-                       // description:
-                       //              Note that there will also be an onChildrenChange() callback for the parent
-                       //              of this item.
-                       // tags:
-                       //              callback
-               },
+               this.inherited(arguments);
+       },
 
-               // =======================================================================
-               // Events from data store
+       onDeleteItem: function(/*Object*/ item){
+               // summary:
+               //              Handler for delete notifications from underlying store
 
-               onNewItem: function(/* dojo.data.Item */ item, /* Object */ parentInfo){
-                       // summary:
-                       //              Handler for when new items appear in the store, either from a drop operation
-                       //              or some other way.   Updates the tree view (if necessary).
-                       // description:
-                       //              If the new item is a child of an existing item,
-                       //              calls onChildrenChange() with the new list of children
-                       //              for that existing item.
-                       //
-                       // tags:
-                       //              extension
+               // check if this was a child of root, and if so send notification that root's children
+               // have changed
+               if(dojo.indexOf(this.root.children, item) != -1){
+                       this._requeryTop();
+               }
 
-                       // We only care about the new item if it has a parent that corresponds to a TreeNode
-                       // we are currently displaying
-                       if(!parentInfo){
-                               return;
-                       }
+               this.inherited(arguments);
+       },
 
-                       // Call onChildrenChange() on parent (ie, existing) item with new list of children
-                       // In the common case, the new list of children is simply parentInfo.newValue or
-                       // [ parentInfo.newValue ], although if items in the store has multiple
-                       // child attributes (see `childrenAttr`), then it's a superset of parentInfo.newValue,
-                       // so call getChildren() to be sure to get right answer.
-                       this.getChildren(parentInfo.item, dojo.hitch(this, function(children){
-                               this.onChildrenChange(parentInfo.item, children);
-                       }));
-               },
+       onSetItem: function(/* item */ item,
+                                       /* attribute-name-string */ attribute,
+                                       /* object | array */ oldValue,
+                                       /* object | array */ newValue){
+               // summary:
+               //              Updates the tree view according to changes to an item in the data store.
+               //              Developers should override this method to be more efficient based on their app/data.
+               // description:
+               //              Handles updates to an item's children by calling onChildrenChange(), and
+               //              other updates to an item by calling onChange().
+               //
+               //              Also, any change to any item re-executes the query for the tree's top-level items,
+               //              since this modified item may have started/stopped matching the query for top level items.
+               //
+               //              If possible, developers should override this function to only call _requeryTop() when
+               //              the change to the item has caused it to stop/start being a top level item in the tree.
+               // tags:
+               //              extension
 
-               onDeleteItem: function(/*Object*/ item){
-                       // summary:
-                       //              Handler for delete notifications from underlying store
-                       this.onDelete(item);
-               },
+               this._requeryTop();
+               this.inherited(arguments);
+       }
 
-               onSetItem: function(/* item */ item,
-                                               /* attribute-name-string */ attribute,
-                                               /* object | array */ oldValue,
-                                               /* object | array */ newValue){
-                       // summary:
-                       //              Updates the tree view according to changes in the data store.
-                       // description:
-                       //              Handles updates to an item's children by calling onChildrenChange(), and
-                       //              other updates to an item by calling onChange().
-                       //
-                       //              See `onNewItem` for more details on handling updates to an item's children.
-                       // tags:
-                       //              extension
+});
 
-                       if(dojo.indexOf(this.childrenAttrs, attribute) != -1){
-                               // item's children list changed
-                               this.getChildren(item, dojo.hitch(this, function(children){
-                                       // See comments in onNewItem() about calling getChildren()
-                                       this.onChildrenChange(item, children);
-                               }));
-                       }else{
-                               // item's label/icon/etc. changed.
-                               this.onChange(item);
-                       }
-               }
-       });
+}
 
+if(!dojo._hasResource["dojo.dnd.Container"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Container"] = true;
+dojo.provide("dojo.dnd.Container");
 
 
-}
 
-if(!dojo._hasResource["dijit.tree.ForestStoreModel"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dijit.tree.ForestStoreModel"] = true;
-dojo.provide("dijit.tree.ForestStoreModel");
 
+/*
+       Container states:
+               ""              - normal state
+               "Over"  - mouse over a container
+       Container item states:
+               ""              - normal state
+               "Over"  - mouse over a container item
+*/
 
+/*=====
+dojo.declare("dojo.dnd.__ContainerArgs", [], {
+       creator: function(){
+               // summary:
+               //              a creator function, which takes a data item, and returns an object like that:
+               //              {node: newNode, data: usedData, type: arrayOfStrings}
+       },
 
-dojo.declare("dijit.tree.ForestStoreModel", dijit.tree.TreeStoreModel, {
-       // summary:
-       //              Interface between Tree and a dojo.store that doesn't have a root item,
-       //              i.e. has multiple "top level" items.
-       //
-       // description
-       //              Use this class to wrap a dojo.store, making all the items matching the specified query
-       //              appear as children of a fabricated "root item".  If no query is specified then all the
-       //              items returned by fetch() on the underlying store become children of the root item.
-       //              It allows dijit.Tree to assume a single root item, even if the store doesn't have one.
+       // skipForm: Boolean
+       //              don't start the drag operation, if clicked on form elements
+       skipForm: false,
 
-       // Parameters to constructor
+       // dropParent: Node||String
+       //              node or node's id to use as the parent node for dropped items
+       //              (must be underneath the 'node' parameter in the DOM)
+       dropParent: null,
 
-       // rootId: String
-       //              ID of fabricated root item
-       rootId: "$root$",
+       // _skipStartup: Boolean
+       //              skip startup(), which collects children, for deferred initialization
+       //              (this is used in the markup mode)
+       _skipStartup: false
+});
 
-       // rootLabel: String
-       //              Label of fabricated root item
-       rootLabel: "ROOT",
+dojo.dnd.Item = function(){
+       // summary:
+       //              Represents (one of) the source node(s) being dragged.
+       //              Contains (at least) the "type" and "data" attributes.
+       // type: String[]
+       //              Type(s) of this item, by default this is ["text"]
+       // data: Object
+       //              Logical representation of the object being dragged.
+       //              If the drag object's type is "text" then data is a String,
+       //              if it's another type then data could be a different Object,
+       //              perhaps a name/value hash.
+       
+       this.type = type;
+       this.data = data;
+}
+=====*/
 
-       // query: String
-       //              Specifies the set of children of the root item.
-       // example:
-       //      |       {type:'continent'}
-       query: null,
+dojo.declare("dojo.dnd.Container", null, {
+       // summary:
+       //              a Container object, which knows when mouse hovers over it,
+       //              and over which element it hovers
+       
+       // object attributes (for markup)
+       skipForm: false,
+       
+       /*=====
+       // current: DomNode
+       //              The DOM node the mouse is currently hovered over
+       current: null,
+       
+       // map: Hash<String, dojo.dnd.Item>
+       //              Map from an item's id (which is also the DOMNode's id) to
+       //              the dojo.dnd.Item itself.
+       map: {},
+       =====*/
+       
+       constructor: function(node, params){
+               // summary:
+               //              a constructor of the Container
+               // node: Node
+               //              node or node's id to build the container on
+               // params: dojo.dnd.__ContainerArgs
+               //              a dictionary of parameters
+               this.node = dojo.byId(node);
+               if(!params){ params = {}; }
+               this.creator = params.creator || null;
+               this.skipForm = params.skipForm;
+               this.parent = params.dropParent && dojo.byId(params.dropParent);
+               
+               // class-specific variables
+               this.map = {};
+               this.current = null;
 
-       // End of parameters to constructor
+               // states
+               this.containerState = "";
+               dojo.addClass(this.node, "dojoDndContainer");
+               
+               // mark up children
+               if(!(params && params._skipStartup)){
+                       this.startup();
+               }
 
-       constructor: function(params){
+               // set up events
+               this.events = [
+                       dojo.connect(this.node, "onmouseover", this, "onMouseOver"),
+                       dojo.connect(this.node, "onmouseout",  this, "onMouseOut"),
+                       // cancel text selection and text dragging
+                       dojo.connect(this.node, "ondragstart",   this, "onSelectStart"),
+                       dojo.connect(this.node, "onselectstart", this, "onSelectStart")
+               ];
+       },
+       
+       // object attributes (for markup)
+       creator: function(){
                // summary:
-               //              Sets up variables, etc.
-               // tags:
-               //              private
-
-               // Make dummy root item
-               this.root = {
-                       store: this,
-                       root: true,
-                       id: params.rootId,
-                       label: params.rootLabel,
-                       children: params.rootChildren   // optional param
-               };
+               //              creator function, dummy at the moment
        },
-
-       // =======================================================================
-       // Methods for traversing hierarchy
-
-       mayHaveChildren: function(/*dojo.data.Item*/ item){
+       
+       // abstract access to the map
+       getItem: function(/*String*/ key){
                // summary:
-               //              Tells if an item has or may have children.  Implementing logic here
-               //              avoids showing +/- expando icon for nodes that we know don't have children.
-               //              (For efficiency reasons we may not want to check if an element actually
-               //              has children until user clicks the expando node)
-               // tags:
-               //              extension
-               return item === this.root || this.inherited(arguments);
+               //              returns a data item by its key (id)
+               return this.map[key];   // dojo.dnd.Item
        },
-
-       getChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ callback, /*function*/ onError){
+       setItem: function(/*String*/ key, /*dojo.dnd.Item*/ data){
                // summary:
-               //              Calls onComplete() with array of child items of given parent item, all loaded.
-               if(parentItem === this.root){
-                       if(this.root.children){
-                               // already loaded, just return
-                               callback(this.root.children);
-                       }else{
-                               this.store.fetch({
-                                       query: this.query,
-                                       onComplete: dojo.hitch(this, function(items){
-                                               this.root.children = items;
-                                               callback(items);
-                                       }),
-                                       onError: onError
-                               });
-                       }
-               }else{
-                       this.inherited(arguments);
-               }
+               //              associates a data item with its key (id)
+               this.map[key] = data;
        },
-
-       // =======================================================================
-       // Inspecting items
-
-       isItem: function(/* anything */ something){
-               return (something === this.root) ? true : this.inherited(arguments);
+       delItem: function(/*String*/ key){
+               // summary:
+               //              removes a data item from the map by its key (id)
+               delete this.map[key];
        },
-
-       fetchItemByIdentity: function(/* object */ keywordArgs){
-               if(keywordArgs.identity == this.root.id){
-                       var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
-                       if(keywordArgs.onItem){
-                               keywordArgs.onItem.call(scope, this.root);
-                       }
-               }else{
-                       this.inherited(arguments);
+       forInItems: function(/*Function*/ f, /*Object?*/ o){
+               // summary:
+               //              iterates over a data map skipping members that
+               //              are present in the empty object (IE and/or 3rd-party libraries).
+               o = o || dojo.global;
+               var m = this.map, e = dojo.dnd._empty;
+               for(var i in m){
+                       if(i in e){ continue; }
+                       f.call(o, m[i], i, this);
                }
+               return o;       // Object
        },
-
-       getIdentity: function(/* item */ item){
-               return (item === this.root) ? this.root.id : this.inherited(arguments);
-       },
-
-       getLabel: function(/* item */ item){
-               return  (item === this.root) ? this.root.label : this.inherited(arguments);
+       clearItems: function(){
+               // summary:
+               //              removes all data items from the map
+               this.map = {};
        },
-
-       // =======================================================================
-       // Write interface
-
-       newItem: function(/* dojo.dnd.Item */ args, /*Item*/ parent, /*int?*/ insertIndex){
+       
+       // methods
+       getAllNodes: function(){
                // summary:
-               //              Creates a new item.   See dojo.data.api.Write for details on args.
-               //              Used in drag & drop when item from external source dropped onto tree.
-               if(parent === this.root){
-                       this.onNewRootItem(args);
-                       return this.store.newItem(args);
-               }else{
-                       return this.inherited(arguments);
-               }
+               //              returns a list (an array) of all valid child nodes
+               return dojo.query("> .dojoDndItem", this.parent);       // NodeList
        },
-
-       onNewRootItem: function(args){
+       sync: function(){
                // summary:
-               //              User can override this method to modify a new element that's being
-               //              added to the root of the tree, for example to add a flag like root=true
+               //              sync up the node list with the data map
+               var map = {};
+               this.getAllNodes().forEach(function(node){
+                       if(node.id){
+                               var item = this.getItem(node.id);
+                               if(item){
+                                       map[node.id] = item;
+                                       return;
+                               }
+                       }else{
+                               node.id = dojo.dnd.getUniqueId();
+                       }
+                       var type = node.getAttribute("dndType"),
+                               data = node.getAttribute("dndData");
+                       map[node.id] = {
+                               data: data || node.innerHTML,
+                               type: type ? type.split(/\s*,\s*/) : ["text"]
+                       };
+               }, this);
+               this.map = map;
+               return this;    // self
        },
-
-       pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){
+       insertNodes: function(data, before, anchor){
                // summary:
-               //              Move or copy an item from one parent item to another.
-               //              Used in drag & drop
-               if(oldParentItem === this.root){
-                       if(!bCopy){
-                               // It's onLeaveRoot()'s responsibility to modify the item so it no longer matches
-                               // this.query... thus triggering an onChildrenChange() event to notify the Tree
-                               // that this element is no longer a child of the root node
-                               this.onLeaveRoot(childItem);
+               //              inserts an array of new nodes before/after an anchor node
+               // data: Array
+               //              a list of data items, which should be processed by the creator function
+               // before: Boolean
+               //              insert before the anchor, if true, and after the anchor otherwise
+               // anchor: Node
+               //              the anchor node to be used as a point of insertion
+               if(!this.parent.firstChild){
+                       anchor = null;
+               }else if(before){
+                       if(!anchor){
+                               anchor = this.parent.firstChild;
+                       }
+               }else{
+                       if(anchor){
+                               anchor = anchor.nextSibling;
                        }
                }
-               dijit.tree.TreeStoreModel.prototype.pasteItem.call(this, childItem,
-                       oldParentItem === this.root ? null : oldParentItem,
-                       newParentItem === this.root ? null : newParentItem,
-                       bCopy,
-                       insertIndex
-               );
-               if(newParentItem === this.root){
-                       // It's onAddToRoot()'s responsibility to modify the item so it matches
-                       // this.query... thus triggering an onChildrenChange() event to notify the Tree
-                       // that this element is now a child of the root node
-                       this.onAddToRoot(childItem);
+               if(anchor){
+                       for(var i = 0; i < data.length; ++i){
+                               var t = this._normalizedCreator(data[i]);
+                               this.setItem(t.node.id, {data: t.data, type: t.type});
+                               this.parent.insertBefore(t.node, anchor);
+                       }
+               }else{
+                       for(var i = 0; i < data.length; ++i){
+                               var t = this._normalizedCreator(data[i]);
+                               this.setItem(t.node.id, {data: t.data, type: t.type});
+                               this.parent.appendChild(t.node);
+                       }
                }
+               return this;    // self
        },
-
-       // =======================================================================
-       // Handling for top level children
-
-       onAddToRoot: function(/* item */ item){
-               // summary:
-               //              Called when item added to root of tree; user must override this method
-               //              to modify the item so that it matches the query for top level items
-               // example:
-               //      |       store.setValue(item, "root", true);
-               // tags:
-               //              extension
-               console.log(this, ": item ", item, " added to root");
-       },
-
-       onLeaveRoot: function(/* item */ item){
+       destroy: function(){
                // summary:
-               //              Called when item removed from root of tree; user must override this method
-               //              to modify the item so it doesn't match the query for top level items
-               // example:
-               //      |       store.unsetAttribute(item, "root");
-               // tags:
-               //              extension
-               console.log(this, ": item ", item, " removed from root");
-       },
-
-       // =======================================================================
-       // Events from data store
-
-       _requeryTop: function(){
-               // reruns the query for the children of the root node,
-               // sending out an onSet notification if those children have changed
-               var oldChildren = this.root.children || [];
-               this.store.fetch({
-                       query: this.query,
-                       onComplete: dojo.hitch(this, function(newChildren){
-                               this.root.children = newChildren;
-
-                               // If the list of children or the order of children has changed...
-                               if(oldChildren.length != newChildren.length ||
-                                       dojo.some(oldChildren, function(item, idx){ return newChildren[idx] != item;})){
-                                       this.onChildrenChange(this.root, newChildren);
-                               }
-                       })
-               });
+               //              prepares this object to be garbage-collected
+               dojo.forEach(this.events, dojo.disconnect);
+               this.clearItems();
+               this.node = this.parent = this.current = null;
        },
 
-       onNewItem: function(/* dojo.data.Item */ item, /* Object */ parentInfo){
-               // summary:
-               //              Handler for when new items appear in the store.  Developers should override this
-               //              method to be more efficient based on their app/data.
-               // description:
-               //              Note that the default implementation requeries the top level items every time
-               //              a new item is created, since any new item could be a top level item (even in
-               //              addition to being a child of another item, since items can have multiple parents).
-               //
-               //              Developers can override this function to do something more efficient if they can
-               //              detect which items are possible top level items (based on the item and the
-               //              parentInfo parameters).  Often all top level items have parentInfo==null, but
-               //              that will depend on which store you use and what your data is like.
-               // tags:
-               //              extension
-               this._requeryTop();
-
-               this.inherited(arguments);
+       // markup methods
+       markupFactory: function(params, node){
+               params._skipStartup = true;
+               return new dojo.dnd.Container(node, params);
        },
-
-       onDeleteItem: function(/*Object*/ item){
+       startup: function(){
                // summary:
-               //              Handler for delete notifications from underlying store
-
-               // check if this was a child of root, and if so send notification that root's children
-               // have changed
-               if(dojo.indexOf(this.root.children, item) != -1){
-                       this._requeryTop();
+               //              collects valid child items and populate the map
+               
+               // set up the real parent node
+               if(!this.parent){
+                       // use the standard algorithm, if not assigned
+                       this.parent = this.node;
+                       if(this.parent.tagName.toLowerCase() == "table"){
+                               var c = this.parent.getElementsByTagName("tbody");
+                               if(c && c.length){ this.parent = c[0]; }
+                       }
                }
+               this.defaultCreator = dojo.dnd._defaultCreator(this.parent);
 
-               this.inherited(arguments);
-       }
-});
-
-
-
-}
-
-if(!dojo._hasResource["dijit.Tree"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dijit.Tree"] = true;
-dojo.provide("dijit.Tree");
-
-
-
-
-
-
-
-
-
-
-
-dojo.declare(
-       "dijit._TreeNode",
-       [dijit._Widget, dijit._Templated, dijit._Container, dijit._Contained, dijit._CssStateMixin],
-{
-       // summary:
-       //              Single node within a tree.   This class is used internally
-       //              by Tree and should not be accessed directly.
-       // tags:
-       //              private
-
-       // item: dojo.data.Item
-       //              the dojo.data entry this tree represents
-       item: null,
-
-       // isTreeNode: [protected] Boolean
-       //              Indicates that this is a TreeNode.   Used by `dijit.Tree` only,
-       //              should not be accessed directly.
-       isTreeNode: true,
-
-       // label: String
-       //              Text of this tree node
-       label: "",
-
-       // isExpandable: [private] Boolean
-       //              This node has children, so show the expando node (+ sign)
-       isExpandable: null,
-
-       // isExpanded: [readonly] Boolean
-       //              This node is currently expanded (ie, opened)
-       isExpanded: false,
-
-       // state: [private] String
-       //              Dynamic loading-related stuff.
-       //              When an empty folder node appears, it is "UNCHECKED" first,
-       //              then after dojo.data query it becomes "LOADING" and, finally "LOADED"
-       state: "UNCHECKED",
-
-       templateString: dojo.cache("dijit", "templates/TreeNode.html", "<div class=\"dijitTreeNode\" waiRole=\"presentation\"\n\t><div dojoAttachPoint=\"rowNode\" class=\"dijitTreeRow\" waiRole=\"presentation\" dojoAttachEvent=\"onmouseenter:_onMouseEnter, onmouseleave:_onMouseLeave, onclick:_onClick, ondblclick:_onDblClick\"\n\t\t><img src=\"${_blankGif}\" alt=\"\" dojoAttachPoint=\"expandoNode\" class=\"dijitTreeExpando\" waiRole=\"presentation\"\n\t\t/><span dojoAttachPoint=\"expandoNodeText\" class=\"dijitExpandoText\" waiRole=\"presentation\"\n\t\t></span\n\t\t><span dojoAttachPoint=\"contentNode\"\n\t\t\tclass=\"dijitTreeContent\" waiRole=\"presentation\">\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" dojoAttachPoint=\"iconNode\" class=\"dijitIcon dijitTreeIcon\" waiRole=\"presentation\"\n\t\t\t/><span dojoAttachPoint=\"labelNode\" class=\"dijitTreeLabel\" wairole=\"treeitem\" tabindex=\"-1\" waiState=\"selected-false\" dojoAttachEvent=\"onfocus:_onLabelFocus\"></span>\n\t\t</span\n\t></div>\n\t<div dojoAttachPoint=\"containerNode\" class=\"dijitTreeContainer\" waiRole=\"presentation\" style=\"display: none;\"></div>\n</div>\n"),
-
-       baseClass: "dijitTreeNode",
-
-       // For hover effect for tree node, and focus effect for label
-       cssStateNodes: {
-               rowNode: "dijitTreeRow",
-               labelNode: "dijitTreeLabel"
+               // process specially marked children
+               this.sync();
        },
 
-       attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
-               label: {node: "labelNode", type: "innerText"},
-               tooltip: {node: "rowNode", type: "attribute", attribute: "title"}
-       }),
-
-       postCreate: function(){
-               this.inherited(arguments);
-
-               // set expand icon for leaf
-               this._setExpando();
-
-               // set icon and label class based on item
-               this._updateItemClasses(this.item);
-
-               if(this.isExpandable){
-                       dijit.setWaiState(this.labelNode, "expanded", this.isExpanded);
+       // mouse events
+       onMouseOver: function(e){
+               // summary:
+               //              event processor for onmouseover
+               // e: Event
+               //              mouse event
+               var n = e.relatedTarget;
+               while(n){
+                       if(n == this.node){ break; }
+                       try{
+                               n = n.parentNode;
+                       }catch(x){
+                               n = null;
+                       }
                }
+               if(!n){
+                       this._changeState("Container", "Over");
+                       this.onOverEvent();
+               }
+               n = this._getChildByEvent(e);
+               if(this.current == n){ return; }
+               if(this.current){ this._removeItemClass(this.current, "Over"); }
+               if(n){ this._addItemClass(n, "Over"); }
+               this.current = n;
        },
-
-       _setIndentAttr: function(indent){
+       onMouseOut: function(e){
                // summary:
-               //              Tell this node how many levels it should be indented
-               // description:
-               //              0 for top level nodes, 1 for their children, 2 for their
-               //              grandchildren, etc.
-               this.indent = indent;
-
-               // Math.max() is to prevent negative padding on hidden root node (when indent == -1)
-               var pixels = (Math.max(indent, 0) * this.tree._nodePixelIndent) + "px";
-
-               dojo.style(this.domNode, "backgroundPosition",  pixels + " 0px");
-               dojo.style(this.rowNode, this.isLeftToRight() ? "paddingLeft" : "paddingRight", pixels);
-
-               dojo.forEach(this.getChildren(), function(child){
-                       child.set("indent", indent+1);
-               });
+               //              event processor for onmouseout
+               // e: Event
+               //              mouse event
+               for(var n = e.relatedTarget; n;){
+                       if(n == this.node){ return; }
+                       try{
+                               n = n.parentNode;
+                       }catch(x){
+                               n = null;
+                       }
+               }
+               if(this.current){
+                       this._removeItemClass(this.current, "Over");
+                       this.current = null;
+               }
+               this._changeState("Container", "");
+               this.onOutEvent();
        },
-
-       markProcessing: function(){
+       onSelectStart: function(e){
                // summary:
-               //              Visually denote that tree is loading data, etc.
-               // tags:
-               //              private
-               this.state = "LOADING";
-               this._setExpando(true);
+               //              event processor for onselectevent and ondragevent
+               // e: Event
+               //              mouse event
+               if(!this.skipForm || !dojo.dnd.isFormElement(e)){
+                       dojo.stopEvent(e);
+               }
        },
-
-       unmarkProcessing: function(){
+       
+       // utilities
+       onOverEvent: function(){
                // summary:
-               //              Clear markup from markProcessing() call
-               // tags:
-               //              private
-               this._setExpando(false);
+               //              this function is called once, when mouse is over our container
        },
-
-       _updateItemClasses: function(item){
+       onOutEvent: function(){
                // summary:
-               //              Set appropriate CSS classes for icon and label dom node
-               //              (used to allow for item updates to change respective CSS)
-               // tags:
-               //              private
-               var tree = this.tree, model = tree.model;
-               if(tree._v10Compat && item === model.root){
-                       // For back-compat with 1.0, need to use null to specify root item (TODO: remove in 2.0)
-                       item = null;
-               }
-               this._applyClassAndStyle(item, "icon", "Icon");
-               this._applyClassAndStyle(item, "label", "Label");
-               this._applyClassAndStyle(item, "row", "Row");
+               //              this function is called once, when mouse is out of our container
        },
-
-       _applyClassAndStyle: function(item, lower, upper){
-               // summary:
-               //              Set the appropriate CSS classes and styles for labels, icons and rows.
-               //
-               // item:
-               //              The data item.
-               //
-               // lower:
-               //              The lower case attribute to use, e.g. 'icon', 'label' or 'row'.
-               //
-               // upper:
-               //              The upper case attribute to use, e.g. 'Icon', 'Label' or 'Row'.
-               //
-               // tags:
-               //              private
-
-               var clsName = "_" + lower + "Class";
-               var nodeName = lower + "Node";
-
-               if(this[clsName]){
-                       dojo.removeClass(this[nodeName], this[clsName]);
-               }
-               this[clsName] = this.tree["get" + upper + "Class"](item, this.isExpanded);
-               if(this[clsName]){
-                       dojo.addClass(this[nodeName], this[clsName]);
-               }
-               dojo.style(this[nodeName], this.tree["get" + upper + "Style"](item, this.isExpanded) || {});
-       },
-
-       _updateLayout: function(){
+       _changeState: function(type, newState){
                // summary:
-               //              Set appropriate CSS classes for this.domNode
-               // tags:
-               //              private
-               var parent = this.getParent();
-               if(!parent || parent.rowNode.style.display == "none"){
-                       /* if we are hiding the root node then make every first level child look like a root node */
-                       dojo.addClass(this.domNode, "dijitTreeIsRoot");
-               }else{
-                       dojo.toggleClass(this.domNode, "dijitTreeIsLast", !this.getNextSibling());
-               }
+               //              changes a named state to new state value
+               // type: String
+               //              a name of the state to change
+               // newState: String
+               //              new state
+               var prefix = "dojoDnd" + type;
+               var state  = type.toLowerCase() + "State";
+               //dojo.replaceClass(this.node, prefix + newState, prefix + this[state]);
+               dojo.replaceClass(this.node, prefix + newState, prefix + this[state]);
+               this[state] = newState;
        },
-
-       _setExpando: function(/*Boolean*/ processing){
+       _addItemClass: function(node, type){
                // summary:
-               //              Set the right image for the expando node
-               // tags:
-               //              private
-
-               var styles = ["dijitTreeExpandoLoading", "dijitTreeExpandoOpened",
-                                               "dijitTreeExpandoClosed", "dijitTreeExpandoLeaf"],
-                       _a11yStates = ["*","-","+","*"],
-                       idx = processing ? 0 : (this.isExpandable ?     (this.isExpanded ? 1 : 2) : 3);
-
-               // apply the appropriate class to the expando node
-               dojo.removeClass(this.expandoNode, styles);
-               dojo.addClass(this.expandoNode, styles[idx]);
-
-               // provide a non-image based indicator for images-off mode
-               this.expandoNodeText.innerHTML = _a11yStates[idx];
-
+               //              adds a class with prefix "dojoDndItem"
+               // node: Node
+               //              a node
+               // type: String
+               //              a variable suffix for a class name
+               dojo.addClass(node, "dojoDndItem" + type);
        },
-
-       expand: function(){
+       _removeItemClass: function(node, type){
                // summary:
-               //              Show my children
-               // returns:
-               //              Deferred that fires when expansion is complete
-
-               // If there's already an expand in progress or we are already expanded, just return
-               if(this._expandDeferred){
-                       return this._expandDeferred;            // dojo.Deferred
-               }
-
-               // cancel in progress collapse operation
-               this._wipeOut && this._wipeOut.stop();
-
-               // All the state information for when a node is expanded, maybe this should be
-               // set when the animation completes instead
-               this.isExpanded = true;
-               dijit.setWaiState(this.labelNode, "expanded", "true");
-               dijit.setWaiRole(this.containerNode, "group");
-               dojo.addClass(this.contentNode,'dijitTreeContentExpanded');
-               this._setExpando();
-               this._updateItemClasses(this.item);
-               if(this == this.tree.rootNode){
-                       dijit.setWaiState(this.tree.domNode, "expanded", "true");
-               }
-
-               var def,
-                       wipeIn = dojo.fx.wipeIn({
-                               node: this.containerNode, duration: dijit.defaultDuration,
-                               onEnd: function(){
-                                       def.callback(true);
-                               }
-                       });
-
-               // Deferred that fires when expand is complete
-               def = (this._expandDeferred = new dojo.Deferred(function(){
-                       // Canceller
-                       wipeIn.stop();
-               }));
-
-               wipeIn.play();
-
-               return def;             // dojo.Deferred
+               //              removes a class with prefix "dojoDndItem"
+               // node: Node
+               //              a node
+               // type: String
+               //              a variable suffix for a class name
+               dojo.removeClass(node, "dojoDndItem" + type);
        },
-
-       collapse: function(){
+       _getChildByEvent: function(e){
                // summary:
-               //              Collapse this node (if it's expanded)
-
-               if(!this.isExpanded){ return; }
-
-               // cancel in progress expand operation
-               if(this._expandDeferred){
-                       this._expandDeferred.cancel();
-                       delete this._expandDeferred;
-               }
-
-               this.isExpanded = false;
-               dijit.setWaiState(this.labelNode, "expanded", "false");
-               if(this == this.tree.rootNode){
-                       dijit.setWaiState(this.tree.domNode, "expanded", "false");
-               }
-               dojo.removeClass(this.contentNode,'dijitTreeContentExpanded');
-               this._setExpando();
-               this._updateItemClasses(this.item);
-
-               if(!this._wipeOut){
-                       this._wipeOut = dojo.fx.wipeOut({
-                               node: this.containerNode, duration: dijit.defaultDuration
-                       });
+               //              gets a child, which is under the mouse at the moment, or null
+               // e: Event
+               //              a mouse event
+               var node = e.target;
+               if(node){
+                       for(var parent = node.parentNode; parent; node = parent, parent = node.parentNode){
+                               if(parent == this.parent && dojo.hasClass(node, "dojoDndItem")){ return node; }
+                       }
                }
-               this._wipeOut.play();
+               return null;
        },
-
-       // indent: Integer
-       //              Levels from this node to the root node
-       indent: 0,
-
-       setChildItems: function(/* Object[] */ items){
+       _normalizedCreator: function(/*dojo.dnd.Item*/ item, /*String*/ hint){
                // summary:
-               //              Sets the child items of this node, removing/adding nodes
-               //              from current children to match specified items[] array.
-               //              Also, if this.persist == true, expands any children that were previously
-               //              opened.
-               // returns:
-               //              Deferred object that fires after all previously opened children
-               //              have been expanded again (or fires instantly if there are no such children).
-
-               var tree = this.tree,
-                       model = tree.model,
-                       defs = [];      // list of deferreds that need to fire before I am complete
-
-
-               // Orphan all my existing children.
-               // If items contains some of the same items as before then we will reattach them.
-               // Don't call this.removeChild() because that will collapse the tree etc.
-               dojo.forEach(this.getChildren(), function(child){
-                       dijit._Container.prototype.removeChild.call(this, child);
-               }, this);
+               //              adds all necessary data to the output of the user-supplied creator function
+               var t = (this.creator || this.defaultCreator).call(this, item, hint);
+               if(!dojo.isArray(t.type)){ t.type = ["text"]; }
+               if(!t.node.id){ t.node.id = dojo.dnd.getUniqueId(); }
+               dojo.addClass(t.node, "dojoDndItem");
+               return t;
+       }
+});
 
-               this.state = "LOADED";
+dojo.dnd._createNode = function(tag){
+       // summary:
+       //              returns a function, which creates an element of given tag
+       //              (SPAN by default) and sets its innerHTML to given text
+       // tag: String
+       //              a tag name or empty for SPAN
+       if(!tag){ return dojo.dnd._createSpan; }
+       return function(text){  // Function
+               return dojo.create(tag, {innerHTML: text});     // Node
+       };
+};
 
-               if(items && items.length > 0){
-                       this.isExpandable = true;
+dojo.dnd._createTrTd = function(text){
+       // summary:
+       //              creates a TR/TD structure with given text as an innerHTML of TD
+       // text: String
+       //              a text for TD
+       var tr = dojo.create("tr");
+       dojo.create("td", {innerHTML: text}, tr);
+       return tr;      // Node
+};
 
-                       // Create _TreeNode widget for each specified tree node, unless one already
-                       // exists and isn't being used (presumably it's from a DnD move and was recently
-                       // released
-                       dojo.forEach(items, function(item){
-                               var id = model.getIdentity(item),
-                                       existingNodes = tree._itemNodesMap[id],
-                                       node;
-                               if(existingNodes){
-                                       for(var i=0;i<existingNodes.length;i++){
-                                               if(existingNodes[i] && !existingNodes[i].getParent()){
-                                                       node = existingNodes[i];
-                                                       node.set('indent', this.indent+1);
-                                                       break;
-                                               }
-                                       }
-                               }
-                               if(!node){
-                                       node = this.tree._createTreeNode({
-                                                       item: item,
-                                                       tree: tree,
-                                                       isExpandable: model.mayHaveChildren(item),
-                                                       label: tree.getLabel(item),
-                                                       tooltip: tree.getTooltip(item),
-                                                       dir: tree.dir,
-                                                       lang: tree.lang,
-                                                       indent: this.indent + 1
-                                               });
-                                       if(existingNodes){
-                                               existingNodes.push(node);
-                                       }else{
-                                               tree._itemNodesMap[id] = [node];
-                                       }
-                               }
-                               this.addChild(node);
+dojo.dnd._createSpan = function(text){
+       // summary:
+       //              creates a SPAN element with given text as its innerHTML
+       // text: String
+       //              a text for SPAN
+       return dojo.create("span", {innerHTML: text});  // Node
+};
 
-                               // If node was previously opened then open it again now (this may trigger
-                               // more data store accesses, recursively)
-                               if(this.tree.autoExpand || this.tree._state(item)){
-                                       defs.push(tree._expandNode(node));
-                               }
-                       }, this);
+// dojo.dnd._defaultCreatorNodes: Object
+//             a dictionary that maps container tag names to child tag names
+dojo.dnd._defaultCreatorNodes = {ul: "li", ol: "li", div: "div", p: "div"};
 
-                       // note that updateLayout() needs to be called on each child after
-                       // _all_ the children exist
-                       dojo.forEach(this.getChildren(), function(child, idx){
-                               child._updateLayout();
-                       });
+dojo.dnd._defaultCreator = function(node){
+       // summary:
+       //              takes a parent node, and returns an appropriate creator function
+       // node: Node
+       //              a container node
+       var tag = node.tagName.toLowerCase();
+       var c = tag == "tbody" || tag == "thead" ? dojo.dnd._createTrTd :
+                       dojo.dnd._createNode(dojo.dnd._defaultCreatorNodes[tag]);
+       return function(item, hint){    // Function
+               var isObj = item && dojo.isObject(item), data, type, n;
+               if(isObj && item.tagName && item.nodeType && item.getAttribute){
+                       // process a DOM node
+                       data = item.getAttribute("dndData") || item.innerHTML;
+                       type = item.getAttribute("dndType");
+                       type = type ? type.split(/\s*,\s*/) : ["text"];
+                       n = item;       // this node is going to be moved rather than copied
                }else{
-                       this.isExpandable=false;
+                       // process a DnD item object or a string
+                       data = (isObj && item.data) ? item.data : item;
+                       type = (isObj && item.type) ? item.type : ["text"];
+                       n = (hint == "avatar" ? dojo.dnd._createSpan : c)(String(data));
                }
+               if(!n.id){
+                       n.id = dojo.dnd.getUniqueId();
+               }
+               return {node: n, data: data, type: type};
+       };
+};
+
+}
 
-               if(this._setExpando){
-                       // change expando to/from dot or + icon, as appropriate
-                       this._setExpando(false);
-               }
+if(!dojo._hasResource["dijit.tree._dndContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.tree._dndContainer"] = true;
+dojo.provide("dijit.tree._dndContainer");
 
-               // Set leaf icon or folder icon, as appropriate
-               this._updateItemClasses(this.item);
 
-               // On initial tree show, make the selected TreeNode as either the root node of the tree,
-               // or the first child, if the root node is hidden
-               if(this == tree.rootNode){
-                       var fc = this.tree.showRoot ? this : this.getChildren()[0];
-                       if(fc){
-                               fc.setFocusable(true);
-                               tree.lastFocused = fc;
-                       }else{
-                               // fallback: no nodes in tree so focus on Tree <div> itself
-                               tree.domNode.setAttribute("tabIndex", "0");
-                       }
-               }
 
-               return new dojo.DeferredList(defs);     // dojo.Deferred
-       },
 
-       removeChild: function(/* treeNode */ node){
-               this.inherited(arguments);
+dojo.getObject("tree", true, dojo);
 
-               var children = this.getChildren();
-               if(children.length == 0){
-                       this.isExpandable = false;
-                       this.collapse();
-               }
+dijit.tree._compareNodes = function(n1, n2){
+       if(n1 === n2){
+               return 0;
+       }
+       
+       if('sourceIndex' in document.documentElement){ //IE
+               //TODO: does not yet work if n1 and/or n2 is a text node
+               return n1.sourceIndex - n2.sourceIndex;
+       }else if('compareDocumentPosition' in document.documentElement){ //FF, Opera
+               return n1.compareDocumentPosition(n2) & 2 ? 1: -1;
+       }else if(document.createRange){ //Webkit
+               var r1 = doc.createRange();
+               r1.setStartBefore(n1);
+
+               var r2 = doc.createRange();
+               r2.setStartBefore(n2);
+
+               return r1.compareBoundaryPoints(r1.END_TO_END, r2);
+       }else{
+               throw Error("dijit.tree._compareNodes don't know how to compare two different nodes in this browser");
+       }
+};
 
-               dojo.forEach(children, function(child){
-                               child._updateLayout();
-               });
-       },
+dojo.declare("dijit.tree._dndContainer",
+       null,
+       {
 
-       makeExpandable: function(){
                // summary:
-               //              if this node wasn't already showing the expando node,
-               //              turn it into one and call _setExpando()
+               //              This is a base class for `dijit.tree._dndSelector`, and isn't meant to be used directly.
+               //              It's modeled after `dojo.dnd.Container`.
+               // tags:
+               //              protected
 
-               // TODO: hmm this isn't called from anywhere, maybe should remove it for 2.0
+               /*=====
+               // current: DomNode
+               //              The currently hovered TreeNode.rowNode (which is the DOM node
+               //              associated w/a given node in the tree, excluding it's descendants)
+               current: null,
+               =====*/
 
-               this.isExpandable = true;
-               this._setExpando(false);
-       },
+               constructor: function(tree, params){
+                       // summary:
+                       //              A constructor of the Container
+                       // tree: Node
+                       //              Node or node's id to build the container on
+                       // params: dijit.tree.__SourceArgs
+                       //              A dict of parameters, which gets mixed into the object
+                       // tags:
+                       //              private
+                       this.tree = tree;
+                       this.node = tree.domNode;       // TODO: rename; it's not a TreeNode but the whole Tree
+                       dojo.mixin(this, params);
 
-       _onLabelFocus: function(evt){
-               // summary:
-               //              Called when this row is focused (possibly programatically)
-               //              Note that we aren't using _onFocus() builtin to dijit
-               //              because it's called when focus is moved to a descendant TreeNode.
-               // tags:
-               //              private
-               this.tree._onNodeFocus(this);
-       },
+                       // class-specific variables
+                       this.map = {};
+                       this.current = null;    // current TreeNode's DOM node
 
-       setSelected: function(/*Boolean*/ selected){
-               // summary:
-               //              A Tree has a (single) currently selected node.
-               //              Mark that this node is/isn't that currently selected node.
-               // description:
-               //              In particular, setting a node as selected involves setting tabIndex
-               //              so that when user tabs to the tree, focus will go to that node (only).
-               dijit.setWaiState(this.labelNode, "selected", selected);
-               dojo.toggleClass(this.rowNode, "dijitTreeRowSelected", selected);
-       },
+                       // states
+                       this.containerState = "";
+                       dojo.addClass(this.node, "dojoDndContainer");
 
-       setFocusable: function(/*Boolean*/ selected){
-               // summary:
-               //              A Tree has a (single) node that's focusable.
-               //              Mark that this node is/isn't that currently focsuable node.
-               // description:
-               //              In particular, setting a node as selected involves setting tabIndex
-               //              so that when user tabs to the tree, focus will go to that node (only).
+                       // set up events
+                       this.events = [
+                               // container level events
+                               dojo.connect(this.node, "onmouseenter", this, "onOverEvent"),
+                               dojo.connect(this.node, "onmouseleave", this, "onOutEvent"),
 
-               this.labelNode.setAttribute("tabIndex", selected ? "0" : "-1");
-       },
+                               // switching between TreeNodes
+                               dojo.connect(this.tree, "_onNodeMouseEnter", this, "onMouseOver"),
+                               dojo.connect(this.tree, "_onNodeMouseLeave", this, "onMouseOut"),
 
-       _onClick: function(evt){
-               // summary:
-               //              Handler for onclick event on a node
-               // tags:
-               //              private
-               this.tree._onClick(this, evt);
-       },
-       _onDblClick: function(evt){
-               // summary:
-               //              Handler for ondblclick event on a node
-               // tags:
-               //              private
-               this.tree._onDblClick(this, evt);
-       },
+                               // cancel text selection and text dragging
+                               dojo.connect(this.node, "ondragstart", dojo, "stopEvent"),
+                               dojo.connect(this.node, "onselectstart", dojo, "stopEvent")
+                       ];
+               },
 
-       _onMouseEnter: function(evt){
-               // summary:
-               //              Handler for onmouseenter event on a node
-               // tags:
-               //              private
-               this.tree._onNodeMouseEnter(this, evt);
-       },
+               getItem: function(/*String*/ key){
+                       // summary:
+                       //              Returns the dojo.dnd.Item (representing a dragged node) by it's key (id).
+                       //              Called by dojo.dnd.Source.checkAcceptance().
+                       // tags:
+                       //              protected
 
-       _onMouseLeave: function(evt){
-               // summary:
-               //              Handler for onmouseenter event on a node
-               // tags:
-               //              private
-               this.tree._onNodeMouseLeave(this, evt);
-       }
-});
+                       var widget = this.selection[key],
+                               ret = {
+                                       data: widget,
+                                       type: ["treeNode"]
+                               };
 
-dojo.declare(
-       "dijit.Tree",
-       [dijit._Widget, dijit._Templated],
-{
-       // summary:
-       //              This widget displays hierarchical data from a store.
+                       return ret;     // dojo.dnd.Item
+               },
 
-       // store: [deprecated] String||dojo.data.Store
-       //              Deprecated.  Use "model" parameter instead.
-       //              The store to get data to display in the tree.
-       store: null,
+               destroy: function(){
+                       // summary:
+                       //              Prepares this object to be garbage-collected
 
-       // model: dijit.Tree.model
-       //              Interface to read tree data, get notifications of changes to tree data,
-       //              and for handling drop operations (i.e drag and drop onto the tree)
-       model: null,
+                       dojo.forEach(this.events, dojo.disconnect);
+                       // this.clearItems();
+                       this.node = this.parent = null;
+               },
 
-       // query: [deprecated] anything
-       //              Deprecated.  User should specify query to the model directly instead.
-       //              Specifies datastore query to return the root item or top items for the tree.
-       query: null,
+               // mouse events
+               onMouseOver: function(/*TreeNode*/ widget, /*Event*/ evt){
+                       // summary:
+                       //              Called when mouse is moved over a TreeNode
+                       // tags:
+                       //              protected
+                       this.current = widget;
+               },
 
-       // label: [deprecated] String
-       //              Deprecated.  Use dijit.tree.ForestStoreModel directly instead.
-       //              Used in conjunction with query parameter.
-       //              If a query is specified (rather than a root node id), and a label is also specified,
-       //              then a fake root node is created and displayed, with this label.
-       label: "",
+               onMouseOut: function(/*TreeNode*/ widget, /*Event*/ evt){
+                       // summary:
+                       //              Called when mouse is moved away from a TreeNode
+                       // tags:
+                       //              protected
+                       this.current = null;
+               },
 
-       // showRoot: [const] Boolean
-       //              Should the root node be displayed, or hidden?
-       showRoot: true,
+               _changeState: function(type, newState){
+                       // summary:
+                       //              Changes a named state to new state value
+                       // type: String
+                       //              A name of the state to change
+                       // newState: String
+                       //              new state
+                       var prefix = "dojoDnd" + type;
+                       var state = type.toLowerCase() + "State";
+                       //dojo.replaceClass(this.node, prefix + newState, prefix + this[state]);
+                       dojo.replaceClass(this.node, prefix + newState, prefix + this[state]);
+                       this[state] = newState;
+               },
 
-       // childrenAttr: [deprecated] String[]
-       //              Deprecated.   This information should be specified in the model.
-       //              One ore more attributes that holds children of a tree node
-       childrenAttr: ["children"],
+               _addItemClass: function(node, type){
+                       // summary:
+                       //              Adds a class with prefix "dojoDndItem"
+                       // node: Node
+                       //              A node
+                       // type: String
+                       //              A variable suffix for a class name
+                       dojo.addClass(node, "dojoDndItem" + type);
+               },
 
-       // path: String[] or Item[]
-       //              Full path from rootNode to selected node expressed as array of items or array of ids.
-       //              Since setting the path may be asynchronous (because ofwaiting on dojo.data), set("path", ...)
-       //              returns a Deferred to indicate when the set is complete.
-       path: [],
+               _removeItemClass: function(node, type){
+                       // summary:
+                       //              Removes a class with prefix "dojoDndItem"
+                       // node: Node
+                       //              A node
+                       // type: String
+                       //              A variable suffix for a class name
+                       dojo.removeClass(node, "dojoDndItem" + type);
+               },
 
-       // selectedItem: [readonly] Item
-       //              The currently selected item in this tree.
-       //              This property can only be set (via set('selectedItem', ...)) when that item is already
-       //              visible in the tree.   (I.e. the tree has already been expanded to show that node.)
-       //              Should generally use `path` attribute to set the selected item instead.
-       selectedItem: null,
+               onOverEvent: function(){
+                       // summary:
+                       //              This function is called once, when mouse is over our container
+                       // tags:
+                       //              protected
+                       this._changeState("Container", "Over");
+               },
+
+               onOutEvent: function(){
+                       // summary:
+                       //              This function is called once, when mouse is out of our container
+                       // tags:
+                       //              protected
+                       this._changeState("Container", "");
+               }
+});
 
-       // openOnClick: Boolean
-       //              If true, clicking a folder node's label will open it, rather than calling onClick()
-       openOnClick: false,
+}
 
-       // openOnDblClick: Boolean
-       //              If true, double-clicking a folder node's label will open it, rather than calling onDblClick()
-       openOnDblClick: false,
+if(!dojo._hasResource["dijit.tree._dndSelector"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.tree._dndSelector"] = true;
+dojo.provide("dijit.tree._dndSelector");
 
-       templateString: dojo.cache("dijit", "templates/Tree.html", "<div class=\"dijitTree dijitTreeContainer\" waiRole=\"tree\"\n\tdojoAttachEvent=\"onkeypress:_onKeyPress\">\n\t<div class=\"dijitInline dijitTreeIndent\" style=\"position: absolute; top: -9999px\" dojoAttachPoint=\"indentDetector\"></div>\n</div>\n"),
 
-       // persist: Boolean
-       //              Enables/disables use of cookies for state saving.
-       persist: true,
 
-       // autoExpand: Boolean
-       //              Fully expand the tree on load.   Overrides `persist`
-       autoExpand: false,
 
-       // dndController: [protected] String
-       //              Class name to use as as the dnd controller.  Specifying this class enables DnD.
-       //              Generally you should specify this as "dijit.tree.dndSource".
-       dndController: null,
+dojo.declare("dijit.tree._dndSelector",
+       dijit.tree._dndContainer,
+       {
+               // summary:
+               //              This is a base class for `dijit.tree.dndSource` , and isn't meant to be used directly.
+               //              It's based on `dojo.dnd.Selector`.
+               // tags:
+               //              protected
 
-       // parameters to pull off of the tree and pass on to the dndController as its params
-       dndParams: ["onDndDrop","itemCreator","onDndCancel","checkAcceptance", "checkItemAcceptance", "dragThreshold", "betweenThreshold"],
+               /*=====
+               // selection: Hash<String, DomNode>
+               //              (id, DomNode) map for every TreeNode that's currently selected.
+               //              The DOMNode is the TreeNode.rowNode.
+               selection: {},
+               =====*/
 
-       //declare the above items so they can be pulled from the tree's markup
+               constructor: function(tree, params){
+                       // summary:
+                       //              Initialization
+                       // tags:
+                       //              private
 
-       // onDndDrop: [protected] Function
-       //              Parameter to dndController, see `dijit.tree.dndSource.onDndDrop`.
-       //              Generally this doesn't need to be set.
-       onDndDrop: null,
+                       this.selection={};
+                       this.anchor = null;
 
-       /*=====
-       itemCreator: function(nodes, target, source){
-               // summary:
-               //              Returns objects passed to `Tree.model.newItem()` based on DnD nodes
-               //              dropped onto the tree.   Developer must override this method to enable
-               //              dropping from external sources onto this Tree, unless the Tree.model's items
-               //              happen to look like {id: 123, name: "Apple" } with no other attributes.
-               // description:
-               //              For each node in nodes[], which came from source, create a hash of name/value
-               //              pairs to be passed to Tree.model.newItem().  Returns array of those hashes.
-               // nodes: DomNode[]
-               //              The DOMNodes dragged from the source container
-               // target: DomNode
-               //              The target TreeNode.rowNode
-               // source: dojo.dnd.Source
-               //              The source container the nodes were dragged from, perhaps another Tree or a plain dojo.dnd.Source
-               // returns: Object[]
-               //              Array of name/value hashes for each new item to be added to the Tree, like:
-               // |    [
-               // |            { id: 123, label: "apple", foo: "bar" },
-               // |            { id: 456, label: "pear", zaz: "bam" }
-               // |    ]
-               // tags:
-               //              extension
-               return [{}];
-       },
-       =====*/
-       itemCreator: null,
+                       dijit.setWaiState(this.tree.domNode, "multiselect", !this.singular);
 
-       // onDndCancel: [protected] Function
-       //              Parameter to dndController, see `dijit.tree.dndSource.onDndCancel`.
-       //              Generally this doesn't need to be set.
-       onDndCancel: null,
+                       this.events.push(
+                               dojo.connect(this.tree.domNode, "onmousedown", this,"onMouseDown"),
+                               dojo.connect(this.tree.domNode, "onmouseup", this,"onMouseUp"),
+                               dojo.connect(this.tree.domNode, "onmousemove", this,"onMouseMove")
+                       );
+               },
 
-/*=====
-       checkAcceptance: function(source, nodes){
-               // summary:
-               //              Checks if the Tree itself can accept nodes from this source
-               // source: dijit.tree._dndSource
-               //              The source which provides items
-               // nodes: DOMNode[]
-               //              Array of DOM nodes corresponding to nodes being dropped, dijitTreeRow nodes if
-               //              source is a dijit.Tree.
-               // tags:
-               //              extension
-               return true;    // Boolean
-       },
-=====*/
-       checkAcceptance: null,
+               //      singular: Boolean
+               //              Allows selection of only one element, if true.
+               //              Tree hasn't been tested in singular=true mode, unclear if it works.
+               singular: false,
 
-/*=====
-       checkItemAcceptance: function(target, source, position){
-               // summary:
-               //              Stub function to be overridden if one wants to check for the ability to drop at the node/item level
-               // description:
-               //              In the base case, this is called to check if target can become a child of source.
-               //              When betweenThreshold is set, position="before" or "after" means that we
-               //              are asking if the source node can be dropped before/after the target node.
-               // target: DOMNode
-               //              The dijitTreeRoot DOM node inside of the TreeNode that we are dropping on to
-               //              Use dijit.getEnclosingWidget(target) to get the TreeNode.
-               // source: dijit.tree.dndSource
-               //              The (set of) nodes we are dropping
-               // position: String
-               //              "over", "before", or "after"
-               // tags:
-               //              extension
-               return true;    // Boolean
-       },
-=====*/
-       checkItemAcceptance: null,
+               // methods
+               getSelectedTreeNodes: function(){
+                       // summary:
+                       //              Returns a list of selected node(s).
+                       //              Used by dndSource on the start of a drag.
+                       // tags:
+                       //              protected
+                       var nodes=[], sel = this.selection;
+                       for(var i in sel){
+                               nodes.push(sel[i]);
+                       }
+                       return nodes;
+               },
 
-       // dragThreshold: Integer
-       //              Number of pixels mouse moves before it's considered the start of a drag operation
-       dragThreshold: 5,
+               selectNone: function(){
+                       // summary:
+                       //              Unselects all items
+                       // tags:
+                       //              private
 
-       // betweenThreshold: Integer
-       //              Set to a positive value to allow drag and drop "between" nodes.
-       //
-       //              If during DnD mouse is over a (target) node but less than betweenThreshold
-       //              pixels from the bottom edge, dropping the the dragged node will make it
-       //              the next sibling of the target node, rather than the child.
-       //
-       //              Similarly, if mouse is over a target node but less that betweenThreshold
-       //              pixels from the top edge, dropping the dragged node will make it
-       //              the target node's previous sibling rather than the target node's child.
-       betweenThreshold: 0,
+                       this.setSelection([]);
+                       return this;    // self
+               },
 
-       // _nodePixelIndent: Integer
-       //              Number of pixels to indent tree nodes (relative to parent node).
-       //              Default is 19 but can be overridden by setting CSS class dijitTreeIndent
-       //              and calling resize() or startup() on tree after it's in the DOM.
-       _nodePixelIndent: 19,
+               destroy: function(){
+                       // summary:
+                       //              Prepares the object to be garbage-collected
+                       this.inherited(arguments);
+                       this.selection = this.anchor = null;
+               },
+               addTreeNode: function(/*dijit._TreeNode*/node, /*Boolean?*/isAnchor){
+                       // summary
+                       //              add node to current selection
+                       // node: Node
+                       //              node to add
+                       // isAnchor: Boolean
+                       //              Whether the node should become anchor.
 
-       _publish: function(/*String*/ topicName, /*Object*/ message){
-               // summary:
-               //              Publish a message for this widget/topic
-               dojo.publish(this.id, [dojo.mixin({tree: this, event: topicName}, message || {})]);
-       },
+                       this.setSelection(this.getSelectedTreeNodes().concat( [node] ));
+                       if(isAnchor){ this.anchor = node; }
+                       return node;
+               },
+               removeTreeNode: function(/*dijit._TreeNode*/node){
+                       // summary
+                       //              remove node from current selection
+                       // node: Node
+                       //              node to remove
+                       this.setSelection(this._setDifference(this.getSelectedTreeNodes(), [node]))
+                       return node;
+               },
+               isTreeNodeSelected: function(/*dijit._TreeNode*/node){
+                       // summary
+                       //              return true if node is currently selected
+                       // node: Node
+                       //              the node to check whether it's in the current selection
 
-       postMixInProperties: function(){
-               this.tree = this;
+                       return node.id && !!this.selection[node.id];
+               },
+               setSelection: function(/*dijit._treeNode[]*/ newSelection){
+                       // summary
+                       //      set the list of selected nodes to be exactly newSelection. All changes to the
+                       //      selection should be passed through this function, which ensures that derived
+                       //      attributes are kept up to date. Anchor will be deleted if it has been removed
+                       //      from the selection, but no new anchor will be added by this function.
+                       // newSelection: Node[]
+                       //      list of tree nodes to make selected
+                       var oldSelection = this.getSelectedTreeNodes();
+                       dojo.forEach(this._setDifference(oldSelection, newSelection), dojo.hitch(this, function(node){
+                               node.setSelected(false);
+                               if(this.anchor == node){
+                                       delete this.anchor;
+                               }
+                               delete this.selection[node.id];
+                       }));
+                       dojo.forEach(this._setDifference(newSelection, oldSelection), dojo.hitch(this, function(node){
+                               node.setSelected(true);
+                               this.selection[node.id] = node;
+                       }));
+                       this._updateSelectionProperties();
+               },
+               _setDifference: function(xs,ys){
+                       // summary
+                       //      Returns a copy of xs which lacks any objects
+                       //      occurring in ys. Checks for membership by
+                       //      modifying and then reading the object, so it will
+                       //      not properly handle sets of numbers or strings.
+                       
+                       dojo.forEach(ys, function(y){ y.__exclude__ = true; });
+                       var ret = dojo.filter(xs, function(x){ return !x.__exclude__; });
 
-               if(this.autoExpand){
-                       // There's little point in saving opened/closed state of nodes for a Tree
-                       // that initially opens all it's nodes.
-                       this.persist = false;
-               }
+                       // clean up after ourselves.
+                       dojo.forEach(ys, function(y){ delete y['__exclude__'] });
+                       return ret;
+               },
+               _updateSelectionProperties: function() {
+                       // summary
+                       //      Update the following tree properties from the current selection:
+                       //      path[s], selectedItem[s], selectedNode[s]
+                       
+                       var selected = this.getSelectedTreeNodes();
+                       var paths = [], nodes = [];
+                       dojo.forEach(selected, function(node) {
+                               nodes.push(node);
+                               paths.push(node.getTreePath());
+                       });
+                       var items = dojo.map(nodes,function(node) { return node.item; });
+                       this.tree._set("paths", paths);
+                       this.tree._set("path", paths[0] || []);
+                       this.tree._set("selectedNodes", nodes);
+                       this.tree._set("selectedNode", nodes[0] || null);
+                       this.tree._set("selectedItems", items);
+                       this.tree._set("selectedItem", items[0] || null);
+               },
+               // mouse events
+               onMouseDown: function(e){
+                       // summary:
+                       //              Event processor for onmousedown
+                       // e: Event
+                       //              mouse event
+                       // tags:
+                       //              protected
 
-               this._itemNodesMap={};
+                       // ignore click on expando node
+                       if(!this.current || this.tree.isExpandoNode( e.target, this.current)){ return; }
 
-               if(!this.cookieName){
-                       this.cookieName = this.id + "SaveStateCookie";
-               }
+                       if(e.button == dojo.mouseButtons.RIGHT){ return; }      // ignore right-click
 
-               this._loadDeferred = new dojo.Deferred();
+                       dojo.stopEvent(e);
 
-               this.inherited(arguments);
-       },
+                       var treeNode = this.current,
+                         copy = dojo.isCopyKey(e), id = treeNode.id;
 
-       postCreate: function(){
-               this._initState();
+                       // if shift key is not pressed, and the node is already in the selection,
+                       // delay deselection until onmouseup so in the case of DND, deselection
+                       // will be canceled by onmousemove.
+                       if(!this.singular && !e.shiftKey && this.selection[id]){
+                               this._doDeselect = true;
+                               return;
+                       }else{
+                               this._doDeselect = false;
+                       }
+                       this.userSelect(treeNode, copy, e.shiftKey);
+               },
 
-               // Create glue between store and Tree, if not specified directly by user
-               if(!this.model){
-                       this._store2model();
-               }
+               onMouseUp: function(e){
+                       // summary:
+                       //              Event processor for onmouseup
+                       // e: Event
+                       //              mouse event
+                       // tags:
+                       //              protected
 
-               // monitor changes to items
-               this.connect(this.model, "onChange", "_onItemChange");
-               this.connect(this.model, "onChildrenChange", "_onItemChildrenChange");
-               this.connect(this.model, "onDelete", "_onItemDelete");
+                       // _doDeselect is the flag to indicate that the user wants to either ctrl+click on
+                       // a already selected item (to deselect the item), or click on a not-yet selected item
+                       // (which should remove all current selection, and add the clicked item). This can not
+                       // be done in onMouseDown, because the user may start a drag after mousedown. By moving
+                       // the deselection logic here, the user can drags an already selected item.
+                       if(!this._doDeselect){ return; }
+                       this._doDeselect = false;
+                       this.userSelect(this.current, dojo.isCopyKey( e ), e.shiftKey);
+               },
+               onMouseMove: function(e){
+                       // summary
+                       //              event processor for onmousemove
+                       // e: Event
+                       //              mouse event
+                       this._doDeselect = false;
+               },
 
-               this._load();
+               userSelect: function(node, multi, range){
+                       // summary:
+                       //              Add or remove the given node from selection, responding
+                       //      to a user action such as a click or keypress.
+                       // multi: Boolean
+                       //              Indicates whether this is meant to be a multi-select action (e.g. ctrl-click)
+                       // range: Boolean
+                       //              Indicates whether this is meant to be a ranged action (e.g. shift-click)
+                       // tags:
+                       //              protected
 
-               this.inherited(arguments);
+                       if(this.singular){
+                               if(this.anchor == node && multi){
+                                       this.selectNone();
+                               }else{
+                                       this.setSelection([node]);
+                                       this.anchor = node;
+                               }
+                       }else{
+                               if(range && this.anchor){
+                                       var cr = dijit.tree._compareNodes(this.anchor.rowNode, node.rowNode),
+                                       begin, end, anchor = this.anchor;
+                                       
+                                       if(cr < 0){ //current is after anchor
+                                               begin = anchor;
+                                               end = node;
+                                       }else{ //current is before anchor
+                                               begin = node;
+                                               end = anchor;
+                                       }
+                                       nodes = [];
+                                       //add everything betweeen begin and end inclusively
+                                       while(begin != end) {
+                                               nodes.push(begin)
+                                               begin = this.tree._getNextNode(begin);
+                                       }
+                                       nodes.push(end)
 
-               if(this.dndController){
-                       if(dojo.isString(this.dndController)){
-                               this.dndController = dojo.getObject(this.dndController);
-                       }
-                       var params={};
-                       for(var i=0; i<this.dndParams.length;i++){
-                               if(this[this.dndParams[i]]){
-                                       params[this.dndParams[i]] = this[this.dndParams[i]];
+                                       this.setSelection(nodes);
+                               }else{
+                                   if( this.selection[ node.id ] && multi ) {
+                                               this.removeTreeNode( node );
+                                   } else if(multi) {
+                                               this.addTreeNode(node, true);
+                                       } else {
+                                               this.setSelection([node]);
+                                               this.anchor = node;
+                                   }
                                }
                        }
-                       this.dndController = new this.dndController(this, params);
+               },
+
+               forInSelectedItems: function(/*Function*/ f, /*Object?*/ o){
+                       // summary:
+                       //              Iterates over selected items;
+                       //              see `dojo.dnd.Container.forInItems()` for details
+                       o = o || dojo.global;
+                       for(var id in this.selection){
+                               // console.log("selected item id: " + id);
+                               f.call(o, this.getItem(id), id, this);
+                       }
                }
-       },
+});
 
-       _store2model: function(){
-               // summary:
-               //              User specified a store&query rather than model, so create model from store/query
-               this._v10Compat = true;
-               dojo.deprecated("Tree: from version 2.0, should specify a model object rather than a store/query");
+}
 
-               var modelParams = {
-                       id: this.id + "_ForestStoreModel",
-                       store: this.store,
-                       query: this.query,
-                       childrenAttrs: this.childrenAttr
-               };
+if(!dojo._hasResource["dijit.Tree"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.Tree"] = true;
+dojo.provide("dijit.Tree");
 
-               // Only override the model's mayHaveChildren() method if the user has specified an override
-               if(this.params.mayHaveChildren){
-                       modelParams.mayHaveChildren = dojo.hitch(this, "mayHaveChildren");
-               }
 
-               if(this.params.getItemChildren){
-                       modelParams.getChildren = dojo.hitch(this, function(item, onComplete, onError){
-                               this.getItemChildren((this._v10Compat && item === this.model.root) ? null : item, onComplete, onError);
-                       });
-               }
-               this.model = new dijit.tree.ForestStoreModel(modelParams);
 
-               // For backwards compatibility, the visibility of the root node is controlled by
-               // whether or not the user has specified a label
-               this.showRoot = Boolean(this.label);
-       },
 
-       onLoad: function(){
-               // summary:
-               //              Called when tree finishes loading and expanding.
-               // description:
-               //              If persist == true the loading may encompass many levels of fetches
-               //              from the data store, each asynchronous.   Waits for all to finish.
-               // tags:
-               //              callback
-       },
 
-       _load: function(){
-               // summary:
-               //              Initial load of the tree.
-               //              Load root node (possibly hidden) and it's children.
-               this.model.getRoot(
-                       dojo.hitch(this, function(item){
-                               var rn = (this.rootNode = this.tree._createTreeNode({
-                                       item: item,
-                                       tree: this,
-                                       isExpandable: true,
-                                       label: this.label || this.getLabel(item),
-                                       indent: this.showRoot ? 0 : -1
-                               }));
-                               if(!this.showRoot){
-                                       rn.rowNode.style.display="none";
-                               }
-                               this.domNode.appendChild(rn.domNode);
-                               var identity = this.model.getIdentity(item);
-                               if(this._itemNodesMap[identity]){
-                                       this._itemNodesMap[identity].push(rn);
-                               }else{
-                                       this._itemNodesMap[identity] = [rn];
-                               }
 
-                               rn._updateLayout();             // sets "dijitTreeIsRoot" CSS classname
 
-                               // load top level children and then fire onLoad() event
-                               this._expandNode(rn).addCallback(dojo.hitch(this, function(){
-                                       this._loadDeferred.callback(true);
-                                       this.onLoad();
-                               }));
-                       }),
-                       function(err){
-                               console.error(this, ": error loading root: ", err);
-                       }
-               );
-       },
 
-       getNodesByItem: function(/*dojo.data.Item or id*/ item){
-               // summary:
-               //              Returns all tree nodes that refer to an item
-               // returns:
-               //              Array of tree nodes that refer to passed item
 
-               if(!item){ return []; }
-               var identity = dojo.isString(item) ? item : this.model.getIdentity(item);
-               // return a copy so widget don't get messed up by changes to returned array
-               return [].concat(this._itemNodesMap[identity]);
-       },
 
-       _setSelectedItemAttr: function(/*dojo.data.Item or id*/ item){
-               // summary:
-               //              Select a tree node related to passed item.
-               //              WARNING: if model use multi-parented items or desired tree node isn't already loaded
-               //              behavior is undefined. Use set('path', ...) instead.
 
-               var oldValue = this.get("selectedItem");
-               var identity = (!item || dojo.isString(item)) ? item : this.model.getIdentity(item);
-               if(identity == oldValue ? this.model.getIdentity(oldValue) : null){ return; }
-               var nodes = this._itemNodesMap[identity];
-               this._selectNode((nodes && nodes[0]) || null);  //select the first item
-       },
 
-       _getSelectedItemAttr: function(){
-               // summary:
-               //              Return item related to selected tree node.
-               return this.selectedNode && this.selectedNode.item;
-       },
 
-       _setPathAttr: function(/*Item[] || String[]*/ path){
-               // summary:
-               //              Select the tree node identified by passed path.
-               // path:
-               //              Array of items or item id's
-               // returns:
-               //              Deferred to indicate when the set is complete
+dojo.declare(
+       "dijit._TreeNode",
+       [dijit._Widget, dijit._Templated, dijit._Container, dijit._Contained, dijit._CssStateMixin],
+{
+       // summary:
+       //              Single node within a tree.   This class is used internally
+       //              by Tree and should not be accessed directly.
+       // tags:
+       //              private
 
-               var d = new dojo.Deferred();
+       // item: [const] dojo.data.Item
+       //              the dojo.data entry this tree represents
+       item: null,
 
-               this._selectNode(null);
-               if(!path || !path.length){
-                       d.resolve(true);
-                       return d;
-               }
+       // isTreeNode: [protected] Boolean
+       //              Indicates that this is a TreeNode.   Used by `dijit.Tree` only,
+       //              should not be accessed directly.
+       isTreeNode: true,
 
-               // If this is called during initialization, defer running until Tree has finished loading
-               this._loadDeferred.addCallback(dojo.hitch(this, function(){
-                       if(!this.rootNode){
-                               d.reject(new Error("!this.rootNode"));
-                               return;
-                       }
-                       if(path[0] !== this.rootNode.item && (dojo.isString(path[0]) && path[0] != this.model.getIdentity(this.rootNode.item))){
-                               d.reject(new Error(this.id + ":path[0] doesn't match this.rootNode.item.  Maybe you are using the wrong tree."));
-                               return;
-                       }
-                       path.shift();
+       // label: String
+       //              Text of this tree node
+       label: "",
 
-                       var node = this.rootNode;
+       // isExpandable: [private] Boolean
+       //              This node has children, so show the expando node (+ sign)
+       isExpandable: null,
 
-                       function advance(){
-                               // summary:
-                               //              Called when "node" has completed loading and expanding.   Pop the next item from the path
-                               //              (which must be a child of "node") and advance to it, and then recurse.
-
-                               // Set item and identity to next item in path (node is pointing to the item that was popped
-                               // from the path _last_ time.
-                               var item = path.shift(),
-                                       identity = dojo.isString(item) ? item : this.model.getIdentity(item);
-
-                               // Change "node" from previous item in path to the item we just popped from path
-                               dojo.some(this._itemNodesMap[identity], function(n){
-                                       if(n.getParent() == node){
-                                               node = n;
-                                               return true;
-                                       }
-                                       return false;
-                               });
+       // isExpanded: [readonly] Boolean
+       //              This node is currently expanded (ie, opened)
+       isExpanded: false,
 
-                               if(path.length){
-                                       // Need to do more expanding
-                                       this._expandNode(node).addCallback(dojo.hitch(this, advance));
-                               }else{
-                                       // Final destination node, select it
-                                       this._selectNode(node);
-                                       
-                                       // signal that path setting is finished
-                                       d.resolve(true);
-                               }
-                       }
+       // state: [private] String
+       //              Dynamic loading-related stuff.
+       //              When an empty folder node appears, it is "UNCHECKED" first,
+       //              then after dojo.data query it becomes "LOADING" and, finally "LOADED"
+       state: "UNCHECKED",
 
-                       this._expandNode(node).addCallback(dojo.hitch(this, advance));
-               }));
-                       
-               return d;
-       },
+       templateString: dojo.cache("dijit", "templates/TreeNode.html", "<div class=\"dijitTreeNode\" role=\"presentation\"\n\t><div dojoAttachPoint=\"rowNode\" class=\"dijitTreeRow\" role=\"presentation\" dojoAttachEvent=\"onmouseenter:_onMouseEnter, onmouseleave:_onMouseLeave, onclick:_onClick, ondblclick:_onDblClick\"\n\t\t><img src=\"${_blankGif}\" alt=\"\" dojoAttachPoint=\"expandoNode\" class=\"dijitTreeExpando\" role=\"presentation\"\n\t\t/><span dojoAttachPoint=\"expandoNodeText\" class=\"dijitExpandoText\" role=\"presentation\"\n\t\t></span\n\t\t><span dojoAttachPoint=\"contentNode\"\n\t\t\tclass=\"dijitTreeContent\" role=\"presentation\">\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" dojoAttachPoint=\"iconNode\" class=\"dijitIcon dijitTreeIcon\" role=\"presentation\"\n\t\t\t/><span dojoAttachPoint=\"labelNode\" class=\"dijitTreeLabel\" role=\"treeitem\" tabindex=\"-1\" aria-selected=\"false\" dojoAttachEvent=\"onfocus:_onLabelFocus\"></span>\n\t\t</span\n\t></div>\n\t<div dojoAttachPoint=\"containerNode\" class=\"dijitTreeContainer\" role=\"presentation\" style=\"display: none;\"></div>\n</div>\n"),
 
-       _getPathAttr: function(){
-               // summary:
-               //              Return an array of items that is the path to selected tree node.
-               if(!this.selectedNode){ return; }
-               var res = [];
-               var treeNode = this.selectedNode;
-               while(treeNode && treeNode !== this.rootNode){
-                       res.unshift(treeNode.item);
-                       treeNode = treeNode.getParent();
-               }
-               res.unshift(this.rootNode.item);
-               return res;
+       baseClass: "dijitTreeNode",
+
+       // For hover effect for tree node, and focus effect for label
+       cssStateNodes: {
+               rowNode: "dijitTreeRow",
+               labelNode: "dijitTreeLabel"
        },
 
-       ////////////// Data store related functions //////////////////////
-       // These just get passed to the model; they are here for back-compat
+       attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
+               label: {node: "labelNode", type: "innerText"},
+               tooltip: {node: "rowNode", type: "attribute", attribute: "title"}
+       }),
 
-       mayHaveChildren: function(/*dojo.data.Item*/ item){
-               // summary:
-               //              Deprecated.   This should be specified on the model itself.
-               //
-               //              Overridable function to tell if an item has or may have children.
-               //              Controls whether or not +/- expando icon is shown.
-               //              (For efficiency reasons we may not want to check if an element actually
-               //              has children until user clicks the expando node)
-               // tags:
-               //              deprecated
-       },
+       buildRendering: function(){
+               this.inherited(arguments);
 
-       getItemChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ onComplete){
-               // summary:
-               //              Deprecated.   This should be specified on the model itself.
-               //
-               //              Overridable function that return array of child items of given parent item,
-               //              or if parentItem==null then return top items in tree
-               // tags:
-               //              deprecated
-       },
+               // set expand icon for leaf
+               this._setExpando();
 
-       ///////////////////////////////////////////////////////
-       // Functions for converting an item to a TreeNode
-       getLabel: function(/*dojo.data.Item*/ item){
-               // summary:
-               //              Overridable function to get the label for a tree node (given the item)
-               // tags:
-               //              extension
-               return this.model.getLabel(item);       // String
-       },
+               // set icon and label class based on item
+               this._updateItemClasses(this.item);
 
-       getIconClass: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
-               // summary:
-               //              Overridable function to return CSS class name to display icon
-               // tags:
-               //              extension
-               return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "dijitLeaf"
-       },
+               if(this.isExpandable){
+                       dijit.setWaiState(this.labelNode, "expanded", this.isExpanded);
+               }
 
-       getLabelClass: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
-               // summary:
-               //              Overridable function to return CSS class name to display label
-               // tags:
-               //              extension
+               //aria-selected should be false on all selectable elements.
+               this.setSelected(false);
        },
 
-       getRowClass: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
+       _setIndentAttr: function(indent){
                // summary:
-               //              Overridable function to return CSS class name to display row
-               // tags:
-               //              extension
-       },
+               //              Tell this node how many levels it should be indented
+               // description:
+               //              0 for top level nodes, 1 for their children, 2 for their
+               //              grandchildren, etc.
 
-       getIconStyle: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
-               // summary:
-               //              Overridable function to return CSS styles to display icon
-               // returns:
-               //              Object suitable for input to dojo.style() like {backgroundImage: "url(...)"}
-               // tags:
-               //              extension
+               // Math.max() is to prevent negative padding on hidden root node (when indent == -1)
+               var pixels = (Math.max(indent, 0) * this.tree._nodePixelIndent) + "px";
+
+               dojo.style(this.domNode, "backgroundPosition",  pixels + " 0px");
+               dojo.style(this.rowNode, this.isLeftToRight() ? "paddingLeft" : "paddingRight", pixels);
+
+               dojo.forEach(this.getChildren(), function(child){
+                       child.set("indent", indent+1);
+               });
+               
+               this._set("indent", indent);
        },
 
-       getLabelStyle: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
+       markProcessing: function(){
                // summary:
-               //              Overridable function to return CSS styles to display label
-               // returns:
-               //              Object suitable for input to dojo.style() like {color: "red", background: "green"}
+               //              Visually denote that tree is loading data, etc.
                // tags:
-               //              extension
+               //              private
+               this.state = "LOADING";
+               this._setExpando(true);
        },
 
-       getRowStyle: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
+       unmarkProcessing: function(){
                // summary:
-               //              Overridable function to return CSS styles to display row
-               // returns:
-               //              Object suitable for input to dojo.style() like {background-color: "#bbb"}
+               //              Clear markup from markProcessing() call
                // tags:
-               //              extension
+               //              private
+               this._setExpando(false);
        },
 
-       getTooltip: function(/*dojo.data.Item*/ item){
+       _updateItemClasses: function(item){
                // summary:
-               //              Overridable function to get the tooltip for a tree node (given the item)
+               //              Set appropriate CSS classes for icon and label dom node
+               //              (used to allow for item updates to change respective CSS)
                // tags:
-               //              extension
-               return "";      // String
+               //              private
+               var tree = this.tree, model = tree.model;
+               if(tree._v10Compat && item === model.root){
+                       // For back-compat with 1.0, need to use null to specify root item (TODO: remove in 2.0)
+                       item = null;
+               }
+               this._applyClassAndStyle(item, "icon", "Icon");
+               this._applyClassAndStyle(item, "label", "Label");
+               this._applyClassAndStyle(item, "row", "Row");
        },
 
-       /////////// Keyboard and Mouse handlers ////////////////////
-
-       _onKeyPress: function(/*Event*/ e){
+       _applyClassAndStyle: function(item, lower, upper){
                // summary:
-               //              Translates keypress events into commands for the controller
-               if(e.altKey){ return; }
-               var dk = dojo.keys;
-               var treeNode = dijit.getEnclosingWidget(e.target);
-               if(!treeNode){ return; }
-
-               var key = e.charOrCode;
-               if(typeof key == "string"){     // handle printables (letter navigation)
-                       // Check for key navigation.
-                       if(!e.altKey && !e.ctrlKey && !e.shiftKey && !e.metaKey){
-                               this._onLetterKeyNav( { node: treeNode, key: key.toLowerCase() } );
-                               dojo.stopEvent(e);
-                       }
-               }else{  // handle non-printables (arrow keys)
-                       // clear record of recent printables (being saved for multi-char letter navigation),
-                       // because "a", down-arrow, "b" shouldn't search for "ab"
-                       if(this._curSearch){
-                               clearTimeout(this._curSearch.timer);
-                               delete this._curSearch;
-                       }
+               //              Set the appropriate CSS classes and styles for labels, icons and rows.
+               //
+               // item:
+               //              The data item.
+               //
+               // lower:
+               //              The lower case attribute to use, e.g. 'icon', 'label' or 'row'.
+               //
+               // upper:
+               //              The upper case attribute to use, e.g. 'Icon', 'Label' or 'Row'.
+               //
+               // tags:
+               //              private
 
-                       var map = this._keyHandlerMap;
-                       if(!map){
-                               // setup table mapping keys to events
-                               map = {};
-                               map[dk.ENTER]="_onEnterKey";
-                               map[this.isLeftToRight() ? dk.LEFT_ARROW : dk.RIGHT_ARROW]="_onLeftArrow";
-                               map[this.isLeftToRight() ? dk.RIGHT_ARROW : dk.LEFT_ARROW]="_onRightArrow";
-                               map[dk.UP_ARROW]="_onUpArrow";
-                               map[dk.DOWN_ARROW]="_onDownArrow";
-                               map[dk.HOME]="_onHomeKey";
-                               map[dk.END]="_onEndKey";
-                               this._keyHandlerMap = map;
-                       }
-                       if(this._keyHandlerMap[key]){
-                               this[this._keyHandlerMap[key]]( { node: treeNode, item: treeNode.item, evt: e } );
-                               dojo.stopEvent(e);
-                       }
-               }
-       },
+               var clsName = "_" + lower + "Class";
+               var nodeName = lower + "Node";
+               var oldCls = this[clsName];
 
-       _onEnterKey: function(/*Object*/ message, /*Event*/ evt){
-               this._publish("execute", { item: message.item, node: message.node } );
-               this._selectNode(message.node);
-               this.onClick(message.item, message.node, evt);
-       },
+               this[clsName] = this.tree["get" + upper + "Class"](item, this.isExpanded);
+               dojo.replaceClass(this[nodeName], this[clsName] || "", oldCls || "");
+               dojo.style(this[nodeName], this.tree["get" + upper + "Style"](item, this.isExpanded) || {});
+       },
 
-       _onDownArrow: function(/*Object*/ message){
+       _updateLayout: function(){
                // summary:
-               //              down arrow pressed; get next visible node, set focus there
-               var node = this._getNextNode(message.node);
-               if(node && node.isTreeNode){
-                       this.focusNode(node);
+               //              Set appropriate CSS classes for this.domNode
+               // tags:
+               //              private
+               var parent = this.getParent();
+               if(!parent || parent.rowNode.style.display == "none"){
+                       /* if we are hiding the root node then make every first level child look like a root node */
+                       dojo.addClass(this.domNode, "dijitTreeIsRoot");
+               }else{
+                       dojo.toggleClass(this.domNode, "dijitTreeIsLast", !this.getNextSibling());
                }
        },
 
-       _onUpArrow: function(/*Object*/ message){
+       _setExpando: function(/*Boolean*/ processing){
                // summary:
-               //              Up arrow pressed; move to previous visible node
+               //              Set the right image for the expando node
+               // tags:
+               //              private
 
-               var node = message.node;
+               var styles = ["dijitTreeExpandoLoading", "dijitTreeExpandoOpened",
+                                               "dijitTreeExpandoClosed", "dijitTreeExpandoLeaf"],
+                       _a11yStates = ["*","-","+","*"],
+                       idx = processing ? 0 : (this.isExpandable ?     (this.isExpanded ? 1 : 2) : 3);
 
-               // if younger siblings
-               var previousSibling = node.getPreviousSibling();
-               if(previousSibling){
-                       node = previousSibling;
-                       // if the previous node is expanded, dive in deep
-                       while(node.isExpandable && node.isExpanded && node.hasChildren()){
-                               // move to the last child
-                               var children = node.getChildren();
-                               node = children[children.length-1];
-                       }
-               }else{
-                       // if this is the first child, return the parent
-                       // unless the parent is the root of a tree with a hidden root
-                       var parent = node.getParent();
-                       if(!(!this.showRoot && parent === this.rootNode)){
-                               node = parent;
-                       }
-               }
+               // apply the appropriate class to the expando node
+               dojo.replaceClass(this.expandoNode, styles[idx], styles);
+
+               // provide a non-image based indicator for images-off mode
+               this.expandoNodeText.innerHTML = _a11yStates[idx];
 
-               if(node && node.isTreeNode){
-                       this.focusNode(node);
-               }
        },
 
-       _onRightArrow: function(/*Object*/ message){
+       expand: function(){
                // summary:
-               //              Right arrow pressed; go to child node
-               var node = message.node;
+               //              Show my children
+               // returns:
+               //              Deferred that fires when expansion is complete
 
-               // if not expanded, expand, else move to 1st child
-               if(node.isExpandable && !node.isExpanded){
-                       this._expandNode(node);
-               }else if(node.hasChildren()){
-                       node = node.getChildren()[0];
-                       if(node && node.isTreeNode){
-                               this.focusNode(node);
-                       }
+               // If there's already an expand in progress or we are already expanded, just return
+               if(this._expandDeferred){
+                       return this._expandDeferred;            // dojo.Deferred
+               }
+
+               // cancel in progress collapse operation
+               this._wipeOut && this._wipeOut.stop();
+
+               // All the state information for when a node is expanded, maybe this should be
+               // set when the animation completes instead
+               this.isExpanded = true;
+               dijit.setWaiState(this.labelNode, "expanded", "true");
+               if(this.tree.showRoot || this !== this.tree.rootNode){
+                       dijit.setWaiRole(this.containerNode, "group");
+               }
+               dojo.addClass(this.contentNode,'dijitTreeContentExpanded');
+               this._setExpando();
+               this._updateItemClasses(this.item);
+               if(this == this.tree.rootNode){
+                       dijit.setWaiState(this.tree.domNode, "expanded", "true");
                }
+
+               var def,
+                       wipeIn = dojo.fx.wipeIn({
+                               node: this.containerNode, duration: dijit.defaultDuration,
+                               onEnd: function(){
+                                       def.callback(true);
+                               }
+                       });
+
+               // Deferred that fires when expand is complete
+               def = (this._expandDeferred = new dojo.Deferred(function(){
+                       // Canceller
+                       wipeIn.stop();
+               }));
+
+               wipeIn.play();
+
+               return def;             // dojo.Deferred
        },
 
-       _onLeftArrow: function(/*Object*/ message){
+       collapse: function(){
                // summary:
-               //              Left arrow pressed.
-               //              If not collapsed, collapse, else move to parent.
+               //              Collapse this node (if it's expanded)
 
-               var node = message.node;
+               if(!this.isExpanded){ return; }
 
-               if(node.isExpandable && node.isExpanded){
-                       this._collapseNode(node);
-               }else{
-                       var parent = node.getParent();
-                       if(parent && parent.isTreeNode && !(!this.showRoot && parent === this.rootNode)){
-                               this.focusNode(parent);
-                       }
+               // cancel in progress expand operation
+               if(this._expandDeferred){
+                       this._expandDeferred.cancel();
+                       delete this._expandDeferred;
                }
-       },
 
-       _onHomeKey: function(){
-               // summary:
-               //              Home key pressed; get first visible node, and set focus there
-               var node = this._getRootOrFirstNode();
-               if(node){
-                       this.focusNode(node);
+               this.isExpanded = false;
+               dijit.setWaiState(this.labelNode, "expanded", "false");
+               if(this == this.tree.rootNode){
+                       dijit.setWaiState(this.tree.domNode, "expanded", "false");
+               }
+               dojo.removeClass(this.contentNode,'dijitTreeContentExpanded');
+               this._setExpando();
+               this._updateItemClasses(this.item);
+
+               if(!this._wipeOut){
+                       this._wipeOut = dojo.fx.wipeOut({
+                               node: this.containerNode, duration: dijit.defaultDuration
+                       });
                }
+               this._wipeOut.play();
        },
 
-       _onEndKey: function(/*Object*/ message){
-               // summary:
-               //              End key pressed; go to last visible node.
+       // indent: Integer
+       //              Levels from this node to the root node
+       indent: 0,
+
+       setChildItems: function(/* Object[] */ items){
+               // summary:
+               //              Sets the child items of this node, removing/adding nodes
+               //              from current children to match specified items[] array.
+               //              Also, if this.persist == true, expands any children that were previously
+               //              opened.
+               // returns:
+               //              Deferred object that fires after all previously opened children
+               //              have been expanded again (or fires instantly if there are no such children).
+
+               var tree = this.tree,
+                       model = tree.model,
+                       defs = [];      // list of deferreds that need to fire before I am complete
+
 
-               var node = this.rootNode;
-               while(node.isExpanded){
-                       var c = node.getChildren();
-                       node = c[c.length - 1];
-               }
+               // Orphan all my existing children.
+               // If items contains some of the same items as before then we will reattach them.
+               // Don't call this.removeChild() because that will collapse the tree etc.
+               dojo.forEach(this.getChildren(), function(child){
+                       dijit._Container.prototype.removeChild.call(this, child);
+               }, this);
 
-               if(node && node.isTreeNode){
-                       this.focusNode(node);
-               }
-       },
+               this.state = "LOADED";
 
-       // multiCharSearchDuration: Number
-       //              If multiple characters are typed where each keystroke happens within
-       //              multiCharSearchDuration of the previous keystroke,
-       //              search for nodes matching all the keystrokes.
-       //
-       //              For example, typing "ab" will search for entries starting with
-       //              "ab" unless the delay between "a" and "b" is greater than multiCharSearchDuration.
-       multiCharSearchDuration: 250,
+               if(items && items.length > 0){
+                       this.isExpandable = true;
 
-       _onLetterKeyNav: function(message){
-               // summary:
-               //              Called when user presses a prinatable key; search for node starting with recently typed letters.
-               // message: Object
-               //              Like { node: TreeNode, key: 'a' } where key is the key the user pressed.
+                       // Create _TreeNode widget for each specified tree node, unless one already
+                       // exists and isn't being used (presumably it's from a DnD move and was recently
+                       // released
+                       dojo.forEach(items, function(item){
+                               var id = model.getIdentity(item),
+                                       existingNodes = tree._itemNodesMap[id],
+                                       node;
+                               if(existingNodes){
+                                       for(var i=0;i<existingNodes.length;i++){
+                                               if(existingNodes[i] && !existingNodes[i].getParent()){
+                                                       node = existingNodes[i];
+                                                       node.set('indent', this.indent+1);
+                                                       break;
+                                               }
+                                       }
+                               }
+                               if(!node){
+                                       node = this.tree._createTreeNode({
+                                                       item: item,
+                                                       tree: tree,
+                                                       isExpandable: model.mayHaveChildren(item),
+                                                       label: tree.getLabel(item),
+                                                       tooltip: tree.getTooltip(item),
+                                                       dir: tree.dir,
+                                                       lang: tree.lang,
+                                                       indent: this.indent + 1
+                                               });
+                                       if(existingNodes){
+                                               existingNodes.push(node);
+                                       }else{
+                                               tree._itemNodesMap[id] = [node];
+                                       }
+                               }
+                               this.addChild(node);
 
-               // Branch depending on whether this key starts a new search, or modifies an existing search
-               var cs = this._curSearch;
-               if(cs){
-                       // We are continuing a search.  Ex: user has pressed 'a', and now has pressed
-                       // 'b', so we want to search for nodes starting w/"ab".
-                       cs.pattern = cs.pattern + message.key;
-                       clearTimeout(cs.timer);
+                               // If node was previously opened then open it again now (this may trigger
+                               // more data store accesses, recursively)
+                               if(this.tree.autoExpand || this.tree._state(item)){
+                                       defs.push(tree._expandNode(node));
+                               }
+                       }, this);
+
+                       // note that updateLayout() needs to be called on each child after
+                       // _all_ the children exist
+                       dojo.forEach(this.getChildren(), function(child, idx){
+                               child._updateLayout();
+                       });
                }else{
-                       // We are starting a new search
-                       cs = this._curSearch = {
-                                       pattern: message.key,
-                                       startNode: message.node
-                       };
+                       this.isExpandable=false;
                }
 
-               // set/reset timer to forget recent keystrokes
-               var self = this;
-               cs.timer = setTimeout(function(){
-                       delete self._curSearch;
-               }, this.multiCharSearchDuration);
+               if(this._setExpando){
+                       // change expando to/from dot or + icon, as appropriate
+                       this._setExpando(false);
+               }
 
-               // Navigate to TreeNode matching keystrokes [entered so far].
-               var node = cs.startNode;
-               do{
-                       node = this._getNextNode(node);
-                       //check for last node, jump to first node if necessary
-                       if(!node){
-                               node = this._getRootOrFirstNode();
-                       }
-               }while(node !== cs.startNode && (node.label.toLowerCase().substr(0, cs.pattern.length) != cs.pattern));
-               if(node && node.isTreeNode){
-                       // no need to set focus if back where we started
-                       if(node !== cs.startNode){
-                               this.focusNode(node);
+               // Set leaf icon or folder icon, as appropriate
+               this._updateItemClasses(this.item);
+
+               // On initial tree show, make the selected TreeNode as either the root node of the tree,
+               // or the first child, if the root node is hidden
+               if(this == tree.rootNode){
+                       var fc = this.tree.showRoot ? this : this.getChildren()[0];
+                       if(fc){
+                               fc.setFocusable(true);
+                               tree.lastFocused = fc;
+                       }else{
+                               // fallback: no nodes in tree so focus on Tree <div> itself
+                               tree.domNode.setAttribute("tabIndex", "0");
                        }
                }
+
+               return new dojo.DeferredList(defs);     // dojo.Deferred
        },
 
-       _onClick: function(/*TreeNode*/ nodeWidget, /*Event*/ e){
-               // summary:
-               //              Translates click events into commands for the controller to process
+       getTreePath: function(){
+               var node = this;
+               var path = [];
+               while(node && node !== this.tree.rootNode){
+                               path.unshift(node.item);
+                               node = node.getParent();
+               }
+               path.unshift(this.tree.rootNode.item);
 
-               var domElement = e.target,
-                       isExpandoClick = (domElement == nodeWidget.expandoNode || domElement == nodeWidget.expandoNodeText);
+               return path;
+       },
 
-               if( (this.openOnClick && nodeWidget.isExpandable) || isExpandoClick ){
-                       // expando node was clicked, or label of a folder node was clicked; open it
-                       if(nodeWidget.isExpandable){
-                               this._onExpandoClick({node:nodeWidget});
-                       }
-               }else{
-                       this._publish("execute", { item: nodeWidget.item, node: nodeWidget, evt: e } );
-                       this.onClick(nodeWidget.item, nodeWidget, e);
-                       this.focusNode(nodeWidget);
-               }
-               if(!isExpandoClick){
-                       this._selectNode(nodeWidget);
-               }
-               dojo.stopEvent(e);
+       getIdentity: function() {
+               return this.tree.model.getIdentity(this.item);
        },
-       _onDblClick: function(/*TreeNode*/ nodeWidget, /*Event*/ e){
-               // summary:
-               //              Translates double-click events into commands for the controller to process
 
-               var domElement = e.target,
-                       isExpandoClick = (domElement == nodeWidget.expandoNode || domElement == nodeWidget.expandoNodeText);
+       removeChild: function(/* treeNode */ node){
+               this.inherited(arguments);
 
-               if( (this.openOnDblClick && nodeWidget.isExpandable) ||isExpandoClick ){
-                       // expando node was clicked, or label of a folder node was clicked; open it
-                       if(nodeWidget.isExpandable){
-                               this._onExpandoClick({node:nodeWidget});
-                       }
-               }else{
-                       this._publish("execute", { item: nodeWidget.item, node: nodeWidget, evt: e } );
-                       this.onDblClick(nodeWidget.item, nodeWidget, e);
-                       this.focusNode(nodeWidget);
-               }
-               if(!isExpandoClick){
-                       this._selectNode(nodeWidget);
+               var children = this.getChildren();
+               if(children.length == 0){
+                       this.isExpandable = false;
+                       this.collapse();
                }
-               dojo.stopEvent(e);
+
+               dojo.forEach(children, function(child){
+                               child._updateLayout();
+               });
        },
 
-       _onExpandoClick: function(/*Object*/ message){
+       makeExpandable: function(){
                // summary:
-               //              User clicked the +/- icon; expand or collapse my children.
-               var node = message.node;
+               //              if this node wasn't already showing the expando node,
+               //              turn it into one and call _setExpando()
 
-               // If we are collapsing, we might be hiding the currently focused node.
-               // Also, clicking the expando node might have erased focus from the current node.
-               // For simplicity's sake just focus on the node with the expando.
-               this.focusNode(node);
+               // TODO: hmm this isn't called from anywhere, maybe should remove it for 2.0
 
-               if(node.isExpanded){
-                       this._collapseNode(node);
-               }else{
-                       this._expandNode(node);
-               }
+               this.isExpandable = true;
+               this._setExpando(false);
        },
 
-       onClick: function(/* dojo.data */ item, /*TreeNode*/ node, /*Event*/ evt){
-               // summary:
-               //              Callback when a tree node is clicked
-               // tags:
-               //              callback
-       },
-       onDblClick: function(/* dojo.data */ item, /*TreeNode*/ node, /*Event*/ evt){
-               // summary:
-               //              Callback when a tree node is double-clicked
-               // tags:
-               //              callback
-       },
-       onOpen: function(/* dojo.data */ item, /*TreeNode*/ node){
+       _onLabelFocus: function(evt){
                // summary:
-               //              Callback when a node is opened
+               //              Called when this row is focused (possibly programatically)
+               //              Note that we aren't using _onFocus() builtin to dijit
+               //              because it's called when focus is moved to a descendant TreeNode.
                // tags:
-               //              callback
+               //              private
+               this.tree._onNodeFocus(this);
        },
-       onClose: function(/* dojo.data */ item, /*TreeNode*/ node){
+
+       setSelected: function(/*Boolean*/ selected){
                // summary:
-               //              Callback when a node is closed
-               // tags:
-               //              callback
+               //              A Tree has a (single) currently selected node.
+               //              Mark that this node is/isn't that currently selected node.
+               // description:
+               //              In particular, setting a node as selected involves setting tabIndex
+               //              so that when user tabs to the tree, focus will go to that node (only).
+               dijit.setWaiState(this.labelNode, "selected", selected);
+               dojo.toggleClass(this.rowNode, "dijitTreeRowSelected", selected);
        },
 
-       _getNextNode: function(node){
+       setFocusable: function(/*Boolean*/ selected){
                // summary:
-               //              Get next visible node
+               //              A Tree has a (single) node that's focusable.
+               //              Mark that this node is/isn't that currently focsuable node.
+               // description:
+               //              In particular, setting a node as selected involves setting tabIndex
+               //              so that when user tabs to the tree, focus will go to that node (only).
 
-               if(node.isExpandable && node.isExpanded && node.hasChildren()){
-                       // if this is an expanded node, get the first child
-                       return node.getChildren()[0];           // _TreeNode
-               }else{
-                       // find a parent node with a sibling
-                       while(node && node.isTreeNode){
-                               var returnNode = node.getNextSibling();
-                               if(returnNode){
-                                       return returnNode;              // _TreeNode
-                               }
-                               node = node.getParent();
-                       }
-                       return null;
-               }
+               this.labelNode.setAttribute("tabIndex", selected ? "0" : "-1");
+       },
+
+       _onClick: function(evt){
+               // summary:
+               //              Handler for onclick event on a node
+               // tags:
+               //              private
+               this.tree._onClick(this, evt);
+       },
+       _onDblClick: function(evt){
+               // summary:
+               //              Handler for ondblclick event on a node
+               // tags:
+               //              private
+               this.tree._onDblClick(this, evt);
        },
 
-       _getRootOrFirstNode: function(){
+       _onMouseEnter: function(evt){
                // summary:
-               //              Get first visible node
-               return this.showRoot ? this.rootNode : this.rootNode.getChildren()[0];
+               //              Handler for onmouseenter event on a node
+               // tags:
+               //              private
+               this.tree._onNodeMouseEnter(this, evt);
        },
 
-       _collapseNode: function(/*_TreeNode*/ node){
+       _onMouseLeave: function(evt){
                // summary:
-               //              Called when the user has requested to collapse the node
+               //              Handler for onmouseenter event on a node
+               // tags:
+               //              private
+               this.tree._onNodeMouseLeave(this, evt);
+       }
+});
 
-               if(node._expandNodeDeferred){
-                       delete node._expandNodeDeferred;
-               }
+dojo.declare(
+       "dijit.Tree",
+       [dijit._Widget, dijit._Templated],
+{
+       // summary:
+       //              This widget displays hierarchical data from a store.
 
-               if(node.isExpandable){
-                       if(node.state == "LOADING"){
-                               // ignore clicks while we are in the process of loading data
-                               return;
-                       }
+       // store: [deprecated] String||dojo.data.Store
+       //              Deprecated.  Use "model" parameter instead.
+       //              The store to get data to display in the tree.
+       store: null,
 
-                       node.collapse();
-                       this.onClose(node.item, node);
+       // model: dijit.Tree.model
+       //              Interface to read tree data, get notifications of changes to tree data,
+       //              and for handling drop operations (i.e drag and drop onto the tree)
+       model: null,
 
-                       if(node.item){
-                               this._state(node.item,false);
-                               this._saveState();
-                       }
-               }
-       },
+       // query: [deprecated] anything
+       //              Deprecated.  User should specify query to the model directly instead.
+       //              Specifies datastore query to return the root item or top items for the tree.
+       query: null,
 
-       _expandNode: function(/*_TreeNode*/ node, /*Boolean?*/ recursive){
-               // summary:
-               //              Called when the user has requested to expand the node
-               // recursive:
-               //              Internal flag used when _expandNode() calls itself, don't set.
-               // returns:
-               //              Deferred that fires when the node is loaded and opened and (if persist=true) all it's descendants
-               //              that were previously opened too
+       // label: [deprecated] String
+       //              Deprecated.  Use dijit.tree.ForestStoreModel directly instead.
+       //              Used in conjunction with query parameter.
+       //              If a query is specified (rather than a root node id), and a label is also specified,
+       //              then a fake root node is created and displayed, with this label.
+       label: "",
 
-               if(node._expandNodeDeferred && !recursive){
-                       // there's already an expand in progress (or completed), so just return
-                       return node._expandNodeDeferred;        // dojo.Deferred
-               }
+       // showRoot: [const] Boolean
+       //              Should the root node be displayed, or hidden?
+       showRoot: true,
 
-               var model = this.model,
-                       item = node.item,
-                       _this = this;
+       // childrenAttr: [deprecated] String[]
+       //              Deprecated.   This information should be specified in the model.
+       //              One ore more attributes that holds children of a tree node
+       childrenAttr: ["children"],
 
-               switch(node.state){
-                       case "UNCHECKED":
-                               // need to load all the children, and then expand
-                               node.markProcessing();
+       // paths: String[][] or Item[][]
+       //              Full paths from rootNode to selected nodes expressed as array of items or array of ids.
+       //              Since setting the paths may be asynchronous (because ofwaiting on dojo.data), set("paths", ...)
+       //              returns a Deferred to indicate when the set is complete.
+       paths: [],
+       
+       // path: String[] or Item[]
+       //      Backward compatible singular variant of paths.
+       path: [],
 
-                               // Setup deferred to signal when the load and expand are finished.
-                               // Save that deferred in this._expandDeferred as a flag that operation is in progress.
-                               var def = (node._expandNodeDeferred = new dojo.Deferred());
+       // selectedItems: [readonly] Item[]
+       //              The currently selected items in this tree.
+       //              This property can only be set (via set('selectedItems', ...)) when that item is already
+       //              visible in the tree.   (I.e. the tree has already been expanded to show that node.)
+       //              Should generally use `paths` attribute to set the selected items instead.
+       selectedItems: null,
 
-                               // Get the children
-                               model.getChildren(
-                                       item,
-                                       function(items){
-                                               node.unmarkProcessing();
+       // selectedItem: [readonly] Item
+       //      Backward compatible singular variant of selectedItems.
+       selectedItem: null,
 
-                                               // Display the children and also start expanding any children that were previously expanded
-                                               // (if this.persist == true).   The returned Deferred will fire when those expansions finish.
-                                               var scid = node.setChildItems(items);
+       // openOnClick: Boolean
+       //              If true, clicking a folder node's label will open it, rather than calling onClick()
+       openOnClick: false,
 
-                                               // Call _expandNode() again but this time it will just to do the animation (default branch).
-                                               // The returned Deferred will fire when the animation completes.
-                                               // TODO: seems like I can avoid recursion and just use a deferred to sequence the events?
-                                               var ed = _this._expandNode(node, true);
+       // openOnDblClick: Boolean
+       //              If true, double-clicking a folder node's label will open it, rather than calling onDblClick()
+       openOnDblClick: false,
 
-                                               // After the above two tasks (setChildItems() and recursive _expandNode()) finish,
-                                               // signal that I am done.
-                                               scid.addCallback(function(){
-                                                       ed.addCallback(function(){
-                                                               def.callback();
-                                                       })
-                                               });
-                                       },
-                                       function(err){
-                                               console.error(_this, ": error loading root children: ", err);
-                                       }
-                               );
-                               break;
+       templateString: dojo.cache("dijit", "templates/Tree.html", "<div class=\"dijitTree dijitTreeContainer\" role=\"tree\"\n\tdojoAttachEvent=\"onkeypress:_onKeyPress\">\n\t<div class=\"dijitInline dijitTreeIndent\" style=\"position: absolute; top: -9999px\" dojoAttachPoint=\"indentDetector\"></div>\n</div>\n"),
 
-                       default:        // "LOADED"
-                               // data is already loaded; just expand node
-                               def = (node._expandNodeDeferred = node.expand());
+       // persist: Boolean
+       //              Enables/disables use of cookies for state saving.
+       persist: true,
 
-                               this.onOpen(node.item, node);
+       // autoExpand: Boolean
+       //              Fully expand the tree on load.   Overrides `persist`.
+       autoExpand: false,
 
-                               if(item){
-                                       this._state(item, true);
-                                       this._saveState();
-                               }
-               }
+       // dndController: [protected] String
+       //              Class name to use as as the dnd controller.  Specifying this class enables DnD.
+       //              Generally you should specify this as "dijit.tree.dndSource".
+       //      Default of "dijit.tree._dndSelector" handles selection only (no actual DnD).
+       dndController: "dijit.tree._dndSelector",
 
-               return def;     // dojo.Deferred
+       // parameters to pull off of the tree and pass on to the dndController as its params
+       dndParams: ["onDndDrop","itemCreator","onDndCancel","checkAcceptance", "checkItemAcceptance", "dragThreshold", "betweenThreshold"],
+
+       //declare the above items so they can be pulled from the tree's markup
+
+       // onDndDrop: [protected] Function
+       //              Parameter to dndController, see `dijit.tree.dndSource.onDndDrop`.
+       //              Generally this doesn't need to be set.
+       onDndDrop: null,
+
+       /*=====
+       itemCreator: function(nodes, target, source){
+               // summary:
+               //              Returns objects passed to `Tree.model.newItem()` based on DnD nodes
+               //              dropped onto the tree.   Developer must override this method to enable
+               //              dropping from external sources onto this Tree, unless the Tree.model's items
+               //              happen to look like {id: 123, name: "Apple" } with no other attributes.
+               // description:
+               //              For each node in nodes[], which came from source, create a hash of name/value
+               //              pairs to be passed to Tree.model.newItem().  Returns array of those hashes.
+               // nodes: DomNode[]
+               //              The DOMNodes dragged from the source container
+               // target: DomNode
+               //              The target TreeNode.rowNode
+               // source: dojo.dnd.Source
+               //              The source container the nodes were dragged from, perhaps another Tree or a plain dojo.dnd.Source
+               // returns: Object[]
+               //              Array of name/value hashes for each new item to be added to the Tree, like:
+               // |    [
+               // |            { id: 123, label: "apple", foo: "bar" },
+               // |            { id: 456, label: "pear", zaz: "bam" }
+               // |    ]
+               // tags:
+               //              extension
+               return [{}];
        },
+       =====*/
+       itemCreator: null,
 
-       ////////////////// Miscellaneous functions ////////////////
+       // onDndCancel: [protected] Function
+       //              Parameter to dndController, see `dijit.tree.dndSource.onDndCancel`.
+       //              Generally this doesn't need to be set.
+       onDndCancel: null,
 
-       focusNode: function(/* _tree.Node */ node){
+/*=====
+       checkAcceptance: function(source, nodes){
                // summary:
-               //              Focus on the specified node (which must be visible)
+               //              Checks if the Tree itself can accept nodes from this source
+               // source: dijit.tree._dndSource
+               //              The source which provides items
+               // nodes: DOMNode[]
+               //              Array of DOM nodes corresponding to nodes being dropped, dijitTreeRow nodes if
+               //              source is a dijit.Tree.
                // tags:
-               //              protected
+               //              extension
+               return true;    // Boolean
+       },
+=====*/
+       checkAcceptance: null,
+
+/*=====
+       checkItemAcceptance: function(target, source, position){
+               // summary:
+               //              Stub function to be overridden if one wants to check for the ability to drop at the node/item level
+               // description:
+               //              In the base case, this is called to check if target can become a child of source.
+               //              When betweenThreshold is set, position="before" or "after" means that we
+               //              are asking if the source node can be dropped before/after the target node.
+               // target: DOMNode
+               //              The dijitTreeRoot DOM node inside of the TreeNode that we are dropping on to
+               //              Use dijit.getEnclosingWidget(target) to get the TreeNode.
+               // source: dijit.tree.dndSource
+               //              The (set of) nodes we are dropping
+               // position: String
+               //              "over", "before", or "after"
+               // tags:
+               //              extension
+               return true;    // Boolean
+       },
+=====*/
+       checkItemAcceptance: null,
+
+       // dragThreshold: Integer
+       //              Number of pixels mouse moves before it's considered the start of a drag operation
+       dragThreshold: 5,
+
+       // betweenThreshold: Integer
+       //              Set to a positive value to allow drag and drop "between" nodes.
+       //
+       //              If during DnD mouse is over a (target) node but less than betweenThreshold
+       //              pixels from the bottom edge, dropping the the dragged node will make it
+       //              the next sibling of the target node, rather than the child.
+       //
+       //              Similarly, if mouse is over a target node but less that betweenThreshold
+       //              pixels from the top edge, dropping the dragged node will make it
+       //              the target node's previous sibling rather than the target node's child.
+       betweenThreshold: 0,
+
+       // _nodePixelIndent: Integer
+       //              Number of pixels to indent tree nodes (relative to parent node).
+       //              Default is 19 but can be overridden by setting CSS class dijitTreeIndent
+       //              and calling resize() or startup() on tree after it's in the DOM.
+       _nodePixelIndent: 19,
 
-               // set focus so that the label will be voiced using screen readers
-               dijit.focus(node.labelNode);
+       _publish: function(/*String*/ topicName, /*Object*/ message){
+               // summary:
+               //              Publish a message for this widget/topic
+               dojo.publish(this.id, [dojo.mixin({tree: this, event: topicName}, message || {})]);
        },
 
-       _selectNode: function(/*_tree.Node*/ node){
-               // summary:
-               //              Mark specified node as select, and unmark currently selected node.
-               // tags:
-               //              protected
+       postMixInProperties: function(){
+               this.tree = this;
 
-               if(this.selectedNode && !this.selectedNode._destroyed){
-                       this.selectedNode.setSelected(false);
-               }
-               if(node){
-                       node.setSelected(true);
+               if(this.autoExpand){
+                       // There's little point in saving opened/closed state of nodes for a Tree
+                       // that initially opens all it's nodes.
+                       this.persist = false;
                }
-               this.selectedNode = node;
-       },
-
-       _onNodeFocus: function(/*dijit._Widget*/ node){
-               // summary:
-               //              Called when a TreeNode gets focus, either by user clicking
-               //              it, or programatically by arrow key handling code.
-               // description:
-               //              It marks that the current node is the selected one, and the previously
-               //              selected node no longer is.
 
-               if(node && node != this.lastFocused){
-                       if(this.lastFocused && !this.lastFocused._destroyed){
-                               // mark that the previously focsable node is no longer focusable
-                               this.lastFocused.setFocusable(false);
-                       }
+               this._itemNodesMap={};
 
-                       // mark that the new node is the currently selected one
-                       node.setFocusable(true);
-                       this.lastFocused = node;
+               if(!this.cookieName){
+                       this.cookieName = this.id + "SaveStateCookie";
                }
-       },
 
-       _onNodeMouseEnter: function(/*dijit._Widget*/ node){
-               // summary:
-               //              Called when mouse is over a node (onmouseenter event),
-               //              this is monitored by the DND code
-       },
+               this._loadDeferred = new dojo.Deferred();
 
-       _onNodeMouseLeave: function(/*dijit._Widget*/ node){
-               // summary:
-               //              Called when mouse leaves a node (onmouseleave event),
-               //              this is monitored by the DND code
+               this.inherited(arguments);
        },
 
-       //////////////// Events from the model //////////////////////////
-
-       _onItemChange: function(/*Item*/ item){
-               // summary:
-               //              Processes notification of a change to an item's scalar values like label
-               var model = this.model,
-                       identity = model.getIdentity(item),
-                       nodes = this._itemNodesMap[identity];
+       postCreate: function(){
+               this._initState();
 
-               if(nodes){
-                       var label = this.getLabel(item),
-                               tooltip = this.getTooltip(item);
-                       dojo.forEach(nodes, function(node){
-                               node.set({
-                                       item: item,             // theoretically could be new JS Object representing same item
-                                       label: label,
-                                       tooltip: tooltip
-                               });
-                               node._updateItemClasses(item);
-                       });
+               // Create glue between store and Tree, if not specified directly by user
+               if(!this.model){
+                       this._store2model();
                }
-       },
 
-       _onItemChildrenChange: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
-               // summary:
-               //              Processes notification of a change to an item's children
-               var model = this.model,
-                       identity = model.getIdentity(parent),
-                       parentNodes = this._itemNodesMap[identity];
+               // monitor changes to items
+               this.connect(this.model, "onChange", "_onItemChange");
+               this.connect(this.model, "onChildrenChange", "_onItemChildrenChange");
+               this.connect(this.model, "onDelete", "_onItemDelete");
 
-               if(parentNodes){
-                       dojo.forEach(parentNodes,function(parentNode){
-                               parentNode.setChildItems(newChildrenList);
-                       });
-               }
-       },
+               this._load();
 
-       _onItemDelete: function(/*Item*/ item){
-               // summary:
-               //              Processes notification of a deletion of an item
-               var model = this.model,
-                       identity = model.getIdentity(item),
-                       nodes = this._itemNodesMap[identity];
+               this.inherited(arguments);
 
-               if(nodes){
-                       dojo.forEach(nodes,function(node){
-                               var parent = node.getParent();
-                               if(parent){
-                                       // if node has not already been orphaned from a _onSetItem(parent, "children", ..) call...
-                                       parent.removeChild(node);
+               if(this.dndController){
+                       if(dojo.isString(this.dndController)){
+                               this.dndController = dojo.getObject(this.dndController);
+                       }
+                       var params={};
+                       for(var i=0; i<this.dndParams.length;i++){
+                               if(this[this.dndParams[i]]){
+                                       params[this.dndParams[i]] = this[this.dndParams[i]];
                                }
-                               node.destroyRecursive();
-                       });
-                       delete this._itemNodesMap[identity];
-               }
-       },
-
-       /////////////// Miscellaneous funcs
-
-       _initState: function(){
-               // summary:
-               //              Load in which nodes should be opened automatically
-               if(this.persist){
-                       var cookie = dojo.cookie(this.cookieName);
-                       this._openedItemIds = {};
-                       if(cookie){
-                               dojo.forEach(cookie.split(','), function(item){
-                                       this._openedItemIds[item] = true;
-                               }, this);
                        }
+                       this.dndController = new this.dndController(this, params);
                }
        },
-       _state: function(item,expanded){
-               // summary:
-               //              Query or set expanded state for an item,
-               if(!this.persist){
-                       return false;
-               }
-               var id=this.model.getIdentity(item);
-               if(arguments.length === 1){
-                       return this._openedItemIds[id];
-               }
-               if(expanded){
-                       this._openedItemIds[id] = true;
-               }else{
-                       delete this._openedItemIds[id];
-               }
-       },
-       _saveState: function(){
-               // summary:
-               //              Create and save a cookie with the currently expanded nodes identifiers
-               if(!this.persist){
-                       return;
-               }
-               var ary = [];
-               for(var id in this._openedItemIds){
-                       ary.push(id);
-               }
-               dojo.cookie(this.cookieName, ary.join(","), {expires:365});
-       },
 
-       destroy: function(){
-               if(this._curSearch){
-                       clearTimeout(this._curSearch.timer);
-                       delete this._curSearch;
-               }
-               if(this.rootNode){
-                       this.rootNode.destroyRecursive();
-               }
-               if(this.dndController && !dojo.isString(this.dndController)){
-                       this.dndController.destroy();
-               }
-               this.rootNode = null;
-               this.inherited(arguments);
-       },
+       _store2model: function(){
+               // summary:
+               //              User specified a store&query rather than model, so create model from store/query
+               this._v10Compat = true;
+               dojo.deprecated("Tree: from version 2.0, should specify a model object rather than a store/query");
 
-       destroyRecursive: function(){
-               // A tree is treated as a leaf, not as a node with children (like a grid),
-               // but defining destroyRecursive for back-compat.
-               this.destroy();
-       },
+               var modelParams = {
+                       id: this.id + "_ForestStoreModel",
+                       store: this.store,
+                       query: this.query,
+                       childrenAttrs: this.childrenAttr
+               };
 
-       resize: function(changeSize){
-               if(changeSize){
-                       dojo.marginBox(this.domNode, changeSize);
-                       dojo.style(this.domNode, "overflow", "auto");   // for scrollbars
+               // Only override the model's mayHaveChildren() method if the user has specified an override
+               if(this.params.mayHaveChildren){
+                       modelParams.mayHaveChildren = dojo.hitch(this, "mayHaveChildren");
                }
 
-               // The only JS sizing involved w/tree is the indentation, which is specified
-               // in CSS and read in through this dummy indentDetector node (tree must be
-               // visible and attached to the DOM to read this)
-               this._nodePixelIndent = dojo.marginBox(this.tree.indentDetector).w;
-
-               if(this.tree.rootNode){
-                       // If tree has already loaded, then reset indent for all the nodes
-                       this.tree.rootNode.set('indent', this.showRoot ? 0 : -1);
+               if(this.params.getItemChildren){
+                       modelParams.getChildren = dojo.hitch(this, function(item, onComplete, onError){
+                               this.getItemChildren((this._v10Compat && item === this.model.root) ? null : item, onComplete, onError);
+                       });
                }
+               this.model = new dijit.tree.ForestStoreModel(modelParams);
+
+               // For backwards compatibility, the visibility of the root node is controlled by
+               // whether or not the user has specified a label
+               this.showRoot = Boolean(this.label);
        },
 
-       _createTreeNode: function(/*Object*/ args){
+       onLoad: function(){
                // summary:
-               //              creates a TreeNode
+               //              Called when tree finishes loading and expanding.
                // description:
-               //              Developers can override this method to define their own TreeNode class;
-               //              However it will probably be removed in a future release in favor of a way
-               //              of just specifying a widget for the label, rather than one that contains
-               //              the children too.
-               return new dijit._TreeNode(args);
-       }
-});
-
-// For back-compat.  TODO: remove in 2.0
-
-
+               //              If persist == true the loading may encompass many levels of fetches
+               //              from the data store, each asynchronous.   Waits for all to finish.
+               // tags:
+               //              callback
+       },
 
-}
+       _load: function(){
+               // summary:
+               //              Initial load of the tree.
+               //              Load root node (possibly hidden) and it's children.
+               this.model.getRoot(
+                       dojo.hitch(this, function(item){
+                               var rn = (this.rootNode = this.tree._createTreeNode({
+                                       item: item,
+                                       tree: this,
+                                       isExpandable: true,
+                                       label: this.label || this.getLabel(item),
+                                       indent: this.showRoot ? 0 : -1
+                               }));
+                               if(!this.showRoot){
+                                       rn.rowNode.style.display="none";
+                                       // if root is not visible, move tree role to the invisible
+                                       // root node's containerNode, see #12135
+                                       dijit.setWaiRole(this.domNode, 'presentation');
+                                       
+                                       dijit.setWaiRole(rn.labelNode, 'presentation');
+                                       dijit.setWaiRole(rn.containerNode, 'tree');
+                               }
+                               this.domNode.appendChild(rn.domNode);
+                               var identity = this.model.getIdentity(item);
+                               if(this._itemNodesMap[identity]){
+                                       this._itemNodesMap[identity].push(rn);
+                               }else{
+                                       this._itemNodesMap[identity] = [rn];
+                               }
 
-if(!dojo._hasResource["dojo.dnd.Container"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dojo.dnd.Container"] = true;
-dojo.provide("dojo.dnd.Container");
+                               rn._updateLayout();             // sets "dijitTreeIsRoot" CSS classname
 
+                               // load top level children and then fire onLoad() event
+                               this._expandNode(rn).addCallback(dojo.hitch(this, function(){
+                                       this._loadDeferred.callback(true);
+                                       this.onLoad();
+                               }));
+                       }),
+                       function(err){
+                               console.error(this, ": error loading root: ", err);
+                       }
+               );
+       },
 
+       getNodesByItem: function(/*dojo.data.Item or id*/ item){
+               // summary:
+               //              Returns all tree nodes that refer to an item
+               // returns:
+               //              Array of tree nodes that refer to passed item
 
+               if(!item){ return []; }
+               var identity = dojo.isString(item) ? item : this.model.getIdentity(item);
+               // return a copy so widget don't get messed up by changes to returned array
+               return [].concat(this._itemNodesMap[identity]);
+       },
 
-/*
-       Container states:
-               ""              - normal state
-               "Over"  - mouse over a container
-       Container item states:
-               ""              - normal state
-               "Over"  - mouse over a container item
-*/
+       _setSelectedItemAttr: function(/*dojo.data.Item or id*/ item){
+               this.set('selectedItems', [item]);
+       },
 
-/*=====
-dojo.declare("dojo.dnd.__ContainerArgs", [], {
-       creator: function(){
+       _setSelectedItemsAttr: function(/*dojo.data.Items or ids*/ items){
                // summary:
-               //              a creator function, which takes a data item, and returns an object like that:
-               //              {node: newNode, data: usedData, type: arrayOfStrings}
+               //              Select tree nodes related to passed items.
+               //              WARNING: if model use multi-parented items or desired tree node isn't already loaded
+               //              behavior is undefined. Use set('paths', ...) instead.
+               var tree = this;
+               this._loadDeferred.addCallback( dojo.hitch(this, function(){
+                       var identities = dojo.map(items, function(item){
+                               return (!item || dojo.isString(item)) ? item : tree.model.getIdentity(item);
+                       });
+                       var nodes = [];
+                       dojo.forEach(identities, function(id){
+                               nodes = nodes.concat(tree._itemNodesMap[id] || []);
+                       });
+                       this.set('selectedNodes', nodes);
+               }));
        },
 
-       // skipForm: Boolean
-       //              don't start the drag operation, if clicked on form elements
-       skipForm: false,
-
-       // dropParent: Node||String
-       //              node or node's id to use as the parent node for dropped items
-       //              (must be underneath the 'node' parameter in the DOM)
-       dropParent: null,
-
-       // _skipStartup: Boolean
-       //              skip startup(), which collects children, for deferred initialization
-       //              (this is used in the markup mode)
-       _skipStartup: false
-});
-
-dojo.dnd.Item = function(){
-       // summary:
-       //              Represents (one of) the source node(s) being dragged.
-       //              Contains (at least) the "type" and "data" attributes.
-       // type: String[]
-       //              Type(s) of this item, by default this is ["text"]
-       // data: Object
-       //              Logical representation of the object being dragged.
-       //              If the drag object's type is "text" then data is a String,
-       //              if it's another type then data could be a different Object,
-       //              perhaps a name/value hash.
-       
-       this.type = type;
-       this.data = data;
-}
-=====*/
-
-dojo.declare("dojo.dnd.Container", null, {
-       // summary:
-       //              a Container object, which knows when mouse hovers over it, 
-       //              and over which element it hovers
-       
-       // object attributes (for markup)
-       skipForm: false,
-       
-       /*=====
-       // current: DomNode
-       //              The DOM node the mouse is currently hovered over
-       current: null,
-       
-       // map: Hash<String, dojo.dnd.Item>
-       //              Map from an item's id (which is also the DOMNode's id) to
-       //              the dojo.dnd.Item itself.
-       map: {},
-       =====*/
+       _setPathAttr: function(/*Item[] || String[]*/ path){
+               // summary:
+               //      Singular variant of _setPathsAttr
+               if(path.length) {
+                       return this.set("paths", [path]);
+               } else {
+                       //Empty list is interpreted as "select nothing"
+                       return this.set("paths", []);
+               }
+       },
        
-       constructor: function(node, params){
+       _setPathsAttr: function(/*Item[][] || String[][]*/ paths){
                // summary:
-               //              a constructor of the Container
-               // node: Node
-               //              node or node's id to build the container on
-               // params: dojo.dnd.__ContainerArgs
-               //              a dictionary of parameters
-               this.node = dojo.byId(node);
-               if(!params){ params = {}; }
-               this.creator = params.creator || null;
-               this.skipForm = params.skipForm;
-               this.parent = params.dropParent && dojo.byId(params.dropParent);
-               
-               // class-specific variables
-               this.map = {};
-               this.current = null;
+               //              Select the tree nodes identified by passed paths.
+               // paths:
+               //              Array of arrays of items or item id's
+               // returns:
+               //              Deferred to indicate when the set is complete
+               var tree = this;
 
-               // states
-               this.containerState = "";
-               dojo.addClass(this.node, "dojoDndContainer");
+               // We may need to wait for some nodes to expand, so setting
+               // each path will involve a Deferred. We bring those deferreds
+               // together witha DeferredList.
+               return new dojo.DeferredList(dojo.map(paths, function(path){
+                       var d = new dojo.Deferred();
+                       
+                       // normalize path to use identity
+                       path = dojo.map(path, function(item){
+                               return dojo.isString(item) ? item : tree.model.getIdentity(item);
+                       });
+
+                       if(path.length){
+                               // Wait for the tree to load, if it hasn't already.
+                               tree._loadDeferred.addCallback(function(){ selectPath(path, [tree.rootNode], d); });
+                       }else{
+                               d.errback("Empty path");
+                       }
+                       return d;
+               })).addCallback(setNodes);
+
+               function selectPath(path, nodes, def){
+                       // Traverse path; the next path component should be among "nodes".
+                       var nextPath = path.shift();
+                       var nextNode = dojo.filter(nodes, function(node){
+                               return node.getIdentity() == nextPath;
+                       })[0];
+                       if(!!nextNode){
+                               if(path.length){
+                                       tree._expandNode(nextNode).addCallback(function(){ selectPath(path, nextNode.getChildren(), def); });
+                               }else{
+                                       //Successfully reached the end of this path
+                                       def.callback(nextNode);
+                               }
+                       } else {
+                               def.errback("Could not expand path at " + nextPath);
+                       }
+               }
                
-               // mark up children
-               if(!(params && params._skipStartup)){
-                       this.startup();
+               function setNodes(newNodes){
+                       //After all expansion is finished, set the selection to
+                       //the set of nodes successfully found.
+                       tree.set("selectedNodes", dojo.map(
+                               dojo.filter(newNodes,function(x){return x[0];}),
+                               function(x){return x[1];}));
                }
+       },
 
-               // set up events
-               this.events = [
-                       dojo.connect(this.node, "onmouseover", this, "onMouseOver"),
-                       dojo.connect(this.node, "onmouseout",  this, "onMouseOut"),
-                       // cancel text selection and text dragging
-                       dojo.connect(this.node, "ondragstart",   this, "onSelectStart"),
-                       dojo.connect(this.node, "onselectstart", this, "onSelectStart")
-               ];
+       _setSelectedNodeAttr: function(node){
+               this.set('selectedNodes', [node]);
        },
-       
-       // object attributes (for markup)
-       creator: function(){
-               // summary:
-               //              creator function, dummy at the moment
+       _setSelectedNodesAttr: function(nodes){
+               this._loadDeferred.addCallback( dojo.hitch(this, function(){
+                       this.dndController.setSelection(nodes);
+               }));
        },
-       
-       // abstract access to the map
-       getItem: function(/*String*/ key){
+
+
+       ////////////// Data store related functions //////////////////////
+       // These just get passed to the model; they are here for back-compat
+
+       mayHaveChildren: function(/*dojo.data.Item*/ item){
                // summary:
-               //              returns a data item by its key (id)
-               return this.map[key];   // dojo.dnd.Item
+               //              Deprecated.   This should be specified on the model itself.
+               //
+               //              Overridable function to tell if an item has or may have children.
+               //              Controls whether or not +/- expando icon is shown.
+               //              (For efficiency reasons we may not want to check if an element actually
+               //              has children until user clicks the expando node)
+               // tags:
+               //              deprecated
        },
-       setItem: function(/*String*/ key, /*dojo.dnd.Item*/ data){
+
+       getItemChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ onComplete){
                // summary:
-               //              associates a data item with its key (id)
-               this.map[key] = data;
+               //              Deprecated.   This should be specified on the model itself.
+               //
+               //              Overridable function that return array of child items of given parent item,
+               //              or if parentItem==null then return top items in tree
+               // tags:
+               //              deprecated
        },
-       delItem: function(/*String*/ key){
+
+       ///////////////////////////////////////////////////////
+       // Functions for converting an item to a TreeNode
+       getLabel: function(/*dojo.data.Item*/ item){
                // summary:
-               //              removes a data item from the map by its key (id)
-               delete this.map[key];
+               //              Overridable function to get the label for a tree node (given the item)
+               // tags:
+               //              extension
+               return this.model.getLabel(item);       // String
        },
-       forInItems: function(/*Function*/ f, /*Object?*/ o){
+
+       getIconClass: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
                // summary:
-               //              iterates over a data map skipping members that 
-               //              are present in the empty object (IE and/or 3rd-party libraries).
-               o = o || dojo.global;
-               var m = this.map, e = dojo.dnd._empty;
-               for(var i in m){
-                       if(i in e){ continue; }
-                       f.call(o, m[i], i, this);
-               }
-               return o;       // Object
+               //              Overridable function to return CSS class name to display icon
+               // tags:
+               //              extension
+               return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "dijitLeaf"
        },
-       clearItems: function(){
+
+       getLabelClass: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
                // summary:
-               //              removes all data items from the map
-               this.map = {};
+               //              Overridable function to return CSS class name to display label
+               // tags:
+               //              extension
        },
-       
-       // methods
-       getAllNodes: function(){
+
+       getRowClass: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
                // summary:
-               //              returns a list (an array) of all valid child nodes
-               return dojo.query("> .dojoDndItem", this.parent);       // NodeList
+               //              Overridable function to return CSS class name to display row
+               // tags:
+               //              extension
        },
-       sync: function(){
+
+       getIconStyle: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
                // summary:
-               //              sync up the node list with the data map
-               var map = {};
-               this.getAllNodes().forEach(function(node){
-                       if(node.id){
-                               var item = this.getItem(node.id);
-                               if(item){
-                                       map[node.id] = item;
-                                       return;
-                               }
-                       }else{
-                               node.id = dojo.dnd.getUniqueId();
-                       }
-                       var type = node.getAttribute("dndType"),
-                               data = node.getAttribute("dndData");
-                       map[node.id] = {
-                               data: data || node.innerHTML,
-                               type: type ? type.split(/\s*,\s*/) : ["text"]
-                       };
-               }, this);
-               this.map = map;
-               return this;    // self
+               //              Overridable function to return CSS styles to display icon
+               // returns:
+               //              Object suitable for input to dojo.style() like {backgroundImage: "url(...)"}
+               // tags:
+               //              extension
+       },
+
+       getLabelStyle: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
+               // summary:
+               //              Overridable function to return CSS styles to display label
+               // returns:
+               //              Object suitable for input to dojo.style() like {color: "red", background: "green"}
+               // tags:
+               //              extension
        },
-       insertNodes: function(data, before, anchor){
+
+       getRowStyle: function(/*dojo.data.Item*/ item, /*Boolean*/ opened){
                // summary:
-               //              inserts an array of new nodes before/after an anchor node
-               // data: Array
-               //              a list of data items, which should be processed by the creator function
-               // before: Boolean
-               //              insert before the anchor, if true, and after the anchor otherwise
-               // anchor: Node
-               //              the anchor node to be used as a point of insertion
-               if(!this.parent.firstChild){
-                       anchor = null;
-               }else if(before){
-                       if(!anchor){
-                               anchor = this.parent.firstChild;
+               //              Overridable function to return CSS styles to display row
+               // returns:
+               //              Object suitable for input to dojo.style() like {background-color: "#bbb"}
+               // tags:
+               //              extension
+       },
+
+       getTooltip: function(/*dojo.data.Item*/ item){
+               // summary:
+               //              Overridable function to get the tooltip for a tree node (given the item)
+               // tags:
+               //              extension
+               return "";      // String
+       },
+
+       /////////// Keyboard and Mouse handlers ////////////////////
+
+       _onKeyPress: function(/*Event*/ e){
+               // summary:
+               //              Translates keypress events into commands for the controller
+               if(e.altKey){ return; }
+               var dk = dojo.keys;
+               var treeNode = dijit.getEnclosingWidget(e.target);
+               if(!treeNode){ return; }
+
+               var key = e.charOrCode;
+               if(typeof key == "string" && key != " "){       // handle printables (letter navigation)
+                       // Check for key navigation.
+                       if(!e.altKey && !e.ctrlKey && !e.shiftKey && !e.metaKey){
+                               this._onLetterKeyNav( { node: treeNode, key: key.toLowerCase() } );
+                               dojo.stopEvent(e);
                        }
-               }else{
-                       if(anchor){
-                               anchor = anchor.nextSibling;
+               }else{  // handle non-printables (arrow keys)
+                       // clear record of recent printables (being saved for multi-char letter navigation),
+                       // because "a", down-arrow, "b" shouldn't search for "ab"
+                       if(this._curSearch){
+                               clearTimeout(this._curSearch.timer);
+                               delete this._curSearch;
                        }
-               }
-               if(anchor){
-                       for(var i = 0; i < data.length; ++i){
-                               var t = this._normalizedCreator(data[i]);
-                               this.setItem(t.node.id, {data: t.data, type: t.type});
-                               this.parent.insertBefore(t.node, anchor);
+
+                       var map = this._keyHandlerMap;
+                       if(!map){
+                               // setup table mapping keys to events
+                               map = {};
+                               map[dk.ENTER]="_onEnterKey";
+                               //On WebKit based browsers, the combination ctrl-enter
+                               //does not get passed through. To allow accessible
+                               //multi-select on those browsers, the space key is
+                               //also used for selection.
+                               map[dk.SPACE]= map[" "] = "_onEnterKey";
+                               map[this.isLeftToRight() ? dk.LEFT_ARROW : dk.RIGHT_ARROW]="_onLeftArrow";
+                               map[this.isLeftToRight() ? dk.RIGHT_ARROW : dk.LEFT_ARROW]="_onRightArrow";
+                               map[dk.UP_ARROW]="_onUpArrow";
+                               map[dk.DOWN_ARROW]="_onDownArrow";
+                               map[dk.HOME]="_onHomeKey";
+                               map[dk.END]="_onEndKey";
+                               this._keyHandlerMap = map;
                        }
-               }else{
-                       for(var i = 0; i < data.length; ++i){
-                               var t = this._normalizedCreator(data[i]);
-                               this.setItem(t.node.id, {data: t.data, type: t.type});
-                               this.parent.appendChild(t.node);
+                       if(this._keyHandlerMap[key]){
+                               this[this._keyHandlerMap[key]]( { node: treeNode, item: treeNode.item, evt: e } );
+                               dojo.stopEvent(e);
                        }
                }
-               return this;    // self
-       },
-       destroy: function(){
-               // summary:
-               //              prepares this object to be garbage-collected
-               dojo.forEach(this.events, dojo.disconnect);
-               this.clearItems();
-               this.node = this.parent = this.current = null;
        },
 
-       // markup methods
-       markupFactory: function(params, node){
-               params._skipStartup = true;
-               return new dojo.dnd.Container(node, params);
+       _onEnterKey: function(/*Object*/ message){
+               this._publish("execute", { item: message.item, node: message.node } );
+               this.dndController.userSelect(message.node, dojo.isCopyKey( message.evt ), message.evt.shiftKey);
+               this.onClick(message.item, message.node, message.evt);
        },
-       startup: function(){
+
+       _onDownArrow: function(/*Object*/ message){
                // summary:
-               //              collects valid child items and populate the map
-               
-               // set up the real parent node
-               if(!this.parent){
-                       // use the standard algorithm, if not assigned
-                       this.parent = this.node;
-                       if(this.parent.tagName.toLowerCase() == "table"){
-                               var c = this.parent.getElementsByTagName("tbody");
-                               if(c && c.length){ this.parent = c[0]; }
-                       }
+               //              down arrow pressed; get next visible node, set focus there
+               var node = this._getNextNode(message.node);
+               if(node && node.isTreeNode){
+                       this.focusNode(node);
                }
-               this.defaultCreator = dojo.dnd._defaultCreator(this.parent);
-
-               // process specially marked children
-               this.sync();
        },
 
-       // mouse events
-       onMouseOver: function(e){
+       _onUpArrow: function(/*Object*/ message){
                // summary:
-               //              event processor for onmouseover
-               // e: Event
-               //              mouse event
-               var n = e.relatedTarget;
-               while(n){
-                       if(n == this.node){ break; }
-                       try{
-                               n = n.parentNode;
-                       }catch(x){
-                               n = null;
+               //              Up arrow pressed; move to previous visible node
+
+               var node = message.node;
+
+               // if younger siblings
+               var previousSibling = node.getPreviousSibling();
+               if(previousSibling){
+                       node = previousSibling;
+                       // if the previous node is expanded, dive in deep
+                       while(node.isExpandable && node.isExpanded && node.hasChildren()){
+                               // move to the last child
+                               var children = node.getChildren();
+                               node = children[children.length-1];
+                       }
+               }else{
+                       // if this is the first child, return the parent
+                       // unless the parent is the root of a tree with a hidden root
+                       var parent = node.getParent();
+                       if(!(!this.showRoot && parent === this.rootNode)){
+                               node = parent;
                        }
                }
-               if(!n){
-                       this._changeState("Container", "Over");
-                       this.onOverEvent();
+
+               if(node && node.isTreeNode){
+                       this.focusNode(node);
                }
-               n = this._getChildByEvent(e);
-               if(this.current == n){ return; }
-               if(this.current){ this._removeItemClass(this.current, "Over"); }
-               if(n){ this._addItemClass(n, "Over"); }
-               this.current = n;
        },
-       onMouseOut: function(e){
+
+       _onRightArrow: function(/*Object*/ message){
                // summary:
-               //              event processor for onmouseout
-               // e: Event
-               //              mouse event
-               for(var n = e.relatedTarget; n;){
-                       if(n == this.node){ return; }
-                       try{
-                               n = n.parentNode;
-                       }catch(x){
-                               n = null;
+               //              Right arrow pressed; go to child node
+               var node = message.node;
+
+               // if not expanded, expand, else move to 1st child
+               if(node.isExpandable && !node.isExpanded){
+                       this._expandNode(node);
+               }else if(node.hasChildren()){
+                       node = node.getChildren()[0];
+                       if(node && node.isTreeNode){
+                               this.focusNode(node);
                        }
                }
-               if(this.current){
-                       this._removeItemClass(this.current, "Over");
-                       this.current = null;
-               }
-               this._changeState("Container", "");
-               this.onOutEvent();
        },
-       onSelectStart: function(e){
+
+       _onLeftArrow: function(/*Object*/ message){
                // summary:
-               //              event processor for onselectevent and ondragevent
-               // e: Event
-               //              mouse event
-               if(!this.skipForm || !dojo.dnd.isFormElement(e)){
-                       dojo.stopEvent(e);
+               //              Left arrow pressed.
+               //              If not collapsed, collapse, else move to parent.
+
+               var node = message.node;
+
+               if(node.isExpandable && node.isExpanded){
+                       this._collapseNode(node);
+               }else{
+                       var parent = node.getParent();
+                       if(parent && parent.isTreeNode && !(!this.showRoot && parent === this.rootNode)){
+                               this.focusNode(parent);
+                       }
                }
        },
-       
-       // utilities
-       onOverEvent: function(){
-               // summary:
-               //              this function is called once, when mouse is over our container
-       },
-       onOutEvent: function(){
-               // summary:
-               //              this function is called once, when mouse is out of our container
-       },
-       _changeState: function(type, newState){
-               // summary:
-               //              changes a named state to new state value
-               // type: String
-               //              a name of the state to change
-               // newState: String
-               //              new state
-               var prefix = "dojoDnd" + type;
-               var state  = type.toLowerCase() + "State";
-               //dojo.replaceClass(this.node, prefix + newState, prefix + this[state]);
-               dojo.removeClass(this.node, prefix + this[state]);
-               dojo.addClass(this.node, prefix + newState);
-               this[state] = newState;
-       },
-       _addItemClass: function(node, type){
-               // summary:
-               //              adds a class with prefix "dojoDndItem"
-               // node: Node
-               //              a node
-               // type: String
-               //              a variable suffix for a class name
-               dojo.addClass(node, "dojoDndItem" + type);
-       },
-       _removeItemClass: function(node, type){
-               // summary:
-               //              removes a class with prefix "dojoDndItem"
-               // node: Node
-               //              a node
-               // type: String
-               //              a variable suffix for a class name
-               dojo.removeClass(node, "dojoDndItem" + type);
-       },
-       _getChildByEvent: function(e){
+
+       _onHomeKey: function(){
                // summary:
-               //              gets a child, which is under the mouse at the moment, or null
-               // e: Event
-               //              a mouse event
-               var node = e.target;
+               //              Home key pressed; get first visible node, and set focus there
+               var node = this._getRootOrFirstNode();
                if(node){
-                       for(var parent = node.parentNode; parent; node = parent, parent = node.parentNode){
-                               if(parent == this.parent && dojo.hasClass(node, "dojoDndItem")){ return node; }
-                       }
+                       this.focusNode(node);
                }
-               return null;
        },
-       _normalizedCreator: function(/*dojo.dnd.Item*/ item, /*String*/ hint){
+
+       _onEndKey: function(/*Object*/ message){
                // summary:
-               //              adds all necessary data to the output of the user-supplied creator function
-               var t = (this.creator || this.defaultCreator).call(this, item, hint);
-               if(!dojo.isArray(t.type)){ t.type = ["text"]; }
-               if(!t.node.id){ t.node.id = dojo.dnd.getUniqueId(); }
-               dojo.addClass(t.node, "dojoDndItem");
-               return t;
-       }
-});
+               //              End key pressed; go to last visible node.
 
-dojo.dnd._createNode = function(tag){
-       // summary:
-       //              returns a function, which creates an element of given tag 
-       //              (SPAN by default) and sets its innerHTML to given text
-       // tag: String
-       //              a tag name or empty for SPAN
-       if(!tag){ return dojo.dnd._createSpan; }
-       return function(text){  // Function
-               return dojo.create(tag, {innerHTML: text});     // Node
-       };
-};
+               var node = this.rootNode;
+               while(node.isExpanded){
+                       var c = node.getChildren();
+                       node = c[c.length - 1];
+               }
 
-dojo.dnd._createTrTd = function(text){
-       // summary:
-       //              creates a TR/TD structure with given text as an innerHTML of TD
-       // text: String
-       //              a text for TD
-       var tr = dojo.create("tr");
-       dojo.create("td", {innerHTML: text}, tr);
-       return tr;      // Node
-};
+               if(node && node.isTreeNode){
+                       this.focusNode(node);
+               }
+       },
 
-dojo.dnd._createSpan = function(text){
-       // summary:
-       //              creates a SPAN element with given text as its innerHTML
-       // text: String
-       //              a text for SPAN
-       return dojo.create("span", {innerHTML: text});  // Node
-};
+       // multiCharSearchDuration: Number
+       //              If multiple characters are typed where each keystroke happens within
+       //              multiCharSearchDuration of the previous keystroke,
+       //              search for nodes matching all the keystrokes.
+       //
+       //              For example, typing "ab" will search for entries starting with
+       //              "ab" unless the delay between "a" and "b" is greater than multiCharSearchDuration.
+       multiCharSearchDuration: 250,
 
-// dojo.dnd._defaultCreatorNodes: Object
-//             a dictionary that maps container tag names to child tag names
-dojo.dnd._defaultCreatorNodes = {ul: "li", ol: "li", div: "div", p: "div"};
+       _onLetterKeyNav: function(message){
+               // summary:
+               //              Called when user presses a prinatable key; search for node starting with recently typed letters.
+               // message: Object
+               //              Like { node: TreeNode, key: 'a' } where key is the key the user pressed.
 
-dojo.dnd._defaultCreator = function(node){
-       // summary:
-       //              takes a parent node, and returns an appropriate creator function
-       // node: Node
-       //              a container node
-       var tag = node.tagName.toLowerCase();
-       var c = tag == "tbody" || tag == "thead" ? dojo.dnd._createTrTd :
-                       dojo.dnd._createNode(dojo.dnd._defaultCreatorNodes[tag]);
-       return function(item, hint){    // Function
-               var isObj = item && dojo.isObject(item), data, type, n;
-               if(isObj && item.tagName && item.nodeType && item.getAttribute){
-                       // process a DOM node
-                       data = item.getAttribute("dndData") || item.innerHTML;
-                       type = item.getAttribute("dndType");
-                       type = type ? type.split(/\s*,\s*/) : ["text"];
-                       n = item;       // this node is going to be moved rather than copied
+               // Branch depending on whether this key starts a new search, or modifies an existing search
+               var cs = this._curSearch;
+               if(cs){
+                       // We are continuing a search.  Ex: user has pressed 'a', and now has pressed
+                       // 'b', so we want to search for nodes starting w/"ab".
+                       cs.pattern = cs.pattern + message.key;
+                       clearTimeout(cs.timer);
                }else{
-                       // process a DnD item object or a string
-                       data = (isObj && item.data) ? item.data : item;
-                       type = (isObj && item.type) ? item.type : ["text"];
-                       n = (hint == "avatar" ? dojo.dnd._createSpan : c)(String(data));
+                       // We are starting a new search
+                       cs = this._curSearch = {
+                                       pattern: message.key,
+                                       startNode: message.node
+                       };
                }
-               if(!n.id){
-                       n.id = dojo.dnd.getUniqueId();
+
+               // set/reset timer to forget recent keystrokes
+               var self = this;
+               cs.timer = setTimeout(function(){
+                       delete self._curSearch;
+               }, this.multiCharSearchDuration);
+
+               // Navigate to TreeNode matching keystrokes [entered so far].
+               var node = cs.startNode;
+               do{
+                       node = this._getNextNode(node);
+                       //check for last node, jump to first node if necessary
+                       if(!node){
+                               node = this._getRootOrFirstNode();
+                       }
+               }while(node !== cs.startNode && (node.label.toLowerCase().substr(0, cs.pattern.length) != cs.pattern));
+               if(node && node.isTreeNode){
+                       // no need to set focus if back where we started
+                       if(node !== cs.startNode){
+                               this.focusNode(node);
+                       }
                }
-               return {node: n, data: data, type: type};
-       };
-};
+       },
 
-}
+       isExpandoNode: function(node, widget){
+               // summary:
+               //              check whether a dom node is the expandoNode for a particular TreeNode widget
+               return dojo.isDescendant(node, widget.expandoNode);
+       },
+       _onClick: function(/*TreeNode*/ nodeWidget, /*Event*/ e){
+               // summary:
+               //              Translates click events into commands for the controller to process
 
-if(!dojo._hasResource["dijit.tree._dndContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dijit.tree._dndContainer"] = true;
-dojo.provide("dijit.tree._dndContainer");
+               var domElement = e.target,
+                       isExpandoClick = this.isExpandoNode(domElement, nodeWidget);
 
+               if( (this.openOnClick && nodeWidget.isExpandable) || isExpandoClick ){
+                       // expando node was clicked, or label of a folder node was clicked; open it
+                       if(nodeWidget.isExpandable){
+                               this._onExpandoClick({node:nodeWidget});
+                       }
+               }else{
+                       this._publish("execute", { item: nodeWidget.item, node: nodeWidget, evt: e } );
+                       this.onClick(nodeWidget.item, nodeWidget, e);
+                       this.focusNode(nodeWidget);
+               }
+               dojo.stopEvent(e);
+       },
+       _onDblClick: function(/*TreeNode*/ nodeWidget, /*Event*/ e){
+               // summary:
+               //              Translates double-click events into commands for the controller to process
 
+               var domElement = e.target,
+                       isExpandoClick = (domElement == nodeWidget.expandoNode || domElement == nodeWidget.expandoNodeText);
 
-dojo.declare("dijit.tree._dndContainer",
-       null,
-       {
+               if( (this.openOnDblClick && nodeWidget.isExpandable) ||isExpandoClick ){
+                       // expando node was clicked, or label of a folder node was clicked; open it
+                       if(nodeWidget.isExpandable){
+                               this._onExpandoClick({node:nodeWidget});
+                       }
+               }else{
+                       this._publish("execute", { item: nodeWidget.item, node: nodeWidget, evt: e } );
+                       this.onDblClick(nodeWidget.item, nodeWidget, e);
+                       this.focusNode(nodeWidget);
+               }
+               dojo.stopEvent(e);
+       },
 
+       _onExpandoClick: function(/*Object*/ message){
                // summary:
-               //              This is a base class for `dijit.tree._dndSelector`, and isn't meant to be used directly.
-               //              It's modeled after `dojo.dnd.Container`.
-               // tags:
-               //              protected
+               //              User clicked the +/- icon; expand or collapse my children.
+               var node = message.node;
 
-               /*=====
-               // current: DomNode
-               //              The currently hovered TreeNode.rowNode (which is the DOM node
-               //              associated w/a given node in the tree, excluding it's descendants)
-               current: null,
-               =====*/
+               // If we are collapsing, we might be hiding the currently focused node.
+               // Also, clicking the expando node might have erased focus from the current node.
+               // For simplicity's sake just focus on the node with the expando.
+               this.focusNode(node);
 
-               constructor: function(tree, params){
-                       // summary:
-                       //              A constructor of the Container
-                       // tree: Node
-                       //              Node or node's id to build the container on
-                       // params: dijit.tree.__SourceArgs
-                       //              A dict of parameters, which gets mixed into the object
-                       // tags:
-                       //              private
-                       this.tree = tree;
-                       this.node = tree.domNode;       // TODO: rename; it's not a TreeNode but the whole Tree
-                       dojo.mixin(this, params);
+               if(node.isExpanded){
+                       this._collapseNode(node);
+               }else{
+                       this._expandNode(node);
+               }
+       },
 
-                       // class-specific variables
-                       this.map = {};
-                       this.current = null;    // current TreeNode's DOM node
+       onClick: function(/* dojo.data */ item, /*TreeNode*/ node, /*Event*/ evt){
+               // summary:
+               //              Callback when a tree node is clicked
+               // tags:
+               //              callback
+       },
+       onDblClick: function(/* dojo.data */ item, /*TreeNode*/ node, /*Event*/ evt){
+               // summary:
+               //              Callback when a tree node is double-clicked
+               // tags:
+               //              callback
+       },
+       onOpen: function(/* dojo.data */ item, /*TreeNode*/ node){
+               // summary:
+               //              Callback when a node is opened
+               // tags:
+               //              callback
+       },
+       onClose: function(/* dojo.data */ item, /*TreeNode*/ node){
+               // summary:
+               //              Callback when a node is closed
+               // tags:
+               //              callback
+       },
+
+       _getNextNode: function(node){
+               // summary:
+               //              Get next visible node
+
+               if(node.isExpandable && node.isExpanded && node.hasChildren()){
+                       // if this is an expanded node, get the first child
+                       return node.getChildren()[0];           // _TreeNode
+               }else{
+                       // find a parent node with a sibling
+                       while(node && node.isTreeNode){
+                               var returnNode = node.getNextSibling();
+                               if(returnNode){
+                                       return returnNode;              // _TreeNode
+                               }
+                               node = node.getParent();
+                       }
+                       return null;
+               }
+       },
 
-                       // states
-                       this.containerState = "";
-                       dojo.addClass(this.node, "dojoDndContainer");
+       _getRootOrFirstNode: function(){
+               // summary:
+               //              Get first visible node
+               return this.showRoot ? this.rootNode : this.rootNode.getChildren()[0];
+       },
 
-                       // set up events
-                       this.events = [
-                               // container level events
-                               dojo.connect(this.node, "onmouseenter", this, "onOverEvent"),
-                               dojo.connect(this.node, "onmouseleave", this, "onOutEvent"),
+       _collapseNode: function(/*_TreeNode*/ node){
+               // summary:
+               //              Called when the user has requested to collapse the node
 
-                               // switching between TreeNodes
-                               dojo.connect(this.tree, "_onNodeMouseEnter", this, "onMouseOver"),
-                               dojo.connect(this.tree, "_onNodeMouseLeave", this, "onMouseOut"),
+               if(node._expandNodeDeferred){
+                       delete node._expandNodeDeferred;
+               }
 
-                               // cancel text selection and text dragging
-                               dojo.connect(this.node, "ondragstart", dojo, "stopEvent"),
-                               dojo.connect(this.node, "onselectstart", dojo, "stopEvent")
-                       ];
-               },
+               if(node.isExpandable){
+                       if(node.state == "LOADING"){
+                               // ignore clicks while we are in the process of loading data
+                               return;
+                       }
 
-               getItem: function(/*String*/ key){
-                       // summary:
-                       //              Returns the dojo.dnd.Item (representing a dragged node) by it's key (id).
-                       //              Called by dojo.dnd.Source.checkAcceptance().
-                       // tags:
-                       //              protected
+                       node.collapse();
+                       this.onClose(node.item, node);
 
-                       var node = this.selection[key],
-                               ret = {
-                                       data: dijit.getEnclosingWidget(node),
-                                       type: ["treeNode"]
-                               };
+                       if(node.item){
+                               this._state(node.item,false);
+                               this._saveState();
+                       }
+               }
+       },
 
-                       return ret;     // dojo.dnd.Item
-               },
+       _expandNode: function(/*_TreeNode*/ node, /*Boolean?*/ recursive){
+               // summary:
+               //              Called when the user has requested to expand the node
+               // recursive:
+               //              Internal flag used when _expandNode() calls itself, don't set.
+               // returns:
+               //              Deferred that fires when the node is loaded and opened and (if persist=true) all it's descendants
+               //              that were previously opened too
 
-               destroy: function(){
-                       // summary:
-                       //              Prepares this object to be garbage-collected
+               if(node._expandNodeDeferred && !recursive){
+                       // there's already an expand in progress (or completed), so just return
+                       return node._expandNodeDeferred;        // dojo.Deferred
+               }
 
-                       dojo.forEach(this.events, dojo.disconnect);
-                       // this.clearItems();
-                       this.node = this.parent = null;
-               },
+               var model = this.model,
+                       item = node.item,
+                       _this = this;
 
-               // mouse events
-               onMouseOver: function(/*TreeNode*/ widget, /*Event*/ evt){
-                       // summary:
-                       //              Called when mouse is moved over a TreeNode
-                       // tags:
-                       //              protected
-                       this.current = widget.rowNode;
-                       this.currentWidget = widget;
-               },
+               switch(node.state){
+                       case "UNCHECKED":
+                               // need to load all the children, and then expand
+                               node.markProcessing();
 
-               onMouseOut: function(/*TreeNode*/ widget, /*Event*/ evt){
-                       // summary:
-                       //              Called when mouse is moved away from a TreeNode
-                       // tags:
-                       //              protected
-                       this.current = null;
-                       this.currentWidget = null;
-               },
+                               // Setup deferred to signal when the load and expand are finished.
+                               // Save that deferred in this._expandDeferred as a flag that operation is in progress.
+                               var def = (node._expandNodeDeferred = new dojo.Deferred());
 
-               _changeState: function(type, newState){
-                       // summary:
-                       //              Changes a named state to new state value
-                       // type: String
-                       //              A name of the state to change
-                       // newState: String
-                       //              new state
-                       var prefix = "dojoDnd" + type;
-                       var state = type.toLowerCase() + "State";
-                       //dojo.replaceClass(this.node, prefix + newState, prefix + this[state]);
-                       dojo.removeClass(this.node, prefix + this[state]);
-                       dojo.addClass(this.node, prefix + newState);
-                       this[state] = newState;
-               },
+                               // Get the children
+                               model.getChildren(
+                                       item,
+                                       function(items){
+                                               node.unmarkProcessing();
 
-               _addItemClass: function(node, type){
-                       // summary:
-                       //              Adds a class with prefix "dojoDndItem"
-                       // node: Node
-                       //              A node
-                       // type: String
-                       //              A variable suffix for a class name
-                       dojo.addClass(node, "dojoDndItem" + type);
-               },
+                                               // Display the children and also start expanding any children that were previously expanded
+                                               // (if this.persist == true).   The returned Deferred will fire when those expansions finish.
+                                               var scid = node.setChildItems(items);
 
-               _removeItemClass: function(node, type){
-                       // summary:
-                       //              Removes a class with prefix "dojoDndItem"
-                       // node: Node
-                       //              A node
-                       // type: String
-                       //              A variable suffix for a class name
-                       dojo.removeClass(node, "dojoDndItem" + type);
-               },
+                                               // Call _expandNode() again but this time it will just to do the animation (default branch).
+                                               // The returned Deferred will fire when the animation completes.
+                                               // TODO: seems like I can avoid recursion and just use a deferred to sequence the events?
+                                               var ed = _this._expandNode(node, true);
 
-               onOverEvent: function(){
-                       // summary:
-                       //              This function is called once, when mouse is over our container
-                       // tags:
-                       //              protected
-                       this._changeState("Container", "Over");
-               },
+                                               // After the above two tasks (setChildItems() and recursive _expandNode()) finish,
+                                               // signal that I am done.
+                                               scid.addCallback(function(){
+                                                       ed.addCallback(function(){
+                                                               def.callback();
+                                                       })
+                                               });
+                                       },
+                                       function(err){
+                                               console.error(_this, ": error loading root children: ", err);
+                                       }
+                               );
+                               break;
 
-               onOutEvent: function(){
-                       // summary:
-                       //              This function is called once, when mouse is out of our container
-                       // tags:
-                       //              protected
-                       this._changeState("Container", "");
-               }
-});
+                       default:        // "LOADED"
+                               // data is already loaded; just expand node
+                               def = (node._expandNodeDeferred = node.expand());
 
-}
+                               this.onOpen(node.item, node);
 
-if(!dojo._hasResource["dijit.tree._dndSelector"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dijit.tree._dndSelector"] = true;
-dojo.provide("dijit.tree._dndSelector");
+                               if(item){
+                                       this._state(item, true);
+                                       this._saveState();
+                               }
+               }
 
+               return def;     // dojo.Deferred
+       },
 
+       ////////////////// Miscellaneous functions ////////////////
 
-dojo.declare("dijit.tree._dndSelector",
-       dijit.tree._dndContainer,
-       {
+       focusNode: function(/* _tree.Node */ node){
                // summary:
-               //              This is a base class for `dijit.tree.dndSource` , and isn't meant to be used directly.
-               //              It's based on `dojo.dnd.Selector`.
+               //              Focus on the specified node (which must be visible)
                // tags:
                //              protected
 
-               /*=====
-               // selection: Hash<String, DomNode>
-               //              (id, DomNode) map for every TreeNode that's currently selected.
-               //              The DOMNode is the TreeNode.rowNode.
-               selection: {},
-               =====*/
-
-               constructor: function(tree, params){
-                       // summary:
-                       //              Initialization
-                       // tags:
-                       //              private
-
-                       this.selection={};
-                       this.anchor = null;
-                       this.simpleSelection=false;
-
-                       this.events.push(
-                               dojo.connect(this.tree.domNode, "onmousedown", this,"onMouseDown"),
-                               dojo.connect(this.tree.domNode, "onmouseup", this,"onMouseUp"),
-                               dojo.connect(this.tree.domNode, "onmousemove", this,"onMouseMove")
-                       );
-               },
+               // set focus so that the label will be voiced using screen readers
+               dijit.focus(node.labelNode);
+       },
 
-               //      singular: Boolean
-               //              Allows selection of only one element, if true.
-               //              Tree hasn't been tested in singular=true mode, unclear if it works.
-               singular: false,
+       _onNodeFocus: function(/*dijit._Widget*/ node){
+               // summary:
+               //              Called when a TreeNode gets focus, either by user clicking
+               //              it, or programatically by arrow key handling code.
+               // description:
+               //              It marks that the current node is the selected one, and the previously
+               //              selected node no longer is.
 
-               // methods
+               if(node && node != this.lastFocused){
+                       if(this.lastFocused && !this.lastFocused._destroyed){
+                               // mark that the previously focsable node is no longer focusable
+                               this.lastFocused.setFocusable(false);
+                       }
 
-               getSelectedNodes: function(){
-                       // summary:
-                       //              Returns the set of selected nodes.
-                       //              Used by dndSource on the start of a drag.
-                       // tags:
-                       //              protected
-                       return this.selection;
-               },
+                       // mark that the new node is the currently selected one
+                       node.setFocusable(true);
+                       this.lastFocused = node;
+               }
+       },
 
-               selectNone: function(){
-                       // summary:
-                       //              Unselects all items
-                       // tags:
-                       //              private
+       _onNodeMouseEnter: function(/*dijit._Widget*/ node){
+               // summary:
+               //              Called when mouse is over a node (onmouseenter event),
+               //              this is monitored by the DND code
+       },
 
-                       return this._removeSelection()._removeAnchor(); // self
-               },
+       _onNodeMouseLeave: function(/*dijit._Widget*/ node){
+               // summary:
+               //              Called when mouse leaves a node (onmouseleave event),
+               //              this is monitored by the DND code
+       },
 
-               destroy: function(){
-                       // summary:
-                       //              Prepares the object to be garbage-collected
-                       this.inherited(arguments);
-                       this.selection = this.anchor = null;
-               },
+       //////////////// Events from the model //////////////////////////
 
-               // mouse events
-               onMouseDown: function(e){
-                       // summary:
-                       //              Event processor for onmousedown
-                       // e: Event
-                       //              mouse event
-                       // tags:
-                       //              protected
+       _onItemChange: function(/*Item*/ item){
+               // summary:
+               //              Processes notification of a change to an item's scalar values like label
+               var model = this.model,
+                       identity = model.getIdentity(item),
+                       nodes = this._itemNodesMap[identity];
 
-                       if(!this.current){ return; }
+               if(nodes){
+                       var label = this.getLabel(item),
+                               tooltip = this.getTooltip(item);
+                       dojo.forEach(nodes, function(node){
+                               node.set({
+                                       item: item,             // theoretically could be new JS Object representing same item
+                                       label: label,
+                                       tooltip: tooltip
+                               });
+                               node._updateItemClasses(item);
+                       });
+               }
+       },
 
-                       if(e.button == dojo.mouseButtons.RIGHT){ return; }      // ignore right-click
+       _onItemChildrenChange: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
+               // summary:
+               //              Processes notification of a change to an item's children
+               var model = this.model,
+                       identity = model.getIdentity(parent),
+                       parentNodes = this._itemNodesMap[identity];
 
-                       var treeNode = dijit.getEnclosingWidget(this.current),
-                               id = treeNode.id + "-dnd"       // so id doesn't conflict w/widget
+               if(parentNodes){
+                       dojo.forEach(parentNodes,function(parentNode){
+                               parentNode.setChildItems(newChildrenList);
+                       });
+               }
+       },
 
-                       if(!dojo.hasAttr(this.current, "id")){
-                               dojo.attr(this.current, "id", id);
-                       }
+       _onItemDelete: function(/*Item*/ item){
+               // summary:
+               //              Processes notification of a deletion of an item
+               var model = this.model,
+                       identity = model.getIdentity(item),
+                       nodes = this._itemNodesMap[identity];
 
-                       if(!this.singular && !dojo.isCopyKey(e) && !e.shiftKey && (this.current.id in this.selection)){
-                               this.simpleSelection = true;
-                               dojo.stopEvent(e);
-                               return;
-                       }
-                       if(this.singular){
-                               if(this.anchor == this.current){
-                                       if(dojo.isCopyKey(e)){
-                                               this.selectNone();
-                                       }
-                               }else{
-                                       this.selectNone();
-                                       this.anchor = this.current;
-                                       this._addItemClass(this.anchor, "Anchor");
+               if(nodes){
+                       dojo.forEach(nodes,function(node){
+                               // Remove node from set of selected nodes (if it's selected)
+                               this.dndController.removeTreeNode(node);
 
-                                       this.selection[this.current.id] = this.current;
-                               }
-                       }else{
-                               if(!this.singular && e.shiftKey){
-                                       if(dojo.isCopyKey(e)){
-                                               //TODO add range to selection
-                                       }else{
-                                               //TODO select new range from anchor
-                                       }
-                               }else{
-                                       if(dojo.isCopyKey(e)){
-                                               if(this.anchor == this.current){
-                                                       delete this.selection[this.anchor.id];
-                                                       this._removeAnchor();
-                                               }else{
-                                                       if(this.current.id in this.selection){
-                                                               this._removeItemClass(this.current, "Selected");
-                                                               delete this.selection[this.current.id];
-                                                       }else{
-                                                               if(this.anchor){
-                                                                       this._removeItemClass(this.anchor, "Anchor");
-                                                                       this._addItemClass(this.anchor, "Selected");
-                                                               }
-                                                               this.anchor = this.current;
-                                                               this._addItemClass(this.current, "Anchor");
-                                                               this.selection[this.current.id] = this.current;
-                                                       }
-                                               }
-                                       }else{
-                                               if(!(id in this.selection)){
-                                                       this.selectNone();
-                                                       this.anchor = this.current;
-                                                       this._addItemClass(this.current, "Anchor");
-                                                       this.selection[id] = this.current;
-                                               }
-                                       }
+                               var parent = node.getParent();
+                               if(parent){
+                                       // if node has not already been orphaned from a _onSetItem(parent, "children", ..) call...
+                                       parent.removeChild(node);
                                }
-                       }
+                               node.destroyRecursive();
+                       }, this);
+                       delete this._itemNodesMap[identity];
+               }
+       },
 
-                       dojo.stopEvent(e);
-               },
+       /////////////// Miscellaneous funcs
 
-               onMouseUp: function(e){
-                       // summary:
-                       //              Event processor for onmouseup
-                       // e: Event
-                       //              mouse event
-                       // tags:
-                       //              protected
+       _initState: function(){
+               // summary:
+               //              Load in which nodes should be opened automatically
+               if(this.persist){
+                       var cookie = dojo.cookie(this.cookieName);
+                       this._openedItemIds = {};
+                       if(cookie){
+                               dojo.forEach(cookie.split(','), function(item){
+                                       this._openedItemIds[item] = true;
+                               }, this);
+                       }
+               }
+       },
+       _state: function(item,expanded){
+               // summary:
+               //              Query or set expanded state for an item,
+               if(!this.persist){
+                       return false;
+               }
+               var id=this.model.getIdentity(item);
+               if(arguments.length === 1){
+                       return this._openedItemIds[id];
+               }
+               if(expanded){
+                       this._openedItemIds[id] = true;
+               }else{
+                       delete this._openedItemIds[id];
+               }
+       },
+       _saveState: function(){
+               // summary:
+               //              Create and save a cookie with the currently expanded nodes identifiers
+               if(!this.persist){
+                       return;
+               }
+               var ary = [];
+               for(var id in this._openedItemIds){
+                       ary.push(id);
+               }
+               dojo.cookie(this.cookieName, ary.join(","), {expires:365});
+       },
 
-                       // TODO: this code is apparently for handling an edge case when the user is selecting
-                       // multiple nodes and then mousedowns on a node by accident... it lets the user keep the
-                       // current selection by moving the mouse away (or something like that).   It doesn't seem
-                       // to work though and requires a lot of plumbing (including this code, the onmousemove
-                       // handler, and the this.simpleSelection attribute.   Consider getting rid of all of it.
+       destroy: function(){
+               if(this._curSearch){
+                       clearTimeout(this._curSearch.timer);
+                       delete this._curSearch;
+               }
+               if(this.rootNode){
+                       this.rootNode.destroyRecursive();
+               }
+               if(this.dndController && !dojo.isString(this.dndController)){
+                       this.dndController.destroy();
+               }
+               this.rootNode = null;
+               this.inherited(arguments);
+       },
 
-                       if(!this.simpleSelection){ return; }
-                       this.simpleSelection = false;
-                       this.selectNone();
-                       if(this.current){
-                               this.anchor = this.current;
-                               this._addItemClass(this.anchor, "Anchor");
-                               this.selection[this.current.id] = this.current;
-                       }
-               },
-               onMouseMove: function(e){
-                       // summary
-                       //              event processor for onmousemove
-                       // e: Event
-                       //              mouse event
-                       this.simpleSelection = false;
-               },
+       destroyRecursive: function(){
+               // A tree is treated as a leaf, not as a node with children (like a grid),
+               // but defining destroyRecursive for back-compat.
+               this.destroy();
+       },
 
-               _removeSelection: function(){
-                       // summary:
-                       //              Unselects all items
-                       // tags:
-                       //              private
-                       var e = dojo.dnd._empty;
-                       for(var i in this.selection){
-                               if(i in e){ continue; }
-                               var node = dojo.byId(i);
-                               if(node){ this._removeItemClass(node, "Selected"); }
-                       }
-                       this.selection = {};
-                       return this;    // self
-               },
+       resize: function(changeSize){
+               if(changeSize){
+                       dojo.marginBox(this.domNode, changeSize);
+               }
 
-               _removeAnchor: function(){
-                       // summary:
-                       //              Removes the Anchor CSS class from a node.
-                       //              According to `dojo.dnd.Selector`, anchor means that
-                       //              "an item is selected, and is an anchor for a 'shift' selection".
-                       //              It's not relevant for Tree at this point, since we don't support multiple selection.
-                       // tags:
-                       //              private
-                       if(this.anchor){
-                               this._removeItemClass(this.anchor, "Anchor");
-                               this.anchor = null;
-                       }
-                       return this;    // self
-               },
+               // The only JS sizing involved w/tree is the indentation, which is specified
+               // in CSS and read in through this dummy indentDetector node (tree must be
+               // visible and attached to the DOM to read this)
+               this._nodePixelIndent = dojo._getMarginSize(this.tree.indentDetector).w;
 
-               forInSelectedItems: function(/*Function*/ f, /*Object?*/ o){
-                       // summary:
-                       //              Iterates over selected items;
-                       //              see `dojo.dnd.Container.forInItems()` for details
-                       o = o || dojo.global;
-                       for(var id in this.selection){
-                               console.log("selected item id: " + id);
-                               f.call(o, this.getItem(id), id, this);
-                       }
+               if(this.tree.rootNode){
+                       // If tree has already loaded, then reset indent for all the nodes
+                       this.tree.rootNode.set('indent', this.showRoot ? 0 : -1);
                }
+       },
+
+       _createTreeNode: function(/*Object*/ args){
+               // summary:
+               //              creates a TreeNode
+               // description:
+               //              Developers can override this method to define their own TreeNode class;
+               //              However it will probably be removed in a future release in favor of a way
+               //              of just specifying a widget for the label, rather than one that contains
+               //              the children too.
+               return new dijit._TreeNode(args);
+       }
 });
 
+// For back-compat.  TODO: remove in 2.0
+
 }
 
 if(!dojo._hasResource["dojo.dnd.Avatar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
@@ -24319,7 +25280,7 @@ dojo.declare("dojo.dnd.Avatar", null, {
                        var icon = dojo.byId("a11yIcon");
                        var text = '+';   // assume canDrop && copy
                        if (this.manager.canDropFlag && !this.manager.copy) {
-                               text = '< '; // canDrop && move 
+                               text = '< '; // canDrop && move
                        }else if (!this.manager.canDropFlag && !this.manager.copy) {
                                text = "o"; //!canDrop && move
                        }else if(!this.manager.canDropFlag){
@@ -24420,7 +25381,7 @@ dojo.declare("dojo.dnd.Manager", null, {
                        dojo.connect(dojo.body(), "onselectstart", dojo.stopEvent)
                ];
                var c = "dojoDnd" + (copy ? "Copy" : "Move");
-               dojo.addClass(dojo.body(), c); 
+               dojo.addClass(dojo.body(), c);
        },
        canDrop: function(flag){
                // summary:
@@ -24434,8 +25395,7 @@ dojo.declare("dojo.dnd.Manager", null, {
        stopDrag: function(){
                // summary:
                //              stop the DnD in progress
-               dojo.removeClass(dojo.body(), "dojoDndCopy");
-               dojo.removeClass(dojo.body(), "dojoDndMove");
+               dojo.removeClass(dojo.body(), ["dojoDndCopy", "dojoDndMove"]);
                dojo.forEach(this.events, dojo.disconnect);
                this.events = [];
                this.avatar.destroy();
@@ -24468,7 +25428,7 @@ dojo.declare("dojo.dnd.Manager", null, {
                        s.left = (e.pageX + this.OFFSET_X) + "px";
                        s.top  = (e.pageY + this.OFFSET_Y) + "px";
                        var copy = Boolean(this.source.copyState(dojo.isCopyKey(e)));
-                       if(this.copy != copy){ 
+                       if(this.copy != copy){
                                this._setCopyStatus(copy);
                        }
                }
@@ -24502,7 +25462,7 @@ dojo.declare("dojo.dnd.Manager", null, {
                        switch(e.keyCode){
                                case dojo.keys.CTRL:
                                        var copy = Boolean(this.source.copyState(true));
-                                       if(this.copy != copy){ 
+                                       if(this.copy != copy){
                                                this._setCopyStatus(copy);
                                        }
                                        break;
@@ -24520,7 +25480,7 @@ dojo.declare("dojo.dnd.Manager", null, {
                //              keyboard event
                if(this.avatar && e.keyCode == dojo.keys.CTRL){
                        var copy = Boolean(this.source.copyState(false));
-                       if(this.copy != copy){ 
+                       if(this.copy != copy){
                                this._setCopyStatus(copy);
                        }
                }
@@ -24535,8 +25495,9 @@ dojo.declare("dojo.dnd.Manager", null, {
                this.copy = copy;
                this.source._markDndStatus(this.copy);
                this.updateAvatar();
-               dojo.removeClass(dojo.body(), "dojoDnd" + (this.copy ? "Move" : "Copy"));
-               dojo.addClass(dojo.body(), "dojoDnd" + (this.copy ? "Copy" : "Move"));
+               dojo.replaceClass(dojo.body(),
+                       "dojoDnd" + (this.copy ? "Copy" : "Move"),
+                       "dojoDnd" + (this.copy ? "Move" : "Copy"));
        }
 });
 
@@ -24694,9 +25655,8 @@ dojo.declare("dijit.tree.dndSource", dijit.tree._dndSelector, {
                //              Keeps track of current drop target.
 
                var m = dojo.dnd.manager(),
-                       oldTarget = this.targetAnchor,                  // the DOMNode corresponding to TreeNode mouse was previously over
-                       newTarget = this.current,                               // DOMNode corresponding to TreeNode mouse is currently over
-                       newTargetWidget = this.currentWidget,   // the TreeNode itself
+                       oldTarget = this.targetAnchor,                  // the TreeNode corresponding to TreeNode mouse was previously over
+                       newTarget = this.current,                               // TreeNode corresponding to TreeNode mouse is currently over
                        oldDropPosition = this.dropPosition;    // the previous drop position (over/before/after)
 
                // calculate if user is indicating to drop the dragged node before, after, or over
@@ -24705,7 +25665,7 @@ dojo.declare("dijit.tree.dndSource", dijit.tree._dndSelector, {
                if(newTarget && this.betweenThreshold > 0){
                        // If mouse is over a new TreeNode, then get new TreeNode's position and size
                        if(!this.targetBox || oldTarget != newTarget){
-                               this.targetBox = dojo.position(newTarget, true);
+                               this.targetBox = dojo.position(newTarget.rowNode, true);
                        }
                        if((e.pageY - this.targetBox.y) <= this.betweenThreshold){
                                newDropPosition = "Before";
@@ -24716,23 +25676,23 @@ dojo.declare("dijit.tree.dndSource", dijit.tree._dndSelector, {
 
                if(newTarget != oldTarget || newDropPosition != oldDropPosition){
                        if(oldTarget){
-                               this._removeItemClass(oldTarget, oldDropPosition);
+                               this._removeItemClass(oldTarget.rowNode, oldDropPosition);
                        }
                        if(newTarget){
-                               this._addItemClass(newTarget, newDropPosition);
+                               this._addItemClass(newTarget.rowNode, newDropPosition);
                        }
 
                        // Check if it's ok to drop the dragged node on/before/after the target node.
                        if(!newTarget){
                                m.canDrop(false);
-                       }else if(newTargetWidget == this.tree.rootNode && newDropPosition != "Over"){
+                       }else if(newTarget == this.tree.rootNode && newDropPosition != "Over"){
                                // Can't drop before or after tree's root node; the dropped node would just disappear (at least visually)
                                m.canDrop(false);
                        }else if(m.source == this && (newTarget.id in this.selection)){
                                // Guard against dropping onto yourself (TODO: guard against dropping onto your descendant, #7140)
                                m.canDrop(false);
-                       }else if(this.checkItemAcceptance(newTarget, m.source, newDropPosition.toLowerCase())
-                                       && !this._isParentChildDrop(m.source, newTarget)){
+                       }else if(this.checkItemAcceptance(newTarget.rowNode, m.source, newDropPosition.toLowerCase())
+                                       && !this._isParentChildDrop(m.source, newTarget.rowNode)){
                                m.canDrop(true);
                        }else{
                                m.canDrop(false);
@@ -24758,12 +25718,23 @@ dojo.declare("dijit.tree.dndSource", dijit.tree._dndSelector, {
                }else{
                        if(this.mouseDown && this.isSource &&
                                 (Math.abs(e.pageX-this._lastX)>=this.dragThreshold || Math.abs(e.pageY-this._lastY)>=this.dragThreshold)){
-                               var n = this.getSelectedNodes();
-                               var nodes=[];
-                               for(var i in n){
-                                       nodes.push(n[i]);
-                               }
+                               var nodes = this.getSelectedTreeNodes();
                                if(nodes.length){
+                                       if(nodes.length > 1){
+                                               //filter out all selected items which has one of their ancestor selected as well
+                                               var seen = this.selection, i = 0, r = [], n, p;
+                                               nextitem: while((n = nodes[i++])){
+                                                       for(p = n.getParent(); p && p !== this.tree; p = p.getParent()){
+                                                               if(seen[p.id]){ //parent is already selected, skip this node
+                                                                       continue nextitem;
+                                                               }
+                                                       }
+                                                       //this node does not have any ancestors selected, add it
+                                                       r.push(n);
+                                               }
+                                               nodes = r;
+                                       }
+                                       nodes = dojo.map(nodes, function(n){return n.domNode});
                                        m.startDrag(this, nodes, this.copyState(dojo.isCopyKey(e)));
                                }
                        }
@@ -24781,7 +25752,7 @@ dojo.declare("dijit.tree.dndSource", dijit.tree._dndSelector, {
                this.mouseButton = e.button;
                this._lastX = e.pageX;
                this._lastY = e.pageY;
-               this.inherited("onMouseDown",arguments);
+               this.inherited(arguments);
        },
 
        onMouseUp: function(e){
@@ -24793,7 +25764,7 @@ dojo.declare("dijit.tree.dndSource", dijit.tree._dndSelector, {
                //              private
                if(this.mouseDown){
                        this.mouseDown = false;
-                       this.inherited("onMouseUp",arguments);
+                       this.inherited(arguments);
                }
        },
 
@@ -24919,7 +25890,7 @@ dojo.declare("dijit.tree.dndSource", dijit.tree._dndSelector, {
                        this.isDragging = false;
 
                        // Compute the new parent item
-                       var targetWidget = dijit.getEnclosingWidget(target);
+                       var targetWidget = target;
                        var newParentItem;
                        var insertIndex;
                        newParentItem = (targetWidget && targetWidget.item) || tree.item;
@@ -24975,7 +25946,7 @@ dojo.declare("dijit.tree.dndSource", dijit.tree._dndSelector, {
                                        // Get the hash to pass to model.newItem().  A single call to
                                        // itemCreator() returns an array of hashes, one for each drag source node.
                                        if(!newItemsParams){
-                                               newItemsParams = this.itemCreator(nodes, target, source);
+                                               newItemsParams = this.itemCreator(nodes, target.rowNode, source);
                                        }
 
                                        // Create new item in the tree, based on the drag source.
@@ -25049,16 +26020,13 @@ dojo.declare("dijit.tree.dndSource", dijit.tree._dndSelector, {
 
 
                var root = source.tree.domNode;
-               var ids = {};
-               for(var x in source.selection){
-                       ids[source.selection[x].parentNode.id] = true;
-               }
+               var ids = source.selection;
 
                var node = targetRow.parentNode;
 
                // Iterate up the DOM hierarchy from the target drop row,
                // checking of any of the dragged nodes have the same ID.
-               while(node != root && (!node.id || !ids[node.id])){
+               while(node != root && !ids[node.id]){
                        node = node.parentNode;
                }
 
@@ -25071,7 +26039,7 @@ dojo.declare("dijit.tree.dndSource", dijit.tree._dndSelector, {
                // tags:
                //              private
                if(!this.targetAnchor){ return; }
-               this._removeItemClass(this.targetAnchor, this.dropPosition);
+               this._removeItemClass(this.targetAnchor.rowNode, this.dropPosition);
                this.targetAnchor = null;
                this.targetBox = null;
                this.dropPosition = null;
@@ -25103,7 +26071,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
        //                      { name:'Fozzie Bear', wears:['hat', 'tie']},
        //                      { name:'Miss Piggy', pets:'Foo-Foo'}
        //              ]}
-       //              Note that it can also contain an 'identifer' property that specified which attribute on the items 
+       //              Note that it can also contain an 'identifer' property that specified which attribute on the items
        //              in the array of items that acts as the unique identifier for that item.
        //
        constructor: function(/* Object */ keywordParameters){
@@ -25118,7 +26086,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                //                      ...
                //                      typeN: function || object
                //              }
-               //              Where if it is a function, it is assumed to be an object constructor that takes the 
+               //              Where if it is a function, it is assumed to be an object constructor that takes the
                //              value of _value as the initialization parameters.  If it is an object, then it is assumed
                //              to be an object of general form:
                //              {
@@ -25184,7 +26152,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
        //all item handles will become invalid and a new fetch must be issued.
        clearOnClose: false,
 
-       //Parameter to allow specifying if preventCache should be passed to the xhrGet call or not when loading data from a url.  
+       //Parameter to allow specifying if preventCache should be passed to the xhrGet call or not when loading data from a url.
        //Note this does not mean the store calls the server on each fetch, only that the data load has preventCache set as an option.
        //Added for tracker: #6072
        urlPreventCache: false,
@@ -25192,19 +26160,19 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
        //Parameter for specifying that it is OK for the xhrGet call to fail silently.
        failOk: false,
 
-       //Parameter to indicate to process data from the url as hierarchical 
-       //(data items can contain other data items in js form).  Default is true 
-       //for backwards compatibility.  False means only root items are processed 
-       //as items, all child objects outside of type-mapped objects and those in 
+       //Parameter to indicate to process data from the url as hierarchical
+       //(data items can contain other data items in js form).  Default is true
+       //for backwards compatibility.  False means only root items are processed
+       //as items, all child objects outside of type-mapped objects and those in
        //specific reference format, are left straight JS data objects.
        hierarchical: true,
 
        _assertIsItem: function(/* item */ item){
                //      summary:
                //              This function tests whether the item passed in is indeed an item in the store.
-               //      item: 
+               //      item:
                //              The item to test for being contained by the store.
-               if(!this.isItem(item)){ 
+               if(!this.isItem(item)){
                        throw new Error("dojo.data.ItemFileReadStore: Invalid item argument.");
                }
        },
@@ -25212,25 +26180,25 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
        _assertIsAttribute: function(/* attribute-name-string */ attribute){
                //      summary:
                //              This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
-               //      attribute: 
+               //      attribute:
                //              The attribute to test for being contained by the store.
-               if(typeof attribute !== "string"){ 
+               if(typeof attribute !== "string"){
                        throw new Error("dojo.data.ItemFileReadStore: Invalid attribute argument.");
                }
        },
 
-       getValue: function(     /* item */ item, 
-                                               /* attribute-name-string */ attribute, 
+       getValue: function(     /* item */ item,
+                                               /* attribute-name-string */ attribute,
                                                /* value? */ defaultValue){
-               //      summary: 
+               //      summary:
                //              See dojo.data.api.Read.getValue()
                var values = this.getValues(item, attribute);
                return (values.length > 0)?values[0]:defaultValue; // mixed
        },
 
-       getValues: function(/* item */ item, 
+       getValues: function(/* item */ item,
                                                /* attribute-name-string */ attribute){
-               //      summary: 
+               //      summary:
                //              See dojo.data.api.Read.getValues()
 
                this._assertIsItem(item);
@@ -25240,7 +26208,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
        },
 
        getAttributes: function(/* item */ item){
-               //      summary: 
+               //      summary:
                //              See dojo.data.api.Read.getAttributes()
                this._assertIsItem(item);
                var attributes = [];
@@ -25255,17 +26223,17 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
 
        hasAttribute: function( /* item */ item,
                                                        /* attribute-name-string */ attribute){
-               //      summary: 
+               //      summary:
                //              See dojo.data.api.Read.hasAttribute()
                this._assertIsItem(item);
                this._assertIsAttribute(attribute);
                return (attribute in item);
        },
 
-       containsValue: function(/* item */ item, 
-                                                       /* attribute-name-string */ attribute, 
+       containsValue: function(/* item */ item,
+                                                       /* attribute-name-string */ attribute,
                                                        /* anything */ value){
-               //      summary: 
+               //      summary:
                //              See dojo.data.api.Read.containsValue()
                var regexp = undefined;
                if(typeof value === "string"){
@@ -25274,22 +26242,22 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                return this._containsValue(item, attribute, value, regexp); //boolean.
        },
 
-       _containsValue: function(       /* item */ item, 
-                                                               /* attribute-name-string */ attribute, 
+       _containsValue: function(       /* item */ item,
+                                                               /* attribute-name-string */ attribute,
                                                                /* anything */ value,
                                                                /* RegExp?*/ regexp){
-               //      summary: 
+               //      summary:
                //              Internal function for looking at the values contained by the item.
-               //      description: 
-               //              Internal function for looking at the values contained by the item.  This 
+               //      description:
+               //              Internal function for looking at the values contained by the item.  This
                //              function allows for denoting if the comparison should be case sensitive for
                //              strings or not (for handling filtering cases where string case should not matter)
-               //      
+               //
                //      item:
                //              The data item to examine for attribute values.
                //      attribute:
                //              The attribute to inspect.
-               //      value:  
+               //      value:
                //              The value to match.
                //      regexp:
                //              Optional regular expression generated off value if value was of string type to handle wildcarding.
@@ -25306,7 +26274,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
        },
 
        isItem: function(/* anything */ something){
-               //      summary: 
+               //      summary:
                //              See dojo.data.api.Read.isItem()
                if(something && something[this._storeRefPropName] === this){
                        if(this._arrayOfAllItems[something[this._itemNumPropName]] === something){
@@ -25317,25 +26285,25 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
        },
 
        isItemLoaded: function(/* anything */ something){
-               //      summary: 
+               //      summary:
                //              See dojo.data.api.Read.isItemLoaded()
                return this.isItem(something); //boolean
        },
 
        loadItem: function(/* object */ keywordArgs){
-               //      summary: 
+               //      summary:
                //              See dojo.data.api.Read.loadItem()
                this._assertIsItem(keywordArgs.item);
        },
 
        getFeatures: function(){
-               //      summary: 
+               //      summary:
                //              See dojo.data.api.Read.getFeatures()
                return this._features; //Object
        },
 
        getLabel: function(/* item */ item){
-               //      summary: 
+               //      summary:
                //              See dojo.data.api.Read.getLabel()
                if(this._labelAttr && this.isItem(item)){
                        return this.getValue(item,this._labelAttr); //String
@@ -25344,7 +26312,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
        },
 
        getLabelAttributes: function(/* item */ item){
-               //      summary: 
+               //      summary:
                //              See dojo.data.api.Read.getLabelAttributes()
                if(this._labelAttr){
                        return [this._labelAttr]; //array
@@ -25352,10 +26320,10 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                return null; //null
        },
 
-       _fetchItems: function(  /* Object */ keywordArgs, 
-                                                       /* Function */ findCallback, 
+       _fetchItems: function(  /* Object */ keywordArgs,
+                                                       /* Function */ findCallback,
                                                        /* Function */ errorCallback){
-               //      summary: 
+               //      summary:
                //              See dojo.data.util.simpleFetch.fetch()
                var self = this,
                    filter = function(requestArgs, arrayOfItems){
@@ -25395,8 +26363,8 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                                }
                                findCallback(items, requestArgs);
                        }else{
-                               // We want a copy to pass back in case the parent wishes to sort the array. 
-                               // We shouldn't allow resort of the internal list, so that multiple callers 
+                               // We want a copy to pass back in case the parent wishes to sort the array.
+                               // We shouldn't allow resort of the internal list, so that multiple callers
                                // can get lists and sort without affecting each other.  We also need to
                                // filter out any null values that have been left as a result of deleteItem()
                                // calls in ItemFileWriteStore.
@@ -25416,11 +26384,11 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                        //Do a check on the JsonFileUrl and crosscheck it.
                        //If it doesn't match the cross-check, it needs to be updated
                        //This allows for either url or _jsonFileUrl to he changed to
-                       //reset the store load location.  Done this way for backwards 
+                       //reset the store load location.  Done this way for backwards
                        //compatibility.  People use _jsonFileUrl (even though officially
                        //private.
                        if(this._jsonFileUrl !== this._ccUrl){
-                               dojo.deprecated("dojo.data.ItemFileReadStore: ", 
+                               dojo.deprecated("dojo.data.ItemFileReadStore: ",
                                        "To change the url, set the url property of the store," +
                                        " not _jsonFileUrl.  _jsonFileUrl support will be removed in 2.0");
                                this._ccUrl = this._jsonFileUrl;
@@ -25431,21 +26399,21 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                        }
 
                        //See if there was any forced reset of data.
-                       if(this.data != null && this._jsonData == null){
+                       if(this.data != null){
                                this._jsonData = this.data;
                                this.data = null;
                        }
 
                        if(this._jsonFileUrl){
                                //If fetches come in before the loading has finished, but while
-                               //a load is in progress, we have to defer the fetching to be 
+                               //a load is in progress, we have to defer the fetching to be
                                //invoked in the callback.
                                if(this._loadInProgress){
                                        this._queuedFetches.push({args: keywordArgs, filter: filter});
                                }else{
                                        this._loadInProgress = true;
                                        var getArgs = {
-                                                       url: self._jsonFileUrl, 
+                                                       url: self._jsonFileUrl,
                                                        handleAs: "json-comment-optional",
                                                        preventCache: this.urlPreventCache,
                                                        failOk: this.failOk
@@ -25505,7 +26473,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
        },
 
        _handleQueuedFetches: function(){
-               //      summary: 
+               //      summary:
                //              Internal function to execute delayed request in the store.
                //Execute any deferred fetches now.
                if(this._queuedFetches.length > 0){
@@ -25514,7 +26482,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                                    delayedQuery = fData.args,
                                    delayedFilter = fData.filter;
                                if(delayedFilter){
-                                       delayedFilter(delayedQuery, this._getItemsArray(delayedQuery.queryOptions)); 
+                                       delayedFilter(delayedQuery, this._getItemsArray(delayedQuery.queryOptions));
                                }else{
                                        this.fetchItemByIdentity(delayedQuery);
                                }
@@ -25524,31 +26492,31 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
        },
 
        _getItemsArray: function(/*object?*/queryOptions){
-               //      summary: 
+               //      summary:
                //              Internal function to determine which list of items to search over.
                //      queryOptions: The query options parameter, if any.
                if(queryOptions && queryOptions.deep){
-                       return this._arrayOfAllItems; 
+                       return this._arrayOfAllItems;
                }
                return this._arrayOfTopLevelItems;
        },
 
        close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
-                //     summary: 
+                //     summary:
                 //             See dojo.data.api.Read.close()
-                if(this.clearOnClose && 
-                       this._loadFinished && 
+                if(this.clearOnClose &&
+                       this._loadFinished &&
                        !this._loadInProgress){
                         //Reset all internalsback to default state.  This will force a reload
-                        //on next fetch.  This also checks that the data or url param was set 
+                        //on next fetch.  This also checks that the data or url param was set
                         //so that the store knows it can get data.  Without one of those being set,
                         //the next fetch will trigger an error.
 
-                        if(((this._jsonFileUrl == "" || this._jsonFileUrl == null) && 
+                        if(((this._jsonFileUrl == "" || this._jsonFileUrl == null) &&
                                 (this.url == "" || this.url == null)
                                ) && this.data == null){
                                 console.debug("dojo.data.ItemFileReadStore: WARNING!  Data reload " +
-                                       " information has not been provided." + 
+                                       " information has not been provided." +
                                        "  Please set 'url' or 'data' to the appropriate value before" +
                                        " the next fetch");
                         }
@@ -25586,7 +26554,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                        //      |       false == valueIsAnItem("Kermit");
                        //      |       false == valueIsAnItem(42);
                        //      |       false == valueIsAnItem(new Date());
-                       //      |       false == valueIsAnItem({_type:'Date', _value:'May 14, 1802'});
+                       //      |       false == valueIsAnItem({_type:'Date', _value:'1802-05-14'});
                        //      |       false == valueIsAnItem({_reference:'Kermit'});
                        //      |       true == valueIsAnItem({name:'Kermit', color:'green'});
                        //      |       true == valueIsAnItem({iggy:'pop'});
@@ -25597,8 +26565,8 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                                (!dojo.isArray(aValue) || addingArrays) &&
                                (!dojo.isFunction(aValue)) &&
                                (aValue.constructor == Object || dojo.isArray(aValue)) &&
-                               (typeof aValue._reference === "undefined") && 
-                               (typeof aValue._type === "undefined") && 
+                               (typeof aValue._reference === "undefined") &&
+                               (typeof aValue._type === "undefined") &&
                                (typeof aValue._value === "undefined") &&
                                self.hierarchical
                        );
@@ -25648,13 +26616,13 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                        item[this._rootItemPropName]=true;
                }
 
-               // Step 2: Walk through all the attribute values of all the items, 
+               // Step 2: Walk through all the attribute values of all the items,
                // and replace single values with arrays.  For example, we change this:
                //              { name:'Miss Piggy', pets:'Foo-Foo'}
                // into this:
                //              { name:['Miss Piggy'], pets:['Foo-Foo']}
-               // 
-               // We also store the attribute names so we can validate our store  
+               //
+               // We also store the attribute names so we can validate our store
                // reference and item id special properties for the O(1) isItem
                var allAttributeNames = {},
                    key;
@@ -25688,9 +26656,9 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                        this._reverseRefMap += "_";
                }
 
-               // Step 4: Some data files specify an optional 'identifier', which is 
-               // the name of an attribute that holds the identity of each item. 
-               // If this data file specified an identifier attribute, then build a 
+               // Step 4: Some data files specify an optional 'identifier', which is
+               // the name of an attribute that holds the identity of each item.
+               // If this data file specified an identifier attribute, then build a
                // hash table of items keyed by the identity of the items.
                var arrayOfValues;
 
@@ -25702,7 +26670,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                                item = this._arrayOfAllItems[i];
                                arrayOfValues = item[identifier];
                                var identity = arrayOfValues[0];
-                               if(!this._itemsByIdentity[identity]){
+                               if(!Object.hasOwnProperty.call(this._itemsByIdentity, identity)){
                                        this._itemsByIdentity[identity] = item;
                                }else{
                                        if(this._jsonFileUrl){
@@ -25716,7 +26684,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                        this._features['dojo.data.api.Identity'] = Number;
                }
 
-               // Step 5: Walk through all the items, and set each item's properties 
+               // Step 5: Walk through all the items, and set each item's properties
                // for _storeRefPropName and _itemNumPropName, so that store.isItem() will return true.
                for(i = 0; i < this._arrayOfAllItems.length; ++i){
                        item = this._arrayOfAllItems[i];
@@ -25730,13 +26698,13 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                // We replace item-references with pointers to items.  For example, we change:
                //              { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
                // into this:
-               //              { name:['Kermit'], friends:[miss_piggy] } 
+               //              { name:['Kermit'], friends:[miss_piggy] }
                // (where miss_piggy is the object representing the 'Miss Piggy' item).
                //
                // We replace type/value pairs with typed-literals.  For example, we change:
-               //              { name:['Nelson Mandela'], born:[{_type:'Date', _value:'July 18, 1918'}] }
+               //              { name:['Nelson Mandela'], born:[{_type:'Date', _value:'1918-07-18'}] }
                // into this:
-               //              { name:['Kermit'], born:(new Date('July 18, 1918')) } 
+               //              { name:['Kermit'], born:(new Date(1918, 6, 18)) }
                //
                // We also generate the associate map for all items for the O(1) isItem function.
                for(i = 0; i < this._arrayOfAllItems.length; ++i){
@@ -25749,7 +26717,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                                                if(("_type" in value) && ("_value" in value)){
                                                        var type = value._type; // examples: 'Date', 'Color', or 'ComplexNumber'
                                                        var mappingObj = this._datatypeMap[type]; // examples: Date, dojo.Color, foo.math.ComplexNumber, {type: dojo.Color, deserialize(value){ return new dojo.Color(value)}}
-                                                       if(!mappingObj){ 
+                                                       if(!mappingObj){
                                                                throw new Error("dojo.data.ItemFileReadStore: in the typeMap constructor arg, no object class was specified for the datatype '" + type + "'");
                                                        }else if(dojo.isFunction(mappingObj)){
                                                                arrayOfValues[j] = new mappingObj(value._value);
@@ -25772,12 +26740,12 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                                                                        var candidateItem = this._arrayOfAllItems[k],
                                                                            found = true;
                                                                        for(var refKey in referenceDescription){
-                                                                               if(candidateItem[refKey] != referenceDescription[refKey]){ 
-                                                                                       found = false; 
+                                                                               if(candidateItem[refKey] != referenceDescription[refKey]){
+                                                                                       found = false;
                                                                                }
                                                                        }
-                                                                       if(found){ 
-                                                                               arrayOfValues[j] = candidateItem; 
+                                                                       if(found){
+                                                                               arrayOfValues[j] = candidateItem;
                                                                        }
                                                                }
                                                        }
@@ -25788,7 +26756,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                                                                }
                                                        }
                                                }else if(this.isItem(value)){
-                                                       //It's a child item (not one referenced through _reference).  
+                                                       //It's a child item (not one referenced through _reference).
                                                        //We need to treat this as a referenced item, so it can be cleaned up
                                                        //in a write store easily.
                                                        if(this.referenceIntegrity){
@@ -25817,7 +26785,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
        },
 
        getIdentity: function(/* item */ item){
-               //      summary: 
+               //      summary:
                //              See dojo.data.api.Identity.getIdentity()
                var identifier = this._features['dojo.data.api.Identity'];
                if(identifier === Number){
@@ -25832,7 +26800,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
        },
 
        fetchItemByIdentity: function(/* Object */ keywordArgs){
-               //      summary: 
+               //      summary:
                //              See dojo.data.api.Identity.fetchItemByIdentity()
 
                // Hasn't loaded yet, we have to trigger the load.
@@ -25843,11 +26811,11 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                        //Do a check on the JsonFileUrl and crosscheck it.
                        //If it doesn't match the cross-check, it needs to be updated
                        //This allows for either url or _jsonFileUrl to he changed to
-                       //reset the store load location.  Done this way for backwards 
+                       //reset the store load location.  Done this way for backwards
                        //compatibility.  People use _jsonFileUrl (even though officially
                        //private.
                        if(this._jsonFileUrl !== this._ccUrl){
-                               dojo.deprecated("dojo.data.ItemFileReadStore: ", 
+                               dojo.deprecated("dojo.data.ItemFileReadStore: ",
                                        "To change the url, set the url property of the store," +
                                        " not _jsonFileUrl.  _jsonFileUrl support will be removed in 2.0");
                                this._ccUrl = this._jsonFileUrl;
@@ -25870,7 +26838,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                                }else{
                                        this._loadInProgress = true;
                                        var getArgs = {
-                                                       url: self._jsonFileUrl, 
+                                                       url: self._jsonFileUrl,
                                                        handleAs: "json-comment-optional",
                                                        preventCache: this.urlPreventCache,
                                                        failOk: this.failOk
@@ -25913,7 +26881,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                                        scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
                                        keywordArgs.onItem.call(scope, item);
                                }
-                       } 
+                       }
                }else{
                        // Already loaded.  We can just look it up and call back.
                        item = this._getItemByIdentity(keywordArgs.identity);
@@ -25928,9 +26896,10 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                //      summary:
                //              Internal function to look an item up by its identity map.
                var item = null;
-               if(this._itemsByIdentity){
+               if(this._itemsByIdentity &&
+                  Object.hasOwnProperty.call(this._itemsByIdentity, identity)){
                        item = this._itemsByIdentity[identity];
-               }else{
+               }else if (Object.hasOwnProperty.call(this._arrayOfAllItems, identity)){
                        item = this._arrayOfAllItems[identity];
                }
                if(item === undefined){
@@ -25940,15 +26909,15 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
        },
 
        getIdentityAttributes: function(/* item */ item){
-               //      summary: 
-               //              See dojo.data.api.Identity.getIdentifierAttributes()
+               //      summary:
+               //              See dojo.data.api.Identity.getIdentityAttributes()
                 
                var identifier = this._features['dojo.data.api.Identity'];
                if(identifier === Number){
                        // If (identifier === Number) it means getIdentity() just returns
                        // an integer item-number for each item.  The dojo.data.api.Identity
-                       // spec says we need to return null if the identity is not composed 
-                       // of attributes 
+                       // spec says we need to return null if the identity is not composed
+                       // of attributes
                        return null; // null
                }else{
                        return [identifier]; // Array
@@ -25956,18 +26925,18 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
        },
        
        _forceLoad: function(){
-               //      summary: 
+               //      summary:
                //              Internal function to force a load of the store if it hasn't occurred yet.  This is required
-               //              for specific functions to work properly.  
+               //              for specific functions to work properly.
                var self = this;
                //Do a check on the JsonFileUrl and crosscheck it.
                //If it doesn't match the cross-check, it needs to be updated
                //This allows for either url or _jsonFileUrl to he changed to
-               //reset the store load location.  Done this way for backwards 
+               //reset the store load location.  Done this way for backwards
                //compatibility.  People use _jsonFileUrl (even though officially
                //private.
                if(this._jsonFileUrl !== this._ccUrl){
-                       dojo.deprecated("dojo.data.ItemFileReadStore: ", 
+                       dojo.deprecated("dojo.data.ItemFileReadStore: ",
                                "To change the url, set the url property of the store," +
                                " not _jsonFileUrl.  _jsonFileUrl support will be removed in 2.0");
                        this._ccUrl = this._jsonFileUrl;
@@ -25978,14 +26947,14 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                }
 
                //See if there was any forced reset of data.
-               if(this.data != null && this._jsonData == null){
+               if(this.data != null){
                        this._jsonData = this.data;
                        this.data = null;
                }
 
                if(this._jsonFileUrl){
                                var getArgs = {
-                                       url: this._jsonFileUrl, 
+                                       url: this._jsonFileUrl,
                                        handleAs: "json-comment-optional",
                                        preventCache: this.urlPreventCache,
                                        failOk: this.failOk,
@@ -25994,7 +26963,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                        var getHandler = dojo.xhrGet(getArgs);
                        getHandler.addCallback(function(data){
                                try{
-                                       //Check to be sure there wasn't another load going on concurrently 
+                                       //Check to be sure there wasn't another load going on concurrently
                                        //So we don't clobber data that comes in on it.  If there is a load going on
                                        //then do not save this data.  It will potentially clobber current data.
                                        //We mainly wanted to sync/wait here.
@@ -26007,7 +26976,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                                                //Okay, we hit an error state we can't recover from.  A forced load occurred
                                                //while an async load was occurring.  Since we cannot block at this point, the best
                                                //that can be managed is to throw an error.
-                                               throw new Error("dojo.data.ItemFileReadStore:  Unable to perform a synchronous load, an async load is in progress."); 
+                                               throw new Error("dojo.data.ItemFileReadStore:  Unable to perform a synchronous load, an async load is in progress.");
                                        }
                                }catch(e){
                                        console.log(e);
@@ -26021,7 +26990,7 @@ dojo.declare("dojo.data.ItemFileReadStore", null,{
                        self._getItemsFromLoadedData(self._jsonData);
                        self._jsonData = null;
                        self._loadFinished = true;
-               } 
+               }
        }
 });
 //Mix in the simple fetch implementation to this class.
@@ -26034,6 +27003,7 @@ dojo._hasResource["dojo.data.ItemFileWriteStore"] = true;
 dojo.provide("dojo.data.ItemFileWriteStore");
 
 
+
 dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
        constructor: function(/* object */ keywordParameters){
                //      keywordParameters: {typeMap: object)
@@ -26044,7 +27014,7 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                //                      ...
                //                      typeN: function || object
                //              }
-               //              Where if it is a function, it is assumed to be an object constructor that takes the 
+               //              Where if it is a function, it is assumed to be an object constructor that takes the
                //              value of _value as the initialization parameters.  It is serialized assuming object.toString()
                //              serialization.  If it is an object, then it is assumed
                //              to be an object of general form:
@@ -26060,8 +27030,8 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                
                // For keeping track of changes so that we can implement isDirty and revert
                this._pending = {
-                       _newItems:{}, 
-                       _modifiedItems:{}, 
+                       _newItems:{},
+                       _modifiedItems:{},
                        _deletedItems:{}
                };
 
@@ -26124,8 +27094,8 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                        }
                }
                
-               // make sure this identity is not already in use by another item, if identifiers were 
-               // defined in the file.  Otherwise it would be the item count, 
+               // make sure this identity is not already in use by another item, if identifiers were
+               // defined in the file.  Otherwise it would be the item count,
                // which should always be unique in this case.
                if(this._itemsByIdentity){
                        this._assert(typeof this._itemsByIdentity[newIdentity] === "undefined");
@@ -26134,7 +27104,7 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                this._assert(typeof this._pending._deletedItems[newIdentity] === "undefined");
                
                var newItem = {};
-               newItem[this._storeRefPropName] = this;         
+               newItem[this._storeRefPropName] = this;
                newItem[this._itemNumPropName] = this._arrayOfAllItems.length;
                if(this._itemsByIdentity){
                        this._itemsByIdentity[newIdentity] = newItem;
@@ -26187,14 +27157,14 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                                // Bummer, the user is trying to do something like
                                // newItem({_S:"foo"}).  Unfortunately, our superclass,
                                // ItemFileReadStore, is already using _S in each of our items
-                               // to hold private info.  To avoid a naming collision, we 
-                               // need to move all our private info to some other property 
+                               // to hold private info.  To avoid a naming collision, we
+                               // need to move all our private info to some other property
                                // of all the items/objects.  So, we need to iterate over all
-                               // the items and do something like: 
+                               // the items and do something like:
                                //    item.__S = item._S;
                                //    item._S = undefined;
-                               // But first we have to make sure the new "__S" variable is 
-                               // not in use, which means we have to iterate over all the 
+                               // But first we have to make sure the new "__S" variable is
+                               // not in use, which means we have to iterate over all the
                                // items checking for that.
                                throw new Error("encountered bug in ItemFileWriteStore.newItem");
                        }
@@ -26231,17 +27201,17 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                this._assertIsItem(item);
 
                // Remove this item from the _arrayOfAllItems, but leave a null value in place
-               // of the item, so as not to change the length of the array, so that in newItem() 
+               // of the item, so as not to change the length of the array, so that in newItem()
                // we can still safely do: newIdentity = this._arrayOfAllItems.length;
                var indexInArrayOfAllItems = item[this._itemNumPropName];
                var identity = this.getIdentity(item);
 
                //If we have reference integrity on, we need to do reference cleanup for the deleted item
                if(this.referenceIntegrity){
-                       //First scan all the attributes of this items for references and clean them up in the map 
+                       //First scan all the attributes of this items for references and clean them up in the map
                        //As this item is going away, no need to track its references anymore.
 
-                       //Get the attributes list before we generate the backup so it 
+                       //Get the attributes list before we generate the backup so it
                        //doesn't pollute the attributes list.
                        var attributes = this.getAttributes(item);
 
@@ -26287,7 +27257,7 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                                                                return !(this.isItem(possibleItem) && this.getIdentity(possibleItem) == identity);
                                                        }, this);
                                                        //Remove the note of the reference to the item and set the values on the modified attribute.
-                                                       this._removeReferenceFromMap(item, containingItem, attribute); 
+                                                       this._removeReferenceFromMap(item, containingItem, attribute);
                                                        if(newValues.length < oldValues.length){
                                                                this._setValueOrValues(containingItem, attribute, newValues, true);
                                                        }
@@ -26349,11 +27319,11 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
 
                var identity = this.getIdentity(item);
                if(!this._pending._modifiedItems[identity]){
-                       // Before we actually change the item, we make a copy of it to 
-                       // record the original state, so that we'll be able to revert if 
+                       // Before we actually change the item, we make a copy of it to
+                       // record the original state, so that we'll be able to revert if
                        // the revert method gets called.  If the item has already been
                        // modified then there's no need to do this now, since we already
-                       // have a record of the original state.                                         
+                       // have a record of the original state.
                        var copyOfItemState = {};
                        for(var key in item){
                                if((key === this._storeRefPropName) || (key === this._itemNumPropName) || (key === this._rootItemPropName)){
@@ -26374,7 +27344,7 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                if(dojo.isArray(newValueOrValues) && newValueOrValues.length === 0){
                        
                        // If we were passed an empty array as the value, that counts
-                       // as "unsetting" the attribute, so we need to remove this 
+                       // as "unsetting" the attribute, so we need to remove this
                        // attribute from the item.
                        success = delete item[attribute];
                        newValueOrValues = undefined; // used in the onSet Notification call below
@@ -26398,7 +27368,7 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                                // Unfortunately, it's not safe to just do this:
                                //    newValueArray = newValues;
                                // Instead, we need to copy the array, which slice() does very nicely.
-                               // This is so that our internal data structure won't  
+                               // This is so that our internal data structure won't
                                // get corrupted if the user mucks with the values array *after*
                                // calling setValues().
                                newValueArray = newValueOrValues.slice(0, newValueOrValues.length);
@@ -26406,7 +27376,7 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                                newValueArray = [newValueOrValues];
                        }
 
-                       //We need to handle reference integrity if this is on. 
+                       //We need to handle reference integrity if this is on.
                        //In the case of set, we need to see if references were added or removed
                        //and update the reference tracking map accordingly.
                        if(this.referenceIntegrity){
@@ -26433,7 +27403,7 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                                                        if(map[id.toString()]){
                                                                delete map[id.toString()];
                                                        }else{
-                                                               this._addReferenceToMap(possibleItem, item, attribute); 
+                                                               this._addReferenceToMap(possibleItem, item, attribute);
                                                        }
                                                }
                                        }, this);
@@ -26463,7 +27433,7 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
 
                // Now we make the dojo.data.api.Notification call
                if(callOnSet){
-                       this.onSet(item, attribute, oldValueOrValues, newValueOrValues); 
+                       this.onSet(item, attribute, oldValueOrValues, newValueOrValues);
                }
                return success; // boolean
        },
@@ -26498,7 +27468,7 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                //              Method to remove an reference map entry for an item and attribute.
                //      description:
                //              Method to remove an reference map entry for an item and attribute.  This will
-               //              also perform cleanup on the map such that if there are no more references at all to 
+               //              also perform cleanup on the map such that if there are no more references at all to
                //              the item, its reference object and entry are removed.
                //
                //      refItem:
@@ -26555,7 +27525,7 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
        _flatten: function(/* anything */ value){
                if(this.isItem(value)){
                        var item = value;
-                       // Given an item, return an serializable object that provides a 
+                       // Given an item, return an serializable object that provides a
                        // reference to the item.
                        // For example, given kermit:
                        //    var kermit = store.newItem({id:2, name:"Kermit"});
@@ -26586,7 +27556,7 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
        },
        
        _getNewFileContentString: function(){
-               // summary: 
+               // summary:
                //              Generate a string that can be saved to a file.
                //              The result should look similar to:
                //              http://trac.dojotoolkit.org/browser/dojo/trunk/tests/data/countries.json
@@ -26627,7 +27597,7 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
        },
 
        _isEmpty: function(something){
-               //      summary: 
+               //      summary:
                //              Function to determine if an array or object has no properties or values.
                //      something:
                //              The array or object to examine.
@@ -26656,7 +27626,7 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                var self = this;
                var saveCompleteCallback = function(){
                        self._pending = {
-                               _newItems:{}, 
+                               _newItems:{},
                                _modifiedItems:{},
                                _deletedItems:{}
                        };
@@ -26705,7 +27675,7 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                                modifiedItem = this._arrayOfAllItems[identity];
                        }
        
-                       // Restore the original item into a full-fledged item again, we want to try to 
+                       // Restore the original item into a full-fledged item again, we want to try to
                        // keep the same object instance as if we don't it, causes bugs like #9022.
                        copyOfItemState[this._storeRefPropName] = this;
                        for(key in modifiedItem){
@@ -26746,7 +27716,7 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                                        }
                                        this._addReferenceToMap(refItem, deletedItem, reference.attr);
                                }, this);
-                               delete deletedItem["backupRefs_" + this._reverseRefMap]; 
+                               delete deletedItem["backupRefs_" + this._reverseRefMap];
                        }
                }
 
@@ -26765,8 +27735,8 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                }
 
                this._pending = {
-                       _newItems:{}, 
-                       _modifiedItems:{}, 
+                       _newItems:{},
+                       _modifiedItems:{},
                        _deletedItems:{}
                };
                return true; // boolean
@@ -26777,13 +27747,13 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
                if(item){
                        // return true if the item is dirty
                        var identity = this.getIdentity(item);
-                       return new Boolean(this._pending._newItems[identity] || 
+                       return new Boolean(this._pending._newItems[identity] ||
                                this._pending._modifiedItems[identity] ||
                                this._pending._deletedItems[identity]).valueOf(); // boolean
                }else{
                        // return true if the store is dirty -- which means return true
                        // if there are any new items, dirty items, or modified items
-                       if(!this._isEmpty(this._pending._newItems) || 
+                       if(!this._isEmpty(this._pending._newItems) ||
                                !this._isEmpty(this._pending._modifiedItems) ||
                                !this._isEmpty(this._pending._deletedItems)){
                                return true;
@@ -26794,28 +27764,28 @@ dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
 
 /* dojo.data.api.Notification */
 
-       onSet: function(/* item */ item, 
-                                       /*attribute-name-string*/ attribute, 
+       onSet: function(/* item */ item,
+                                       /*attribute-name-string*/ attribute,
                                        /*object | array*/ oldValue,
                                        /*object | array*/ newValue){
                // summary: See dojo.data.api.Notification.onSet()
                
-               // No need to do anything. This method is here just so that the 
+               // No need to do anything. This method is here just so that the
                // client code can connect observers to it.
        },
 
        onNew: function(/* item */ newItem, /*object?*/ parentInfo){
                // summary: See dojo.data.api.Notification.onNew()
                
-               // No need to do anything. This method is here just so that the 
-               // client code can connect observers to it. 
+               // No need to do anything. This method is here just so that the
+               // client code can connect observers to it.
        },
 
        onDelete: function(/* item */ deletedItem){
                // summary: See dojo.data.api.Notification.onDelete()
                
-               // No need to do anything. This method is here just so that the 
-               // client code can connect observers to it. 
+               // No need to do anything. This method is here just so that the
+               // client code can connect observers to it.
        },
 
        close: function(/* object? */ request){