File Coverage

blib/lib/HTML/Form/ListInput.pm
Criterion Covered Total %
statement 125 127 98.4
branch 65 70 92.8
condition 44 44 100.0
subroutine 13 13 100.0
pod 0 9 0.0
total 247 263 93.9


line stmt bran cond sub pod time code
1             package HTML::Form::ListInput;
2              
3 11     11   71 use strict;
  11         24  
  11         326  
4 11     11   56 use parent 'HTML::Form::Input';
  11         28  
  11         51  
5              
6 11     11   591 use Carp 'croak';
  11         21  
  11         14888  
7              
8             our $VERSION = '6.11';
9              
10             # ABSTRACT: An HTML form list input element for use with HTML::Form
11              
12             #select/option (val1, val2, ....)
13             #input/radio (undef, val1, val2,...)
14             #input/checkbox (undef, value)
15             #select-multiple/option (undef, value)
16              
17             sub new {
18 93     93 0 164 my $class = shift;
19 93         327 my $self = $class->SUPER::new(@_);
20              
21 93         195 my $value = delete $self->{value};
22 93         145 my $value_name = delete $self->{value_name};
23 93         144 my $type = $self->{type};
24              
25 93 100       222 if ( $type eq "checkbox" ) {
26 7 100       19 $value = "on" unless defined $value;
27             $self->{menu} = [
28 7         42 { value => undef, name => "off", },
29             { value => $value, name => $value_name, },
30             ];
31 7 100       26 $self->{current} = ( delete $self->{checked} ) ? 1 : 0;
32              
33             }
34             else {
35             $self->{option_disabled}++
36 86 100 100     215 if $type eq "radio" && delete $self->{disabled};
37             $self->{menu} = [
38 86         290 { value => $value, name => $value_name },
39             ];
40 86   100     272 my $checked = $self->{checked} || $self->{option_selected};
41 86         135 delete $self->{checked};
42 86         109 delete $self->{option_selected};
43 86 100       152 if ( exists $self->{multiple} ) {
44 16         20 unshift( @{ $self->{menu} }, { value => undef, name => "off" } );
  16         64  
45 16 100       43 $self->{current} = $checked ? 1 : 0;
46             }
47             else {
48 70 100       150 $self->{current} = 0 if $checked;
49             }
50             }
51 93         202 $self;
52             }
53              
54             sub add_to_form {
55 93     93 0 170 my ( $self, $form ) = @_;
56 93         212 my $type = $self->type;
57              
58 93 100       214 return $self->SUPER::add_to_form($form)
59             if $type eq "checkbox";
60              
61 86 100 100     278 if ( $type eq "option" && exists $self->{multiple} ) {
62 16   100     73 $self->{disabled} ||= delete $self->{option_disabled};
63 16         43 return $self->SUPER::add_to_form($form);
64             }
65              
66 70 50       85 Carp::croak "Assert" if @{ $self->{menu} } != 1;
  70         153  
67 70         119 my $m = $self->{menu}[0];
68 70 100       131 $m->{disabled}++ if delete $self->{option_disabled};
69              
70             # if there was no name we have to search for an input that explicitly has
71             # no name either, because otherwise the name attribute would be ignored
72             my $prev = $form->find_input(
73             $self->{name} || \undef, $self->{type},
74             $self->{idx}
75 70   100     264 );
76 70 100       200 return $self->SUPER::add_to_form($form) unless $prev;
77              
78             # merge menus
79 38 100       76 $prev->{current} = @{ $prev->{menu} } if exists $self->{current};
  4         9  
80 38         55 push( @{ $prev->{menu} }, $m );
  38         273  
81             }
82              
83             sub fixup {
84 55     55 0 95 my $self = shift;
85 55 100 100     180 if ( $self->{type} eq "option" && !( exists $self->{current} ) ) {
86 11         33 $self->{current} = 0;
87             }
88 55 100       241 $self->{menu}[ $self->{current} ]{seen}++ if exists $self->{current};
89             }
90              
91             sub disabled {
92 46     46 0 72 my $self = shift;
93 46         109 my $type = $self->type;
94              
95 46   100     108 my $old = $self->{disabled} || _menu_all_disabled( @{ $self->{menu} } );
96 46 100       94 if (@_) {
97 5         10 my $v = shift;
98 5         7 $self->{disabled} = $v;
99 5         8 for ( @{ $self->{menu} } ) {
  5         10  
100 11         18 $_->{disabled} = $v;
101             }
102             }
103 46         176 return $old;
104             }
105              
106             sub _menu_all_disabled {
107 36     36   64 for (@_) {
108 38 100       119 return 0 unless $_->{disabled};
109             }
110 4         11 return 1;
111             }
112              
113             sub value {
114 96     96 0 135 my $self = shift;
115 96         120 my $old;
116             $old = $self->{menu}[ $self->{current} ]{value}
117 96 100       256 if exists $self->{current};
118 96 50       196 $old = $self->{value} if exists $self->{value};
119 96 100       179 if (@_) {
120 41         61 my $i = 0;
121 41         100 my $val = shift;
122 41         66 my $cur;
123             my $disabled;
124 41         54 for ( @{ $self->{menu} } ) {
  41         84  
125 79 100 100     474 if (
      100        
      100        
      100        
126             (
127             defined($val)
128             && defined( $_->{value} )
129             && $val eq $_->{value}
130             )
131             || ( !defined($val) && !defined( $_->{value} ) )
132             ) {
133 27         41 $cur = $i;
134 27         41 $disabled = $_->{disabled};
135 27 100       57 last unless $disabled;
136             }
137 59         92 $i++;
138             }
139 41 100 100     128 if ( !( defined $cur ) || $disabled ) {
140 21 100       48 if ( defined $val ) {
    50          
141              
142             # try to search among the alternative names as well
143 20         29 my $i = 0;
144 20         27 my $cur_ignorecase;
145 20         36 my $lc_val = lc($val);
146 20         25 for ( @{ $self->{menu} } ) {
  20         37  
147 43 100       87 if ( defined $_->{name} ) {
148 35 100       78 if ( $val eq $_->{name} ) {
149 4         7 $disabled = $_->{disabled};
150 4         7 $cur = $i;
151 4 100       9 last unless $disabled;
152             }
153 32 100 100     115 if ( !defined($cur_ignorecase)
154             && $lc_val eq lc( $_->{name} ) ) {
155 3         6 $cur_ignorecase = $i;
156             }
157             }
158 40         61 $i++;
159             }
160 20 100       45 unless ( defined $cur ) {
161 10         21 $cur = $cur_ignorecase;
162 10 100       25 if ( defined $cur ) {
    50          
163 2         5 $disabled = $self->{menu}[$cur]{disabled};
164             }
165             elsif ( $self->{strict} ) {
166 8         19 my $n = $self->name;
167 8         660 Carp::croak("Illegal value '$val' for field '$n'");
168             }
169             }
170             }
171             elsif ( $self->{strict} ) {
172 1         15 my $n = $self->name;
173 1         121 Carp::croak("The '$n' field can't be unchecked");
174             }
175             }
176 32 100 100     102 if ( $self->{strict} && $disabled ) {
177 7         20 my $n = $self->name;
178 7         687 Carp::croak("The value '$val' has been disabled for field '$n'");
179             }
180 25 50       47 if ( defined $cur ) {
181 25         39 $self->{current} = $cur;
182 25         46 $self->{menu}[$cur]{seen}++;
183 25         40 delete $self->{value};
184             }
185             else {
186 0         0 $self->{value} = $val;
187 0         0 delete $self->{current};
188             }
189             }
190 80         252 $old;
191             }
192              
193             sub check {
194 1     1 0 3 my $self = shift;
195 1         3 $self->{current} = 1;
196 1         4 $self->{menu}[1]{seen}++;
197             }
198              
199             sub possible_values {
200 2     2 0 7 my $self = shift;
201 2         4 map $_->{value}, grep !$_->{disabled}, @{ $self->{menu} };
  2         31  
202             }
203              
204             sub other_possible_values {
205 3     3 0 8 my $self = shift;
206 3   100     6 map $_->{value}, grep !$_->{seen} && !$_->{disabled}, @{ $self->{menu} };
  3         43  
207             }
208              
209             sub value_names {
210 7     7 0 14 my $self = shift;
211 7         13 my @names;
212 7         9 for ( @{ $self->{menu} } ) {
  7         16  
213 10         16 my $n = $_->{name};
214 10 100       22 $n = $_->{value} unless defined $n;
215 10         21 push( @names, $n );
216             }
217 7         55 @names;
218             }
219              
220             1;
221              
222             __END__