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 <input
066 * type="hidden"> (or equivalent) are grouped together, which ensures that the output HTML is
067 * valid (ie. doesn't have <input> improperly nested with <tr>, 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} 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 </form> 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 }