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 2006/10/08 05:11:05 UTC

svn commit: r454068 - in /tapestry/tapestry4/trunk: ./ tapestry-examples/TimeTracker/src/context/ tapestry-examples/TimeTracker/src/context/WEB-INF/ tapestry-examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/ tapestry-framework/src/jav...

Author: jkuhnert
Date: Sat Oct  7 20:11:04 2006
New Revision: 454068

URL: http://svn.apache.org/viewvc?view=rev&rev=454068
Log:
Finished functionality for DropdownDatePicker / DropdownTimePicker (ie fully localizable / working /etc..). 
Fixed bug in JSONObject translating Long values. 
Upgraded commons-lang dependency to 2.2 version.
Added ability for tapestry widget manager to detect widgets supporting disable/enable functions so that 
they can be rendered as disabled/enabled properly.

Added:
    tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/dojo/AjaxShellDelegateTest.java
    tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/dojo/form/TestDropdownTimePicker.java
Modified:
    tapestry/tapestry4/trunk/pom.xml
    tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/context/Home.html
    tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/context/WEB-INF/log4j.properties
    tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java
    tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/dojo/form/DropdownDatePicker.java
    tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/dojo/form/DropdownDatePicker.script
    tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/dojo/form/DropdownTimePicker.java
    tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/json/JSONObject.java
    tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/dojo.js
    tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/dojo.js.uncompressed.js
    tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry/core.js
    tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry/form.js
    tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry/widget/Widget.js
    tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/asset/TestUnprotectedAsset.java
    tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/form/translator/TestDateTranslator.java

Modified: tapestry/tapestry4/trunk/pom.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/pom.xml?view=diff&rev=454068&r1=454067&r2=454068
==============================================================================
--- tapestry/tapestry4/trunk/pom.xml (original)
+++ tapestry/tapestry4/trunk/pom.xml Sat Oct  7 20:11:04 2006
@@ -160,7 +160,7 @@
             <dependency>
                 <groupId>ognl</groupId>
                 <artifactId>ognl</artifactId>
-                <version>2.6.7</version>
+                <version>2.6.9</version>
             </dependency>
             <dependency>
                 <groupId>javax.servlet</groupId>
@@ -180,7 +180,7 @@
             <dependency>
                 <groupId>commons-lang</groupId>
                 <artifactId>commons-lang</artifactId>
-                <version>2.1</version>
+                <version>2.2</version>
             </dependency>
             <dependency>
                 <groupId>org.apache.tapestry</groupId>

Modified: tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/context/Home.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/context/Home.html?view=diff&rev=454068&r1=454067&r2=454068
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/context/Home.html (original)
+++ tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/context/Home.html Sat Oct  7 20:11:04 2006
@@ -44,7 +44,8 @@
       </td>
       <td>
       	<input jwcid="@Submit" value="message:button.add" class="submitButton" 
-      			action="listener:addTask" async="ognl:true" updateComponents="taskForm" />
+      			action="listener:addTask"
+      			async="true" updateComponents="taskForm" />
       </td>
     </tr>
     

Modified: tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/context/WEB-INF/log4j.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/context/WEB-INF/log4j.properties?view=diff&rev=454068&r1=454067&r2=454068
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/context/WEB-INF/log4j.properties (original)
+++ tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/context/WEB-INF/log4j.properties Sat Oct  7 20:11:04 2006
@@ -25,7 +25,7 @@
 log4j.logger.org.apache=INFO
 log4j.logger.hivemind=INFO
 log4j.logger.tapestry=INFO
-log4j.logger.timetracker=INFO
+log4j.logger.timetracker=DEBUG
 log4j.logger.org.apache.tapestry=INFO
 
 log4j.logger.org.apache.tapestry.timetracker=DEBUG

Modified: tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java?view=diff&rev=454068&r1=454067&r2=454068
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java (original)
+++ tapestry/tapestry4/trunk/tapestry-examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java Sat Oct  7 20:11:04 2006
@@ -15,6 +15,7 @@
 
 import java.util.Date;
 
+import org.apache.log4j.Logger;
 import org.apache.tapestry.IRequestCycle;
 import org.apache.tapestry.annotations.Component;
 import org.apache.tapestry.annotations.EventListener;
@@ -42,6 +43,8 @@
 public abstract class TaskEntryPage extends BasePage
 {
     
+    private static final Logger _log = Logger.getLogger(TaskEntryPage.class);
+    
     @Component(id = "projectChoose", bindings = { "model=projectModel", "value=selectedProject",
             "displayName=message:choose.project", "filterOnChange=true",
             "validators=validators:required"})
@@ -56,7 +59,7 @@
     public abstract Project getCurrentProject();
     
     @Component(bindings = {"value=date", 
-            "displayName=message:task.start.date"})
+            "displayName=message:task.start.date","disabled=true"})
     public abstract DropdownDatePicker getDatePicker();
     public abstract Date getDate();
     
@@ -107,6 +110,11 @@
         Task task = new Task();
         task.setProjectId(getSelectedProject().getId());
         task.setDescription(getDescription());
+        
+        _log.debug("addTask date: " + getDate()
+                + "\n startTime: " + getStartTime()
+                + "\n endTime: " + getEndTime());
+        
         task.setStartDate(getStartTime());
         task.setEndDate(getEndTime());
         

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/dojo/form/DropdownDatePicker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/dojo/form/DropdownDatePicker.java?view=diff&rev=454068&r1=454067&r2=454068
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/dojo/form/DropdownDatePicker.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/dojo/form/DropdownDatePicker.java Sat Oct  7 20:11:04 2006
@@ -80,11 +80,14 @@
         json.put("inputName", getName());
         json.put("iconAlt", getIconAlt());
         json.put("displayFormat", translator.getPattern());
