jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From edgarp...@apache.org
Subject svn commit: r473755 [37/43] - in /jackrabbit/trunk/contrib/jcr-browser: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/jackrabbit/ src/main/java/org/apache/jackrabbit/browser/ src/main/resources/ ...
Date Sat, 11 Nov 2006 16:44:48 GMT
Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeLoadingController.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeLoadingController.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeLoadingController.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeLoadingController.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,195 @@
+
+dojo.provide("dojo.widget.TreeLoadingController");
+
+dojo.require("dojo.widget.TreeBasicController");
+dojo.require("dojo.event.*");
+dojo.require("dojo.json")
+dojo.require("dojo.io.*");
+
+
+dojo.widget.defineWidget("dojo.widget.TreeLoadingController", dojo.widget.TreeBasicController, {
+	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: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeLoadingController.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeLoadingControllerV3.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeLoadingControllerV3.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeLoadingControllerV3.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeLoadingControllerV3.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,453 @@
+
+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) {
+		var deferred
+		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: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeLoadingControllerV3.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeNode.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeNode.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeNode.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeNode.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,513 @@
+dojo.provide("dojo.widget.TreeNode");
+
+dojo.require("dojo.html.*");
+dojo.require("dojo.event.*");
+dojo.require("dojo.io.*");
+
+dojo.widget.defineWidget("dojo.widget.TreeNode", dojo.widget.HtmlWidget, function() {
+	this.actionsDisabled = [];
+},
+{
+	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: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeNode.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeNodeV3.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeNodeV3.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeNodeV3.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeNodeV3.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,730 @@
+dojo.provide("dojo.widget.TreeNodeV3");
+
+dojo.require("dojo.html.*");
+dojo.require("dojo.event.*");
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.TreeWithNode");
+
+dojo.widget.defineWidget(
+	"dojo.widget.TreeNodeV3",
+	[dojo.widget.HtmlWidget, dojo.widget.TreeWithNode],
+	function() {
+		this.actionsDisabled = [];
+        this.object = {};
+    },
+{
+	tryLazyInit: true,
+
+	/*
+	 * Basic actions one can perform on nodes and, some(addchild) on trees
+	 */
+	actions: {
+		MOVE: "MOVE",
+    	DETACH: "DETACH",
+    	EDIT: "EDIT",
+    	ADDCHILD: "ADDCHILD",
+		SELECT: "SELECT"
+	},
+	
+	
+	labelClass: "",
+	contentClass: "",
+
+	expandNode: null,
+	labelNode: null,
+		
+    /**
+     *	can't call it nodeType cause of IE problems
+     */
+	nodeDocType: "",
+    selected: false,
+	
+	getnodeDocType: function() {
+		return this.nodeDocType;
+	},
+	
+	cloneProperties: ["actionsDisabled","tryLazyInit","nodeDocType","objectId","object",
+		   "title","isFolder","isExpanded","state"],
+	
+	
+	/**
+	 * copy cloneProperties with recursion into them
+	 * contains "copy constructor"
+	 */
+	clone: function(deep) {
+		var ret = new this.constructor();
+		
+		//dojo.debug("start cloning props "+this);
+		
+		for(var i=0; i<this.cloneProperties.length; i++) {
+			var prop = this.cloneProperties[i];
+			//dojo.debug("cloning "+prop+ ":" +this[prop]);
+			ret[prop] = dojo.lang.shallowCopy(this[prop], true);			
+		}
+		
+		if (this.tree.unsetFolderOnEmpty && !deep && this.isFolder) {
+			ret.isFolder = false;
+		}
+		
+		//dojo.debug("cloned props "+this);
+		
+		ret.toggleObj = this.toggleObj;
+		
+		dojo.widget.manager.add(ret);
+		
+		ret.tree = this.tree;
+		ret.buildRendering({},{});
+		ret.initialize({},{});
+				
+		if (deep && this.children.length) {
+			//dojo.debug("deeper copy start");
+			for(var i=0; i<this.children.length; i++) {
+				var child = this.children[i];
+				//dojo.debug("copy child "+child);
+				if (child.clone) {
+					ret.children.push(child.clone(deep));
+				} else {
+					ret.children.push(dojo.lang.shallowCopy(child, deep));
+				}
+			}
+			//dojo.debug("deeper copy end");
+			ret.setChildren();
+		}
+		
+		
+				
+		return ret;
+	},
+				
+			
+	markProcessing: function() {
+		this.markProcessingSavedClass = dojo.html.getClass(this.expandNode);
+		dojo.html.setClass(this.expandNode, this.tree.classPrefix+'ExpandLoading');			
+	},
+	
+	unmarkProcessing: function() {
+		dojo.html.setClass(this.expandNode, this.markProcessingSavedClass);			
+	},
+	
+	
+	
+	
+	/**
+	 * get information from args & parent, then build rendering
+	 */
+	buildRendering: function(args, fragment, parent) {
+		//dojo.debug("Build for "+args.toSource());
+		
+		if (args.tree) {
+			this.tree = dojo.lang.isString(args.tree) ? dojo.widget.manager.getWidgetById(args.tree) : args.tree;			
+		} else if (parent && parent.tree) {
+			this.tree = parent.tree;
+		} 
+		
+		if (!this.tree) {
+			dojo.raise("Can't evaluate tree from arguments or parent");
+		}
+		
+		
+		//dojo.profile.start("buildRendering - cloneNode");
+		
+		this.domNode = this.tree.nodeTemplate.cloneNode(true);
+		this.expandNode = this.domNode.firstChild;
+		this.contentNode = this.domNode.childNodes[1];
+		this.labelNode = this.contentNode.firstChild;
+		
+		if (this.labelClass) {
+			dojo.html.addClass(this.labelNode, this.labelClass);
+		}
+		
+		if (this.contentClass) {
+			dojo.html.addClass(this.contentNode, this.contentClass);
+		}
+		
+		
+		//dojo.profile.end("buildRendering - cloneNode");
+		
+		
+		this.domNode.widgetId = this.widgetId;
+		
+		//dojo.profile.start("buildRendering - innerHTML");
+		this.labelNode.innerHTML = this.title;
+		//dojo.profile.end("buildRendering - innerHTML");
+		
+	},
+	
+
+	isTreeNode: true,
+
+	
+	object: {},
+
+	title: "",
+	
+	isFolder: null, // set by widget depending on children/args
+
+	contentNode: null, // the item label
+	
+	expandClass: "",
+
+
+	isExpanded: false,
+	
+
+	containerNode: null,
+
+	
+	getInfo: function() {
+		// No title here (title may be widget)
+		var info = {
+			widgetId: this.widgetId,
+			objectId: this.objectId,
+			index: this.getParentIndex()
+		}
+
+		return info;
+	},
+	
+	setFolder: function() {
+		//dojo.debug("SetFolder in "+this);
+		this.isFolder = true;
+		this.viewSetExpand();
+		if (!this.containerNode) { // maybe this node was unfolderized and still has container
+			this.viewAddContainer(); // all folders have container.
+		}
+		//dojo.debug("publish "+this.tree.eventNames.setFolder);
+		dojo.event.topic.publish(this.tree.eventNames.afterSetFolder, { source: this });
+	},
+	
+	
+	
+	initialize: function(args, frag, parent) {
+		
+		//dojo.profile.start("initialize");
+		
+		/**
+		 * first we populate current widget from args,
+		 * then use its data to initialize
+		 * args may be empty, all data inside widget for copy constructor
+		 */
+		if (args.isFolder) {
+			this.isFolder = true;
+		}
+		
+		if (this.children.length || this.isFolder) {
+			//dojo.debug("children found");
+			//dojo.debug(this.children);
+			//dojo.debug("isFolder "+args.isFolder);
+			
+			// viewSetExpand for Folder is set here also
+			this.setFolder();			
+		} else {
+			// set expandicon for leaf 	
+			this.viewSetExpand();
+		}
+		
+		for(var i=0; i<this.actionsDisabled.length;i++) {
+			this.actionsDisabled[i] = this.actionsDisabled[i].toUpperCase();
+		}
+		//dojo.debug("publish "+this.tree.eventNames.changeTree);
+		
+		        
+
+		dojo.event.topic.publish(this.tree.eventNames.afterChangeTree, {oldTree:null, newTree:this.tree, node:this} );
+		
+		
+		//dojo.profile.end("initialize");
+		
+		//dojo.debug("initialize out "+this);
+		//dojo.debug(this+" parent "+parent);
+	},
+		
+	unsetFolder: function() {
+		this.isFolder = false;
+		this.viewSetExpand();		
+		dojo.event.topic.publish(this.tree.eventNames.afterUnsetFolder, { source: this });
+	},
+	
+	
+	insertNode: function(parent, index) {
+		
+		if (!index) index = 0;
+		//dojo.debug("insertNode "+this+" parent "+parent+" before "+index);
+		
+		if (index==0) {
+			dojo.html.prependChild(this.domNode, parent.containerNode);
+		} else {
+			dojo.html.insertAfter(this.domNode, parent.children[index-1].domNode);
+		}
+	},
+	
+	updateTree: function(newTree) {
+
+		if (this.tree === newTree) {
+			return;
+		}
+		
+		var oldTree = this.tree;
+		
+		
+		dojo.lang.forEach(this.getDescendants(),
+			function(elem) {			
+				elem.tree = newTree;			
+		});
+		
+		/**
+		 * UNTESTED
+		 * changes class prefix for all domnodes when moving between trees
+		 */
+		if (oldTree.classPrefix != newTree.classPrefix) {
+			var stack = [this.domNode]
+			var elem;
+			var reg = new RegExp("(^|\\s)"+oldTree.classPrefix, "g");
+			
+			while (elem = stack.pop()) {
+				for(var i=0; i<elem.childNodes.length; i++) {
+					var childNode = elem.childNodes[i]
+					if (childNode.nodeDocType != 1) continue;
+					// change prefix for classes
+					dojo.html.setClass(childNode, dojo.html.getClass(childNode).replace(reg, '$1'+newTree.classPrefix));
+					stack.push(childNode);
+				}
+			}
+			
+		}
+		
+		var message = {oldTree:oldTree, newTree:newTree, node:this}
+		
+		dojo.event.topic.publish(this.tree.eventNames.afterChangeTree, message );		
+		dojo.event.topic.publish(newTree.eventNames.afterChangeTree, message );
+			
+				
+	},
+	
+	
+	/**
+	 * called every time the widget is added with createWidget or created wia markup
+	 * from addChild -> registerChild or from postInitialize->registerChild
+	 * not called in batch procession
+	 * HTML & widget.createWidget only
+	 * Layout MUST be removed when node is detached
+	 * 
+	 */
+	addedTo: function(parent, index, dontPublishEvent) {
+		//dojo.profile.start("addedTo");
+		//dojo.debug(this + " addedTo "+parent+" index "+index);
+		//dojo.debug(parent.children);
+		//dojo.debug(parent.containerNode.innerHTML);
+		
+		//dojo.debug((new Error()).stack);
+					
+				
+		if (this.tree !== parent.tree) {
+			this.updateTree(parent.tree);
+		}
+		
+		if (parent.isTreeNode) {
+			if (!parent.isFolder) {
+				//dojo.debug("folderize parent "+parent);
+				parent.setFolder();
+				parent.state = parent.loadStates.LOADED;
+			}
+		}
+		
+		
+		var siblingsCount = parent.children.length;
+		
+		// setFolder works BEFORE insertNode
+		this.insertNode(parent, index);
+		
+		
+		this.viewAddLayout();
+	
+		
+		//dojo.debug("siblings "+parent.children);
+		
+		if (siblingsCount > 1) {
+			if (index == 0 && parent.children[1] instanceof dojo.widget.Widget) {
+				parent.children[1].viewUpdateLayout();				
+			}
+			if (index == siblingsCount-1 && parent.children[siblingsCount-2] instanceof dojo.widget.Widget) {
+				parent.children[siblingsCount-2].viewUpdateLayout();			
+			}
+		} else if (parent.isTreeNode) {
+			// added as the first child
+			//dojo.debug("added as first");
+			parent.viewSetHasChildren();
+		}
+		
+		if (!dontPublishEvent) {
+
+			var message = {
+				child: this,
+				index: index,
+				parent: parent
+			}
+				
+			dojo.event.topic.publish(this.tree.eventNames.afterAddChild, message);
+		}
+
+		//dojo.profile.end("addedTo");
+		
+				
+	},
+	
+	/**
+	 * Fast program-only hacky creation of widget
+	 * 	
+	 */
+	createSimple: function(args, parent) {
+		// I pass no args and ignore default controller
+		//dojo.profile.start(this.widgetType+" createSimple");
+		//dojo.profile.start(this.widgetType+" createSimple constructor");
+		if (args.tree) {
+			var tree = args.tree;
+		} else if (parent) {
+			var tree = parent.tree;
+		} else {
+			dojo.raise("createSimple: can't evaluate tree");
+		}
+		tree = dojo.widget.byId(tree);
+		
+		//dojo.debug(tree);
+		
+		var treeNode = new tree.defaultChildWidget(); 
+		//dojo.profile.end(this.widgetType+" createSimple constructor");
+		
+		//dojo.profile.start(this.widgetType+" createSimple mixin");		
+		for(var x in args){ // fastMixIn			
+			treeNode[x] = args[x];
+		}
+		
+		
+		//dojo.profile.end(this.widgetType+" createSimple mixin");
+		
+				
+		// HtmlWidget.postMixIn 
+		treeNode.toggleObj = dojo.lfx.toggle[treeNode.toggle.toLowerCase()] || dojo.lfx.toggle.plain;
+
+		//dojo.profile.start(this.widgetType + " manager");
+		dojo.widget.manager.add(treeNode);
+		//dojo.profile.end(this.widgetType + " manager");
+		
+		//dojo.profile.start(this.widgetType + " buildRendering");
+		treeNode.buildRendering(args, {}, parent);		
+		//dojo.profile.end(this.widgetType + " buildRendering");
+		
+		treeNode.initialize(args, {}, parent);
+		
+		//dojo.profile.end(this.widgetType+"createSimple");
+		if (treeNode.parent) {
+			delete dojo.widget.manager.topWidgets[treeNode.widgetId];
+		}
+		
+		return treeNode;
+	},
+	
+	
+	
+	// can override e.g for case of div with +- text inside
+	viewUpdateLayout: function() {
+		//dojo.profile.start("viewUpdateLayout");
+		//dojo.debug("UpdateLayout in "+this);
+
+		this.viewRemoveLayout();
+		this.viewAddLayout();
+		//dojo.profile.end("viewUpdateLayout");	
+	},
+	
+	
+	viewAddContainer: function() {
+		// make controller only if children exist
+		this.containerNode = this.tree.containerNodeTemplate.cloneNode(true);
+		this.domNode.appendChild(this.containerNode);
+	},
+	/*
+	viewRemoveContainer: function() {
+		// make controller only if children exist
+		this.domNode.removeChild(this.containerNode);
+		this.containerNode = null;
+	},
+	*/
+	
+	viewAddLayout: function() {
+		//dojo.profile.start("viewAddLayout");
+		//dojo.debug("viewAddLayout in "+this);
+		
+		if (this.parent["isTree"]) {
+			//dojo.debug("Parent isTree => add isTreeRoot");
+			
+			// use setClass, not addClass for speed
+			dojo.html.setClass(this.domNode, dojo.html.getClass(this.domNode) + ' '+this.tree.classPrefix+'IsRoot')
+		}
+		//dojo.debug(this.parent.children.length);
+		//dojo.debug(this.parent.children[this.parent.children.length-1]);
+		if (this.isLastChild()) {
+			//dojo.debug("Checked last node for "+this);
+			//dojo.debug("Parent last is "+this.parent.children[this.parent.children.length-1]);
+			//dojo.debug("last node => add isTreeLast for "+this);
+			dojo.html.setClass(this.domNode, dojo.html.getClass(this.domNode) + ' '+this.tree.classPrefix+'IsLast')			
+		}
+		//dojo.profile.end("viewAddLayout");
+		//dojo.debug("viewAddLayout out");
+		
+	},
+	
+	
+	viewRemoveLayout: function() {		
+		//dojo.debug("viewRemoveLayout in "+this);
+		//dojo.profile.start("viewRemoveLayout");
+		//dojo.debug((new Error()).stack);
+		dojo.html.removeClass(this.domNode, this.tree.classPrefix+"IsRoot");
+		dojo.html.removeClass(this.domNode, this.tree.classPrefix+"IsLast");
+		//dojo.profile.end("viewRemoveLayout");
+	},
+		
+	viewGetExpandClass: function() {
+		if (this.isFolder) {			
+			return this.isExpanded ? "ExpandOpen" : "ExpandClosed";
+		} else {
+			return "ExpandLeaf";
+		}
+	},
+	
+	viewSetExpand: function() {
+		//dojo.profile.start("viewSetExpand");
+		
+		//dojo.debug("viewSetExpand in "+this);
+		
+		var expand = this.tree.classPrefix+this.viewGetExpandClass();
+		var reg = new RegExp("(^|\\s)"+this.tree.classPrefix+"Expand\\w+",'g');			
+			
+		dojo.html.setClass(this.domNode, dojo.html.getClass(this.domNode).replace(reg,'') + ' '+expand);
+		
+		//dojo.debug(dojo.html.getClass(this.domNode))
+		//dojo.profile.end("viewSetExpand");
+		this.viewSetHasChildrenAndExpand();
+	},	
+
+	viewGetChildrenClass: function() {
+		return 'Children'+(this.children.length ? 'Yes' : 'No');
+	},
+	
+	viewSetHasChildren: function() {		
+		//dojo.debug(this+' '+this.children.length)
+		
+		var clazz = this.tree.classPrefix+this.viewGetChildrenClass();
+
+		var reg = new RegExp("(^|\\s)"+this.tree.classPrefix+"Children\\w+",'g');			
+		
+		dojo.html.setClass(this.domNode, dojo.html.getClass(this.domNode).replace(reg,'') + ' '+clazz);
+		
+		this.viewSetHasChildrenAndExpand();
+	},
+	
+	/**
+	 * set TreeStateChildrenYes-ExpandClosed pair
+	 * needed for IE, because IE reads only last class from .TreeChildrenYes.TreeExpandClosed pair
+	 */
+	viewSetHasChildrenAndExpand: function() {
+		var clazz = this.tree.classPrefix+'State'+this.viewGetChildrenClass()+'-'+this.viewGetExpandClass();
+		
+		var reg = new RegExp("(^|\\s)"+this.tree.classPrefix+"State[\\w-]+",'g');			
+		
+		dojo.html.setClass(this.domNode, dojo.html.getClass(this.domNode).replace(reg,'') + ' '+clazz);		
+	},
+		
+	viewUnfocus: function() {
+		dojo.html.removeClass(this.labelNode, this.tree.classPrefix+"LabelFocused");
+	},
+	
+	viewFocus: function() {
+		dojo.html.addClass(this.labelNode, this.tree.classPrefix+"LabelFocused");
+	},
+    
+    viewEmphase: function() {
+        dojo.html.clearSelection(this.labelNode);
+        
+		dojo.html.addClass(this.labelNode, this.tree.classPrefix+'NodeEmphased');
+    },
+    
+    viewUnemphase: function() {
+        dojo.html.removeClass(this.labelNode, this.tree.classPrefix+'NodeEmphased');
+    },
+	
+	
+// ================================ detach from parent ===================================
+
+	detach: function() {
+		if (!this.parent) return;
+
+		var parent = this.parent;
+		var index = this.getParentIndex();
+
+		this.doDetach.apply(this, arguments);
+
+		dojo.event.topic.publish(this.tree.eventNames.afterDetach,
+			{ child: this, parent: parent, index:index }
+		);
+		
+	},
+	
+
+	/* node does not leave tree */
+	doDetach: function() {
+		//dojo.debug("doDetach in "+this+" parent "+this.parent+" class "+dojo.html.getClass(this.domNode));
+				
+		var parent = this.parent;
+		
+		//dojo.debug(parent.containerNode.style.display)
+		
+		if (!parent) return;
+		
+		var index = this.getParentIndex();
+		
+		
+		this.viewRemoveLayout();
+		
+		dojo.widget.DomWidget.prototype.removeChild.call(parent, this);
+		
+		var siblingsCount = parent.children.length;
+		
+		//dojo.debug("siblingsCount "+siblingsCount);
+		
+		if (siblingsCount > 0) {
+			if (index == 0) {	// deleted first node => update new first
+				parent.children[0].viewUpdateLayout();		
+			}
+			if (index == siblingsCount) { // deleted last node
+				parent.children[siblingsCount-1].viewUpdateLayout();		
+			}
+		} else {
+			if (parent.isTreeNode) {
+				parent.viewSetHasChildren();
+			}
+		}
+				
+		if (this.tree.unsetFolderOnEmpty && !parent.children.length && parent.isTreeNode) {
+			parent.unsetFolder();
+		}		
+		
+		//dojo.debug(parent.containerNode.style.display)
+		
+		this.parent = null;
+	},
+	
+	
+	/**
+	 * publish destruction event so that controller may unregister/unlisten
+	 */
+	destroy: function() {
+		
+		dojo.event.topic.publish(this.tree.eventNames.beforeNodeDestroy, { source: this } );
+		
+		this.detach();		
+
+		return dojo.widget.HtmlWidget.prototype.destroy.apply(this, arguments);
+	},
+	
+	
+	expand: function(){
+        		
+		if (this.isExpanded) return;
+
+
+		//dojo.profile.start("expand "+this);
+		
+		//dojo.debug("expand in "+this);
+		
+		//dojo.profile.start("expand - lazy init "+this);
+		if (this.tryLazyInit) {
+			this.setChildren();
+			this.tryLazyInit = false;
+		}
+		
+		//dojo.profile.end("expand - lazy init "+this);
+		
+		
+		this.isExpanded = true;
+
+		this.viewSetExpand();
+
+		//dojo.profile.start("expand - showChildren "+this);
+		
+		/**
+		 * no matter if I have children or not. need to show/hide container anyway.
+		 * use case: empty folder is expanded => then child is added, container already shown all fine
+		 */
+		this.showChildren();
+		
+		//dojo.profile.end("expand - showChildren "+this);
+						
+		
+		//dojo.profile.end("expand "+this);
+	},
+
+
+	collapse: function(){
+						
+		if (!this.isExpanded) return;
+		
+		this.isExpanded = false;
+		
+		this.hideChildren();
+	},
+
+
+	hideChildren: function(){
+		this.tree.toggleObj.hide(
+			this.containerNode, this.tree.toggleDuration, this.explodeSrc, dojo.lang.hitch(this, "onHideChildren")
+		);
+	},
+
+
+	showChildren: function(){
+		//dojo.profile.start("showChildren"+this);
+        
+		this.tree.toggleObj.show(
+			this.containerNode, this.tree.toggleDuration, this.explodeSrc, dojo.lang.hitch(this, "onShowChildren")
+		);
+        
+		//dojo.profile.end("showChildren"+this);
+	},
+	 
+    
+    
+	onShowChildren: function() {
+        
+		//dojo.profile.start("onShowChildren"+this);
+        
+        this.onShow();
+        
+		//dojo.profile.end("onShowChildren"+this);
+        
+		dojo.event.topic.publish(this.tree.eventNames.afterExpand, {source: this} );		
+	},
+	
+	onHideChildren: function() {
+
+		this.viewSetExpand();
+		this.onHide();
+		dojo.event.topic.publish(this.tree.eventNames.afterCollapse, {source: this} );
+	},
+
+	/* Edit current node : change properties and update contents */
+	setTitle: function(title) {
+		var oldTitle = this.title;
+		
+		this.labelNode.innerHTML = this.title = title;
+				
+		dojo.event.topic.publish(this.tree.eventNames.afterSetTitle, { source: this, oldTitle:oldTitle });
+
+	},
+
+
+	toString: function() {
+		return '['+this.widgetType+', '+this.title+']';
+	}
+
+
+});

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeNodeV3.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeRPCController.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeRPCController.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeRPCController.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeRPCController.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,152 @@
+
+dojo.provide("dojo.widget.TreeRPCController");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.json")
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.TreeLoadingController");
+
+
+dojo.widget.defineWidget("dojo.widget.TreeRPCController", dojo.widget.TreeLoadingController, {
+	/**
+	 * Make request to server about moving children.
+	 *
+	 * Request returns "true" if move succeeded,
+	 * object with error field if failed
+	 *
+	 * I can't leave DragObject floating until async request returns, need to return false/true
+	 * so making it sync way...
+	 *
+	 * Also, "loading" icon is not shown until function finishes execution, so no indication for remote request.
+	*/
+	doMove: function(child, newParent, index){
+
+		//if (newParent.isTreeNode) newParent.markLoading();
+
+		var params = {
+			// where from
+			child: this.getInfo(child),
+			childTree: this.getInfo(child.tree),
+			// where to
+			newParent: this.getInfo(newParent),
+			newParentTree: this.getInfo(newParent.tree),
+			newIndex: index
+		};
+
+		var success;
+
+		this.runRPC({		
+			url: this.getRPCUrl('move'),
+			/* I hitch to get this.loadOkHandler */
+			load: function(response){
+				success = this.doMoveProcessResponse(response, child, newParent, index) ;
+			},
+			sync: true,
+			lock: [child, newParent],
+			params: params
+		});
+
+
+		return success;
+	},
+
+	doMoveProcessResponse: function(response, child, newParent, index){
+
+		if(!dojo.lang.isUndefined(response.error)){
+			this.RPCErrorHandler("server", response.error);
+			return false;
+		}
+
+		var args = [child, newParent, index];
+		return dojo.widget.TreeLoadingController.prototype.doMove.apply(this, args);
+
+	},
+
+
+	doRemoveNode: function(node, callObj, callFunc){
+
+		var params = {
+			node: this.getInfo(node),
+			tree: this.getInfo(node.tree)
+		}
+
+		this.runRPC({
+				url: this.getRPCUrl('removeNode'),
+				/* I hitch to get this.loadOkHandler */
+				load: function(response){
+					this.doRemoveNodeProcessResponse(response, node, callObj, callFunc) 
+				},
+				params: params,
+				lock: [node]
+		});
+
+	},
+
+
+	doRemoveNodeProcessResponse: function(response, node, callObj, callFunc){
+		if(!dojo.lang.isUndefined(response.error)){
+			this.RPCErrorHandler("server", response.error);
+			return false;
+		}
+
+		if(!response){ return false; }
+
+		if(response == true){
+			/* change parent succeeded */
+			var args = [ node, callObj, callFunc ];
+			dojo.widget.TreeLoadingController.prototype.doRemoveNode.apply(this, args);
+
+			return;
+		}else if(dojo.lang.isObject(response)){
+			dojo.raise(response.error);
+		}else{
+			dojo.raise("Invalid response "+response)
+		}
+
+
+	},
+
+
+
+	// -----------------------------------------------------------------------------
+	//                             Create node stuff
+	// -----------------------------------------------------------------------------
+
+
+	doCreateChild: function(parent, index, output, callObj, callFunc){
+
+			var params = {
+				tree: this.getInfo(parent.tree),
+				parent: this.getInfo(parent),
+				index: index,
+				data: output
+			}
+
+			this.runRPC({
+				url: this.getRPCUrl('createChild'),
+				load: function(response) {
+					// suggested data is dead, fresh data from server is used
+					this.doCreateChildProcessResponse( response, parent, index, callObj, callFunc) 
+				},
+				params: params,
+				lock: [parent]
+			});
+
+	},
+
+	doCreateChildProcessResponse: function(response, parent, index, callObj, callFunc){
+
+		if(!dojo.lang.isUndefined(response.error)){
+			this.RPCErrorHandler("server",response.error);
+			return false;
+		}
+
+		if(!dojo.lang.isObject(response)){
+			dojo.raise("Invalid result "+response)
+		}
+
+		var args = [parent, index, response, callObj, callFunc];
+		
+		dojo.widget.TreeLoadingController.prototype.doCreateChild.apply(this, args);
+	}
+});

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeRPCController.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeRpcControllerV3.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeRpcControllerV3.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeRpcControllerV3.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeRpcControllerV3.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,414 @@
+
+dojo.provide("dojo.widget.TreeRpcControllerV3");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.json")
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.TreeLoadingControllerV3");
+
+dojo.widget.defineWidget(
+	"dojo.widget.TreeRpcControllerV3",
+	dojo.widget.TreeLoadingControllerV3,
+{
+	// TODO: do something with addChild / setChild, so that RpcController become able
+	// to hook on this and report to server
+
+	extraRpcOnEdit: false,
+				
+	/**
+	 * Make request to server about moving children.
+	 *
+	 * Request returns "true" if move succeeded,
+	 * object with error field if failed
+	 *
+	 * I can't leave DragObject floating until async request returns, need to return false/true
+	 * so making it sync way...
+	 *
+	 * Also, "loading" icon is not shown until function finishes execution, so no indication for remote request.
+	*/
+	doMove: function(child, newParent, index, sync){
+
+		//if (newParent.isTreeNode) newParent.markLoading();
+
+		
+		var params = {
+			// where from
+			child: this.getInfo(child),
+			childTree: this.getInfo(child.tree),
+			// where to
+			newParent: this.getInfo(newParent),
+			newParentTree: this.getInfo(newParent.tree),
+			newIndex: index
+		};
+
+
+		var deferred = this.runRpc({		
+			url: this.getRpcUrl('move'),
+			sync: sync,			
+			params: params
+		});
+
+		var _this = this;
+		var args = arguments;	
+		
+		//deferred.addCallback(function(res) { dojo.debug("doMove fired "+res); return res});
+		
+		deferred.addCallback(function() {			
+			dojo.widget.TreeBasicControllerV3.prototype.doMove.apply(_this,args);
+		});
+
+		
+		return deferred;
+	},
+
+	// -------------- detach
+	
+	prepareDetach: function(node, sync) {
+		var deferred = this.startProcessing(node);		
+		return deferred;
+	},
+	
+	finalizeDetach: function(node) {
+		this.finishProcessing(node);
+	},
+
+	doDetach: function(node, sync){
+
+		
+		var params = {
+			node: this.getInfo(node),
+			tree: this.getInfo(node.tree)
+		}
+
+		var deferred = this.runRpc({
+			url: this.getRpcUrl('detach'),
+			sync: sync,
+			params: params			
+		});
+		
+		
+		var _this = this;
+		var args = arguments;
+		
+		deferred.addCallback(function() {			
+			dojo.widget.TreeBasicControllerV3.prototype.doDetach.apply(_this,args);
+		});
+		
+						
+		return deferred;
+
+	},
+
+	// -------------------------- Inline edit node ---------------------	
+
+	/**
+	 * send edit start request if needed
+	 * useful for server-side locking 
+	 */
+	requestEditConfirmation: function(node, action, sync) {
+		if (!this.extraRpcOnEdit) {			
+			return dojo.Deferred.prototype.makeCalled();
+		}
+	
+		//dojo.debug("requestEditConfirmation "+node+" "+action);
+		
+		var _this = this;
+	
+		var deferred = this.startProcessing(node);
+			
+		//dojo.debug("startProcessing "+node);
+		
+		var params = {
+			node: this.getInfo(node),
+			tree: this.getInfo(node.tree)
+		}
+		
+		deferred.addCallback(function() {
+			//dojo.debug("add action on requestEditConfirmation "+action);
+			return _this.runRpc({
+				url: _this.getRpcUrl(action),
+				sync: sync,
+				params: params			
+			});
+		});
+		
+		
+		deferred.addBoth(function(r) {
+			//dojo.debug("finish rpc with "+r);
+			_this.finishProcessing(node);
+			return r;
+		});
+	
+		return deferred;
+	},
+	
+	editLabelSave: function(node, newContent, sync) {
+		var deferred = this.startProcessing(node);
+						
+		var _this = this;
+		
+		var params = {
+			node: this.getInfo(node),
+			tree: this.getInfo(node.tree),
+			newContent: newContent
+		}
+		
+	
+		deferred.addCallback(function() {
+			return _this.runRpc({
+				url: _this.getRpcUrl('editLabelSave'),
+				sync: sync,
+				params: params			
+			});
+		});
+		
+		
+		deferred.addBoth(function(r) {
+			_this.finishProcessing(node);
+			return r;
+		});
+	
+		return deferred;
+	},
+	
+	editLabelStart: function(node, sync) {		
+		if (!this.canEditLabel(node)) {
+			return false;
+		}
+		
+		var _this = this;
+		
+		if (!this.editor.isClosed()) {
+			//dojo.debug("editLabelStart editor open");
+			var deferred = this.editLabelFinish(this.editor.saveOnBlur, sync);
+			deferred.addCallback(function() {
+				return _this.editLabelStart(node, sync);
+			});
+			return deferred;
+		}
+						
+		//dojo.debug("editLabelStart closed, request");
+		var deferred = this.requestEditConfirmation(node, 'editLabelStart', sync);
+		
+		deferred.addCallback(function() {
+			//dojo.debug("start edit");
+			_this.doEditLabelStart(node);
+		});
+	
+		
+		return deferred;
+	
+	},
+
+	editLabelFinish: function(save, sync) {
+		var _this = this;
+		
+		var node = this.editor.node;
+		
+		var deferred = dojo.Deferred.prototype.makeCalled();
+		
+		if (!save && !node.isPhantom) {
+			deferred = this.requestEditConfirmation(this.editor.node,'editLabelFinishCancel', sync);
+		}
+		
+		if (save) {
+			if (node.isPhantom) {
+				deferred = this.sendCreateChildRequest(
+					node.parent,
+					node.getParentIndex(),
+					{title:this.editor.getContents()},
+					sync
+				);
+			} else {				
+				// this deferred has new information from server
+				deferred = this.editLabelSave(node, this.editor.getContents(), sync);
+			}
+		}
+		
+		deferred.addCallback(function(server_data) {			
+			_this.doEditLabelFinish(save, server_data);
+		});
+		
+		deferred.addErrback(function(r) {
+			//dojo.debug("Error occured");
+			//dojo.debugShallow(r);
+			_this.doEditLabelFinish(false);
+			return false;
+		});
+		
+		return deferred;
+	},
+	
+			
+	
+	/**
+	 * TODO: merge server-side info
+	 */
+	createAndEdit: function(parent, index, sync) {
+		var data = {title:parent.tree.defaultChildTitle};
+		
+		if (!this.canCreateChild(parent, index, data)) {
+			return false;
+		}
+		
+		/* close editor first */
+		if (!this.editor.isClosed()) {
+			//dojo.debug("editLabelStart editor open");
+			var deferred = this.editLabelFinish(this.editor.saveOnBlur, sync);
+			deferred.addCallback(function() {
+				return _this.createAndEdit(parent, index, sync);
+			});
+			return deferred;
+		}
+			
+		var _this = this;
+		
+		/* load parent and create child*/
+		var deferred = this.prepareCreateChild(parent, index, data, sync);
+		
+		
+		deferred.addCallback(function() {
+			var child = _this.makeDefaultNode(parent, index);			
+			child.isPhantom = true;
+			return child;
+		});
+		
+		
+		deferred.addBoth(function(r) {
+			_this.finalizeCreateChild(parent, index, data, sync);
+			return r;
+		});
+		
+		/* expand parent */
+		deferred.addCallback(function(child) {
+			var d = _this.exposeCreateChild(parent, index, data, sync);
+			d.addCallback(function() { return child });
+			return d;
+		});
+		
+		
+		deferred.addCallback(function(child) {
+			//dojo.debug("start edit");
+			_this.doEditLabelStart(child);
+			return child;
+		});
+		
+		
+		
+		return deferred;
+	
+	},
+
+	prepareDestroyChild: function(node, sync) {
+		//dojo.debug(node);
+		var deferred = this.startProcessing(node);		
+		return deferred;
+	},
+	
+	finalizeDestroyChild: function(node) {
+		this.finishProcessing(node);
+	},
+		
+
+	doDestroyChild: function(node, sync){
+
+		
+		var params = {
+			node: this.getInfo(node),
+			tree: this.getInfo(node.tree)
+		}
+
+		var deferred = this.runRpc({
+			url: this.getRpcUrl('destroyChild'),
+			sync: sync,
+			params: params			
+		});
+		
+		
+		var _this = this;
+		var args = arguments;
+		
+		deferred.addCallback(function() {			
+			dojo.widget.TreeBasicControllerV3.prototype.doDestroyChild.apply(_this,args);
+		});
+		
+						
+		return deferred;
+
+	},
+
+	// -----------------------------------------------------------------------------
+	//                             Create node stuff
+	// -----------------------------------------------------------------------------
+	sendCreateChildRequest: function(parent, index, data, sync) {
+		var params = {
+			tree: this.getInfo(parent.tree),
+			parent: this.getInfo(parent),
+			index: index,
+			data: data
+		}
+
+		var deferred = this.runRpc({
+			url: this.getRpcUrl('createChild'),
+			sync: sync,
+			params: params
+		});
+		
+		return deferred;
+	},
+		
+
+	doCreateChild: function(parent, index, data, sync){		
+		
+		if (dojo.lang.isUndefined(data.title)) {
+			data.title = parent.tree.defaultChildTitle;
+		}
+
+		var deferred = this.sendCreateChildRequest(parent,index,data,sync);
+		
+		var _this = this;
+		var args = arguments;
+		
+		
+		deferred.addCallback(function(server_data) {
+			dojo.lang.mixin(server_data, data); // add my data as less priority
+			//dojo.debug("Create ");
+			//dojo.debug(server_data);
+			return dojo.widget.TreeBasicControllerV3.prototype.doCreateChild.call(_this,parent,index,server_data);
+		});
+		
+						
+		return deferred;
+	},
+	
+	// TODO: merge server data into cloned node, like in createChild	
+	doClone: function(child, newParent, index, deep, sync) {
+		
+		var params = {
+			child: this.getInfo(child),
+			newParent: this.getInfo(newParent),
+			index: index,
+			deep: deep ? true : false, // undefined -> false
+			tree: this.getInfo(child.tree)
+		}
+		
+		
+		var deferred = this.runRpc({
+			url: this.getRpcUrl('clone'),
+			sync: sync,
+			params: params
+		});
+		
+		var _this = this;
+		var args = arguments;
+		
+		deferred.addCallback(function() {			
+			dojo.widget.TreeBasicControllerV3.prototype.doClone.apply(_this,args);
+		});
+		
+						
+		return deferred;	
+	}
+
+	
+});

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeRpcControllerV3.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeSelector.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeSelector.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeSelector.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeSelector.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,169 @@
+
+dojo.provide("dojo.widget.TreeSelector");
+
+dojo.require("dojo.widget.HtmlWidget");
+
+
+dojo.widget.defineWidget("dojo.widget.TreeSelector", dojo.widget.HtmlWidget, function() {
+	this.eventNames = {};
+
+	this.listenedTrees = [];
+
+},
+{
+	widgetType: "TreeSelector",
+	selectedNode: null,
+
+	dieWithTree: false,
+
+	eventNamesDefault: {
+		select : "select",
+		destroy : "destroy",
+		deselect : "deselect",
+		dblselect: "dblselect" // select already selected node.. Edit or whatever
+	},
+
+	initialize: function() {
+
+		for(name in this.eventNamesDefault) {
+			if (dojo.lang.isUndefined(this.eventNames[name])) {
+				this.eventNames[name] = this.widgetId+"/"+this.eventNamesDefault[name];
+			}
+		}
+
+	},
+
+
+	destroy: function() {
+		dojo.event.topic.publish(this.eventNames.destroy, { source: this } );
+
+		return dojo.widget.HtmlWidget.prototype.destroy.apply(this, arguments);
+	},
+
+
+	listenTree: function(tree) {
+		dojo.event.topic.subscribe(tree.eventNames.titleClick, this, "select");
+		dojo.event.topic.subscribe(tree.eventNames.iconClick, this, "select");
+		dojo.event.topic.subscribe(tree.eventNames.collapse, this, "onCollapse");
+		dojo.event.topic.subscribe(tree.eventNames.moveFrom, this, "onMoveFrom");
+		dojo.event.topic.subscribe(tree.eventNames.removeNode, this, "onRemoveNode");
+		dojo.event.topic.subscribe(tree.eventNames.treeDestroy, this, "onTreeDestroy");
+
+		/* remember all my trees to deselect when element is movedFrom them */
+		this.listenedTrees.push(tree);
+	},
+
+
+	unlistenTree: function(tree) {
+
+		dojo.event.topic.unsubscribe(tree.eventNames.titleClick, this, "select");
+		dojo.event.topic.unsubscribe(tree.eventNames.iconClick, this, "select");
+		dojo.event.topic.unsubscribe(tree.eventNames.collapse, this, "onCollapse");
+		dojo.event.topic.unsubscribe(tree.eventNames.moveFrom, this, "onMoveFrom");
+		dojo.event.topic.unsubscribe(tree.eventNames.removeNode, this, "onRemoveNode");
+		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);
+
+		if (this.dieWithTree) {
+			//dojo.debug("Killing myself "+this.widgetId);
+			this.destroy();
+			//dojo.debug("done");
+		}
+	},
+
+
+	// deselect node if parent is collapsed
+	onCollapse: function(message) {
+		if (!this.selectedNode) return;
+
+		var node = message.source;
+		var parent = this.selectedNode.parent;
+		while (parent !== node && parent.isTreeNode) {
+			parent = parent.parent;
+		}
+		if (parent.isTreeNode) {
+			this.deselect();
+		}
+	},
+
+
+
+	select: function(message) {
+		var node = message.source;
+		var e = message.event;
+
+		if (this.selectedNode === node) {
+			if(e.ctrlKey || e.shiftKey || e.metaKey){
+				// If the node is currently selected, and they select it again while holding
+				// down a meta key, it deselects it
+				this.deselect();
+				return;
+			}
+			dojo.event.topic.publish(this.eventNames.dblselect, { node: node });
+			return;
+		}
+
+		if (this.selectedNode) {
+			this.deselect();
+		}
+
+		this.doSelect(node);
+
+		dojo.event.topic.publish(this.eventNames.select, {node: node} );
+	},
+
+	/**
+	 * Deselect node if target tree is out of our concern
+	 */
+	onMoveFrom: function(message) {
+		if (message.child !== this.selectedNode) {
+			return;
+		}
+
+		if (!dojo.lang.inArray(this.listenedTrees, message.newTree)) {
+			this.deselect();
+		}
+	},
+
+	onRemoveNode: function(message) {
+		if (message.child !== this.selectedNode) {
+			return;
+		}
+
+		this.deselect();
+	},
+
+	doSelect: function(node){
+
+		node.markSelected();
+
+		this.selectedNode = node;
+	},
+
+	deselect: function(){
+
+		var node = this.selectedNode;
+
+		this.selectedNode = null;
+		node.unMarkSelected();
+		dojo.event.topic.publish(this.eventNames.deselect, {node: node} );
+
+	}
+
+});
+
+
+

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeSelector.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeSelectorV3.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeSelectorV3.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeSelectorV3.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeSelectorV3.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,241 @@
+
+dojo.provide("dojo.widget.TreeSelectorV3");
+
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.TreeCommon");
+
+dojo.widget.defineWidget(
+	"dojo.widget.TreeSelectorV3",
+	[dojo.widget.HtmlWidget, dojo.widget.TreeCommon],
+	function() {
+		this.eventNames = {};
+		this.listenedTrees = {};
+		this.selectedNodes = [];		
+	},
+{
+	// TODO: add multiselect
+
+	listenTreeEvents: ["afterTreeCreate","afterCollapse","afterChangeTree", "afterDetach", "beforeTreeDestroy"],
+	listenNodeFilter: function(elem) { return elem instanceof dojo.widget.Widget},	
+	
+	allowedMulti: true,
+	
+	eventNamesDefault: {
+		select : "select",
+		deselect : "deselect",
+		dblselect: "dblselect" // select already selected node.. Edit or whatever
+	},
+
+	onAfterTreeCreate: function(message) {
+		var tree = message.source;
+		dojo.event.browser.addListener(tree.domNode, "onclick", dojo.lang.hitch(this, this.onTreeClick));
+		if (dojo.render.html.ie) {
+			dojo.event.browser.addListener(tree.domNode, "ondblclick", dojo.lang.hitch(this, this.onTreeDblClick));
+		}
+		dojo.event.browser.addListener(tree.domNode, "onKey", dojo.lang.hitch(this, this.onKey));
+		
+	},
+	
+	
+	onKey: function(e) {
+		if (!e.key || e.ctrkKey || e.altKey) { return; }
+		
+		switch(e.key) {
+			case e.KEY_ENTER:
+				var node = this.domElement2TreeNode(e.target);
+				if (node) {
+					this.processNode(node, e);
+				}
+		
+		}
+	},
+	
+	
+		
+	onAfterChangeTree: function(message) {
+		
+		if (!message.oldTree && message.node.selected) {
+			this.select(message.node);
+		}
+		
+		if (!message.newTree || !this.listenedTrees[message.newTree.widgetId]) {
+			// moving from our trfee to new one that we don't listen
+			
+			if (this.selectedNode && message.node.children) {
+				this.deselectIfAncestorMatch(message.node);
+			}						
+			
+		}
+		
+		
+	},
+		
+		
+		
+	initialize: function(args) {
+
+		for(name in this.eventNamesDefault) {
+			if (dojo.lang.isUndefined(this.eventNames[name])) {
+				this.eventNames[name] = this.widgetId+"/"+this.eventNamesDefault[name];
+			}
+		}
+				
+	},
+
+	onBeforeTreeDestroy: function(message) {
+		this.unlistenTree(message.source);
+	},
+
+	// deselect node if ancestor is collapsed
+	onAfterCollapse: function(message) {		
+		this.deselectIfAncestorMatch(message.source);		
+	},
+
+	// IE will throw select -> dblselect. Need to transform to select->select
+	onTreeDblClick: function(event) {
+		this.onTreeClick(event);			
+	},		
+		
+	checkSpecialEvent: function(event) {		
+		return event.shiftKey || event.ctrlKey;
+	},
+	
+	
+	onTreeClick: function(event) {
+		
+		
+		var node = this.domElement2TreeNode(event.target);
+		
+		if (node) {
+			this.processNode(node, event);
+		}
+	},
+	
+	
+	/**
+	 * press on selected with ctrl => deselect it
+	 * press on selected w/o ctrl => dblselect it and deselect all other
+	 *
+	 * press on unselected with ctrl => add it to selection
+	 *
+	 * event may be both mouse & keyboard enter
+	 */
+	processNode: function(node, event) {
+		
+		if (node.actionIsDisabled(node.actions.SELECT)) {
+			return;
+		}
+		
+		//dojo.debug("click "+node+ "special "+this.checkSpecialEvent(event));
+		//dojo.html.setClass(event.target, "TreeLabel TreeNodeEmphased");
+		
+		if (dojo.lang.inArray(this.selectedNodes, node)) {			
+			if(this.checkSpecialEvent(event)){				
+				// If the node is currently selected, and they select it again while holding
+				// down a meta key, it deselects it
+				this.deselect(node);
+				return;
+			}
+			
+			var _this = this;
+			var i=0;
+			var selectedNode;
+			while(this.selectedNodes.length > i) {
+				selectedNode = this.selectedNodes[i];
+				if (selectedNode !== node) {
+					//dojo.debug("Deselect "+selectedNode);
+					_this.deselect(selectedNode);
+					continue;
+				}
+			
+				i++; // skip the doubleclicked node
+			}
+		
+			
+			dojo.event.topic.publish(this.eventNames.dblselect, { node: node });
+			return;
+		}
+		
+		// if unselected node..
+		
+		this.deselectIfNoMulti(event);
+		
+		//dojo.debug("select");
+
+		this.select(node);
+
+	},
+	
+	// deselect all if no meta key or disallowed
+	deselectIfNoMulti: function(event) {
+		if (!this.checkSpecialEvent(event) || !this.allowedMulti) {
+			//dojo.debug("deselect All");
+			this.deselectAll();
+		}
+	},
+
+	deselectIfAncestorMatch: function(ancestor) {
+		/* deselect all nodes with this ancestor */
+		var _this = this;
+		dojo.lang.forEach(this.selectedNodes, function(node) {
+			var selectedNode = node;
+			while (node && node.isTreeNode) {
+				if (node === ancestor) {
+					_this.deselect(selectedNode); 
+					return;					
+				}
+				node = node.parent;
+			}
+		});
+	},
+	
+			
+
+
+	onAfterDetach: function(message) {
+		this.deselectIfAncestorMatch(message.child);		
+	},
+
+
+	select: function(node) {
+
+		var index = dojo.lang.find(this.selectedNodes, node, true);
+		
+		if (index >=0 ) {
+			return; // already selected
+		}
+				
+		//dojo.debug("select "+node);
+		this.selectedNodes.push(node);
+						
+		dojo.event.topic.publish(this.eventNames.select, {node: node} );
+	},
+
+
+	deselect: function(node){
+		var index = dojo.lang.find(this.selectedNodes, node, true);
+		if (index < 0) {
+			//dojo.debug("not selected");
+			return; // not selected
+		}
+		
+		//dojo.debug("deselect "+node);
+		//dojo.debug((new Error()).stack);
+		
+		this.selectedNodes.splice(index, 1);
+		dojo.event.topic.publish(this.eventNames.deselect, {node: node} );
+		//dojo.debug("deselect");
+
+	},
+	
+	deselectAll: function() {
+		//dojo.debug("deselect all "+this.selectedNodes);
+		while (this.selectedNodes.length) {
+			this.deselect(this.selectedNodes[0]);
+		}
+	}
+
+});
+
+
+

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeSelectorV3.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeTimeoutIterator.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeTimeoutIterator.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeTimeoutIterator.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeTimeoutIterator.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,159 @@
+
+dojo.provide("dojo.widget.TreeTimeoutIterator");
+
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.json")
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.TreeCommon");
+
+
+/**
+ * Iterates the tree processNext
+ * filterFunc/filterObj called to determine if I need to pass the node
+ * 
+ * callFunc/callObj called to process the node
+ *    callObj.callFunc(elem, iterator) should call iterator.forward() to go on
+ *    callFunc may change elem to another object (e.g create widget from it),
+ *       keeping its parent and parent position are untouched *
+ *
+ * finishFunc/finishObj called at the end
+ *
+ * TODO: it should work only sync-way to solve CPU-hungry tasks 
+ */
+ dojo.declare(
+ 	"dojo.widget.TreeTimeoutIterator",
+ 	null,
+ 	
+function(elem, callFunc, callObj) {
+	var _this = this;
+	
+	this.currentParent = elem;
+	
+	this.callFunc = callFunc;
+	this.callObj = callObj ? callObj: this;
+	this.stack = [];	
+},
+
+{
+	// public
+	maxStackDepth: Number.POSITIVE_INFINITY,
+	
+	stack: null,
+	currentParent: null,
+		
+	currentIndex: 0,
+	
+	filterFunc: function() { return true },
+	
+	finishFunc: function() { return true },
+	
+	
+	setFilter: function(func, obj) {
+		this.filterFunc = func;
+		this.filterObj = obj;
+	},
+	
+	
+	setMaxLevel: function(level) {
+		this.maxStackDepth = level-2;
+	},
+	
+	forward: function(timeout) {
+		var _this = this;
+		
+		if (this.timeout) { // if timeout required between forwards
+			// tid will be assigned at the end of outer func execution
+			var tid = setTimeout(function() {_this.processNext(); clearTimeout(tid); }, _this.timeout);
+		} else {
+			return this.processNext();
+		}
+	},
+	
+	start: function(processFirst) {
+		if (processFirst) {			
+			return this.callFunc.call(this.callObj, this.currentParent, this);			
+		}
+				
+		return this.processNext();
+	},
+	
+	/**
+	 * @private
+	 * find next node, move current parent to it if possible & process
+	 */
+	processNext: function() {
+				
+		//dojo.debug("processNext with currentParent "+this.currentParent+" index "+this.currentIndex);
+		var handler;
+		
+		var _this = this;
+		
+		var found;
+		
+		var next;
+			
+		if (this.maxStackDepth == -2) {   
+			return; // process only first cause level=0, do not process children
+		}
+		
+		while (true) {
+			var children = this.currentParent.children;
+		
+			if (children && children.length) {
+		
+				// look for a node that can be the next target
+				do {					
+					next = children[this.currentIndex];
+					//dojo.debug("check "+next);
+				} while (this.currentIndex++ < children.length && !(found = this.filterFunc.call(this.filterObj,next)));
+			
+			
+				if (found) {
+					//dojo.debug("found "+next);
+					// move to next node as new parent if depth is fine
+					// I can't check current children to decide whether to move it or not,
+					// because expand may populate children					
+					if (next.isFolder && this.stack.length <= this.maxStackDepth) {
+						this.moveParent(next,0);
+					}
+					//dojo.debug("Run callFunc on "+next);
+					return this.callFunc.call(this.callObj, next, this);					
+				}
+			}
+				
+			if (this.stack.length) {
+				this.popParent();
+				continue;
+			}
+			
+			break;
+		}
+
+		/**
+		 * couldn't find next node to process, finish here
+		 */
+		return this.finishFunc.call(this.finishObj);
+
+	},
+	
+	setFinish: function(func, obj) {
+		this.finishFunc = func;
+		this.finishObj = obj;
+	},
+		
+	popParent: function() {
+		var p = this.stack.pop();
+		//dojo.debug("Pop "+p[0]+":"+p[1]);		
+		this.currentParent = p[0];
+		this.currentIndex = p[1];
+	},
+	
+	moveParent: function(nextParent, nextIndex) {
+		//dojo.debug("Move from "+this.currentParent+":"+this.currentIndex+" to "+nextParent+":"+nextIndex);
+		this.stack.push([this.currentParent, this.currentIndex]);
+		this.currentParent = nextParent;
+		this.currentIndex = nextIndex;
+	}
+
+});
\ No newline at end of file

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeTimeoutIterator.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeV3.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeV3.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeV3.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeV3.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,337 @@
+/**
+ * Tree model does all the drawing, visual node management etc.
+ * Throws events about clicks on it, so someone may catch them and process
+ * Tree knows nothing about DnD stuff, covered in TreeDragAndDrop and (if enabled) attached by controller
+*/
+
+/**
+ * TODO: use domNode.cloneNode instead of createElement for grid
+ * Should be faster (lyxsus)
+ */
+dojo.provide("dojo.widget.TreeV3");
+
+dojo.require("dojo.widget.TreeWithNode");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.event.*");
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.TreeNodeV3");
+
+dojo.widget.defineWidget(
+	"dojo.widget.TreeV3",
+	[dojo.widget.HtmlWidget, dojo.widget.TreeWithNode],
+	function() {
+		this.eventNames = {};
+		
+		this.DndAcceptTypes = [];
+		this.actionsDisabled = [];
+		
+		this.listeners = [];
+		
+		this.tree = this;
+	},
+{
+	DndMode: "",
+
+	/**
+	 * factory to generate default widgets
+	 */
+	defaultChildWidget: null,
+	
+	defaultChildTitle: "New Node", // for editing
+	
+	
+	eagerWidgetInstantiation: false,
+	
+	eventNamesDefault: {
+
+		// tree created.. Perform tree-wide actions if needed
+		afterTreeCreate: "afterTreeCreate",
+		beforeTreeDestroy: "beforeTreeDestroy",
+		/* can't name it "beforeDestroy", because such name causes memleaks in IE */
+		beforeNodeDestroy: "beforeNodeDestroy",
+		afterChangeTree: "afterChangeTree",
+
+		afterSetFolder: "afterSetFolder",
+		afterUnsetFolder: "afterUnsetFolder",		
+		beforeMoveFrom: "beforeMoveFrom",
+		beforeMoveTo: "beforeMoveTo",
+		afterMoveFrom: "afterMoveFrom",
+		afterMoveTo: "afterMoveTo",
+		afterAddChild: "afterAddChild",
+		afterDetach: "afterDetach",
+		afterExpand: "afterExpand",
+		beforeExpand: "beforeExpand",
+		afterSetTitle: "afterSetTitle",		
+		afterCollapse: "afterCollapse",	
+		beforeCollapse: "beforeCollapse"
+	},
+
+	classPrefix: "Tree",
+	
+	style: "",
+	
+	/**
+	 * is it possible to add a new child to leaf ?
+	 */	
+	allowAddChildToLeaf: true,
+	
+	/**
+	 * when last children is removed from node should it stop being a "folder" ?
+	 */
+	unsetFolderOnEmpty: true,
+
+
+	DndModes: {
+		BETWEEN: 1,
+		ONTO: 2
+	},
+
+	DndAcceptTypes: "",
+
+    // will have cssRoot before it 
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/TreeV3.css"),
+
+	templateString: '<div style="${this.style}">\n</div>',
+
+	isExpanded: true, // consider this "root node" to be always expanded
+
+	isTree: true,
+	
+	
+
+	createNode: function(data) {
+			
+		data.tree = this.widgetId;		
+		
+		if (data.widgetName) {
+			// TODO: check if such widget has createSimple			
+			return dojo.widget.createWidget(data.widgetName, data);		
+		} else if (this.defaultChildWidget.prototype.createSimple) {			
+			return this.defaultChildWidget.prototype.createSimple(data);					
+		} else {
+			var ns = this.defaultChildWidget.prototype.ns; 
+			var wt = this.defaultChildWidget.prototype.widgetType; 
+
+			return dojo.widget.createWidget(ns + ":" + wt, data); 
+		}
+ 	    	
+	},
+				
+
+	// expandNode has +- CSS background. Not img.src for performance, background src string resides in single place.
+	// selection in KHTML/Mozilla disabled treewide, IE requires unselectable for every node
+	// you can add unselectable if you want both in postCreate of tree and in this template
+
+	// create new template and put into prototype
+	makeNodeTemplate: function() {
+		
+		var domNode = document.createElement("div");
+		dojo.html.setClass(domNode, this.classPrefix+"Node "+this.classPrefix+"ExpandLeaf "+this.classPrefix+"ChildrenNo");		
+		this.nodeTemplate = domNode;
+		
+		var expandNode = document.createElement("div");
+		var clazz = this.classPrefix+"Expand";
+		if (dojo.render.html.ie) {
+			clazz = clazz + ' ' + this.classPrefix+"IEExpand";
+		}
+		dojo.html.setClass(expandNode, clazz);
+		
+		this.expandNodeTemplate = expandNode;
+
+		// need <span> inside <div>
+		// div for multiline support, span for styling exactly the text, not whole line
+		var labelNode = document.createElement("span");
+		dojo.html.setClass(labelNode, this.classPrefix+"Label");
+		this.labelNodeTemplate = labelNode;
+		
+		var contentNode = document.createElement("div");
+		var clazz = this.classPrefix+"Content";
+		
+		/**
+		 * IE does not support min-height properly so I have to rely
+		 * on this hack
+		 * FIXME: do it in CSS only, remove iconHeight from code
+		 */
+		if (dojo.render.html.ie) {
+			clazz = clazz + ' ' + this.classPrefix+"IEContent";
+		}	
+		
+				
+		dojo.html.setClass(contentNode, clazz);
+		
+		this.contentNodeTemplate = contentNode;
+		
+		domNode.appendChild(expandNode);
+		domNode.appendChild(contentNode);
+		contentNode.appendChild(labelNode);
+		
+		
+	},
+
+	makeContainerNodeTemplate: function() {
+		
+		var div = document.createElement('div');
+		div.style.display = 'none';			
+		dojo.html.setClass(div, this.classPrefix+"Container");
+		
+		this.containerNodeTemplate = div;
+		
+	},
+
+	
+	actions: {
+    	ADDCHILD: "ADDCHILD"
+	},
+
+
+	getInfo: function() {
+		var info = {
+			widgetId: this.widgetId,
+			objectId: this.objectId
+		}
+
+		return info;
+	},
+
+	adjustEventNames: function() {
+		
+		for(var name in this.eventNamesDefault) {
+			if (dojo.lang.isUndefined(this.eventNames[name])) {
+				this.eventNames[name] = this.widgetId+"/"+this.eventNamesDefault[name];
+			}
+		}
+	},
+
+	
+	adjustDndMode: function() {
+		var _this = this;
+		
+		
+		var DndMode = 0;
+		dojo.lang.forEach(this.DndMode.split(';'),
+			function(elem) {
+				var mode = _this.DndModes[dojo.string.trim(elem).toUpperCase()];
+				if (mode) DndMode = DndMode | mode;
+			}
+		 );
+	
+		
+		this.DndMode = DndMode;
+
+	},
+	
+	/**
+	 * publish destruction event so that any listeners should stop listening
+	 */
+	destroy: function() {
+		dojo.event.topic.publish(this.tree.eventNames.beforeTreeDestroy, { source: this } );
+
+		return dojo.widget.HtmlWidget.prototype.destroy.apply(this, arguments);
+	},
+
+	initialize: function(args){
+		
+		this.domNode.widgetId = this.widgetId;
+		
+		for(var i=0; i<this.actionsDisabled.length;i++) {
+			this.actionsDisabled[i] = this.actionsDisabled[i].toUpperCase();
+		}
+		
+		//dojo.debug(args.defaultChildWidget ? true : false)
+		
+		if (!args.defaultChildWidget) {
+			this.defaultChildWidget = dojo.widget.TreeNodeV3;
+		} else {
+			this.defaultChildWidget = dojo.lang.getObjPathValue(args.defaultChildWidget);
+		}
+		
+		this.adjustEventNames();
+		this.adjustDndMode();
+
+		this.makeNodeTemplate();
+		this.makeContainerNodeTemplate();
+		
+		this.containerNode = this.domNode;
+		
+		dojo.html.setClass(this.domNode, this.classPrefix+"Container");
+		
+		var _this = this;
+			
+		//dojo.html.disableSelection(this.domNode)
+				
+		dojo.lang.forEach(this.listeners,
+			function(elem) {
+				var t = dojo.lang.isString(elem) ? dojo.widget.byId(elem) : elem;
+				t.listenTree(_this)				
+			}
+		);
+		
+
+		
+		
+
+	},
+
+	
+	postCreate: function() {						
+		dojo.event.topic.publish(this.eventNames.afterTreeCreate, { source: this } );
+	},
+	
+	
+	/**
+	 * Move child to newParent as last child
+	 * redraw tree and update icons.
+	 *
+	 * Called by target, saves source in event.
+	 * events are published for BOTH trees AFTER update.
+	*/
+	move: function(child, newParent, index) {
+		
+		if (!child.parent) {
+			dojo.raise(this.widgetType+": child can be moved only while it's attached");
+		}
+		
+		var oldParent = child.parent;
+		var oldTree = child.tree;
+		var oldIndex = child.getParentIndex();
+		var newTree = newParent.tree;
+		var newParent = newParent;
+		var newIndex = index;
+
+		var message = {
+				oldParent: oldParent, oldTree: oldTree, oldIndex: oldIndex,
+				newParent: newParent, newTree: newTree, newIndex: newIndex,
+				child: child
+		};
+
+		dojo.event.topic.publish(oldTree.eventNames.beforeMoveFrom, message);
+		dojo.event.topic.publish(newTree.eventNames.beforeMoveTo, message);
+		
+		this.doMove.apply(this, arguments);
+
+		
+		/* publish events here about structural changes for both source and target trees */
+		dojo.event.topic.publish(oldTree.eventNames.afterMoveFrom, message);
+		dojo.event.topic.publish(newTree.eventNames.afterMoveTo, message);
+
+	},
+
+
+	/* do actual parent change here. Write remove child first */
+	doMove: function(child, newParent, index) {
+		//dojo.debug("MOVE "+child+" to "+newParent+" at "+index);
+
+		//var parent = child.parent;
+		child.doDetach();
+
+		//dojo.debug("addChild "+child+" to "+newParent+" at "+index);
+
+		newParent.doAddChild(child, index);
+	},
+
+	toString: function() {
+		return "["+this.widgetType+" ID:"+this.widgetId	+"]"
+	}
+
+});

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TreeV3.js
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message