You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by jk...@apache.org on 2006/06/12 03:56:18 UTC

svn commit: r413562 - in /tapestry/tapestry4/trunk: examples/TimeTracker/src/context/ examples/TimeTracker/src/context/css/ examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/ framework/src/java/org/apache/tapestry/ framework/src/java/o...

Author: jkuhnert
Date: Sun Jun 11 18:56:16 2006
New Revision: 413562

URL: http://svn.apache.org/viewvc?rev=413562&view=rev
Log:
A little validation.

Added:
    tapestry/tapestry4/trunk/framework/src/js/tapestry/form/
    tapestry/tapestry4/trunk/framework/src/js/tapestry/form/__package__.js   (with props)
    tapestry/tapestry4/trunk/framework/src/js/tapestry/form/validation.js   (with props)
    tapestry/tapestry4/trunk/framework/src/js/tests/test_form_validation.js   (with props)
Modified:
    tapestry/tapestry4/trunk/examples/TimeTracker/src/context/Home.html
    tapestry/tapestry4/trunk/examples/TimeTracker/src/context/css/forms.css
    tapestry/tapestry4/trunk/examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/FormBehavior.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/dojo/form/Autocompleter.jwc
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/Form.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/FormComponentContributorContext.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/FormComponentContributorContextImpl.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/FormSupportImpl.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/PropertySelection.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/validator/BaseValidator.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/validator/Required.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/valid/ValidationConstants.java
    tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/valid/ValidationDelegate.java
    tapestry/tapestry4/trunk/framework/src/js/tapestry/__package__.js
    tapestry/tapestry4/trunk/framework/src/js/tapestry/form.js
    tapestry/tapestry4/trunk/framework/src/js/tapestry/test.js
    tapestry/tapestry4/trunk/framework/src/js/tests/test_event.js
    tapestry/tapestry4/trunk/framework/src/js/tests/test_form.js
    tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/form/MockForm.java

Modified: tapestry/tapestry4/trunk/examples/TimeTracker/src/context/Home.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/examples/TimeTracker/src/context/Home.html?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/examples/TimeTracker/src/context/Home.html (original)
+++ tapestry/tapestry4/trunk/examples/TimeTracker/src/context/Home.html Sun Jun 11 18:56:16 2006
@@ -6,7 +6,7 @@
 using them.
 </p>
 
-<form jwcid="taskForm@Form" class="container">
+<form jwcid="taskForm@Form" class="container" clientValidationEnabled="true" >
 <h3><span jwcid="@Insert" value="message:new.task"/></h3>
 	<fieldset>
     <table width="90%" class="form" cellpadding="2" cellspacing="0" >

Modified: tapestry/tapestry4/trunk/examples/TimeTracker/src/context/css/forms.css
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/examples/TimeTracker/src/context/css/forms.css?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/examples/TimeTracker/src/context/css/forms.css (original)
+++ tapestry/tapestry4/trunk/examples/TimeTracker/src/context/css/forms.css Sun Jun 11 18:56:16 2006
@@ -53,3 +53,12 @@
 	cursor: hand;
 	cursor: pointer;
 }
+
+.fieldMissing {
+    background: #bedef4;
+}
+
+.fieldInvalid {
+    background: #ffaf7e;
+    font-weight: bold;
+}
\ No newline at end of file

Modified: tapestry/tapestry4/trunk/examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java (original)
+++ tapestry/tapestry4/trunk/examples/TimeTracker/src/java/org/apache/tapestry/timetracker/page/TaskEntryPage.java Sun Jun 11 18:56:16 2006
@@ -46,7 +46,8 @@
     
     @Component(type = "Autocompleter", id = "projectChoose",
             bindings = { "model=projectModel", "value=selectedProject",
-            "displayName=message:choose.project", "filterOnChange=true"})
+            "displayName=message:choose.project", "filterOnChange=true",
+            "validators=validators:required"})
     public abstract Autocompleter getProjectSelection();
     
     @InjectObject("service:timetracker.dao.ProjectDao")
