File Coverage

lib/CGI/FormBuilder/Field/select.pm
Criterion Covered Total %
statement 89 90 98.8
branch 39 46 84.7
condition 24 27 88.8
subroutine 8 8 100.0
pod 1 2 50.0
total 161 173 93.0


line stmt bran cond sub pod time code
1              
2             ###########################################################################
3             # Copyright (c) Nate Wiger http://nateware.com. All Rights Reserved.
4             # Please visit http://formbuilder.org for tutorials, support, and examples.
5             ###########################################################################
6              
7             # The majority of this module's methods (including new) are
8             # inherited directly from ::base, since they involve things
9             # which are common, such as parameter parsing. The only methods
10             # that are individual to different fields are those that affect
11             # the rendering, such as script() and tag()
12              
13             package CGI::FormBuilder::Field::select;
14              
15 3     3   19 use strict;
  3         4  
  3         131  
16 3     3   18 use warnings;
  3         6  
  3         109  
17 3     3   17 no warnings 'uninitialized';
  3         5  
  3         117  
18              
19 3     3   18 use CGI::FormBuilder::Util;
  3         6  
  3         631  
20 3     3   20 use CGI::FormBuilder::Field;
  3         8  
  3         77  
21 3     3   18 use base 'CGI::FormBuilder::Field';
  3         7  
  3         4021  
