1use strict;
2
3package HTML::FormFu::Role::Element::Field;
4$HTML::FormFu::Role::Element::Field::VERSION = '2.07';
5# ABSTRACT: Role for all form-field elements
6
7use Moose::Role;
8use MooseX::Aliases;
9
10with 'HTML::FormFu::Role::ContainsElementsSharedWithField',
11    'HTML::FormFu::Role::NestedHashUtils',
12    'HTML::FormFu::Role::FormBlockAndFieldMethods',
13    'HTML::FormFu::Role::Element::Layout';
14
15use HTML::FormFu::Attribute qw(
16    mk_attrs
17    mk_output_accessors
18);
19use HTML::FormFu::Constants qw( $EMPTY_STR );
20use HTML::FormFu::Util qw(
21    _parse_args                 append_xml_attribute
22    xml_escape                  require_class
23    process_attrs               _filter_components
24);
25use Class::MOP::Method;
26use Clone ();
27use List::Util 1.45 qw( uniq );
28use Carp qw( croak carp );
29
30__PACKAGE__->mk_attrs( qw(
31        comment_attributes
32        container_attributes
33        label_attributes
34        error_attributes
35        error_container_attributes
36) );
37
38has _constraints         => ( is => 'rw', traits => ['Chained'] );
39has _filters             => ( is => 'rw', traits => ['Chained'] );
40has _inflators           => ( is => 'rw', traits => ['Chained'] );
41has _deflators           => ( is => 'rw', traits => ['Chained'] );
42has _validators          => ( is => 'rw', traits => ['Chained'] );
43has _transformers        => ( is => 'rw', traits => ['Chained'] );
44has _plugins             => ( is => 'rw', traits => ['Chained'] );
45has _errors              => ( is => 'rw', traits => ['Chained'] );
46has container_tag        => ( is => 'rw', traits => ['Chained'] );
47has field_filename       => ( is => 'rw', traits => ['Chained'] );
48has label_filename       => ( is => 'rw', traits => ['Chained'] );
49has label_tag            => ( is => 'rw', traits => ['Chained'] );
50has retain_default       => ( is => 'rw', traits => ['Chained'] );
51has force_default        => ( is => 'rw', traits => ['Chained'] );
52has javascript           => ( is => 'rw', traits => ['Chained'] );
53has non_param            => ( is => 'rw', traits => ['Chained'] );
54has reverse_single       => ( is => 'rw', traits => ['Chained'] );
55has reverse_multi        => ( is => 'rw', traits => ['Chained'] );
56has multi_value          => ( is => 'rw', traits => ['Chained'] );
57has original_name        => ( is => 'rw', traits => ['Chained'] );
58has original_nested_name => ( is => 'rw', traits => ['Chained'] );
59has default_empty_value  => ( is => 'rw', traits => ['Chained'] );
60
61__PACKAGE__->mk_output_accessors(qw( comment label value ));
62
63alias( "default",     "value" );
64alias( "default_xml", "value_xml" );
65alias( "default_loc", "value_loc" );
66
67after BUILD => sub {
68    my $self = shift;
69
70    $self->_constraints(  [] );
71    $self->_filters(      [] );
72    $self->_deflators(    [] );
73    $self->_inflators(    [] );
74    $self->_validators(   [] );
75    $self->_transformers( [] );
76    $self->_plugins(      [] );
77    $self->_errors(       [] );
78    $self->comment_attributes(         {} );
79    $self->container_attributes(       {} );
80    $self->label_attributes(           {} );
81    $self->error_attributes(           {} );
82    $self->error_container_attributes( {} );
83    $self->label_filename('label');
84    $self->label_tag('label');
85    $self->container_tag('div');
86    $self->is_field(1);
87
88    return;
89};
90
91sub nested {
92    my ($self) = @_;
93
94    croak 'cannot set nested' if @_ > 1;
95
96    if ( defined $self->name ) {
97        my $parent = $self;
98
99        while ( defined( $parent = $parent->parent ) ) {
100
101            if ( $parent->can('is_field') && $parent->is_field ) {
102                return 1 if defined $parent->name;
103            }
104            else {
105                return 1 if defined $parent->nested_name;
106            }
107        }
108    }
109
110    return;
111}
112
113sub nested_name {
114    my ($self) = @_;
115
116    croak 'cannot set nested_name' if @_ > 1;
117
118    return if !defined $self->name;
119
120    my @names = $self->nested_names;
121
122    if ( $self->form->nested_subscript ) {
123        my $name = shift @names;
124        map { $name .= "[$_]" } @names;
125
126     # TODO - Mario Minati 19.05.2009
127     # Does this (name formatted as '[name]') collide with FF::Model::HashRef as
128     # it uses /_\d/ to parse repeatable names?
129        return $name;
130    }
131    else {
132        return join ".", @names;
133    }
134}
135
136sub nested_names {
137    my ($self) = @_;
138
139    croak 'cannot set nested_names' if @_ > 1;
140
141    if ( defined( my $name = $self->name ) ) {
142        my @names;
143        my $parent = $self;
144
145        # micro optimization! this method's called a lot, so access
146        # parent hashkey directly, instead of calling parent()
147        while ( defined( $parent = $parent->{parent} ) ) {
148
149            if ( $parent->can('is_field') && $parent->is_field ) {
150
151                # handling Field
152                push @names, $parent->name
153                    if defined $parent->name;
154            }
155            elsif ( $parent->can('is_repeatable') && $parent->is_repeatable ) {
156
157                # handling Repeatable
158                # ignore Repeatables nested_name attribute as it is provided
159                # by the childrens Block elements
160            }
161            else {
162
163                # handling 'not Field' and 'not Repeatable'
164                push @names, $parent->nested_name
165                    if defined $parent->nested_name;
166            }
167        }
168
169        if (@names) {
170            return reverse $name, @names;
171        }
172    }
173
174    return ( $self->name );
175}
176
177sub build_original_nested_name {
178    my ($self) = @_;
179
180    croak 'cannot set build_original_nested_name' if @_ > 1;
181
182    return if !defined $self->name;
183
184    my @names = $self->build_original_nested_names;
185
186    if ( $self->form->nested_subscript ) {
187        my $name = shift @names;
188        map { $name .= "[$_]" } @names;
189
190     # TODO - Mario Minati 19.05.2009
191     # Does this (name formatted as '[name]') collide with FF::Model::HashRef as
192     # it uses /_\d/ to parse repeatable names?
193        return $name;
194    }
195    else {
196        return join ".", @names;
197    }
198}
199
200sub build_original_nested_names {
201    my ($self) = @_;
202
203    croak 'cannot set build_original_nested_names' if @_ > 1;
204
205    # TODO - Mario Minati 19.05.2009
206    # Maybe we have to use original_name instead of name.
207    # Yet there is no testcase, which is currently failing.
208
209    if ( defined( my $name = $self->name ) ) {
210        my @names;
211        my $parent = $self;
212
213        # micro optimization! this method's called a lot, so access
214        # parent hashkey directly, instead of calling parent()
215        while ( defined( $parent = $parent->{parent} ) ) {
216
217            if ( $parent->can('is_field') && $parent->is_field ) {
218
219                # handling Field
220                if ( defined $parent->original_name ) {
221                    push @names, $parent->original_name;
222                }
223                elsif ( defined $parent->name ) {
224                    push @names, $parent->name;
225                }
226            }
227            elsif ( $parent->can('is_repeatable') && $parent->is_repeatable ) {
228
229     # handling Repeatable
230     # TODO - Mario Minati 19.05.2009
231     # Do we have to take care of chains of Repeatable elements, if the Block
232     # elements have already been created for the outer Repeatable elements to
233     # avoid 'outer.outer_1.inner'
234     # Yet there is no failing testcase. All testcases in FF and FF::Model::DBIC
235     # which have nested repeatable elements are passing currently.
236                push @names, $parent->original_nested_name
237                    if defined $parent->original_nested_name;
238            }
239            else {
240
241                # handling 'not Field' and 'not Repeatable'
242                if ( $parent->can('original_nested_name')
243                    && defined $parent->original_nested_name )
244                {
245                    push @names, $parent->original_nested_name;
246                }
247                elsif ( defined $parent->nested_name ) {
248                    push @names, $parent->nested_name;
249                }
250            }
251        }
252
253        if (@names) {
254            return reverse $name, @names;
255        }
256    }
257
258    return ( $self->name );
259}
260
261sub nested_base {
262    my ($self) = @_;
263
264    croak 'cannot set nested_base' if @_ > 1;
265
266    my $parent = $self;
267
268    while ( defined( $parent = $parent->parent ) ) {
269
270        return $parent->nested_name if defined $parent->nested_name;
271    }
272}
273
274sub get_deflators {
275    my $self = shift;
276    my %args = _parse_args(@_);
277
278    my @x = @{ $self->_deflators };
279
280    return _filter_components( \%args, \@x );
281}
282
283sub get_filters {
284    my $self = shift;
285    my %args = _parse_args(@_);
286
287    my @x = @{ $self->_filters };
288
289    return _filter_components( \%args, \@x );
290}
291
292sub get_constraints {
293    my $self = shift;
294    my %args = _parse_args(@_);
295
296    my @x = @{ $self->_constraints };
297
298    return _filter_components( \%args, \@x );
299}
300
301sub get_inflators {
302    my $self = shift;
303    my %args = _parse_args(@_);
304
305    my @x = @{ $self->_inflators };
306
307    return _filter_components( \%args, \@x );
308}
309
310sub get_validators {
311    my $self = shift;
312    my %args = _parse_args(@_);
313
314    my @x = @{ $self->_validators };
315
316    return _filter_components( \%args, \@x );
317}
318
319sub get_transformers {
320    my $self = shift;
321    my %args = _parse_args(@_);
322
323    my @x = @{ $self->_transformers };
324
325    return _filter_components( \%args, \@x );
326}
327
328sub get_errors {
329    my $self = shift;
330    my %args = _parse_args(@_);
331
332    my @x = @{ $self->_errors };
333
334    _filter_components( \%args, \@x );
335
336    if ( !$args{forced} ) {
337        @x = grep { !$_->forced } @x;
338    }
339
340    return \@x;
341}
342
343sub clear_errors {
344    my ($self) = @_;
345
346    $self->_errors( [] );
347
348    return;
349}
350
351after pre_process => sub {
352    my $self = shift;
353
354    for my $plugin ( @{ $self->_plugins } ) {
355        $plugin->pre_process;
356    }
357
358    return;
359};
360
361after process => sub {
362    my $self = shift;
363
364    for my $plugin ( @{ $self->_plugins } ) {
365        $plugin->process;
366    }
367
368    return;
369};
370
371after post_process => sub {
372    my $self = shift;
373
374    for my $plugin ( @{ $self->_plugins } ) {
375        $plugin->post_process;
376    }
377
378    return;
379};
380
381sub process_input {
382    my ( $self, $input ) = @_;
383
384    my $submitted = $self->form->submitted;
385    my $default   = $self->default;
386    my $original  = $self->value;
387    my $name      = $self->nested_name;
388
389    # set input to default value (defined before calling FormFu->process)
390    if ( $submitted && $self->force_default && defined $default ) {
391        $self->set_nested_hash_value( $input, $name, $default );
392    }
393
394    # checkbox, radio
395    elsif ($submitted
396        && $self->force_default
397        && $self->can('checked')
398        && $self->checked )
399    {
400
401        # the checked attribute is set, so force input to be the original value
402        $self->set_nested_hash_value( $input, $name, $original );
403    }
404
405    # checkbox, radio
406    elsif ($submitted
407        && $self->force_default
408        && !defined $default
409        && defined $original )
410    {
411
412    # default and value are not equal, so this element is not checked by default
413        $self->set_nested_hash_value( $input, $name, undef );
414    }
415
416    return;
417}
418
419sub prepare_id {
420    my ( $self, $render ) = @_;
421
422    if (  !defined $render->{attributes}{id}
423        && defined $self->auto_id
424        && length $self->auto_id )
425    {
426        my $form_name
427            = defined $self->form->id
428            ? $self->form->id
429            : $EMPTY_STR;
430
431        my $field_name
432            = defined $render->{nested_name}
433            ? $render->{nested_name}
434            : $EMPTY_STR;
435
436        my %string = (
437            f => $form_name,
438            n => $field_name,
439        );
440
441        my $id = $self->auto_id;
442        $id =~ s/%([fn])/$string{$1}/g;
443
444        if ( defined( my $count = $self->repeatable_count ) ) {
445            $id =~ s/%r/$count/g;
446        }
447
448        $render->{attributes}{id} = $id;
449    }
450
451    return;
452}
453
454sub process_value {
455    my ( $self, $value ) = @_;
456
457    my $submitted = $self->form->submitted;
458    my $default   = $self->default;
459
460    my $new;
461
462    if ($submitted) {
463        if ( defined $value ) {
464            $new = $value;
465        }
466        elsif ( defined $default ) {
467            $new = $EMPTY_STR;
468        }
469    }
470    else {
471        $new = $default;
472    }
473
474    if (   $submitted
475        && $self->retain_default
476        && defined $new
477        && $new eq $EMPTY_STR )
478    {
479        $new = $default;
480    }
481
482    # if the default value has been changed after FormFu->process has been
483    # called we use it and set the value to that changed default again
484    if (   $submitted
485        && $self->force_default
486        && defined $default
487        && $new ne $default )
488    {
489        $new = $default;
490    }
491
492    return $new;
493}
494
495around render_data_non_recursive => sub {
496    my ( $orig, $self, $args ) = @_;
497
498    my $render = $self->$orig(
499        {   nested_name                => xml_escape( $self->nested_name ),
500            comment_attributes         => xml_escape( $self->comment_attributes ),
501            container_attributes       => xml_escape( $self->container_attributes ),
502            error_container_attributes => xml_escape( $self->error_container_attributes ),
503            label_attributes           => xml_escape( $self->label_attributes ),
504            comment                    => xml_escape( $self->comment ),
505            label                      => xml_escape( $self->label ),
506            field_filename             => $self->field_filename,
507            label_filename             => $self->label_filename,
508            label_tag                  => $self->label_tag,
509            container_tag              => $self->container_tag,
510            error_container_tag        => $self->error_container_tag,
511            error_tag                  => $self->error_tag,
512            reverse_single             => $self->reverse_single,
513            reverse_multi              => $self->reverse_multi,
514            javascript                 => $self->javascript,
515            $args ? %$args : (),
516        } );
517
518    $self->_render_container_class($render);
519    $self->_render_comment_class($render);
520    $self->_render_label($render);
521    $self->_render_value($render);
522    $self->_render_constraint_class($render);
523    $self->_render_inflator_class($render);
524    $self->_render_validator_class($render);
525    $self->_render_transformer_class($render);
526    $self->_render_error_class($render);
527
528    return $render;
529};
530
531sub _render_label {
532    my ( $self, $render ) = @_;
533
534    if (  !defined $render->{label}
535        && defined $self->auto_label
536        && length $self->auto_label )
537    {
538        my %string = (
539            f => defined $self->form->id ? $self->form->id : '',
540            n => defined $render->{name} ? $render->{name} : '',
541        );
542
543        my $label = $self->auto_label;
544        $label =~ s/%([fn])/$string{$1}/g;
545
546        $render->{label} = $self->form->localize($label);
547    }
548
549    if (   defined $render->{label}
550        && defined $self->auto_label_class
551        && length $self->auto_label_class )
552    {
553        my $form_name
554            = defined $self->form->id
555            ? $self->form->id
556            : $EMPTY_STR;
557
558        my $field_name
559            = defined $render->{nested_name}
560            ? $render->{nested_name}
561            : $EMPTY_STR;
562
563        my $type = lc $self->type;
564        $type =~ s/:://g;
565
566        my %string = (
567            f => $form_name,
568            n => $field_name,
569            t => $type,
570        );
571
572        my $class = $self->auto_label_class;
573        $class =~ s/%([fnt])/$string{$1}/g;
574
575        append_xml_attribute( $render->{label_attributes}, 'class', $class );
576    }
577
578    if (   defined $render->{label}
579        && defined $self->auto_container_label_class
580        && length $self->auto_container_label_class )
581    {
582        my $form_name
583            = defined $self->form->id
584            ? $self->form->id
585            : $EMPTY_STR;
586
587        my $field_name
588            = defined $render->{nested_name}
589            ? $render->{nested_name}
590            : $EMPTY_STR;
591
592        my $type = lc $self->type;
593        $type =~ s/:://g;
594
595        my %string = (
596            f => $form_name,
597            n => $field_name,
598            t => $type,
599        );
600
601        my $class = $self->auto_container_label_class;
602        $class =~ s/%([fnt])/$string{$1}/g;
603
604        append_xml_attribute( $render->{container_attributes},
605            'class', $class );
606    }
607
608    # label "for" attribute
609    if (   defined $render->{label}
610        && defined $render->{attributes}{id}
611        && !exists $render->{label_attributes}{for} )
612    {
613        $render->{label_attributes}{for} = $render->{attributes}{id};
614    }
615
616    return;
617}
618
619sub _render_comment_class {
620    my ( $self, $render ) = @_;
621
622    if (   defined $render->{comment}
623        && defined $self->auto_comment_class
624        && length $self->auto_comment_class )
625    {
626        my $form_name
627            = defined $self->form->id
628            ? $self->form->id
629            : $EMPTY_STR;
630
631        my $field_name
632            = defined $render->{nested_name}
633            ? $render->{nested_name}
634            : $EMPTY_STR;
635
636        my %string = (
637            f => $form_name,
638            n => $field_name,
639        );
640
641        my $class = $self->auto_comment_class;
642        $class =~ s/%([fn])/$string{$1}/g;
643
644        append_xml_attribute( $render->{comment_attributes}, 'class', $class );
645    }
646
647    if (   defined $render->{comment}
648        && defined $self->auto_container_comment_class
649        && length $self->auto_container_comment_class )
650    {
651        my $form_name
652            = defined $self->form->id
653            ? $self->form->id
654            : $EMPTY_STR;
655
656        my $field_name
657            = defined $render->{nested_name}
658            ? $render->{nested_name}
659            : $EMPTY_STR;
660
661        my %string = (
662            f => $form_name,
663            n => $field_name,
664        );
665
666        my $class = $self->auto_container_comment_class;
667        $class =~ s/%([fn])/$string{$1}/g;
668
669        append_xml_attribute( $render->{container_attributes},
670            'class', $class );
671    }
672
673    return;
674}
675
676sub _render_value {
677    my ( $self, $render ) = @_;
678
679    my $form = $self->form;
680    my $name = $self->nested_name;
681
682    my $input;
683
684    if (   $self->form->submitted
685        && defined $name
686        && $self->nested_hash_key_exists( $form->input, $name ) )
687    {
688        if ( $self->render_processed_value ) {
689            $input
690                = $self->get_nested_hash_value( $form->_processed_params,
691                $name, );
692        }
693        else {
694            $input = $self->get_nested_hash_value( $form->input, $name, );
695        }
696    }
697
698    if ( ref $input eq 'ARRAY' ) {
699        my $elems = $self->form->get_fields( $self->name );
700        for ( 0 .. @$elems - 1 ) {
701            if ( $self == $elems->[$_] ) {
702                $input = $input->[$_];
703            }
704        }
705    }
706
707    my $value = $self->process_value($input);
708
709    if ( !$self->form->submitted
710        || ( $self->render_processed_value && defined $value ) )
711    {
712        for my $deflator ( @{ $self->_deflators } ) {
713            $value = $deflator->process($value);
714        }
715    }
716
717    # handle multiple values for the same name
718    if ( ref $value eq 'ARRAY' && defined $self->name ) {
719        my $max = $#$value;
720        my $fields = $self->form->get_fields( name => $self->name );
721
722        for my $i ( 0 .. $max ) {
723            if ( defined $fields->[$i] && $fields->[$i] eq $self ) {
724                $value = $value->[$i];
725                last;
726            }
727        }
728    }
729
730    $render->{value} = xml_escape($value);
731
732    return;
733}
734
735sub _render_container_class {
736    my ( $self, $render ) = @_;
737
738    if ( defined $self->auto_container_class
739        && length $self->auto_container_class )
740    {
741        my $form_name
742            = defined $self->form->id
743            ? $self->form->id
744            : $EMPTY_STR;
745
746        my $field_name
747            = defined $render->{nested_name}
748            ? $render->{nested_name}
749            : $EMPTY_STR;
750
751        my $type = lc $self->type;
752        $type =~ s/:://g;
753
754        my %string = (
755            f => $form_name,
756            n => $field_name,
757            t => $type,
758        );
759
760        my $class = $self->auto_container_class;
761        $class =~ s/%([fnt])/$string{$1}/g;
762
763        append_xml_attribute( $render->{container_attributes},
764            'class', $class );
765    }
766
767    return;
768}
769
770sub _render_constraint_class {
771    my ( $self, $render ) = @_;
772
773    my $auto_class = $self->auto_constraint_class;
774
775    return if !defined $auto_class;
776
777    for my $c ( @{ $self->_constraints } ) {
778        my %string = (
779            f => defined $self->form->id ? $self->form->id : '',
780            n => defined $render->{name} ? $render->{name} : '',
781            t => defined $c->type        ? lc( $c->type )  : '',
782        );
783
784        $string{t} =~ s/::/_/g;
785        $string{t} =~ s/\+//;
786
787        my $class = $auto_class;
788
789        $class =~ s/%([fnt])/$string{$1}/g;
790
791        append_xml_attribute( $render->{container_attributes},
792            'class', $class, );
793    }
794
795    return;
796}
797
798sub _render_inflator_class {
799    my ( $self, $render ) = @_;
800
801    my $auto_class = $self->auto_inflator_class;
802
803    return if !defined $auto_class;
804
805    for my $c ( @{ $self->_inflators } ) {
806        my %string = (
807            f => defined $self->form->id ? $self->form->id : '',
808            n => defined $render->{name} ? $render->{name} : '',
809            t => defined $c->type        ? lc( $c->type )  : '',
810        );
811
812        $string{t} =~ s/::/_/g;
813        $string{t} =~ s/\+//;
814
815        my $class = $auto_class;
816
817        $class =~ s/%([fnt])/$string{$1}/g;
818
819        append_xml_attribute( $render->{container_attributes},
820            'class', $class, );
821    }
822
823    return;
824}
825
826sub _render_validator_class {
827    my ( $self, $render ) = @_;
828
829    my $auto_class = $self->auto_validator_class;
830
831    return if !defined $auto_class;
832
833    for my $c ( @{ $self->_validators } ) {
834        my %string = (
835            f => defined $self->form->id ? $self->form->id : '',
836            n => defined $render->{name} ? $render->{name} : '',
837            t => defined $c->type        ? lc( $c->type )  : '',
838        );
839
840        $string{t} =~ s/::/_/g;
841        $string{t} =~ s/\+//;
842
843        my $class = $auto_class;
844
845        $class =~ s/%([fnt])/$string{$1}/g;
846
847        append_xml_attribute( $render->{container_attributes},
848            'class', $class, );
849    }
850
851    return;
852}
853
854sub _render_transformer_class {
855    my ( $self, $render ) = @_;
856
857    my $auto_class = $self->auto_transformer_class;
858
859    return if !defined $auto_class;
860
861    for my $c ( @{ $self->_transformers } ) {
862        my %string = (
863            f => defined $self->form->id ? $self->form->id : '',
864            n => defined $render->{name} ? $render->{name} : '',
865            t => defined $c->type        ? lc( $c->type )  : '',
866        );
867
868        $string{t} =~ s/::/_/g;
869        $string{t} =~ s/\+//;
870
871        my $class = $auto_class;
872
873        $class =~ s/%([fnt])/$string{$1}/g;
874
875        append_xml_attribute( $render->{container_attributes},
876            'class', $class, );
877    }
878
879    return;
880}
881
882sub _render_error_class {
883    my ( $self, $render ) = @_;
884
885    my @errors = @{ $self->get_errors( { forced => 1 } ) };
886
887    return if !@errors;
888
889    @errors = map { $_->render_data } @errors;
890
891    $render->{errors} = \@errors;
892
893    # auto_error_field_class
894    my $field_class = $self->auto_error_field_class;
895
896    if ( defined $field_class && length $field_class ) {
897        my %string = (
898            f => sub { defined $self->form->id ? $self->form->id : '' },
899            n => sub { defined $render->{name} ? $render->{name} : '' },
900        );
901
902        $field_class =~ s/%([fn])/$string{$1}->()/ge;
903
904        append_xml_attribute( $render->{attributes}, 'class', $field_class );
905    }
906
907    my @container_class;
908
909    # auto_container_error_class
910    my $auto_class = $self->auto_container_error_class;
911
912    if ( defined $auto_class && length $auto_class ) {
913        my %string = (
914            f => sub { defined $self->form->id ? $self->form->id : '' },
915            n => sub { defined $render->{name} ? $render->{name} : '' },
916        );
917
918        $auto_class =~ s/%([fn])/$string{$1}->()/ge;
919
920        push @container_class, $auto_class;
921    }
922
923    # auto_container_per_error_class
924    my $item_class = $self->auto_container_per_error_class;
925
926    if ( defined $item_class && length $item_class ) {
927        for my $error (@errors) {
928            my %string = (
929                f => sub { defined $self->form->id ? $self->form->id : '' },
930                n => sub { defined $render->{name} ? $render->{name} : '' },
931                s => sub { $error->{stage} },
932                t => sub { lc $error->{type} },
933            );
934
935            my $string = $item_class;
936            $string =~ s/%([fnst])/$string{$1}->()/ge;
937
938            push @container_class, $string;
939        }
940    }
941
942    map { append_xml_attribute( $render->{container_attributes}, 'class', $_ ) }
943        uniq @container_class;
944
945    my @error_container_class;
946
947    if ( $self->error_container_tag ) {
948
949        # auto_error_container_class
950        my $auto_class = $self->auto_error_container_class;
951
952        if ( defined $auto_class && length $auto_class ) {
953            my %string = (
954                f => sub { defined $self->form->id ? $self->form->id : '' },
955                n => sub { defined $render->{name} ? $render->{name} : '' },
956            );
957
958            $auto_class =~ s/%([fn])/$string{$1}->()/ge;
959
960            push @error_container_class, $auto_class;
961        }
962
963        # auto_container_per_error_class
964        my $item_class = $self->auto_container_per_error_class;
965
966        if ( defined $item_class && length $item_class ) {
967            for my $error (@errors) {
968                my %string = (
969                    f => sub { defined $self->form->id ? $self->form->id : '' },
970                    n => sub { defined $render->{name} ? $render->{name} : '' },
971                    s => sub { $error->{stage} },
972                    t => sub { lc $error->{type} },
973                );
974
975                my $string = $item_class;
976                $string =~ s/%([fnst])/$string{$1}->()/ge;
977
978                push @error_container_class, $string;
979            }
980        }
981
982        map {
983            append_xml_attribute( $render->{error_container_attributes},
984                'class', $_ )
985        } uniq @error_container_class;
986    }
987
988    return;
989}
990
991sub render_label {
992    my ($self) = @_;
993
994    my $render = $self->render_data;
995
996    return $self->_string_label($render);
997}
998
999sub render_field {
1000    my ($self) = @_;
1001
1002    my $render = $self->render_data;
1003
1004    return $self->_string_field($render);
1005}
1006
1007sub _string_field_start {
1008    my ( $self, $render ) = @_;
1009
1010    # field wrapper template - start
1011
1012    my $html = '';
1013
1014    if ( defined $render->{container_tag} ) {
1015        $html .= sprintf '<%s%s>',
1016            $render->{container_tag},
1017            process_attrs( $render->{container_attributes} );
1018    }
1019
1020    if ( defined $render->{label} && $render->{label_tag} eq 'legend' ) {
1021        $html .= sprintf "\n%s", $self->_string_label($render);
1022    }
1023
1024    $html .= $self->_string_errors($render);
1025
1026    if (   defined $render->{label}
1027        && $render->{label_tag} ne 'legend'
1028        && !$render->{reverse_single} )
1029    {
1030        $html .= sprintf "\n%s", $self->_string_label($render);
1031    }
1032
1033    if ( defined $render->{container_tag} ) {
1034        $html .= "\n";
1035    }
1036
1037    return $html;
1038}
1039
1040sub _string_label {
1041    my ( $self, $render ) = @_;
1042
1043    # label template
1044
1045    my $html = sprintf "<%s%s>%s</%s>",
1046        $render->{label_tag},
1047        process_attrs( $render->{label_attributes} ),
1048        $render->{label},
1049        $render->{label_tag},
1050        ;
1051
1052    return $html;
1053}
1054
1055sub _string_errors {
1056    my ( $self, $render ) = @_;
1057
1058    return '' if !$render->{errors};
1059
1060    my $html = '';
1061
1062    if ( $render->{error_container_tag} ) {
1063        $html .= sprintf qq{<%s%s>\n},
1064            $render->{error_container_tag},
1065            process_attrs( $render->{error_container_attributes} ),
1066            ;
1067    }
1068
1069    my @error_html;
1070    for my $error ( @{ $render->{errors} } ) {
1071        push @error_html, sprintf qq{<%s%s>%s</%s>},
1072            $render->{error_tag},
1073            process_attrs( $error->{attributes} ),
1074            $error->{message},
1075            $render->{error_tag},
1076            ;
1077    }
1078    $html .= join "\n", @error_html;
1079
1080    if ( $render->{error_container_tag} ) {
1081        $html .= sprintf qq{\n</%s>}, $render->{error_container_tag};
1082    }
1083
1084    return $html;
1085}
1086
1087sub _string_field_end {
1088    my ( $self, $render ) = @_;
1089
1090    # field wrapper template - end
1091
1092    my $html = '';
1093
1094    if (   defined $render->{label}
1095        && $render->{label_tag} ne 'legend'
1096        && $render->{reverse_single} )
1097    {
1098        $html .= sprintf "\n%s", $self->_string_label($render);
1099    }
1100
1101    if ( defined $render->{comment} ) {
1102        $html .= sprintf "\n<span%s>\n%s\n</span>",
1103            process_attrs( $render->{comment_attributes} ),
1104            $render->{comment},
1105            ;
1106    }
1107
1108    if ( defined $render->{container_tag} ) {
1109        $html .= sprintf "\n</%s>", $render->{container_tag},;
1110    }
1111
1112    if ( defined $render->{javascript} ) {
1113        $html .= sprintf qq{\n<script type="text/javascript">\n%s\n</script>},
1114            $render->{javascript},
1115            ;
1116    }
1117
1118    return $html;
1119}
1120
1121around clone => sub {
1122    my $orig = shift;
1123    my $self = shift;
1124
1125    my $clone = $self->$orig(@_);
1126
1127    for my $list ( qw(
1128        _filters _constraints _inflators _validators _transformers
1129        _deflators _errors _plugins )
1130        )
1131    {
1132        $clone->$list( [ map { $_->clone } @{ $self->$list } ] );
1133
1134        map { $_->parent($clone) } @{ $clone->$list };
1135    }
1136
1137    $clone->comment_attributes( Clone::clone( $self->comment_attributes ) );
1138    $clone->container_attributes( Clone::clone( $self->container_attributes ) );
1139    $clone->label_attributes( Clone::clone( $self->label_attributes ) );
1140
1141    return $clone;
1142};
1143
11441;
1145
1146__END__
1147
1148=pod
1149
1150=encoding UTF-8
1151
1152=head1 NAME
1153
1154HTML::FormFu::Role::Element::Field - Role for all form-field elements
1155
1156=head1 VERSION
1157
1158version 2.07
1159
1160=head1 DESCRIPTION
1161
1162Base-class for all form-field elements.
1163
1164=head1 METHODS
1165
1166=head2 default
1167
1168Set the form-field's default value.
1169
1170Is an L<output accessor|HTML::FormFu/OUTPUT ACCESSORS>.
1171
1172=head2 value
1173
1174For most fields, L</value> is an alias for L</default>.
1175
1176For the L<HTML::FormFu::Element::Checkbox> and
1177L<HTML::FormFu::Element::Radio> elements, L</value> sets what the value of
1178the field will be if it is checked or selected. If the L</default> is the
1179same as the L</value>, then the field will be checked or selected when
1180rendered.
1181
1182For the L<HTML::FormFu::Element::Radiogroup> and
1183L<HTML::FormFu::Element::Select> elements, the L</value> is ignored:
1184L<values|HTML::FormFu::Role::Element::Group/values> or
1185L<options|HTML::FormFu::Role::Element::Group/options> provides the equivalent
1186function.
1187
1188Is an L<output accessor|HTML::FormFu/OUTPUT ACCESSORS>.
1189
1190=head2 non_param
1191
1192Arguments: bool
1193
1194Default Value: false
1195
1196If true, values for this field are never returned by L<HTML::FormFu/params>,
1197L<HTML::FormFu/param> and L<HTML::FormFu/valid>.
1198
1199This is useful for Submit buttons, when you only use its value as an
1200L<indicator|HTML::FormFu/indicator>
1201
1202=head2 placeholder
1203
1204Sets the HTML5 attribute C<placeholder> to the specified value.
1205
1206Is an L<output accessor|HTML::FormFu/OUTPUT ACCESSORS>.
1207
1208=head2 javascript
1209
1210Arguments: [$javascript]
1211
1212If set, the contents will be rendered within a C<script> tag, within the
1213field's container.
1214
1215=head2 retain_default
1216
1217If L</retain_default> is true and the form was submitted, but the field
1218didn't have a value submitted, then when the form is redisplayed to the user
1219the field will have its value set to its default value, rather than the
1220usual behaviour of having an empty value.
1221
1222Default Value: C<false>
1223
1224=head2 force_default
1225
1226If L</force_default> is true and the form was submitted, and the field
1227has a default/value set, then when the form is redisplayed to the user
1228the field will have its value set to its default value.
1229
1230If the default value is being changed after FormFu->process is being called
1231the later default value is respected for rendering, *but* nevertheless the
1232input value doesn't respect that, it will remain the first value.
1233
1234Default Value: C<false>
1235
1236=head2 default_empty_value
1237
1238Designed for use by Checkbox fields. Normally if a checkbox is not checked,
1239no value is submitted for that field. If C<default_empty_value> is true,
1240the Checkbox field is given an empty value during
1241L<process|HTML::FormFu/process>. Please note that, with this setting,
1242the checkbox gets an EMPTY value (as opposed to no value at all without
1243enabling it), NOT the default value assigned to the element (if any).
1244
1245Default Value: C<false>
1246
1247=head2 repeatable_count
1248
1249Only available for fields attached to a
1250L<Repeatable|HTML::FormFu::Element::Repeatable> element, after
1251L<< $repeatable->repeat($count) | HTML::FormFu::Element::Repeatable/repeat >>
1252has been called.
1253
1254The value is inherited from
1255L<HTML::FormFu::Element::Repeatable/repeatable_count>.
1256
1257=head2 clone
1258
1259See L<HTML::FormFu/clone> for details.
1260
1261=head2 deflators
1262
1263See L<HTML::FormFu/deflators> for details.
1264
1265=head2 deflator
1266
1267See L<HTML::FormFu/deflator> for details.
1268
1269=head2 auto_datalist_id
1270
1271Arguments: [$string]
1272
1273If any L<Input|HTML::FormFu::Role::Element::Input> element had a datalist,
1274but does not have L<HTML::FormFu::Role::Element::Input/datalist_id> set,
1275L</auto_datalist_id> is used to generate the datalist id.
1276
1277The following character substitution will be performed: C<%f> will be
1278replaced by L<< $form->id|/id >>, C<%n> will be replaced by
1279L<< $field->name|HTML::FormFu::Element/name >>, C<%r> will be replaced by
1280L<< $block->repeatable_count|HTML::FormFu::Element::Repeatable/repeatable_count >>.
1281
1282Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1283
1284=head1 FORM LOGIC AND VALIDATION
1285
1286=head2 filters
1287
1288See L<HTML::FormFu/filters> for details.
1289
1290=head2 filter
1291
1292See L<HTML::FormFu/filter> for details.
1293
1294=head2 constraints
1295
1296See L<HTML::FormFu/constraints> for details.
1297
1298=head2 constraint
1299
1300See L<HTML::FormFu/constraint> for details.
1301
1302=head2 inflators
1303
1304See L<HTML::FormFu/inflators> for details.
1305
1306=head2 inflator
1307
1308See L<HTML::FormFu/inflator> for details.
1309
1310=head2 validators
1311
1312See L<HTML::FormFu/validators> for details.
1313
1314=head2 validator
1315
1316See L<HTML::FormFu/validator> for details.
1317
1318=head2 transformers
1319
1320See L<HTML::FormFu/transformers> for details.
1321
1322=head2 transformer
1323
1324See L<HTML::FormFu/transformer> for details.
1325
1326=head1 CUSTOMIZING GENERATED MARKUP
1327
1328Each field is, by default, wrapped in a container.
1329Each container may also contain a label, a comment, and after an invalid
1330submission may contain 1 or more error messages.
1331
1332Example of generated form:
1333
1334    1   <form action="" method="post">
1335    2       <div class="has-errors">    # container
1336    3           <ul class="errors">     # error container
1337    4               <li>                # error message
1338    5                   This field must contain an email address
1339    6               </li>
1340    7           </li>
1341    8           <label>Foo</label>      # label
1342    9           <input name="foo" type="text" value="example.com" />
1343    10          <span class="comment">  # comment
1344    11              This is Foo
1345    12          </span>
1346    13      </div>
1347    14  </form>
1348
1349    # Line 2 starts the 'container' - by default a DIV.
1350    # Line 2 starts an error container, which may contain 1 or more error
1351             messages - in this case, a unordered list (UL).
1352    # Line 4 starts a single error message - in this case, a list item (LI).
1353    # Line 8 shows a 'label'.
1354    # Line 9 shows the field's 'input' tag.
1355    # Lines 10 starts a 'comment'.
1356
1357To re-order the various parts of each form (label, input, errors, etc) and
1358arbitrary extra tags, see the L<layout|/layout> method.
1359
1360=head2 CONTAINER
1361
1362=head3 container_tag
1363
1364Default value: 'div'
1365
1366The container wrapping each entire field, any label, comment, and errors.
1367
1368=head3 container_attributes
1369
1370Attributes added to the container tag.
1371
1372Is an L<attribute accessor|HTML::FormFu/ATTRIBUTE ACCESSOR>.
1373
1374=head3 auto_container_class
1375
1376Default Value: '%t'
1377
1378If set, then the container of each field will be given a class-name based on
1379the given pattern.
1380
1381Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>, C<%t>.
1382
1383Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1384
1385=head3 auto_container_label_class
1386
1387Default Value: 'label'
1388
1389If set, and if the field has a L<label|/label>, the container will be given a
1390class-name based on the given pattern.
1391
1392Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>, C<%t>.
1393
1394Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1395
1396=head3 auto_container_comment_class
1397
1398Default Value: '%t'
1399
1400If set, and if the field has a
1401L<comment|HTML::FormFu::Role::Element::Field/comment>, the container will be
1402given a class-name based on the given pattern.
1403
1404Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>, C<%t>.
1405
1406Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1407
1408=head3 auto_container_error_class
1409
1410Default Value: 'error'
1411
1412If set, then the container of each field with an error will be given a
1413class-name based on the given pattern.
1414
1415Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>.
1416
1417Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1418
1419=head3 auto_container_per_error_class
1420
1421Default Value: 'error_%s_%t'
1422
1423If set, then the container of each field with an error will be given a
1424class-name based on the given pattern.
1425
1426Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>, C<%t>, C<%s>.
1427
1428Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1429
1430=head2 FORM FIELD
1431
1432=head3 auto_id
1433
1434If set, then the field will be given an L<id|HTML::FormFu::Element/id>
1435attribute, if it doesn't have one already.
1436
1437E.g., setting C<< $form->auto_id('%n') >> will make each field have an ID
1438the same as the field's name. This makes our form config simpler, and ensures
1439we don't need to manually update IDs if any field names are changed.
1440
1441Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>, C<%r>.
1442
1443Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1444
1445=head2 LABEL
1446
1447=head3 label
1448
1449Set a label to communicate the purpose of the form-field to the user.
1450
1451Is an L<output accessor|HTML::FormFu/OUTPUT ACCESSORS>.
1452
1453=head3 auto_label
1454
1455If L<label|/label> isn't already set, the value of L</auto_label> is passed through
1456L<localize|HTML::FormFu/localize> to generate a label.
1457
1458Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>.
1459
1460The generated string will be passed to L</localize> to create the label.
1461
1462Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1463
1464=head3 label_tag
1465
1466Default value: 'label'
1467(except L<Checkboxgroup|HTML::FormFu::Element::Checkboxgroup>)
1468
1469Default value: 'legend'
1470(only L<Checkboxgroup|HTML::FormFu::Element::Checkboxgroup>)
1471
1472Set which tag is used to wrap a L<label|/label>.
1473
1474Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1475
1476=head3 label_attributes
1477
1478Attributes added to the label container.
1479
1480Is an L<attribute accessor|HTML::FormFu/ATTRIBUTE ACCESSOR>.
1481
1482=head2 COMMENT
1483
1484=head3 comment
1485
1486Set a comment to be displayed along with the form-field.
1487
1488Is an L<output accessor|HTML::FormFu/OUTPUT ACCESSORS>.
1489
1490=head3 comment_attributes
1491
1492Attributes added to the comment container.
1493
1494Is an L<attribute accessor|HTML::FormFu/ATTRIBUTE ACCESSOR>.
1495
1496=head3 auto_comment_class
1497
1498Default Value: '%t'
1499
1500If set, and if the field has a
1501L<comment|HTML::FormFu::Role::Element::Field/comment>, the comment tag will
1502be given a class-name based on the given pattern.
1503
1504Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>, C<%t>.
1505
1506Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1507
1508=head2 ERROR CONTAINER
1509
1510=head3 error_container_tag
1511
1512If set, and if the field has any errors, a container of this type is
1513wrapped around all of the field error messages.
1514
1515    # Example - this would wrap each individual error in a 'li' tag,
1516    # with a single 'ul' tag wrapped around all the errors.
1517
1518    element:
1519      name: foo
1520      error_container_tag: ul
1521      error_tag: li
1522
1523Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1524
1525=head3 error_container_attributes
1526
1527Set attributes on the container-tag, if L</error_container_tag> is set.
1528
1529Is an L<attribute accessor|HTML::FormFu/ATTRIBUTE ACCESSOR>.
1530
1531=head3 auto_error_container_class
1532
1533Add a class-name to the error container.
1534
1535Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>.
1536
1537Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1538
1539=head3 auto_error_container_per_error_class
1540
1541Add a class-name to the error container for each error on that field.
1542
1543Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>, C<%t>, C<%s>.
1544
1545Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1546
1547=head2 ERROR MESSAGES
1548
1549=head3 error_tag
1550
1551Default value: 'span'
1552
1553Sets the tag used to wrap each individual error message.
1554
1555Defaults to C<span>.
1556
1557Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1558
1559=head3 auto_error_message
1560
1561Default Value: 'form_%s_%t'
1562
1563If set, then each error will be given an auto-generated
1564L<message|HTML::FormFu::Exception::Input/message>, if it doesn't have one
1565already.
1566
1567The generated string will be passed to L</localize> to create the message.
1568
1569For example, a L<Required constraint|HTML::FormFu::Constraint::Required>
1570will return the string C<form_constraint_required>. Under the default
1571localization behaviour, the appropriate message for
1572C<form_constraint_required> will be used from the default I18N package.
1573
1574Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>, C<%t>, C<%s>.
1575
1576Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1577
1578=head3 error_attributes
1579
1580Set attributes on the tag of each error message.
1581
1582Is an L<attribute accessor|HTML::FormFu/ATTRIBUTE ACCESSOR>.
1583
1584=head3 auto_error_field_class
1585
1586Upon error, add a class name firectly to the field tag (e.g. C<input>, C<select> tag).
1587
1588Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>.
1589
1590=head3 auto_error_class
1591
1592Default Value: 'error_%s_%t'
1593
1594Add a class-name to the tag of each error message.
1595
1596Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>, C<%t>, C<%s>.
1597
1598Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1599
1600=head2 PROCESSOR CLASSES
1601
1602=head3 auto_constraint_class
1603
1604Add a class-name to the container tag, for each constraint added to the field.
1605
1606Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>, C<%t>.
1607
1608Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1609
1610=head3 auto_inflator_class
1611
1612Add a class-name to the container tag, for each inflator added to the field.
1613
1614Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>, C<%t>.
1615
1616Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1617
1618=head3 auto_validator_class
1619
1620Add a class-name to the container tag, for each validator added to the field.
1621
1622Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>, C<%t>.
1623
1624Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1625
1626=head3 auto_transformer_class
1627
1628Add a class-name to the container tag, for each transformer added to the field.
1629
1630Supports L<substitutions|HTML::FormFu/ATTRIBUTE SUBSTITUTIONS>: C<%f>, C<%n>, C<%t>.
1631
1632Is an L<inheriting accessor|HTML::FormFu/INHERITING ACCESSORS>.
1633
1634=head2 REORDERING FIELD COMPONENTS
1635
1636=head2 layout
1637
1638Specify the order that each sub-part of the element should appear in the
1639rendered markup.
1640
1641    # Default Value
1642    $element->layout( [
1643        'errors',
1644        'label',
1645        'field',
1646        'comment',
1647        'javascript',
1648    ] );
1649
1650Example: Move the form field (the input tag or equivalent) inside the label
1651tag, after the label text.
1652Remove the comment - this will now never be rendered.
1653
1654    # YAML config
1655    layout:
1656      - errors
1657      - label:
1658          - label_text
1659          - field
1660      - javascript
1661
1662    # prettified example of rendered markup
1663    <div>
1664        <span>This field is required.</span>
1665        <label>
1666            Foo
1667            <input name="foo" type="text" />
1668        </label>
1669    </div>
1670
1671Example: Don't wrap the label text inside it's usual tag.
1672Insert the form field (the input tag or equivalent) inside an arbitrary
1673extra tag.
1674
1675    # YAML config
1676    layout:
1677      - errors
1678      - label_text
1679      -
1680        div:
1681          attributes:
1682            class: xxx
1683          content: field
1684      - comment
1685      - javascript
1686
1687    # prettified example of rendered markup
1688    <div>
1689        <span>This field is required.</span>
1690        Foo
1691        <div class="xxx">
1692            <input name="foo" type="text" />
1693        </div>
1694    </div>
1695
1696The following elements override the default L<layout> value:
1697
1698=over
1699
1700=item L<HTML::FormFu::Element::Checkboxgroup|HTML::FormFu::Element::Checkboxgroup>
1701
1702=item L<HTML::FormFu::Element::Hidden|HTML::FormFu::Element::Hidden>
1703
1704=back
1705
1706=head3 Specification
1707
1708The L<layout|/layout> method accepts an array-ref, hash-ref, or string
1709argument.
1710
1711The processing is recursive, so each item in an array-ref may be any value
1712accepted by the L<layout|/layout> method.
1713
1714A hash-ref must contain a single key and value pair.
1715If the hash key is the string C<label>, it creates a C<label> tag, using any
1716previously defined L<LABEL|/LABEL> customizations.
1717This allows the label tag to contains other elements, such as the form field.
1718
1719All other hash key values are asssumed to be an arbitrary block tag name.
1720The value must be a hash-ref, and may contain one or both C<attributes> or
1721C<content> keys.
1722
1723Any C<attributes> value must be a hash-ref, whose key/values are added to
1724the block tag. No processing or expansion is done to the C<attributes>
1725hash-ref at all.
1726
1727The C<content> value may be anything accepted by the L<layout|/layout>
1728method.
1729
1730The following strings are accepted:
1731
1732=over
1733
1734=item errors
1735
1736Renders the element error messages.
1737
1738See L<ERROR CONTAINER|/"ERROR CONTAINER"> and
1739L<ERROR MESSAGES|/"ERROR MESSAGES"> to customize the tags and attributes.
1740
1741=item label
1742
1743Renders the element L<label|/label>.
1744
1745See L<LABEL|/LABEL> to customize the tag and attributes.
1746
1747=item label_text
1748
1749Renders the element L<label|/label> text, without the usual
1750L<label_tag|/label_tag>.
1751
1752=item field
1753
1754Renders the form field control (an input tag, button, or other control).
1755
1756=item comment
1757
1758Renders the element L<comment|/comment>.
1759
1760See L<COMMENT|/COMMENT> to customize the tag and attributes.
1761
1762=item javascript
1763
1764Renders a C<script> tag containing any L<javascript|/javascript>.
1765
1766=back
1767
1768=head2 multi_layout
1769
1770Specify the order that each sub-part of each element within a
1771L<HTML::FormFu::Element::Multi|HTML::FormFu::Element::Multi> should
1772appear in the rendered markup.
1773
1774    # Default Value
1775    $element->multi_layout( [
1776        'label',
1777        'field',
1778    ] );
1779
1780Example: Swap the label/field order. This is equivalent to the
1781now-deprecated L<reverse_multi|/reverse_multi> method.
1782
1783    # YAML config
1784    multi_layout:
1785      - field
1786      - label
1787
1788The following elements override the default C<multi_layout> value:
1789
1790=over
1791
1792=item L<HTML::FormFu::Element::Checkbox|HTML::FormFu::Element::Checkbox>
1793
1794=back
1795
1796=head1 RENDERING
1797
1798=head2 field_filename
1799
1800The template filename to be used for just the form field - not including the
1801display of any container, label, errors, etc.
1802
1803Must be set by more specific field classes.
1804
1805=head2 label_filename
1806
1807The template filename to be used to render the label.
1808
1809Defaults to C<label>.
1810
1811=head1 ERROR HANDLING
1812
1813=head2 get_errors
1814
1815See L<HTML::FormFu/get_errors> for details.
1816
1817=head2 add_error
1818
1819=head2 clear_errors
1820
1821See L<HTML::FormFu/clear_errors> for details.
1822
1823=head1 INTROSPECTION
1824
1825=head2 get_deflators
1826
1827See L<HTML::FormFu/get_deflators> for details.
1828
1829=head2 get_deflator
1830
1831See L<HTML::FormFu/get_deflator> for details.
1832
1833=head2 get_filters
1834
1835See L<HTML::FormFu/get_filters> for details.
1836
1837=head2 get_filter
1838
1839See L<HTML::FormFu/get_filter> for details.
1840
1841=head2 get_constraints
1842
1843See L<HTML::FormFu/get_constraints> for details.
1844
1845=head2 get_constraint
1846
1847See L<HTML::FormFu/get_constraint> for details.
1848
1849=head2 get_inflators
1850
1851See L<HTML::FormFu/get_inflators> for details.
1852
1853=head2 get_inflator
1854
1855See L<HTML::FormFu/get_inflator> for details.
1856
1857=head2 get_validators
1858
1859See L<HTML::FormFu/get_validators> for details.
1860
1861=head2 get_validator
1862
1863See L<HTML::FormFu/get_validator> for details.
1864
1865=head2 get_transformers
1866
1867See L<HTML::FormFu/get_transformers> for details.
1868
1869=head2 get_transformer
1870
1871See L<HTML::FormFu/get_transformer> for details.
1872
1873=head2 get_errors
1874
1875See L<HTML::FormFu/get_errors> for details.
1876
1877=head2 clear_errors
1878
1879See L<HTML::FormFu/clear_errors> for details.
1880
1881=head1 DEPRECATED METHODS
1882
1883=over
1884
1885=item reverse_single
1886
1887See L<layout|/layout> instead.
1888
1889=item reverse_multi
1890
1891See L<multi_layout|/multi_layout> instead.
1892
1893=item errors_filename
1894
1895See L<layout_errors_filename|/layout_errors_filename> instead.
1896
1897=back
1898
1899=head1 SEE ALSO
1900
1901Base-class for L<HTML::FormFu::Role::Element::Group>,
1902L<HTML::FormFu::Role::Element::Input>,
1903L<HTML::FormFu::Element::Multi>,
1904L<HTML::FormFu::Element::ContentButton>,
1905L<HTML::FormFu::Element::Textarea>.
1906
1907Is a sub-class of, and inherits methods from L<HTML::FormFu::Element>
1908
1909L<HTML::FormFu>
1910
1911=head1 AUTHOR
1912
1913Carl Franks, C<cfranks@cpan.org>
1914
1915=head1 LICENSE
1916
1917This library is free software, you can redistribute it and/or modify it under
1918the same terms as Perl itself.
1919
1920=head1 AUTHOR
1921
1922Carl Franks <cpan@fireartist.com>
1923
1924=head1 COPYRIGHT AND LICENSE
1925
1926This software is copyright (c) 2018 by Carl Franks.
1927
1928This is free software; you can redistribute it and/or modify it under
1929the same terms as the Perl 5 programming language system itself.
1930
1931=cut
1932