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 2009/12/11 07:57:00 UTC

svn commit: r889518 - /tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java

Author: hlship
Date: Fri Dec 11 06:56:59 2009
New Revision: 889518

URL: http://svn.apache.org/viewvc?rev=889518&view=rev
Log:
TAP5-796: Form component generates invalid xHtml: there should not be the "name" attribute

Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java?rev=889518&r1=889517&r2=889518&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java Fri Dec 11 06:56:59 2009
@@ -41,81 +41,103 @@
 import java.io.ObjectInputStream;
 
 /**
- * An HTML form, which will enclose other components to render out the various types of fields.
+ * An HTML form, which will enclose other components to render out the various
+ * types of fields.
  * <p/>
- * A Form emits many notification events. When it renders, it fires a {@link org.apache.tapestry5.EventConstants#PREPARE_FOR_RENDER}
- * notification, followed by a {@link org.apache.tapestry5.EventConstants#PREPARE} notification.
+ * A Form emits many notification events. When it renders, it fires a
+ * {@link org.apache.tapestry5.EventConstants#PREPARE_FOR_RENDER} notification,
+ * followed by a {@link org.apache.tapestry5.EventConstants#PREPARE}
+ * notification.
  * <p/>
- * When the form is submitted, the component emits several notifications: first a {@link
- * org.apache.tapestry5.EventConstants#PREPARE_FOR_SUBMIT}, then a {@link org.apache.tapestry5.EventConstants#PREPARE}:
- * these allow the page to update its state as necessary to prepare for the form submission, then (after components
- * enclosed by the form have operated), a {@link org.apache.tapestry5.EventConstants#VALIDATE_FORM} event is emitted, to
- * allow for cross-form validation. After that, either a {@link org.apache.tapestry5.EventConstants#SUCCESS} OR {@link
- * org.apache.tapestry5.EventConstants#FAILURE} event (depending on whether the {@link ValidationTracker} has recorded
- * any errors). Lastly, a {@link org.apache.tapestry5.EventConstants#SUBMIT} event, for any listeners that care only
- * about form submission, regardless of success or failure.
+ * When the form is submitted, the component emits several notifications: first
+ * a {@link org.apache.tapestry5.EventConstants#PREPARE_FOR_SUBMIT}, then a
+ * {@link org.apache.tapestry5.EventConstants#PREPARE}: these allow the page to
+ * update its state as necessary to prepare for the form submission, then (after
+ * components enclosed by the form have operated), a
+ * {@link org.apache.tapestry5.EventConstants#VALIDATE_FORM} event is emitted,
+ * to allow for cross-form validation. After that, either a
+ * {@link org.apache.tapestry5.EventConstants#SUCCESS} OR
+ * {@link org.apache.tapestry5.EventConstants#FAILURE} event (depending on
+ * whether the {@link ValidationTracker} has recorded any errors). Lastly, a
+ * {@link org.apache.tapestry5.EventConstants#SUBMIT} event, for any listeners
+ * that care only about form submission, regardless of success or failure.
  * <p/>
- * For all of these notifications, the event context is derived from the <strong>context</strong> parameter. This
- * context is encoded into the form's action URI (the parameter is not read when the form is submitted, instead the
+ * For all of these notifications, the event context is derived from the
+ * <strong>context</strong> parameter. This context is encoded into the form's
+ * action URI (the parameter is not read when the form is submitted, instead the
  * values encoded into the form are used).
  */