22              
23              
24             our $VERSION = '3.09';
25              
26             sub script {
27 43     43 0 91 my $self = shift;
28 43         136 my $name = $self->name;
29              
30             # The way script() works is slightly backwards: First the
31             # type-specific JS DOM code is generated, then this is
32             # passed as a string to Field->jsfield, which wraps this
33             # in the generic handling.
34              
35             # Holders for different parts of JS code
36 43         91 my $jsfunc = '';
37 43         125 my $jsfield = tovar($name);
38 43         90 my $close_brace = '';
39 43         163 my $in = indent(my $idt = 1); # indent
40              
41 43         190 my $alertstr = escapejs($self->jsmessage); # handle embedded '
42 43         86 $alertstr .= '\n';
43              
44             # Get value for field from select list
45             # Always assume it's multiple to guarantee we get all values
46 43         218 $jsfunc .= <
47             // $name: select list, always assume it's multiple to get all values
48             var $jsfield = null;
49             var selected_$jsfield = 0;
50             for (var loop = 0; loop < form.elements['$name'].options.length; loop++) {
51             if (form.elements['$name'].options[loop].selected) {
52             $jsfield = form.elements['$name'].options[loop].value;
53             selected_$jsfield++;
54             EOJS
55              
56             # Add catch for "other" if applicable
57 43 100       141 if ($self->other) {
58 3         11 my $oth = $self->othername;
59 3         15 $jsfunc .= <
60             if ($jsfield == '$oth') $jsfield = form.elements['$oth'].value;
61             EOJS
62             }
63              
64 43         95 $close_brace = <
65              
66             } // if
67             } // for $name
68             EOJS
69              
70 43 100       230 $close_brace .= <required;
71             if (! selected_$jsfield) {
72             alertstr += '$alertstr';
73             invalid++;
74             }
75             EOJS
76              
77             # indent the very last if/else tests so they're in the for loop
78 43         135 $in = indent($idt += 2);
79              
80 43         173 return $self->jsfield($jsfunc, $close_brace, $in);
81             }
82              
83             *render = \&tag;
84             sub tag {
85 47     47 1 168 local $^W = 0; # -w sucks
86 47         98 my $self = shift;
87 47         202 my $attr = $self->attr;
88              
89 47         308 my $jspre = $self->{_form}->jsprefix;
90              
91 47         125 my $tag = '';
92 47         167 my @value = $self->tag_value; # sticky is different in
93 47         191 my @opt = $self->options;
94 47         376 debug 2, "my(@opt) = \$field->options";
95              
96             # Add in our "Other:" option if applicable
97 47 100       206 push @opt, [$self->othername, $self->{_form}{messages}->form_other_default]
98             if $self->other;
99              
100 47         269 debug 2, "$self->{name}: generating $attr->{type} input type";
101              
102             # First the top-level select
103 47         123 delete $attr->{type}; # type="select" invalid
104 47 100       178 $self->multiple ? $attr->{multiple} = 'multiple'
105             : delete $attr->{multiple};
106              
107 47 50       138 belch "$self->{name}: No options specified for 'select' field" unless @opt;
108              
109             # Prefix options with "-select-", unless selectname => 0
110 47 100 66     304 if ($self->{_form}->smartness && ! $attr->{multiple} # set above
      100        
111             && $self->selectname ne 0)
112             {
113             # Use selectname if => "choose" or messages otherwise
114 29 100       150 my $name = $self->selectname =~ /\D+/
115             ? $self->selectname
116             : $self->{_form}{messages}->form_select_default;
117 29         133 unshift @opt, ['', $name]
118             }
119              
120             # Special event handling for our _other field
121 47 100 66     174 if ($self->other && $self->javascript) {
122 3         10 my $b = $self->othername; # box
123             # w/o newlines
124 3         26 $attr->{onchange} .= "if (this.selectedIndex + 1 == this.options.length) { "
125             . "${jspre}other_on('$b') } else { ${jspre}other_off('$b') }";
126             }
127              
128             # render
129 47         183 $tag .= htmltag('select', $attr) . "\n";
130              
131             # Stuff for optgroups
132 47         303 my $optgroups = $self->optgroups;
133 47         104 my $lastgroup = '';
134 47         70 my $didgroup = 0;
135 47         64 my $foundit = 0; # found option in list? (for "Other:")
136 47         357 debug 2, "$self->{name}: rendering options: (@opt)";
137 47         177 while (defined(my $opt = shift @opt)) {
138             # Since our data structure is a series of ['',''] things,
139             # we get the name from that. If not, then it's a list
140             # of regular old data that we toname() if nameopts => 1
141 449         1133 my($o,$n,$g) = optval($opt);
142 449         2030 debug 2, "optval($opt) = ($o,$n,$g)";
143              
144             # Must use defined() or else labels of "0" are lost
145 449 100       939 unless (defined($n)) {
146 307         575 $n = $attr->{labels}{$o};
147 307 50       617 unless (defined($n)) {
148 307 100       1363 $n = $self->nameopts ? toname($o) : $o;
149             }
150             }
151              
152             # If we asked for optgroups => 1, then we add an our
153             # each time our $lastgroup changes
154 449 100       1014 if ($optgroups) {
155 48 100 100     228 if ($g && $g ne $lastgroup) {
    100 100        
156             # close previous optgroup and start a new one
157 10 100       21 $tag .= " \n" if $didgroup;
158 10         11 $lastgroup = $g;
159 10 50       24 if (UNIVERSAL::isa($optgroups, 'HASH')) {
    0          
160             # lookup by name
161 10 100       24 $g = exists $optgroups->{$g} ? $optgroups->{$g} : $g;
162             } elsif ($self->nameopts) {
163 0         0 $g = toname($g);
164             }
165 10         24 $tag .= ' ' . htmltag('optgroup', label => $g) . "\n";
166 10         13 $didgroup++;
167             } elsif (!$g && $lastgroup) {
168             # finished an optgroup but next option is not in one
169 10 100       21 $tag .= " \n" if $didgroup;
170 10         11 $didgroup = 0; # reset counter
171             }
172             }
173              
174 449         490 my %slct;
175 449 100 100     1124 if (ismember($o, @value) ||
      100        
      100        
      66        
176             (! $foundit && $self->other && @value && ! @opt))
177             {
178 65         316 debug 2, "$self->{name}: found $o as member of (@value), setting 'selected'";
179 65         166 %slct = (selected => 'selected');
180 65         77 $foundit++;
181             }
182 449         945 $slct{value} = $o;
183              
184 449         1585 debug 2, "$self->{name}: tag .= option $n";
185 449 50       1478 $tag .= ' '
186             . htmltag('option', %slct)
187             . ($self->cleanopts ? escapehtml($n) : $n)
188             . "\n";
189              
190             }
191 47 50       125 $tag .= " \n" if $didgroup;
192 47         83 $tag .= ' ';
193              
194             # add an additional tag for our _other field
195 47 100       168 $tag .= ' ' . $self->othertag if $self->other;
196              
197 47         439 debug 2, "$self->{name}: generated tag = $tag";
198 47         587 return $tag; # always return scalar tag
199             }
200              
201             1;
202              
203             __END__