001    // Copyright 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry;
016    
017    import org.apache.hivemind.ApplicationRuntimeException;
018    import org.apache.hivemind.Location;
019    import org.apache.tapestry.form.FormEventType;
020    import org.apache.tapestry.form.IFormComponent;
021    import org.apache.tapestry.json.JSONObject;
022    import org.apache.tapestry.services.ResponseBuilder;
023    import org.apache.tapestry.valid.ValidationConstants;
024    
025    /**
026     * Common interface extended by {@link org.apache.tapestry.IForm} and
027     * {@link org.apache.tapestry.form.FormSupport}.
028     * 
029     * @author Howard M. Lewis Ship
030     * @since 4.0
031     */
032    public interface FormBehavior
033    {
034        /**
035         * Adds an additional event handler. The type determines when the handler will be invoked,
036         * {@link FormEventType#SUBMIT}is most typical.
037         *
038         * @param type
039         *          Type of event to add.
040         * @param functionName
041         *          Name of the javascript function being added.
042         * 
043         * @deprecated Wiring of form event handlers is now managed on the client side. This method may
044         *             be removed in Tapestry 4.1.2.
045         */
046        void addEventHandler(FormEventType type, String functionName);
047    
048        /**
049         * Adds a hidden field value to be stored in the form. This ensures that all of the <input
050         * type="hidden"> (or equivalent) are grouped together, which ensures that the output HTML is
051         * valid (ie. doesn't have <input> improperly nested with <tr>, etc.).
052         * <p>
053         * It is acceptible to add multiple hidden fields with the same name. They will be written in
054         * the order they are received.
055         *
056         * @param name
057         *          The name of the hidden input.
058         * @param value
059         *          The value to store in the hidden field.
060         */
061    
062        void addHiddenValue(String name, String value);
063    
064        /**
065         * Adds a hidden field value to be stored in the form. This ensures that all of the &lt;input
066         * type="hidden"&gt; (or equivalent) are grouped together, which ensures that the output HTML is
067         * valid (ie. doesn't have &lt;input&gt; improperly nested with &lt;tr&gt;, etc.).
068         * <p>
069         * It is acceptible to add multiple hidden fields with the same name. They will be written in
070         * the order they are received.
071         *
072         * @param name
073         *          The name of the hidden input.
074         * @param id
075         *          The id of the hidden input - should almost always be the same as the name.
076         * @param value
077         *          The value to store in the hidden field.
078         * @since 3.0
079         */
080    
081        void addHiddenValue(String name, String id, String value);
082    
083        /**
084         * Constructs a unique identifier (within the Form). The identifier consists of the component's
085         * id, with an index number added to ensure uniqueness.
086         * <p>
087         * Simply invokes {@link #getElementId(IFormComponent, String)}with the component's id.
088         * <p>
089         *
090         * <p>Note: yes, some confusion on naming here. This is the form element id, which should be (for
091         * Tapestry purposes) unique within the rendered form. The {@link IFormComponent#getClientId()}
092         * is different, and should be unique within the rendered page.
093         * </p>
094         *
095         * @param component
096         *          The component to get the unique id of.
097         * @return The unique id for this component, to be used in rendering name="id" type elements.
098         *
099         */
100    
101        String getElementId(IFormComponent component);
102    
103        /**
104         * Constructs a unique identifier from the base id. If possible, the id is used as-is.
105         * Otherwise, a unique identifier is appended to the id.
106         * <p>
107         * This method is provided simply so that some components (
108         * {@link org.apache.tapestry.form.ImageSubmit}) have more specific control over their names.
109         * <p>
110         * Invokes {@link IFormComponent#setName(String)}with the result, as well as returning it.
111         *
112         * @param component
113         *          The component to generate an element id for.
114         * @param baseId
115         *          The basic id of the component.
116         * @return The form specific unique identifier for the given element.  May be the same as the baseId
117         *          if this is the first render of that specific component.
118         * @throws StaleLinkException
119         *             if, when the form itself is rewinding, the element id allocated does not match
120         *             the expected id (as allocated when the form rendered). This indicates that the
121         *             state of the application has changed between the time the form renderred and the
122         *             time it was submitted.
123         */
124    
125        String getElementId(IFormComponent component, String baseId);
126        
127        /**
128         * Used internally to "peek" at what the next generated client id will be for the 
129         * given component when it renders. Similar to the logic found in {@link IRequestCycle#peekUniqueId(String)}.
130         *
131         * @param component
132         *          The component to determine the next client id for.
133         * 
134         * @return The next possible client ID for the component.
135         */
136        String peekClientId(IFormComponent component);
137        
138        /**
139         * Returns true if the form is rewinding (meaning, the form was the subject of the request
140         * cycle).
141         *
142         * @return True if the form is rewinding, false otherwise.
143         */
144    
145        boolean isRewinding();
146    
147        /**
148         * May be invoked by a component to force the encoding type of the form to a particular value.
149         *
150         * @param encodingType
151         *          The encoding type to set.
152         * @see org.apache.tapestry.form.Upload
153         * @throws ApplicationRuntimeException
154         *             if the current encoding type is not null and doesn't match the provided encoding
155         *             type
156         */
157    
158        void setEncodingType(String encodingType);
159    
160        /**
161         * Pre-renders the specified field, buffering the result for later use by
162         * {@link #wasPrerendered(IMarkupWriter, IComponent)}. Typically, it is a
163         * {@link org.apache.tapestry.valid.FieldLabel}&nbsp;component that pre-renders an associated
164         * field. This little dance is necessary to properly support field labels inside loops, and to
165         * handle the portlet action/render request cycle.
166         * 
167         * @param writer
168         *            the markup writer (from which a nested markup writer is obtained)
169         * @param field
170         *            the field to pre-render. The field is responsible for invoking
171         *            {@link #wasPrerendered(IMarkupWriter, IComponent)}.
172         * @param location
173         *            an optional location (of the FieldLabel component) used when reporting errors.
174         */
175        void prerenderField(IMarkupWriter writer, IComponent field, Location location);
176    
177        /**
178         * Invoked by a form control component (a field) that may have been pre-rendered. If the field
179         * was pre-rendered, then the buffered output is printed into the writer and true is returned.
180         * Otherwise, false is returned.
181         *
182         * @param writer
183         *          The markup writer to render with. (may be ignored during dynamic requests)
184         * @param field
185         *          The component to check for pre-rendering.
186         * 
187         * @return true if the field was pre-rendered and should do nothing during its render phase,
188         *         false if the field should continue as normal.
189         */
190        boolean wasPrerendered(IMarkupWriter writer, IComponent field);
191    
192        /**
193         * Invoked to check if a particular component has been pre-rendered.
194         *
195         * @param field
196         *          The component to check for pre-rendering. (Such as is done by {@link org.apache.tapestry.valid.FieldLabel}.
197         * 
198         * @return True if the component was pre-rendered, false otherwise.
199         */
200        boolean wasPrerendered(IComponent field);
201    
202        /**
203         * Adds a deferred runnable, an object to be executed either before the &lt;/form&gt; tag is
204         * rendered (when rendering), or before the form's listener is invoked (when rewinding).
205         * Runnables are executed in the order in which they are added.
206         * 
207         * @param runnable
208         *            the object to execute (which may not be null)
209         */
210    
211        void addDeferredRunnable(Runnable runnable);
212    
213        /**
214         * Registers a field for automatic focus. The goal is for the first field that is in error to
215         * get focus; failing that, the first required field; failing that, any field.
216         * 
217         * @param field
218         *            the field requesting focus
219         * @param priority
220         *            a priority level used to determine whether the registered field becomes the focus
221         *            field. Constants for this purpose are defined in {@link ValidationConstants}.
222         * @since 4.0
223         */
224    
225        void registerForFocus(IFormComponent field, int priority);
226    
227        /**
228         * The javascript object profile being built by this context to validate/translate
229         * form values.
230         * @return {@link JSONObject} profile.
231         */
232        JSONObject getProfile();
233        
234        /**
235         * Sets a flag denoting whether or not an {@link IFormComponent} field has been
236         * updated according to the logic defined in 
237         * {@link org.apache.tapestry.services.ResponseBuilder#updateComponent(String)}.
238         * 
239         * <p>
240         * Currently this flag is used during ajax/json responses so that cooperating 
241         * {@link ResponseBuilder}s can be worked with to ensure form state is properly
242         * updated on the client. Specifically, that the hidden form input fields and 
243         * any associated validation profiles are updated.
244         * </p>
245         * 
246         * @param value 
247         *          The value to set.
248         */
249        void setFormFieldUpdating(boolean value);
250        
251        /**
252         * Checks to see if a form field has been updated. 
253         * 
254         * @see #setFormFieldUpdating(boolean)
255         * @return True if any form field was updated.
256         */
257        boolean isFormFieldUpdating();
258    }