File Coverage

blib/lib/Mojolicious/Plugin/FormFieldsFromJSON.pm
Criterion Covered Total %
statement 453 470 96.3
branch 201 244 82.3
condition 152 253 60.0
subroutine 33 33 100.0
pod 1 1 100.0
total 840 1001 83.9


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::FormFieldsFromJSON;
2 85     85   85680 use Mojo::Base 'Mojolicious::Plugin';
  85         228  
  85         690  
3              
4             # ABSTRACT: create form fields based on a definition in a JSON file
5              
6             our $VERSION = '1.02';
7              
8 85     85   20438 use Carp;
  85         218  
  85         5427  
9 85     85   598 use File::Basename;
  85         190  
  85         5130  
10 85     85   601 use File::Spec;
  85         201  
  85         2472  
11 85     85   46934 use IO::Dir;
  85         146813  
  85         4720  
12 85     85   991 use List::Util qw(first);
  85         223  
  85         5351  
13              
14 85     85   555 use Mojo::Asset::File;
  85         215  
  85         1302  
15 85     85   2559 use Mojo::Collection;
  85         208  
  85         3496  
16 85     85   489 use Mojo::ByteStream;
  85         201  
  85         2646  
17 85     85   504 use Mojo::File;
  85         190  
  85         3058  
18 85     85   474 use Mojo::JSON qw(decode_json);
  85         205  
  85         3832  
19              
20 85     85   553 use Mojolicious ();
  85         196  
  85         596751  