+        json.put("lang", getPage().getLocale().getLanguage());
         
         if (getValue() != null) {
-            json.put("date", getTranslatedFieldSupport().format(this, getValue()));
+            json.put("value", getValue().getTime());
         }
         
+        json.put("disabled", isDisabled());
+        
         Map parms = new HashMap();
         parms.put("clientId", getClientId());
         parms.put("props", json.toString());
@@ -102,9 +105,9 @@
         try
         {
             Date date = (Date) getTranslatedFieldSupport().parse(this, value);
-
+            
             getValidatableFieldSupport().validate(this, writer, cycle, date);
-
+            
             setValue(date);
         }
         catch (ValidatorException e)

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/dojo/form/DropdownDatePicker.script
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/dojo/form/DropdownDatePicker.script?view=diff&rev=454068&r1=454067&r2=454068
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/dojo/form/DropdownDatePicker.script (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/dojo/form/DropdownDatePicker.script Sat Oct  7 20:11:04 2006
@@ -7,8 +7,7 @@
 <input-symbol key="props" required="yes" />
     <body>
         <unique>
-            dojo.require("dojo.widget.Manager");
-            dojo.require("dojo.widget.DropdownDatePicker");
+            dojo.require("dojo.widget.*");
             dojo.require("tapestry.widget.Widget");
         </unique>
     </body>

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/dojo/form/DropdownTimePicker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/dojo/form/DropdownTimePicker.java?view=diff&rev=454068&r1=454067&r2=454068
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/dojo/form/DropdownTimePicker.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/dojo/form/DropdownTimePicker.java Sat Oct  7 20:11:04 2006
@@ -17,6 +17,7 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.commons.lang.time.DateFormatUtils;
 import org.apache.tapestry.IMarkupWriter;
 import org.apache.tapestry.IRequestCycle;
 import org.apache.tapestry.IScript;
@@ -26,7 +27,6 @@
 import org.apache.tapestry.form.ValidatableFieldSupport;
 import org.apache.tapestry.form.translator.DateTranslator;
 import org.apache.tapestry.json.JSONObject;
-import org.apache.tapestry.util.Strftime;
 import org.apache.tapestry.valid.ValidatorException;
 
 /**
@@ -80,12 +80,15 @@
         json.put("inputId", getClientId());
         json.put("inputName", getName());
         json.put("iconAlt", getIconAlt());
-        json.put("timeFormat", Strftime.convertToPosixFormat(translator.getPattern()));
+        json.put("displayFormat", translator.getPattern());
+        json.put("lang", getPage().getLocale().getLanguage());
         
         if (getValue() != null) {
-            json.put("storedtime", getTranslatedFieldSupport().format(this, getValue()));
+            json.put("value", DateFormatUtils.ISO_TIME_NO_T_TIME_ZONE_FORMAT.format(getValue()));
         }
         
+        json.put("disabled", isDisabled());
+        
         Map parms = new HashMap();
         parms.put("clientId", getClientId());
         parms.put("props", json.toString());
@@ -105,7 +108,7 @@
             Date date = (Date) getTranslatedFieldSupport().parse(this, value);
             
             getValidatableFieldSupport().validate(this, writer, cycle, date);
-
+            
             setValue(date);
         }
         catch (ValidatorException e)

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/json/JSONObject.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/json/JSONObject.java?view=diff&rev=454068&r1=454067&r2=454068
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/json/JSONObject.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/json/JSONObject.java Sat Oct  7 20:11:04 2006
@@ -417,20 +417,18 @@
     /**
      * Produce a string from a number.
      * 
-     * @param n
-     *            A Number
+     * @param n A Number
      * @return A String.
      * @exception ArithmeticException
      *                JSON can only serialize finite numbers.
      */
     public static String numberToString(Number n)
     {
-        if ((n instanceof Float && (((Float) n).isInfinite() || ((Float) n)
-                .isNaN()))
-                || (n instanceof Double && (((Double) n).isInfinite() || ((Double) n)
-                        .isNaN()))) { throw new ArithmeticException(
-                "JSON can only serialize finite numbers."); }
-
+        if ((n instanceof Float && (((Float) n).isInfinite() || ((Float) n).isNaN()))
+                || (n instanceof Double && (((Double) n).isInfinite() || ((Double) n).isNaN()))) { 
+            throw new ArithmeticException("JSON can only serialize finite numbers."); 
+        }
+        
         // Shave off trailing zeros and decimal point, if possible.
         
         String s = n.toString();
@@ -597,6 +595,12 @@
         return this;
     }
 
+    public JSONObject put(String key, long value)
+    {
+        put(key, new Long(value));
+        return this;
+    }
+    
     /** 
      * {@inheritDoc}
      */

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/dojo.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/dojo.js?view=diff&rev=454068&r1=454067&r2=454068
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/dojo.js (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/dojo.js Sat Oct  7 20:11:04 2006
@@ -2740,4 +2740,212 @@
 elem.setAttributeNode(_25f);
 }
 };