@@ -63,18 +64,21 @@
     public abstract Date getDate();
     
     @Component(type = "DropdownTimePicker", id = "startPicker",
-            bindings = {"value=startTime", "displayName=message:task.start.time"})
+            bindings = {"value=startTime", "displayName=message:task.start.time",
+            "validators=validators:required"})
     public abstract DropdownTimePicker getStartPicker();
     public abstract Date getStartTime();
     
     @Component(type = "DropdownTimePicker", id = "endPicker",
-            bindings = {"value=endTime", "displayName=message:task.end.time"})
+            bindings = {"value=endTime", "displayName=message:task.end.time",
+            "validators=validators:required"})
     public abstract DropdownTimePicker getEndPicker();
     public abstract Date getEndTime();
     
     @Component(type = "TextField", id = "descriptionField",
             bindings = { "value=description", 
-            "displayName=message:task.description"})
+            "displayName=message:task.description",
+            "validators=validators:required"})
     public abstract TextField getDescriptionField();
     public abstract String getDescription();
     

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/FormBehavior.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/FormBehavior.java?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/FormBehavior.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/FormBehavior.java Sun Jun 11 18:56:16 2006
@@ -17,6 +17,7 @@
 import org.apache.hivemind.Location;
 import org.apache.tapestry.form.FormEventType;
 import org.apache.tapestry.form.IFormComponent;
+import org.apache.tapestry.json.JSONObject;
 
 /**
  * Common interface extended by {@link org.apache.tapestry.IForm}&nbsp;and
@@ -161,4 +162,10 @@
 
     void registerForFocus(IFormComponent field, int priority);
 
+    /**
+     * The javascript object profile being built by this context to validate/translate
+     * form values.
+     * @return {@link JSONObject} profile.
+     */
+    JSONObject getProfile();
 }

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/dojo/form/Autocompleter.jwc
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/dojo/form/Autocompleter.jwc?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/dojo/form/Autocompleter.jwc (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/dojo/form/Autocompleter.jwc Sun Jun 11 18:56:16 2006
@@ -49,7 +49,7 @@
   <parameter name="id" property="idParameter" default-value="id"/>
 
   <reserved-parameter name="name"/>
-
+  
   <inject property="validatableFieldSupport" object="service:tapestry.form.ValidatableFieldSupport"/>
   
   <inject property="directService" object="service:tapestry.services.Direct"/>

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/Form.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/Form.java?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/Form.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/Form.java Sun Jun 11 18:56:16 2006
@@ -30,6 +30,7 @@
 import org.apache.tapestry.engine.DirectServiceParameter;
 import org.apache.tapestry.engine.IEngineService;
 import org.apache.tapestry.engine.ILink;
+import org.apache.tapestry.json.JSONObject;
 import org.apache.tapestry.listener.ListenerInvoker;
 import org.apache.tapestry.valid.IValidationDelegate;
 import org.apache.tapestry.web.WebResponse;
@@ -64,7 +65,7 @@
     private String _name;
 
     private FormSupport _formSupport;
-
+    
     /**
      * Renders informal parameters.
      * @author hls
@@ -444,4 +445,11 @@
         _formSupport.registerForFocus(field, priority);
     }
 
+    /** 
+     * {@inheritDoc}
+     */
+    public JSONObject getProfile()
+    {
+        return _formSupport.getProfile();
+    }
 }

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/FormComponentContributorContext.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/FormComponentContributorContext.java?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/FormComponentContributorContext.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/FormComponentContributorContext.java Sun Jun 11 18:56:16 2006
@@ -14,6 +14,8 @@
 
 package org.apache.tapestry.form;
 
+import org.apache.tapestry.json.JSONObject;
+
 /**
  * Object that provides support to objects that implement
  * {@link org.apache.tapestry.form.FormComponentContributor}. For the moment, at least, this is all
@@ -55,4 +57,11 @@
      */
 
      void registerForFocus(int priority);
+     
+     /**
+      * The javascript object profile being built by this context to validate/translate
+      * form values. This is really just a delegate to {@link FormBehavior}.
+      * @return {@link JSONObject} profile.
+      */
+     JSONObject getProfile();
 }

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/FormComponentContributorContextImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/FormComponentContributorContextImpl.java?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/FormComponentContributorContextImpl.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/FormComponentContributorContextImpl.java Sun Jun 11 18:56:16 2006
@@ -23,6 +23,7 @@
 import org.apache.tapestry.IRequestCycle;
 import org.apache.tapestry.PageRenderSupport;
 import org.apache.tapestry.TapestryUtils;
+import org.apache.tapestry.json.JSONObject;
 
 /**
  * Implementation of {@link org.apache.tapestry.form.FormComponentContributorContext}.
@@ -42,7 +43,7 @@
     private final IForm _form;
 
     private final String _formId;
-
+    
     /**
      * Used only for testing.
      */
