File Coverage

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


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