File Coverage

blib/lib/HTML/Widget/Plugin/Select.pm
Criterion Covered Total %
statement 59 59 100.0
branch 26 26 100.0
condition 6 6 100.0
subroutine 12 12 100.0
pod 6 6 100.0
total 109 109 100.0


line stmt bran cond sub pod time code
1 15     15   10568 use strict;
  15         34  
  15         510  
2 15     15   74 use warnings;
  15         28  
  15         719  
3             package HTML::Widget::Plugin::Select;
4             # ABSTRACT: a widget for selection from a list
5             $HTML::Widget::Plugin::Select::VERSION = '0.202';
6 15     15   84 use parent 'HTML::Widget::Plugin';
  15         36  
  15         118  
7              
8             #pod =head1 SYNOPSIS
9             #pod
10             #pod $widget_factory->select({
11             #pod id => 'the-selector', # if no name attr given, defaults to id value
12             #pod value => 10,
13             #pod options => [
14             #pod [ 0 => "Zero" ],
15             #pod [ 5 => "Five" ],
16             #pod [ 10 => "Ten" ],
17             #pod ],
18             #pod });
19             #pod
20             #pod =head1 DESCRIPTION
21             #pod
22             #pod This plugin provides a select-from-list widget.
23             #pod
24             #pod The C attribute may be used to add a default class to every
25             #pod produced input. This class cannot be overridden.
26             #pod
27             #pod my $plugin = HTML::Widget::Factory::Input->new({
28             #pod default_classes => [ qw(foo bar) ],
29             #pod });
30             #pod
31             #pod =head1 METHODS
32             #pod
33             #pod =head2 C< provided_widgets >
34             #pod
35             #pod This plugin provides the following widgets: select
36             #pod
37             #pod =cut
38              
39 17     17 1 57 sub provided_widgets { qw(select) }
40              
41             #pod =head2 C< select >
42             #pod
43             #pod This method returns a select-from-list widget.
44             #pod
45             #pod In addition to the generic L attributes, the following
46             #pod are valid arguments:
47             #pod
48             #pod =over
49             #pod
50             #pod =item disabled
51             #pod
52             #pod If true, this option indicates that the select widget can't be changed by the
53             #pod user.
54             #pod
55             #pod =item ignore_invalid
56             #pod
57             #pod If this is given and true, an invalid value is ignored instead of throwing an
58             #pod exception.
59             #pod
60             #pod =item options
61             #pod
62             #pod This may be an arrayref of arrayrefs, each containing a value/name pair, or it
63             #pod may be a hashref of values and names.
64             #pod
65             #pod Use the array form if you need multiple entries for a single value or if order
66             #pod is important.
67             #pod
68             #pod =item value
69             #pod
70             #pod If this argument is given, the option with this value will be pre-selected in
71             #pod the widget's initial state.
72             #pod
73             #pod An exception will be thrown if more or less than one of the provided options
74             #pod has this value.
75             #pod
76             #pod =back
77             #pod
78             #pod =cut
79              
80 15     15   1435 use HTML::Element;
  15         53  
  15         95  
81              
82 33     33   120 sub _attribute_args { qw(disabled) }
83 82     82   2909 sub _boolean_args { qw(disabled) }
84              
85             sub select { ## no critic Builtin
86 11     11 1 17 my ($self, $factory, $arg) = @_;
87              
88 11         24 $self->build($factory, $arg);
89             }
90              
91             #pod =head2 C< build >
92             #pod
93             #pod my $widget = $class->build($factory, \%arg)
94             #pod
95             #pod This method does the actual construction of the widget based on the args set up
96             #pod in the exported widget-constructing call. It's here for subclasses to exploit.
97             #pod
98             #pod =cut
99              
100             sub build {
101 15     15 1 23 my ($self, $factory, $arg) = @_;
102 15 100       56 $arg->{attr}{name} = $arg->{attr}{id} unless $arg->{attr}{name};
103              
104 15         54 my $widget = HTML::Element->new('select');
105              
106 15         358 my @options;
107 15 100       48 if (ref $arg->{options} eq 'HASH') {
108 1         2 @options = map { [ $_, $arg->{options}{$_} ] } keys %{ $arg->{options} };
  3         10  
  1         3  
109             } else {
110 14         17 @options = @{ $arg->{options} };
  14         40  
111 56 100 100     501 Carp::croak "undefined value passed to select widget"
112 14 100       23 if grep { not(defined $_) or ref $_ and not defined $_->[0] } @options;
113             }
114              
115 13 100       72 $self->validate_value($arg->{value}, \@options) unless $arg->{ignore_invalid};
116              
117 10         23 for my $entry (@options) {
118 44 100       504 my ($value, $name) = (ref $entry) ? @$entry : ($entry) x 2;
119 44         107 my $option = $self->make_option($factory, $value, $name, $arg);
120 44         106 $widget->push_content($option);
121             }
122              
123 10         134 $widget->attr($_ => $arg->{attr}{$_}) for keys %{ $arg->{attr} };
  10         55  
124 10         328 return $widget->as_XML;
125             }
126              
127             #pod =head2 C< make_option >
128             #pod
129             #pod my $option = $class->make_option($factory, $value, $name, $arg);
130             #pod
131             #pod This method constructs the HTML::Element option element that will represent one
132             #pod of the options that may be put into the select box. This is here for
133             #pod subclasses to exploit.
134             #pod
135             #pod =cut
136              
137             sub make_option {
138 32     32 1 44 my ($self, $factory, $value, $name, $arg) = @_;
139              
140 32         80 my $option = HTML::Element->new('option', value => $value);
141 32         844 $option->push_content($name);
142 32 100 100     448 $option->attr(selected => 'selected')
143             if defined $arg->{value} and $arg->{value} eq $value;
144              
145 32         94 return $option;
146             }
147              
148             #pod =head2 C< validate_value >
149             #pod
150             #pod This method checks whether the given value option is valid. See C>
151             #pod for an explanation of its default rules.
152             #pod
153             #pod =cut
154              
155             sub validate_value {
156 7     7 1 14 my ($class, $value, $options) = @_;
157              
158 7 100       11 my @options = map { ref $_ ? $_->[0] : $_ } @$options;
  32         70  
159             # maybe this should be configurable?
160 7 100       22 if ($value) {
161 4         7 my $matches = grep { $value eq $_ } @options;
  11         23  
162              
163 4 100       91 if (not $matches) {
    100          
164 1         202 Carp::croak "provided value '$value' not in given options: "
165 1         4 . join(q{ }, map { "'$_'" } @options);
166             } elsif ($matches > 1) {
167 1         155 Carp::croak "provided value '$matches' matches more than one option";
168             }
169             }
170             }
171              
172             sub rewrite_arg {
173 15     15 1 35 my ($self, $arg, @rest) = @_;
174              
175 15         71 $arg = $self->SUPER::rewrite_arg($arg, @rest);
176              
177 15 100       54 if ($self->{default_classes}) {
178 2         6 my $class = join q{ }, @{ $self->{default_classes} };
  2         37  
179 2 100       12 $arg->{attr}{class} = defined $arg->{attr}{class}
180             ? "$class $arg->{attr}{class}"
181             : $class;
182             }
183              
184 15         103 return $arg;
185             }
186              
187              
188             1;
189              
190             __END__