=encoding utf8

=for comment POD_DERIVED_INDEX_GENERATED
The following documentation is automatically generated.  Please do not edit
this file, but rather the original, inline with HTML::FormBuilder::Validation
at lib/HTML/FormBuilder/Validation.pm
(on the system that originally ran this).
If you do edit this file, and don't want your changes to be removed, make
sure you change the first line.

=cut

=head1 NAME

HTML::FormBuilder::Validation - An extension of the Form object, to allow for javascript-side validation of inputs
and also server-side validation after the form is POSTed

=head1 SYNOPSIS

First, create the Form object. The keys in the HASH reference is the attributes
of the form.

    # Form attributes require to create new form object
    my $form_attributes =
    {
        'name'     => 'name_test_form',
        'id'       => 'id_test_form',
        'method'   => 'post',
        'action'   => "http://www.domain.com/contact.cgi",
        'class'    => 'formObject',
    };
    my $form_obj = new HTML::FormBuilder::Validation(data => $form_attributes);

    my $fieldset = $form_obj->add_fieldset({});

=head2 Create the input fields with validation

This is quite similar to creating input field in Form object. Likewise you can
add validation to HASH reference as the attribute of input field.

Below you can see the sample included four types of validation:

1. regexp: Just write the reqular expression that should be apply to the value

2. min_amount: Needs both type=min_amount and also minimum amount that declared
in amount

3. max_amount: Just like min_amount

4. checkbox_checked: Ensure checkbox is checked by user

5. custom: Just the javascript function call with parameters should be given to.
It only specifies client side validation.

    my $input_field_amount =
    {
        'label' =>
        {
            'text'     => 'Amount',
            'for'      => 'amount',
            'optional' => '0',
        },
        'input' =>
        {
            'type'      => 'text',
            'id'        => 'amount',
            'name'      => 'amount',
            'maxlength' => 40,
            'value'     => '',
        },
        'error' =>
        {
            'text' => '',
            'id'    => 'error_amount',
            'class' => 'errorfield',
        },
        'validation' =>
        [
            {
                'type'    => 'regexp',
                'regexp'  => '\w+',
                'err_msg' => 'Not empty',
            },
            {
                'type'    => 'regexp',
                'regexp'  => '\d+',
                'err_msg' => 'Must be digit',
            },
            {
                'type'    => 'min_amount',
                'amount'  => 50,
                'err_msg' => 'Too little',
            },
            {
                'type'    => 'max_amount',
                'amount'  => 500,
                'err_msg' => 'Too much',
            },
            {
                'type' => 'custom',
                'function' => 'custom_amount_validation()',
                'err_msg' => 'It is not good',
            },
        ],
    };

    my $terms_and_condition_checkbox =
    {
        'label' =>
        {
            'text'     => 'I have read & agree to the terms & condition of the site',
            'for'      => 'tnc',
        },
        'input' =>
        {
            'type'      => 'checkbox',
            'id'        => 'tnc',
            'name'      => 'tnc',
            'value'     => '1',             # optional
        },
        'error' =>
        {
            'id'    => 'error_tnc',
            'class' => 'errorfield',
        },
        'validation' =>
        [
            {
                'type'    => 'checkbox_checked',
                'err_msg' => 'In order to proceed, you need to agree to the terms & condition',
            },
        ],
    };

Below is another example with two different fields. In this matter we need to
indicate the id of each field in validation attributes.

    my $select_curr =
    {
        'id'      => 'select_text_curr',
        'name'    => 'select_text_curr',
        'type'    => 'select',
        'options' => '<option value=""></option><option value="USD">USD</option><option value="EUR">EUR</option>',
    };
    my $input_amount =
    {
        'id'    => 'select_text_amount',
        'name'  => 'select_text_amount',
        'type'  => 'text',
        'value' => ''
    };
    my $input_field_select_text =
    {
        'label' =>
        {
            'text'     => 'select_text',
            'for'      => 'select_text',
        },
        'input' => [ $select_curr, $input_amount ],
        'error' =>
        {
            'text'  => '',
            'id'    => 'error_select_text',
            'class' => 'errorfield',
        },
        'validation' =>
        [
            {
                'type' => 'regexp',
                'id'   => 'select_text_curr',
                'regexp'  => '\w+',
                'err_msg' => 'Must be select',
            },
            {
                'type' => 'regexp',
                'id'   => 'select_text_amount',
                'regexp'  => '\d+',
                'err_msg' => 'Must be digits',
            },
            {
                'type' => 'min_amount',
                'id'   => 'select_text_amount',
                'amount'  => 50,
                'err_msg' => 'Too little',
            },
        ],
    };

    my $general_error_field =
    {
        'error' =>
        {
            'text' => '',
            'id' => 'error_general',
            'class' => 'errorfield'
        },
    };

=head2 Adding input fields to form object

Here is just add fields to the form object like before.

    $form_obj->add_field($fieldset_index, $general_error_field);
    $form_obj->add_field($fieldset_index, $input_field_amount);
    $form_obj->add_field($fieldset_index, $input_field_select_text);

=head2 Define Javascript code to be run, during onsubmit input validation error

