blib/lib/HTML/StickyForm.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 40 | 248 | 16.1 |
branch | 18 | 100 | 18.0 |
condition | 2 | 30 | 6.6 |
subroutine | 10 | 24 | 41.6 |
pod | 18 | 18 | 100.0 |
total | 88 | 420 | 20.9 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | |||||||
2 | =head1 NAME | ||||||
3 | |||||||
4 | HTML::StickyForm - Lightweight general-purpose HTML form generation, with sticky values | ||||||
5 | |||||||
6 | =head1 SYNOPSIS | ||||||
7 | |||||||
8 | # mod_perl example | ||||||
9 | |||||||
10 | use HTML::StickyForm; | ||||||
11 | use Apache::Request; | ||||||
12 | |||||||
13 | sub handler{ | ||||||
14 | my($r)=@_; | ||||||
15 | $r=Apache::Request->new($r); | ||||||
16 | my $f=HTML::StickyForm->new($r); | ||||||
17 | |||||||
18 | $r->send_http_header; | ||||||
19 | |||||||
20 | '', | ||||||
21 | $form->form_start, | ||||||
22 | |||||||
23 | "Text field:", | ||||||
24 | $f->text(name => 'field1', size => 40, default => 'default value'), | ||||||
25 | |||||||
26 | " Text area:", |
||||||
27 | $f->textarea(name => 'field2', cols => 60, rows => 5, default => 'stuff'), | ||||||
28 | |||||||
29 | " Single radio button:", |
||||||
30 | $f->radio(name => 'field3', value => 'xyz', checked => 1), | ||||||
31 | |||||||
32 | " Radio buttons:", |
||||||
33 | $f->radio_group(name => 'field4', values => [1,2,3], | ||||||
34 | labels => { 1=>'one', 2=>'two', 3=>'three' }, default => 2), | ||||||
35 | |||||||
36 | " Single checkbox:", |
||||||
37 | $f->checkbox(name => 'field5', value => 'xyz', checked => 1), | ||||||
38 | |||||||
39 | " Checkbox group:", |
||||||
40 | $f->checkbox_group(name => 'field6', values => [4,5,6], | ||||||
41 | labels => { 4=>'four', 5=>'five', 6=>'six' }, default => [5,6]), | ||||||
42 | |||||||
43 | " Password field:", |
||||||
44 | $f->password(name => 'field7', size => 20), | ||||||
45 | |||||||
46 | ' ", |
||||||
47 | $f->submit(value => ' Hit me! '), | ||||||
48 | |||||||
49 | $f->form_end, | ||||||
50 | '', | ||||||
51 | ; | ||||||
52 | return OK; | ||||||
53 | } | ||||||
54 | |||||||
55 | =head1 DESCRIPTION | ||||||
56 | |||||||
57 | This module provides a simple interface for generating HTML form | ||||||
58 | elements, with default values chosen from the previous form submission. This | ||||||
59 | module was written with mod_perl (L |
||||||
60 | equally well with CGI.pm, including the new 3.x version, or any other module | ||||||
61 | which implements a param() method, or even completely standalone. | ||||||
62 | |||||||
63 | The module does not provide methods for generating all possible HTML elements, | ||||||
64 | only those which are used in form construction. | ||||||
65 | In addition, this module's interface is much less flexible than CGI.pm's; all | ||||||
66 | routines work only as methods, and there is only one way of passing parameters | ||||||
67 | to each method. This was done for two reasons: to keep the API simple and | ||||||
68 | consistent, and to keep the code size down to a minimum. | ||||||
69 | |||||||
70 | =cut | ||||||
71 | |||||||
72 | |||||||
73 | package HTML::StickyForm; | ||||||
74 | BEGIN { | ||||||
75 | 7 | 7 | 169502 | $HTML::StickyForm::VERSION = '0.08'; | |||
76 | } | ||||||
77 | 7 | 7 | 58 | use strict; | |||
7 | 13 | ||||||
7 | 201 | ||||||
78 | 7 | 7 | 33 | use warnings; | |||
7 | 14 | ||||||
7 | 20772 | ||||||
79 | |||||||
80 | =head1 CLASS METHODS | ||||||
81 | |||||||
82 | =over | ||||||
83 | |||||||
84 | =item new([REQUEST]) | ||||||
85 | |||||||
86 | Creates a new form generation object. The single argument can be: | ||||||
87 | |||||||
88 | =over | ||||||
89 | |||||||
90 | =item * | ||||||
91 | |||||||
92 | any object which responds to a C method in the same way that L |
||||||
93 | L |
||||||
94 | parameters are returned as a list. With a single argument, the value(s) of the | ||||||
95 | supplied parameter is/are returned; in scalar context the first value, | ||||||
96 | and in list context all values. | ||||||
97 | |||||||
98 | =item * | ||||||
99 | |||||||
100 | a plain arrayref. This will be used to construct an | ||||||
101 | L |
||||||
102 | The array will be passed directly to the RequestHash constructor, so both | ||||||
103 | methods for specifying multiple values are allowed. | ||||||
104 | |||||||
105 | =item * | ||||||
106 | |||||||
107 | a plain hashref. This will be used to construct an | ||||||
108 | L |
||||||
109 | as arrayref values. | ||||||
110 | |||||||
111 | =item * | ||||||
112 | |||||||
113 | a false value. This will be used to construct an | ||||||
114 | L |
||||||
115 | |||||||
116 | =back | ||||||
117 | |||||||
118 | The constructor dies if passed an unrecognised request object. | ||||||
119 | |||||||
120 | If an appropriate object is supplied, parameters will be fetched from the | ||||||
121 | object on an as needed basis, which means that changes made to the request | ||||||
122 | object after the form object is constructed may affect the default values | ||||||
123 | used in generated form elements. However, once constructed, the form object's | ||||||
124 | sticky status does not get automatically updated, so if changes made to the | ||||||
125 | request object need to affect the form object's sticky status, set_sticky() | ||||||
126 | must be called between request object modification and form generation. | ||||||
127 | |||||||
128 | In contrast, L |
||||||
129 | object construction use copies of the parameters from the supplied hashref or | ||||||
130 | arrayref. This means that the changes made to the original data do not affect | ||||||
131 | the request object, so have absolutely no effect of the behaviour of the | ||||||
132 | form object. | ||||||
133 | |||||||
134 | =cut | ||||||
135 | |||||||
136 | sub new{ | ||||||
137 | 4 | 4 | 1 | 4914 | my($class,$req)=@_; | ||
138 | |||||||
139 | # Identify the type of request | ||||||
140 | 4 | 7 | my $type; | ||||
141 | 4 | 100 | 14 | if(!$req){ | |||
50 | |||||||
0 | |||||||
0 | |||||||
142 | 2 | 6 | $type='hash'; | ||||
143 | 2 | 5 | $req={}; | ||||
144 | 2 | 8 | }elsif(eval{ local $SIG{__DIE__}; $req->can('param'); }){ | ||||
2 | 9 | ||||||
145 | 2 | 27 | $type='object'; | ||||
146 | }elsif(ref($req) eq 'HASH'){ | ||||||
147 | 0 | 0 | $type='hash'; | ||||
148 | }elsif(ref($req) eq 'ARRAY'){ | ||||||
149 | 0 | 0 | $type='array'; | ||||
150 | }else{ | ||||||
151 | 0 | 0 | require Carp; | ||||
152 | 0 | 0 | Carp::croak( | ||||
153 | "Unrecognised request passed to HTML::StickyForm constructor ($req)"); | ||||||
154 | } | ||||||
155 | 4 | 100 | 66 | 22 | if($type eq 'hash' || $type eq 'array'){ | ||
156 | 2 | 1234 | require HTML::StickyForm::RequestHash; | ||||
157 | 2 | 50 | 22 | $req=HTML::StickyForm::RequestHash->new($type eq 'hash' ? %$req : @$req); | |||
158 | } | ||||||
159 | |||||||
160 | 4 | 25 | my $self=bless { | ||||
161 | req => $req, | ||||||
162 | values_as_labels => 0, | ||||||
163 | well_formed => ' /', | ||||||
164 | },$class; | ||||||
165 | |||||||
166 | # Count submitted fields | ||||||
167 | 4 | 14 | $self->set_sticky; | ||||
168 | |||||||
169 | 4 | 57 | $self; | ||||
170 | } | ||||||
171 | |||||||
172 | =back | ||||||
173 | |||||||
174 | =head1 METHODS | ||||||
175 | |||||||
176 | =head2 Configuration methods | ||||||
177 | |||||||
178 | =over | ||||||
179 | |||||||
180 | =item set_sticky([BOOL]) | ||||||
181 | |||||||
182 | With no arguments, the request object's parameters are counted, and the form | ||||||
183 | object is made sticky if one or more parameters are present, non-sticky | ||||||
184 | otherwise. If an argument is given, its value as a boolean determines whether | ||||||
185 | the form object will be sticky or not. In both cases, the return value will be | ||||||
186 | the new value of the sticky flag. | ||||||
187 | |||||||
188 | A non-sticky form object always uses the values supplied to methods when | ||||||
189 | constructing HTML elements, whereas a sticky form object will use the values | ||||||
190 | from the request. | ||||||
191 | |||||||
192 | This method is called by the constructor when the form object is created, so it | ||||||
193 | is not usually necessary to call it explicitly. However, it may be necessary to | ||||||
194 | call this method if parameters are set with the C method after the | ||||||
195 | form object is created. | ||||||
196 | |||||||
197 | =cut | ||||||
198 | |||||||
199 | sub set_sticky{ | ||||||
200 | 9 | 9 | 1 | 393 | my $self=shift; | ||
201 | 9 | 100 | 41 | return $self->{params}=!!$_[0] if @_; | |||
202 | |||||||
203 | 7 | 35 | $self->{params}=!!(()=$self->{req}->param); | ||||
204 | } | ||||||
205 | |||||||
206 | =item get_sticky() | ||||||
207 | |||||||
208 | Returns true if the form object is sticky. | ||||||
209 | |||||||
210 | =cut | ||||||
211 | |||||||
212 | sub get_sticky{ | ||||||
213 | 7 | 7 | 1 | 820 | my($self)=@_; | ||
214 | |||||||
215 | 7 | 307 | !!$self->{params}; | ||||
216 | } | ||||||
217 | |||||||
218 | =item values_as_labels([BOOL]) | ||||||
219 | |||||||
220 | With no arguments, this method returns the C |
||||||
221 | which determines what should happen when a value has no label in the | ||||||
222 | checkbox_group(), radio_group() and select() methods. If this attribute | ||||||
223 | is false (the default), no labels will be automatically generated. If it is | ||||||
224 | true, labels will default to the corresponding value if they are not supplied | ||||||
225 | by the user. | ||||||
226 | |||||||
227 | If an argument is passed, it is used to set the C |
||||||
228 | |||||||
229 | =cut | ||||||
230 | |||||||
231 | sub values_as_labels{ | ||||||
232 | 6 | 6 | 1 | 9 | my $self=shift; | ||
233 | 6 | 100 | 24 | return $self->{values_as_labels}=!!$_[0] if @_; | |||
234 | 4 | 17 | $self->{values_as_labels}; | ||||
235 | } | ||||||
236 | |||||||
237 | =item well_formed([BOOL]) | ||||||
238 | |||||||
239 | With no arguments, this method return the C |
||||||
240 | determines whether to generate well-formed XML, by including the trailing | ||||||
241 | slash in non-container elements. | ||||||
242 | If true, all generated elements will be well-formed. If false, no slashes | ||||||
243 | are added - which is unfortunately required by some older browsers. | ||||||
244 | |||||||
245 | If an argument is passed, it is used to set the C |
||||||
246 | |||||||
247 | =cut | ||||||
248 | |||||||
249 | sub well_formed{ | ||||||
250 | 6 | 6 | 1 | 9 | my $self=shift; | ||
251 | 6 | 100 | 27 | return !!($self->{well_formed}=$_[0] ? ' /' : '') if @_; | |||
100 | |||||||
252 | 4 | 19 | !!$self->{well_formed}; | ||||
253 | } | ||||||
254 | |||||||
255 | =back | ||||||
256 | |||||||
257 | =head2 HTML generation methods | ||||||
258 | |||||||
259 | Most of these methods are specified as taking PAIRLIST arguments. This means | ||||||
260 | that arguments must be passed as a list of name/value pairs. For example: | ||||||
261 | |||||||
262 | $form->text(name => 'fred',value => 'bloggs'); | ||||||
263 | |||||||
264 | This represents two arguments; "name" with a value of "fred", and "value" | ||||||
265 | with a value of "bloggs". | ||||||
266 | |||||||
267 | In cases where sticky values are useful, there are two ways of specifying the | ||||||
268 | values, depending on whether stickiness is required for the element being | ||||||
269 | generated. To set sticky value defaults, use the C |
||||||
270 | Alternatively, to set values which are not affected by previous values entered | ||||||
271 | by the user, use the C |
||||||
272 | on the type of element being generated). | ||||||
273 | |||||||
274 | =over | ||||||
275 | |||||||
276 | =item form_start(PAIRLIST) | ||||||
277 | |||||||
278 | Generates a C |
||||||
279 | as attributes for the element. All names and values are HTML escaped. | ||||||
280 | The following arguments are treated specially: | ||||||
281 | |||||||
282 | C |
||||||
283 | |||||||
284 | =cut | ||||||
285 | |||||||
286 | sub form_start{ | ||||||
287 | 0 | 0 | 1 | 0 | my($self,$args)=&_args; | ||
288 | 0 | 0 | 0 | $args->{method}='GET' unless exists $args->{method}; | |||
289 | |||||||
290 | 0 | 0 | my $field=' | ||||
291 | 0 | 0 | while(my($name,$val)=each %$args){ | ||||
292 | 0 | 0 | _escape($name); | ||||
293 | 0 | 0 | _escape($val); | ||||
294 | 0 | 0 | $field.=qq( $name="$val"); | ||||
295 | } | ||||||
296 | 0 | 0 | $field.='>'; | ||||
297 | |||||||
298 | 0 | 0 | $field; | ||||
299 | } | ||||||
300 | |||||||
301 | =item form_start_multipart(PAIRLIST) | ||||||
302 | |||||||
303 | As form_start(), but the C |
||||||
304 | |||||||
305 | =cut | ||||||
306 | |||||||
307 | sub form_start_multipart{ | ||||||
308 | 0 | 0 | 1 | 0 | my($self,$args)=&_args; | ||
309 | 0 | 0 | 0 | $args->{enctype}||='mutipart/form-data'; | |||
310 | 0 | 0 | $self->form_start($args); | ||||
311 | } | ||||||
312 | |||||||
313 | =item form_end() | ||||||
314 | |||||||
315 | Generates a C |
||||||
316 | |||||||
317 | =cut | ||||||
318 | |||||||
319 | sub form_end{ | ||||||
320 | 0 | 0 | 1 | 0 | ''; | ||
321 | } | ||||||
322 | |||||||
323 | =item text(PAIRLIST) | ||||||
324 | |||||||
325 | Generates an C |
||||||
326 | as attributes for the element. All names and values are HTML escaped. The | ||||||
327 | following arguments are treated specially: | ||||||
328 | |||||||
329 | C |
||||||
330 | |||||||
331 | C |
||||||
332 | value to be ignored. | ||||||
333 | |||||||
334 | C |
||||||
335 | sticky, the sticky value will be used for the C |
||||||
336 | Otherwise, the supplied C |
||||||
337 | A C |
||||||
338 | |||||||
339 | =cut | ||||||
340 | |||||||
341 | sub text{ | ||||||
342 | 0 | 0 | 1 | 0 | my($self,$args)=&_args; | ||
343 | 0 | 0 | 0 | my $type=delete $args->{type} || 'text'; | |||
344 | 0 | 0 | my $name=delete $args->{name}; | ||||
345 | 0 | 0 | my $value; | ||||
346 | 0 | 0 | 0 | if(exists $args->{value}){ | |||
347 | 0 | 0 | $value=delete $args->{value}; | ||||
348 | 0 | 0 | delete $args->{default}; | ||||
349 | }else{ | ||||||
350 | 0 | 0 | $value=delete $args->{default}; | ||||
351 | 0 | 0 | 0 | $value=$self->{req}->param($name) if $self->{params}; | |||
352 | } | ||||||
353 | |||||||
354 | 0 | 0 | _escape($type); | ||||
355 | 0 | 0 | _escape($name); | ||||
356 | 0 | 0 | _escape($value); | ||||
357 | |||||||
358 | 0 | 0 | my $field=qq( | ||||
359 | 0 | 0 | while(my($key,$val)=each %$args){ | ||||
360 | 0 | 0 | _escape($key); | ||||
361 | 0 | 0 | _escape($val); | ||||
362 | 0 | 0 | $field.=qq( $key="$val"); | ||||
363 | } | ||||||
364 | |||||||
365 | 0 | 0 | return "$field$self->{well_formed}>"; | ||||
366 | } | ||||||
367 | |||||||
368 | =item hidden(PAIRLIST) | ||||||
369 | |||||||
370 | As text(), but produces an input element of type C |
||||||
371 | |||||||
372 | =cut | ||||||
373 | |||||||
374 | sub hidden{ | ||||||
375 | 0 | 0 | 1 | 0 | my($self,$args)=&_args; | ||
376 | 0 | 0 | 0 | $args->{type}||='hidden'; | |||
377 | 0 | 0 | $self->text($args); | ||||
378 | } | ||||||
379 | |||||||
380 | =item password(PAIRLIST) | ||||||
381 | |||||||
382 | As text(), but produces an input element of type C |
||||||
383 | |||||||
384 | =cut | ||||||
385 | |||||||
386 | sub password{ | ||||||
387 | 0 | 0 | 1 | 0 | my($self,$args)=&_args; | ||
388 | 0 | 0 | 0 | $args->{type}||='password'; | |||
389 | 0 | 0 | $self->text($args); | ||||
390 | } | ||||||
391 | |||||||
392 | =item textarea(PAIRLIST) | ||||||
393 | |||||||
394 | Generates a E |
||||||
395 | to generate attributes for the start tag, except for those listed below. | ||||||
396 | All values are HTML-escaped. | ||||||
397 | |||||||
398 | C |
||||||
399 | container, and causes C |
||||||
400 | C |
||||||
401 | |||||||
402 | C |
||||||
403 | stikcy, the sticky value wil be used for the container contents. Otherwise, | ||||||
404 | sticky, the supplied C |
||||||
405 | A C |
||||||
406 | |||||||
407 | =cut | ||||||
408 | |||||||
409 | sub textarea{ | ||||||
410 | 0 | 0 | 1 | 0 | my($self,$args)=&_args; | ||
411 | 0 | 0 | my $name=delete $args->{name}; | ||||
412 | 0 | 0 | my $value; | ||||
413 | 0 | 0 | 0 | if(exists $args->{value}){ | |||
414 | 0 | 0 | $value=delete $args->{value}; | ||||
415 | 0 | 0 | delete $args->{default}; | ||||
416 | }else{ | ||||||
417 | 0 | 0 | $value=delete $args->{default}; | ||||
418 | 0 | 0 | 0 | $value=$self->{req}->param($name) if $self->{params}; | |||
419 | } | ||||||
420 | |||||||
421 | 0 | 0 | _escape($name); | ||||
422 | 0 | 0 | _escape($value); | ||||
423 | |||||||
424 | 0 | 0 | my $field=qq( | ||||
425 | 0 | 0 | while(my($key,$val)=each %$args){ | ||||
426 | 0 | 0 | _escape($key); | ||||
427 | 0 | 0 | _escape($val); | ||||
428 | 0 | 0 | $field.=qq( $key="$val"); | ||||
429 | } | ||||||
430 | |||||||
431 | 0 | 0 | return "$field>$value"; | ||||
432 | } | ||||||
433 | |||||||
434 | =item checkbox(PAIRLIST) | ||||||
435 | |||||||
436 | Generates a single C |
||||||
437 | are used directly to generate attributes for the tag, except for those listed | ||||||
438 | below. All values are HTML-escaped. | ||||||
439 | |||||||
440 | C |
||||||
441 | a checked attribute, and causes C |
||||||
442 | |||||||
443 | C |
||||||
444 | is sticky, the sticky value will be used to determine whether to include a | ||||||
445 | checked attribute. Otherwise, the supplied C |
||||||
446 | |||||||
447 | If the decision to include the C |
||||||
448 | value, the sticky parameter must include at least one value which is the same | ||||||
449 | as the supplied C |
||||||
450 | the C |
||||||
451 | true for the C |
||||||
452 | |||||||
453 | =cut | ||||||
454 | |||||||
455 | sub checkbox{ | ||||||
456 | 0 | 0 | 1 | 0 | my($self,$args)=&_args; | ||
457 | 0 | 0 | 0 | my $type=delete $args->{type} || 'checkbox'; | |||
458 | 0 | 0 | my $name=delete $args->{name}; | ||||
459 | 0 | 0 | my $value=delete $args->{value}; | ||||
460 | 0 | 0 | my $checked; | ||||
461 | 0 | 0 | 0 | if(exists $args->{checked}){ | |||
462 | 0 | 0 | $checked=delete $args->{checked}; | ||||
463 | 0 | 0 | delete $args->{default}; | ||||
464 | }else{ | ||||||
465 | 0 | 0 | $checked=delete $args->{default}; | ||||
466 | 0 | 0 | 0 | $value='' unless defined($value); | |||
467 | 0 | 0 | 0 | $checked=grep $_ eq $value,$self->{req}->param($name) if $self->{params}; | |||
468 | } | ||||||
469 | |||||||
470 | 0 | 0 | _escape($name); | ||||
471 | 0 | 0 | _escape($value); | ||||
472 | |||||||
473 | 0 | 0 | my $field=qq( | ||||
474 | 0 | 0 | 0 | $field.=' checked="checked"' if $checked; | |||
475 | 0 | 0 | while(my($key,$val)=each %$args){ | ||||
476 | 0 | 0 | _escape($key); | ||||
477 | 0 | 0 | _escape($val); | ||||
478 | 0 | 0 | $field.=qq( $key="$val"); | ||||
479 | } | ||||||
480 | |||||||
481 | 0 | 0 | return "$field$self->{well_formed}>"; | ||||
482 | } | ||||||
483 | |||||||
484 | =item checkbox_group(PAIRLIST) | ||||||
485 | |||||||
486 | Generates a group of C |
||||||
487 | list context, returns a list of elements, otherwise a single string containing | ||||||
488 | all tags. All arguments are used directly to generate attributes in each tag, | ||||||
489 | except for those listed below. Arguments with scalar values result in that | ||||||
490 | value being used for each element, whereas hashref values result in the value | ||||||
491 | keyed by the element's C |
||||||
492 | Unless otherwise stated, all names and values are HTML-escaped. | ||||||
493 | |||||||
494 | C |
||||||
495 | One element will be generated for each element, in the order supplied. | ||||||
496 | If not supplied, the label keys will be used instead. | ||||||
497 | |||||||
498 | C |
||||||
499 | Each element generated will be followed by the label keyed | ||||||
500 | by the value. Values will be HTML-escaped unless a false C |
||||||
501 | is supplied. If no label is present for a given value and C |
||||||
502 | is true, the value will also be used for the label. | ||||||
503 | |||||||
504 | C |
||||||
505 | |||||||
506 | C |
||||||
507 | checkbox is marked as checked, and causes C |
||||||
508 | sticky values to be ignored. May be a single value or arrayref of values. | ||||||
509 | |||||||
510 | C |
||||||
511 | If the form is sticky, individual checkboxes are marked as checked if the | ||||||
512 | sticky parameter includes at least one value which is the same as the individual | ||||||
513 | checkbox's value. Otherwise, the supplied C |
||||||
514 | used in the same way. May be a single value or arrayref of values. | ||||||
515 | |||||||
516 | C |
||||||
517 | element. | ||||||
518 | |||||||
519 | C |
||||||
520 | C |
||||||
521 | |||||||
522 | =cut | ||||||
523 | |||||||
524 | sub checkbox_group{ | ||||||
525 | 0 | 0 | 1 | 0 | my($self,$args)=&_args; | ||
526 | 0 | 0 | 0 | my $type=delete $args->{type} || 'checkbox'; | |||
527 | 0 | 0 | my $name=delete $args->{name}; | ||||
528 | 0 | 0 | 0 | my $labels=delete $args->{labels} || {}; | |||
529 | 0 | 0 | my $escape_labels=1; | ||||
530 | 0 | 0 | 0 | $escape_labels=delete $args->{escape_labels} if exists $args->{escape_labels}; | |||
531 | 0 | 0 | my $values=delete $args->{values}; | ||||
532 | 0 | 0 | 0 | $values||=[keys %$labels]; | |||
533 | 0 | 0 | my $checked=[]; | ||||
534 | 0 | 0 | 0 | if(exists $args->{checked}){ | |||
535 | 0 | 0 | $checked=delete $args->{checked}; | ||||
536 | 0 | 0 | 0 | $checked=[$checked] if ref($checked) ne 'ARRAY'; | |||
537 | 0 | 0 | delete $args->{default}; | ||||
538 | }else{ | ||||||
539 | 0 | 0 | 0 | if(exists $args->{default}){ | |||
540 | 0 | 0 | $checked=delete $args->{default}; | ||||
541 | 0 | 0 | 0 | $checked=[$checked] if ref($checked) ne 'ARRAY'; | |||
542 | } | ||||||
543 | 0 | 0 | 0 | $checked=[$self->{req}->param($name)] if $self->{params}; | |||
544 | } | ||||||
545 | 0 | 0 | my %checked=map +($_,'checked'),@$checked; | ||||
546 | 0 | 0 | 0 | my $br=delete $args->{linebreak} ? " {well_formed}>" : ''; |
|||
547 | 0 | 0 | my $v_as_l=$self->{values_as_labels}; | ||||
548 | 0 | 0 | 0 | if(exists $args->{values_as_labels}){ | |||
549 | 0 | 0 | $v_as_l=delete $args->{values_as_labels}; | ||||
550 | } | ||||||
551 | |||||||
552 | 0 | 0 | _escape($type); | ||||
553 | 0 | 0 | _escape($name); | ||||
554 | |||||||
555 | 0 | 0 | my $field=qq( | ||||
556 | 0 | 0 | my %per_value=( | ||||
557 | checked => \%checked, | ||||||
558 | value => {map +($_,$_),@$values}, | ||||||
559 | ); | ||||||
560 | 0 | 0 | while(my($key,$val)=each %$args){ | ||||
561 | 0 | 0 | 0 | 0 | if($val && ref($val) eq 'HASH'){ | ||
562 | 0 | 0 | $per_value{$key}=$val; | ||||
563 | 0 | 0 | next; | ||||
564 | } | ||||||
565 | 0 | 0 | _escape($key); | ||||
566 | 0 | 0 | _escape($val); | ||||
567 | 0 | 0 | $field.=qq( $key="$val"); | ||||
568 | } | ||||||
569 | |||||||
570 | 0 | 0 | my @checkboxes; | ||||
571 | 0 | 0 | for my $value(@$values){ | ||||
572 | 0 | 0 | my $field=$field; | ||||
573 | 0 | 0 | while(my($key,$hash)=each %per_value){ | ||||
574 | 0 | 0 | 0 | exists $hash->{$value} | |||
575 | or next; | ||||||
576 | 0 | 0 | _escape($key); | ||||
577 | 0 | 0 | _escape(my $val=$hash->{$value}); | ||||
578 | 0 | 0 | $field.=qq( $key="$val"); | ||||
579 | } | ||||||
580 | 0 | 0 | $field.="$self->{well_formed}>"; | ||||
581 | |||||||
582 | 0 | 0 | 0 | if(exists $labels->{$value}){ | |||
0 | |||||||
583 | 0 | 0 | my $label=$labels->{$value}; | ||||
584 | 0 | 0 | 0 | _escape($label) if $escape_labels; | |||
585 | 0 | 0 | $field.=$label; | ||||
586 | }elsif($v_as_l){ | ||||||
587 | 0 | 0 | _escape(my $evalue=$value); | ||||
588 | 0 | 0 | $field.=$evalue; | ||||
589 | } | ||||||
590 | 0 | 0 | $field.=$br; | ||||
591 | 0 | 0 | push @checkboxes,$field; | ||||
592 | } | ||||||
593 | |||||||
594 | 0 | 0 | 0 | return @checkboxes if wantarray; | |||
595 | 0 | 0 | return join '',@checkboxes; | ||||
596 | } | ||||||
597 | |||||||
598 | =item radio(PAIRLIST) | ||||||
599 | |||||||
600 | As radio_group(), but setting C |
||||||
601 | |||||||
602 | =cut | ||||||
603 | |||||||
604 | sub radio{ | ||||||
605 | 0 | 0 | 1 | 0 | my($self,$args)=&_args; | ||
606 | 0 | 0 | 0 | $args->{type}||='radio'; | |||
607 | 0 | 0 | $self->checkbox($args); | ||||
608 | } | ||||||
609 | |||||||
610 | =item radio_group(PAIRLIST) | ||||||
611 | |||||||
612 | As checkbox_group(), but setting C |
||||||
613 | |||||||
614 | =cut | ||||||
615 | |||||||
616 | sub radio_group{ | ||||||
617 | 0 | 0 | 1 | 0 | my($self,$args)=&_args; | ||
618 | 0 | 0 | 0 | $args->{type}||='radio'; | |||
619 | 0 | 0 | $self->checkbox_group($args); | ||||
620 | } | ||||||
621 | |||||||
622 | =item select(PAIRLIST) | ||||||
623 | |||||||
624 | Generates a C |
||||||
625 | are used directly to generate attributes in the C |
||||||
626 | All other arguments are used directly to | ||||||
627 | generate attributes in the C |
||||||
628 | Unless otherwise stated, all names and values are HTML-escaped. | ||||||
629 | |||||||
630 | C |
||||||
631 | Scalar values are used directly to create C |
||||||
632 | whereas arrayrefs represent option groups. The first element in an option | ||||||
633 | group is either the group's label or a hashref holding all of the group's | ||||||
634 | attributes, of which C |
||||||
635 | value C |
||||||
636 | Defaults to label keys. | ||||||
637 | |||||||
638 | C |
||||||
639 | Each C |
||||||
640 | label keyed by its value. If no label is present for a given value, no label | ||||||
641 | will be generated. Defaults to an empty hashref. | ||||||
642 | |||||||
643 | C |
||||||
644 | used to decide which options to mark as selected, and C |
||||||
645 | sticky values will be ignored. May be a single value or arrayref. | ||||||
646 | |||||||
647 | C |
||||||
648 | supplied. If the form is sticky, the sticky values will be used to decide which | ||||||
649 | options are selected. Otherwise, the supplied values will be used. | ||||||
650 | May be a single value or arrayref. | ||||||
651 | |||||||
652 | C |
||||||
653 | |||||||
654 | C |
||||||
655 | This is of little value, since it's the default behaviour of HTML in any case. | ||||||
656 | |||||||
657 | =cut | ||||||
658 | |||||||
659 | sub select{ | ||||||
660 | 0 | 0 | 1 | 0 | my($self,$args)=_args(@_); | ||
661 | 0 | 0 | my $name=delete $args->{name}; | ||||
662 | 0 | 0 | my $multiple=delete $args->{multiple}; | ||||
663 | 0 | 0 | 0 | my $labels=delete $args->{labels} || {}; | |||
664 | 0 | 0 | 0 | my $values=delete $args->{values} || [keys %$labels]; | |||
665 | 0 | 0 | my $selected; | ||||
666 | 0 | 0 | 0 | if(exists $args->{selected}){ | |||
667 | 0 | 0 | $selected=delete $args->{selected}; | ||||
668 | 0 | 0 | delete $args->{default}; | ||||
669 | }else{ | ||||||
670 | 0 | 0 | $selected=delete $args->{default}; | ||||
671 | 0 | 0 | 0 | $selected=[$self->{req}->param($name)] if $self->{params}; | |||
672 | } | ||||||
673 | 0 | 0 | 0 | if(!defined $selected){ $selected=[]; } | |||
0 | 0 | 0 | |||||
674 | 0 | 0 | elsif(ref($selected) ne 'ARRAY'){ $selected=[$selected]; } | ||||
675 | 0 | 0 | my %selected=map +($_,'selected'),@$selected; | ||||
676 | 0 | 0 | my $v_as_l=$self->{values_as_labels}; | ||||
677 | 0 | 0 | 0 | if(exists $args->{values_as_labels}){ | |||
678 | 0 | 0 | $v_as_l=delete $args->{values_as_labels}; | ||||
679 | } | ||||||
680 | |||||||
681 | 0 | 0 | my %option_args; | ||||
682 | 0 | 0 | for my $key(keys %$args){ | ||||
683 | 0 | 0 | 0 | (my $option_key=$key)=~s/\A-// or next; | |||
684 | 0 | 0 | $option_args{$option_key}=delete $args->{$key}; | ||||
685 | } | ||||||
686 | 0 | 0 | $option_args{selected}=\%selected; | ||||
687 | |||||||
688 | 0 | 0 | _escape($name); | ||||
689 | 0 | 0 | my $field=qq( | ||||
690 | 0 | 0 | while(my($key,$val)=each %$args){ | ||||
691 | 0 | 0 | _escape($key); | ||||
692 | 0 | 0 | _escape($val); | ||||
693 | 0 | 0 | $field.=qq( $key="$val"); | ||||
694 | } | ||||||
695 | 0 | 0 | 0 | $field.=' multiple="multiple"' if $multiple; | |||
696 | 0 | 0 | $field.=">"; | ||||
697 | |||||||
698 | 0 | 0 | $field.=_select_options($values,\%option_args,$labels,$v_as_l); | ||||
699 | 0 | 0 | $field.=""; | ||||
700 | |||||||
701 | 0 | 0 | $field; | ||||
702 | } | ||||||
703 | |||||||
704 | |||||||
705 | |||||||
706 | =item submit(PAIRLIST) | ||||||
707 | |||||||
708 | Generates an C |
||||||
709 | arguments are HTML-escaped, and used directly as attributes. C |
||||||
710 | fields are not sticky. | ||||||
711 | |||||||
712 | =cut | ||||||
713 | |||||||
714 | sub submit{ | ||||||
715 | 0 | 0 | 1 | 0 | my($self,$args)=_args(@_); | ||
716 | 0 | 0 | 0 | $args->{type}='submit' unless exists $args->{type}; | |||
717 | |||||||
718 | 0 | 0 | my $field=' | ||||
719 | 0 | 0 | while(my($key,$val)=each %$args){ | ||||
720 | 0 | 0 | _escape($key); | ||||
721 | 0 | 0 | _escape($val); | ||||
722 | 0 | 0 | $field.=qq( $key="$val"); | ||||
723 | } | ||||||
724 | 0 | 0 | $field.="$self->{well_formed}>"; | ||||
725 | |||||||
726 | 0 | 0 | $field; | ||||
727 | } | ||||||
728 | |||||||
729 | |||||||
730 | =back | ||||||
731 | |||||||
732 | |||||||
733 | |||||||
734 | |||||||
735 | =begin private | ||||||
736 | |||||||
737 | =head1 PRIVATE SUBROUTINES | ||||||
738 | |||||||
739 | These subs are only intended for internal use. | ||||||
740 | |||||||
741 | =over | ||||||
742 | |||||||
743 | =item _escape($string) | ||||||
744 | |||||||
745 | Escape HTML-special characters in $string, in place. If $string is not defined, | ||||||
746 | it will be updated to an empty string. | ||||||
747 | |||||||
748 | =cut | ||||||
749 | |||||||
750 | sub _escape($){ | ||||||
751 | 7 | 100 | 7 | 3970 | if(defined $_[0]){ | ||
752 | 6 | 38 | $_[0]=~s/([<>&"]|[^\0-\177])/sprintf "%d;",ord $1/ge; | ||||
9 | 50 | ||||||
753 | }else{ | ||||||
754 | 1 | 3 | $_[0]=''; | ||||
755 | } | ||||||
756 | } | ||||||
757 | |||||||
758 | =item _args(@_) | ||||||
759 | |||||||
760 | Work out which of the two argument passing conventions is being used, and | ||||||
761 | return ($self,\%args). This essentially converts the public unrolled | ||||||
762 | PAIRLIST arguments into a single hashref, as used by the internal | ||||||
763 | interfaces. | ||||||
764 | |||||||
765 | =cut | ||||||
766 | |||||||
767 | sub _args{ | ||||||
768 | 4 | 4 | 4323 | my $self=shift; | |||
769 | 4 | 100 | 14 | my $args=ref($_[0]) ? {%{$_[0]}} : {@_}; | |||
2 | 7 | ||||||
770 | 4 | 14 | ($self,$args); | ||||
771 | } | ||||||
772 | |||||||
773 | =item _select_options(\@values,\%option_args,\%labels,$values_as_labels) | ||||||
774 | |||||||
775 | Returns an HTML fragment containing C | ||||||
776 | list of option values. Values which are arrayrefs are used to represent | ||||||
777 | option groups, wherein the zeroth element is either the group name, or | ||||||
778 | a hashref holding the group's attributes. | ||||||
779 | |||||||
780 | =cut | ||||||
781 | |||||||
782 | sub _select_options{ | ||||||
783 | 0 | 0 | my($values,$option_args,$labels,$v_as_l)=@_; | ||||
784 | 0 | my $field=''; | |||||
785 | 0 | for my $value(@$values){ | |||||
786 | 0 | 0 | if(ref $value){ | ||||
787 | # Handle option group | ||||||
788 | 0 | my($_group,@subvalues)=@$value; | |||||
789 | 0 | 0 | my %group=ref($_group) ? %$_group : (label => $_group); | ||||
790 | 0 | 0 | if(delete $group{disabled}){ | ||||
791 | 0 | $group{disabled}='disabled'; | |||||
792 | } | ||||||
793 | 0 | $field.=qq( | |||||
794 | 0 | while(my($name,$value)=each %group){ | |||||
795 | 0 | _escape($value); | |||||
796 | 0 | $field.=qq( $name="$value"); | |||||
797 | } | ||||||
798 | 0 | $field.='>'; | |||||
799 | 0 | $field.=_select_options(\@subvalues,$option_args,$labels,$v_as_l); | |||||
800 | 0 | $field.=''; | |||||
801 | }else{ | ||||||
802 | # Handle single option | ||||||
803 | 0 | _escape(my $evalue=$value); | |||||
804 | 0 | $field.=qq( | |||||
805 | 0 | while(my($key,$val)=each %$option_args){ | |||||
806 | 0 | 0 | if(ref $val){ | ||||
807 | 0 | 0 | defined($val=$val->{$value}) | ||||
808 | or next; | ||||||
809 | } | ||||||
810 | 0 | _escape($val); | |||||
811 | 0 | $field.=qq( $key="$val"); | |||||
812 | } | ||||||
813 | 0 | $field.=">"; | |||||
814 | 0 | 0 | if(exists $labels->{$value}){ | ||||
0 | |||||||
815 | 0 | my $label=$labels->{$value}; | |||||
816 | 0 | _escape($label); | |||||
817 | 0 | $field.=$label; | |||||
818 | }elsif($v_as_l){ | ||||||
819 | 0 | $field.=$evalue; | |||||
820 | } | ||||||
821 | 0 | $field.=""; | |||||
822 | } | ||||||
823 | } | ||||||
824 | |||||||
825 | 0 | $field; | |||||
826 | } | ||||||
827 | |||||||
828 | =back | ||||||
829 | |||||||
830 | =end private | ||||||
831 | |||||||
832 | =cut | ||||||
833 | |||||||
834 | # Return true to require | ||||||
835 | 1; | ||||||
836 | |||||||
837 | |||||||
838 | |||||||
839 | =head1 AUTHOR | ||||||
840 | |||||||
841 | Copyright (C) Institute of Physics Publishing 2000-2011 | ||||||
842 | |||||||
843 | Peter Haworth |
||||||
844 | |||||||
845 | You may use and distribute this module according to the same terms | ||||||
846 | that Perl is distributed under. | ||||||
847 | |||||||
848 |