| 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 |