This javascript code will be run before onsubmit return false

    $form_obj->onsubmit_js_error("\$('#residence').attr('disabled', true);");
    $form_obj->onsubmit_js_error('onsubmit_error_disable_fields()');

=head2 Custom javascript validation

Custom javascript validation should be defined and assigned to the form object.
Note that, the name and parameters should be the same as the way you indicate
function call in validation attributes.

You can see a sample below:

    my $custom_javascript = qq~
        function custom_amount_validation()
        {
            var input_amount = document.getElementById('amount');
            if (input_amount.value == 100)
            {
                return false;
            }
            return true;
        }~;

=head2 Custom server side validation

The custom server side validation is quite similar to javascript. A reference to
a subrotine should be pass to form object.

    my $custom_server_side_sub_ref = sub {
        if ($form_obj->get_field_value('name') eq 'felix')
        {
            $form_obj->set_field_error_message('name', 'felix is not allow to use this page');
            $form_obj->set_field_error_message('error_general', 'There is an error !!!');
        }
    };

    $form_obj->set_server_side_checks($custom_server_side_sub_ref);

=head2 Use form object in cgi files

Somewhere in cgi files you can just print the result of build().

    print $form_obj->build();

In submit you need to fill form values, use set_input_fields(\%input) and pass
%input HASH and then show what ever you want in result of validation. Just like
below:

    if (not $form_obj->validate())
    {
        print '<h1>Test Form</h1>';
        print $form_obj->build();
    }
    else
    {
        print '<h1>Success !!!</h1>';
    }

    code_exit();

=head1 Attributes

=head2 has_error_of

The tag that error happened during validation

=head2 custom_server_side_check_of

The custom server side subroutine that will be run on server side.

=head2 onsubmit_js_error

javasript code to run during onsubmit error by javasript validation

=head1 METHODS

=head2 set_input_fields

    $form_validation_obj->set_input_fields({username => $username});

assign value to the input fields

=head2 validate

    $form_validation_obj->validate();

validate form input and return true or false

=head2 is_error_found_in

    $form_validation_obj->is_error_found_in($input_element_id);

check the erorr is founded in the input element or not

=head2 get_has_error

=head2 set_field_error_message

=head2 set_server_side_checks

=head2 validate_csrf

=head1 CROSS SITE REQUEST FORGERY PROTECTION

for plain CGI or other framework, read Dancer example below.

=head2 CSRF and Dancer

=over 4

=item * create form HTML and store csrftoken in session

    my $form = HTML::FormBuilder::Validation->new(data => $form_attributes, csrftoken => 1);
    ...
    my $html = $form->build;

    # save csrf token in session or cookie
    session(__csrftoken => $form->csrftoken);

=item * validate csrftoken on form submit

    my $csrftoken = session('__csrftoken');
    my $form = HTML::FormBuilder::Validation->new(data => $form_attributes, csrftoken => $csrftoken);
    $form->validate_csrf() or die 'CSRF failed.';
    # or call
    if ( $form->validate() ) { # it calls validate_csrf inside
        # Yap! it's ok
    } else {
        # NOTE we do not have error for csrf on form HTML build
        # show form again with $form->build
    }

=back

=head2 CSRF and Mojolicious

if you're using Mojolicious and have DefaultHelpers plugin enabled, it's simple to add csrftoken in Validation->new as below:

    my $form = HTML::FormBuilder::Validation->new(data => $form_attributes, csrftoken => $c->csrf_token);

Mojolicious $c->csrf_token will handle the session part for you.

=head1 AUTHOR

Chylli L<mailto:chylli@binary.com>

=head1 INHERITED METHODS

=over 4

=item L<HTML::FormBuilder>

L<BUILDARGS|HTML::FormBuilder/BUILDARGS>, L<add_field|HTML::FormBuilder/add_field>, L<add_fieldset|HTML::FormBuilder/add_fieldset>, L<after_form|HTML::FormBuilder/after_form>, L<build_confirmation_button_with_all_inputs_hidden|HTML::FormBuilder/build_confirmation_button_with_all_inputs_hidden>, L<csrftoken|HTML::FormBuilder/csrftoken>, L<data|HTML::FormBuilder/data>, L<fieldsets|HTML::FormBuilder/fieldsets>, L<get_field_error_message|HTML::FormBuilder/get_field_error_message>, L<get_field_value|HTML::FormBuilder/get_field_value>, L<set_field_value|HTML::FormBuilder/set_field_value>

=item L<HTML::FormBuilder::Base>

L<classes|HTML::FormBuilder::Base/classes>, L<localize|HTML::FormBuilder::Base/localize>

=item L<Moo::Object>

L<BUILDALL|Moo::Object/BUILDALL>, L<DEMOLISHALL|Moo::Object/DEMOLISHALL>, L<does|Moo::Object/does>, L<meta|Moo::Object/meta>

=back

=head1 CONTRIBUTOR

Fayland Lam L<mailto:fayland@binary.com>

Tee Shuwn Yuan L<mailto:shuwnyuan@binary.com>

=head1 COPYRIGHT AND LICENSE

