File Coverage

lib/CGI/FormBuilder/Field/checkbox.pm
Criterion Covered Total %
statement 83 89 93.2
branch 35 48 72.9
condition 4 9 44.4
subroutine 8 8 100.0
pod 1 2 50.0
total 131 156 83.9


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::checkbox;
14              
15 4     4   26 use strict;
  4         7  
  4         182  
16 4     4   23 use warnings;
  4         9  
  4         158  
17 4     4   21 no warnings 'uninitialized';
  4         8  
  4         178  
18              
19 4     4   24 use CGI::FormBuilder::Util;
  4         13  
  4         874  
20 4     4   28 use CGI::FormBuilder::Field;
  4         7  
  4         113  
21 4     4   32 use base 'CGI::FormBuilder::Field';
  4         177  
  4         6332  
22              
23              
24             our $VERSION = '3.09';
25              
26             sub script {
27 16     16 0 42 my $self = shift;
28 16         54 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 16         45 my $jsfunc = '';
37 16         53 my $jsfield = tovar($name);
38 16         31 my $close_brace = '';
39 16         59 my $in = indent(my $idt = 1); # indent
40              
41 16         106 my $alertstr = escapejs($self->jsmessage); # handle embedded '
42 16         33 $alertstr .= '\n';
43              
44             #
45             # If you can believe this, the Javascript DOM actually changes
46             # based on whether there are more than 1 option to checkboxes.
47             # Damn damn damn I hate the JavaScript DOM so damn much!!!!!!
48             #
49             # Whoever designed this should be shot.
50             #
51 16 100       63 if ($self->options == 1) {
52              
53             # Simple single-element on/off checkbox
54 4         19 $jsfunc .= <
55             // $name: single-element checkbox
56             var $jsfield = null;
57             if (document.getElementById('$name') != null && form.elements['$name'].checked) {
58             $jsfield = form.elements['$name'].value;
59             }
60             EOJS
61              
62             } else {
63              
64             # Get field from radio buttons or checkboxes.
65             # Must cycle through all again to see which is checked. Yeesh.
66              
67 12         81 $jsfunc .= <
68             // $name: radio group or multiple checkboxes
69             var $jsfield = null;
70             var selected_$jsfield = 0;
71             for (var loop = 0; loop < form.elements['$name'].length; loop++) {
72             if (form.elements['$name']\[loop].checked) {
73             $jsfield = form.elements['$name']\[loop].value;
74             selected_$jsfield++;
75             EOJS
76              
77             # Add catch for "other" if applicable
78 12 50       49 if ($self->other) {
79 0         0 my $oth = $self->othername;
80 0         0 $jsfunc .= <
81             if ($jsfield == '$oth') $jsfield = form.elements['$oth'].value;
82             EOJS
83             }
84              
85 12         41 $close_brace = <
86              
87             } // if
88             } // for $name
89             EOJS
90              
91             # required?
92 12 50       88 $close_brace .= <required;
93             if (! selected_$jsfield) {
94             alertstr += '$alertstr';
95             invalid++;
96             }
97             EOJS
98              
99             # indent the very last if/else tests so they're in the for loop
100 12         48 $in = indent($idt += 2);
101             }
102            
103 16         81 return $self->jsfield($jsfunc, $close_brace, $in);
104             }
105              
106             *render = \&tag;
107             sub tag {
108 16     16 1 58 local $^W = 0; # -w sucks
109 16         36 my $self = shift;
110 16         91 my $attr = $self->attr;
111              
112 16         109 my $jspre = $self->{_form}->jsprefix;
113              
114 16         34 my $tag = '';
115 16         70 my @value = $self->tag_value; # sticky is different in
116 16         129 my @opt = $self->options;
117 16         102 debug 2, "my(@opt) = \$field->options";
118              
119             # Add in our "Other:" option if applicable
120 16 50       77 push @opt, [$self->othername, $self->{_form}{messages}->form_other_default]
121             if $self->other;
122              
123 16         79 debug 2, "$self->{name}: generating $attr->{type} input type";
124              
125 16         28 my $checkbox_table = 0; # toggle
126 16         21 my $checkbox_col = 0;
127 16 100       101 if ($self->columns > 0) {
128 12         23 $checkbox_table = 1;
129 12         52 my $c = $self->{_form}->class('_columns');
130 12         55 $tag .= $self->{_form}->table(class => $c) . "\n";
131             }
132              
133 16 50       62 belch "$self->{name}: No options specified for 'checkbox' field" unless @opt;
134 16         115 for my $opt (@opt) {
135             # Divide up checkboxes in a user-controlled manner
136 46 100       112 if ($checkbox_table) {
137 36 100       192 $tag .= " ".htmltag('tr')."\n" if $checkbox_col % $self->columns == 0;
138 36         120 $tag .= ' '.htmltag('td') . $self->{_form}->font;
139             }
140             # Since our data structure is a series of ['',''] things,
141             # we get the name from that. If not, then it's a list
142             # of regular old data that we toname() if nameopts => 1
143 46         148 my($o,$n) = optval($opt);
144              
145             # Must use defined() or else labels of "0" are lost
146 46 100       123 unless (defined($n)) {
147 36         84 $n = $attr->{labels}{$o};
148 36 50       85 unless (defined($n)) {
149 36 50       183 $n = $self->nameopts ? toname($o) : $o;
150             }
151             }
152              
153 46 100       149 ismember($o, @value) ? $attr->{checked} = 'checked'
154             : delete $attr->{checked};
155              
156             # reset some attrs
157 46         105 $attr->{value} = $o;
158 46 100       104 if (@opt == 1) {
159             # single option checkboxes do not modify id
160 4   33     28 $attr->{id} ||= tovar($attr->{name});
161             } else {
162             # all others add the current option name
163 42 50       247 $attr->{id} = tovar($o eq $self->othername
164             ? "_$attr->{name}" : "$attr->{name}_$o");
165             }
166              
167             #
168             # Special event handling for our _other field
169             #
170             # This is the only piece that's different from ::radio, since
171             # here what we do is just key off whether the "Other" box is
172             # being checked or unchecked.
173             #
174 46 50 33     243 if ($self->other && $self->javascript) {
175 0         0 my $b = $self->othername; # box
176 0 0       0 if ($n eq $self->{_form}{messages}->form_other_default) {
177             #
178             # Turn on when they click the "_other" field
179             #
180 0         0 my $vct = "${jspre}${b}_ct";
181 0         0 $attr->{onclick} = "var $vct;"
182             . "if (this.checked && ! $vct) ${jspre}other_on('$b'); "
183             . "else { ${jspre}other_off('$b'); $vct = 1 }";
184             }
185             }
186              
187             # Each radio/checkbox gets a human thingy with
188 46         253 $tag .= $self->add_before_option;
189 46         321 $tag .= htmltag('input', $attr);
190 46 100       184 $tag .= $checkbox_table
191             ? (htmltag('/td')."\n ".htmltag('td').$self->{_form}->font) : ' ';
192 46         185 my $c = $self->{_form}->class('_option');
193 46 100       185 $tag .= htmltag('label', for => $attr->{id}, class => $c)
194             . ($self->cleanopts ? escapehtml($n) : $n)
195             . htmltag('/label');
196 46         296 $tag .= $self->add_after_option;
197              
198 46 50       411 $tag .= '
' if $self->linebreaks;
199              
200 46 100       278 if ($checkbox_table) {
201 36         45 $checkbox_col++;
202 36         100 $tag .= htmltag('/td');
203 36 100       186 $tag .= "\n ".htmltag('/tr') if $checkbox_col % $self->columns == 0;
204             }
205 46         133 $tag .= "\n";
206             }
207 16 50 66     324 $tag .= ' '.htmltag('/tr') if $checkbox_table && ($checkbox_col % $self->columns > 0);
208 16 100       70 $tag .= ' '.htmltag('/table') if $checkbox_table;
209              
210             # add an additional tag for our _other field
211 16 50       56 $tag .= ' ' . $self->othertag if $self->other;
212              
213 16         92 debug 2, "$self->{name}: generated tag = $tag";
214 16         175 return $tag; # always return scalar tag
215             }
216              
217             1;
218              
219             __END__