-@Events({ EventConstants.PREPARE_FOR_RENDER, EventConstants.PREPARE, EventConstants.PREPARE_FOR_SUBMIT,
-        EventConstants.VALIDATE_FORM,
-        EventConstants.SUBMIT, EventConstants.FAILURE, EventConstants.SUCCESS })
+@Events(
+{ EventConstants.PREPARE_FOR_RENDER, EventConstants.PREPARE, EventConstants.PREPARE_FOR_SUBMIT,
+        EventConstants.VALIDATE_FORM, EventConstants.SUBMIT, EventConstants.FAILURE,
+        EventConstants.SUCCESS })
 public class Form implements ClientElement, FormValidationControl
 {
     /**
-     * @deprecated Use constant from {@link org.apache.tapestry5.EventConstants} instead.
+     * @deprecated Use constant from {@link org.apache.tapestry5.EventConstants}
+     *             instead.
      */
     public static final String PREPARE_FOR_RENDER = EventConstants.PREPARE_FOR_RENDER;
 
     /**
-     * @deprecated Use constant from {@link org.apache.tapestry5.EventConstants} instead.
+     * @deprecated Use constant from {@link org.apache.tapestry5.EventConstants}
+     *             instead.
      */
     public static final String PREPARE_FOR_SUBMIT = EventConstants.PREPARE_FOR_SUBMIT;
 
     /**
-     * @deprecated Use constant from {@link org.apache.tapestry5.EventConstants} instead.
+     * @deprecated Use constant from {@link org.apache.tapestry5.EventConstants}
+     *             instead.
      */
     public static final String PREPARE = EventConstants.PREPARE;
 
     /**
-     * @deprecated Use constant from {@link org.apache.tapestry5.EventConstants} instead.
+     * @deprecated Use constant from {@link org.apache.tapestry5.EventConstants}
+     *             instead.
      */
     public static final String SUBMIT = EventConstants.SUBMIT;
 
     /**
-     * @deprecated Use constant from {@link org.apache.tapestry5.EventConstants} instead.
+     * @deprecated Use constant from {@link org.apache.tapestry5.EventConstants}
+     *             instead.
      */
     public static final String VALIDATE_FORM = EventConstants.VALIDATE_FORM;
 
     /**
-     * @deprecated Use constant from {@link org.apache.tapestry5.EventConstants} instead.
+     * @deprecated Use constant from {@link org.apache.tapestry5.EventConstants}
+     *             instead.
      */
     public static final String SUCCESS = EventConstants.SUCCESS;
 
     /**
-     * @deprecated Use constant from {@link org.apache.tapestry5.EventConstants} instead.
+     * @deprecated Use constant from {@link org.apache.tapestry5.EventConstants}
+     *             instead.
      */
     public static final String FAILURE = EventConstants.FAILURE;
 
     /**
-     * Query parameter name storing form data (the serialized commands needed to process a form submission).
+     * Query parameter name storing form data (the serialized commands needed to
+     * process a form submission).
      */
     public static final String FORM_DATA = "t:formdata";
 
     /**
-     * The context for the link (optional parameter). This list of values will be converted into strings and included in
-     * the URI. The strings will be coerced back to whatever their values are and made available to event handler
+     * The context for the link (optional parameter). This list of values will
+     * be converted into strings and included in
+     * the URI. The strings will be coerced back to whatever their values are
+     * and made available to event handler
      * methods.
      */
     @Parameter
     private Object[] context;
 
     /**
-     * The object which will record user input and validation errors. The object must be persistent between requests
-     * (since the form submission and validation occurs in an component event request and the subsequent render occurs
-     * in a render request). The default is a persistent property of the Form component and this is sufficient for
+     * The object which will record user input and validation errors. The object
+     * must be persistent between requests
+     * (since the form submission and validation occurs in an component event
+     * request and the subsequent render occurs
+     * in a render request). The default is a persistent property of the Form
+     * component and this is sufficient for
      * nearly all purposes (except when a Form is rendered inside a loop).
      */
     @Parameter("defaultTracker")
@@ -126,42 +148,52 @@
     private boolean clientLogicDefaultEnabled;
 
     /**
-     * If true (the default) then client validation is enabled for the form, and the default set of JavaScript libraries
-     * (Prototype, Scriptaculous and the Tapestry library) will be added to the rendered page, and the form will
-     * register itself for validation. This may be turned off when client validation is not desired; for example, when
+     * If true (the default) then client validation is enabled for the form, and
+     * the default set of JavaScript libraries
+     * (Prototype, Scriptaculous and the Tapestry library) will be added to the
+     * rendered page, and the form will
+     * register itself for validation. This may be turned off when client
+     * validation is not desired; for example, when
      * many validations are used that do not operate on the client side at all.
      */
     @Parameter
     private boolean clientValidation = clientLogicDefaultEnabled;
 
     /**
-     * If true (the default), then the JavaScript will be added to position the cursor into the form. The field to
-     * receive focus is the first rendered field that is in error, or required, or present (in that order of priority).
-     *
+     * If true (the default), then the JavaScript will be added to position the
+     * cursor into the form. The field to
+     * receive focus is the first rendered field that is in error, or required,
+     * or present (in that order of priority).
+     * 
      * @see SymbolConstants#FORM_CLIENT_LOGIC_ENABLED
      */
     @Parameter
     private boolean autofocus = clientLogicDefaultEnabled;
 
     /**
-     * Binding the zone parameter will cause the form submission to be handled as an Ajax request that updates the
-     * indicated zone.  Often a Form will update the same zone that contains it.
+     * Binding the zone parameter will cause the form submission to be handled
+     * as an Ajax request that updates the
+     * indicated zone. Often a Form will update the same zone that contains it.
      */
     @Parameter(defaultPrefix = BindingConstants.LITERAL)
     private String zone;
 
     /**
-     * Prefix value used when searching for validation messages and constraints.  The default is the Form component's
-     * id. This is overriden by {@link org.apache.tapestry5.corelib.components.BeanEditForm}.
-     *
+     * Prefix value used when searching for validation messages and constraints.
+     * The default is the Form component's
+     * id. This is overriden by
+     * {@link org.apache.tapestry5.corelib.components.BeanEditForm}.
+     * 
      * @see org.apache.tapestry5.services.FormSupport#getFormValidationId()
      */
     @Parameter
     private String validationId;
-    
+
     /**
-     * Object to validate during the form submission process. The value of this parameter is pushed as a 
-     * {@link org.apache.tapestry5.services.BeanValidationContext} into the environment. This parameter should
+     * Object to validate during the form submission process. The value of this
+     * parameter is pushed as a
+     * {@link org.apache.tapestry5.services.BeanValidationContext} into the
+     * environment. This parameter should
      * only be used in combination with the Bean Validation Library.
      */
     @Parameter
@@ -197,7 +229,8 @@
 
     private Element div;
 
-    // Collects a stream of component actions. Each action goes in as a UTF string (the component
+    // Collects a stream of component actions. Each action goes in as a UTF
+    // string (the component
     // component id), followed by a ComponentAction
 
     private ComponentActionSink actionSink;
@@ -223,7 +256,7 @@
     {
         return resources.getId();
     }
-    
+
     Object defaultValidate()
     {
         return resources.getContainer();
@@ -231,7 +264,8 @@
 
     public ValidationTracker getDefaultTracker()
     {
-        if (defaultTracker == null) defaultTracker = new ValidationTrackerImpl();
+        if (defaultTracker == null)
+            defaultTracker = new ValidationTrackerImpl();
 
         return defaultTracker;
     }
@@ -259,35 +293,35 @@
 
         formSupport = createRenderTimeFormSupport(name, actionSink, new IdAllocator());
 
-        if (zone != null) clientBehaviorSupport.linkZone(name, zone, link);
+        if (zone != null)
+            clientBehaviorSupport.linkZone(name, zone, link);
 
-        // TODO: Forms should not allow to nest. Perhaps a set() method instead of a push() method
-        // for this kind of check?  
+        // TODO: Forms should not allow to nest. Perhaps a set() method instead
+        // of a push() method
+        // for this kind of check?
 
         environment.push(FormSupport.class, formSupport);
         environment.push(ValidationTracker.class, tracker);
 
         if (autofocus)
         {
-            ValidationDecorator autofocusDecorator = new AutofocusValidationDecorator(environment.peek(
-                    ValidationDecorator.class), tracker, renderSupport);
+            ValidationDecorator autofocusDecorator = new AutofocusValidationDecorator(environment
+                    .peek(ValidationDecorator.class), tracker, renderSupport);
             environment.push(ValidationDecorator.class, autofocusDecorator);
         }
 
-        // Now that the environment is setup, inform the component or other listeners that the form
-        // is about to render.  
+        // Now that the environment is setup, inform the component or other
+        // listeners that the form
+        // is about to render.
 
         resources.triggerEvent(EventConstants.PREPARE_FOR_RENDER, context, null);
 
         resources.triggerEvent(EventConstants.PREPARE, context, null);
 
-        // Save the form element for later, in case we want to write an encoding type attribute.
+        // Save the form element for later, in case we want to write an encoding
+        // type attribute.
 
-        form = writer.element("form",
-                              "name", name,
-                              "id", name,
-                              "method", "post",
-                              "action", link);
+        form = writer.element("form", "id", name, "method", "post", "action", link);
 
         if ((zone != null || clientValidation) && !request.isXHR())
             writer.attributes("onsubmit", MarkupConstants.WAIT_FOR_PAGE);
@@ -300,10 +334,7 @@
         {
             String value = link.getParameterValue(parameterName);
 
-            writer.element("input",
-                           "type", "hidden",
-                           "name", parameterName,
-                           "value", value);
+            writer.element("input", "type", "hidden", "name", parameterName, "value", value);
             writer.end();
         }
 
@@ -313,19 +344,27 @@
     }
 
     /**
-     * Creates an {@link org.apache.tapestry5.corelib.internal.InternalFormSupport} for this Form. This method is used
+     * Creates an
+     * {@link org.apache.tapestry5.corelib.internal.InternalFormSupport} for
+     * this Form. This method is used
      * by {@link org.apache.tapestry5.corelib.components.FormInjector}.
-     *
-     * @param name       the client-side name and client id for the rendered form element
-     * @param actionSink used to collect component actions that will, ultimately, be written as the t:formdata hidden
-     *                   field
-     * @param allocator  used to allocate unique ids
+     * 
+     * @param name
+     *            the client-side name and client id for the rendered form
+     *            element
+     * @param actionSink
+     *            used to collect component actions that will, ultimately, be
+     *            written as the t:formdata hidden
+     *            field
+     * @param allocator
+     *            used to allocate unique ids
      * @return form support object
      */
-    InternalFormSupport createRenderTimeFormSupport(String name, ComponentActionSink actionSink, IdAllocator allocator)
+    InternalFormSupport createRenderTimeFormSupport(String name, ComponentActionSink actionSink,
+            IdAllocator allocator)
     {
         return new FormSupportImpl(resources, name, actionSink, clientBehaviorSupport,
-                                   clientValidation, allocator, validationId);
+                clientValidation, allocator, validationId);
     }
 
     void afterRender(MarkupWriter writer)
