Source code: org/apache/tapestry/form/Form.java
1 /* $$ Clover has instrumented this file $$ */// Copyright 2004 The Apache Software Foundation
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package org.apache.tapestry.form;
16
17 import java.util.ArrayList;
18 import java.util.HashMap;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Map;
22
23 import org.apache.tapestry.AbstractComponent;
24 import org.apache.hivemind.ApplicationRuntimeException;
25 import org.apache.tapestry.IActionListener;
26 import org.apache.tapestry.IBinding;
27 import org.apache.tapestry.IDirect;
28 import org.apache.tapestry.IEngine;
29 import org.apache.tapestry.IForm;
30 import org.apache.tapestry.IMarkupWriter;
31 import org.apache.tapestry.IRequestCycle;
32 import org.apache.tapestry.RenderRewoundException;
33 import org.apache.tapestry.StaleLinkException;
34 import org.apache.tapestry.Tapestry;
35 import org.apache.tapestry.engine.IEngineService;
36 import org.apache.tapestry.engine.ILink;
37 import org.apache.tapestry.html.Body;
38 import org.apache.tapestry.util.IdAllocator;
39 import org.apache.tapestry.util.StringSplitter;
40 import org.apache.tapestry.valid.IValidationDelegate;
41
42 /**
43 * Component which contains form element components. Forms use the
44 * action or direct services to handle the form submission. A Form will wrap
45 * other components and static HTML, including
46 * form components such as {@link TextArea}, {@link TextField}, {@link Checkbox}, etc.
47 *
48 * [<a href="../../../../../ComponentReference/Form.html">Component Reference</a>]
49 *
50 * <p>When a form is submitted, it continues through the rewind cycle until
51 * <em>after</em> all of its wrapped elements have renderred. As the form
52 * component render (in the rewind cycle), they will be updating
53 * properties of the containing page and notifying thier listeners. Again:
54 * each form component is responsible not only for rendering HTML (to present the
55 * form), but for handling it's share of the form submission.
56 *
57 * <p>Only after all that is done will the Form notify its listener.
58 *
59 * <p>Starting in release 1.0.2, a Form can use either the direct service or
60 * the action service. The default is the direct service, even though
61 * in earlier releases, only the action service was available.
62 *
63 * @author Howard Lewis Ship, David Solis
64 **/
65
66 public abstract class Form extends AbstractComponent implements IForm, IDirect
67 {public static com.cortexeb.tools.clover.d __CLOVER_130_0 = com.cortexeb.tools.clover.aq.getRecorder(new char[] {67,58,92,119,111,114,107,115,112,97,99,101,92,106,97,107,97,114,116,97,45,116,97,112,101,115,116,114,121,92,102,114,97,109,101,119,111,114,107,92,116,97,114,103,101,116,92,99,108,111,118,101,114,45,100,98},1096998272901L);
68 private static class HiddenValue
69 {
70 String _name;
71 String _value;
72 String _id;
73
74 private HiddenValue(String name, String value)
75 {
76 this(name, null, value);__CLOVER_130_0.S[3037]++;try { __CLOVER_130_0.M[687]++;
77 } finally { }}
78
79 private HiddenValue(String name, String id, String value)
80 {try { __CLOVER_130_0.M[688]++;
81 __CLOVER_130_0.S[3038]++;_name = name;
82 __CLOVER_130_0.S[3039]++;_id = id;
83 __CLOVER_130_0.S[3040]++;_value = value;
84 } finally { }}
85 }
86
87 private boolean _rewinding;
88 private boolean _rendering;
89 private String _name;
90
91 /**
92 * Used when rewinding the form to figure to match allocated ids (allocated during
93 * the rewind) against expected ids (allocated in the previous request cycle, when
94 * the form was rendered).
95 *
96 * @since 3.0
97 *
98 **/
99
100 private int _allocatedIdIndex;
101
102 /**
103 * The list of allocated ids for form elements within this form. This list
104 * is constructed when a form renders, and is validated against when the
105 * form is rewound.
106 *
107 * @since 3.0
108 *
109 **/
110
111 private List _allocatedIds = new ArrayList();
112
113 /**
114 * {@link Map}, keyed on {@link FormEventType}. Values are either a String (the name
115 * of a single event), or a {@link List} of Strings.
116 *
117 * @since 1.0.2
118 **/
119
120 private Map _events;
121
122 private static final int EVENT_MAP_SIZE = 3;
123
124 private IdAllocator _elementIdAllocator = new IdAllocator();
125
126 private String _encodingType;
127
128 private List _hiddenValues;
129
130 /**
131 * Returns the currently active {@link IForm}, or null if no form is
132 * active. This is a convienience method, the result will be
133 * null, or an instance of {@link IForm}, but not necessarily a
134 * <code>Form</code>.
135 *
136 **/
137
138 public static IForm get(IRequestCycle cycle)
139 {try { __CLOVER_130_0.M[689]++;
140 __CLOVER_130_0.S[3041]++;return (IForm) cycle.getAttribute(ATTRIBUTE_NAME);
141 } finally { }}
142
143 /**
144 * Indicates to any wrapped form components that they should respond to the form
145 * submission.
146 *
147 * @throws ApplicationRuntimeException if not rendering.
148 **/
149
150 public boolean isRewinding()
151 {try { __CLOVER_130_0.M[690]++;
152 __CLOVER_130_0.S[3042]++;if ((((!_rendering) && (++__CLOVER_130_0.CT[552] != 0)) || (++__CLOVER_130_0.CF[552] == 0))){
153 __CLOVER_130_0.S[3043]++;throw Tapestry.createRenderOnlyPropertyException(this, "rewinding");}
154
155 __CLOVER_130_0.S[3044]++;return _rewinding;
156 } finally { }}
157
158 /**
159 * Returns true if this Form is configured to use the direct
160 * service.
161 *
162 * <p>This is derived from the direct parameter, and defaults
163 * to true if not bound.
164 *
165 * @since 1.0.2
166 **/
167
168 public abstract boolean isDirect();
169
170 /**
171 * Returns true if the stateful parameter is bound to
172 * a true value. If stateful is not bound, also returns
173 * the default, true.
174 *
175 * @since 1.0.1
176 **/
177
178 public boolean getRequiresSession()
179 {try { __CLOVER_130_0.M[691]++;
180 __CLOVER_130_0.S[3045]++;return isStateful();
181 } finally { }}
182
183 /**
184 * Constructs a unique identifier (within the Form). The identifier
185 * consists of the component's id, with an index number added to
186 * ensure uniqueness.
187 *
188 * <p>Simply invokes {@link #getElementId(org.apache.tapestry.form.IFormComponent, java.lang.String)}
189 * with the component's id.
190 *
191 *
192 * @since 1.0.2
193 **/
194
195 public String getElementId(IFormComponent component)
196 {try { __CLOVER_130_0.M[692]++;
197 __CLOVER_130_0.S[3046]++;return getElementId(component, component.getId());
198 } finally { }}
199
200 /**
201 * Constructs a unique identifier from the base id. If possible, the
202 * id is used as-is. Otherwise, a unique identifier is appended
203 * to the id.
204 *
205 * <p>This method is provided simply so that some components
206 * ({@link ImageSubmit}) have more specific control over
207 * their names.
208 *
209 * @since 1.0.3
210 *
211 **/
212
213 public String getElementId(IFormComponent component, String baseId)
214 {try { __CLOVER_130_0.M[693]++;
215 __CLOVER_130_0.S[3047]++;String result = _elementIdAllocator.allocateId(baseId);
216
217 __CLOVER_130_0.S[3048]++;if ((((_rewinding) && (++__CLOVER_130_0.CT[553] != 0)) || (++__CLOVER_130_0.CF[553] == 0))){
218 {
219 __CLOVER_130_0.S[3049]++;if ((((_allocatedIdIndex >= _allocatedIds.size()) && (++__CLOVER_130_0.CT[554] != 0)) || (++__CLOVER_130_0.CF[554] == 0))){
220 {
221 __CLOVER_130_0.S[3050]++;throw new StaleLinkException(
222 Tapestry.format(
223 "Form.too-many-ids",
224 getExtendedId(),
225 Integer.toString(_allocatedIds.size()),
226 component.getExtendedId()),
227 this);
228 }}
229
230 __CLOVER_130_0.S[3051]++;String expected = (String) _allocatedIds.get(_allocatedIdIndex);
231
232 __CLOVER_130_0.S[3052]++;if ((((!result.equals(expected)) && (++__CLOVER_130_0.CT[555] != 0)) || (++__CLOVER_130_0.CF[555] == 0))){
233 __CLOVER_130_0.S[3053]++;throw new StaleLinkException(
234 Tapestry.format(
235 "Form.id-mismatch",
236 new Object[] {
237 getExtendedId(),
238 Integer.toString(_allocatedIdIndex + 1),
239 expected,
240 result,
241 component.getExtendedId()}),
242 this);}
243 }}
244 else{
245 {
246 __CLOVER_130_0.S[3054]++;_allocatedIds.add(result);
247 }}
248
249 __CLOVER_130_0.S[3055]++;_allocatedIdIndex++;
250
251 __CLOVER_130_0.S[3056]++;component.setName(result);
252
253 __CLOVER_130_0.S[3057]++;return result;
254 } finally { }}
255
256 /**
257 * Returns the name generated for the form. This is used to faciliate
258 * components that write JavaScript and need to access the form or
259 * its contents.
260 *
261 * <p>This value is generated when the form renders, and is not cleared.
262 * If the Form is inside a {@link org.apache.tapestry.components.Foreach},
263 * this will be the most recently
264 * generated name for the Form.
265 *
266 * <p>This property is exposed so that sophisticated applications can write
267 * JavaScript handlers for the form and components within the form.
268 *
269 * @see AbstractFormComponent#getName()
270 *
271 **/
272
273 public String getName()
274 {try { __CLOVER_130_0.M[694]++;
275 __CLOVER_130_0.S[3058]++;return _name;
276 } finally { }}
277
278 /** @since 3.0 **/
279
280 protected void prepareForRender(IRequestCycle cycle)
281 {try { __CLOVER_130_0.M[695]++;
282 __CLOVER_130_0.S[3059]++;super.prepareForRender(cycle);
283
284 __CLOVER_130_0.S[3060]++;if ((((cycle.getAttribute(ATTRIBUTE_NAME) != null) && (++__CLOVER_130_0.CT[556] != 0)) || (++__CLOVER_130_0.CF[556] == 0))){
285 __CLOVER_130_0.S[3061]++;throw new ApplicationRuntimeException(
286 Tapestry.getMessage("Form.forms-may-not-nest"),
287 this,
288 null,
289 null);}
290
291 __CLOVER_130_0.S[3062]++;cycle.setAttribute(ATTRIBUTE_NAME, this);
292 } finally { }}
293
294 protected void cleanupAfterRender(IRequestCycle cycle)
295 {try { __CLOVER_130_0.M[696]++;
296 __CLOVER_130_0.S[3063]++;_rendering = false;
297
298 __CLOVER_130_0.S[3064]++;_allocatedIdIndex = 0;
299 __CLOVER_130_0.S[3065]++;_allocatedIds.clear();
300
301 __CLOVER_130_0.S[3066]++;_events = null;
302
303 __CLOVER_130_0.S[3067]++;_elementIdAllocator.clear();
304
305 __CLOVER_130_0.S[3068]++;if ((((_hiddenValues != null) && (++__CLOVER_130_0.CT[557] != 0)) || (++__CLOVER_130_0.CF[557] == 0))){
306 __CLOVER_130_0.S[3069]++;_hiddenValues.clear();}
307
308 __CLOVER_130_0.S[3070]++;cycle.removeAttribute(ATTRIBUTE_NAME);
309
310 __CLOVER_130_0.S[3071]++;_encodingType = null;
311
312 __CLOVER_130_0.S[3072]++;IValidationDelegate delegate = getDelegate();
313
314 __CLOVER_130_0.S[3073]++;if ((((delegate != null) && (++__CLOVER_130_0.CT[558] != 0)) || (++__CLOVER_130_0.CF[558] == 0))){
315 __CLOVER_130_0.S[3074]++;delegate.setFormComponent(null);}
316
317 __CLOVER_130_0.S[3075]++;super.cleanupAfterRender(cycle);
318 } finally { }}
319
320 protected void writeAttributes(IMarkupWriter writer, ILink link)
321 {try { __CLOVER_130_0.M[697]++;
322 __CLOVER_130_0.S[3076]++;String method = getMethod();
323
324 __CLOVER_130_0.S[3077]++;writer.begin(getTag());
325 __CLOVER_130_0.S[3078]++;writer.attribute("method", ((((method == null) ) && (++__CLOVER_130_0.CT[559] != 0)) || (++__CLOVER_130_0.CF[559] == 0))? "post" : method);
326 __CLOVER_130_0.S[3079]++;writer.attribute("name", _name);
327 __CLOVER_130_0.S[3080]++;writer.attribute("action", link.getURL(null, false));
328
329 __CLOVER_130_0.S[3081]++;if ((((_encodingType != null) && (++__CLOVER_130_0.CT[560] != 0)) || (++__CLOVER_130_0.CF[560] == 0))){
330 __CLOVER_130_0.S[3082]++;writer.attribute("enctype", _encodingType);}
331 } finally { }}
332
333 protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
334 {try { __CLOVER_130_0.M[698]++;
335 __CLOVER_130_0.S[3083]++;String actionId = cycle.getNextActionId();
336 __CLOVER_130_0.S[3084]++;_name = getDisplayName() + actionId;
337
338 __CLOVER_130_0.S[3085]++;boolean renderForm = !cycle.isRewinding();
339 __CLOVER_130_0.S[3086]++;boolean rewound = cycle.isRewound(this);
340
341 __CLOVER_130_0.S[3087]++;_rewinding = rewound;
342
343 __CLOVER_130_0.S[3088]++;_allocatedIdIndex = 0;
344
345 __CLOVER_130_0.S[3089]++;_rendering = true;
346
347 __CLOVER_130_0.S[3090]++;if ((((rewound) && (++__CLOVER_130_0.CT[561] != 0)) || (++__CLOVER_130_0.CF[561] == 0))){
348 {
349 __CLOVER_130_0.S[3091]++;String storedIdList = cycle.getRequestContext().getParameter(_name);
350
351 __CLOVER_130_0.S[3092]++;reconstructAllocatedIds(storedIdList);
352 }}
353
354 __CLOVER_130_0.S[3093]++;ILink link = getLink(cycle, actionId);
355
356 // When rendering, use a nested writer so that an embedded Upload
357 // component can force the encoding type.
358
359 __CLOVER_130_0.S[3094]++;IMarkupWriter nested = writer.getNestedWriter();
360
361 __CLOVER_130_0.S[3095]++;renderBody(nested, cycle);
362
363 __CLOVER_130_0.S[3096]++;if ((((renderForm) && (++__CLOVER_130_0.CT[562] != 0)) || (++__CLOVER_130_0.CF[562] == 0))){
364 {
365 __CLOVER_130_0.S[3097]++;writeAttributes(writer, link);
366
367 __CLOVER_130_0.S[3098]++;renderInformalParameters(writer, cycle);
368 __CLOVER_130_0.S[3099]++;writer.println();
369 }}
370
371 // Write the hidden's, or at least, reserve the query parameters
372 // required by the Gesture.
373
374 __CLOVER_130_0.S[3100]++;writeLinkParameters(writer, link, !renderForm);
375
376 __CLOVER_130_0.S[3101]++;if ((((renderForm) && (++__CLOVER_130_0.CT[563] != 0)) || (++__CLOVER_130_0.CF[563] == 0))){
377 {
378 // What's this for? It's part of checking for stale links.
379 // We record the list of allocated ids.
380 // On rewind, we check that the stored list against which
381 // ids were allocated. If the persistent state of the page or
382 // application changed between render (previous request cycle)
383 // and rewind (current request cycle), then the list
384 // of ids will change as well.
385
386 __CLOVER_130_0.S[3102]++;writeHiddenField(writer, _name, buildAllocatedIdList());
387 __CLOVER_130_0.S[3103]++;writeHiddenValues(writer);
388
389 __CLOVER_130_0.S[3104]++;nested.close();
390
391 __CLOVER_130_0.S[3105]++;writer.end(getTag());
392
393 // Write out event handlers collected during the rendering.
394
395 __CLOVER_130_0.S[3106]++;emitEventHandlers(writer, cycle);
396 }}
397
398 __CLOVER_130_0.S[3107]++;if ((((rewound) && (++__CLOVER_130_0.CT[564] != 0)) || (++__CLOVER_130_0.CF[564] == 0))){
399 {
400 __CLOVER_130_0.S[3108]++;int expected = _allocatedIds.size();
401
402 // The other case, _allocatedIdIndex > expected, is
403 // checked for inside getElementId(). Remember that
404 // _allocatedIdIndex is incremented after allocating.
405
406 __CLOVER_130_0.S[3109]++;if ((((_allocatedIdIndex < expected) && (++__CLOVER_130_0.CT[565] != 0)) || (++__CLOVER_130_0.CF[565] == 0))){
407 {
408 __CLOVER_130_0.S[3110]++;String nextExpectedId = (String) _allocatedIds.get(_allocatedIdIndex);
409
410 __CLOVER_130_0.S[3111]++;throw new StaleLinkException(
411 Tapestry.format(
412 "Form.too-few-ids",
413 getExtendedId(),
414 Integer.toString(expected - _allocatedIdIndex),
415 nextExpectedId),
416 this);
417 }}
418
419 __CLOVER_130_0.S[3112]++;IActionListener listener = getListener();
420
421 __CLOVER_130_0.S[3113]++;if ((((listener != null) && (++__CLOVER_130_0.CT[566] != 0)) || (++__CLOVER_130_0.CF[566] == 0))){
422 __CLOVER_130_0.S[3114]++;listener.actionTriggered(this, cycle);}
423
424 // Abort the rewind render.
425
426 __CLOVER_130_0.S[3115]++;throw new RenderRewoundException(this);
427 }}
428 } finally { }}
429
430 /**
431 * Adds an additional event handler.
432 *
433 * @since 1.0.2
434 *
435 **/
436
437 public void addEventHandler(FormEventType type, String functionName)
438 {try { __CLOVER_130_0.M[699]++;
439 __CLOVER_130_0.S[3116]++;if ((((_events == null) && (++__CLOVER_130_0.CT[567] != 0)) || (++__CLOVER_130_0.CF[567] == 0))){
440 __CLOVER_130_0.S[3117]++;_events = new HashMap(EVENT_MAP_SIZE);}
441
442 __CLOVER_130_0.S[3118]++;Object value = _events.get(type);
443
444 // The value can either be a String, or a List of String. Since
445 // it is rare for there to be more than one event handling function,
446 // we start with just a String.
447
448 __CLOVER_130_0.S[3119]++;if ((((value == null) && (++__CLOVER_130_0.CT[568] != 0)) || (++__CLOVER_130_0.CF[568] == 0))){
449 {
450 __CLOVER_130_0.S[3120]++;_events.put(type, functionName);
451 __CLOVER_130_0.S[3121]++;return;
452 }}
453
454 // The second function added converts it to a List.
455
456 __CLOVER_130_0.S[3122]++;if ((((value instanceof String) && (++__CLOVER_130_0.CT[569] != 0)) || (++__CLOVER_130_0.CF[569] == 0))){
457 {
458 __CLOVER_130_0.S[3123]++;List list = new ArrayList();
459 __CLOVER_130_0.S[3124]++;list.add(value);
460 __CLOVER_130_0.S[3125]++;list.add(functionName);
461
462 __CLOVER_130_0.S[3126]++;_events.put(type, list);
463 __CLOVER_130_0.S[3127]++;return;
464 }}
465
466 // The third and subsequent function just
467 // adds to the List.
468
469 __CLOVER_130_0.S[3128]++;List list = (List) value;
470 __CLOVER_130_0.S[3129]++;list.add(functionName);
471 } finally { }}
472
473 protected void emitEventHandlers(IMarkupWriter writer, IRequestCycle cycle)
474 {try { __CLOVER_130_0.M[700]++;
475
476 __CLOVER_130_0.S[3130]++;if ((((_events == null || _events.isEmpty()) && (++__CLOVER_130_0.CT[570] != 0)) || (++__CLOVER_130_0.CF[570] == 0))){
477 __CLOVER_130_0.S[3131]++;return;}
478
479 __CLOVER_130_0.S[3132]++;Body body = Body.get(cycle);
480
481 __CLOVER_130_0.S[3133]++;if ((((body == null) && (++__CLOVER_130_0.CT[571] != 0)) || (++__CLOVER_130_0.CF[571] == 0))){
482 __CLOVER_130_0.S[3134]++;throw new ApplicationRuntimeException(
483 Tapestry.getMessage("Form.needs-body-for-event-handlers"),
484 this,
485 null,
486 null);}
487
488 __CLOVER_130_0.S[3135]++;StringBuffer buffer = new StringBuffer();
489
490 __CLOVER_130_0.S[3136]++;Iterator i = _events.entrySet().iterator();
491 __CLOVER_130_0.S[3137]++;while ((((i.hasNext()) && (++__CLOVER_130_0.CT[572] != 0)) || (++__CLOVER_130_0.CF[572] == 0))){
492 {
493
494 __CLOVER_130_0.S[3138]++;Map.Entry entry = (Map.Entry) i.next();
495 __CLOVER_130_0.S[3139]++;FormEventType type = (FormEventType) entry.getKey();
496 __CLOVER_130_0.S[3140]++;Object value = entry.getValue();
497
498 __CLOVER_130_0.S[3141]++;buffer.append("document.");
499 __CLOVER_130_0.S[3142]++;buffer.append(_name);
500 __CLOVER_130_0.S[3143]++;buffer.append(".");
501 __CLOVER_130_0.S[3144]++;buffer.append(type.getPropertyName());
502 __CLOVER_130_0.S[3145]++;buffer.append(" = ");
503
504 // The typical case; one event one event handler. Easy enough.
505
506 __CLOVER_130_0.S[3146]++;if ((((value instanceof String) && (++__CLOVER_130_0.CT[573] != 0)) || (++__CLOVER_130_0.CF[573] == 0))){
507 {
508 __CLOVER_130_0.S[3147]++;buffer.append(value.toString());
509 __CLOVER_130_0.S[3148]++;buffer.append(";");
510 }}
511 else{
512 {
513 // Build a composite function in-place
514
515 __CLOVER_130_0.S[3149]++;buffer.append("function ()\n{\n");
516
517 __CLOVER_130_0.S[3150]++;boolean combineWithAnd = type.getCombineUsingAnd();
518
519 __CLOVER_130_0.S[3151]++;List l = (List) value;
520 __CLOVER_130_0.S[3152]++;int count = l.size();
521
522 __CLOVER_130_0.S[3153]++;for (int j = 0; (((j < count) && (++__CLOVER_130_0.CT[574] != 0)) || (++__CLOVER_130_0.CF[574] == 0)); j++){
523 {
524 __CLOVER_130_0.S[3154]++;String functionName = (String) l.get(j);
525
526 __CLOVER_130_0.S[3155]++;if ((((j > 0) && (++__CLOVER_130_0.CT[575] != 0)) || (++__CLOVER_130_0.CF[575] == 0))){
527 {
528
529 __CLOVER_130_0.S[3156]++;if ((((combineWithAnd) && (++__CLOVER_130_0.CT[576] != 0)) || (++__CLOVER_130_0.CF[576] == 0))){
530 __CLOVER_130_0.S[3157]++;buffer.append(" &&");}
531 else{
532 __CLOVER_130_0.S[3158]++;buffer.append(";");}
533 }}
534
535 __CLOVER_130_0.S[3159]++;buffer.append("\n ");
536
537 __CLOVER_130_0.S[3160]++;if ((((combineWithAnd) && (++__CLOVER_130_0.CT[577] != 0)) || (++__CLOVER_130_0.CF[577] == 0))){
538 {
539 __CLOVER_130_0.S[3161]++;if ((((j == 0) && (++__CLOVER_130_0.CT[578] != 0)) || (++__CLOVER_130_0.CF[578] == 0))){
540 __CLOVER_130_0.S[3162]++;buffer.append("return ");}
541 else{
542 __CLOVER_130_0.S[3163]++;buffer.append(" ");}
543 }}
544
545 __CLOVER_130_0.S[3164]++;buffer.append(functionName);
546 __CLOVER_130_0.S[3165]++;buffer.append("()");
547 }}
548
549 __CLOVER_130_0.S[3166]++;buffer.append(";\n}");
550 }}
551
552 __CLOVER_130_0.S[3167]++;buffer.append("\n\n");
553 }}
554
555 __CLOVER_130_0.S[3168]++;body.addInitializationScript(buffer.toString());
556 } finally { }}
557
558 /**
559 * Simply invokes {@link #render(IMarkupWriter, IRequestCycle)}.
560 *
561 * @since 1.0.2
562 *
563 **/
564
565 public void rewind(IMarkupWriter writer, IRequestCycle cycle)
566 {try { __CLOVER_130_0.M[701]++;
567 __CLOVER_130_0.S[3169]++;render(writer, cycle);
568 } finally { }}
569
570 /**
571 * Method invoked by the direct service.
572 *
573 * @since 1.0.2
574 *
575 **/
576
577 public void trigger(IRequestCycle cycle)
578 {try { __CLOVER_130_0.M[702]++;
579 __CLOVER_130_0.S[3170]++;Object[] parameters = cycle.getServiceParameters();
580
581 __CLOVER_130_0.S[3171]++;cycle.rewindForm(this, (String) parameters[0]);
582 } finally { }}
583
584 /**
585 * Builds the EngineServiceLink for the form, using either the direct or
586 * action service.
587 *
588 * @since 1.0.3
589 *
590 **/
591
592 private ILink getLink(IRequestCycle cycle, String actionId)
593 {try { __CLOVER_130_0.M[703]++;
594 __CLOVER_130_0.S[3172]++;String serviceName = null;
595
596 __CLOVER_130_0.S[3173]++;if ((((isDirect()) && (++__CLOVER_130_0.CT[579] != 0)) || (++__CLOVER_130_0.CF[579] == 0))){
597 __CLOVER_130_0.S[3174]++;serviceName = Tapestry.DIRECT_SERVICE;}
598 else{
599 __CLOVER_130_0.S[3175]++;serviceName = Tapestry.ACTION_SERVICE;}
600
601 __CLOVER_130_0.S[3176]++;IEngine engine = cycle.getEngine();
602 __CLOVER_130_0.S[3177]++;IEngineService service = engine.getService(serviceName);
603
604 // A single service parameter is used to store the actionId.
605
606 __CLOVER_130_0.S[3178]++;return service.getLink(cycle, this, new String[] { actionId });
607 } finally { }}
608
609 private void writeLinkParameters(IMarkupWriter writer, ILink link, boolean reserveOnly)
610 {try { __CLOVER_130_0.M[704]++;
611 __CLOVER_130_0.S[3179]++;String[] names = link.getParameterNames();
612 __CLOVER_130_0.S[3180]++;int count = Tapestry.size(names);
613
614 __CLOVER_130_0.S[3181]++;for (int i = 0; (((i < count) && (++__CLOVER_130_0.CT[580] != 0)) || (++__CLOVER_130_0.CF[580] == 0)); i++){
615 {
616 __CLOVER_130_0.S[3182]++;String name = names[i];
617
618 // Reserve the name.
619
620 __CLOVER_130_0.S[3183]++;_elementIdAllocator.allocateId(name);
621
622 __CLOVER_130_0.S[3184]++;if ((((!reserveOnly) && (++__CLOVER_130_0.CT[581] != 0)) || (++__CLOVER_130_0.CF[581] == 0))){
623 __CLOVER_130_0.S[3185]++;writeHiddenFieldsForParameter(writer, link, name);}
624 }}
625 } finally { }}
626
627 /**
628 * @since 3.0
629 *
630 **/
631
632 protected void writeHiddenField(IMarkupWriter writer, String name, String value)
633 {try { __CLOVER_130_0.M[705]++;
634 __CLOVER_130_0.S[3186]++;writeHiddenField(writer, name, null, value);
635 } finally { }}
636
637 protected void writeHiddenField(IMarkupWriter writer, String name, String id, String value)
638 {try { __CLOVER_130_0.M[706]++;
639 __CLOVER_130_0.S[3187]++;writer.beginEmpty("input");
640 __CLOVER_130_0.S[3188]++;writer.attribute("type", "hidden");
641 __CLOVER_130_0.S[3189]++;writer.attribute("name", name);
642
643 __CLOVER_130_0.S[3190]++;if((((id != null && id.length() != 0) && (++__CLOVER_130_0.CT[582] != 0)) || (++__CLOVER_130_0.CF[582] == 0))){
644 __CLOVER_130_0.S[3191]++;writer.attribute("id", id);}
645
646 __CLOVER_130_0.S[3192]++;writer.attribute("value", value);
647 __CLOVER_130_0.S[3193]++;writer.println();
648 } finally { }}
649
650 /**
651 * @since 2.2
652 *
653 **/
654
655 private void writeHiddenFieldsForParameter(
656 IMarkupWriter writer,
657 ILink link,
658 String parameterName)
659 {try { __CLOVER_130_0.M[707]++;
660 __CLOVER_130_0.S[3194]++;String[] values = link.getParameterValues(parameterName);
661
662 __CLOVER_130_0.S[3195]++;for (int i = 0; (((i < values.length) && (++__CLOVER_130_0.CT[583] != 0)) || (++__CLOVER_130_0.CF[583] == 0)); i++){
663 {
664 __CLOVER_130_0.S[3196]++;writeHiddenField(writer, parameterName, values[i]);
665 }}
666 } finally { }}
667
668 /**
669 * Converts the allocateIds property into a string, a comma-separated list of ids.
670 * This is included as a hidden field in the form and is used to identify
671 * discrepencies when the form is submitted.
672 *
673 * @since 3.0
674 *
675 **/
676
677 protected String buildAllocatedIdList()
678 {try { __CLOVER_130_0.M[708]++;
679 __CLOVER_130_0.S[3197]++;StringBuffer buffer = new StringBuffer();
680 __CLOVER_130_0.S[3198]++;int count = _allocatedIds.size();
681
682 __CLOVER_130_0.S[3199]++;for (int i = 0; (((i < count) && (++__CLOVER_130_0.CT[584] != 0)) || (++__CLOVER_130_0.CF[584] == 0)); i++){
683 {
684 __CLOVER_130_0.S[3200]++;if ((((i > 0) && (++__CLOVER_130_0.CT[585] != 0)) || (++__CLOVER_130_0.CF[585] == 0))){
685 __CLOVER_130_0.S[3201]++;buffer.append(',');}
686
687 __CLOVER_130_0.S[3202]++;buffer.append(_allocatedIds.get(i));
688 }}
689
690 __CLOVER_130_0.S[3203]++;return buffer.toString();
691 } finally { }}
692
693 /**
694 * Converts a string passed as a parameter (and containing a comma
695 * separated list of ids) back into the allocateIds property.
696 *
697 * @see #buildAllocatedIdList()
698 *
699 * @since 3.0
700 *
701 **/
702
703 protected void reconstructAllocatedIds(String storedIdList)
704 {try { __CLOVER_130_0.M[709]++;
705 __CLOVER_130_0.S[3204]++;if ((((Tapestry.isBlank(storedIdList)) && (++__CLOVER_130_0.CT[586] != 0)) || (++__CLOVER_130_0.CF[586] == 0))){
706 __CLOVER_130_0.S[3205]++;return;}
707
708 __CLOVER_130_0.S[3206]++;StringSplitter splitter = new StringSplitter(',');
709
710 __CLOVER_130_0.S[3207]++;String[] ids = splitter.splitToArray(storedIdList);
711
712 __CLOVER_130_0.S[3208]++;for (int i = 0; (((i < ids.length) && (++__CLOVER_130_0.CT[587] != 0)) || (++__CLOVER_130_0.CF[587] == 0)); i++){
713 __CLOVER_130_0.S[3209]++;_allocatedIds.add(ids[i]);}
714 } finally { }}
715
716 public abstract IValidationDelegate getDelegate();
717
718 public abstract void setDelegate(IValidationDelegate delegate);
719
720 public abstract void setDirect(boolean direct);
721
722 public abstract IActionListener getListener();
723
724 public abstract String getMethod();
725
726 /**
727 * Invoked when not rendering, so it uses the stateful binding.
728 * If not bound, returns true.
729 *
730 **/
731
732 public boolean isStateful()
733 {try { __CLOVER_130_0.M[710]++;
734 __CLOVER_130_0.S[3210]++;IBinding statefulBinding = getStatefulBinding();
735
736 __CLOVER_130_0.S[3211]++;if ((((statefulBinding == null) && (++__CLOVER_130_0.CT[588] != 0)) || (++__CLOVER_130_0.CF[588] == 0))){
737 __CLOVER_130_0.S[3212]++;return true;}
738
739 __CLOVER_130_0.S[3213]++;return statefulBinding.getBoolean();
740 } finally { }}
741
742 public abstract IBinding getStatefulBinding();
743
744 protected void finishLoad()
745 {try { __CLOVER_130_0.M[711]++;
746 __CLOVER_130_0.S[3214]++;setDirect(true);
747 } finally { }}
748
749 public void setEncodingType(String encodingType)
750 {try { __CLOVER_130_0.M[712]++;
751 __CLOVER_130_0.S[3215]++;if ((((_encodingType != null && !_encodingType.equals(encodingType)) && (++__CLOVER_130_0.CT[589] != 0)) || (++__CLOVER_130_0.CF[589] == 0))){
752 __CLOVER_130_0.S[3216]++;throw new ApplicationRuntimeException(
753 Tapestry.format(
754 "Form.encoding-type-contention",
755 getExtendedId(),
756 _encodingType,
757 encodingType),
758 this,
759 null,
760 null);}
761
762 __CLOVER_130_0.S[3217]++;_encodingType = encodingType;
763 } finally { }}
764
765 /**
766 * Returns the tag of the form.
767 *
768 * @since 3.0
769 *
770 **/
771
772 protected String getTag()
773 {try { __CLOVER_130_0.M[713]++;
774 __CLOVER_130_0.S[3218]++;return "form";
775 } finally { }}
776
777 /**
778 * Returns the name of the element.
779 *
780 *
781 * @since 3.0
782 **/
783
784 protected String getDisplayName()
785 {try { __CLOVER_130_0.M[714]++;
786 __CLOVER_130_0.S[3219]++;return "Form";
787 } finally { }}
788
789 /** @since 3.0 */
790
791 public void addHiddenValue(String name, String value)
792 {try { __CLOVER_130_0.M[715]++;
793 __CLOVER_130_0.S[3220]++;if ((((_hiddenValues == null) && (++__CLOVER_130_0.CT[590] != 0)) || (++__CLOVER_130_0.CF[590] == 0))){
794 __CLOVER_130_0.S[3221]++;_hiddenValues = new ArrayList();}
795
796 __CLOVER_130_0.S[3222]++;_hiddenValues.add(new HiddenValue(name, value));
797 } finally { }}
798
799 /** @since 3.0 */
800
801 public void addHiddenValue(String name, String id, String value)
802 {try { __CLOVER_130_0.M[716]++;
803 __CLOVER_130_0.S[3223]++;if ((((_hiddenValues == null) && (++__CLOVER_130_0.CT[591] != 0)) || (++__CLOVER_130_0.CF[591] == 0))){
804 __CLOVER_130_0.S[3224]++;_hiddenValues = new ArrayList();}
805
806 __CLOVER_130_0.S[3225]++;_hiddenValues.add(new HiddenValue(name, id, value));
807 } finally { }}
808
809 /**
810 * Writes hidden values accumulated during the render
811 * (by components invoking {@link #addHiddenValue(String, String)}.
812 *
813 * @since 3.0
814 */
815
816 protected void writeHiddenValues(IMarkupWriter writer)
817 {try { __CLOVER_130_0.M[717]++;
818 __CLOVER_130_0.S[3226]++;int count = Tapestry.size(_hiddenValues);
819
820 __CLOVER_130_0.S[3227]++;for (int i = 0; (((i < count) && (++__CLOVER_130_0.CT[592] != 0)) || (++__CLOVER_130_0.CF[592] == 0)); i++){
821 {
822 __CLOVER_130_0.S[3228]++;HiddenValue hv = (HiddenValue) _hiddenValues.get(i);
823
824 __CLOVER_130_0.S[3229]++;writeHiddenField(writer, hv._name, hv._id, hv._value);
825 }}
826 } finally { }}
827 }