The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package HTML::Shakan::Widgets::Simple;
use strict;
use warnings;
use HTML::Escape;
use List::MoreUtils qw/zip/;

sub render {
    my ($self, $form, $field) = @_;

    my $type = $field->widget;
    my $code = $self->can("widget_${type}") or die "unknown widget type: $type";
    $code->(
        $self, $form, $field
    );
}

sub _attr {
    my $attr = shift;

    my @ret;

    for my $key (sort keys %$attr) {
        push @ret, sprintf(q{%s="%s"}, HTML::Escape::escape_html($key), HTML::Escape::escape_html($attr->{$key}));
    }
    join ' ', @ret;
}


sub widget_input {
    my ($self, $form, $field) = @_;

    my $value = $form->fillin_param($field->{name});
    if (defined $value) {
        $field->value($value);
    }

    return '<input ' . _attr($field->attr) . " />";
}

sub widget_textarea {
    my ($self, $form, $field) = @_;

    my $value = $form->fillin_param($field->{name}) || '';
    my $attr = {%{$field->attr}}; # shallow copy
    delete $attr->{type}; # textarea tag doesn't need this
    return '<textarea ' . _attr($attr) . ">${value}</textarea>";
}

sub widget_select {
    my ($self, $form, $field) = @_;

    my $choices = $field->{choices};

    my $value = $form->fillin_param($field->{name});

    my @t;
    push @t, sprintf(q{<select %s>}, _attr($field->attr));
    for (my $i=0; $i<@$choices; $i+=2) {
        my ($a, $b) = ($choices->[$i], $choices->[$i+1]);
        push @t, sprintf(
            q{<option value="%s"%s>%s</option>},
            HTML::Escape::escape_html($a),
            (defined $value && $value eq $a ? ' selected="selected"' : ''),
            HTML::Escape::escape_html($b));
    }
    push @t, q{</select>};
    return join "\n", @t;
}

sub widget_radio {
    my ($self, $form, $field) = @_;

    my $choices = $field->{choices};

    my $value = $form->fillin_param($field->{name});

    my @t;
    push @t, "<ul>";
    for (my $i=0; $i<@$choices; $i+=2) {
        my ($a, $b) = ($choices->[$i], $choices->[$i+1]);
        push @t, sprintf(
            q{<li><label><input %s type="radio" value="%s"%s />%s</label></li>},
            _attr({
                %{ $field->attr },
                id => sprintf( $field->id_tmpl, $field->{name}, $i / 2 ),
            }),
            HTML::Escape::escape_html($a),
            (defined $value && $value eq $a ? ' checked="checked"' : ''),
            HTML::Escape::escape_html($b)
        );
    }
    push @t, "</ul>";
    join "\n", @t;
}

sub widget_checkbox {
    my ($self, $form, $field) = @_;

    my $choices = $field->{choices};

    my $values = $form->fillin_param($field->{name});
    unless (ref $values) {
        $values = defined $values ? [$values] : [];
    }
    my @t;
    push @t, "<ul>";
    for (my $i=0; $i<@$choices; $i+=2) {
        my ($val, $label) = ($choices->[$i], $choices->[$i+1]);
        my $checked = grep /^$val$/, @$values;

       push @t, sprintf(
            '<li><label><input %s type="checkbox" value="%s"%s />%s</label></li>',
            _attr({
                %{ $field->attr },
                id => sprintf( $field->id_tmpl, $field->{name}, $i / 2 ),
            }),
            HTML::Escape::escape_html($val),
            ($checked ? ' checked="checked"' : ''),
            HTML::Escape::escape_html($label),
        );
    }
    push @t, "</ul>";
    join "\n", @t;
}

sub widget_date {
    my ($self, $form, $field) = @_;
    my $name = $field->{name} or die "missing name";
    my $years = $field->{years} or die "missing years";

    my $set = sub {
        my ($choices, $suffix) = @_;
        $self->widget_select(
            $form,
            HTML::Shakan::Field::Choice->new(
                name => "${name}_${suffix}",
                choices => [zip(@$choices, @$choices)],
            )
        );
    };

    my @t;

    push @t, '<span>';

    push @t, $set->($years, 'year');
    push @t, $set->([1..12], 'month');
    push @t, $set->([1..31], 'day');

    push @t, '</span>';

    join "\n", @t;
}

sub field_filter {
    my ($self, $form, $field, $params) = @_;

    if ($field->widget eq 'date') {
        my @c;
        for my $k (qw/year month day/) {
            my $key = $field->name . '_' . $k;
            my $v = $form->request->param($key);
            if (defined $v) {
                push @c, $v;
            }
        }

        if (@c == 3) {
            $params->{$field->name} = join '-', @c; # http-date style
        }
    }
}

1;
__END__

=head1 NAME

HTML::Shakan::Widgets::Simple - simple default HTML widgets

=head1 DESCRIPTION

This is basic default widgets class.

This module generates basic XHTML.

=head1 AUTHORS

Tokuhiro Matsuno

=head1 SEE ALSO

L<HTML::Shakan>