You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2005/06/17 18:52:20 UTC

cvs commit: jakarta-tapestry/framework/src/java/org/apache/tapestry/valid IValidationDelegate.java

hlship      2005/06/17 09:52:19

  Modified:    .        status.xml
               framework/src/documentation/content/xdocs/tapestry/ComponentReference
                        Form.xml
               framework/src/java/org/apache/tapestry/form
                        FormSupportImpl.java Form.java Form.jwc
               framework/src/test/org/apache/tapestry/form
                        TestFormSupport.java
               framework/src/java/org/apache/tapestry/wml Go.jwc Go.java
               src/documentation/content/xdocs index.xml
               framework/src/java/org/apache/tapestry FormBehavior.java
               framework/src/java/org/apache/tapestry/valid
                        IValidationDelegate.java
  Added:       framework/src/java/org/apache/tapestry/form FormSupport.java
                        FormConstants.java
               framework/src/test/org/apache/tapestry/form TestForm.java
  Removed:     framework/src/java/org/apache/tapestry FormSupport.java
  Log:
  Add cancel and refresh listener parameters to Form.
  
  Revision  Changes    Path
  1.135     +1 -0      jakarta-tapestry/status.xml
  
  Index: status.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/status.xml,v
  retrieving revision 1.134
  retrieving revision 1.135
  diff -u -r1.134 -r1.135
  --- status.xml	16 Jun 2005 20:57:10 -0000	1.134
  +++ status.xml	17 Jun 2005 16:52:19 -0000	1.135
  @@ -83,6 +83,7 @@
          <action type="add" dev="PF">Refactored and expanded validation functionality to include DatePicker, PropertySelection, RadioGroup, Select, TextArea, TextField, Upload, contrib:Palette, and contrib:MultiplePropertySelection.</action>		
          <action type="update" dev="HLS">Rework form event management to be primarily a client-side concern.</action>
          <action type="add" dev="HLS">Add translator binding prefix.</action>
  +       <action type="add" dev="HLS">Add cancel and refresh listener parameters to Form.</action>
       </release>
       <release version="4.0-alpha-3" date="May 16 2005">
         <action type="add" dev="HLS">Add initial support for the validator: binding prefix.</action>
  
  
  
  1.3       +89 -9     jakarta-tapestry/framework/src/documentation/content/xdocs/tapestry/ComponentReference/Form.xml
  
  Index: Form.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/documentation/content/xdocs/tapestry/ComponentReference/Form.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Form.xml	6 Jan 2005 02:17:15 -0000	1.2
  +++ Form.xml	17 Jun 2005 16:52:19 -0000	1.3
  @@ -28,11 +28,17 @@
     
     <body>
   
  -<p> <strong>THIS PAGE UNDER CONSTRUCTION</strong>
  +<p> A Form component must enclose the other form element components (such as &TextField; and &Checkbox;).
  +  It manages the rendering of the form as well as processing when the form is submitted
  +  (known as "rewinding" the form).  In traditional web applications, the developer is responsible
  +  for providing a name for each form and each form control element; in Tapestry, the Form component
  +  generates its own unique name, and unique names for each enclosed component ... this is necessary
  +  to support advanced features such as loops within forms.
   </p>
   
   <p>
  -  <strong>See also:</strong> 
  +  <strong>See also: <link href="&apiroot;/form/Form.html">org.apache.tapestry.form.Form</link>,
  +    &IValidationDelegate;</strong> 
   </p>
   
   <section>
  @@ -45,28 +51,102 @@
   	  <th>Direction</th>
       <th>Required</th> 
       <th>Default</th>
  +    <th>Default Binding</th>
       <th>Description</th>
     </tr>
  +  
  +  <tr>
  +    <td>method</td> <td>string</td> <td>in</td> <td>no</td> <td>post</td> <td>literal</td>
  +      <td>Method used by the form when it is submitted.</td>
  +  </tr>
  +
  +  <tr>
  +    <td>listener</td> <td>&IActionListener;</td> <td>in</td> <td>no</td>
  +    <td/> <td>listener</td>
  +    <td>Default listener to be invoked when the form is submitted. Invoked
  +      after the form has rewond (all enclosed components have read query parameters
  +      and updated server-side properties), and after any listeners related
  +      to submit components (&Submit;, &ImageSubmit;, etc.) have been invoked.</td>
  +  </tr>
  +  
  +  <tr>
  +    <td>cancel</td> <td>&IActionListener;</td> <td>in</td> <td>no</td>
  +    <td/> <td>listener</td>
  +    <td>Listener used when a form is cancelled, overriding the default listener. Forms
  +      are cancelled by invoking the client-side JavaScript function
  +      document.<em>form-name</em>.events.cancel().  A cancelled form <em>does not</em> rewind.
  +      If no cancel listener is provided, then the normal listener will be used.</td>
  +  </tr>
  +  
  +  <tr>
  +    <td>refresh</td>  <td>&IActionListener;</td> <td>in</td> <td>no</td>
  +    <td/> <td>listener</td>
  +    <td>
  +      Listener used when a form is refreshed, overriding the default listener.  A refreshed form bypasses
  +      input field validation  on the client side, though validation still
  +      occurs on the server side. If no refresh listener is provided, then the normal listener
  +      will be used.
  +    </td>
  +  </tr>
  +  
  +  <tr>
  +    <td>stateful</td> <td>boolean</td> <td>in</td> <td>no</td> <td>true</td> <td>ognl</td>
  +    <td>
  +     If true (the default), then an active session is required when the
  +        form is submitted, if there was an active session when the
  +        form was rendered.
  +    </td>
  +  </tr>
  +  
  +  <tr>
  +    <td>direct</td> <td>boolean</td> <td>in</td> <td>no</td> <td>true</td> <td>ognl</td>
  +    <td>    If true (the default), then the more efficient direct service is used.
  +    If false, then the action service is used.  The action service requires
  +    rewinding of the entire page, and is rarely (if ever) used.</td>
  +  </tr>
  +  
  +  <tr>
  +    <td>delegate</td> <td>&IValidationDelegate;</td> <td>in</td> <td>no</td>
  +    <td>default instance</td>
  +    <td>ognl</td>
  +    <td>
  +      An object that tracks user input and input field errors, and decorates
  +      fields and field labels. This is typically overriden to provide
  +      an application-specific look and feel.
  +    </td>
  +  </tr>
  +  
  +  <tr>
  +    <td>clientValidationEnabled</td>
  +    <td>boolean</td> <td>in</td> <td>no</td> <td>false</td> <td>ognl</td>
  +    <td>
  +      If true, then client-side validation will be enabled for components 
  +      that support it (such as &TextField;). 
  +    </td>
  +  </tr>
   
   	</table>
     
  +  
   <p>
  -  Body: <strong>removed / allowed</strong>
  +  Body: <strong>allowed</strong>
   </p>  
   
   <p>
  -  Informal parameters: <strong>allowed  / forbidden</strong>
  +  Informal parameters: <strong>allowed</strong>
   </p>
   
   <p>
  -  Reserved parameters: <em>none</em>
  +  Reserved parameters: action, enctype, name, onsubmit, onreset
   </p>
   
  -</section>
  -
  -<section>
  -  <title>Examples</title>
  +<p>
  +A note about clientValidationEnabled: This refers to the revamped input validation support 
  +that debuts in Tapestry 4.0.  The older validation system, centered around the &ValidField; component,
  +still requires that clientScriptingEnabled be set on individual &IValidators;.
  +</p>
   
   </section>
  +
   </body>
   </document>
  \ No newline at end of file
  
  
  
  1.9       +31 -4     jakarta-tapestry/framework/src/java/org/apache/tapestry/form/FormSupportImpl.java
  
  Index: FormSupportImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/form/FormSupportImpl.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- FormSupportImpl.java	17 Jun 2005 13:28:01 -0000	1.8
  +++ FormSupportImpl.java	17 Jun 2005 16:52:19 -0000	1.9
  @@ -30,7 +30,6 @@
   import org.apache.hivemind.Resource;
   import org.apache.hivemind.util.ClasspathResource;
   import org.apache.hivemind.util.Defense;
  -import org.apache.tapestry.FormSupport;
   import org.apache.tapestry.IComponent;
   import org.apache.tapestry.IForm;
   import org.apache.tapestry.IMarkupWriter;
  @@ -92,6 +91,18 @@
           _standardReservedIds = Collections.unmodifiableSet(set);
       }
   
  +    private final static Set _submitModes;
  +
  +    static
  +    {
  +        Set set = new HashSet();
  +        set.add(FormConstants.SUBMIT_CANCEL);
  +        set.add(FormConstants.SUBMIT_NORMAL);
  +        set.add(FormConstants.SUBMIT_REFRESH);
  +
  +        _submitModes = Collections.unmodifiableSet(set);
  +    }
  +
       /**
        * Used when rewinding the form to figure to match allocated ids (allocated during the rewind)
        * against expected ids (allocated in the previous request cycle, when the form was rendered).
  @@ -487,12 +498,19 @@
           return eventManager;
       }
   
  -    public void rewind()
  +    public String rewind()
       {
  -        reinitializeIdAllocatorForRewind();
  -
           _form.getDelegate().clear();
   
  +        String mode = _cycle.getParameter(SUBMIT_MODE);
  +
  +        // On a cancel, don't bother rendering the body or anything else at all.
  +
  +        if (FormConstants.SUBMIT_CANCEL.equals(mode))
  +            return mode;
  +
  +        reinitializeIdAllocatorForRewind();
  +
           _form.renderBody(_writer, _cycle);
   
           int expected = _allocatedIds.size();
  @@ -510,6 +528,15 @@
           }
   
           runDeferredRunnables();
  +
  +        if (_submitModes.contains(mode))
  +            return mode;
  +
  +        // Either something wacky on the client side, or a client without
  +        // javascript enabled.
  +
  +        return FormConstants.SUBMIT_NORMAL;
  +
       }
   
       private void runDeferredRunnables()
  
  
  
  1.19      +33 -3     jakarta-tapestry/framework/src/java/org/apache/tapestry/form/Form.java
  
  Index: Form.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/form/Form.java,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- Form.java	15 May 2005 22:56:36 -0000	1.18
  +++ Form.java	17 Jun 2005 16:52:19 -0000	1.19
  @@ -17,7 +17,6 @@
   import org.apache.hivemind.ApplicationRuntimeException;
   import org.apache.hivemind.Location;
   import org.apache.tapestry.AbstractComponent;
  -import org.apache.tapestry.FormSupport;
   import org.apache.tapestry.IActionListener;
   import org.apache.tapestry.IComponent;
   import org.apache.tapestry.IDirect;
  @@ -53,6 +52,10 @@
    * Starting in release 1.0.2, a Form can use either the direct service or the action service. The
    * default is the direct service, even though in earlier releases, only the action service was
    * available.
  + * <p>
  + * Release 4.0 adds two new listener, {@link #getCancel()} and {@link #getRefresh()} and
  + * corresponding client-side behavior to force a form to refresh (update, bypassing input field
  + * validation) or cancel (update immediately).
    * 
    * @author Howard Lewis Ship, David Solis
    */
  @@ -220,9 +223,11 @@
   
           if (isRewinding())
           {
  -            _formSupport.rewind();
  +            String submitType = _formSupport.rewind();
  +
  +            IActionListener listener = findListener(submitType);
   
  -            getListenerInvoker().invokeListener(getListener(), this, cycle);
  +            getListenerInvoker().invokeListener(listener, this, cycle);
   
               // Abort the rewind render.
   
  @@ -245,6 +250,25 @@
           _formSupport.render(getMethod(), _renderInformalParameters, link);
       }
   
  +    IActionListener findListener(String mode)
  +    {
  +        IActionListener result = null;
  +
  +        if (mode.equals(FormConstants.SUBMIT_CANCEL))
  +            result = getCancel();
  +        else if (mode.equals(FormConstants.SUBMIT_REFRESH))
  +            result = getRefresh();
  +
  +        // If not cancel or refresh, or the corresponding listener
  +        // is itself null, then use the default listener
  +        // (which may be null as well!).
  +
  +        if (result == null)
  +            result = getListener();
  +
  +        return result;
  +    }
  +
       /**
        * Construct a form name for use with the action service. This implementation returns "Form"
        * appended with the actionId.
  @@ -346,6 +370,12 @@
       /** listener parameter, may be null */
       public abstract IActionListener getListener();
   
  +    /** cancel parameter, may be null */
  +    public abstract IActionListener getCancel();
  +
  +    /** refresh parameter, may be null */
  +    public abstract IActionListener getRefresh();
  +
       /** method parameter */
       public abstract String getMethod();
   
  
  
  
  1.13      +20 -1     jakarta-tapestry/framework/src/java/org/apache/tapestry/form/Form.jwc
  
  Index: Form.jwc
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/form/Form.jwc,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- Form.jwc	6 Jun 2005 18:48:41 -0000	1.12
  +++ Form.jwc	17 Jun 2005 16:52:19 -0000	1.13
  @@ -31,7 +31,7 @@
     
     <parameter name="method" default-value="post" default-binding="literal">
       <description>
  -    The method used by the form when it is submitted, defaults to POST.
  +    The method used by the form when it is submitted, defaults to "post".
       </description>
     </parameter>
     
  @@ -42,6 +42,22 @@
       </description>
     </parameter>
     
  +  <parameter name="cancel" default-binding="listener">
  +      <description>
  +          Object invoked when the form is cancelled (a special type of form submission).
  +          The cancel listener (if any) overrides the standard listener. Other properties
  +          will not be affected by the rewind.
  +       </description>
  +   </parameter>
  +  
  +  <parameter name="refresh" default-binding="listener">
  +      <description>
  +          Object invoked when the form is refreshed (a special type of form submission).
  +          The refresh listener (if any) overrides the standard listener.
  +          Other properties managed by enclosed components will be updated.
  +      </description>
  +  </parameter>
  +  
     <parameter name="stateful" default-value="true" default-binding="ognl">
       <description>
       If true (the default), then an active session is required when the
  @@ -73,6 +89,9 @@
     
     <reserved-parameter name="action"/>
     <reserved-parameter name="name"/>
  +  <reserved-parameter name="onsubmit"/>
  +  <reserved-parameter name="onreset"/>
  +  <reserved-parameter name="enctype"/>
     
     <inject property="directService" object="engine-service:direct"/>
     <inject property="actionService" object="engine-service:action"/>
  
  
  
  1.1                  jakarta-tapestry/framework/src/java/org/apache/tapestry/form/FormSupport.java
  
  Index: FormSupport.java
  ===================================================================
  // Copyright 2005 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.form;
  
  import org.apache.tapestry.FormBehavior;
  import org.apache.tapestry.IRender;
  import org.apache.tapestry.engine.ILink;
  
  /**
   * Interface for a utility object that encapsulates the majority of the
   * {@link org.apache.tapestry.form.Form}'s behavior.
   * 
   * @author Howard M. Lewis Ship
   * @since 4.0
   */
  public interface FormSupport extends FormBehavior
  {
  
      /**
       * Invoked when the form is rendering. This should only be invoked by the {@link Form}
       * component.
       * 
       * @param method
       *            the HTTP method ("get" or "post")
       * @param informalParametersRenderer
       *            object that will render informal parameters
       * @param link
       *            The link to which the form will submit (encapsulating the URL and the query
       *            parameters)
       */
      public void render(String method, IRender informalParametersRenderer, ILink link);
  
      /**
       * Invoked to rewind the form, which renders the body of the form, allowing form element
       * components to pull data from the request and update page properties. This should only be
       * invoked by the {@link Form} component.
       * 
       * @return a code indicating why the form was submitted: {@link FormConstants#SUBMIT_NORMAL},
       *         {@link FormConstants#SUBMIT_CANCEL} or {@link FormConstants#SUBMIT_REFRESH}.
       */
      public String rewind();
  }
  
  
  1.1                  jakarta-tapestry/framework/src/java/org/apache/tapestry/form/FormConstants.java
  
  Index: FormConstants.java
  ===================================================================
  // Copyright 2005 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.form;
  
  /**
   * Constants used by the Form component.
   * 
   * @author Howard Lewis Ship
   * @since 4.0
   */
  public class FormConstants
  {
      /**
       * Normal submit of the form, typically by the user clicking a submit control.
       */
  
      public static final String SUBMIT_NORMAL = "submit";
  
      /**
       * Indicates that the form was cancelled. A form is cancelled on the client side when the
       * JavaScript function document.<em>form-name</em>.events.cancel() is invoked.
       */
  
      public static final String SUBMIT_CANCEL = "cancel";
  
      /**
       * Indicates that the form was submitted to force a refresh. Most client-side submit listeners
       * will have been skipped (particularily, those related to validaton). A form is submitted for
       * refresh on the client side when the JavaScript function document.<em>form-name</em>.events.refresh()
       * is invoked.
       */
      public static final String SUBMIT_REFRESH = "refresh";
  }
  
  
  
  1.9       +123 -19   jakarta-tapestry/framework/src/test/org/apache/tapestry/form/TestFormSupport.java
  
  Index: TestFormSupport.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/test/org/apache/tapestry/form/TestFormSupport.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- TestFormSupport.java	17 Jun 2005 13:28:01 -0000	1.8
  +++ TestFormSupport.java	17 Jun 2005 16:52:19 -0000	1.9
  @@ -18,7 +18,6 @@
   import org.apache.hivemind.Location;
   import org.apache.hivemind.test.HiveMindTestCase;
   import org.apache.hivemind.util.ClasspathResource;
  -import org.apache.tapestry.FormSupport;
   import org.apache.tapestry.IEngine;
   import org.apache.tapestry.IMarkupWriter;
   import org.apache.tapestry.IRender;
  @@ -246,7 +245,7 @@
   
           replayControls();
   
  -        fs.rewind();
  +        assertEquals(FormConstants.SUBMIT_NORMAL, fs.rewind());
   
           verifyControls();
       }
  @@ -335,7 +334,7 @@
           trainHidden(writer, "formids", "");
           trainHidden(writer, "service", "fred");
           trainHidden(writer, "submitmode", "");
  -        
  +
           nested.close();
   
           writer.end();
  @@ -434,7 +433,7 @@
           trainHidden(writer, "formids", "");
           trainHidden(writer, "service", "fred");
           trainHidden(writer, "submitmode", "");
  -        
  +
           nested.close();
   
           writer.end();
  @@ -709,7 +708,7 @@
           trainHidden(writer, "action", "fred");
           trainHidden(writer, "reservedids", "action");
           trainHidden(writer, "submitmode", "");
  -        
  +
           nested.close();
   
           writer.end();
  @@ -804,7 +803,7 @@
           trainHidden(writer, "formids", "");
           trainHidden(writer, "service", "fred");
           trainHidden(writer, "submitmode", "");
  -        
  +
           nested.close();
   
           writer.end();
  @@ -861,7 +860,7 @@
   
           replayControls();
   
  -        fs.rewind();
  +        assertEquals(FormConstants.SUBMIT_NORMAL, fs.rewind());
   
           verifyControls();
       }
  @@ -1146,7 +1145,7 @@
           trainHidden(writer, "formids", "barney");
           trainHidden(writer, "service", "fred");
           trainHidden(writer, "submitmode", "");
  -        
  +
           nested.close();
   
           writer.end();
  @@ -1158,7 +1157,7 @@
           verifyControls();
       }
   
  -public void testSimpleRenderWithDeferredRunnable()
  +    public void testSimpleRenderWithDeferredRunnable()
       {
           MockControl writerc = newControl(IMarkupWriter.class);
           IMarkupWriter writer = (IMarkupWriter) writerc.getMock();
  @@ -1221,7 +1220,7 @@
   
           support.addExternalScript(new ClasspathResource(getClassResolver(),
                   "/org/apache/tapestry/form/Form.js"));
  -        
  +
           support
                   .addInitializationScript("var myform_events = new FormEventManager(document.myform);");
   
  @@ -1252,7 +1251,7 @@
           trainHidden(writer, "formids", "");
           trainHidden(writer, "service", "fred");
           trainHidden(writer, "submitmode", "");
  -        
  +
           // EasyMock can't fully verify that this gets called at the right moment, nor can we truly
           // prove (well, except by looking at the code), that the deferred runnables execute at the
           // right time.
  @@ -1268,7 +1267,9 @@
           fs.render("post", render, link);
   
           verifyControls();
  -    }    public void testSimpleRewind()
  +    }
  +
  +    public void testSimpleRewind()
       {
           IMarkupWriter writer = newWriter();
   
  @@ -1309,7 +1310,99 @@
   
           replayControls();
   
  -        fs.rewind();
  +        assertEquals(FormConstants.SUBMIT_NORMAL, fs.rewind());
  +
  +        verifyControls();
  +    }
  +
  +    public void testRefreshRewind()
  +    {
  +        IMarkupWriter writer = newWriter();
  +
  +        MockControl cyclec = newControl(IRequestCycle.class);
  +        IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
  +
  +        IValidationDelegate delegate = newDelegate();
  +
  +        MockControl enginec = newControl(IEngine.class);
  +        IEngine engine = (IEngine) enginec.getMock();
  +
  +        MockForm form = new MockForm(delegate);
  +
  +        cycle.isRewound(form);
  +        cyclec.setReturnValue(true);
  +
  +        cycle.getEngine();
  +        cyclec.setReturnValue(engine);
  +
  +        engine.getClassResolver();
  +        enginec.setReturnValue(getClassResolver());
  +
  +        replayControls();
  +
  +        final FormSupport fs = new FormSupportImpl(writer, cycle, form);
  +
  +        verifyControls();
  +
  +        delegate.clear();
  +
  +        trainCycleForRewind(cyclec, cycle, "refresh", "barney", null);
  +
  +        final IFormComponent component = newFormComponent("barney", "barney");
  +
  +        IRender body = newComponentRenderBody(fs, component, writer);
  +
  +        form.setBody(body);
  +
  +        replayControls();
  +
  +        assertEquals(FormConstants.SUBMIT_REFRESH, fs.rewind());
  +
  +        verifyControls();
  +    }
  +
  +    public void testCancelRewind()
  +    {
  +        IMarkupWriter writer = newWriter();
  +
  +        MockControl cyclec = newControl(IRequestCycle.class);
  +        IRequestCycle cycle = (IRequestCycle) cyclec.getMock();
  +
  +        IValidationDelegate delegate = newDelegate();
  +
  +        MockControl enginec = newControl(IEngine.class);
  +        IEngine engine = (IEngine) enginec.getMock();
  +
  +        MockForm form = new MockForm(delegate);
  +
  +        cycle.isRewound(form);
  +        cyclec.setReturnValue(true);
  +
  +        cycle.getEngine();
  +        cyclec.setReturnValue(engine);
  +
  +        engine.getClassResolver();
  +        enginec.setReturnValue(getClassResolver());
  +
  +        replayControls();
  +
  +        final FormSupport fs = new FormSupportImpl(writer, cycle, form);
  +
  +        verifyControls();
  +
  +        delegate.clear();
  +
  +        trainGetParameter(cyclec, cycle, FormSupportImpl.SUBMIT_MODE, "cancel");
  +
  +        // Create a body, just to provie it doesn't get invoked.
  +
  +        IRender body = (IRender) newMock(IRender.class);
  +
  +        form.setBody(body);
  +
  +        replayControls();
  +
  +        assertEquals(FormConstants.SUBMIT_CANCEL, fs.rewind());
   
           verifyControls();
       }
  @@ -1370,7 +1463,7 @@
   
           form.setBody(body);
   
  -        fs.rewind();
  +        assertEquals(FormConstants.SUBMIT_NORMAL, fs.rewind());
   
           verifyControls();
       }
  @@ -1457,7 +1550,7 @@
           trainHidden(writer, "formids", "");
           trainHidden(writer, "service", "fred");
           trainHidden(writer, "submitmode", "");
  -        
  +
           nested.close();
   
           writer.end();
  @@ -1476,11 +1569,22 @@
       private void trainCycleForRewind(MockControl cyclec, IRequestCycle cycle, String allocatedIds,
               String reservedIds)
       {
  -        cycle.getParameter(FormSupportImpl.FORM_IDS);
  -        cyclec.setReturnValue(allocatedIds);
  +        trainCycleForRewind(cyclec, cycle, "submit", allocatedIds, reservedIds);
  +    }
  +
  +    private void trainCycleForRewind(MockControl cyclec, IRequestCycle cycle, String submitMode,
  +            String allocatedIds, String reservedIds)
  +    {
  +        trainGetParameter(cyclec, cycle, FormSupportImpl.SUBMIT_MODE, submitMode);
  +        trainGetParameter(cyclec, cycle, FormSupportImpl.FORM_IDS, allocatedIds);
  +        trainGetParameter(cyclec, cycle, FormSupportImpl.RESERVED_FORM_IDS, reservedIds);
  +    }
   
  -        cycle.getParameter(FormSupportImpl.RESERVED_FORM_IDS);
  -        cyclec.setReturnValue(reservedIds);
  +    private void trainGetParameter(MockControl cyclec, IRequestCycle cycle, String parameterName,
  +            String value)
  +    {
  +        cycle.getParameter(parameterName);
  +        cyclec.setReturnValue(value);
       }
   
       private void trainForPageSupport(MockControl cyclec, IRequestCycle cycle, String initialization)
  
  
  
  1.1                  jakarta-tapestry/framework/src/test/org/apache/tapestry/form/TestForm.java
  
  Index: TestForm.java
  ===================================================================
  // Copyright 2005 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.form;
  
  import org.apache.tapestry.IActionListener;
  import org.apache.tapestry.components.BaseComponentTestCase;
  
  /**
   * Tests for {@link org.apache.tapestry.form.Form}. Most of the testing is, still alas, done with
   * mock objects.
   * 
   * @author Howard Lewis Ship
   * @since 4.0
   */
  public class TestForm extends BaseComponentTestCase
  {
      private IActionListener newListener()
      {
          return (IActionListener) newMock(IActionListener.class);
      }
  
      public void testFindCancelListener()
      {
          IActionListener cancel = newListener();
          IActionListener listener = newListener();
  
          replayControls();
  
          Form form = (Form) newInstance(Form.class, new Object[]
          { "listener", listener, "cancel", cancel });
  
          assertSame(cancel, form.findListener(FormConstants.SUBMIT_CANCEL));
  
          verifyControls();
      }
  
      public void testFindCancelDefaultListener()
      {
          IActionListener listener = newListener();
  
          replayControls();
  
          Form form = (Form) newInstance(Form.class, "listener", listener);
  
          assertSame(listener, form.findListener(FormConstants.SUBMIT_CANCEL));
  
          verifyControls();
      }
  
      public void testFindRefreshListener()
      {
          IActionListener refresh = newListener();
          IActionListener listener = newListener();
  
          replayControls();
  
          Form form = (Form) newInstance(Form.class, new Object[]
          { "listener", listener, "refresh", refresh });
  
          assertSame(refresh, form.findListener(FormConstants.SUBMIT_REFRESH));
  
          verifyControls();
      }
  
      public void testFindRefreshListenerDefault()
      {
          IActionListener listener = newListener();
  
          replayControls();
  
          Form form = (Form) newInstance(Form.class, new Object[]
          { "listener", listener });
  
          assertSame(listener, form.findListener(FormConstants.SUBMIT_REFRESH));
  
          verifyControls();
      }
  
      public void testFindListenerNormal()
      {
          IActionListener cancel = newListener();
          IActionListener refresh = newListener();
          IActionListener listener = newListener();
  
          replayControls();
  
          Form form = (Form) newInstance(Form.class, new Object[]
          { "listener", listener, "cancel", cancel, "refresh", refresh });
  
          assertSame(listener, form.findListener(FormConstants.SUBMIT_NORMAL));
  
          verifyControls();
      }
  }
  
  
  
  1.13      +16 -0     jakarta-tapestry/framework/src/java/org/apache/tapestry/wml/Go.jwc
  
  Index: Go.jwc
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/wml/Go.jwc,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- Go.jwc	15 May 2005 22:56:37 -0000	1.12
  +++ Go.jwc	17 Jun 2005 16:52:19 -0000	1.13
  @@ -39,6 +39,22 @@
               to the submission.
           </description>
       </parameter>
  +    
  +  <parameter name="cancel" default-binding="listener">
  +      <description>
  +          Object invoked when the form is cancelled (a special type of form submission).
  +          The oncancel listener (if any) overrides the standard listener. Other properties
  +          will not be affected by the rewind.
  +       </description>
  +   </parameter>
  +  
  +  <parameter name="refresh" default-binding="listener">
  +      <description>
  +          Object invoked when the form is refreshed (a special type of form submission).
  +          The onrefresh listener (if any) overrides the standard listener.
  +          Other properties managed by enclosed components will be updated.
  +      </description>
  +  </parameter>    
   
       <parameter name="stateful" default-value="true">
           <description>
  
  
  
  1.6       +1 -1      jakarta-tapestry/framework/src/java/org/apache/tapestry/wml/Go.java
  
  Index: Go.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/wml/Go.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- Go.java	3 May 2005 17:41:26 -0000	1.5
  +++ Go.java	17 Jun 2005 16:52:19 -0000	1.6
  @@ -14,10 +14,10 @@
   
   package org.apache.tapestry.wml;
   
  -import org.apache.tapestry.FormSupport;
   import org.apache.tapestry.IMarkupWriter;
   import org.apache.tapestry.IRequestCycle;
   import org.apache.tapestry.form.Form;
  +import org.apache.tapestry.form.FormSupport;
   
   /**
    * The go element declares a go task, indicating navigation to a URI. If the URI names a WML card or
  
  
  
  1.11      +83 -10    jakarta-tapestry/src/documentation/content/xdocs/index.xml
  
  Index: index.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/src/documentation/content/xdocs/index.xml,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- index.xml	16 Jun 2005 22:01:07 -0000	1.10
  +++ index.xml	17 Jun 2005 16:52:19 -0000	1.11
  @@ -75,29 +75,102 @@
   </p>
   
   <p>
  -Tapestry is distributed under the terms of the Apache Software License.
  +Tapestry is distributed under the terms of the Apache Software License. It can be freely used, shared and modified with minimal
  +constraints.
   </p>
   
   <section>
  -  <title>Status</title>
  +  <title>Tapestry 4.0</title>
     
   <p>
  -Work has begun on Tapestry 4.0, which is currently in a late alpha stage.  Documentation is being converted
  -from the old DocBook format, to the new Forrest format, leaving many temporary gaps. Only the framework and the contrib
  -library is being built, most example code is not.
  +Tapestry 4.0 is just overflowing with new features aimed at further enhancing 
  +your productivity. Here's a few of our favorites:
  +</p>  
  +
  +<ul>
  +  <li>
  +  The new 4.0 specification DTDs have been simplified.    
  +  </li>
  +  <li>
  +    The syntax used for binding parameters inside an HTML template and inside
  +    an XML specification is now consistent. Both make use of the binding prefixes.
  +  </li>
  +  <li>
  +    "Friendly" URLs (that is, URLs that pack more information into the path and less into query
  +    parameters) are built in. This makes it easy to divide your application across many folders (reducing
  +    clutter),
  +    and leverage J2EE declarative security along the way.
  +  </li>
  +  <li>
  +    Component parameters now <em>just work</em>, without having to worry about
  +    "direction". 
  +  </li>
  +  <li>
  +    Applications can now have a global message catalog, in addition to per-page and per-component
  +    message catalogs. Messages not found in the component message catalog are searched for in the 
  +    application catalog.
  +  </li>
  +  <li>
  +    Full, native support for <link href="tapestry-portlet/index.html">developing JSR-168 Portlets</link> has been added.
  +  </li>
  +  <li>
  +    Tapestry 4.0 makes much less use of reflection and &OGNL; than Tapestry 3.0; partly
  +    because there are many new <link href="UsersGuide/bindings.html">binding prefixes</link>.
  +  </li>
  +  <li>
  +   HiveMind services and &Spring; beans to be directly injected
  +    into page and component classes.
  +  </li>
  +  <li>
  +    Tapestry 4.0 includes optional <link href="tapestry-annotations/index.html">JDK 1.5 annotation support</link> 
  +    (but Tapestry still works with <link href="dependencies.html">JDK 1.3</link>).
  +  </li>
  +  <li>
  +    Tapestry 4.0 debuts a new and much more sophisticated user input validation subsystem.  Thanks Paul!
  +  </li>
  +  <li>
  +    Line precise error reporting can now display the contents of files containing errors.
  +  </li>
  +  <li>
  +    Forms can now be canceled, bypassing client-side validation logic, and invoking an  alternate
  +    listener on the server-side.
  +  </li>
  +  <li>
  +    You are no longer limited to just Global and Visit; you can have 
  +    <link href="UsersGuide/state.html#state.aso">application state objects</link> as you like.
  +  </li>
  +  <li>
  +    The use of &HiveMind; under the covers means that Tapestry can be easily customized to fit your needs.
  +  </li>
  +  <li>
  +    Page properties can now be persisted on the client, as well as in the session.
  +  </li>
  +</ul>
  +
  +<p>
  +The complete list of changes is almost too numerous to list.  Suffice to say, everything is about
  +getting more bang for less work, and reducing the amount of Java code, reducing the complexity
  +of templates, and simplifying (or eliminating) XML files.
   </p>
   
  +</section>
  +
  +<section>
  +  <title>Status</title>
  +  
   <p>
  -If you are using Tapestry in a production environment, it is recommended that you stick with Tapestry <strong>3.0.3</strong>,
  -the latest stable release.
  +Work on Tapestry 4.0 is in full swing.  Documentation is being converted
  +from the old DocBook format, to the new Forrest format, leaving many temporary gaps. Only the 
  +main code base and the Workbench example is being built, all other example code is not (this unfortunately
  +includes the Virtual Library).
   </p>
   
   <p>
  -Tapestry 4.0 now supports <link href="tapestry-annotations/index.html">JDK 1.5 annotations</link>, which can be used
  -as an alternative to the XML page and component specifcations (in some cases).
  +Tapestry 4.0 should be production-ready soon.  It needs more exposure and more documentation. For the
  +momement, it is still recommended that you stick with Tapestry <strong>3.0.3</strong>,
  +the latest stable release.
   </p>
     
  -  
   </section>
   
   <section>
  
  
  
  1.4       +1 -1      jakarta-tapestry/framework/src/java/org/apache/tapestry/FormBehavior.java
  
  Index: FormBehavior.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/FormBehavior.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- FormBehavior.java	16 Jun 2005 18:27:11 -0000	1.3
  +++ FormBehavior.java	17 Jun 2005 16:52:19 -0000	1.4
  @@ -21,7 +21,7 @@
   
   /**
    * Common interface extended by {@link org.apache.tapestry.IForm}&nbsp;and
  - * {@link org.apache.tapestry.FormSupport}.
  + * {@link org.apache.tapestry.form.FormSupport}.
    * 
    * @author Howard M. Lewis Ship
    * @since 4.0
  
  
  
  1.8       +1 -1      jakarta-tapestry/framework/src/java/org/apache/tapestry/valid/IValidationDelegate.java
  
  Index: IValidationDelegate.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/valid/IValidationDelegate.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- IValidationDelegate.java	21 May 2005 15:36:22 -0000	1.7
  +++ IValidationDelegate.java	17 Jun 2005 16:52:19 -0000	1.8
  @@ -54,7 +54,7 @@
    * {@link org.apache.tapestry.form.ListEdit}&nbsp;inside your form? Some of your components will
    * render multiple times. In this case you will have multiple <em>fields</em>. Each field will
    * have a unique field name (the
  - * {@link org.apache.tapestry.FormSupport#getElementId(IFormComponent) element id}, which you can
  + * {@link org.apache.tapestry.form.FormSupport#getElementId(IFormComponent) element id}, which you can
    * see this in the generated HTML). It is this field name that the delegate keys off of, which means
    * that some fields generated by a component may have errors and some may not, it all works fine
    * (with one exception).
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org