extended select() support
authorMischa Poslawsky <mischa@mediadesign.nl>
Fri, 25 Jul 2008 14:11:42 +0000 (16:11 +0200)
committerMischa Poslawsky <mischa@mediadesign.nl>
Fri, 25 Jul 2008 14:14:20 +0000 (16:14 +0200)
- Default values.
- Keep options seperate in list context.
- Input types (checkbox, radio).
- Various tests.
- Shorthand methods check() and radio().

lib/HTML/Form/Simple.pm
t/html.t

index 6e84888296e51a5deb508b6232f69a0c00c085cf..57b2a918b6f2a1351abdadc515de642598f9fb3b 100644 (file)
@@ -28,7 +28,7 @@ sub tag {
 
        # add booleans
        delete $attr->{$_} and $return .= ' '.$_
-               for qw(disabled readonly);
+               for qw(selected checked disabled readonly);
 
        $return .= sprintf ' %s="%s"', $_, $self->quote($attr->{$_})
                for sort grep { defined $attr->{$_} } keys %$attr;
@@ -107,15 +107,92 @@ sub select {
 
        if (ref $value eq 'HASH') {
                $attr = $value;
+               $value = delete $attr->{value};
        }
        else {
                $attr ||= {};
+               delete $attr->{value};
        }
        $attr->{name} = $name;
+       $attr->{id}   = $attr->{name} unless defined $attr->{id};
+       $attr->{type} = 'select' unless defined $attr->{type};
+
+       my @options = map { ref $_ ? $_ : {value => $_} } @$rows;
+
+       if ($attr->{type} eq 'select') {
+               delete $attr->{type};
+               if (defined $value) {
+                       for (@options) {
+                               $_->{selected} = 1 if defined $_->{value} and $_->{value} eq $value;
+                       }
+               }
+               my @return = (
+                       $self->tag(select => $attr),
+                       (map { $self->tag(option => $_) } @options),
+                       '</select>',
+               );
+               return wantarray ? @return : join('', @return);
+       }
+       else {
+               if (defined $attr->{id}) {
+                       defined $_->{id} or defined $_->{value} and $_->{id} = $attr->{id}.'_'.$_->{value}
+                               for @options;
+               }
+               if (defined $attr->{label}) {
+                       defined $_->{value} and not defined $_->{label}
+                               and $_->{label} = $attr->{label}->{$_->{value}}
+                                       for @options;
+                       delete $attr->{label};
+               }
+               if (defined $value) {
+                       for (@options) {
+                               $_->{checked} = 1 if defined $_->{value} and $_->{value} eq $value;
+                       }
+               }
+               $_ = {%$attr, %$_} for @options;
+               my @return = map {
+                       my $label = delete $_->{label};
+                       defined $label && $label ne ''
+                               ? '<label>'.$self->tag(input => $_)." $label</label>"
+                               :           $self->tag(input => $_)
+               } @options;
+               return wantarray ? @return : join('', @return);
+       }
+}
+
+sub radio {
+       my ($self, $name, $value, $attr) = @_;
+
+       if (ref $value eq 'HASH') {
+               $attr = $value;
+       }
+       else {
+               $attr ||= {};
+               $attr->{value} = $value;
+       }
 
-       return $self->tag(select => $attr) . join('',
-               map { $self->tag(option => (ref $_ ? $_ : {value => $_})) } @$rows
-       ) . '</select>';
+       $self->select($name, [$attr], {type => 'radio'});
+}
+
+sub check {
+       my ($self, $name, $label, $checked, $attr) = @_;
+
+       if (ref $label eq 'HASH') {
+               $attr = $label;
+               undef $label;
+       }
+       elsif (ref $checked eq 'HASH') {
+               $attr = $checked;
+               $attr->{label} = $label;
+       }
+       else {
+               $attr ||= {};
+               $attr->{checked} = $checked;
+               $attr->{label} = $label;
+       }
+       $attr->{value} = '1' unless exists $attr->{value};
+
+       $self->select($name, [$attr], {type => 'checkbox'});
 }
 
 1;
@@ -135,9 +212,15 @@ HTML::Form::Simple
                [ Message => $input->text(
                        msg => 'Textarea default', {rows => 4, style => 'background:red'}
                ) ],
-               [ Colour => $input->select(
+               [ Gender => join ' or ', $input->radio(
+                       sex => ['m', 'f']
+               ) ],
+               [ Colour => scalar $input->select(
                        favcolour => [qw(Blue Green Red)], 'Green'
                ) ],
+               [ Options => $input->check(
+                       spam => 'Receive weekly newsletter'
+               ) ],
        );
        say $input->stop; # </form>
 
index e023997831b20a951b6fd949dc55dbe0e2a4bb7e..d12d6ef8127ee73a16e2ba4c837dcab0b3616ccc 100644 (file)
--- a/t/html.t
+++ b/t/html.t
@@ -5,7 +5,7 @@ use warnings;
 
 use Test::More;
 
-plan tests => 31;
+plan tests => 43;
 
 use_ok('HTML::Form::Simple');
 
@@ -176,29 +176,139 @@ is(
 
 # select
 
-is(
-       $form->select,
-       '<select></select>', # malformed html: at least 1 option required
+is_deeply(
+       [ $form->select ],
+       [ qw(<select> </select>) ], # malformed html: at least 1 option required
        'empty select'
 );
 
-is(
-       $form->select(undef, [], '', {name => ''}),
-       '<select></select>',
+is_deeply(
+       [ $form->select(undef, [], '', {name => '', class => ''}) ],
+       [ qw(<select> </select>) ],
        'explicit empty select'
 );
 
-is(
-       $form->select(undef, [undef]),
-       '<select><option></select>',
+is_deeply(
+       [ $form->select(undef, [undef]) ],
+       [ qw(<select> <option> </select>) ],
        'minimal select'
 );
 
-is(
-       $form->select(foo => [1..2]),
-       '<select name="foo"><option value="1"><option value="2"></select>',
+is_deeply(
+       [ $form->select(foo => [1, 2]) ],
+       [
+               '<select id="foo" name="foo">',
+               '<option value="1">', '<option value="2">',
+               '</select>'
+       ],
        'select contents'
 );
 
+is_deeply(
+       [ $form->select(foo => [1, 2], 3) ],
+       [
+               '<select id="foo" name="foo">',
+               '<option value="1">', '<option value="2">',
+               '</select>'
+       ],
+       'select invalid default'
+);
+
+is_deeply(
+       [ $form->select(undef, [1, 2], 2) ],
+       [
+               '<select>',
+               '<option value="1">', '<option selected value="2">',
+               '</select>'
+       ],
+       'select default'
+);
+
+is_deeply(
+       [
+               $form->select(foo => [
+                       '<">', {value => 2, disabled => 1, selected => 0, class => 1}, {selected => 1}
+               ], '2', {id => '', class => 'a <b', value => 1})
+       ],
+       [
+               '<select class="a &lt;b" name="foo">',
+               '<option value="&lt;&quot;>">',
+               '<option selected disabled class="1" value="2">',
+               '<option selected>',
+               '</select>'
+       ],
+       'complex select'
+);
+
+is(
+       scalar $form->select(foo => [1, 2]),
+       '<select id="foo" name="foo"><option value="1"><option value="2"></select>',
+       'select scalar'
+);
+
+# radio
+
+is_deeply(
+       [ $form->select(foo => [1], {type => 'radio'}) ],
+       [ '<input id="foo_1" name="foo" type="radio" value="1">' ],
+       'input select'
+);
+
+is_deeply(
+       [
+               $form->select(foo => [
+                       1, {value => 2, name => '', label => ''}, {value => 3, id => '', type => ''}
+               ], {type => 'checkbox', label => {3 => 'test', 2 => 'ignore'}, value => '1'})
+       ],
+       [
+               '<input checked id="foo_1" name="foo" type="checkbox" value="1">',
+               '<input id="foo_2" name="" type="checkbox" value="2">',
+               '<label><input name="foo" value="3"> test</label>',
+       ],
+       'input selects'
+);
+
+is(
+       $form->radio(foo => 1),
+       '<input id="foo_1" name="foo" type="radio" value="1">',
+       'radio method'
+);
+
+is(
+       $form->radio(undef, {checked => 1}),
+       '<input checked type="radio">',
+       'simple radio button'
+);
+
+is(
+       $form->check('foo'),
+       '<input id="foo_1" name="foo" type="checkbox" value="1">',
+       'check method'
+);
+
+is(
+       $form->check(foo => 'test', {value => undef}),
+       '<label><input id="foo" name="foo" type="checkbox"> test</label>',
+       'check parameters'
+);
+
+is(
+       $form->check(undef, '', 1),
+       '<input checked type="checkbox" value="1">',
+       'simple checkbox'
+);
+
+TODO: {
+       local $TODO = 'shorthand';
+is_deeply(
+       [ $form->check(undef, ['', '<">']) ],
+       [
+               '<input checked type="checkbox" value="1">',
+               '<label><input checked type="checkbox" value="2"> &lt;&quot;></label>',
+       ],
+       'multiple checkboxes'
+);
+};
+
 #TODO