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