You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by jk...@apache.org on 2008/02/04 23:08:37 UTC

svn commit: r618461 [42/43] - in /tapestry/tapestry4/trunk/tapestry-framework/src/js: dojo-0.4.3-custom-4.1.5/ dojo-0.4.3-custom-4.1.5/nls/ dojo-0.4.3-custom-4.1.5/src/ dojo-0.4.3-custom-4.1.5/src/animation/ dojo-0.4.3-custom-4.1.5/src/cal/ dojo-0.4.3-...

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/Parse.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/Parse.js?rev=618461&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/Parse.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/Parse.js Mon Feb  4 14:07:13 2008
@@ -0,0 +1,152 @@
+dojo.provide("dojo.xml.Parse");
+dojo.require("dojo.dom");
+dojo.xml.Parse=function(){
+var _1=((dojo.render.html.capable)&&(dojo.render.html.ie));
+function getTagName(_2){
+try{
+return _2.tagName.toLowerCase();
+}
+catch(e){
+return "";
+}
+}
+function getDojoTagName(_3){
+var _4=getTagName(_3);
+if(!_4){
+return "";
+}
+if((dojo.widget)&&(dojo.widget.tags[_4])){
+return _4;
+}
+var p=_4.indexOf(":");
+if(p>=0){
+return _4;
+}
+if(_4.substr(0,5)=="dojo:"){
+return _4;
+}
+if(dojo.render.html.capable&&dojo.render.html.ie&&_3.scopeName!="HTML"){
+return _3.scopeName.toLowerCase()+":"+_4;
+}
+if(_4.substr(0,4)=="dojo"){
+return "dojo:"+_4.substring(4);
+}
+var _6=_3.getAttribute("dojoType")||_3.getAttribute("dojotype");
+if(_6){
+if(_6.indexOf(":")<0){
+_6="dojo:"+_6;
+}
+return _6.toLowerCase();
+}
+_6=_3.getAttributeNS&&_3.getAttributeNS(dojo.dom.dojoml,"type");
+if(_6){
+return "dojo:"+_6.toLowerCase();
+}
+try{
+_6=_3.getAttribute("dojo:type");
+}
+catch(e){
+}
+if(_6){
+return "dojo:"+_6.toLowerCase();
+}
+if((dj_global["djConfig"])&&(!djConfig["ignoreClassNames"])){
+var _7=_3.className||_3.getAttribute("class");
+if((_7)&&(_7.indexOf)&&(_7.indexOf("dojo-")!=-1)){
+var _8=_7.split(" ");
+for(var x=0,c=_8.length;x<c;x++){
+if(_8[x].slice(0,5)=="dojo-"){
+return "dojo:"+_8[x].substr(5).toLowerCase();
+}
+}
+}
+}
+return "";
+}
+this.parseElement=function(_b,_c,_d,_e){
+var _f=getTagName(_b);
+if(_1&&_f.indexOf("/")==0){
+return null;
+}
+try{
+var _10=_b.getAttribute("parseWidgets");
+if(_10&&_10.toLowerCase()=="false"){
+return {};
+}
+}
+catch(e){
+}
+var _11=true;
+if(_d){
+var _12=getDojoTagName(_b);
+_f=_12||_f;
+_11=Boolean(_12);
+}
+var _13={};
+_13[_f]=[];
+var pos=_f.indexOf(":");
+if(pos>0){
+var ns=_f.substring(0,pos);
+_13["ns"]=ns;
+if((dojo.ns)&&(!dojo.ns.allow(ns))){
+_11=false;
+}
+}
+if(_11){
+var _16=this.parseAttributes(_b);
+for(var _10 in _16){
+if((!_13[_f][_10])||(typeof _13[_f][_10]!="array")){
+_13[_f][_10]=[];
+}
+_13[_f][_10].push(_16[_10]);
+}
+_13[_f].nodeRef=_b;
+_13.tagName=_f;
+_13.index=_e||0;
+}
+var _17=0;
+for(var i=0;i<_b.childNodes.length;i++){
+var tcn=_b.childNodes.item(i);
+switch(tcn.nodeType){
+case dojo.dom.ELEMENT_NODE:
+var ctn=getDojoTagName(tcn)||getTagName(tcn);
+if(!_13[ctn]){
+_13[ctn]=[];
+}
+_13[ctn].push(this.parseElement(tcn,true,_d,_17));
+if((tcn.childNodes.length==1)&&(tcn.childNodes.item(0).nodeType==dojo.dom.TEXT_NODE)){
+_13[ctn][_13[ctn].length-1].value=tcn.childNodes.item(0).nodeValue;
+}
+_17++;
+break;
+case dojo.dom.TEXT_NODE:
+if(_b.childNodes.length==1){
+_13[_f].push({value:_b.childNodes.item(0).nodeValue});
+}
+break;
+default:
+break;
+}
+}
+return _13;
+};
+this.parseAttributes=function(_1b){
+var _1c={};
+var _1d=_1b.attributes;
+var _1e,i=0;
+while((_1e=_1d[i++])){
+if(_1){
+if(!_1e){
+continue;
+}
+if((typeof _1e=="object")&&(typeof _1e.nodeValue=="undefined")||(_1e.nodeValue==null)||(_1e.nodeValue=="")){
+continue;
+}
+}
+var nn=_1e.nodeName.split(":");
+nn=(nn.length==2)?nn[1]:_1e.nodeName;
+_1c[nn]={value:_1e.nodeValue};
+}
+return _1c;
+};
+};

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/Parse.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/Parse.js
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/Parse.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/XslTransform.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/XslTransform.js?rev=618461&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/XslTransform.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/XslTransform.js Mon Feb  4 14:07:13 2008
@@ -0,0 +1,146 @@
+dojo.provide("dojo.xml.XslTransform");
+dojo.xml.XslTransform=function(_1){
+dojo.debug("XslTransform is supported by Internet Explorer and Mozilla, with limited support in Opera 9 (no document function support).");
+var _2=dojo.render.html.ie;
+var _3=["Msxml2.DOMDocument.5.0","Msxml2.DOMDocument.4.0","Msxml2.DOMDocument.3.0","MSXML2.DOMDocument","MSXML.DOMDocument","Microsoft.XMLDOM"];
+var _4=["Msxml2.FreeThreadedDOMDocument.5.0","MSXML2.FreeThreadedDOMDocument.4.0","MSXML2.FreeThreadedDOMDocument.3.0"];
+var _5=["Msxml2.XSLTemplate.5.0","Msxml2.XSLTemplate.4.0","MSXML2.XSLTemplate.3.0"];
+function getActiveXImpl(_6){
+for(var i=0;i<_6.length;i++){
+try{
+var _8=new ActiveXObject(_6[i]);
+if(_8){
+return _6[i];
+}
+}
+catch(e){
+}
+}
+dojo.raise("Could not find an ActiveX implementation in:\n\n "+_6);
+}
+if(_1==null||_1==undefined){
+dojo.raise("You must pass the URI String for the XSL file to be used!");
+return false;
+}
+var _9=null;
+var _a=null;
+if(_2){
+_9=new ActiveXObject(getActiveXImpl(_4));
+_9.async=false;
+}else{
+_a=new XSLTProcessor();
+_9=document.implementation.createDocument("","",null);
+_9.addEventListener("load",onXslLoad,false);
+}
+_9.load(_1);
+if(_2){
+var _b=new ActiveXObject(getActiveXImpl(_5));
+_b.stylesheet=_9;
+_a=_b.createProcessor();
+}
+function onXslLoad(){
+_a.importStylesheet(_9);
+}
+function getResultDom(_c,_d){
+if(_2){
+addIeParams(_d);
+var _e=getIeResultDom(_c);
+removeIeParams(_d);
+return _e;
+}else{
+return getMozillaResultDom(_c,_d);
+}
+}
+function addIeParams(_f){
+if(!_f){
+return;
+}
+for(var i=0;i<_f.length;i++){
+_a.addParameter(_f[i][0],_f[i][1]);
+}
+}
+function removeIeParams(_11){
+if(!_11){
+return;
+}
+for(var i=0;i<_11.length;i++){
+_a.addParameter(_11[i][0],"");
+}
+}
+function getIeResultDom(_13){
+_a.input=_13;
+var _14=new ActiveXObject(getActiveXImpl(_3));
+_14.async=false;
+_14.validateOnParse=false;
+_a.output=_14;
+_a.transform();
+if(_14.parseError.errorCode!=0){
+var err=_14.parseError;
+dojo.raise("err.errorCode: "+err.errorCode+"\n\nerr.reason: "+err.reason+"\n\nerr.url: "+err.url+"\n\nerr.srcText: "+err.srcText);
+}
+return _14;
+}
+function getIeResultStr(_16,_17){
+_a.input=_16;
+_a.transform();
+return _a.output;
+}
+function addMozillaParams(_18){
+if(!_18){
+return;
+}
+for(var i=0;i<_18.length;i++){
+_a.setParameter(null,_18[i][0],_18[i][1]);
+}
+}
+function getMozillaResultDom(_1a,_1b){
+addMozillaParams(_1b);
+var _1c=_a.transformToDocument(_1a);
+_a.clearParameters();
+return _1c;
+}
+function getMozillaResultStr(_1d,_1e,_1f){
+addMozillaParams(_1e);
+var _20=_a.transformToFragment(_1d,_1f);
+var _21=new XMLSerializer();
+_a.clearParameters();
+return _21.serializeToString(_20);
+}
+this.getResultString=function(_22,_23,_24){
+var _25=null;
+if(_2){
+addIeParams(_23);
+_25=getIeResultStr(_22,_23);
+removeIeParams(_23);
+}else{
+_25=getMozillaResultStr(_22,_23,_24);
+}
+return _25;
+};
+this.transformToContentPane=function(_26,_27,_28,_29){
+var _2a=this.getResultString(_26,_27,_29);
+_28.setContent(_2a);
+};
+this.transformToRegion=function(_2b,_2c,_2d,_2e){
+try{
+var _2f=this.getResultString(_2b,_2c,_2e);
+_2d.innerHTML=_2f;
+}
+catch(e){
+dojo.raise(e.message+"\n\n xsltUri: "+_1);
+}
+};
+this.transformToDocument=function(_30,_31){
+return getResultDom(_30,_31);
+};
+this.transformToWindow=function(_32,_33,_34,_35){
+try{
+_34.open();
+_34.write(this.getResultString(_32,_33,_35));
+_34.close();
+}
+catch(e){
+dojo.raise(e.message+"\n\n xsltUri: "+_1);
+}
+};
+};

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/XslTransform.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/XslTransform.js
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/XslTransform.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/__package__.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/__package__.js?rev=618461&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/__package__.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/__package__.js Mon Feb  4 14:07:13 2008
@@ -0,0 +1,3 @@
+dojo.require("dojo.xml.Parse");
+dojo.kwCompoundRequire({common:["dojo.dom"],browser:["dojo.html.*"],dashboard:["dojo.html.*"]});
+dojo.provide("dojo.xml.*");

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/__package__.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/__package__.js
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/src/xml/__package__.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/storage_dialog.swf
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/storage_dialog.swf?rev=618461&view=auto
==============================================================================
Binary file - no diff available.

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo-0.4.3-custom-4.1.5/storage_dialog.swf
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/core.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/core.js?rev=618461&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/core.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/core.js Mon Feb  4 14:07:13 2008
@@ -0,0 +1,946 @@
+dojo.provide("tapestry.core");
+dojo.provide("tapestry.html");
+dojo.provide("tapestry.event");
+dojo.provide("tapestry.lang");
+
+dojo.require("dojo.lang.common");
+dojo.require("dojo.io.BrowserIO");
+dojo.require("dojo.event.browser");
+dojo.require("dojo.html.style");
+dojo.require("dojo.lang.func");
+dojo.require("dojo.string.extras");
+
+// redirect logging calls to standard debug if logging not enabled
+if (dj_undef("logging", dojo)) {
+    dojo.log = {
+        debug:function(){
+            dojo.debug.apply(this, arguments);
+        },
+        info:function(){
+            dojo.debug.apply(this, arguments);
+        },
+        warn:function(){
+            dojo.debug.apply(this, arguments);
+        },
+        err:function(){
+            dojo.debug.apply(this, arguments);
+        },
+        exception:function(){
+            dojo.debug.apply(this, arguments);
+        }
+    }
+}
+
+/**
+ * package: tapestry
+ * Provides the core functionality for the Tapestry javascript package libraries. 
+ * 
+ * Most of the functions in here are related to initiating and parsing IO 
+ * requests. 
+ */
+var tapestry={
+
+	// property: version
+	// The current client side library version, usually matching the current java library version. (ie 4.1, etc..)
+	version:"4.1.4",
+	scriptInFlight:false, // whether or not javascript is currently being eval'd, default false
+	ScriptFragment:new RegExp('(?:<script.*?>)((\n|.|\r)*?)(?:<\/script>)', 'im'), // regexp for script elements
+    GlobalScriptFragment:new RegExp('(?:<script.*?>)((\n|.|\r)*?)(?:<\/script>)', 'img'), // regexp for global script fragments
+    requestsInFlight:0, // how many ajax requests are currently in progress
+    isIE:dojo.render.html.ie,
+    isMozilla:dojo.render.html.mozilla,
+	// property: requestEncoding
+	// Defines the encoding that will be used in all Tapestry initiated XHR requests to encode
+	// URL or form data. Gets set by AjaxShellDelegate class on server on most requests by default.
+	requestEncoding:"UTF-8",
+
+	/**
+	 * Function: bind
+	 *
+	 * Core XHR bind function for tapestry internals. The
+	 * <error>/<load> functions defined in this package are used to handle
+	 * load/error of dojo.io.bind.
+	 *
+	 * Parameters:
+	 *
+	 * 	url - The url to bind the request to.
+	 * 	content - A properties map of optional extra content to send.
+	 *  json - Boolean, optional parameter specifying whether or not to create a
+	 * 		   json request. If not specified the default is to use XHR.
+	 */
+	bind:function(url, content, json){
+		var parms = {
+			url:url,
+			content:content,
+            useCache:true,
+            preventCache:true,
+			encoding: tapestry.requestEncoding,
+			error: (function(){tapestry.error.apply(this, arguments);})
+		};
+
+		// setup content type
+		if (typeof json != "undefined" && json) {
+			parms.mimetype = "text/json";
+			parms.headers={"json":true};
+			parms.load=(function(){tapestry.loadJson.apply(this, arguments);});
+		} else {
+			parms.headers={"dojo-ajax-request":true};
+			parms.mimetype="text/xml";
+			parms.load=(function(){tapestry.load.apply(this, arguments);});
+		}
+
+        tapestry.requestsInFlight++;
+        dojo.io.queueBind(parms);
+	},
+
+	/**
+	 * Function: error
+	 *
+	 * Global error handling function for dojo.io.bind requests. This function is mapped
+	 * as the "error:functionName" part of a request in the dojo.io.bind arguments
+	 * in <tapestry.bind> calls.
+	 *
+	 * See Also:
+	 * 	<tapestry.bind>, <tapestry.load>
+	 */
+	error:function(type, exception, http, kwArgs){
+        tapestry.requestsInFlight--;
+        dojo.log.exception("Error received in IO response.", exception);
+	},
+
+	/**
+	 * Function: load
+	 *
+	 * Global load handling function for dojo.io.bind requests. This isn't typically
+	 * called directly by anything, but passed in as the "load" argument to
+	 * dojo.io.bind when making IO requests as the function that will handle the
+	 * return response.
+	 *
+	 * Parameters:
+	 * 	type - Type of request.
+	 * 	data - The data returned, depending on the request type might be an xml document /
+	 * 			plaintext / json / etc.
+	 * 	http - The http object used in request, like XmlHttpRequest.
+	 * 	kwArgs - The original set of arguments passed into dojo.io.bind({arg:val,arg1:val2}).
+	 *
+	 */
+	load:function(type, data, http, kwArgs){
+		dojo.log.debug("tapestry.load() Response received.", data);
+        tapestry.requestsInFlight--;
+        if (!data) {
+			dojo.log.warn("No data received in response.");
+			return;
+		}
+
+		var resp=data.getElementsByTagName("ajax-response");
+		if (!resp || resp.length < 1 || !resp[0].childNodes) {
+			dojo.log.warn("No ajax-response elements received.");
+			return;
+		}
+
+		var elms=resp[0].childNodes;
+		var bodyScripts=[];
+		var initScripts=[];
+		var rawData=[];
+		for (var i=0; i<elms.length; i++) {
+			var elmType=elms[i].getAttribute("type");
+			var id=elms[i].getAttribute("id");
+
+			if (elmType == "exception") {
+				dojo.log.err("Remote server exception received.");
+				tapestry.presentException(elms[i], kwArgs);
+				return;
+			} else if (elmType == "page") {
+                window.location=elms[i].getAttribute("url");
+                return;
+            } else if (elmType == "status") {
+                dojo.event.topic.publish(id, {message: tapestry.html.getContentAsString(elms[i])});
+                continue;
+            }
+
+			// handle javascript evaluations
+			if (elmType == "script") {
+
+				if (id == "initializationscript") {
+					initScripts.push(elms[i]);
+					continue;
+				} else if (id == "bodyscript") {
+					bodyScripts.push(elms[i]);
+					continue;
+				} else if (id == "includescript") {
+					// includes get processed immediately (synchronously)
+					var includes=elms[i].getElementsByTagName("include");
+					if (!includes){continue;}
+					for (var e=0; e<includes.length;e++) {
+						tapestry.loadScriptFromUrl(includes[e].getAttribute("url"));
+					}
+					continue;
+				}
+			} else {
+				rawData.push(elms[i]);
+			}
+
+			if (!id){
+				dojo.log.warn("No element id found in ajax-response node.");
+				continue;
+			}
+
+			var node=dojo.byId(id);
+			if (!node) {
+				dojo.log.warn("No node could be found to update content in with id " + id);
+				continue;
+			}
+
+            tapestry.loadContent(id, node, elms[i]);
+        }
+
+		// load body scripts before initialization
+		for (var i=0; i<bodyScripts.length; i++) {
+			tapestry.loadScriptContent(bodyScripts[i], true);
+		}
+
+		for (var i=0; i<rawData.length; i++) {
+			tapestry.loadScriptContent(rawData[i], true);
+		}
+
+		for (var i=0; i<initScripts.length; i++) {
+			tapestry.loadScriptContent(initScripts[i], true);
+		}
+	},
+
+	/**
+ 	 * Function: loadJson
+ 	 *
+ 	 * Executed by default during JSON requests - default implementation does nothing but decrement
+ 	 * the <tapestry.requestsInFlight> global variable.
+ 	 *
+ 	 * Parameters:
+ 	 * 	type - Type of request.
+	 * 	data - The data returned, depending on the request type might be an xml document /
+	 * 			plaintext / json / etc.
+	 * 	http - The http object used in request, like XmlHttpRequest.
+	 * 	kwArgs - The original set of arguments passed into dojo.io.bind({arg:val,arg1:val2}).
+ 	 */
+	loadJson:function(type, data, http, kwArgs) {
+		dojo.log.debug("tapestry.loadJson() Response received.", data);
+		tapestry.requestsInFlight--;
+	},
+
+	/**
+	 * Function: loadContent
+	 *
+	 * Used by <tapestry.load> when handling xml responses to iterate over the tapestry
+	 * specific xml response and appropriately load all content types / perform animations /
+	 * execute scripts in the proper order / etc..
+	 *
+	 * Parameters:
+	 * 	id - The element id that this content should be applied to in the existing document.
+	 * 	node - The node that this new content will be applied to.
+	 * 	element - The incoming xml node containing rules/content to apply to this node.
+	 *
+	 */
+	loadContent:function(id, node, element){
+        if (typeof element.childNodes != "undefined" && element.childNodes.length > 0) {
+            for (var i = 0; i < element.childNodes.length; i++) {
+                if (element.childNodes[i].nodeType != 1) { continue; }
+
+                var nodeId = element.childNodes[i].getAttribute("id");
+                if (nodeId) {
+                    element=element.childNodes[i];
+                    break;
+                }
+            }
+        }
+
+    	var content=tapestry.html.getContentAsString(element);
+    	if (djConfig["isDebug"]) {
+    		dojo.log.debug("Received element content for id <" + id + "> of: " + content);
+    	}
+
+        // on IE don't destroy event listeners on single element nodes like form input boxes/etc
+        if (!tapestry.isIE || (tapestry.isIE && node.childNodes && node.childNodes.length > 0)){
+            dojo.event.browser.clean(node); // prevent mem leaks in ie
+        }
+
+        // fix for IE - setting innerHTML does not work for SELECTs
+        if (tapestry.isIE && !dj_undef("outerHTML", node) && node.nodeName == "SELECT") {
+            node.outerHTML = node.outerHTML.replace(/(<SELECT[^<]*>).*(<\/SELECT>)/, '$1' + content + '$2');
+            node=dojo.byId(id);
+        } else if (content && content.length > 0
+                && (!tapestry.isIE || content.length > 1)){
+            node.innerHTML=content;
+        }
+        
+        // copy attributes
+		var atts=element.attributes;
+		var attnode, i=0;
+		while((attnode=atts[i++])){
+            if(tapestry.isIE){
+				if(!attnode){ continue; }
+				if((typeof attnode == "object")&&
+					(typeof attnode.nodeValue == 'undefined')||
+					(attnode.nodeValue == null)||
+					(attnode.nodeValue == '')){
+					continue;
+				}
+			}
+
+			var nn = attnode.nodeName;
+			var nv = attnode.nodeValue;
+			if (nn == "id" || nn == "type" || nn == "name"){continue;}
+
+			if (nn == "style") {
+				dojo.html.setStyleText(node, nv);
+			} else if (nn == "class") {
+				dojo.html.setClass(node, nv);
+			} else if (nn == "value") {
+                node.value = nv;
+            } else {
+				node.setAttribute(nn, nv);
+			}
+        }
+
+    	// apply disabled/not disabled
+    	var disabled = element.getAttribute("disabled");
+        if (!disabled && node["disabled"]) {
+            node.disabled = false;
+        } else if (disabled) {
+    		node.disabled = true;
+        }
+	},
+
+	/**
+	 * Function: loadScriptContent
+	 *
+	 * Manages loading javascript content for a specific incoming xml element.
+	 *
+	 * Parameters:
+	 * 	element - The element to parse javascript statements from and execute.
+	 * 	async - Whether or not to process the script content asynchronously, meaning
+	 * 			whether or not to execute the script in a block done in a setTimeout call
+	 * 			so as to avoid IE specific issues.
+	 */
+	loadScriptContent:function(element, async){
+		if (typeof async == "undefined") { async = true; }
+        async = this.isIE;
+
+        if (tapestry.scriptInFlight) {
+			dojo.log.debug("loadScriptContent(): scriptInFlight is true, sleeping");
+			setTimeout(function() { tapestry.loadScriptContent(element, async);}, 5);
+			return;
+		}
+
+		var text=tapestry.html.getContentAsString(element);
+	    text.replace(this.GlobalScriptFragment, '');
+	    var scripts = text.match(this.GlobalScriptFragment);
+
+		if (!scripts) { return; }
+
+        if (async) {
+        	setTimeout(function() {
+        		tapestry.evaluateScripts(scripts);
+        	}, 60);
+        } else {
+        	tapestry.evaluateScripts(scripts);
+        }
+	},
+
+	evaluateScripts:function(scripts){
+		tapestry.scriptInFlight = true;
+
+        for (var i=0; i<scripts.length; i++) {
+            var scr = scripts[i].match(this.ScriptFragment)[1];
+            if(!scr || scr.length <= 0){continue;}
+            try {
+                dojo.log.debug("evaluating script:", scr);
+                eval(scr);
+            } catch (e) {
+            	tapestry.scriptInFlight = false;
+                dojo.log.exception("Error evaluating script: " + scr, e, false);
+            }
+        }
+
+        tapestry.scriptInFlight = false;
+	},
+
+	/**
+	 * Function: loadScriptFromUrl
+	 *
+	 * Takes a url string and loads the javascript it points to as a normal
+	 * document head script include section. ie:
+	 *
+	 * : <script type="text/javascript" src="http://localhost/js/foo.js"></script>
+	 *
+	 * Parameters:
+	 * 	url - The url to the script to load into this documents head.
+	 */
+	loadScriptFromUrl:function(url){
+	    var scripts = window.document.getElementsByTagName("script");
+	    if (scripts){
+		    for (var i = 0; i < scripts.length; i++) {
+		        var src = scripts[i].src;
+		        if (src && src.length > 0 && src.indexOf(url)>=0 ) {
+		            return;
+		        }
+		    }
+	    }
+
+	    if (djConfig.isDebug) {
+	    	dojo.log.debug("loadScriptFromUrl: " + url + " success?: " + dojo.hostenv.loadUri(url));
+	    } else {
+	    	dojo.hostenv.loadUri(url);
+	    }
+	},
+
+	/**
+	 * Function: presentException
+	 *
+	 * When remote exceptions are caught on the server special xml blocks are returned to
+	 * the client when the requests are initiated via async IO. This function takes the incoming
+	 * Tapestry exception page content and dumps it into a modal dialog that is presented to the user.
+	 *
+	 * Parameters:
+	 * 	node - The incoming xml exception node.
+	 * 	kwArgs - The kwArgs used to initiate the original IO request.
+	 */
+	presentException:function(node, kwArgs) {
+        dojo.require("dojo.widget.*");
+        dojo.require("dojo.widget.Dialog");
+
+        var excnode=document.createElement("div");
+		excnode.setAttribute("id", "exceptiondialog");
+		document.body.appendChild(excnode);
+
+		var contentnode=document.createElement("div");
+		contentnode.innerHTML=tapestry.html.getContentAsString(node);
+		dojo.html.setClass(contentnode, "exceptionDialog");
+
+		var navnode=document.createElement("div");
+		navnode.setAttribute("id", "exceptionDialogHandle");
+		dojo.html.setClass(navnode, "exceptionCloseLink");
+		navnode.appendChild(document.createTextNode("Close"));
+
+		excnode.appendChild(navnode);
+		excnode.appendChild(contentnode);
+
+		var dialog=dojo.widget.createWidget("Dialog", {widgetId:"exception"}, excnode);
+		dojo.event.connect(navnode, "onclick", dialog, "hide");
+		dojo.event.connect(dialog, "hide", dialog, "destroy");
+
+        setTimeout(function(){
+            dialog.show();
+        }, 100);
+    },
+
+	/**
+	 * Function: cleanConnect
+	 *
+	 * Utility used to disconnect a previously connected event/function.
+	 *
+	 * This assumes that the incoming function name is being attached to
+	 * the global namespace "tapestry".
+	 */
+	cleanConnect:function(target, event, funcName){
+        target = dojo.byId(target);
+		if (!dj_undef(funcName, tapestry)){
+        	dojo.event.disconnect(target, event, tapestry, funcName);
+        }
+	},
+
+	/**
+	 * Function: cleanConnectWidget
+	 */
+	cleanConnectWidget:function(target, event, funcName){
+        tapestry.cleanConnect(dojo.widget.byId(target), event, funcName);
+	},
+
+	/**
+	 * Function: connect
+	 *
+	 * Utility used to connect an event/function.
+	 *
+	 * This assumes that the incoming function name is being attached to
+	 * the global namespace "tapestry".
+	 */
+	connect:function(target, event, funcName){
+        target = dojo.byId(target);
+		if (!dj_undef(funcName, tapestry)){
+        	dojo.event.connect(target, event, tapestry, funcName);
+        }
+	},
+
+	/**
+	 * Function: connectBefore
+	 */
+	connectBefore:function(target, event, funcName){
+        target = dojo.byId(target);
+		if (!dj_undef(funcName, tapestry)){
+        	dojo.event.connect("before", target, event, tapestry, funcName);
+        }
+	},
+
+	/**
+	 * Function: connectWidget
+	 */
+	connectWidget:function(target, event, funcName){
+        tapestry.connect(dojo.widget.byId(target), event, funcName);
+	},
+
+	/**
+	 * Function: byId
+     */
+    byId:dojo.byId,
+
+	/**
+	 * Function: raise
+     */
+    raise:dojo.raise,
+
+	/**
+	 * Function: addOnLoad
+     */
+    addOnLoad:dojo.addOnLoad,
+
+	/**
+	 * Function: provide
+     */
+    provide:dojo.provide,
+
+    /**
+	 * Function: linkOnClick
+     */
+	linkOnClick:function(url, id, isJson, eventName){
+		var content={beventname:(eventName || "onClick")};
+		content["beventtarget.id"]=id;
+
+		tapestry.bind(url, content, isJson);
+		return false;
+	},
+
+    /**
+	 * Function: isServingRequests
+	 *
+	 * Utility used to find out if there are any ajax requests in progress.
+	 */
+    isServingRequests:function(){
+	    return (this.requestsInFlight > 0);
+    }
+}
+
+/**
+ * package: tapestry.html
+ * Provides functionality related to parsing and rendering dom nodes.
+ */
+tapestry.html={
+
+    CompactElementRegexp:/<([a-zA-Z](?!nput)[a-zA-Z]*)([^>]*?)\/>/g, // regexp for compact html elements
+    CompactElementReplacer:'<$1$2></$1>', // replace pattern for compact html elements
+
+    /**
+	 * Function: getContentAsString
+	 *
+	 * Takes a dom node and returns its contents rendered in a string.
+     *
+     * The resulting string does NOT contain any markup (or attributes) of
+     * the given node - only child nodes are rendered and returned.Content
+     *
+     * Implementation Note: This function tries to make use of browser
+     * specific features (the xml attribute of nodes in IE and the XMLSerializer
+     * object in Mozilla derivatives) - if those fails, a generic implementation
+     * is used that is guaranteed to work in all platforms.
+	 *
+	 * Parameters:
+	 *
+	 *	node - The dom node.
+	 * Returns:
+	 *
+	 * The string representation of the given node's contents.
+	 */
+	getContentAsString:function(node){
+        if (typeof node.xml != "undefined") {
+			return this._getContentAsStringIE(node);
+		} else if (typeof XMLSerializer != "undefined" ) {
+			return this._getContentAsStringMozilla(node);
+		} else {
+			return this._getContentAsStringGeneric(node);
+		}
+	},
+
+   /**
+	 * Function: getElementAsString
+	 *
+	 * Takes a dom node and returns itself and its contents rendered in a string.
+     *
+     * Implementation Note: This function uses a generic implementation in order
+     * to generate the returned string.
+	 *
+	 * Parameters:
+	 *
+	 *	node - The dom node.
+	 * Returns:
+	 *
+	 * The string representation of the given node.
+	 */
+	getElementAsString:function(node){
+		if (!node) { return ""; }
+
+		var s='<' + node.nodeName;
+		// add attributes
+		if (node.attributes && node.attributes.length > 0) {
+			for (var i=0; i < node.attributes.length; i++) {
+				s += " " + node.attributes[i].name + "=\"" + node.attributes[i].value + "\"";
+			}
+		}
+		// close start tag
+		s += '>';
+		// content of tag
+		s += this._getContentAsStringGeneric(node);
+		// end tag
+		s += '</' + node.nodeName + '>';
+		return s;
+	},
+
+    /**
+     * Adds togglers and js effects to the exception page.
+     */
+    enhanceExceptionPage:function(){
+        // attach toggles + hide content
+
+        var elms=dojo.html.getElementsByClass('toggle');
+
+        if(elms && elms.length > 0){
+            for(var i=0;i<elms.length;i++){
+
+                dojo.event.connect(elms[i], "onclick", function(e) {
+                    var thisLink = e.target;
+                    dojo.html.toggleShowing(dojo.byId(thisLink.id + 'Data'));
+                    if(dojo.html.hasClass(thisLink, "toggleSelected"))
+                        dojo.html.removeClass(thisLink, "toggleSelected")
+                    else
+                        dojo.html.addClass(thisLink, "toggleSelected");
+                    if (e.preventDefault)
+                        dojo.event.browser.stopEvent(e);
+                    return false;
+                });
+                dojo.html.toggleShowing(elms[i].id+'Data');
+            }
+        }
+
+        // but show last exception's content
+        elms=dojo.html.getElementsByClass('exception-link');
+        if(elms && elms.length > 0){
+            elms[elms.length-1].onclick({target:elms[elms.length-1]});
+        }
+    },
+
+	_getContentAsStringIE:function(node){
+		var s=" "; //blank works around an IE-bug
+    	for (var i = 0; i < node.childNodes.length; i++){
+        	s += node.childNodes[i].xml;
+    	}
+    	return s;
+	},
+
+	_getContentAsStringMozilla:function(node){
+        if (!this.xmlSerializer){ this.xmlSerializer = new XMLSerializer();}
+
+	    var s = "";
+        for (var i = 0; i < node.childNodes.length; i++) {
+	        s += this.xmlSerializer.serializeToString(node.childNodes[i]);
+	        if (s == "undefined")
+		        return this._getContentAsStringGeneric(node);
+        }
+
+        return this._processCompactElements(s);
+	},
+
+	_getContentAsStringGeneric:function(node){
+		var s="";
+		if (node == null) { return s; }
+		for (var i = 0; i < node.childNodes.length; i++) {
+			switch (node.childNodes[i].nodeType) {
+				case 1: // ELEMENT_NODE
+				case 5: // ENTITY_REFERENCE_NODE
+					s += this.getElementAsString(node.childNodes[i]);
+					break;
+				case 3: // TEXT_NODE
+				case 2: // ATTRIBUTE_NODE
+				case 4: // CDATA_SECTION_NODE
+					s += node.childNodes[i].nodeValue;
+					break;
+				default:
+					break;
+			}
+		}
+		return s;
+	},
+
+	_processCompactElements:function(htmlData)
+ 	{
+		 return htmlData.replace(this.CompactElementRegexp, this.CompactElementReplacer);
+ 	}
+}
+
+/**
+ * package: tapestry.event
+ * 
+ * Utility functions that handle converting javascript event objects into 
+ * a name/value pair format that can be sent to the remote server.
+ */
+tapestry.event={
+
+	/**
+	 * Function: buildEventProperties
+	 *
+	 * Takes an incoming browser generated event (like key/mouse events) and
+	 * creates a js object holding the basic values of the event in order for
+	 * it to be submitted to the server.
+	 *
+	 * Parameters:
+	 *
+	 *	event - The javascript event method is based on, if it isn't a valid
+	 * 				browser event it will be ignored.
+	 *	props - The existing property object to set the values on, if it doesn't
+	 * 				exist one will be created.
+	 *  args  - The arguments from an method-call interception
+	 * Returns:
+	 *
+	 * The desired event properties bound to an object. Ie obj.target,obj.charCode, etc..
+	 */
+	buildEventProperties:function(event, props, args){
+		if (!props) props={};
+
+		if (dojo.event.browser.isEvent(event)) {
+			if(event["type"]) props.beventtype=event.type;
+			if(event["keys"]) props.beventkeys=event.keys;
+			if(event["charCode"]) props.beventcharCode=event.charCode;
+			if(event["pageX"]) props.beventpageX=event.pageX;
+			if(event["pageY"]) props.beventpageY=event.pageY;
+			if(event["layerX"]) props.beventlayerX=event.layerX;
+			if(event["layerY"]) props.beventlayerY=event.layerY;
+
+			if (event["target"]) this.buildTargetProperties(props, event.target);
+		}
+
+		props.methodArguments = dojo.json.serialize( args );
+
+		return props;
+	},
+
+
+
+	/**
+	 * Function: buildTargetProperties
+	 *
+	 * Generic function to build a properties object populated with
+	 * relevent target data.
+	 *
+	 * Parameters:
+	 *
+	 * 	props - The object that event properties are being set on to return to
+	 * 			the server.
+	 * 	target - The javscript Event.target object that the original event was targeted for.
+	 *
+	 * Returns:
+	 * 	The original props object passed in, populated with any data found.
+	 */
+	buildTargetProperties:function(props, target){
+		if(!target) { return; }
+
+		if (dojo.dom.isNode(target)) {
+			return this.buildNodeProperties(props, target);
+		} else {
+			dojo.raise("buildTargetProperties() Unknown target type:" + target);
+		}
+	},
+
+	/**
+	 * Function: buildNodeProperties
+	 *
+	 * Builds needed target node properties, like the node's id.
+	 *
+	 * Parameters:
+	 * 	props - The object that event properties are being set on to return to
+	 * 			the server.
+	 * 	node - The dom node specified as the Event.target in a javascript event.
+	 */
+	buildNodeProperties:function(props, node) {
+		if (node.getAttribute("id")) {
+			props["beventtarget.id"]=node.getAttribute("id");
+		}
+	},
+
+    /**
+    * Function: stopEvent
+    */
+    stopEvent:dojo.event.browser.stopEvent
+}
+
+tapestry.lang = {
+
+	/**
+	 * Searches the specified list for an object with a matching propertyName/value pair.
+	 * @param list 			The array of objects to search.
+	 * @param properyName	The object property key to match on. (ie object[propertyName])
+	 * 			Can also be a template object to match in the form of {key:{key:value}} nested
+	 * 			as deeply as you like.
+	 * @param value 		The value to be matched against
+	 * @return The matching array object found, or null.
+	 */
+	find:function(list, property, value){
+		if (!list || !property || list.length < 1) return null;
+
+		// if not propMatch then template object was passed in
+		var propMatch=dojo.lang.isString(property);
+		if (propMatch && !value) return null; //if doing string/other non template match and no value
+
+		for (var i=0; i < list.length; i++) {
+			if (!list[i]) continue;
+			if (propMatch) {
+				if (list[i] && list[i][property] && list[i][property] == value) return list[i];
+			} else {
+				if (this.matchProperty(property, list[i])) return list[i];
+			}
+		}
+		return null;
+	},
+
+	// called recursively to match object properties
+	// partially stolen logic from dojo.widget.html.SortableTable.sort
+	matchProperty:function(template, object){
+		if(!dojo.lang.isObject(template) || !dojo.lang.isObject(object))
+			return template.valueOf() == object.valueOf();
+
+		for(var p in template){
+			if(!(p in object)) return false;	//	boolean
+			if (!this.matchProperty(template[p], object[p])) return false;
+		}
+		return true;
+	}
+}
+
+dojo.provide("dojo.AdapterRegistry");
+dojo.provide("dojo.json");
+
+dojo.AdapterRegistry = function (returnWrappers) {
+	this.pairs = [];
+	this.returnWrappers = returnWrappers || false;
+};
+dojo.lang.extend(dojo.AdapterRegistry, {register:function (name, check, wrap, directReturn, override) {
+	var type = (override) ? "unshift" : "push";
+	this.pairs[type]([name, check, wrap, directReturn]);
+}, match:function () {
+	for (var i = 0; i < this.pairs.length; i++) {
+		var pair = this.pairs[i];
+		if (pair[1].apply(this, arguments)) {
+			if ((pair[3]) || (this.returnWrappers)) {
+				return pair[2];
+			} else {
+				return pair[2].apply(this, arguments);
+			}
+		}
+	}
+	throw new Error("No match found");
+}, unregister:function (name) {
+	for (var i = 0; i < this.pairs.length; i++) {
+		var pair = this.pairs[i];
+		if (pair[0] == name) {
+			this.pairs.splice(i, 1);
+			return true;
+		}
+	}
+	return false;
+}});
+
+
+dojo.json = {
+	jsonRegistry:new dojo.AdapterRegistry(),
+	register:function (name, check, wrap, override) {
+		dojo.json.jsonRegistry.register(name, check, wrap, override);
+	},
+
+	evalJson:function (json) {
+	try {
+		return eval("(" + json + ")");
+	}
+	catch (e) {
+		dojo.debug(e);
+		return json;
+	}
+	},
+
+	serialize:function (o) {
+	var objtype = typeof (o);
+	if (objtype == "undefined") {
+		return "undefined";
+	} else {
+		if ((objtype == "number") || (objtype == "boolean")) {
+			return o + "";
+		} else {
+			if (o === null) {
+				return "null";
+			}
+		}
+	}
+	if (objtype == "string") {
+		return dojo.string.escapeString(o);
+	}
+	var me = arguments.callee;
+	var newObj;
+	if (typeof (o.__json__) == "function") {
+		newObj = o.__json__();
+		if (o !== newObj) {
+			return me(newObj);
+		}
+	}
+
+	if (typeof (o.json) == "function") {
+		newObj = o.json();
+		if (o !== newObj) {
+			return me(newObj);
+		}
+	}
+
+	if (objtype != "function" && typeof (o.length) == "number") {
+		var res = [];
+		for (var i = 0; i < o.length; i++) {
+			if (dojo.event.browser.isEvent(o[i]) || o[i]["stopPropagation"]){continue;}
+			var val = me(o[i]);
+			if (typeof (val) != "string") {
+				val = "undefined";
+			}
+			res.push(val);
+		}
+		return "[" + res.join(",") + "]";
+	}
+	try {
+		window.o = o;
+		newObj = dojo.json.jsonRegistry.match(o);
+		return me(newObj);
+	}
+	catch (e) {
+	}
+	if (objtype == "function") {
+		return null;
+	}
+
+	res = [];
+	for (var k in o) {
+		var useKey;
+		if (typeof (k) == "number") {
+			useKey = "\"" + k + "\"";
+		} else {
+			if (typeof (k) == "string") {
+				useKey = dojo.string.escapeString(k);
+			} else {
+				continue;
+			}
+		}
+		val = me(o[k]);
+		if (typeof (val) != "string") {
+			continue;
+		}
+		res.push(useKey + ":" + val);
+	}
+	return "{" + res.join(",") + "}";
+}};

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/core.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/core.js
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/core.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/form.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/form.js?rev=618461&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/form.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/form.js Mon Feb  4 14:07:13 2008
@@ -0,0 +1,836 @@
+dojo.provide("tapestry.form");
+dojo.provide("tapestry.form.datetime");
+dojo.provide("tapestry.form.validation");
+
+dojo.require("dojo.event.browser");
+dojo.require("dojo.dom");
+dojo.require("dojo.html.selection");
+dojo.require("tapestry.core");
+dojo.require("dojo.date.format");
+dojo.require("dojo.validate.datetime");
+dojo.require("dojo.validate.check");
+dojo.require("dojo.html.style");
+
+/**
+ * package: tapestry.form
+ * Provides central handling of all client side form related logic.
+ */
+tapestry.form={
+	
+	// property: forms
+	// Contains a reference to all registered Tapestry forms in the current document.
+	forms:{}, // registered form references
+	// property: currentFocus 
+	// Reference to form element/element id of field that should currently recieve focus, if any
+	currentFocus:null,
+	
+	/**
+	 * Function: focusField
+	 * If possible, brings keyboard input focus to the specified field.
+	 * 
+	 * Parameters:
+	 * 	field - The field(field id) of the field to focus.
+	 * 
+	 * Note:
+	 * 	Function deprecated in favor of dojo equivalent, like 
+	 *  dojo.html.selectInputText(node).
+	 */
+	focusField:function(field){
+		if (arguments.length < 1) {return;}
+		try{
+		var f=dojo.widget.byId(field);
+		if(f && !dj_undef("focus", f)){
+			if (dojo.html.isVisible(f)){
+				f.focus();
+			}
+			return;
+		} else {
+			f = dojo.byId(field);
+		}
+		
+		if (!f) { return; }
+        if (field.disabled || field.clientWidth < 1) {
+			return;
+		}
+        
+        if(!dj_undef("focus", f) && dojo.html.isShowing(f)){
+            f.focus();
+			return;
+		}
+		
+        dojo.html.selectInputText(field);} catch(e){dojo.log.debug(e);}
+	},
+	
+	/**
+	 * Used by AlertDialog to focus the highest priority form field 
+	 * that failed validation. This happens because the field needs to 
+	 * be focused ~after~ the dialog is hidden.
+	 */
+	_focusCurrentField:function(){
+		if(!this.currentFocus){return;}
+		
+		this.focusField(this.currentFocus);
+	},
+	
+	/**
+	 * Function: registerForm
+	 * 
+	 * Registers the form with the local <forms> property so 
+	 * that there is a central reference of all tapestry forms.
+	 * 
+	 * Parameters:
+	 * 
+	 *	id		-	The form(form id) to register.
+	 *  async	-	Boolean, if true causes form submission to be asynchronous.
+	 *  json	-	Boolean, if true causes form submission to be asyncrhronous with an 
+	 * 				expected JSON response.
+	 */
+	registerForm:function(id, async, json){
+		var form=dojo.byId(id);
+		if (!form) {
+			dojo.raise("Form not found with id " + id);
+			return;
+		}
+		
+		// make sure id is correct just in case node passed in has only name
+		id=form.getAttribute("id");
+		
+		// if previously connected, cleanup and reconnect
+		if (this.forms[id]) {
+			dojo.event.disconnect(form, "onsubmit", this, "onFormSubmit");
+			for(var i = 0; i < form.elements.length; i++) {
+				var node = form.elements[i];
+				if(node && node.type && dojo.lang.inArray(["submit", "button"],node.type.toLowerCase())) {
+					dojo.event.disconnect(node, "onclick", tapestry.form, "inputClicked");
+				}
+			}
+			
+			var inputs = form.getElementsByTagName("input");
+			for(var i = 0; i < inputs.length; i++) {
+				var input = inputs[i];
+				if(input.type.toLowerCase() == "image" && input.form == form) {
+					dojo.event.disconnect(input, "onclick", tapestry.form, "inputClicked");
+				}
+			}
+			
+			dojo.event.disconnect(form, "onsubmit", this, "overrideSubmit");
+			delete this.forms[id];
+		}
+		
+		this.forms[id]={};
+		this.forms[id].validateForm=true;
+		this.forms[id].profiles=[];
+		this.forms[id].async=(typeof async != "undefined") ? async : false;
+		this.forms[id].json=(typeof json != "undefined") ? json : false;
+		
+		if (!this.forms[id].async) {
+			dojo.event.connect(form, "onsubmit", this, "onFormSubmit");
+		} else {
+			for(var i = 0; i < form.elements.length; i++) {
+				var node = form.elements[i];
+				if(node && node.type && dojo.lang.inArray(["submit", "button"],node.type.toLowerCase())) {
+					dojo.event.connect(node, "onclick", tapestry.form, "inputClicked");
+				}
+			}
+			
+			var inputs = form.getElementsByTagName("input");
+			for(var i = 0; i < inputs.length; i++) {
+				var input = inputs[i];
+				if(input.type.toLowerCase() == "image" && input.form == form) {
+					dojo.event.connect(input, "onclick", tapestry.form, "inputClicked");
+				}
+			}
+			
+			dojo.event.connect(form, "onsubmit", this, "overrideSubmit");
+		}
+	},
+	
+	overrideSubmit:function(e){
+        dojo.event.browser.stopEvent(e);
+        var elm = e.target;
+        if (!dj_undef("form", elm)){
+            dojo.log.debug("Submit event was generated from element: ", elm);
+            elm = elm.form;
+        }
+        tapestry.form.submitAsync(elm);
+	},
+	
+	/**
+	 * Function: registerProfile
+	 * 
+	 * Registers a form validation/translation profile. There
+	 * can potentially be more than one profile registered with
+	 * a form.
+	 * 
+	 * The profiles will be consulted at various points in the forms
+	 * life, which currently only involves running the profile checks
+	 * before form submission. (more points to be determined in the future)
+	 * 
+	 * See Also:
+	 * 	<dojo.validate.check>
+	 * 
+	 * Parameters:
+	 * 
+	 *	id		-	The form(form id) to register profile with.
+	 *	profile	-	The object containing all of the validation/value constraints for the form. 
+	 */
+	registerProfile:function(id, profile){
+		if (!this.forms[id]) {
+			dojo.raise("registerProfile(" + id + ") No form previously registered with that id.");
+			return;
+		}
+		
+		this.forms[id].profiles.push(profile);
+	},
+
+	/**
+	 * Function: clearProfiles
+	 * 
+	 * Clears any previously registered validation profiles 
+	 * on the specified form. Normally called during XHR requests
+	 * by returned JS response to ensure new validation logic coming
+	 * in from potentially new form fields is accounted for.
+	 * 
+	 * Parameters:
+	 * 
+	 *	id - The form id to clear profiles for.
+	 */
+	clearProfiles:function(id){
+		if (!this.forms[id]) return;
+		
+		for (var i=0; i < this.forms[id].profiles.length; i++) {
+			delete this.forms[id].profiles[i];
+		}
+		this.forms[id].profiles=[];
+	},
+	
+	inputClicked:function(e){
+		var node = e.currentTarget;
+		if(node.disabled || dj_undef("form", node)) { return; }
+		this.forms[node.form.getAttribute("id")].clickedButton = node;
+	},
+	
+	/**
+	 * Function: setFormValidating
+	 * 
+	 * If a form registered with the specified formId
+	 * exists a local property will be set that causes
+	 * validation to be turned on/off depending on the argument.
+	 * 
+	 * Parameters:
+	 * 
+	 * formId - The id of the form to turn validation on/off for.
+	 * validate - Boolean for whether or not to validate form, if not specified assumes true.
+	 */
+	setFormValidating:function(formId, validate){
+		if (this.forms[formId]){
+			this.forms[formId].validateForm = validate;
+        }
+	},
+	
+	/**
+	 * Event connected function that is invoked when a form
+	 * is submitted.
+	 */
+	onFormSubmit:function(evt){
+		if(!evt || dj_undef("target", evt)) {
+			dojo.raise("No valid form event found with argument: " + evt);
+			return;
+		}
+
+        var id=evt.target.getAttribute("id");
+		if (!id) {
+			dojo.raise("Form had no id attribute.");
+			return;
+		}
+		var form = dojo.byId(id);
+		
+		if (!dj_undef("value", form.submitmode)
+			&& (form.submitmode.value == "cancel" || form.submitmode.value == "refresh")) {
+			return;
+		}
+		
+		if (!tapestry.form.validation.validateForm(form, this.forms[id])) {
+			dojo.event.browser.stopEvent(evt);
+		}
+	},
+	
+	/**
+	 * Function: submit
+	 * 
+	 * Submits the form specified, optionally setting the submitname
+	 * hidden input field to the value of submitName to let the Form 
+	 * component on server know which button caused the submission. (For
+	 * the case of submit button listeners).
+	 * 
+	 * Parameters:
+	 * 
+	 * form			-	The form(form id) to submit.
+	 * submitName	- 	Optional submit name string to use when submitting. This is used
+	 * 					to associate a form submission with a particular component, like a
+	 * 					Submit/LinkSubmit/etc..
+	 * parms		-	Optional extra set of arguments that can control the form submission semantics
+	 * 					such as url/async/json/etc. 
+	 */
+	submit:function(form, submitName, parms){
+		form=dojo.byId(form);
+		if (!form) {
+			dojo.raise("Form not found with id " + form);
+			return;
+		}
+		var id=form.getAttribute("id");
+        if (submitName){
+            form.submitname.value = submitName;
+        }
+
+        if (!dj_undef("value", form.submitmode)
+                && (form.submitmode.value == "cancel" || form.submitmode.value == "refresh")
+                && !parms) {
+            form.submit();
+            return;
+        }
+
+        if (!tapestry.form.validation.validateForm(form, this.forms[id])) {
+			return;
+        }
+
+		if (parms && !dj_undef("async", parms) && parms.async) {
+			tapestry.form.submitAsync(form, null, submitName, parms);
+			return;
+		} else if(!dj_undef(id, this.forms) && this.forms[id].async){
+			tapestry.form.submitAsync(form);
+			return;
+		}
+
+            form.submit();
+    },
+	
+	/**
+	 * Function: cancel
+	 * 
+	 * Submits the form to the server in "cancel" mode, invoking any cancel listeners
+	 * registered to the server side equivalent to the form passed in.
+	 * 
+	 * Parameters:
+	 * 	
+	 * 	form 		-	The form(form id) to cancel.
+	 * 	submitName	- 	Optional submit name string to use when submitting. This is used
+	 * 					to associate a form submission with a particular component, like a
+	 * 					Submit/LinkSubmit/etc..
+	 *  parms       -   Optional object parms passed through to tapestry.form.submit().
+	 */
+	cancel:function(form, submitName, parms){
+		form=dojo.byId(form);
+		if (!form){
+			dojo.raise("Form not found with id " + form);
+			return;
+		}
+
+        var formName=form.getAttribute("id");
+        var validateState=tapestry.form.forms[formName].validateForm;
+        tapestry.form.setFormValidating(formName, false);
+
+        var previous = form.submitmode.value;
+        form.submitmode.value="cancel";
+
+        if (parms && !dj_undef("async", parms) && parms.async){
+            this.submitAsync(form, null, submitName, parms);
+        } else {
+            this.submit(form, submitName, parms);
+        }
+
+        form.submitmode.value = previous;
+        tapestry.form.setFormValidating(formName, validateState);
+	},
+	
+	/**
+	 * Function: refresh
+	 * 
+	 * Submits the form to the server in "refresh" mode, invoking any refresh listeners
+	 * registered to the server side equivalent to the form passed in.
+	 * 
+	 * Parameters:
+	 * 	
+	 * 	form 		-	The form(form id) to refresh.
+	 * 	submitName	- 	Optional submit name string to use when submitting. This is used
+	 * 					to associate a form submission with a particular component, like a
+	 * 					Submit/LinkSubmit/etc..
+	 *  parms       -   Optional object parms passed through to tapestry.form.submit().
+	 */
+	refresh:function(form, submitName, parms){
+		form=dojo.byId(form);
+		if (!form){
+			dojo.raise("Form not found with id " + form);
+			return;
+		}
+
+        var formName=form.getAttribute("id");
+        var validateState=tapestry.form.forms[formName].validateForm;
+        tapestry.form.setFormValidating(formName, false);
+
+        var previous = form.submitmode.value;
+        form.submitmode.value="refresh";
+
+        if (parms && !dj_undef("async", parms) && parms.async){
+            this.submitAsync(form, null, submitName, parms);
+        } else {
+            this.submit(form, submitName, parms);
+        }
+
+        form.submitmode.value = previous;
+        tapestry.form.setFormValidating(formName, validateState);
+    },
+	
+	/**
+	 * Function: submitAsync
+	 * 
+	 * Does almost the same thing as <tapestry.form.submit>, 
+	 * but submits the request via XHR to the server asynchronously.
+	 * 
+	 * Parameters:
+	 * 
+	 *	form		-	The form(form id) to submit.
+	 *	content		-	Optional content map, mainly used to pass in browser
+	 * 					event parameters to form submission, but can be any
+	 * 					typical form/value pair.
+	 *	submitName	-	Optional submit name string to use when submitting.
+	 *	parms		-	Optional set of extra parms that can override the defautls for 
+	 * 					this specific form submission, like the url/async/json behaviour of 
+	 * 					the submission.
+	 */
+	submitAsync:function(form, content, submitName, parms){
+		form=dojo.byId(form);
+		if (!form) {
+			dojo.raise("Form not found with id " + id);
+			return;
+		}
+		var formId=form.getAttribute("id");
+
+        if (!tapestry.form.validation.validateForm(form, this.forms[formId])) {
+			dojo.log.debug("Form validation failed for form with id " + formId);
+			return;
+		}
+
+        if (submitName){
+            var previous = form.submitname.value;
+            form.submitname.value=submitName;
+			if(!content){ content={}; }
+			if(form[submitName]){
+				content[submitName]=form[submitName].value;
+			}
+		}
+		
+		// handle submissions from input buttons
+		if (!dj_undef("clickedButton", this.forms[formId])) {
+			if (!content) { content={}; }
+			content[this.forms[formId].clickedButton.getAttribute("name")]=this.forms[formId].clickedButton.getAttribute("value");
+            delete this.forms[formId].clickedButton;
+        }
+
+		var kwArgs={
+			formNode:form,
+			content:content,
+            useCache:true,
+            preventCache:true,
+            error: (function(){tapestry.error.apply(this, arguments);}),
+            encoding: tapestry.requestEncoding
+		};
+		
+		// check for override
+		if (parms){
+			if (!dj_undef("url", parms)) { kwArgs.url=parms.url; }
+		}
+
+		if (this.forms[formId].json || parms && parms.json) {
+			kwArgs.headers={"json":true};
+			kwArgs.mimetype="text/json";
+            kwArgs.load=(function(){tapestry.loadJson.apply(this, arguments);});
+        } else {
+			kwArgs.headers={"dojo-ajax-request":true};
+			kwArgs.mimetype="text/xml";
+			kwArgs.load=(function(){tapestry.load.apply(this, arguments);});
+		}
+		tapestry.requestsInFlight++;
+        dojo.io.queueBind(kwArgs);
+
+        if (submitName){
+            form.submitname.value = previous;
+        }
+    }
+}
+
+tapestry.form.validation={
+
+	missingClass:"fieldMissing", // default css class that will be applied to fields missing a value
+	invalidClass:"fieldInvalid", // default css class applied to fields with invalid data
+
+	dialogName:"tapestry:AlertDialog",
+
+	/**
+	 * Main entry point for running form validation. The
+	 * props object passed in contains a number of fields that
+	 * are managed by tapestry.form:
+	 *
+	 * 		props = {
+	 * 			validateForm:[true|false] // whether to run validation at all
+	 * 			profiles:[profile1, profile2] // set of dojo.validate.check() style profiles
+	 * 										  // that may have been registered with form
+	 * 		}
+	 *
+	 * The individual profiles will contain any of the data described by the dojo documentation
+	 * for dojo.validate.check(). In addition to that, each profile will also have a corresponding
+	 * string message to display if the specified condition has been met. For example, if you have
+	 * specified that a select field named "select1" was required your profile would look something
+	 * like:
+	 *
+	 * 		profile = {
+	 * 			"required":["select1"], // normal dojo.validate.check data
+	 * 			"select1":{ // tapestry field/error type specific data
+	 * 				"required":"You must select a value for select1."
+	 * 			}
+	 * 		}
+	 *
+	 * It is intended for you to call dojo.validate.check(form, profile) for each profile
+	 * stored in the "profiles" field, as well as deciding how to display errors / warnings.
+	 *
+	 * @return Boolean indicating if form submission should continue. If false the form
+	 * 			will ~not~ be submitted.
+	 */
+	validateForm:function(form, props){
+		if (typeof form == "undefined") {return false;}
+		if (typeof props == "undefined") {return true;} // form exists but no profile? just submit I guess..
+        if (!props.validateForm) {return true;}
+
+		try {
+			this.clearValidationDecorations(form, props);
+
+			for (var i=0; i < props.profiles.length; i++) {
+				var results=dojo.validate.check(form, props.profiles[i]);
+                if (!this.processResults(form, results, props.profiles[i])) {
+					this.summarizeErrors(form, results, props.profiles[i]);
+					return false;
+				}
+			}
+		} catch (e) {
+			// since so many dynamic function calls may happen in here it's best that we
+			// catch all of them and log them or else peoples forms might still get submitted
+			// and they'd never be able to figure out what was wrong
+			dojo.log.exception("Error validating", e, true);
+			return false;
+		}
+
+		return true;
+	},
+
+	/**
+	 * Called for each registered profile on a form after
+	 * dojo.validate.check() has been called. This function is
+	 * expected to do UI related notifications of fields in error.
+	 *
+	 * @param form The form that was validated.
+	 * @param results The result of calling dojo.validate.check(form,profile)
+	 * @param profile The original profile used to validate form, also holds
+	 * 				  validation error messages to be used for each field.
+	 *
+	 * @return Boolean, if false form should not be submitted and all validation
+	 * 		   should be stopped. If true validation will continue and eventually
+	 * 		   form will be submitted.
+	 */
+	processResults:function(form, results, profile){
+		if (results.isSuccessful()) { return true; }
+
+        var formValid=true;
+		if (results.hasMissing()) {
+			var missing=results.getMissing();
+            for (var i=0; i < missing.length; i++) {
+				this.handleMissingField(missing[i], profile);
+			}
+
+			formValid=false;
+		}
+
+		if (results.hasInvalid()) {
+			var invalid=results.getInvalid();
+            for (var i=0; i < invalid.length; i++) {
+				this.handleInvalidField(invalid[i], profile);
+			}
+
+			formValid=false;
+		}
+
+		return formValid; // if got past successful everything is invalid
+	},
+
+	/**
+	 * Default field decorator for missing fields.
+	 *
+	 * @param field The field element that was missing data.
+	 * @param profile The form validation profile.
+	 */
+	handleMissingField:function(field, profile){
+		field=dojo.byId(field);
+		if (dj_undef("type", field)) {return;}
+		dojo.html.removeClass(field, this.invalidClass);
+
+		if (!dojo.html.hasClass(field, this.missingClass)){
+			dojo.html.prependClass(field, this.missingClass);
+		}
+	},
+
+	/**
+	 * Default field decorator for invalid fields.
+	 *
+	 * @param field The field element that had invalid data.
+	 * @param profile The form validation profile.
+	 */
+	handleInvalidField:function(field, profile){
+		field=dojo.byId(field);
+		if (dj_undef("type", field)) {return;}
+		dojo.html.removeClass(field, this.missingClass);
+
+		if (!dojo.html.hasClass(field, this.invalidClass)){
+			dojo.html.prependClass(field, this.invalidClass);
+		}
+	},
+
+	/**
+	 * Clears out previous css classes set on fields
+	 * in error.
+	 */
+	clearValidationDecorations:function(form, props){
+
+        for (var i=0; i < props.profiles.length; i++) {
+
+            for (var fieldName in props.profiles[i]) {
+                if (dj_undef("type", form.elements[fieldName]) || typeof form.elements[fieldName].type == "undefined"
+                        || form.elements[fieldName].type == "submit"
+                        || form.elements[fieldName].type == "hidden") { continue; }
+
+                dojo.html.removeClass(form.elements[fieldName], this.missingClass);
+                dojo.html.removeClass(form.elements[fieldName], this.invalidClass);
+            }
+        }
+	},
+
+	/**
+	 * Optionally allows an alert dialog/dhtml dialog/etc to
+	 * be displayed to user to alert them to the invalid state
+	 * of their form if validation errors have occurred.
+	 *
+	 * @param form The form being validated.
+	 * @param results Returned value of dojo.validate.check(form, profile)
+	 * @param profile Validation profile definition
+	 */
+	summarizeErrors:function(form, results, profile){
+		var merrs=[];
+		var ierrs=[];
+		tapestry.form.currentFocus=null;
+
+		if (results.hasMissing()){
+			var fields=results.getMissing();
+			for (var i=0; i<fields.length; i++){
+				if(i==0 && !tapestry.form.currentFocus){
+					tapestry.form.currentFocus=fields[i];
+				}
+				if (profile[fields[i]] && profile[fields[i]]["required"]){
+					if (dojo.lang.isArray(profile[fields[i]]["required"])) {
+						for (var z=0; z < profile[fields[i]]["required"].length; z++)
+							merrs.push(profile[fields[i]]["required"][z]);
+					} else
+						merrs.push(profile[fields[i]]["required"]);
+				}
+			}
+		}
+		if (results.hasInvalid()){
+			var fields=results.getInvalid();
+			for (var i=0; i<fields.length; i++){
+				if(i==0 && !tapestry.form.currentFocus){
+					tapestry.form.currentFocus=fields[i];
+				}
+				if (profile[fields[i]] && profile[fields[i]]["constraints"]){
+					if (dojo.lang.isArray(profile[fields[i]]["constraints"])) {
+						for (var z=0; z < profile[fields[i]]["constraints"].length; z++)
+							ierrs.push(profile[fields[i]]["constraints"][z]);
+					} else
+						ierrs.push(profile[fields[i]]["constraints"]);
+				}
+			}
+		}
+
+		var msg="";
+		if (merrs.length > 0) {
+			msg+='<ul class="missingList">';
+			for (var i=0; i<merrs.length;i++) {
+				msg+="<li>"+merrs[i]+"</li>";
+			}
+			msg+="</ul>";
+		}
+		if (ierrs.length > 0) {
+			msg+='<ul class="invalidList">';
+			for (var i=0; i<ierrs.length;i++) {
+				msg+="<li>"+ierrs[i]+"</li>";
+			}
+			msg+="</ul>";
+		}
+
+        dojo.require("dojo.widget.*");
+        dojo.require("tapestry.widget.AlertDialog");
+
+        var ad=dojo.widget.byId("validationDialog");
+		if (ad) {
+			ad.setMessage(msg);
+			ad.show();
+			return;
+		}
+
+		var node=document.createElement("span");
+		document.body.appendChild(node);
+		var dialog=dojo.widget.createWidget(this.dialogName,
+						{
+							widgetId:"validationDialog",
+							message:msg
+						}, node);
+		dialog.show();
+	},
+
+	/**
+	 * Validates that the input value matches the given
+	 * regexp pattern.
+	 *
+	 * @param value The string value to be evaluated.
+	 * @param pattern The regexp pattern used to match against value.
+	 */
+	isValidPattern:function(value, pattern){
+		if (typeof value != "string" || typeof pattern != "string") { return false; }
+
+		var re = new RegExp(pattern);
+		return re.test(value);
+	},
+
+	isPalleteSelected:function(elem){
+		return elem.length > 0;
+	},
+
+   /**
+    * Validates that the input value is equal with the value of the given input control.
+    */
+    isEqual:function(value, other){
+        var otherValue = dojo.byId(other).value;
+        return value == otherValue;
+    },
+
+   /**
+    * Validates that the input value is not equal with the value of the given input control.
+    */
+    isNotEqual:function(value, other){
+        return !tapestry.form.validation.isEqual(value, other);
+    },
+
+   /**
+    *  Checks that the value given is greater than or equal to the value of
+    *  minString. Uses dojo.i18n.number.parse() to parse out the values using
+    *  the locale settings configured for the current page.
+    */
+    greaterThanOrEqual:function(value, minString, flags){
+        dojo.require("dojo.i18n.number");
+        flags.validate=false;
+        var min = dojo.i18n.number.parse(minString, null, flags);
+        var num = dojo.i18n.number.parse(value, null, flags);
+        if (Number.NaN == num) { return false; }
+
+        return num >= min;
+    },
+
+   /**
+    *  Checks that the value given is less than or equal to the value of
+    *  maxString. Uses dojo.i18n.number.parse() to parse out the values using
+    *  the locale settings configured for the current page.
+    */
+    lessThanOrEqual:function(value, maxString, flags){
+        dojo.require("dojo.i18n.number");
+        flags.validate=false;
+        var max = dojo.i18n.number.parse(maxString, null, flags);
+        var num = dojo.i18n.number.parse(value, null, flags);
+        if (Number.NaN == num) { return false; }
+
+        return num <= max;
+    },
+    
+    isText:dojo.validate.isText,
+    
+    isEmailAddress:function(){
+        dojo.require("dojo.validate.web");
+        return dojo.validate.isEmailAddress.apply(dojo.validate, arguments);
+    },
+    
+    isReal:function(){
+        dojo.require("dojo.i18n.number");
+        return dojo.i18n.number.isReal.apply(dojo.i18n.number, arguments);        
+    }    
+    
+}
+
+tapestry.form.datetime={
+
+	/**
+	 * Checks if the specified value is a valid date, according to
+	 * the flags passed in.
+	 *
+	 * @param value The string value of the date being validated.
+	 * @param flags An object.
+	 * 		flags.format 	A string format pattern that will be used to validate
+	 * 						the incoming value via @link dojo.validate.isValidDate(value, format).
+	 * 		flags.max		A string date value representing the maximum date that can be selected.
+	 * 		flags.min		A string date value representing the minimum date that can be selected.
+	 * @return Boolean. True if valid, false otherwise.
+	 */
+	isValidDate:function(value, flags){
+		if(!value){return false;}
+
+		if (!flags){
+			dojo.raise("isValidDate: value and flags must be specified");
+			return;
+		}
+
+		// parse date value
+		var dateValue=null;
+		try {
+			dateValue = dojo.date.parse(value, flags);
+		} catch (e) {
+			dojo.log.exception("Error parsing input date.", e, true);
+			return false;
+		}
+
+		if(dateValue == null) { return false; }
+
+		// convert to format that is validatable
+		value=dojo.date.format(dateValue, flags);
+
+		// TODO: This is totally useless right now, doesn't even accept formats with string equivs
+		// See a better method http://www.mattkruse.com/javascript/date/source.html
+		// basic format validation
+		// if (!dojo.validate.isValidDate(value, flags.format))
+		//	return false;
+
+		// max date
+		if (!dj_undef("max", flags)){
+			if (typeof flags.max == "string"){
+				flags.max=dojo.date.parse(flags.max, flags);
+			}
+			if (dojo.date.compare(dateValue, flags.max, dojo.date.compareTypes.DATE) > 0)
+				return false;
+		}
+
+		// min date
+		if (!dj_undef("min", flags)){
+			if (typeof flags.min == "string"){
+				flags.min=dojo.date.parse(flags.min, flags);
+			}
+			if (dojo.date.compare(dateValue, flags.min, dojo.date.compareTypes.DATE) < 0)
+				return false;
+		}
+
+		return true;
+	}
+
+}

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/form.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/form.js
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/form.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/fx.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/fx.js?rev=618461&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/fx.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/fx.js Mon Feb  4 14:07:13 2008
@@ -0,0 +1,166 @@
+dojo.provide("tapestry.fx");
+dojo.require("tapestry.core");
+
+/**
+ * package: tapestry.fx
+ * Provides handling of effects applied before, during or after an XHR request/response.
+ */
+tapestry.fx={
+    
+    // property: preEffects
+    // Contains a reference to all registered pre-effects, i.e. effects that are
+    // executed before an XHR request.
+    preEffects:{},
+    // property: postEffects
+    // Contains a reference to all registered post-effects, i.e. effects that are
+    // executed when new content arrives through an XHR response.
+    postEffects:{},
+    // property: ajaxStatusAction
+    ajaxStatusAction:'loading',
+    
+    /**
+     * Function: attachPreEffect
+     * Schedules the execution of an effect when the specified link
+     * is clicked (and thus an XHR request begins).
+     * 
+     * See Also:
+     * 	<tapestry.fx.attachPostEffect>  
+     *  <dojo.lfx.IAnimation> 
+     *
+     * Parameters:
+     * 	triggerId - The clientId of the DirectLink that triggers the effect.
+     *  animationFunc - A function that returns the animation to execute. 
+     *  async - Boolean for whether to execute the effect in parallel to the
+     *          XHR request. Defaults to false, i.e. the XHR is blocked until
+     *          the effect ends.
+     * 
+     * Note:
+     * 	Here's an example usage:
+     *      tapestry.fx.attachPreEffect("DirectLink",
+     *          function(){return dojo.lfx.wipeOut("entry", 800, dojo.lfx.easeDefault) });
+     */   
+    attachPreEffect:function(triggerId, animationFunc, async){
+        if (dojo.lang.isEmpty(this.preEffects))
+            this._initPreEffects();
+        this.preEffects[triggerId] = {async:async, animation:animationFunc};        
+    },
+    
+    /**
+     * Function: attachPostEffect
+     * Schedules the execution of an effect when the specified content
+     * is returned through an XHR response.
+     * 
+     * See Also:
+     * 	<tapestry.fx.attachPreEffect>  
+     *  <dojo.lfx.IAnimation> 
+     *
+     * Parameters:
+     * 	updateId - The id of a dom node that (when updated) triggers the effect.
+     *  animationFunc - A function that returns the animation to execute. 
+     * 
+     * Note:
+     * 	Here's an example usage:
+     *      tapestry.fx.attachPostEffect("entry",
+     *          function(){return dojo.lfx.wipeIn("entry", 1500, dojo.lfx.easeDefault) });
+     */       
+    attachPostEffect:function(updateId, animationFunc){
+        if (dojo.lang.isEmpty(this.postEffects))
+            this._initPostEffects();        
+        this.postEffects[updateId] = {animation:animationFunc};
+    },
+    
+    /**
+     * Function: removeAll
+     * Removes all registered effects (preEffects and postEffects).
+     */       
+    removeAll:function(){
+        this.preEffects={};
+        this.postEffects={};
+    },
+
+    /**
+     * Function: attachAjaxStatus
+     * Allows specifying a dom node that will be shown or hidden while ajax requests
+     * are in progress or have finished.
+     * Alternatively, one can specify a custom
+     * function which will get invoked when an ajax request starts or ends - the first
+     * argument to that function will be a boolean corresponding to wheather the status
+     * element should be showing or not.
+     *
+     * Parameters:
+     *  a1 - The dom id to show - hide, or the function to invoke when ajax starts or ends.
+     */
+    attachAjaxStatus:function(a1){
+        dojo.log.debug("Attaching ajax status listener");
+        if (dojo.lang.isString(a1)) {
+            tapestry.fx.ajaxStatusAction =
+                function(bShow){if (bShow) dojo.html.show(a1); else dojo.html.hide(a1);};
+        }
+        else if (dojo.lang.isFunction(a1)) {
+            tapestry.fx.ajaxStatusAction = a1;
+        }
+        else {
+            dojo.log.warn("Argument to tapestry.fx.attachAjaxStatus should be either a string or a function");
+            return;
+        }
+        dojo.event.connectOnce(dojo.io, "queueBind", tapestry.fx._processAjaxStatus);
+        dojo.event.connectOnce(tapestry, "error", tapestry.fx._processAjaxStatus);
+        dojo.event.connectOnce(tapestry, "load", tapestry.fx._processAjaxStatus);
+        dojo.event.connectOnce(tapestry, "loadJson", tapestry.fx._processAjaxStatus);        
+    },
+
+    _processAjaxStatus:function(){
+        tapestry.fx.ajaxStatusAction.apply(this, [tapestry.isServingRequests()]);
+    },
+    
+    _initPreEffects:function(){
+        dojo.log.debug("Advising tapestry.linkOnClick");
+        dojo.event.connectAround(tapestry, "linkOnClick", tapestry.fx, "_applyPreEffects");
+    },
+    
+    _initPostEffects:function(){
+        dojo.log.debug("Advising tapestry.loadContent");
+        dojo.event.connectAround(tapestry, "loadContent", tapestry.fx, "_applyPostEffects");
+    },
+    
+    _applyPreEffects:function(miObj){
+        var id = miObj.args[1];        
+        var effect = this.preEffects[id];
+        if (effect){
+            dojo.log.debug("Found pre-effect:", effect, id);
+                       
+            var anim = effect.animation();
+            
+            if (effect.async){          
+                anim.play();
+                return miObj.proceed();                
+            }
+            else{
+                anim.connect("onEnd", function(){ miObj.proceed(); });
+                anim.play();
+                return false;
+            }
+        }
+        else{
+            return miObj.proceed();
+        }        
+    },
+    
+    _applyPostEffects:function(miObj){
+        var id = miObj.args[0];
+        var effect = this.postEffects[id];
+        if (effect){
+            dojo.log.debug("Found post-effect:", effect, id);
+            
+            var ret = miObj.proceed();
+            
+            var anim = effect.animation();
+            anim.play();
+            
+            return ret;
+        }
+        else{            
+            return miObj.proceed();
+        }        
+    }
+}

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/fx.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/fx.js
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/fx.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/namespace.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/namespace.js?rev=618461&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/namespace.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/namespace.js Mon Feb  4 14:07:13 2008
@@ -0,0 +1,28 @@
+dojo.provide("tapestry.namespace");
+
+dojo.require("dojo.ns");
+
+(function(){
+	
+	var map = {
+		html: {
+			"alertdialog": "tapestry.widget.AlertDialog",
+			"timepicker": "tapestry.widget.TimePicker"
+		}
+	};
+	
+	function resolveNamespace(name, domain){
+		if(!domain){ domain="html"; }
+		if(!map[domain]){ return null; }
+		return map[domain][name];
+	}
+	
+	var tpath;
+	if (dojo.hostenv.moduleHasPrefix("tapestry")){
+		tpath=dojo.hostenv.getModulePrefix("tapestry");
+	} else {
+		tpath="../tapestry";
+	}
+	dojo.registerNamespaceManifest("tapestry", tpath, "tapestry", "tapestry.widget");
+	dojo.registerNamespaceResolver("tapestry", resolveNamespace);
+})();

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/namespace.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/namespace.js
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/namespace.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/skeleton/core.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/skeleton/core.js?rev=618461&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/skeleton/core.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/skeleton/core.js Mon Feb  4 14:07:13 2008
@@ -0,0 +1,165 @@
+/**
+ * This is a skeleton file. It contains the
+ * javascript objects and methods that tapestry requires.
+ *
+ * It should be used as a reference for building implementations
+ * specific to existing javascript frameworks.  
+ */
+
+// the two required objects, dojo and tapestry
+var dojo={
+    // those methods should only be needed for the dojo implementations
+    // others will probably leave those empty
+    registerModulePath: function() {tapestry.log('dojo.registerModulePath', arguments);},
+    require: function() {tapestry.log('dojo.require', arguments);}
+};
+
+var tapestry={
+    // setup firebug logging - useful for finding unimplemented methods
+    log: function() {                   
+        if (window.console) console.log.apply(this, arguments);
+    },
+    /**
+     * Executes the passed function when the document has done loading
+     */
+    addOnLoad: function(fn) {
+        tapestry.log('t.addOnLoad');
+    },
+    /**
+     * Returns the dom node with the given id
+     */
+    byId: document.getElementById,
+
+    /**
+     * Makes sure that the given namespace (passed as a string) exists
+     * and is a valid javascript object.  
+     */
+    provide: function() {tapestry.log('t.provide', arguments);},
+
+    /**
+     * Connects the event of the given target node to the given function of
+     * the global namespace "tapestry".
+     * Users of this method usually attach custom methods to the tapestry namespace
+     * before calling this.
+     *
+     * Parameters: target, event, funcName
+     */
+    connect: function() {tapestry.log('t.connect', arguments);},
+
+    /**
+     * Disconnects the event of the given target node from the given function of
+     * the global namespace "tapestry"
+     *
+     * Parameters: target, event, funcName
+     */
+    cleanConnect: function() {tapestry.log('t.cleanConnect', arguments);},
+
+	/**
+	 * Perform an XHR.
+	 * Implementation should set the mime-type to either "text/xml" or
+	 * "text/json" and include the request headers described in the comments to the
+	 * json parameter.
+     * Implementations are also responsible for handling the responses.  
+	 *
+	 * Parameters:
+	 * 	url     - The url to bind the request to.
+	 * 	content - A properties map of optional extra content to send.
+	 *  json    - (Optional) Boolean parameter specifying whether or not to create a
+	 * 		    json request. If true, the request headers should include "json":true.
+	 *          If false or unspecified, they should contain "dojo-ajax-request":true
+	 */
+    bind: function(url, content, json){tapestry.log('t.bind', arguments);},
+
+    /**
+     * Helper that builds the content from eventName and (triggered) id and then forwards
+     * execution to tapestry.bind
+     * 
+     * @param url
+     * @param id
+     * @param json
+     * @param eventName
+     */
+    linkOnClick: function(url, id, json, eventName) {tapestry.log('t.linkOnClick', arguments);}
+};
+
+tapestry.form = {
+    /**
+     * Submits the specified form.
+     * Should check the value of form.submitmode to find out what type of
+     * submission (cancel, refresh or normal) to do and whether to run client validation.
+     *
+     * Parameters:
+	 * form			-	The form or form id to submit.
+	 * submitName	- 	(Optional) Submit name to use when submitting. This is used
+	 * 					to associate a form submission with a particular component.
+	 *                  Implementations will typically just set form.submitname to this value.
+	 * parms		-	(Optional) Extra set of parameters. Implementations can just look for
+     *                  the async key and if that's set to true, they should perform an async
+     *                  submission.
+     */
+    submit: function(formId, submitName, parms) {tapestry.log('t.f.submit', arguments);},
+
+    /** Same as submit, but forces cancel submission */
+    cancel: function(formId, submitName, parms) {tapestry.log('t.f.submit', arguments);},
+
+    /** Same as submit, but forces refresh submission */
+    refresh: function(formId, submitName, parms) {tapestry.log('t.f.submit', arguments);},
+
+    /**
+	 * Registers a form and allows definition of its properties.
+	 * Implementation should keep track of such properties and
+	 * use them later on, when the form is submitted.
+	 *
+	 * Parameters:
+	 *	id		-	The form or form id to register.
+	 *  async	-	Boolean, if true form submission should be asynchronous.
+	 *  json	-	Boolean, if true form submission should be asyncrhronous json.
+	 */
+    registerForm: function(formId, async, json) {tapestry.log('t.f.registerForm', arguments);},
+
+    /**
+     * Registers a form validation/translation profile.
+     * TODO: Describe profile structure.
+     *
+	 * Parameters:
+	 *	formId		-	The form or form id to register profile with.
+	 *	profile	    -	The object containing all of the validation/value constraints for the form.
+     */    
+    registerProfile: function(formId, profile) {tapestry.log('t.f.registerProfile', arguments);},
+
+	/**
+	 * Clears any previously registered validation profiles on the specified form.
+	 *
+	 * Parameters:
+	 *	formId      -   The form id to clear profiles for.
+	 */
+    clearProfiles: function(formId) {tapestry.log('t.f.clearProfiles', arguments);},
+
+    /**
+     * Brings keyboard input focus to the specified field.
+     */
+    focusField: function(fieldId) {tapestry.log('t.f.focusField', arguments);},
+
+    // TODO: Describe validation methods
+    datetime: {
+        isValidDate: function(date) {tapestry.log('t.f.d.isValidDate', arguments);return true;}        
+    },
+    
+    validation: {
+        isReal: function() {tapestry.log('t.f.v.isReal', arguments);return true;},
+        greaterThanOrEqual: function() {tapestry.log('t.f.v.greaterThanOrEqual', arguments);return true;},
+        lessThanOrEqual: function() {tapestry.log('t.f.v.lessThanOrEqual', arguments);return true;},
+        isText: function() {tapestry.log('t.f.v.isText', arguments);return true;},
+        isEmailAddress: function() {tapestry.log('t.f.v.isEmailAddress', arguments);return true;},
+        isValidPattern: function() {tapestry.log('t.f.v.isValidPattern', arguments);return true;},
+        validateForm: function() {tapestry.log('t.f.v.validateForm', arguments);return true;}
+    }
+};
+
+tapestry.event = {
+    stopEvent: function() {tapestry.log('t.e.stopEvent', arguments);}
+};
+
+tapestry.widget = {
+    synchronizeWidgetState: function() {tapestry.log('t.w.synchronizeWidgetState', arguments);}
+};

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/skeleton/core.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/skeleton/core.js
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/skeleton/core.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/test.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/test.js?rev=618461&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/test.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/test.js Mon Feb  4 14:07:13 2008
@@ -0,0 +1,33 @@
+dojo.provide("tapestry.test");
+
+dojo.require("dojo.logging.Logger");
+dojo.require("dojo.event.browser");
+
+djConfig.locale="en_US";
+
+// override to make sure our fake events pass
+dojo.event.browser.isEvent=function() { return true; }
+
+function lastMsgContains(str){
+	if (arguments.length < 1) return false;
+	
+	var last=dojo.logging.logQueueHandler.data.pop();
+	if (!last || !last.message) return false;
+	
+	return last.message.toUpperCase().indexOf(str.toUpperCase()) > -1;
+}
+
+// helper object for logging method calls
+function mock(){
+	this.mockArgs=arguments;
+	this.called=false;
+	
+	this.intercept=function(){
+		this.called=true;
+		jum.assertEquals("mockArgLength", this.mockArgs.length, arguments.length);
+
+		for (var i=0; i < this.mockArgs.length; i++) {
+			jum.assertEquals("mockArgument", this.mockArgs[i], arguments[i]);
+		}
+	}
+}

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/test.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/test.js
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry-4.1.5/test.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain