You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by jk...@apache.org on 2008/02/04 23:08:37 UTC

svn commit: r618461 [11/43] - in /tapestry/tapestry4/trunk/tapestry-framework/src/js: dojo-0.4.3-custom-4.1.5/ dojo-0.4.3-custom-4.1.5/nls/ dojo-0.4.3-custom-4.1.5/src/ dojo-0.4.3-custom-4.1.5/src/animation/ dojo-0.4.3-custom-4.1.5/src/cal/ dojo-0.4.3-...

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/dojo3.js.uncompressed.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/dojo3.js.uncompressed.js?rev=618461&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/dojo3.js.uncompressed.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/dojo3.js.uncompressed.js Mon Feb  4 14:07:13 2008
@@ -0,0 +1,8566 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("layer.widget");
+dojo.provide("dojo.namespaces.dojo");
+dojo.require("dojo.ns");
+
+(function(){
+	// Mapping of all widget short names to their full package names
+	// This is used for widget autoloading - no dojo.require() is necessary.
+	// If you use a widget in markup or create one dynamically, then this
+	// mapping is used to find and load any dependencies not already loaded.
+	// You should use your own namespace for any custom widgets.
+	// For extra widgets you use, dojo.declare() may be used to explicitly load them.
+	// Experimental and deprecated widgets are not included in this table
+	var map = {
+		html: {
+			"accordioncontainer": "dojo.widget.AccordionContainer",
+			"animatedpng": "dojo.widget.AnimatedPng",
+			"button": "dojo.widget.Button",
+			"chart": "dojo.widget.Chart",
+			"checkbox": "dojo.widget.Checkbox",
+			"clock": "dojo.widget.Clock",
+			"colorpalette": "dojo.widget.ColorPalette",
+			"combobox": "dojo.widget.ComboBox",
+			"combobutton": "dojo.widget.Button",
+			"contentpane": "dojo.widget.ContentPane",
+			"currencytextbox": "dojo.widget.CurrencyTextbox",
+			"datepicker": "dojo.widget.DatePicker",
+			"datetextbox": "dojo.widget.DateTextbox",
+			"debugconsole": "dojo.widget.DebugConsole",
+			"dialog": "dojo.widget.Dialog",
+			"dropdownbutton": "dojo.widget.Button",
+			"dropdowndatepicker": "dojo.widget.DropdownDatePicker",
+			"dropdowntimepicker": "dojo.widget.DropdownTimePicker",
+			"emaillisttextbox": "dojo.widget.InternetTextbox",
+			"emailtextbox": "dojo.widget.InternetTextbox",
+			"editor": "dojo.widget.Editor",
+			"editor2": "dojo.widget.Editor2",
+			"filteringtable": "dojo.widget.FilteringTable",
+			"fisheyelist": "dojo.widget.FisheyeList",
+			"fisheyelistitem": "dojo.widget.FisheyeList",
+			"floatingpane": "dojo.widget.FloatingPane",
+			"modalfloatingpane": "dojo.widget.FloatingPane",
+			"form": "dojo.widget.Form",
+			"googlemap": "dojo.widget.GoogleMap",
+			"inlineeditbox": "dojo.widget.InlineEditBox",
+			"integerspinner": "dojo.widget.Spinner",
+			"integertextbox": "dojo.widget.IntegerTextbox",
+			"ipaddresstextbox": "dojo.widget.InternetTextbox",
+			"layoutcontainer": "dojo.widget.LayoutContainer",
+			"linkpane": "dojo.widget.LinkPane",
+			"popupmenu2": "dojo.widget.Menu2",
+			"menuitem2": "dojo.widget.Menu2",
+			"menuseparator2": "dojo.widget.Menu2",
+			"menubar2": "dojo.widget.Menu2",
+			"menubaritem2": "dojo.widget.Menu2",
+			"pagecontainer": "dojo.widget.PageContainer",
+			"pagecontroller": "dojo.widget.PageContainer",
+			"popupcontainer": "dojo.widget.PopupContainer",
+			"progressbar": "dojo.widget.ProgressBar",
+			"radiogroup": "dojo.widget.RadioGroup",
+			"realnumbertextbox": "dojo.widget.RealNumberTextbox",
+			"regexptextbox": "dojo.widget.RegexpTextbox",
+			"repeater": "dojo.widget.Repeater", 
+			"resizabletextarea": "dojo.widget.ResizableTextarea",
+			"richtext": "dojo.widget.RichText",
+			"select": "dojo.widget.Select",
+			"show": "dojo.widget.Show",
+			"showaction": "dojo.widget.ShowAction",
+			"showslide": "dojo.widget.ShowSlide",
+			"slidervertical": "dojo.widget.Slider",
+			"sliderhorizontal": "dojo.widget.Slider",
+			"slider":"dojo.widget.Slider",
+			"slideshow": "dojo.widget.SlideShow",
+			"sortabletable": "dojo.widget.SortableTable",
+			"splitcontainer": "dojo.widget.SplitContainer",
+			"tabcontainer": "dojo.widget.TabContainer",
+			"tabcontroller": "dojo.widget.TabContainer",
+			"taskbar": "dojo.widget.TaskBar",
+			"textbox": "dojo.widget.Textbox",
+			"timepicker": "dojo.widget.TimePicker",
+			"timetextbox": "dojo.widget.DateTextbox",
+			"titlepane": "dojo.widget.TitlePane",
+			"toaster": "dojo.widget.Toaster",
+			"toggler": "dojo.widget.Toggler",
+			"toolbar": "dojo.widget.Toolbar",
+			"toolbarcontainer": "dojo.widget.Toolbar",
+			"toolbaritem": "dojo.widget.Toolbar",
+			"toolbarbuttongroup": "dojo.widget.Toolbar",
+			"toolbarbutton": "dojo.widget.Toolbar",
+			"toolbardialog": "dojo.widget.Toolbar",
+			"toolbarmenu": "dojo.widget.Toolbar",
+			"toolbarseparator": "dojo.widget.Toolbar",
+			"toolbarspace": "dojo.widget.Toolbar",
+			"toolbarselect": "dojo.widget.Toolbar",
+			"toolbarcolordialog": "dojo.widget.Toolbar",
+			"tooltip": "dojo.widget.Tooltip",
+			"tree": "dojo.widget.Tree",
+			"treebasiccontroller": "dojo.widget.TreeBasicController",
+			"treecontextmenu": "dojo.widget.TreeContextMenu",
+			"treedisablewrapextension": "dojo.widget.TreeDisableWrapExtension",
+			"treedociconextension": "dojo.widget.TreeDocIconExtension",
+			"treeeditor": "dojo.widget.TreeEditor",
+			"treeemphasizeonselect": "dojo.widget.TreeEmphasizeOnSelect",
+			"treeexpandtonodeonselect": "dojo.widget.TreeExpandToNodeOnSelect",
+			"treelinkextension": "dojo.widget.TreeLinkExtension",
+			"treeloadingcontroller": "dojo.widget.TreeLoadingController",
+			"treemenuitem": "dojo.widget.TreeContextMenu",
+			"treenode": "dojo.widget.TreeNode",
+			"treerpccontroller": "dojo.widget.TreeRPCController",
+			"treeselector": "dojo.widget.TreeSelector",
+			"treetoggleonselect": "dojo.widget.TreeToggleOnSelect",
+			"treev3": "dojo.widget.TreeV3",
+			"treebasiccontrollerv3": "dojo.widget.TreeBasicControllerV3",
+			"treecontextmenuv3": "dojo.widget.TreeContextMenuV3",
+			"treedndcontrollerv3": "dojo.widget.TreeDndControllerV3",
+			"treeloadingcontrollerv3": "dojo.widget.TreeLoadingControllerV3",
+			"treemenuitemv3": "dojo.widget.TreeContextMenuV3",
+			"treerpccontrollerv3": "dojo.widget.TreeRpcControllerV3",
+			"treeselectorv3": "dojo.widget.TreeSelectorV3",
+			"urltextbox": "dojo.widget.InternetTextbox",
+			"usphonenumbertextbox": "dojo.widget.UsTextbox",
+			"ussocialsecuritynumbertextbox": "dojo.widget.UsTextbox",
+			"usstatetextbox": "dojo.widget.UsTextbox",
+			"usziptextbox": "dojo.widget.UsTextbox",
+			"validationtextbox": "dojo.widget.ValidationTextbox",
+			"treeloadingcontroller": "dojo.widget.TreeLoadingController",
+			"wizardcontainer": "dojo.widget.Wizard",
+			"wizardpane": "dojo.widget.Wizard",
+			"yahoomap": "dojo.widget.YahooMap"
+		},
+		svg: {
+			"chart": "dojo.widget.svg.Chart"
+		},
+		vml: {
+			"chart": "dojo.widget.vml.Chart"
+		}
+	};
+
+	dojo.addDojoNamespaceMapping = function(/*String*/shortName, /*String*/packageName){
+	// summary:
+	//	Add an entry to the mapping table for the dojo: namespace
+	//
+	// shortName: the name to be used as the widget's tag name in the dojo: namespace
+	// packageName: the path to the Javascript module in dotted package notation
+		map[shortName]=packageName;    
+	};
+	
+	function dojoNamespaceResolver(name, domain){
+		if(!domain){ domain="html"; }
+		if(!map[domain]){ return null; }
+		return map[domain][name];    
+	}
+
+	dojo.registerNamespaceResolver("dojo", dojoNamespaceResolver);
+})();
+
+dojo.provide("dojo.xml.Parse");
+dojo.require("dojo.dom");
+
+//TODO: determine dependencies
+// currently has dependency on dojo.xml.DomUtil nodeTypes constants...
+
+// using documentFragment nomenclature to generalize in case we don't want to require passing a collection of nodes with a single parent
+
+dojo.xml.Parse = function(){
+	// summary:
+	//		generic class for taking a DOM node and parsing it into an object
+	//		based on the "dojo tag name" of that node.
+	// 
+	//		supported dojoTagName's:
+	//			<prefix:tag> => prefix:tag
+	//			<dojo:tag> => dojo:tag
+	//			<dojoTag> => dojo:tag
+	//			<tag dojoType="type"> => dojo:type
+	//			<tag dojoType="prefix:type"> => prefix:type
+	//			<tag dojo:type="type"> => dojo:type
+	//			<tag class="classa dojo-type classb"> => dojo:type	
+
+	var isIE = ((dojo.render.html.capable)&&(dojo.render.html.ie));
+
+	// get normalized (lowercase) tagName
+	// some browsers report tagNames in lowercase no matter what
+	function getTagName(node){
+		/*
+		return ((node)&&(node["tagName"]) ? node.tagName.toLowerCase() : '');
+		*/
+		try{
+			return node.tagName.toLowerCase();
+		}catch(e){
+			return "";
+		}
+	}
+
+	// locate dojo qualified tag name
+	function getDojoTagName(node){
+		var tagName = getTagName(node);
+		if (!tagName){
+				return '';
+		}
+		// any registered tag
+		if((dojo.widget)&&(dojo.widget.tags[tagName])){
+			return tagName;
+		}
+		// <prefix:tag> => prefix:tag
+		var p = tagName.indexOf(":");
+		if(p>=0){
+			return tagName;
+		}
+		// <dojo:tag> => dojo:tag
+		if(tagName.substr(0,5) == "dojo:"){
+			return tagName;
+		}
+		if(dojo.render.html.capable && dojo.render.html.ie && node.scopeName != 'HTML'){
+			return node.scopeName.toLowerCase() + ':' + tagName;
+		}
+		// <dojoTag> => dojo:tag
+		if(tagName.substr(0,4) == "dojo"){
+			// FIXME: this assumes tag names are always lower case
+			return "dojo:" + tagName.substring(4);
+		}
+		// <tag dojoType="prefix:type"> => prefix:type
+		// <tag dojoType="type"> => dojo:type
+		var djt = node.getAttribute("dojoType") || node.getAttribute("dojotype");
+		if(djt){
+			if (djt.indexOf(":")<0){
+				djt = "dojo:"+djt;
+			}
+			return djt.toLowerCase();
+		}
+		// <tag dojo:type="type"> => dojo:type
+		djt = node.getAttributeNS && node.getAttributeNS(dojo.dom.dojoml,"type");
+		if(djt){
+			return "dojo:" + djt.toLowerCase();
+		}
+		// <tag dojo:type="type"> => dojo:type
+		try{
+			// FIXME: IE really really doesn't like this, so we squelch errors for it
+			djt = node.getAttribute("dojo:type");
+		}catch(e){ 
+			// FIXME: log?  
+		}
+		if(djt){ return "dojo:"+djt.toLowerCase(); }
+		// <tag class="classa dojo-type classb"> => dojo:type	
+		if((dj_global["djConfig"])&&(!djConfig["ignoreClassNames"])){ 
+			// FIXME: should we make this optionally enabled via djConfig?
+			var classes = node.className||node.getAttribute("class");
+			// FIXME: following line, without check for existence of classes.indexOf
+			// breaks firefox 1.5's svg widgets
+			if((classes )&&(classes.indexOf)&&(classes.indexOf("dojo-")!=-1)){
+				var aclasses = classes.split(" ");
+				for(var x=0, c=aclasses.length; x<c; x++){
+					if(aclasses[x].slice(0, 5) == "dojo-"){
+						return "dojo:"+aclasses[x].substr(5).toLowerCase(); 
+					}
+				}
+			}
+		}
+		// no dojo-qualified name
+		return '';
+	}
+
+
+	this.parseElement = function(	/*DomNode*/node,
+									/*Boolean*/hasParentNodeSet, 
+									/*Boolean*/optimizeForDojoML, 
+									/*Integer*/thisIdx	){
+		// summary:
+		//		recursively parse the passed node, returning a normalized data
+		//		structure that represents the "attributes of interest" of said
+		//		elements. If optimizeForDojoML is true, only nodes that contain
+		//		a "dojo tag name" will be inspected for attributes.
+		// node: the DomNode to be treated as the root of inspection
+		// hasParentNodeSet: no-op, please pass "null"
+		// optimizeForDojoML: should we ignore non-Dojo nodes? Defaults to false.
+		// thisIdx:
+		//		a way to specify a synthetic "index" property in the resulting
+		//		data structure. Otherwise the index property of the top-level
+		//		return element is always "0".
+
+		// TODOC: document return structure of a non-trivial element set
+
+		// run shortcuts to bail out of processing up front to save time and
+		// object alloc if possible.
+		var tagName = getTagName(node);
+		//There's a weird bug in IE where it counts end tags, e.g. </dojo:button> as nodes that should be parsed.  Ignore these
+		if(isIE && tagName.indexOf("/")==0){ return null; }
+
+		try{
+			var attr = node.getAttribute("parseWidgets");
+			if(attr && attr.toLowerCase() == "false"){
+				return {};
+			}
+		}catch(e){/*continue*/}
+
+		
+		// look for a dojoml qualified name
+		// process dojoml only when optimizeForDojoML is true
+		var process = true;
+		if(optimizeForDojoML){
+			var dojoTagName = getDojoTagName(node);
+			tagName = dojoTagName || tagName;
+			process = Boolean(dojoTagName);
+		}
+
+		var parsedNodeSet = {};
+		parsedNodeSet[tagName] = [];
+		var pos = tagName.indexOf(":");
+		if(pos>0){
+			var ns = tagName.substring(0,pos);
+			parsedNodeSet["ns"] = ns;
+			// honor user namespace filters
+			if((dojo.ns)&&(!dojo.ns.allow(ns))){process=false;}
+		}
+
+		if(process){
+			var attributeSet = this.parseAttributes(node);
+			for(var attr in attributeSet){
+				if((!parsedNodeSet[tagName][attr])||(typeof parsedNodeSet[tagName][attr] != "array")){
+					parsedNodeSet[tagName][attr] = [];
+				}
+				parsedNodeSet[tagName][attr].push(attributeSet[attr]);
+			}	
+			// FIXME: we might want to make this optional or provide cloning instead of
+			// referencing, but for now, we include a node reference to allow
+			// instantiated components to figure out their "roots"
+			parsedNodeSet[tagName].nodeRef = node;
+			parsedNodeSet.tagName = tagName;
+			parsedNodeSet.index = thisIdx||0;
+		}
+
+		var count = 0;
+		for(var i = 0; i < node.childNodes.length; i++){
+			var tcn = node.childNodes.item(i);
+			switch(tcn.nodeType){
+				case  dojo.dom.ELEMENT_NODE: // element nodes, call this function recursively
+					var ctn = getDojoTagName(tcn) || getTagName(tcn);
+					if(!parsedNodeSet[ctn]){
+						parsedNodeSet[ctn] = [];
+					}
+					parsedNodeSet[ctn].push(this.parseElement(tcn, true, optimizeForDojoML, count));
+					if(	(tcn.childNodes.length == 1)&&
+						(tcn.childNodes.item(0).nodeType == dojo.dom.TEXT_NODE)){
+						parsedNodeSet[ctn][parsedNodeSet[ctn].length-1].value = tcn.childNodes.item(0).nodeValue;
+					}
+					count++;
+					break;
+				case  dojo.dom.TEXT_NODE: // if a single text node is the child, treat it as an attribute
+					if(node.childNodes.length == 1){
+						parsedNodeSet[tagName].push({ value: node.childNodes.item(0).nodeValue });
+					}
+					break;
+				default: break;
+				/*
+				case  dojo.dom.ATTRIBUTE_NODE: // attribute node... not meaningful here
+					break;
+				case  dojo.dom.CDATA_SECTION_NODE: // cdata section... not sure if this would ever be meaningful... might be...
+					break;
+				case  dojo.dom.ENTITY_REFERENCE_NODE: // entity reference node... not meaningful here
+					break;
+				case  dojo.dom.ENTITY_NODE: // entity node... not sure if this would ever be meaningful
+					break;
+				case  dojo.dom.PROCESSING_INSTRUCTION_NODE: // processing instruction node... not meaningful here
+					break;
+				case  dojo.dom.COMMENT_NODE: // comment node... not not sure if this would ever be meaningful 
+					break;
+				case  dojo.dom.DOCUMENT_NODE: // document node... not sure if this would ever be meaningful
+					break;
+				case  dojo.dom.DOCUMENT_TYPE_NODE: // document type node... not meaningful here
+					break;
+				case  dojo.dom.DOCUMENT_FRAGMENT_NODE: // document fragment node... not meaningful here
+					break;
+				case  dojo.dom.NOTATION_NODE:// notation node... not meaningful here
+					break;
+				*/
+			}
+		}
+		//return (hasParentNodeSet) ? parsedNodeSet[node.tagName] : parsedNodeSet;
+		//if(parsedNodeSet.tagName)dojo.debug("parseElement: RETURNING NODE WITH TAGNAME "+parsedNodeSet.tagName);
+		return parsedNodeSet;
+	};
+
+
+	/* parses a set of attributes on a node into an object tree */
+	this.parseAttributes = function(/*DomNode*/node){
+		// summary:
+		// 		creates an attribute object that maps attribute values for the
+		// 		passed node. Note that this is similar to creating a JSON
+		// 		representation of a DOM node.
+		// usage:
+		//		a node with the following serialization:
+		//			<div foo="bar" baz="thud">...</div>	
+		//		would yeild the following return structure when passed into this
+		//		function:
+		//			{
+		//				"foo": {
+		//					"value": "bar"
+		//				},
+		//				"baz": {
+		//					"value": "thud"
+		//				}
+		//			}
+		//
+		var parsedAttributeSet = {};
+		var atts = node.attributes;
+		// TODO: should we allow for duplicate attributes at this point...
+		// would any of the relevant dom implementations even allow this?
+		var attnode, i=0;
+		while((attnode=atts[i++])){
+			if(isIE){
+				if(!attnode){ continue; }
+				if((typeof attnode == "object")&&
+					(typeof attnode.nodeValue == 'undefined')||
+					(attnode.nodeValue == null)||
+					(attnode.nodeValue == '')){ 
+					continue; 
+				}
+			}
+
+			var nn = attnode.nodeName.split(":");
+			nn = (nn.length == 2) ? nn[1] : attnode.nodeName;
+						
+			parsedAttributeSet[nn] = { 
+				value: attnode.nodeValue 
+			};
+		}
+		return parsedAttributeSet;
+	};
+};
+
+dojo.provide("dojo.widget.Widget");
+
+dojo.require("dojo.lang.func");
+dojo.require("dojo.lang.array");
+dojo.require("dojo.lang.extras");
+dojo.require("dojo.lang.declare");
+dojo.require("dojo.ns");
+dojo.require("dojo.widget.Manager");
+dojo.require("dojo.event.*");
+
+dojo.declare("dojo.widget.Widget", null,
+	function(){
+		// these properties aren't primitives and need to be created on a per-item
+		// basis.
+
+		// children: Array
+		//		a list of all of the widgets that have been added as children of
+		//		this component. Should only have values if isContainer is true.
+		this.children = [];
+
+		// extraArgs: Object
+		//		a map of properties which the widget system tried to assign from
+		//		user input but did not correspond to any of the properties set on
+		//		the class prototype. These names will also be available in all
+		//		lower-case form in this map
+		this.extraArgs = {};
+	},
+{
+	// parent: Widget
+	//		the parent of this widget
+	parent: null, 
+
+	// isTopLevel: Boolean
+	//		should this widget eat all events that bubble up to it?
+	//		obviously, top-level and modal widgets should set these appropriately
+	isTopLevel:  false, 
+
+	// disabled: Boolean
+	//		should this widget respond to user input?
+	//		in markup, this is specified as "disabled='disabled'", or just "disabled"
+	disabled: false,
+
+	// isContainer: Boolean
+	//		can this widget contain other widgets?
+	isContainer: false, 
+
+	// widgetId: String
+	//		a unique, opaque ID string that can be assigned by users or by the
+	//		system. If the developer passes an ID which is known not to be
+	//		unique, the specified ID is ignored and the system-generated ID is
+	//		used instead.
+	widgetId: "",
+
+	// widgetType: String
+	//		used for building generic widgets
+	widgetType: "Widget",
+
+	// ns: String
+	//		defaults to 'dojo'.  "namespace" is a reserved word in JavaScript, so we abbreviate
+	ns: "dojo",
+
+	getNamespacedType: function(){ 
+		// summary:
+		//		get the "full" name of the widget. If the widget comes from the
+		//		"dojo" namespace and is a Button, calling this method will
+		//		return "dojo:button", all lower-case
+		return (this.ns ? this.ns + ":" + this.widgetType : this.widgetType).toLowerCase(); // String
+	},
+	
+	toString: function(){
+		// summary:
+		//		returns a string that represents the widget. When a widget is
+		//		cast to a string, this method will be used to generate the
+		//		output. Currently, it does not implement any sort of reversable
+		//		serialization.
+		return '[Widget ' + this.getNamespacedType() + ', ' + (this.widgetId || 'NO ID') + ']'; // String
+	},
+
+	repr: function(){
+		// summary: returns the string representation of the widget.
+		return this.toString(); // String
+	},
+
+	enable: function(){
+		// summary:
+		//		enables the widget, usually involving unmasking inputs and
+		//		turning on event handlers. Not implemented here.
+		this.disabled = false;
+	},
+
+	disable: function(){
+		// summary:
+		//		disables the widget, usually involves masking inputs and
+		//		unsetting event handlers. Not implemented here.
+		this.disabled = true;
+	},
+
+	// TODO:
+	//	1) this would be better in HtmlWidget rather than here?
+	//	2) since many widgets don't care if they've been resized, maybe this should be a mixin?
+	onResized: function(){
+		// summary:
+		//		A signal that widgets will call when they have been resized.
+		//		Can be connected to for determining if a layout needs to be
+		//		reflowed. Clients should override this function to do special
+		//		processing, then call this.notifyChildrenOfResize() to notify
+		//		children of resize.
+		this.notifyChildrenOfResize();
+	},
+	
+	notifyChildrenOfResize: function(){
+		// summary: dispatches resized events to all children of this widget
+		for(var i=0; i<this.children.length; i++){
+			var child = this.children[i];
+			//dojo.debug(this.widgetId + " resizing child " + child.widgetId);
+			if( child.onResized ){
+				child.onResized();
+			}
+		}
+	},
+
+	create: function(args, fragment, parent, ns){
+		// summary:
+		//		'create' manages the initialization part of the widget
+		//		lifecycle. It's called implicitly when any widget is created.
+		//		All other initialization functions for widgets, except for the
+		//		constructor, are called as a result of 'create' being fired.
+		// args: Object
+		//		a normalized view of the parameters that the widget should take
+		// fragment: Object
+		//		if the widget is being instantiated from markup, this object 
+		// parent: Widget?
+		//		the widget, if any, that this widget will be the child of.  If
+		//		none is passed, the global default widget is used.
+		// ns: String?
+		//		what namespace the widget belongs to
+		// description:
+		//		to understand the process by which widgets are instantiated, it
+		//		is critical to understand what other methods 'create' calls and
+		//		which of them you'll want to over-ride. Of course, adventurous
+		//		developers could over-ride 'create' entirely, but this should
+		//		only be done as a last resort.
+		//
+		//		Below is a list of the methods that are called, in the order
+		//		they are fired, along with notes about what they do and if/when
+		//		you should over-ride them in your widget:
+		//			
+		//			mixInProperties:
+		//				takes the args and does lightweight type introspection
+		//				on pre-existing object properties to initialize widget
+		//				values by casting the values that are passed in args
+		//			postMixInProperties:
+		//				a stub function that you can over-ride to modify
+		//				variables that may have been naively assigned by
+		//				mixInProperties
+		//			# widget is added to manager object here
+		//			buildRendering
+		//				subclasses use this method to handle all UI initialization
+		//			initialize:
+		//				a stub function that you can over-ride.
+		//			postInitialize:
+		//				a stub function that you can over-ride.
+		//			postCreate
+		//				a stub function that you can over-ride to modify take
+		//				actions once the widget has been placed in the UI
+		//
+		//		all of these functions are passed the same arguments as are
+		//		passed to 'create'
+
+		//dojo.profile.start(this.widgetType + " create");
+		if(ns){
+			this.ns = ns;
+		}
+		// dojo.debug(this.widgetType, "create");
+		//dojo.profile.start(this.widgetType + " satisfyPropertySets");
+		this.satisfyPropertySets(args, fragment, parent);
+		//dojo.profile.end(this.widgetType + " satisfyPropertySets");
+		// dojo.debug(this.widgetType, "-> mixInProperties");
+		//dojo.profile.start(this.widgetType + " mixInProperties");
+		this.mixInProperties(args, fragment, parent);
+		//dojo.profile.end(this.widgetType + " mixInProperties");
+		// dojo.debug(this.widgetType, "-> postMixInProperties");
+		//dojo.profile.start(this.widgetType + " postMixInProperties");
+		this.postMixInProperties(args, fragment, parent);
+		//dojo.profile.end(this.widgetType + " postMixInProperties");
+		// dojo.debug(this.widgetType, "-> dojo.widget.manager.add");
+		dojo.widget.manager.add(this);
+		// dojo.debug(this.widgetType, "-> buildRendering");
+		//dojo.profile.start(this.widgetType + " buildRendering");
+		this.buildRendering(args, fragment, parent);
+		//dojo.profile.end(this.widgetType + " buildRendering");
+		// dojo.debug(this.widgetType, "-> initialize");
+		//dojo.profile.start(this.widgetType + " initialize");
+		this.initialize(args, fragment, parent);
+		//dojo.profile.end(this.widgetType + " initialize");
+		// dojo.debug(this.widgetType, "-> postInitialize");
+		// postinitialize includes subcomponent creation
+		// profile is put directly to function
+		this.postInitialize(args, fragment, parent);
+		// dojo.debug(this.widgetType, "-> postCreate");
+		//dojo.profile.start(this.widgetType + " postCreate");
+		this.postCreate(args, fragment, parent);
+		//dojo.profile.end(this.widgetType + " postCreate");
+		// dojo.debug(this.widgetType, "done!");
+		
+		//dojo.profile.end(this.widgetType + " create");
+		
+		return this;
+	},
+
+	destroy: function(finalize){
+		// summary:
+		// 		Destroy this widget and it's descendants. This is the generic
+		// 		"destructor" function that all widget users should call to
+		// 		clealy discard with a widget. Once a widget is destroyed, it's
+		// 		removed from the manager object.
+		// finalize: Boolean
+		//		is this function being called part of global environment
+		//		tear-down?
+
+		// FIXME: this is woefully incomplete
+		if(this.parent){
+			this.parent.removeChild(this);
+		}
+		this.destroyChildren();
+		this.uninitialize();
+		this.destroyRendering(finalize);
+		dojo.widget.manager.removeById(this.widgetId);
+	},
+
+	destroyChildren: function(){
+		// summary:
+		//		Recursively destroy the children of this widget and their
+		//		descendents.
+		var widget;
+		var i=0;
+		while(this.children.length > i){
+			widget = this.children[i];
+			if (widget instanceof dojo.widget.Widget) { // find first widget
+				this.removeChild(widget);
+				widget.destroy();
+				continue;
+			}
+			
+			i++; // skip data object
+		}
+				
+	},
+
+	getChildrenOfType: function(/*String*/type, recurse){
+		// summary: 
+		//		return an array of descendant widgets who match the passed type
+		// recurse: Boolean
+		//		should we try to get all descendants that match? Defaults to
+		//		false.
+		var ret = [];
+		var isFunc = dojo.lang.isFunction(type);
+		if(!isFunc){
+			type = type.toLowerCase();
+		}
+		for(var x=0; x<this.children.length; x++){
+			if(isFunc){
+				if(this.children[x] instanceof type){
+					ret.push(this.children[x]);
+				}
+			}else{
+				if(this.children[x].widgetType.toLowerCase() == type){
+					ret.push(this.children[x]);
+				}
+			}
+			if(recurse){
+				ret = ret.concat(this.children[x].getChildrenOfType(type, recurse));
+			}
+		}
+		return ret; // Array
+	},
+
+	getDescendants: function(){
+		// returns: a flattened array of all direct descendants including self
+		var result = [];
+		var stack = [this];
+		var elem;
+		while ((elem = stack.pop())){
+			result.push(elem);
+			// a child may be data object without children field set (not widget)
+			if (elem.children) {
+				dojo.lang.forEach(elem.children, function(elem) { stack.push(elem); });
+			}
+		}
+		return result; // Array
+	},
+
+
+	isFirstChild: function(){
+		return this === this.parent.children[0]; // Boolean
+	},
+
+	isLastChild: function() {
+		return this === this.parent.children[this.parent.children.length-1]; // Boolean
+	},
+
+	satisfyPropertySets: function(args){
+		// summary: not implemented!
+
+		// dojo.profile.start("satisfyPropertySets");
+		// get the default propsets for our component type
+		/*
+		var typePropSets = []; // FIXME: need to pull these from somewhere!
+		var localPropSets = []; // pull out propsets from the parser's return structure
+
+		// for(var x=0; x<args.length; x++){
+		// }
+
+		for(var x=0; x<typePropSets.length; x++){
+		}
+
+		for(var x=0; x<localPropSets.length; x++){
+		}
+		*/
+		// dojo.profile.end("satisfyPropertySets");
+		
+		return args;
+	},
+
+	mixInProperties: function(args, /*Object*/frag){
+		// summary:
+		// 		takes the list of properties listed in args and sets values of
+		// 		the current object based on existence of properties with the
+		// 		same name (case insensitive) and the type of the pre-existing
+		// 		property. This is a lightweight conversion and is not intended
+		// 		to capture custom type semantics.
+		// args: Object
+		//		A map of properties and values to set on the current object. By
+		//		default it is assumed that properties in args are in string
+		//		form and need to be converted. However, if there is a
+		//		'fastMixIn' property with the value 'true' in the args param,
+		//		this assumption is ignored and all values in args are copied
+		//		directly to the current object without any form of type
+		//		casting.
+		// description:
+		//		The mix-in code attempts to do some type-assignment based on
+		//		PRE-EXISTING properties of the "this" object. When a named
+		//		property of args is located, it is first tested to make
+		//		sure that the current object already "has one". Properties
+		//		which are undefined in the base widget are NOT settable here.
+		//		The next step is to try to determine type of the pre-existing
+		//		property. If it's a string, the property value is simply
+		//		assigned. If a function, it is first cast using "new
+		//		Function()" and the execution scope modified such that it
+		//		always evaluates in the context of the current object. This
+		//		listener is then added to the original function via
+		//		dojo.event.connect(). If an Array, the system attempts to split
+		//		the string value on ";" chars, and no further processing is
+		//		attempted (conversion of array elements to a integers, for
+		//		instance). If the property value is an Object
+		//		(testObj.constructor === Object), the property is split first
+		//		on ";" chars, secondly on ":" chars, and the resulting
+		//		key/value pairs are assigned to an object in a map style. The
+		//		onus is on the property user to ensure that all property values
+		//		are converted to the expected type before usage. Properties
+		//		which do not occur in the "this" object are assigned to the
+		//		this.extraArgs map using both the original name and the
+		//		lower-case name of the property. This allows for consistent
+		//		access semantics regardless of the case preservation of the
+		//		source of the property names.
+		
+		if((args["fastMixIn"])||(frag["fastMixIn"])){
+			// dojo.profile.start("mixInProperties_fastMixIn");
+			// fast mix in assumes case sensitivity, no type casting, etc...
+			// dojo.lang.mixin(this, args);
+			for(var x in args){
+				this[x] = args[x];
+			}
+			// dojo.profile.end("mixInProperties_fastMixIn");
+			return;
+		}
+		// dojo.profile.start("mixInProperties");
+
+		var undef;
+
+		// NOTE: we cannot assume that the passed properties are case-correct
+		// (esp due to some browser bugs). Therefore, we attempt to locate
+		// properties for assignment regardless of case. This may cause
+		// problematic assignments and bugs in the future and will need to be
+		// documented with big bright neon lights.
+
+		// FIXME: fails miserably if a mixin property has a default value of null in 
+		// a widget
+
+		// NOTE: caching lower-cased args in the prototype is only 
+		// acceptable if the properties are invariant.
+		// if we have a name-cache, get it
+		var lcArgs = dojo.widget.lcArgsCache[this.widgetType];
+		if ( lcArgs == null ){
+			// build a lower-case property name cache if we don't have one
+			lcArgs = {};
+			for(var y in this){
+				lcArgs[((new String(y)).toLowerCase())] = y;
+			}
+			dojo.widget.lcArgsCache[this.widgetType] = lcArgs;
+		}
+		var visited = {};
+		for(var x in args){
+			if(!this[x]){ // check the cache for properties
+				var y = lcArgs[(new String(x)).toLowerCase()];
+				if(y){
+					args[y] = args[x];
+					x = y; 
+				}
+			}
+			if(visited[x]){ continue; }
+			visited[x] = true;
+			if((typeof this[x]) != (typeof undef)){
+				if(typeof args[x] != "string"){
+					this[x] = args[x];
+				}else{
+					if(dojo.lang.isString(this[x])){
+						this[x] = args[x];
+					}else if(dojo.lang.isNumber(this[x])){
+						this[x] = new Number(args[x]); // FIXME: what if NaN is the result?
+					}else if(dojo.lang.isBoolean(this[x])){
+						this[x] = (args[x].toLowerCase()=="false") ? false : true;
+					}else if(dojo.lang.isFunction(this[x])){
+
+						// FIXME: need to determine if always over-writing instead
+						// of attaching here is appropriate. I suspect that we
+						// might want to only allow attaching w/ action items.
+						
+						// RAR, 1/19/05: I'm going to attach instead of
+						// over-write here. Perhaps function objects could have
+						// some sort of flag set on them? Or mixed-into objects
+						// could have some list of non-mutable properties
+						// (although I'm not sure how that would alleviate this
+						// particular problem)? 
+
+						// this[x] = new Function(args[x]);
+
+						// after an IRC discussion last week, it was decided
+						// that these event handlers should execute in the
+						// context of the widget, so that the "this" pointer
+						// takes correctly.
+						
+						// argument that contains no punctuation other than . is 
+						// considered a function spec, not code
+						if(args[x].search(/[^\w\.]+/i) == -1){
+							this[x] = dojo.evalObjPath(args[x], false);
+						}else{
+							var tn = dojo.lang.nameAnonFunc(new Function(args[x]), this);
+							dojo.event.kwConnect({
+								srcObj: this, 
+								srcFunc: x, 
+								adviceObj: this, 
+								adviceFunc: tn
+							});
+						}
+					}else if(dojo.lang.isArray(this[x])){ // typeof [] == "object"
+						this[x] = args[x].split(";");
+					} else if (this[x] instanceof Date) {
+						this[x] = new Date(Number(args[x])); // assume timestamp
+					}else if(typeof this[x] == "object"){ 
+						// FIXME: should we be allowing extension here to handle
+						// other object types intelligently?
+
+						// if a plain string is passed to a property of type dojo.uri.Uri,
+						// we assume it is relative to root of dojo
+						if (this[x] instanceof dojo.uri.Uri){
+							this[x] = dojo.uri.dojoUri(args[x]);
+						}else{
+							// FIXME: unlike all other types, we do not replace the
+							// object with a new one here. Should we change that?
+							var pairs = args[x].split(";");
+							for(var y=0; y<pairs.length; y++){
+								var si = pairs[y].indexOf(":");
+								if((si != -1)&&(pairs[y].length>si)){
+									this[x][pairs[y].substr(0, si).replace(/^\s+|\s+$/g, "")] = pairs[y].substr(si+1);
+								}
+							}
+						}
+					}else{
+						// the default is straight-up string assignment. When would
+						// we ever hit this?
+						this[x] = args[x];
+					}
+				}
+			}else{
+				// collect any extra 'non mixed in' args
+				this.extraArgs[x.toLowerCase()] = args[x];
+			}
+		}
+		// dojo.profile.end("mixInProperties");
+	},
+	
+	postMixInProperties: function(/*Object*/args, /*Object*/frag, /*Widget*/parent){
+		// summary
+		//	Called after the parameters to the widget have been read-in,
+		//	but before the widget template is instantiated.
+		//	Especially useful to set properties that are referenced in the widget template.
+	},
+
+	initialize: function(/*Object*/args, /*Object*/frag, /*Widget*/parent){
+		// summary: stub function.
+		return false;
+		// dojo.unimplemented("dojo.widget.Widget.initialize");
+	},
+
+	postInitialize: function(/*Object*/args, /*Object*/frag, /*Widget*/parent){
+		// summary: stub function.
+		return false;
+	},
+
+	postCreate: function(/*Object*/args, /*Object*/frag, /*Widget*/parent){
+		// summary: stub function.
+		return false;
+	},
+
+	uninitialize: function(){
+		// summary: 
+		//		stub function. Over-ride to implement custom widget tear-down
+		//		behavior.
+		return false;
+	},
+
+	buildRendering: function(/*Object*/args, /*Object*/frag, /*Widget*/parent){
+		// summary: stub function. SUBCLASSES MUST IMPLEMENT
+		dojo.unimplemented("dojo.widget.Widget.buildRendering, on "+this.toString()+", ");
+		return false;
+	},
+
+	destroyRendering: function(){
+		// summary: stub function. SUBCLASSES MUST IMPLEMENT
+		dojo.unimplemented("dojo.widget.Widget.destroyRendering");
+		return false;
+	},
+
+	addedTo: function(parent){
+		// summary:
+		//		stub function this is just a signal that can be caught
+		// parent: Widget
+		//		instance of dojo.widget.Widget that we were added to
+	},
+
+	addChild: function(child){
+		// summary: stub function. SUBCLASSES MUST IMPLEMENT
+		dojo.unimplemented("dojo.widget.Widget.addChild");
+		return false;
+	},
+
+	// Detach the given child widget from me, but don't destroy it
+	removeChild: function(/*Widget*/widget){
+		// summary: 
+		//		removes the passed widget instance from this widget but does
+		//		not destroy it
+		for(var x=0; x<this.children.length; x++){
+			if(this.children[x] === widget){
+				this.children.splice(x, 1);
+				widget.parent=null;
+				break;
+			}
+		}
+		return widget; // Widget
+	},
+
+	getPreviousSibling: function(){
+		// summary:
+		//		returns null if this is the first child of the parent,
+		//		otherwise returns the next sibling to the "left".
+		var idx = this.getParentIndex();
+ 
+		 // first node is idx=0 not found is idx<0
+		if (idx<=0) return null;
+ 
+		return this.parent.children[idx-1]; // Widget
+	},
+ 
+	getSiblings: function(){
+		// summary: gets an array of all children of our parent, including "this"
+		return this.parent.children; // Array
+	},
+ 
+	getParentIndex: function(){
+		// summary: what index are we at in the parent's children array?
+		return dojo.lang.indexOf(this.parent.children, this, true); // int
+	},
+ 
+	getNextSibling: function(){
+		// summary:
+		//		returns null if this is the last child of the parent,
+		//		otherwise returns the next sibling to the "right".
+ 
+		var idx = this.getParentIndex();
+ 
+		if (idx == this.parent.children.length-1){return null;} // last node
+		if (idx < 0){return null;} // not found
+ 
+		return this.parent.children[idx+1]; // Widget
+	}
+});
+
+// Lower case name cache: listing of the lower case elements in each widget.
+// We can't store the lcArgs in the widget itself because if B subclasses A,
+// then B.prototype.lcArgs might return A.prototype.lcArgs, which is not what we
+// want
+dojo.widget.lcArgsCache = {};
+
+// TODO: should have a more general way to add tags or tag libraries?
+// TODO: need a default tags class to inherit from for things like getting propertySets
+// TODO: parse properties/propertySets into component attributes
+// TODO: parse subcomponents
+// TODO: copy/clone raw markup fragments/nodes as appropriate
+dojo.widget.tags = {};
+dojo.widget.tags.addParseTreeHandler = function(/*String*/type){
+	// summary: deprecated!
+	dojo.deprecated("addParseTreeHandler", ". ParseTreeHandlers are now reserved for components. Any unfiltered DojoML tag without a ParseTreeHandler is assumed to be a widget", "0.5");
+	/*
+	var ltype = type.toLowerCase();
+	this[ltype] = function(fragment, widgetParser, parentComp, insertionIndex, localProps){
+		var _ltype = ltype;
+		dojo.profile.start(_ltype);
+		var n = dojo.widget.buildWidgetFromParseTree(ltype, fragment, widgetParser, parentComp, insertionIndex, localProps);
+		dojo.profile.end(_ltype);
+		return n;
+	}
+	*/
+}
+
+//dojo.widget.tags.addParseTreeHandler("dojo:widget");
+
+dojo.widget.tags["dojo:propertyset"] = function(fragment, widgetParser, parentComp){
+	// FIXME: Is this needed?
+	// FIXME: Not sure that this parses into the structure that I want it to parse into...
+	// FIXME: add support for nested propertySets
+	var properties = widgetParser.parseProperties(fragment["dojo:propertyset"]);
+}
+
+// FIXME: need to add the <dojo:connect />
+dojo.widget.tags["dojo:connect"] = function(fragment, widgetParser, parentComp){
+	var properties = widgetParser.parseProperties(fragment["dojo:connect"]);
+}
+
+// FIXME: if we know the insertion point (to a reasonable location), why then do we:
+//	- create a template node
+//	- clone the template node
+//	- render the clone and set properties
+//	- remove the clone from the render tree
+//	- place the clone
+// this is quite dumb
+dojo.widget.buildWidgetFromParseTree = function(/*String*/				type,
+												/*Object*/				frag, 
+												/*dojo.widget.Parse*/	parser,
+												/*Widget, optional*/	parentComp, 
+												/*int, optional*/		insertionIndex,
+												/*Object*/				localProps){
+
+	// summary: creates a tree of widgets from the data structure produced by the first-pass parser (frag)
+	
+
+	var stype = type.split(":");
+	stype = (stype.length == 2) ? stype[1] : type;
+	
+	// FIXME: we don't seem to be doing anything with this!
+	// var propertySets = parser.getPropertySets(frag);
+	var localProperties = localProps || parser.parseProperties(frag[frag["ns"]+":"+stype]);
+	var twidget = dojo.widget.manager.getImplementation(stype,null,null,frag["ns"]);
+	if(!twidget){
+		throw new Error('cannot find "' + type + '" widget');
+	}else if (!twidget.create){
+		throw new Error('"' + type + '" widget object has no "create" method and does not appear to implement *Widget');
+	}
+	localProperties["dojoinsertionindex"] = insertionIndex;
+	// FIXME: we lose no less than 5ms in construction!
+	var ret = twidget.create(localProperties, frag, parentComp, frag["ns"]);
+	// dojo.profile.end("buildWidgetFromParseTree");
+	return ret;
+}
+
+dojo.widget.defineWidget = function(widgetClass, renderer, superclasses, init, props){
+	// summary: Create a widget constructor function (aka widgetClass)
+	// widgetClass: String
+	//		the location in the object hierarchy to place the new widget class constructor
+	// renderer: String
+	//		usually "html", determines when this delcaration will be used
+	// superclasses: Function||Function[]
+	//		can be either a single function or an array of functions to be
+	//		mixed in as superclasses. If an array, only the first will be used
+	//		to set prototype inheritance.
+	// init: Function
+	//		an optional constructor function. Will be called after superclasses are mixed in.
+	// props: Object
+	//		a map of properties and functions to extend the class prototype with
+
+	// This meta-function does parameter juggling for backward compat and overloading
+	// if 4th argument is a string, we are using the old syntax
+	// old sig: widgetClass, superclasses, props (object), renderer (string), init (function)
+	if(dojo.lang.isString(arguments[3])){
+		dojo.widget._defineWidget(arguments[0], arguments[3], arguments[1], arguments[4], arguments[2]);
+	}else{
+		// widgetClass
+		var args = [ arguments[0] ], p = 3;
+		if(dojo.lang.isString(arguments[1])){
+			// renderer, superclass
+			args.push(arguments[1], arguments[2]);
+		}else{
+			// superclass
+			args.push('', arguments[1]);
+			p = 2;
+		}
+		if(dojo.lang.isFunction(arguments[p])){
+			// init (function), props (object) 
+			args.push(arguments[p], arguments[p+1]);
+		}else{
+			// props (object) 
+			args.push(null, arguments[p]);
+		}
+		dojo.widget._defineWidget.apply(this, args);
+	}
+}
+
+dojo.widget.defineWidget.renderers = "html|svg|vml";
+
+dojo.widget._defineWidget = function(widgetClass /*string*/, renderer /*string*/, superclasses /*function||array*/, init /*function*/, props /*object*/){
+	// FIXME: uncomment next line to test parameter juggling ... remove when confidence improves
+	// dojo.debug('(c:)' + widgetClass + '\n\n(r:)' + renderer + '\n\n(i:)' + init + '\n\n(p:)' + props);
+	// widgetClass takes the form foo.bar.baz<.renderer>.WidgetName (e.g. foo.bar.baz.WidgetName or foo.bar.baz.html.WidgetName)
+	var module = widgetClass.split(".");
+	var type = module.pop(); // type <= WidgetName, module <= foo.bar.baz<.renderer>
+	var regx = "\\.(" + (renderer ? renderer + '|' : '') + dojo.widget.defineWidget.renderers + ")\\.";
+	var r = widgetClass.search(new RegExp(regx));
+	module = (r < 0 ? module.join(".") : widgetClass.substr(0, r));
+
+	// deprecated in favor of namespace system, remove for 0.5
+	dojo.widget.manager.registerWidgetPackage(module);
+	
+	var pos = module.indexOf(".");
+	var nsName = (pos > -1) ? module.substring(0,pos) : module;
+
+	// FIXME: hrm, this might make things simpler
+	//dojo.widget.tags.addParseTreeHandler(nsName+":"+type.toLowerCase());
+	
+	props=(props)||{};
+	props.widgetType = type;
+	if((!init)&&(props["classConstructor"])){
+		init = props.classConstructor;
+		delete props.classConstructor;
+	}
+	dojo.declare(widgetClass, superclasses, init, props);
+}
+
+dojo.provide("dojo.widget.Parse");
+dojo.require("dojo.widget.Manager");
+dojo.require("dojo.dom");
+
+//
+// dojoML parser should be moved out of 'widget', codifying the difference between a 'component'
+// and a 'widget'. A 'component' being anything that can be generated from a tag.
+//
+// a particular dojoML tag would be handled by a registered tagHandler with a hook for a default handler
+// if the widget system is loaded, a widget builder would be attach itself as the default handler
+// 
+// widget tags are no longer registered themselves:
+// they are now arbitrarily namespaced, so we cannot register them all, and the non-prefixed portions 
+// are no longer guaranteed unique 
+// 
+// therefore dojo.widget.tags should go with this parser code out of the widget module
+//
+
+dojo.widget.Parse = function(/*Object*/fragment){
+	this.propertySetsList = [];
+	this.fragment = fragment;
+
+	this.createComponents = function(/*Object*/frag, /*Object*/parentComp){
+		var comps = [];
+		var built = false;
+		// if we have items to parse/create at this level, do it!
+		try{
+			if(frag && frag.tagName && (frag != frag.nodeRef)){
+				
+				// these are in fact, not ever for widgets per-se anymore, 
+				// but for other markup elements (aka components)
+				var djTags = dojo.widget.tags;
+				
+				// we split so that you can declare multiple 
+				// non-destructive components from the same ctor node
+				var tna = String(frag.tagName).split(";");
+				for(var x=0; x<tna.length; x++){
+					var ltn = tna[x].replace(/^\s+|\s+$/g, "").toLowerCase();
+					// FIXME: unsure what this does
+					frag.tagName = ltn;
+					var ret;
+					if(djTags[ltn]){
+						built = true;
+						ret = djTags[ltn](frag, this, parentComp, frag.index);
+						comps.push(ret);
+					}else{
+						// we require a namespace prefix, default to dojo:
+						if(ltn.indexOf(":") == -1){
+							ltn = "dojo:"+ltn;
+						}
+						// FIXME: handling failure condition correctly?
+						// ret = djTags[ltn](frag, this, parentComp, frag.index);
+						ret = dojo.widget.buildWidgetFromParseTree(ltn, frag, this, parentComp, frag.index);
+						if(ret){
+							built = true;
+							comps.push(ret);
+						}
+					}
+				}
+			}
+		}catch(e){
+			dojo.debug("dojo.widget.Parse: error:", e);
+			// note, commenting out the next line is breaking several widgets for me
+			// throw e;
+			// IE is such a pain sometimes
+		}
+		// if there's a sub-frag, build widgets from that too
+		if(!built){
+			comps = comps.concat(this.createSubComponents(frag, parentComp));
+		}
+		return comps; // Array
+	}
+
+	this.createSubComponents = function(/*Object*/fragment, /*Object*/parentComp){
+		// summary: recurses over a raw JavaScript object structure,
+		// and calls the corresponding handler for its normalized tagName if it exists
+
+		var frag, comps = [];
+		for(var item in fragment){
+			frag = fragment[item];
+			if(frag && typeof frag == "object"
+				&&(frag!=fragment.nodeRef)
+				&&(frag!=fragment.tagName)
+				&&(!dojo.dom.isNode(frag))){// needed in IE when we have event.connected to the domNode
+				comps = comps.concat(this.createComponents(frag, parentComp));
+			}
+		}
+		return comps; // Array
+	}
+
+	this.parsePropertySets = function(/*Object*/fragment){
+		// summary: checks the top level of a raw JavaScript object
+		//	structure for any propertySets.  It stores an array of references to 
+		//	propertySets that it finds.
+		return [];
+		/*
+		var propertySets = [];
+		for(var item in fragment){
+			if((fragment[item]["tagName"] == "dojo:propertyset")){
+				propertySets.push(fragment[item]);
+			}
+		}
+		// FIXME: should we store these propertySets somewhere for later retrieval
+		this.propertySetsList.push(propertySets);
+		return propertySets;
+		*/
+	}
+
+	this.parseProperties = function(/*Object*/fragment){
+		// summary: parseProperties checks a raw JavaScript object structure for
+		//	properties, and returns a hash of properties that it finds.
+		var properties = {};
+		for(var item in fragment){
+			// FIXME: need to check for undefined?
+			// case: its a tagName or nodeRef
+			if((fragment[item] == fragment.tagName)||(fragment[item] == fragment.nodeRef)){
+				// do nothing
+			}else{
+				var frag = fragment[item];
+				if(frag.tagName && dojo.widget.tags[frag.tagName.toLowerCase()]){
+					// TODO: it isn't a property or property set, it's a fragment, 
+					// so do something else
+					// FIXME: needs to be a better/stricter check
+					// TODO: handle xlink:href for external property sets
+				}else if(frag[0] && frag[0].value!="" && frag[0].value!=null){
+					try{
+						// FIXME: need to allow more than one provider
+						if(item.toLowerCase() == "dataprovider"){
+							var _this = this;
+							this.getDataProvider(_this, frag[0].value);
+							properties.dataProvider = this.dataProvider;
+						}
+						properties[item] = frag[0].value;
+						var nestedProperties = this.parseProperties(frag);
+						// FIXME: this kind of copying is expensive and inefficient!
+						for(var property in nestedProperties){
+							properties[property] = nestedProperties[property];
+						}
+					}catch(e){ dojo.debug(e); }
+				}
+				switch(item.toLowerCase()){
+				case "checked":
+				case "disabled":
+					if (typeof properties[item] != "boolean"){ 
+						properties[item] = true;
+					}
+					break;
+				}
+			} 
+		}
+		return properties; // Object
+	}
+
+	this.getDataProvider = function(/*Object*/objRef, /*String*/dataUrl){
+		// FIXME: this is currently sync.  To make this async, we made need to move 
+		//this step into the widget ctor, so that it is loaded when it is needed 
+		// to populate the widget
+		dojo.io.bind({
+			url: dataUrl,
+			load: function(type, evaldObj){
+				if(type=="load"){
+					objRef.dataProvider = evaldObj;
+				}
+			},
+			mimetype: "text/javascript",
+			sync: true
+		});
+	}
+
+	this.getPropertySetById = function(propertySetId){
+		// summary: returns the propertySet that matches the provided id
+		for(var x = 0; x < this.propertySetsList.length; x++){
+			if(propertySetId == this.propertySetsList[x]["id"][0].value){
+				return this.propertySetsList[x];
+			}
+		}
+		return ""; // String
+	}
+	
+	//FIXME: doesn't use the componentType param?
+	this.getPropertySetsByType = function(componentType){
+		// summary: returns the propertySet(s) that match(es) the
+	 	// provided componentClass
+
+		var propertySets = [];
+		for(var x=0; x < this.propertySetsList.length; x++){
+			var cpl = this.propertySetsList[x];
+			var cpcc = cpl.componentClass || cpl.componentType || null; //FIXME: is componentType supposed to be an indirect reference?
+			var propertySetId = this.propertySetsList[x]["id"][0].value;
+			if(cpcc && (propertySetId == cpcc[0].value)){
+				propertySets.push(cpl);
+			}
+		}
+		return propertySets; // Array
+	}
+
+	this.getPropertySets = function(/*Object*/fragment){
+		// summary: returns the propertySet for a given component fragment
+
+		var ppl = "dojo:propertyproviderlist";
+		var propertySets = [];
+		var tagname = fragment.tagName;
+		if(fragment[ppl]){ 
+			var propertyProviderIds = fragment[ppl].value.split(" ");
+			// FIXME: should the propertyProviderList attribute contain #
+			// 		  syntax for reference to ids or not?
+			// FIXME: need a better test to see if this is local or external
+			// FIXME: doesn't handle nested propertySets, or propertySets that
+			// 		  just contain information about css documents, etc.
+			for(var propertySetId in propertyProviderIds){
+				if((propertySetId.indexOf("..")==-1)&&(propertySetId.indexOf("://")==-1)){
+					// get a reference to a propertySet within the current parsed structure
+					var propertySet = this.getPropertySetById(propertySetId);
+					if(propertySet != ""){
+						propertySets.push(propertySet);
+					}
+				}else{
+					// FIXME: add code to parse and return a propertySet from
+					// another document
+					// alex: is this even necessaray? Do we care? If so, why?
+				}
+			}
+		}
+		// we put the typed ones first so that the parsed ones override when
+		// iteration happens.
+		return this.getPropertySetsByType(tagname).concat(propertySets); // Array
+	}
+
+	this.createComponentFromScript = function(/*Node*/nodeRef, /*String*/componentName, /*Object*/properties, /*String?*/ns){
+		// summary:
+		// nodeRef: the node to be replaced... in the future, we might want to add 
+		// an alternative way to specify an insertion point
+		// componentName: the expected dojo widget name, i.e. Button of ContextMenu
+		// properties: an object of name value pairs
+		// ns: the namespace of the widget.  Defaults to "dojo"
+
+		properties.fastMixIn = true;			
+		// FIXME: we pulled it apart and now we put it back together ... 
+		var ltn = (ns || "dojo") + ":" + componentName.toLowerCase();
+		if(dojo.widget.tags[ltn]){
+			return [dojo.widget.tags[ltn](properties, this, null, null, properties)]; // Array
+		}
+		return [dojo.widget.buildWidgetFromParseTree(ltn, properties, this, null, null, properties)]; // Array
+	}
+}
+
+dojo.widget._parser_collection = {"dojo": new dojo.widget.Parse() };
+
+dojo.widget.getParser = function(/*String?*/name){
+	if(!name){ name = "dojo"; }
+	if(!this._parser_collection[name]){
+		this._parser_collection[name] = new dojo.widget.Parse();
+	}
+	return this._parser_collection[name];
+}
+
+dojo.widget.createWidget = function(/*String*/name, /*String*/props, /*Node*/refNode, /*String*/position){
+	// summary: Creates widget
+	// name: The name of the widget to create with optional namespace prefix,
+	//	e.g."ns:widget", namespace defaults to "dojo".
+	// props: Key-Value pairs of properties of the widget
+	// refNode: If the position argument is specified, this node is used as
+	//	a reference for inserting this node into a DOM tree; else
+	//	the widget becomes the domNode
+	// position: The position to insert this widget's node relative to the
+	//	refNode argument
+
+	var isNode = false;
+	var isNameStr = (typeof name == "string");
+	if(isNameStr){
+		var pos = name.indexOf(":");
+		var ns = (pos > -1) ? name.substring(0,pos) : "dojo";
+		if(pos > -1){ name = name.substring(pos+1); }
+		var lowerCaseName = name.toLowerCase();
+		var namespacedName = ns + ":" + lowerCaseName;
+		isNode = (dojo.byId(name) && !dojo.widget.tags[namespacedName]); 
+	}
+
+	if((arguments.length == 1) && (isNode || !isNameStr)){
+		// we got a DOM node 
+		var xp = new dojo.xml.Parse(); 
+		// FIXME: we should try to find the parent! 
+		var tn = isNode ? dojo.byId(name) : name; 
+		return dojo.widget.getParser().createComponents(xp.parseElement(tn, null, true))[0]; 
+	}
+
+	function fromScript(placeKeeperNode, name, props, ns){
+		props[namespacedName] = { 
+			dojotype: [{value: lowerCaseName}],
+			nodeRef: placeKeeperNode,
+			fastMixIn: true
+		};
+		props.ns = ns;
+		return dojo.widget.getParser().createComponentFromScript(placeKeeperNode, name, props, ns);
+	}
+
+	props = props||{};
+	var notRef = false;
+	var tn = null;
+	var h = dojo.render.html.capable;
+	if(h){
+		tn = document.createElement("span");
+	}
+	if(!refNode){
+		notRef = true;
+		refNode = tn;
+		if(h){
+			dojo.body().appendChild(refNode);
+		}
+	}else if(position){
+		dojo.dom.insertAtPosition(tn, refNode, position);
+	}else{ // otherwise don't replace, but build in-place
+		tn = refNode;
+	}
+	var widgetArray = fromScript(tn, name.toLowerCase(), props, ns);
+	if(	(!widgetArray)||(!widgetArray[0])||
+		(typeof widgetArray[0].widgetType == "undefined") ){
+		throw new Error("createWidget: Creation of \"" + name + "\" widget failed.");
+	}
+	try{
+		if(notRef && widgetArray[0].domNode.parentNode){
+			widgetArray[0].domNode.parentNode.removeChild(widgetArray[0].domNode);
+		}
+	}catch(e){
+		/* squelch for Safari */
+		dojo.debug(e);
+	}
+	return widgetArray[0]; // Widget
+}
+
+dojo.kwCompoundRequire({
+	common: [["dojo.uri.Uri", false, false]]
+});
+dojo.provide("dojo.uri.*");
+
+dojo.provide("dojo.widget.DomWidget");
+
+dojo.require("dojo.event.*");
+
+dojo.require("dojo.dom");
+dojo.require("dojo.html.style");
+
+
+dojo.require("dojo.lang.func");
+dojo.require("dojo.lang.extras");
+
+dojo.widget._cssFiles = {};
+dojo.widget._cssStrings = {};
+dojo.widget._templateCache = {};
+
+dojo.widget.defaultStrings = {
+	// summary: a mapping of strings that are used in template variable replacement
+	dojoRoot: dojo.hostenv.getBaseScriptUri(),
+	dojoWidgetModuleUri: dojo.uri.moduleUri("dojo.widget"),
+	baseScriptUri: dojo.hostenv.getBaseScriptUri()
+};
+
+dojo.widget.fillFromTemplateCache = function(obj, templatePath, templateString, avoidCache){
+	// summary:
+	//		static method to build from a template w/ or w/o a real widget in
+	//		place
+	// obj: DomWidget
+	//		an instance of dojo.widget.DomWidget to initialize the template for
+	// templatePath: String
+	//		the URL to get the template from. dojo.uri.Uri is often passed as well.
+	// templateString: String?
+	//		a string to use in lieu of fetching the template from a URL
+	// avoidCache: Boolean?
+	//		should the template system not use whatever is in the cache and
+	//		always use the passed templatePath or templateString?
+
+	// dojo.debug("avoidCache:", avoidCache);
+	var tpath = templatePath || obj.templatePath;
+
+	var tmplts = dojo.widget._templateCache;
+	if(!tpath && !obj["widgetType"]) { // don't have a real template here
+		do {
+			var dummyName = "__dummyTemplate__" + dojo.widget._templateCache.dummyCount++;
+		} while(tmplts[dummyName]);
+		obj.widgetType = dummyName;
+	}
+	var wt = tpath?tpath.toString():obj.widgetType;
+
+	var ts = tmplts[wt];
+	if(!ts){
+		tmplts[wt] = {"string": null, "node": null};
+		if(avoidCache){
+			ts = {};
+		}else{
+			ts = tmplts[wt];
+		}
+	}
+
+	if((!obj.templateString)&&(!avoidCache)){
+		obj.templateString = templateString || ts["string"];
+	}
+	if(obj.templateString){
+		obj.templateString = this._sanitizeTemplateString(obj.templateString);
+	}
+
+	if((!obj.templateNode)&&(!avoidCache)){
+		obj.templateNode = ts["node"];
+	}
+	if((!obj.templateNode)&&(!obj.templateString)&&(tpath)){
+		// fetch a text fragment and assign it to templateString
+		// NOTE: we rely on blocking IO here!
+		var tstring = this._sanitizeTemplateString(dojo.hostenv.getText(tpath));
+
+		obj.templateString = tstring;
+		if(!avoidCache){
+			tmplts[wt]["string"] = tstring;
+		}
+	}
+	if((!ts["string"])&&(!avoidCache)){
+		ts.string = obj.templateString;
+	}
+}
+
+dojo.widget._sanitizeTemplateString = function(/*String*/tString){
+	//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.
+	if(tString){
+		tString = tString.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
+		var matches = tString.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
+		if(matches){
+			tString = matches[1];
+		}
+	}else{
+		tString = "";
+	}
+	return tString; //String
+}
+
+dojo.widget._templateCache.dummyCount = 0;
+
+// Array: list of properties to search for node-to-property mappings
+dojo.widget.attachProperties = ["dojoAttachPoint", "id"];
+
+// String: name of the property to use for mapping DOM events to widget functions
+dojo.widget.eventAttachProperty = "dojoAttachEvent";
+
+// String: property name of code to evaluate when the widget is constructed
+dojo.widget.onBuildProperty = "dojoOnBuild";
+
+// Array:  possible accessibility values to set on widget elements - role or state
+dojo.widget.waiNames  = ["waiRole", "waiState"];
+
+dojo.widget.wai = {
+	// summary: Contains functions to set accessibility roles and states
+	//		onto widget elements
+	waiRole: { 	
+				// name: String:
+				//		information for mapping accessibility role
+				name: "waiRole", 
+				// namespace: String:
+				//		URI of the namespace for the set of roles
+				"namespace": "http://www.w3.org/TR/xhtml2", 
+				// alias: String:
+				//		The alias to assign the namespace
+				alias: "x2",
+				// prefix: String:
+				//		The prefix to assign to the role value
+				prefix: "wairole:"
+	},
+	waiState: { 
+				// name: String:
+				//		information for mapping accessibility state
+				name: "waiState", 
+				// namespace: String:
+				//		URI of the namespace for the set of states
+				"namespace": "http://www.w3.org/2005/07/aaa", 
+				// alias: String:
+				//		The alias to assign the namespace
+				alias: "aaa",
+				// prefix: String:
+				//		empty string - state value does not require prefix
+				prefix: ""
+	},
+	setAttr: function(/*DomNode*/node, /*String*/ ns, /*String*/ attr, /*String|Boolean*/value){
+		// summary: Use appropriate API to set the role or state attribute onto the element.
+		// description: In IE use the generic setAttribute() api.  Append a namespace
+		//   alias to the attribute name and appropriate prefix to the value. 
+		//   Otherwise, use the setAttribueNS api to set the namespaced attribute. Also
+		//   add the appropriate prefix to the attribute value.
+		if(dojo.render.html.ie){
+			node.setAttribute(this[ns].alias+":"+ attr, this[ns].prefix+value);
+		}else{
+			node.setAttributeNS(this[ns]["namespace"], attr, this[ns].prefix+value);
+		}
+	},
+
+	getAttr: function(/*DomNode*/ node, /*String*/ ns, /*String|Boolena*/ attr){
+		// Summary:  Use the appropriate API to retrieve the role or state value
+		// Description: In IE use the generic getAttribute() api.  An alias value 
+		// 	was added to the attribute name to simulate a namespace when the attribute
+		//  was set.  Otherwise use the getAttributeNS() api to retrieve the state value
+		if(dojo.render.html.ie){
+			return node.getAttribute(this[ns].alias+":"+attr);
+		}else{
+			return node.getAttributeNS(this[ns]["namespace"], attr);
+		}
+	},
+	removeAttr: function(/*DomNode*/ node, /*String*/ ns, /*String|Boolena*/ attr){
+		// summary:  Use the appropriate API to remove the role or state value
+		// description: In IE use the generic removeAttribute() api.  An alias value 
+		// 	was added to the attribute name to simulate a namespace when the attribute
+		//  was set.  Otherwise use the removeAttributeNS() api to remove the state value
+		var success = true; //only IE returns a value
+		if(dojo.render.html.ie){
+			 success = node.removeAttribute(this[ns].alias+":"+attr);
+		}else{
+			node.removeAttributeNS(this[ns]["namespace"], attr);
+		}
+		return success;
+	}
+};
+
+dojo.widget.attachTemplateNodes = function(rootNode, /*Widget*/ targetObj, events ){
+	// summary:
+	//		map widget properties and functions to the handlers specified in
+	//		the dom node and it's descendants. This function iterates over all
+	//		nodes and looks for these properties:
+	//			* dojoAttachPoint
+	//			* dojoAttachEvent	
+	//			* waiRole
+	//			* waiState
+	//			* any "dojoOn*" proprties passed in the events array
+	// rootNode: DomNode
+	//		the node to search for properties. All children will be searched.
+	// events: Array
+	//		a list of properties generated from getDojoEventsFromStr.
+
+	// FIXME: this method is still taking WAAAY too long. We need ways of optimizing:
+	//	a.) what we are looking for on each node
+	//	b.) the nodes that are subject to interrogation (use xpath instead?)
+	//	c.) how expensive event assignment is (less eval(), more connect())
+	// var start = new Date();
+	var elementNodeType = dojo.dom.ELEMENT_NODE;
+
+	function trim(str){
+		return str.replace(/^\s+|\s+$/g, "");
+	}
+
+	if(!rootNode){ 
+		rootNode = targetObj.domNode;
+	}
+
+	if(rootNode.nodeType != elementNodeType){
+		return;
+	}
+	// alert(events.length);
+
+	var nodes = rootNode.all || rootNode.getElementsByTagName("*");
+	var _this = targetObj;
+	for(var x=-1; x<nodes.length; x++){
+		var baseNode = (x == -1) ? rootNode : nodes[x];
+		// FIXME: is this going to have capitalization problems?  Could use getAttribute(name, 0); to get attributes case-insensitve
+		var attachPoint = [];
+		if(!targetObj.widgetsInTemplate || !baseNode.getAttribute('dojoType')){
+			for(var y=0; y<this.attachProperties.length; y++){
+				var tmpAttachPoint = baseNode.getAttribute(this.attachProperties[y]);
+				if(tmpAttachPoint){
+					attachPoint = tmpAttachPoint.split(";");
+					for(var z=0; z<attachPoint.length; z++){
+						if(dojo.lang.isArray(targetObj[attachPoint[z]])){
+							targetObj[attachPoint[z]].push(baseNode);
+						}else{
+							targetObj[attachPoint[z]]=baseNode;
+						}
+					}
+					break;
+				}
+			}
+
+			var attachEvent = baseNode.getAttribute(this.eventAttachProperty);
+			if(attachEvent){
+				// NOTE: we want to support attributes that have the form
+				// "domEvent: nativeEvent; ..."
+				var evts = attachEvent.split(";");
+				for(var y=0; y<evts.length; y++){
+					if((!evts[y])||(!evts[y].length)){ continue; }
+					var thisFunc = null;
+					var tevt = trim(evts[y]);
+					if(evts[y].indexOf(":") >= 0){
+						// oh, if only JS had tuple assignment
+						var funcNameArr = tevt.split(":");
+						tevt = trim(funcNameArr[0]);
+						thisFunc = trim(funcNameArr[1]);
+					}
+					if(!thisFunc){
+						thisFunc = tevt;
+					}
+	
+					var tf = function(){ 
+						var ntf = new String(thisFunc);
+						return function(evt){
+							if(_this[ntf]){
+								_this[ntf](dojo.event.browser.fixEvent(evt, this));
+							}
+						};
+					}();
+					dojo.event.browser.addListener(baseNode, tevt, tf, false, true);
+					// dojo.event.browser.addListener(baseNode, tevt, dojo.lang.hitch(_this, thisFunc));
+				}
+			}
+	
+			for(var y=0; y<events.length; y++){
+				//alert(events[x]);
+				var evtVal = baseNode.getAttribute(events[y]);
+				if((evtVal)&&(evtVal.length)){
+					var thisFunc = null;
+					var domEvt = events[y].substr(4); // clober the "dojo" prefix
+					thisFunc = trim(evtVal);
+					var funcs = [thisFunc];
+					if(thisFunc.indexOf(";")>=0){
+						funcs = dojo.lang.map(thisFunc.split(";"), trim);
+					}
+					for(var z=0; z<funcs.length; z++){
+						if(!funcs[z].length){ continue; }
+						var tf = function(){ 
+							var ntf = new String(funcs[z]);
+							return function(evt){
+								if(_this[ntf]){
+									_this[ntf](dojo.event.browser.fixEvent(evt, this));
+								}
+							}
+						}();
+						dojo.event.browser.addListener(baseNode, domEvt, tf, false, true);
+						// dojo.event.browser.addListener(baseNode, domEvt, dojo.lang.hitch(_this, funcs[z]));
+					}
+				}
+			}
+		}
+		// continue;
+
+		// FIXME: we need to put this into some kind of lookup structure
+		// instead of direct assignment
+		var tmpltPoint = baseNode.getAttribute(this.templateProperty);
+		if(tmpltPoint){
+			targetObj[tmpltPoint]=baseNode;
+		}
+
+		dojo.lang.forEach(dojo.widget.waiNames, function(name){
+			var wai = dojo.widget.wai[name];
+			var val = baseNode.getAttribute(wai.name);
+			if(val){
+				if(val.indexOf('-') == -1){ 
+					dojo.widget.wai.setAttr(baseNode, wai.name, "role", val);
+				}else{
+					// this is a state-value pair
+					var statePair = val.split('-');
+					dojo.widget.wai.setAttr(baseNode, wai.name, statePair[0], statePair[1]);
+				}
+			}
+		}, this);
+
+		var onBuild = baseNode.getAttribute(this.onBuildProperty);
+		if(onBuild){
+			eval("var node = baseNode; var widget = targetObj; "+onBuild);
+		}
+	}
+
+}
+
+dojo.widget.getDojoEventsFromStr = function(str){
+	// summary:
+	//		generates a list of properties with names that match the form
+	//		dojoOn*
+	// str: String
+	//		the template string to search
+	
+	// var lstr = str.toLowerCase();
+	var re = /(dojoOn([a-z]+)(\s?))=/gi;
+	var evts = str ? str.match(re)||[] : [];
+	var ret = [];
+	var lem = {};
+	for(var x=0; x<evts.length; x++){
+		if(evts[x].length < 1){ continue; }
+		var cm = evts[x].replace(/\s/, "");
+		cm = (cm.slice(0, cm.length-1));
+		if(!lem[cm]){
+			lem[cm] = true;
+			ret.push(cm);
+		}
+	}
+	return ret; // Array
+}
+
+dojo.declare("dojo.widget.DomWidget", 
+	dojo.widget.Widget,
+	function(){
+		// summary:
+		//		dojo.widget.DomWidget is the superclass that provides behavior for all
+		//		DOM-based renderers, including HtmlWidget and SvgWidget. DomWidget
+		//		implements the templating system that most widget authors use to define
+		//		the UI for their widgets.
+		if((arguments.length>0)&&(typeof arguments[0] == "object")){
+			this.create(arguments[0]);
+		}
+	},
+	{							 
+		// templateNode: DomNode
+		//		a node that represents the widget template. Pre-empts both templateString and templatePath.
+		templateNode: null,
+
+		// templateString String:
+		//		a string that represents the widget template. Pre-empts the
+		//		templatePath. In builds that have their strings "interned", the
+		//		templatePath is converted to an inline templateString, thereby
+		//		preventing a synchronous network call.
+		templateString: null,
+
+		// templateCssString String:
+		//		a string that represents the CSS for the widgettemplate.
+		//		Pre-empts the templateCssPath. In builds that have their
+		//		strings "interned", the templateCssPath is converted to an
+		//		inline templateCssString, thereby preventing a synchronous
+		//		network call.
+		templateCssString: null,
+
+		// preventClobber Boolean:
+		//		should the widget not replace the node from which it was
+		//		constructed? Widgets that apply behaviors to pre-existing parts
+		//		of a page can be implemented easily by setting this to "true".
+		//		In these cases, the domNode property will point to the node
+		//		which the widget was created from.
+		preventClobber: false,
+
+		// domNode DomNode:
+		//		this is our visible representation of the widget! Other DOM
+		//		Nodes may by assigned to other properties, usually through the
+		//		template system's dojoAttachPonit syntax, but the domNode
+		//		property is the canonical "top level" node in widget UI.
+		domNode: null, 
+
+		// containerNode DomNode:
+		//		holds child elements. "containerNode" is generally set via a
+		//		dojoAttachPoint assignment and it designates where widgets that
+		//		are defined as "children" of the parent will be placed
+		//		visually.
+		containerNode: null,
+
+		// widgetsInTemplate Boolean:
+		//		should we parse the template to find widgets that might be
+		//		declared in markup inside it? false by default.
+		widgetsInTemplate: false,
+
+		addChild: function(/*Widget*/	widget, overrideContainerNode, pos, ref, insertIndex){
+			// summary:
+			//		Process the given child widget, inserting it's dom node as
+			//		a child of our dom node
+			// overrideContainerNode: DomNode?
+			//		a non-default container node for the widget
+			// pos: String?
+			//		can be one of "before", "after", "first", or "last". This
+			//		has the same meaning as in dojo.dom.insertAtPosition()
+			// ref: DomNode?
+			//		a node to place the widget relative to
+			// insertIndex: int?
+			//		DOM index, same meaning as in dojo.dom.insertAtIndex()
+			// returns: the widget that was inserted
+
+			// FIXME: should we support addition at an index in the children arr and
+			// order the display accordingly? Right now we always append.
+			if(!this.isContainer){ // we aren't allowed to contain other widgets, it seems
+				dojo.debug("dojo.widget.DomWidget.addChild() attempted on non-container widget");
+				return null;
+			}else{
+				if(insertIndex == undefined){
+					insertIndex = this.children.length;
+				}
+				this.addWidgetAsDirectChild(widget, overrideContainerNode, pos, ref, insertIndex);
+				this.registerChild(widget, insertIndex);
+			}
+			return widget; // Widget
+		},
+		
+		addWidgetAsDirectChild: function(/*Widget*/	widget, overrideContainerNode, pos, ref, insertIndex){
+			// summary:
+			//		Process the given child widget, inserting it's dom node as
+			//		a child of our dom node
+			// overrideContainerNode: DomNode
+			//		a non-default container node for the widget
+			// pos: String?
+			//		can be one of "before", "after", "first", or "last". This
+			//		has the same meaning as in dojo.dom.insertAtPosition()
+			// ref: DomNode?
+			//		a node to place the widget relative to
+			// insertIndex: int?
+			//		DOM index, same meaning as in dojo.dom.insertAtIndex()
+			if((!this.containerNode)&&(!overrideContainerNode)){
+				this.containerNode = this.domNode;
+			}
+			var cn = (overrideContainerNode) ? overrideContainerNode : this.containerNode;
+			if(!pos){ pos = "after"; }
+			if(!ref){ 
+				if(!cn){ cn = dojo.body(); }
+				ref = cn.lastChild; 
+			}
+			if(!insertIndex) { insertIndex = 0; }
+			widget.domNode.setAttribute("dojoinsertionindex", insertIndex);
+
+			// insert the child widget domNode directly underneath my domNode, in the
+			// specified position (by default, append to end)
+			if(!ref){
+				cn.appendChild(widget.domNode);
+			}else{
+				// FIXME: was this meant to be the (ugly hack) way to support insert @ index?
+				//dojo.dom[pos](widget.domNode, ref, insertIndex);
+
+				// CAL: this appears to be the intended way to insert a node at a given position...
+				if (pos == 'insertAtIndex'){
+					// dojo.debug("idx:", insertIndex, "isLast:", ref === cn.lastChild);
+					dojo.dom.insertAtIndex(widget.domNode, ref.parentNode, insertIndex);
+				}else{
+					// dojo.debug("pos:", pos, "isLast:", ref === cn.lastChild);
+					if((pos == "after")&&(ref === cn.lastChild)){
+						cn.appendChild(widget.domNode);
+					}else{
+						dojo.dom.insertAtPosition(widget.domNode, cn, pos);
+					}
+				}
+			}
+		},
+
+		registerChild: function(widget, insertionIndex){
+			// summary: record that given widget descends from me
+			// widget: Widget
+			//		the widget that is now a child
+			// insertionIndex: int
+			//		where in the children[] array to place it
+
+			// we need to insert the child at the right point in the parent's 
+			// 'children' array, based on the insertionIndex
+
+			widget.dojoInsertionIndex = insertionIndex;
+
+			var idx = -1;
+			for(var i=0; i<this.children.length; i++){
+
+				//This appears to fix an out of order issue in the case of mixed
+				//markup and programmatically added children.  Previously, if a child
+				//existed from markup, and another child was addChild()d without specifying
+				//any additional parameters, it would end up first in the list, when in fact
+				//it should be after.  I can't see cases where this would break things, but
+				//I could see no other obvious solution. -dustin
+
+				if (this.children[i].dojoInsertionIndex <= insertionIndex){
+					idx = i;
+				}
+			}
+
+			this.children.splice(idx+1, 0, widget);
+
+			widget.parent = this;
+			widget.addedTo(this, idx+1);
+			
+			// If this widget was created programatically, then it was erroneously added
+			// to dojo.widget.manager.topWidgets.  Fix that here.
+			delete dojo.widget.manager.topWidgets[widget.widgetId];
+		},
+
+		removeChild: function(/*Widget*/ widget){
+			// summary: detach child domNode from parent domNode
+			dojo.dom.removeNode(widget.domNode);
+
+			// remove child widget from parent widget 
+			return dojo.widget.DomWidget.superclass.removeChild.call(this, widget); // Widget
+		},
+
+		getFragNodeRef: function(frag){
+			// summary:
+			//		returns the source node, if any, that the widget was
+			//		declared from
+			// frag: Object
+			//		an opaque data structure generated by the first-pass parser
+			if(!frag){return null;} // null
+			if(!frag[this.getNamespacedType()]){
+				dojo.raise("Error: no frag for widget type " + this.getNamespacedType() 
+					+ ", id " + this.widgetId
+					+ " (maybe a widget has set it's type incorrectly)");
+			}
+			return frag[this.getNamespacedType()]["nodeRef"]; // DomNode
+		},
+		
+		postInitialize: function(/*Object*/ args, /*Object*/ frag, /*Widget*/ parentComp){
+			// summary:
+			//		Replace the source domNode with the generated dom
+			//		structure, and register the widget with its parent.
+			//		This is an implementation of the stub function defined in
+			//		dojo.widget.Widget.
+			
+			//dojo.profile.start(this.widgetType + " postInitialize");
+			
+			var sourceNodeRef = this.getFragNodeRef(frag);
+			// Stick my generated dom into the output tree
+			//alert(this.widgetId + ": replacing " + sourceNodeRef + " with " + this.domNode.innerHTML);
+			if (parentComp && (parentComp.snarfChildDomOutput || !sourceNodeRef)){
+				// Add my generated dom as a direct child of my parent widget
+				// This is important for generated widgets, and also cases where I am generating an
+				// <li> node that can't be inserted back into the original DOM tree
+				parentComp.addWidgetAsDirectChild(this, "", "insertAtIndex", "",  args["dojoinsertionindex"], sourceNodeRef);
+			} else if (sourceNodeRef){
+				// Do in-place replacement of the my source node with my generated dom
+				if(this.domNode && (this.domNode !== sourceNodeRef)){
+					this._sourceNodeRef = dojo.dom.replaceNode(sourceNodeRef, this.domNode);
+				}
+			}
+
+			// Register myself with my parent, or with the widget manager if
+			// I have no parent
+			// TODO: the code below erroneously adds all programatically generated widgets
+			// to topWidgets (since we don't know who the parent is until after creation finishes)
+			if ( parentComp ) {
+				parentComp.registerChild(this, args.dojoinsertionindex);
+			} else {
+				dojo.widget.manager.topWidgets[this.widgetId]=this;
+			}
+
+			if(this.widgetsInTemplate){
+				var parser = new dojo.xml.Parse();
+
+				var subContainerNode;
+				//TODO: use xpath here?
+				var subnodes = this.domNode.getElementsByTagName("*");
+				for(var i=0;i<subnodes.length;i++){
+					if(subnodes[i].getAttribute('dojoAttachPoint') == 'subContainerWidget'){
+						subContainerNode = subnodes[i];
+//						break;
+					}
+					if(subnodes[i].getAttribute('dojoType')){
+						subnodes[i].setAttribute('isSubWidget', true);
+					}
+				}
+				if (this.isContainer && !this.containerNode){
+					//no containerNode is available, which means a widget is used as a container. find it here and move
+					//all dom nodes defined in the main html page as children of this.domNode into the actual container
+					//widget's node (at this point, the subwidgets defined in the template file is not parsed yet)
+					if(subContainerNode){
+						var src = this.getFragNodeRef(frag);
+						if (src){
+							dojo.dom.moveChildren(src, subContainerNode);
+							//do not need to follow children nodes in the main html page, as they
+							//will be dealt with in the subContainerWidget
+							frag['dojoDontFollow'] = true;
+						}
+					}else{
+						dojo.debug("No subContainerWidget node can be found in template file for widget "+this);
+					}
+				}
+
+				var templatefrag = parser.parseElement(this.domNode, null, true);
+				// createSubComponents not createComponents because frag has already been created
+				dojo.widget.getParser().createSubComponents(templatefrag, this);
+	
+				//find all the sub widgets defined in the template file of this widget
+				var subwidgets = [];
+				var stack = [this];
+				var w;
+				while((w = stack.pop())){
+					for(var i = 0; i < w.children.length; i++){
+						var cwidget = w.children[i];
+						if(cwidget._processedSubWidgets || !cwidget.extraArgs['issubwidget']){ continue; }
+						subwidgets.push(cwidget);
+						if(cwidget.isContainer){
+							stack.push(cwidget);
+						}
+					}
+				}
+	
+				//connect event to this widget/attach dom node
+				for(var i = 0; i < subwidgets.length; i++){
+					var widget = subwidgets[i];
+					if(widget._processedSubWidgets){
+						dojo.debug("This should not happen: widget._processedSubWidgets is already true!");
+						return;
+					}
+					widget._processedSubWidgets = true;
+					if(widget.extraArgs['dojoattachevent']){
+						var evts = widget.extraArgs['dojoattachevent'].split(";");
+						for(var j=0; j<evts.length; j++){
+							var thisFunc = null;
+							var tevt = dojo.string.trim(evts[j]);
+							if(tevt.indexOf(":") >= 0){
+								// oh, if only JS had tuple assignment
+								var funcNameArr = tevt.split(":");
+								tevt = dojo.string.trim(funcNameArr[0]);
+								thisFunc = dojo.string.trim(funcNameArr[1]);
+							}
+							if(!thisFunc){
+								thisFunc = tevt;
+							}
+							if(dojo.lang.isFunction(widget[tevt])){
+								dojo.event.kwConnect({
+									srcObj: widget, 
+									srcFunc: tevt, 
+									targetObj: this, 
+									targetFunc: thisFunc
+								});
+							}else{
+								alert(tevt+" is not a function in widget "+widget);
+							}
+						}
+					}
+	
+					if(widget.extraArgs['dojoattachpoint']){
+						//don't attach widget.domNode here, as we do not know which
+						//dom node we should connect to (in checkbox widget case, 
+						//it is inputNode). So we make the widget itself available
+						this[widget.extraArgs['dojoattachpoint']] = widget;
+					}
+				}
+			}
+
+			//dojo.profile.end(this.widgetType + " postInitialize");
+
+			// Expand my children widgets
+			/* dojoDontFollow is important for a very special case
+			 * basically if you have a widget that you instantiate from script
+			 * and that widget is a container, and it contains a reference to a parent
+			 * instance, the parser will start recursively parsing until the browser
+			 * complains.  So the solution is to set an initialization property of 
+			 * dojoDontFollow: true and then it won't recurse where it shouldn't
+			 */
+			if(this.isContainer && !frag["dojoDontFollow"]){
+				//alert("recurse from " + this.widgetId);
+				// build any sub-components with us as the parent
+				dojo.widget.getParser().createSubComponents(frag, this);
+			}
+		},
+
+		// method over-ride
+		buildRendering: function(/*Object*/ args, /*Object*/ frag){
+			// summary:
+			//		Construct the UI for this widget, generally from a
+			//		template. This can be over-ridden for custom UI creation to
+			//		to side-step the template system.  This is an
+			//		implementation of the stub function defined in
+			//		dojo.widget.Widget.
+
+			// DOM widgets construct themselves from a template
+			var ts = dojo.widget._templateCache[this.widgetType];
+			
+			// Handle style for this widget here, as even if templatePath
+			// is not set, style specified by templateCssString or templateCssPath
+			// should be applied. templateCssString has higher priority
+			// than templateCssPath
+			if(args["templatecsspath"]){
+				args["templateCssPath"] = args["templatecsspath"];
+			}
+			var cpath = args["templateCssPath"] || this.templateCssPath;
+			if(cpath && !dojo.widget._cssFiles[cpath.toString()]){
+				if((!this.templateCssString)&&(cpath)){
+					this.templateCssString = dojo.hostenv.getText(cpath);
+					this.templateCssPath = null;
+				}
+				dojo.widget._cssFiles[cpath.toString()] = true;
+			}
+		
+			if((this["templateCssString"])&&(!dojo.widget._cssStrings[this.templateCssString])){
+				dojo.html.insertCssText(this.templateCssString, null, cpath);
+				dojo.widget._cssStrings[this.templateCssString] = true;
+			}
+			if(	
+				(!this.preventClobber)&&(
+					(this.templatePath)||
+					(this.templateNode)||
+					(
+						(this["templateString"])&&(this.templateString.length) 
+					)||
+					(
+						(typeof ts != "undefined")&&( (ts["string"])||(ts["node"]) )
+					)
+				)
+			){
+				// if it looks like we can build the thing from a template, do it!
+				this.buildFromTemplate(args, frag);
+			}else{
+				// otherwise, assign the DOM node that was the source of the widget
+				// parsing to be the root node
+				this.domNode = this.getFragNodeRef(frag);
+			}
+			this.fillInTemplate(args, frag); 	// this is where individual widgets
+												// will handle population of data
+												// from properties, remote data
+												// sets, etc.
+		},
+
+		buildFromTemplate: function(/*Object*/ args, /*Object*/ frag){
+			// summary:
+			//		Called by buildRendering, creates the actual UI in a DomWidget.
+
+			// var start = new Date();
+			// copy template properties if they're already set in the templates object
+			// dojo.debug("buildFromTemplate:", this);
+			var avoidCache = false;
+			if(args["templatepath"]){
+//				avoidCache = true;
+				args["templatePath"] = args["templatepath"];
+			}
+			dojo.widget.fillFromTemplateCache(	this, 
+												args["templatePath"], 
+												null,
+												avoidCache);
+			var ts = dojo.widget._templateCache[this.templatePath?this.templatePath.toString():this.widgetType];
+			if((ts)&&(!avoidCache)){
+				if(!this.templateString.length){
+					this.templateString = ts["string"];
+				}
+				if(!this.templateNode){
+					this.templateNode = ts["node"];
+				}
+			}
+			var matches = false;
+			var node = null;
+			// var tstr = new String(this.templateString); 
+			var tstr = this.templateString; 
+			// attempt to clone a template node, if there is one
+			if((!this.templateNode)&&(this.templateString)){
+				matches = this.templateString.match(/\$\{([^\}]+)\}/g);
+				if(matches) {
+					// if we do property replacement, don't create a templateNode
+					// to clone from.
+					var hash = this.strings || {};
+					// FIXME: should this hash of default replacements be cached in
+					// templateString?
+					for(var key in dojo.widget.defaultStrings) {
+						if(dojo.lang.isUndefined(hash[key])) {
+							hash[key] = dojo.widget.defaultStrings[key];
+						}
+					}
+					// FIXME: this is a lot of string munging. Can we make it faster?
+					for(var i = 0; i < matches.length; i++) {
+						var key = matches[i];
+						key = key.substring(2, key.length-1);
+						var kval = (key.substring(0, 5) == "this.") ? dojo.lang.getObjPathValue(key.substring(5), this) : hash[key];
+						var value;
+						if((kval)||(dojo.lang.isString(kval))){
+							value = new String((dojo.lang.isFunction(kval)) ? kval.call(this, key, this.templateString) : kval);
+							// Safer substitution, see heading "Attribute values" in  
+							// http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
+							while (value.indexOf("\"") > -1) {
+								value=value.replace("\"","&quot;");
+							}
+							tstr = tstr.replace(matches[i], value);
+						}
+					}
+				}else{
+					// otherwise, we are required to instantiate a copy of the template
+					// string if one is provided.
+					
+					// FIXME: need to be able to distinguish here what should be done
+					// or provide a generic interface across all DOM implementations
+					// FIMXE: this breaks if the template has whitespace as its first 
+					// characters
+					// node = this.createNodesFromText(this.templateString, true);
+					// this.templateNode = node[0].cloneNode(true); // we're optimistic here
+					this.templateNode = this.createNodesFromText(this.templateString, true)[0];
+					if(!avoidCache){
+						ts.node = this.templateNode;
+					}
+				}
+			}
+			if((!this.templateNode)&&(!matches)){ 
+				dojo.debug("DomWidget.buildFromTemplate: could not create template");
+				return false;
+			}else if(!matches){
+				node = this.templateNode.cloneNode(true);
+				if(!node){ return false; }
+			}else{
+				node = this.createNodesFromText(tstr, true)[0];
+			}
+
+			// recurse through the node, looking for, and attaching to, our
+			// attachment points which should be defined on the template node.
+
+			this.domNode = node;
+			// dojo.profile.start("attachTemplateNodes");
+			this.attachTemplateNodes();
+			// dojo.profile.end("attachTemplateNodes");
+		
+			// relocate source contents to templated container node
+			// this.containerNode must be able to receive children, or exceptions will be thrown
+			if (this.isContainer && this.containerNode){
+				var src = this.getFragNodeRef(frag);
+				if (src){
+					dojo.dom.moveChildren(src, this.containerNode);
+				}
+			}
+		},
+
+		attachTemplateNodes: function(baseNode, targetObj){
+			// summary: 
+			//		hooks up event handlers and property/node linkages. Calls
+			//		dojo.widget.attachTemplateNodes to do all the hard work.
+			// baseNode: DomNode
+			//		defaults to "this.domNode"
+			// targetObj: Widget
+			//		defaults to "this"
+			if(!baseNode){ baseNode = this.domNode; }
+			if(!targetObj){ targetObj = this; }
+			return dojo.widget.attachTemplateNodes(baseNode, targetObj, 
+						dojo.widget.getDojoEventsFromStr(this.templateString));
+		},
+
+		fillInTemplate: function(){
+			// summary:
+			//		stub function! sub-classes may use as a default UI
+			//		initializer function. The UI rendering will be available by
+			//		the time this is called from buildRendering. If
+			//		buildRendering is over-ridden, this function may not be
+			//		fired!
+
+			// dojo.unimplemented("dojo.widget.DomWidget.fillInTemplate");
+		},
+		
+		// method over-ride
+		destroyRendering: function(){
+			// summary: UI destructor.  Destroy the dom nodes associated w/this widget.
+			try{
+				dojo.dom.destroyNode(this.domNode);
+				delete this.domNode;
+			}catch(e){ /* squelch! */ }
+			if(this._sourceNodeRef){

[... 6157 lines stripped ...]