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 [12/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/Widget.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Widget.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Widget.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Widget.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,428 @@
+dojo.provide("dojo.widget.Widget");
+dojo.provide("dojo.widget.tags");
+
+dojo.require("dojo.lang");
+dojo.require("dojo.widget.Manager");
+dojo.require("dojo.event.*");
+dojo.require("dojo.string");
+
+dojo.widget.Widget = function(){
+	// these properties aren't primitives and need to be created on a per-item
+	// basis.
+	this.children = [];
+	// this.selection = new dojo.widget.Selection();
+	// FIXME: need to replace this with context menu stuff
+	this.rightClickItems = [];
+	this.extraArgs = {};
+}
+// FIXME: need to be able to disambiguate what our rendering context is
+//        here!
+
+// needs to be a string with the end classname. Every subclass MUST
+// over-ride.
+dojo.lang.extend(dojo.widget.Widget, {
+	// base widget properties
+	parent: null,
+	// obviously, top-level and modal widgets should set these appropriately
+	isTopLevel:  false,
+	isModal: false,
+
+	isEnabled: true,
+	isHidden: false,
+	isContainer: false, // can we contain other widgets?
+	widgetId: "",
+	widgetType: "Widget", // used for building generic widgets
+
+	toString: function() {
+		return '[Widget ' + this.widgetType + ', ' + (this.widgetId || 'NO ID') + ']';
+	},
+
+	enable: function(){
+		// should be over-ridden
+		this.isEnabled = true;
+	},
+
+	disable: function(){
+		// should be over-ridden
+		this.isEnabled = false;
+	},
+
+	hide: function(){
+		// should be over-ridden
+		this.isHidden = true;
+	},
+
+	show: function(){
+		// should be over-ridden
+		this.isHidden = false;
+	},
+
+	create: function(args, fragment, parentComp){
+		this.satisfyPropertySets(args, fragment, parentComp);
+		this.mixInProperties(args, fragment, parentComp);
+		this.postMixInProperties(args, fragment, parentComp);
+		dojo.widget.manager.add(this);
+		this.buildRendering(args, fragment, parentComp);
+		this.initialize(args, fragment, parentComp);
+		this.postInitialize(args, fragment, parentComp);
+		this.postCreate(args, fragment, parentComp);
+		return this;
+	},
+
+	destroy: function(finalize){
+		// FIXME: this is woefully incomplete
+		this.uninitialize();
+		this.destroyRendering(finalize);
+		dojo.widget.manager.removeById(this.widgetId);
+	},
+
+	destroyChildren: function(testFunc){
+		testFunc = (!testFunc) ? function(){ return true; } : testFunc;
+		for(var x=0; x<this.children.length; x++){
+			var tc = this.children[x];
+			if((tc)&&(testFunc(tc))){
+				tc.destroy();
+			}
+		}
+		// this.children = [];
+	},
+
+	destroyChildrenOfType: function(type){
+		type = type.toLowerCase();
+		this.destroyChildren(function(item){
+			if(item.widgetType.toLowerCase() == type){
+				return true;
+			}else{
+				return false;
+			}
+		});
+	},
+
+	getChildrenOfType: function(type, recurse){
+		var ret = [];
+		type = type.toLowerCase();
+		for(var x=0; x<this.children.length; x++){
+			if(this.children[x].widgetType.toLowerCase() == type){
+				ret.push(this.children[x]);
+			}
+			if(recurse){
+				ret = ret.concat(this.children[x].getChildrenOfType(type, recurse));
+			}
+		}
+		return ret;
+	},
+
+	satisfyPropertySets: function(args){
+		// dojo.profile.start("satisfyPropertySets");
+		// get the default propsets for our component type
+		/*
+		var typePropSets = []; // FIXME: need to pull these from somewhere!
+		var localPropSets = []; // pull out propsets from the parser's return structure
+
+		// for(var x=0; x<args.length; x++){
+		// }
+
+		for(var x=0; x<typePropSets.length; x++){
+		}
+
+		for(var x=0; x<localPropSets.length; x++){
+		}
+		*/
+		// dojo.profile.end("satisfyPropertySets");
+		
+		return args;
+	},
+
+	mixInProperties: function(args, frag){
+		if((args["fastMixIn"])||(frag["fastMixIn"])){
+			// dojo.profile.start("mixInProperties_fastMixIn");
+			// fast mix in assumes case sensitivity, no type casting, etc...
+			// dojo.lang.mixin(this, args);
+			for(var x in args){
+				this[x] = args[x];
+			}
+			// dojo.profile.end("mixInProperties_fastMixIn");
+			return;
+		}
+		// dojo.profile.start("mixInProperties");
+		/*
+		 * the actual mix-in code attempts to do some type-assignment based on
+		 * PRE-EXISTING properties of the "this" object. When a named property
+		 * of a propset is located, it is first tested to make sure that the
+		 * current object already "has one". Properties which are undefined in
+		 * the base widget are NOT settable here. The next step is to try to
+		 * determine type of the pre-existing property. If it's a string, the
+		 * property value is simply assigned. If a function, the property is
+		 * replaced with a "new Function()" declaration. If an Array, the
+		 * system attempts to split the string value on ";" chars, and no
+		 * further processing is attempted (conversion of array elements to a
+		 * integers, for instance). If the property value is an Object
+		 * (testObj.constructor === Object), the property is split first on ";"
+		 * chars, secondly on ":" chars, and the resulting key/value pairs are
+		 * assigned to an object in a map style. The onus is on the property
+		 * user to ensure that all property values are converted to the
+		 * expected type before usage.
+		 */
+
+		var undef;
+
+		// NOTE: we cannot assume that the passed properties are case-correct
+		// (esp due to some browser bugs). Therefore, we attempt to locate
+		// properties for assignment regardless of case. This may cause
+		// problematic assignments and bugs in the future and will need to be
+		// documented with big bright neon lights.
+
+		// FIXME: fails miserably if a mixin property has a default value of null in 
+		// a widget
+
+		// NOTE: caching lower-cased args in the prototype is only 
+		// acceptable if the properties are invariant.
+		// if we have a name-cache, get it
+		var lcArgs = dojo.widget.lcArgsCache[this.widgetType];
+		if ( lcArgs == null ){
+			// build a lower-case property name cache if we don't have one
+			lcArgs = {};
+			for(var y in this){
+				lcArgs[((new String(y)).toLowerCase())] = y;
+			}
+			dojo.widget.lcArgsCache[this.widgetType] = lcArgs;
+		}
+		var visited = {};
+		for(var x in args){
+			if(!this[x]){ // check the cache for properties
+				var y = lcArgs[(new String(x)).toLowerCase()];
+				if(y){
+					args[y] = args[x];
+					x = y; 
+				}
+			}
+			if(visited[x]){ continue; }
+			visited[x] = true;
+			if((typeof this[x]) != (typeof undef)){
+				if(typeof args[x] != "string"){
+					this[x] = args[x];
+				}else{
+					if(dojo.lang.isString(this[x])){
+						this[x] = args[x];
+					}else if(dojo.lang.isNumber(this[x])){
+						this[x] = new Number(args[x]); // FIXME: what if NaN is the result?
+					}else if(dojo.lang.isBoolean(this[x])){
+						this[x] = (args[x].toLowerCase()=="false") ? false : true;
+					}else if(dojo.lang.isFunction(this[x])){
+
+						// FIXME: need to determine if always over-writing instead
+						// of attaching here is appropriate. I suspect that we
+						// might want to only allow attaching w/ action items.
+						
+						// RAR, 1/19/05: I'm going to attach instead of
+						// over-write here. Perhaps function objects could have
+						// some sort of flag set on them? Or mixed-into objects
+						// could have some list of non-mutable properties
+						// (although I'm not sure how that would alleviate this
+						// particular problem)? 
+
+						// this[x] = new Function(args[x]);
+
+						// after an IRC discussion last week, it was decided
+						// that these event handlers should execute in the
+						// context of the widget, so that the "this" pointer
+						// takes correctly.
+						var tn = dojo.event.nameAnonFunc(new Function(args[x]), this);
+						dojo.event.connect(this, x, this, tn);
+					}else if(dojo.lang.isArray(this[x])){ // typeof [] == "object"
+						this[x] = args[x].split(";");
+					} else if (this[x] instanceof Date) {
+						this[x] = new Date(Number(args[x])); // assume timestamp
+					}else if(typeof this[x] == "object"){ 
+						// FIXME: should we be allowing extension here to handle
+						// other object types intelligently?
+
+						// FIXME: unlike all other types, we do not replace the
+						// object with a new one here. Should we change that?
+						var pairs = args[x].split(";");
+						for(var y=0; y<pairs.length; y++){
+							var si = pairs[y].indexOf(":");
+							if((si != -1)&&(pairs[y].length>si)){
+								this[x][dojo.string.trim(pairs[y].substr(0, si))] = pairs[y].substr(si+1);
+							}
+						}
+					}else{
+						// the default is straight-up string assignment. When would
+						// we ever hit this?
+						this[x] = args[x];
+					}
+				}
+			}else{
+				// collect any extra 'non mixed in' args
+				this.extraArgs[x] = args[x];
+			}
+		}
+		// dojo.profile.end("mixInProperties");
+	},
+	
+	postMixInProperties: function(){
+	},
+
+	initialize: function(args, frag){
+		// dj_unimplemented("dojo.widget.Widget.initialize");
+		return false;
+	},
+
+	postInitialize: function(args, frag){
+		return false;
+	},
+
+	postCreate: function(args, frag){
+		return false;
+	},
+
+	uninitialize: function(){
+		// dj_unimplemented("dojo.widget.Widget.uninitialize");
+		return false;
+	},
+
+	buildRendering: function(){
+		// SUBCLASSES MUST IMPLEMENT
+		dj_unimplemented("dojo.widget.Widget.buildRendering");
+		return false;
+	},
+
+	destroyRendering: function(){
+		// SUBCLASSES MUST IMPLEMENT
+		dj_unimplemented("dojo.widget.Widget.destroyRendering");
+		return false;
+	},
+
+	cleanUp: function(){
+		// SUBCLASSES MUST IMPLEMENT
+		dj_unimplemented("dojo.widget.Widget.cleanUp");
+		return false;
+	},
+
+	addedTo: function(parent){
+		// this is just a signal that can be caught
+	},
+
+	addChild: function(child){
+		// SUBCLASSES MUST IMPLEMENT
+		dj_unimplemented("dojo.widget.Widget.addChild");
+		return false;
+	},
+
+	addChildAtIndex: function(child, index){
+		// SUBCLASSES MUST IMPLEMENT
+		dj_unimplemented("dojo.widget.Widget.addChildAtIndex");
+		return false;
+	},
+
+	removeChild: function(childRef){
+		// SUBCLASSES MUST IMPLEMENT
+		dj_unimplemented("dojo.widget.Widget.removeChild");
+		return false;
+	},
+
+	removeChildAtIndex: function(index){
+		// SUBCLASSES MUST IMPLEMENT
+		dj_unimplemented("dojo.widget.Widget.removeChildAtIndex");
+		return false;
+	},
+
+	resize: function(width, height){
+		// both width and height may be set as percentages. The setWidth and
+		// setHeight  functions attempt to determine if the passed param is
+		// specified in percentage or native units. Integers without a
+		// measurement are assumed to be in the native unit of measure.
+		this.setWidth(width);
+		this.setHeight(height);
+	},
+
+	setWidth: function(width){
+		if((typeof width == "string")&&(width.substr(-1) == "%")){
+			this.setPercentageWidth(width);
+		}else{
+			this.setNativeWidth(width);
+		}
+	},
+
+	setHeight: function(height){
+		if((typeof height == "string")&&(height.substr(-1) == "%")){
+			this.setPercentageHeight(height);
+		}else{
+			this.setNativeHeight(height);
+		}
+	},
+
+	setPercentageHeight: function(height){
+		// SUBCLASSES MUST IMPLEMENT
+		return false;
+	},
+
+	setNativeHeight: function(height){
+		// SUBCLASSES MUST IMPLEMENT
+		return false;
+	},
+
+	setPercentageWidth: function(width){
+		// SUBCLASSES MUST IMPLEMENT
+		return false;
+	},
+
+	setNativeWidth: function(width){
+		// SUBCLASSES MUST IMPLEMENT
+		return false;
+	}
+});
+
+// Lower case name cache: listing of the lower case elements in each widget.
+// We can't store the lcArgs in the widget itself because if B subclasses A,
+// then B.prototype.lcArgs might return A.prototype.lcArgs, which is not what we
+// want
+dojo.widget.lcArgsCache = {};
+
+// TODO: should have a more general way to add tags or tag libraries?
+// TODO: need a default tags class to inherit from for things like getting propertySets
+// TODO: parse properties/propertySets into component attributes
+// TODO: parse subcomponents
+// TODO: copy/clone raw markup fragments/nodes as appropriate
+dojo.widget.tags = {};
+dojo.widget.tags.addParseTreeHandler = function(type){
+	var ltype = type.toLowerCase();
+	this[ltype] = function(fragment, widgetParser, parentComp, insertionIndex){ 
+		return dojo.widget.buildWidgetFromParseTree(ltype, fragment, widgetParser, parentComp, insertionIndex);
+	}
+}
+dojo.widget.tags.addParseTreeHandler("dojo:widget");
+
+dojo.widget.tags["dojo:propertyset"] = function(fragment, widgetParser, parentComp){
+	// FIXME: Is this needed?
+	// FIXME: Not sure that this parses into the structure that I want it to parse into...
+	// FIXME: add support for nested propertySets
+	var properties = widgetParser.parseProperties(fragment["dojo:propertyset"]);
+}
+
+// FIXME: need to add the <dojo:connect />
+dojo.widget.tags["dojo:connect"] = function(fragment, widgetParser, parentComp){
+	var properties = widgetParser.parseProperties(fragment["dojo:connect"]);
+}
+
+dojo.widget.buildWidgetFromParseTree = function(type, frag, parser, parentComp, insertionIndex){
+	var localProperties = {};
+	var stype = type.split(":");
+	stype = (stype.length == 2) ? stype[1] : type;
+	// outputObjectInfo(frag["dojo:"+stype]);
+	// FIXME: we don't seem to be doing anything with this!
+	// var propertySets = parser.getPropertySets(frag);
+	var localProperties = parser.parseProperties(frag["dojo:"+stype]);
+	// var tic = new Date();
+	var twidget = dojo.widget.manager.getImplementation(stype);
+	if(!twidget){
+		throw new Error("cannot find \"" + stype + "\" widget");
+	}else if (!twidget.create){
+		throw new Error("\"" + stype + "\" widget object does not appear to implement *Widget");
+	}
+	localProperties["dojoinsertionindex"] = insertionIndex;
+	// FIXME: we loose no less than 5ms in construction!
+	var ret = twidget.create(localProperties, frag, parentComp);
+	// dojo.debug(new Date() - tic);
+	return ret;
+}

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Wizard.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Wizard.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Wizard.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/Wizard.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,199 @@
+dojo.provide("dojo.widget.Wizard");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlLayoutPane");
+dojo.require("dojo.event.*");
+dojo.require("dojo.html");
+dojo.require("dojo.style");
+
+//////////////////////////////////////////
+// Wizard -- a set of panels
+//////////////////////////////////////////
+dojo.widget.Wizard = function() {
+	dojo.widget.HtmlLayoutPane.call(this);
+}
+dojo.inherits(dojo.widget.Wizard, dojo.widget.HtmlLayoutPane);
+
+dojo.lang.extend(dojo.widget.Wizard, {
+
+	widgetType: "Wizard",
+
+	labelPosition: "top",
+
+	templatePath: dojo.uri.dojoUri("src/widget/templates/Wizard.html"),
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/Wizard.css"),
+
+	selected: null,		// currently selected panel
+	wizardNode: null, // the outer wizard node
+	wizardPanelContainerNode: null, // the container for the panels
+	wizardControlContainerNode: null, // the container for the wizard controls
+	previousButton: null, // the previous button
+	nextButton: null, // the next button
+	cancelButton: null, // the cancel button
+	doneButton: null, // the done button
+	nextButtonLabel: "next",
+	previousButtonLabel: "previous",
+	cancelButtonLabel: "cancel",
+	doneButtonLabel: "done",
+	cancelFunction : "",
+
+	hideDisabledButtons: false,
+
+	fillInTemplate: function(args, frag){
+		dojo.event.connect(this.nextButton, "onclick", this, "nextPanel");
+		dojo.event.connect(this.previousButton, "onclick", this, "previousPanel");
+		if (this.cancelFunction){
+			dojo.event.connect(this.cancelButton, "onclick", this.cancelFunction);
+		}else{
+			this.cancelButton.style.display = "none";
+		}
+		dojo.event.connect(this.doneButton, "onclick", this, "done");
+		this.nextButton.value = this.nextButtonLabel;
+		this.previousButton.value = this.previousButtonLabel;
+		this.cancelButton.value = this.cancelButtonLabel;
+		this.doneButton.value = this.doneButtonLabel;
+	},
+
+	checkButtons: function(){
+		var lastStep = !this.hasNextPanel();
+		this.nextButton.disabled = lastStep;
+		this.setButtonClass(this.nextButton);
+		if(this.selected.doneFunction){
+			this.doneButton.style.display = "";
+			// hide the next button if this is the last one and we have a done function
+			if(lastStep){
+				this.nextButton.style.display = "none";
+			}
+		}else{
+			this.doneButton.style.display = "none";
+		}
+		this.previousButton.disabled = ((!this.hasPreviousPanel()) || (!this.selected.canGoBack));
+		this.setButtonClass(this.previousButton);
+	},
+
+	setButtonClass: function(button){
+		if(!this.hideDisabledButtons){
+			button.style.display = "";
+			dojo.html.setClass(button, button.disabled ? "WizardButtonDisabled" : "WizardButton");
+		}else{
+			button.style.display = button.disabled ? "none" : "";
+		}
+	},
+
+	registerChild: function(panel, insertionIndex){
+		dojo.widget.Wizard.superclass.registerChild.call(this, panel, insertionIndex);
+		this.wizardPanelContainerNode.appendChild(panel.domNode);
+		panel.hide();
+
+		if(!this.selected){
+			this.onSelected(panel);
+		}
+		this.checkButtons();
+	},
+
+	onSelected: function(panel){
+		// Deselect old panel and select new one
+		if(this.selected ){
+			if (this.selected.checkPass()) {
+				this.selected.hide();
+			} else {
+				return;
+			}
+		}
+		panel.show();
+		this.selected = panel;
+	},
+
+	getPanels: function() {
+		return this.getChildrenOfType("WizardPane", false);
+	},
+
+	selectedIndex: function() {
+		if (this.selected) {
+			return dojo.lang.indexOf(this.getPanels(), this.selected);
+		}
+		return -1;
+	},
+
+	nextPanel: function() {
+		var selectedIndex = this.selectedIndex();
+		if ( selectedIndex > -1 ) {
+			var childPanels = this.getPanels();
+			if (childPanels[selectedIndex + 1]) {
+				this.onSelected(childPanels[selectedIndex + 1]);
+			}
+		}
+		this.checkButtons();
+	},
+
+	previousPanel: function() {
+		var selectedIndex = this.selectedIndex();
+		if ( selectedIndex > -1 ) {
+			var childPanels = this.getPanels();
+			if (childPanels[selectedIndex - 1]) {
+				this.onSelected(childPanels[selectedIndex - 1]);
+			}
+		}
+		this.checkButtons();
+	},
+
+	hasNextPanel: function() {
+		var selectedIndex = this.selectedIndex();
+		return (selectedIndex < (this.getPanels().length - 1));
+	},
+
+	hasPreviousPanel: function() {
+		var selectedIndex = this.selectedIndex();
+		return (selectedIndex > 0);
+	},
+
+	done: function() {
+		this.selected.done();
+	}
+});
+dojo.widget.tags.addParseTreeHandler("dojo:Wizard");
+
+//////////////////////////////////////////
+// WizardPane -- a panel in a wizard
+//////////////////////////////////////////
+dojo.widget.WizardPane = function() {
+	dojo.widget.HtmlLayoutPane.call(this);
+}
+dojo.inherits(dojo.widget.WizardPane, dojo.widget.HtmlLayoutPane);
+
+dojo.lang.extend(dojo.widget.WizardPane, {
+	widgetType: "WizardPane",
+
+	canGoBack: true,
+
+	passFunction: "",
+	doneFunction: "",
+
+	fillInTemplate: function(args, frag) {
+		if (this.passFunction) {
+			this.passFunction = dj_global[this.passFunction];
+		}
+		if (this.doneFunction) {
+			this.doneFunction = dj_global[this.doneFunction];
+		}
+	},
+
+	checkPass: function() {
+		if (this.passFunction && dojo.lang.isFunction(this.passFunction)) {
+			var failMessage = this.passFunction();
+			if (failMessage) {
+				alert(failMessage);
+				return false;
+			}
+		}
+		return true;
+	},
+
+	done: function() {
+		if (this.doneFunction && dojo.lang.isFunction(this.doneFunction)) {
+			this.doneFunction();
+		}
+	}
+});
+
+dojo.widget.tags.addParseTreeHandler("dojo:WizardPane");

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/__package__.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/__package__.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/__package__.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/__package__.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,10 @@
+dojo.hostenv.conditionalLoadModule({
+	common: ["dojo.xml.Parse", 
+			 "dojo.widget.Widget", 
+			 "dojo.widget.Parse", 
+			 "dojo.widget.Manager"],
+	browser: ["dojo.widget.DomWidget",
+			  "dojo.widget.HtmlWidget"],
+	svg: 	 ["dojo.widget.SvgWidget"]
+});
+dojo.hostenv.moduleLoaded("dojo.widget.*");

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/Button.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/Button.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/Button.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/Button.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,50 @@
+dojo.provide("dojo.widget.html.Button");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.Button");
+
+dojo.widget.html.Button = function(){
+	// mix in the button properties
+	dojo.widget.Button.call(this);
+	dojo.widget.HtmlWidget.call(this);
+}
+dojo.inherits(dojo.widget.html.Button, dojo.widget.HtmlWidget);
+dojo.lang.extend(dojo.widget.html.Button, {
+
+	templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlButtonTemplate.html"),
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlButtonTemplate.css"),
+
+	label: "undefined",
+	labelNode: null,
+	containerNode: null,
+
+	postCreate: function(args, frag){
+		this.labelNode = this.containerNode;
+		if(this.label != "undefined"){
+			this.domNode.appendChild(document.createTextNode(this.label));
+		}
+	},
+	
+	onMouseOver: function(e){
+		dojo.html.addClass(this.domNode, "dojoButtonHover");
+		dojo.html.removeClass(this.domNode, "dojoButtonNoHover");
+	},
+	
+	onMouseOut: function(e){
+		dojo.html.removeClass(this.domNode, "dojoButtonHover");
+		dojo.html.addClass(this.domNode, "dojoButtonNoHover");
+	},
+
+	// By default, when I am clicked, click the item (link) inside of me.
+	// By default, a button is a disguised link.
+	// Todo: support actual submit and reset buttons.
+	onClick: function (e) {
+		var child = dojo.dom.getFirstChildElement(this.domNode);
+		if(child){
+			if(child.click){
+				child.click();
+			}else if(child.href){
+				location.href = child.href;
+			}
+		}
+	}
+});

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/Button2.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/Button2.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/Button2.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/Button2.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,270 @@
+dojo.provide("dojo.widget.html.Button2");
+dojo.require("dojo.lang");
+dojo.require("dojo.html");
+dojo.require("dojo.style");
+
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.Button2");
+
+dojo.widget.html.Button2 = function(){
+	// mix in the button properties
+	dojo.widget.Button2.call(this);
+	dojo.widget.HtmlWidget.call(this);
+}
+dojo.inherits(dojo.widget.html.Button2, dojo.widget.HtmlWidget);
+dojo.lang.extend(dojo.widget.html.Button2, {
+
+	templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlButton2Template.html"),
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlButton2Template.css"),
+
+	// Constructor arguments
+	caption: "",
+	disabled: false,
+	onClick: function(){ },
+	
+	// button images
+	inactiveImg: "src/widget/templates/images/pill-button-blue_benji-",
+	activeImg: "src/widget/templates/images/pill-button-seagreen_benji-",
+	pressedImg: "src/widget/templates/images/pill-button-purple_benji-",
+	disabledImg: "src/widget/templates/images/pill-button-gray_benji-",
+
+	// attach points
+	containerNode: null,
+	leftImage: null,
+	centerImage: null,
+	rightImage: null,
+
+	fillInTemplate: function(args, frag){
+		if(this.caption != ""){
+			this.containerNode.appendChild(document.createTextNode(this.caption));
+		}
+		dojo.html.disableSelection(this.containerNode);
+		if ( this.disabled ) {
+			dojo.html.prependClass(this.domNode, "dojoButtonDisabled");
+		}
+		
+		// after the browser has had a little time to calculate the size needed
+		// for the button contents, size the button
+		dojo.lang.setTimeout(this, this.sizeMyself, 0);
+	},
+
+	sizeMyself: function(e){
+		this.height = dojo.style.getOuterHeight(this.containerNode);
+		this.containerWidth = dojo.style.getOuterWidth(this.containerNode);
+		var endWidth= this.height/3;
+
+		this.containerNode.style.left=endWidth+"px";
+
+		this.leftImage.height = this.rightImage.height = this.centerImage.height = this.height;
+		this.leftImage.width = this.rightImage.width = endWidth+1;
+		this.centerImage.width = this.containerWidth;
+		this.centerImage.style.left=endWidth+"px";
+		this._setImage(this.disabled ? this.disabledImg : this.inactiveImg);
+			
+		this.domNode.style.height=this.height + "px";
+		this.domNode.style.width= (this.containerWidth+2*endWidth) + "px";
+	},
+
+	onMouseOver: function(e){
+		if( this.disabled ){ return; }
+		dojo.html.prependClass(this.domNode, "dojoButtonHover");
+		this._setImage(this.activeImg);
+	},
+
+	onMouseDown: function(e){
+		if( this.disabled ){ return; }
+		dojo.html.prependClass(this.domNode, "dojoButtonDepressed");
+		dojo.html.removeClass(this.domNode, "dojoButtonHover");
+		this._setImage(this.pressedImg);
+	},
+	onMouseUp: function(e){
+		if( this.disabled ){ return; }
+		dojo.html.prependClass(this.domNode, "dojoButtonHover");
+		dojo.html.removeClass(this.domNode, "dojoButtonDepressed");
+		this._setImage(this.activeImg);
+	},
+
+	onMouseOut: function(e){
+		if( this.disabled ){ return; }
+		dojo.html.removeClass(this.domNode, "dojoButtonHover");
+		this._setImage(this.inactiveImg);
+	},
+
+	buttonClick: function(e){
+		if( !this.disabled && this.onClick ) { this.onClick(e); }
+	},
+
+	_setImage: function(prefix){
+		this.leftImage.src=dojo.uri.dojoUri(prefix + "l.gif");
+		this.centerImage.src=dojo.uri.dojoUri(prefix + "c.gif");
+		this.rightImage.src=dojo.uri.dojoUri(prefix + "r.gif");
+	},
+	
+	_toggleMenu: function(menuId){
+		var menu = dojo.widget.getWidgetById(menuId);
+		if ( !menu ) { return; }
+
+		if ( menu.open && !menu.isShowing) {
+			var x = dojo.style.getAbsoluteX(this.domNode);
+			var y = dojo.style.getAbsoluteY(this.domNode) + this.height;
+			menu.open(x, y, null, this.domNode);
+		} else {
+			menu.toggle();
+		}
+	}
+});
+
+
+/**** DropDownButton - push the button and a menu shows up *****/
+dojo.widget.html.DropDownButton2 = function(){
+	// call constructors of superclasses
+	dojo.widget.html.Button2.call(this);
+	dojo.widget.DropDownButton2.call(this);
+}
+dojo.inherits(dojo.widget.html.DropDownButton2, dojo.widget.html.Button2);
+dojo.lang.extend(dojo.widget.html.DropDownButton2, {
+	// constructor arguments
+	menuId: '',
+
+	downArrow: "src/widget/templates/images/whiteDownArrow.gif",
+	disabledDownArrow: "src/widget/templates/images/whiteDownArrow.gif",
+
+	fillInTemplate: function(args, frag){
+		dojo.widget.html.DropDownButton2.superclass.fillInTemplate.call(this, args, frag);
+
+		// draw the arrow
+		var arrow = document.createElement("img");
+		arrow.src = dojo.uri.dojoUri(this.disabled ? this.disabledDownArrow : this.downArrow);
+		dojo.html.setClass(arrow, "downArrow");
+		this.containerNode.appendChild(arrow);
+	},
+
+	onClick: function (e){
+		if( this.disabled ){ return; }
+		this._toggleMenu(this.menuId);
+	}
+});
+
+/**** ComboButton - left side is normal button, right side shows menu *****/
+dojo.widget.html.ComboButton2 = function(){
+	// call constructors of superclasses
+	dojo.widget.html.Button2.call(this);
+	dojo.widget.ComboButton2.call(this);
+}
+dojo.inherits(dojo.widget.html.ComboButton2, dojo.widget.html.Button2);
+dojo.lang.extend(dojo.widget.html.ComboButton2, {
+
+	templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlComboButton2Template.html"),
+
+	// Constructor arguments
+	menuId: '',
+	
+	// attach points
+	leftPart: null,
+	rightPart: null,
+	arrowBackgroundImage: null,
+
+	// constants
+	splitWidth: 1,		// pixels between left&right part of button
+	arrowWidth: 10,		// width of segment holding down arrow
+
+	sizeMyself: function(e){
+		this.height = dojo.style.getOuterHeight(this.containerNode);
+		this.containerWidth = dojo.style.getOuterWidth(this.containerNode);
+		var endWidth= this.height/3;
+
+		// left part
+		this.leftImage.height = this.rightImage.height = this.centerImage.height = 
+			this.arrowBackgroundImage.height = this.height;
+		this.leftImage.width = endWidth+1;
+		this.centerImage.width = this.containerWidth;
+		this.leftPart.style.height = this.height + "px";
+		this.leftPart.style.width = endWidth + this.containerWidth + "px";
+		this._setImageL(this.disabled ? this.disabledImg : this.inactiveImg);
+
+		// right part
+		this.arrowBackgroundImage.width=this.arrowWidth;
+		this.rightImage.width = endWidth+1;
+		this.rightPart.style.height = this.height + "px";
+		this.rightPart.style.width = this.arrowWidth + endWidth + "px";
+		this._setImageR(this.disabled ? this.disabledImg : this.inactiveImg);
+
+		// outer container
+		this.domNode.style.height=this.height + "px";
+		var totalWidth = this.containerWidth+this.splitWidth+this.arrowWidth+2*endWidth;
+		this.domNode.style.width= totalWidth + "px";
+	},
+
+	/** functions on left part of button**/
+	leftOver: function(e){
+		if( this.disabled ){ return; }
+		dojo.html.prependClass(this.leftPart, "dojoButtonHover");
+		this._setImageL(this.activeImg);
+	},
+
+	leftDown: function(e){
+		if( this.disabled ){ return; }
+		dojo.html.prependClass(this.leftPart, "dojoButtonDepressed");
+		dojo.html.removeClass(this.leftPart, "dojoButtonHover");
+		this._setImageL(this.pressedImg);
+	},
+	leftUp: function(e){
+		if( this.disabled ){ return; }
+		dojo.html.prependClass(this.leftPart, "dojoButtonHover");
+		dojo.html.removeClass(this.leftPart, "dojoButtonDepressed");
+		this._setImageL(this.activeImg);
+	},
+
+	leftOut: function(e){
+		if( this.disabled ){ return; }
+		dojo.html.removeClass(this.leftPart, "dojoButtonHover");
+		this._setImageL(this.inactiveImg);
+	},
+
+	leftClick: function(e){
+		if ( !this.disabled && this.onClick ) {
+			this.onClick(e);
+		}
+	},
+
+	_setImageL: function(prefix){
+		this.leftImage.src=dojo.uri.dojoUri(prefix + "l.gif");
+		this.centerImage.src=dojo.uri.dojoUri(prefix + "c.gif");
+	},
+
+	/*** functions on right part of button ***/
+	rightOver: function(e){
+		if( this.disabled ){ return; }
+		dojo.html.prependClass(this.rightPart, "dojoButtonHover");
+		this._setImageR(this.activeImg);
+	},
+
+	rightDown: function(e){
+		if( this.disabled ){ return; }
+		dojo.html.prependClass(this.rightPart, "dojoButtonDepressed");
+		dojo.html.removeClass(this.rightPart, "dojoButtonHover");
+		this._setImageR(this.pressedImg);
+	},
+	rightUp: function(e){
+		if( this.disabled ){ return; }
+		dojo.html.prependClass(this.rightPart, "dojoButtonHover");
+		dojo.html.removeClass(this.rightPart, "dojoButtonDepressed");
+		this._setImageR(this.activeImg);
+	},
+
+	rightOut: function(e){
+		if( this.disabled ){ return; }
+		dojo.html.removeClass(this.rightPart, "dojoButtonHover");
+		this._setImageR(this.inactiveImg);
+	},
+
+	rightClick: function(e){
+		if( this.disabled ){ return; }
+		this._toggleMenu(this.menuId);
+	},
+
+	_setImageR: function(prefix){
+		this.arrowBackgroundImage.src=dojo.uri.dojoUri(prefix + "c.gif");
+		this.rightImage.src=dojo.uri.dojoUri(prefix + "r.gif");
+	}
+});

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/ComboBox.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/ComboBox.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/ComboBox.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/ComboBox.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,392 @@
+dojo.provide("dojo.widget.html.ComboBox");
+dojo.require("dojo.widget.ComboBox");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.io.*");
+dojo.require("dojo.fx.*");
+dojo.require("dojo.dom");
+dojo.require("dojo.html");
+dojo.require("dojo.string");
+dojo.require("dojo.widget.html.stabile");
+
+dojo.widget.html.ComboBox = function(){
+	dojo.widget.ComboBox.call(this);
+	dojo.widget.HtmlWidget.call(this);
+
+	this.autoComplete = true;
+	this.formInputName = "";
+	this.name = ""; // clone in the name from the DOM node
+	this.textInputNode = null;
+	this.comboBoxValue = null;
+	this.comboBoxSelectionValue = null;
+	this.optionsListNode = null;
+	this.downArrowNode = null;
+	this.cbTableNode = null;
+	this.searchTimer = null;
+	this.searchDelay = 100;
+	this.timeoutWrapperName = null;
+	this.dataUrl = "";
+	// mode can also be "remote" for JSON-returning live search or "html" for
+	// dumber live search
+	this.mode = "local"; 
+	this.selectedResult = null;
+	this._highlighted_option = null;
+	this._prev_key_backspace = false;
+	this._prev_key_esc = false;
+	this._result_list_open = false;
+}
+
+dojo.inherits(dojo.widget.html.ComboBox, dojo.widget.HtmlWidget);
+
+// copied from superclass since we can't really over-ride via prototype
+dojo.lang.extend(dojo.widget.html.ComboBox, dojo.widget.ComboBox.defaults);
+
+dojo.lang.extend(dojo.widget.html.ComboBox, {
+
+
+	templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlComboBox.html"),
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlComboBox.css"),
+
+	setValue: function(value) {
+		this.comboBoxValue.value = this.textInputNode.value = value;
+		dojo.widget.html.stabile.setState(this.widgetId, this.getState(), true);
+	},
+
+	getValue: function() {
+		return this.comboBoxValue.value;
+	},
+
+	getState: function() {
+		return {value: this.getValue()};
+	},
+
+	setState: function(state) {
+        	this.setValue(state.value);
+	},
+
+
+	getCaretPos: function(element){
+		// FIXME: we need to figure this out for Konq/Safari!
+		if(dojo.render.html.mozilla){
+			// FIXME: this is totally borked on Moz < 1.3. Any recourse?
+			return element.selectionStart;
+		}else if(dojo.render.html.ie){
+			// in the case of a mouse click in a popup being handled,
+			// then the document.selection is not the textarea, but the popup
+			// var r = document.selection.createRange();
+			// hack to get IE 6 to play nice. What a POS browser.
+			// var tr = r.duplicate();
+			var tr = document.selection.createRange().duplicate();
+			// var ntr = document.selection.createRange().duplicate();
+			var ntr = element.createTextRange();
+			// FIXME: this seems to work but I'm getting some execptions on reverse-tab
+			tr.move("character",0);
+			ntr.move("character",0);
+			/*
+			try{
+				ntr.moveToElementText(element);
+			}catch(e){ dojo.debug(e); }
+			*/
+			ntr.setEndPoint("EndToEnd", tr);
+			return String(ntr.text).replace(/\r/g,"").length;
+		}
+	},
+
+	setCaretPos: function(element, location){
+		location = parseInt(location);
+		this.setSelectedRange(element, location, location);
+	},
+
+	setSelectedRange: function(element, start, end){
+		if(!end){ end = element.value.length; }
+		// Mozilla
+		// parts borrowed from http://www.faqts.com/knowledge_base/view.phtml/aid/13562/fid/130
+		if(element.setSelectionRange){
+			element.focus();
+			element.setSelectionRange(start, end);
+		}else if(element.createTextRange){ // IE
+			var range = element.createTextRange();
+			with(range){
+				collapse(true);
+				moveEnd('character', end);
+				moveStart('character', start);
+				select();
+			}
+		}else{ //otherwise try the event-creation hack (our own invention)
+			// do we need these?
+			element.value = element.value;
+			element.blur();
+			element.focus();
+			// figure out how far back to go
+			var dist = parseInt(element.value.length)-end;
+			var tchar = String.fromCharCode(37);
+			var tcc = tchar.charCodeAt(0);
+			for(var x = 0; x < dist; x++){
+				var te = document.createEvent("KeyEvents");
+				te.initKeyEvent("keypress", true, true, null, false, false, false, false, tcc, tcc);
+				twe.dispatchEvent(te);
+			}
+		}
+	},
+
+	killEvent: function(evt){
+		evt.preventDefault();
+		evt.stopPropagation();
+	},
+
+	onKeyDown: function(evt){
+	},
+
+	setSelectedValue: function(value){
+		// FIXME, not sure what to do here!
+		this.comboBoxSelectionValue.value = value;
+		this.hideResultList();
+	},
+
+	highlightNextOption: function(){
+		if(this._highlighted_option){
+			dojo.html.removeClass(this._highlighted_option, "cbItemHighlight");
+		}
+		if((!this._highlighted_option)||(!this._highlighted_option.nextSibling)){
+			this._highlighted_option = this.optionsListNode.firstChild;
+		}else{
+			this._highlighted_option = this._highlighted_option.nextSibling;
+		}
+		dojo.html.addClass(this._highlighted_option, "cbItemHighlight");
+	},
+
+	highlightPrevOption: function(){
+		if(this._highlighted_option){
+			dojo.html.removeClass(this._highlighted_option, "cbItemHighlight");
+		}
+		if((!this._highlighted_option)||(!this._highlighted_option.previousSibling)){
+			this._highlighted_option = this.optionsListNode.lastChild;
+		}else{
+			this._highlighted_option = this._highlighted_option.previousSibling;
+		}
+		dojo.html.addClass(this._highlighted_option, "cbItemHighlight");
+	},
+
+	onKeyUp: function(evt){
+		if(evt.keyCode == 27){ // esc is 27
+			this.hideResultList();
+			if(this._prev_key_esc){
+				this.textInputNode.blur();
+				this.selectedResult = null;
+			}
+			this._prev_key_esc = true;
+			return;
+		}else if((evt.keyCode == 32)||(evt.keyCode == 13)){ // space is 32, enter is 13.
+			/*
+			// Cancel the enter key event bubble to avoid submitting the form.
+			if (evt.keyCode == 13) {
+				// FIXME: the does not cancel the form submission.
+				this.killEvent(evt);
+			}
+			*/
+			// If the list is open select the option with the event.
+			if(this._result_list_open){
+				evt = { target: this._highlighted_option };
+				this.selectOption(evt);
+			}else{
+				// Otherwise select the option with out the event.
+				this.selectOption();
+			}
+			return;
+		}else if(evt.keyCode == 40){ // down is 40
+			if(!this._result_list_open){
+				this.startSearchFromInput();
+			}
+			this.highlightNextOption();
+			return;
+		}else if(evt.keyCode == 38){ // up is 38
+			this.highlightPrevOption();
+			return;
+		}else{
+			this.setValue(this.textInputNode.value);
+		}
+
+		// backspace is 8
+		this._prev_key_backspace = (evt.keyCode == 8) ? true : false;
+		this._prev_key_esc = false;
+
+		if(this.searchTimer){
+			clearTimeout(this.searchTimer);
+		}
+		if((this._prev_key_backspace)&&(!this.textInputNode.value.length)){
+			this.hideResultList();
+		}else{
+			var _this = this;
+			if(!this.timeoutWrapperName){
+				this.timeoutWrapperName = dojo.event.nameAnonFunc(function(){
+					_this.startSearchFromInput();
+				}, dj_global);
+			}
+			this.searchTimer = setTimeout(this.timeoutWrapperName+"()", this.searchDelay);
+		}
+	},
+
+	fillInTemplate: function(args, frag){
+		// FIXME: need to get/assign DOM node names for form participation here.
+		this.comboBoxValue.name = this.name;
+		this.comboBoxSelectionValue.name = this.name+"_selected";
+
+		// FIXME: add logic
+		this.dataProvider = new dojo.widget.ComboBoxDataProvider();
+
+		if(!dojo.string.isBlank(this.dataUrl)){
+			if("local" == this.mode){
+				var _this = this;
+				dojo.io.bind({
+					url: this.dataUrl,
+					load: function(type, data, evt){ 
+						if(type=="load"){
+							_this.dataProvider.setData(data);
+						}
+					},
+					mimetype: "text/javascript"
+				});
+			}else if("remote" == this.mode){
+				this.dataProvider = new dojo.widget.incrementalComboBoxDataProvider(this.dataUrl);
+			}
+		}else{
+			// check to see if we can populate the list from <option> elements
+			var node = frag["dojo:"+this.widgetType.toLowerCase()]["nodeRef"];
+			if((node)&&(node.nodeName.toLowerCase() == "select")){
+				// NOTE: we're not handling <optgroup> here yet
+				var opts = node.getElementsByTagName("option");
+				var ol = opts.length;
+				var data = [];
+				for(var x=0; x<ol; x++){
+					data.push([new String(opts[x].innerHTML), new String(opts[x].value)]);
+				}
+				this.dataProvider.setData(data);
+			}
+		}
+	},
+
+	openResultList: function(results){
+		this.clearResultList();
+		if(!results.length){
+			this.hideResultList();
+		}else{
+			this.showResultList();
+		}
+		if(	(this.autoComplete)&&
+			(results.length)&&
+			(!this._prev_key_backspace)&&
+			(this.textInputNode.value.length > 0)){
+			var cpos = this.getCaretPos(this.textInputNode);
+			// only try to extend if we added the last charachter at the end of the input
+			if((cpos+1) >= this.textInputNode.value.length){
+				this.textInputNode.value = results[0][0];
+				// build a new range that has the distance from the earlier
+				// caret position to the end of the first string selected
+				this.setSelectedRange(this.textInputNode, cpos, this.textInputNode.value.length);
+			}
+		}
+
+		var even = true;
+		while(results.length){
+			var tr = results.shift();
+			var td = document.createElement("div");
+			td.appendChild(document.createTextNode(tr[0]));
+			td.setAttribute("resultName", tr[0]);
+			td.setAttribute("resultValue", tr[1]);
+			td.className = "cbItem "+((even) ? "cbItemEven" : "cbItemOdd");
+			even = (!even);
+			this.optionsListNode.appendChild(td);
+		}
+
+		dojo.event.connect(this.optionsListNode, "onclick", this, "selectOption");
+		dojo.event.kwConnect({
+			once: true,
+			srcObj: dojo.html.body(),
+			srcFunc: "onclick", 
+			adviceObj: this, 
+			adviceFunc: "hideResultList"
+		});
+		// dojo.event.connect(dojo.html.body(), "onclick", this, "hideResultList");
+	},
+
+	selectOption: function(evt){
+		if(!evt){
+			evt = { target: this._highlighted_option };
+		}
+
+		if(!dojo.dom.isDescendantOf(evt.target, this.optionsListNode)){
+			return;
+		}
+
+		var tgt = evt.target;
+		while((tgt.nodeType!=1)||(!tgt.getAttribute("resultName"))){
+			tgt = tgt.parentNode;
+			if(tgt === dojo.html.body()){
+				return false;
+			}
+		}
+
+		this.textInputNode.value = tgt.getAttribute("resultName");
+		this.selectedResult = [tgt.getAttribute("resultName"), tgt.getAttribute("resultValue")];
+		this.setValue(tgt.getAttribute("resultName"));
+		this.comboBoxSelectionValue.value = tgt.getAttribute("resultValue");
+		this.hideResultList();
+	},
+
+	clearResultList: function(){
+		var oln = this.optionsListNode;
+		while(oln.firstChild){
+			oln.removeChild(oln.firstChild);
+		}
+	},
+
+	hideResultList: function(){
+		dojo.fx.fadeHide(this.optionsListNode, 200);
+		dojo.event.disconnect(dojo.html.body(), "onclick", this, "hideResultList");
+		this._result_list_open = false;
+		return;
+	},
+
+	showResultList: function(){
+		if(this._result_list_open){ return; }
+		with(this.optionsListNode.style){
+			display = "";
+			// visibility = "hidden";
+			height = "";
+			width = dojo.html.getInnerWidth(this.downArrowNode)+dojo.html.getInnerWidth(this.textInputNode)+"px";
+			if(dojo.render.html.khtml){
+				marginTop = dojo.html.totalOffsetTop(this.optionsListNode.parentNode)+"px";
+			/*
+				left = dojo.html.totalOffsetLeft(this.optionsListNode.parentNode)+3+"px";
+				zIndex = "1000";
+				position = "relative";
+			*/
+			}
+		}
+		dojo.html.setOpacity(this.optionsListNode, 0);
+		dojo.fx.fadeIn(this.optionsListNode, 200);
+		this._result_list_open = true;
+		return;
+	},
+
+	handleArrowClick: function(){
+		if(this._result_list_open){
+			this.hideResultList();
+		}else{
+			this.startSearchFromInput();
+		}
+	},
+
+	startSearchFromInput: function(){
+		this.startSearch(this.textInputNode.value);
+	},
+
+	postCreate: function(){
+		dojo.event.connect(this, "startSearch", this.dataProvider, "startSearch");
+		dojo.event.connect(this.dataProvider, "provideSearchResults", this, "openResultList");
+		var s = dojo.widget.html.stabile.getState(this.widgetId);
+		if (s) {
+			this.setState(s);
+		}
+	}
+
+});

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/ContextMenu.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/ContextMenu.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/ContextMenu.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/ContextMenu.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,156 @@
+dojo.provide("dojo.widget.html.ContextMenu");
+dojo.require("dojo.html");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.ContextMenu");
+dojo.require("dojo.lang");
+
+dojo.widget.html.ContextMenu = function(){
+	dojo.widget.ContextMenu.call(this);
+	dojo.widget.HtmlWidget.call(this);
+
+	this.isShowing = 0;
+	this.templatePath = dojo.uri.dojoUri("src/widget/templates/HtmlContextMenuTemplate.html");
+	this.templateCssPath = dojo.uri.dojoUri("src/widget/templates/Menu.css");
+
+	this.targetNodeIds = []; // fill this with nodeIds upon widget creation and it only responds to those nodes
+
+	// default event detection method 
+	var eventType = "oncontextmenu"; 
+
+	var doc = document.documentElement  || dojo.html.body(); 
+
+	var _blockHide = false; 
+
+	this.fillInTemplate = function(args, frag){
+
+		var func = "onShow";
+		var attached = false;
+
+		// connect with rightclick if oncontextmenu is not around
+		// NOTE: It would be very nice to have a dojo.event.browser.supportsEvent here
+		// NOTE: Opera does not have rightclick events, it is listed here only because
+		//     it bails out when connecting with oncontextmenu event
+
+		if((dojo.render.html.khtml && !dojo.render.html.safari) || (dojo.render.html.opera)){
+			eventType = "onmousedown";
+			func = "_checkRightClick";
+		}
+
+		// attach event listeners to our selected nodes
+		for(var i=0; i<this.targetNodeIds.length; i++){
+			var node = document.getElementById(this.targetNodeIds[i]);
+			if(node){
+				dojo.event.connect(node, eventType, this, func);
+				attached = true;
+			}else{
+				// remove this nodeId
+				dj_debug("Couldent find "+this.targetNodeIds[i]+", cant do ContextMenu on this node");
+				this.targetNodeIds.splice(i,1);
+			}
+		}
+
+		// if we got attached to a node, hide on all non node contextevents
+		if(attached){ func = "_canHide"; }
+
+		dojo.event.connect(doc, eventType, this, func);
+	}
+
+	this.onShow = function(evt){
+		// if (this.isShowing){ this.onHide(evt); } // propably not needed
+		this.isShowing = 1;
+
+		// if I do this, I cant preventDefault in khtml
+		//evt = dojo.event.browser.fixEvent(evt);
+ 
+		// stop default contextmenu, needed in khtml
+		if (evt.preventDefault){ evt.preventDefault(); }
+
+		// need to light up this one before we check width and height
+		this.domNode.style.left = "-9999px";
+		this.domNode.style.top  = "-9999px";
+		this.domNode.style.display = "block";
+
+		// calculate if menu is going to apear within window
+		// or if its partially out of visable area
+		with(dojo.html){
+
+			var menuW = getInnerWidth(this.domNode);
+			var menuH = getInnerHeight(this.domNode);
+
+			var viewport = getViewportSize();
+			var scrolloffset = getScrollOffset();
+		}
+
+		var minX = viewport[0];
+		var minY = viewport[1];
+
+		var maxX = (viewport[0] + scrolloffset[0]) - menuW;
+		var maxY = (viewport[1] + scrolloffset[1]) - menuH;
+
+		var posX = evt.clientX + scrolloffset[0];
+		var posY = evt.clientY + scrolloffset[1];
+
+		if (posX > maxX){ posX = posX - menuW; }
+		if (posY > maxY){ posY = posY - menuH; }
+
+		this.domNode.style.left = posX + "px";
+		this.domNode.style.top = posY + "px";
+
+
+		// block the onclick that follows this particular right click
+		// not if the eventtrigger is documentElement and always when
+		// we use onmousedown hack
+		_blockHide = (evt.currentTarget!=doc || eventType=='onmousedown');
+
+		//return false; // we propably doesnt need to return false as we dont stop the event as we did before
+	}
+
+	/*
+	* _canHide is meant to block the onHide call that follows the event that triggered
+	* onShow. This is (hopefully) faster that event.connect and event.disconnect every
+	* time the code executes and it makes connecting with onmousedown event possible
+	* and we dont have to stop the event from bubbling further.
+	*
+	* this code is moved into a separete function because it makes it possible for the
+	* user to connect to a onHide event, if anyone would like that.
+	*/
+
+	this._canHide = function(evt){
+		// block the onclick that follows the same event that turn on contextmenu
+		if(_blockHide){
+			// the onclick check is needed to prevent displaying multiple
+			// menus when we have 2 or more contextmenus loaded and are using
+			// the onmousedown hack
+			if(evt.type=='click' || eventType=='oncontextmenu'){
+				_blockHide = false;
+				return;
+			}else{
+				return;
+			}
+		}
+
+		this.onHide(evt);
+	}
+	
+	this.onHide = function(evt){
+		// FIXME: use whatever we use to do more general style setting?
+		this.domNode.style.display = "none";
+		//dojo.event.disconnect(doc, "onclick", this, "onHide");
+		this.isShowing = 0;
+	}
+
+	// callback for rightclicks, needed for browsers that doesnt implement oncontextmenu, konqueror and more? 
+	this._checkRightClick = function(evt){ 
+
+		// for some reason konq comes here even when we are not clicking on the attached nodes 
+		// added check for targetnode 
+		if (evt.button==2 && (this.targetNodeIds.length==0 || (evt.currentTarget.id!="" && dojo.lang.inArray(this.targetNodeIds, evt.currentTarget.id)))){
+
+			return this.onShow(evt);
+		}
+	}
+
+	dojo.event.connect(doc, "onclick", this, "_canHide");
+}
+
+dojo.inherits(dojo.widget.html.ContextMenu, dojo.widget.HtmlWidget);

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/DatePicker.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/DatePicker.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/DatePicker.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/DatePicker.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,327 @@
+dojo.provide("dojo.widget.html.DatePicker");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.DatePicker");
+dojo.require("dojo.event.*");
+dojo.require("dojo.html");
+
+/*
+	Some assumptions:
+	- I'm planning on always showing 42 days at a time, and we can scroll by week,
+	not just by month or year
+	- To get a sense of what month to highlight, I basically initialize on the 
+	first Saturday of each month, since that will be either the first of two or 
+	the second of three months being partially displayed, and then I work forwards 
+	and backwards from that point.
+	Currently, I assume that dates are stored in the RFC 3339 format,
+	because I find it to be most human readable and easy to parse
+	http://www.faqs.org/rfcs/rfc3339.html: 		2005-06-30T08:05:00-07:00
+	FIXME: scroll by week not yet implemented
+*/
+
+
+dojo.widget.html.DatePicker = function(){
+	dojo.widget.DatePicker.call(this);
+	dojo.widget.HtmlWidget.call(this);
+
+	var _this = this;
+	// today's date, JS Date object
+	this.today = "";
+	// selected date, JS Date object
+	this.date = "";
+	// rfc 3339 date
+	this.storedDate = "";
+	// date currently selected in the UI, stored in year, month, date in the format that will be actually displayed
+	this.currentDate = {};
+	// stored in year, month, date in the format that will be actually displayed
+	this.firstSaturday = {};
+	this.classNames = {
+		previous: "previousMonth",
+		current: "currentMonth",
+		next: "nextMonth",
+		currentDate: "currentDate",
+		selectedDate: "selectedItem"
+	}
+
+	this.templatePath =  dojo.uri.dojoUri("src/widget/templates/HtmlDatePicker.html");
+	this.templateCssPath = dojo.uri.dojoUri("src/widget/templates/HtmlDatePicker.css");
+	
+	this.fillInTemplate = function(){
+		this.initData();
+		this.initUI();
+	}
+	
+	this.initData = function() {
+		this.today = new Date();
+		if(this.storedDate && (this.storedDate.split("-").length > 2)) {
+			this.date = this.fromRfcDate(this.storedDate);
+		} else {
+			this.date = this.today;
+		}
+		// calendar math is simplified if time is set to 0
+		this.today.setHours(0);
+		this.date.setHours(0);
+		var month = this.date.getMonth();
+		this.initFirstSaturday(this.date.getMonth().toString(), this.date.getFullYear());
+	}
+	
+	this.setDate = function(rfcDate) {
+		this.storedDate = rfcDate;
+	}
+	
+	this.toRfcDate = function(jsDate) {
+		if(!jsDate) {
+			jsDate = this.today;
+		}
+		var year = jsDate.getFullYear();
+		var month = jsDate.getMonth() + 1;
+		if (month < 10) {
+			month = "0" + month.toString();
+		}
+		var date = jsDate.getDate();
+		if (date < 10) {
+			date = "0" + date.toString();
+		}
+		// because this is a date picker and not a time picker, we treat time 
+		// as zero
+		return year + "-" + month + "-" + date + "T00:00:00+00:00";
+	}
+	
+	this.fromRfcDate = function(rfcDate) {
+		var tempDate = rfcDate.split("-");
+		if(tempDate.length < 3) {
+			return new Date();
+		}
+		// fullYear, month, date
+		return new Date(parseInt(tempDate[0]), (parseInt(tempDate[1], 10) - 1), parseInt(tempDate[2].substr(0,2), 10));
+	}
+	
+	this.initFirstSaturday = function(month, year) {
+		if(!month) {
+			month = this.date.getMonth();
+		}
+		if(!year) {
+			year = this.date.getFullYear();
+		}
+		var firstOfMonth = new Date(year, month, 1);
+		this.firstSaturday.year = year;
+		this.firstSaturday.month = month;
+		this.firstSaturday.date = 7 - firstOfMonth.getDay();
+	}
+	
+	this.initUI = function() {
+		this.selectedIsUsed = false;
+		this.currentIsUsed = false;
+		var currentClassName = "";
+		var previousDate = new Date();
+		var calendarNodes = this.calendarDatesContainerNode.getElementsByTagName("td");
+		var currentCalendarNode;
+		// set hours of date such that there is no chance of rounding error due to 
+		// time change in local time zones
+		previousDate.setHours(8);
+		var nextDate = new Date(this.firstSaturday.year, this.firstSaturday.month, this.firstSaturday.date, 8);
+
+		
+		if(this.firstSaturday.date < 7) {
+			// this means there are days to show from the previous month
+			var dayInWeek = 6;
+			for (var i=this.firstSaturday.date; i>0; i--) {
+				currentCalendarNode = calendarNodes.item(dayInWeek);
+				currentCalendarNode.innerHTML = nextDate.getDate();
+				dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "current"));
+				dayInWeek--;
+				previousDate = nextDate;
+				nextDate = this.incrementDate(nextDate, false);
+			}
+			for(var i=dayInWeek; i>-1; i--) {
+				currentCalendarNode = calendarNodes.item(i);
+				currentCalendarNode.innerHTML = nextDate.getDate();
+				dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "previous"));
+				previousDate = nextDate;
+				nextDate = this.incrementDate(nextDate, false);				
+			}
+		} else {
+			nextDate.setDate(0);
+			for(var i=0; i<7; i++) {
+				currentCalendarNode = calendarNodes.item(i);
+				currentCalendarNode.innerHTML = i + 1;
+				dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "current"));
+				previousDate = nextDate;
+				nextDate = this.incrementDate(nextDate, true);				
+			}
+		}
+		previousDate.setDate(this.firstSaturday.date);
+		previousDate.setMonth(this.firstSaturday.month);
+		previousDate.setFullYear(this.firstSaturday.year);
+		nextDate = this.incrementDate(previousDate, true);
+		var count = 7;
+		currentCalendarNode = calendarNodes.item(count);
+		while((nextDate.getMonth() == previousDate.getMonth()) && (count<42)) {
+			currentCalendarNode.innerHTML = nextDate.getDate();
+			dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "current"));
+			currentCalendarNode = calendarNodes.item(++count);
+			previousDate = nextDate;
+			nextDate = this.incrementDate(nextDate, true);
+		}
+		
+		while(count < 42) {
+			currentCalendarNode.innerHTML = nextDate.getDate();
+			dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "next"));
+			currentCalendarNode = calendarNodes.item(++count);
+			previousDate = nextDate;
+			nextDate = this.incrementDate(nextDate, true);
+		}
+		this.setMonthLabel(this.firstSaturday.month);
+		this.setYearLabels(this.firstSaturday.year);
+	}
+	
+	this.incrementDate = function(date, bool) {
+		// bool: true to increase, false to decrease
+		var time = date.getTime();
+		var increment = 1000 * 60 * 60 * 24;
+		time = (bool) ? (time + increment) : (time - increment);
+		var returnDate = new Date();
+		returnDate.setTime(time);
+		return returnDate;
+	}
+	
+	this.incrementWeek = function(date, bool) {
+		dojo.unimplemented('dojo.widget.html.DatePicker.incrementWeek');
+	}
+
+	this.incrementMonth = function(date, bool) {
+		dojo.unimplemented('dojo.widget.html.DatePicker.incrementMonth');
+	}
+
+	this.incrementYear = function(date, bool) {
+		dojo.unimplemented('dojo.widget.html.DatePicker.incrementYear');
+	}
+
+	this.onIncrementDate = function(evt) {
+		dojo.unimplemented('dojo.widget.html.DatePicker.onIncrementDate');
+	}
+	
+	this.onIncrementWeek = function(evt) {
+		// FIXME: should make a call to incrementWeek when that is implemented
+		evt.stopPropagation();
+		dojo.unimplemented('dojo.widget.html.DatePicker.onIncrementWeek');
+		switch(evt.target) {
+			case this.increaseWeekNode:
+				break;
+			case this.decreaseWeekNode:
+				break;
+		}
+	}
+
+	this.onIncrementMonth = function(evt) {
+		// FIXME: should make a call to incrementMonth when that is implemented
+		evt.stopPropagation();
+		var month = this.firstSaturday.month;
+		var year = this.firstSaturday.year;
+		switch(evt.currentTarget) {
+			case this.increaseMonthNode:
+				if(month < 11) {
+					month++;
+				} else {
+					month = 0;
+					year++;
+					
+					this.setYearLabels(year);
+				}
+				break;
+			case this.decreaseMonthNode:
+				if(month > 0) {
+					month--;
+				} else {
+					month = 11;
+					year--;
+					this.setYearLabels(year);
+				}
+				break;
+			case this.increaseMonthNode.getElementsByTagName("img").item(0):
+				if(month < 11) {
+					month++;
+				} else {
+					month = 0;
+					year++;
+					this.setYearLabels(year);
+				}
+				break;
+			case this.decreaseMonthNode.getElementsByTagName("img").item(0):
+				if(month > 0) {
+					month--;
+				} else {
+					month = 11;
+					year--;
+					this.setYearLabels(year);
+				}
+				break;
+		}
+		this.initFirstSaturday(month.toString(), year);
+		this.initUI();
+	}
+	
+	this.onIncrementYear = function(evt) {
+		// FIXME: should make a call to incrementYear when that is implemented
+		evt.stopPropagation();
+		var year = this.firstSaturday.year;
+		switch(evt.target) {
+			case this.nextYearLabelNode:
+				year++;
+				break;
+			case this.previousYearLabelNode:
+				year--;
+				break;
+		}
+		this.initFirstSaturday(this.firstSaturday.month.toString(), year);
+		this.initUI();
+	}
+
+	this.setMonthLabel = function(monthIndex) {
+		this.monthLabelNode.innerHTML = this.months[monthIndex];
+	}
+	
+	this.setYearLabels = function(year) {
+		this.previousYearLabelNode.innerHTML = year - 1;
+		this.currentYearLabelNode.innerHTML = year;
+		this.nextYearLabelNode.innerHTML = year + 1;
+	}
+	
+	this.getDateClassName = function(date, monthState) {
+		var currentClassName = this.classNames[monthState];
+		if ((!this.selectedIsUsed) && (date.getDate() == this.date.getDate()) && (date.getMonth() == this.date.getMonth()) && (date.getFullYear() == this.date.getFullYear())) {
+			currentClassName = this.classNames.selectedDate + " " + currentClassName;
+			this.selectedIsUsed = 1;
+		}
+		if((!this.currentIsUsed) && (date.getDate() == this.today.getDate()) && (date.getMonth() == this.today.getMonth()) && (date.getFullYear() == this.today.getFullYear())) {
+			currentClassName = currentClassName + " "  + this.classNames.currentDate;
+			this.currentIsUsed = 1;
+		}
+		return currentClassName;
+	}
+
+	this.onClick = function(evt) {
+		dojo.event.browser.stopEvent(evt)
+	}
+	
+	this.onSetDate = function(evt) {
+		dojo.event.browser.stopEvent(evt);
+		this.selectedIsUsed = 0;
+		this.todayIsUsed = 0;
+		var month = this.firstSaturday.month;
+		var year = this.firstSaturday.year;
+		if (dojo.html.hasClass(evt.target, this.classNames["next"])) {
+			month = ++month % 12;
+			// if month is now == 0, add a year
+			year = (month==0) ? ++year : year;
+		} else if (dojo.html.hasClass(evt.target, this.classNames["previous"])) {
+			month = --month % 12;
+			// if month is now == 0, add a year
+			year = (month==11) ? --year : year;
+		}
+		this.date = new Date(year, month, evt.target.innerHTML);
+		this.setDate(this.toRfcDate(this.date));
+		this.initUI();
+	}
+}
+dojo.inherits(dojo.widget.html.DatePicker, dojo.widget.HtmlWidget);

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/DropdownButton.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/DropdownButton.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/DropdownButton.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/DropdownButton.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,178 @@
+/* TODO:
+ * - make the dropdown "smart" so it can't get cutoff on bottom of page, sides of page, etc.
+ */
+
+dojo.provide("dojo.widget.html.DropdownButton");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.uri.Uri");
+dojo.require("dojo.dom");
+dojo.require("dojo.style");
+dojo.require("dojo.html");
+
+dojo.widget.html.DropdownButton = function() {
+	// mix in the button properties
+	dojo.widget.DropdownButton.call(this);
+	dojo.widget.HtmlWidget.call(this);
+}
+
+dojo.inherits(dojo.widget.html.DropdownButton, dojo.widget.HtmlWidget);
+
+dojo.lang.extend(dojo.widget.html.DropdownButton, {
+	
+	// In IE, event handlers on objects inside buttons don't work correctly, so
+	// we just set onClick on the button itself.
+	templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlDropDownButtonTemplate.html"),
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlButtonTemplate.css"),
+
+	// attach points
+	button: null,
+	table: null,
+	labelCell: null,
+	borderCell: null,
+	arrowCell: null,
+	arrow: null,
+
+	fillInTemplate: function(args, frag) {
+		// input data (containing the anchor for the button itself, plus the
+		// thing to display when you push the down arrow)
+		var input = frag["dojo:"+this.widgetType.toLowerCase()]["nodeRef"];
+
+		// Recursively expand widgets inside of the <dojo:dropdownButton>
+		var parser = new dojo.xml.Parse();
+		var frag = parser.parseElement(input, null, true);
+		var ary = dojo.widget.getParser().createComponents(frag);
+
+		this.a = dojo.dom.getFirstChildElement(input);	// the button contents
+		this.menu = dojo.dom.getNextSiblingElement(this.a);	// the menu under the button
+		
+		this.disabled = dojo.html.hasClass(this.a, "disabled");
+		if( this.disabled ) {
+			dojo.html.addClass(this.button, "dojoDisabled");
+			this.domNode.setAttribute("disabled", "true");
+		}
+
+		dojo.html.disableSelection(this.a);
+		this.a.style["text-decoration"]="none";
+		this.labelCell.appendChild(this.a);
+
+		this.arrow.src =
+			dojo.uri.dojoUri("src/widget/templates/images/dropdownButtonsArrow" +
+			(this.disabled ? "-disabled" : "") + ".gif");
+
+		// Attach menu to body so that it appears above other buttons
+		this.menu.style.position="absolute";
+		this.menu.style.display="none";
+		this.menu.style["z-index"] = 99;
+		dojo.html.body().appendChild(this.menu);
+	},
+
+	postCreate: function() {
+		if ( dojo.render.html.ie ) {
+			// Compensate for IE's weird padding of button content, which seems to be relative
+			// to the length of the content
+			var contentWidth = dojo.style.getOuterWidth(this.table);
+			this.labelCell.style["left"] = "-" + (contentWidth / 10) + "px";
+			this.arrowCell.style["left"] = (contentWidth / 10) + "px";
+		}
+
+		// Make menu at least as wide as the button
+		var buttonWidth = dojo.style.getOuterWidth(this.button);
+		var menuWidth = dojo.style.getOuterWidth(this.menu);
+		if ( buttonWidth > menuWidth ) {
+			dojo.style.setOuterWidth(this.menu, buttonWidth);
+		}
+	},
+
+	// If someone clicks anywhere else on the screen (including another menu),
+	// then close this menu.
+	onCanvasMouseDown: function(e) {
+		if( !dojo.dom.isDescendantOf(e.target, this.button) &&
+			!dojo.dom.isDescendantOf(e.target, this.menu) ) {
+			this.hideMenu();
+		}
+	},
+
+	eventWasOverArrow: function(e) {
+		// want to use dojo.html.overElement() but also need to detect clicks
+		// on the area between the arrow and the edge of the button
+		var eventX = e.clientX;
+		var borderX = dojo.style.totalOffsetLeft(this.borderCell);
+		return (eventX > borderX );
+	},
+
+	onMouseOver: function(e) {
+		dojo.html.addClass(this.button, "dojoButtonHover");
+		dojo.html.removeClass(this.button, "dojoButtonNoHover");
+	},
+	
+	onMouseOut: function(e) {
+		dojo.html.removeClass(this.button, "dojoButtonHover");
+		dojo.html.addClass(this.button, "dojoButtonNoHover");
+	},
+
+	onClick: function(e) {
+		if ( this.eventWasOverArrow(e) ) {
+			this._onClickArrow();
+		} else {
+			this._onClickButton();
+		}
+	},
+
+	// Action when the user presses the button
+	_onClickButton: function(e) {
+		if ( this.a ) {
+			if ( this.a.click ) {
+				this.a.click();
+			} else if ( this.a.href ) {
+				location.href = this.a.href;
+			}
+		}
+	},
+
+	// Action when user presses the arrow
+	_onClickArrow: function() {
+		if ( this.menu.style.display == "none" ) {
+			this.showMenu();
+		} else {
+			this.hideMenu();
+		}
+	},
+	
+	showMenu: function() {
+		if ( this.disabled )
+			return;
+
+		// Position it accordingly, relative to screen root (since
+		// it's attached to document.body)
+		this.menu.style.left = dojo.style.totalOffsetLeft(this.button) + "px";
+		this.menu.style.top = dojo.style.totalOffsetTop(this.button) + dojo.style.getOuterHeight(this.button) + "px";
+
+		// Display the menu; do this funky code below to stop the menu from extending
+		// all the way to the right edge of the screen.
+		// TODO: retest simple display="" to confirm that it doesn't work.
+		try {
+			this.menu.style.display="table";	// mozilla
+		} catch(e) {
+			this.menu.style.display="block";	// IE
+		}
+
+		// If someone clicks somewhere else on the screen then close the menu
+		dojo.event.connect(document.documentElement, "onmousedown", this, "onCanvasMouseDown");
+		
+		// When someone clicks the menu, after the menu handles the event,
+		// close the menu (be careful not to close the menu too early or else
+		// the menu will never receive the event.)
+		dojo.event.connect(this.menu, "onclick", this, "hideMenu");
+	},
+
+	hideMenu: function() {
+		this.menu.style.display = "none";
+		dojo.event.disconnect(document.documentElement, "onmousedown", this, "onCanvasMouseDown");
+		dojo.event.disconnect(this.menu, "onclick", this, "hideMenu");
+	}
+});
+
+

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/TaskBar.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/TaskBar.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/TaskBar.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/TaskBar.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,56 @@
+dojo.provide("dojo.widget.html.TaskBar");
+dojo.provide("dojo.widget.html.TaskBarItem");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.Toggler");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.event");
+
+// Icon associated w/a floating pane
+dojo.widget.html.TaskBarItem = function(){
+	dojo.widget.TaskBarItem.call(this);
+	dojo.widget.HtmlWidget.call(this);
+}
+dojo.inherits(dojo.widget.html.TaskBarItem, dojo.widget.HtmlWidget);
+
+dojo.lang.extend(dojo.widget.html.TaskBarItem, {
+	// constructor arguments
+	iconSrc: '',
+	caption: 'Untitled',
+	task: null,
+	iconWidth: 18,
+	iconHeight: 18,
+
+	templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlTaskBarItemTemplate.html"),
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlTaskBar.css"),
+
+	fillInTemplate: function() {
+		if ( this.iconSrc != '' ) {
+			var img = document.createElement("img");
+			img.src = this.iconSrc;
+			img.width = this.iconWidth;
+			img.height = this.iconHeight;
+			this.domNode.appendChild(img);
+		}
+		this.domNode.appendChild(document.createTextNode(this.caption));
+		dojo.html.disableSelection(this.domNode);
+	},
+
+	postCreate: function() {
+		this.task.explodeSrc = this.domNode;
+	},
+
+	onClick: function() {
+		this.task.doToggle();
+	}
+});
+
+// Collection of widgets in a bar, like Windows task bar
+dojo.widget.html.TaskBar = function(){
+	dojo.widget.TaskBar.call(this);
+	dojo.widget.HtmlWidget.call(this);
+}
+dojo.inherits(dojo.widget.html.TaskBar, dojo.widget.HtmlWidget);
+
+dojo.lang.extend(dojo.widget.html.TaskBar, {
+});
\ No newline at end of file

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/TimePicker.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/TimePicker.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/TimePicker.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/TimePicker.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,313 @@
+dojo.provide("dojo.widget.html.TimePicker");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.TimePicker");
+dojo.require("dojo.event.*");
+dojo.require("dojo.html");
+
+dojo.widget.html.TimePicker = function(){
+	dojo.widget.TimePicker.call(this);
+	dojo.widget.HtmlWidget.call(this);
+
+
+	var _this = this;
+	// selected time, JS Date object
+	this.time = "";
+	// set following flag to true if a default time should be set
+	this.useDefaultTime = false;
+	// rfc 3339 date
+	this.storedTime = "";
+	// time currently selected in the UI, stored in hours, minutes, seconds in the format that will be actually displayed
+	this.currentTime = {};
+	this.classNames = {
+		selectedTime: "selectedItem"
+	}
+	this.any = "any"
+	// dom node indecies for selected hour, minute, amPm, and "any time option"
+	this.selectedTime = {
+		hour: "",
+		minute: "",
+		amPm: "",
+		anyTime: false
+	}
+
+	// minutes are ordered as follows: ["12", "6", "1", "7", "2", "8", "3", "9", "4", "10", "5", "11"]
+	this.hourIndexMap = ["", 2, 4, 6, 8, 10, 1, 3, 5, 7, 9, 11, 0];
+	// minutes are ordered as follows: ["00", "30", "05", "35", "10", "40", "15", "45", "20", "50", "25", "55"]
+	this.minuteIndexMap = [0, 2, 4, 6, 8, 10, 1, 3, 5, 7, 9, 11];
+
+	this.templatePath =  dojo.uri.dojoUri("src/widget/templates/HtmlTimePicker.html");
+	this.templateCssPath = dojo.uri.dojoUri("src/widget/templates/HtmlTimePicker.css");
+
+	// utility functions
+	this.toRfcDateTime = function(jsDate) {
+		if(!jsDate) {
+			jsDate = this.today;
+		}
+		var year = jsDate.getFullYear();
+		var month = jsDate.getMonth() + 1;
+		if (month < 10) {
+			month = "0" + month.toString();
+		}
+		var date = jsDate.getDate();
+		if (date < 10) {
+			date = "0" + date.toString();
+		}
+		var hour = jsDate.getHours();
+		if (hour < 10) {
+			hour = "0" + hour.toString();
+		}
+		var minute = jsDate.getMinutes();
+		if (minute < 10) {
+			minute = "0" + minute.toString();
+		}
+		// no way to set seconds, so set to zero
+		var second = "00";
+		var timeZone = jsDate.getTimezoneOffset();
+		var timeZoneHour = parseInt(timeZone/60);
+		if(timeZoneHour > -10 && timeZoneHour < 0) {
+			timeZoneHour = "-0" + Math.abs(timeZoneHour);
+		} else if(timeZoneHour < 10) {
+			timeZoneHour = "+0" + timeZoneHour.toString();
+		} else if(timeZoneHour >= 10) {
+			timeZoneHour = "+" + timeZoneHour.toString();
+		}
+		var timeZoneMinute = timeZone%60;
+		if(timeZoneMinute < 10) {
+			timeZoneMinute = "0" + timeZoneMinute.toString();
+		}
+		return year + "-" + month + "-" + date + "T" + hour + ":" + minute + ":" + second + timeZoneHour +":" + timeZoneMinute;
+	}
+
+	this.fromRfcDateTime = function(rfcDate) {
+		var tempDate = new Date();
+		if(!rfcDate || !rfcDate.split("T")[1]) {
+			tempDate.setMinutes(Math.floor(tempDate.getMinutes()/5)*5);
+		} else {
+			var tempTime = rfcDate.split("T")[1].split(":");
+			// fullYear, month, date
+			var tempDate = new Date();
+			tempDate.setHours(tempTime[0]);
+			tempDate.setMinutes(tempTime[1]);
+		}
+		return tempDate;
+	}
+
+	this.toAmPmHour = function(hour) {
+		var amPmHour = hour;
+		var isAm = true;
+		if (amPmHour == 0) {
+			amPmHour = 12;
+		} else if (amPmHour>12) {
+			amPmHour = amPmHour - 12;
+			isAm = false;
+		} else if (amPmHour == 12) {
+			isAm = false;
+		}
+		return [amPmHour, isAm];
+	}
+
+	this.fromAmPmHour = function(amPmHour, isAm) {
+		var hour = parseInt(amPmHour, 10);
+		if(isAm && hour == 12) {
+			hour = 0;
+		} else if (!isAm && hour<12) {
+			hour = hour + 12;
+		}
+		return hour;
+	}
+
+	this.fillInTemplate = function(){
+		this.initData();
+		this.initUI();
+	}
+
+	this.initData = function() {
+		// FIXME: doesn't currently validate the time before trying to set it
+		// Determine the date/time from stored info, or by default don't 
+		//  have a set time
+		// FIXME: should normalize against whitespace on storedTime... for now 
+		// just a lame hack
+		if(this.storedTime.split("T")[1] && this.storedTime!=" " && this.storedTime.split("T")[1]!="any") {
+			this.time = this.fromRfcDateTime(this.storedTime);
+		} else if (this.useDefaultTime) {
+			this.time = this.fromRfcDateTime();
+		} else {
+			this.selectedTime.anyTime = true;
+		}
+	}
+
+	this.initUI = function() {
+		// set UI to match the currently selected time
+		if(this.time) {
+			var amPmHour = this.toAmPmHour(this.time.getHours());
+			var hour = amPmHour[0];
+			var isAm = amPmHour[1];
+			var minute = this.time.getMinutes();
+			var minuteIndex = parseInt(minute/5);
+			this.onSetSelectedHour(this.hourIndexMap[hour]);
+			this.onSetSelectedMinute(this.minuteIndexMap[minuteIndex]);
+			this.onSetSelectedAmPm(isAm);
+		} else {
+			this.onSetSelectedAnyTime();
+		}
+	}
+
+	this.setDateTime = function(rfcDate) {
+		this.storedTime = rfcDate;
+	}
+	
+	this.onClearSelectedHour = function(evt) {
+		this.clearSelectedHour();
+	}
+
+	this.onClearSelectedMinute = function(evt) {
+		this.clearSelectedMinute();
+	}
+
+	this.onClearSelectedAmPm = function(evt) {
+		this.clearSelectedAmPm();
+	}
+
+	this.onClearSelectedAnyTime = function(evt) {
+		this.clearSelectedAnyTime();
+		if(this.selectedTime.anyTime) {
+			this.selectedTime.anyTime = false;
+			this.time = this.fromRfcDateTime();
+			this.initUI();
+		}
+	}
+
+	this.clearSelectedHour = function() {
+		var hourNodes = this.hourContainerNode.getElementsByTagName("td");
+		for (var i=0; i<hourNodes.length; i++) {
+			dojo.html.setClass(hourNodes.item(i), "");
+		}
+	}
+
+	this.clearSelectedMinute = function() {
+		var minuteNodes = this.minuteContainerNode.getElementsByTagName("td");
+		for (var i=0; i<minuteNodes.length; i++) {
+			dojo.html.setClass(minuteNodes.item(i), "");
+		}
+	}
+
+	this.clearSelectedAmPm = function() {
+		var amPmNodes = this.amPmContainerNode.getElementsByTagName("td");
+		for (var i=0; i<amPmNodes.length; i++) {
+			dojo.html.setClass(amPmNodes.item(i), "");
+		}
+	}
+
+	this.clearSelectedAnyTime = function() {
+		dojo.html.setClass(this.anyTimeContainerNode, "anyTimeContainer");
+	}
+
+	this.onSetSelectedHour = function(evt) {
+		this.onClearSelectedAnyTime();
+		this.onClearSelectedHour();
+		this.setSelectedHour(evt);
+		this.onSetTime();
+	}
+
+	this.setSelectedHour = function(evt) {
+		if(evt && evt.target) {
+			dojo.html.setClass(evt.target, this.classNames.selectedTime);
+			this.selectedTime["hour"] = evt.target.innerHTML;
+		} else if (!isNaN(evt)) {
+			var hourNodes = this.hourContainerNode.getElementsByTagName("td");
+			if(hourNodes.item(evt)) {
+				dojo.html.setClass(hourNodes.item(evt), this.classNames.selectedTime);
+				this.selectedTime["hour"] = hourNodes.item(evt).innerHTML;
+			}
+		}
+		this.selectedTime.anyTime = false;
+	}
+
+	this.onSetSelectedMinute = function(evt) {
+		this.onClearSelectedAnyTime();
+		this.onClearSelectedMinute();
+		this.setSelectedMinute(evt);
+		this.selectedTime.anyTime = false;
+		this.onSetTime();
+	}
+
+	this.setSelectedMinute = function(evt) {
+		if(evt && evt.target) {
+			dojo.html.setClass(evt.target, this.classNames.selectedTime);
+			this.selectedTime["minute"] = evt.target.innerHTML;
+		} else if (!isNaN(evt)) {
+			var minuteNodes = this.minuteContainerNode.getElementsByTagName("td");
+			if(minuteNodes.item(evt)) {
+				dojo.html.setClass(minuteNodes.item(evt), this.classNames.selectedTime);
+				this.selectedTime["minute"] = minuteNodes.item(evt).innerHTML;
+			}
+		}
+	}
+
+	this.onSetSelectedAmPm = function(evt) {
+		this.onClearSelectedAnyTime();
+		this.onClearSelectedAmPm();
+		this.setSelectedAmPm(evt);
+		this.selectedTime.anyTime = false;
+		this.onSetTime();
+	}
+
+	this.setSelectedAmPm = function(evt) {
+		if(evt && evt.target) {
+			dojo.html.setClass(evt.target, this.classNames.selectedTime);
+			this.selectedTime["amPm"] = evt.target.innerHTML;
+		} else {
+			evt = evt ? 0 : 1;
+			var amPmNodes = this.amPmContainerNode.getElementsByTagName("td");
+			if(amPmNodes.item(evt)) {
+				dojo.html.setClass(amPmNodes.item(evt), this.classNames.selectedTime);
+				this.selectedTime["amPm"] = amPmNodes.item(evt).innerHTML;
+			}
+		}
+	}
+
+	this.onSetSelectedAnyTime = function(evt) {
+		this.onClearSelectedHour();
+		this.onClearSelectedMinute();
+		this.onClearSelectedAmPm();
+		this.setSelectedAnyTime();
+		this.onSetTime();
+	}
+
+	this.setSelectedAnyTime = function(evt) {
+		this.selectedTime.anyTime = true;
+		dojo.html.setClass(this.anyTimeContainerNode, this.classNames.selectedTime + " " + "anyTimeContainer");
+	}
+
+	this.onClick = function(evt) {
+		dojo.event.browser.stopEvent(evt)
+	}
+
+	this.onSetTime = function() {
+		if(this.selectedTime.anyTime) {
+			this.time = new Date();
+			var tempDateTime = this.toRfcDateTime(this.time);
+			this.setDateTime(tempDateTime.split("T")[0] + "T" + this.any);
+		} else {
+			var hour = 12;
+			var minute = 0;
+			var isAm = false;
+			if(this.selectedTime["hour"]) {
+				hour = parseInt(this.selectedTime["hour"], 10);
+			}
+			if(this.selectedTime["minute"]) {
+				minute = parseInt(this.selectedTime["minute"], 10);
+			}
+			if(this.selectedTime["amPm"]) {
+				isAm = (this.selectedTime["amPm"].toLowerCase() == "am");
+			}
+			this.time = new Date();
+			this.time.setHours(this.fromAmPmHour(hour, isAm));
+			this.time.setMinutes(minute);
+			this.setDateTime(this.toRfcDateTime(this.time));
+		}
+	}
+
+}
+dojo.inherits(dojo.widget.html.TimePicker, dojo.widget.HtmlWidget);