@@ -90,4 +91,8 @@
         _form.registerForFocus(_field, priority);
     }
 
+    public JSONObject getProfile()
+    {
+        return _form.getProfile();
+    }
 }

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/FormSupportImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/FormSupportImpl.java?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/FormSupportImpl.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/FormSupportImpl.java Sun Jun 11 18:56:16 2006
@@ -40,6 +40,7 @@
 import org.apache.tapestry.TapestryUtils;
 import org.apache.tapestry.engine.ILink;
 import org.apache.tapestry.event.BrowserEvent;
+import org.apache.tapestry.json.JSONObject;
 import org.apache.tapestry.services.ServiceConstants;
 import org.apache.tapestry.util.IdAllocator;
 import org.apache.tapestry.valid.IValidationDelegate;
@@ -157,6 +158,8 @@
 
     private final PageRenderSupport _pageRenderSupport;
 
+    private final JSONObject _profile;
+    
     public FormSupportImpl(IMarkupWriter writer, IRequestCycle cycle, IForm form)
     {
         Defense.notNull(writer, "writer");
@@ -172,6 +175,7 @@
         _allocatedIdIndex = 0;
         
         _pageRenderSupport = TapestryUtils.getOptionalPageRenderSupport(cycle);
+        _profile = new JSONObject();
     }
 
     /**
@@ -187,6 +191,7 @@
         _writer = null;
         _delegate = null;
         _pageRenderSupport = null;
+        _profile = null;
     }
 
     /**
@@ -530,10 +535,16 @@
 
         if (!_form.getFocus() || _cycle.getAttribute(FIELD_FOCUS_ATTRIBUTE) != null)
             return;
-
-        _pageRenderSupport.addInitializationScript("Tapestry.set_focus('" + fieldId + "');");
-
+        
+        _pageRenderSupport.addInitializationScript(_form, "tapestry.form.focusField('" + fieldId + "');");
         _cycle.setAttribute(FIELD_FOCUS_ATTRIBUTE, Boolean.TRUE);
+        
+        // register the validation profile with client side form manager
+        
+        if (_form.isClientValidationEnabled()) {
+            _pageRenderSupport.addInitializationScript(_form, "tapestry.form.registerProfile('" + formId + "'," 
+                    + _profile.toString() + ");");
+        }
     }
 
     /**
@@ -545,10 +556,10 @@
         if (_pageRenderSupport == null)
             return;
         
-        _pageRenderSupport.addInitializationScript("dojo.require(\"tapestry.form\");");
-        _pageRenderSupport.addInitializationScript("Tapestry.register_form('" + formId + "');");
+        _pageRenderSupport.addInitializationScript(_form, "dojo.require(\"tapestry.form\");"
+                + "tapestry.form.registerForm('" + formId + "');");
     }
-
+    
     public String rewind()
     {
         _form.getDelegate().clear();
@@ -746,4 +757,11 @@
         _delegate.registerForFocus(field, priority);
     }
 
+    /** 
+     * {@inheritDoc}
+     */
+    public JSONObject getProfile()
+    {
+        return _profile;
+    }
 }

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/PropertySelection.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/PropertySelection.java?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/PropertySelection.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/PropertySelection.java Sun Jun 11 18:56:16 2006
@@ -43,7 +43,6 @@
  * 
  * @author Howard Lewis Ship
  * @author Paul Ferraro
- * @author Jesse Kuhnert
  */
 public abstract class PropertySelection extends AbstractFormComponent 
     implements ValidatableField

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/validator/BaseValidator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/validator/BaseValidator.java?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/validator/BaseValidator.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/validator/BaseValidator.java Sun Jun 11 18:56:16 2006
@@ -19,6 +19,8 @@
 import org.apache.tapestry.IRequestCycle;
 import org.apache.tapestry.form.FormComponentContributorContext;
 import org.apache.tapestry.form.IFormComponent;
