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   13 use strict;
  3         3  
  3         81  
16 3     3   10 use warnings;
  3         4  
  3         103  
17 3     3   10 no warnings 'uninitialized';
  3         3  
  3         102  
18              
19 3     3   11 use CGI::FormBuilder::Util;
  3         3  
  3         327  
20 3     3   10 use CGI::FormBuilder::Field;
  3         4  
  3         57  
21 3     3   9 use base 'CGI::FormBuilder::Field';
  3         3  
  3         2528  
22              
23              
24             our $VERSION = '3.10';
25              
26             sub script {
27 43     43 0 48 my $self = shift;
28 43         73 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         37 my $jsfunc = '';
37 43         83 my $jsfield = tovar($name);
38 43         50 my $close_brace = '';
39 43         82 my $in = indent(my $idt = 1); # indent
40              
41 43         94 my $alertstr = escapejs($self->jsmessage); # handle embedded '
42 43         52 $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         121 $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       66 if ($self->other) {
58 3         4 my $oth = $self->othername;
59 3         7 $jsfunc .= <
60             if ($jsfield == '$oth') $jsfield = form.elements['$oth'].value;
61             EOJS
62             }
63              
64 43         56 $close_brace = <
65              
66             } // if
67             } // for $name
68             EOJS
69              
70 43 100       153 $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         80 $in = indent($idt += 2);
79              
80 43         94 return $self->jsfield($jsfunc, $close_brace, $in);
81             }
82              
83             *render = \&tag;
84             sub tag {
85 47     47 1 107 local $^W = 0; # -w sucks
86 47         51 my $self = shift;
87 47         101 my $attr = $self->attr;
88              
89 47         187 my $jspre = $self->{_form}->jsprefix;
90              
91 47         63 my $tag = '';
92 47         96 my @value = $self->tag_value; # sticky is different in
93 47         104 my @opt = $self->options;
94 47         208 debug 2, "my(@opt) = \$field->options";
95              
96             # Add in our "Other:" option if applicable
97 47 100       109 push @opt, [$self->othername, $self->{_form}{messages}->form_other_default]
98             if $self->other;
99              
100 47         135 debug 2, "$self->{name}: generating $attr->{type} input type";
101              
102             # First the top-level select
103 47         66 delete $attr->{type}; # type="select" invalid
104             $self->multiple ? $attr->{multiple} = 'multiple'
105 47 100       90 : delete $attr->{multiple};
106              
107 47 50       82 belch "$self->{name}: No options specified for 'select' field" unless @opt;
108              
109             # Prefix options with "-select-", unless selectname => 0
110 47 100 66     195 if ($self->{_form}->smartness && ! $attr->{multiple} # set above
      100        
111             && $self->selectname ne 0)
112             {
113             # Use selectname if => "choose" or messages otherwise
114             my $name = $self->selectname =~ /\D+/
115             ? $self->selectname
116 29 100       82 : $self->{_form}{messages}->form_select_default;
117 29         85 unshift @opt, ['', $name]
118             }
119              
120             # Special event handling for our _other field
121 47 100 66     102 if ($self->other && $self->javascript) {
122 3         5 my $b = $self->othername; # box
123             # w/o newlines
124 3         10 $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         87 $tag .= htmltag('select', $attr) . "\n";
130              
131             # Stuff for optgroups
132 47         193 my $optgroups = $self->optgroups;
133 47         49 my $lastgroup = '';
134 47         38 my $didgroup = 0;
135 47         37 my $foundit = 0; # found option in list? (for "Other:")
136 47         249 debug 2, "$self->{name}: rendering options: (@opt)";
137 47         105 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         655 my($o,$n,$g) = optval($opt);
142 449         1065 debug 2, "optval($opt) = ($o,$n,$g)";
143              
144             # Must use defined() or else labels of "0" are lost
145 449 100       608 unless (defined($n)) {
146 307         294 $n = $attr->{labels}{$o};
147 307 50       390 unless (defined($n)) {
148 307 100       803 $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       566 if ($optgroups) {
155 48 100 100     175 if ($g && $g ne $lastgroup) {
    100 100        
156             # close previous optgroup and start a new one
157 10 100       16 $tag .= " \n" if $didgroup;
158 10         6 $lastgroup = $g;
159 10 50       18 if (UNIVERSAL::isa($optgroups, 'HASH')) {
    0          
160             # lookup by name
161 10 100       16 $g = exists $optgroups->{$g} ? $optgroups->{$g} : $g;
162             } elsif ($self->nameopts) {
163 0         0 $g = toname($g);
164             }
165 10         15 $tag .= ' ' . htmltag('optgroup', label => $g) . "\n";
166 10         11 $didgroup++;
167             } elsif (!$g && $lastgroup) {
168             # finished an optgroup but next option is not in one
169 10 100       16 $tag .= " \n" if $didgroup;
170 10         8 $didgroup = 0; # reset counter
171             }
172             }
173              
174 449         322 my %slct;
175 449 100 100     649 if (ismember($o, @value) ||
      100        
      100        
      66        
176             (! $foundit && $self->other && @value && ! @opt))
177             {
178 65         187 debug 2, "$self->{name}: found $o as member of (@value), setting 'selected'";
179 65         100 %slct = (selected => 'selected');
180 65         50 $foundit++;
181             }
182 449         513 $slct{value} = $o;
183              
184 449         884 debug 2, "$self->{name}: tag .= option $n";
185 449 50       839 $tag .= ' '
186             . htmltag('option', %slct)
187             . ($self->cleanopts ? escapehtml($n) : $n)
188             . "\n";
189              
190             }
191 47 50       85 $tag .= " \n" if $didgroup;
192 47         50 $tag .= ' ';
193              
194             # add an additional tag for our _other field
195 47 100       82 $tag .= ' ' . $self->othertag if $self->other;
196              
197 47         135 debug 2, "$self->{name}: generated tag = $tag";
198 47         296 return $tag; # always return scalar tag
199             }
200              
201             1;
202              
203             __END__