You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by mu...@apache.org on 2007/03/03 06:49:21 UTC

svn commit: r514083 [47/49] - in /struts/struts2/trunk/plugins/dojo: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/struts2/ src/main/java/org/apache/struts2/components/ src/main/java/org/apache/s...

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/widget/vml/Chart.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/widget/vml/Chart.js?view=auto&rev=514083
==============================================================================
--- struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/widget/vml/Chart.js (added)
+++ struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/widget/vml/Chart.js Fri Mar  2 21:48:54 2007
@@ -0,0 +1,639 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.widget.vml.Chart");
+
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.Chart");
+dojo.require("dojo.math");
+dojo.require("dojo.html.layout");
+dojo.require("dojo.gfx.color");
+
+dojo.widget.defineWidget(
+	"dojo.widget.vml.Chart",
+	[dojo.widget.HtmlWidget, dojo.widget.Chart],
+	function(){
+		//	summary
+		//	initializes the VML version of Chart.
+		this.templatePath=null;
+		this.templateCssPath=null;
+		this._isInitialize=false;
+		this.hasData=false;
+		this.vectorNode=null;
+		this.plotArea=null;
+		this.dataGroup=null;
+		this.axisGroup=null;
+		this.properties={
+			height:0,	//	defaults, will resize to the domNode.
+			width:0,
+			defaultWidth:600,
+			defaultHeight:400,
+			plotType:null,
+			padding:{
+				top:10,
+				bottom:2,
+				left:60,
+				right:30
+			},
+			axes:{
+				x:{
+					plotAt:0,
+					label:"",
+					unitLabel:"",
+					unitType:Number,
+					nUnitsToShow:10,
+					range:{
+						min:0,
+						max:200
+					}
+				},
+				y:{
+					plotAt:0,
+					label:"",
+					unitLabel:"",
+					unitType:Number,
+					nUnitsToShow:10,
+					range:{
+						min:0,
+						max:200
+					}
+				}
+			}
+		};
+	},
+{
+	parseProperties:function(/* HTMLElement */node){
+		//	summary
+		//	Parse the properties off the main tag
+		var bRangeX=false;
+		var bRangeY=false;
+		if (node.getAttribute("width")){ 
+			this.properties.width=node.getAttribute("width");
+		}
+		if (node.getAttribute("height")){
+			this.properties.height=node.getAttribute("height");
+		}
+		if (node.getAttribute("plotType")){
+			this.properties.plotType=node.getAttribute("plotType");
+		}
+		if (node.getAttribute("padding")){
+			if (node.getAttribute("padding").indexOf(",") > -1)
+				var p=node.getAttribute("padding").split(","); 
+			else var p=node.getAttribute("padding").split(" ");
+			if (p.length==1){
+				var pad=parseFloat(p[0]);
+				this.properties.padding.top=pad;
+				this.properties.padding.right=pad;
+				this.properties.padding.bottom=pad;
+				this.properties.padding.left=pad;
+			} else if(p.length==2){
+				var padV=parseFloat(p[0]);
+				var padH=parseFloat(p[1]);
+				this.properties.padding.top=padV;
+				this.properties.padding.right=padH;
+				this.properties.padding.bottom=padV;
+				this.properties.padding.left=padH;
+			} else if(p.length==4){
+				this.properties.padding.top=parseFloat(p[0]);
+				this.properties.padding.right=parseFloat(p[1]);
+				this.properties.padding.bottom=parseFloat(p[2]);
+				this.properties.padding.left=parseFloat(p[3]);
+			}
+		}
+		if (node.getAttribute("rangeX")){
+			var p=node.getAttribute("rangeX");
+			if (p.indexOf(",")>-1) p=p.split(",");
+			else p=p.split(" ");
+			this.properties.axes.x.range.min=parseFloat(p[0]);
+			this.properties.axes.x.range.max=parseFloat(p[1]);
+			bRangeX=true;
+		}
+		if (node.getAttribute("rangeY")){
+			var p=node.getAttribute("rangeY");
+			if (p.indexOf(",")>-1) p=p.split(",");
+			else p=p.split(" ");
+			this.properties.axes.y.range.min=parseFloat(p[0]);
+			this.properties.axes.y.range.max=parseFloat(p[1]);
+			bRangeY=true;
+		}
+		return { rangeX:bRangeX, rangeY:bRangeY };
+	},
+	setAxesPlot:function(/* HTMLElement */table){
+		//	summary
+		//	figure out where to plot the axes
+		if (table.getAttribute("axisAt")){
+			var p=table.getAttribute("axisAt");
+			if (p.indexOf(",")>-1) p=p.split(",");
+			else p=p.split(" ");
+			
+			//	x axis
+			if (!isNaN(parseFloat(p[0]))){
+				this.properties.axes.x.plotAt=parseFloat(p[0]);
+			} else if (p[0].toLowerCase()=="ymin"){
+				this.properties.axes.x.plotAt=this.properties.axes.y.range.min;
+			} else if (p[0].toLowerCase()=="ymax"){
+				this.properties.axes.x.plotAt=this.properties.axes.y.range.max;
+			}
+
+			// y axis
+			if (!isNaN(parseFloat(p[1]))){
+				this.properties.axes.y.plotAt=parseFloat(p[1]);
+			} else if (p[1].toLowerCase()=="xmin"){
+				this.properties.axes.y.plotAt=this.properties.axes.x.range.min;
+			} else if (p[1].toLowerCase()=="xmax"){
+				this.properties.axes.y.plotAt=this.properties.axes.x.range.max;
+			}
+		} else {
+			this.properties.axes.x.plotAt=this.properties.axes.y.range.min;
+			this.properties.axes.y.plotAt=this.properties.axes.x.range.min;
+		}
+	},
+	drawVectorNode:function(){
+		//	summary
+		//	Draws the main canvas for the chart
+		if(this.vectorNode){ this.destroy(); }
+		this.vectorNode=document.createElement("div");
+		this.vectorNode.style.width=this.properties.width+"px";
+		this.vectorNode.style.height=this.properties.height+"px";
+		this.vectorNode.style.position="relative";
+		this.domNode.appendChild(this.vectorNode);
+	},
+	drawPlotArea:function(){
+		//	summary
+		//	Draws the plot area for the chart
+		var plotWidth=this.properties.width-this.properties.padding.left-this.properties.padding.right;
+		var plotHeight=this.properties.height-this.properties.padding.top-this.properties.padding.bottom;
+
+		if(this.plotArea){
+			this.plotArea.parentNode.removeChild(this.plotArea);
+			this.plotArea=null;
+		}
+		this.plotArea=document.createElement("div");
+		this.plotArea.style.position="absolute";
+		this.plotArea.style.backgroundColor="#fff";
+		this.plotArea.style.top=(this.properties.padding.top)-2+"px";
+		this.plotArea.style.left=(this.properties.padding.left-1)+"px";
+		this.plotArea.style.width=plotWidth+"px";
+		this.plotArea.style.height=plotHeight+"px";
+		this.plotArea.style.clip="rect(0 "+plotWidth+" "+plotHeight+" 0)";
+		this.vectorNode.appendChild(this.plotArea);
+	},
+	drawDataGroup:function(){
+		//	summary
+		//	Draws the data group for the chart
+		var plotWidth=this.properties.width-this.properties.padding.left-this.properties.padding.right;
+		var plotHeight=this.properties.height-this.properties.padding.top-this.properties.padding.bottom;
+
+		if(this.dataGroup){
+			this.dataGroup.parentNode.removeChild(this.dataGroup);
+			this.dataGroup=null;
+		}
+		this.dataGroup=document.createElement("div");
+		this.dataGroup.style.position="absolute";
+		this.dataGroup.setAttribute("title", "Data Group");
+		this.dataGroup.style.top="0px";
+		this.dataGroup.style.left="0px";
+		this.dataGroup.style.width=plotWidth+"px";
+		this.dataGroup.style.height=plotHeight+"px";
+		this.plotArea.appendChild(this.dataGroup);
+	},
+	drawAxes:function(){
+		//	summary
+		//	Draws the axes for the chart
+		var plotWidth=this.properties.width-this.properties.padding.left-this.properties.padding.right;
+		var plotHeight=this.properties.height-this.properties.padding.top-this.properties.padding.bottom;
+
+		if(this.axisGroup){
+			this.axisGroup.parentNode.removeChild(this.axisGroup);
+			this.axisGroup=null;
+		}
+		this.axisGroup=document.createElement("div");
+		this.axisGroup.style.position="absolute";
+		this.axisGroup.setAttribute("title", "Axis Group");
+		this.axisGroup.style.top="0px";
+		this.axisGroup.style.left="0px";
+		this.axisGroup.style.width=plotWidth+"px";
+		this.axisGroup.style.height=plotHeight+"px";
+		this.plotArea.appendChild(this.axisGroup);
+		var stroke=1;
+
+		//	x axis
+		var line=document.createElement("v:line");
+		var y=dojo.widget.vml.Chart.Plotter.getY(this.properties.axes.x.plotAt, this);
+		line.setAttribute("from", "0px,"+y+"px");
+		line.setAttribute("to", plotWidth+"px,"+y+"px");
+		line.style.position="absolute";
+		line.style.top="0px";
+		line.style.left="0px";
+		line.style.antialias="false";
+		line.setAttribute("strokecolor", "#666");
+		line.setAttribute("strokeweight", stroke*2+"px");
+		this.axisGroup.appendChild(line);
+
+		//	y axis
+		var line=document.createElement("v:line");
+		var x=dojo.widget.vml.Chart.Plotter.getX(this.properties.axes.y.plotAt, this);
+		line.setAttribute("from", x+"px,0px");
+		line.setAttribute("to", x+"px,"+plotHeight+"px");
+		line.style.position="absolute";
+		line.style.top="0px";
+		line.style.left="0px";
+		line.style.antialias="false";
+		line.setAttribute("strokecolor", "#666");
+		line.setAttribute("strokeweight", stroke*2+"px");
+		this.axisGroup.appendChild(line);
+		
+		//	labels
+		var size=10;
+
+		//	x axis labels.
+		var t=document.createElement("div");
+		t.style.position="absolute";
+		t.style.top=(this.properties.height-this.properties.padding.bottom)+"px";
+		t.style.left=this.properties.padding.left+"px";
+		t.style.fontFamily="sans-serif";
+		t.style.fontSize=size+"px";
+		t.innerHTML=dojo.math.round(parseFloat(this.properties.axes.x.range.min),2);
+		this.vectorNode.appendChild(t);
+
+		t=document.createElement("div");
+		t.style.position="absolute";
+		t.style.top=(this.properties.height-this.properties.padding.bottom)+"px";
+		t.style.left=(this.properties.width-this.properties.padding.right-size)+"px";
+		t.style.fontFamily="sans-serif";
+		t.style.fontSize=size+"px";
+		t.innerHTML=dojo.math.round(parseFloat(this.properties.axes.x.range.max),2);
+		this.vectorNode.appendChild(t);
+
+		//	y axis labels.
+		t=document.createElement("div");
+		t.style.position="absolute";
+		t.style.top=(size/2)+"px";
+		t.style.left="0px";
+		t.style.width=this.properties.padding.left + "px";
+		t.style.textAlign="right";
+		t.style.paddingRight="4px";
+		t.style.fontFamily="sans-serif";
+		t.style.fontSize=size+"px";
+		t.innerHTML=dojo.math.round(parseFloat(this.properties.axes.y.range.max),2);
+		this.vectorNode.appendChild(t);
+		
+		t=document.createElement("div");
+		t.style.position="absolute";
+		t.style.top=(this.properties.height-this.properties.padding.bottom-size)+"px";
+		t.style.left="0px";
+		t.style.width=this.properties.padding.left + "px";
+		t.style.textAlign="right";
+		t.style.paddingRight="4px";
+		t.style.fontFamily="sans-serif";
+		t.style.fontSize=size+"px";
+		t.innerHTML=dojo.math.round(parseFloat(this.properties.axes.y.range.min),2);
+		this.vectorNode.appendChild(t);
+	},
+	
+	init:function(){
+		//	summary
+		//	Initialize the chart
+		if(!this.properties.width || !this.properties.height){
+			var box=dojo.html.getContentBox(this.domNode);
+			if(!this.properties.width){
+				this.properties.width=(box.width<32)?this.properties.defaultWidth:box.width;
+			}
+			if(!this.properties.height){
+				this.properties.height=(box.height<32)?this.properties.defaultHeight:box.height;
+			}
+		}
+
+		//	set up the chart; each is a method so that it can be selectively overridden.
+		this.drawVectorNode();
+		this.drawPlotArea();
+		this.drawDataGroup();
+		this.drawAxes();
+
+		//	this is last.
+		this.assignColors();
+		this._isInitialized=true;
+	},
+	destroy:function(){
+		//	summary
+		//	Node cleanup
+		while(this.domNode.childNodes.length>0){
+			this.domNode.removeChild(this.domNode.childNodes[0]);
+		}
+		this.vectorNode=this.plotArea=this.dataGroup=this.axisGroup=null;
+	},
+	render:function(){
+		//	summary
+		//	Draws the data on the chart
+		if (this.dataGroup){
+			while(this.dataGroup.childNodes.length>0){
+				this.dataGroup.removeChild(this.dataGroup.childNodes[0]);
+			}
+		} else {
+			this.init();
+		}
+		for(var i=0; i<this.series.length; i++){
+			dojo.widget.vml.Chart.Plotter.plot(this.series[i], this);
+		}
+	},
+	postCreate:function(){
+		//	summary
+		//	Parse any data if included with the chart, and kick off the rendering.
+		var table=this.domNode.getElementsByTagName("table")[0];
+		if (table){
+			var ranges=this.parseProperties(table);
+			var bRangeX=false;
+			var bRangeY=false;
+		
+			//	fix the axes
+			var axisValues = this.parseData(table);
+			if(!bRangeX){
+				this.properties.axes.x.range={min:axisValues.x.min, max:axisValues.x.max};
+			}
+			if(!bRangeY){
+				this.properties.axes.y.range={min:axisValues.y.min, max:axisValues.y.max};
+			}
+			this.setAxesPlot(table);
+
+			//	table values should be populated, now pop it off.
+			this.domNode.removeChild(table);
+		}
+		if(this.series.length>0){
+			this.render();
+		}
+	}
+});
+
+dojo.widget.vml.Chart.Plotter=new function(){
+	//	summary
+	//	Singleton for plotting series of data.
+	var self=this;
+	var plotters = {};
+	var types=dojo.widget.Chart.PlotTypes;
+	
+	this.getX=function(/* string||number */value, /* dojo.widget.Chart */chart){
+		//	summary
+		//	Calculate the x coord on the passed chart for the passed value
+		var v=parseFloat(value);
+		var min=chart.properties.axes.x.range.min;
+		var max=chart.properties.axes.x.range.max;
+		var ofst=0-min;
+		min+=ofst; max+=ofst; v+=ofst;
+
+		var xmin = 0;
+		var xmax=chart.properties.width-chart.properties.padding.left-chart.properties.padding.right;
+		var x=(v*((xmax-xmin)/max))+xmin;
+		return x;
+	};
+	this.getY=function(/* string||number */value, /* dojo.widget.Chart */chart){
+		//	summary
+		//	Calculate the y coord on the passed chart for the passed value
+		var v=parseFloat(value);
+		var max=chart.properties.axes.y.range.max;
+		var min=chart.properties.axes.y.range.min;
+		var ofst=0;
+		if(min<0)ofst+=Math.abs(min);
+		min+=ofst; max+=ofst; v+=ofst;
+		
+		var ymin=chart.properties.height-chart.properties.padding.top-chart.properties.padding.bottom;
+		var ymax = 0;
+		var y=(((ymin-ymax)/(max-min))*(max-v))+ymax;
+		return y;
+	};
+
+	this.addPlotter=function(/* string */name, /* function */func){
+		//	summary
+		//	add a custom plotter function to this object.
+		plotters[name]=func;
+	};
+	this.plot=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
+		//	summary
+		//	plot the passed series.
+		if (series.values.length==0) return;	//	void
+		if (series.plotType && plotters[series.plotType]){
+			return plotters[series.plotType](series, chart);	//	void
+		}
+		else if (chart.plotType && plotters[chart.plotType]){
+			return plotters[chart.plotType](series, chart);		//	void
+		}
+	};
+
+	//	plotting
+	plotters["bar"]=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
+		//	summary
+		//	plot the passed series as a set of bars.
+		var space=1;
+		var lastW = 0;
+		var ys = [];
+		var yAxis=self.getY(chart.properties.axes.x.plotAt, chart);
+		var yA = yAxis;
+		for (var i=0; i<series.values.length; i++){
+			var x=self.getX(series.values[i].x, chart);
+			var w;
+			if (i==series.values.length-1){
+				w=lastW;
+			} else{
+				w=self.getX(series.values[i+1].x, chart)-x-space;
+				lastW=w;
+			}
+			x-=(w/2);
+
+			var y=self.getY(series.values[i].value, chart);
+			var h=Math.abs(yA-y);
+			if (parseFloat(series.values[i].value) < chart.properties.axes.x.plotAt){
+				y=yA;
+			}
+
+			var bar=document.createElement("v:rect");
+			bar.style.position="absolute";
+			bar.style.top=y+"px";
+			bar.style.left=x+"px";
+			bar.style.width=w+"px";
+			bar.style.height=h+"px";
+			bar.setAttribute("fillColor", series.color);
+			bar.setAttribute("stroked", "false");
+			bar.style.antialias="false";
+			bar.setAttribute("title", series.label + " (" + i + "): " + series.values[i].value);
+			var fill=document.createElement("v:fill");
+			fill.setAttribute("opacity", "0.9");
+			bar.appendChild(fill);
+			chart.dataGroup.appendChild(bar);
+		}
+	};	
+	plotters["line"]=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
+		//	summary
+		//	plot the passed series as a line with tensioning
+		var tension=1.5;
+
+		var line=document.createElement("v:shape");
+		line.setAttribute("strokeweight", "2px");
+		line.setAttribute("strokecolor", series.color);
+		line.setAttribute("fillcolor", "none");
+		line.setAttribute("filled", "false");
+		line.setAttribute("title", series.label);
+		line.setAttribute("coordsize", chart.properties.width + "," + chart.properties.height);
+		line.style.position="absolute";
+		line.style.top="0px";
+		line.style.left="0px";
+		line.style.width= chart.properties.width+"px";
+		line.style.height=chart.properties.height+"px";
+		var stroke=document.createElement("v:stroke");
+		stroke.setAttribute("opacity", "0.85");
+		line.appendChild(stroke);
+
+		var path = [];
+		for (var i=0; i<series.values.length; i++){
+			var x = Math.round(self.getX(series.values[i].x, chart));
+			var y = Math.round(self.getY(series.values[i].value, chart));
+
+			if (i==0){
+				path.push("m");
+				path.push(x+","+y);
+			}else{
+				var lastx=Math.round(self.getX(series.values[i-1].x, chart));
+				var lasty=Math.round(self.getY(series.values[i-1].value, chart));
+				var dx=x-lastx;
+				var dy=y-lasty;
+				
+				path.push("c");
+				var cx=Math.round((x-(tension-1)*(dx/tension)));
+				path.push(cx+","+lasty);
+				cx=Math.round((x-(dx/tension)));
+				path.push(cx+","+y);
+				path.push(x+","+y);
+			}
+		}
+		line.setAttribute("path", path.join(" ")+" e");
+		chart.dataGroup.appendChild(line);
+	};
+	plotters["area"]=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
+		//	summary
+		//	plot the passed series as an area with tensioning.
+		var tension=1.5;
+
+		var line=document.createElement("v:shape");
+		line.setAttribute("strokeweight", "1px");
+		line.setAttribute("strokecolor", series.color);
+		line.setAttribute("fillcolor", series.color);
+		line.setAttribute("title", series.label);
+		line.setAttribute("coordsize", chart.properties.width + "," + chart.properties.height);
+		line.style.position="absolute";
+		line.style.top="0px";
+		line.style.left="0px";
+		line.style.width= chart.properties.width+"px";
+		line.style.height=chart.properties.height+"px";
+		var stroke=document.createElement("v:stroke");
+		stroke.setAttribute("opacity", "0.8");
+		line.appendChild(stroke);
+		var fill=document.createElement("v:fill");
+		fill.setAttribute("opacity", "0.4");
+		line.appendChild(fill);
+
+		var path = [];
+		for (var i=0; i<series.values.length; i++){
+			var x = Math.round(self.getX(series.values[i].x, chart));
+			var y = Math.round(self.getY(series.values[i].value, chart));
+
+			if (i==0){
+				path.push("m");
+				path.push(x+","+y);
+			}else{
+				var lastx=Math.round(self.getX(series.values[i-1].x, chart));
+				var lasty=Math.round(self.getY(series.values[i-1].value, chart));
+				var dx=x-lastx;
+				var dy=y-lasty;
+				
+				path.push("c");
+				var cx=Math.round((x-(tension-1)*(dx/tension)));
+				path.push(cx+","+lasty);
+				cx=Math.round((x-(dx/tension)));
+				path.push(cx+","+y);
+				path.push(x+","+y);
+			}
+		}
+		path.push("l");
+		path.push(x + "," + self.getY(0, chart));
+		path.push("l");
+		path.push(self.getX(0, chart) + "," + self.getY(0,chart));
+		line.setAttribute("path", path.join(" ")+" x e");
+		chart.dataGroup.appendChild(line);
+	};
+	plotters["scatter"]=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
+		//	summary
+		//	plot the passed series as a scatter chart
+		var r=6;
+		for (var i=0; i<series.values.length; i++){
+			var x=self.getX(series.values[i].x, chart);
+			var y=self.getY(series.values[i].value, chart);
+			var mod=r/2;
+
+			var point=document.createElement("v:rect");
+			point.setAttribute("fillcolor", series.color);
+			point.setAttribute("strokecolor", series.color);
+			point.setAttribute("title", series.label + ": " + series.values[i].value);
+			point.style.position="absolute";
+			point.style.rotation="45";
+			point.style.top=(y-mod)+"px";
+			point.style.left=(x-mod)+"px";
+			point.style.width=r+"px";
+			point.style.height=r+"px";
+			var fill=document.createElement("v:fill");
+			fill.setAttribute("opacity", "0.6");
+			point.appendChild(fill);
+			chart.dataGroup.appendChild(point);
+		}
+	};	
+	plotters["bubble"]=function(/* dojo.widget.Chart.DataSeries */series, /* dojo.widget.Chart */chart){
+		//	summary
+		//	plot the passed series as a series of bubbles (scatter with 3rd dimension)
+		//	added param for series[n].value: size
+		var minR=1;
+		
+		//	do this off the x axis?
+		var min=chart.properties.axes.x.range.min;
+		var max=chart.properties.axes.x.range.max;
+		var ofst=0-min;
+
+		min+=ofst; max+=ofst;
+		var xmin=chart.properties.padding.left;
+		var xmax=chart.properties.width-chart.properties.padding.right;
+		var factor=(max-min)/(xmax-xmin)*25;
+		
+		for (var i=0; i<series.values.length; i++){
+			var size = series.values[i].size;
+			if (isNaN(parseFloat(size))) size=minR;
+
+			var radius=(parseFloat(size)*factor)/2;
+			var diameter=radius * 2;
+			var cx=self.getX(series.values[i].x, chart);
+			var cy=self.getY(series.values[i].value, chart);
+
+			var top=cy-radius;
+			var left=cx-radius;
+
+			var point=document.createElement("v:oval");
+			point.setAttribute("fillcolor", series.color);
+			point.setAttribute("title", series.label + ": " + series.values[i].value + " (" + size + ")");
+			point.setAttribute("stroked", "false");
+			point.style.position="absolute";
+			
+			point.style.top=top+"px";
+			point.style.left=left+"px";
+			point.style.width=diameter+"px";
+			point.style.height=diameter+"px";
+
+			var fill=document.createElement("v:fill");
+			fill.setAttribute("opacity", "0.8");
+			point.appendChild(fill);
+			
+			chart.dataGroup.appendChild(point);
+		}
+	};
+}();

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/xml/Parse.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/xml/Parse.js?view=auto&rev=514083
==============================================================================
--- struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/xml/Parse.js (added)
+++ struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/xml/Parse.js Fri Mar  2 21:48:54 2007
@@ -0,0 +1,235 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.xml.Parse");
+dojo.require("dojo.dom");
+
+//TODO: determine dependencies
+// currently has dependency on dojo.xml.DomUtil nodeTypes constants...
+
+/* 
+  generic class for taking a node and parsing it into an object
+*/
+
+// using documentFragment nomenclature to generalize in case we don't want to require passing a collection of nodes with a single parent
+
+dojo.xml.Parse = function(){
+
+	// supported dojoTagName's:
+	// 
+	// <prefix:tag> => prefix:tag
+	// <dojo:tag> => dojo:tag
+	// <dojoTag> => dojo:tag
+	// <tag dojoType="type"> => dojo:type
+	// <tag dojoType="prefix:type"> => prefix:type
+	// <tag dojo:type="type"> => dojo:type
+	// <tag class="classa dojo-type classb"> => dojo:type	
+
+	// get normalized (lowercase) tagName
+	// some browsers report tagNames in lowercase no matter what
+	function getTagName(node){
+		return ((node)&&(node.tagName) ? node.tagName.toLowerCase() : '');
+	}
+
+	// locate dojo qualified tag name
+	function getDojoTagName(node){
+		var tagName = getTagName(node);
+		if (!tagName){
+				return '';
+		}
+		// any registered tag
+		if((dojo.widget)&&(dojo.widget.tags[tagName])){
+			return tagName;
+		}
+		// <prefix:tag> => prefix:tag
+		var p = tagName.indexOf(":");
+		if(p>=0){
+			return tagName;
+		}
+		// <dojo:tag> => dojo:tag
+		if(tagName.substr(0,5) == "dojo:"){
+			return tagName;
+		}
+		if(dojo.render.html.capable && dojo.render.html.ie && node.scopeName != 'HTML'){
+			return node.scopeName.toLowerCase() + ':' + tagName;
+		}
+		// <dojoTag> => dojo:tag
+		if(tagName.substr(0,4) == "dojo"){
+			// FIXME: this assumes tag names are always lower case
+			return "dojo:" + tagName.substring(4);
+		}
+		// <tag dojoType="prefix:type"> => prefix:type
+		// <tag dojoType="type"> => dojo:type
+		var djt = node.getAttribute("dojoType") || node.getAttribute("dojotype");
+		if(djt){
+			if (djt.indexOf(":")<0){
+				djt = "dojo:"+djt;
+			}
+			return djt.toLowerCase();
+		}
+		// <tag dojo:type="type"> => dojo:type
+		djt = node.getAttributeNS && node.getAttributeNS(dojo.dom.dojoml,"type");
+		if(djt){
+			return "dojo:" + djt.toLowerCase();
+		}
+		// <tag dojo:type="type"> => dojo:type
+		try{
+			// FIXME: IE really really doesn't like this, so we squelch errors for it
+			djt = node.getAttribute("dojo:type");
+		}catch(e){ 
+			// FIXME: log?  
+		}
+		if(djt){ return "dojo:"+djt.toLowerCase(); }
+		// <tag class="classa dojo-type classb"> => dojo:type	
+		if((!dj_global["djConfig"])|| (djConfig["ignoreClassNames"])){ 
+			// FIXME: should we make this optionally enabled via djConfig?
+			var classes = node.className||node.getAttribute("class");
+			// FIXME: following line, without check for existence of classes.indexOf
+			// breaks firefox 1.5's svg widgets
+			if((classes )&&(classes.indexOf)&&(classes.indexOf("dojo-")!=-1)){
+		    var aclasses = classes.split(" ");
+		    for(var x=0, c=aclasses.length; x<c; x++){
+	        if(aclasses[x].slice(0, 5) == "dojo-"){
+            return "dojo:"+aclasses[x].substr(5).toLowerCase(); 
+					}
+				}
+			}
+		}
+		// no dojo-qualified name
+		return '';
+	}
+
+	this.parseElement = function(node, hasParentNodeSet, optimizeForDojoML, thisIdx){
+
+		var parsedNodeSet = {};
+		
+		var tagName = getTagName(node);
+		//There's a weird bug in IE where it counts end tags, e.g. </dojo:button> as nodes that should be parsed.  Ignore these
+		if((tagName)&&(tagName.indexOf("/")==0)){
+			return null;
+		}
+		
+		// look for a dojoml qualified name
+		// process dojoml only when optimizeForDojoML is true
+		var process = true;
+		if(optimizeForDojoML){
+			var dojoTagName = getDojoTagName(node);
+			tagName = dojoTagName || tagName;
+			process = Boolean(dojoTagName);
+		}
+		
+		if(node && node.getAttribute && node.getAttribute("parseWidgets") && node.getAttribute("parseWidgets") == "false") {
+			return {};
+		}
+
+		parsedNodeSet[tagName] = [];
+		var pos = tagName.indexOf(":");
+		if(pos>0){
+			var ns = tagName.substring(0,pos);
+			parsedNodeSet["ns"] = ns;
+			// honor user namespace filters
+			if((dojo.ns)&&(!dojo.ns.allow(ns))){process=false;}
+		}
+
+		if(process){
+			var attributeSet = this.parseAttributes(node);
+			for(var attr in attributeSet){
+				if((!parsedNodeSet[tagName][attr])||(typeof parsedNodeSet[tagName][attr] != "array")){
+					parsedNodeSet[tagName][attr] = [];
+				}
+				parsedNodeSet[tagName][attr].push(attributeSet[attr]);
+			}	
+			// FIXME: we might want to make this optional or provide cloning instead of
+			// referencing, but for now, we include a node reference to allow
+			// instantiated components to figure out their "roots"
+			parsedNodeSet[tagName].nodeRef = node;
+			parsedNodeSet.tagName = tagName;
+			parsedNodeSet.index = thisIdx||0;
+		}
+
+		var count = 0;
+		for(var i = 0; i < node.childNodes.length; i++){
+			var tcn = node.childNodes.item(i);
+			switch(tcn.nodeType){
+				case  dojo.dom.ELEMENT_NODE: // element nodes, call this function recursively
+					count++;
+					var ctn = getDojoTagName(tcn) || getTagName(tcn);
+					if(!parsedNodeSet[ctn]){
+						parsedNodeSet[ctn] = [];
+					}
+					parsedNodeSet[ctn].push(this.parseElement(tcn, true, optimizeForDojoML, count));
+					if(	(tcn.childNodes.length == 1)&&
+						(tcn.childNodes.item(0).nodeType == dojo.dom.TEXT_NODE)){
+						parsedNodeSet[ctn][parsedNodeSet[ctn].length-1].value = tcn.childNodes.item(0).nodeValue;
+					}
+					break;
+				case  dojo.dom.TEXT_NODE: // if a single text node is the child, treat it as an attribute
+					if(node.childNodes.length == 1){
+						parsedNodeSet[tagName].push({ value: node.childNodes.item(0).nodeValue });
+					}
+					break;
+				default: break;
+				/*
+				case  dojo.dom.ATTRIBUTE_NODE: // attribute node... not meaningful here
+					break;
+				case  dojo.dom.CDATA_SECTION_NODE: // cdata section... not sure if this would ever be meaningful... might be...
+					break;
+				case  dojo.dom.ENTITY_REFERENCE_NODE: // entity reference node... not meaningful here
+					break;
+				case  dojo.dom.ENTITY_NODE: // entity node... not sure if this would ever be meaningful
+					break;
+				case  dojo.dom.PROCESSING_INSTRUCTION_NODE: // processing instruction node... not meaningful here
+					break;
+				case  dojo.dom.COMMENT_NODE: // comment node... not not sure if this would ever be meaningful 
+					break;
+				case  dojo.dom.DOCUMENT_NODE: // document node... not sure if this would ever be meaningful
+					break;
+				case  dojo.dom.DOCUMENT_TYPE_NODE: // document type node... not meaningful here
+					break;
+				case  dojo.dom.DOCUMENT_FRAGMENT_NODE: // document fragment node... not meaningful here
+					break;
+				case  dojo.dom.NOTATION_NODE:// notation node... not meaningful here
+					break;
+				*/
+			}
+		}
+		//return (hasParentNodeSet) ? parsedNodeSet[node.tagName] : parsedNodeSet;
+		//if(parsedNodeSet.tagName)dojo.debug("parseElement: RETURNING NODE WITH TAGNAME "+parsedNodeSet.tagName);
+		return parsedNodeSet;
+	};
+
+	/* parses a set of attributes on a node into an object tree */
+	this.parseAttributes = function(node){
+		var parsedAttributeSet = {};
+		var atts = node.attributes;
+		// TODO: should we allow for duplicate attributes at this point...
+		// would any of the relevant dom implementations even allow this?
+		var attnode, i=0;
+		while((attnode=atts[i++])){
+			if((dojo.render.html.capable)&&(dojo.render.html.ie)){
+				if(!attnode){ continue; }
+				if((typeof attnode == "object")&&
+					(typeof attnode.nodeValue == 'undefined')||
+					(attnode.nodeValue == null)||
+					(attnode.nodeValue == '')){ 
+					continue; 
+				}
+			}
+
+			var nn = attnode.nodeName.split(":");
+			nn = (nn.length == 2) ? nn[1] : attnode.nodeName;
+						
+			parsedAttributeSet[nn] = { 
+				value: attnode.nodeValue 
+			};
+		}
+		return parsedAttributeSet;
+	};
+};

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/xml/XslTransform.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/xml/XslTransform.js?view=auto&rev=514083
==============================================================================
--- struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/xml/XslTransform.js (added)
+++ struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/xml/XslTransform.js Fri Mar  2 21:48:54 2007
@@ -0,0 +1,188 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.xml.XslTransform");
+
+dojo.xml.XslTransform = function(/*String*/ xsltUri) {
+	//	summary:
+	//	dojo.xml.XslTransform is a convenience object that takes the URI String 
+	//		of an XSL file as a constructor argument.
+	//	After each transformation all parameters will be cleared.
+
+	//	Note this is supported by IE and Mozilla ONLY.
+
+	dojo.debug("XslTransform is supported by Internet Explorer and Mozilla, with limited support in Opera 9 (no document function support).");
+	var IS_IE = window.ActiveXObject ? true : false;
+	var ACTIVEX_DOMS = [
+		"Msxml2.DOMDocument.5.0", 
+		"Msxml2.DOMDocument.4.0", 
+		"Msxml2.DOMDocument.3.0", 
+		"MSXML2.DOMDocument", 
+		"MSXML.DOMDocument", 
+		"Microsoft.XMLDOM"
+	];
+	var ACTIVEX_FT_DOMS = [
+		"Msxml2.FreeThreadedDOMDocument.5.0", 
+		"MSXML2.FreeThreadedDOMDocument.4.0", 
+		"MSXML2.FreeThreadedDOMDocument.3.0"
+	];
+	var ACTIVEX_TEMPLATES = [
+		"Msxml2.XSLTemplate.5.0", 
+		"Msxml2.XSLTemplate.4.0", 
+		"MSXML2.XSLTemplate.3.0"
+	];
+  
+	function getActiveXImpl(activeXArray) {
+		for (var i=0; i < activeXArray.length; i++) {
+			try {
+				var testObj = new ActiveXObject(activeXArray[i]);
+				if (testObj) {
+					return activeXArray[i];
+				}
+			} catch (e) {}
+		}
+		dojo.raise("Could not find an ActiveX implementation in:\n\n " + activeXArray);
+	}
+    
+    if (xsltUri == null || xsltUri == undefined) {
+        dojo.raise("You must pass the URI String for the XSL file to be used!");
+        return false;
+    }
+    
+    var xsltDocument = null;
+    var xsltProcessor = null;
+    if (IS_IE) {
+        xsltDocument = new ActiveXObject(getActiveXImpl(ACTIVEX_FT_DOMS));
+        xsltDocument.async = false;
+    } else {
+        xsltProcessor = new XSLTProcessor();
+        xsltDocument = document.implementation.createDocument("", "", null);
+        xsltDocument.addEventListener("load", onXslLoad, false);
+    }
+    xsltDocument.load(xsltUri);
+    
+    if (IS_IE) {
+        var xslt = new ActiveXObject(getActiveXImpl(ACTIVEX_TEMPLATES));
+        xslt.stylesheet = xsltDocument;  
+        xsltProcessor = xslt.createProcessor();
+    }
+      
+    function onXslLoad() {
+        xsltProcessor.importStylesheet(xsltDocument); 
+    }
+  
+    function getResultDom(xmlDoc, params) {
+      if (IS_IE) {
+          addIeParams(params);
+          var result = getIeResultDom(xmlDoc);
+          removeIeParams(params);   
+          return result;
+      } else {
+          return getMozillaResultDom(xmlDoc, params);
+      }
+    }
+    
+    function addIeParams(params) {
+        if (params != null) {
+          for (var i=0; i<params.length; i++) 
+              xsltProcessor.addParameter(params[i][0], params[i][1]);
+        }
+    }
+    
+    function removeIeParams(params) {
+        if (params != null) {
+            for (var i=0; i<params.length; i++) 
+                xsltProcessor.addParameter(params[i][0], "");
+        }
+    }
+    
+    function getIeResultDom(xmlDoc) {
+        xsltProcessor.input = xmlDoc;
+        var outDoc = new ActiveXObject(getActiveXImpl(ACTIVEX_DOMS));
+        outDoc.async = false;  
+        outDoc.validateOnParse = false;
+        xsltProcessor.output = outDoc;
+        xsltProcessor.transform();
+        if (outDoc.parseError.errorCode != 0) {
+            var err = outDoc.parseError;
+			dojo.raise("err.errorCode: " + err.errorCode + "\n\nerr.reason: " + err.reason + "\n\nerr.url: " + err.url + "\n\nerr.srcText: " + err.srcText);
+        }
+        return outDoc;
+    }
+    
+    function getIeResultStr(xmlDoc, params) {
+        xsltProcessor.input = xmlDoc;
+        xsltProcessor.transform();    
+        return xsltProcessor.output;
+    }
+    
+    function addMozillaParams(params) {
+        if (params != null) {
+            for (var i=0; i<params.length; i++) 
+                xsltProcessor.setParameter(null, params[i][0], params[i][1]);
+        }
+    }
+    
+    function getMozillaResultDom(xmlDoc, params) {
+        addMozillaParams(params);
+        var resultDoc = xsltProcessor.transformToDocument(xmlDoc);
+        xsltProcessor.clearParameters();
+        return resultDoc;
+    }
+    
+    function getMozillaResultStr(xmlDoc, params, parentDoc) {
+        addMozillaParams(params);
+        var resultDoc = xsltProcessor.transformToFragment(xmlDoc, parentDoc);
+        var serializer = new XMLSerializer();
+        xsltProcessor.clearParameters();
+        return serializer.serializeToString(resultDoc);
+    }
+  
+    this.getResultString = function(/*XMLDocument*/ xmlDoc, /*2 Dimensional Array*/params, /*HTMLDocument*/parentDoc) {
+        var content = null;
+        if (IS_IE) {
+            addIeParams(params);
+            content = getIeResultStr(xmlDoc, params);
+            removeIeParams(params);  
+        } else {
+            content = getMozillaResultStr(xmlDoc, params, parentDoc);
+        } 
+        //dojo.debug(content);
+        return content;
+    };
+  
+    this.transformToContentPane = function(/*XMLDocument*/ xmlDoc, /*2 Dimensional Array*/params, /*ContentPane*/contentPane, /*HTMLDocument*/parentDoc) {
+        var content = this.getResultString(xmlDoc, params, parentDoc);
+        contentPane.setContent(content);
+    };
+      
+    this.transformToRegion = function(/*XMLDocument*/ xmlDoc, /*2 Dimensional Array*/params, /*HTMLElement*/region, /*HTMLDocument*/parentDoc) {
+        try {
+            var content = this.getResultString(xmlDoc, params, parentDoc);
+            region.innerHTML = content;
+        } catch (e) {
+            dojo.raise(e.message + "\n\n xsltUri: " + xsltUri)
+        }
+    };
+  
+    this.transformToDocument = function(/*XMLDocument*/ xmlDoc, /*2 Dimensional Array*/params) {
+        return getResultDom(xmlDoc, params);
+    }
+  
+    this.transformToWindow = function(/*XMLDocument*/ xmlDoc, /*2 Dimensional Array*/params, /*HTMLDocument*/windowDoc, /*HTMLDocument*/parentDoc) {
+        try {
+            windowDoc.open();
+            windowDoc.write(this.getResultString(xmlDoc, params, parentDoc));
+            windowDoc.close();
+        } catch (e) {
+            dojo.raise(e.message + "\n\n xsltUri: " + xsltUri)
+        }
+    };
+};

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/xml/__package__.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/xml/__package__.js?view=auto&rev=514083
==============================================================================
--- struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/xml/__package__.js (added)
+++ struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/xml/__package__.js Fri Mar  2 21:48:54 2007
@@ -0,0 +1,18 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.require("dojo.xml.Parse");
+dojo.kwCompoundRequire({
+	common:		["dojo.dom"],
+    browser: 	["dojo.html.*"],
+    dashboard: 	["dojo.html.*"],
+    svg: 		["dojo.xml.svgUtil"]
+});
+dojo.provide("dojo.xml.*");

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/xml/svgUtil.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/xml/svgUtil.js?view=auto&rev=514083
==============================================================================
--- struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/xml/svgUtil.js (added)
+++ struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/src/xml/svgUtil.js Fri Mar  2 21:48:54 2007
@@ -0,0 +1,32 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.xml.svgUtil");
+// FIXME: add imports for deps!
+
+dojo.xml.svgUtil = new function(){
+
+	this.getInnerWidth = function(node){
+		// FIXME: need to find out from dylan how to 
+	}
+
+	this.getOuterWidth = function(node){
+		
+	}
+
+	this.getInnerHeight = function(node){
+		
+	}
+
+	this.getOuterHeight = function(node){
+		
+	}
+
+}

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/storage_dialog.swf
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/storage_dialog.swf?view=auto&rev=514083
==============================================================================
Binary file - no diff available.

