| blib/lib/HTML/StickyForm.pm | |||
|---|---|---|---|
| Criterion | Covered | Total | % |
| statement | 40 | 239 | 16.7 |
| branch | 18 | 96 | 18.7 |
| condition | 2 | 30 | 6.6 |
| subroutine | 10 | 24 | 41.6 |
| pod | 18 | 18 | 100.0 |
| total | 88 | 407 | 21.6 |
| 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 | 98267 | $HTML::StickyForm::VERSION = '0.07_02'; | |||
| 76 | } | ||||||
| 77 | 7 | 7 | 38 | use strict; | |||
| 7 | 17 | ||||||
| 7 | 116 | ||||||
| 78 | 7 | 7 | 22 | use warnings; | |||
| 7 | 11 | ||||||
| 7 | 13854 | ||||||
| 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 | 426 | my($class,$req)=@_; | ||
| 138 | |||||||
| 139 | # Identify the type of request | ||||||
| 140 | 4 | 5 | my $type; | ||||
| 141 | 4 | 100 | 54 | if(!$req){ | |||
| 50 | |||||||
| 0 | |||||||
| 0 | |||||||
| 142 | 2 | 3 | $type='hash'; | ||||
| 143 | 2 | 5 | $req={}; | ||||
| 144 | 2 | 5 | }elsif(eval{ local $SIG{__DIE__}; $req->can('param'); }){ | ||||
| 2 | 14 | ||||||
| 145 | 2 | 3 | $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 | 20 | if($type eq 'hash' || $type eq 'array'){ | ||
| 156 | 2 | 864 | require HTML::StickyForm::RequestHash; | ||||
| 157 | 2 | 50 | 20 | $req=HTML::StickyForm::RequestHash->new($type eq 'hash' ? %$req : @$req); | |||
| 158 | } | ||||||
| 159 | |||||||
| 160 | 4 | 18 | my $self=bless { | ||||
| 161 | req => $req, | ||||||
| 162 | values_as_labels => 0, | ||||||
| 163 | well_formed => ' /', | ||||||
| 164 | },$class; | ||||||
| 165 | |||||||
| 166 | # Count submitted fields | ||||||
| 167 | 4 | 12 | $self->set_sticky; | ||||
| 168 | |||||||
| 169 | 4 | 42 | $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 | 175 | my $self=shift; | ||
| 201 | 9 | 100 | 25 | return $self->{params}=!!$_[0] if @_; | |||
| 202 | |||||||
| 203 | 7 | 26 | $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 | 491 | my($self)=@_; | ||
| 214 | |||||||
| 215 | 7 | 21 | !!$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 | 6 | my $self=shift; | ||
| 233 | 6 | 100 | 20 | return $self->{values_as_labels}=!!$_[0] if @_; | |||
| 234 | 4 | 12 | $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 | 6 | my $self=shift; | ||
| 251 | 6 | 100 | 20 | return !!($self->{well_formed}=$_[0] ? ' /' : '') if @_; | |||
| 100 | |||||||
| 252 | 4 | 14 | !!$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 | generate attributes in the C |
||||||
| 626 | |||||||
| 627 | C |
||||||
| 628 | Scalar values are used directly to create C |
||||||
| 629 | whereas arrayrefs represent option groups. The first element in an option | ||||||
| 630 | group is either the group's label or a hashref holding all of the group's | ||||||
| 631 | attributes, of which C |
||||||
| 632 | value C |
||||||
| 633 | Defaults to label keys. | ||||||
| 634 | |||||||
| 635 | C |
||||||
| 636 | Each C |
||||||
| 637 | label keyed by its value. If no label is present for a given value, no label | ||||||
| 638 | will be generated. Defaults to an empty hashref. | ||||||
| 639 | |||||||
| 640 | C |
||||||
| 641 | used to decide which options to mark as selected, and C |
||||||
| 642 | sticky values will be ignored. May be a single value or arrayref. | ||||||
| 643 | |||||||
| 644 | C |
||||||
| 645 | supplied. If the form is sticky, the sticky values will be used to decide which | ||||||
| 646 | options are selected. Otherwise, the supplied values will be used. | ||||||
| 647 | May be a single value or arrayref. | ||||||
| 648 | |||||||
| 649 | C |
||||||
| 650 | |||||||
| 651 | C |
||||||
| 652 | This is of little value, since it's the default behaviour of HTML in any case. | ||||||
| 653 | |||||||
| 654 | =cut | ||||||
| 655 | |||||||
| 656 | sub select{ | ||||||
| 657 | 0 | 0 | 1 | 0 | my($self,$args)=_args(@_); | ||
| 658 | 0 | 0 | my $name=delete $args->{name}; | ||||
| 659 | 0 | 0 | my $multiple=delete $args->{multiple}; | ||||
| 660 | 0 | 0 | 0 | my $labels=delete $args->{labels} || {}; | |||
| 661 | 0 | 0 | 0 | my $values=delete $args->{values} || [keys %$labels]; | |||
| 662 | 0 | 0 | my $selected; | ||||
| 663 | 0 | 0 | 0 | if(exists $args->{selected}){ | |||
| 664 | 0 | 0 | $selected=delete $args->{selected}; | ||||
| 665 | 0 | 0 | delete $args->{default}; | ||||
| 666 | }else{ | ||||||
| 667 | 0 | 0 | $selected=delete $args->{default}; | ||||
| 668 | 0 | 0 | 0 | $selected=[$self->{req}->param($name)] if $self->{params}; | |||
| 669 | } | ||||||
| 670 | 0 | 0 | 0 | if(!defined $selected){ $selected=[]; } | |||
| 0 | 0 | 0 | |||||
| 671 | 0 | 0 | elsif(ref($selected) ne 'ARRAY'){ $selected=[$selected]; } | ||||
| 672 | 0 | 0 | my %selected=map +($_,1),@$selected; | ||||
| 673 | 0 | 0 | my $v_as_l=$self->{values_as_labels}; | ||||
| 674 | 0 | 0 | 0 | if(exists $args->{values_as_labels}){ | |||
| 675 | 0 | 0 | $v_as_l=delete $args->{values_as_labels}; | ||||
| 676 | } | ||||||
| 677 | |||||||
| 678 | 0 | 0 | _escape($name); | ||||
| 679 | 0 | 0 | my $field=qq( | ||||
| 680 | 0 | 0 | while(my($key,$val)=each %$args){ | ||||
| 681 | 0 | 0 | _escape($key); | ||||
| 682 | 0 | 0 | _escape($val); | ||||
| 683 | 0 | 0 | $field.=qq( $key="$val"); | ||||
| 684 | } | ||||||
| 685 | 0 | 0 | 0 | $field.=' multiple="multiple"' if $multiple; | |||
| 686 | 0 | 0 | $field.=">"; | ||||
| 687 | |||||||
| 688 | 0 | 0 | $field.=_select_options($values,\%selected,$labels,$v_as_l); | ||||
| 689 | 0 | 0 | $field.=""; | ||||
| 690 | |||||||
| 691 | 0 | 0 | $field; | ||||
| 692 | } | ||||||
| 693 | |||||||
| 694 | |||||||
| 695 | |||||||
| 696 | =item submit(PAIRLIST) | ||||||
| 697 | |||||||
| 698 | Generates an C |
||||||
| 699 | arguments are HTML-escaped, and used directly as attributes. C |
||||||
| 700 | fields are not sticky. | ||||||
| 701 | |||||||
| 702 | =cut | ||||||
| 703 | |||||||
| 704 | sub submit{ | ||||||
| 705 | 0 | 0 | 1 | 0 | my($self,$args)=_args(@_); | ||
| 706 | 0 | 0 | 0 | $args->{type}='submit' unless exists $args->{type}; | |||
| 707 | |||||||
| 708 | 0 | 0 | my $field=' | ||||
| 709 | 0 | 0 | while(my($key,$val)=each %$args){ | ||||
| 710 | 0 | 0 | _escape($key); | ||||
| 711 | 0 | 0 | _escape($val); | ||||
| 712 | 0 | 0 | $field.=qq( $key="$val"); | ||||
| 713 | } | ||||||
| 714 | 0 | 0 | $field.="$self->{well_formed}>"; | ||||
| 715 | |||||||
| 716 | 0 | 0 | $field; | ||||
| 717 | } | ||||||
| 718 | |||||||
| 719 | |||||||
| 720 | =back | ||||||
| 721 | |||||||
| 722 | |||||||
| 723 | |||||||
| 724 | |||||||
| 725 | =begin private | ||||||
| 726 | |||||||
| 727 | =head1 PRIVATE SUBROUTINES | ||||||
| 728 | |||||||
| 729 | These subs are only intended for internal use. | ||||||
| 730 | |||||||
| 731 | =over | ||||||
| 732 | |||||||
| 733 | =item _escape($string) | ||||||
| 734 | |||||||
| 735 | Escape HTML-special characters in $string, in place. If $string is not defined, | ||||||
| 736 | it will be updated to an empty string. | ||||||
| 737 | |||||||
| 738 | =cut | ||||||
| 739 | |||||||
| 740 | sub _escape($){ | ||||||
| 741 | 7 | 100 | 7 | 1901 | if(defined $_[0]){ | ||
| 742 | 6 | 24 | $_[0]=~s/([<>&"]|[^\0-\177])/sprintf "%d;",ord $1/ge; | ||||
| 9 | 34 | ||||||
| 743 | }else{ | ||||||
| 744 | 1 | 3 | $_[0]=''; | ||||
| 745 | } | ||||||
| 746 | } | ||||||
| 747 | |||||||
| 748 | =item _args(@_) | ||||||
| 749 | |||||||
| 750 | Work out which of the two argument passing conventions is being used, and | ||||||
| 751 | return ($self,\%args). This essentially converts the public unrolled | ||||||
| 752 | PAIRLIST arguments into a single hashref, as used by the internal | ||||||
| 753 | interfaces. | ||||||
| 754 | |||||||
| 755 | =cut | ||||||
| 756 | |||||||
| 757 | sub _args{ | ||||||
| 758 | 4 | 4 | 2199 | my $self=shift; | |||
| 759 | 4 | 100 | 12 | my $args=ref($_[0]) ? {%{$_[0]}} : {@_}; | |||
| 2 | 6 | ||||||
| 760 | 4 | 8 | ($self,$args); | ||||
| 761 | } | ||||||
| 762 | |||||||
| 763 | =item _select_options(\@values,\%selected,\%labels,$values_as_labels) | ||||||
| 764 | |||||||
| 765 | Returns an HTML fragment containing C | ||||||
| 766 | list of option values. Values which are arrayrefs are used to represent | ||||||
| 767 | option groups, wherein the zeroth element is either the group name, or | ||||||
| 768 | a hashref holding the group's attributes. | ||||||
| 769 | |||||||
| 770 | =cut | ||||||
| 771 | |||||||
| 772 | sub _select_options{ | ||||||
| 773 | 0 | 0 | my($values,$selected,$labels,$v_as_l)=@_; | ||||
| 774 | 0 | my $field=''; | |||||
| 775 | 0 | for my $value(@$values){ | |||||
| 776 | 0 | 0 | if(ref $value){ | ||||
| 777 | # Handle option group | ||||||
| 778 | 0 | my($_group,@subvalues)=@$value; | |||||
| 779 | 0 | 0 | my %group=ref($_group) ? %$_group : (label => $_group); | ||||
| 780 | 0 | 0 | if(delete $group{disabled}){ | ||||
| 781 | 0 | $group{disabled}='disabled'; | |||||
| 782 | } | ||||||
| 783 | 0 | $field.=qq( | |||||
| 784 | 0 | while(my($name,$value)=each %group){ | |||||
| 785 | 0 | _escape($value); | |||||
| 786 | 0 | $field.=qq( $name="$value"); | |||||
| 787 | } | ||||||
| 788 | 0 | $field.='>'; | |||||
| 789 | 0 | $field.=_select_options(\@subvalues,$selected,$labels); | |||||
| 790 | 0 | $field.=''; | |||||
| 791 | }else{ | ||||||
| 792 | # Handle single option | ||||||
| 793 | 0 | _escape(my $evalue=$value); | |||||
| 794 | 0 | $field.=qq( | |||||
| 795 | 0 | 0 | $field.=' selected="selected"' if $selected->{$value}; | ||||
| 796 | 0 | $field.=">"; | |||||
| 797 | 0 | 0 | if(exists $labels->{$value}){ | ||||
| 0 | |||||||
| 798 | 0 | my $label=$labels->{$value}; | |||||
| 799 | 0 | _escape($label); | |||||
| 800 | 0 | $field.=$label; | |||||
| 801 | }elsif($v_as_l){ | ||||||
| 802 | 0 | $field.=$evalue; | |||||
| 803 | } | ||||||
| 804 | 0 | $field.=""; | |||||
| 805 | } | ||||||
| 806 | } | ||||||
| 807 | |||||||
| 808 | 0 | $field; | |||||
| 809 | } | ||||||
| 810 | |||||||
| 811 | =back | ||||||
| 812 | |||||||
| 813 | =end private | ||||||
| 814 | |||||||
| 815 | =cut | ||||||
| 816 | |||||||
| 817 | # Return true to require | ||||||
| 818 | 1; | ||||||
| 819 | |||||||
| 820 | |||||||
| 821 | |||||||
| 822 | =head1 AUTHOR | ||||||
| 823 | |||||||
| 824 | Copyright (C) Institute of Physics Publishing 2000-2011 | ||||||
| 825 | |||||||
| 826 | Peter Haworth |
||||||
| 827 | |||||||
| 828 | You may use and distribute this module according to the same terms | ||||||
| 829 | that Perl is distributed under. | ||||||
| 830 | |||||||
| 831 |