+import org.apache.tapestry.json.JSONArray;
+import org.apache.tapestry.json.JSONObject;
 
 /**
  * Abstract implementation of {@link org.apache.tapestry.form.validator.Validator}.
@@ -75,5 +77,43 @@
     public boolean isRequired()
     {
         return false;
+    }
+    
+    /**
+     * Utility method to store a field specific profile property which can later
+     * be used by client side validation. 
+     * 
+     * @param field
+     *          The field to store the property for, will key off of {@link IFormComponent#getClientId()}.
+     * @param profile
+     *          The profile for the form.
+     * @param key
+     *          The property key to store.
+     * @param property
+     *          The property to store.
+     */
+    public void setProfileProperty(IFormComponent field, JSONObject profile, 
+            String key, Object property)
+    {
+        if (!profile.has(field.getClientId())) 
+            profile.put(field.getClientId(), new JSONObject());
+        
+        JSONObject fieldProps = profile.getJSONObject(field.getClientId());
+        fieldProps.put(key, property);
+    }
+    
+    /**
+     * Utility used to append onto an existing property represented as an
+     * object array. 
+     * @param profile
+     * @param key
+     * @param value
+     */
+    public void accumulateProperty(JSONObject profile, String key, Object value)
+    {
+        if (!profile.has(key))
+            profile.put(key, new JSONArray());
+        
+        profile.accumulate(key, value);
     }
 }

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/validator/Required.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/validator/Required.java?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/validator/Required.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/form/validator/Required.java Sun Jun 11 18:56:16 2006
@@ -18,10 +18,10 @@
 
 import org.apache.tapestry.IMarkupWriter;
 import org.apache.tapestry.IRequestCycle;
-import org.apache.tapestry.TapestryUtils;
 import org.apache.tapestry.form.FormComponentContributorContext;
 import org.apache.tapestry.form.IFormComponent;
 import org.apache.tapestry.form.ValidationMessages;
+import org.apache.tapestry.json.JSONObject;
 import org.apache.tapestry.multipart.UploadPart;
 import org.apache.tapestry.valid.ValidationConstants;
 import org.apache.tapestry.valid.ValidationConstraint;
@@ -71,19 +71,18 @@
                 new Object[]
                 { field.getDisplayName() });
     }
-
+    
     public void renderContribution(IMarkupWriter writer, IRequestCycle cycle,
             FormComponentContributorContext context, IFormComponent field)
     {
         context.registerForFocus(ValidationConstants.REQUIRED_FIELD);
-
-        StringBuffer buffer = new StringBuffer("function(event) { Tapestry.require_field(event, '");
-        buffer.append(field.getClientId());
-        buffer.append("', ");
-        buffer.append(TapestryUtils.enquote(buildMessage(context, field)));
-        buffer.append("); }");
-
-        context.addSubmitHandler(buffer.toString());
+        
+        JSONObject profile = context.getProfile();
+        
+        accumulateProperty(profile, ValidationConstants.REQUIRED, field.getClientId());
+        
+        setProfileProperty(field, profile, 
+                ValidationConstants.REQUIRED, buildMessage(context, field));
     }
 
     /**

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/valid/ValidationConstants.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/valid/ValidationConstants.java?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/valid/ValidationConstants.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/valid/ValidationConstants.java Sun Jun 11 18:56:16 2006
@@ -21,7 +21,7 @@
  * @author Howard Lewis Ship
  * @since 4.0
  */
