File Coverage

blib/lib/Validation/Class/Plugin/FormFields.pm
Criterion Covered Total %
statement 21 258 8.1
branch 0 64 0.0
condition 0 44 0.0
subroutine 7 39 17.9
pod 18 22 81.8
total 46 427 10.7


line stmt bran cond sub pod time code
1             # ABSTRACT: HTML Form Field Renderer for Validation::Class
2              
3             package Validation::Class::Plugin::FormFields;
4              
5 1     1   30354 use strict;
  1         3  
  1         34  
6 1     1   4 use warnings;
  1         2  
  1         38  
7 1     1   1748 use overload '""' => \&render, fallback => 1;
  1         1099  
  1         8  
8              
9 1     1   63 use Carp;
  1         1  
  1         96  
10              
11 1     1   5220 use List::MoreUtils 'any';
  1         1339  
  1         90  
12 1     1   958 use Validation::Class::Util;
  1         4475  
  1         8  
13 1     1   1937 use HTML::Element;
  1         45475  
  1         8  
14              
15             our $VERSION = '7.900022'; # VERSION
16              
17              
18             sub new {
19              
20 0     0 0   my $class = shift;
21 0           my $prototype = shift;
22              
23 0           my $self = {
24             target => '',
25             elements => {},
26             prototype => $prototype
27             };
28              
29 0           return bless $self, $class;
30              
31             }
32              
33              
34             sub checkbox {
35              
36 0     0 1   my ($self, $name, %attributes) = @_;
37              
38 0           $self->{target} = $name;
39              
40 0           $self->declare('checkbox', $name, %attributes);
41              
42 0           return $self;
43              
44             }
45              
46              
47             sub checkgroup {
48              
49 0     0 1   my ($self, $name, %attributes) = @_;
50              
51 0           $self->{target} = $name;
52              
53 0           $self->declare('checkgroup', $name, %attributes);
54              
55 0           return $self;
56              
57             }
58              
59              
60             sub error_count {
61              
62 0     0 1   my $self = shift;
63              
64 0           return $self->prototype->error_count(@_);
65              
66             }
67              
68              
69             sub error_fields {
70              
71 0     0 1   my $self = shift;
72              
73 0           return $self->prototype->error_fields(@_);
74              
75             }
76              
77              
78             sub errors {
79              
80 0     0 1   my $self = shift;
81              
82 0           return $self->prototype->errors(@_);
83              
84             }
85              
86              
87             sub errors_to_string {
88              
89 0     0 1   my $self = shift;
90              
91 0           return $self->prototype->errors_to_string(@_);
92              
93             }
94              
95             sub declare {
96              
97 0     0 0   my ($self, $method, $name, %attributes) = @_;
98              
99 0           my $proto = $self->{prototype};
100              
101 0 0 0       croak qq(Can't declare new element without a field and type),
102             unless $name && $method
103             ;
104              
105 0 0         croak qq(Can't locate field $name for use with element $method),
106             unless $proto->fields->has($name)
107             ;
108              
109 0           my $field = $proto->fields->get($name);
110              
111 0   0       $attributes{id} ||= $field->name;
112 0   0       $attributes{name} ||= $field->name;
113              
114 0           my $value;
115              
116 0 0         if (defined $attributes{value}) {
117 0           $value = $attributes{value};
118             }
119              
120             else {
121 0           $value = $field->default;
122             }
123              
124 0           my $param = []; # everything gets easier if we always expect an arrayref
125              
126 0 0         if ($proto->params->has($name)) {
127 0           $param = $proto->params->get($name);
128 0 0         $param = isa_arrayref($param) ? $param : [$param];
129             }
130              
131 0           my $processor = "_declare_$method";
132              
133 0 0         $self->$processor($field, $param, $value, %attributes)
134             if $self->can($processor)
135             ;
136              
137 0           return $self;
138              
139             }
140              
141             sub _declare_checkbox {
142              
143 0     0     my ($self, $field, $param, $value, %attributes) = @_;
144              
145 0           my $name = $field->name;
146              
147 0           my $element = HTML::Element->new('input');
148              
149 0           my $proto = $self->proto;
150              
151 0   0       $attributes{type} ||= 'checkbox';
152              
153 0 0         $value = isa_arrayref($value) ? $value->[0] : $value;
154              
155 0 0         croak qq(Can't process checkbox without a default value for field $name)
156             unless $value
157             ;
158              
159             # set value attribute
160 0           $attributes{value} = $value;
161              
162             # set checked attribute
163 0 0   0     if (any { $_ eq $value } @{$param}) {
  0            
  0            
164 0           $attributes{checked} = 'checked';
165             }
166              
167             # set attributes
168 0           while (my($key, $val) = each(%attributes)) {
169 0           $element->attr($key, $val);
170             }
171              
172 0           return $self->{elements}->{$name} = $element;
173              
174             }
175              
176             sub _declare_checkgroup {
177              
178 0     0     my ($self, $field, $param, $value, %attributes) = @_;
179              
180 0           my $name = $field->name;
181              
182 0           my @elements = ();
183              
184 0           my $proto = $self->proto;
185              
186 0   0       $attributes{type} ||= 'checkbox';
187              
188 0 0         $value = isa_arrayref($value) ? $value->[0] : $value;
189              
190             # set value attribute (although it'll likely be overwritten)
191 0           $attributes{value} = $value;
192              
193 0           my @opts = grep defined, @{$field->options};
  0            
194              
195 0 0         croak qq(Can't process checkbox group without options for field $name),
196             unless @opts
197             ;
198              
199 0           my %values = map { $_ => $_ } @{$param};
  0            
  0            
200              
201 0           foreach my $opt (@opts) {
202              
203 0           my ($v, $c);
204              
205 0 0         if ($opt =~ /^([^\|]+)?\|(.*)/) {
    0          
206 0           ($v, $c) = $opt =~ /^([^\|]+)?\|(.*)/;
207             }
208              
209             elsif (isa_arrayref($opt)) {
210 0           ($v, $c) = @{$opt};
  0            
211             }
212              
213             else {
214 0           ($v, $c) = ($opt, $opt);
215             }
216              
217 0           my $element = HTML::Element->new('input');
218              
219             # set basic attributes
220 0           while (my($key, $val) = each(%attributes)) {
221 0           $element->attr($key, $val);
222             }
223              
224 0           $element->attr(value => $v);
225 0           $element->push_content(HTML::Element->new('span', _content => [$c]));
226 0 0         $element->attr(checked => 'checked') if $v eq $values{$v};
227              
228 0           push @elements, $element;
229              
230             }
231              
232 0           return $self->{elements}->{$name} = \@elements;
233              
234             }
235              
236             sub _declare_hidden {
237              
238 0     0     my ($self, $field, $param, $value, %attributes) = @_;
239              
240 0           my $name = $field->name;
241              
242 0           my $element = HTML::Element->new('input');
243              
244 0           my $proto = $self->proto;
245              
246 0   0       $attributes{type} ||= 'hidden';
247              
248 0 0         $value = isa_arrayref($value) ? $value->[0] : $value;
249              
250 0 0         croak qq(Can't process hidden field without a default value for field $name)
251             unless $value
252             ;
253              
254             # set value attribute
255 0           $attributes{value} = $value;
256              
257             # set attributes
258 0           while (my($key, $val) = each(%attributes)) {
259 0           $element->attr($key, $val);
260             }
261              
262 0           return $self->{elements}->{$name} = $element;
263              
264             }
265              
266             sub _declare_selectbox {
267              
268 0     0     my ($self, $field, $param, $value, %attributes) = @_;
269              
270 0           my $name = $field->name;
271              
272 0           my $element = HTML::Element->new('select');
273              
274             # default state (minor liberties taken)
275 0 0         if (defined $attributes{placeholder}) {
276 0           $element->push_content(
277             HTML::Element->new('option',
278             value => '', _content => [
279             delete $attributes{placeholder}
280             ]
281             )
282             );
283             }
284              
285             # set basic attributes
286 0           while (my($key, $val) = each(%attributes)) {
287 0           $element->attr($key, $val);
288             }
289              
290 0           my $proto = $self->proto;
291              
292 0 0         $value = isa_arrayref($value) ? $value->[0] : $value;
293              
294 0           my @opts = grep defined, @{$field->options};
  0            
295              
296 0 0         croak qq(Can't process selectbox without options for field $name),
297             unless @opts
298             ;
299              
300 0           my %values = map { $_ => $_ } @{$param};
  0            
  0            
301              
302 0           foreach my $opt (@opts) {
303              
304 0           my ($v, $c);
305              
306 0 0         if ($opt =~ /^([^\|]+)?\|(.*)/) {
    0          
307 0           ($v, $c) = $opt =~ /^([^\|]+)?\|(.*)/;
308             }
309              
310             elsif (isa_arrayref($opt)) {
311 0           ($v, $c) = @{$opt};
  0            
312             }
313              
314             else {
315 0           ($v, $c) = ($opt, $opt);
316             }
317              
318 0           my $option = HTML::Element->new('option');
319              
320 0   0       $option->attr(value => $v || '');
321 0   0       $option->push_content( $c || '');
322 0 0 0       $option->attr(selected => 'selected')
      0        
323             if ($v && $values{$v}) and ($v eq $values{$v})
324             ;
325              
326 0           $element->push_content($option);
327              
328             }
329              
330 0           return $self->{elements}->{$name} = $element;
331              
332             }
333              
334             sub _declare_radiobutton {
335              
336 0     0     my ($self, $field, $param, $value, %attributes) = @_;
337              
338 0           my $name = $field->name;
339              
340 0           my $element = HTML::Element->new('input');
341              
342 0           my $proto = $self->proto;
343              
344 0   0       $attributes{type} ||= 'radio';
345              
346 0 0         $value = isa_arrayref($value) ? $value->[0] : $value;
347              
348 0 0         croak qq(Can't process radiobutton without a default value for field $name)
349             unless $value
350             ;
351              
352             # set value attribute
353 0           $attributes{value} = $value;
354              
355             # set checked attribute
356 0 0   0     if (any { $_ eq $value } @{$param}) {
  0            
  0            
357 0           $attributes{checked} = 'checked';
358             }
359              
360             # set attributes
361 0           while (my($key, $val) = each(%attributes)) {
362 0           $element->attr($key, $val);
363             }
364              
365 0           return $self->{elements}->{$name} = $element;
366              
367             }
368              
369             sub _declare_radiogroup {
370              
371 0     0     my ($self, $field, $param, $value, %attributes) = @_;
372              
373 0           my $name = $field->name;
374              
375 0           my @elements = ();
376              
377 0           my $proto = $self->proto;
378              
379 0   0       $attributes{type} ||= 'radio';
380              
381 0 0         $value = isa_arrayref($value) ? $value->[0] : $value;
382              
383             # set value attribute (although it'll likely be overwritten)
384 0           $attributes{value} = $value;
385              
386 0           my @opts = grep defined, @{$field->options};
  0            
387              
388 0 0         croak qq(Can't process radio group without options for field $name),
389             unless @opts
390             ;
391              
392 0           my %values = map { $_ => $_ } @{$param};
  0            
  0            
393              
394 0           foreach my $opt (@opts) {
395              
396 0           my ($v, $c);
397              
398 0 0         if ($opt =~ /^([^\|]+)?\|(.*)/) {
    0          
399 0           ($v, $c) = $opt =~ /^([^\|]+)?\|(.*)/;
400             }
401              
402             elsif (isa_arrayref($opt)) {
403 0           ($v, $c) = @{$opt};
  0            
404             }
405              
406             else {
407 0           ($v, $c) = ($opt, $opt);
408             }
409              
410 0           my $element = HTML::Element->new('input');
411              
412             # set basic attributes
413 0           while (my($key, $val) = each(%attributes)) {
414 0           $element->attr($key, $val);
415             }
416              
417 0           $element->attr(value => $v);
418 0           $element->push_content(HTML::Element->new('span', _content => [$c]));
419 0 0         $element->attr(checked => 'checked') if $v eq $values{$v};
420              
421 0           push @elements, $element;
422              
423             }
424              
425 0           return $self->{elements}->{$name} = \@elements;
426              
427             }
428              
429             sub _declare_textarea {
430              
431 0     0     my ($self, $field, $param, $value, %attributes) = @_;
432              
433 0           my $name = $field->name;
434              
435 0           my $element = HTML::Element->new('textarea');
436              
437 0           my $proto = $self->proto;
438              
439 0   0       $attributes{type} ||= 'text';
440              
441 0   0       $value = $param->[0] || (isa_arrayref($value) ? $value->[0] : $value);
442              
443 0   0       $element->push_content($value || '');
444              
445             # set basic attributes
446 0           while (my($key, $val) = each(%attributes)) {
447 0           $element->attr($key, $val);
448             }
449              
450 0           return $self->{elements}->{$name} = $element;
451              
452             }
453              
454             sub _declare_textbox {
455              
456 0     0     my ($self, $field, $param, $value, %attributes) = @_;
457              
458 0           my $name = $field->name;
459              
460 0           my $element = HTML::Element->new('input');
461              
462 0           my $proto = $self->proto;
463              
464 0   0       $attributes{type} ||= 'text';
465              
466 0   0       $value = $param->[0] || (isa_arrayref($value) ? $value->[0] : $value);
467              
468             # set value attribute
469 0           $attributes{value} = $value;
470              
471             # set attributes
472 0           while (my($key, $val) = each(%attributes)) {
473 0           $element->attr($key, $val);
474             }
475              
476 0           return $self->{elements}->{$name} = $element;
477              
478             }
479              
480              
481             sub element {
482              
483 0     0 1   my ($self, $target) = @_;
484              
485 0   0       $target ||= $self->{target};
486              
487 0           return $self->{elements}->{$target};
488              
489             }
490              
491              
492             sub hidden {
493              
494 0     0 1   my ($self, $name, %attributes) = @_;
495              
496 0           $self->{target} = $name;
497              
498 0           $self->declare('hidden', $name, %attributes);
499              
500 0           return $self;
501              
502             }
503              
504              
505             sub lockbox {
506              
507 0     0 1   goto &password;
508              
509             }
510              
511              
512             sub multiselect {
513              
514 0     0 1   my ($self, $name, %attributes) = @_;
515              
516 0           $self->{target} = $name;
517              
518 0           $attributes{multiple} = 'yes';
519              
520 0           $self->selectbox($name, %attributes);
521              
522 0           return $self;
523              
524             }
525              
526              
527             sub password {
528              
529 0     0 1   my ($self, $name, %attributes) = @_;
530              
531 0           $attributes{type} = 'password';
532              
533 0           $self->textbox($name, %attributes);
534              
535 0           return $self;
536              
537             }
538              
539             sub proto {
540              
541 0     0 0   goto &prototype;
542              
543             }
544              
545              
546             sub prototype {
547              
548 0     0 1   my ($self) = @_;
549              
550 0           return $self->{prototype};
551              
552             }
553              
554              
555             sub radiobutton {
556              
557 0     0 1   my ($self, $name, %attributes) = @_;
558              
559 0           $self->{target} = $name;
560              
561 0           $self->declare('radiobutton', $name, %attributes);
562              
563 0           return $self;
564              
565             }
566              
567              
568             sub radiogroup {
569              
570 0     0 1   my ($self, $name, %attributes) = @_;
571              
572 0           $self->{target} = $name;
573              
574 0           $self->declare('radiogroup', $name, %attributes);
575              
576 0           return $self;
577              
578             }
579              
580              
581             sub selectbox {
582              
583 0     0 1   my ($self, $name, %attributes) = @_;
584              
585 0           $self->{target} = $name;
586              
587 0           $self->declare('selectbox', $name, %attributes);
588              
589 0           return $self;
590              
591             }
592              
593              
594             sub textarea {
595              
596 0     0 1   my ($self, $name, %attributes) = @_;
597              
598 0           $self->{target} = $name;
599              
600 0           $self->declare('textarea', $name, %attributes);
601              
602 0           return $self;
603              
604             }
605              
606              
607             sub textbox {
608              
609 0     0 1   my ($self, $name, %attributes) = @_;
610              
611 0           $self->{target} = $name;
612              
613 0           $self->declare('textbox', $name, %attributes);
614              
615 0           return $self;
616              
617             }
618              
619              
620             sub render {
621              
622 0     0 1   my ($self, $target) = @_;
623              
624 0           my $element = $self->element($target);
625              
626 0           return isa_arrayref($element) ?
627 0 0         [map { $_->as_HTML } @{$element}] : $element->as_HTML
  0            
628             ;
629              
630             }
631              
632             sub render_inner {
633              
634 0     0 0   my ($self) = @_;
635              
636 0           my @pairs;
637 0           my %attrs = $self->element->all_attr;
638              
639 0           my $type = delete $attrs{_tag};
640              
641 0           for (keys %attrs) {
642 0 0         delete $attrs{$_} if /^_/;
643             }
644              
645 0           my @attrs = %attrs;
646              
647 0           push @pairs, sprintf('%s="%s"', splice(@attrs, 0, 2)) while @attrs;
648              
649 0           return $type . ' ' . join ' ', @pairs;
650              
651             }
652              
653             1;
654              
655             __END__