You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by he...@apache.org on 2006/11/13 23:55:14 UTC

svn commit: r474551 [31/49] - in /struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo: ./ src/ src/alg/ src/animation/ src/cal/ src/charting/ src/charting/svg/ src/charting/vml/ src/collections/ src/crypto/ src/data/ src/data/cs...

Modified: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/ContentPane.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/ContentPane.js?view=diff&rev=474551&r1=474550&r2=474551
==============================================================================
--- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/ContentPane.js (original)
+++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/ContentPane.js Mon Nov 13 14:54:45 2006
@@ -1,5 +1,5 @@
 /*
-	Copyright (c) 2004-2005, The Dojo Foundation
+	Copyright (c) 2004-2006, The Dojo Foundation
 	All Rights Reserved.
 
 	Licensed under the Academic Free License version 2.1 or above OR the
@@ -8,9 +8,699 @@
 		http://dojotoolkit.org/community/licensing.shtml
 */
 
-// This widget doesn't do anything; is basically the same as <div>.
-// It's useful as a child of LayoutPane, SplitPane, or TabPane.
-// But note that those classes can contain any widget as a child.
-
 dojo.provide("dojo.widget.ContentPane");
-dojo.requireAfterIf("html", "dojo.widget.html.ContentPane");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.string");
+dojo.require("dojo.string.extras");
+dojo.require("dojo.html.style");
+
+
+// summary:
+//		dojo.widget.ContentPane, a widget that can be used as a standalone widget 
+//		or as a baseclass for other widgets
+//		Handles replacement of document fragment using either external uri or javascript/java 
+//		generated markup or DomNode content, instanciating widgets within content and runs scripts.
+//		Dont confuse it with an iframe, it only needs document fragments.
+//		It's useful as a child of LayoutContainer, SplitContainer, or TabContainer.
+//		But note that those classes can contain any widget as a child.
+dojo.widget.defineWidget(
+	"dojo.widget.ContentPane",
+	dojo.widget.HtmlWidget,
+	function(){
+		// per widgetImpl variables
+		this._styleNodes =  [];
+		this._onLoadStack = [];
+		this._onUnloadStack = [];
+		this._callOnUnload = false;
+		this._ioBindObj;
+		// Function:
+		//		reference holder to the inline scripts container, if scriptSeparation is true
+		//	Note:
+		//		dont change this value externally
+		this.scriptScope; // undefined for now
+
+		// loading option
+		// Object:
+		//		Send in extra args to the dojo.io.bind call
+		//	example:
+		//		bindArgs="preventCache:false;" overrides cacheContent
+		this.bindArgs = {};
+
+	
+	}, {
+		isContainer: true,
+
+		// loading options
+		// Boolean:
+		//		adjust relative paths in markup to fit this page
+		adjustPaths: true,
+
+		// String:
+		//		The href of the content that displays now
+		//		Set this at construction if you want to load externally,
+		//		changing href after creation doesnt have any effect, see setUrl
+		href: "",
+
+		// Boolean: Extract visible content from inside of <body> .... </body>
+		extractContent: true,
+
+		// Boolean: Construct all widgets that is in content
+		parseContent:	true,
+
+		// Boolean: Cache content retreived externally
+		cacheContent:	true,
+
+		// Boolean:
+		//		Force load of data even if pane is hidden
+		//	Note:
+		//		In order to delay download you need to initially hide the node it constructs from
+		preload: false,
+
+		// Boolean:
+		//		Refresh (re-download) content when pane goes from hidden to shown
+		refreshOnShow: false,
+
+		// String||Function:
+		//		Generate pane content from a java function
+		//		The name of the java proxy function
+		handler: "",
+
+		// Boolean:
+		//		Run scripts within content, extractContent has NO effect on this
+		//	Note:
+		//		if true scripts in content will be evaled after content is innerHTML'ed
+		executeScripts: false,
+
+		// Boolean:
+		//		Run scripts in a separate scope, unique for each ContentPane
+		scriptSeparation: true,
+
+		// String: Message that shows while downloading
+		loadingMessage: "Loading...",
+
+		// Boolean: Tells loading status
+		isLoaded: false,
+
+		postCreate: function(args, frag, parentComp){
+			if (this.handler!==""){
+				this.setHandler(this.handler);
+			}
+			if(this.isShowing() || this.preload){
+				this.loadContents(); 
+			}
+		},
+	
+		show: function(){
+			// if refreshOnShow is true, reload the contents every time; otherwise, load only the first time
+			if(this.refreshOnShow){
+				this.refresh();
+			}else{
+				this.loadContents();
+			}
+			dojo.widget.ContentPane.superclass.show.call(this);
+		},
+	
+		refresh: function(){
+			// summary:
+			//		Force a refresh (re-download) of content, be sure to turn of cache
+			this.isLoaded=false;
+			this.loadContents();
+		},
+	
+		loadContents: function() {
+			// summary:
+			//		Download if isLoaded is false, else ignore
+			if ( this.isLoaded ){
+				return;
+			}
+			if ( dojo.lang.isFunction(this.handler)) {
+				this._runHandler();
+			} else if ( this.href != "" ) {
+				this._downloadExternalContent(this.href, this.cacheContent && !this.refreshOnShow);
+			}
+		},
+		
+		setUrl: function(/*String||dojo.uri.Uri*/ url) {
+			// summary:
+			//		Reset the (external defined) content of this pane and replace with new url
+			//	Note:
+			//		It delays the download until widget is shown if preload is false
+			this.href = url;
+			this.isLoaded = false;
+			if ( this.preload || this.isShowing() ){
+				this.loadContents();
+			}
+		},
+
+		abort: function(){
+			// summary
+			//		Aborts a inflight download of content
+			var bind = this._ioBindObj;
+			if(!bind || !bind.abort){ return; }
+			bind.abort();
+			delete this._ioBindObj;
+		},
+	
+		_downloadExternalContent: function(url, useCache) {
+			this.abort();
+			this._handleDefaults(this.loadingMessage, "onDownloadStart");
+			var self = this;
+			this._ioBindObj = dojo.io.bind(
+				this._cacheSetting({
+					url: url,
+					mimetype: "text/html",
+					handler: function(type, data, xhr){
+						delete self._ioBindObj; // makes sure abort doesnt clear cache
+						if(type=="load"){
+							self.onDownloadEnd.call(self, url, data);
+						}else{
+							// XHR isnt a normal JS object, IE doesnt have prototype on XHR so we cant extend it or shallowCopy it
+							var e = {
+								responseText: xhr.responseText,
+								status: xhr.status,
+								statusText: xhr.statusText,
+								responseHeaders: xhr.getAllResponseHeaders(),
+								text: "Error loading '" + url + "' (" + xhr.status + " "+  xhr.statusText + ")"
+							};
+							self._handleDefaults.call(self, e, "onDownloadError");
+							self.onLoad();
+						}
+					}
+				}, useCache)
+			);
+		},
+	
+		_cacheSetting: function(bindObj, useCache){
+			for(var x in this.bindArgs){
+				if(dojo.lang.isUndefined(bindObj[x])){
+					bindObj[x] = this.bindArgs[x];
+				}
+			}
+
+			if(dojo.lang.isUndefined(bindObj.useCache)){ bindObj.useCache = useCache; }
+			if(dojo.lang.isUndefined(bindObj.preventCache)){ bindObj.preventCache = !useCache; }
+			if(dojo.lang.isUndefined(bindObj.mimetype)){ bindObj.mimetype = "text/html"; }
+			return bindObj;
+		},
+
+		onLoad: function(e){
+			// summary:
+			//		Event hook, is called after everything is loaded and widgetified 
+			this._runStack("_onLoadStack");
+			this.isLoaded=true;
+		},
+	
+		onUnLoad: function(e){
+			// summary:
+			//		Deprecated, use onUnload (lowercased load)
+			dojo.deprecated(this.widgetType+".onUnLoad, use .onUnload (lowercased load)", 0.5);
+		},
+
+		onUnload: function(e){
+			// summary:
+			//		Event hook, is called before old content is cleared
+			this._runStack("_onUnloadStack");
+			delete this.scriptScope;
+			// FIXME: remove for 0.5 along with onUnLoad
+			if(this.onUnLoad !== dojo.widget.ContentPane.prototype.onUnLoad){
+				this.onUnLoad.apply(this, arguments);
+			}
+		},
+	
+		_runStack: function(stName){
+			var st = this[stName]; var err = "";
+			var scope = this.scriptScope || window;
+			for(var i = 0;i < st.length; i++){
+				try{
+					st[i].call(scope);
+				}catch(e){ 
+					err += "\n"+st[i]+" failed: "+e.description;
+				}
+			}
+			this[stName] = [];
+	
+			if(err.length){
+				var name = (stName== "_onLoadStack") ? "addOnLoad" : "addOnUnLoad";
+				this._handleDefaults(name+" failure\n "+err, "onExecError", "debug");
+			}
+		},
+	
+		addOnLoad: function(/*Function||Object, optional*/ obj, /*Function*/ func){
+			// summary
+			//		Stores function refs and calls them one by one in the order they came in
+			//		when load event occurs.
+			//	obj:
+			//		holder object
+			//	func:
+			//		function that will be called 
+			this._pushOnStack(this._onLoadStack, obj, func);
+		},
+	
+		addOnUnload: function(/*Function||Object, optional*/ obj, /*Function*/ func){
+			// summary
+			//		Stores function refs and calls them one by one in the order they came in
+			//		when unload event occurs.
+			//	obj:
+			//		holder object
+			//	func:
+			//		function that will be called 
+			this._pushOnStack(this._onUnloadStack, obj, func);
+		},
+
+		addOnUnLoad: function(){
+			// summary:
+			//		Deprecated use addOnUnload (lower cased load)
+			dojo.deprecated(this.widgetType + ".addOnUnLoad, use addOnUnload instead. (lowercased Load)", 0.5);
+			this.addOnUnload.apply(this, arguments);
+		},
+	
+		_pushOnStack: function(stack, obj, func){
+			if(typeof func == 'undefined') {
+				stack.push(obj);
+			}else{
+				stack.push(function(){ obj[func](); });
+			}
+		},
+	
+		destroy: function(){
+			// make sure we call onUnload
+			this.onUnload();
+			dojo.widget.ContentPane.superclass.destroy.call(this);
+		},
+ 
+		onExecError: function(/*Object*/e){
+			// summary:
+			//		called when content script eval error or Java error occurs, preventDefault-able
+			//		default is to debug not alert as in 0.3.1
+		},
+	
+		onContentError: function(/*Object*/e){
+			// summary: 
+			//		called on DOM faults, require fault etc in content, preventDefault-able
+			//		default is to display errormessage inside pane
+		},
+	
+		onDownloadError: function(/*Object*/e){
+			// summary: 
+			//		called when download error occurs, preventDefault-able
+			//		default is to display errormessage inside pane
+		},
+	
+		onDownloadStart: function(/*Object*/e){
+			// summary:
+			//		called before download starts, preventDefault-able
+			//		default is to display loadingMessage inside pane
+			//		by changing e.text in your event handler you can change loading message
+		},
+	
+		// 
+		onDownloadEnd: function(/*String*/ url, /*String*/ data){
+			// summary:
+			//		called when download is finished
+			//
+			//	url: url that downloaded data
+			//	data: the markup that was downloaded
+			data = this.splitAndFixPaths(data, url);
+			this.setContent(data);
+		},
+	
+		// useful if user wants to prevent default behaviour ie: _setContent("Error...")
+		_handleDefaults: function(e, handler, messType){
+			if(!handler){ handler = "onContentError"; }
+
+			if(dojo.lang.isString(e)){ e = {text: e}; }
+
+			if(!e.text){ e.text = e.toString(); }
+
+			e.toString = function(){ return this.text; };
+
+			if(typeof e.returnValue != "boolean"){
+				e.returnValue = true; 
+			}
+			if(typeof e.preventDefault != "function"){
+				e.preventDefault = function(){ this.returnValue = false; };
+			}
+			// call our handler
+			this[handler](e);
+			if(e.returnValue){
+				switch(messType){
+					case true: // fallthrough, old compat
+					case "alert":
+						alert(e.toString()); break;
+					case "debug":
+						dojo.debug(e.toString()); break;
+					default:
+					// makes sure scripts can clean up after themselves, before we setContent
+					if(this._callOnUnload){ this.onUnload(); } 
+					// makes sure we dont try to call onUnLoad again on this event,
+					// ie onUnLoad before 'Loading...' but not before clearing 'Loading...'
+					this._callOnUnload = false;
+
+					// we might end up in a endless recursion here if domNode cant append content
+					if(arguments.callee._loopStop){
+						dojo.debug(e.toString());
+					}else{
+						arguments.callee._loopStop = true;
+						this._setContent(e.toString());
+					}
+				}
+			}
+			arguments.callee._loopStop = false;
+		},
+	
+		// pathfixes, require calls, css stuff and neccesary content clean
+		splitAndFixPaths: function(/*String*/s, /*String||dojo.uri.Uri, optional*/url){
+			// summary:
+			// 		adjusts all relative paths in (hopefully) all cases, images, remote scripts, links etc.
+			// 		splits up content in different pieces, scripts, title, style, link and whats left becomes .xml
+
+			//	s:	The markup in string
+			//	url: url that pulled in markup
+
+			var titles = [], scripts = [],tmp = [];// init vars
+			var match = [], requires = [], attr = [], styles = [];
+			var str = '', path = '', fix = '', tagFix = '', tag = '', origPath = '';
+	
+			if(!url) { url = "./"; } // point to this page if not set
+
+			if(s){ // make sure we dont run regexes on empty content
+
+				/************** <title> ***********/
+				// khtml is picky about dom faults, you can't attach a <style> or <title> node as child of body
+				// must go into head, so we need to cut out those tags
+				var regex = /<title[^>]*>([\s\S]*?)<\/title>/i;
+				while(match = regex.exec(s)){
+					titles.push(match[1]);
+					s = s.substring(0, match.index) + s.substr(match.index + match[0].length);
+				};
+		
+				/************** adjust paths *****************/
+				if(this.adjustPaths){
+					// attributepaths one tag can have multiple paths example:
+					// <input src="..." style="url(..)"/> or <a style="url(..)" href="..">
+					// strip out the tag and run fix on that.
+					// this guarantees that we won't run replace on another tag's attribute + it was easier do
+					var regexFindTag = /<[a-z][a-z0-9]*[^>]*\s(?:(?:src|href|style)=[^>])+[^>]*>/i;
+					var regexFindAttr = /\s(src|href|style)=(['"]?)([\w()\[\]\/.,\\'"-:;#=&?\s@]+?)\2/i;
+					// these are the supported protocols, all other is considered relative
+					var regexProtocols = /^(?:[#]|(?:(?:https?|ftps?|file|javascript|mailto|news):))/;
+		
+					while(tag = regexFindTag.exec(s)){
+						str += s.substring(0, tag.index);
+						s = s.substring((tag.index + tag[0].length), s.length);
+						tag = tag[0];
+			
+						// loop through attributes
+						tagFix = '';
+						while(attr = regexFindAttr.exec(tag)){
+							path = ""; origPath = attr[3];
+							switch(attr[1].toLowerCase()){
+								case "src":// falltrough
+								case "href":
+									if(regexProtocols.exec(origPath)){
+										path = origPath;
+									} else {
+										path = (new dojo.uri.Uri(url, origPath).toString());
+									}
+									break;
+								case "style":// style
+									path = dojo.html.fixPathsInCssText(origPath, url);
+									break;
+								default:
+									path = origPath;
+							}
+							fix = " " + attr[1] + "=" + attr[2] + path + attr[2];
+							// slices up tag before next attribute check
+							tagFix += tag.substring(0, attr.index) + fix;
+							tag = tag.substring((attr.index + attr[0].length), tag.length);
+						}
+						str += tagFix + tag; //dojo.debug(tagFix + tag);
+					}
+					s = str+s;
+				}
+
+				/****************  cut out all <style> and <link rel="stylesheet" href=".."> **************/
+				regex = /(?:<(style)[^>]*>([\s\S]*?)<\/style>|<link ([^>]*rel=['"]?stylesheet['"]?[^>]*)>)/i;
+				while(match = regex.exec(s)){
+					if(match[1] && match[1].toLowerCase() == "style"){
+						styles.push(dojo.html.fixPathsInCssText(match[2],url));
+					}else if(attr = match[3].match(/href=(['"]?)([^'">]*)\1/i)){
+						styles.push({path: attr[2]});
+					}
+					s = s.substring(0, match.index) + s.substr(match.index + match[0].length);
+				};
+
+				/***************** cut out all <script> tags, push them into scripts array ***************/
+				var regex = /<script([^>]*)>([\s\S]*?)<\/script>/i;
+				var regexSrc = /src=(['"]?)([^"']*)\1/i;
+				var regexDojoJs = /.*(\bdojo\b\.js(?:\.uncompressed\.js)?)$/;
+				var regexInvalid = /(?:var )?\bdjConfig\b(?:[\s]*=[\s]*\{[^}]+\}|\.[\w]*[\s]*=[\s]*[^;\n]*)?;?|dojo\.hostenv\.writeIncludes\(\s*\);?/g;
+				var regexRequires = /dojo\.(?:(?:require(?:After)?(?:If)?)|(?:widget\.(?:manager\.)?registerWidgetPackage)|(?:(?:hostenv\.)?setModulePrefix|registerModulePath)|defineNamespace)\((['"]).*?\1\)\s*;?/;
+
+				while(match = regex.exec(s)){
+					if(this.executeScripts && match[1]){
+						if(attr = regexSrc.exec(match[1])){
+							// remove a dojo.js or dojo.js.uncompressed.js from remoteScripts
+							// we declare all files named dojo.js as bad, regardless of path
+							if(regexDojoJs.exec(attr[2])){
+								dojo.debug("Security note! inhibit:"+attr[2]+" from  being loaded again.");
+							}else{
+								scripts.push({path: attr[2]});
+							}
+						}
+					}
+					if(match[2]){
+						// remove all invalid variables etc like djConfig and dojo.hostenv.writeIncludes()
+						var sc = match[2].replace(regexInvalid, "");
+						if(!sc){ continue; }
+		
+						// cut out all dojo.require (...) calls, if we have execute 
+						// scripts false widgets dont get there require calls
+						// takes out possible widgetpackage registration as well
+						while(tmp = regexRequires.exec(sc)){
+							requires.push(tmp[0]);
+							sc = sc.substring(0, tmp.index) + sc.substr(tmp.index + tmp[0].length);
+						}
+						if(this.executeScripts){
+							scripts.push(sc);
+						}
+					}
+					s = s.substr(0, match.index) + s.substr(match.index + match[0].length);
+				}
+
+				/********* extract content *********/
+				if(this.extractContent){
+					match = s.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
+					if(match) { s = match[1]; }
+				}
+	
+				/*** replace scriptScope prefix in html Event handler
+				* working order: find tags with scriptScope in a tag attribute
+				* then replace all standalone scriptScope occurencies with reference to to this widget
+				* valid onClick="scriptScope.func()" or onClick="scriptScope['func']();scriptScope.i++"
+				* not valid onClick="var.scriptScope.ref" nor onClick="var['scriptScope'].ref" */
+				if(this.executeScripts && this.scriptSeparation){
+					var regex = /(<[a-zA-Z][a-zA-Z0-9]*\s[^>]*?\S=)((['"])[^>]*scriptScope[^>]*>)/;
+					var regexAttr = /([\s'";:\(])scriptScope(.*)/; // we rely on that attribute begins ' or "
+					str = ""; 
+					while(tag = regex.exec(s)){
+						tmp = ((tag[3]=="'") ? '"': "'");fix= "";
+						str += s.substring(0, tag.index) + tag[1];
+						while(attr = regexAttr.exec(tag[2])){
+							tag[2] = tag[2].substring(0, attr.index) + attr[1] + "dojo.widget.byId("+ tmp + this.widgetId + tmp + ").scriptScope" + attr[2];
+						}
+						str += tag[2];
+						s = s.substr(tag.index + tag[0].length);
+					}
+					s = str + s;
+				}
+	 		}
+
+			return {"xml": 		s, // Object
+				"styles":		styles,
+				"titles": 		titles,
+				"requires": 	requires,
+				"scripts": 		scripts,
+				"url": 			url};
+		},
+	
+		
+		_setContent: function(cont){
+			this.destroyChildren();
+	
+			// remove old stylenodes from HEAD
+			for(var i = 0; i < this._styleNodes.length; i++){
+				if(this._styleNodes[i] && this._styleNodes[i].parentNode){
+					this._styleNodes[i].parentNode.removeChild(this._styleNodes[i]);
+				}
+			}
+			this._styleNodes = [];
+	
+			var node = this.containerNode || this.domNode;
+			while(node.firstChild){
+				try{
+					dojo.event.browser.clean(node.firstChild);
+				}catch(e){}
+				node.removeChild(node.firstChild);
+			}
+			try{
+				if(typeof cont != "string"){
+					node.innerHTML = "";
+					node.appendChild(cont);
+				}else{
+					node.innerHTML = cont;
+				}
+			}catch(e){
+				e.text = "Couldn't load content:"+e.description;
+				this._handleDefaults(e, "onContentError");
+			}
+		},
+	
+		setContent: function(/*String||DomNode*/ data){
+			// summary:
+			//		Replaces old content with data content, include style classes from old content
+			//	data:	new content, be it Document fragment or a DomNode chain
+			//			If data contains style tags, link rel=stylesheet it inserts those styles into DOM
+			this.abort();
+			if(this._callOnUnload){ this.onUnload(); }// this tells a remote script clean up after itself
+			this._callOnUnload = true;
+	
+			if(!data || dojo.html.isNode(data)){
+				// if we do a clean using setContent(""); or setContent(#node) bypass all parsing, extractContent etc
+				this._setContent(data);
+				this.onResized();
+				this.onLoad();
+			}else{
+				// need to run splitAndFixPaths? ie. manually setting content
+				// adjustPaths is taken care of inside splitAndFixPaths
+				if(typeof data.xml != "string"){ 
+					this.href = ""; // so we can refresh safely
+					data = this.splitAndFixPaths(data); 
+				}
+
+				this._setContent(data.xml);
+
+				// insert styles from content (in same order they came in)
+				for(var i = 0; i < data.styles.length; i++){
+					if(data.styles[i].path){
+						this._styleNodes.push(dojo.html.insertCssFile(data.styles[i].path));
+					}else{
+						this._styleNodes.push(dojo.html.insertCssText(data.styles[i]));
+					}
+				}
+	
+				if(this.parseContent){
+					for(var i = 0; i < data.requires.length; i++){
+						try{
+							eval(data.requires[i]);
+						} catch(e){
+							e.text = "ContentPane: error in package loading calls, " + (e.description||e);
+							this._handleDefaults(e, "onContentError", "debug");
+						}
+					}
+				}
+				// need to allow async load, Xdomain uses it
+				// is inline function because we cant send args to dojo.addOnLoad
+				var _self = this;
+				function asyncParse(){
+					if(_self.executeScripts){
+						_self._executeScripts(data.scripts);
+					}
+	
+					if(_self.parseContent){
+						var node = _self.containerNode || _self.domNode;
+						var parser = new dojo.xml.Parse();
+						var frag = parser.parseElement(node, null, true);
+						// createSubComponents not createComponents because frag has already been created
+						dojo.widget.getParser().createSubComponents(frag, _self);
+					}
+	
+					_self.onResized();
+					_self.onLoad();
+				}
+				// try as long as possible to make setContent sync call
+				if(dojo.hostenv.isXDomain && data.requires.length){
+					dojo.addOnLoad(asyncParse);
+				}else{
+					asyncParse();
+				}
+			}
+		},
+
+		setHandler: function(/*Function*/ handler) {
+			// summary:
+			//		Generate pane content from given java function
+			var fcn = dojo.lang.isFunction(handler) ? handler : window[handler];
+			if(!dojo.lang.isFunction(fcn)) {
+				// FIXME: needs testing! somebody with java knowledge needs to try this
+				this._handleDefaults("Unable to set handler, '" + handler + "' not a function.", "onExecError", true);
+				return;
+			}
+			this.handler = function() {
+				return fcn.apply(this, arguments);
+			}
+		},
+	
+		_runHandler: function() {
+			var ret = true;
+			if(dojo.lang.isFunction(this.handler)) {
+				this.handler(this, this.domNode);
+				ret = false;
+			}
+			this.onLoad();
+			return ret;
+		},
+	
+		_executeScripts: function(scripts) {
+			// loop through the scripts in the order they came in
+			var self = this;
+			var tmp = "", code = "";
+			for(var i = 0; i < scripts.length; i++){
+				if(scripts[i].path){ // remotescript
+					dojo.io.bind(this._cacheSetting({
+						"url": 		scripts[i].path,
+						"load":     function(type, scriptStr){
+								dojo.lang.hitch(self, tmp = ";"+scriptStr);
+						},
+						"error":    function(type, error){
+								error.text = type + " downloading remote script";
+								self._handleDefaults.call(self, error, "onExecError", "debug");
+						},
+						"mimetype": "text/plain",
+						"sync":     true
+					}, this.cacheContent));
+					code += tmp;
+				}else{
+					code += scripts[i];
+				}
+			}
+
+
+			try{
+				if(this.scriptSeparation){
+					// initialize a new anonymous container for our script, dont make it part of this widgets scope chain
+					// instead send in a variable that points to this widget, useful to connect events to onLoad, onUnload etc..
+					delete this.scriptScope;
+					this.scriptScope = new (new Function('_container_', code+'; return this;'))(self);
+				}else{
+					// exec in global, lose the _container_ feature
+					var djg = dojo.global();
+					if(djg.execScript){
+						djg.execScript(code);
+					}else{
+						var djd = dojo.doc();
+						var sc = djd.createElement("script");
+						sc.appendChild(djd.createTextNode(code));
+						(this.containerNode||this.domNode).appendChild(sc);
+					}
+				}
+			}catch(e){
+				e.text = "Error running scripts from content:\n"+e.description;
+				this._handleDefaults(e, "onExecError", "debug");
+			}
+		}
+	}
+);

Added: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/CurrencyTextbox.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/CurrencyTextbox.js?view=auto&rev=474551
==============================================================================
--- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/CurrencyTextbox.js (added)
+++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/CurrencyTextbox.js Mon Nov 13 14:54:45 2006
@@ -0,0 +1,63 @@
+/*
+	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.CurrencyTextbox");
+
+dojo.require("dojo.widget.IntegerTextbox");
+dojo.require("dojo.validate.common");
+
+/*
+  ****** CurrencyTextbox ******
+
+  A subclass that extends IntegerTextbox.
+  Over-rides isValid/isInRange to test if input denotes a monetary value .
+  Has 5 new properties that can be specified as attributes in the markup.
+
+  @attr fractional      The decimal places (e.g. for cents).  Can be true or false, optional if omitted.
+  @attr symbol     A currency symbol such as Yen "???", Pound "???", or the Euro "???". Default is "$".
+  @attr separator  Default is "," instead of no separator as in IntegerTextbox.
+  @attr min  Minimum signed value.  Default is -Infinity
+  @attr max  Maximum signed value.  Default is +Infinity
+*/
+dojo.widget.defineWidget(
+	"dojo.widget.CurrencyTextbox",
+	dojo.widget.IntegerTextbox,
+	{
+		mixInProperties: function(localProperties, frag){
+			// First initialize properties in super-class.
+			dojo.widget.CurrencyTextbox.superclass.mixInProperties.apply(this, arguments);
+	
+			// Get properties from markup attributes, and assign to flags object.
+			if(localProperties.fractional){
+				this.flags.fractional = (localProperties.fractional == "true");
+			}else if(localProperties.cents){
+				dojo.deprecated("dojo.widget.IntegerTextbox", "use fractional attr instead of cents", "0.5");
+				this.flags.fractional = (localProperties.cents == "true");
+			}
+			if(localProperties.symbol){
+				this.flags.symbol = localProperties.symbol;
+			}
+			if(localProperties.min){ 
+				this.flags.min = parseFloat(localProperties.min);
+			}
+			if(localProperties.max){ 
+				this.flags.max = parseFloat(localProperties.max);
+			}
+		},
+
+		// Over-ride for currency validation
+		isValid: function(){
+			return dojo.validate.isCurrency(this.textbox.value, this.flags);
+		},
+		isInRange: function(){
+			return dojo.validate.isInRange(this.textbox.value, this.flags);
+		}
+	}
+);

Propchange: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/CurrencyTextbox.js
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DatePicker.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DatePicker.js?view=diff&rev=474551&r1=474550&r2=474551
==============================================================================
--- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DatePicker.js (original)
+++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DatePicker.js Mon Nov 13 14:54:45 2006
@@ -1,5 +1,5 @@
 /*
-	Copyright (c) 2004-2005, The Dojo Foundation
+	Copyright (c) 2004-2006, The Dojo Foundation
 	All Rights Reserved.
 
 	Licensed under the Academic Free License version 2.1 or above OR the
@@ -8,67 +8,489 @@
 		http://dojotoolkit.org/community/licensing.shtml
 */
 
-dojo.provide("dojo.widget.DatePicker");
-dojo.provide("dojo.widget.DatePicker.util");
-dojo.require("dojo.widget.DomWidget");
-dojo.require("dojo.date");
-
-dojo.widget.DatePicker = function(){
-	dojo.widget.Widget.call(this);
-	this.widgetType = "DatePicker";
-	this.isContainer = false;
-	// the following aliases prevent breaking people using 0.2.x
-	this.months = dojo.date.months;
-	this.weekdays = dojo.date.days;
-	this.toRfcDate = dojo.widget.DatePicker.util.toRfcDate;
-	this.fromRfcDate = dojo.widget.DatePicker.util.fromRfcDate;
-	this.initFirstSaturday = dojo.widget.DatePicker.util.initFirstSaturday;
-}
-
-dojo.inherits(dojo.widget.DatePicker, dojo.widget.Widget);
-dojo.widget.tags.addParseTreeHandler("dojo:datepicker");
-
-dojo.requireAfterIf("html", "dojo.widget.html.DatePicker");
-
-dojo.widget.DatePicker.util = new function() {
-	this.months = dojo.date.months;
-	this.weekdays = dojo.date.days;
-	
-	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";
-	}
+	dojo.provide("dojo.widget.DatePicker");
+dojo.require("dojo.date.common");
+dojo.require("dojo.date.format");
+dojo.require("dojo.date.serialize");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.event.*");
+dojo.require("dojo.dom");
+dojo.require("dojo.html.style");
+
+dojo.widget.defineWidget(
+	"dojo.widget.DatePicker",
+	dojo.widget.HtmlWidget,
+	{	
+		/*
+		summary: 
+	 	              Base class for a stand-alone DatePicker widget 
+	 	              which makes it easy to select a date, or switch by month and/or year. 
+	 	description: 
+	 	              A stand-alone DatePicker widget that makes it  
+	 	              easy to select a date, or increment by week, month, and/or year. 
+	 	              It is designed to be used on its own, or inside of other widgets to  
+	 	              (see dojo.widget.DropdownDatePicker) or other similar combination widgets. 
+	 	              
+	 	              Dates attributes passed in the `RFC 3339` format:
+	 	              http://www.faqs.org/rfcs/rfc3339.html (2005-06-30T08:05:00-07:00)
+	 	              so that they are serializable and locale-independent.
+
+	 	 usage: 
+	 	              var datePicker = dojo.widget.createWidget("DatePicker", {},   
+	 	              dojo.byId("datePickerNode")); 
+	 	 
+	 	              <div dojoType="DatePicker"></div> 
+		*/
+
+		//start attributes
+		
+		//String|Date
+		//	form value property if =='today' will default to todays date
+		value: "", 
+		//String
+		// 	name of the form element
+		name: "",
+		//Integer
+		//	total weeks to display default 
+		displayWeeks: 6, 
+		//Boolean
+		//	if true, weekly size of calendar changes to acomodate the month if false, 42 day format is used
+		adjustWeeks: false,
+		//String|Date
+		//	first available date in the calendar set
+		startDate: "1492-10-12",
+		//String|Date
+		//	last available date in the calendar set
+		endDate: "2941-10-12",
+		//Integer
+		//	adjusts the first day of the week 0==Sunday..6==Saturday
+		weekStartsOn: "",
+		//String
+		//	deprecated use value instead
+		storedDate: "",
+		//Boolean
+		//d	isable all incremental controls, must pick a date in the current display
+		staticDisplay: false,
+		
+		//how to render the names of the days in the header.  see dojo.date.getDayNames
+		dayWidth: 'narrow',
+		classNames: {
+		// summary:
+		//              stores a list of class names that may be overriden 
+			previous: "previousMonth",
+			disabledPrevious: "previousMonthDisabled",
+			current: "currentMonth",
+			disabledCurrent: "currentMonthDisabled",
+			next: "nextMonth",
+			disabledNext: "nextMonthDisabled",
+			currentDate: "currentDate",
+			selectedDate: "selectedItem"
+		},
+		templatePath:  dojo.uri.dojoUri("src/widget/templates/DatePicker.html"),
+		templateCssPath:  dojo.uri.dojoUri("src/widget/templates/DatePicker.css"),
+
+		postMixInProperties: function(){
+			// summary: see dojo.widget.DomWidget
+
+			dojo.widget.DatePicker.superclass.postMixInProperties.apply(this, arguments);
+			if(this.storedDate){
+				dojo.deprecated("dojo.widget.DatePicker", "use 'value' instead of 'storedDate'", "0.5");
+				this.value=this.storedDate;
+			}
+			this.startDate = dojo.date.fromRfc3339(this.startDate);
+			this.endDate = dojo.date.fromRfc3339(this.endDate);
+			this.startDate.setHours(0,0,0,0); //adjust startDate to be exactly midnight
+			this.endDate.setHours(24,0,0,-1); //adjusting endDate to be a fraction of a second before  midnight
+			if(!this.weekStartsOn){
+				this.weekStartsOn=dojo.date.getFirstDayOfWeek(this.lang);
+			}
+			this.today = new Date();
+			this.today.setHours(0,0,0,0);
+			if(typeof(this.value)=='string'&&this.value.toLowerCase()=='today'){
+				this.value = new Date();
+			}else if(this.value && (typeof this.value=="string") && (this.value.split("-").length > 2)) {
+				this.value = dojo.date.fromRfc3339(this.value);
+				this.value.setHours(0,0,0,0);
+			}
+		},
+
+		fillInTemplate: function(args, frag) {
+			// summary: see dojo.widget.DomWidget
+
+			dojo.widget.DatePicker.superclass.fillInTemplate.apply(this, arguments);
+
+			// Copy style info from input node to output node
+			var source = this.getFragNodeRef(frag);
+			dojo.html.copyStyle(this.domNode, source);
+
+			this.weekTemplate = dojo.dom.removeNode(this.calendarWeekTemplate);
+			this._preInitUI(this.value ? this.value : this.today, false, true); //init UI with date selected ONLY if user supplies one
+
+			// Insert localized day names in the template
+			var dayLabels = dojo.lang.unnest(dojo.date.getNames('days', this.dayWidth, 'standAlone', this.lang)); //if we dont use unnest, we risk modifying the dayLabels array inside of dojo.date and screwing up other calendars on the page
+			if(this.weekStartsOn > 0){
+				//adjust dayLabels for different first day of week. ie: Monday or Thursday instead of Sunday
+				for(var i=0;i<this.weekStartsOn;i++){
+					dayLabels.push(dayLabels.shift());
+				}
+			}
+			var dayLabelNodes = this.dayLabelsRow.getElementsByTagName("td");
+ 			for(i=0; i<7; i++) {
+				dayLabelNodes.item(i).innerHTML = dayLabels[i];
+			}
+
+			if(this.value){
+				this.setValue(this.value);
+			}
+
+		},
+		
+		getValue: function() {
+			// summary: return current date in RFC 3339 format
+			return dojo.date.toRfc3339(new Date(this.value),'dateOnly'); /*String*/
+		},
+
+		getDate: function() {
+			// summary: return current date as a Date object
+			return this.value; /*Date*/
+		},
+
+		setValue: function(/*Date|String*/rfcDate) {
+			//summary: set the current date from RFC 3339 formatted string or a date object, synonymous with setDate
+			this.setDate(rfcDate);
+		},			
+
+		setDate: function(/*Date|String*/dateObj) {
+			//summary: set the current date and update the UI
+			if(typeof dateObj=="string"){
+				this.value = dojo.date.fromRfc3339(dateObj);
+			}else{
+				this.value = new Date(dateObj);
+			}
+			this.value.setHours(0,0,0,0);
+			if(this.selectedNode!=null){
+				dojo.html.removeClass(this.selectedNode,this.classNames.selectedDate);
+			}
+			if(this.clickedNode!=null){
+				dojo.html.addClass(this.clickedNode,this.classNames.selectedDate);
+				this.selectedNode = this.clickedNode;
+			}else{
+				//only call this if setDate was called by means other than clicking a date
+				this._preInitUI(this.value,false,true);
+			}
+			this.clickedNode=null;
+			this.onValueChanged(this.value);
+		},
+
+		_preInitUI: function(dateObj,initFirst,initUI) {
+			/*
+	 	              To get a sense of what month to highlight, we 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 work forwards and backwards from that point.
+			*/
+
+			//initFirst is to tell _initFirstDay if you want first day of the displayed calendar, or first day of the week for dateObj
+			//initUI tells preInitUI to go ahead and run initUI if set to true
+			if(dateObj<this.startDate||dateObj>this.endDate){
+				dateObj = new Date((dateObj<this.startDate)?this.startDate:this.endDate);
+			}
+			this.firstDay = this._initFirstDay(dateObj,initFirst);
+			this.selectedIsUsed = false;
+			this.currentIsUsed = false;
+			var nextDate = new Date(this.firstDay);
+			var tmpMonth = nextDate.getMonth();
+			this.curMonth = new Date(nextDate);
+			this.curMonth.setDate(nextDate.getDate()+6); //first saturday gives us the current Month
+			this.curMonth.setDate(1);
+			if(this.displayWeeks=="" || this.adjustWeeks){
+				this.adjustWeeks = true;
+				this.displayWeeks = Math.ceil((dojo.date.getDaysInMonth(this.curMonth) + this._getAdjustedDay(this.curMonth))/7);
+			}
+			var days = this.displayWeeks*7; //init total days to display
+			if(dojo.date.diff(this.startDate,this.endDate, dojo.date.dateParts.DAY) < days){
+				this.staticDisplay = true;
+				if(dojo.date.diff(nextDate,this.endDate, dojo.date.dateParts.DAY) > days){
+					this._preInitUI(this.startDate,true,false);
+					nextDate = new Date(this.firstDay);
+				}
+				this.curMonth = new Date(nextDate);
+				this.curMonth.setDate(nextDate.getDate()+6);
+				this.curMonth.setDate(1);
+				var curClass = (nextDate.getMonth() == this.curMonth.getMonth())?'current':'previous';
+			}
+			if(initUI){
+				this._initUI(days);
+			}
+		},
+		_initUI: function(days) {
+			dojo.dom.removeChildren(this.calendarDatesContainerNode);
+			for(var i=0;i<this.displayWeeks;i++){
+				this.calendarDatesContainerNode.appendChild(this.weekTemplate.cloneNode(true));
+			}
+
+			var nextDate = new Date(this.firstDay);
+			this._setMonthLabel(this.curMonth.getMonth());
+			this._setYearLabels(this.curMonth.getFullYear());
+			var calendarNodes = this.calendarDatesContainerNode.getElementsByTagName("td");
+			var calendarRows = this.calendarDatesContainerNode.getElementsByTagName("tr");
+			var currentCalendarNode;
+			for(i=0;i<days;i++){
+				//this is our new UI loop... one loop to rule them all, and in the datepicker bind them
+				currentCalendarNode = calendarNodes.item(i);
+				currentCalendarNode.innerHTML = nextDate.getDate();
+				var curClass = (nextDate.getMonth()<this.curMonth.getMonth())?'previous':(nextDate.getMonth()==this.curMonth.getMonth())?'current':'next';
+				var mappedClass = curClass;
+				if(this._isDisabledDate(nextDate)){
+					var classMap={previous:"disabledPrevious",current:"disabledCurrent",next:"disabledNext"};
+					mappedClass=classMap[curClass];
+				}
+				dojo.html.setClass(currentCalendarNode, this._getDateClassName(nextDate, mappedClass));
+				if(dojo.html.hasClass(currentCalendarNode,this.classNames.selectedDate)){
+					this.selectedNode = currentCalendarNode;
+				}
+				nextDate = dojo.date.add(nextDate, dojo.date.dateParts.DAY, 1);
+			}
+			this.lastDay = dojo.date.add(nextDate,dojo.date.dateParts.DAY,-1);
+			this._initControls();
+		},
+		_initControls: function(){
+			var d = this.firstDay;
+			var d2 = this.lastDay;
+			var decWeek, incWeek, decMonth, incMonth, decYear, incYear;
+			decWeek = incWeek = decMonth = incMonth = decYear = incYear = !this.staticDisplay;
+			with(dojo.date.dateParts){
+				var add = dojo.date.add;
+				if(decWeek && add(d,DAY,(-1*(this._getAdjustedDay(d)+1)))<this.startDate){
+					decWeek = decMonth = decYear = false;
+				}
+				if(incWeek && d2>this.endDate){
+					incWeek = incMonth = incYear = false;
+				}
+				if(decMonth && add(d,DAY,-1)<this.startDate){
+					decMonth = decYear = false;
+				}
+				if(incMonth && add(d2,DAY,1)>this.endDate){
+					incMonth = incYear = false;
+				}
+				if(decYear && add(d2,YEAR,-1)<this.startDate){
+					decYear = false;
+				}
+				if(incYear && add(d,YEAR,1)>this.endDate){
+					incYear = false;
+				}
+			}
+
+			function enableControl(node, enabled){
+				dojo.html.setVisibility(node, enabled ? '' : 'hidden');
+			}
+			enableControl(this.decreaseWeekNode,decWeek);
+			enableControl(this.increaseWeekNode,incWeek);
+			enableControl(this.decreaseMonthNode,decMonth);
+			enableControl(this.increaseMonthNode,incMonth);
+			enableControl(this.previousYearLabelNode,decYear);
+			enableControl(this.nextYearLabelNode,incYear);
+		},
+		
+		_incrementWeek: function(evt) {
+			var d = new Date(this.firstDay);
+			switch(evt.target) {
+				case this.increaseWeekNode.getElementsByTagName("img").item(0): 
+				case this.increaseWeekNode:
+					var tmpDate = dojo.date.add(d, dojo.date.dateParts.WEEK, 1);
+					if(tmpDate < this.endDate){
+						d = dojo.date.add(d, dojo.date.dateParts.WEEK, 1);
+					}
+					break;
+				case this.decreaseWeekNode.getElementsByTagName("img").item(0):
+				case this.decreaseWeekNode:
+					if(d >= this.startDate){
+						d = dojo.date.add(d, dojo.date.dateParts.WEEK, -1);
+					}
+					break;
+			}
+			this._preInitUI(d,true,true);
+		},
 	
-	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));
-	}
+		_incrementMonth: function(evt) {
+			var d = new Date(this.curMonth);
+			var tmpDate = new Date(this.firstDay);
+			switch(evt.currentTarget) {
+				case this.increaseMonthNode.getElementsByTagName("img").item(0):
+				case this.increaseMonthNode:
+					tmpDate = dojo.date.add(tmpDate, dojo.date.dateParts.DAY, this.displayWeeks*7);
+					if(tmpDate < this.endDate){
+						d = dojo.date.add(d, dojo.date.dateParts.MONTH, 1);
+					}else{
+						var revertToEndDate = true;
+					}
+					break;
+				case this.decreaseMonthNode.getElementsByTagName("img").item(0):
+				case this.decreaseMonthNode:
+					if(tmpDate > this.startDate){
+						d = dojo.date.add(d, dojo.date.dateParts.MONTH, -1);
+					}else{
+						var revertToStartDate = true;
+					}
+					break;
+			}
+			if(revertToStartDate){
+				d = new Date(this.startDate);
+			}else if(revertToEndDate){
+				d = new Date(this.endDate);
+			}
+			this._preInitUI(d,false,true);
+		},
 	
-	this.initFirstSaturday = function(month, year) {
-		if(!month) {
-			month = this.date.getMonth();
-		}
-		if(!year) {
-			year = this.date.getFullYear();
+		_incrementYear: function(evt) {
+			var year = this.curMonth.getFullYear();
+			var tmpDate = new Date(this.firstDay);
+			switch(evt.target) {
+				case this.nextYearLabelNode:
+					tmpDate = dojo.date.add(tmpDate, dojo.date.dateParts.YEAR, 1);
+					if(tmpDate<this.endDate){
+						year++;
+					}else{
+						var revertToEndDate = true;
+					}
+					break;
+				case this.previousYearLabelNode:
+					tmpDate = dojo.date.add(tmpDate, dojo.date.dateParts.YEAR, -1);
+					if(tmpDate>this.startDate){
+						year--;
+					}else{
+						var revertToStartDate = true;
+					}
+					break;
+			}
+			var d;
+			if(revertToStartDate){
+				d = new Date(this.startDate);
+			}else if(revertToEndDate){
+				d = new Date(this.endDate);
+			}else{
+				d = new Date(year, this.curMonth.getMonth(), 1);
+			}
+			this._preInitUI(d,false,true);
+		},
+	
+		onIncrementWeek: function(/*Event*/evt) {
+			// summary: handler for increment week event
+			evt.stopPropagation();
+			if(!this.staticDisplay){
+				this._incrementWeek(evt);
+			}
+		},
+	
+		onIncrementMonth: function(/*Event*/evt) {
+			// summary: handler for increment month event
+			evt.stopPropagation();
+			if(!this.staticDisplay){
+				this._incrementMonth(evt);
+			}
+		},
+		
+		onIncrementYear: function(/*Event*/evt) {
+			// summary: handler for increment year event
+			evt.stopPropagation();
+			if(!this.staticDisplay){
+				this._incrementYear(evt);
+			}
+		},
+	
+		_setMonthLabel: function(monthIndex) {
+			this.monthLabelNode.innerHTML = dojo.date.getNames('months', 'wide', 'standAlone', this.lang)[monthIndex];
+		},
+		
+		_setYearLabels: function(year) {
+			var y = year - 1;
+			var that = this;
+			function f(n){
+				that[n+"YearLabelNode"].innerHTML =
+					dojo.date.format(new Date(y++, 0), {formatLength:'yearOnly', locale:that.lang});
+			}
+			f("previous");
+			f("current");
+			f("next");
+		},
+		
+		_getDateClassName: function(date, monthState) {
+			var currentClassName = this.classNames[monthState];
+			//we use Number comparisons because 2 dateObjects never seem to equal each other otherwise
+			if ((!this.selectedIsUsed && this.value) && (Number(date) == Number(this.value))) {
+				currentClassName = this.classNames.selectedDate + " " + currentClassName;
+				this.selectedIsUsed = true;
+			}
+			if((!this.currentIsUsed) && (Number(date) == Number(this.today))) {
+				currentClassName = currentClassName + " "  + this.classNames.currentDate;
+				this.currentIsUsed = true;
+			}
+			return currentClassName;
+		},
+	
+		onClick: function(/*Event*/evt) {
+			//summary: the click event handler
+			dojo.event.browser.stopEvent(evt);
+		},
+
+		_handleUiClick: function(/*Event*/evt) {
+			var eventTarget = evt.target;
+			if(eventTarget.nodeType != dojo.dom.ELEMENT_NODE){eventTarget = eventTarget.parentNode;}
+			dojo.event.browser.stopEvent(evt);
+			this.selectedIsUsed = this.todayIsUsed = false;
+			var month = this.curMonth.getMonth();
+			var year = this.curMonth.getFullYear();
+			if(dojo.html.hasClass(eventTarget, this.classNames["disabledPrevious"])||dojo.html.hasClass(eventTarget, this.classNames["disabledCurrent"])||dojo.html.hasClass(eventTarget, this.classNames["disabledNext"])){
+				return; //this date is disabled... ignore it
+			}else if (dojo.html.hasClass(eventTarget, this.classNames["next"])) {
+				month = ++month % 12;
+				if(month===0){++year;}
+			} else if (dojo.html.hasClass(eventTarget, this.classNames["previous"])) {
+				month = --month % 12;
+				if(month==11){--year;}
+			}
+			this.clickedNode = eventTarget;
+			this.setDate(new Date(year, month, eventTarget.innerHTML));
+		},
+		
+		onValueChanged: function(/*Date*/date) {
+			//summary: the set date event handler
+		},
+		
+		_isDisabledDate: function(dateObj){
+			if(dateObj<this.startDate||dateObj>this.endDate){
+				return true;
+			}
+
+			return this.isDisabledDate(dateObj, this.lang);
+		},
+
+		isDisabledDate: function(/*Date*/dateObj, /*String?*/locale){
+		// summary:
+		//	May be overridden to disable certain dates in the calendar e.g. isDisabledDate=dojo.date.isWeekend
+
+			return false; // Boolean
+		},
+
+		_initFirstDay: function(/*Date*/dateObj, /*Boolean*/adj){
+			//adj: false for first day of month, true for first day of week adjusted by startOfWeek
+			var d = new Date(dateObj);
+			if(!adj){d.setDate(1);}
+			d.setDate(d.getDate()-this._getAdjustedDay(d,this.weekStartsOn));
+			d.setHours(0,0,0,0);
+			return d; // Date
+		},
+
+		_getAdjustedDay: function(/*Date*/dateObj){
+			//summary: used to adjust date.getDay() values to the new values based on the current first day of the week value
+			var days = [0,1,2,3,4,5,6];
+			if(this.weekStartsOn>0){
+				for(var i=0;i<this.weekStartsOn;i++){
+					days.unshift(days.pop());
+				}
+			}
+			return days[dateObj.getDay()]; // Number: 0..6 where 0=Sunday
 		}
-		var firstOfMonth = new Date(year, month, 1);
-		return {year: year, month: month, date: 7 - firstOfMonth.getDay()};
 	}
-}
+);

Added: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DateTextbox.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DateTextbox.js?view=auto&rev=474551
==============================================================================
--- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DateTextbox.js (added)
+++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DateTextbox.js Mon Nov 13 14:54:45 2006
@@ -0,0 +1,98 @@
+/*
+	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.DateTextbox");
+
+dojo.require("dojo.widget.ValidationTextbox");
+dojo.require("dojo.date.format");
+dojo.require("dojo.validate.datetime");
+
+//TODO: combine date and time widgets?
+dojo.widget.defineWidget(
+	"dojo.widget.DateTextbox",
+	dojo.widget.ValidationTextbox,
+	{
+		// summary: A TextBox which tests for a valid date
+		// format: Deprecated. Style as described in v0.3 in dojo.validate.  Default is  "MM/DD/YYYY".
+
+		// optional pattern used in display of formatted date.  Uses locale-specific format by default.  See dojo.date.format.
+		displayFormat: "",
+		// type of format appropriate to locale.  see dojo.date.format
+		formatLength: "short",
+//TODO: add date, saveFormat attributes like DropdownDatePicker?
+
+		mixInProperties: function(/*Object*/localProperties){
+			// summary: see dojo.widget.Widget
+
+			// First initialize properties in super-class.
+			dojo.widget.DateTextbox.superclass.mixInProperties.apply(this, arguments);
+	
+			// Get properties from markup attributes, and assign to flags object.
+			if(localProperties.format){ 
+				this.flags.format = localProperties.format;
+			}
+		},
+
+		isValid: function(){ 
+			// summary: see dojo.widget.ValidationTextbox
+
+			if(this.flags.format){
+				dojo.deprecated("dojo.widget.DateTextbox", "format attribute is deprecated; use displayFormat or formatLength instead", "0.5");
+				return dojo.validate.isValidDate(this.textbox.value, this.flags.format);
+			}
+
+			return dojo.date.parse(this.textbox.value, {formatLength:this.formatLength, selector:'dateOnly', locale:this.lang, datePattern: this.displayFormat});
+		}
+	}
+);
+
+dojo.widget.defineWidget(
+	"dojo.widget.TimeTextbox",
+	dojo.widget.ValidationTextbox,
+	{
+		// summary: A TextBox which tests for a valid time
+		// format: Deprecated. Described in v0.3 in dojo.validate.  Default is  "h:mm:ss t".
+		// amSymbol: Deprecated. Used with format. The symbol used for AM.  Default is "AM" or "am".
+		// pmSymbol: Deprecated. Used with format. The symbol used for PM.  Default is "PM" or "pm".
+
+		// optional pattern used in display of formatted date.  Uses locale-specific format by default.  See dojo.date.format.
+		displayFormat: "",
+		// type of format appropriate to locale.  see dojo.date.format
+		formatLength: "short",
+
+		mixInProperties: function(/*Object*/localProperties){
+			// summary: see dojo.widget.Widget
+
+			// First initialize properties in super-class.
+			dojo.widget.TimeTextbox.superclass.mixInProperties.apply(this, arguments);
+	
+			// Get properties from markup attributes, and assign to flags object.
+			if(localProperties.format){ 
+				this.flags.format = localProperties.format;
+			}
+			if(localProperties.amsymbol){ 
+				this.flags.amSymbol = localProperties.amsymbol;
+			}
+			if(localProperties.pmsymbol){ 
+				this.flags.pmSymbol = localProperties.pmsymbol;
+			}
+		},
+
+		isValid: function(){ 
+			// summary: see dojo.widget.ValidationTextbox
+			if(this.flags.format){
+				dojo.deprecated("dojo.widget.TimeTextbox", "format attribute is deprecated; use displayFormat or formatLength instead", "0.5");
+				return dojo.validate.isValidTime(this.textbox.value, this.flags);
+			}
+
+			return dojo.date.parse(this.textbox.value, {formatLength:this.formatLength, selector:'timeOnly', locale:this.lang, timePattern: this.displayFormat});
+		}
+	}
+);

Propchange: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DateTextbox.js
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DebugConsole.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DebugConsole.js?view=diff&rev=474551&r1=474550&r2=474551
==============================================================================
--- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DebugConsole.js (original)
+++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DebugConsole.js Mon Nov 13 14:54:45 2006
@@ -1,5 +1,5 @@
 /*
-	Copyright (c) 2004-2005, The Dojo Foundation
+	Copyright (c) 2004-2006, The Dojo Foundation
 	All Rights Reserved.
 
 	Licensed under the Academic Free License version 2.1 or above OR the
@@ -8,15 +8,19 @@
 		http://dojotoolkit.org/community/licensing.shtml
 */
 
-dojo.provide("dojo.widget.DebugConsole");
-dojo.require("dojo.widget.Widget");
-
-dojo.widget.DebugConsole= function(){
-	dojo.widget.Widget.call(this);
-
-	this.widgetType = "DebugConsole";
-	this.isContainer = true;
-}
-dojo.inherits(dojo.widget.DebugConsole, dojo.widget.Widget);
-dojo.widget.tags.addParseTreeHandler("dojo:debugconsole");
-dojo.requireAfterIf("html", "dojo.widget.html.DebugConsole");
+dojo.provide("dojo.widget.DebugConsole");
+dojo.require("dojo.widget.Widget");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.FloatingPane");
+
+dojo.widget.defineWidget(
+	"dojo.widget.DebugConsole",
+	dojo.widget.FloatingPane,
+{
+	fillInTemplate: function() {
+		dojo.widget.DebugConsole.superclass.fillInTemplate.apply(this, arguments);
+		this.containerNode.id = "debugConsoleClientPane";
+		djConfig.isDebug = true;
+		djConfig.debugContainerId = this.containerNode.id;
+	}
+});

Modified: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/Dialog.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/Dialog.js?view=diff&rev=474551&r1=474550&r2=474551
==============================================================================
--- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/Dialog.js (original)
+++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/Dialog.js Mon Nov 13 14:54:45 2006
@@ -1,5 +1,5 @@
 /*
-	Copyright (c) 2004-2005, The Dojo Foundation
+	Copyright (c) 2004-2006, The Dojo Foundation
 	All Rights Reserved.
 
 	Licensed under the Academic Free License version 2.1 or above OR the
@@ -9,289 +9,338 @@
 */
 
 dojo.provide("dojo.widget.Dialog");
-dojo.provide("dojo.widget.HtmlDialog");
 
 dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.ContentPane");
 dojo.require("dojo.event.*");
-dojo.require("dojo.graphics.color");
-dojo.require("dojo.fx.*");
-dojo.require("dojo.html");
-
-dojo.widget.tags.addParseTreeHandler("dojo:dialog");
-
-dojo.widget.HtmlDialog = function(){
-	dojo.widget.HtmlWidget.call(this);
-
-	this.resizeConnectArgs = {
-		srcObj: window,
-		srcFunc: "onresize",
-		adviceObj: this,
-		adviceFunc: "onResize",
-		rate: 500
-	}
-}
+dojo.require("dojo.gfx.color");
+dojo.require("dojo.html.layout");
+dojo.require("dojo.html.display");
+dojo.require("dojo.html.iframe");
+
+// summary
+//	Mixin for widgets implementing a modal dialog
+dojo.declare(
+	"dojo.widget.ModalDialogBase", 
+	null,
+	{
+		isContainer: true,
+
+		// static variables
+		shared: {bg: null, bgIframe: null},
+
+		// String
+		//	provide a focusable element or element id if you need to
+		//	work around FF's tendency to send focus into outer space on hide
+		focusElement: "",
+
+		// String
+		//	color of viewport when displaying a dialog
+		bgColor: "black",
+		
+		// Number
+		//	opacity (0~1) of viewport color (see bgColor attribute)
+		bgOpacity: 0.4,
+
+		// Boolean
+		//	if true, readjusts the dialog (and dialog background) when the user moves the scrollbar
+		followScroll: true,
+
+		trapTabs: function(/*Event*/ e){
+			// summary
+			//	callback on focus
+			if(e.target == this.tabStartOuter) {
+				if(this._fromTrap) {
+					this.tabStart.focus();
+					this._fromTrap = false;
+				} else {
+					this._fromTrap = true;
+					this.tabEnd.focus();
+				}
+			} else if (e.target == this.tabStart) {
+				if(this._fromTrap) {
+					this._fromTrap = false;
+				} else {
+					this._fromTrap = true;
+					this.tabEnd.focus();
+				}
+			} else if(e.target == this.tabEndOuter) {
+				if(this._fromTrap) {
+					this.tabEnd.focus();
+					this._fromTrap = false;
+				} else {
+					this._fromTrap = true;
+					this.tabStart.focus();
+				}
+			} else if(e.target == this.tabEnd) {
+				if(this._fromTrap) {
+					this._fromTrap = false;
+				} else {
+					this._fromTrap = true;
+					this.tabStart.focus();
+				}
+			}
+		},
 
-dojo.inherits(dojo.widget.HtmlDialog, dojo.widget.HtmlWidget);
+		clearTrap: function(/*Event*/ e) {
+			// summary
+			//	callback on blur
+			var _this = this;
+			setTimeout(function() {
+				_this._fromTrap = false;
+			}, 100);
+		},
+
+		postCreate: function() {
+			// summary
+			//	if the target mixin class already defined postCreate,
+			//	dojo.widget.ModalDialogBase.prototype.postCreate.call(this)
+			//	should be called in its postCreate()
+			with(this.domNode.style){
+				position = "absolute";
+				zIndex = 999;
+				display = "none";
+				overflow = "visible";
+			}
+			var b = dojo.body();
+			b.appendChild(this.domNode);
 
-dojo.lang.extend(dojo.widget.HtmlDialog, {
-	templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlDialog.html"),
-	widgetType: "Dialog",
-	isContainer: true,
-
-	_scrollConnected: false,
-	_resizeConnected: false,
-	
-	// provide a focusable element or element id if you need to
-	// work around FF's tendency to send focus into outer space on hide
-	focusElement: "",
-
-	// Only supports fade right now
-	effect: "fade",
-	effectDuration: 250,
-
-	bg: null,
-	bgIframe: null,
-	bgColor: "black",
-	bgOpacity: 0.4,
-	followScroll: 1,
-	_fromTrap: false,
-	anim: null,
-
-	trapTabs: function(e){
-		if(e.target == this.tabStart) {
-			if(this._fromTrap) {
-				this._fromTrap = false;
-			} else {
-				this._fromTrap = true;
-				this.tabEnd.focus();
+			if(!this.shared.bg){
+				this.shared.bg = document.createElement("div");
+				this.shared.bg.className = "dialogUnderlay";
+				with(this.shared.bg.style){
+					position = "absolute";
+					left = top = "0px";
+					zIndex = 998;
+					display = "none";
+				}
+				this.setBackgroundColor(this.bgColor);
+				b.appendChild(this.shared.bg);
+				this.shared.bgIframe = new dojo.html.BackgroundIframe(this.shared.bg);
 			}
-		} else if(e.target == this.tabEnd) {
-			if(this._fromTrap) {
-				this._fromTrap = false;
+		},
+
+		setBackgroundColor: function(/*String*/ color) {
+			// summary
+			//	changes background color specified by "bgColor" parameter
+			//	usage:
+			//		setBackgrounColor("black");
+			//		setBackgroundColor(0xff, 0xff, 0xff);
+			if(arguments.length >= 3) {
+				color = new dojo.gfx.color.Color(arguments[0], arguments[1], arguments[2]);
 			} else {
-				this._fromTrap = true;
-				this.tabStart.focus();
+				color = new dojo.gfx.color.Color(color);
 			}
-		}
-	},
-
-	clearTrap: function(e) {
-		var _this = this;
-		setTimeout(function() {
-			_this._fromTrap = false;
-		}, 100);
-	},
-
-	postCreate: function(args, frag, parentComp) {
-		with(this.domNode.style) {
-			position = "absolute";
-			zIndex = 999;
-			display = "none";
-		}
-		var b = dojo.html.body();
-		b.appendChild(this.domNode);
-		this.nodeRef = frag["dojo:"+this.widgetType.toLowerCase()]["nodeRef"];
-		if(this.nodeRef) {
-			this.setContent(this.nodeRef);
-		}
+			this.shared.bg.style.backgroundColor = color.toString();
+			return this.bgColor = color;
+		},
+
+		setBackgroundOpacity: function(/*Number*/ op) {
+			// summary
+			//	changes background opacity set by "bgOpacity" parameter
+			if(arguments.length == 0) { op = this.bgOpacity; }
+			dojo.html.setOpacity(this.shared.bg, op);
+			try {
+				this.bgOpacity = dojo.html.getOpacity(this.shared.bg);
+			} catch (e) {
+				this.bgOpacity = op;
+			}
+			return this.bgOpacity;
+		},
 
-		this.bgIframe = new dojo.html.BackgroundIframe();
+		_sizeBackground: function() {
+			if(this.bgOpacity > 0) {
+				
+				var viewport = dojo.html.getViewport();
+				var h = viewport.height;
+				var w = viewport.width;
+				with(this.shared.bg.style){
+					width = w + "px";
+					height = h + "px";
+				}
+				var scroll_offset = dojo.html.getScroll().offset;
+				this.shared.bg.style.top = scroll_offset.y + "px";
+				this.shared.bg.style.left = scroll_offset.x + "px";
+				// process twice since the scroll bar may have been removed
+				// by the previous resizing
+				var viewport = dojo.html.getViewport();
+				if (viewport.width != w) { this.shared.bg.style.width = viewport.width + "px"; }
+				if (viewport.height != h) { this.shared.bg.style.height = viewport.height + "px"; }
+			}
+		},
 
-		this.bg = document.createElement("div");
-		this.bg.className = "dialogUnderlay";
-		with(this.bg.style) {
-			position = "absolute";
-			left = top = "0px";
-			zIndex = 998;
-			display = "none";
-		}
-		this.setBackgroundColor(this.bgColor);
-		b.appendChild(this.bg);
-		this.bgIframe.setZIndex(this.bg);
-	},
-
-	setContent: function(content) {
-		if(typeof content == "string") {
-			this.containerNode.innerHTML = content;
-		} else if(content.nodeType != undefined) {
-			// dojo.dom.removeChildren(this.containerNode);
-			this.containerNode.appendChild(content);
-		} else {
-			dojo.raise("Tried to setContent with unknown content (" + content + ")");
-		}
-	},
+		_showBackground: function() {
+			if(this.bgOpacity > 0) {
+				this.shared.bg.style.display = "block";
+			}
+		},
 
-	setBackgroundColor: function(color) {
-		if(arguments.length >= 3) {
-			color = new dojo.graphics.color.Color(arguments[0], arguments[1], arguments[2]);
-		} else {
-			color = new dojo.graphics.color.Color(color);
-		}
-		this.bg.style.backgroundColor = color.toString();
-		return this.bgColor = color;
-	},
-	
-	setBackgroundOpacity: function(op) {
-		if(arguments.length == 0) { op = this.bgOpacity; }
-		dojo.style.setOpacity(this.bg, op);
-		try {
-			this.bgOpacity = dojo.style.getOpacity(this.bg);
-		} catch (e) {
-			this.bgOpacity = op;
-		}
-		return this.bgOpacity;
-	},
+		placeModalDialog: function() {
+			var scroll_offset = dojo.html.getScroll().offset;
+			var viewport_size = dojo.html.getViewport();
+			
+			// find the size of the dialog
+			var mb = dojo.html.getMarginBox(this.containerNode);
+			
+			var x = scroll_offset.x + (viewport_size.width - mb.width)/2;
+			var y = scroll_offset.y + (viewport_size.height - mb.height)/2;
+
+			with(this.domNode.style){
+				left = x + "px";
+				top = y + "px";
+			}
+		},
 
-	sizeBackground: function() {
-		if(this.bgOpacity > 0) {
-			var h = document.documentElement.scrollHeight || dojo.html.body().scrollHeight;
-			var w = dojo.html.getViewportWidth();
-			this.bg.style.width = w + "px";
-			this.bg.style.height = h + "px";
-			this.bgIframe.size([0, 0, w, h]);
-		} else {
-			this.bgIframe.size(this.domNode);
-		}
-	},
+		showModalDialog: function() {
+			// summary
+			//	call this function in show() of subclass
+			if (this.followScroll && !this._scrollConnected){
+				this._scrollConnected = true;
+				dojo.event.connect(window, "onscroll", this, "_onScroll");
+			}
+			
+			this.setBackgroundOpacity();
+			this._sizeBackground();
+			this._showBackground();
+		},
+
+		hideModalDialog: function(){
+			// summary
+			//	call this function in hide() of subclass
+
+			// workaround for FF focus going into outer space
+			if (this.focusElement) { 
+				dojo.byId(this.focusElement).focus(); 
+				dojo.byId(this.focusElement).blur();
+			}
 
-	showBackground: function() {
-		this.sizeBackground();
-		this.bgIframe.show();
-		if(this.bgOpacity > 0) {
-			this.bg.style.display = "block";
-		}
-	},
+			this.shared.bg.style.display = "none";
+			this.shared.bg.style.width = this.shared.bg.style.height = "1px";
 
-	placeDialog: function() {
-		var scroll_offset = dojo.html.getScrollOffset();
-		var viewport_size = dojo.html.getViewportSize();
-
-		// find the size of the dialog
-		// we should really be using dojo.style but i'm not sure
-		// which (inner, outer, box, content, client) --cal
-		this.domNode.style.display = "block";
-		var w = this.domNode.offsetWidth;
-		var h = this.domNode.offsetHeight;
-		this.domNode.style.display = "none";
-
-		var x = scroll_offset[0] + (viewport_size[0] - w)/2;
-		var y = scroll_offset[1] + (viewport_size[1] - h)/2;
-
-		with(this.domNode.style) {
-			left = x + "px";
-			top = y + "px";
-		}
+			if (this._scrollConnected){
+				this._scrollConnected = false;
+				dojo.event.disconnect(window, "onscroll", this, "_onScroll");
+			}
+		},
 
-		// tied to domNode, so we need to update the position
-		if(this.bgOpacity == 0) {
-			this.bgIframe.size([x, y, w, h]);
+		_onScroll: function(){
+			var scroll_offset = dojo.html.getScroll().offset;
+			this.shared.bg.style.top = scroll_offset.y + "px";
+			this.shared.bg.style.left = scroll_offset.x + "px";
+			this.placeModalDialog();
+		},
+
+		checkSize: function() {
+			if(this.isShowing()){
+				this._sizeBackground();
+				this.placeModalDialog();
+				this.onResized();
+			}
 		}
-	},
+	});
 
-	show: function() {
-		this.setBackgroundOpacity();
-		this.placeDialog();
-		this.showBackground();
-		switch((this.effect||"").toLowerCase()){
-			case "fade":
-				this.domNode.style.display = "block";
-				var _this = this;
-				if(this.anim){ this.anim.stop(); }
-				// FIXME: we should be supporting other effect types here!
-				this.anim = dojo.fx.fade(this.domNode, 
-					this.effectDuration, 
-					0, 
-					1,
-					dojo.lang.hitch(this, 
-						function(node){
-							if(dojo.lang.isFunction(_this.onShow)) {
-								_this.onShow(node);
-							}
-						}
-					)
-				);
-				break;
-			default:
-				this.domNode.style.display = "block";
-				if(dojo.lang.isFunction(this.onShow)){
-					this.onShow(this.domNode);
+// summary
+//	Pops up a modal dialog window, blocking access to the screen and also graying out the screen
+//	Dialog is extended from ContentPane so it supports all the same parameters (href, etc.)
+dojo.widget.defineWidget(
+	"dojo.widget.Dialog",
+	[dojo.widget.ContentPane, dojo.widget.ModalDialogBase],
+	{
+		templatePath: dojo.uri.dojoUri("src/widget/templates/Dialog.html"),
+
+		// Integer
+		//	number of seconds for which the user cannot dismiss the dialog
+		blockDuration: 0,
+		
+		// Integer
+		//	if set, this controls the number of seconds the dialog will be displayed before automatically disappearing
+		lifetime: 0,
+
+		show: function() {
+			if(this.lifetime){
+				this.timeRemaining = this.lifetime;
+				if(!this.blockDuration){
+					dojo.event.connect(this.shared.bg, "onclick", this, "hide");
+				}else{
+					dojo.event.disconnect(this.shared.bg, "onclick", this, "hide");
 				}
-				break;
-		}
-
-		// FIXME: moz doesn't generate onscroll events for mouse or key scrolling (wtf)
-		// we should create a fake event by polling the scrolltop/scrollleft every X ms.
-		// this smells like it should be a dojo feature rather than just for this widget.
-
-		if (this.followScroll && !this._scrollConnected){
-			this._scrollConnected = true;
-			dojo.event.connect(window, "onscroll", this, "onScroll");
-		}
-
-		if(!this._resizeConnected) {
-			this._resizeConnected = true;
-			dojo.event.kwConnect(this.resizeConnectArgs);
-		}
-	},
-
-	hide: function(){
-		// workaround for FF focus going into outer space
-		if (this.focusElement) { 
-			dojo.byId(this.focusElement).focus(); 
-			dojo.byId(this.focusElement).blur();
-		}
-		switch((this.effect||"").toLowerCase()) {
-			case "fade":
-				this.bg.style.display = "none";
-				this.bgIframe.hide();
-				var _this = this;
-				if(this.anim){ this.anim.stop(); }
-				this.anim = dojo.fx.fadeOut(this.domNode, this.effectDuration, function(node) {
-					node.style.display = "none";
-					if(dojo.lang.isFunction(_this.onHide)) {
-						_this.onHide(node);
+				if(this.timerNode){
+					this.timerNode.innerHTML = Math.ceil(this.timeRemaining/1000);
+				}
+				if(this.blockDuration && this.closeNode){
+					if(this.lifetime > this.blockDuration){
+						this.closeNode.style.visibility = "hidden";
+					}else{
+						this.closeNode.style.display = "none";
 					}
-					_this.anim = null;
-				});
-				break;
-			default:
-				this.bg.style.display = "none";
-				this.bgIframe.hide();
-				this.domNode.style.display = "none";
-				if(dojo.lang.isFunction(this.onHide)) {
-					this.onHide(node);
 				}
-				break;
-		}
-
-		this.bg.style.width = this.bg.style.height = "1px";
+				this.timer = setInterval(dojo.lang.hitch(this, "_onTick"), 100);
+			}
 
-		if (this._scrollConnected){
-			this._scrollConnected = false;
-			dojo.event.disconnect(window, "onscroll", this, "onScroll");
-		}
+			this.showModalDialog();
+			dojo.widget.Dialog.superclass.show.call(this);
+		},
+
+		onLoad: function(){
+			// when href is specified we need to reposition
+			// the dialog after the data is loaded
+			this.placeModalDialog();
+			dojo.widget.Dialog.superclass.onLoad.call(this);
+		},
+		
+		fillInTemplate: function(){
+			// dojo.event.connect(this.domNode, "onclick", this, "killEvent");
+		},
+
+		hide: function(){
+			this.hideModalDialog();
+			dojo.widget.Dialog.superclass.hide.call(this);
 
-		if(this._resizeConnected) {
-			this._resizeConnected = false;
-			dojo.event.kwDisconnect(this.resizeConnectArgs);
+			if(this.timer){
+				clearInterval(this.timer);
+			}
+		},
+		
+		setTimerNode: function(node){
+			// summary
+			//	specify into which node to write the remaining # of seconds
+			// TODO: make this a parameter too
+			this.timerNode = node;
+		},
+
+		setCloseControl: function(node) {
+			// summary
+			//	specify which node is the close button for this dialog
+			// TODO: make this a parameter too
+			this.closeNode = node;
+			dojo.event.connect(node, "onclick", this, "hide");
+		},
+
+		setShowControl: function(node) {
+			// summary
+			//	when specified node is clicked, show this dialog
+			// TODO: make this a parameter too
+			dojo.event.connect(node, "onclick", this, "show");
+		},
+		
+		_onTick: function(){
+			// summary
+			//	callback every second that the timer clicks
+			if(this.timer){
+				this.timeRemaining -= 100;
+				if(this.lifetime - this.timeRemaining >= this.blockDuration){
+					dojo.event.connect(this.shared.bg, "onclick", this, "hide");
+					if(this.closeNode){
+						this.closeNode.style.visibility = "visible";
+					}
+				}
+				if(!this.timeRemaining){
+					clearInterval(this.timer);
+					this.hide();
+				}else if(this.timerNode){
+					this.timerNode.innerHTML = Math.ceil(this.timeRemaining/1000);
+				}
+			}
 		}
-	},
-
-	setCloseControl: function(node) {
-		dojo.event.connect(node, "onclick", this, "hide");
-	},
-
-	setShowControl: function(node) {
-		dojo.event.connect(node, "onclick", this, "show");
-	},
-
-	onScroll: function(){
-		this.placeDialog();
-		this.domNode.style.display = "block";
-	},
-
-	onResize: function(e) {
-		this.sizeBackground();
 	}
-});
-
+);

Added: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DocPane.js
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DocPane.js?view=auto&rev=474551
==============================================================================
--- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DocPane.js (added)
+++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DocPane.js Mon Nov 13 14:54:45 2006
@@ -0,0 +1,382 @@
+/*
+	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.DocPane");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.io.*");
+dojo.require("dojo.event.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.Editor2");
+dojo.require("dojo.widget.Dialog");
+
+dojo.require("dojo.html.common");
+dojo.require("dojo.html.display");
+
+dojo.widget.DocPane = function(){
+	dojo.event.topic.subscribe("/docs/function/results", this, "onDocResults");
+	dojo.event.topic.subscribe("/docs/package/results", this, "onPkgResults");
+	dojo.event.topic.subscribe("/docs/function/detail", this, "onDocSelectFunction");
+}
+
+dojo.widget.defineWidget(
+	"dojo.widget.DocPane",
+	dojo.widget.HtmlWidget,
+	{
+		// Template parameters
+		dialog: null,
+		dialogBg: null,
+		dialogFg: null,
+		logIn: null,
+		edit: null,
+		save: null,
+		cancel: null,
+		detail: null,
+		result: null,
+		packag: null,
+		fn: null,
+		fnLink: null,
+		count: null,
+		row: null,
+		summary: null,
+		description: null,
+		variables: null,
+		vRow: null,
+		vLink: null,
+		vDesc: null,
+		methods: null,
+		mRow: null,
+		mLink: null,
+		mDesc: null,
+		requires: null,
+		rRow: null,
+		rRow2: null,
+		rH3: null,
+		rLink: null,
+		parameters: null,
+		pRow: null,
+		pLink: null,
+		pDesc: null,
+		pOpt: null,
+		pType: null,
+		sType: null,
+		sName: null,
+		sParams: null,
+		sPType: null,
+		sPTypeSave: null,
+		sPName: null,
+		sPNameSave: null,
+		pkgDescription: null,
+
+		// Fields and methods
+		_appends: [],
+		templatePath: dojo.uri.dojoUri("src/widget/templates/DocPane.html"),
+		templateCssPath: dojo.uri.dojoUri("src/widget/templates/DocPane.css"),
+		isContainer: true,
+		fillInTemplate: function(){
+			this.requires = dojo.html.removeNode(this.requires);
+			this.rRow.style.display = "none";
+			this.rRow2.style.display = "none";
+			
+			this.methods = dojo.html.removeNode(this.methods);
+			this.mRow.style.display = "none";
+			
+			this.dialog = dojo.widget.createWidget("dialog", {}, this.dialog);
+			this.dialog.setCloseControl(this.cancel);
+			dojo.html.setOpacity(this.dialogBg, 0.8);
+			dojo.html.setOpacity(this.dialogFg, 1);
+
+			dojo.event.connect(this.edit, "onclick", dojo.lang.hitch(this, function(){
+				if(!this._isLoggedIn){
+					this.dialog.show();
+				}
+			}));
+			dojo.event.connect(this.logIn, "onclick", this, "_logIn");
+			dojo.event.connect(this.save, "onclick", this, "_save");
+			dojo.event.connect(dojo.docs, "logInSuccess", this, "_loggedIn");
+			
+			/*
+			this.pkgDescription = dojo.widget.createWidget("editor2", {
+				toolbarAlwaysVisible: true
+			}, this.pkgDescription);
+			*/
+			
+			this.homeSave = this.containerNode.cloneNode(true);
+			this.detailSave = dojo.html.removeNode(this.detail);
+			this.resultSave = dojo.html.removeNode(this.result);
+			this.packageSave = dojo.html.removeNode(this.packag);
+			this.results = dojo.html.removeNode(this.results);
+			this.rowParent = this.row.parentNode;
+			this.rowSave = dojo.html.removeNode(this.row);
+			this.vParent = this.vRow.parentNode;
+			this.vSave = dojo.html.removeNode(this.vRow);
+			this.pParent = this.pRow.parentNode;
+			this.pSave = dojo.html.removeNode(this.pRow);
+			this.sPTypeSave = dojo.html.removeNode(this.sPType);
+			this.sPNameSave = dojo.html.removeNode(this.sPName);
+			this.navSave = dojo.html.removeNode(this.nav);
+		},
+
+		_logIn: function(){
+			dojo.docs.setUserName(this.userName.value);
+			dojo.docs.setPassword(this.password.value);
+		},
+
+		_loggedIn: function(){
+			this._isLoggedIn = true;
+			this.dialog.hide();
+			this.pkgEditor = dojo.widget.createWidget("editor2", {
+				toolbarAlwaysVisible: true
+			}, this.pkgDescription);
+		},
+
+		_save: function(){
+			if(this.pkgEditor){
+				dojo.docs.savePackage(this._pkgPath, {
+					description: this.pkgEditor.getEditorContent()
+				});
+			}
+		},
+
+		onDocSelectFunction: function(message){
+			dojo.debug("onDocSelectFunction()");
+			for(var key in message){
+				dojo.debug(key + ": " + dojo.json.serialize(message[key]));
+			}
+			var meta = message.meta;
+			if(meta){
+				var variables = meta.variables;
+				var this_variables = meta.this_variables;
+				var child_variables = meta.child_variables;
+				var parameters = meta.parameters;
+			}
+			var doc = message.doc;
+			dojo.debug(dojo.json.serialize(doc));
+
+			var appends = this._appends;
+			dojo.html.removeChildren(this.domNode);
+			this.fn.innerHTML = message.name;
+
+			this.variables.style.display = "block";
+			var all = [];
+			if(variables){
+				all = variables;
+			}
+			if(this_variables){
+				all = all.concat(this_variables);
+			}
+			if(child_variables){
+				all = all.concat(child_variables);
+			}
+			if(!all.length){
+				this.variables.style.display = "none";
+			}else{
+				for(var i = 0, one; one = all[i]; i++){
+					this.vLink.innerHTML = one;
+					this.vDesc.parentNode.style.display = "none";
+					appends.push(this.vParent.appendChild(this.vSave.cloneNode(true)));
+				}
+			}
+
+			this.sParams.innerHTML = "";
+			var first = true;
+			for(var param in parameters){
+				var paramType = parameters[param].type;
+				var paramSummary = parameters[param].summary;
+				var paramName = param;
+				this.parameters.style.display = "block";		
+				this.pLink.innerHTML = paramName;
+				this.pOpt.style.display = "none";
+				if(parameters[param].opt){
+					this.pOpt.style.display = "inline";				
+				}
+				this.pType.parentNode.style.display = "none";
+				if(parameters[param][0]){
+					this.pType.parentNode.style.display = "inline";
+					this.pType.innerHTML = paramType;
+				}
+				this.pDesc.parentNode.style.display = "none";
+				if(paramSummary){
+					this.pDesc.parentNode.style.display = "inline";
+					this.pDesc.innerHTML = paramSummary;
+				}
+				appends.push(this.pParent.appendChild(this.pSave.cloneNode(true)));
+
+				if(!first) {
+					this.sParams.appendChild(document.createTextNode(", "));
+				}
+				first = false;
+				if(paramType){
+					dojo.debug(this.sPTypeSave);
+					this.sPTypeSave.innerHTML = paramType;
+					this.sParams.appendChild(this.sPTypeSave.cloneNode(true));
+					this.sParams.appendChild(document.createTextNode(" "));
+				}
+				dojo.debug(this.sPNameSave);
+				this.sPNameSave.innerHTML = paramName;
+				this.sParams.appendChild(this.sPNameSave.cloneNode(true))
+			}
+
+			if(message.returns){
+				this.sType.innerHTML = message.returns;
+			}else{
+				this.sType.innerHTML = "void";
+			}
+
+			this.sName.innerHTML = message.name;
+
+			this.domNode.appendChild(this.navSave);
+			this.domNode.appendChild(this.detailSave.cloneNode(true));
+
+			for(var i = 0, append; append = appends[i]; i++){
+				dojo.html.removeNode(append);
+			}
+		},
+
+		onPkgResult: function(/*Object*/ results){
+			if(this.pkgEditor){
+				this.pkgEditor.close(true);
+				dojo.debug(this.pkgDescription);
+			}
+			var methods = results.methods;
+			var requires = results.requires;
+			var description = results.description;
+			this._pkgPath = results.path;
+			var requireLinks = [];
+			var appends = this._appends;
+			while(appends.length){
+				dojo.html.removeNode(appends.shift());
+			}
+
+			dojo.html.removeChildren(this.domNode);
+			
+			this.pkg.innerHTML = results.pkg;
+			
+			var hasRequires = false;
+			for(var env in requires){
+				hasRequires = true;
+
+				this.rH3.style.display = "none";
+				if(env != "common"){
+					this.rH3.style.display = "";
+					this.rH3.innerHTML = env;
+				}
+
+				for(var i = 0, require; require = requires[env][i]; i++){
+					requireLinks.push({
+						name: require
+					});
+					this.rLink.innerHTML = require;
+					this.rLink.href = "#" + require;
+					var rRow2 = this.rRow2.parentNode.insertBefore(this.rRow2.cloneNode(true), this.rRow2);
+					rRow2.style.display = "";
+					appends.push(rRow2);
+				}
+				var rRow = this.rRow.parentNode.insertBefore(this.rRow.cloneNode(true), this.rRow);
+				rRow.style.display = "";
+				appends.push(rRow);
+			}
+			
+			if(hasRequires){
+				appends.push(this.packageSave.appendChild(this.requires.cloneNode(true)));
+			}
+
+			if(results.size){
+				for(var i = 0, method; method = methods[i]; i++){
+					this.mLink.innerHTML = method.name;
+					this.mLink.href = "#" + method.name;
+					this.mDesc.parentNode.style.display = "none";
+					if(method.summary){
+						this.mDesc.parentNode.style.display = "inline";				
+						this.mDesc.innerHTML = method.summary;
+					}
+					var mRow = this.mRow.parentNode.insertBefore(this.mRow.cloneNode(true), this.mRow);
+					mRow.style.display = "";
+					appends.push(mRow);
+				}
+				appends.push(this.packageSave.appendChild(this.methods.cloneNode(true)));
+			}
+
+			this.domNode.appendChild(this.packageSave);
+			
+			/*
+			dojo.debug(description);
+			function fillContent(){
+				this.pkgDescription.replaceEditorContent(description);
+				this.pkgDescription._updateHeight();
+			}
+			if(this.pkgDescription.isLoaded){
+				fillContent();
+			}else{
+				dojo.event.connect(this.pkgDescription, "onLoad", dojo.lang.hitch(this, fillContent));
+			}
+			*/
+			this.pkgDescription.innerHTML = description;
+			
+			function makeSelect(fOrP, x){
+				return function(e) {
+					dojo.event.topic.publish("/docs/" + fOrP + "/select", x);
+				}
+			}
+
+			var as = this.domNode.getElementsByTagName("a");
+			for(var i = 0, a; a = as[i]; i++){
+				if(a.className == "docMLink"){
+					dojo.event.connect(a, "onclick", makeSelect("function", methods[i]));
+				}else if(a.className == "docRLink"){
+					dojo.event.connect(a, "onclick", makeSelect("package", requireLinks[i]));
+				}
+			}
+		},
+
+		onDocResults: function(fns){
+			dojo.debug("onDocResults(): called");
+
+			if(fns.length == 1){
+				dojo.event.topic.publish("/docs/function/select", fns[0]);
+				return;
+			}
+
+			dojo.html.removeChildren(this.domNode);
+
+			this.count.innerHTML = fns.length;
+			var appends = [];
+			for(var i = 0, fn; fn = fns[i]; i++){
+				this.fnLink.innerHTML = fn.name;
+				this.fnLink.href = "#" + fn.name;
+				if(fn.id){
+					this.fnLink.href = this.fnLink.href + "," + fn.id;	
+				}
+				this.summary.parentNode.style.display = "none";
+				if(fn.summary){
+					this.summary.parentNode.style.display = "inline";				
+					this.summary.innerHTML = fn.summary;
+				}
+				appends.push(this.rowParent.appendChild(this.rowSave.cloneNode(true)));
+			}
+
+			function makeSelect(x){
+				return function(e) {
+					dojo.event.topic.publish("/docs/function/select", x);
+				}
+			}
+
+			this.domNode.appendChild(this.resultSave.cloneNode(true));
+			var as = this.domNode.getElementsByTagName("a");
+			for(var i = 0, a; a = as[i]; i++){
+				dojo.event.connect(a, "onclick", makeSelect(fns[i]));
+			}
+
+			for(var i = 0, append; append = appends[i]; i++){
+				this.rowParent.removeChild(append);
+			}
+		}
+	}
+);

Propchange: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/static/dojo/src/widget/DocPane.js
------------------------------------------------------------------------------
    svn:eol-style = native