You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by jk...@apache.org on 2006/09/23 01:22:51 UTC

svn commit: r449122 [32/40] - in /tapestry/tapestry4/trunk/tapestry-framework/src: java/org/apache/tapestry/ java/org/apache/tapestry/dojo/ java/org/apache/tapestry/dojo/form/ java/org/apache/tapestry/dojo/html/ java/org/apache/tapestry/form/ java/org/...

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeCommon.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeCommon.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeCommon.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeCommon.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,128 @@
+/*
+	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("dojo.widget.TreeCommon");
+dojo.require("dojo.widget.*"); // for dojo.widget.manager
+
+dojo.declare(
+	"dojo.widget.TreeCommon",
+	null,
+{
+	listenTreeEvents: [],
+	listenedTrees: {},
+	
+	/**
+	 * evaluates to false => skip unlistening nodes
+	 * provided => use it
+	 */	
+	listenNodeFilter: null,
+	
+	listenTree: function(tree) {
+		
+		//dojo.debug("listenTree in "+this+" tree "+tree);
+		
+		var _this = this;
+		
+		if (this.listenedTrees[tree.widgetId]) {
+			return; // already listening
+		}
+		
+		dojo.lang.forEach(this.listenTreeEvents, function(event) {
+			var eventHandler =  "on" + event.charAt(0).toUpperCase() + event.substr(1);
+			//dojo.debug("subscribe: event "+tree.eventNames[event]+" widget "+_this+" handler "+eventHandler);
+			dojo.event.topic.subscribe(tree.eventNames[event], _this, eventHandler);
+		});
+		
+		
+		var filter;
+		
+		if (this.listenNodeFilter) {			
+			this.processDescendants(tree, this.listenNodeFilter, this.listenNode, true);
+		}
+		
+		/**
+		 * remember that I listen to this tree. No unbinding/binding/deselection
+		 * needed when transfer between listened trees
+		 */
+		this.listenedTrees[tree.widgetId] = true;
+		
+	},			
+	
+	// interface functions
+	listenNode: function() {},	
+	unlistenNode: function() {},
+			
+	unlistenTree: function(tree, nodeFilter) {
+		
+		var _this = this;
+	
+		if (!this.listenedTrees[tree.widgetId]) {
+			return; 
+		}
+		
+		dojo.lang.forEach(this.listenTreeEvents, function(event) {
+			var eventHandler =  "on" + event.charAt(0).toUpperCase() + event.substr(1);
+			dojo.event.topic.unsubscribe(tree.eventNames[event], _this, eventHandler);
+		});
+		
+		
+		if (this.listenNodeFilter) {
+			this.processDescendants(tree, this.listenNodeFilter, this.unlistenNode, true);
+		}
+		
+		delete this.listenedTrees[tree.widgetId];
+		
+	},
+	
+	
+	domElement2TreeNode: function(domElement) {
+		while (domElement && !domElement.widgetId) {
+			domElement = domElement.parentNode;
+		}
+		
+		if (!domElement) {
+			return null;
+		}
+		
+		var widget = dojo.widget.byId(domElement.widgetId);
+		if (!widget.isTreeNode) {
+			return null;
+		}
+		
+		return widget;
+	},
+	
+	/**
+	 * it is here, not in Widget, because mostly tree needs it
+	 */
+	processDescendants: function(elem, filter, func, skipFirst) {
+		
+		var _this = this;
+		
+		if (!skipFirst) {
+			if (!filter.call(_this,elem)) {
+				return;
+			}
+			func.call(_this,elem);	        
+		}
+		
+		
+		var stack = [elem];
+		while (elem = stack.pop()) {
+			dojo.lang.forEach(elem.children, function(elem) {
+				if (filter.call(_this, elem)) {		
+					func.call(_this, elem);
+					stack.push(elem);
+				}
+			});
+		}
+    }
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeCommon.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeContextMenu.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeContextMenu.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeContextMenu.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeContextMenu.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,216 @@
+/*
+	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("dojo.widget.TreeContextMenu");
+dojo.provide("dojo.widget.TreeMenuItem");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.Menu2");
+
+dojo.deprecated("dojo.widget.TreeContextMenu", "use TreeV3 and TreeContextMenuV3 instead", "0.5");
+
+
+dojo.widget.tags.addParseTreeHandler("dojo:TreeContextMenu");
+dojo.widget.tags.addParseTreeHandler("dojo:TreeMenuItem");
+
+
+
+dojo.widget.TreeContextMenu = function() {
+	dojo.widget.PopupMenu2.call(this);
+
+	this.listenedTrees = [];
+
+}
+
+
+dojo.inherits(dojo.widget.TreeContextMenu, dojo.widget.PopupMenu2);
+
+dojo.lang.extend(dojo.widget.TreeContextMenu, {
+
+	widgetType: "TreeContextMenu",
+
+	open: function(x, y, parentMenu, explodeSrc){
+
+		var result = dojo.widget.PopupMenu2.prototype.open.apply(this, arguments);
+
+		/* publish many events here about structural changes */
+		dojo.event.topic.publish(this.eventNames.open, { menu:this });
+
+		return result;
+	},
+
+	listenTree: function(tree) {
+		/* add context menu to all nodes that exist already */
+		var nodes = tree.getDescendants();
+
+		for(var i=0; i<nodes.length; i++) {
+			if (!nodes[i].isTreeNode) continue;
+			this.bindDomNode(nodes[i].labelNode);
+		}
+
+
+		/* bind context menu to all nodes that will be created in the future (e.g loaded from server)*/
+		var _this = this;
+		dojo.event.topic.subscribe(tree.eventNames.createDOMNode, this, "onCreateDOMNode");
+		dojo.event.topic.subscribe(tree.eventNames.moveFrom, this, "onMoveFrom");
+		dojo.event.topic.subscribe(tree.eventNames.moveTo, this, "onMoveTo");
+		dojo.event.topic.subscribe(tree.eventNames.removeNode, this, "onRemoveNode");
+		dojo.event.topic.subscribe(tree.eventNames.addChild, this, "onAddChild");
+		dojo.event.topic.subscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");
+
+		this.listenedTrees.push(tree);
+
+	},
+
+	unlistenTree: function(tree) {
+		/* clear event listeners */
+
+		dojo.event.topic.unsubscribe(tree.eventNames.createDOMNode, this, "onCreateDOMNode");
+		dojo.event.topic.unsubscribe(tree.eventNames.moveFrom, this, "onMoveFrom");
+		dojo.event.topic.unsubscribe(tree.eventNames.moveTo, this, "onMoveTo");
+		dojo.event.topic.unsubscribe(tree.eventNames.removeNode, this, "onRemoveNode");
+		dojo.event.topic.unsubscribe(tree.eventNames.addChild, this, "onAddChild");
+		dojo.event.topic.unsubscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");
+
+		for(var i=0; i<this.listenedTrees.length; i++){
+           if(this.listenedTrees[i] === tree){
+                   this.listenedTrees.splice(i, 1);
+                   break;
+           }
+		}
+	},
+
+	onTreeDestroy: function(message) {
+		this.unlistenTree(message.source);
+	},
+
+	bindTreeNode: function(node) {
+		var _this = this;
+		//dojo.debug("bind to "+node);
+		dojo.lang.forEach(node.getDescendants(),
+			function(e) {_this.bindDomNode(e.labelNode); }
+		);
+	},
+
+
+	unBindTreeNode: function(node) {
+		var _this = this;
+		//dojo.debug("Unbind from "+node);
+		dojo.lang.forEach(node.getDescendants(),
+			function(e) {_this.unBindDomNode(e.labelNode); }
+		);
+	},
+
+	onCreateDOMNode: function(message) {
+		this.bindTreeNode(message.source);
+	},
+
+
+	onMoveFrom: function(message) {
+		if (!dojo.lang.inArray(this.listenedTrees, message.newTree)) {
+			this.unBindTreeNode(message.child);
+		}
+	},
+
+	onMoveTo: function(message) {
+		if (dojo.lang.inArray(this.listenedTrees, message.newTree)) {
+			this.bindTreeNode(message.child);
+		}
+	},
+
+	onRemoveNode: function(message) {
+		this.unBindTreeNode(message.child);
+	},
+
+	onAddChild: function(message) {
+		if (message.domNodeInitialized) {
+			// dom node was there already => I did not process onNodeDomCreate
+			this.bindTreeNode(message.child);
+		}
+	}
+
+
+});
+
+
+
+
+
+
+dojo.widget.TreeMenuItem = function() {
+	dojo.widget.MenuItem2.call(this);
+
+}
+
+
+dojo.inherits(dojo.widget.TreeMenuItem, dojo.widget.MenuItem2);
+
+
+dojo.lang.extend(dojo.widget.TreeMenuItem, {
+
+	widgetType: "TreeMenuItem",
+
+	// treeActions menu item performs following actions (to be checked for permissions)
+	treeActions: "",
+
+	initialize: function(args, frag) {
+
+		this.treeActions = this.treeActions.split(",");
+		for(var i=0; i<this.treeActions.length; i++) {
+			this.treeActions[i] = this.treeActions[i].toUpperCase();
+		}
+
+	},
+
+	getTreeNode: function() {
+		var menu = this;
+
+		while (! (menu instanceof dojo.widget.TreeContextMenu) ) {
+			menu = menu.parent;
+		}
+
+		var source = menu.getTopOpenEvent().target;
+
+		while (!source.getAttribute('treeNode') && source.tagName != 'body') {
+			source = source.parentNode;
+		}
+		if (source.tagName == 'body') {
+			dojo.raise("treeNode not detected");
+		}
+		var treeNode = dojo.widget.manager.getWidgetById(source.getAttribute('treeNode'));
+
+		return treeNode;
+	},
+
+
+	menuOpen: function(message) {
+		var treeNode = this.getTreeNode();
+
+		this.setDisabled(false); // enable by default
+
+		var _this = this;
+		dojo.lang.forEach(_this.treeActions,
+			function(action) {
+				_this.setDisabled( treeNode.actionIsDisabled(action) );
+			}
+		);
+
+	},
+
+	toString: function() {
+		return "["+this.widgetType+" node "+this.getTreeNode()+"]";
+	}
+
+});
+
+

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeContextMenu.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeContextMenuV3.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeContextMenuV3.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeContextMenuV3.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeContextMenuV3.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,122 @@
+/*
+	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("dojo.widget.TreeContextMenuV3");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.Menu2");
+dojo.require("dojo.widget.TreeCommon");
+
+dojo.widget.defineWidget(
+	"dojo.widget.TreeContextMenuV3",
+	[dojo.widget.PopupMenu2, dojo.widget.TreeCommon],
+	function() {
+		this.listenedTrees = {};
+	},
+{
+	open: function(x, y, parentMenu, explodeSrc){
+
+		var result = dojo.widget.PopupMenu2.prototype.open.apply(this, arguments);
+
+		/* publish many events here about structural changes */
+		dojo.event.topic.publish(this.eventNames.open, { menu:this });
+
+		return result;
+	},
+
+	listenTreeEvents: ["afterChangeTree","beforeTreeDestroy"],
+	listenNodeFilter: function(elem) { return elem instanceof dojo.widget.Widget},
+	
+	onBeforeTreeDestroy: function(message) {
+		this.unlistenTree(message.source);
+	},
+
+
+	onAfterChangeTree: function(message) {
+		//dojo.debugShallow(message);
+				
+		            
+		if (!message.newTree || !this.listenedTrees[message.newTree.widgetId]) {
+			// I got this message because node leaves me (oldtree)
+			this.processDescendants(message.node, this.listenNodeFilter, this.unlistenNode);
+		}		
+		
+		if (!message.oldTree || !this.listenedTrees[message.oldTree.widgetId]) {
+			// we have new node
+			this.processDescendants(message.node, this.listenNodeFilter, this.listenNode);
+		}
+		
+		//dojo.profile.end("onTreeChange");
+	},
+
+	
+	listenNode: function(node) {
+		this.bindDomNode(node.labelNode);
+	},
+
+
+	unlistenNode: function(node) {
+		this.unBindDomNode(node.labelNode);
+	}
+});
+
+
+dojo.widget.defineWidget(
+	"dojo.widget.TreeMenuItemV3",
+	[dojo.widget.MenuItem2, dojo.widget.TreeCommon],
+	function() {
+		this.treeActions = [];
+	},
+{
+	// treeActions menu item performs following actions (to be checked for permissions)
+	treeActions: "",
+
+	initialize: function(args, frag) {
+		for(var i=0; i<this.treeActions.length; i++) {
+			this.treeActions[i] = this.treeActions[i].toUpperCase();
+		}
+	},
+
+	getTreeNode: function() {
+		var menu = this;
+
+		// FIXME: change to dojo.widget[this.widgetType]
+		while (! (menu instanceof dojo.widget.TreeContextMenuV3) ) {
+			menu = menu.parent;
+		}
+
+		var source = menu.getTopOpenEvent().target;
+
+		var treeNode = this.domElement2TreeNode(source);
+		
+		return treeNode;
+	},
+
+
+	menuOpen: function(message) {
+		var treeNode = this.getTreeNode();
+
+		this.setDisabled(false); // enable by default
+
+		var _this = this;
+		dojo.lang.forEach(_this.treeActions,
+			function(action) {
+				_this.setDisabled( treeNode.actionIsDisabledNow(action) );
+			}
+		);
+
+	},
+
+	toString: function() {
+		return "["+this.widgetType+" node "+this.getTreeNode()+"]";
+	}
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeContextMenuV3.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeControllerExtension.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeControllerExtension.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeControllerExtension.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeControllerExtension.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,94 @@
+/*
+	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
+*/
+
+/**
+ * Additional tree utils
+ *
+ */
+dojo.provide("dojo.widget.TreeControllerExtension");
+
+dojo.declare(
+	"dojo.widget.TreeControllerExtension",
+	null,
+{
+	saveExpandedIndices: function(node, field) {
+		var obj = {};
+
+		for(var i=0; i<node.children.length; i++) {
+			if (node.children[i].isExpanded) {
+				var key = dojo.lang.isUndefined(field) ? i : node.children[i][field];
+				obj[key] = this.saveExpandedIndices(node.children[i], field);
+			}
+		}
+
+		return obj;
+	},
+
+
+	restoreExpandedIndices: function(node, savedIndices, field) {
+		var _this = this;
+
+		var handler = function(node, savedIndices) {
+			this.node = node; //.children[i];
+			this.savedIndices = savedIndices; //[i];
+			// recursively read next savedIndices level and apply to opened node
+			this.process = function() {
+				//dojo.debug("Callback applied for "+this.node);
+				_this.restoreExpandedIndices(this.node, this.savedIndices, field);
+			};
+		}
+
+
+		for(var i=0; i<node.children.length; i++) {
+			var child = node.children[i];
+
+			var found = false;
+			var key = -1;
+
+			//dojo.debug("Check "+child)
+			// process field set case
+			if (dojo.lang.isUndefined(field) && savedIndices[i]) {
+				found = true;
+				key = i;
+			}
+
+			// process case when field is not set
+			if (field) {
+				for(var key in savedIndices) {
+					//dojo.debug("Compare "+key+" "+child[field])
+					if (key == child[field]) {
+						found = true;
+						break;
+					}
+				}
+			}
+
+			// if we found anything - expand it
+			if (found) {
+				//dojo.debug("Found at "+key)
+				var h = new handler(child, savedIndices[key]);
+				_this.expand(child, false, h, h.process);
+			} else if (child.isExpanded) { // not found, so collapse
+				//dojo.debug("Collapsing all descendants "+node.children[i])
+				dojo.lang.forEach(child.getDescendants(), function(elem) { _this.collapse(elem); });
+				//this.collapse(node.children[i]);
+			}
+
+		}
+
+
+	}
+
+});
+
+
+
+
+

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeControllerExtension.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDemo.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDemo.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDemo.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDemo.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,123 @@
+/*
+	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("dojo.widget.TreeDemo");
+dojo.require("dojo.Deferred");
+
+dojo.widget.TreeDemo = {
+	
+	reportIfDefered: function(res) {
+		if (res instanceof dojo.Deferred) {			
+			res.addCallbacks(
+				function(res) { /* dojo.debug("OK " + (res ? res: '')); */ return res },
+				function(err) { dojo.debug("Error"); dojo.debugShallow(err); }
+			);
+		}		
+	},
+	
+	resetRandomChildren: function(maxCount) {
+		this.randomChildrenMaxCount = maxCount;
+		this.randomChildrenCount = 0;
+		this.randomChildrenDepth = 0;
+	},
+	
+	
+	makeRandomChildren: function(title) {		
+
+		this.randomChildrenDepth++;
+			
+		var children = [];
+		for (var i=1; i<=5; i++) {				
+
+			var t = title+(this.randomChildrenDepth==1 ? '' : '.')+i;
+			var node = {title: t};
+				
+			children.push(node);		
+			this.randomChildrenCount++	
+			if (this.randomChildrenCount >= this.randomChildrenMaxCount) {
+				break;			
+			}
+		}
+
+		var i=1;
+		var _this = this;
+		dojo.lang.forEach(children, function(child) {
+			var t = title+(_this.randomChildrenDepth==1 ? '' : '.')+i;
+			i++;
+		
+			// first node is always folder for tests
+			if (_this.randomChildrenCount<_this.randomChildrenMaxCount && (
+				_this.randomChildrenDepth==1 && child === children[0] || _this.randomChildrenDepth<5 && Math.random()>0.3 )
+			  ) {
+				//dojo.debug("add child "+t);
+				child.children = _this.makeRandomChildren(t);	
+			}
+		});
+				
+
+			//dojo.debug("out "+nodeOrTree);
+			
+		this.randomChildrenDepth--;
+			
+		return children;			
+	},
+	
+	bindDemoMenu: function(controller) {
+		var _t = this;
+		
+		dojo.event.topic.subscribe('treeContextMenuDestroy/engage',
+			function (menuItem) { 
+				var node = menuItem.getTreeNode();
+				//if (confirm("Delete node with descendants: "+node.title.replace(/(<([^>]+)>)/ig," ") +" ?")) {
+				_t.reportIfDefered(controller.destroyChild(node)); 
+				
+			}
+		);
+
+
+		dojo.event.topic.subscribe('treeContextMenuCreate/engage',
+			function (menuItem) {
+				var node = menuItem.getTreeNode();
+				var d = controller.createAndEdit(node, 0);
+				_t.reportIfDefered(d);
+            }
+		);
+
+
+		dojo.event.topic.subscribe('treeContextMenuUp/engage',
+			function (menuItem) {
+                var node = menuItem.getTreeNode();
+                if (node.isFirstChild()) return;
+                _t.reportIfDefered(controller.move(node, node.parent, node.getParentIndex()-1));
+            }
+		);
+
+
+		dojo.event.topic.subscribe('treeContextMenuDown/engage',
+			function (menuItem) {
+                var node = menuItem.getTreeNode();
+                if (node.isLastChild()) return;
+                _t.reportIfDefered(controller.move(node, node.parent, node.getParentIndex()+1));
+            }
+		);
+
+		dojo.event.topic.subscribe('treeContextMenuEdit/engage',
+			function (menuItem) {
+                var node = menuItem.getTreeNode();
+                _t.reportIfDefered(controller.editLabelStart(node));
+			}
+		);
+
+	}
+	
+	
+	
+}

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDemo.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDeselectOnDblselect.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDeselectOnDblselect.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDeselectOnDblselect.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDeselectOnDblselect.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,36 @@
+/*
+	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("dojo.widget.TreeDeselectOnDblselect");
+
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.TreeSelectorV3");
+
+// selector extension to emphase node
+
+dojo.widget.defineWidget(
+	"dojo.widget.TreeDeselectOnDblselect",
+	[dojo.widget.HtmlWidget],
+{
+	selector: "",
+	
+	initialize: function() {
+		this.selector = dojo.widget.byId(this.selector);
+		//dojo.debug("OK "+this.selector);
+		dojo.event.topic.subscribe(this.selector.eventNames.dblselect, this, "onDblselect");		
+	},
+
+	onDblselect: function(message) {
+		//dojo.debug("happen "+this.selector);
+		//dojo.debug(message.node);
+		this.selector.deselect(message.node);
+	}
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDeselectOnDblselect.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDisableWrapExtension.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDisableWrapExtension.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDisableWrapExtension.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDisableWrapExtension.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,55 @@
+/*
+	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( "dojo.widget.TreeDisableWrapExtension" );
+
+dojo.require( "dojo.widget.HtmlWidget" );
+dojo.require( "dojo.widget.TreeExtension" );
+
+// selector extension to emphase node
+dojo.widget.defineWidget(
+	"dojo.widget.TreeDisableWrapExtension",
+	dojo.widget.TreeExtension,
+{
+	/**
+	 * can't unlisten
+	 */
+	templateCssPath: dojo.uri.dojoUri( "src/widget/templates/TreeDisableWrap.css" ),
+		
+	listenTree: function(tree) {
+		
+		var wrappingDiv = document.createElement( "div" );
+		var clazz = tree.classPrefix+"DisableWrap";
+		if (dojo.render.html.ie) {
+			clazz = clazz+' '+ tree.classPrefix+"IEDisableWrap";
+		}
+		dojo.html.setClass(wrappingDiv, clazz);
+		
+		var table = document.createElement( "table" );
+		wrappingDiv.appendChild( table );
+		
+		var tbody = document.createElement( "tbody" );
+		table.appendChild( tbody );
+		
+		var tr = document.createElement( "tr" );
+		tbody.appendChild( tr );
+		
+		var td = document.createElement( "td" );
+		tr.appendChild( td );
+		
+		if( tree.domNode.parentNode ) {
+			tree.domNode.parentNode.replaceChild( wrappingDiv, tree.domNode );
+		}
+		
+		td.appendChild( tree.domNode );
+		tree.domNode = wrappingDiv;
+	}
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDisableWrapExtension.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDndControllerV3.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDndControllerV3.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDndControllerV3.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDndControllerV3.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,137 @@
+/*
+	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("dojo.widget.TreeDndControllerV3");
+
+dojo.require("dojo.dnd.TreeDragAndDropV3");
+	
+dojo.widget.defineWidget(
+	"dojo.widget.TreeDndControllerV3",
+	[dojo.widget.HtmlWidget, dojo.widget.TreeCommon],
+	function() {
+		this.dragSources = {};
+		this.dropTargets = {};
+		this.listenedTrees = {};
+	},
+{
+	listenTreeEvents: ["afterChangeTree","beforeTreeDestroy", "afterAddChild"],
+	listenNodeFilter: function(elem) { return elem instanceof dojo.widget.Widget}, 
+	
+	initialize: function(args) {
+		this.treeController = dojo.lang.isString(args.controller) ? dojo.widget.byId(args.controller) : args.controller;
+		
+		if (!this.treeController) {
+			dojo.raise("treeController must be declared");
+		}
+		
+	},
+
+	onBeforeTreeDestroy: function(message) {
+		this.unlistenTree(message.source);
+	},
+	
+	// first Dnd registration happens in addChild
+	// because I have information about parent on this stage and can use it
+	// to check locking or other things
+	onAfterAddChild: function(message) {
+		//dojo.debug("Dnd addChild "+message.child);
+		this.listenNode(message.child);		
+	},
+
+
+	onAfterChangeTree: function(message) {
+		/* catch new nodes on afterAddChild, because I need parent */		
+		if (!message.oldTree) return;
+		
+		//dojo.debug("HERE");
+		
+		if (!message.newTree || !this.listenedTrees[message.newTree.widgetId]) {			
+			this.processDescendants(message.node, this.listenNodeFilter, this.unlistenNode);
+		}		
+		
+		if (!this.listenedTrees[message.oldTree.widgetId]) {
+			// we have new node
+			this.processDescendants(message.node, this.listenNodeFilter, this.listenNode);	
+		}
+		//dojo.profile.end("onTreeChange");
+	},
+	
+	
+	/**
+	 * Controller(node model) creates DndNodes because it passes itself to node for synchroneous drops processing
+	 * I can't process DnD with events cause an event can't return result success/false
+	*/
+	listenNode: function(node) {
+
+		//dojo.debug("listen dnd "+node);
+		//dojo.debug((new Error()).stack)
+		//dojo.profile.start("Dnd listenNode "+node);		
+		if (!node.tree.DndMode) return;
+		if (this.dragSources[node.widgetId] || this.dropTargets[node.widgetId]) return;
+
+	
+		/* I drag label, not domNode, because large domNodes are very slow to copy and large to drag */
+
+		var source = null;
+		var target = null;
+
+	
+		if (!node.actionIsDisabled(node.actions.MOVE)) {
+			//dojo.debug("reg source")
+			
+			//dojo.profile.start("Dnd source "+node);		
+			var source = this.makeDragSource(node);
+			//dojo.profile.end("Dnd source "+node);		
+
+			this.dragSources[node.widgetId] = source;
+		}
+
+		//dojo.profile.start("Dnd target "+node);		
+		//dojo.debug("reg target");
+		var target = this.makeDropTarget(node);
+		//dojo.profile.end("Dnd target "+node);		
+
+		this.dropTargets[node.widgetId] = target;
+
+		//dojo.profile.end("Dnd listenNode "+node);		
+
+
+	},
+	
+	/**
+	 * Factory method, override it to create special source
+	 */
+	makeDragSource: function(node) {
+		return new dojo.dnd.TreeDragSourceV3(node.contentNode, this, node.tree.widgetId, node);
+	},
+
+
+	/**
+	 * Factory method, override it to create special target
+	 */
+	makeDropTarget: function(node) {
+		 return new dojo.dnd.TreeDropTargetV3(node.contentNode, this.treeController, node.tree.DndAcceptTypes, node);
+	},
+
+	unlistenNode: function(node) {
+
+		if (this.dragSources[node.widgetId]) {
+			dojo.dnd.dragManager.unregisterDragSource(this.dragSources[node.widgetId]);
+			delete this.dragSources[node.widgetId];
+		}
+
+		if (this.dropTargets[node.widgetId]) {
+			dojo.dnd.dragManager.unregisterDropTarget(this.dropTargets[node.widgetId]);
+			delete this.dropTargets[node.widgetId];
+		}
+	}
+
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDndControllerV3.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDocIconExtension.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDocIconExtension.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDocIconExtension.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDocIconExtension.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,117 @@
+/*
+	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("dojo.widget.TreeDocIconExtension");
+
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.TreeExtension");
+
+// selector extension to emphase node
+
+dojo.widget.defineWidget(
+	"dojo.widget.TreeDocIconExtension",
+	[dojo.widget.TreeExtension],
+{
+	/**
+	 * can't unlisten
+	 */
+	
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/TreeDocIcon.css"),
+
+	
+	listenTreeEvents: ["afterChangeTree","afterSetFolder","afterUnsetFolder"],
+	
+	listenNodeFilter: function(elem) { return elem instanceof dojo.widget.Widget },
+	
+	getNodeType: function(node) {
+		var nodeType = node.getNodeType();
+		if (!nodeType) { // set default type
+			nodeType = node.isFolder ? "Folder" : "Document";
+		}
+		return nodeType;
+	},
+	
+	setNodeTypeClass: function(node) {
+		
+		var reg = new RegExp("(^|\\s)"+node.tree.classPrefix+"Icon\\w+",'g');			
+				
+		var clazz = dojo.html.getClass(node.iconNode).replace(reg,'') + ' ' + node.tree.classPrefix+'Icon'+this.getNodeType(node);
+		dojo.html.setClass(node.iconNode, clazz);		
+	},
+		
+		
+	onAfterSetFolder: function(message) {
+		//dojo.debug("FOLDER");
+		if (message.source.iconNode) {
+			// on node-initialize time when folder is set there is no iconNode
+			// this case will be processed in treeChange anyway			
+			this.setNodeTypeClass(message.source);
+		}
+	},
+	
+	
+	onAfterUnsetFolder: function(message) {
+		this.setNodeTypeClass(message.source);
+	},
+		
+	
+	listenNode: function(node) {
+		/**
+		 * add node with document type icon to node template and Tree.iconNodeTemplate
+		 * it will be set to TreeNode.iconNode on node creation
+		 * we do not assign document type yet, its node specific
+		 */
+		//dojo.debug("listenNode in "+node);
+			
+		node.contentIconNode = document.createElement("div");
+		var clazz = node.tree.classPrefix+"IconContent";
+		if (dojo.render.html.ie) {
+			clazz = clazz+' '+ node.tree.classPrefix+"IEIconContent";
+		}
+		dojo.html.setClass(node.contentIconNode, clazz);
+		
+		node.contentNode.parentNode.replaceChild(node.contentIconNode, node.expandNode);
+									  
+	  	node.iconNode = document.createElement("div");
+		dojo.html.setClass(node.iconNode, node.tree.classPrefix+"Icon"+' '+node.tree.classPrefix+'Icon'+this.getNodeType(node));
+		
+		node.contentIconNode.appendChild(node.expandNode);
+		node.contentIconNode.appendChild(node.iconNode);
+		
+		dojo.dom.removeNode(node.contentNode);
+		node.contentIconNode.appendChild(node.contentNode);
+		
+	
+		
+		//dojo.html.insertAfter(node.iconNode, node.expandNode);
+		
+		//dojo.debug("listenNode out "+node);
+		
+	},
+			
+	
+	onAfterChangeTree: function(message) {
+		var _this = this;
+		
+		//dojo.debug(message.node)
+		
+		if (!message.oldTree || !this.listenedTrees[message.oldTree.widgetId]) {			
+			// moving from old tree to our tree
+			this.processDescendants(message.node,
+				this.listenNodeFilter,
+				this.listenNode
+			);
+		}
+		
+	}
+	
+
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeDocIconExtension.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeEditor.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeEditor.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeEditor.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeEditor.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,115 @@
+/*
+	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.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.RichText");
+
+dojo.provide("dojo.widget.TreeEditor");
+
+dojo.widget.defineWidget(
+	"dojo.widget.TreeEditor",
+	dojo.widget.HtmlWidget,
+{
+		
+		
+	singleLineMode: false, // enter saves
+	saveOnBlur: true, // blur or new edit saves current
+	sync: false,  // finish editing in sync/async mode
+	selectOnOpen: true,
+	
+	controller: null,
+		
+	node: null,
+	
+	richTextParams: {},
+	
+	
+	
+	getContents: function() {
+		return this.richText.getEditorContent();
+	},
+	
+	open: function(node) {
+		
+		if (!this.richText) {
+			this.richText = dojo.widget.createWidget("RichText", this.richTextParams, node.labelNode);
+		
+			dojo.event.connect("around", this.richText, "onKeyDown", this, "richText_onKeyDown" );
+			dojo.event.connect(this.richText, "onBlur", this, "richText_onBlur" );
+			
+			var self = this;
+			dojo.event.connect(this.richText, "onLoad", function(){
+				if (self.selectOnOpen) {
+					self.richText.execCommand("selectall");
+				}
+			});
+		} else {
+			this.richText.open(node.labelNode);
+		}
+		
+		this.node = node;		
+	},
+	
+	close: function(save) {
+		
+		this.richText.close(save);
+		
+		
+		this.node = null;	
+	},
+	
+	isClosed: function() {
+		return !this.richText || this.richText.isClosed;
+	},
+	
+	execCommand: function() {
+		this.richText.execCommand.apply(this.richText, arguments);
+	},
+	
+	richText_onKeyDown: function(invocation) {
+		var e = invocation.args[0];
+		if((!e)&&(this.object)) {
+			e = dojo.event.browser.fixEvent(this.editor.window.event);
+		}
+		
+		switch (e.keyCode) {
+			case e.KEY_ESCAPE:
+				this.finish(false);
+				dojo.event.browser.stopEvent(e);		
+				break;
+			case e.KEY_ENTER:
+				if( e.ctrlKey && !this.singleLineMode ) {
+					this.execCommand( "inserthtml", "<br/>" );
+							
+				}
+				else {
+					this.finish(true);					
+					//dojo.debug("finish");
+				}
+				dojo.event.browser.stopEvent(e);
+				break;
+			default:
+				return invocation.proceed();
+		}
+	},
+	
+	richText_onBlur: function() {
+		this.finish(this.saveOnBlur);
+	},
+	
+	
+	finish: function(save) {
+		return this.controller.editLabelFinish(save, this.sync);
+	}
+		
+		
+	
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeEditor.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeEmphaseOnSelect.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeEmphaseOnSelect.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeEmphaseOnSelect.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeEmphaseOnSelect.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,56 @@
+/*
+	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("dojo.widget.TreeEmphaseOnSelect");
+
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.TreeSelectorV3");
+dojo.require("dojo.html.selection");
+
+// selector extension to emphase node
+
+dojo.widget.defineWidget(
+	"dojo.widget.TreeEmphaseOnSelect",
+	dojo.widget.HtmlWidget,
+	function() {
+		this.saveSelected = {}
+	},
+{
+	selector: "",
+	
+	initialize: function() {
+		this.selector = dojo.widget.byId(this.selector);
+		
+		dojo.event.topic.subscribe(this.selector.eventNames.select, this, "onSelect");
+		dojo.event.topic.subscribe(this.selector.eventNames.deselect, this, "onDeselect");	
+	},
+
+	
+	onSelect: function(message) {
+		var domNode = message.node.labelNode;
+		
+		dojo.html.clearSelection(domNode);
+		
+
+		dojo.html.addClass(domNode, message.node.tree.classPrefix+'NodeEmphased');
+		//dojo.debug("after select "+dojo.html.getClass(message.node.labelNode))
+		
+	},
+	
+	onDeselect: function(message) {
+		var domNode = message.node.labelNode;
+		
+		//dojo.debug(dojo.html.getClass(message.node.labelNode))		
+		dojo.html.removeClass(domNode, message.node.tree.classPrefix+'NodeEmphased');
+	}
+	
+
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeEmphaseOnSelect.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeExtension.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeExtension.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeExtension.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeExtension.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,24 @@
+/*
+	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("dojo.widget.TreeExtension");
+
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.TreeCommon");
+
+dojo.widget.defineWidget(
+	"dojo.widget.TreeExtension",
+	[dojo.widget.HtmlWidget, dojo.widget.TreeCommon],
+	function() {
+		this.listenedTrees = {};
+	},
+	{}
+);

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeExtension.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeLinkExtension.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeLinkExtension.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeLinkExtension.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeLinkExtension.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,73 @@
+/*
+	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("dojo.widget.TreeLinkExtension");
+
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.TreeExtension");
+
+dojo.widget.defineWidget(
+	"dojo.widget.TreeLinkExtension",
+	dojo.widget.TreeExtension,
+	function() {
+		this.params = {};
+	},
+{
+	/**
+	 * can only listen, no unlisten
+	 */
+
+	listenTreeEvents: ["afterChangeTree"],	
+
+	listenTree: function(tree) {
+		
+		dojo.widget.TreeCommon.prototype.listenTree.call(this,tree);
+		
+		var labelNode = tree.labelNodeTemplate;
+		var newLabel = this.makeALabel();
+		dojo.html.setClass(newLabel, dojo.html.getClass(labelNode));
+		labelNode.parentNode.replaceChild(newLabel, labelNode);		
+	},
+	
+		
+	
+	makeALabel: function() {		
+		var newLabel = document.createElement("a");
+		
+		for(key in this.params) {
+			if (key in {}) continue;
+			newLabel.setAttribute(key, this.params[key]);
+		}
+		
+		return newLabel;
+	},
+		
+	
+	onAfterChangeTree: function(message) {
+		var _this = this;
+		
+		
+		// only for new nodes
+		if (!message.oldTree) {
+			this.listenNode(message.node);
+		}
+		
+	},
+	
+	listenNode: function(node) {
+		for(key in node.object) {
+			if (key in {}) continue;
+			node.labelNode.setAttribute(key, node.object[key]);
+		}
+	}
+
+
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeLinkExtension.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeLoadingController.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeLoadingController.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeLoadingController.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeLoadingController.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,219 @@
+/*
+	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("dojo.widget.TreeLoadingController");
+
+dojo.require("dojo.widget.TreeBasicController");
+dojo.require("dojo.event.*");
+dojo.require("dojo.json")
+dojo.require("dojo.io.*");
+
+dojo.deprecated("dojo.widget.TreeLoadingController", "use TreeV3 and TreeLoadingControllerV3 instead", "0.5");
+
+
+dojo.widget.tags.addParseTreeHandler("dojo:TreeLoadingController");
+
+
+dojo.widget.TreeLoadingController = function() {
+	dojo.widget.TreeBasicController.call(this);
+}
+
+dojo.inherits(dojo.widget.TreeLoadingController, dojo.widget.TreeBasicController);
+
+
+dojo.lang.extend(dojo.widget.TreeLoadingController, {
+	widgetType: "TreeLoadingController",
+
+	RPCUrl: "",
+
+	RPCActionParam: "action", // used for GET for RPCUrl
+
+
+	/**
+	 * Common RPC error handler (dies)
+	*/
+	RPCErrorHandler: function(type, obj, evt) {
+		alert( "RPC Error: " + (obj.message||"no message"));
+	},
+
+	preventCache: true,
+
+	getRPCUrl: function(action) {
+
+		// RPCUrl=local meant SOLELY for DEMO and LOCAL TESTS.
+		// May lead to widgetId collisions
+		if (this.RPCUrl == "local") {
+			var dir = document.location.href.substr(0, document.location.href.lastIndexOf('/'));
+			var localUrl = dir+"/"+action;
+			//dojo.debug(localUrl);
+			return localUrl;
+		}
+
+		if (!this.RPCUrl) {
+			dojo.raise("Empty RPCUrl: can't load");
+		}
+
+		return this.RPCUrl + ( this.RPCUrl.indexOf("?") > -1 ? "&" : "?") + this.RPCActionParam+"="+action;
+	},
+
+
+	/**
+	 * Add all loaded nodes from array obj as node children and expand it
+	*/
+	loadProcessResponse: function(node, result, callObj, callFunc) {
+
+		if (!dojo.lang.isUndefined(result.error)) {
+			this.RPCErrorHandler("server", result.error);
+			return false;
+		}
+
+		//dojo.debugShallow(result);
+
+		var newChildren = result;
+
+		if (!dojo.lang.isArray(newChildren)) {
+			dojo.raise('loadProcessResponse: Not array loaded: '+newChildren);
+		}
+
+		for(var i=0; i<newChildren.length; i++) {
+			// looks like dojo.widget.manager needs no special "add" command
+			newChildren[i] = dojo.widget.createWidget(node.widgetType, newChildren[i]);
+			node.addChild(newChildren[i]);
+		}
+
+
+		//node.addAllChildren(newChildren);
+
+		node.state = node.loadStates.LOADED;
+
+		//dojo.debug(callFunc);
+
+		if (dojo.lang.isFunction(callFunc)) {
+			callFunc.apply(dojo.lang.isUndefined(callObj) ? this : callObj, [node, newChildren]);
+		}
+		//this.expand(node);
+	},
+
+	getInfo: function(obj) {
+		return obj.getInfo();
+	},
+
+	runRPC: function(kw) {
+		var _this = this;
+
+		var handle = function(type, data, evt) {
+			// unlock BEFORE any processing is done
+			// so errorHandler may apply locking
+			if (kw.lock) {
+				dojo.lang.forEach(kw.lock,
+					function(t) { t.unlock() }
+				);
+			}
+
+			if(type == "load"){
+				kw.load.call(this, data);
+			}else{
+				this.RPCErrorHandler(type, data, evt);
+			}
+
+		}
+
+		if (kw.lock) {
+			dojo.lang.forEach(kw.lock,
+				function(t) { t.lock() }
+			);
+		}
+
+
+		dojo.io.bind({
+			url: kw.url,
+			/* I hitch to get this.loadOkHandler */
+			handle: dojo.lang.hitch(this, handle),
+			mimetype: "text/json",
+			preventCache: _this.preventCache,
+			sync: kw.sync,
+			content: { data: dojo.json.serialize(kw.params) }
+		});
+	},
+
+
+
+	/**
+	 * Load children of the node from server
+	 * Synchroneous loading doesn't break control flow
+	 * I need sync mode for DnD
+	*/
+	loadRemote: function(node, sync, callObj, callFunc){
+		var _this = this;
+
+		var params = {
+			node: this.getInfo(node),
+			tree: this.getInfo(node.tree)
+		};
+
+		//dojo.debug(callFunc)
+
+		this.runRPC({
+			url: this.getRPCUrl('getChildren'),
+			load: function(result) {
+				_this.loadProcessResponse(node, result, callObj, callFunc) ;
+			},
+			sync: sync,
+			lock: [node],
+			params: params
+		});
+
+	},
+
+
+	expand: function(node, sync, callObj, callFunc) {
+
+		if (node.state == node.loadStates.UNCHECKED && node.isFolder) {
+
+			this.loadRemote(node, sync,
+				this,
+				function(node, newChildren) {
+					this.expand(node, sync, callObj, callFunc);
+				}
+			);
+
+			return;
+		}
+
+		dojo.widget.TreeBasicController.prototype.expand.apply(this, arguments);
+
+	},
+
+
+
+	doMove: function(child, newParent, index) {
+		/* load nodes into newParent in sync mode, if needed, first */
+		if (newParent.isTreeNode && newParent.state == newParent.loadStates.UNCHECKED) {
+			this.loadRemote(newParent, true);
+		}
+
+		return dojo.widget.TreeBasicController.prototype.doMove.apply(this, arguments);
+	},
+
+
+	doCreateChild: function(parent, index, data, callObj, callFunc) {
+
+		/* load nodes into newParent in sync mode, if needed, first */
+		if (parent.state == parent.loadStates.UNCHECKED) {
+			this.loadRemote(parent, true);
+		}
+
+		return dojo.widget.TreeBasicController.prototype.doCreateChild.apply(this, arguments);
+	}
+
+
+
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeLoadingController.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeLoadingControllerV3.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeLoadingControllerV3.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeLoadingControllerV3.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeLoadingControllerV3.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,461 @@
+/*
+	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("dojo.widget.TreeLoadingControllerV3");
+
+dojo.require("dojo.widget.TreeBasicControllerV3");
+dojo.require("dojo.event.*");
+dojo.require("dojo.json")
+dojo.require("dojo.io.*");
+dojo.require("dojo.Deferred");
+dojo.require("dojo.DeferredList");
+
+dojo.declare(
+	"dojo.Error",
+	Error,
+	function(message, extra) {
+		this.message = message;
+		this.extra = extra;
+		this.stack = (new Error()).stack;	
+	}
+);
+
+dojo.declare(
+	"dojo.CommunicationError",
+	dojo.Error,
+	function() {
+		this.name="CommunicationError";
+	}
+);
+
+dojo.declare(
+	"dojo.LockedError",
+	dojo.Error,
+	function() {
+		this.name="LockedError";
+	}
+);
+
+dojo.declare(
+	"dojo.FormatError",
+	dojo.Error,
+	function() {
+		this.name="FormatError";
+	}
+);
+
+dojo.declare(
+	"dojo.RpcError",
+	dojo.Error,
+	function() {
+		this.name="RpcError";
+	}
+);
+
+dojo.widget.defineWidget(
+	"dojo.widget.TreeLoadingControllerV3",
+	dojo.widget.TreeBasicControllerV3,
+{	
+	RpcUrl: "",
+
+	RpcActionParam: "action", // used for GET for RpcUrl
+
+	preventCache: true,
+
+	checkValidRpcResponse: function(type, obj) {
+		if (type != "load") {
+			var extra = {}				
+			for(var i=1; i<arguments.length;i++) {
+				dojo.lang.mixin(extra, arguments[i]);					
+			}
+			return new dojo.CommunicationError(obj, extra);				
+		}
+		
+		if (typeof obj != 'object') {
+			return new dojo.FormatError("Wrong server answer format "+(obj && obj.toSource ? obj.toSource() : obj)+" type "+(typeof obj), obj);
+		}
+		
+		//dojo.debugShallow(obj);
+			
+		if (!dojo.lang.isUndefined(obj.error)) {
+			return new dojo.RpcError(obj.error, obj);
+		}
+		
+		return false;
+	},
+		
+
+	getDeferredBindHandler: function(/* dojo.rpc.Deferred */ deferred){
+		// summary
+		// create callback that calls the Deferred's callback method		
+		
+		return dojo.lang.hitch(this, 
+			function(type, obj){				
+				//dojo.debug("getDeferredBindHandler "+obj.toSource());
+								
+				var error = this.checkValidRpcResponse.apply(this, arguments);
+				
+				if (error) {
+					deferred.errback(error);
+					return;
+				}
+	
+				deferred.callback(obj);								
+			}
+		);
+		
+	},
+
+	getRpcUrl: function(action) {
+
+		// RpcUrl=local meant SOLELY for DEMO and LOCAL TESTS
+		if (this.RpcUrl == "local") {
+			var dir = document.location.href.substr(0, document.location.href.lastIndexOf('/'));
+			var localUrl = dir+"/local/"+action;
+			//dojo.debug(localUrl);
+			return localUrl;	
+		}
+
+		if (!this.RpcUrl) {
+			dojo.raise("Empty RpcUrl: can't load");
+		}
+		
+		var url = this.RpcUrl;
+		
+		if (url.indexOf("/") != 0) { // not absolute
+			var protocol = document.location.href.replace(/:\/\/.*/,'');
+			var prefix = document.location.href.substring(protocol.length+3);
+			
+			if (prefix.lastIndexOf("/") != prefix.length-1) {
+				prefix = prefix.replace(/\/[^\/]+$/,'/'); // strip file name
+			}
+			if (prefix.lastIndexOf("/") != prefix.length-1) {
+				prefix = prefix+'/'; // add / if not exists it all
+			}
+			//dojo.debug(url);
+			url = protocol + '://' + prefix + url;
+		}
+			
+
+		return url + (url.indexOf("?")>-1 ? "&" : "?") + this.RpcActionParam+"="+action;
+	},
+
+
+	/**
+	 * Add all loaded nodes from array obj as node children and expand it
+	*/
+	loadProcessResponse: function(node, result) {
+		//dojo.debug("Process response "+node);
+				
+		if (!dojo.lang.isArray(result)) {
+			throw new dojo.FormatError('loadProcessResponse: Not array loaded: '+result);
+		}
+
+		node.setChildren(result);
+		
+	},
+
+	/**
+	 * kw = { url, sync, params }
+	 */
+	runRpc: function(kw) {
+		var _this = this;
+		
+		var deferred = new dojo.Deferred();
+		
+		dojo.io.bind({
+			url: kw.url,			
+			handle: this.getDeferredBindHandler(deferred),
+			mimetype: "text/javascript",
+			preventCache: this.preventCache,
+			sync: kw.sync,
+			content: { data: dojo.json.serialize(kw.params) }
+		});
+		
+		return deferred;
+
+	},
+
+
+
+	/**
+	 * Load children of the node from server
+	 * Synchroneous loading doesn't break control flow
+	 * I need sync mode for DnD
+	*/
+	loadRemote: function(node, sync){
+		var _this = this;
+
+		var params = {
+			node: this.getInfo(node),
+			tree: this.getInfo(node.tree)
+		};
+
+		
+		var deferred = this.runRpc({
+			url: this.getRpcUrl('getChildren'),
+			sync: sync,
+			params: params
+		});
+		
+		deferred.addCallback(function(res) { return _this.loadProcessResponse(node,res) });
+		
+				
+		
+		return deferred;
+
+	},
+
+	batchExpandTimeout: 0,
+
+	recurseToLevel: function(widget, level, callFunc, callObj, skipFirst, sync) {
+		if (level == 0) return;
+
+
+		
+		if (!skipFirst) {
+			var deferred = callFunc.call(callObj, widget, sync);
+		} else {
+			var deferred = dojo.Deferred.prototype.makeCalled();
+		}
+		
+		//dojo.debug("expand deferred saved "+node+" sync "+sync);
+		
+		
+		var _this = this;
+		
+		var recurseOnExpand = function() {
+			var children = widget.children;
+			var deferreds = [];		
+			for(var i=0; i<children.length; i++) {
+				//dojo.debug("push recursive call for "+node.children[i]+" level "+level);
+				deferreds.push(_this.recurseToLevel(children[i], level-1, callFunc, callObj, sync));
+			}
+			return new dojo.DeferredList(deferreds);
+		}
+		
+		deferred.addCallback(recurseOnExpand);
+		
+		return deferred;
+	},
+	
+	expandToLevel: function(nodeOrTree, level, sync) {
+		return this.recurseToLevel(nodeOrTree, nodeOrTree.isTree ? level+1 : level, this.expand, this, nodeOrTree.isTree, sync);
+	},
+	
+	loadToLevel: function(nodeOrTree, level, sync) {
+		return this.recurseToLevel(nodeOrTree, nodeOrTree.isTree ? level+1 : level, this.loadIfNeeded, this, nodeOrTree.isTree, sync);
+	},
+	
+	
+	loadAll: function(nodeOrTree, sync) {
+		return this.loadToLevel(nodeOrTree, Number.POSITIVE_INFINITY, sync);
+	},
+		
+	
+	
+	expand: function(node, sync) {		
+		// widget which children are data objects, is UNCHECKED, but has children and shouldn't be loaded
+		// so I put children check here too
+		
+		var _this = this;
+		
+		var deferred = this.startProcessing(node);
+		
+		deferred.addCallback(function() {
+			return _this.loadIfNeeded(node, sync);
+		});
+				
+		deferred.addCallback(function(res) {
+			//dojo.debug("Activated callback dojo.widget.TreeBasicControllerV3.prototype.expand(node); "+res);
+			dojo.widget.TreeBasicControllerV3.prototype.expand(node);
+			return res;
+		});
+		
+		deferred.addBoth(function(res) {
+			_this.finishProcessing(node);
+			return res;
+		});
+		
+		
+		
+		return deferred;
+	},
+
+	
+	loadIfNeeded: function(node, sync) {
+		if (node.state == node.loadStates.UNCHECKED && node.isFolder && !node.children.length) {
+			// populate deferred with other things to pre-do
+			deferred = this.loadRemote(node, sync);			
+		} else {
+			/* "fake action" here */
+			deferred = new dojo.Deferred();
+			deferred.callback();
+		}
+		
+		return deferred;
+	},
+	
+	/**
+	 * 1) if specified, run check, return false if failed
+	 * 2) if specified, run prepare
+	 * 3) run make if prepare if no errors
+	 * 4) run finalize no matter what happened, pass through make result
+	 * 5) if specified, run expose if no errors
+	 */
+	runStages: function(check, prepare, make, finalize, expose, args) {
+		var _this = this;
+		
+		if (check && !check.apply(this, args)) {
+			return false;
+		}
+		
+		var deferred = dojo.Deferred.prototype.makeCalled();
+		
+		
+		if (prepare) {
+			deferred.addCallback(function() {
+				return prepare.apply(_this, args);
+			});
+		}
+		
+		
+		//deferred.addCallback(function(res) { dojo.debug("Prepare fired "+res); return res});
+		
+		var _this = this;
+		deferred.addCallback(function() {			
+			var res = make.apply(_this, args);
+			//res.addBoth(function(r) {dojo.debugShallow(r); return r;});
+			return res;
+		});
+		
+		//deferred.addCallback(function(res) { dojo.debug("Main fired "+res); return res});
+		
+		if (finalize) {
+			deferred.addBoth(function(res) {
+				finalize.apply(_this, args);
+				return res;
+			});
+		}
+			
+				
+		// exposer does not affect result
+		if (expose) {
+			deferred.addCallback(function(res) {
+				expose.apply(_this, args);
+				return res;
+			});
+		}
+		
+		return deferred;
+	},
+		
+	startProcessing: function(nodesArray) {
+		var deferred = new dojo.Deferred();
+		
+		
+		var nodes = dojo.lang.isArray(nodesArray) ? nodesArray : arguments;
+		
+		/*
+		for(var i=0;i<nodes.length;i++) {
+			dojo.debug(nodes[i]);
+		}*/
+		
+		for(var i=0;i<nodes.length;i++) {
+			if (nodes[i].isLocked()) {
+				deferred.errback(new dojo.LockedError("item locked "+nodes[i], nodes[i]));
+				//dojo.debug("startProcessing errback "+arguments[i]);
+				return deferred;
+			}
+			if (nodes[i].isTreeNode) {
+				//dojo.debug("mark "+nodes[i]);
+				nodes[i].markProcessing();
+			}
+			nodes[i].lock();
+		}
+				
+		//dojo.debug("startProcessing callback");
+				
+		deferred.callback();
+		
+		return deferred;
+	},
+	
+	finishProcessing: function(nodesArray) {
+		
+		var nodes = dojo.lang.isArray(nodesArray) ? nodesArray : arguments;
+		
+		for(var i=0;i<nodes.length;i++) {
+			if (!nodes[i].hasLock()) {
+				// is not processed. probably we locked it and then met bad node in startProcessing
+				continue; 
+			}
+			//dojo.debug("has lock");	
+			nodes[i].unlock();
+			if (nodes[i].isTreeNode) {
+				nodes[i].unmarkProcessing();
+			}
+		}
+	},
+	
+	refresh: function(nodeOrTree, sync) {
+		nodeOrTree.destroyChildren();
+		
+		nodeOrTree.state == nodeOrTree.loadStates.UNCHECKED;
+		
+		
+		return this.loadRemote(nodeOrTree, sync);
+	},
+
+	// ----------------- move -----------------
+
+	prepareMove: function(child, newParent, index, sync) {
+		var deferred = this.startProcessing(newParent);
+		deferred.addCallback(dojo.lang.hitch(this, function() {
+			return this.loadIfNeeded(newParent, sync);
+		}));
+		return deferred;
+	},
+	
+	finalizeMove: function(child, newParent) {
+		this.finishProcessing(newParent);
+	},
+
+	// -------------------- createChild ------------
+
+	prepareCreateChild: function(parent, index, data, sync) {
+		var deferred = this.startProcessing(parent);
+		
+		deferred.addCallback(dojo.lang.hitch(this, function() {
+			return this.loadIfNeeded(parent, sync);
+		}));
+		return deferred;
+	},
+	
+	finalizeCreateChild: function(parent) {
+		this.finishProcessing(parent);
+	},
+
+	// ---------------- clone ---------------
+	
+	prepareClone: function(child, newParent, index, deep, sync) {
+		var deferred = this.startProcessing(child, newParent);
+		deferred.addCallback(dojo.lang.hitch(this, function() {
+			return this.loadIfNeeded(newParent, sync);
+		}));		
+		return deferred;	
+	},	
+	
+	finalizeClone: function(child, newParent) {
+		this.finishProcessing(child, newParent);
+	}
+
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeLoadingControllerV3.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeNode.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeNode.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeNode.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeNode.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,534 @@
+/*
+	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("dojo.widget.TreeNode");
+
+dojo.require("dojo.html.*");
+dojo.require("dojo.event.*");
+dojo.require("dojo.io.*");
+
+// make it a tag
+dojo.widget.tags.addParseTreeHandler("dojo:TreeNode");
+
+
+// # //////////
+
+dojo.widget.TreeNode = function() {
+	dojo.widget.HtmlWidget.call(this);
+
+	this.actionsDisabled = [];
+}
+
+dojo.inherits(dojo.widget.TreeNode, dojo.widget.HtmlWidget);
+
+dojo.lang.extend(dojo.widget.TreeNode, {
+	widgetType: "TreeNode",
+
+	loadStates: {
+		UNCHECKED: "UNCHECKED",
+    	LOADING: "LOADING",
+    	LOADED: "LOADED"
+	},
+
+
+	actions: {
+		MOVE: "MOVE",
+    	REMOVE: "REMOVE",
+    	EDIT: "EDIT",
+    	ADDCHILD: "ADDCHILD"
+	},
+
+	isContainer: true,
+
+	lockLevel: 0, // lock ++ unlock --, so nested locking works fine
+
+
+	templateString: ('<div class="dojoTreeNode"> '
+		+ '<span treeNode="${this.widgetId}" class="dojoTreeNodeLabel" dojoAttachPoint="labelNode"> '
+		+ '		<span dojoAttachPoint="titleNode" dojoAttachEvent="onClick: onTitleClick" class="dojoTreeNodeLabelTitle">${this.title}</span> '
+		+ '</span> '
+		+ '<span class="dojoTreeNodeAfterLabel" dojoAttachPoint="afterLabelNode">${this.afterLabel}</span> '
+		+ '<div dojoAttachPoint="containerNode" style="display:none"></div> '
+		+ '</div>').replace(/(>|<)\s+/g, '$1'), // strip whitespaces between nodes
+
+
+	childIconSrc: "",
+	childIconFolderSrc: dojo.uri.dojoUri("src/widget/templates/images/Tree/closed.gif"), // for under root parent item child icon,
+	childIconDocumentSrc: dojo.uri.dojoUri("src/widget/templates/images/Tree/document.gif"), // for under root parent item child icon,
+
+	childIcon: null,
+	isTreeNode: true,
+
+	objectId: "", // the widget represents an object
+
+	afterLabel: "",
+	afterLabelNode: null, // node to the left of labelNode
+
+	// an icon left from childIcon: imgs[-2].
+	// if +/- for folders, blank for leaves
+	expandIcon: null,
+
+	title: "",
+	object: "", // node may have object attached, settable from HTML
+	isFolder: false,
+
+	labelNode: null, // the item label
+	titleNode: null, // the item title
+	imgs: null, // an array of icons imgs
+
+	expandLevel: "", // expand to level
+
+	tree: null,
+
+	depth: 0,
+
+	isExpanded: false,
+
+	state: null,  // after creation will change to loadStates: "loaded/loading/unchecked"
+	domNodeInitialized: false,  // domnode is initialized with icons etc
+
+
+	isFirstChild: function() {
+		return this.getParentIndex() == 0 ? true: false;
+	},
+
+	isLastChild: function() {
+		return this.getParentIndex() == this.parent.children.length-1 ? true : false;
+	},
+
+	lock: function(){ return this.tree.lock.apply(this, arguments) },
+	unlock: function(){ return this.tree.unlock.apply(this, arguments) },
+	isLocked: function(){ return this.tree.isLocked.apply(this, arguments) },
+	cleanLock: function(){ return this.tree.cleanLock.apply(this, arguments) },
+
+	actionIsDisabled: function(action) {
+		var _this = this;
+
+		var disabled = false;
+
+		if (this.tree.strictFolders && action == this.actions.ADDCHILD && !this.isFolder) {
+			disabled = true;
+		}
+
+		if (dojo.lang.inArray(_this.actionsDisabled, action)) {
+			disabled = true;
+		}
+
+		if (this.isLocked()) {
+			disabled = true;
+		}
+
+		return disabled;
+	},
+
+	getInfo: function() {
+		// No title here (title may be widget)
+		var info = {
+			widgetId: this.widgetId,
+			objectId: this.objectId,
+			index: this.getParentIndex(),
+			isFolder: this.isFolder
+		}
+
+		return info;
+	},
+
+	initialize: function(args, frag){
+
+		//dojo.debug(this.title)
+
+		this.state = this.loadStates.UNCHECKED;
+
+		for(var i=0; i<this.actionsDisabled.length; i++) {
+			this.actionsDisabled[i] = this.actionsDisabled[i].toUpperCase();
+		}
+
+		this.expandLevel = parseInt(this.expandLevel);
+
+	},
+
+
+	/**
+	 * Change visible node depth by appending/prepending with blankImgs
+	 * @param depthDiff Integer positive => move right, negative => move left
+	*/
+	adjustDepth: function(depthDiff) {
+
+		for(var i=0; i<this.children.length; i++) {
+			this.children[i].adjustDepth(depthDiff);
+		}
+
+		this.depth += depthDiff;
+
+		if (depthDiff>0) {
+			for(var i=0; i<depthDiff; i++) {
+				var img = this.tree.makeBlankImg();
+				this.imgs.unshift(img);
+				//dojo.debugShallow(this.domNode);
+				dojo.html.insertBefore(this.imgs[0], this.domNode.firstChild);
+
+			}
+		}
+		if (depthDiff<0) {
+			for(var i=0; i<-depthDiff;i++) {
+				this.imgs.shift();
+				dojo.html.removeNode(this.domNode.firstChild);
+			}
+		}
+
+	},
+
+
+	markLoading: function() {
+		this._markLoadingSavedIcon = this.expandIcon.src;
+		this.expandIcon.src = this.tree.expandIconSrcLoading;
+	},
+
+	// if icon is "Loading" then
+	unMarkLoading: function() {
+		if (!this._markLoadingSavedIcon) return;
+
+		var im = new Image();
+		im.src = this.tree.expandIconSrcLoading;
+
+		//dojo.debug("Unmark "+this.expandIcon.src+" : "+im.src);
+		if (this.expandIcon.src == im.src) {
+			this.expandIcon.src = this._markLoadingSavedIcon;
+		}
+		this._markLoadingSavedIcon = null;
+	},
+
+
+	setFolder: function() {
+		dojo.event.connect(this.expandIcon, 'onclick', this, 'onTreeClick');
+		this.expandIcon.src = this.isExpanded ? this.tree.expandIconSrcMinus : this.tree.expandIconSrcPlus;
+		this.isFolder = true;
+	},
+
+
+	createDOMNode: function(tree, depth){
+
+		this.tree = tree;
+		this.depth = depth;
+
+
+		//
+		// add the tree icons
+		//
+
+		this.imgs = [];
+
+		for(var i=0; i<this.depth+1; i++){
+
+			var img = this.tree.makeBlankImg();
+
+			this.domNode.insertBefore(img, this.labelNode);
+
+			this.imgs.push(img);
+		}
+
+
+		this.expandIcon = this.imgs[this.imgs.length-1];
+
+
+		this.childIcon = this.tree.makeBlankImg();
+
+		// add to images before the title
+		this.imgs.push(this.childIcon);
+
+		dojo.html.insertBefore(this.childIcon, this.titleNode);
+
+		// node with children(from source html) becomes folder on build stage.
+		if (this.children.length || this.isFolder) {
+			this.setFolder();
+		}
+		else {
+			// leaves are always loaded
+			//dojo.debug("Set "+this+" state to loaded");
+			this.state = this.loadStates.LOADED;
+		}
+
+		dojo.event.connect(this.childIcon, 'onclick', this, 'onIconClick');
+
+
+		//
+		// create the child rows
+		//
+
+
+		for(var i=0; i<this.children.length; i++){
+			this.children[i].parent = this;
+
+			var node = this.children[i].createDOMNode(this.tree, this.depth+1);
+
+			this.containerNode.appendChild(node);
+		}
+
+
+		if (this.children.length) {
+			this.state = this.loadStates.LOADED;
+		}
+
+		this.updateIcons();
+
+		this.domNodeInitialized = true;
+
+		dojo.event.topic.publish(this.tree.eventNames.createDOMNode, { source: this } );
+
+		return this.domNode;
+	},
+
+	onTreeClick: function(e){
+		dojo.event.topic.publish(this.tree.eventNames.treeClick, { source: this, event: e });
+	},
+
+	onIconClick: function(e){
+		dojo.event.topic.publish(this.tree.eventNames.iconClick, { source: this, event: e });
+	},
+
+	onTitleClick: function(e){
+		dojo.event.topic.publish(this.tree.eventNames.titleClick, { source: this, event: e });
+	},
+
+	markSelected: function() {
+		dojo.html.addClass(this.titleNode, 'dojoTreeNodeLabelSelected');
+	},
+
+
+	unMarkSelected: function() {
+		//dojo.debug('unmark')
+		dojo.html.removeClass(this.titleNode, 'dojoTreeNodeLabelSelected');
+	},
+
+	updateExpandIcon: function() {
+		if (this.isFolder){
+			this.expandIcon.src = this.isExpanded ? this.tree.expandIconSrcMinus : this.tree.expandIconSrcPlus;
+		} else {
+			this.expandIcon.src = this.tree.blankIconSrc;
+		}
+	},
+
+	/* set the grid under the expand icon */
+	updateExpandGrid: function() {
+
+		if (this.tree.showGrid){
+			if (this.depth){
+				this.setGridImage(-2, this.isLastChild() ? this.tree.gridIconSrcL : this.tree.gridIconSrcT);
+			}else{
+				if (this.isFirstChild()){
+					this.setGridImage(-2, this.isLastChild() ? this.tree.gridIconSrcX : this.tree.gridIconSrcY);
+				}else{
+					this.setGridImage(-2, this.isLastChild() ? this.tree.gridIconSrcL : this.tree.gridIconSrcT);
+				}
+			}
+		}else{
+			this.setGridImage(-2, this.tree.blankIconSrc);
+		}
+
+	},
+
+	/* set the grid under the child icon */
+	updateChildGrid: function() {
+
+		if ((this.depth || this.tree.showRootGrid) && this.tree.showGrid){
+			this.setGridImage(-1, (this.children.length && this.isExpanded) ? this.tree.gridIconSrcP : this.tree.gridIconSrcC);
+		}else{
+			if (this.tree.showGrid && !this.tree.showRootGrid){
+				this.setGridImage(-1, (this.children.length && this.isExpanded) ? this.tree.gridIconSrcZ : this.tree.blankIconSrc);
+			}else{
+				this.setGridImage(-1, this.tree.blankIconSrc);
+			}
+		}
+
+
+	},
+
+	updateParentGrid: function() {
+		var parent = this.parent;
+
+		//dojo.debug("updateParentGrid "+this);
+
+		for(var i=0; i<this.depth; i++){
+
+			//dojo.debug("Parent "+parent);
+
+			var idx = this.imgs.length-(3+i);
+			var img = (this.tree.showGrid && !parent.isLastChild()) ? this.tree.gridIconSrcV : this.tree.blankIconSrc;
+
+			//dojo.debug("Image "+img+" for "+idx);
+
+			this.setGridImage(idx, img);
+
+			parent = parent.parent;
+		}
+	},
+
+	updateExpandGridColumn: function() {
+		if (!this.tree.showGrid) return;
+
+		var _this = this;
+
+		var icon = this.isLastChild() ? this.tree.blankIconSrc : this.tree.gridIconSrcV;
+
+		dojo.lang.forEach(_this.getDescendants(),
+			function(node) { node.setGridImage(_this.depth, icon); }
+		);
+
+		this.updateExpandGrid();
+	},
+
+	updateIcons: function(){
+
+
+		//dojo.profile.start("updateIcons")
+
+		//dojo.debug("Update icons for "+this)
+		//dojo.debug(this.isFolder)
+
+		this.imgs[0].style.display = this.tree.showRootGrid ? 'inline' : 'none';
+
+
+		//
+		// set the expand icon
+		//
+
+
+		//
+		// set the child icon
+		//
+		this.buildChildIcon();
+
+		this.updateExpandGrid();
+		this.updateChildGrid();
+		this.updateParentGrid();
+
+
+
+		dojo.profile.stop("updateIcons")
+
+	},
+
+	buildChildIcon: function() {
+		// IE (others?) tries to download whatever is on src attribute so setting "url()" like before isnt a good idea
+		// Only results in a 404
+		if(this.childIconSrc){
+			this.childIcon.src = this.childIconSrc;
+		}
+		this.childIcon.style.display = this.childIconSrc ? 'inline' : 'none';
+	},
+
+	setGridImage: function(idx, src){
+
+		if (idx < 0){
+			idx = this.imgs.length + idx;
+		}
+
+		//if (idx >= this.imgs.length-2) return;
+		this.imgs[idx].style.backgroundImage = 'url(' + src + ')';
+	},
+
+
+	updateIconTree: function(){
+		this.tree.updateIconTree.call(this);
+	},
+
+
+
+
+	expand: function(){
+		if (this.isExpanded) return;
+
+		if (this.children.length) {
+			this.showChildren();
+		}
+
+		this.isExpanded = true;
+
+		this.updateExpandIcon();
+
+		dojo.event.topic.publish(this.tree.eventNames.expand, {source: this} );
+	},
+
+	collapse: function(){
+		if (!this.isExpanded) return;
+
+		this.hideChildren();
+		this.isExpanded = false;
+
+		this.updateExpandIcon();
+
+		dojo.event.topic.publish(this.tree.eventNames.collapse, {source: this} );
+	},
+
+	hideChildren: function(){
+		this.tree.toggleObj.hide(
+			this.containerNode, this.toggleDuration, this.explodeSrc, dojo.lang.hitch(this, "onHide")
+		);
+
+		/* if dnd is in action, recalculate changed coordinates */
+		if(dojo.exists(dojo, 'dnd.dragManager.dragObjects') && dojo.dnd.dragManager.dragObjects.length) {
+			dojo.dnd.dragManager.cacheTargetLocations();
+		}
+	},
+
+	showChildren: function(){
+		this.tree.toggleObj.show(
+			this.containerNode, this.toggleDuration, this.explodeSrc, dojo.lang.hitch(this, "onShow")
+		);
+
+		/* if dnd is in action, recalculate changed coordinates */
+		if(dojo.exists(dojo, 'dnd.dragManager.dragObjects') && dojo.dnd.dragManager.dragObjects.length) {
+			dojo.dnd.dragManager.cacheTargetLocations();
+		}
+	},
+
+	addChild: function(){
+		return this.tree.addChild.apply(this, arguments);
+	},
+
+	doAddChild: function(){
+		return this.tree.doAddChild.apply(this, arguments);
+	},
+
+
+
+	/* Edit current node : change properties and update contents */
+	edit: function(props) {
+		dojo.lang.mixin(this, props);
+		if (props.title) {
+			this.titleNode.innerHTML = this.title;
+		}
+
+		if (props.afterLabel) {
+			this.afterLabelNode.innerHTML = this.afterLabel;
+		}
+
+		if (props.childIconSrc) {
+			this.buildChildIcon();
+		}
+
+
+	},
+
+
+	removeNode: function(){ return this.tree.removeNode.apply(this, arguments) },
+	doRemoveNode: function(){ return this.tree.doRemoveNode.apply(this, arguments) },
+
+
+	toString: function() {
+		return "["+this.widgetType+" Tree:"+this.tree+" ID:"+this.widgetId+" Title:"+this.title+"]";
+
+	}
+
+});
+
+
+
+

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/TreeNode.js
------------------------------------------------------------------------------
    svn:eol-style = native