File Coverage

blib/lib/HTML/FormFu/Element/Checkboxgroup.pm
Criterion Covered Total %
statement 78 81 96.3
branch 28 32 87.5
condition 21 30 70.0
subroutine 11 12 91.6
pod n/a
total 138 155 89.0


line stmt bran cond sub pod time code
1             package HTML::FormFu::Element::Checkboxgroup;
2              
3 20     20   7947 use strict;
  20         29  
  20         733  
4             our $VERSION = '2.05'; # VERSION
5              
6 20     20   68 use Moose;
  20         21  
  20         89  
7 20     20   79365 use MooseX::Attribute::FormFuChained;
  20         31  
  20         721  
8             extends 'HTML::FormFu::Element';
9              
10             with 'HTML::FormFu::Role::Element::Group';
11              
12 20     20   84 use HTML::FormFu::Constants qw( $EMPTY_STR );
  20         22  
  20         1548  
13 20     20   85 use HTML::FormFu::Util qw( append_xml_attribute process_attrs );
  20         26  
  20         907  
14 20     20   77 use List::Util 1.33 qw( any );
  20         514  
  20         20163  
15              
16             has input_type => (
17             is => 'rw',
18             default => 'checkbox',
19             lazy => 1,
20             traits => ['FormFuChained'],
21             );
22              
23             has reverse_group => (
24             is => 'rw',
25             traits => ['FormFuChained'],
26             );
27              
28             after BUILD => sub {
29             my ( $self, $args ) = @_;
30              
31             $self->layout_field_filename('field_layout_checkboxgroup_field');
32             $self->label_tag('legend');
33             $self->container_tag('fieldset');
34             $self->multi_value(1);
35             $self->reverse_group(1);
36             $self->input_type('checkbox');
37              
38             $self->layout( [
39             'label',
40             'errors',
41             'field',
42             'comment',
43             'javascript',
44             ] );
45              
46             return;
47             };
48              
49             sub prepare_id {
50 48     48   64 my ( $self, $render ) = @_;
51              
52 48 100       123 my $form_id = defined $self->form->id ? $self->form->id : '';
53 48 50       130 my $field_name = defined $self->nested_name ? $self->nested_name : '';
54 48         81 my $count = 0;
55              
56 48         49 for my $option ( @{ $render->{options} } ) {
  48         108  
57 122 100       178 if ( exists $option->{group} ) {
58 15         22 for my $item ( @{ $option->{group} } ) {
  15         31  
59 30         43 $self->_prepare_id( $item, $form_id, $field_name, \$count );
60             }
61             }
62             else {
63 107         241 $self->_prepare_id( $option, $form_id, $field_name, \$count );
64             }
65             }
66              
67 48         90 return;
68             }
69              
70             sub _prepare_id {
71 137     137   158 my ( $self, $option, $form_id, $field_name, $count_ref ) = @_;
72              
73 137 100 66     450 if ( !exists $option->{attributes}{id} && defined $self->auto_id ) {
74 6         18 my %string = (
75             f => $form_id,
76             n => $field_name,
77             );
78              
79 6         11 my $id = $self->auto_id;
80 6         34 $id =~ s/%([fn])/$string{$1}/g;
81 6         9 $id =~ s/%c/ ++$$count_ref /gex;
  2         8  
82 6         12 $id =~ s/%v/ $option->{value} /gex;
  4         6  
83              
84 6 50       27 if ( defined( my $count = $self->repeatable_count ) ) {
85 0         0 $id =~ s/%r/$count/g;
86             }
87              
88 6         17 $option->{attributes}{id} = $id;
89             }
90              
91             # label "for" attribute
92 137 100 33     463 if ( exists $option->{label}
      66        
93             && exists $option->{attributes}{id}
94             && !exists $option->{label_attributes}{for} )
95             {
96 6         10 $option->{label_attributes}{for} = $option->{attributes}{id};
97             }
98              
99 137         939 return;
100             }
101              
102             sub _prepare_attrs {
103 137     137   148 my ( $self, $submitted, $value, $default, $option ) = @_;
104              
105 137 100 100     2240 if ( $submitted
    50 66        
    100 100        
    100 66        
    100 66        
    100 66        
      66        
106             && defined $value
107             && (ref $value eq 'ARRAY'
108 3     3   5 ? any { $_ eq $option->{value} } @$value
109             : $value eq $option->{value} ) )
110             {
111 15         27 $option->{attributes}{checked} = 'checked';
112             }
113             elsif ($submitted
114             && $self->retain_default
115             && ( !defined $value || $value eq $EMPTY_STR )
116             && $self->value eq $option->{value} )
117             {
118 4         10 $option->{attributes}{checked} = 'checked';
119             }
120             elsif ($submitted) {
121 52         57 delete $option->{attributes}{checked};
122             }
123             elsif (
124             defined $default
125             && (ref $default eq 'ARRAY'
126 0     0   0 ? any { $_ eq $option->{value} } @$default
127             : $default eq $option->{value} ) )
128             {
129 8         17 $option->{attributes}{checked} = 'checked';
130             }
131 137         241 return;
132             }
133              
134             sub render_data_non_recursive {
135             my ( $self, $args ) = @_;
136              
137             my $render = $self->SUPER::render_data_non_recursive( {
138             field_filename => $self->field_filename,
139             reverse_group => $self->reverse_group,
140             input_type => $self->input_type,
141             $args ? %$args : (),
142             } );
143              
144             for my $item ( @{ $render->{options} } ) {
145             if ( exists $item->{group} ) {
146             append_xml_attribute( $item->{attributes}, 'class', 'subgroup' );
147             }
148             }
149              
150             return $render;
151             }
152              
153             sub _string_field {
154 48     48   58 my ( $self, $render ) = @_;
155              
156             # radiogroup_tag template
157              
158 48         378 my $html .= sprintf "<span%s>\n", process_attrs( $render->{attributes} );
159              
160 48         66 for my $option ( @{ $render->{options} } ) {
  48         89  
161 122 100       177 if ( defined $option->{group} ) {
162             $html .= sprintf "<span%s>\n",
163 15         293 process_attrs( $option->{attributes} ),
164             ;
165              
166 15 100       39 if ( defined $option->{label} ) {
167 8         11 $html .= sprintf "<p>%s</p>\n", $option->{label};
168             }
169              
170 15         12 for my $item ( @{ $option->{group} } ) {
  15         25  
171             $html .= sprintf
172             "<span%s>\n",
173 30         42 process_attrs( $item->{container_attributes} );
174              
175             my $label = sprintf
176             "<label%s>%s</label>\n",
177             process_attrs( $item->{label_attributes} ),
178             $item->{label},
179 30         52 ;
180              
181             my $input = sprintf
182             qq{<input name="%s" type="%s" value="%s"%s />\n},
183             $render->{nested_name},
184             $render->{input_type},
185             $item->{value},
186 30         56 process_attrs( $item->{attributes} ),
187             ;
188              
189 30 50       39 if ( $render->{reverse_group} ) {
190 30         41 $html .= $input . $label;
191             }
192             else {
193 0         0 $html .= $label . $input;
194             }
195              
196 30         35 $html .= "</span>\n";
197             }
198              
199 15         18 $html .= "</span>\n";
200             }
201             else {
202             $html .= sprintf
203             "<span%s>\n",
204 107         184 process_attrs( $option->{container_attributes} );
205              
206             my $label = sprintf
207             "<label%s>%s</label>\n",
208             process_attrs( $option->{label_attributes} ),
209             $option->{label},
210 107         186 ;
211              
212             my $input = sprintf
213             qq{<input name="%s" type="%s" value="%s"%s />\n},
214             $render->{nested_name},
215             $render->{input_type},
216             $option->{value},
217 107         234 process_attrs( $option->{attributes} ),
218             ;
219              
220 107 100       176 if ( $render->{reverse_group} ) {
221 99         161 $html .= $input . $label;
222             }
223             else {
224 8         13 $html .= $label . $input;
225             }
226              
227 107         141 $html .= "</span>\n";
228             }
229             }
230              
231 48         58 $html .= "</span>";
232              
233 48         117 return $html;
234             }
235              
236             __PACKAGE__->meta->make_immutable;
237              
238             1;
239              
240             __END__
241              
242             =head1 NAME
243              
244             HTML::FormFu::Element::Checkboxgroup - Group of checkbox form fields
245              
246             =head1 VERSION
247              
248             version 2.05
249              
250             =head1 SYNOPSIS
251              
252             YAML config:
253              
254             ---
255             elements:
256             - type: Checkboxgroup
257             name: subjects
258             options:
259             - [ 'Math' ]
260             - [ 'Science' ]
261             - [ 'English' ]
262              
263             =head1 DESCRIPTION
264              
265             Convenient to use group of checkbox fields.
266              
267             Use the same syntax as you would to create a Select element optgroup to
268             create Checkboxgroup sub-groups, see L<HTML::FormFu::Role::Element::Group/options>
269             for details.
270              
271             =head1 METHODS
272              
273             =head2 options
274              
275             See L<HTML::FormFu::Role::Element::Group/options>.
276              
277             =head2 values
278              
279             See L<HTML::FormFu::Role::Element::Group/values>.
280              
281             =head2 value_range
282              
283             See L<HTML::FormFu::Role::Element::Group/value_range>.
284              
285             =head2 auto_id
286              
287             In addition to the substitutions documented by L<HTML::FormFu/auto_id>,
288             C<%c> will be replaced by an incremented integer, to ensure there are
289             no duplicated ID's, and C<%v> will be replaced by the item's value to
290             allow multiple elements with the same name to coexist, and their labels
291             to correctly select the appropriate item.
292              
293             ---
294             elements:
295             type: Checkboxgroup
296             name: foo
297             auto_id: "%n_%c"
298              
299             =head2 reverse_group
300              
301             If true, then the label for each checkbox in the checkbox group should
302             be rendered to the right of the field control. Otherwise, the label
303             is rendered to the left of the field control.
304              
305             The default value is C<true>, causing each label to be rendered to the
306             right of its field control (or to be explicit: the markup for the
307             label comes after the field control in the source).
308              
309             Default Value: C<true>
310              
311             =head1 SEE ALSO
312              
313             Is a sub-class of, and inherits methods from
314             L<HTML::FormFu::Role::Element::Group>,
315             L<HTML::FormFu::Role::Element::Field>,
316             L<HTML::FormFu::Element>
317              
318             L<HTML::FormFu>
319              
320             =head1 AUTHOR
321              
322             Carl Franks, C<cfranks@cpan.org>
323              
324             =head1 LICENSE
325              
326             This library is free software, you can redistribute it and/or modify it under
327             the same terms as Perl itself.
328              
329             =cut