|
|||||||||||||||||||
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover | |||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
FormSupportImpl.java | 98.4% | 99.4% | 100% | 99.3% |
|
1 |
// Copyright 2005 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.Arrays;
|
|
19 |
import java.util.Collections;
|
|
20 |
import java.util.HashMap;
|
|
21 |
import java.util.HashSet;
|
|
22 |
import java.util.Iterator;
|
|
23 |
import java.util.List;
|
|
24 |
import java.util.Map;
|
|
25 |
import java.util.Set;
|
|
26 |
|
|
27 |
import org.apache.hivemind.ApplicationRuntimeException;
|
|
28 |
import org.apache.hivemind.HiveMind;
|
|
29 |
import org.apache.hivemind.Location;
|
|
30 |
import org.apache.hivemind.util.Defense;
|
|
31 |
import org.apache.tapestry.FormSupport;
|
|
32 |
import org.apache.tapestry.IComponent;
|
|
33 |
import org.apache.tapestry.IForm;
|
|
34 |
import org.apache.tapestry.IMarkupWriter;
|
|
35 |
import org.apache.tapestry.IRender;
|
|
36 |
import org.apache.tapestry.IRequestCycle;
|
|
37 |
import org.apache.tapestry.NestedMarkupWriter;
|
|
38 |
import org.apache.tapestry.PageRenderSupport;
|
|
39 |
import org.apache.tapestry.StaleLinkException;
|
|
40 |
import org.apache.tapestry.Tapestry;
|
|
41 |
import org.apache.tapestry.TapestryUtils;
|
|
42 |
import org.apache.tapestry.engine.ILink;
|
|
43 |
import org.apache.tapestry.services.ServiceConstants;
|
|
44 |
import org.apache.tapestry.util.IdAllocator;
|
|
45 |
|
|
46 |
/**
|
|
47 |
* Encapsulates most of the behavior of a Form component.
|
|
48 |
*
|
|
49 |
* @author Howard M. Lewis Ship
|
|
50 |
* @since 4.0
|
|
51 |
*/
|
|
52 |
public class FormSupportImpl implements FormSupport |
|
53 |
{ |
|
54 |
/**
|
|
55 |
* Name of query parameter storing the ids alloocated while rendering the form, as a comma
|
|
56 |
* seperated list. This information is used when the form is submitted, to ensure that the
|
|
57 |
* rewind allocates the exact same sequence of ids.
|
|
58 |
*/
|
|
59 |
|
|
60 |
public static final String FORM_IDS = "formids"; |
|
61 |
|
|
62 |
/**
|
|
63 |
* Names of additional ids that were pre-reserved, as a comma-sepereated list. These are names
|
|
64 |
* beyond that standard set. Certain engine services include extra parameter values that must be
|
|
65 |
* accounted for, and page properties may be encoded as additional query parameters.
|
|
66 |
*/
|
|
67 |
|
|
68 |
public static final String RESERVED_FORM_IDS = "reservedids"; |
|
69 |
|
|
70 |
private final static Set _standardReservedIds; |
|
71 |
|
|
72 |
static
|
|
73 |
{ |
|
74 | 1 |
Set set = new HashSet();
|
75 |
|
|
76 | 1 |
set.addAll(Arrays.asList(ServiceConstants.RESERVED_IDS)); |
77 | 1 |
set.add(FORM_IDS); |
78 | 1 |
set.add(RESERVED_FORM_IDS); |
79 |
|
|
80 | 1 |
_standardReservedIds = Collections.unmodifiableSet(set); |
81 |
} |
|
82 |
|
|
83 |
/**
|
|
84 |
* Used when rewinding the form to figure to match allocated ids (allocated during the rewind)
|
|
85 |
* against expected ids (allocated in the previous request cycle, when the form was rendered).
|
|
86 |
*/
|
|
87 |
|
|
88 |
private int _allocatedIdIndex; |
|
89 |
|
|
90 |
/**
|
|
91 |
* The list of allocated ids for form elements within this form. This list is constructed when a
|
|
92 |
* form renders, and is validated against when the form is rewound.
|
|
93 |
*/
|
|
94 |
|
|
95 |
private final List _allocatedIds = new ArrayList(); |
|
96 |
|
|
97 |
private final IRequestCycle _cycle;
|
|
98 |
|
|
99 |
private final IdAllocator _elementIdAllocator = new IdAllocator(); |
|
100 |
|
|
101 |
private String _encodingType;
|
|
102 |
|
|
103 |
private final List _deferredRunnables = new ArrayList(); |
|
104 |
|
|
105 |
/**
|
|
106 |
* Map keyed on extended component id, value is the pre-rendered markup for that component.
|
|
107 |
*/
|
|
108 |
|
|
109 |
private final Map _prerenderMap = new HashMap(); |
|
110 |
|
|
111 |
/**
|
|
112 |
* {@link Map}, keyed on {@link FormEventType}. Values are either a String (the function name
|
|
113 |
* of a single event handler), or a List of Strings (a sequence of event handler function
|
|
114 |
* names).
|
|
115 |
*/
|
|
116 |
|
|
117 |
private Map _events;
|
|
118 |
|
|
119 |
private final IForm _form;
|
|
120 |
|
|
121 |
private final List _hiddenValues = new ArrayList(); |
|
122 |
|
|
123 |
private boolean _rewinding; |
|
124 |
|
|
125 |
private final IMarkupWriter _writer;
|
|
126 |
|
|
127 | 115 |
public FormSupportImpl(IMarkupWriter writer, IRequestCycle cycle, IForm form)
|
128 |
{ |
|
129 | 115 |
Defense.notNull(writer, "writer");
|
130 | 115 |
Defense.notNull(cycle, "cycle");
|
131 | 115 |
Defense.notNull(form, "form");
|
132 |
|
|
133 | 115 |
_writer = writer; |
134 | 115 |
_cycle = cycle; |
135 | 115 |
_form = form; |
136 |
|
|
137 | 115 |
_rewinding = cycle.isRewound(form); |
138 | 115 |
_allocatedIdIndex = 0; |
139 |
} |
|
140 |
|
|
141 |
/**
|
|
142 |
* Adds an event handler for the form, of the given type.
|
|
143 |
*/
|
|
144 |
|
|
145 | 10 |
public void addEventHandler(FormEventType type, String functionName) |
146 |
{ |
|
147 | 10 |
if (_events == null) |
148 | 5 |
_events = new HashMap();
|
149 |
|
|
150 | 10 |
Object value = _events.get(type); |
151 |
|
|
152 |
// The value can either be a String, or a List of String. Since
|
|
153 |
// it is rare for there to be more than one event handling function,
|
|
154 |
// we start with just a String.
|
|
155 |
|
|
156 | 10 |
if (value == null) |
157 |
{ |
|
158 | 5 |
_events.put(type, functionName); |
159 | 5 |
return;
|
160 |
} |
|
161 |
|
|
162 |
// The second function added converts it to a List.
|
|
163 |
|
|
164 | 5 |
if (value instanceof String) |
165 |
{ |
|
166 | 4 |
List list = new ArrayList();
|
167 | 4 |
list.add(value); |
168 | 4 |
list.add(functionName); |
169 |
|
|
170 | 4 |
_events.put(type, list); |
171 | 4 |
return;
|
172 |
} |
|
173 |
|
|
174 |
// The third and subsequent function just
|
|
175 |
// adds to the List.
|
|
176 |
|
|
177 | 1 |
List list = (List) value; |
178 | 1 |
list.add(functionName); |
179 |
} |
|
180 |
|
|
181 |
/**
|
|
182 |
* Adds hidden fields for parameters provided by the {@link ILink}. These parameters define the
|
|
183 |
* information needed to dispatch the request, plus state information. The names of these
|
|
184 |
* parameters must be reserved so that conflicts don't occur that could disrupt the request
|
|
185 |
* processing. For example, if the id 'page' is not reserved, then a conflict could occur with a
|
|
186 |
* component whose id is 'page'. A certain number of ids are always reserved, and we find any
|
|
187 |
* additional ids beyond that set.
|
|
188 |
*/
|
|
189 |
|
|
190 | 72 |
private void addHiddenFieldsForLinkParameters(ILink link) |
191 |
{ |
|
192 | 72 |
String[] names = link.getParameterNames(); |
193 | 72 |
int count = Tapestry.size(names);
|
194 |
|
|
195 | 72 |
StringBuffer extraIds = new StringBuffer();
|
196 | 72 |
String sep = "";
|
197 | 72 |
boolean hasExtra = false; |
198 |
|
|
199 |
// All the reserved ids, which are essential for
|
|
200 |
// dispatching the request, are automatically reserved.
|
|
201 |
// Thus, if you have a component with an id of 'service', its element id
|
|
202 |
// will likely be 'service$0'.
|
|
203 |
|
|
204 | 72 |
preallocateReservedIds(); |
205 |
|
|
206 | 72 |
for (int i = 0; i < count; i++) |
207 |
{ |
|
208 | 382 |
String name = names[i]; |
209 |
|
|
210 |
// Reserve the name.
|
|
211 |
|
|
212 | 382 |
if (!_standardReservedIds.contains(name))
|
213 |
{ |
|
214 | 17 |
_elementIdAllocator.allocateId(name); |
215 |
|
|
216 | 17 |
extraIds.append(sep); |
217 | 17 |
extraIds.append(name); |
218 |
|
|
219 | 17 |
sep = ",";
|
220 | 17 |
hasExtra = true;
|
221 |
} |
|
222 |
|
|
223 | 382 |
addHiddenFieldsForLinkParameter(link, name); |
224 |
} |
|
225 |
|
|
226 | 72 |
if (hasExtra)
|
227 | 17 |
addHiddenValue(RESERVED_FORM_IDS, extraIds.toString()); |
228 |
} |
|
229 |
|
|
230 | 263 |
public void addHiddenValue(String name, String value) |
231 |
{ |
|
232 | 263 |
_hiddenValues.add(new HiddenFieldData(name, value));
|
233 |
} |
|
234 |
|
|
235 | 5 |
public void addHiddenValue(String name, String id, String value) |
236 |
{ |
|
237 | 5 |
_hiddenValues.add(new HiddenFieldData(name, id, value));
|
238 |
} |
|
239 |
|
|
240 |
/**
|
|
241 |
* Converts the allocateIds property into a string, a comma-separated list of ids. This is
|
|
242 |
* included as a hidden field in the form and is used to identify discrepencies when the form is
|
|
243 |
* submitted.
|
|
244 |
*/
|
|
245 |
|
|
246 | 66 |
private String buildAllocatedIdList()
|
247 |
{ |
|
248 | 66 |
StringBuffer buffer = new StringBuffer();
|
249 | 66 |
int count = _allocatedIds.size();
|
250 |
|
|
251 | 66 |
for (int i = 0; i < count; i++) |
252 |
{ |
|
253 | 70 |
if (i > 0)
|
254 | 26 |
buffer.append(','); |
255 |
|
|
256 | 70 |
buffer.append(_allocatedIds.get(i)); |
257 |
} |
|
258 |
|
|
259 | 66 |
return buffer.toString();
|
260 |
} |
|
261 |
|
|
262 | 66 |
private void emitEventHandlers() |
263 |
{ |
|
264 | 66 |
if (_events == null || _events.isEmpty()) |
265 | 61 |
return;
|
266 |
|
|
267 | 5 |
PageRenderSupport pageRenderSupport = TapestryUtils.getPageRenderSupport(_cycle, _form); |
268 |
|
|
269 | 5 |
StringBuffer buffer = new StringBuffer();
|
270 |
|
|
271 | 5 |
Iterator i = _events.entrySet().iterator(); |
272 | 5 |
while (i.hasNext())
|
273 |
{ |
|
274 |
|
|
275 | 5 |
Map.Entry entry = (Map.Entry) i.next(); |
276 | 5 |
FormEventType type = (FormEventType) entry.getKey(); |
277 | 5 |
Object value = entry.getValue(); |
278 |
|
|
279 | 5 |
buffer.append("document.");
|
280 | 5 |
buffer.append(_form.getName()); |
281 | 5 |
buffer.append(".");
|
282 | 5 |
buffer.append(type.getPropertyName()); |
283 | 5 |
buffer.append(" = ");
|
284 |
|
|
285 |
// The typical case; one event one event handler. Easy enough.
|
|
286 |
|
|
287 | 5 |
if (value instanceof String) |
288 |
{ |
|
289 | 1 |
buffer.append(value.toString()); |
290 | 1 |
buffer.append(";");
|
291 |
} |
|
292 |
else
|
|
293 |
{ |
|
294 |
// Build a composite function in-place
|
|
295 |
|
|
296 | 4 |
buffer.append("function ()\n{");
|
297 |
|
|
298 | 4 |
boolean combineWithAnd = type.getCombineUsingAnd();
|
299 |
|
|
300 | 4 |
List l = (List) value; |
301 | 4 |
int count = l.size();
|
302 |
|
|
303 | 4 |
for (int j = 0; j < count; j++) |
304 |
{ |
|
305 | 9 |
String functionName = (String) l.get(j); |
306 |
|
|
307 | 9 |
if (j > 0)
|
308 |
{ |
|
309 |
|
|
310 | 5 |
if (combineWithAnd)
|
311 | 4 |
buffer.append(" &&");
|
312 |
else
|
|
313 | 1 |
buffer.append(";");
|
314 |
} |
|
315 |
|
|
316 | 9 |
buffer.append("\n ");
|
317 |
|
|
318 | 9 |
if (combineWithAnd)
|
319 |
{ |
|
320 | 7 |
if (j == 0)
|
321 | 3 |
buffer.append("return ");
|
322 |
else
|
|
323 | 4 |
buffer.append(" ");
|
324 |
} |
|
325 |
|
|
326 | 9 |
buffer.append(functionName); |
327 | 9 |
buffer.append("()");
|
328 |
} |
|
329 |
|
|
330 | 4 |
buffer.append(";\n}");
|
331 |
} |
|
332 |
|
|
333 | 5 |
buffer.append("\n");
|
334 |
} |
|
335 |
|
|
336 | 5 |
pageRenderSupport.addInitializationScript(buffer.toString()); |
337 |
} |
|
338 |
|
|
339 |
/**
|
|
340 |
* Constructs a unique identifier (within the Form). The identifier consists of the component's
|
|
341 |
* id, with an index number added to ensure uniqueness.
|
|
342 |
* <p>
|
|
343 |
* Simply invokes
|
|
344 |
* {@link #getElementId(org.apache.tapestry.form.IFormComponent, java.lang.String)}with the
|
|
345 |
* component's id.
|
|
346 |
*/
|
|
347 |
|
|
348 | 18 |
public String getElementId(IFormComponent component)
|
349 |
{ |
|
350 | 18 |
return getElementId(component, component.getId());
|
351 |
} |
|
352 |
|
|
353 |
/**
|
|
354 |
* Constructs a unique identifier (within the Form). The identifier consists of the component's
|
|
355 |
* id, with an index number added to ensure uniqueness.
|
|
356 |
* <p>
|
|
357 |
* Simply invokes
|
|
358 |
* {@link #getElementId(org.apache.tapestry.form.IFormComponent, java.lang.String)}with the
|
|
359 |
* component's id.
|
|
360 |
*/
|
|
361 |
|
|
362 | 140 |
public String getElementId(IFormComponent component, String baseId)
|
363 |
{ |
|
364 | 140 |
String result = _elementIdAllocator.allocateId(baseId); |
365 |
|
|
366 | 140 |
if (_rewinding)
|
367 |
{ |
|
368 | 67 |
if (_allocatedIdIndex >= _allocatedIds.size())
|
369 |
{ |
|
370 | 1 |
throw new StaleLinkException(FormMessages.formTooManyIds(_form, _allocatedIds |
371 |
.size(), component), component); |
|
372 |
} |
|
373 |
|
|
374 | 66 |
String expected = (String) _allocatedIds.get(_allocatedIdIndex); |
375 |
|
|
376 | 66 |
if (!result.equals(expected))
|
377 | 2 |
throw new StaleLinkException(FormMessages.formIdMismatch( |
378 |
_form, |
|
379 |
_allocatedIdIndex, |
|
380 |
expected, |
|
381 |
result, |
|
382 |
component), component); |
|
383 |
} |
|
384 |
else
|
|
385 |
{ |
|
386 | 73 |
_allocatedIds.add(result); |
387 |
} |
|
388 |
|
|
389 | 137 |
_allocatedIdIndex++; |
390 |
|
|
391 | 137 |
component.setName(result); |
392 |
|
|
393 | 137 |
return result;
|
394 |
} |
|
395 |
|
|
396 | 221 |
public boolean isRewinding() |
397 |
{ |
|
398 | 221 |
return _rewinding;
|
399 |
} |
|
400 |
|
|
401 | 115 |
private void preallocateReservedIds() |
402 |
{ |
|
403 | 115 |
for (int i = 0; i < ServiceConstants.RESERVED_IDS.length; i++) |
404 | 690 |
_elementIdAllocator.allocateId(ServiceConstants.RESERVED_IDS[i]); |
405 |
} |
|
406 |
|
|
407 |
/**
|
|
408 |
* Invoked when rewinding a form to re-initialize the _allocatedIds and _elementIdAllocator.
|
|
409 |
* Converts a string passed as a parameter (and containing a comma separated list of ids) back
|
|
410 |
* into the allocateIds property. In addition, return the state of the ID allocater back to
|
|
411 |
* where it was at the start of the render.
|
|
412 |
*
|
|
413 |
* @see #buildAllocatedIdList()
|
|
414 |
* @since 3.0
|
|
415 |
*/
|
|
416 |
|
|
417 | 43 |
private void reinitializeIdAllocatorForRewind() |
418 |
{ |
|
419 | 43 |
String allocatedFormIds = _cycle.getParameter(FORM_IDS); |
420 |
|
|
421 | 43 |
String[] ids = TapestryUtils.split(allocatedFormIds); |
422 |
|
|
423 | 43 |
for (int i = 0; i < ids.length; i++) |
424 | 71 |
_allocatedIds.add(ids[i]); |
425 |
|
|
426 |
// Now, reconstruct the the initial state of the
|
|
427 |
// id allocator.
|
|
428 |
|
|
429 | 43 |
preallocateReservedIds(); |
430 |
|
|
431 | 43 |
String extraReservedIds = _cycle.getParameter(RESERVED_FORM_IDS); |
432 |
|
|
433 | 43 |
ids = TapestryUtils.split(extraReservedIds); |
434 |
|
|
435 | 43 |
for (int i = 0; i < ids.length; i++) |
436 | 3 |
_elementIdAllocator.allocateId(ids[i]); |
437 |
} |
|
438 |
|
|
439 | 72 |
public void render(String method, IRender informalParametersRenderer, ILink link) |
440 |
{ |
|
441 |
// Convert the link's query parameters into a series of
|
|
442 |
// hidden field values (that will be rendered later).
|
|
443 |
|
|
444 | 72 |
addHiddenFieldsForLinkParameters(link); |
445 |
|
|
446 | 72 |
IMarkupWriter nested = _writer.getNestedWriter(); |
447 |
|
|
448 | 72 |
_form.renderBody(nested, _cycle); |
449 |
|
|
450 | 66 |
runDeferredRunnables(); |
451 |
|
|
452 | 66 |
writeTag(_writer, method, link.getURL(null, false)); |
453 |
|
|
454 | 66 |
_writer.attribute("name", _form.getName());
|
455 |
|
|
456 | 66 |
if (_encodingType != null) |
457 | 3 |
_writer.attribute("enctype", _encodingType);
|
458 |
|
|
459 |
// Write out event handlers collected during the rendering.
|
|
460 |
|
|
461 | 66 |
emitEventHandlers(); |
462 |
|
|
463 | 66 |
informalParametersRenderer.render(_writer, _cycle); |
464 |
|
|
465 |
// Finish the <form> tag
|
|
466 |
|
|
467 | 66 |
_writer.println(); |
468 |
|
|
469 | 66 |
writeHiddenField(FORM_IDS, null, buildAllocatedIdList());
|
470 | 66 |
writeHiddenFields(); |
471 |
|
|
472 |
// Close the nested writer, inserting its contents.
|
|
473 |
|
|
474 | 66 |
nested.close(); |
475 |
|
|
476 |
// Close the <form> tag.
|
|
477 |
|
|
478 | 66 |
_writer.end(); |
479 |
} |
|
480 |
|
|
481 | 43 |
public void rewind() |
482 |
{ |
|
483 | 43 |
reinitializeIdAllocatorForRewind(); |
484 |
|
|
485 | 43 |
_form.getDelegate().clear(); |
486 |
|
|
487 | 43 |
_form.renderBody(_writer, _cycle); |
488 |
|
|
489 | 39 |
int expected = _allocatedIds.size();
|
490 |
|
|
491 |
// The other case, _allocatedIdIndex > expected, is
|
|
492 |
// checked for inside getElementId(). Remember that
|
|
493 |
// _allocatedIdIndex is incremented after allocating.
|
|
494 |
|
|
495 | 39 |
if (_allocatedIdIndex < expected)
|
496 |
{ |
|
497 | 1 |
String nextExpectedId = (String) _allocatedIds.get(_allocatedIdIndex); |
498 |
|
|
499 | 1 |
throw new StaleLinkException(FormMessages.formTooFewIds(_form, expected |
500 |
- _allocatedIdIndex, nextExpectedId), _form); |
|
501 |
} |
|
502 |
|
|
503 | 38 |
runDeferredRunnables(); |
504 |
} |
|
505 |
|
|
506 | 104 |
private void runDeferredRunnables() |
507 |
{ |
|
508 | 104 |
Iterator i = _deferredRunnables.iterator(); |
509 | 104 |
while (i.hasNext())
|
510 |
{ |
|
511 | 2 |
Runnable r = (Runnable) i.next(); |
512 |
|
|
513 | 2 |
r.run(); |
514 |
} |
|
515 |
} |
|
516 |
|
|
517 | 5 |
public void setEncodingType(String encodingType) |
518 |
{ |
|
519 |
|
|
520 | 5 |
if (_encodingType != null && !_encodingType.equals(encodingType)) |
521 | 1 |
throw new ApplicationRuntimeException(FormMessages.encodingTypeContention( |
522 |
_form, |
|
523 |
_encodingType, |
|
524 |
encodingType), _form, null, null); |
|
525 |
|
|
526 | 4 |
_encodingType = encodingType; |
527 |
} |
|
528 |
|
|
529 | 284 |
protected void writeHiddenField(IMarkupWriter writer, String name, String id, String value) |
530 |
{ |
|
531 | 284 |
writer.beginEmpty("input");
|
532 | 284 |
writer.attribute("type", "hidden"); |
533 | 284 |
writer.attribute("name", name);
|
534 |
|
|
535 | 284 |
if (HiveMind.isNonBlank(id))
|
536 | 2 |
writer.attribute("id", id);
|
537 |
|
|
538 | 284 |
writer.attribute("value", value);
|
539 | 284 |
writer.println(); |
540 |
} |
|
541 |
|
|
542 | 314 |
private void writeHiddenField(String name, String id, String value) |
543 |
{ |
|
544 | 314 |
writeHiddenField(_writer, name, id, value); |
545 |
} |
|
546 |
|
|
547 |
/**
|
|
548 |
* Writes out all hidden values previously added by
|
|
549 |
* {@link #addHiddenValue(String, String, String)}.
|
|
550 |
*/
|
|
551 |
|
|
552 | 66 |
private void writeHiddenFields() |
553 |
{ |
|
554 | 66 |
Iterator i = _hiddenValues.iterator(); |
555 | 66 |
while (i.hasNext())
|
556 |
{ |
|
557 | 248 |
HiddenFieldData data = (HiddenFieldData) i.next(); |
558 |
|
|
559 | 248 |
writeHiddenField(data.getName(), data.getId(), data.getValue()); |
560 |
} |
|
561 |
} |
|
562 |
|
|
563 | 382 |
private void addHiddenFieldsForLinkParameter(ILink link, String parameterName) |
564 |
{ |
|
565 | 382 |
String[] values = link.getParameterValues(parameterName); |
566 |
|
|
567 |
// In some cases, there are no values, but a space is "reserved" for the provided name.
|
|
568 |
|
|
569 | 382 |
if (values == null) |
570 | 143 |
return;
|
571 |
|
|
572 | 239 |
for (int i = 0; i < values.length; i++) |
573 |
{ |
|
574 | 239 |
addHiddenValue(parameterName, values[i]); |
575 |
} |
|
576 |
} |
|
577 |
|
|
578 | 60 |
protected void writeTag(IMarkupWriter writer, String method, String url) |
579 |
{ |
|
580 | 60 |
writer.begin("form");
|
581 | 60 |
writer.attribute("method", method);
|
582 | 60 |
writer.attribute("action", url);
|
583 |
} |
|
584 |
|
|
585 | 5 |
public void prerenderField(IMarkupWriter writer, IComponent field, Location location) |
586 |
{ |
|
587 | 5 |
Defense.notNull(writer, "writer");
|
588 | 5 |
Defense.notNull(field, "field");
|
589 |
|
|
590 | 5 |
String key = field.getExtendedId(); |
591 |
|
|
592 | 5 |
if (_prerenderMap.containsKey(key))
|
593 | 0 |
throw new ApplicationRuntimeException(FormMessages.fieldAlreadyPrerendered(field), |
594 |
location, null);
|
|
595 |
|
|
596 | 5 |
NestedMarkupWriter nested = writer.getNestedWriter(); |
597 |
|
|
598 | 5 |
field.render(nested, _cycle); |
599 |
|
|
600 | 5 |
_prerenderMap.put(key, nested.getBuffer()); |
601 |
} |
|
602 |
|
|
603 | 106 |
public boolean wasPrerendered(IMarkupWriter writer, IComponent field) |
604 |
{ |
|
605 | 106 |
String key = field.getExtendedId(); |
606 |
|
|
607 | 106 |
String buffer = (String) _prerenderMap.get(key); |
608 |
|
|
609 | 106 |
if (buffer == null) |
610 | 101 |
return false; |
611 |
|
|
612 | 5 |
writer.printRaw(buffer); |
613 |
|
|
614 | 5 |
_prerenderMap.remove(key); |
615 |
|
|
616 | 5 |
return true; |
617 |
} |
|
618 |
|
|
619 | 2 |
public void addDeferredRunnable(Runnable runnable) |
620 |
{ |
|
621 | 2 |
Defense.notNull(runnable, "runnable");
|
622 |
|
|
623 | 2 |
_deferredRunnables.add(runnable); |
624 |
} |
|
625 |
} |
|