Propchange: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/storage_dialog.swf
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/ComboBox.css
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/ComboBox.css?view=auto&rev=514083
==============================================================================
--- struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/ComboBox.css (added)
+++ struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/ComboBox.css Fri Mar  2 21:48:54 2007
@@ -0,0 +1,68 @@
+.dojoComboBoxOuter {
+	border: 0px !important;
+	margin: 0px !important;
+	padding: 0px !important;
+	background: transparent !important;
+	white-space: nowrap !important;
+}
+
+.dojoComboBox {
+	border: 1px inset #afafaf;
+	margin: 0px;
+	padding: 0px;
+	vertical-align: middle !important;
+	float: none !important;
+	position: static !important;
+	display: inline;
+}
+
+/* the input box */
+input.dojoComboBox {
+	border-right-width: 1px !important;
+	margin-right: 0px !important;
+	padding-right: 0px !important;
+}
+
+/* the down arrow */
+img.dojoComboBox {
+	border-left-width: 0px !important;
+	padding-left: 0px !important;
+	margin-left: 0px !important;
+}
+
+/* IE vertical-alignment calculations can be off by +-1 but these margins are collapsed away */
+.dj_ie img.dojoComboBox {
+	margin-top: 1px;
+	margin-bottom: 1px;
+}
+
+/* the drop down */
+.dojoComboBoxOptions {
+	font-family: Verdana, Helvetica, Garamond, sans-serif;
+	/* font-size: 0.7em; */
+	background-color: white;
+	border: 1px solid #afafaf;
+	position: absolute;
+	z-index: 1000;
+	overflow: auto;
+	cursor: default;
+}
+
+.dojoComboBoxItem {
+	padding-left: 2px;
+	padding-top: 2px;
+	margin: 0px;
+}
+
+.dojoComboBoxItemEven {
+	background-color: #f4f4f4;
+}
+
+.dojoComboBoxItemOdd {
+	background-color: white;
+}
+
+.dojoComboBoxItemHighlight {
+	background-color: #63709A;
+	color: white;
+}

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/Util.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/Util.js?view=auto&rev=514083
==============================================================================
--- struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/Util.js (added)
+++ struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/Util.js Fri Mar  2 21:48:54 2007
@@ -0,0 +1,51 @@
+dojo.provide("struts.Util");
+
+struts.Util.passThroughArgs = function(args, target){
+  // pass through the extra args, catering for special cases of style and class for html elements
+  for (n in args) {
+    var v = args[n];
+    if (n == "style") {
+      target.style.cssText = v;
+    }else if (n == "class") {
+      target.className = v;
+    }else if (n == "dojoType") {
+    }else if (n == "dojotype") {
+    }else{
+      target[n] = v;
+    }
+  }
+}
+
+struts.Util.passThroughWidgetTagContent = function(widget, frag, target) {
+  // fill in the target with the contents of the widget tag
+  var widgetTag = frag["dojo:" + widget.widgetType.toLowerCase()].nodeRef;
+  if(widgetTag) target.innerHTML = widgetTag.innerHTML;
+}
+
+struts.Util.copyProperties = function(source, target){
+  // pass through the extra args, catering for special cases of style and class for html elements
+  for (key in source) target[key] = source[key];
+}
+
+
+struts.Util.globalCallbackCount = 0;
+
+struts.Util.makeGlobalCallback = function(target) {
+  var name = 'callback_hack_' + struts.Util.globalCallbackCount++;
+  window[name] = target;
+  return name;
+}
+
+struts.Util.setTimeout = function(callback, method, millis) {
+  window.setTimeout(callback + "." + method + "()", millis);
+}
+struts.Util.clearTimeout = function(callback) {
+  window.clearTimeout(callback);
+}
+
+
+struts.Util.nextIdValue = 0;
+
+struts.Util.nextId = function(scope) {
+  return (scope==null?"id":scope) + struts.Util.nextIdValue++;
+}

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/tooltip.gif
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/tooltip.gif?view=auto&rev=514083
==============================================================================
Binary file - no diff available.