@@ -336,14 +375,13 @@
 
         String encodingType = formSupport.getEncodingType();
 
-        if (encodingType != null) form.forceAttributes("enctype", encodingType);
+        if (encodingType != null)
+            form.forceAttributes("enctype", encodingType);
 
         writer.end(); // form
 
-        div.element("input",
-                    "type", "hidden",
-                    "name", FORM_DATA,
-                    "value", actionSink.getClientData());
+        div.element("input", "type", "hidden", "name", FORM_DATA, "value", actionSink
+                .getClientData());
 
         if (autofocus)
             environment.pop(ValidationDecorator.class);
@@ -358,7 +396,8 @@
         environment.pop(ValidationTracker.class);
     }
 
-    @SuppressWarnings({ "unchecked", "InfiniteLoopStatement" })
+    @SuppressWarnings(
+    { "unchecked", "InfiniteLoopStatement" })
     @Log
     Object onAction(EventContext context) throws IOException
     {
@@ -368,12 +407,14 @@
 
         environment.push(ValidationTracker.class, tracker);
         environment.push(FormSupport.class, formSupport);
-        environment.push(BeanValidationContext.class, new BeanValidationContext(){
+        environment.push(BeanValidationContext.class, new BeanValidationContext()
+        {
 
             public Object getObject()
             {
                 return validate;
-            }});
+            }
+        });
 
         Heartbeat heartbeat = new HeartbeatImpl();
 
