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 * @deprecated Wiring of form event handlers is now managed on the client side. This method may 039 * be removed in a future release of Tapestry. 040 */ 041 void addEventHandler(FormEventType type, String functionName); 042 043 /** 044 * Adds a hidden field value to be stored in the form. This ensures that all of the <input 045 * type="hidden"> (or equivalent) are grouped together, which ensures that the output HTML is 046 * valid (ie. doesn't have <input> improperly nested with <tr>, etc.). 047 * <p> 048 * It is acceptible to add multiple hidden fields with the same name. They will be written in 049 * the order they are received. 050 */ 051 052 void addHiddenValue(String name, String value); 053 054 /** 055 * Adds a hidden field value to be stored in the form. This ensures that all of the <input 056 * type="hidden"> (or equivalent) are grouped together, which ensures that the output HTML is 057 * valid (ie. doesn't have <input> improperly nested with <tr>, etc.). 058 * <p> 059 * It is acceptible to add multiple hidden fields with the same name. They will be written in 060 * the order they are received. 061 * 062 * @since 3.0 063 */ 064 065 void addHiddenValue(String name, String id, String value); 066 067 /** 068 * Constructs a unique identifier (within the Form). The identifier consists of the component's 069 * id, with an index number added to ensure uniqueness. 070 * <p> 071 * Simply invokes {@link #getElementId(IFormComponent, String)}with the component's id. 072 * <p> 073 * Note: yes, some confusion on naming here. This is the form element id, which should be (for 074 * Tapestry purposes) unique within the rendered form. The {@link IFormComponent#getClientId()} 075 * is different, and should be unique within the rendered page. 076 */ 077 078 String getElementId(IFormComponent component); 079 080 /** 081 * Constructs a unique identifier from the base id. If possible, the id is used as-is. 082 * Otherwise, a unique identifier is appended to the id. 083 * <p> 084 * This method is provided simply so that some components ( 085 * {@link org.apache.tapestry.form.ImageSubmit}) have more specific control over their names. 086 * <p> 087 * Invokes {@link IFormComponent#setName(String)}with the result, as well as returning it. 088 * 089 * @throws StaleLinkException 090 * if, when the form itself is rewinding, the element id allocated does not match 091 * the expected id (as allocated when the form rendered). This indicates that the 092 * state of the application has changed between the time the form renderred and the 093 * time it was submitted. 094 */ 095 096 String getElementId(IFormComponent component, String baseId); 097 098 /** 099 * Used internally to "peek" at what the next generated client id will be for the 100 * given component when it renders. Similar to the logic found in {@link IRequestCycle#peekUniqueId(String)}. 101 * 102 * @return The next possible client ID for the component. 103 */ 104 String peekClientId(IFormComponent component); 105 106 /** 107 * Returns true if the form is rewinding (meaning, the form was the subject of the request 108 * cycle). 109 */ 110 111 boolean isRewinding(); 112 113 /** 114 * May be invoked by a component to force the encoding type of the form to a particular value. 115 * 116 * @see org.apache.tapestry.form.Upload 117 * @throws ApplicationRuntimeException 118 * if the current encoding type is not null and doesn't match the provided encoding 119 * type 120 */ 121 122 void setEncodingType(String encodingType); 123 124 /** 125 * Pre-renders the specified field, buffering the result for later use by 126 * {@link #wasPrerendered(IMarkupWriter, IComponent)}. Typically, it is a 127 * {@link org.apache.tapestry.valid.FieldLabel} component that pre-renders an associated 128 * field. This little dance is necessary to properly support field labels inside loops, and to 129 * handle the portlet action/render request cycle. 130 * 131 * @param writer 132 * the markup writer (from which a nested markup writer is obtained) 133 * @param field 134 * the field to pre-render. The field is responsible for invoking 135 * {@link #wasPrerendered(IMarkupWriter, IComponent)}. 136 * @param location 137 * an optional location (of the FieldLabel component) used when reporting errors. 138 */ 139 void prerenderField(IMarkupWriter writer, IComponent field, Location location); 140 141 /** 142 * Invoked by a form control component (a field) that may have been pre-rendered. If the field 143 * was pre-rendered, then the buffered output is printed into the writer and true is returned. 144 * Otherwise, false is returned. 145 * 146 * @return true if the field was pre-rendered and should do nothing during its render phase, 147 * false if the field should continue as normal. 148 */ 149 boolean wasPrerendered(IMarkupWriter writer, IComponent field); 150 151 /** 152 * Adds a deferred runnable, an object to be executed either before the </form> tag is 153 * rendered (when rendering), or before the form's listener is invoked (when rewinding). 154 * Runnables are executed in the order in which they are added. 155 * 156 * @param runnable 157 * the object to execute (which may not be null) 158 */ 159 160 void addDeferredRunnable(Runnable runnable); 161 162 /** 163 * Registers a field for automatic focus. The goal is for the first field that is in error to 164 * get focus; failing that, the first required field; failing that, any field. 165 * 166 * @param field 167 * the field requesting focus 168 * @param priority 169 * a priority level used to determine whether the registered field becomes the focus 170 * field. Constants for this purpose are defined in {@link ValidationConstants}. 171 * @since 4.0 172 */ 173 174 void registerForFocus(IFormComponent field, int priority); 175 176 /** 177 * The javascript object profile being built by this context to validate/translate 178 * form values. 179 * @return {@link JSONObject} profile. 180 */ 181 JSONObject getProfile(); 182 183 /** 184 * Sets a flag denoting whether or not an {@link IFormComponent} field has been 185 * updated according to the logic defined in 186 * {@link org.apache.tapestry.services.ResponseBuilder#updateComponent(String)}. 187 * 188 * <p> 189 * Currently this flag is used during ajax/json responses so that cooperating 190 * {@link ResponseBuilder}s can be worked with to ensure form state is properly 191 * updated on the client. Specifically, that the hidden form input fields and 192 * any associated validation profiles are updated. 193 * </p> 194 * 195 * @param value 196 * The value to set. 197 */ 198 void setFormFieldUpdating(boolean value); 199 200 /** 201 * Checks to see if a form field has been updated. 202 * 203 * @see #setFormFieldUpdating(boolean) 204 * @return True if any form field was updated. 205 */ 206 boolean isFormFieldUpdating(); 207 }