+dojo.provide("dojo.logging.Logger");
+dojo.provide("dojo.log");
+dojo.logging.Record=function(lvl,msg){
+this.level=lvl;
+this.message="";
+this.msgArgs=[];
+this.time=new Date();
+if(dojo.lang.isArray(msg)){
+if(msg.length>0&&dojo.lang.isString(msg[0])){
+this.message=msg.shift();
+}
+this.msgArgs=msg;
+}else{
+this.message=msg;
+}
+};
+dojo.logging.LogFilter=function(_262){
+this.passChain=_262||"";
+this.filter=function(_263){
+return true;
+};
+};
+dojo.logging.Logger=function(){
+this.cutOffLevel=0;
+this.propagate=true;
+this.parent=null;
+this.data=[];
+this.filters=[];
+this.handlers=[];
+};
+dojo.extend(dojo.logging.Logger,{argsToArr:function(args){
+var ret=[];
+for(var x=0;x<args.length;x++){
+ret.push(args[x]);
+}
+return ret;
+},setLevel:function(lvl){
+this.cutOffLevel=parseInt(lvl);
+},isEnabledFor:function(lvl){
+return parseInt(lvl)>=this.cutOffLevel;
+},getEffectiveLevel:function(){
+if((this.cutOffLevel==0)&&(this.parent)){
+return this.parent.getEffectiveLevel();
+}
+return this.cutOffLevel;
+},addFilter:function(flt){
+this.filters.push(flt);
+return this.filters.length-1;
+},removeFilterByIndex:function(_26a){
+if(this.filters[_26a]){
+delete this.filters[_26a];
+return true;
+}
+return false;
+},removeFilter:function(_26b){
+for(var x=0;x<this.filters.length;x++){
+if(this.filters[x]===_26b){
+delete this.filters[x];
+return true;
+}
+}
+return false;
+},removeAllFilters:function(){
+this.filters=[];
+},filter:function(rec){
+for(var x=0;x<this.filters.length;x++){
+if((this.filters[x]["filter"])&&(!this.filters[x].filter(rec))||(rec.level<this.cutOffLevel)){
+return false;
+}
+}
+return true;
+},addHandler:function(hdlr){
+this.handlers.push(hdlr);
+return this.handlers.length-1;
+},handle:function(rec){
+if((!this.filter(rec))||(rec.level<this.cutOffLevel)){
+return false;
+}
+for(var x=0;x<this.handlers.length;x++){
+if(this.handlers[x]["handle"]){
+this.handlers[x].handle(rec);
+}
+}
+return true;
+},log:function(lvl,msg){
+if((this.propagate)&&(this.parent)&&(this.parent.rec.level>=this.cutOffLevel)){
+this.parent.log(lvl,msg);
+return false;
+}
+this.handle(new dojo.logging.Record(lvl,msg));
+return true;
+},debug:function(msg){
+return this.logType("DEBUG",this.argsToArr(arguments));
+},info:function(msg){
+return this.logType("INFO",this.argsToArr(arguments));
+},warning:function(msg){
+return this.logType("WARNING",this.argsToArr(arguments));
+},error:function(msg){
+return this.logType("ERROR",this.argsToArr(arguments));
+},critical:function(msg){
+return this.logType("CRITICAL",this.argsToArr(arguments));
+},exception:function(msg,e,_27b){
+if(e){
+var _27c=[e.name,(e.description||e.message)];
+if(e.fileName){
+_27c.push(e.fileName);
+_27c.push("line "+e.lineNumber);
+}
+msg+=" "+_27c.join(" : ");
+}
+this.logType("ERROR",msg);
+if(!_27b){
+throw e;
+}
+},logType:function(type,args){
+return this.log.apply(this,[dojo.logging.log.getLevel(type),args]);
+},warn:function(){
+this.warning.apply(this,arguments);
+},err:function(){
+this.error.apply(this,arguments);
+},crit:function(){
+this.critical.apply(this,arguments);
+}});
+dojo.logging.LogHandler=function(_27f){
+this.cutOffLevel=(_27f)?_27f:0;
+this.formatter=null;
+this.data=[];
+this.filters=[];
+};
+dojo.lang.extend(dojo.logging.LogHandler,{setFormatter:function(_280){
+dojo.unimplemented("setFormatter");
+},flush:function(){
+},close:function(){
+},handleError:function(){
+},handle:function(_281){
+if((this.filter(_281))&&(_281.level>=this.cutOffLevel)){
+this.emit(_281);
+}
+},emit:function(_282){
+dojo.unimplemented("emit");
+}});
+void (function(){
+var _283=["setLevel","addFilter","removeFilterByIndex","removeFilter","removeAllFilters","filter"];
+var tgt=dojo.logging.LogHandler.prototype;
+var src=dojo.logging.Logger.prototype;
+for(var x=0;x<_283.length;x++){
+tgt[_283[x]]=src[_283[x]];
+}
+})();
+dojo.logging.log=new dojo.logging.Logger();
+dojo.logging.log.levels=[{"name":"DEBUG","level":1},{"name":"INFO","level":2},{"name":"WARNING","level":3},{"name":"ERROR","level":4},{"name":"CRITICAL","level":5}];
+dojo.logging.log.loggers={};
+dojo.logging.log.getLogger=function(name){
+if(!this.loggers[name]){
+this.loggers[name]=new dojo.logging.Logger();
+this.loggers[name].parent=this;
+}
+return this.loggers[name];
+};
+dojo.logging.log.getLevelName=function(lvl){
+for(var x=0;x<this.levels.length;x++){
+if(this.levels[x].level==lvl){
+return this.levels[x].name;
+}
+}
+return null;
+};
+dojo.logging.log.addLevelName=function(name,lvl){
+if(this.getLevelName(name)){
+this.err("could not add log level "+name+" because a level with that name already exists");
+return false;
+}
+this.levels.append({"name":name,"level":parseInt(lvl)});
+return true;
+};
+dojo.logging.log.getLevel=function(name){
+for(var x=0;x<this.levels.length;x++){
+if(this.levels[x].name.toUpperCase()==name.toUpperCase()){
+return this.levels[x].level;
+}
+}
+return null;
+};
+dojo.logging.MemoryLogHandler=function(_28e,_28f,_290,_291){
+dojo.logging.LogHandler.call(this,_28e);
+this.numRecords=(typeof djConfig["loggingNumRecords"]!="undefined")?djConfig["loggingNumRecords"]:((_28f)?_28f:-1);
+this.postType=(typeof djConfig["loggingPostType"]!="undefined")?djConfig["loggingPostType"]:(_290||-1);
+this.postInterval=(typeof djConfig["loggingPostInterval"]!="undefined")?djConfig["loggingPostInterval"]:(_290||-1);
+};
+dojo.lang.inherits(dojo.logging.MemoryLogHandler,dojo.logging.LogHandler);
+dojo.lang.extend(dojo.logging.MemoryLogHandler,{emit:function(_292){
+if(!djConfig.isDebug){
+return;
+}
+var _293=String(dojo.log.getLevelName(_292.level)+": "+_292.time.toLocaleTimeString())+": "+_292.message;
+if(!dj_undef("println",dojo.hostenv)){
+dojo.hostenv.println(_293);
+}
+this.data.push(_292);
+if(this.numRecords!=-1){
+while(this.data.length>this.numRecords){
+this.data.shift();
+}
+}
+}});
+dojo.logging.logQueueHandler=new dojo.logging.MemoryLogHandler(0,50,0,10000);
+dojo.logging.log.addHandler(dojo.logging.logQueueHandler);
+dojo.log=dojo.logging.log;
 

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/dojo.js.uncompressed.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/dojo.js.uncompressed.js?view=diff&rev=454068&r1=454067&r2=454068
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/dojo.js.uncompressed.js (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/dojo.js.uncompressed.js Sat Oct  7 20:11:04 2006
@@ -3937,3 +3937,381 @@
 	}
 }
 