@@ -388,11 +429,13 @@
 
             resources.triggerContextEvent(EventConstants.PREPARE_FOR_SUBMIT, context, callback);
 
-            if (callback.isAborted()) return true;
+            if (callback.isAborted())
+                return true;
 
             resources.triggerContextEvent(EventConstants.PREPARE, context, callback);
 
-            if (callback.isAborted()) return true;
+            if (callback.isAborted())
+                return true;
 
             executeStoredActions();
 
@@ -402,24 +445,29 @@
 
             fireValidateFormEvent(context, callback);
 
-            if (callback.isAborted()) return true;
+            if (callback.isAborted())
+                return true;
 
-            // Let the listeners know about overall success or failure. Most listeners fall into
+            // Let the listeners know about overall success or failure. Most
+            // listeners fall into
             // one of those two camps.
 
             // If the tracker has no errors, then clear it of any input values
             // as well, so that the next page render will be "clean" and show
-            // true persistent data, not value from the previous form submission.
+            // true persistent data, not value from the previous form
+            // submission.
 
             if (!tracker.getHasErrors())
                 tracker.clear();
 
-            resources.triggerContextEvent(tracker.getHasErrors() ? EventConstants.FAILURE : EventConstants.SUCCESS,
-                                          context, callback);
+            resources.triggerContextEvent(tracker.getHasErrors() ? EventConstants.FAILURE
+                    : EventConstants.SUCCESS, context, callback);
 