-public class ValidationConstants
+public final class ValidationConstants
 {
     
     public static final int NORMAL_FIELD = 1;
@@ -29,4 +29,8 @@
     public static final int REQUIRED_FIELD = 2;
     
     public static final int ERROR_FIELD = 3;
+    
+    public static final String REQUIRED = "required";
+    
+    public static final String REQUIRED_MESSAGE = "required-message";
 }

Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/valid/ValidationDelegate.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/valid/ValidationDelegate.java?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/valid/ValidationDelegate.java (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/valid/ValidationDelegate.java Sun Jun 11 18:56:16 2006
@@ -28,7 +28,7 @@
 import org.apache.tapestry.form.IFormComponent;
 
 /**
- * A base implementation of {@link IValidationDelegate}that can be used as a
+ * A base implementation of {@link IValidationDelegate} that can be used as a
  * managed bean. This class is often subclassed, typically to override
  * presentation details.
  * 

Modified: tapestry/tapestry4/trunk/framework/src/js/tapestry/__package__.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/tapestry/__package__.js?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/tapestry/__package__.js (original)
+++ tapestry/tapestry4/trunk/framework/src/js/tapestry/__package__.js Sun Jun 11 18:56:16 2006
@@ -2,6 +2,6 @@
 	common: [
 		"tapestry.core","tapestry.event"
 	],
-	browser: ["tapestry.html","tapestry.form"]
+	browser: ["tapestry.html"]
 });
 dojo.provide("tapestry.*");

Modified: tapestry/tapestry4/trunk/framework/src/js/tapestry/form.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/tapestry/form.js?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/tapestry/form.js (original)
+++ tapestry/tapestry4/trunk/framework/src/js/tapestry/form.js Sun Jun 11 18:56:16 2006
@@ -1,5 +1,8 @@
 dojo.provide("tapestry.form");
 
+dojo.require("dojo.event");
+dojo.require("dojo.event.browser");
+
 dojo.require("tapestry.core");
 
 /**
@@ -9,6 +12,8 @@
  */
 tapestry.form={
 	
+	forms:{}, // registered form references
+	
 	/**
 	 * Generically displays a window alert for the 
 	 * given field when in error.
@@ -99,6 +104,11 @@
 		}
 	},
 	
+	/**
+	 * Registers the form with the local <code>forms</code> property so 
+	 * that there is a central reference of all tapestry forms.
+	 * @param id The form(form id) to register.
+	 */
 	registerForm:function(id){
 		var form=dojo.byId(id);
 		if (!form) {
@@ -106,7 +116,73 @@
 			return;
 		}
 		
-		dojo.log.warn("registerForm() not implemented yet.");
+		if (!this.forms[id]) {
+			this.forms[id]={};
+			this.forms[id].validateForm=true;
+			this.forms[id].profiles=[];
+			
+			dojo.event.connect(form, "onsubmit", this, "onFormSubmit");
+		} else {
+			dojo.log.warn("registerForm(" + id + ") Form already registered.");
+		}
+	},
+	
+	/**
+	 * 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 {@link dojo.validate.check(form, profile)}.
+	 * 
+	 * @param id The form(form id) to register profile with.
+	 * @param 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);
+	},
+
+	/**
+	 * 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.
+	 * 
+	 * @param formId The id of the form to turn validation on/off for.
+	 * @param validate Boolean for whether or not to validate form, if
+	 * 				   not specified assumes true.
+	 */
+	setFormValidating:function(formId, validate){
+		if (this.forms[id]){
+			this.forms[id].validateForm = validate ? true : false;
+		}
+	},
+	
+	/**
+	 * Event connected function that is invoked when a form
+	 * is submitted.
+	 */
+	onFormSubmit:function(evt){
+		if (!evt || !evt.target) {
+			dojo.raise("No target for form event." + evt);
+			return;
+		}
+		
+		var id=evt.target.getAttribute("id");
+		if (!id) return;
+		
+		if (!tapestry.form.validation.validateForm(evt.target, this.forms[id])) {
+			dojo.event.browser.stopEvent(evt);
+			dojo.log.info("Stopped form submission, invalid input.");
+		}
 	},
 	
 	/**
@@ -165,4 +241,5 @@
 	}
 }
 
+dojo.require("tapestry.form.validation");
 dojo.require("tapestry.form_compat");

Added: tapestry/tapestry4/trunk/framework/src/js/tapestry/form/__package__.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/tapestry/form/__package__.js?rev=413562&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/tapestry/form/__package__.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/tapestry/form/__package__.js Sun Jun 11 18:56:16 2006
@@ -0,0 +1,6 @@
+dojo.kwCompoundRequire({
+	browser: [
+		"tapestry.form.validation"
+	]
+});
+dojo.provide("tapestry.form.*");
\ No newline at end of file

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

Added: tapestry/tapestry4/trunk/framework/src/js/tapestry/form/validation.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/tapestry/form/validation.js?rev=413562&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/tapestry/form/validation.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/tapestry/form/validation.js Sun Jun 11 18:56:16 2006
@@ -0,0 +1,114 @@
+dojo.provide("tapestry.form.validation");
+
+dojo.require("dojo.validate.check");
+dojo.require("dojo.html");
+
+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
+	
+	/**
+	 * 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 (!form) return false;
+		if (!props) return true; // form exists but no profile? just submit I guess..
+		if (!props.validateForm) return true;
+		
+		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])) {
+				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;
+		}
+		
+		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){
+		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){
+		dojo.html.removeClass(field, this.missingClass);
+		
+		if (!dojo.html.hasClass(field, this.invalidClass)){
+			dojo.html.prependClass(field, this.invalidClass);
+		}
+	}
+}
\ No newline at end of file

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

Modified: tapestry/tapestry4/trunk/framework/src/js/tapestry/test.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/tapestry/test.js?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/tapestry/test.js (original)
+++ tapestry/tapestry4/trunk/framework/src/js/tapestry/test.js Sun Jun 11 18:56:16 2006
@@ -1,5 +1,8 @@
 dojo.provide("tapestry.test");
 
+// override to make sure our fake events pass
+dojo.event.browser.isEvent=function() { return true; }
+
 if (dj_undef("byId", dj_global)) {
 dojo.byId = function(id, doc){
 	if(id && (typeof id == "string" || id instanceof String)){

Modified: tapestry/tapestry4/trunk/framework/src/js/tests/test_event.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/tests/test_event.js?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/tests/test_event.js (original)
+++ tapestry/tapestry4/trunk/framework/src/js/tests/test_event.js Sun Jun 11 18:56:16 2006
@@ -3,9 +3,6 @@
 dojo.require("tapestry.*");
 dojo.require("tapestry.test");
 
-// override to make sure our fake events pass
-dojo.event.browser.isEvent=function() { return true; }
-
 function test_eventCapture_props(){
 	var fevent=document.createEvent('UIEvents');
 	fevent.type="testType";

Modified: tapestry/tapestry4/trunk/framework/src/js/tests/test_form.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/tests/test_form.js?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/tests/test_form.js (original)
+++ tapestry/tapestry4/trunk/framework/src/js/tests/test_form.js Sun Jun 11 18:56:16 2006
@@ -4,9 +4,6 @@
 dojo.require("tapestry.test");
 dojo.require("tapestry.form");
 
-// override to make sure our fake events pass
-dojo.event.browser.isEvent=function() { return true; }
-
 tapestry.form.invalidField=function(field, message){
 }
 

Added: tapestry/tapestry4/trunk/framework/src/js/tests/test_form_validation.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/tests/test_form_validation.js?rev=413562&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/tests/test_form_validation.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/tests/test_form_validation.js Sun Jun 11 18:56:16 2006
@@ -0,0 +1,29 @@
+dojo.setModulePrefix("tapestry", "../tapestry");
+
+dojo.require("tapestry.*");
+dojo.require("tapestry.test");
+dojo.require("tapestry.form");
+dojo.require("dojo.lang.*");
+
+function test_register_invalidform(){
+	try {
+		tapestry.form.registerForm("bsid");
+		throw new JUMAssertFailure("Previous test should have failed.");
+	} catch (e) { 
+		jum.assertTrue("testFormRegisterInvalid", e instanceof Error); 
+	}
+}
+
+function test_register_form(){
+	var form = document.createElement("form");
+	form.setAttribute("id", "regform");
+	form.submit=function(){
+		form.submitCalled=true;
+	}
+	form.submitname={value:""};
+	
+	tapestry.form.registerForm("regform");
+	jum.assertTrue("formregForm", dojo.lang.isObject(tapestry.form.forms["regform"]));
+	jum.assertTrue("formregProfiles", dojo.lang.isArray(tapestry.form.forms["regform"].profiles));
+	jum.assertEquals("formregProfileLength", 0, tapestry.form.forms["regform"].profiles.length);
+}

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

Modified: tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/form/MockForm.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/form/MockForm.java?rev=413562&r1=413561&r2=413562&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/form/MockForm.java (original)
+++ tapestry/tapestry4/trunk/framework/src/test/org/apache/tapestry/form/MockForm.java Sun Jun 11 18:56:16 2006
@@ -33,6 +33,7 @@
 import org.apache.tapestry.IRender;
 import org.apache.tapestry.IRequestCycle;
 import org.apache.tapestry.engine.IPageLoader;
+import org.apache.tapestry.json.JSONObject;
 import org.apache.tapestry.listener.ListenerMap;
 import org.apache.tapestry.services.impl.ComponentEventInvoker;
 import org.apache.tapestry.spec.IComponentSpecification;
@@ -57,6 +58,8 @@
 
     private boolean _focus = true;
 
+    private JSONObject _profile = new JSONObject();
+    
     public MockForm()
     {
         this(null, null);
@@ -368,5 +371,13 @@
      */
     public void setEventInvoker(ComponentEventInvoker invoker)
     {
+    }
+
+    /** 
+     * {@inheritDoc}
+     */
+    public JSONObject getProfile()
+    {
+        return _profile;
     }
 }