Propchange: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/tooltip.gif
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/Bind.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/Bind.js?view=auto&rev=514083
==============================================================================
--- struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/Bind.js (added)
+++ struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/Bind.js Fri Mar  2 21:48:54 2007
@@ -0,0 +1,338 @@
+dojo.provide("struts.widget.Bind");
+
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.io");
+
+dojo.widget.defineWidget(
+  "struts.widget.Bind",
+  dojo.widget.HtmlWidget, {
+  widgetType : "Bind",
+  executeScripts : false,
+  targets : "",
+  targetsArray : null,
+  href : "",
+  handler : "",
+
+  //messages
+  loadingText : "Loading...",
+  errorText : "",
+  showError : true,
+  showLoading : true,
+
+  //pub/sub events
+  listenTopics : "",
+  notifyTopics : "",
+  notifyTopicsArray : null,
+  beforeNotifyTopics : "",
+  beforeNotifyTopicsArray : null,
+  afterNotifyTopics : "",
+  afterNotifyTopicsArray : null,
+  errorNotifyTopics : "",
+  errorNotifyTopicsArray : "",
+  
+  //callbacks
+  beforeLoading : "",
+  afterLoading : "",
+
+  formId : "",
+  formFilter : "",
+  formNode : null,
+
+  event : "",
+  indicator : "",
+
+  parseContent : true,
+  postCreate : function() {
+    var self = this;
+
+    //attach listeners
+    if(!dojo.string.isBlank(this.listenTopics)) {
+      this.log("Listening to " + this.listenTopics + " to refresh");
+      var topics = this.listenTopics.split(",");
+      if(topics) {
+        dojo.lang.forEach(topics, function(topic){
+          dojo.event.topic.subscribe(topic, self, "reloadContents");
+        });
+      }
+    }
+
+    //topics
+    if(!dojo.string.isBlank(this.notifyTopics)) {
+      this.notifyTopicsArray = this.notifyTopics.split(",");
+    }
+    
+    //before topics
+    if(!dojo.string.isBlank(this.beforeNotifyTopcis)) {
+      this.beforeNotifyTopcisArray = this.beforeNotifyTopics.split(",");
+    }
+    
+    //after topics
+    if(!dojo.string.isBlank(this.afterNotifyTopcis)) {
+      this.afterNotifyTopcisArray = this.afterNotifyTopics.split(",");
+    }
+    
+    //error topics
+    if(!dojo.string.isBlank(this.errorNotifyTopcis)) {
+      this.errorNotifyTopcisArray = this.errorNotifyTopics.split(",");
+    }
+
+    if(!dojo.string.isBlank(this.targets)) {
+      //split targets
+      this.targetsArray = this.targets.split(",");
+    }
+
+    if(!dojo.string.isBlank(this.event)) {
+      dojo.event.connect(this.domNode, this.event, function(evt) {
+        evt.preventDefault();
+        evt.stopPropagation();
+        self.reloadContents();
+      });
+    }
+
+    if(dojo.string.isBlank(this.href) && dojo.string.isBlank(this.formId)) {
+      //no href and no formId, we must be inside a form
+      this.formNode = dojo.dom.getFirstAncestorByTag(this.domNode, "form");
+    } else {
+      this.formNode = dojo.byId(this.formId);
+    }
+
+    if(this.formNode && dojo.string.isBlank(this.href)) {
+      this.href = this.formNode.action;
+    }
+
+    if(!dojo.string.isBlank(this.formId)) {
+      this.formNode = dojo.byId(this.formId);
+    }
+  },
+
+  log : function(text) {
+    dojo.debug("[" + (this.widgetId ? this.widgetId : "unknown")  + "] " + text);
+  },
+
+  setContent : function(text) {
+    if(this.targetsArray) {
+      var self = this;
+	  var xmlParser = new dojo.xml.Parse();
+      dojo.lang.forEach(this.targetsArray, function(target) {
+        var node = dojo.byId(target);
+        node.innerHTML = text;
+
+        if(self.parseContent && text != self.loadingText){
+          var frag  = xmlParser.parseElement(node, null, true);
+          dojo.widget.getParser().createSubComponents(frag, dojo.widget.byId(target));
+		}
+      });
+    }
+  },
+
+  bindHandler : function(type, data, e) {
+     //hide indicator
+     dojo.html.hide(this.indicator);
+
+     //post script
+     if(!dojo.string.isBlank(this.afterLoading)) {
+       this.log("Executing " + this.afterLoading);
+       eval(this.afterLoading);
+     }
+     //publish topics
+     this.notify(data, type, e);
+
+     if(type == "load") {
+       if(this.executeScripts) {
+         //update targets content
+         var parsed = this.parse(data);
+         //eval scripts
+         if(parsed.scripts && parsed.scripts.length > 0) {
+           var scripts = "";
+           for(var i = 0; i < parsed.scripts.length; i++){
+             scripts += parsed.scripts[i];
+           }
+           (new Function('_container_', scripts+'; return this;'))(this);
+         }
+         this.setContent(parsed.text);
+       }
+       else {
+         this.setContent(data);
+       }
+     } else {
+       if(this.showError) {
+         var message = dojo.string.isBlank(this.errorText) ? e.message : this.errorText;
+         this.setContent(message);
+       }
+     }
+  },
+
+  notify : function(data, type, e) {
+    var self = this;
+    //general topics
+    if(this.notifyTopicsArray) {
+      dojo.lang.forEach(this.notifyTopicsArray, function(topic) {
+        try {
+          dojo.event.topic.publish(topic, data, type, e);
+        } catch(ex){
+		  self.log(ex);
+        }
+      });
+    }
+    
+    //before, after and error topics
+    var topicsArray = null;
+    switch(type) {
+      case "before":
+        topicsArray = this.beforeNotifyTopicsArray;
+        break;
+      case "load":
+        topicsArray = this.afterNotifyTopicsArray;
+        break;
+      case "error":
+        topicsArray = this.errorNotifyTopicsArray;
+        break;
+    }
+    
+    this.notifyTo(topicsArray, data, e);
+  },
+  
+  notifyTo : function(topicsArray, data, e) {
+    var self = this;
+    if(topicsArray) {
+      dojo.lang.forEach(topicsArray, function(topic) {
+        try {
+          dojo.event.topic.publish(topic, data, e);
+        } catch(ex){
+          self.log(ex);
+        }
+      });
+    }
+  },
+
+  onDownloadStart : function(event) {
+    if(!dojo.string.isBlank(this.beforeLoading)) {
+      //for backward compatibility
+      var data = null;
+      var type = null;
+
+      eval(this.beforeLoading);
+    }
+    if(this.showLoading && !dojo.string.isBlank(this.loadingText)) {
+      event.text = this.loadingText;
+    }
+  },
+
+  reloadContents : function(evt) {
+
+    if(!dojo.string.isBlank(this.handler)) {
+      //use custom handler
+      this.log("Invoking handler: " + this.handler);
+      window[this.handler](this, this.domNode);
+    }
+    else {
+      //pre script
+      if(!dojo.string.isBlank(this.beforeLoading)) {
+        this.log("Executing " + this.beforeLoading);
+        //backward compatibility
+        var data = null;
+        var type = null;
+
+        eval(this.beforeLoading);
+      }
+
+      try {
+          var self = this;
+          var request = {cancel: false};
+          this.notify(this.widgetId, "before", request);
+          if(request.cancel) {
+            this.log("Request canceled");
+            return;
+          }
+
+          //if the href is null, we still call the "beforeLoading"
+          // and publish the notigy topics
+          if(dojo.string.isBlank(this.href)) {
+            return;
+          }
+
+          //if there is a parent form, and it has a "onsubmit"
+          //execute it, validation is usually there
+          if(this.formNode && this.formNode.onsubmit != null) {
+            var makeRequest = this.formNode.onsubmit.call(evt);
+            if(makeRequest != null && !makeRequest) {
+              this.log("Request canceled by 'onsubmit' of the form");
+              return;
+            }
+          }
+
+          //show indicator
+          dojo.html.show(this.indicator);
+		  if(this.showLoading) {
+            this.setContent(this.loadingText);
+          }
+
+          dojo.io.bind({
+            url: this.href,
+            useCache: false,
+            preventCache: true,
+            formNode: self.formNode,
+            formFilter: window[self.formFilter],
+            handler: function(type, data, e) {
+              dojo.lang.hitch(self, "bindHandler")(type, data, e);
+            },
+            mimetype: "text/html"
+         });
+      }
+      catch(ex) {
+        var message = dojo.string.isBlank(this.errorText) ? ex : this.errorText;
+        this.setContent(message);
+      }
+    }
+  },
+
+  //from Dojo's ContentPane
+  parse : function(s) {
+    this.log("Parsing: " + s);
+    var match = [];
+    var tmp = [];
+    var scripts = [];
+    while(match){
+      match = s.match(/<script([^>]*)>([\s\S]*?)<\/script>/i);
+      if(!match){ break; }
+      if(match[1]){
+        attr = match[1].match(/src=(['"]?)([^"']*)\1/i);
+        if(attr){
+          // remove a dojo.js or dojo.js.uncompressed.js from remoteScripts
+          // we declare all files with dojo.js as bad, regardless of folder
+          var tmp2 = attr[2].search(/.*(\bdojo\b(?:\.uncompressed)?\.js)$/);
+          if(tmp2 > -1){
+            this.log("Security note! inhibit:"+attr[2]+" from  beeing loaded again.");
+          }
+        }
+      }
+      if(match[2]){
+        // strip out all djConfig variables from script tags nodeValue
+        // this is ABSOLUTLY needed as reinitialize djConfig after dojo is initialised
+        // makes a dissaster greater than Titanic, update remove writeIncludes() to
+        var sc = match[2].replace(/(?:var )?\bdjConfig\b(?:[\s]*=[\s]*\{[^}]+\}|\.[\w]*[\s]*=[\s]*[^;\n]*)?;?|dojo\.hostenv\.writeIncludes\(\s*\);?/g, "");
+        if(!sc){ continue; }
+
+        // cut out all dojo.require (...) calls, if we have execute
+        // scripts false widgets dont get there require calls
+        // does suck out possible widgetpackage registration as well
+        tmp = [];
+        while(tmp){
+          tmp = sc.match(/dojo\.(?:(?:require(?:After)?(?:If)?)|(?:widget\.(?:manager\.)?registerWidgetPackage)|(?:(?:hostenv\.)?setModulePrefix))\((['"]).*?\1\)\s*;?/);
+          if(!tmp){ break;}
+          sc = sc.replace(tmp[0], "");
+        }
+        scripts.push(sc);
+      }
+      s = s.replace(/<script[^>]*>[\s\S]*?<\/script>/i, "");
+    }
+
+    return {
+      text: s,
+      scripts: scripts
+    };
+  }
+});
+
+
+

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindAnchor.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindAnchor.js?view=auto&rev=514083
==============================================================================
--- struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindAnchor.js (added)
+++ struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindAnchor.js Fri Mar  2 21:48:54 2007
@@ -0,0 +1,21 @@
+dojo.provide("struts.widget.BindAnchor");
+
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.io");
+dojo.require("struts.widget.Bind");
+
+dojo.widget.defineWidget(
+  "struts.widget.BindAnchor",
+  struts.widget.Bind, {
+  widgetType : "BindAnchor",
+
+  event: "onclick",
+
+  postCreate : function() {
+     struts.widget.BindAnchor.superclass.postCreate.apply(this);
+     this.domNode.href = "#";
+  }
+});
+
+
+

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindDiv.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindDiv.js?view=auto&rev=514083
==============================================================================
--- struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindDiv.js (added)
+++ struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/BindDiv.js Fri Mar  2 21:48:54 2007
@@ -0,0 +1,254 @@
+dojo.provide("struts.widget.BindDiv");
+
+dojo.require("dojo.io");
+dojo.require("dojo.widget.ContentPane");
+dojo.require("dojo.lang.timing.Timer");
+
+dojo.widget.defineWidget(
+  "struts.widget.BindDiv",
+  dojo.widget.ContentPane, {
+    widgetType : "BindDiv",
+
+    //from ContentPane
+    href : "",
+    extractContent : false,
+    parseContent : false,
+    cacheContent : false,
+    refreshOnShow : false,
+    executeScripts : false,
+
+    //update times
+    updateFreq : 0,
+    delay : 0,
+    autoStart : true,
+    timer : null,
+
+    //messages
+    loadingText : "Loading...",
+    showLoading : true,
+    errorText : "",
+    showError : true,
+
+    //pub/sub events
+    listenTopics : "",
+    notifyTopics : "",
+    notifyTopicsArray : null,
+    stopTimerListenTopics : "",
+    startTimerListenTopics : "",
+
+    //callbacks
+    beforeLoading : "",
+    afterLoading : "",
+
+    formId : "",
+    formFilter : "",
+    firstTime : true,
+
+    indicator: "",
+
+	//make dojo process the content
+	parseContent : true,
+
+    onDownloadStart : function(event) {
+      if(!dojo.string.isBlank(this.beforeLoading)) {
+        this.log("Executing " + this.beforeLoading);
+        var result = eval(this.beforeLoading);
+        if(result !== null && !result) {
+          return;
+        }
+      }
+      if(!this.showLoading) {
+        event.returnValue = false;
+        return;
+      }
+      if(this.showLoading && !dojo.string.isBlank(this.loadingText)) {
+        event.text = this.loadingText;
+      }
+    },
+
+    onDownloadError : function(event) {
+      this.onError(event);
+    },
+
+    onContentError : function(event) {
+      this.onError(event);
+    },
+
+    onExecError : function(event) {
+      this.onError(event);
+    },
+
+    onError : function(event) {
+      if(this.showError) {
+        if(!dojo.string.isBlank(this.errorText)) {
+          event.text = this.errorText;
+        }
+      } else {
+        event.text = "";
+      }
+    },
+
+    notify : function(data, type, e) {
+      if(this.notifyTopicsArray) {
+        var self = this;
+        dojo.lang.forEach(this.notifyTopicsArray, function(topic) {
+          try {
+            dojo.event.topic.publish(topic, data, type, e);
+          } catch(ex) {
+            self.log(ex);
+          }
+        });
+      }
+    },
+
+    postCreate : function(args, frag) {
+      struts.widget.BindDiv.superclass.postCreate.apply(this);
+
+      var self = this;
+      var hitchedRefresh = function() {
+        dojo.lang.hitch(self, "refresh")();
+      };
+      var hitchedStartTimer = function() {
+        dojo.lang.hitch(self, "startTimer")();
+      };
+
+      if(this.updateFreq > 0) {
+        this.timer = new dojo.lang.timing.Timer(this.updateFreq);
+        this.timer.onTick = hitchedRefresh;
+
+        //start the timer
+        if(this.autoStart) {
+          //start after delay
+          if(this.delay > 0) {
+            //start time after delay
+            dojo.lang.setTimeout(this.delay, hitchedStartTimer);
+          } else {
+            //start timer now
+            this.startTimer();
+          }
+        }
+      } else {
+        //no timer
+        if(this.delay > 0) {
+          //load after delay
+          dojo.lang.setTimeout(this.delay, hitchedRefresh);
+        }
+      }
+
+      //start the timer
+      if(this.autoStart) {
+        //start after delay
+        if(this.delay > 0) {
+          if(this.updateFreq > 0) {
+            //start time after delay
+          	dojo.lang.setTimeout(this.delay, hitchedStartTimer);
+          } else {
+            //load after delay
+            dojo.lang.setTimeout(this.delay, hitchedRefresh);
+          }
+        }
+      }
+
+      //attach listeners
+      if(!dojo.string.isBlank(this.listenTopics)) {
+        this.log("Listening to " + this.listenTopics + " to refresh");
+        var topics = this.listenTopics.split(",");
+        if(topics) {
+          dojo.lang.forEach(topics, function(topic){
+            dojo.event.topic.subscribe(topic, self, "refresh");
+          });
+        }
+      }
+
+      if(!dojo.string.isBlank(this.notifyTopics)) {
+        this.notifyTopicsArray = this.notifyTopics.split(",");
+      }
+
+      if(!dojo.string.isBlank(this.stopTimerListenTopics)) {
+        this.log("Listening to " + this.stopTimerListenTopics + " to stop timer");
+        var stopTopics = this.stopTimerListenTopics.split(",");
+        if(stopTopics) {
+          dojo.lang.forEach(stopTopics, function(topic){
+            dojo.event.topic.subscribe(topic, self, "stopTimer");
+          });
+        }
+      }
+
+      if(!dojo.string.isBlank(this.startTimerListenTopics)) {
+        this.log("Listening to " + this.stopTimerListenTopics + " to start timer");
+        var startTopics = this.startTimerListenTopics.split(",");
+        if(startTopics) {
+          dojo.lang.forEach(startTopics, function(topic){
+            dojo.event.topic.subscribe(topic, self, "startTimer");
+          });
+        }
+      }
+    },
+
+    _downloadExternalContent: function(url, useCache) {
+      if(this.firstTime) {
+        this.firstTime = false;
+        if(this.delay > 0) {
+          return;
+        }
+      }
+
+      var request = {cancel: false};
+      this.notify(this.widgetId, "before", request);
+      if(request.cancel) {
+        return;
+      }
+
+      //show indicator
+      dojo.html.show(this.indicator);
+
+      this._handleDefaults("Loading...", "onDownloadStart");
+      var self = this;
+      dojo.io.bind({
+        url: url,
+        useCache: useCache,
+        preventCache: !useCache,
+        mimetype: "text/html",
+        formNode: dojo.byId(self.formId),
+        formFilter: window[self.formFilter],
+        handler: function(type, data, e) {
+          //hide indicator
+          dojo.html.hide(self.indicator);
+
+          if(!dojo.string.isBlank(self.afterLoading)) {
+            self.log("Executing " + self.afterLoading);
+            eval(self.afterLoading);
+          }
+
+          self.notify(data, type, null);
+
+          if(type == "load") {
+            self.onDownloadEnd.call(self, url, data);
+          } else {
+            // works best when from a live server instead of from file system
+            self._handleDefaults.call(self, "Error loading '" + url + "' (" + e.status + " "+  e.statusText + ")", "onDownloadError");
+            self.onLoad();
+          }
+        }
+      });
+     },
+
+    log : function(text) {
+      dojo.debug("[" + this.widgetId + "] " + text);
+    },
+
+    stopTimer : function() {
+      if(this.timer && this.timer.isRunning) {
+        this.log("stopping timer");
+        this.timer.stop();
+      }
+    },
+
+    startTimer : function() {
+      if(this.timer && !this.timer.isRunning) {
+        this.log("starting timer with update interval " + this.updateFreq);
+        this.timer.start();
+      }
+    }
+  }
+);

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/ComboBox.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/ComboBox.js?view=auto&rev=514083
==============================================================================
--- struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/ComboBox.js (added)
+++ struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/ComboBox.js Fri Mar  2 21:48:54 2007
@@ -0,0 +1,405 @@
+dojo.provide("struts.widget.ComboBox");
+
+dojo.require("dojo.html.*");
+dojo.require("dojo.widget.ComboBox");
+
+struts.widget.ComboBoxDataProvider = function(/*Array*/ dataPairs, /*Number*/ limit, /*Number*/ timeout){
+  // NOTE: this data provider is designed as a naive reference
+  // implementation, and as such it is written more for readability than
+  // speed. A deployable data provider would implement lookups, search
+  // caching (and invalidation), and a significantly less naive data
+  // structure for storage of items.
+
+  this.data = [];
+  this.searchTimeout = timeout || 500;
+  this.searchLimit = limit || 30;
+  this.searchType = "STARTSTRING"; // may also be "STARTWORD" or "SUBSTRING"
+  this.caseSensitive = false;
+  // for caching optimizations
+  this._lastSearch = "";
+  this._lastSearchResults = null;
+
+  this.formId = "";
+  this.formFilter = "";
+  this.firstRequest = true;
+
+  this.cbox = null;
+  this.init = function(/*Widget*/ cbox, /*DomNode*/ node){
+    this.cbox = cbox;
+    this.formId = cbox.formId;
+    this.formFilter = cbox.formFilter;
+
+    if(!dojo.string.isBlank(cbox.dataUrl)){
+      this.getData(cbox.dataUrl);
+    }else{
+      // check to see if we can populate the list from <option> elements
+      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++){
+          var text = opts[x].textContent || opts[x].innerText || opts[x].innerHTML;
+          var keyValArr = [String(text), String(opts[x].value)];
+          data.push(keyValArr);
+          if(opts[x].selected){
+            cbox.setAllValues(keyValArr[0], keyValArr[1]);
+          }
+        }
+        this.setData(data);
+      }
+    }
+  };
+
+  this.getData = function(/*String*/ url){
+    //show indicator
+    dojo.html.show(this.cbox.indicator);
+
+    dojo.io.bind({
+      url: url,
+      formNode: dojo.byId(this.formId),
+      formFilter: window[this.formFilter],
+      load: dojo.lang.hitch(this, function(type, data, evt) {
+        //show indicator
+        dojo.html.hide(this.cbox.indicator);
+
+        //if notifyTopics is published on the first request (onload)
+        //the value of listeners will be reset
+        if(!this.firstRequest) {
+          this.cbox.notify.apply(this.cbox, [data, type, evt]);
+        }
+        if(!dojo.lang.isArray(data)) {
+           //if there is a dataFieldName, take it
+           if(!dojo.string.isBlank(this.cbox.dataFieldName) && data[this.cbox.dataFieldName] != null) {
+             arrData = data[this.cbox.dataFieldName];
+           } else {
+             //try to find a match
+             var arrData = null;
+             for(var key in data){
+               //does it start with the field name? take it
+               if(key == this.cbox.name) {
+                 arrData = data[key];
+                 break;
+               }
+               //grab the first array found, we will use it if nothing else
+               //is found
+               if(!arrData && dojo.lang.isArray(data[key])) {
+                 arrData = data = data[key];
+               }
+             }
+           }
+           
+           data = arrData;
+        }
+        this.setData(data);
+        this.firstRequest = false;
+      }),
+      mimetype: "text/json"
+    });
+  };
+
+  this.startSearch = function(/*String*/ searchStr, /*String*/ type, /*Boolean*/ ignoreLimit){
+    // FIXME: need to add timeout handling here!!
+    this._preformSearch(searchStr, type, ignoreLimit);
+  };
+
+  this._preformSearch = function(/*String*/ searchStr, /*String*/ type, /*Boolean*/ ignoreLimit){
+    //
+    //  NOTE: this search is LINEAR, which means that it exhibits perhaps
+    //  the worst possible speed characteristics of any search type. It's
+    //  written this way to outline the responsibilities and interfaces for
+    //  a search.
+    //
+    var st = type||this.searchType;
+    // FIXME: this is just an example search, which means that we implement
+    // only a linear search without any of the attendant (useful!) optimizations
+    var ret = [];
+    if(!this.caseSensitive){
+      searchStr = searchStr.toLowerCase();
+    }
+    for(var x=0; x<this.data.length; x++){
+      if(!this.data[x]) {
+        //needed for IE
+        continue;
+      }
+      if((!ignoreLimit)&&(ret.length >= this.searchLimit)){
+        break;
+      }
+      // FIXME: we should avoid copies if possible!
+      var dataLabel = new String((!this.caseSensitive) ? this.data[x][0].toLowerCase() : this.data[x][0]);
+      if(dataLabel.length < searchStr.length){
+        // this won't ever be a good search, will it? What if we start
+        // to support regex search?
+        continue;
+      }
+
+      if(st == "STARTSTRING"){
+        if(searchStr == dataLabel.substr(0, searchStr.length)){
+          ret.push(this.data[x]);
+        }
+      }else if(st == "SUBSTRING"){
+        // this one is a gimmie
+        if(dataLabel.indexOf(searchStr) >= 0){
+          ret.push(this.data[x]);
+        }
+      }else if(st == "STARTWORD"){
+        // do a substring search and then attempt to determine if the
+        // preceeding char was the beginning of the string or a
+        // whitespace char.
+        var idx = dataLabel.indexOf(searchStr);
+        if(idx == 0){
+          // implicit match
+          ret.push(this.data[x]);
+        }
+        if(idx <= 0){
+          // if we didn't match or implicily matched, march onward
+          continue;
+        }
+        // otherwise, we have to go figure out if the match was at the
+        // start of a word...
+        // this code is taken almost directy from nWidgets
+        var matches = false;
+        while(idx!=-1){
+          // make sure the match either starts whole string, or
+          // follows a space, or follows some punctuation
+          if(" ,/(".indexOf(dataLabel.charAt(idx-1)) != -1){
+            // FIXME: what about tab chars?
+            matches = true; break;
+          }
+          idx = dataLabel.indexOf(searchStr, idx+1);
+        }
+        if(!matches){
+          continue;
+        }else{
+          ret.push(this.data[x]);
+        }
+      }
+    }
+    this.provideSearchResults(ret);
+  };
+
+  this.provideSearchResults = function(/*Array*/ resultsDataPairs){
+  };
+
+  this.addData = function(/*Array*/ pairs){
+    // FIXME: incredibly naive and slow!
+    this.data = this.data.concat(pairs);
+  };
+
+  this.setData = function(/*Array*/ pdata){
+    // populate this.data and initialize lookup structures
+    this.data = pdata;
+    //all ellements must be a key and value pair
+    for(var i = 0; i < this.data.length; i++) {
+      var element = this.data[i];
+      if(!dojo.lang.isArray(element)) {
+        this.data[i] = [element, element];
+      }
+    }
+  };
+
+  if(dataPairs){
+    this.setData(dataPairs);
+  }
+};
+
+dojo.widget.defineWidget(
+  "struts.widget.ComboBox",
+  dojo.widget.ComboBox, {
+  widgetType : "ComboBox",
+
+  dropdownHeight: 120,
+  dropdownWidth: 0,
+  itemHeight: 0,
+
+  listenTopics : "",
+  notifyTopics : "",
+  notifyTopicsArray : null,
+
+  indicator : "",
+
+  formId : "",
+  formFilter : "",
+  dataProviderClass: "struts.widget.ComboBoxDataProvider",
+
+  loadOnType : false,
+  loadMinimum : 3,
+
+  initialValue : "",
+  initialKey : "",
+
+  visibleDownArrow : true,
+  fadeTime : 100,
+
+  //dojo has "stringstart" which is invalid
+  searchType: "STARTSTRING",
+
+  dataFieldName : ""  ,
+  keyName: "",
+  templateCssPath: dojo.uri.dojoUri("struts/ComboBox.css"),
+  //from Dojo's  ComboBox
+  showResultList: function() {
+  // Our dear friend IE doesnt take max-height so we need to calculate that on our own every time
+    var childs = this.optionsListNode.childNodes;
+    if(childs.length){
+
+      this.optionsListNode.style.width = this.dropdownWidth === 0 ? (dojo.html.getMarginBox(this.domNode).width-2)+"px" : this.dropdownWidth + "px";
+
+      if(this.itemHeight === 0 || dojo.string.isBlank(this.textInputNode.value)) {
+        this.optionsListNode.style.height = this.dropdownHeight + "px";
+        this.optionsListNode.style.display = "";
+        this.itemHeight = dojo.html.getMarginBox(childs[0]).height;
+      }
+
+      //if there is extra space, adjust height
+      var totalHeight = this.itemHeight * childs.length;
+      if(totalHeight < this.dropdownHeight) {
+        this.optionsListNode.style.height = totalHeight + 2 + "px";
+      }
+
+      this.popupWidget.open(this.domNode, this, this.downArrowNode);
+    } else {
+        this.hideResultList();
+    }
+  },
+
+  openResultList: function(/*Array*/ results){
+    if (!this.isEnabled){
+        return;
+    }
+    this.clearResultList();
+    if(!results.length){
+        this.hideResultList();
+    }
+
+    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 character at the end of the input
+        if((cpos+1) > this.textInputNode.value.length){
+            // only add to input node as we would overwrite Capitalisation of chars
+            this.textInputNode.value += results[0][0].substr(cpos);
+            // 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 typedText = this.textInputNode.value;
+    var even = true;
+    while(results.length){
+        var tr = results.shift();
+        if(tr){
+            var td = document.createElement("div");
+            var text = tr[0];
+            var i = text.toLowerCase().indexOf(typedText.toLowerCase());
+            if(i >= 0) {
+                var pre = text.substring(0, i);
+                var matched = text.substring(i, i + typedText.length);
+                var post = text.substring(i + typedText.length);
+
+                if(!dojo.string.isBlank(pre)) {
+                  td.appendChild(document.createTextNode(pre));
+                }
+                var boldNode = document.createElement("b");
+                td.appendChild(boldNode);
+                boldNode.appendChild(document.createTextNode(matched));
+                td.appendChild(document.createTextNode(post));
+            } else {
+                td.appendChild(document.createTextNode(tr[0]));
+            }
+
+            td.setAttribute("resultName", tr[0]);
+            td.setAttribute("resultValue", tr[1]);
+            td.className = "dojoComboBoxItem "+((even) ? "dojoComboBoxItemEven" : "dojoComboBoxItemOdd");
+            even = (!even);
+            this.optionsListNode.appendChild(td);
+        }
+    }
+
+    // show our list (only if we have content, else nothing)
+    this.showResultList();
+  },
+
+  postCreate : function() {
+    struts.widget.ComboBox.superclass.postCreate.apply(this);
+    var self = this;
+    //events
+    if(!dojo.string.isBlank(this.listenTopics)) {
+      var topics = this.listenTopics.split(",");
+      for(var i = 0; i < topics.length; i++) {
+        dojo.event.topic.subscribe(topics[i], function() {
+          var request = {cancel: false};
+	      self.notify(this.widgetId, "before", request);
+	      if(request.cancel) {
+	        return;
+	      }
+          self.clearValues();
+          self.dataProvider.getData(self.dataUrl);
+        });
+      }
+    }
+
+    if(!dojo.string.isBlank(this.notifyTopics)) {
+      this.notifyTopicsArray = this.notifyTopics.split(",");
+    }
+
+    //better name
+    this.comboBoxSelectionValue.name = dojo.string.isBlank(this.keyName) ? this.name + "Key" : this.keyName;
+
+    //init values
+    this.comboBoxValue.value = this.initialValue;
+    this.comboBoxSelectionValue.value = this.initialKey;
+    this.textInputNode.value = this.initialValue;
+
+    //hide arrow?
+    if(!this.visibleDownArrow) {
+      dojo.html.hide(this.downArrowNode);
+    }
+
+    //search type
+    if(!dojo.string.isBlank(this.searchType)) {
+      this.dataProvider.searchType = this.searchType.toUpperCase();
+    }
+  },
+
+  clearValues : function() {
+  	this.comboBoxValue.value = "";
+    this.comboBoxSelectionValue.value = "";
+    this.textInputNode.value = "";
+  },
+
+  onValueChanged : function(data) {
+    this.notify(data, "valuechanged", null);
+  },
+
+  notify : function(data, type, e) {
+    if(this.notifyTopicsArray) {
+      dojo.lang.forEach(this.notifyTopicsArray, function(topic) {
+        try {
+          dojo.event.topic.publish(topic, data, type, e);
+        } catch(ex) {
+          dojo.debug(ex);
+        }
+      });
+    }
+  },
+
+  startSearchFromInput: function() {
+    var searchStr = this.textInputNode.value;
+    if(this.loadOnType) {
+    	if(searchStr.length >= this.loadMinimum) {
+    	    var nuHref = this.dataUrl + (this.dataUrl.indexOf("?") > -1 ? "&" : "?");
+   		nuHref += this.name + '=' + searchStr;
+   		this.dataProvider.getData(nuHref);
+   		this.startSearch(searchStr);
+    	} else {
+           this.hideResultList();
+        }
+    }
+    else {
+	  this.startSearch(searchStr);
+	}
+  }
+});

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/StrutsTimePicker.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/StrutsTimePicker.js?view=auto&rev=514083
==============================================================================
--- struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/StrutsTimePicker.js (added)
+++ struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/StrutsTimePicker.js Fri Mar  2 21:48:54 2007
@@ -0,0 +1,35 @@
+//If we use "TimePicker" for the name, Dojo get's confused and breaks
+//TODO remove this file on nect Dojo release
+
+dojo.provide("struts.widget.StrutsTimePicker");
+
+dojo.require("dojo.widget.DropdownTimePicker");
+
+dojo.widget.defineWidget(
+  "struts.widget.StrutsTimePicker",
+  dojo.widget.DropdownTimePicker, {
+  widgetType : "TimePicker",
+
+  inputName: "",
+  name: "",
+  
+  postCreate: function() {
+    struts.widget.StrutsTimePicker.superclass.postCreate.apply(this, arguments);
+  
+    if(this.value.toLowerCase() == "today") {
+      this.value = dojo.date.toRfc3339(new Date());
+    }
+
+    this.inputNode.name = this.name;
+    this.valueNode.name = this.inputName;
+  },
+  
+  onSetTime: function() {
+    struts.widget.StrutsTimePicker.superclass.onSetTime.apply(this, arguments);
+    if(this.timePicker.selectedTime.anyTime){
+      this.valueNode.value = "";
+    } else {
+      this.valueNode.value = dojo.date.toRfc3339(this.timePicker.time);
+    }
+  }
+});
\ No newline at end of file

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/__package__.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/__package__.js?view=auto&rev=514083
==============================================================================
--- struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/__package__.js (added)
+++ struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widget/__package__.js Fri Mar  2 21:48:54 2007
@@ -0,0 +1,8 @@
+dojo.kwCompoundRequire({
+	common: ["struts.widget.Bind",
+	         "struts.widget.BindDiv",
+	         "struts.widget.BindAnchor",
+	         "struts.widget.ComboBox",
+             "struts.widget.StrutsTimePicker"]
+});
+dojo.provide("struts.widget.*");

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widgets/dateIcon.gif
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widgets/dateIcon.gif?view=auto&rev=514083
==============================================================================
Binary file - no diff available.

Propchange: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widgets/dateIcon.gif
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widgets/dropdowncontainer.css
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widgets/dropdowncontainer.css?view=auto&rev=514083
==============================================================================
    (empty)

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widgets/timeIcon.gif
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widgets/timeIcon.gif?view=auto&rev=514083
==============================================================================
Binary file - no diff available.

Propchange: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/dojo/struts/widgets/timeIcon.gif
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/inputtransferselect.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/inputtransferselect.js?view=auto&rev=514083
==============================================================================
--- struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/inputtransferselect.js (added)
+++ struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/inputtransferselect.js Fri Mar  2 21:48:54 2007
@@ -0,0 +1,108 @@
+function addOption(objTextBox, objTargetElement) {
+    var value = objTextBox.value;
+    if(value != null && value != '') {
+        objTargetElement.options[objTargetElement.options.length] = new Option(value, value);
+        objTextBox.value = '';
+    }
+}
+
+function removeOptions(objTargetElement) {
+    for(var i=0;i<objTargetElement.options.length;i++) {
+        if(objTargetElement.options[i].selected) {
+            objTargetElement.options[i] = null;
+        }
+    }
+}
+
+function removeAllOptions(objTargetElement) {
+    while(objTargetElement.options.length != 0) {
+        objTargetElement.options[0] = null;
+    }
+}
+
+function selectAllOptionsExceptSome(objTargetElement, type, ptn) {
+    var test = compile(ptn);
+    for (var i = 0; i < objTargetElement.length; i++) {
+        var opt = objTargetElement.options[i];
+        if ((type == 'key' && !test(opt.value)) ||
+              (type == 'text' && !test(opt.text))) {
+            opt.selected = true;
+        } else {
+            opt.selected = false;
+        }    
+    }
+    return false;
+}
+
+function compile(ptn) {
+    if (ptn != undefined) {
+    	if (ptn == '' || !window.RegExp) {
+            return function(val) { return val == ptn; }
+        } else {
+            var reg = new RegExp(ptn);
+            return function (val) {
+                if (val == '') { // ignore empty option added by template
+                	return true;
+                }
+            	return reg.test(val); }
+        }
+    }
+    return function(val) { return false; }
+}
+
+function selectAllOptions(objTargetElement) {
+    for (var i = 0; i < objTargetElement.length; i++) {
+        if (objTargetElement.options[i].value != '') {
+            objTargetElement.options[i].selected = true;    
+        }    
+    }
+    return false;
+}
+
+function moveOptionUp(objTargetElement, type, ptn) {
+	var test = compile(ptn);
+	for (i=0; i<objTargetElement.length; i++) {
+		if (objTargetElement[i].selected) {
+			var v;
+			if (i != 0 && !objTargetElement[i-1].selected) {
+		    	if (type == 'key') {
+		    		v = objTargetElement[i-1].value
+		    	}
+		    	else {
+		    		v = objTargetElement[i-1].text;
+		    	}
+				if (!test(v)) {
+					swapOptions(objTargetElement,i,i-1);
+				}
+		    }
+		}
+	}
+}
+
+function moveOptionDown(objTargetElement, type, ptn) {
+	var test = compile(ptn);
+	for (i=(objTargetElement.length-1); i>= 0; i--) {
+		if (objTargetElement[i].selected) {
+			var v;
+			if ((i != (objTargetElement.length-1)) && !objTargetElement[i+1].selected) {
+		    	if (type == 'key') {
+		    		v = objTargetElement[i].value
+		    	}
+		    	else {
+		    		v = objTargetElement[i].text;
+		    	}
+				if (!test(v)) {
+					swapOptions(objTargetElement,i,i+1);
+				}
+		    }
+		}
+	}
+}
+
+function swapOptions(objTargetElement, first, second) {
+	var opt = objTargetElement.options;
+	var temp = new Option(opt[first].text, opt[first].value, opt[first].defaultSelected, opt[first].selected);
+	var temp2= new Option(opt[second].text, opt[second].value, opt[second].defaultSelected, opt[second].selected);
+	opt[first] = temp2;
+	opt[second] = temp;
+}

Added: struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/niftycorners/layout.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/niftycorners/layout.js?view=auto&rev=514083
==============================================================================
--- struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/niftycorners/layout.js (added)
+++ struts/struts2/trunk/plugins/dojo/src/main/resources/org/apache/struts2/static/niftycorners/layout.js Fri Mar  2 21:48:54 2007
@@ -0,0 +1,13 @@
+window.onload=function(){
+if(!NiftyCheck())
+    return;
+Rounded("div#header","bottom","#D6DEEC","#84B7FF","smooth");
+Rounded("div#header h1","bottom","#84B7FF","#657DA6","small smooth");
+Rounded("div#content","tl bottom","#D6DEEC","#FFF","smooth");
+Rounded("div#nav","tr bottom","#D6DEEC","#95B3DE","smooth");
+Rounded("div#sidenotes","all","#D6DEEC","#B1C0D5","smooth");
+Rounded("form","all","#D6DEEC","#B4CEF7","smooth");
+Rounded("blockquote","tr bl","#FFF","#CDFFAA","border #88D84F");
+Rounded("div#relax","all","#FFF","transparent");
+Rounded("div#footer","all","#D6DEEC","#CCCCCC","small border #fff");
+}