-            // Lastly, tell anyone whose interested that the form is completely submitted.
+            // Lastly, tell anyone whose interested that the form is completely
+            // submitted.
 
-            if (callback.isAborted()) return true;
+            if (callback.isAborted())
+                return true;
 
             resources.triggerContextEvent(EventConstants.SUBMIT, context, callback);
 
@@ -430,17 +478,20 @@
             environment.pop(Heartbeat.class);
             environment.pop(FormSupport.class);
 
-            // This forces an update that feeds through the system and gets the updated
-            // state of the tracker (if using the Form's defaultTracker property, which is flash persisted)
+            // This forces an update that feeds through the system and gets the
+            // updated
+            // state of the tracker (if using the Form's defaultTracker
+            // property, which is flash persisted)
             // stored back into the session.
 
             tracker = environment.pop(ValidationTracker.class);
-            
+
             environment.pop(BeanValidationContext.class);
         }
     }
 
-    private void fireValidateFormEvent(EventContext context, ComponentResultProcessorWrapper callback)
+    private void fireValidateFormEvent(EventContext context,
+            ComponentResultProcessorWrapper callback)
     {
         try
         {
@@ -461,7 +512,8 @@
     }
 
     /**
-     * Pulls the stored actions out of the request, converts them from MIME stream back to object stream and then
+     * Pulls the stored actions out of the request, converts them from MIME
+     * stream back to object stream and then
      * objects, and executes them.
      */
     private void executeStoredActions()
@@ -471,11 +523,13 @@
         if (!request.getMethod().equals("POST") || values == null)
             throw new RuntimeException(messages.format("invalid-request", FORM_DATA));
 
-        // Due to Ajax (FormInjector) there may be multiple values here, so handle each one individually.
+        // Due to Ajax (FormInjector) there may be multiple values here, so
+        // handle each one individually.
 
         for (String clientEncodedActions : values)
         {
-            if (InternalUtils.isBlank(clientEncodedActions)) continue;
+            if (InternalUtils.isBlank(clientEncodedActions))
+                continue;
 
             logger.debug("Processing actions: {}", clientEncodedActions);
 
@@ -507,7 +561,8 @@
             }
             catch (Exception ex)
             {
-                Location location = component == null ? null : component.getComponentResources().getLocation();
+                Location location = component == null ? null : component.getComponentResources()
+                        .getLocation();
 
                 throw new TapestryException(ex.getMessage(), location, ex);
             }