21              
22             has dir => sub { ["."] };
23              
24             my $selected_value = Mojolicious->VERSION < 6.16 ? 'selected' : undef;
25             my $checked_value = Mojolicious->VERSION < 6.16 ? 'checked' : undef;
26              
27             sub register {
28 85     85 1 4509 my ( $self, $app, $config ) = @_;
29              
30 85   50     406 $config //= {};
31              
32 85 100       392 if ( $config->{template_file} ) {
33 1         9 $config->{template} = Mojo::File->new( $app->home, 'templates', $config->{template_file} )->slurp;
34 1   33     242 $config->{template} //= $app->renderer->get_data_template( $config->{template_file} );
35             }
36              
37 85         206 my %configs;
38 85 100       333 if ( ref $config->{dir} eq "ARRAY" ) {
39 1         2 @{ $self->dir } = @{ $config->{dir} };
  1         3  
  1         3  
40             }
41             else {
42 84         225 @{ $self->dir } = ( $config->{dir} );
  84         350  
43             }
44              
45             my %valid_types = (
46 85 100       203 %{ $config->{types} || {} },
  85         1203  
47             text => 1,
48             checkbox => 1,
49             select => 1,
50             radio => 1,
51             hidden => 1,
52             textarea => 1,
53             password => 1,
54             );
55              
56 85         267 my %configfiles;
57             $app->helper(
58             forms => sub {
59 1 50   1   17323 if (%configfiles) {
60 0         0 my @sorted_configfiles = sort keys %configfiles;
61 0         0 return @sorted_configfiles;
62             }
63              
64 1         12 for my $dir ( @{ $self->dir } ) {
  1         5  
65 1         10 my $dir = IO::Dir->new($dir);
66              
67             FILE:
68 1         90 while ( my $file = $dir->read ) {
69 5 100       84 next FILE if $file !~ m{\.json\z};
70              
71 3         78 my $filename = basename $file;
72 3         13 $filename =~ s{\.json\z}{};
73              
74 3         14 $configfiles{$filename} = 1;
75             }
76             }
77              
78 1         60 my @sorted_configfiles = sort keys %configfiles;
79 1         7 return @sorted_configfiles;
80             }
81 85         1152 );
82              
83 85     1   13517 $app->helper( "form_fields_from_json_dir" => sub { return $self->dir } );
  1         4532  
84              
85             $app->helper(
86             fields => sub {
87 2     2   28277 my ( $c, $file, $params ) = @_;
88              
89 2 100       19 if ( !$configs{$file} ) {
90 1         10 $self->_load_config_from_file( $c, \%configs, $file );
91             }
92              
93 2         7 my @fields;
94             my @fields_long;
95 2         5 for my $field ( @{ $configs{$file} } ) {
  2         7  
96 4   33     14 my $name = $field->{label} // $field->{name} // '';
      0        
97 4         10 push @fields, $name;
98 4   50     18 push @fields_long, +{ label => $name, name => $field->{name} // '' };
99             }
100              
101 2 100 66     14 if ( $params and $params->{hash} ) {
102 1         7 return @fields_long;
103             }
104              
105 1         9 return @fields;
106             }
107 85         8126 );
108              
109             $app->helper(
110             'validate_form_fields' => sub {
111 23     23   315146 my ( $c, $file ) = @_;
112              
113 23 50       132 return '' if !$file;
114              
115 23 100       123 if ( !$configs{$file} ) {
116 10         64 $self->_load_config_from_file( $c, \%configs, $file );
117             }
118              
119 23 50       104 return '' if !$configs{$file};
120              
121 23         68 my $config = $configs{$file};
122              
123 23         189 my $validation = $c->validation;
124              
125 23         16933 my $params_hash = $c->req->params->to_hash;
126 23 50       817 my @param_names = keys %{ $params_hash || {} };
  23         145  
127              
128 23         71 my %params = map { $_ => $c->every_param($_) } @param_names;
  20         127  
129 23         2042 $validation->input( \%params );
130              
131 23         168 my %errors;
132              
133             FIELD:
134 23         50 for my $field ( @{$config} ) {
  23         72  
135 23 50       103 if ( 'HASH' ne ref $field ) {
136 0         0 $app->log->error('Field definition must be a HASH - skipping field');
137 0         0 next FIELD;
138             }
139              
140 23 50       126 if ( !$field->{validation} ) {
141 0         0 next FIELD;
142             }
143              
144 23 50       97 if ( 'HASH' ne ref $field->{validation} ) {
145 0         0 $app->log->warn('Validation settings must be a HASH - skipping field');
146 0         0 next FIELD;
147             }
148              
149 23   33     102 my $name = $field->{name} // $field->{label} // '';
      0        
150 23         102 my $global_error = 1;
151              
152 23 100       105 if ( $field->{validation}->{required} ) {
153 7         38 $validation->required($name);
154              
155 7         405 my $value = $field->{validation}->{required};
156 7 100 66     44 if ( ref $value && 'HASH' eq ref $value ) {
157 2   50     20 $global_error = $value->{msg} // 1;
158             }
159             }
160             else {
161 16         96 $validation->optional($name);
162             }
163              
164             RULE:
165 23         1037 for my $rule ( sort keys %{ $field->{validation} } ) {
  23         176  
166 27 100       164 last RULE if !defined $params{$name};
167              
168 22 100       94 next RULE if $rule eq 'required';
169              
170 19         53 my $value = $field->{validation}->{$rule};
171 19         47 my $ref = ref $value;
172 19         43 my $method = $rule;
173 19         45 my $error = 1;
174              
175 19         69 my @params;
176              
177 19 100       90 if ( !$ref ) {
    100          
    50          
178 3         11 @params = $value;
179             }
180             elsif ( $ref eq 'ARRAY' ) {
181 6         12 @params = @{$value};
  6         24  
182             }
183             elsif ( $ref eq 'HASH' ) {
184 10 50       36 @params = ref $value->{args} ? @{ $value->{args} } : $value->{args};
  10         41  
185 10   50     39 $error = $value->{msg} // 1;
186             }
187              
188             eval {
189 19         92 $validation->check( $method, @params );
190 19         1202 1;
191 19 50       54 } or do {
192 0         0 $app->log->error("Validating $name with rule $method failed: $@");
193             };
194              
195 19 100       78 if ( $validation->has_error($name) ) {
196 8         58 $errors{$name} = $error;
197 8         27 last RULE;
198             }
199             }
200              
201 23 100 100     188 if ( $validation->has_error($name) && !defined $errors{$name} ) {
202 4         61 $errors{$name} = $global_error;
203             }
204             }
205              
206 23         329 return %errors;
207             }
208 85         7781 );
209              
210             $app->helper(
211             'form_fields' => sub {
212 107     107   1602987 my ( $c, $file, %params ) = @_;
213              
214             # get form config
215 107 100       822 return '' if !$self->_load_config_from_file( $c, \%configs, $file );
216 106 50 66     502 return '' if !$configs{$file} && !ref $file;
217 106   66     485 my $field_config = $configs{$file} || $file;
218              
219 106         259 my @fields;
220              
221 106 100       242 my %fields_to_show = map { $_ => 1 } @{ $params{fields} || [] };
  2         9  
  106         767  
222              
223             FIELD:
224 106         297 for my $field ( @{$field_config} ) {
  106         371  
225 145 100 100     629 next FIELD if %fields_to_show && !$fields_to_show{ $field->{name} };
226              
227 143         759 my $field_content = $self->_build_form_field( $c, $field, \%params, $config, \%valid_types );
228              
229 143 50       476 if ( length $field_content ) {
230 143         1369 push @fields, $field_content;
231             }
232             }
233              
234 106         433 return Mojo::ByteStream->new( join "\n\n", @fields );
235             }
236 85         7750 );
237              
238             $app->helper(
239             'form_field_by_name' => sub {
240 4     4   56198 my ( $c, $file, $field_name, %params ) = @_;
241              
242             # get form config
243 4 50       18 return '' if !$self->_load_config_from_file( $c, \%configs, $file );
244 4 0 33     12 return '' if !$configs{$file} && !ref $file;
245 4   33     13 my $field_config = $configs{$file} || $file;
246              
247             # find field config
248 4         10 my @fields_filtered = grep { $_->{name} eq $field_name } @{$field_config};
  8         45  
  4         10  
249              
250 4 50       32 return '' if !( scalar @fields_filtered );
251              
252 4         20 return $self->_build_form_field( $c, $fields_filtered[0], \%params, $config, \%valid_types );
253             }
254 85         7605 );
255              
256 85         7821 return 1;
257             }
258              
259             sub _load_config_from_file {
260 122     122   480 my ( $self, $c, $configs, $file ) = @_;
261              
262 122 50       618 return 0 if !$file;
263              
264 122 100 100     1174 if ( !$configs->{$file} && !ref $file ) {
265 85         295 my $path;
266              
267             # search until first match
268 85         256 my $i = 0;
269             do {
270 89         565 my $_path = File::Spec->catfile( $self->dir->[$i], $file . '.json' );
271 89 100       5650 $path = $_path if -r $_path;
272 85   100     235 } while ( not defined $path and ++$i <= $#{ $self->dir } );
  5         24  
273              
274 85 100       663 if ( not defined $path ) {
275 1         6 $c->app->log->error("FORMFIELDS $file: not found in directories");
276 1         21 $c->app->log->error(" $_") for @{ $self->dir };
  1         4  
277 1         32 return 0;
278             }
279              
280             eval {
281 84         1141 my $content = Mojo::Asset::File->new( path => $path )->slurp;
282 84         28683 $configs->{$file} = decode_json $content;
283 84 50       330 } or do {
284 0         0 $c->app->log->error("FORMFIELDS $file: $@");
285 0         0 return 0;
286             };
287              
288 84 50       35618 if ( 'ARRAY' ne ref $configs->{$file} ) {
289 0         0 $c->app->log->error('Definition JSON must be an ARRAY');
290 0         0 return 0;
291             }
292             }
293              
294 121         543 return 1;
295             }
296              
297             sub _build_form_field {
298 147     147   510 my ( $self, $c, $field, $params, $plugin_config, $valid_types ) = @_;
299              
300 147 50       621 if ( 'HASH' ne ref $field ) {
301 0         0 $c->app->log->error('Field definition must be an HASH - skipping field');
302 0         0 return '';
303             }
304              
305 147         744 my $type = lc $field->{type};
306 147         388 my $orig_type = $type;
307              
308 147 100 100     661 if ( $plugin_config->{alias} && $plugin_config->{alias}->{$type} ) {
309 3         8 $type = $plugin_config->{alias}->{$type};
310             }
311              
312 147 50       766 if ( !$valid_types->{$type} ) {
313 0         0 $c->app->log->warn("Invalid field type $type - falling back to 'text'");
314 0         0 $type = 'text';
315             }
316              
317 147 100 100     1056 if ( $plugin_config->{global_attributes}
      66        
318             && $type ne 'hidden'
319             && 'HASH' eq ref $plugin_config->{global_attributes} )
320             {
321              
322             ATTRIBUTE:
323 24         44 for my $attribute ( keys %{ $plugin_config->{global_attributes} } ) {
  24         79  
324 24   100     103 $field->{attributes}->{$attribute} //= '';
325              
326 24         50 my $field_attr = $field->{attributes}->{$attribute};
327 24         47 my $global_attr = $plugin_config->{global_attributes}->{$attribute};
328              
329 24 100       152 next ATTRIBUTE if $field_attr =~ m{\Q$global_attr};
330              
331 18 100       63 my $space = length $field_attr ? ' ' : '';
332              
333 18         68 $field->{attributes}->{$attribute} .= $space . $global_attr;
334             }
335             }
336              
337 147 50 66     591 if ( $field->{translate_sublabels}
      33        
338             && $plugin_config->{translation_method}
339             && !$field->{translation_method} )
340             {
341 2         6 $field->{translation_method} = $plugin_config->{translation_method};
342             }
343              
344 147         1693 my $sub = $self->can( '_' . $type );
345 147         461 my $form_field = $self->$sub( $c, $field, %{$params} );
  147         676  
346              
347 147         34303 $form_field = Mojo::ByteStream->new($form_field);
348              
349             my $template = $field->{template} // $plugin_config->{templates}->{$orig_type}
350 147   100     3657 // $plugin_config->{template};
      100        
351              
352 147 100 66     747 if ( $template && $type ne 'hidden' ) {
353 23   50     153 my $label = $field->{label} // '';
354 23         90 my $loc = $plugin_config->{translation_method};
355              
356 23 50 66     111 if ( $plugin_config->{translate_labels} && $loc && 'CODE' eq ref $loc ) {
      66        
357 1         8 $label = $loc->( $c, $label );
358             }
359              
360             $form_field = Mojo::ByteStream->new(
361             $c->render_to_string(
362             inline => $template,
363             id => $field->{id} // $field->{name} // $field->{label} // '',
364             label => $label,
365             field => $form_field,
366             message => $field->{msg} // '',
367 23   33     442 info => $field->{info} // '',
      33        
      0        
      100        
      100        
368             )
369             );
370              
371             # $c->app->log->debug("rendered formfield: ".$form_field);
372             }
373              
374 147         61668 return $form_field;
375             }
376              
377             sub _hidden {
378 8     8   30 my ( $self, $c, $field, %params ) = @_;
379              
380 8   33     33 my $name = $field->{name} // $field->{label} // '';
      0        
381              
382 8         31 my $from_stash_key = $params{from_stash};
383             my $from_stash =
384             $from_stash_key
385 8 50       32 ? $c->stash($from_stash_key)->{$name}
386             : undef;
387              
388             my $value = $params{$name}->{data} // $from_stash // $c->stash($name) // $c->param($name)
389 8   66     94 // $field->{data} // '';
      66        
      66        
      66        
      50        
390              
391 8   33     1032 my $id = $field->{id} // $name;
392 8 50       30 my %attrs = %{ $field->{attributes} || {} };
  8         55  
393              
394 8         83 return $c->hidden_field( $name, $value, id => $id, %attrs );
395             }
396              
397             sub _text {
398 33     33   131 my ( $self, $c, $field, %params ) = @_;
399              
400 33   33     239 my $name = $field->{name} // $field->{label} // '';
      0        
401              
402 33         92 my $from_stash_key = $params{from_stash};
403             my $from_stash =
404             $from_stash_key
405 33 100       177 ? $c->stash($from_stash_key)->{$name}
406             : undef;
407              
408             my $value = $params{$name}->{data} // $from_stash // $c->stash($name) // $c->param($name)
409 33   100     469 // $field->{data} // '';
      100        
      100        
      100        
      100        
410              
411 33   33     7310 my $id = $field->{id} // $name;
412 33 100       109 my %attrs = %{ $field->{attributes} || {} };
  33         287  
413              
414 33         439 return $c->text_field( $name, $value, id => $id, %attrs );
415             }
416              
417             sub _select {
418 38     38   137 my ( $self, $c, $field, %params ) = @_;
419              
420 38   33     185 my $name = $field->{name} // $field->{label} // '';
      0        
421              
422 38         92 my $from_stash_key = $params{from_stash};
423             my $from_stash =
424             $from_stash_key
425 38 100       151 ? $c->stash($from_stash_key)->{$name}
426             : undef;
427              
428 38   100     328 my $field_params = $params{$name} || {},
429              
430             my %select_params = (
431             disabled => $self->_get_highlighted_values( $field, 'disabled' ),
432             selected => $self->_get_highlighted_values( $field, 'selected' ),
433             );
434              
435 38         219 my $stash_values = $c->every_param($name);
436 38 50 100     8846 if ( scalar( @{ $stash_values || [] } ) == 0 && defined( $c->stash($name) ) ) {
  38 100       339  
437 3         49 my $local_stash = $c->stash($name);
438 3 100       42 $stash_values = ref $local_stash ? $local_stash : [$local_stash];
439             }
440              
441 38 100       501 if ($from_stash) {
442 1 50       5 $stash_values = ref $from_stash ? $from_stash : [$from_stash];
443             }
444              
445 38         88 my $reset;
446 38 50       78 if ( @{ $stash_values || [] } ) {
  38 100       165  
447             $select_params{selected} =
448 13         64 $self->_get_highlighted_values( +{ selected => $stash_values }, 'selected', );
449              
450 13         74 $reset = 1;
451             }
452              
453 38         124 for my $key (qw/disabled selected/) {
454 76         285 my $hashref = $self->_get_highlighted_values( $field_params, $key );
455 76 100       162 if ( keys %{$hashref} ) {
  76         414  
456 7         31 $select_params{$key} = $hashref;
457             }
458             }
459              
460 38 100       137 if ( $field_params->{data} ) {
461 5         11 $select_params{data} = $field_params->{data};
462             }
463              
464 38         319 my @values = $self->_get_select_values( $c, $field, %select_params );
465 38   33     267 my $id = $field->{id} // $name;
466 38 100       84 my %attrs = %{ $field->{attributes} || {} };
  38         240  
467              
468 38 100       211 if ( $field->{multiple} ) {
469 4         17 $attrs{multiple} = 'multiple';
470 4   50     16 $attrs{size} = $field->{size} || 5;
471             }
472              
473 38         90 my @selected = keys %{ $select_params{selected} };
  38         132  
474 38 100       128 if (@selected) {
475 18         36 my $single = scalar @selected;
476 18 100       69 my $param = $single == 1 ? $selected[0] : \@selected;
477 18         122 $c->param( $name, $param );
478             }
479              
480 38         733 my $select_field = $c->select_field( $name, [@values], id => $id, %attrs );
481              
482             # reset parameters
483 38 100       36795 if ($reset) {
484 13         31 my $single = scalar @{$stash_values};
  13         30  
485 13 100       52 my $param = $single == 1 ? $stash_values->[0] : $stash_values;
486 13         53 $c->param( $name, $param );
487             }
488              
489 38         455 return $select_field;
490             }
491              
492             sub _get_highlighted_values {
493 386     386   1014 my ( $self, $field, $key ) = @_;
494              
495 386 100       1563 return +{} if !$field->{$key};
496              
497 69         191 my %highlighted;
498              
499 69 100       314 if ( !ref $field->{$key} ) {
    50          
500 25         54 my $value = $field->{$key};
501 25         82 $highlighted{$value} = 1;
502             }
503             elsif ( 'ARRAY' eq ref $field->{$key} ) {
504 44         88 for my $value ( @{ $field->{$key} } ) {
  44         135  
505 52         256 $highlighted{$value} = 1;
506             }
507             }
508              
509 69         251 return \%highlighted;
510             }
511              
512             sub _get_select_values {
513 39     39   170 my ( $self, $c, $field, %params ) = @_;
514              
515 39   100     360 my $data = $params{data} || $field->{data} || [];
516 39 100       210 if ( $field->{data_cb} ) {
517 1         8 my @parts = split /::/, $field->{data_cb};
518 1         3 my $subname = pop @parts;
519 1         68 my $class = join '::', @parts;
520 1         30 my $sub = $class->can($subname);
521 1 50       31 $data = $sub->() if $sub;
522             }
523              
524 39         110 my @values;
525 39 100       173 if ( 'ARRAY' eq ref $data ) {
    50          
526 35         177 @values = $self->_transform_array_values( $data, %params );
527             }
528             elsif ( 'HASH' eq ref $data ) {
529 4         38 @values = $self->_transform_hash_values( $c, $data, %params );
530             }
531              
532 39         150 return @values;
533             }
534              
535             sub _transform_hash_values {
536 4     4   18 my ( $self, $c, $data, %params ) = @_;
537              
538 4         81 my @values;
539 4         13 my $numeric = 1;
540 4         8 my $counter = 0;
541 4         10 my %mapping;
542              
543             KEY:
544 4         10 for my $key ( keys %{$data} ) {
  4         18  
545 7 100       25 if ( ref $data->{$key} ) {
546 1         17 my @group_values = $self->_get_select_values( $c, +{ data => $data->{$key} }, %params );
547 1         13 $values[$counter] = Mojo::Collection->new( $key => \@group_values );
548 1         10 $mapping{$key} = $counter;
549             }
550             else {
551 6         13 my %opts;
552              
553 6 50       36 $opts{disabled} = 'disabled' if $params{disabled}->{$key};
554 6 50       19 $opts{selected} = $selected_value if $params{selected}->{$key};
555              
556             #$opts{selected} = undef if $params{selected}->{$key};
557              
558 6         25 $values[$counter] = [ $data->{$key} => $key, %opts ];
559 6         23 $mapping{$key} = $counter;
560             }
561              
562 7         17 $counter++;
563             }
564              
565 4 100   5   34 if ( first { $_ =~ m{[^0-9]} } keys %mapping ) {
  5         29  
566 3         6 $numeric = 0;
567             }
568              
569             my @sorted_keys =
570             $numeric
571 1         6 ? sort { $a <=> $b } keys %mapping
572 4 100       48 : sort { $a cmp $b } keys %mapping;
  2         14  
573              
574 4         13 my @indexes = @mapping{@sorted_keys};
575              
576 4         13 my @sorted_values = @values[@indexes];
577              
578 4         19 return @sorted_values;
579             }
580              
581             sub _transform_array_values {
582 35     35   148 my ( $self, $data, %params ) = @_;
583              
584 35         195 my @values;
585 35         90 my $numeric = 1;
586              
587 35         86 for my $value ( @{$data} ) {
  35         103  
588 93 100 66     469 if ( $numeric && $value =~ m{[^0-9]} ) {
589 35         88 $numeric = 0;
590             }
591              
592 93         171 my %opts;
593              
594 93 100       254 $opts{disabled} = 'disabled' if $params{disabled}->{$value};
595 93 100       265 $opts{selected} = $selected_value if $params{selected}->{$value};
596              
597             #$opts{selected} = undef if $params{selected}->{$value};
598              
599 93         398 push @values, [ $value => $value, %opts ];
600             }
601              
602             @values =
603             $numeric
604 0         0 ? sort { $a->[0] <=> $b->[0] } @values
605 35 50       322 : sort { $a->[0] cmp $b->[0] } @values;
  80         256  
606              
607 35         147 return @values;
608             }
609              
610             sub _radio {
611 25     25   96 my ( $self, $c, $field, %params ) = @_;
612              
613 25   33     122 my $name = $field->{name} // $field->{label} // '';
      0        
614 25   33     137 my $id = $field->{id} // $name;
615 25 100       67 my %attrs = %{ $field->{attributes} || {} };
  25         162  
616              
617 25   66     221 my $data = $params{$name}->{data} // $field->{data} // [];
      50        
618 25 100       128 my @values = ref $data ? @{$data} : ($data);
  17         99  
619              
620 25   50     210 my $field_params = $params{$name} || {},
621              
622             my %select_params = (
623             disabled => $self->_get_highlighted_values( $field, 'disabled' ),
624             selected => $self->_get_highlighted_values( $field, 'selected' ),
625             );
626              
627 25         149 my $stash_values = $c->every_param($name);
628 25 50 100     5184 if ( scalar( @{ $stash_values || [] } ) == 0 && defined( $c->stash($name) ) ) {
  25 100       302  
629 1         24 my $local_stash = $c->stash($name);
630 1 50       15 $stash_values = ref $local_stash ? $local_stash : [$local_stash];
631             }
632 25         366 my $reset;
633 25 50       63 if ( @{ $stash_values || [] } ) {
  25 100       155  
634             $select_params{selected} =
635 4         24 $self->_get_highlighted_values( +{ selected => $stash_values }, 'selected', );
636 4         11 $reset = 1;
637             }
638              
639 25         81 for my $key (qw/disabled selected/) {
640 50         185 my $hashref = $self->_get_highlighted_values( $field_params, $key );
641 50 100       96 if ( keys %{$hashref} ) {
  50         264  
642 5         41 $select_params{$key} = $hashref;
643             }
644             }
645              
646 25         144 my @selected = keys %{ $select_params{selected} };
  25         97  
647 25 100       103 if (@selected) {
648 6         12 my $single = scalar @selected;
649 6 50       27 my $param = $single == 1 ? $selected[0] : \@selected;
650 6         27 $c->param( $name, $param );
651             }
652              
653 25         181 my $radiobuttons = '';
654 25         96 for my $radio_value (@values) {
655 42         134 my %value_attributes;
656              
657 42 100       265 if ( $select_params{disabled}->{$radio_value} ) {
658 3         10 $value_attributes{disabled} = 'disabled';
659             }
660              
661 42 100       230 if ( $select_params{selected}->{$radio_value} ) {
662 6         18 $value_attributes{checked} = $checked_value;
663             }
664              
665 42         108 my $local_label = '';
666 42 100       157 if ( $field->{show_value} ) {
667 4         10 $local_label = $radio_value;
668             }
669              
670 42         91 my $loc = $field->{translation_method};
671 42 50 100     177 if ( length $local_label && $field->{translate_sublabels} && $loc && 'CODE' eq ref $loc ) {
      66        
      66        
672 2         9 $local_label = $loc->( $c, $local_label );
673             }
674              
675 42 100       144 $local_label = " " . $local_label if length $local_label;
676              
677 42         402 $radiobuttons .= $c->radio_button(
678             $name => $radio_value,
679             id => $id,
680             %attrs,
681             %value_attributes,
682             ) . "$local_label\n";
683              
684 42 100       21943 if ( defined $field->{after_element} ) {
685 2         9 $radiobuttons .= $field->{after_element};
686             }
687             }
688              
689 25 100       99 if ($reset) {
690 4         9 my $single = scalar @{$stash_values};
  4         11  
691 4 50       18 my $param = $single == 1 ? $stash_values->[0] : $stash_values;
692 4         16 $c->param( $name, $param );
693             }
694              
695 25         196 return $radiobuttons;
696             }
697              
698             sub _checkbox {
699 28     28   97 my ( $self, $c, $field, %params ) = @_;
700              
701 28   33     137 my $name = $field->{name} // $field->{label} // '';
      0        
702 28   33     168 my $id = $field->{id} // $name;
703 28 100       84 my %attrs = %{ $field->{attributes} || {} };
  28         191  
704              
705 28   66     270 my $data = $params{$name}->{data} // $field->{data} // [];
      50        
706 28 100       169 my @values = ref $data ? @{$data} : ($data);
  15         71  
707              
708 28   50     210 my $field_params = $params{$name} || {},
709              
710             my %select_params = (
711             disabled => $self->_get_highlighted_values( $field, 'disabled' ),
712             selected => $self->_get_highlighted_values( $field, 'selected' ),
713             );
714              
715 28         169 my $stash_values = $c->every_param($name);
716 28 50 100     5852 if ( scalar( @{ $stash_values || [] } ) == 0 && defined( $c->stash($name) ) ) {
  28 100       308  
717 2         64 my $local_stash = $c->stash($name);
718 2 100       29 $stash_values = ref $local_stash ? $local_stash : [$local_stash];
719             }
720 28         435 my $reset;
721 28 50       87 if ( @{ $stash_values || [] } ) {
  28 100       133  
722             $select_params{selected} =
723 5         26 $self->_get_highlighted_values( +{ selected => $stash_values }, 'selected', );
724 5         29 $c->param( $name, '' );
725 5         124 $reset = 1;
726             }
727              
728 28         97 for my $key (qw/disabled selected/) {
729 56         167 my $hashref = $self->_get_highlighted_values( $field_params, $key );
730 56 100       134 if ( keys %{$hashref} ) {
  56         266  
731 6         53 $select_params{$key} = $hashref;
732             }
733             }
734              
735 28         170 my @selected = keys %{ $select_params{selected} };
  28         453  
736 28 100       113 if (@selected) {
737 8         23 my $single = scalar @selected;
738 8 100       31 my $param = $single == 1 ? $selected[0] : \@selected;
739 8         34 $c->param( $name, $param );
740             }
741              
742 28         196 my $checkboxes = '';
743 28         89 for my $checkbox_value (@values) {
744 44         143 my %value_attributes;
745              
746 44 100       279 if ( $select_params{disabled}->{$checkbox_value} ) {
747 3         10 $value_attributes{disabled} = 'disabled';
748             }
749              
750 44 100       244 if ( $select_params{selected}->{$checkbox_value} ) {
751 9         27 $value_attributes{checked} = $checked_value;
752             }
753              
754 44         102 my $local_label = '';
755 44 100       159 if ( $field->{show_value} ) {
756 4         10 $local_label = $checkbox_value;
757             }
758              
759 44         99 my $loc = $field->{translation_method};
760 44 50 100     164 if ( length $local_label && $field->{translate_sublabels} && $loc && 'CODE' eq ref $loc ) {
      66        
      66        
761 2         8 $local_label = $loc->( $c, $local_label );
762             }
763              
764 44 100       147 $local_label = " " . $local_label if length $local_label;
765              
766 44         384 $checkboxes .= $c->check_box(
767             $name => $checkbox_value,
768             id => $id,
769             %attrs,
770             %value_attributes,
771             ) . "$local_label\n";
772              
773 44 100       23711 if ( defined $field->{after_element} ) {
774 3         12 $checkboxes .= $field->{after_element};
775             }
776             }
777              
778 28 100       115 if ($reset) {
779 5         10 my $single = scalar @{$stash_values};
  5         17  
780 5 100       24 my $param = $single == 1 ? $stash_values->[0] : $stash_values;
781 5         31 $c->param( $name, $param );
782             }
783              
784 28         225 return $checkboxes;
785             }
786              
787             sub _textarea {
788 8     8   34 my ( $self, $c, $field, %params ) = @_;
789              
790 8   33     86 my $name = $field->{name} // $field->{label} // '';
      0        
791 8   66     68 my $value = $params{$name}->{data} // $c->stash($name) // $c->param($name) // $field->{data} // '';
      100        
      100        
      100        
792 8   33     1298 my $id = $field->{id} // $name;
793 8 100       19 my %attrs = %{ $field->{attributes} || {} };
  8         65  
794              
795 8         103 return $c->text_area( $name, $value, id => $id, %attrs );
796             }
797              
798             sub _password {
799 6     6   21 my ( $self, $c, $field, %params ) = @_;
800              
801 6   33     40 my $name = $field->{name} // $field->{label} // '';
      0        
802 6   33     47 my $value = $params{$name}->{data} // $c->stash($name) // $c->param($name) // $field->{data} // '';
      66        
      66        
      50        
803 6   33     944 my $id = $field->{id} // $name;
804 6 100       15 my %attrs = %{ $field->{attributes} || {} };
  6         49  
805              
806 6         54 return $c->password_field( $name, value => $value, id => $id, %attrs );
807             }
808              
809             1;
810              
811             __END__