You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jetspeed-dev@portals.apache.org by ta...@apache.org on 2005/12/06 20:30:51 UTC

svn commit: r354516 [11/15] - in /portals/jetspeed-2/trunk: applications/j2-admin/src/java/org/apache/jetspeed/portlets/customizer/ applications/j2-admin/src/webapp/WEB-INF/ applications/j2-admin/src/webapp/WEB-INF/view/customizer/ applications/j2-admi...

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/RichText.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/RichText.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/RichText.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/RichText.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,966 @@
+dojo.provide("dojo.widget.RichText");
+dojo.provide("dojo.widget.HtmlRichText");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.dom");
+dojo.require("dojo.html");
+dojo.require("dojo.event.*");
+dojo.require("dojo.style");
+
+// used to save content
+try {
+	document.write('<textarea id="dojo.widget.RichText.savedContent" ' +
+		'style="display:none;position:absolute;top:-100px;left:-100px;"></textarea>');
+} catch (e) { }
+
+dojo.widget.tags.addParseTreeHandler("dojo:richtext");
+
+dojo.widget.HtmlRichText = function () {
+	dojo.widget.HtmlWidget.call(this);
+	this.contentFilters = [];
+}
+dojo.inherits(dojo.widget.HtmlRichText, dojo.widget.HtmlWidget);
+
+dojo.lang.extend(dojo.widget.HtmlRichText, {
+
+	widgetType: "richtext",
+
+	/** whether to inherit the parent's width or simply use 100% */
+	inheritWidth: false,
+	
+	/**
+	 * If a save name is specified the content is saved and restored if the
+	 * editor is not properly closed after editing has started.
+	 */
+	saveName: "",
+	_content: "",
+	
+	/** The minimum height that the editor should have */
+	minHeight: "1em",
+	
+	isClosed: true,
+	
+	/** whether to use the active-x object in IE */
+	useActiveX: false,
+	
+	_SEPARATOR: "@@**%%__RICHTEXTBOUNDRY__%%**@@",
+
+	// contentFilters: [],
+
+/* Init
+ *******/
+
+	fillInTemplate: function (){
+		this.open();
+
+		// add the formatting functions
+		var funcs = ["queryCommandEnabled", "queryCommandState",
+			"queryCommandValue", "execCommand"];
+		for (var i = 0; i < funcs.length; i++) {
+			dojo.event.connect("around", this, funcs[i], this, "_normalizeCommand");
+		}
+		
+		// backwards compatibility, needs to be removed
+		dojo.event.connect(this, "onKeyPressed", this, "afterKeyPress");
+		dojo.event.connect(this, "onKeyPress", this, "keyPress");
+		dojo.event.connect(this, "onKeyDown", this, "keyDown");
+		dojo.event.connect(this, "onKeyUp", this, "keyUp");
+	},
+
+	/**
+	 * Transforms the node referenced in this.domNode into a rich text editing
+	 * node. This can result in the creation and replacement with an <iframe> if
+	 * designMode is used, an <object> and active-x component if inside of IE or
+	 * a reguler element if contentEditable is available.
+	 */
+	open: function (element) {
+		dojo.event.topic.publish("dojo.widget.RichText::open", this);
+
+		if (!this.isClosed) { this.close(); }
+		this._content = "";
+		if (arguments.length == 1) { this.domNode = element; } // else unchanged
+		
+		if (this.domNode.nodeName == "TEXTAREA") {
+			this.textarea = this.domNode;
+			var html = this.textarea.value;
+			this.domNode = document.createElement("div");
+			this.textarea.style.display = "none";
+			dojo.dom.insertBefore(this.domNode, this.textarea);
+			
+			if (this.textarea.form) {
+				this.connect(this.textarea.form, "onsubmit", "save");
+			}
+			
+			// dojo plucks our original domNode from the document so we need
+			// to go back and put ourselves back in
+			var editor = this;
+			dojo.event.connect(this, "postCreate", function () {
+				dojo.dom.insertAfter(editor.textarea, editor.domNode);
+			});
+		} else {
+			var html = this.domNode.innerHTML;
+		}
+				
+		this._oldHeight = dojo.style.getContentHeight(this.domNode);
+		this._oldWidth = dojo.style.getContentWidth(this.domNode);
+		
+		this.savedContent = document.createElement("div");
+		while (this.domNode.hasChildNodes()) {
+			this.savedContent.appendChild(this.domNode.firstChild);
+		}
+		
+		// If we're a list item we have to put in a blank line to force the
+		// bullet to nicely align at the top of text
+		if (this.domNode.nodeName == "LI") { this.domNode.innerHTML = " <br>"; }
+				
+		if (this.saveName != "") {
+			var saveTextarea = document.getElementById("dojo.widget.RichText.savedContent");
+			if (saveTextarea.value != "") {
+				var datas = saveTextarea.value.split(this._SEPARATOR);
+				for (var i = 0; i < datas.length; i++) {
+					var data = datas[i].split(":");
+					if (data[0] == this.saveName) {
+						html = data[1];
+						datas.splice(i, 1);
+						break;
+					}
+				}				
+			}
+			this.connect(window, "onunload", "_saveContent");
+		}
+
+		// Safari's selections go all out of whack if we do it inline,
+		// so for now IE is our only hero
+		//if (typeof document.body.contentEditable != "undefined") {
+		if (this.useActiveX && dojo.render.html.ie) { // active-x
+			this._drawObject(html);
+		} else if (dojo.render.html.ie) { // contentEditable, easy
+			this.editNode = document.createElement("div");
+			with (this.editNode) {
+				contentEditable = true;
+				innerHTML = html;
+				style.height = this.minHeight;
+			}
+			this.domNode.appendChild(this.editNode);
+			
+			var events = ["onBlur", "onFocus", "onKeyPress",
+				"onKeyDown", "onKeyUp", "onClick"];
+			for (var i = 0; i < events.length; i++) {
+				this.connect(this.editNode, events[i].toLowerCase(), events[i]);
+			}
+		
+			this.window = window;
+			this.document = document;
+			
+			this.onLoad();
+		} else { // designMode in iframe
+			this._drawIframe(html);
+		}
+
+		// TODO: this is a guess at the default line-height, kinda works
+		if (this.domNode.nodeName == "LI") { this.domNode.lastChild.style.marginTop = "-1.2em"; }
+		dojo.html.addClass(this.domNode, "RichTextEditable");
+		
+		this.isClosed = false;
+	},
+	
+	/** Draws an iFrame using the existing one if one exists. Used by Mozilla and Safari */
+	_drawIframe: function (html) {
+		if (!this.iframe) {
+			this.iframe = document.createElement("iframe");
+			with (this.iframe) {
+				scrolling = "no";
+				style.border = "none";
+				style.lineHeight = "0"; // squash line height
+				style.verticalAlign = "bottom";
+			}
+		}
+
+		with (this.iframe) {
+			width = this.inheritWidth ? this._oldWidth : "100%";
+			height = this._oldHeight;
+		}
+		this.domNode.appendChild(this.iframe);
+
+		if (!this.editNode) {
+			this.window = this.iframe.contentWindow;
+			this.document = this.iframe.contentDocument;
+		
+			// curry the getStyle function
+			var getStyle = (function (domNode) { return function (style) {
+				return dojo.style.getStyle(domNode, style);
+			}; })(this.domNode);
+			var font = getStyle('font-size') + " " + getStyle('font-family');
+	
+			var contentEditable = Boolean(document.body.contentEditable);
+			with (this.document) {
+				if (!contentEditable) { designMode = "on"; }
+				open();
+				write(
+					//'<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">' +
+					'<title></title>\n' +
+					'<style type="text/css">\n' +
+					'    body,html { padding: 0; margin: 0; font: ' + font + '; }\n' +
+					// TODO: left positioning will case contents to disappear out of view
+					//       if it gets too wide for the visible area
+					'    body { position: fixed; top: 0; left: 0; right: 0;' +
+					'        min-height: ' + this.minHeight + '; }\n' +
+					'    p { margin: 1em 0 !important; }\n' +
+					'    body > *:first-child { padding-top: 0 !important; margin-top: 0 !important; }\n' +
+					'    body > *:last-child { padding-bottom: 0 !important; margin-bottom: 0 !important; }\n' +
+					'    li > ul:-moz-first-node, li > ol:-moz-first-node { padding-top: 1.2em; }\n' +
+					'    li { min-height: 1.2em; }\n' +
+					//'    p,ul,li { padding-top: 0; padding-bottom: 0; margin-top:0; margin-bottom: 0; }\n' +
+					'</style>\n' +
+					//'<base href="' + window.location + '">' +
+					'<body' + (contentEditable ? ' contentEditable="true"' : '') + '>' +
+					html + '</body>');
+				close();
+			}
+			
+			this.onLoad();
+			
+		} else {
+			this.editNode.innerHTML = html;
+			this.onDisplayChanged(e);
+		}
+	},
+
+	/** Draws an active x object, used by IE */
+	_drawObject: function (html) {
+		this.object = document.createElement("object");
+
+		with (this.object) {
+			classid = "clsid:2D360201-FFF5-11D1-8D03-00A0C959BC0A";
+			width = this.inheritWidth ? this._oldWidth : "100%";
+			height = this._oldHeight;
+			Scrollbars = false;
+			Appearance = this._activeX.appearance.flat;
+		}
+		this.domNode.appendChild(this.object);
+
+		function hitch (obj, meth) {
+			return function () { return obj[meth].apply(obj, arguments); }
+		}
+		
+		this.object.attachEvent("DocumentComplete", hitch(this, "onLoad"));
+		this.object.attachEvent("DisplayChanged", hitch(this, "_updateHeight"));
+		this.object.attachEvent("DisplayChanged", hitch(this, "onDisplayChanged"));
+
+		this.object.DocumentHTML = '<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">' +
+			'<title></title>' +
+			'<style type="text/css">' +
+			'    body,html { padding: 0; margin: 0; }' + //font: ' + font + '; }' +
+			'    body { overflow: hidden; }' +
+			//'    #bodywrapper {  }' +
+			'</style>' +
+			//'<base href="' + window.location + '">' +
+			'<body><div id="bodywrapper">' + html + '</div></body>';
+	},
+
+/* Event handlers
+ *****************/
+
+	onLoad: function (e) {
+		if (this.object) {
+			this.document = this.object.DOM;
+			this.editNode = this.document.body.firstChild;
+		} else if (this.iframe) {
+			this.editNode = this.document.body;
+	
+			try { // sanity check for Mozilla
+				this.document.execCommand("useCSS", false, true); // old moz call
+				this.document.execCommand("styleWithCSS", false, false); // new moz call
+				//this.document.execCommand("insertBrOnReturn", false, false); // new moz call
+			} catch (e) { }
+			
+			function hitch (obj, meth) {
+				return function () { return obj[meth].apply(obj, arguments); }
+			}
+			
+			if (dojo.render.html.safari) {
+				this.connect(this.editNode, "onblur", "onBlur");
+				this.connect(this.editNode, "onfocus", "onFocus");
+			
+				this.interval = setInterval(hitch(this, "onDisplayChanged"), 500);
+			} else if (dojo.render.html.mozilla) {
+
+				// We need to unhook the blur event listener on close as we
+				// can encounter a garunteed crash in FF if another event is
+				// also fired
+				var doc = this.document;
+				var blurfp = dojo.event.browser.addListener(this.document, "blur", hitch(this, "onBlur"));
+				var unBlur = { unBlur: function(e){
+						dojo.event.browser.removeListener(doc, "blur", blurfp);
+				} };
+				dojo.event.connect("before", this, "close", unBlur, "unBlur");
+				dojo.event.browser.addListener(this.document, "focus", hitch(this, "onFocus"));
+			
+				// safari can't handle key listeners, it kills the speed
+				var addListener = dojo.event.browser.addListener;
+				addListener(this.document, "keypress", hitch(this, "onKeyPress"));
+				addListener(this.document, "keydown", hitch(this, "onKeyDown"));
+				addListener(this.document, "keyup", hitch(this, "onKeyUp"));
+				addListener(this.document, "click", hitch(this, "onClick"));
+			}
+
+			// FIXME: when scrollbars appear/disappear this needs to be fired						
+			this.connect(this, "onDisplayChanged", "_updateHeight");
+		}
+		
+		this.focus();
+		this.onDisplayChanged(e);
+	},
+
+	/** Fired on keydown */
+	onKeyDown: function (e) {
+		// we need this event at the moment to get the events from control keys
+		// such as the backspace. It might be possible to add this to Dojo, so that
+		// keyPress events can be emulated by the keyDown and keyUp detection.
+	},
+	
+	/** Fired on keyup */
+	onKeyUp: function (e) {
+	},
+	
+	/** Fired on keypress. */
+	onKeyPress: function (e) {
+		// handle the various key events
+
+		var character = e.charCode > 0 ? String.fromCharCode(e.charCode) : null;
+		var code = e.keyCode;
+				
+		var preventDefault = true; // by default assume we cancel;
+
+		// define some key combos
+		if (e.ctrlKey || e.metaKey) { // modifier pressed
+			switch (character) {
+				case "b": this.execCommand("bold"); break;
+				case "i": this.execCommand("italic"); break;
+				case "u": this.execCommand("underline"); break;
+				//case "a": this.execCommand("selectall"); break;
+				//case "k": this.execCommand("createlink", ""); break;
+				case "Z": this.execCommand("redo"); break;
+				case "s": this.close(true); break; // saves
+				default: switch (code) {
+					case e.KEY_LEFT_ARROW:
+					case e.KEY_RIGHT_ARROW:
+						//break; // preventDefault stops the browser
+						       // going through its history
+					default:
+						preventDefault = false; break; // didn't handle here
+				}
+			}
+		} else {
+			switch (code) {
+				case e.KEY_TAB:
+				  // commenting out bcs it's crashing FF
+					// this.execCommand(e.shiftKey ? "unindent" : "indent");
+					// break;
+				default:
+					preventDefault = false; break; // didn't handle here
+			}
+		}
+		
+		if (preventDefault) { e.preventDefault(); }
+
+		// function call after the character has been inserted
+		dojo.lang.setTimeout(this, this.onKeyPressed, 1, e);
+	},
+	
+	/**
+	 * Fired after a keypress event has occured and it's action taken. This
+	 * is useful if action needs to be taken after text operations have
+	 * finished
+	 */
+	onKeyPressed: function (e) {
+		// Mozilla adds a single <p> with an embedded <br> when you hit enter once:
+		//   <p><br>\n</p>
+		// when you hit enter again it adds another <br> inside your enter
+		//   <p><br>\n<br>\n</p>
+		// and if you hit enter again it splits the <br>s over 2 <p>s
+		//   <p><br>\n</p>\n<p><br>\n</p>
+		// now this assumes that <p>s have double the line-height of <br>s to work
+		// and so we need to remove the <p>s to ensure the position of the cursor
+		// changes from the users perspective when they hit enter, as the second two
+		// html snippets render the same when margins are set to 0.
+		
+		// TODO: doesn't really work; is this really needed?
+		//if (dojo.render.html.moz) {
+		//	for (var i = 0; i < this.document.getElementsByTagName("p").length; i++) {
+		//		var p = this.document.getElementsByTagName("p")[i];
+		//		if (p.innerHTML.match(/^<br>\s$/m)) {
+		//			while (p.hasChildNodes()) { p.parentNode.insertBefore(p.firstChild, p); }
+		//			p.parentNode.removeChild(p);
+		//		}
+		//	}
+		//}
+		this.onDisplayChanged(/*e*/); // can't pass in e
+	},
+	
+	onClick: function (e) { this.onDisplayChanged(e); },
+	
+	onBlur: function (e){ },
+	onFocus: function (e){ },
+
+	blur: function () {
+		if (this.iframe) { this.window.blur(); }
+		else if (this.editNode) { this.editNode.blur(); }
+	},
+	
+	focus: function () {
+		if(this.iframe){
+			this.window.focus();
+		}else if(this.editNode){
+			this.editNode.focus();
+		}
+	},
+	
+	/** this event will be fired everytime the display context changes and the
+	 result needs to be reflected in the UI */
+	onDisplayChanged: function (e) {},
+	
+
+/* Formatting commands
+ **********************/
+	
+	/** IE's Active X codes */
+	_activeX: {
+		command: {
+			bold: 5000,
+			italic: 5023,
+			underline: 5048,
+
+			justifycenter: 5024,
+			justifyleft: 5025,
+			justifyright: 5026,
+
+			cut: 5003,
+			copy: 5002,
+			paste: 5032,
+			"delete": 5004,
+
+			undo: 5049,
+			redo: 5033,
+
+			removeformat: 5034,
+			selectall: 5035,
+			unlink: 5050,
+
+			indent: 5018,
+			outdent: 5031,
+
+			insertorderedlist: 5030,
+			insertunorderedlist: 5051,
+
+			// table commands
+			inserttable: 5022,
+			insertcell: 5019,
+			insertcol: 5020,
+			insertrow: 5021,
+			deletecells: 5005,
+			deletecols: 5006,
+			deleterows: 5007,
+			mergecells: 5029,
+			splitcell: 5047,
+			
+			// the command need mapping, they don't translate directly
+			// to the contentEditable commands
+			setblockformat: 5043,
+			getblockformat: 5011,
+			getblockformatnames: 5012,
+			setfontname: 5044,
+			getfontname: 5013,
+			setfontsize: 5045,
+			getfontsize: 5014,
+			setbackcolor: 5042,
+			getbackcolor: 5010,
+			setforecolor: 5046,
+			getforecolor: 5015,
+			
+			findtext: 5008,
+			font: 5009,
+			hyperlink: 5016,
+			image: 5017,
+			
+			lockelement: 5027,
+			makeabsolute: 5028,
+			sendbackward: 5036,
+			bringforward: 5037,
+			sendbelowtext: 5038,
+			bringabovetext: 5039,
+			sendtoback: 5040,
+			bringtofront: 5041,
+			
+			properties: 5052
+		},
+		
+		ui: {
+			"default": 0,
+			prompt: 1,
+			noprompt: 2
+		},
+		
+		status: {
+			notsupported: 0,
+			disabled: 1,
+			enabled: 3,
+			latched: 7,
+			ninched: 11
+		},
+		
+		appearance: {
+			flat: 0,
+			inset: 1
+		},
+		
+		state: {
+			unchecked: 0,
+			checked: 1,
+			gray: 2
+		}
+	},
+	
+	/**
+	 * Used as the advice function by dojo.event.connect to map our
+	 * normalized set of commands to those supported by the target
+	 * browser
+	 *
+	 * @param arugments The arguments Array, containing at least one
+	 *                  item, the command and an optional second item,
+	 *                  an argument.
+	 */
+	_normalizeCommand: function (joinObject){
+		var drh = dojo.render.html;
+		
+		var command = joinObject.args[0].toLowerCase();
+		if(command == "formatblock"){
+			if(drh.safari){ command = "heading"; }
+			if(drh.ie){ joinObject.args[1] = "<"+joinObject.args[1]+">"; }
+		}
+		if (command == "hilitecolor" && !drh.mozilla) { command = "backcolor"; }
+		joinObject.args[0] = command;
+		
+		if (joinObject.args.length > 1) { // a command was specified
+			var argument = joinObject.args[1];
+			if (command == "heading") { throw new Error("unimplemented"); }
+			joinObject.args[1] = argument;
+		}
+		
+		return joinObject.proceed();
+	},
+	
+	/**
+	 * Tests whether a command is supported by the host. Clients SHOULD check
+	 * whether a command is supported before attempting to use it, behaviour
+	 * for unsupported commands is undefined.
+	 *
+	 * @param command The command to test for
+	 * @return true if the command is supported, false otherwise
+	 */
+	queryCommandAvailable: function (command) {
+		var ie = 1;
+		var mozilla = 1 << 1;
+		var safari = 1 << 2;
+		var opera = 1 << 3;
+		function isSupportedBy (browsers) {
+			return {
+				ie: Boolean(browsers & ie),
+				mozilla: Boolean(browsers & mozilla),
+				safari: Boolean(browsers & safari),
+				opera: Boolean(browsers & opera)
+			}
+		}
+
+		var supportedBy = null;
+		
+		switch (command.toLowerCase()) {
+			case "bold": case "italic": case "underline":
+			case "subscript": case "superscript":
+			case "fontname": case "fontsize":
+			case "forecolor": case "hilitecolor":
+			case "justifycenter": case "justifyfull": case "justifyleft": case "justifyright":
+			case "cut": case "copy": case "paste": case "delete":
+			case "undo": case "redo":
+				supportedBy = isSupportedBy(mozilla | ie | safari | opera);
+				break;
+				
+			case "createlink": case "unlink": case "removeformat":
+			case "inserthorizontalrule": case "insertimage":
+			case "insertorderedlist": case "insertunorderedlist":
+			case "indent": case "outdent": case "formatblock": case "strikethrough": 
+				supportedBy = isSupportedBy(mozilla | ie | opera);
+				break;
+				
+			case "blockdirltr": case "blockdirrtl":
+			case "dirltr": case "dirrtl":
+			case "inlinedirltr": case "inlinedirrtl":
+				supportedBy = isSupportedBy(ie);
+				break;
+			
+			case "inserttable":
+				supportedBy = isSupportedBy(mozilla | (this.object ? ie : 0));
+				break;
+			
+			case "insertcell": case "insertcol": case "insertrow":
+			case "deletecells": case "deletecols": case "deleterows":
+			case "mergecells": case "splitcell":
+				supportedBy = isSupportedBy(this.object ? ie : 0);
+				break;
+			
+			default: return false;
+		}
+		
+		return (dojo.render.html.ie && supportedBy.ie) ||
+			(dojo.render.html.mozilla && supportedBy.mozilla) ||
+			(dojo.render.html.safari && supportedBy.safari) ||
+			(dojo.render.html.opera && supportedBy.opera);
+	},
+	
+	/**
+	 * Executes a command in the Rich Text area
+	 *
+	 * @param command The command to execute
+	 * @param argument An optional argument to the command
+	 */
+	execCommand: function (command, argument) {
+		if (this.object) {
+			if (command == "forecolor") { command = "setforecolor"; }
+			else if (command == "backcolor") { command = "setbackcolor"; }
+		
+			//if (typeof this._activeX.command[command] == "undefined") { return null; }
+		
+			if (command == "inserttable") {
+				var tableInfo = this.constructor._tableInfo;
+				if (!tableInfo) {
+					tableInfo = document.createElement("object");
+					tableInfo.classid = "clsid:47B0DFC7-B7A3-11D1-ADC5-006008A5848C";
+					document.body.appendChild(tableInfo);
+					this.constructor._table = tableInfo;
+				}
+				
+				tableInfo.NumRows = argument.rows;
+				tableInfo.NumCols = argument.cols;
+				tableInfo.TableAttrs = argument["TableAttrs"];
+				tableInfo.CellAttrs = arr["CellAttrs"];
+				tableInfo.Caption = arr["Caption"];
+			}
+		
+			if (arguments.length == 1) {
+				return this.object.ExecCommand(this._activeX.command[command],
+					this._activeX.ui.noprompt);
+			} else {
+				return this.object.ExecCommand(this._activeX.command[command],
+					this._activeX.ui.noprompt, argument);
+			}
+	
+		// fix up unlink in Mozilla to unlink the link and not just the selection
+		} else if (command == "unlink" &&
+			this.queryCommandEnabled("unlink") && dojo.render.html.mozilla) {
+			// grab selection
+			// Mozilla gets upset if we just store the range so we have to
+			// get the basic properties and recreate to save the selection
+			var selection = this.window.getSelection();
+			var selectionRange = selection.getRangeAt(0);
+			var selectionStartContainer = selectionRange.startContainer;
+			var selectionStartOffset = selectionRange.startOffset;
+			var selectionEndContainer = selectionRange.endContainer;
+			var selectionEndOffset = selectionRange.endOffset;
+			
+			// select our link and unlink
+			var range = document.createRange();
+			var a = this.getSelectedNode();
+			while (a.nodeName != "A") { a = a.parentNode; }
+			range.selectNode(a);
+			selection.removeAllRanges();
+			selection.addRange(range);
+			
+			var returnValue = this.document.execCommand("unlink", false, null);
+			
+			// restore original selection
+			var selectionRange = document.createRange();
+			selectionRange.setStart(selectionStartContainer, selectionStartOffset);
+			selectionRange.setEnd(selectionEndContainer, selectionEndOffset);
+			selection.removeAllRanges();
+			selection.addRange(selectionRange);
+			
+			return returnValue;
+		} else if (command == "inserttable" && dojo.render.html.mozilla) {
+
+			var cols = "<tr>";
+			for (var i = 0; i < argument.cols; i++) { cols += "<td></td>"; }
+			cols += "</tr>";
+		
+			var table = "<table><tbody>";
+			for (var i = 0; i < argument.rows; i++) { table += cols; }
+			table += "</tbody></table>";
+			var returnValue = this.document.execCommand("inserthtml", false, table);
+
+		} else if (command == "hilitecolor" && dojo.render.html.mozilla) {
+			// mozilla doesn't support hilitecolor properly when useCSS is
+			// set to false (bugzilla #279330)
+			
+			this.document.execCommand("useCSS", false, false);
+			var returnValue = this.document.execCommand(command, false, argument);			
+			this.document.execCommand("useCSS", false, true);
+		
+		} else {
+			argument = arguments.length > 1 ? argument : null;
+			var returnValue = this.document.execCommand(command, false, argument);
+		}
+		
+		this.onDisplayChanged();
+		return returnValue;
+	},
+
+	queryCommandEnabled: function (command, argument) {
+		if (this.object) {
+			if (command == "forecolor") { command = "setforecolor"; }
+			else if (command == "backcolor") { command = "setbackcolor"; }
+
+			if (typeof this._activeX.command[command] == "undefined") { return false; }
+			var status = this.object.QueryStatus(this._activeX.command[command]);
+			return (status != this.activeX.status.notsupported && 
+				status != this.activeX.status.diabled);
+		} else {
+			// mozilla returns true always
+			if (command == "unlink" && dojo.render.html.mozilla) {
+				var node = this.getSelectedNode();
+				while (node.parentNode && node.nodeName != "A") { node = node.parentNode; }
+				return node.nodeName == "A";
+			} else if (command == "inserttable" && dojo.render.html.mozilla) {
+				return true;
+			}
+			return this.document.queryCommandEnabled(command);
+		}
+	},
+
+	queryCommandState: function (command, argument) {
+		if (this.object) {
+			if (command == "forecolor") { command = "setforecolor"; }
+			else if (command == "backcolor") { command = "setbackcolor"; }
+
+			if (typeof this._activeX.command[command] == "undefined") { return null; }
+			var status = this.object.QueryStatus(this._activeX.command[command]);
+			return (status == this._activeX.status.enabled ||
+				status == this._activeX.status.ninched);
+		} else {
+			return this.document.queryCommandState(command);
+		}
+	},
+
+	queryCommandValue: function (command, argument) {
+		if (this.object) {
+			switch (command) {
+				case "forecolor":
+				case "backcolor":
+				case "fontsize":
+				case "fontname":
+				case "blockformat":
+					command = "get" + command;
+					return this.object.execCommand(
+						this._activeX.command[command],
+						this._activeX.ui.noprompt);
+			}			
+		
+			//var status = this.object.QueryStatus(this._activeX.command[command]);
+		} else {
+			return this.document.queryCommandValue(command);
+		}
+	},
+	
+	
+/* Misc.
+ ********/
+
+	getSelectedNode: function () {
+		if (this.document.selection) {
+			return this.document.selection.createRange().parentElement();
+		} else if (dojo.render.html.mozilla) {
+			return this.window.getSelection().getRangeAt(0).commonAncestorContainer;
+		}
+		return this.editNode;
+	},
+	
+	placeCursorAtStart: function () {
+		if (this.window.getSelection) {
+			var selection = this.window.getSelection;
+			if (selection.removeAllRanges) { // Mozilla			
+				var range = this.document.createRange();
+				range.selectNode(this.editNode.firstChild);
+				range.collapse(true);
+				var selection = this.window.getSelection();
+				selection.removeAllRanges();
+				selection.addRange(range);
+			} else { // Safari
+				// not a great deal we can do
+			}
+		} else if (this.document.selection) { // IE
+			var range = this.document.body.createTextRange();
+			range.moveToElementText(this.editNode);
+			range.collapse(true);
+			range.select();
+		}
+	},
+	
+	placeCursorAtEnd: function () {
+		if (this.window.getSelection) {
+			var selection = this.window.getSelection;
+			if (selection.removeAllRanges) { // Mozilla			
+				var range = this.document.createRange();
+				range.selectNode(this.editNode.lastChild);
+				range.collapse(false);
+				var selection = this.window.getSelection();
+				selection.removeAllRanges();
+				selection.addRange(range);
+			} else { // Safari
+				// not a great deal we can do
+			}
+		} else if (this.document.selection) { // IE
+			var range = this.document.body.createTextRange();
+			range.moveToElementText(this.editNode);
+			range.collapse(true);
+			range.select();
+		}
+	},
+
+	/** Updates the height of the iframe to fit the contents. */
+	_updateHeight: function () {
+		if (this.iframe) {
+			// The height includes the padding, borders and margins so these
+			// need to be added on
+			var heights = ["margin-top", "margin-bottom",
+				"padding-bottom", "padding-top",
+				"border-width-bottom", "border-width-top"];
+			for (var i = 0, chromeheight = 0; i < heights.length; i++) {
+				var height = dojo.style.getStyle(this.iframe, heights[i]);
+				// Safari doesn't have all the heights so we have to test
+				if (height) {
+					chromeheight += Number(height.replace(/[^0-9]/g, ""));
+				}
+			}
+			this.iframe.height = this.document.body.offsetHeight + chromeheight + "px";
+			this.window.scrollTo(0, 0);
+		} else if (this.object) {
+			this.object.height = dojo.style.getInnerHeight(this.editNode);
+		}
+	},
+	
+	/**
+	 * Saves the content in an onunload event if the editor has not been closed
+	 */
+	_saveContent: function (e) {
+		var saveTextarea = document.getElementById("dojo.widget.RichText.savedContent");
+		saveTextarea.value += this._SEPARATOR + this.saveName + ":" + this.getEditorContent();
+	},
+
+	getEditorContent: function(){
+		var ec = "";
+		try{
+			ec = (this._content.length > 0) ? this._content : this.editNode.innerHTML;
+		}catch(e){ /* squelch */ }
+
+		dojo.lang.forEach(this.contentFilters, function(ef){
+			ec = ef(ec);
+		});
+		return ec;
+	},
+	
+	/**
+	 * Kills the editor and optionally writes back the modified contents to the 
+	 * element from which it originated.
+	 *
+	 * @param save Whether or not to save the changes. If false, the changes are
+	 *             discarded.
+	 * @return true if the contents has been modified, false otherwise
+	 */
+	close: function(save, force){
+		if(this.isClosed){return false; }
+
+		if (arguments.length == 0) { save = true; }
+		this._content = this.editNode.innerHTML;
+		var changed = (this.savedContent.innerHTML != this._content);
+		
+		// line height is squashed for iframes
+		if (this.iframe){ this.domNode.style.lineHeight = null; }
+		
+		if(this.interval){ clearInterval(this.interval); }
+		
+		if(dojo.render.html.ie && !this.object){
+			dojo.event.browser.clean(this.editNode);
+		}
+		if(dojo.render.html.moz){
+			var ifr = this.domNode.firstChild;
+			ifr.style.display = "none";
+			/*
+			setTimeout(function(){
+				ifr.parentNode.removeChild(ifr);
+			}, 0);
+			*/
+		}else{
+			this.domNode.innerHTML = "";
+		}
+		// dojo.dom.removeChildren(this.domNode);
+		if(save){
+			if(dojo.render.html.moz){
+				var nc = document.createElement("span");
+				this.domNode.appendChild(nc);
+				nc.innerHTML = this.editNode.innerHTML;
+			}else{
+				this.domNode.innerHTML = this._content;
+			}
+			// kill listeners on the saved content
+			dojo.event.browser.clean(this.savedContent);
+		} else {
+			while (this.savedContent.hasChildNodes()) {
+				this.domNode.appendChild(this.savedContent.firstChild);
+			}
+		}
+		delete this.savedContent;
+		
+		dojo.html.removeClass(this.domNode, "RichTextEditable");
+		this.isClosed = true;
+
+		return changed;
+	},
+	
+	destroy: function () {
+		if (!this.isClosed) { this.close(false); }
+	
+		// disconnect those listeners.
+		while (this._connected.length) {
+			this.disconnect(this._connected[0],
+				this._connected[1], this._connected[2]);
+		}
+	},
+
+	_connected: [],
+	connect: function (targetObj, targetFunc, thisFunc) {
+		dojo.event.connect(targetObj, targetFunc, this, thisFunc);
+		// this._connected.push([targetObj, targetFunc, thisFunc]);	
+	},
+	
+	// FIXME: below two functions do not work with the above line commented out
+	disconnect: function (targetObj, targetFunc, thisFunc) {
+		for (var i = 0; i < this._connected.length; i++) {
+			if (this._connected[0] == targetObj &&
+				this._connected[1] == targetFunc &&
+				this._connected[2] == thisFunc) {
+				dojo.event.disconnect(targetObj, targetFunc, this, thisFunc);
+				this._connected.splice(i, 1);
+				break;
+			}
+		}
+	},
+	
+	disconnectAllWithRoot: function (targetObj) {
+		for (var i = 0; i < this._connected.length; i++) {
+			if (this._connected[0] == targetObj) {
+				dojo.event.disconnect(targetObj,
+					this._connected[1], this, this._connected[2]);
+				this._connected.splice(i, 1);
+			}
+		}	
+	}
+	
+});

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/SimpleDropdownButtons.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/SimpleDropdownButtons.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/SimpleDropdownButtons.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/SimpleDropdownButtons.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,146 @@
+/* TODO:
+ * - make the dropdowns "smart" so they can't get cutoff on bottom of page, sides of page, etc.
+ * - unify menus with the MenuItem and Menu classes so we can add stuff to all menus at once
+ * - allow buttons to be enabled/disabled at runtime
+ *     - this probably means creating all menus upfront and then triggering a disable action
+ *       for disabled buttons in the constructor loop. we'll need a disable and enable action anyway
+ * - should each button with menu be a widget object of it's own?
+ */
+dojo.provide("dojo.widget.SimpleDropdownButtons");
+dojo.provide("dojo.widget.HtmlSimpleDropdownButtons");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.uri.Uri");
+dojo.require("dojo.dom");
+dojo.require("dojo.style");
+dojo.require("dojo.html");
+
+dojo.widget.tags.addParseTreeHandler("dojo:simpledropdownbuttons");
+
+dojo.widget.HtmlSimpleDropdownButtons = function() {
+	dojo.widget.HtmlWidget.call(this);
+
+	this.widgetType = "SimpleDropdownButtons";
+	this.templateCssPath = dojo.uri.dojoUri("src/widget/templates/HtmlSimpleDropdownButtons.css");
+
+	this.menuTriggerClass = "dojoSimpleDropdownButtons";
+	this.menuClass = "dojoSimpleDropdownButtonsMenu";
+
+	// overwrite buildRendering so we don't clobber our list
+	this.buildRendering = function(args, frag) {
+		if(this.templateCssPath) {
+			dojo.style.insertCssFile(this.templateCssPath, null, true);
+		}
+		this.domNode = frag["dojo:"+this.widgetType.toLowerCase()]["nodeRef"];
+
+		var menu = this.domNode;
+		if( !dojo.html.hasClass(menu, this.menuTriggerClass) ) {
+			dojo.html.addClass(menu, this.menuTriggerClass);
+		}
+		var li = dojo.dom.getFirstChildElement(menu);
+		var menuIDs = [];
+		var arrowIDs = [];
+
+		while(li) {
+			if(li.getElementsByTagName("ul").length > 0) {
+				var a = dojo.dom.getFirstChildElement(li);
+				var arrow = document.createElement("a");
+				arrow.href = "javascript:;";
+				arrow.innerHTML = "&nbsp;";
+				dojo.html.setClass(arrow, "downArrow");
+				if(!arrow.id) {
+					arrow.id = dojo.dom.getUniqueId();
+				}
+				arrowIDs.push(arrow.id);
+				var submenu = dojo.dom.getNextSiblingElement(a);
+				if(!submenu.id) {
+					submenu.id = dojo.dom.getUniqueId();
+				}
+				menuIDs.push(submenu.id);
+
+				if( dojo.html.hasClass(a, "disabled") ) {
+					dojo.html.addClass(arrow, "disabled");
+					dojo.html.disableSelection(li);
+					arrow.onfocus = function(){ this.blur(); }
+				} else {
+					dojo.html.addClass(submenu, this.menuClass);
+					dojo.html.body().appendChild(submenu);
+					dojo.event.connect(arrow, "onmousedown", (function() {
+						var ar = arrow;
+						return function(e) {
+							dojo.html.addClass(ar, "pressed");
+						}
+					})());
+					dojo.event.connect(arrow, "onclick", (function() {
+						var aa = a;
+						var ar = arrow;
+						var sm = submenu;
+						var setWidth = false;
+
+						return function(e) {
+							hideAll(sm, ar);
+							sm.style.left = (dojo.html.getScrollLeft()
+								+ e.clientX - e.layerX + aa.offsetLeft) + "px";
+							sm.style.top = (dojo.html.getScrollTop() + e.clientY
+								- e.layerY + aa.offsetTop + aa.offsetHeight) + "px";
+							sm.style.display = sm.style.display == "block" ? "none" : "block";
+							if(sm.style.display == "none") {
+								dojo.html.removeClass(ar, "pressed");
+								e.target.blur()
+							}
+							if(!setWidth && sm.style.display == "block"
+								&& sm.offsetWidth < aa.offsetWidth + ar.offsetWidth) {
+								sm.style.width = aa.offsetWidth + ar.offsetWidth + "px";
+								setWidth = true;
+							}
+							e.preventDefault();
+						}
+					})());
+				}
+
+				dojo.event.connect(a, "onclick", function(e) {
+					if(e && e.target && e.target.blur) {
+						e.target.blur();
+					}
+				});
+
+				if(a.nextSibling) {
+					li.insertBefore(arrow, a.nextSibling);
+				} else {
+					li.appendChild(arrow);
+				}
+
+			}
+			li = dojo.dom.getNextSiblingElement(li);
+		}
+
+		function hideAll(excludeMenu, excludeArrow) {
+			// hide menus
+			for(var i = 0; i < menuIDs.length; i++) {
+				var m = document.getElementById(menuIDs[i]);
+				if(!excludeMenu || m != excludeMenu) {
+					document.getElementById(menuIDs[i]).style.display = "none";
+				}
+			}
+			// restore arrows to non-pressed state
+			for(var i = 0; i < arrowIDs.length; i++) {
+				var m = document.getElementById(arrowIDs[i]);
+				if(!excludeArrow || m != excludeArrow) {
+					dojo.html.removeClass(m, "pressed");
+				}
+			}
+		}
+
+		dojo.event.connect(document.documentElement, "onmousedown", function(e) {
+			if( dojo.html.hasClass(e.target, "downArrow") ) { return };
+			for(var i = 0; i < menuIDs.length; i++) {
+				if( dojo.dom.isDescendantOf(e.target, document.getElementById(menuIDs[i])) ) {
+					return;
+				}
+			}
+			hideAll();
+		});
+	}
+}
+dojo.inherits(dojo.widget.HtmlSimpleDropdownButtons, dojo.widget.HtmlWidget);

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/SvgButton.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/SvgButton.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/SvgButton.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/SvgButton.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,133 @@
+// FIXME: not yet functional
+
+dojo.provide("dojo.widget.SvgButton");
+
+dojo.require("dojo.widget.Button");
+
+dojo.widget.SvgButton = function(){
+	// FIXME: this is incomplete and doesn't work yet
+	// if DOMButton turns into a mixin, we should subclass Button instead and
+	// just mix in the DOMButton properties.
+
+	dojo.widget.DomButton.call(this);
+	dojo.widget.SvgWidget.call(this);
+
+	// FIXME: freaking implement this already!
+	this.onFoo = function(){ alert("bar"); }
+
+	this.label = "huzzah!";
+
+	this.setLabel = function(x, y, textSize, label, shape){
+		//var labelNode = this.domNode.ownerDocument.createTextNode(this.label);
+		//var textNode = this.domNode.ownerDocument.createElement("text");
+		var coords = dojo.widget.SvgButton.prototype.coordinates(x, y, textSize, label, shape);
+		var textString = "";
+		switch(shape) {
+			case "ellipse":
+				textString = "<text x='"+ coords[6] + "' y='"+ coords[7] + "'>"+ label + "</text>";
+				//textNode.setAttribute("x", coords[6]);
+				//textNode.setAttribute("y", coords[7]);
+				break;
+			case "rectangle":
+				//FIXME: implement
+				textString = "";
+				//textNode.setAttribute("x", coords[6]);
+				//textNode.setAttribute("y", coords[7]);
+				break;
+			case "circle":
+				//FIXME: implement
+				textString = "";
+				//textNode.setAttribute("x", coords[6]);
+				//textNode.setAttribute("y", coords[7]);
+				break;
+		}
+		//textNode.appendChild(labelNode);
+		//this.domNode.appendChild(textNode);
+		return textString;
+		alert(textNode.getComputedTextLength());
+	}
+
+	this.fillInTemplate = function(x, y, textSize, label, shape){
+		// the idea is to set the text to the appropriate place given its length
+		// and the template shape
+		
+		// FIXME: For now, assuming text sizes are integers in SVG units
+		this.textSize = textSize || 12;
+		this.label = label;
+		// FIXEME: for now, I'm going to fake this... need to come up with a real way to 
+		// determine the actual width of the text, such as computedStyle
+		var textWidth = this.label.length*this.textSize ;
+		//this.setLabel();
+	}
+}
+
+dojo.inherits(dojo.widget.SvgButton, dojo.widget.DomButton);
+
+// FIXME
+dojo.widget.SvgButton.prototype.shapeString = function(x, y, textSize, label, shape) {
+	switch(shape) {
+		case "ellipse":
+			var coords = dojo.widget.SvgButton.prototype.coordinates(x, y, textSize, label, shape)
+			return "<ellipse cx='"+ coords[4]+"' cy='"+ coords[5]+"' rx='"+ coords[2]+"' ry='"+ coords[3]+"'/>";
+			break;
+		case "rect":
+			//FIXME: implement
+			return "";
+			//return "<rect x='110' y='45' width='70' height='30'/>";
+			break;
+		case "circle":
+			//FIXME: implement
+			return "";
+			//return "<circle cx='210' cy='60' r='23'/>";
+			break;
+	}
+}
+
+dojo.widget.SvgButton.prototype.coordinates = function(x, y, textSize, label, shape) {
+	switch(shape) {
+		case "ellipse":
+			var buttonWidth = label.length*textSize;
+			var buttonHeight = textSize*2.5
+			var rx = buttonWidth/2;
+			var ry = buttonHeight/2;
+			var cx = rx + x;
+			var cy = ry + y;
+			var textX = cx - rx*textSize/25;
+			var textY = cy*1.1;
+			return [buttonWidth, buttonHeight, rx, ry, cx, cy, textX, textY];
+			break;
+		case "rectangle":
+			//FIXME: implement
+			return "";
+			break;
+		case "circle":
+			//FIXME: implement
+			return "";
+			break;
+	}
+}
+
+dojo.widget.SvgButton.prototype.labelString = function(x, y, textSize, label, shape){
+	var textString = "";
+	var coords = dojo.widget.SvgButton.prototype.coordinates(x, y, textSize, label, shape);
+	switch(shape) {
+		case "ellipse":
+			textString = "<text x='"+ coords[6] + "' y='"+ coords[7] + "'>"+ label + "</text>";
+			break;
+		case "rectangle":
+			//FIXME: implement
+			textString = "";
+			break;
+		case "circle":
+			//FIXME: implement
+			textString = "";
+			break;
+	}
+	return textString;
+}
+
+//dojo.widget.SVGButton.prototype.templateString = "<g class='dojoButton' dojoAttachEvent='onClick; onMouseMove: onFoo;' dojoAttachPoint='labelNode'>"+ dojo.webui.widgets.SVGButton.prototype.shapeString("ellipse") + "</g>";
+
+dojo.widget.SvgButton.prototype.templateString = function(x, y, textSize, label, shape) {
+	return "<g class='dojoButton' dojoAttachEvent='onClick; onMouseMove: onFoo;' dojoAttachPoint='labelNode'>"+ dojo.webui.widgets.SVGButton.prototype.shapeString(x, y, textSize, label, shape) + dojo.widget.SVGButton.prototype.labelString(x, y, textSize, label, shape) + "</g>";
+}

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/SvgWidget.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/SvgWidget.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/SvgWidget.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/SvgWidget.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,82 @@
+dojo.require("dojo.widget.DomWidget");
+dojo.provide("dojo.widget.SvgWidget");
+dojo.provide("dojo.widget.SVGWidget"); // back compat
+
+dojo.require("dojo.dom");
+
+// SVGWidget is a mixin ONLY
+dojo.widget.SvgWidget = function(args){
+	// mix in the parent type
+	// dojo.widget.DomWidget.call(this);
+}
+dojo.inherits(dojo.widget.SvgWidget, dojo.widget.DomWidget);
+
+dojo.lang.extend(dojo.widget.SvgWidget, {
+	getContainerHeight: function(){
+		// NOTE: container height must be returned as the INNER height
+		dj_unimplemented("dojo.widget.SvgWidget.getContainerHeight");
+	},
+
+	getContainerWidth: function(){
+		// return this.parent.domNode.offsetWidth;
+		dj_unimplemented("dojo.widget.SvgWidget.getContainerWidth");
+	},
+
+	setNativeHeight: function(height){
+		// var ch = this.getContainerHeight();
+		dj_unimplemented("dojo.widget.SVGWidget.setNativeHeight");
+	},
+
+	createNodesFromText: function(txt, wrap){
+		return dojo.dom.createNodesFromText(txt, wrap);
+	}
+});
+
+dojo.widget.SVGWidget = dojo.widget.SvgWidget;
+
+try{
+(function(){
+	var tf = function(){
+		// FIXME: fill this in!!!
+		var rw = new function(){
+			dojo.widget.SvgWidget.call(this);
+			this.buildRendering = function(){ return; }
+			this.destroyRendering = function(){ return; }
+			this.postInitialize = function(){ return; }
+			this.cleanUp = function(){ return; }
+			this.widgetType = "SVGRootWidget";
+			this.domNode = document.documentElement;
+		}
+		var wm = dojo.widget.manager;
+		wm.root = rw;
+		wm.add(rw);
+
+		// extend the widgetManager with a getWidgetFromNode method
+		wm.getWidgetFromNode = function(node){
+			var filter = function(x){
+				if(x.domNode == node){
+					return true;
+				}
+			}
+			var widgets = [];
+			while((node)&&(widgets.length < 1)){
+				widgets = this.getWidgetsByFilter(filter);
+				node = node.parentNode;
+			}
+			if(widgets.length > 0){
+				return widgets[0];
+			}else{
+				return null;
+			}
+		}
+
+		wm.getWidgetFromEvent = function(domEvt){
+			return this.getWidgetFromNode(domEvt.target);
+		}
+
+		wm.getWidgetFromPrimitive = wm.getWidgetFromNode;
+	}
+	// make sure we get called when the time is right
+	dojo.event.connect(dojo.hostenv, "loaded", tf);
+})();
+}catch(e){ alert(e); }

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/TaskBar.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/TaskBar.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/TaskBar.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/TaskBar.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,24 @@
+dojo.provide("dojo.widget.TaskBar");
+dojo.provide("dojo.widget.TaskBarItem");
+dojo.require("dojo.widget.Widget");
+
+dojo.requireIf("html", "dojo.widget.html.TaskBar");
+
+
+dojo.widget.TaskBar = function(){
+	dojo.widget.Widget.call(this);
+
+	this.widgetType = "TaskBar";
+	this.isContainer = true;
+}
+dojo.inherits(dojo.widget.TaskBar, dojo.widget.Widget);
+dojo.widget.tags.addParseTreeHandler("dojo:taskbar");
+
+dojo.widget.TaskBarItem = function(){
+	dojo.widget.Widget.call(this);
+
+	this.widgetType = "TaskBarItem";
+}
+dojo.inherits(dojo.widget.TaskBarItem, dojo.widget.Widget);
+dojo.widget.tags.addParseTreeHandler("dojo:taskbaritem");
+

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/TimePicker.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/TimePicker.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/TimePicker.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/TimePicker.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,14 @@
+dojo.provide("dojo.widget.TimePicker");
+dojo.require("dojo.widget.DomWidget");
+
+dojo.requireIf("html", "dojo.widget.html.TimePicker");
+
+dojo.widget.TimePicker = function(){
+	dojo.widget.Widget.call(this);
+	this.widgetType = "TimePicker";
+	this.isContainer = false;
+
+}
+
+dojo.inherits(dojo.widget.TimePicker, dojo.widget.Widget);
+dojo.widget.tags.addParseTreeHandler("dojo:timepicker");

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Toggler.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Toggler.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Toggler.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Toggler.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,30 @@
+dojo.provide("dojo.widget.Toggler");
+dojo.require("dojo.widget.DomWidget");
+dojo.require("dojo.event");
+
+// clicking on this node shows/hides another widget
+
+dojo.widget.Toggler = function(){
+	dojo.widget.DomWidget.call(this);
+}
+
+dojo.inherits(dojo.widget.Toggler, dojo.widget.DomWidget);
+
+dojo.lang.extend(dojo.widget.Toggler, {
+	widgetType: "Toggler",
+	
+	// Associated widget 
+	targetId: '',
+	
+	fillInTemplate: function() {
+		dojo.event.connect(this.domNode, "onclick", this, "onClick");
+	},
+	
+	onClick: function() {
+		var pane = dojo.widget.getWidgetById(this.targetId);
+		if ( !pane || !pane.toggle ) { return; }
+		pane.explodeSrc = this.domNode;
+		pane.doToggle();
+	}
+});
+dojo.widget.tags.addParseTreeHandler("dojo:toggler");
\ No newline at end of file

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Toolbar.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Toolbar.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Toolbar.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Toolbar.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,950 @@
+dojo.provide("dojo.widget.ToolbarContainer");
+dojo.provide("dojo.widget.HTMLToolbarContainer");
+dojo.provide("dojo.widget.Toolbar");
+dojo.provide("dojo.widget.HTMLToolbar");
+dojo.provide("dojo.widget.ToolbarItem");
+dojo.provide("dojo.widget.HTMLToolbarButtonGroup");
+dojo.provide("dojo.widget.HTMLToolbarButton");
+dojo.provide("dojo.widget.HTMLToolbarDialog");
+dojo.provide("dojo.widget.HTMLToolbarMenu");
+dojo.provide("dojo.widget.HTMLToolbarSeparator");
+dojo.provide("dojo.widget.HTMLToolbarSpace");
+dojo.provide("dojo.widget.Icon");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.html");
+
+/* ToolbarContainer
+ *******************/
+dojo.widget.HTMLToolbarContainer = function() {
+	dojo.widget.HtmlWidget.call(this);
+
+	this.widgetType = "ToolbarContainer";
+	this.isContainer = true;
+
+	this.templateString = '<div class="toolbarContainer" dojoAttachPoint="containerNode"></div>';
+	this.templateCssPath = dojo.uri.dojoUri("src/widget/templates/HtmlToolbar.css");
+
+	this.getItem = function(name) {
+		if(name instanceof dojo.widget.ToolbarItem) { return name; }
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.HTMLToolbar) {
+				var item = child.getItem(name);
+				if(item) { return item; }
+			}
+		}
+		return null;
+	}
+
+	this.getItems = function() {
+		var items = [];
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.HTMLToolbar) {
+				items = items.concat(child.getItems());
+			}
+		}
+		return items;
+	}
+
+	this.enable = function() {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.HTMLToolbar) {
+				child.enable.apply(child, arguments);
+			}
+		}
+	}
+
+	this.disable = function() {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.HTMLToolbar) {
+				child.disable.apply(child, arguments);
+			}
+		}
+	}
+
+	this.select = function(name) {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.HTMLToolbar) {
+				child.select(arguments);
+			}
+		}
+	}
+
+	this.deselect = function(name) {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.HTMLToolbar) {
+				child.deselect(arguments);
+			}
+		}
+	}
+
+	this.getItemsState = function() {
+		var values = {};
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.HTMLToolbar) {
+				dojo.lang.mixin(values, child.getItemsState());
+			}
+		}
+		return values;
+	}
+
+	this.getItemsActiveState = function() {
+		var values = {};
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.HTMLToolbar) {
+				dojo.lang.mixin(values, child.getItemsActiveState());
+			}
+		}
+		return values;
+	}
+
+	this.getItemsSelectedState = function() {
+		var values = {};
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.HTMLToolbar) {
+				dojo.lang.mixin(values, child.getItemsSelectedState());
+			}
+		}
+		return values;
+	}
+}
+dojo.inherits(dojo.widget.HTMLToolbarContainer, dojo.widget.HtmlWidget);
+dojo.widget.tags.addParseTreeHandler("dojo:toolbarContainer");
+
+/* Toolbar
+ **********/
+dojo.widget.HTMLToolbar = function() {
+	dojo.widget.HtmlWidget.call(this);
+
+	this.widgetType = "Toolbar";
+	this.isContainer = true;
+
+	this.templateString = '<div class="toolbar" dojoAttachPoint="containerNode" unselectable="on" dojoOnMouseover="_onmouseover" dojoOnMouseout="_onmouseout" dojoOnClick="_onclick" dojoOnMousedown="_onmousedown" dojoOnMouseup="_onmouseup"></div>';
+	//this.templateString = '<div class="toolbar" dojoAttachPoint="containerNode" unselectable="on"></div>';
+
+	// given a node, tries to find it's toolbar item
+	this._getItem = function(node) {
+		var start = new Date();
+		var widget = null;
+		while(node && node != this.domNode) {
+			if(dojo.html.hasClass(node, "toolbarItem")) {
+				var widgets = dojo.widget.manager.getWidgetsByFilter(function(w) { return w.domNode == node; });
+				if(widgets.length == 1) {
+					widget = widgets[0];
+					break;
+				} else if(widgets.length > 1) {
+					dojo.raise("Toolbar._getItem: More than one widget matches the node");
+				}
+			}
+			node = node.parentNode;
+		}
+		return widget;
+	}
+
+	this._onmouseover = function(e) {
+		var widget = this._getItem(e.target);
+		if(widget && widget._onmouseover) { widget._onmouseover(e); }
+	}
+
+	this._onmouseout = function(e) {
+		var widget = this._getItem(e.target);
+		if(widget && widget._onmouseout) { widget._onmouseout(e); }
+	}
+
+	this._onclick = function(e) {
+		var widget = this._getItem(e.target);
+		if(widget && widget._onclick){ 
+			widget._onclick(e);
+		}
+	}
+
+	this._onmousedown = function(e) {
+		var widget = this._getItem(e.target);
+		if(widget && widget._onmousedown) { widget._onmousedown(e); }
+	}
+
+	this._onmouseup = function(e) {
+		var widget = this._getItem(e.target);
+		if(widget && widget._onmouseup) { widget._onmouseup(e); }
+	}
+
+	var oldAddChild = this.addChild;
+	this.addChild = function(item, pos, props) {
+		var widget = dojo.widget.ToolbarItem.make(item, null, props);
+		var ret = oldAddChild.call(this, widget, null, pos, null);
+		return ret;
+	}
+
+	this.push = function() {
+		for(var i = 0; i < arguments.length; i++) {
+			this.addChild(arguments[i]);
+		}
+	}
+
+	this.getItem = function(name) {
+		if(name instanceof dojo.widget.ToolbarItem) { return name; }
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem
+				&& child._name == name) { return child; }
+		}
+		return null;
+	}
+
+	this.getItems = function() {
+		var items = [];
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				items.push(child);
+			}
+		}
+		return items;
+	}
+
+	this.getItemsState = function() {
+		var values = {};
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				values[child._name] = {
+					selected: child._selected,
+					enabled: child._enabled
+				};
+			}
+		}
+		return values;
+	}
+
+	this.getItemsActiveState = function() {
+		var values = this.getItemsState();
+		for(var item in values) {
+			values[item] = values[item].enabled;
+		}
+		return values;
+	}
+
+	this.getItemsSelectedState = function() {
+		var values = this.getItemsState();
+		for(var item in values) {
+			values[item] = values[item].selected;
+		}
+		return values;
+	}
+
+	this.enable = function() {
+		var items = arguments.length ? arguments : this.children;
+		for(var i = 0; i < items.length; i++) {
+			var child = this.getItem(items[i]);
+			if(child instanceof dojo.widget.ToolbarItem) {
+				child.enable(false, true);
+			}
+		}
+	}
+
+	this.disable = function() {
+		var items = arguments.length ? arguments : this.children;
+		for(var i = 0; i < items.length; i++) {
+			var child = this.getItem(items[i]);
+			if(child instanceof dojo.widget.ToolbarItem) {
+				child.disable();
+			}
+		}
+	}
+
+	this.select = function() {
+		for(var i = 0; i < arguments.length; i++) {
+			var name = arguments[i];
+			var item = this.getItem(name);
+			if(item) { item.select(); }
+		}
+	}
+
+	this.deselect = function() {
+		for(var i = 0; i < arguments.length; i++) {
+			var name = arguments[i];
+			var item = this.getItem(name);
+			if(item) { item.disable(); }
+		}
+	}
+
+	this.setValue = function() {
+		for(var i = 0; i < arguments.length; i += 2) {
+			var name = arguments[i], value = arguments[i+1];
+			var item = this.getItem(name);
+			if(item) {
+				if(item instanceof dojo.widget.ToolbarItem) {
+					item.setValue(value);
+				}
+			}
+		}
+	}
+}
+dojo.inherits(dojo.widget.HTMLToolbar, dojo.widget.HtmlWidget);
+dojo.widget.tags.addParseTreeHandler("dojo:toolbar");
+
+/* ToolbarItem hierarchy:
+	- ToolbarItem
+		- ToolbarButton
+		- ToolbarDialog
+			- ToolbarMenu
+		- ToolbarSeparator
+			- ToolbarSpace
+				- ToolbarFlexibleSpace
+*/
+
+
+/* ToolbarItem
+ **************/
+dojo.widget.ToolbarItem = function() {
+	dojo.widget.HtmlWidget.call(this);
+}
+dojo.inherits(dojo.widget.ToolbarItem, dojo.widget.HtmlWidget);
+
+dojo.lang.extend(dojo.widget.ToolbarItem, {
+	templateString: '<span unselectable="on" class="toolbarItem"></span>',
+
+	_name: null,
+	getName: function() { return this._name; },
+	setName: function(value) { return this._name = value; },
+	getValue: function() { return this.getName(); },
+	setValue: function(value) { return this.setName(value); },
+
+	_selected: false,
+	isSelected: function() { return this._selected; },
+	setSelected: function(is, force, preventEvent) {
+		if(!this._toggleItem && !force) { return; }
+		is = Boolean(is);
+		if(force || this._enabled && this._selected != is) {
+			this._selected = is;
+			this.update();
+			if(!preventEvent) {
+				this._fireEvent(is ? "onSelect" : "onDeselect");
+				this._fireEvent("onChangeSelect");
+			}
+		}
+	},
+	select: function(force, preventEvent) {
+		return this.setSelected(true, force, preventEvent);
+	},
+	deselect: function(force, preventEvent) {
+		return this.setSelected(false, force, preventEvent);
+	},
+
+	_toggleItem: false,
+	isToggleItem: function() { return this._toggleItem; },
+	setToggleItem: function(value) { this._toggleItem = Boolean(value); },
+
+	toggleSelected: function(force) {
+		return this.setSelected(!this._selected, force);
+	},
+
+	_enabled: true,
+	isEnabled: function() { return this._enabled; },
+	setEnabled: function(is, force, preventEvent) {
+		is = Boolean(is);
+		if(force || this._enabled != is) {
+			this._enabled = is;
+			this.update();
+			if(!preventEvent) {
+				this._fireEvent(this._enabled ? "onEnable" : "onDisable");
+				this._fireEvent("onChangeEnabled");
+			}
+		}
+		return this._enabled;
+	},
+	enable: function(force, preventEvent) {
+		return this.setEnabled(true, force, preventEvent);
+	},
+	disable: function(force, preventEvent) {
+		return this.setEnabled(false, force, preventEvent);
+	},
+	toggleEnabled: function(force, preventEvent) {
+		return this.setEnabled(!this._enabled, force, preventEvent);
+	},
+
+	_icon: null,
+	getIcon: function() { return this._icon; },
+	setIcon: function(value) {
+		var icon = dojo.widget.Icon.make(value);
+		if(this._icon) {
+			this._icon.setIcon(icon);
+		} else {
+			this._icon = icon;
+		}
+		var iconNode = this._icon.getNode();
+		if(iconNode.parentNode != this.domNode) {
+			if(this.domNode.hasChildNodes()) {
+				this.domNode.insertBefore(iconNode, this.domNode.firstChild);
+			} else {
+				this.domNode.appendChild(iconNode);
+			}
+		}
+		return this._icon;
+	},
+
+	// TODO: update the label node (this.labelNode?)
+	_label: "",
+	getLabel: function() { return this._label; },
+	setLabel: function(value) {
+		var ret = this._label = value;
+		if(!this.labelNode) {
+			this.labelNode = document.createElement("span");
+			this.domNode.appendChild(this.labelNode);
+		}
+		this.labelNode.innerHTML = "";
+		this.labelNode.appendChild(document.createTextNode(this._label));
+		this.update();
+		return ret;
+	},
+
+	// fired from: setSelected, setEnabled, setLabel
+	update: function() {
+		if(this._enabled) {
+			dojo.html.removeClass(this.domNode, "disabled");
+			if(this._selected) {
+				dojo.html.addClass(this.domNode, "selected");
+			} else {
+				dojo.html.removeClass(this.domNode, "selected");
+			}
+		} else {
+			this._selected = false;
+			dojo.html.addClass(this.domNode, "disabled");
+			dojo.html.removeClass(this.domNode, "down");
+			dojo.html.removeClass(this.domNode, "hover");
+		}
+		this._updateIcon();
+	},
+
+	_updateIcon: function() {
+		if(this._icon) {
+			if(this._enabled) {
+				if(this._cssHover) {
+					this._icon.hover();
+				} else if(this._selected) {
+					this._icon.select();
+				} else {
+					this._icon.enable();
+				}
+			} else {
+				this._icon.disable();
+			}
+		}
+	},
+
+	_fireEvent: function(evt) {
+		if(typeof this[evt] == "function") {
+			var args = [this];
+			for(var i = 1; i < arguments.length; i++) {
+				args.push(arguments[i]);
+			}
+			this[evt].apply(this, args);
+		}
+	},
+
+	_onmouseover: function(e) {
+		if(!this._enabled) { return };
+		dojo.html.addClass(this.domNode, "hover");
+	},
+
+	_onmouseout: function(e) {
+		dojo.html.removeClass(this.domNode, "hover");
+		dojo.html.removeClass(this.domNode, "down");
+		if(!this._selected) {
+			dojo.html.removeClass(this.domNode, "selected");
+		}
+	},
+
+	_onclick: function(e) {
+		// FIXME: buttons never seem to have this._enabled set to true on Opera 9
+		// dojo.debug("widget:", this.widgetType, ":", this.getName(), ", enabled:", this._enabled);
+		if(this._enabled && !this._toggleItem) {
+			this._fireEvent("onClick");
+		}
+	},
+
+	_onmousedown: function(e) {
+		if(e.preventDefault) { e.preventDefault(); }
+		if(!this._enabled) { return };
+		dojo.html.addClass(this.domNode, "down");
+		if(this._toggleItem) {
+			if(this.parent.preventDeselect && this._selected) {
+				return;
+			}
+			this.toggleSelected();
+		}
+	},
+
+	_onmouseup: function(e) {
+		dojo.html.removeClass(this.domNode, "down");
+	},
+
+	fillInTemplate: function(args, frag) {
+		if(args.name) { this._name = args.name; }
+		if(args.selected) { this.select(); }
+		if(args.disabled) { this.disable(); }
+		if(args.label) { this.setLabel(args.label); }
+		if(args.icon) { this.setIcon(args.icon); }
+		if(args.toggleitem||args.toggleItem) { this.setToggleItem(true); }
+	}
+});
+
+dojo.widget.ToolbarItem.make = function(wh, whIsType, props) {
+	var item = null;
+
+	if(wh instanceof Array) {
+		item = dojo.widget.fromScript("ToolbarButtonGroup", props);
+		item.setName(wh[0]);
+		for(var i = 1; i < wh.length; i++) {
+			item.addChild(wh[i]);
+		}
+	} else if(wh instanceof dojo.widget.ToolbarItem) {
+		item = wh;
+	} else if(wh instanceof dojo.uri.Uri) {
+		item = dojo.widget.fromScript("ToolbarButton",
+			dojo.lang.mixin(props||{}, {icon: new dojo.widget.Icon(wh.toString())}));
+	} else if(whIsType) {
+		item = dojo.widget.fromScript(wh, props)
+	} else if(typeof wh == "string" || wh instanceof String) {
+		switch(wh.charAt(0)) {
+			case "|":
+			case "-":
+			case "/":
+				item = dojo.widget.fromScript("ToolbarSeparator", props);
+				break;
+			case " ":
+				if(wh.length == 1) {
+					item = dojo.widget.fromScript("ToolbarSpace", props);
+				} else {
+					item = dojo.widget.fromScript("ToolbarFlexibleSpace", props);
+				}
+				break;
+			default:
+				if(/\.(gif|jpg|jpeg|png)$/i.test(wh)) {
+					item = dojo.widget.fromScript("ToolbarButton",
+						dojo.lang.mixin(props||{}, {icon: new dojo.widget.Icon(wh.toString())}));
+				} else {
+					item = dojo.widget.fromScript("ToolbarButton",
+						dojo.lang.mixin(props||{}, {label: wh.toString()}));
+				}
+		}
+	} else if(wh && wh.tagName && /^img$/i.test(wh.tagName)) {
+		item = dojo.widget.fromScript("ToolbarButton",
+			dojo.lang.mixin(props||{}, {icon: wh}));
+	} else {
+		item = dojo.widget.fromScript("ToolbarButton",
+			dojo.lang.mixin(props||{}, {label: wh.toString()}));
+	}
+	return item;
+}
+
+/* ToolbarButtonGroup
+ *********************/
+dojo.widget.HTMLToolbarButtonGroup = function() {
+	dojo.widget.ToolbarItem.call(this);
+
+	this.widgetType = "ToolbarButtonGroup";
+	this.isContainer = true;
+
+	this.templateString = '<span unselectable="on" class="toolbarButtonGroup" dojoAttachPoint="containerNode"></span>';
+
+	// if a button has the same name, it will be selected
+	// if this is set to a number, the button at that index will be selected
+	this.defaultButton = "";
+
+	var oldAddChild = this.addChild;
+	this.addChild = function(item, pos, props) {
+		var widget = dojo.widget.ToolbarItem.make(item, null, dojo.lang.mixin(props||{}, {toggleItem:true}));
+		dojo.event.connect(widget, "onSelect", this, "onChildSelected");
+		var ret = oldAddChild.call(this, widget, null, pos, null);
+		if(widget._name == this.defaultButton
+			|| (typeof this.defaultButton == "number"
+			&& this.children.length-1 == this.defaultButton)) {
+			widget.select(false, true);
+		}
+		return ret;
+	}
+
+	this.getItem = function(name) {
+		if(name instanceof dojo.widget.ToolbarItem) { return name; }
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem
+				&& child._name == name) { return child; }
+		}
+		return null;
+	}
+
+	this.getItems = function() {
+		var items = [];
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				items.push(child);
+			}
+		}
+		return items;
+	}
+
+	this.onChildSelected = function(e) {
+		this.select(e._name);
+	}
+
+	this.enable = function(force, preventEvent) {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				child.enable(force, preventEvent);
+				if(child._name == this._value) {
+					child.select(force, preventEvent);
+				}
+			}
+		}
+	}
+
+	this.disable = function(force, preventEvent) {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				child.disable(force, preventEvent);
+			}
+		}
+	}
+
+	this._value = "";
+	this.getValue = function() { return this._value; }
+
+	this.select = function(name, force, preventEvent) {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				if(child._name == name) {
+					child.select(force, preventEvent);
+					this._value = name;
+				} else {
+					child.deselect(true, preventEvent);
+				}
+			}
+		}
+		if(!preventEvent) {
+			this._fireEvent("onSelect", this._value);
+			this._fireEvent("onChangeSelect", this._value);
+		}
+	}
+	this.setValue = this.select;
+
+	this.preventDeselect = false; // if true, once you select one, you can't have none selected
+}
+dojo.inherits(dojo.widget.HTMLToolbarButtonGroup, dojo.widget.ToolbarItem);
+dojo.widget.tags.addParseTreeHandler("dojo:toolbarButtonGroup");
+
+/* ToolbarButton
+ ***********************/
+dojo.widget.HTMLToolbarButton = function() {
+	dojo.widget.ToolbarItem.call(this);
+}
+dojo.inherits(dojo.widget.HTMLToolbarButton, dojo.widget.ToolbarItem);
+dojo.widget.tags.addParseTreeHandler("dojo:toolbarButton");
+
+dojo.lang.extend(dojo.widget.HTMLToolbarButton, {
+	widgetType: "ToolbarButton",
+
+	fillInTemplate: function(args, frag) {
+		dojo.widget.HTMLToolbarButton.superclass.fillInTemplate.call(this, args, frag);
+		dojo.html.addClass(this.domNode, "toolbarButton");
+		if(this._icon) {
+			this.setIcon(this._icon);
+		}
+		if(this._label) {
+			this.setLabel(this._label);
+		}
+
+		if(!this._name) {
+			if(this._label) {
+				this.setName(this._label);
+			} else if(this._icon) {
+				var src = this._icon.getSrc("enabled").match(/[\/^]([^\.\/]+)\.(gif|jpg|jpeg|png)$/i);
+				if(src) { this.setName(src[1]); }
+			} else {
+				this._name = this._widgetId;
+			}
+		}
+	}
+});
+
+/* ToolbarDialog
+ **********************/
+dojo.widget.HTMLToolbarDialog = function() {
+	dojo.widget.HTMLToolbarButton.call(this);
+}
+dojo.inherits(dojo.widget.HTMLToolbarDialog, dojo.widget.HTMLToolbarButton);
+dojo.widget.tags.addParseTreeHandler("dojo:toolbarDialog");
+
+dojo.lang.extend(dojo.widget.HTMLToolbarDialog, {
+	widgetType: "ToolbarDialog",
+	
+	fillInTemplate: function (args, frag) {
+		dojo.widget.HTMLToolbarDialog.superclass.fillInTemplate.call(this, args, frag);
+		dojo.event.connect(this, "onSelect", this, "showDialog");
+		dojo.event.connect(this, "onDeselect", this, "hideDialog");
+	},
+	
+	showDialog: function (e) {
+		dojo.lang.setTimeout(dojo.event.connect, 1, document, "onmousedown", this, "deselect");
+	},
+	
+	hideDialog: function (e) {
+		dojo.event.disconnect(document, "onmousedown", this, "deselect");
+	}
+
+});
+
+/* ToolbarMenu
+ **********************/
+dojo.widget.HTMLToolbarMenu = function() {
+	dojo.widget.HTMLToolbarDialog.call(this);
+
+	this.widgetType = "ToolbarMenu";
+}
+dojo.inherits(dojo.widget.HTMLToolbarMenu, dojo.widget.HTMLToolbarDialog);
+dojo.widget.tags.addParseTreeHandler("dojo:toolbarMenu");
+
+/* ToolbarMenuItem
+ ******************/
+dojo.widget.ToolbarMenuItem = function() {
+}
+
+/* ToolbarSeparator
+ **********************/
+dojo.widget.HTMLToolbarSeparator = function() {
+	dojo.widget.ToolbarItem.call(this);
+
+	this.widgetType = "ToolbarSeparator";
+	this.templateString = '<span unselectable="on" class="toolbarItem toolbarSeparator"></span>';
+
+	this.defaultIconPath = new dojo.uri.dojoUri("src/widget/templates/buttons/-.gif");
+
+	var oldFillInTemplate = this.fillInTemplate;
+	this.fillInTemplate = function(args, frag, skip) {
+		oldFillInTemplate.call(this, args, frag);
+		this._name = this.widgetId;
+		if(!skip) {
+			if(!this._icon) {
+				this.setIcon(this.defaultIconPath);
+			}
+			this.domNode.appendChild(this._icon.getNode());
+		}
+	}
+
+	// don't want events!
+	this._onmouseover = this._onmouseout = this._onclick
+		= this._onmousedown = this._onmouseup = null;
+}
+dojo.inherits(dojo.widget.HTMLToolbarSeparator, dojo.widget.ToolbarItem);
+dojo.widget.tags.addParseTreeHandler("dojo:toolbarSeparator");
+
+/* ToolbarSpace
+ **********************/
+dojo.widget.HTMLToolbarSpace = function() {
+	dojo.widget.HTMLToolbarSeparator.call(this);
+
+	this.widgetType = "ToolbarSpace";
+
+	var oldFillInTemplate = this.fillInTemplate;
+	this.fillInTemplate = function(args, frag, skip) {
+		oldFillInTemplate.call(this, args, frag, true);
+		if(!skip) {
+			dojo.html.addClass(this.domNode, "toolbarSpace");
+		}
+	}
+}
+dojo.inherits(dojo.widget.HTMLToolbarSpace, dojo.widget.HTMLToolbarSeparator);
+dojo.widget.tags.addParseTreeHandler("dojo:toolbarSpace");
+
+/* ToolbarSelect
+ ******************/
+ 
+/*dojo.widget.HTMLToolbarSelect = function() {
+	dojo.widget.HTMLToolbarDialog.call(this);
+
+	// fix inheritence chain
+	for (var method in this.constructor.prototype) {
+		this[method] = this.constructor.prototype[method];
+	}
+}
+dojo.inherits(dojo.widget.HTMLToolbarSelect, dojo.widget.HTMLToolbarDialog);
+dojo.widget.tags.addParseTreeHandler("dojo:toolbarSelect");
+
+dojo.lang.extend(dojo.widget.HTMLToolbarSelect, {
+	widgetType: "ToolbarSelect",
+	
+	fillInTemplate: function (args, frag) {
+		dojo.widget.HTMLToolbarSelect.superclass.fillInTemplate.call(this, args, frag);
+		
+		this.dialog = document.createElement("ul");
+		for(var value in args.values) {
+			var li = document.createElement("li");
+			li.value = args.values[value];
+			li.appendChild(document.createTextNode(value));
+			this.dialog.appendChild(li);
+		}
+	},
+	
+	showDialog: function (e) {
+		dojo.widget.HTMLToolbarSelect.superclass.showDialog.call(this, e);
+		with (dojo.html) {
+			var x = getAbsoluteX(this.domNode);
+			var y = getAbsoluteY(this.domNode) + getInnerHeight(this.domNode);
+		}
+		with (this.domNode.style) { top = y + "px"; left = x + "px"; }
+		dojo.html.body().appendChild(this.dialog);
+	},
+	
+	hideDialog: function (e) {
+		dojo.widget.HTMLToolbarSelect.superclass.hideDialog.call(this, e);
+		this.dialog.parentNode.removeChild(this.dialog);
+	}
+
+});*/
+
+dojo.widget.HTMLToolbarSelect = function() {
+	dojo.widget.ToolbarItem.call(this);
+	this.widgetType = "ToolbarSelect";
+	this.templateString = '<span class="toolbarItem toolbarSelect" unselectable="on"><select dojoAttachPoint="selectBox" dojoOnChange="changed"></select></span>';
+
+	var oldFillInTemplate = this.fillInTemplate;
+	this.fillInTemplate = function(args, frag) {
+		oldFillInTemplate.call(this, args, frag, true);
+		var keys = args.values;
+		var i = 0;
+		for(var val in keys) {
+			var opt = document.createElement("option");
+			opt.setAttribute("value", keys[val]);
+			opt.innerHTML = val;
+			this.selectBox.appendChild(opt);
+		}
+	}
+
+	this.changed = function(e) {
+		this._fireEvent("onSetValue", this.selectBox.value);
+	}
+
+	var oldSetEnabled = this.setEnabled;
+	this.setEnabled = function(is, force, preventEvent) {
+		var ret = oldSetEnabled.call(this, is, force, preventEvent);
+		this.selectBox.disabled = !this._enabled;
+		return ret;
+	}
+
+	// don't want events!
+	this._onmouseover = this._onmouseout = this._onclick
+		= this._onmousedown = this._onmouseup = null;
+}
+dojo.inherits(dojo.widget.HTMLToolbarSelect, dojo.widget.ToolbarItem);
+dojo.widget.tags.addParseTreeHandler("dojo:toolbarSelect");
+
+/* Icon
+ *********/
+// arguments can be IMG nodes, Image() instances or URLs -- enabled is the only one required
+dojo.widget.Icon = function(enabled, disabled, hover, selected) {
+	if(arguments.length == 0) {
+		throw new Error("Icon must have at least an enabled state");
+	}
+	var states = ["enabled", "disabled", "hover", "selected"];
+	var currentState = "enabled";
+	var domNode = document.createElement("img");
+
+	this.getState = function() { return currentState; }
+	this.setState = function(value) {
+		if(dojo.lang.inArray(value, states)) {
+			if(this[value]) {
+				currentState = value;
+				domNode.setAttribute("src", this[currentState].src);
+			}
+		} else {
+			throw new Error("Invalid state set on Icon (state: " + value + ")");
+		}
+	}
+
+	this.setSrc = function(state, value) {
+		if(/^img$/i.test(value.tagName)) {
+			this[state] = value;
+		} else if(typeof value == "string" || value instanceof String
+			|| value instanceof dojo.uri.Uri) {
+			this[state] = new Image();
+			this[state].src = value.toString();
+		}
+		return this[state];
+	}
+
+	this.setIcon = function(icon) {
+		for(var i = 0; i < states.length; i++) {
+			if(icon[states[i]]) {
+				this.setSrc(states[i], icon[states[i]]);
+			}
+		}
+		this.update();
+	}
+
+	this.enable = function() { this.setState("enabled"); }
+	this.disable = function() { this.setState("disabled"); }
+	this.hover = function() { this.setState("hover"); }
+	this.select = function() { this.setState("selected"); }
+
+	this.getSize = function() {
+		return {
+			width: domNode.width||domNode.offsetWidth,
+			height: domNode.height||domNode.offsetHeight
+		};
+	}
+
+	this.setSize = function(w, h) {
+		domNode.width = w;
+		domNode.height = h;
+		return { width: w, height: h };
+	}
+
+	this.getNode = function() {
+		return domNode;
+	}
+
+	this.getSrc = function(state) {
+		if(state) { return this[state].src; }
+		return domNode.src||"";
+	}
+
+	this.update = function() {
+		this.setState(currentState);
+	}
+
+	for(var i = 0; i < states.length; i++) {
+		var arg = arguments[i];
+		var state = states[i];
+		this[state] = null;
+		if(!arg) { continue; }
+		this.setSrc(state, arg);
+	}
+
+	this.enable();
+}
+
+dojo.widget.Icon.make = function(a,b,c,d) {
+	for(var i = 0; i < arguments.length; i++) {
+		if(arguments[i] instanceof dojo.widget.Icon) {
+			return arguments[i];
+		} else if(!arguments[i]) {
+			nullArgs++;
+		}
+	}
+
+	return new dojo.widget.Icon(a,b,c,d);
+}

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Tooltip.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Tooltip.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Tooltip.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Tooltip.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,14 @@
+dojo.provide("dojo.widget.Tooltip");
+dojo.require("dojo.widget.Widget");
+
+dojo.requireIf("html", "dojo.widget.html.Tooltip");
+
+dojo.widget.tags.addParseTreeHandler("dojo:tooltip");
+
+dojo.widget.Tooltip = function(){
+	dojo.widget.Widget.call(this);
+
+	this.widgetType = "Tooltip";
+	this.isContainer = true;
+}
+dojo.inherits(dojo.widget.Tooltip, dojo.widget.Widget);

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Tree.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Tree.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Tree.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Tree.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,507 @@
+dojo.provide("dojo.widget.Tree");
+dojo.provide("dojo.widget.HtmlTree");
+dojo.provide("dojo.widget.TreeNode");
+dojo.provide("dojo.widget.HtmlTreeNode");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.fx.html");
+dojo.require("dojo.widget.HtmlLayoutPane");
+
+
+dojo.widget.HtmlTree = function() {
+	dojo.widget.HtmlLayoutPane.call(this);
+}
+dojo.inherits(dojo.widget.HtmlTree, dojo.widget.HtmlLayoutPane);
+
+dojo.lang.extend(dojo.widget.HtmlTree, {
+	widgetType: "Tree",
+	isContainer: true,
+
+	domNode: null,
+
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/Tree.css"),
+	templateString: '<div class="dojoTree"></div>',
+
+	selectedNode: null,
+	toggler: null,
+
+
+	//
+	// these icons control the grid and expando buttons for the whole tree
+	//
+
+	blankIconSrc: dojo.uri.dojoUri("src/widget/templates/images/treenode_blank.gif").toString(),
+
+	gridIconSrcT: dojo.uri.dojoUri("src/widget/templates/images/treenode_grid_t.gif").toString(), // for non-last child grid
+	gridIconSrcL: dojo.uri.dojoUri("src/widget/templates/images/treenode_grid_l.gif").toString(), // for last child grid
+	gridIconSrcV: dojo.uri.dojoUri("src/widget/templates/images/treenode_grid_v.gif").toString(), // vertical line
+	gridIconSrcP: dojo.uri.dojoUri("src/widget/templates/images/treenode_grid_p.gif").toString(), // for under parent item child icons
+	gridIconSrcC: dojo.uri.dojoUri("src/widget/templates/images/treenode_grid_c.gif").toString(), // for under child item child icons
+	gridIconSrcX: dojo.uri.dojoUri("src/widget/templates/images/treenode_grid_x.gif").toString(), // grid for sole root item
+	gridIconSrcY: dojo.uri.dojoUri("src/widget/templates/images/treenode_grid_y.gif").toString(), // grid for last rrot item
+	gridIconSrcZ: dojo.uri.dojoUri("src/widget/templates/images/treenode_grid_z.gif").toString(), // for under root parent item child icon
+
+	expandIconSrcPlus: dojo.uri.dojoUri("src/widget/templates/images/treenode_expand_plus.gif").toString(),
+	expandIconSrcMinus: dojo.uri.dojoUri("src/widget/templates/images/treenode_expand_minus.gif").toString(),
+
+	iconWidth: 18,
+	iconHeight: 18,
+
+
+	//
+	// tree options
+	//
+
+	showGrid: true,
+	showRootGrid: true,
+
+	toggle: "default",
+	toggleDuration: 150,
+
+
+	//
+	// subscribable events
+	//
+
+	publishSelectionTopic: "",
+	publishExpandedTopic: "",
+	publishCollapsedTopic: "",
+
+
+	initialize: function(args, frag){
+		switch (this.toggle) {
+			case "fade": this.toggler = new dojo.widget.Tree.FadeToggle(); break;
+			case "wipe": this.toggler = new dojo.widget.Tree.WipeToggle(); break;
+			default    : this.toggler = new dojo.widget.Tree.DefaultToggle();
+		}
+	},
+
+	postCreate: function(){
+		this.buildTree();
+	},
+
+	buildTree: function(){
+
+		dojo.html.disableSelection(this.domNode);
+
+		for(var i=0; i<this.children.length; i++){
+
+			this.children[i].isFirstNode = (i == 0) ? true : false;
+			this.children[i].isLastNode = (i == this.children.length-1) ? true : false;
+
+			var node = this.children[i].buildNode(this, 0);
+
+			this.domNode.appendChild(node);
+		}
+
+
+		//
+		// when we don't show root toggles, we need to auto-expand root nodes
+		//
+
+		if (!this.showRootGrid){
+			for(var i=0; i<this.children.length; i++){
+				this.children[i].expand();
+			}
+		}
+
+		for(var i=0; i<this.children.length; i++){
+			this.children[i].startMe();
+		}
+	},
+
+	addChild: function(child){
+
+		//
+		// this function gets called to add nodes to both trees and nodes, so it's a little confusing :)
+		//
+
+		if (child.widgetType != 'TreeNode'){
+			dojo.raise("You can only add TreeNode widgets to a "+this.widgetType+" widget!");
+			return;
+		}
+
+		if (this.children.length){
+
+			var lastChild = this.children[this.children.length-1];
+			lastChild.isLastNode = false;
+			lastChild.updateIconTree();
+		}else{
+
+			if (this.widgetType == 'TreeNode'){
+				this.isParent = true;
+				this.isExpanded = false;
+				this.updateIcons();
+			}
+
+			child.isFirstNode = true;
+		}
+
+
+
+		if (this.widgetType == 'TreeNode'){
+
+			var childDepth = this.depth+1;
+			var childTree = this.tree;
+
+			child.parentNode = this;
+			child.isLastNode = true;
+
+		}else{
+			var childDepth = 0;
+			var childTree = this;
+
+			child.isLastNode = true;
+		}
+
+		this.children.push(child);
+		var node = child.buildNode(childTree, childDepth);
+
+		if (this.widgetType == 'Tree'){
+			this.domNode.appendChild(node);
+		}else{
+			this.containerNode.appendChild(node);
+		}
+
+		child.startMe();
+	}
+});
+
+
+dojo.widget.HtmlTreeNode = function() {
+	dojo.widget.HtmlWidget.call(this);
+}
+
+dojo.inherits(dojo.widget.HtmlTreeNode, dojo.widget.HtmlWidget);
+
+dojo.lang.extend(dojo.widget.HtmlTreeNode, {
+	widgetType: "TreeNode",
+	isContainer: true,
+	messWithMyChildren: true,
+
+	domNode: null,
+	continerNode: null,
+
+	templateString: '<div class="dojoTreeNode"><div dojoAttachPoint="containerNode"></div></div>',
+
+	childIconSrc: '',
+
+	childIcon: null,
+	underChildIcon: null,
+	expandIcon: null,
+
+	title: "",
+
+	labelNode: null, // the item label
+	imgs: null, // an array of icons imgs
+	rowNode: null, // the tr
+
+	tree: null,
+	parentNode: null,
+	depth: 0,
+
+	isFirstNode: false,
+	isLastNode: false,
+	isExpanded: false,
+	isParent: false,
+	booted: false,
+
+	buildNode: function(tree, depth){
+
+		this.tree = tree;
+		this.depth = depth;
+
+
+		//
+		// add the tree icons
+		//
+
+		this.imgs = [];
+
+		for(var i=0; i<this.depth+2; i++){
+
+			var img = document.createElement('img');
+
+			img.style.width = this.tree.iconWidth + 'px';
+			img.style.height = this.tree.iconHeight + 'px';
+			img.src = this.tree.blankIconSrc;
+			img.style.verticalAlign = 'middle';
+
+			this.domNode.insertBefore(img, this.containerNode);
+
+			this.imgs.push(img);
+		}
+
+		this.expandIcon = this.imgs[this.imgs.length-2];
+		this.childIcon = this.imgs[this.imgs.length-1];
+
+
+		//
+		// add the cell label
+		//
+
+
+		this.labelNode = document.createElement('span');
+
+		this.labelNode.appendChild(document.createTextNode(this.title));
+
+		this.domNode.insertBefore(this.labelNode, this.containerNode);
+
+		dojo.html.addClass(this.labelNode, 'dojoTreeNodeLabel');
+
+
+		dojo.event.connect(this.expandIcon, 'onclick', this, 'onTreeClick');
+		dojo.event.connect(this.childIcon, 'onclick', this, 'onIconClick');
+		dojo.event.connect(this.labelNode, 'onclick', this, 'onLabelClick');
+
+
+		//
+		// create the child rows
+		//
+
+		for(var i=0; i<this.children.length; i++){
+
+			this.children[i].isFirstNode = (i == 0) ? true : false;
+			this.children[i].isLastNode = (i == this.children.length-1) ? true : false;
+			this.children[i].parentNode = this;
+			var node = this.children[i].buildNode(this.tree, this.depth+1);
+
+			this.containerNode.appendChild(node);
+		}
+
+		this.isParent = (this.children.length > 0) ? true : false;
+
+		this.collapse();
+
+		return this.domNode;
+	},
+
+	onTreeClick: function(e){
+
+		if (this.isExpanded){
+			this.collapse();
+		}else{
+			this.expand();
+		}
+	},
+
+	onIconClick: function(){
+		this.onLabelClick();
+	},
+
+	onLabelClick: function(){
+
+		if (this.tree.selectedNode == this){
+
+			//this.editInline();
+			dojo.debug('TODO: start inline edit here!');
+			return;
+		}
+
+		if (this.tree.selectedNode){ this.tree.selectedNode.deselect(); }
+
+		this.tree.selectedNode = this;
+		this.tree.selectedNode.select();
+	},
+
+	select: function(){
+
+		dojo.html.addClass(this.labelNode, 'dojoTreeNodeLabelSelected');
+
+		dojo.event.topic.publish(this.tree.publishSelectionTopic, this.widgetId);
+	},
+
+	deselect: function(){
+
+		dojo.html.removeClass(this.labelNode, 'dojoTreeNodeLabelSelected');
+	},
+
+	updateIcons: function(){
+
+		this.imgs[0].style.display = this.tree.showRootGrid ? 'inline' : 'none';
+
+
+		//
+		// set the expand icon
+		//
+
+		if (this.isParent){
+			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
+		//
+
+		if (this.tree.showGrid){
+			if (this.depth){
+
+				this.setGridImage(-2, this.isLastNode ? this.tree.gridIconSrcL : this.tree.gridIconSrcT);
+			}else{
+				if (this.isFirstNode){
+					this.setGridImage(-2, this.isLastNode ? this.tree.gridIconSrcX : this.tree.gridIconSrcY);
+				}else{
+					this.setGridImage(-2, this.isLastNode ? this.tree.gridIconSrcL : this.tree.gridIconSrcT);
+				}
+			}
+		}else{
+			this.setGridImage(-2, this.tree.blankIconSrc);
+		}
+
+
+		//
+		// set the child icon
+		//
+
+		if (this.childIconSrc){
+			this.childIcon.style.display = 'inline';
+			this.childIcon.src = this.childIconSrc;
+		}else{
+			this.childIcon.style.display = 'none';
+		}
+
+
+		//
+		// set the grid under the child icon
+		//
+
+		if ((this.depth || this.tree.showRootGrid) && this.tree.showGrid){
+
+			this.setGridImage(-1, (this.isParent && this.isExpanded) ? this.tree.gridIconSrcP : this.tree.gridIconSrcC);
+		}else{
+			if (this.tree.showGrid && !this.tree.showRootGrid){
+
+				this.setGridImage(-1, (this.isParent && this.isExpanded) ? this.tree.gridIconSrcZ : this.tree.blankIconSrc);
+			}else{
+				this.setGridImage(-1, this.tree.blankIconSrc);
+			}
+		}
+
+
+		//
+		// set the vertical grid icons
+		//
+
+		var parent = this.parentNode;
+
+		for(var i=0; i<this.depth; i++){
+
+			var idx = this.imgs.length-(3+i);
+
+			this.setGridImage(idx, (this.tree.showGrid && !parent.isLastNode) ? this.tree.gridIconSrcV : this.tree.blankIconSrc);
+
+			parent = parent.parentNode;
+		}
+
+	},
+
+	setGridImage: function(idx, src){
+
+		if (idx < 0){
+			idx = this.imgs.length + idx;
+		}
+
+		this.imgs[idx].style.backgroundImage = 'url(' + src + ')';
+	},
+
+	updateIconTree: function(){
+
+		this.updateIcons();
+
+		for(var i=0; i<this.children.length; i++){
+			this.children[i].updateIconTree();
+		}
+	},
+
+	expand: function(){
+		this.showChildren();
+		this.isExpanded = true;
+		this.updateIcons();
+	},
+
+	collapse: function(){
+		this.hideChildren();
+		this.isExpanded = false;
+		this.updateIcons();
+	},
+
+	hideChildren: function(){
+
+		if (this.booted){
+			this.tree.toggler.hide(this.containerNode);
+		}else{
+			this.containerNode.style.display = 'none';
+		}
+		dojo.event.topic.publish(this.tree.publishCollapsedTopic, this.widgetId);
+	},
+
+	showChildren: function(){
+
+		if (this.booted){
+			this.tree.toggler.show(this.containerNode);
+		}else{
+			this.containerNode.style.display = 'block';
+		}
+		dojo.event.topic.publish(this.tree.publishExpandedTopic, this.widgetId);
+	},
+
+	startMe: function(){
+
+		this.booted = true;
+		for(var i=0; i<this.children.length; i++){
+			this.children[i].startMe();
+		}
+	},
+
+	addChild: function(child){
+
+		this.tree.addChild.call(this, child);
+	}
+
+});
+
+dojo.widget.Tree.DefaultToggle = function(){
+
+	this.show = function(node){
+		node.style.display = 'block';
+	}
+
+	this.hide = function(node){
+		node.style.display = 'none';
+	}
+}
+
+dojo.widget.Tree.FadeToggle = function(duration){
+	this.toggleDuration = duration ? duration : 150;
+
+	this.show = function(node){
+		node.style.display = 'block';
+		dojo.fx.html.fade(node, this.toggleDuration, 0, 1);
+	}
+
+	this.hide = function(node){
+		dojo.fx.html.fadeOut(node, this.toggleDuration, function(node){ node.style.display = 'none'; });
+	}
+}
+
+dojo.widget.Tree.WipeToggle = function(duration){
+	this.toggleDuration = duration ? duration : 150;
+
+	this.show = function(node){
+		node.style.display = 'block';
+		dojo.fx.html.wipeIn(node, this.toggleDuration);
+	}
+
+	this.hide = function(node){
+		dojo.fx.html.wipeOut(node, this.toggleDuration, function(node){ node.style.display = 'none'; });
+	}
+}
+
+
+// make it a tag
+dojo.widget.tags.addParseTreeHandler("dojo:Tree");
+dojo.widget.tags.addParseTreeHandler("dojo:TreeNode");
+



---------------------------------------------------------------------
To unsubscribe, e-mail: jetspeed-dev-unsubscribe@portals.apache.org
For additional commands, e-mail: jetspeed-dev-help@portals.apache.org