You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by js...@apache.org on 2009/03/19 11:37:20 UTC

svn commit: r755904 [27/40] - in /camel/trunk/components/camel-web/src/main/webapp/js/dojox: ./ analytics/ analytics/logger/ analytics/plugins/ analytics/profiles/ atom/ atom/io/ atom/widget/ atom/widget/nls/ atom/widget/nls/cs/ atom/widget/nls/de/ ato...

Added: camel/trunk/components/camel-web/src/main/webapp/js/dojox/grid/DataGrid.js.uncompressed.js
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/dojox/grid/DataGrid.js.uncompressed.js?rev=755904&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/dojox/grid/DataGrid.js.uncompressed.js (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/dojox/grid/DataGrid.js.uncompressed.js Thu Mar 19 10:37:00 2009
@@ -0,0 +1,9545 @@
+/*
+	Copyright (c) 2004-2009, 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
+*/
+
+/*
+	This is a compiled version of Dojo, built for deployment and not for
+	development. To get an editable version, please visit:
+
+		http://dojotoolkit.org
+
+	for documentation and information on getting the source.
+*/
+
+if(!dojo._hasResource["dijit._KeyNavContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._KeyNavContainer"] = true;
+dojo.provide("dijit._KeyNavContainer");
+
+
+dojo.declare("dijit._KeyNavContainer",
+	[dijit._Container],
+	{
+
+		// summary:
+		//		A _Container with keyboard navigation of its children.
+		// description:
+		//		To use this mixin, call connectKeyNavHandlers() in
+		//		postCreate() and call startupKeyNavChildren() in startup().
+		//		It provides normalized keyboard and focusing code for Container
+		//		widgets.
+/*=====
+		// focusedChild: [protected] Widget
+		//		The currently focused child widget, or null if there isn't one
+		focusedChild: null,
+=====*/
+
+		// tabIndex: Integer
+		//		Tab index of the container; same as HTML tabindex attribute.
+		//		Note then when user tabs into the container, focus is immediately
+		//		moved to the first item in the container.
+		tabIndex: "0",
+
+
+		_keyNavCodes: {},
+
+		connectKeyNavHandlers: function(/*dojo.keys[]*/ prevKeyCodes, /*dojo.keys[]*/ nextKeyCodes){
+			// summary:
+			//		Call in postCreate() to attach the keyboard handlers
+			//		to the container.
+			// preKeyCodes: dojo.keys[]
+			//		Key codes for navigating to the previous child.
+			// nextKeyCodes: dojo.keys[]
+			//		Key codes for navigating to the next child.
+			// tags:
+			//		protected
+
+			var keyCodes = this._keyNavCodes = {};
+			var prev = dojo.hitch(this, this.focusPrev);
+			var next = dojo.hitch(this, this.focusNext);
+			dojo.forEach(prevKeyCodes, function(code){ keyCodes[code] = prev; });
+			dojo.forEach(nextKeyCodes, function(code){ keyCodes[code] = next; });
+			this.connect(this.domNode, "onkeypress", "_onContainerKeypress");
+			this.connect(this.domNode, "onfocus", "_onContainerFocus");
+		},
+
+		startupKeyNavChildren: function(){
+			// summary:
+			//		Call in startup() to set child tabindexes to -1
+			// tags:
+			//		protected
+			dojo.forEach(this.getChildren(), dojo.hitch(this, "_startupChild"));
+		},
+
+		addChild: function(/*Widget*/ widget, /*int?*/ insertIndex){
+			// summary:
+			//		Add a child to our _Container
+			dijit._KeyNavContainer.superclass.addChild.apply(this, arguments);
+			this._startupChild(widget);
+		},
+
+		focus: function(){
+			// summary:
+			//		Default focus() implementation: focus the first child.
+			this.focusFirstChild();
+		},
+
+		focusFirstChild: function(){
+			// summary:
+			//		Focus the first focusable child in the container.
+			// tags:
+			//		protected
+			this.focusChild(this._getFirstFocusableChild());
+		},
+
+		focusNext: function(){
+			// summary:
+			//		Focus the next widget or focal node (for widgets
+			//		with multiple focal nodes) within this container.
+			// tags:
+			//		protected
+			if(this.focusedChild && this.focusedChild.hasNextFocalNode
+					&& this.focusedChild.hasNextFocalNode()){
+				this.focusedChild.focusNext();
+				return;
+			}
+			var child = this._getNextFocusableChild(this.focusedChild, 1);
+			if(child.getFocalNodes){
+				this.focusChild(child, child.getFocalNodes()[0]);
+			}else{
+				this.focusChild(child);
+			}
+		},
+
+		focusPrev: function(){
+			// summary:
+			//		Focus the previous widget or focal node (for widgets
+			//		with multiple focal nodes) within this container.
+			// tags:
+			//		protected
+			if(this.focusedChild && this.focusedChild.hasPrevFocalNode
+					&& this.focusedChild.hasPrevFocalNode()){
+				this.focusedChild.focusPrev();
+				return;
+			}
+			var child = this._getNextFocusableChild(this.focusedChild, -1);
+			if(child.getFocalNodes){
+				var nodes = child.getFocalNodes();
+				this.focusChild(child, nodes[nodes.length-1]);
+			}else{
+				this.focusChild(child);
+			}
+		},
+
+		focusChild: function(/*Widget*/ widget, /*Node?*/ node){
+			// summary:
+			//		Focus widget. Optionally focus 'node' within widget.
+			// tags:
+			//		protected
+			if(widget){
+				if(this.focusedChild && widget !== this.focusedChild){
+					this._onChildBlur(this.focusedChild);
+				}
+				this.focusedChild = widget;
+				if(node && widget.focusFocalNode){
+					widget.focusFocalNode(node);
+				}else{
+					widget.focus();
+				}
+			}
+		},
+
+		_startupChild: function(/*Widget*/ widget){
+			// summary:
+			//		Set tabindex="-1" on focusable widgets so that we
+			// 		can focus them programmatically and by clicking.
+			//		Connect focus and blur handlers.
+			// tags:
+			//		private
+			if(widget.getFocalNodes){
+				dojo.forEach(widget.getFocalNodes(), function(node){
+					dojo.attr(node, "tabindex", -1);
+					this._connectNode(node);
+				}, this);
+			}else{
+				var node = widget.focusNode || widget.domNode;
+				if(widget.isFocusable()){
+					dojo.attr(node, "tabindex", -1);
+				}
+				this._connectNode(node);
+			}
+		},
+
+		_connectNode: function(/*Element*/ node){
+			// summary:
+			//		Monitor focus and blur events on the node
+			// tags:
+			//		private
+			this.connect(node, "onfocus", "_onNodeFocus");
+			this.connect(node, "onblur", "_onNodeBlur");
+		},
+
+		_onContainerFocus: function(evt){
+			// summary:
+			//		Handler for when the container gets focus
+			// description:
+			//		Initially the container itself has a tabIndex, but when it gets
+			//		focus, switch focus to first child...
+			// tags:
+			//		private
+
+			// Note that we can't use _onFocus() because switching focus from the
+			// _onFocus() handler confuses the focus.js code
+			// (because it causes _onFocusNode() to be called recursively)
+
+			// focus bubbles on Firefox,
+			// so just make sure that focus has really gone to the container
+			if(evt.target !== this.domNode){ return; }
+
+			this.focusFirstChild();
+			
+			// and then remove the container's tabIndex,
+			// so that tab or shift-tab will go to the fields after/before
+			// the container, rather than the container itself
+			dojo.removeAttr(this.domNode, "tabIndex");
+		},
+
+		_onBlur: function(evt){
+			// When focus is moved away the container, and it's descendant (popup) widgets,
+			// then restore the container's tabIndex so that user can tab to it again.
+			// Note that using _onBlur() so that this doesn't happen when focus is shifted
+			// to one of my child widgets (typically a popup)
+			if(this.tabIndex){
+				dojo.attr(this.domNode, "tabindex", this.tabIndex);
+			}
+			// TODO: this.inherited(arguments);
+		},
+
+		_onContainerKeypress: function(evt){
+			// summary:
+			//		When a key is pressed, if it's an arrow key etc. then
+			//		it's handled here.
+			// tags:
+			//		private
+			if(evt.ctrlKey || evt.altKey){ return; }
+			var func = this._keyNavCodes[evt.charOrCode];
+			if(func){
+				func();
+				dojo.stopEvent(evt);
+			}
+		},
+
+		_onNodeFocus: function(evt){
+			// summary:
+			//		Handler for onfocus event on a child node
+			// tags:
+			//		private
+
+			// record the child that has been focused
+			var widget = dijit.getEnclosingWidget(evt.target);
+			if(widget && widget.isFocusable()){
+				this.focusedChild = widget;
+			}
+			dojo.stopEvent(evt);
+		},
+
+		_onNodeBlur: function(evt){
+			// summary:
+			//		Handler for onblur event on a child node
+			// tags:
+			//		private
+			dojo.stopEvent(evt);
+		},
+
+		_onChildBlur: function(/*Widget*/ widget){
+			// summary:
+			//		Called when focus leaves a child widget to go
+			//		to a sibling widget.
+			// tags:
+			//		protected
+		},
+
+		_getFirstFocusableChild: function(){
+			// summary:
+			//		Returns first child that can be focused
+			return this._getNextFocusableChild(null, 1);
+		},
+
+		_getNextFocusableChild: function(child, dir){
+			// summary:
+			//		Returns the next or previous focusable child, compared
+			//		to "child"
+			// child: Widget
+			//		The current widget
+			// dir: Integer
+			//		* 1 = after
+			//		* -1 = before
+			if(child){
+				child = this._getSiblingOfChild(child, dir);
+			}
+			var children = this.getChildren();
+			for(var i=0; i < children.length; i++){
+				if(!child){
+					child = children[(dir>0) ? 0 : (children.length-1)];
+				}
+				if(child.isFocusable()){
+					return child;
+				}
+				child = this._getSiblingOfChild(child, dir);
+			}
+			// no focusable child found
+			return null;
+		}
+	}
+);
+
+}
+
+if(!dojo._hasResource["dijit.MenuItem"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.MenuItem"] = true;
+dojo.provide("dijit.MenuItem");
+
+
+
+
+
+dojo.declare("dijit.MenuItem",
+		[dijit._Widget, dijit._Templated, dijit._Contained],
+		{
+		// summary:
+		//		A line item in a Menu Widget
+
+		// Make 3 columns
+		// icon, label, and expand arrow (BiDi-dependent) indicating sub-menu
+		templateString:"<tr class=\"dijitReset dijitMenuItem\" dojoAttachPoint=\"focusNode\" waiRole=\"menuitem\" tabIndex=\"-1\"\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\n\t<td class=\"dijitReset\" waiRole=\"presentation\">\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"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",
+
+		attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
+			label: { node: "containerNode", type: "innerHTML" },
+			iconClass: { node: "iconNode", type: "class" }
+		}),
+
+		// label: String
+		//		Menu text
+		label: '',
+
+		// iconClass: String
+		//		Class to apply to DOMNode to make it display an icon.
+		iconClass: "",
+
+		// accelKey: String
+		//		Text for the accelerator (shortcut) key combination.
+		//		Note that although Menu can display accelerator keys there
+		//		is no infrastructure to actually catch and execute these
+		//		accelerators.
+		accelKey: "",
+
+		// disabled: Boolean
+		//		If true, the menu item is disabled.
+		//		If false, the menu item is enabled.
+		disabled: false,
+
+		_fillContent: function(/*DomNode*/ source){
+			// If button label is specified as srcNodeRef.innerHTML rather than
+			// this.params.label, handle it here.
+			if(source && !("label" in this.params)){
+				this.attr('label', source.innerHTML);
+			}
+		},
+
+		postCreate: function(){
+			dojo.setSelectable(this.domNode, false);
+			dojo.attr(this.containerNode, "id", this.id+"_text");
+			dijit.setWaiState(this.domNode, "labelledby", this.id+"_text");
+		},
+
+		_onHover: function(){
+			// summary:
+			//		Handler when mouse is moved onto menu item
+			// tags:
+			//		protected
+			dojo.addClass(this.domNode, 'dijitMenuItemHover');
+			this.getParent().onItemHover(this);
+		},
+
+		_onUnhover: function(){
+			// summary:
+			//		Handler when mouse is moved off of menu item,
+			//		possibly to a child menu, or maybe to a sibling
+			//		menuitem or somewhere else entirely.
+			// tags:
+			//		protected
+
+			// if we are unhovering the currently selected item
+			// then unselect it
+			dojo.removeClass(this.domNode, 'dijitMenuItemHover');
+			this.getParent().onItemUnhover(this);
+		},
+
+		_onClick: function(evt){
+			// summary:
+			//		Internal handler for click events on MenuItem.
+			// tags:
+			//		private
+			this.getParent().onItemClick(this, evt);
+			dojo.stopEvent(evt);
+		},
+
+		onClick: function(/*Event*/ evt){
+			// summary:
+			//		User defined function to handle clicks
+			// tags:
+			//		callback
+		},
+
+		focus: function(){
+			// summary:
+			//		Focus on this MenuItem
+			try{
+				dijit.focus(this.focusNode);
+			}catch(e){
+				// this throws on IE (at least) in some scenarios
+			}
+		},
+
+		_onFocus: function(){
+			// summary:
+			//		This is called by the focus manager when focus
+			//		goes to this MenuItem or a child menu.
+			// tags:
+			//		protected
+			this._setSelected(true);
+
+			// TODO: this.inherited(arguments);
+		},
+
+		_setSelected: function(selected){
+			// summary:
+			//		Indicate that this node is the currently selected one
+			// tags:
+			//		private
+
+			/***
+			 * TODO: remove this method and calls to it, when _onBlur() is working for MenuItem.
+			 * Currently _onBlur() gets called when focus is moved from the MenuItem to a child menu.
+			 * That's not supposed to happen, but the problem is:
+			 * In order to allow dijit.popup's getTopPopup()  work,a sub menu's popupParent
+			 * points to the parent Menu, bypassing the parent MenuItem... thus the
+			 * MenuItem is not in the chain of active widgets and gets a premature call to
+			 * _onBlur()
+			 */
+			
+			dojo.toggleClass(this.domNode, "dijitMenuItemSelected", selected);
+		},
+
+		setLabel: function(/*String*/ content){
+			// summary:
+			//		Deprecated.   Use attr('label', ...) instead.
+			// tags:
+			//		deprecated
+			dojo.deprecated("dijit.MenuItem.setLabel() is deprecated.  Use attr('label', ...) instead.", "", "2.0");
+			this.attr("label", content);
+		},
+
+		setDisabled: function(/*Boolean*/ disabled){
+			// summary:
+			//		Deprecated.   Use attr('disabled', bool) instead.
+			// tags:
+			//		deprecated
+			dojo.deprecated("dijit.Menu.setDisabled() is deprecated.  Use attr('disabled', bool) instead.", "", "2.0");
+			this.attr('disabled', disabled);
+		},
+		_setDisabledAttr: function(/*Boolean*/ value){
+			// summary:
+			//		Hook for attr('disabled', ...) to work.
+			//		Enable or disable this menu item.
+			this.disabled = value;
+			dojo[value ? "addClass" : "removeClass"](this.domNode, 'dijitMenuItemDisabled');
+			dijit.setWaiState(this.focusNode, 'disabled', value ? 'true' : 'false');
+		},
+		_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");
+		}
+	});
+
+}
+
+if(!dojo._hasResource["dijit.PopupMenuItem"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.PopupMenuItem"] = true;
+dojo.provide("dijit.PopupMenuItem");
+
+
+
+dojo.declare("dijit.PopupMenuItem",
+		dijit.MenuItem,
+		{
+		_fillContent: function(){
+			// summary: 
+			//		When Menu is declared in markup, this code gets the menu label and
+			//		the popup widget from the srcNodeRef.
+			// description:
+			//		srcNodeRefinnerHTML contains both the menu item text and a popup widget
+			//		The first part holds the menu item text and the second part is the popup
+			// example: 
+			// |	<div dojoType="dijit.PopupMenuItem">
+			// |		<span>pick me</span>
+			// |		<popup> ... </popup>
+			// |	</div>
+			// tags:
+			//		protected
+
+			if(this.srcNodeRef){
+				var nodes = dojo.query("*", this.srcNodeRef);
+				dijit.PopupMenuItem.superclass._fillContent.call(this, nodes[0]);
+
+				// save pointer to srcNode so we can grab the drop down widget after it's instantiated
+				this.dropDownContainer = this.srcNodeRef;
+			}
+		},
+
+		startup: function(){
+			if(this._started){ return; }
+			this.inherited(arguments);
+
+			// we didn't copy the dropdown widget from the this.srcNodeRef, so it's in no-man's
+			// land now.  move it to dojo.doc.body.
+			if(!this.popup){
+				var node = dojo.query("[widgetId]", this.dropDownContainer)[0];
+				this.popup = dijit.byNode(node);
+			}
+			dojo.body().appendChild(this.popup.domNode);
+
+			this.popup.domNode.style.display="none";
+			if(this.arrowWrapper){
+				dojo.style(this.arrowWrapper, "visibility", "");
+			}
+			dijit.setWaiState(this.focusNode, "haspopup", "true");
+		},
+		
+		destroyDescendants: function(){
+			if(this.popup){
+				this.popup.destroyRecursive();
+				delete this.popup;
+			}
+			this.inherited(arguments);
+		}
+	});
+
+
+}
+
+if(!dojo._hasResource["dijit.CheckedMenuItem"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.CheckedMenuItem"] = true;
+dojo.provide("dijit.CheckedMenuItem");
+
+
+
+dojo.declare("dijit.CheckedMenuItem",
+		dijit.MenuItem,
+		{
+		// summary:
+		//		A checkbox-like menu item for toggling on and off
+		
+		templateString:"<tr class=\"dijitReset dijitMenuItem\" dojoAttachPoint=\"focusNode\" waiRole=\"menuitemcheckbox\" tabIndex=\"-1\"\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\n\t<td class=\"dijitReset\" 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\">\n\t</td>\n</tr>\n",
+
+		// checked: Boolean
+		//		Our checked state
+		checked: false,
+		_setCheckedAttr: function(/*Boolean*/ checked){
+			// summary:
+			//		Hook so attr('checked', bool) works.
+			//		Sets the class and state for the check box.
+			dojo.toggleClass(this.domNode, "dijitCheckedMenuItemChecked", checked);
+			dijit.setWaiState(this.domNode, "checked", checked);
+			this.checked = checked;
+		},
+
+		onChange: function(/*Boolean*/ checked){
+			// summary:
+			//		User defined function to handle check/uncheck events
+			// tags:
+			//		callback
+		},
+
+		_onClick: function(/*Event*/ e){
+			// summary:
+			//		Clicking this item just toggles its state
+			// tags:
+			//		private
+			if(!this.disabled){
+				this.attr("checked", !this.checked);
+				this.onChange(this.checked);
+			}
+			this.inherited(arguments);
+		}
+	});
+
+}
+
+if(!dojo._hasResource["dijit.MenuSeparator"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.MenuSeparator"] = true;
+dojo.provide("dijit.MenuSeparator");
+
+
+
+
+
+dojo.declare("dijit.MenuSeparator",
+		[dijit._Widget, dijit._Templated, dijit._Contained],
+		{
+		// summary:
+		//		A line between two menu items
+
+		templateString:"<tr class=\"dijitMenuSeparator\">\n\t<td colspan=\"4\">\n\t\t<div class=\"dijitMenuSeparatorTop\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n</tr>\n",
+
+		postCreate: function(){
+			dojo.setSelectable(this.domNode, false);
+		},
+		
+		isFocusable: function(){
+			// summary:
+			//		Override to always return false
+			// tags:
+			//		protected
+
+			return false; // Boolean
+		}
+	});
+
+
+}
+
+if(!dojo._hasResource["dijit.Menu"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.Menu"] = true;
+dojo.provide("dijit.Menu");
+
+
+
+
+
+dojo.declare("dijit._MenuBase",
+	[dijit._Widget, dijit._Templated, dijit._KeyNavContainer],
+{
+	// summary:
+	//		Base class for Menu and MenuBar
+
+	// parentMenu: [readonly] Widget
+	//		pointer to menu that displayed me
+	parentMenu: null,
+
+	// popupDelay: Integer
+	//		number of milliseconds before hovering (without clicking) causes the popup to automatically open.
+	popupDelay: 500,
+
+	startup: function(){
+		if(this._started){ return; }
+
+		dojo.forEach(this.getChildren(), function(child){ child.startup(); });
+		this.startupKeyNavChildren();
+
+		this.inherited(arguments);
+	},
+
+	onExecute: function(){
+		// summary:
+		//		Attach point for notification about when a menu item has been executed.
+		//		This is an internal mechanism used for Menus to signal to their parent to
+		//		close them, because they are about to execute the onClick handler.   In
+		//		general developers should not attach to or override this method.
+		// tags:
+		//		protected
+	},
+
+	onCancel: function(/*Boolean*/ closeAll){
+		// summary:
+		//		Attach point for notification about when the user cancels the current menu
+		//		This is an internal mechanism used for Menus to signal to their parent to
+		//		close them.  In general developers should not attach to or override this method.
+		// tags:
+		//		protected
+	},
+
+	_moveToPopup: function(/*Event*/ evt){
+		// summary:
+		//		This handles the right arrow key (left arrow key on RTL systems),
+		//		which will either open a submenu, or move to the next item in the
+		//		ancestor MenuBar
+		// tags:
+		//		private
+
+		if(this.focusedChild && this.focusedChild.popup && !this.focusedChild.disabled){
+			this.focusedChild._onClick(evt);
+		}else{
+			var topMenu = this._getTopMenu();
+			if(topMenu && topMenu._isMenuBar){
+				topMenu.focusNext();
+			}
+		}
+	},
+
+	onItemHover: function(/*MenuItem*/ item){
+		// summary:
+		//		Called when cursor is over a MenuItem.
+		// tags:
+		//		protected
+
+		// Don't do anything unless user has "activated" the menu by:
+		//		1) clicking it
+		//		2) tabbing into it
+		//		3) opening it from a parent menu (which automatically focuses it)
+		if(this.isActive){
+			this.focusChild(item);
+	
+			if(this.focusedChild.popup && !this.focusedChild.disabled && !this.hover_timer){
+				this.hover_timer = setTimeout(dojo.hitch(this, "_openPopup"), this.popupDelay);
+			}
+		}
+	},
+
+	_onChildBlur: function(item){
+		// summary:
+		//		Called when a child MenuItem becomes inactive because focus
+		//		has been removed from the MenuItem *and* it's descendant menus.
+		// tags:
+		//		private
+
+		item._setSelected(false);
+
+		// Close all popups that are open and descendants of this menu
+		dijit.popup.close(item.popup);
+		this._stopPopupTimer();
+	},
+
+	onItemUnhover: function(/*MenuItem*/ item){
+		// summary:
+		//		Callback fires when mouse exits a MenuItem
+		// tags:
+		//		protected
+		if(this.isActive){
+			this._stopPopupTimer();
+		}
+	},
+
+	_stopPopupTimer: function(){
+		// summary:
+		//		Cancels the popup timer because the user has stop hovering
+		//		on the MenuItem, etc.
+		// tags:
+		//		private
+		if(this.hover_timer){
+			clearTimeout(this.hover_timer);
+			this.hover_timer = null;
+		}
+	},
+
+	_getTopMenu: function(){
+		// summary:
+		//		Returns the top menu in this chain of Menus
+		// tags:
+		//		private
+		for(var top=this; top.parentMenu; top=top.parentMenu);
+		return top;
+	},
+
+	onItemClick: function(/*Widget*/ item, /*Event*/ evt){
+		// summary:
+		//		Handle clicks on an item.
+		// tags:
+		//		private
+		if(item.disabled){ return false; }
+
+		this.focusChild(item);
+
+		if(item.popup){
+			if(!this.is_open){
+				this._openPopup();
+			}
+		}else{
+			// before calling user defined handler, close hierarchy of menus
+			// and restore focus to place it was when menu was opened
+			this.onExecute();
+
+			// user defined handler for click
+			item.onClick(evt);
+		}
+	},
+
+	_openPopup: function(){
+		// summary:
+		//		Open the popup to the side of/underneath the current menu item
+		// tags:
+		//		protected
+
+		this._stopPopupTimer();
+		var from_item = this.focusedChild;
+		var popup = from_item.popup;
+
+		if(popup.isShowingNow){ return; }
+		popup.parentMenu = this;
+		var self = this;
+		dijit.popup.open({
+			parent: this,
+			popup: popup,
+			around: from_item.domNode,
+			orient: this._orient || (this.isLeftToRight() ? {'TR': 'TL', 'TL': 'TR'} : {'TL': 'TR', 'TR': 'TL'}),
+			onCancel: function(){
+				// called when the child menu is canceled
+				dijit.popup.close(popup);
+				from_item.focus();	// put focus back on my node
+				self.currentPopup = null;
+			},
+			onExecute: dojo.hitch(this, "_onDescendantExecute")
+		});
+
+		this.currentPopup = popup;
+
+		if(popup.focus){
+			// If user is opening the popup via keyboard (right arrow, or down arrow for MenuBar),
+			// if the cursor happens to collide with the popup, it will generate an onmouseover event
+			// even though the mouse wasn't moved.   Use a setTimeout() to call popup.focus so that
+			// our focus() call overrides the onmouseover event, rather than vice-versa.  (#8742)
+			setTimeout(dojo.hitch(popup, "focus"), 0);
+		}
+	},
+
+	onOpen: function(/*Event*/ e){
+		// summary:
+		//		Callback when this menu is opened.
+		//		This is called by the popup manager as notification that the menu
+		//		was opened.
+		// tags:
+		//		private
+
+		this.isShowingNow = true;
+	},
+
+	onClose: function(){
+		// summary:
+		//		Callback when this menu is closed.
+		//		This is called by the popup manager as notification that the menu
+		//		was closed.
+		// tags:
+		//		private
+
+		this._stopPopupTimer();
+		this.parentMenu = null;
+		this.isShowingNow = false;
+		this.currentPopup = null;
+		if(this.focusedChild){
+			this._onChildBlur(this.focusedChild);
+			this.focusedChild = null;
+		}
+	},
+
+	_onFocus: function(){
+		// summary:
+		//		Called when this Menu gets focus from:
+		//			1) clicking it
+		//			2) tabbing into it
+		//			3) being opened by a parent menu.
+		//		This is not called just from mouse hover.
+		// tags:
+		//		protected
+		this.isActive = true;
+		dojo.addClass(this.domNode, "dijitMenuActive");
+		dojo.removeClass(this.domNode, "dijitMenuPassive");
+		this.inherited(arguments);
+	},
+	
+	_onBlur: function(){
+		// summary:
+		//		Called when focus is moved away from this Menu and it's submenus.
+		// tags:
+		//		protected
+		this.isActive = false;
+		dojo.removeClass(this.domNode, "dijitMenuActive");
+		dojo.addClass(this.domNode, "dijitMenuPassive");
+
+		// If user blurs/clicks away from a MenuBar (or always visible Menu), then close all popped up submenus etc.
+		this.onClose();
+
+		this.inherited(arguments);
+	},
+
+	_onDescendantExecute: function(){
+		// summary:
+		//		Called when submenu is clicked.  Close hierarchy of menus.
+		// tags:
+		//		private
+		this.onClose();
+	}
+});
+
+dojo.declare("dijit.Menu",
+	dijit._MenuBase,
+	{
+	// summary
+	//		A context menu you can assign to multiple elements
+
+	// TODO: most of the code in here is just for context menu (right-click menu)
+	// support.  In retrospect that should have been a separate class (dijit.ContextMenu).
+	// Split them for 2.0
+
+	constructor: function(){
+		this._bindings = [];
+	},
+
+	templateString:"<table class=\"dijit dijitMenu dijitMenuPassive dijitReset dijitMenuTable\" waiRole=\"menu\" tabIndex=\"${tabIndex}\" dojoAttachEvent=\"onkeypress:_onKeyPress\">\n\t<tbody class=\"dijitReset\" dojoAttachPoint=\"containerNode\"></tbody>\n</table>\n",
+
+	// targetNodeIds: [const] String[]
+	//		Array of dom node ids of nodes to attach to.
+	//		Fill this with nodeIds upon widget creation and it becomes context menu for those nodes.
+	targetNodeIds: [],
+
+	// contextMenuForWindow: [const] Boolean
+	//		If true, right clicking anywhere on the window will cause this context menu to open.
+	//		If false, must specify targetNodeIds.
+	contextMenuForWindow: false,
+
+	// leftClickToOpen: [const] Boolean
+	//		If true, menu will open on left click instead of right click, similiar to a file menu.
+	leftClickToOpen: false,
+	
+	// _contextMenuWithMouse: [private] Boolean
+	//		Used to record mouse and keyboard events to determine if a context
+	//		menu is being opened with the keyboard or the mouse.
+	_contextMenuWithMouse: false,
+
+	postCreate: function(){
+		if(this.contextMenuForWindow){
+			this.bindDomNode(dojo.body());
+		}else{
+			dojo.forEach(this.targetNodeIds, this.bindDomNode, this);
+		}
+		var k = dojo.keys, l = this.isLeftToRight();
+		this._openSubMenuKey = l ? k.RIGHT_ARROW : k.LEFT_ARROW;
+		this._closeSubMenuKey = l ? k.LEFT_ARROW : k.RIGHT_ARROW;
+		this.connectKeyNavHandlers([k.UP_ARROW], [k.DOWN_ARROW]);
+	},
+
+	_onKeyPress: function(/*Event*/ evt){
+		// summary:
+		//		Handle keyboard based menu navigation.
+		// tags:
+		//		protected
+
+		if(evt.ctrlKey || evt.altKey){ return; }
+
+		switch(evt.charOrCode){
+			case this._openSubMenuKey:
+				this._moveToPopup(evt);
+				dojo.stopEvent(evt);
+				break;
+			case this._closeSubMenuKey:
+				if(this.parentMenu){
+					if(this.parentMenu._isMenuBar){
+						this.parentMenu.focusPrev();
+					}else{
+						this.onCancel(false);
+					}
+				}else{
+					dojo.stopEvent(evt);
+				}
+				break;
+		}
+	},
+
+	// thanks burstlib!
+	_iframeContentWindow: function(/* HTMLIFrameElement */iframe_el){
+		// summary:
+		//		Returns the window reference of the passed iframe
+		// tags:
+		//		private
+		var win = dijit.getDocumentWindow(dijit.Menu._iframeContentDocument(iframe_el)) ||
+			// Moz. TODO: is this available when defaultView isn't?
+			dijit.Menu._iframeContentDocument(iframe_el)['__parent__'] ||
+			(iframe_el.name && dojo.doc.frames[iframe_el.name]) || null;
+		return win;	//	Window
+	},
+
+	_iframeContentDocument: function(/* HTMLIFrameElement */iframe_el){
+		// summary:
+		//		Returns a reference to the document object inside iframe_el
+		// tags:
+		//		protected
+		var doc = iframe_el.contentDocument // W3
+			|| (iframe_el.contentWindow && iframe_el.contentWindow.document) // IE
+			|| (iframe_el.name && dojo.doc.frames[iframe_el.name] && dojo.doc.frames[iframe_el.name].document)
+			|| null;
+		return doc;	//	HTMLDocument
+	},
+
+	bindDomNode: function(/*String|DomNode*/ node){
+		// summary:
+		//		Attach menu to given node
+		node = dojo.byId(node);
+
+		//TODO: this is to support context popups in Editor.  Maybe this shouldn't be in dijit.Menu
+		var win = dijit.getDocumentWindow(node.ownerDocument);
+		if(node.tagName.toLowerCase()=="iframe"){
+			win = this._iframeContentWindow(node);
+			node = dojo.withGlobal(win, dojo.body);
+		}
+
+		// to capture these events at the top level,
+		// attach to document, not body
+		var cn = (node == dojo.body() ? dojo.doc : node);
+
+		node[this.id] = this._bindings.push([
+			dojo.connect(cn, (this.leftClickToOpen)?"onclick":"oncontextmenu", this, "_openMyself"),
+			dojo.connect(cn, "onkeydown", this, "_contextKey"),
+			dojo.connect(cn, "onmousedown", this, "_contextMouse")
+		]);
+	},
+
+	unBindDomNode: function(/*String|DomNode*/ nodeName){
+		// summary:
+		//		Detach menu from given node
+		var node = dojo.byId(nodeName);
+		if(node){
+			var bid = node[this.id]-1, b = this._bindings[bid];
+			dojo.forEach(b, dojo.disconnect);
+			delete this._bindings[bid];
+		}
+	},
+
+	_contextKey: function(e){
+		// summary:
+		//		Code to handle popping up editor using F10 key rather than mouse
+		// tags:
+		//		private
+		this._contextMenuWithMouse = false;
+		if(e.keyCode == dojo.keys.F10){
+			dojo.stopEvent(e);
+			if(e.shiftKey && e.type=="keydown"){
+				// FF: copying the wrong property from e will cause the system
+				// context menu to appear in spite of stopEvent. Don't know
+				// exactly which properties cause this effect.
+				var _e = { target: e.target, pageX: e.pageX, pageY: e.pageY };
+				_e.preventDefault = _e.stopPropagation = function(){};
+				// IE: without the delay, focus work in "open" causes the system
+				// context menu to appear in spite of stopEvent.
+				window.setTimeout(dojo.hitch(this, function(){ this._openMyself(_e); }), 1);
+			}
+		}
+	},
+
+	_contextMouse: function(e){
+		// summary:
+		//		Helper to remember when we opened the context menu with the mouse instead
+		//		of with the keyboard
+		// tags:
+		//		private
+		this._contextMenuWithMouse = true;
+	},
+
+	_openMyself: function(/*Event*/ e){
+		// summary:
+		//		Internal function for opening myself when the user
+		//		does a right-click or something similar
+		// tags:
+		//		private
+
+		if(this.leftClickToOpen&&e.button>0){
+			return;
+		}
+		dojo.stopEvent(e);
+
+		// Get coordinates.
+		// if we are opening the menu with the mouse or on safari open
+		// the menu at the mouse cursor
+		// (Safari does not have a keyboard command to open the context menu
+		// and we don't currently have a reliable way to determine
+		// _contextMenuWithMouse on Safari)
+		var x,y;
+		if(dojo.isSafari || this._contextMenuWithMouse){
+			x=e.pageX;
+			y=e.pageY;
+		}else{
+			// otherwise open near e.target
+			var coords = dojo.coords(e.target, true);
+			x = coords.x + 10;
+			y = coords.y + 10;
+		}
+
+		var self=this;
+		var savedFocus = dijit.getFocus(this);
+		function closeAndRestoreFocus(){
+			// user has clicked on a menu or popup
+			dijit.focus(savedFocus);
+			dijit.popup.close(self);
+		}
+		dijit.popup.open({
+			popup: this,
+			x: x,
+			y: y,
+			onExecute: closeAndRestoreFocus,
+			onCancel: closeAndRestoreFocus,
+			orient: this.isLeftToRight() ? 'L' : 'R'
+		});
+		this.focus();
+
+		this._onBlur = function(){
+			this.inherited('_onBlur', arguments);
+			// Usually the parent closes the child widget but if this is a context
+			// menu then there is no parent
+			dijit.popup.close(this);
+			// don't try to restore focus; user has clicked another part of the screen
+			// and set focus there
+		};
+	},
+
+	uninitialize: function(){
+ 		dojo.forEach(this.targetNodeIds, this.unBindDomNode, this);
+ 		this.inherited(arguments);
+	}
+}
+);
+
+// Back-compat (TODO: remove in 2.0)
+
+
+
+
+
+
+}
+
+if(!dojo._hasResource["dojox.html.metrics"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.html.metrics"] = true;
+dojo.provide("dojox.html.metrics");
+
+(function(){
+	var dhm = dojox.html.metrics;
+
+	//	derived from Morris John's emResized measurer
+	dhm.getFontMeasurements = function(){
+		//	summary
+		//	Returns an object that has pixel equivilents of standard font size values.
+		var heights = {
+			'1em':0, '1ex':0, '100%':0, '12pt':0, '16px':0, 'xx-small':0, 'x-small':0,
+			'small':0, 'medium':0, 'large':0, 'x-large':0, 'xx-large':0
+		};
+	
+		if(dojo.isIE){
+			//	we do a font-size fix if and only if one isn't applied already.
+			//	NOTE: If someone set the fontSize on the HTML Element, this will kill it.
+			dojo.doc.documentElement.style.fontSize="100%";
+		}
+	
+		//	set up the measuring node.
+		var div=dojo.doc.createElement("div");
+		var ds = div.style;
+		ds.position="absolute";
+		ds.left="-100px";
+		ds.top="0";
+		ds.width="30px";
+		ds.height="1000em";
+		ds.border="0";
+		ds.margin="0";
+		ds.padding="0";
+		ds.outline="0";
+		ds.lineHeight="1";
+		ds.overflow="hidden";
+		dojo.body().appendChild(div);
+	
+		//	do the measurements.
+		for(var p in heights){
+			ds.fontSize = p;
+			heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000;
+		}
+		
+		dojo.body().removeChild(div);
+		div = null;
+		return heights; 	//	object
+	};
+
+	var fontMeasurements = null;
+	
+	dhm.getCachedFontMeasurements = function(recalculate){
+		if(recalculate || !fontMeasurements){
+			fontMeasurements = dhm.getFontMeasurements();
+		}
+		return fontMeasurements;
+	};
+
+	var measuringNode = null, empty = {};
+	dhm.getTextBox = function(/* String */ text, /* Object */ style, /* String? */ className){
+		var m;
+		if(!measuringNode){
+			m = measuringNode = dojo.doc.createElement("div");
+			m.style.position = "absolute";
+			m.style.left = "-10000px";
+			m.style.top = "0";
+			dojo.body().appendChild(m);
+		}else{
+			m = measuringNode;
+		}
+		// reset styles
+		m.className = "";
+		m.style.border = "0";
+		m.style.margin = "0";
+		m.style.padding = "0";
+		m.style.outline = "0";
+		// set new style
+		if(arguments.length > 1 && style){
+			for(var i in style){
+				if(i in empty){ continue; }
+				m.style[i] = style[i];
+			}
+		}
+		// set classes
+		if(arguments.length > 2 && className){
+			m.className = className;
+		}
+		// take a measure
+		m.innerHTML = text;
+		return dojo.marginBox(m);
+	};
+
+	//	determine the scrollbar sizes on load.
+	var scroll={ w:16, h:16 };
+	dhm.getScrollbar=function(){ return { w:scroll.w, h:scroll.h }; };
+
+	dhm._fontResizeNode = null;
+
+	dhm.initOnFontResize = function(interval){
+		var f = dhm._fontResizeNode = dojo.doc.createElement("iframe");
+		var fs = f.style;
+		fs.position = "absolute";
+		fs.width = "5em";
+		fs.height = "10em";
+		fs.top = "-10000px";
+		f.src = dojo.config["dojoBlankHtmlUrl"] || dojo.moduleUrl("dojo", "resources/blank.html");
+		dojo.body().appendChild(f);
+
+		if(dojo.isIE){
+			f.onreadystatechange = function(){
+				if(f.contentWindow.document.readyState == "complete"){
+					f.onresize = Function('window.parent.'+dojox._scopeName+'.html.metrics._fontresize()');
+				}
+			};
+		}else{
+			f.onload = function(){
+				f.contentWindow.onresize = Function('window.parent.'+dojox._scopeName+'.html.metrics._fontresize()');
+			};
+		}
+		dhm.initOnFontResize = function(){};
+	};
+
+	dhm.onFontResize = function(){};
+	dhm._fontresize = function(){
+		dhm.onFontResize();
+	}
+
+	dojo.addOnUnload(function(){
+		// destroy our font resize iframe if we have one
+		var f = dhm._fontResizeNode;
+		if(f){
+			if(dojo.isIE && f.onresize){
+				f.onresize = null;
+			}else if(f.contentWindow && f.contentWindow.onresize){
+				f.contentWindow.onresize = null;
+			}
+			dhm._fontResizeNode = null;
+		}
+	});
+
+	dojo.addOnLoad(function(){
+		// getScrollbar metrics node
+		try{
+			var n=dojo.doc.createElement("div");
+			n.style.cssText = "top:0;left:0;width:100px;height:100px;overflow:scroll;position:absolute;visibility:hidden;";
+			dojo.body().appendChild(n);
+			scroll.w = n.offsetWidth - n.clientWidth;
+			scroll.h = n.offsetHeight - n.clientHeight;
+			dojo.body().removeChild(n);
+			//
+			delete n;
+		}catch(e){}
+
+		// text size poll setup
+		if("fontSizeWatch" in dojo.config && !!dojo.config.fontSizeWatch){
+			dhm.initOnFontResize();
+		}
+	});
+})();
+
+}
+
+if(!dojo._hasResource["dojox.grid.util"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.grid.util"] = true;
+dojo.provide("dojox.grid.util");
+
+// summary: grid utility library
+(function(){
+	var dgu = dojox.grid.util;
+
+	dgu.na = '...';
+	dgu.rowIndexTag = "gridRowIndex";
+	dgu.gridViewTag = "gridView";
+
+
+	dgu.fire = function(ob, ev, args){
+		var fn = ob && ev && ob[ev];
+		return fn && (args ? fn.apply(ob, args) : ob[ev]());
+	};
+	
+	dgu.setStyleHeightPx = function(inElement, inHeight){
+		if(inHeight >= 0){
+			var s = inElement.style;
+			var v = inHeight + 'px';
+			if(inElement && s['height'] != v){
+				s['height'] = v;
+			}
+		}
+	};
+	
+	dgu.mouseEvents = [ 'mouseover', 'mouseout', /*'mousemove',*/ 'mousedown', 'mouseup', 'click', 'dblclick', 'contextmenu' ];
+
+	dgu.keyEvents = [ 'keyup', 'keydown', 'keypress' ];
+
+	dgu.funnelEvents = function(inNode, inObject, inMethod, inEvents){
+		var evts = (inEvents ? inEvents : dgu.mouseEvents.concat(dgu.keyEvents));
+		for (var i=0, l=evts.length; i<l; i++){
+			inObject.connect(inNode, 'on' + evts[i], inMethod);
+		}
+	},
+
+	dgu.removeNode = function(inNode){
+		inNode = dojo.byId(inNode);
+		inNode && inNode.parentNode && inNode.parentNode.removeChild(inNode);
+		return inNode;
+	};
+	
+	dgu.arrayCompare = function(inA, inB){
+		for(var i=0,l=inA.length; i<l; i++){
+			if(inA[i] != inB[i]){return false;}
+		}
+		return (inA.length == inB.length);
+	};
+	
+	dgu.arrayInsert = function(inArray, inIndex, inValue){
+		if(inArray.length <= inIndex){
+			inArray[inIndex] = inValue;
+		}else{
+			inArray.splice(inIndex, 0, inValue);
+		}
+	};
+	
+	dgu.arrayRemove = function(inArray, inIndex){
+		inArray.splice(inIndex, 1);
+	};
+	
+	dgu.arraySwap = function(inArray, inI, inJ){
+		var cache = inArray[inI];
+		inArray[inI] = inArray[inJ];
+		inArray[inJ] = cache;
+	};
+})();
+
+}
+
+if(!dojo._hasResource["dojox.grid._Scroller"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.grid._Scroller"] = true;
+dojo.provide("dojox.grid._Scroller");
+
+(function(){
+	var indexInParent = function(inNode){
+		var i=0, n, p=inNode.parentNode;
+		while((n = p.childNodes[i++])){
+			if(n == inNode){
+				return i - 1;
+			}
+		}
+		return -1;
+	};
+	
+	var cleanNode = function(inNode){
+		if(!inNode){
+			return;
+		}
+		var filter = function(inW){
+			return inW.domNode && dojo.isDescendant(inW.domNode, inNode, true);
+		}
+		var ws = dijit.registry.filter(filter);
+		for(var i=0, w; (w=ws[i]); i++){
+			w.destroy();
+		}
+		delete ws;
+	};
+
+	var getTagName = function(inNodeOrId){
+		var node = dojo.byId(inNodeOrId);
+		return (node && node.tagName ? node.tagName.toLowerCase() : '');
+	};
+	
+	var nodeKids = function(inNode, inTag){
+		var result = [];
+		var i=0, n;
+		while((n = inNode.childNodes[i++])){
+			if(getTagName(n) == inTag){
+				result.push(n);
+			}
+		}
+		return result;
+	};
+	
+	var divkids = function(inNode){
+		return nodeKids(inNode, 'div');
+	};
+
+	dojo.declare("dojox.grid._Scroller", null, {
+		constructor: function(inContentNodes){
+			this.setContentNodes(inContentNodes);
+			this.pageHeights = [];
+			this.pageNodes = [];
+			this.stack = [];
+		},
+		// specified
+		rowCount: 0, // total number of rows to manage
+		defaultRowHeight: 32, // default height of a row
+		keepRows: 100, // maximum number of rows that should exist at one time
+		contentNode: null, // node to contain pages
+		scrollboxNode: null, // node that controls scrolling
+		// calculated
+		defaultPageHeight: 0, // default height of a page
+		keepPages: 10, // maximum number of pages that should exists at one time
+		pageCount: 0,
+		windowHeight: 0,
+		firstVisibleRow: 0,
+		lastVisibleRow: 0,
+		averageRowHeight: 0, // the average height of a row
+		// private
+		page: 0,
+		pageTop: 0,
+		// init
+		init: function(inRowCount, inKeepRows, inRowsPerPage){
+			switch(arguments.length){
+				case 3: this.rowsPerPage = inRowsPerPage;
+				case 2: this.keepRows = inKeepRows;
+				case 1: this.rowCount = inRowCount;
+			}
+			this.defaultPageHeight = this.defaultRowHeight * this.rowsPerPage;
+			this.pageCount = this._getPageCount(this.rowCount, this.rowsPerPage);
+			this.setKeepInfo(this.keepRows);
+			this.invalidate();
+			if(this.scrollboxNode){
+				this.scrollboxNode.scrollTop = 0;
+				this.scroll(0);
+				this.scrollboxNode.onscroll = dojo.hitch(this, 'onscroll');
+			}
+		},
+		_getPageCount: function(rowCount, rowsPerPage){
+			return rowCount ? (Math.ceil(rowCount / rowsPerPage) || 1) : 0;
+		},
+		destroy: function(){
+			this.invalidateNodes();
+			delete this.contentNodes;
+			delete this.contentNode;
+			delete this.scrollboxNode;
+		},
+		setKeepInfo: function(inKeepRows){
+			this.keepRows = inKeepRows;
+			this.keepPages = !this.keepRows ? this.keepRows : Math.max(Math.ceil(this.keepRows / this.rowsPerPage), 2);
+		},
+		// nodes
+		setContentNodes: function(inNodes){
+			this.contentNodes = inNodes;
+			this.colCount = (this.contentNodes ? this.contentNodes.length : 0);
+			this.pageNodes = [];
+			for(var i=0; i<this.colCount; i++){
+				this.pageNodes[i] = [];
+			}
+		},
+		getDefaultNodes: function(){
+			return this.pageNodes[0] || [];
+		},
+		// updating
+		invalidate: function(){
+			this.invalidateNodes();
+			this.pageHeights = [];
+			this.height = (this.pageCount ? (this.pageCount - 1)* this.defaultPageHeight + this.calcLastPageHeight() : 0);
+			this.resize();
+		},
+		updateRowCount: function(inRowCount){
+			this.invalidateNodes();
+			this.rowCount = inRowCount;
+			// update page count, adjust document height
+			var oldPageCount = this.pageCount;
+			this.pageCount = this._getPageCount(this.rowCount, this.rowsPerPage);
+			if(this.pageCount < oldPageCount){
+				for(var i=oldPageCount-1; i>=this.pageCount; i--){
+					this.height -= this.getPageHeight(i);
+					delete this.pageHeights[i]
+				}
+			}else if(this.pageCount > oldPageCount){
+				this.height += this.defaultPageHeight * (this.pageCount - oldPageCount - 1) + this.calcLastPageHeight();
+			}
+			this.resize();
+		},
+		// implementation for page manager
+		pageExists: function(inPageIndex){
+			return Boolean(this.getDefaultPageNode(inPageIndex));
+		},
+		measurePage: function(inPageIndex){
+			var n = this.getDefaultPageNode(inPageIndex);
+			return (n&&n.innerHTML) ? n.offsetHeight : 0;
+		},
+		positionPage: function(inPageIndex, inPos){
+			for(var i=0; i<this.colCount; i++){
+				this.pageNodes[i][inPageIndex].style.top = inPos + 'px';
+			}
+		},
+		repositionPages: function(inPageIndex){
+			var nodes = this.getDefaultNodes();
+			var last = 0;
+
+			for(var i=0; i<this.stack.length; i++){
+				last = Math.max(this.stack[i], last);
+			}
+			//
+			var n = nodes[inPageIndex];
+			var y = (n ? this.getPageNodePosition(n) + this.getPageHeight(inPageIndex) : 0);
+			//
+			//
+			for(var p=inPageIndex+1; p<=last; p++){
+				n = nodes[p];
+				if(n){
+					//
+					if(this.getPageNodePosition(n) == y){
+						return;
+					}
+					//
+					this.positionPage(p, y);
+				}
+				y += this.getPageHeight(p);
+			}
+		},
+		installPage: function(inPageIndex){
+			for(var i=0; i<this.colCount; i++){
+				this.contentNodes[i].appendChild(this.pageNodes[i][inPageIndex]);
+			}
+		},
+		preparePage: function(inPageIndex, inReuseNode){
+			var p = (inReuseNode ? this.popPage() : null);
+			for(var i=0; i<this.colCount; i++){
+				var nodes = this.pageNodes[i];
+				var new_p = (p === null ? this.createPageNode() : this.invalidatePageNode(p, nodes));
+				new_p.pageIndex = inPageIndex;
+				new_p.id = (this._pageIdPrefix || "") + 'page-' + inPageIndex;
+				nodes[inPageIndex] = new_p;
+			}
+		},
+		// rendering implementation
+		renderPage: function(inPageIndex){
+			var nodes = [];
+			for(var i=0; i<this.colCount; i++){
+				nodes[i] = this.pageNodes[i][inPageIndex];
+			}
+			for(var i=0, j=inPageIndex*this.rowsPerPage; (i<this.rowsPerPage)&&(j<this.rowCount); i++, j++){
+				this.renderRow(j, nodes);
+			}
+		},
+		removePage: function(inPageIndex){
+			for(var i=0, j=inPageIndex*this.rowsPerPage; i<this.rowsPerPage; i++, j++){
+				this.removeRow(j);
+			}
+		},
+		destroyPage: function(inPageIndex){
+			for(var i=0; i<this.colCount; i++){
+				var n = this.invalidatePageNode(inPageIndex, this.pageNodes[i]);
+				if(n){
+					dojo.destroy(n);
+				}
+			}
+		},
+		pacify: function(inShouldPacify){
+		},
+		// pacification
+		pacifying: false,
+		pacifyTicks: 200,
+		setPacifying: function(inPacifying){
+			if(this.pacifying != inPacifying){
+				this.pacifying = inPacifying;
+				this.pacify(this.pacifying);
+			}
+		},
+		startPacify: function(){
+			this.startPacifyTicks = new Date().getTime();
+		},
+		doPacify: function(){
+			var result = (new Date().getTime() - this.startPacifyTicks) > this.pacifyTicks;
+			this.setPacifying(true);
+			this.startPacify();
+			return result;
+		},
+		endPacify: function(){
+			this.setPacifying(false);
+		},
+		// default sizing implementation
+		resize: function(){
+			if(this.scrollboxNode){
+				this.windowHeight = this.scrollboxNode.clientHeight;
+			}
+			for(var i=0; i<this.colCount; i++){
+				dojox.grid.util.setStyleHeightPx(this.contentNodes[i], this.height);
+			}
+			
+			// Calculate the average row height and update the defaults (row and page).
+			this.needPage(this.page, this.pageTop);
+			var rowsOnPage = (this.page < this.pageCount - 1) ? this.rowsPerPage : ((this.rowCount % this.rowsPerPage) || this.rowsPerPage);
+			var pageHeight = this.getPageHeight(this.page);
+			this.averageRowHeight = (pageHeight > 0 && rowsOnPage > 0) ? (pageHeight / rowsOnPage) : 0;
+		},
+		calcLastPageHeight: function(){
+			if(!this.pageCount){
+				return 0;
+			}
+			var lastPage = this.pageCount - 1;
+			var lastPageHeight = ((this.rowCount % this.rowsPerPage)||(this.rowsPerPage)) * this.defaultRowHeight;
+			this.pageHeights[lastPage] = lastPageHeight;
+			return lastPageHeight;
+		},
+		updateContentHeight: function(inDh){
+			this.height += inDh;
+			this.resize();
+		},
+		updatePageHeight: function(inPageIndex){
+			if(this.pageExists(inPageIndex)){
+				var oh = this.getPageHeight(inPageIndex);
+				var h = (this.measurePage(inPageIndex))||(oh);
+				this.pageHeights[inPageIndex] = h;
+				if((h)&&(oh != h)){
+					this.updateContentHeight(h - oh)
+					this.repositionPages(inPageIndex);
+				}
+			}
+		},
+		rowHeightChanged: function(inRowIndex){
+			this.updatePageHeight(Math.floor(inRowIndex / this.rowsPerPage));
+		},
+		// scroller core
+		invalidateNodes: function(){
+			while(this.stack.length){
+				this.destroyPage(this.popPage());
+			}
+		},
+		createPageNode: function(){
+			var p = document.createElement('div');
+			p.style.position = 'absolute';
+			//p.style.width = '100%';
+			p.style[dojo._isBodyLtr() ? "left" : "right"] = '0';
+			return p;
+		},
+		getPageHeight: function(inPageIndex){
+			var ph = this.pageHeights[inPageIndex];
+			return (ph !== undefined ? ph : this.defaultPageHeight);
+		},
+		// FIXME: this is not a stack, it's a FIFO list
+		pushPage: function(inPageIndex){
+			return this.stack.push(inPageIndex);
+		},
+		popPage: function(){
+			return this.stack.shift();
+		},
+		findPage: function(inTop){
+			var i = 0, h = 0;
+			for(var ph = 0; i<this.pageCount; i++, h += ph){
+				ph = this.getPageHeight(i);
+				if(h + ph >= inTop){
+					break;
+				}
+			}
+			this.page = i;
+			this.pageTop = h;
+		},
+		buildPage: function(inPageIndex, inReuseNode, inPos){
+			this.preparePage(inPageIndex, inReuseNode);
+			this.positionPage(inPageIndex, inPos);
+			// order of operations is key below
+			this.installPage(inPageIndex);
+			this.renderPage(inPageIndex);
+			// order of operations is key above
+			this.pushPage(inPageIndex);
+		},
+		needPage: function(inPageIndex, inPos){
+			var h = this.getPageHeight(inPageIndex), oh = h;
+			if(!this.pageExists(inPageIndex)){
+				this.buildPage(inPageIndex, this.keepPages&&(this.stack.length >= this.keepPages), inPos);
+				h = this.measurePage(inPageIndex) || h;
+				this.pageHeights[inPageIndex] = h;
+				if(h && (oh != h)){
+					this.updateContentHeight(h - oh)
+				}
+			}else{
+				this.positionPage(inPageIndex, inPos);
+			}
+			return h;
+		},
+		onscroll: function(){
+			this.scroll(this.scrollboxNode.scrollTop);
+		},
+		scroll: function(inTop){
+			this.grid.scrollTop = inTop;
+			if(this.colCount){
+				this.startPacify();
+				this.findPage(inTop);
+				var h = this.height;
+				var b = this.getScrollBottom(inTop);
+				for(var p=this.page, y=this.pageTop; (p<this.pageCount)&&((b<0)||(y<b)); p++){
+					y += this.needPage(p, y);
+				}
+				this.firstVisibleRow = this.getFirstVisibleRow(this.page, this.pageTop, inTop);
+				this.lastVisibleRow = this.getLastVisibleRow(p - 1, y, b);
+				// indicates some page size has been updated
+				if(h != this.height){
+					this.repositionPages(p-1);
+				}
+				this.endPacify();
+			}
+		},
+		getScrollBottom: function(inTop){
+			return (this.windowHeight >= 0 ? inTop + this.windowHeight : -1);
+		},
+		// events
+		processNodeEvent: function(e, inNode){
+			var t = e.target;
+			while(t && (t != inNode) && t.parentNode && (t.parentNode.parentNode != inNode)){
+				t = t.parentNode;
+			}
+			if(!t || !t.parentNode || (t.parentNode.parentNode != inNode)){
+				return false;
+			}
+			var page = t.parentNode;
+			e.topRowIndex = page.pageIndex * this.rowsPerPage;
+			e.rowIndex = e.topRowIndex + indexInParent(t);
+			e.rowTarget = t;
+			return true;
+		},
+		processEvent: function(e){
+			return this.processNodeEvent(e, this.contentNode);
+		},
+		// virtual rendering interface
+		renderRow: function(inRowIndex, inPageNode){
+		},
+		removeRow: function(inRowIndex){
+		},
+		// page node operations
+		getDefaultPageNode: function(inPageIndex){
+			return this.getDefaultNodes()[inPageIndex];
+		},
+		positionPageNode: function(inNode, inPos){
+		},
+		getPageNodePosition: function(inNode){
+			return inNode.offsetTop;
+		},
+		invalidatePageNode: function(inPageIndex, inNodes){
+			var p = inNodes[inPageIndex];
+			if(p){
+				delete inNodes[inPageIndex];
+				this.removePage(inPageIndex, p);
+				cleanNode(p);
+				p.innerHTML = '';
+			}
+			return p;
+		},
+		// scroll control
+		getPageRow: function(inPage){
+			return inPage * this.rowsPerPage;
+		},
+		getLastPageRow: function(inPage){
+			return Math.min(this.rowCount, this.getPageRow(inPage + 1)) - 1;
+		},
+		getFirstVisibleRow: function(inPage, inPageTop, inScrollTop){
+			if(!this.pageExists(inPage)){
+				return 0;
+			}
+			var row = this.getPageRow(inPage);
+			var nodes = this.getDefaultNodes();
+			var rows = divkids(nodes[inPage]);
+			for(var i=0,l=rows.length; i<l && inPageTop<inScrollTop; i++, row++){
+				inPageTop += rows[i].offsetHeight;
+			}
+			return (row ? row - 1 : row);
+		},
+		getLastVisibleRow: function(inPage, inBottom, inScrollBottom){
+			if(!this.pageExists(inPage)){
+				return 0;
+			}
+			var nodes = this.getDefaultNodes();
+			var row = this.getLastPageRow(inPage);
+			var rows = divkids(nodes[inPage]);
+			for(var i=rows.length-1; i>=0 && inBottom>inScrollBottom; i--, row--){
+				inBottom -= rows[i].offsetHeight;
+			}
+			return row + 1;
+		},
+		findTopRow: function(inScrollTop){
+			var nodes = this.getDefaultNodes();
+			var rows = divkids(nodes[this.page]);
+			for(var i=0,l=rows.length,t=this.pageTop,h; i<l; i++){
+				h = rows[i].offsetHeight;
+				t += h;
+				if(t >= inScrollTop){
+					this.offset = h - (t - inScrollTop);
+					return i + this.page * this.rowsPerPage;
+				}
+			}
+			return -1;
+		},
+		findScrollTop: function(inRow){
+			var rowPage = Math.floor(inRow / this.rowsPerPage);
+			var t = 0;
+			for(var i=0; i<rowPage; i++){
+				t += this.getPageHeight(i);
+			}
+			this.pageTop = t;
+			this.needPage(rowPage, this.pageTop);
+
+			var nodes = this.getDefaultNodes();
+			var rows = divkids(nodes[rowPage]);
+			var r = inRow - this.rowsPerPage * rowPage;
+			for(var i=0,l=rows.length; i<l && i<r; i++){
+				t += rows[i].offsetHeight;
+			}
+			return t;
+		},
+		dummy: 0
+	});
+})();
+
+}
+
+if(!dojo._hasResource["dojox.grid.cells._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.grid.cells._base"] = true;
+dojo.provide("dojox.grid.cells._base");
+
+
+
+(function(){
+	var focusSelectNode = function(inNode){
+		try{
+			dojox.grid.util.fire(inNode, "focus");
+			dojox.grid.util.fire(inNode, "select");
+		}catch(e){// IE sux bad
+		}
+	};
+	
+	var whenIdle = function(/*inContext, inMethod, args ...*/){
+		setTimeout(dojo.hitch.apply(dojo, arguments), 0);
+	};
+
+	var dgc = dojox.grid.cells;
+
+	dojo.declare("dojox.grid.cells._Base", null, {
+		// summary:
+		//	Respresents a grid cell and contains information about column options and methods
+		//	for retrieving cell related information.
+		//	Each column in a grid layout has a cell object and most events and many methods
+		//	provide access to these objects.
+		styles: '',
+		classes: '',
+		editable: false,
+		alwaysEditing: false,
+		formatter: null,
+		defaultValue: '...',
+		value: null,
+		hidden: false,
+		noresize: false,
+		//private
+		_valueProp: "value",
+		_formatPending: false,
+
+		constructor: function(inProps){
+			this._props = inProps || {};
+			dojo.mixin(this, inProps);
+		},
+
+		// data source
+		format: function(inRowIndex, inItem){
+			// summary:
+			//	provides the html for a given grid cell.
+			// inRowIndex: int
+			// grid row index
+			// returns: html for a given grid cell
+			var f, i=this.grid.edit.info, d=this.get ? this.get(inRowIndex, inItem) : (this.value || this.defaultValue);
+			if(this.editable && (this.alwaysEditing || (i.rowIndex==inRowIndex && i.cell==this))){
+				return this.formatEditing(d, inRowIndex);
+			}else{
+				var v = (d != this.defaultValue && (f = this.formatter)) ? f.call(this, d, inRowIndex) : d;
+				return (typeof v == "undefined" ? this.defaultValue : v);
+			}
+		},
+		formatEditing: function(inDatum, inRowIndex){
+			// summary:
+			//	formats the cell for editing
+			// inDatum: anything
+			//	cell data to edit
+			// inRowIndex: int
+			//	grid row index
+			// returns: string of html to place in grid cell
+		},
+		// utility
+		getNode: function(inRowIndex){
+			// summary:
+			//	gets the dom node for a given grid cell.
+			// inRowIndex: int
+			// grid row index
+			// returns: dom node for a given grid cell
+			return this.view.getCellNode(inRowIndex, this.index);
+		},
+		getHeaderNode: function(){
+			return this.view.getHeaderCellNode(this.index);
+		},
+		getEditNode: function(inRowIndex){
+			return (this.getNode(inRowIndex) || 0).firstChild || 0;
+		},
+		canResize: function(){
+			var uw = this.unitWidth;
+			return uw && (uw=='auto');
+		},
+		isFlex: function(){
+			var uw = this.unitWidth;
+			return uw && dojo.isString(uw) && (uw=='auto' || uw.slice(-1)=='%');
+		},
+		// edit support
+		applyEdit: function(inValue, inRowIndex){
+			this.grid.edit.applyCellEdit(inValue, this, inRowIndex);
+		},
+		cancelEdit: function(inRowIndex){
+			this.grid.doCancelEdit(inRowIndex);
+		},
+		_onEditBlur: function(inRowIndex){
+			if(this.grid.edit.isEditCell(inRowIndex, this.index)){
+				//
+				this.grid.edit.apply();
+			}
+		},
+		registerOnBlur: function(inNode, inRowIndex){
+			if(this.commitOnBlur){
+				dojo.connect(inNode, "onblur", function(e){
+					// hack: if editor still thinks this editor is current some ms after it blurs, assume we've focused away from grid
+					setTimeout(dojo.hitch(this, "_onEditBlur", inRowIndex), 250);
+				});
+			}
+		},
+		//protected
+		needFormatNode: function(inDatum, inRowIndex){
+			this._formatPending = true;
+			whenIdle(this, "_formatNode", inDatum, inRowIndex);
+		},
+		cancelFormatNode: function(){
+			this._formatPending = false;
+		},
+		//private
+		_formatNode: function(inDatum, inRowIndex){
+			if(this._formatPending){
+				this._formatPending = false;
+				// make cell selectable
+				dojo.setSelectable(this.grid.domNode, true);
+				this.formatNode(this.getEditNode(inRowIndex), inDatum, inRowIndex);
+			}
+		},
+		//protected
+		formatNode: function(inNode, inDatum, inRowIndex){
+			// summary:
+			//	format the editing dom node. Use when editor is a widget.
+			// inNode: dom node
+			// dom node for the editor
+			// inDatum: anything
+			//	cell data to edit
+			// inRowIndex: int
+			//	grid row index
+			if(dojo.isIE){
+				// IE sux bad
+				whenIdle(this, "focus", inRowIndex, inNode);
+			}else{
+				this.focus(inRowIndex, inNode);
+			}
+		},
+		dispatchEvent: function(m, e){
+			if(m in this){
+				return this[m](e);
+			}
+		},
+		//public
+		getValue: function(inRowIndex){
+			// summary:
+			//	returns value entered into editor
+			// inRowIndex: int
+			// grid row index
+			// returns:
+			//	value of editor
+			return this.getEditNode(inRowIndex)[this._valueProp];
+		},
+		setValue: function(inRowIndex, inValue){
+			// summary:
+			//	set the value of the grid editor
+			// inRowIndex: int
+			// grid row index
+			// inValue: anything
+			//	value of editor
+			var n = this.getEditNode(inRowIndex);
+			if(n){
+				n[this._valueProp] = inValue
+			};
+		},
+		focus: function(inRowIndex, inNode){
+			// summary:
+			//	focus the grid editor
+			// inRowIndex: int
+			// grid row index
+			// inNode: dom node
+			//	editor node
+			focusSelectNode(inNode || this.getEditNode(inRowIndex));
+		},
+		save: function(inRowIndex){
+			// summary:
+			//	save editor state
+			// inRowIndex: int
+			// grid row index
+			this.value = this.value || this.getValue(inRowIndex);
+			//
+		},
+		restore: function(inRowIndex){
+			// summary:
+			//	restore editor state
+			// inRowIndex: int
+			// grid row index
+			this.setValue(inRowIndex, this.value);
+			//
+		},
+		//protected
+		_finish: function(inRowIndex){
+			// summary:
+			//	called when editing is completed to clean up editor
+			// inRowIndex: int
+			// grid row index
+			dojo.setSelectable(this.grid.domNode, false);
+			this.cancelFormatNode();
+		},
+		//public
+		apply: function(inRowIndex){
+			// summary:
+			//	apply edit from cell editor
+			// inRowIndex: int
+			// grid row index
+			this.applyEdit(this.getValue(inRowIndex), inRowIndex);
+			this._finish(inRowIndex);
+		},
+		cancel: function(inRowIndex){
+			// summary:
+			//	cancel cell edit
+			// inRowIndex: int
+			// grid row index
+			this.cancelEdit(inRowIndex);
+			this._finish(inRowIndex);
+		}
+	});
+	dgc._Base.markupFactory = function(node, cellDef){
+		var d = dojo;
+		var formatter = d.trim(d.attr(node, "formatter")||"");
+		if(formatter){
+			cellDef.formatter = dojo.getObject(formatter);
+		}
+		var get = d.trim(d.attr(node, "get")||"");
+		if(get){
+			cellDef.get = dojo.getObject(get);
+		}
+		var getBoolAttr = function(attr){
+			var value = d.trim(d.attr(node, attr)||"");
+			return value ? !(value.toLowerCase()=="false") : undefined;
+		}
+		cellDef.sortDesc = getBoolAttr("sortDesc");
+		cellDef.editable = getBoolAttr("editable");
+		cellDef.alwaysEditing = getBoolAttr("alwaysEditing");
+		cellDef.noresize = getBoolAttr("noresize");
+
+		var value = d.trim(d.attr(node, "loadingText")||d.attr(node, "defaultValue")||"");
+		if(value){
+			cellDef.defaultValue = value;
+		}
+
+		var getStrAttr = function(attr){
+			return d.trim(d.attr(node, attr)||"")||undefined;
+		};
+		cellDef.styles = getStrAttr("styles");
+		cellDef.headerStyles = getStrAttr("headerStyles");
+		cellDef.cellStyles = getStrAttr("cellStyles");
+		cellDef.classes = getStrAttr("classes");
+		cellDef.headerClasses = getStrAttr("headerClasses");
+		cellDef.cellClasses = getStrAttr("cellClasses");
+	}
+
+	dojo.declare("dojox.grid.cells.Cell", dgc._Base, {
+		// summary
+		// grid cell that provides a standard text input box upon editing
+		constructor: function(){
+			this.keyFilter = this.keyFilter;
+		},
+		// keyFilter: RegExp
+		//		optional regex for disallowing keypresses
+		keyFilter: null,
+		formatEditing: function(inDatum, inRowIndex){
+			this.needFormatNode(inDatum, inRowIndex);
+			return '<input class="dojoxGridInput" type="text" value="' + inDatum + '">';
+		},
+		formatNode: function(inNode, inDatum, inRowIndex){
+			this.inherited(arguments);
+			// FIXME: feels too specific for this interface
+			this.registerOnBlur(inNode, inRowIndex);
+		},
+		doKey: function(e){
+			if(this.keyFilter){
+				var key = String.fromCharCode(e.charCode);
+				if(key.search(this.keyFilter) == -1){
+					dojo.stopEvent(e);
+				}
+			}
+		},
+		_finish: function(inRowIndex){
+			this.inherited(arguments);
+			var n = this.getEditNode(inRowIndex);
+			try{
+				dojox.grid.util.fire(n, "blur");
+			}catch(e){}
+		}
+	});
+	dgc.Cell.markupFactory = function(node, cellDef){
+		dgc._Base.markupFactory(node, cellDef);
+		var d = dojo;
+		var keyFilter = d.trim(d.attr(node, "keyFilter")||"");
+		if(keyFilter){
+			cellDef.keyFilter = new RegExp(keyFilter);
+		}
+	}
+
+	dojo.declare("dojox.grid.cells.RowIndex", dgc.Cell, {
+		name: 'Row',
+
+		postscript: function(){
+			this.editable = false;
+		},
+		get: function(inRowIndex){
+			return inRowIndex + 1;
+		}
+	});
+	dgc.RowIndex.markupFactory = function(node, cellDef){
+		dgc.Cell.markupFactory(node, cellDef);
+	}
+
+	dojo.declare("dojox.grid.cells.Select", dgc.Cell, {
+		// summary:
+		// grid cell that provides a standard select for editing
+
+		// options: Array
+		// 		text of each item
+		options: null,
+
+		// values: Array
+		//		value for each item
+		values: null,
+
+		// returnIndex: Integer
+		// 		editor returns only the index of the selected option and not the value
+		returnIndex: -1,
+
+		constructor: function(inCell){
+			this.values = this.values || this.options;
+		},
+		formatEditing: function(inDatum, inRowIndex){
+			this.needFormatNode(inDatum, inRowIndex);
+			var h = [ '<select class="dojoxGridSelect">' ];
+			for (var i=0, o, v; ((o=this.options[i]) !== undefined)&&((v=this.values[i]) !== undefined); i++){
+				h.push("<option", (inDatum==v ? ' selected' : ''), ' value="' + v + '"', ">", o, "</option>");
+			}
+			h.push('</select>');
+			return h.join('');
+		},
+		getValue: function(inRowIndex){
+			var n = this.getEditNode(inRowIndex);
+			if(n){
+				var i = n.selectedIndex, o = n.options[i];
+				return this.returnIndex > -1 ? i : o.value || o.innerHTML;
+			}
+		}
+	});
+	dgc.Select.markupFactory = function(node, cell){
+		dgc.Cell.markupFactory(node, cell);
+		var d=dojo;
+		var options = d.trim(d.attr(node, "options")||"");
+		if(options){
+			var o = options.split(',');
+			if(o[0] != options){
+				cell.options = o;
+			}
+		}
+		var values = d.trim(d.attr(node, "values")||"");
+		if(values){
+			var v = values.split(',');
+			if(v[0] != values){
+				cell.values = v;
+			}
+		}
+	}
+
+	dojo.declare("dojox.grid.cells.AlwaysEdit", dgc.Cell, {
+		// summary:
+		// grid cell that is always in an editable state, regardless of grid editing state
+		alwaysEditing: true,
+		_formatNode: function(inDatum, inRowIndex){
+			this.formatNode(this.getEditNode(inRowIndex), inDatum, inRowIndex);
+		},
+		applyStaticValue: function(inRowIndex){
+			var e = this.grid.edit;
+			e.applyCellEdit(this.getValue(inRowIndex), this, inRowIndex);
+			e.start(this, inRowIndex, true);
+		}
+	});
+	dgc.AlwaysEdit.markupFactory = function(node, cell){
+		dgc.Cell.markupFactory(node, cell);
+	}
+
+	dojo.declare("dojox.grid.cells.Bool", dgc.AlwaysEdit, {
+		// summary:
+		// grid cell that provides a standard checkbox that is always on for editing
+		_valueProp: "checked",
+		formatEditing: function(inDatum, inRowIndex){
+			return '<input class="dojoxGridInput" type="checkbox"' + (inDatum ? ' checked="checked"' : '') + ' style="width: auto" />';
+		},
+		doclick: function(e){
+			if(e.target.tagName == 'INPUT'){
+				this.applyStaticValue(e.rowIndex);
+			}
+		}
+	});
+	dgc.Bool.markupFactory = function(node, cell){
+		dgc.AlwaysEdit.markupFactory(node, cell);
+	}
+})();
+
+}
+
+if(!dojo._hasResource["dojox.grid.cells"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.grid.cells"] = true;
+dojo.provide("dojox.grid.cells");
+
+
+}
+
+if(!dojo._hasResource["dojo.dnd.common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.common"] = true;
+dojo.provide("dojo.dnd.common");
+
+dojo.dnd._isMac = navigator.appVersion.indexOf("Macintosh") >= 0;
+dojo.dnd._copyKey = dojo.dnd._isMac ? "metaKey" : "ctrlKey";
+
+dojo.dnd.getCopyKeyState = function(e) {
+	// summary: abstracts away the difference between selection on Mac and PC,
+	//	and returns the state of the "copy" key to be pressed.
+	// e: Event: mouse event
+	return e[dojo.dnd._copyKey];	// Boolean
+};
+
+dojo.dnd._uniqueId = 0;
+dojo.dnd.getUniqueId = function(){
+	// summary: returns a unique string for use with any DOM element
+	var id;
+	do{
+		id = dojo._scopeName + "Unique" + (++dojo.dnd._uniqueId);
+	}while(dojo.byId(id));
+	return id;
+};
+
+dojo.dnd._empty = {};
+
+dojo.dnd.isFormElement = function(/*Event*/ e){
+	// summary: returns true, if user clicked on a form element
+	var t = e.target;
+	if(t.nodeType == 3 /*TEXT_NODE*/){
+		t = t.parentNode;
+	}
+	return " button textarea input select option ".indexOf(" " + t.tagName.toLowerCase() + " ") >= 0;	// Boolean
+};
+
+// doesn't take into account when multiple buttons are pressed
+dojo.dnd._lmb = dojo.isIE ? 1 : 0;	// left mouse button
+
+dojo.dnd._isLmbPressed = dojo.isIE ?
+	function(e){ return e.button & 1; } : // intentional bit-and
+	function(e){ return e.button === 0; };
+
+}
+
+if(!dojo._hasResource["dojo.dnd.autoscroll"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+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)
+
+	// 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.dnd.V_TRIGGER_AUTOSCROLL = 32;
+dojo.dnd.H_TRIGGER_AUTOSCROLL = 32;
+
+dojo.dnd.V_AUTOSCROLL_VALUE = 16;
+dojo.dnd.H_AUTOSCROLL_VALUE = 16;
+
+dojo.dnd.autoScroll = function(e){
+	// summary:
+	//		a handler for onmousemove event, which scrolls the window, if
+	//		necesary
+	// e: Event:
+	//		onmousemove event
+
+	// FIXME: needs more docs!
+	var v = dojo.dnd.getViewport(), 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){
+		dx = dojo.dnd.H_AUTOSCROLL_VALUE;
+	}
+	if(e.clientY < dojo.dnd.V_TRIGGER_AUTOSCROLL){
+		dy = -dojo.dnd.V_AUTOSCROLL_VALUE;
+	}else if(e.clientY > v.h - dojo.dnd.V_TRIGGER_AUTOSCROLL){
+		dy = dojo.dnd.V_AUTOSCROLL_VALUE;
+	}
+	window.scrollBy(dx, dy);
+};
+
+dojo.dnd._validNodes = {"div": 1, "p": 1, "td": 1};
+dojo.dnd._validOverflow = {"auto": 1, "scroll": 1};
+
+dojo.dnd.autoScrollNodes = function(e){
+	// summary:
+	//		a handler for onmousemove event, which scrolls the first avaialble
+	//		Dom element, it falls back to dojo.dnd.autoScroll()
+	// e: Event:
+	//		onmousemove event
+
+	// FIXME: needs more docs!
+	for(var n = e.target; n;){
+		if(n.nodeType == 1 && (n.tagName.toLowerCase() in dojo.dnd._validNodes)){
+			var s = dojo.getComputedStyle(n);
+			if(s.overflow.toLowerCase() in dojo.dnd._validOverflow){
+				var b = dojo._getContentBox(n, s), t = dojo._abs(n, true);
+				//
+				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 
+					// either by the event fixing code, or the dojo._abs()
+					// FIXME: this code doesn't work on Opera 9.5 Beta
+					rx += dojo.body().scrollLeft, ry += dojo.body().scrollTop;
+				}
+				if(rx > 0 && rx < b.w){
+					if(rx < w){
+						dx = -w;
+					}else if(rx > b.w - w){
+						dx = w;
+					}
+				}
+				//
+				if(ry > 0 && ry < b.h){
+					if(ry < h){
+						dy = -h;
+					}else if(ry > b.h - h){
+						dy = h;
+					}
+				}
+				var oldLeft = n.scrollLeft, oldTop = n.scrollTop;
+				n.scrollLeft = n.scrollLeft + dx;
+				n.scrollTop  = n.scrollTop  + dy;
+				if(oldLeft != n.scrollLeft || oldTop != n.scrollTop){ return; }
+			}
+		}
+		try{
+			n = n.parentNode;
+		}catch(x){
+			n = null;
+		}
+	}
+	dojo.dnd.autoScroll(e);
+};
+
+}
+
+if(!dojo._hasResource["dojo.dnd.Mover"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Mover"] = true;
+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, 
+		//	used as a default mover, and as a base class for custom movers
+		// node: Node: a node (or node's id) to be moved
+		// e: Event: a mouse event, which started the move;
+		//	only pageX and pageY properties are used
+		// host: Object?: 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};
+		this.mouseButton = e.button;
+		var h = this.host = host, d = node.ownerDocument, 
+			firstEvent = dojo.connect(d, "onmousemove", this, "onFirstMove");
+		this.events = [
+			dojo.connect(d, "onmousemove", this, "onMouseMove"),
+			dojo.connect(d, "onmouseup",   this, "onMouseUp"),
+			// cancel text selection and text dragging
+			dojo.connect(d, "ondragstart",   dojo.stopEvent),
+			dojo.connect(d.body, "onselectstart", dojo.stopEvent),
+			firstEvent
+		];
+		// notify that the move has started
+		if(h && h.onMoveStart){
+			h.onMoveStart(this);
+		}
+	},
+	// mouse event processors
+	onMouseMove: function(e){
+		// summary: event processor for onmousemove
+		// e: Event: mouse event
+		dojo.dnd.autoScroll(e);
+		var m = this.marginBox;
+		this.host.onMove(this, {l: m.l + e.pageX, t: m.t + e.pageY});
+		dojo.stopEvent(e);
+	},
+	onMouseUp: function(e){
+		if(dojo.isWebKit && dojo.dnd._isMac && this.mouseButton == 2 ? 
+				e.button == 0 : this.mouseButton == e.button){
+			this.destroy();
+		}
+		dojo.stopEvent(e);
+	},
+	// utilities
+	onFirstMove: function(){
+		// summary: makes the node absolute; it is meant to be called only once
+		var s = this.node.style, l, t, h = this.host;
+		switch(s.position){
+			case "relative":
+			case "absolute":
+				// assume that left and top values are in pixels already
+				l = Math.round(parseFloat(s.left));
+				t = Math.round(parseFloat(s.top));
+				break;
+			default:
+				s.position = "absolute";	// enforcing the absolute mode
+				var m = dojo.marginBox(this.node);
+				// event.pageX/pageY (which we used to generate the initial
+				// margin box) includes padding and margin set on the body.
+				// However, setting the node's position to absolute and then
+				// doing dojo.marginBox on it *doesn't* take that additional
+				// 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. 
+				var b = dojo.doc.body;
+				var bs = dojo.getComputedStyle(b);
+				var bm = dojo._getMarginBox(b, bs);
+				var bc = dojo._getContentBox(b, bs);
+				l = m.l - (bc.l - bm.l);
+				t = m.t - (bc.t - bm.t);
+				break;
+		}
+		this.marginBox.l = l - this.marginBox.l;
+		this.marginBox.t = t - this.marginBox.t;
+		if(h && h.onFirstMove){
+			h.onFirstMove(this);
+		}
+		dojo.disconnect(this.events.pop());
+	},
+	destroy: function(){
+		// summary: stops the move, deletes all references, so the object can be garbage-collected
+		dojo.forEach(this.events, dojo.disconnect);
+		// undo global settings
+		var h = this.host;
+		if(h && h.onMoveStop){
+			h.onMoveStop(this);
+		}
+		// destroy objects
+		this.events = this.node = this.host = null;
+	}
+});
+
+}
+
+if(!dojo._hasResource["dojo.dnd.Moveable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.dnd.Moveable"] = true;
+dojo.provide("dojo.dnd.Moveable");
+
+
+
+dojo.declare("dojo.dnd.Moveable", null, {
+	// object attributes (for markup)
+	handle: "",
+	delay: 0,
+	skip: false,
+	
+	constructor: function(node, params){
+		// summary: an object, which makes a node moveable
+		// node: Node: a node (or node's id) to be moved
+		// params: Object: an optional object with additional parameters;
+		//	following parameters are recognized:
+		//		handle: Node: a node (or node's id), which is used as a mouse handle
+		//			if omitted, the node itself is used as a handle
+		//		delay: Number: delay move by this number of pixels
+		//		skip: Boolean: skip move of form elements
+		//		mover: Object: a constructor of custom Mover
+		this.node = dojo.byId(node);
+		if(!params){ params = {}; }
+		this.handle = params.handle ? dojo.byId(params.handle) : null;
+		if(!this.handle){ this.handle = this.node; }
+		this.delay = params.delay > 0 ? params.delay : 0;
+		this.skip  = params.skip;
+		this.mover = params.mover ? params.mover : dojo.dnd.Mover;
+		this.events = [
+			dojo.connect(this.handle, "onmousedown", this, "onMouseDown"),
+			// cancel text selection and text dragging
+			dojo.connect(this.handle, "ondragstart",   this, "onSelectStart"),
+			dojo.connect(this.handle, "onselectstart", this, "onSelectStart")
+		];
+	},
+
+	// markup methods
+	markupFactory: function(params, node){
+		return new dojo.dnd.Moveable(node, params);
+	},
+
+	// methods
+	destroy: function(){
+		// summary: stops watching for possible move, deletes all references, so the object can be garbage-collected
+		dojo.forEach(this.events, dojo.disconnect);
+		this.events = this.node = this.handle = null;
+	},
+	
+	// mouse event processors
+	onMouseDown: function(e){
+		// summary: event processor for onmousedown, creates a Mover for the node
+		// e: Event: mouse 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")
+			);
+			this._lastX = e.pageX;
+			this._lastY = e.pageY;
+		}else{
+			this.onDragDetected(e);
+		}
+		dojo.stopEvent(e);
+	},
+	onMouseMove: function(e){
+		// summary: event processor for onmousemove, 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){
+			this.onMouseUp(e);
+			this.onDragDetected(e);
+		}
+		dojo.stopEvent(e);
+	},
+	onMouseUp: function(e){
+		// summary: event processor for onmouseup, used only for delayed drags
+		// e: Event: mouse event
+		for(var i = 0; i < 2; ++i){
+			dojo.disconnect(this.events.pop());
+		}
+		dojo.stopEvent(e);
+	},
+	onSelectStart: function(e){
+		// summary: event processor for onselectevent and ondragevent
+		// e: Event: mouse event
+		if(!this.skip || !dojo.dnd.isFormElement(e)){
+			dojo.stopEvent(e);
+		}
+	},
+	
+	// local events
+	onDragDetected: function(/* Event */ e){
+		// summary: called when the drag is detected,
+		// responsible for creation of the mover
+		new this.mover(this.node, e, this);
+	},
+	onMoveStart: function(/* dojo.dnd.Mover */ mover){
+		// summary: called before every move operation
+		dojo.publish("/dnd/move/start", [mover]);
+		dojo.addClass(dojo.body(), "dojoMove"); 
+		dojo.addClass(this.node, "dojoMoveItem"); 
+	},
+	onMoveStop: function(/* dojo.dnd.Mover */ mover){
+		// summary: called after every move operation
+		dojo.publish("/dnd/move/stop", [mover]);
+		dojo.removeClass(dojo.body(), "dojoMove");
+		dojo.removeClass(this.node, "dojoMoveItem");
+	},
+	onFirstMove: function(/* dojo.dnd.Mover */ mover){
+		// summary: called during the very first move notification,
+		//	can be used to initialize coordinates, can be overwritten.
+		
+		// default implementation does nothing
+	},
+	onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
+		// summary: called during every move notification,
+		//	should actually move the node, can be overwritten.
+		this.onMoving(mover, leftTop);
+		var s = mover.node.style;
+		s.left = leftTop.l + "px";
+		s.top  = leftTop.t + "px";
+		this.onMoved(mover, leftTop);
+	},
+	onMoving: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
+		// summary: called before every incremental move,
+		//	can be overwritten.
+		
+		// default implementation does nothing
+	},
+	onMoved: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
+		// summary: called after every incremental move,
+		//	can be overwritten.
+		
+		// default implementation does nothing
+	}
+});
+
+}
+
+if(!dojo._hasResource["dojox.grid._Builder"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.grid._Builder"] = true;
+dojo.provide("dojox.grid._Builder");
+
+
+
+
+(function(){
+	var dg = dojox.grid;
+
+	var getTdIndex = function(td){
+		return td.cellIndex >=0 ? td.cellIndex : dojo.indexOf(td.parentNode.cells, td);
+	};
+	
+	var getTrIndex = function(tr){
+		return tr.rowIndex >=0 ? tr.rowIndex : dojo.indexOf(tr.parentNode.childNodes, tr);
+	};
+	
+	var getTr = function(rowOwner, index){
+		return rowOwner && ((rowOwner.rows||0)[index] || rowOwner.childNodes[index]);
+	};
+
+	var findTable = function(node){
+		for(var n=node; n && n.tagName!='TABLE'; n=n.parentNode);
+		return n;
+	};
+	
+	var ascendDom = function(inNode, inWhile){
+		for(var n=inNode; n && inWhile(n); n=n.parentNode);
+		return n;
+	};
+	
+	var makeNotTagName = function(inTagName){
+		var name = inTagName.toUpperCase();
+		return function(node){ return node.tagName != name; };
+	};
+
+	var rowIndexTag = dojox.grid.util.rowIndexTag;
+	var gridViewTag = dojox.grid.util.gridViewTag;
+
+	// base class for generating markup for the views
+	dg._Builder = dojo.extend(function(view){
+		if(view){
+			this.view = view;
+			this.grid = view.grid;
+		}
+	},{
+		view: null,
+		// boilerplate HTML
+		_table: '<table class="dojoxGridRowTable" border="0" cellspacing="0" cellpadding="0" role="wairole:presentation"',
+
+		// Returns the table variable as an array - and with the view width, if specified
+		getTableArray: function(){
+			var html = [this._table];
+			if(this.view.viewWidth){
+				html.push([' style="width:', this.view.viewWidth, ';"'].join(''));
+			}
+			html.push('>');
+			return html;
+		},
+		
+		// generate starting tags for a cell
+		generateCellMarkup: function(inCell, inMoreStyles, inMoreClasses, isHeader){
+			var result = [], html;
+			var waiPrefix = dojo.isFF<3 ? "wairole:" : "";
+			if(isHeader){
+				html = ['<th tabIndex="-1" role="', waiPrefix, 'columnheader"'];
+			}else{
+				html = ['<td tabIndex="-1" role="', waiPrefix, 'gridcell"'];
+			}
+			inCell.colSpan && html.push(' colspan="', inCell.colSpan, '"');
+			inCell.rowSpan && html.push(' rowspan="', inCell.rowSpan, '"');
+			html.push(' class="dojoxGridCell ');
+			inCell.classes && html.push(inCell.classes, ' ');
+			inMoreClasses && html.push(inMoreClasses, ' ');
+			// result[0] => td opener, style
+			result.push(html.join(''));
+			// SLOT: result[1] => td classes 
+			result.push('');
+			html = ['" idx="', inCell.index, '" style="'];
+			if(inMoreStyles && inMoreStyles[inMoreStyles.length-1] != ';'){
+				inMoreStyles += ';';
+			}
+			html.push(inCell.styles, inMoreStyles||'', inCell.hidden?'display:none;':'');
+			inCell.unitWidth && html.push('width:', inCell.unitWidth, ';');
+			// result[2] => markup
+			result.push(html.join(''));
+			// SLOT: result[3] => td style 
+			result.push('');
+			html = [ '"' ];
+			inCell.attrs && html.push(" ", inCell.attrs);
+			html.push('>');
+			// result[4] => td postfix
+			result.push(html.join(''));
+			// SLOT: result[5] => content
+			result.push('');
+			// result[6] => td closes
+			result.push('</td>');
+			return result; // Array
+		},
+
+		// cell finding
+		isCellNode: function(inNode){
+			return Boolean(inNode && inNode!=dojo.doc && dojo.attr(inNode, "idx"));
+		},
+		
+		getCellNodeIndex: function(inCellNode){
+			return inCellNode ? Number(dojo.attr(inCellNode, "idx")) : -1;
+		},
+		
+		getCellNode: function(inRowNode, inCellIndex){
+			for(var i=0, row; row=getTr(inRowNode.firstChild, i); i++){
+				for(var j=0, cell; cell=row.cells[j]; j++){
+					if(this.getCellNodeIndex(cell) == inCellIndex){
+						return cell;
+					}
+				}
+			}
+		},
+		
+		findCellTarget: function(inSourceNode, inTopNode){
+			var n = inSourceNode;
+			while(n && (!this.isCellNode(n) || (n.offsetParent && gridViewTag in n.offsetParent.parentNode && n.offsetParent.parentNode[gridViewTag] != this.view.id)) && (n!=inTopNode)){
+				n = n.parentNode;
+			}
+			return n!=inTopNode ? n : null 
+		},
+		
+		// event decoration
+		baseDecorateEvent: function(e){
+			e.dispatch = 'do' + e.type;
+			e.grid = this.grid;
+			e.sourceView = this.view;
+			e.cellNode = this.findCellTarget(e.target, e.rowNode);
+			e.cellIndex = this.getCellNodeIndex(e.cellNode);
+			e.cell = (e.cellIndex >= 0 ? this.grid.getCell(e.cellIndex) : null);
+		},
+		
+		// event dispatch
+		findTarget: function(inSource, inTag){
+			var n = inSource;
+			while(n && (n!=this.domNode) && (!(inTag in n) || (gridViewTag in n && n[gridViewTag] != this.view.id))){
+				n = n.parentNode;
+			}
+			return (n != this.domNode) ? n : null; 
+		},
+
+		findRowTarget: function(inSource){
+			return this.findTarget(inSource, rowIndexTag);
+		},
+
+		isIntraNodeEvent: function(e){
+			try{
+				return (e.cellNode && e.relatedTarget && dojo.isDescendant(e.relatedTarget, e.cellNode));
+			}catch(x){
+				// e.relatedTarget has permission problem in FF if it's an input: https://bugzilla.mozilla.org/show_bug.cgi?id=208427
+				return false;
+			}
+		},
+
+		isIntraRowEvent: function(e){
+			try{
+				var row = e.relatedTarget && this.findRowTarget(e.relatedTarget);
+				return !row && (e.rowIndex==-1) || row && (e.rowIndex==row.gridRowIndex);			
+			}catch(x){
+				// e.relatedTarget on INPUT has permission problem in FF: https://bugzilla.mozilla.org/show_bug.cgi?id=208427
+				return false;
+			}
+		},
+
+		dispatchEvent: function(e){
+			if(e.dispatch in this){
+				return this[e.dispatch](e);
+			}
+		},
+
+		// dispatched event handlers
+		domouseover: function(e){
+			if(e.cellNode && (e.cellNode!=this.lastOverCellNode)){
+				this.lastOverCellNode = e.cellNode;
+				this.grid.onMouseOver(e);
+			}
+			this.grid.onMouseOverRow(e);
+		},
+
+		domouseout: function(e){
+			if(e.cellNode && (e.cellNode==this.lastOverCellNode) && !this.isIntraNodeEvent(e, this.lastOverCellNode)){
+				this.lastOverCellNode = null;
+				this.grid.onMouseOut(e);
+				if(!this.isIntraRowEvent(e)){
+					this.grid.onMouseOutRow(e);
+				}
+			}
+		},
+		
+		domousedown: function(e){
+			if (e.cellNode)
+				this.grid.onMouseDown(e);
+			this.grid.onMouseDownRow(e)
+		}
+	});
+
+	// Produces html for grid data content. Owned by grid and used internally 
+	// for rendering data. Override to implement custom rendering.
+	dg._ContentBuilder = dojo.extend(function(view){
+		dg._Builder.call(this, view);
+	},dg._Builder.prototype,{
+		update: function(){
+			this.prepareHtml();
+		},
+
+		// cache html for rendering data rows
+		prepareHtml: function(){
+			var defaultGet=this.grid.get, cells=this.view.structure.cells;
+			for(var j=0, row; (row=cells[j]); j++){
+				for(var i=0, cell; (cell=row[i]); i++){
+					cell.get = cell.get || (cell.value == undefined) && defaultGet;
+					cell.markup = this.generateCellMarkup(cell, cell.cellStyles, cell.cellClasses, false);
+				}
+			}
+		},
+
+		// time critical: generate html using cache and data source
+		generateHtml: function(inDataIndex, inRowIndex){
+			var
+				html = this.getTableArray(),
+				v = this.view,
+				cells = v.structure.cells,
+				item = this.grid.getItem(inRowIndex);
+
+			dojox.grid.util.fire(this.view, "onBeforeRow", [inRowIndex, cells]);
+			for(var j=0, row; (row=cells[j]); j++){
+				if(row.hidden || row.header){
+					continue;
+				}
+				html.push(!row.invisible ? '<tr>' : '<tr class="dojoxGridInvisible">');
+				for(var i=0, cell, m, cc, cs; (cell=row[i]); i++){
+					m = cell.markup, cc = cell.customClasses = [], cs = cell.customStyles = [];
+					// content (format can fill in cc and cs as side-effects)
+					m[5] = cell.format(inRowIndex, item);
+					// classes
+					m[1] = cc.join(' ');
+					// styles
+					m[3] = cs.join(';');
+					// in-place concat
+					html.push.apply(html, m);
+				}
+				html.push('</tr>');
+			}
+			html.push('</table>');
+			return html.join(''); // String
+		},
+
+		decorateEvent: function(e){
+			e.rowNode = this.findRowTarget(e.target);
+			if(!e.rowNode){return false};
+			e.rowIndex = e.rowNode[rowIndexTag];
+			this.baseDecorateEvent(e);
+			e.cell = this.grid.getCell(e.cellIndex);
+			return true; // Boolean
+		}
+	});
+
+	// Produces html for grid header content. Owned by grid and used internally 
+	// for rendering data. Override to implement custom rendering.
+	dg._HeaderBuilder = dojo.extend(function(view){
+		this.moveable = null;
+		dg._Builder.call(this, view);
+	},dg._Builder.prototype,{
+		_skipBogusClicks: false,
+		overResizeWidth: 4,
+		minColWidth: 1,
+		
+		update: function(){
+			if(this.tableMap){
+				this.tableMap.mapRows(this.view.structure.cells);
+			}else{
+				this.tableMap = new dg._TableMap(this.view.structure.cells);
+			}
+		},
+
+		generateHtml: function(inGetValue, inValue){
+			var html = this.getTableArray(), cells = this.view.structure.cells;
+			
+			dojox.grid.util.fire(this.view, "onBeforeRow", [-1, cells]);
+			for(var j=0, row; (row=cells[j]); j++){
+				if(row.hidden){
+					continue;
+				}
+				html.push(!row.invisible ? '<tr>' : '<tr class="dojoxGridInvisible">');
+				for(var i=0, cell, markup; (cell=row[i]); i++){
+					cell.customClasses = [];
+					cell.customStyles = [];
+					if(this.view.simpleStructure){
+						if(cell.headerClasses){
+							if(cell.headerClasses.indexOf('dojoDndItem') == -1){

[... 6619 lines stripped ...]