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 }