+/*		This is the dojo logging facility, which is imported from nWidgets
+		(written by Alex Russell, CLA on file), which is patterned on the
+		Python logging module, which in turn has been heavily influenced by
+		log4j (execpt with some more pythonic choices, which we adopt as well).
+
+		While the dojo logging facilities do provide a set of familiar
+		interfaces, many of the details are changed to reflect the constraints
+		of the browser environment. Mainly, file and syslog-style logging
+		facilites are not provided, with HTTP POST and GET requests being the
+		only ways of getting data from the browser back to a server. Minimal
+		support for this (and XML serialization of logs) is provided, but may
+		not be of practical use in a deployment environment.
+
+		The Dojo logging classes are agnostic of any environment, and while
+		default loggers are provided for browser-based interpreter
+		environments, this file and the classes it define are explicitly
+		designed to be portable to command-line interpreters and other
+		ECMA-262v3 envrionments.
+
+	the logger needs to accomidate:
+		log "levels"
+		type identifiers
+		file?
+		message
+		tic/toc?
+
+	The logger should ALWAYS record:
+		time/date logged
+		message
+		type
+		level
+*/
+// TODO: conver documentation to javadoc style once we confirm that is our choice
+// TODO: define DTD for XML-formatted log messages
+// TODO: write XML Formatter class
+// TODO: write HTTP Handler which uses POST to send log lines/sections
+
+// Filename:	LogCore.js
+// Purpose:		a common logging infrastructure for dojo
+// Classes:		dojo.logging, dojo.logging.Logger, dojo.logging.Record, dojo.logging.LogFilter
+// Global Objects:	dojo.logging
+// Dependencies:	none
+
+dojo.provide("dojo.logging.Logger");
+dojo.provide("dojo.log");
+
+/*
+	A simple data structure class that stores information for and about
+	a logged event. Objects of this type are created automatically when
+	an event is logged and are the internal format in which information
+	about log events is kept.
+*/
+
+dojo.logging.Record = function(lvl, msg){
+	this.level = lvl;
+	this.message = "";
+	this.msgArgs = [];
+	this.time = new Date();
+	
+	if(dojo.lang.isArray(msg)){
+		if(msg.length > 0 && dojo.lang.isString(msg[0])){
+			this.message=msg.shift();
+		}
+		this.msgArgs=msg;
+	}else{
+		this.message=msg;
+	}
+	// FIXME: what other information can we receive/discover here?
+}
+
+// an empty parent (abstract) class which concrete filters should inherit from.
+dojo.logging.LogFilter = function(loggerChain){
+	this.passChain = loggerChain || "";
+	this.filter = function(record){
+		// FIXME: need to figure out a way to enforce the loggerChain
+		// restriction
+		return true; // pass all records
+	}
+}
+
+dojo.logging.Logger = function(){
+	this.cutOffLevel = 0;
+	this.propagate = true;
+	this.parent = null;
+	// storage for dojo.logging.Record objects seen and accepted by this logger
+	this.data = [];
+	this.filters = [];
+	this.handlers = [];
+}
+
+dojo.extend(dojo.logging.Logger,{
+	argsToArr: function(args){
+		// utility function, reproduced from __util__ here to remove dependency
+		var ret = [];
+		for(var x=0; x<args.length; x++){
+			ret.push(args[x]);
+		}
+		return ret;
+	},
+
+	setLevel: function(lvl){
+		this.cutOffLevel = parseInt(lvl);
+	},
+
+	isEnabledFor: function(lvl){
+		return parseInt(lvl) >= this.cutOffLevel;
+	},
+
+	getEffectiveLevel: function(){
+		if((this.cutOffLevel==0)&&(this.parent)){
+			return this.parent.getEffectiveLevel();
+		}
+		return this.cutOffLevel;
+	},
+
+	addFilter: function(flt){
+		this.filters.push(flt);
+		return this.filters.length-1;
+	},
+
+	removeFilterByIndex: function(fltIndex){
+		if(this.filters[fltIndex]){
+			delete this.filters[fltIndex];
+			return true;
+		}
+		return false;
+	},
+
+	removeFilter: function(fltRef){
+		for(var x=0; x<this.filters.length; x++){
+			if(this.filters[x]===fltRef){
+				delete this.filters[x];
+				return true;
+			}
+		}
+		return false;
+	},
+
+	removeAllFilters: function(){
+		this.filters = []; // clobber all of them
+	},
+
+	filter: function(rec){
+		for(var x=0; x<this.filters.length; x++){
+			if((this.filters[x]["filter"])&&
+			   (!this.filters[x].filter(rec))||
+			   (rec.level<this.cutOffLevel)){
+				return false;
+			}
+		}
+		return true;
+	},
+
+	addHandler: function(hdlr){
+		this.handlers.push(hdlr);
+		return this.handlers.length-1;
+	},
+
+	handle: function(rec){
+		if((!this.filter(rec))||(rec.level<this.cutOffLevel)){ return false; }
+		for(var x=0; x<this.handlers.length; x++){
+			if(this.handlers[x]["handle"]){
+			   this.handlers[x].handle(rec);
+			}
+		}
+		// FIXME: not sure what to do about records to be propagated that may have
+		// been modified by the handlers or the filters at this logger. Should
+		// parents always have pristine copies? or is passing the modified record
+		// OK?
+		// if((this.propagate)&&(this.parent)){ this.parent.handle(rec); }
+		return true;
+	},
+
+	// the heart and soul of the logging system
+	log: function(lvl, msg){
+		if(	(this.propagate)&&(this.parent)&&
+			(this.parent.rec.level>=this.cutOffLevel)){
+			this.parent.log(lvl, msg);
+			return false;
+		}
+		// FIXME: need to call logging providers here!
+		this.handle(new dojo.logging.Record(lvl, msg));
+		return true;
+	},
+
+	// logger helpers
+	debug:function(msg){
+		return this.logType("DEBUG", this.argsToArr(arguments));
+	},
+
+	info: function(msg){
+		return this.logType("INFO", this.argsToArr(arguments));
+	},
+
+	warning: function(msg){
+		return this.logType("WARNING", this.argsToArr(arguments));
+	},
+
+	error: function(msg){
+		return this.logType("ERROR", this.argsToArr(arguments));
+	},
+
+	critical: function(msg){
+		return this.logType("CRITICAL", this.argsToArr(arguments));
+	},
+
+	exception: function(msg, e, squelch){
+		// FIXME: this needs to be modified to put the exception in the msg
+		// if we're on Moz, we can get the following from the exception object:
+		//		lineNumber
+		//		message
+		//		fileName
+		//		stack
+		//		name
+		// on IE, we get:
+		//		name
+		//		message (from MDA?)
+		//		number
+		//		description (same as message!)
+		if(e){
+			var eparts = [e.name, (e.description||e.message)];
+			if(e.fileName){
+				eparts.push(e.fileName);
+				eparts.push("line "+e.lineNumber);
+				// eparts.push(e.stack);
+			}
+			msg += " "+eparts.join(" : ");
+		}
+
+		this.logType("ERROR", msg);
+		if(!squelch){
+			throw e;
+		}
+	},
+
+	logType: function(type, args){
+		return this.log.apply(this, [dojo.logging.log.getLevel(type), 
+			args]);
+	},
+	
+	warn:function(){
+		this.warning.apply(this,arguments);
+	},
+	err:function(){
+		this.error.apply(this,arguments);
+	},
+	crit:function(){
+		this.critical.apply(this,arguments);
+	}
+});
+
+// the Handler class
+dojo.logging.LogHandler = function(level){
+	this.cutOffLevel = (level) ? level : 0;
+	this.formatter = null; // FIXME: default formatter?
+	this.data = [];
+	this.filters = [];
+}
+dojo.lang.extend(dojo.logging.LogHandler,{
+	
+	setFormatter:function(formatter){
+		dojo.unimplemented("setFormatter");
+	},
+	
+	flush:function(){},
+	close:function(){},
+	handleError:function(){},
+	
+	handle:function(record){
+		if((this.filter(record))&&(record.level>=this.cutOffLevel)){
+			this.emit(record);
+		}
+	},
+	
+	emit:function(record){
+		dojo.unimplemented("emit");
+	}
+});
+
+// set aliases since we don't want to inherit from dojo.logging.Logger
+void(function(){ // begin globals protection closure
+	var names = [
+		"setLevel", "addFilter", "removeFilterByIndex", "removeFilter",
+		"removeAllFilters", "filter"
+	];
+	var tgt = dojo.logging.LogHandler.prototype;
+	var src = dojo.logging.Logger.prototype;
+	for(var x=0; x<names.length; x++){
+		tgt[names[x]] = src[names[x]];
+	}
+})(); // end globals protection closure
+
+dojo.logging.log = new dojo.logging.Logger();
+
+// an associative array of logger objects. This object inherits from
+// a list of level names with their associated numeric levels
+dojo.logging.log.levels = [ {"name": "DEBUG", "level": 1},
+						   {"name": "INFO", "level": 2},
+						   {"name": "WARNING", "level": 3},
+						   {"name": "ERROR", "level": 4},
+						   {"name": "CRITICAL", "level": 5} ];
+
+dojo.logging.log.loggers = {};
+
+dojo.logging.log.getLogger = function(name){
+	if(!this.loggers[name]){
+		this.loggers[name] = new dojo.logging.Logger();
+		this.loggers[name].parent = this;
+	}
+	return this.loggers[name];
+}
+
+dojo.logging.log.getLevelName = function(lvl){
+	for(var x=0; x<this.levels.length; x++){
+		if(this.levels[x].level == lvl){
+			return this.levels[x].name;
+		}
+	}
+	return null;
+}
+
+dojo.logging.log.addLevelName = function(name, lvl){
+	if(this.getLevelName(name)){
+		this.err("could not add log level "+name+" because a level with that name already exists");
+		return false;
+	}
+	this.levels.append({"name": name, "level": parseInt(lvl)});
+	return true;
+}
+
+dojo.logging.log.getLevel = function(name){
+	for(var x=0; x<this.levels.length; x++){
+		if(this.levels[x].name.toUpperCase() == name.toUpperCase()){
+			return this.levels[x].level;
+		}
+	}
+	return null;
+}
+
+// a default handler class, it simply saves all of the handle()'d records in
+// memory. Useful for attaching to with dojo.event.connect()
+dojo.logging.MemoryLogHandler = function(level, recordsToKeep, postType, postInterval){
+	// mixin style inheritance
+	dojo.logging.LogHandler.call(this, level);
+	// default is unlimited
+	this.numRecords = (typeof djConfig['loggingNumRecords'] != 'undefined') ? djConfig['loggingNumRecords'] : ((recordsToKeep) ? recordsToKeep : -1);
+	// 0=count, 1=time, -1=don't post TODO: move this to a better location for prefs
+	this.postType = (typeof djConfig['loggingPostType'] != 'undefined') ? djConfig['loggingPostType'] : ( postType || -1);
+	// milliseconds for time, interger for number of records, -1 for non-posting,
+	this.postInterval = (typeof djConfig['loggingPostInterval'] != 'undefined') ? djConfig['loggingPostInterval'] : ( postType || -1);
+}
+
+dojo.lang.inherits(dojo.logging.MemoryLogHandler, dojo.logging.LogHandler);
+dojo.lang.extend(dojo.logging.MemoryLogHandler,{
+	
+	emit:function(record){
+		if (!djConfig.isDebug) { return; }
+		
+		var logStr = String(dojo.log.getLevelName(record.level)+": "
+					+record.time.toLocaleTimeString())+": "+record.message;
+		if(!dj_undef("println", dojo.hostenv)){
+			dojo.hostenv.println(logStr);
+		}
+		
+		this.data.push(record);
+		if(this.numRecords != -1){
+			while(this.data.length>this.numRecords){
+				this.data.shift();
+			}
+		}
+	}
+});
+
+dojo.logging.logQueueHandler = new dojo.logging.MemoryLogHandler(0,50,0,10000);
+
+dojo.logging.log.addHandler(dojo.logging.logQueueHandler);
+dojo.log = dojo.logging.log;
+

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry/core.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry/core.js?view=diff&rev=454068&r1=454067&r2=454068
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry/core.js (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry/core.js Sat Oct  7 20:11:04 2006
@@ -185,7 +185,7 @@
     	
     	if (djConfig["isDebug"]) {
     		var content=tapestry.html.getContentAsString(element);
-    		dojo.log.debug("Received element content for id <" + id + "> of:\n" + content);
+    		dojo.log.debug("Received element content for id <" + id + "> of:", content);
     		node.innerHTML=content;
     		return;
     	}
@@ -237,7 +237,7 @@
         for (var i=0; i<scripts.length; i++) {
             var scr = scripts[i].match(match)[1];
             try {
-                dojo.log.debug("evaluating script:" + scr);
+                dojo.log.debug("evaluating script:", scr);
                 eval(scr);
             } catch (e) {
             	tapestry.scriptInFlight = false;

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry/form.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry/form.js?view=diff&rev=454068&r1=454067&r2=454068
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry/form.js (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry/form.js Sat Oct  7 20:11:04 2006
@@ -328,6 +328,10 @@
 		
 		if (submitName){
 			form.submitname.value=submitName;
+			if(!content){ content={}; }
+			if(form[submitName]){
+				content[submitName]=form[submitName].value;
+			}
 		}
 		
 		// handle submissions from input buttons

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry/widget/Widget.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry/widget/Widget.js?view=diff&rev=454068&r1=454067&r2=454068
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry/widget/Widget.js (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/tapestry/widget/Widget.js Sat Oct  7 20:11:04 2006
@@ -53,9 +53,16 @@
 			return;
 		}
 		
-		if (!props["widgetId"]) props["widgetId"]=widgetId;
+		if (!props["widgetId"]) {
+			props["widgetId"]=widgetId;
+		}
 		
-		dojo.widget.createWidget(type, props, node);
+		// handle disabling widgets
+		var w = dojo.widget.createWidget(type, props, node);
+		if (!dj_undef("disabled",props) && props.disabled == true 
+			&& dojo.lang.isFunction(w["disable"])){
+			w.disable();
+		}
 	}
 	
 }

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/asset/TestUnprotectedAsset.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/asset/TestUnprotectedAsset.java?view=diff&rev=454068&r1=454067&r2=454068
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/asset/TestUnprotectedAsset.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/asset/TestUnprotectedAsset.java Sat Oct  7 20:11:04 2006
@@ -191,7 +191,7 @@
         assertEquals("src/", service.translatePath("dojo/../src/"));
         assertEquals("/", service.translatePath("/dojo/../"));
         assertEquals("", service.translatePath("dojo/../"));
-    }     
+    }
 
     public void test_Relative_Css_Paths()
     {

Added: tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/dojo/AjaxShellDelegateTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/dojo/AjaxShellDelegateTest.java?view=auto&rev=454068
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/dojo/AjaxShellDelegateTest.java (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/dojo/AjaxShellDelegateTest.java Sat Oct  7 20:11:04 2006
@@ -0,0 +1,131 @@
+// Copyright Oct 7, 2006 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.tapestry.dojo;
+
+import static org.easymock.EasyMock.*;
+
+import org.apache.hivemind.Resource;
+import org.apache.tapestry.BaseComponentTestCase;
+import org.apache.tapestry.IAsset;
+import org.apache.tapestry.IMarkupWriter;
+import org.apache.tapestry.IRequestCycle;
+import org.apache.tapestry.engine.IEngineService;
+import org.apache.tapestry.engine.ILink;
+import org.testng.annotations.Test;
+
+
+/**
+ * Tests basic functionality of {@link AjaxShellDelegate}.
+ * 
+ * @author jkuhnert
+ */
+@Test
+public class AjaxShellDelegateTest extends BaseComponentTestCase
+{
+
+    void trainStaticPath(IEngineService engine, IAsset asset, String path)
+    {
+        Resource res = newMock(Resource.class);
+        expect(asset.getResourceLocation()).andReturn(res);
+        expect(res.getPath()).andReturn(path);
+        
+        ILink link = newLink();
+        expect(engine.getLink(Boolean.TRUE, path)).andReturn(link);
+        expect(link.getAbsoluteURL()).andReturn("http://" + path);
+    }
+    
+    public void test_Default_Render()
+    {
+        IAsset dojoSource = newAsset();
+        IAsset dojoPath = newAsset();
+        IAsset tSource = newAsset();
+        IEngineService assetService = newEngineService();
+        
+        IRequestCycle cycle = newCycle();
+        IMarkupWriter writer = newBufferWriter();
+        
+        trainStaticPath(assetService, dojoPath, "/dojo/path");
+        
+        trainStaticPath(assetService, dojoSource, "/dojo/path/dojo.js");
+        
+        trainStaticPath(assetService, tSource, "/tapestry/tapestry.js");
+        
+        AjaxShellDelegate d = new AjaxShellDelegate();
+        d.setAssetService(assetService);
+        d.setDojoPath(dojoPath);
+        d.setDojoSource(dojoSource);
+        d.setTapestrySource(tSource);
+        
+        replay();
+        
+        d.render(writer, cycle);
+        
+        verify();
+        
+        assertBuffer("<script type=\"text/javascript\">djConfig = {\"isDebug\":false,"
+                + "\"debugAtAllCosts\":false,\"baseRelativePath\":\"http:///dojo/path\","
+                +"\"preventBackButtonFix\":false,\"parseWidgets\":false} </script>\n" + 
+                "\n" + 
+                " <script type=\"text/javascript\" src=\"http:///dojo/path/dojo.js\"></script>"
+                +"<script type=\"text/javascript\" src=\"http:///tapestry/tapestry.js\"></script>\n" + 
+                "<script type=\"text/javascript\">\n" + 
+                "dojo.require(\"dojo.logging.Logger\");\n" + 
+                "dojo.log.setLevel(dojo.log.getLevel(\"WARNING\"));\n" + 
+                "dojo.require(\"tapestry.namespace\")\n" + 
+        "</script>\n");
+    }
+    
+    public void test_Debug_Render()
+    {
+        IAsset dojoSource = newAsset();
+        IAsset dojoPath = newAsset();
+        IAsset tSource = newAsset();
+        IEngineService assetService = newEngineService();
+        
+        IRequestCycle cycle = newCycle();
+        IMarkupWriter writer = newBufferWriter();
+        
+        trainStaticPath(assetService, dojoPath, "/dojo/path");
+        
+        trainStaticPath(assetService, dojoSource, "/dojo/path/dojo.js");
+        
+        trainStaticPath(assetService, tSource, "/tapestry/tapestry.js");
+        
+        AjaxShellDelegate d = new AjaxShellDelegate();
+        d.setAssetService(assetService);
+        d.setDojoPath(dojoPath);
+        d.setDojoSource(dojoSource);
+        d.setTapestrySource(tSource);
+        d.setLogLevel(AjaxShellDelegate.BROWSER_LOG_DEBUG);
+        d.setConsoleEnabled(true);
+        
+        replay();
+        
+        d.render(writer, cycle);
+        
+        verify();
+        
+        assertBuffer("<script type=\"text/javascript\">djConfig = {\"isDebug\":false,"
+                + "\"debugAtAllCosts\":false,\"baseRelativePath\":\"http:///dojo/path\","
+                +"\"preventBackButtonFix\":false,\"parseWidgets\":false} </script>\n" + 
+                "\n" + 
+                " <script type=\"text/javascript\" src=\"http:///dojo/path/dojo.js\"></script>"
+                +"<script type=\"text/javascript\" src=\"http:///tapestry/tapestry.js\"></script>\n" + 
+                "<script type=\"text/javascript\">\n" + 
+                "dojo.require(\"dojo.debug.console\");\n" + 
+                "dojo.log.setLevel(dojo.log.getLevel(\"DEBUG\"));\n" + 
+                "dojo.require(\"tapestry.namespace\")\n" + 
+        "</script>\n");
+    }
+}

Added: tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/dojo/form/TestDropdownTimePicker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/dojo/form/TestDropdownTimePicker.java?view=auto&rev=454068
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/dojo/form/TestDropdownTimePicker.java (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/dojo/form/TestDropdownTimePicker.java Sat Oct  7 20:11:04 2006
@@ -0,0 +1,125 @@
+// Copyright Oct 7, 2006 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.tapestry.dojo.form;
+
+import static org.easymock.EasyMock.checkOrder;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.isA;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.tapestry.IForm;
+import org.apache.tapestry.IMarkupWriter;
+import org.apache.tapestry.IPage;
+import org.apache.tapestry.IRequestCycle;
+import org.apache.tapestry.IScript;
+import org.apache.tapestry.PageRenderSupport;
+import org.apache.tapestry.form.BaseFormComponentTestCase;
+import org.apache.tapestry.form.MockDelegate;
+import org.apache.tapestry.form.ValidatableFieldSupport;
+import org.apache.tapestry.form.translator.DateTranslator;
+import org.apache.tapestry.json.JSONObject;
+import org.testng.annotations.Test;
+
+
+/**
+ * Tests functionality of {@link DropdownTimePicker} component.
+ * 
+ * @author jkuhnert
+ */
+@Test
+public class TestDropdownTimePicker extends BaseFormComponentTestCase
+{
+    
+    public void test_Render()
+    {
+        ValidatableFieldSupport vfs = newMock(ValidatableFieldSupport.class);
+        DateTranslator translator = new DateTranslator();
+        translator.setPattern("hh:mm a");
+        
+        IRequestCycle cycle = newMock(IRequestCycle.class);
+        IForm form = newMock(IForm.class);
+        checkOrder(form, false);
+        IPage page = newPage();
+        
+        MockDelegate delegate = new MockDelegate();
+        
+        IScript script = newMock(IScript.class);
+        
+        Date dtValue = new Date();
+        
+        DropdownTimePicker component = newInstance(DropdownTimePicker.class, 
+                new Object[] { 
+            "name", "fred",
+            "script", script,
+            "validatableFieldSupport", vfs,
+            "translator", translator,
+            "value", dtValue,
+            "page", page
+        });
+        
+        expect(cycle.renderStackPush(component)).andReturn(component);
+        
+        expect(form.getName()).andReturn("testform").anyTimes();
+        
+        form.setFormFieldUpdating(true);
+        
+        IMarkupWriter writer = newBufferWriter();
+        
+        trainGetForm(cycle, form);
+        trainWasPrerendered(form, writer, component, false);
+        
+        trainGetDelegate(form, delegate);
+        
+        delegate.setFormComponent(component);
+        
+        trainGetElementId(form, component, "fred");
+        trainIsRewinding(form, false);
+        trainIsRewinding(cycle, false);
+        
+        delegate.setFormComponent(component);
+        
+        vfs.renderContributions(component, writer, cycle);
+        
+        expect(page.getLocale()).andReturn(Locale.ENGLISH);
+        
+        PageRenderSupport prs = newPageRenderSupport();
+        trainGetPageRenderSupport(cycle, prs);
+        
+        script.execute(eq(component), eq(cycle), eq(prs), isA(Map.class));
+        
+        expect(cycle.renderStackPop()).andReturn(component);
+        
+        replay();
+        
+        component.render(writer, cycle);
+        
+        verify();
+        
+        assertBuffer("<span class=\"prefix\"><div class=\"validation-delegate\"></div></span>");
+    }
+    
+    public void test_Json_Time()
+    {
+        long time = System.currentTimeMillis();
+        
+        JSONObject json = new JSONObject();
+        json.put("time", time);
+        
+        assertEquals(json.toString(), "{\"time\":"+time+"}");
+    }
+}

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/form/translator/TestDateTranslator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/form/translator/TestDateTranslator.java?view=diff&rev=454068&r1=454067&r2=454068
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/form/translator/TestDateTranslator.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/form/translator/TestDateTranslator.java Sat Oct  7 20:11:04 2006
@@ -116,7 +116,29 @@
 
         testParse(translator, "10/29/1976", buildDate(1976, Calendar.OCTOBER, 29));
     }
-
+    
+    public void test_Time_Parse() throws Exception
+    {
+        DateTranslator translator = new DateTranslator();
+        
+        String input = "6:50 pm";
+        
+        translator.setPattern("hh:mm a");
+        
+        IFormComponent field = newField();
+        
+        ValidationMessages messages = newValidationMessages(Locale.ENGLISH);
+        
+        replay();
+        
+        Date result = (Date) translator.parse(field, messages, input);
+        
+        assertEquals(18, result.getHours());
+        assertEquals(50, result.getMinutes());
+        
+        verify();
+    }
+    
     public void testCustomParse() throws Exception
     {
         DateTranslator translator = new DateTranslator();