Added: portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/Tooltip.js
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/Tooltip.js?rev=354516&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/Tooltip.js (added)
+++ portals/jetspeed-2/trunk/applications/j2-admin/src/webapp/dojo/src/widget/html/Tooltip.js Tue Dec  6 11:29:56 2005
@@ -0,0 +1,107 @@
+dojo.provide("dojo.widget.html.Tooltip");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.Tooltip");
+dojo.require("dojo.uri");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.event");
+dojo.require("dojo.style");
+dojo.require("dojo.html");
+
+dojo.widget.html.Tooltip = function(){
+	// mix in the tooltip properties
+	dojo.widget.Tooltip.call(this);
+	dojo.widget.HtmlWidget.call(this);
+}
+dojo.inherits(dojo.widget.html.Tooltip, dojo.widget.HtmlWidget);
+dojo.lang.extend(dojo.widget.html.Tooltip, {
+
+	// Constructor arguments (should these be in tooltip.js rather than html/tooltip.js???)
+	caption: "undefined",
+	delay: 500,
+	connectId: "",
+
+	templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlTooltipTemplate.html"),
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlTooltipTemplate.css"),
+
+	containerNode: null,
+	connectNode: null,
+
+	hovering: false,
+	displayed: false,
+
+	fillInTemplate: function(args, frag){
+		if(this.caption != "undefined"){
+			this.domNode.appendChild(document.createTextNode(this.caption));
+		}
+		dojo.html.body().appendChild(this.domNode);
+		this.connectNode = dojo.byId(this.connectId);
+		if(dojo.render.html.ie){
+			this.bgIframe = document.createElement("<iframe frameborder='0' src='about:blank'>");
+			with(this.bgIframe.style){
+				position = "absolute";
+				left = top = "0px";
+				display = "none";
+			}
+			dojo.html.body().appendChild(this.bgIframe);
+			dojo.style.setOpacity(this.bgIframe, 0);
+		}
+	},
+	
+	postCreate: function(args, frag){
+		var self = this;
+		this.timerEvent = function () { self.display.apply(self); };
+		dojo.event.connect(this.connectNode, "onmouseover", this, "onMouseOver");
+		dojo.event.connect(this.connectNode, "onmousemove", this, "recordMousePosition");
+		dojo.event.connect(this.connectNode, "onmouseout", this, "onMouseOut");
+	},
+	
+	onMouseOver: function(e) {
+		this.timerEventId = setTimeout(this.timerEvent, this.delay);
+		this.recordMousePosition(e);
+	},
+	
+	recordMousePosition: function(e) {
+		this.mouseX = e.pageX || e.clientX + dojo.html.body().scrollLeft;
+		this.mouseY = e.pageY || e.clientY + dojo.html.body().scrollTop;
+	},
+
+	display: function() {
+		this.domNode.style.top = this.mouseY + 15 + "px";
+		this.domNode.style.left = this.mouseX + 10 + "px";
+
+		// if rendering using explosion effect, need to set explosion source
+		this.explodeSrc = [this.mouseX, this.mouseY];
+			
+		this.show();
+		if(this.bgIframe){
+			with(this.bgIframe.style){
+				display = "block";
+				top = this.domNode.style.top;
+				left = this.domNode.style.left;
+				zIndex = 998;
+				width = dojo.html.getOuterWidth(this.domNode) + "px";
+				height = dojo.html.getOuterHeight(this.domNode) + "px";
+			}
+
+		}
+		this.displayed=true;
+	},
+
+	onMouseOut: function() {
+		if ( this.timerEventId ) {
+			clearTimeout(this.timerEventId);
+			delete this.timerEventId;
+		}
+		if ( this.displayed ) {
+			this.hide();
+			this.displayed=false;
+		}
+	},
+	
+	hide: function() {
+		if(this.bgIframe){
+			this.bgIframe.style.display = "none";
+		}
+		dojo.widget.html.Tooltip.superclass.hide.call(this);
+	}
+});



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