File Coverage

lib/CGI/FormBuilder/Field.pm
Criterion Covered Total %
statement 345 394 87.5
branch 183 264 69.3
condition 72 128 56.2
subroutine 42 44 95.4
pod 11 32 34.3
total 653 862 75.7


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             package CGI::FormBuilder::Field;
8              
9             =head1 NAME
10              
11             CGI::FormBuilder::Field - Base class for FormBuilder fields
12              
13             =head1 SYNOPSIS
14              
15             use CGI::FormBuilder::Field;
16              
17             # delegated straight from FormBuilder
18             my $f = CGI::FormBuilder::Field->new($form, name => 'whatever');
19              
20             # attribute functions
21             my $n = $f->name; # name of field
22             my $n = "$f"; # stringify to $f->name
23              
24             my $t = $f->type; # auto-type
25             my @v = $f->value; # auto-stickiness
26             my @o = $f->options; # options, aligned and sorted
27              
28             my $l = $f->label; # auto-label
29             my $h = $f->tag; # field XHTML tag (name/type/value)
30             my $s = $f->script; # per-field JS validation script
31              
32             my $m = $f->message; # error message if invalid
33             my $m = $f->jsmessage; # JavaScript error message
34              
35             my $r = $f->required; # required?
36             my $k = $f->validate; # run validation check
37              
38             my $v = $f->tag_value; # value in tag (stickiness handling)
39             my $v = $f->cgi_value; # CGI value if any
40             my $v = $f->def_value; # manually-specified value
41              
42             $f->field(opt => 'val'); # FormBuilder field() call
43              
44             =cut
45              
46 11     11   65 use Carp; # confess used manually in this pkg
  11         18  
  11         730  
47 11     11   114 use strict;
  11         25  
  11         463  
48 11     11   67 use warnings;
  11         43  
  11         414  
49 11     11   50 no warnings 'uninitialized';
  11         24  
  11         443  
50              
51 11     11   70 use CGI::FormBuilder::Util;
  11         36  
  11         5472  
52              
53              
54             our $VERSION = '3.09';
55             our $AUTOLOAD;
56              
57             # what to generate for tag
58             our @TAGATTR = qw(name type multiple jsclick);
59              
60             # Catches for special validation patterns
61             # These are semi-Perl patterns; they must be usable by JavaScript
62             # as well so they do not take advantage of features JS can't use
63             # If the value is an arrayref, then the second arg is a tag to
64             # spit out at the person after the field label to help with format
65              
66             our %VALIDATE = (
67             WORD => '/^\w+$/',
68             NAME => '/^[a-zA-Z]+$/',
69             NUM => '/^-?\s*[0-9]+\.?[0-9]*$|^-?\s*\.[0-9]+$/', # 1, 1.25, .25
70             INT => '/^-?\s*[0-9]+$/',
71             FLOAT => '/^-?\s*[0-9]+\.[0-9]+$/',
72             PHONE => '/^\d{3}\-\d{3}\-\d{4}$|^\(\d{3}\)\s+\d{3}\-\d{4}$/',
73             INTPHONE => '/^\+\d+[\s\-][\d\-\s]+$/',
74             EMAIL => '/^[\w\-\+\._]+\@[a-zA-Z0-9][-a-zA-Z0-9\.]*\.[a-zA-Z]+$/',
75             CARD => '/^\d{4}[\- ]?\d{4}[\- ]?\d{4}[\- ]?\d{4}$|^\d{4}[\- ]?\d{6}[\- ]?\d{5}$/',
76             MMYY => '/^(0?[1-9]|1[0-2])\/?[0-9]{2}$/',
77             MMYYYY => '/^(0?[1-9]|1[0-2])\/?[0-9]{4}$/',
78             DATE => '/^(0?[1-9]|1[0-2])\/?(0?[1-9]|[1-2][0-9]|3[0-1])\/?[0-9]{4}$/',
79             EUDATE => '/^(0?[1-9]|[1-2][0-9]|3[0-1])\/?(0?[1-9]|1[0-2])\/?[0-9]{4}$/',
80             TIME => '/^[0-9]{1,2}:[0-9]{2}$/',
81             AMPM => '/^[0-9]{1,2}:[0-9]{2}\s*([aA]|[pP])[mM]$/',
82             ZIPCODE => '/^\d{5}$|^\d{5}\-\d{4}$/',
83             STATE => '/^[a-zA-Z]{2}$/',
84             COUNTRY => '/^[a-zA-Z]{2}$/',
85             IPV4 => '/^([0-1]??\d{1,2}|2[0-4]\d|25[0-5])\.([0-1]??\d{1,2}|2[0-4]\d|25[0-5])\.([0-1]??\d{1,2}|2[0-4]\d|25[0-5])\.([0-1]??\d{1,2}|2[0-4]\d|25[0-5])$/',
86             NETMASK => '/^([0-1]??\d{1,2}|2[0-4]\d|25[0-5])\.([0-1]??\d{1,2}|2[0-4]\d|25[0-5])\.([0-1]??\d{1,2}|2[0-4]\d|25[0-5])\.([0-1]??\d{1,2}|2[0-4]\d|25[0-5])$/',
87             FILE => '/^[\/\w\.\-_]+$/',
88             WINFILE => '/^[a-zA-Z]:\\[\\\w\s\.\-]+$/',
89             MACFILE => '/^[:\w\.\-_]+$/',
90             USER => '/^[-a-zA-Z0-9_]{4,8}$/',
91             HOST => '/^[a-zA-Z0-9][-a-zA-Z0-9]*$/',
92             DOMAIN => '/^[a-zA-Z0-9][-a-zA-Z0-9\.]*\.[a-zA-Z]+$/',
93             ETHER => '/^[\da-f]{1,2}[\.:]?[\da-f]{1,2}[\.:]?[\da-f]{1,2}[\.:]?[\da-f]{1,2}[\.:]?[\da-f]{1,2}[\.:]?[\da-f]{1,2}$/i',
94             # Many thanks to Mark Belanger for these additions
95             FNAME => '/^[a-zA-Z]+[- ]?[a-zA-Z]*$/',
96             LNAME => '/^[a-zA-Z]+[- ]?[a-zA-Z]+\s*,?([a-zA-Z]+|[a-zA-Z]+\.)?$/',
97             CCMM => '/^0[1-9]|1[012]$/',
98             CCYY => '/^[1-9]{2}$/',
99             );
100              
101             # stringify to name
102 6498     6498   20000 use overload '""' => sub { $_[0]->name },
103             #'.' => sub { $_[0]->name },
104 0     0   0 '0+' => sub { $_[0]->name },
105 226     226   625 'bool' => sub { $_[0]->name },
106 11     11   23196 'eq' => sub { $_[0]->name eq $_[1] };
  11     3   14517  
  11         195  
  3         9  
107              
108             sub new {
109 346 50   346 1 1058 puke "Not enough arguments for Field->new()" unless @_ > 1;
110 346         453 my $self = shift;
111              
112 346         455 my $form = shift; # need for top-level attr
113 346         926 my $opt = arghash(@_);
114 346         903 $opt->{_form} = $form; # parental ptr
115 346 50       833 puke "Missing name for field() in Field->new()"
116             unless $opt->{name};
117              
118 346   33     1258 my $class = ref($self) || $self;
119 346         1031 my $f = bless $opt, $class;
120              
121             # Note that at this point, the object is a generic field
122             # without a type. Not until it's called via $f->type does
123             # it get a type, which affects its HTML representation.
124             # Everything else is inherited from this module.
125              
126 346         950 return $f;
127             }
128              
129             sub field {
130 181     181 1 267 my $self = shift;
131              
132 181 100 66     1272 if (ref $_[0] || @_ > 1) {
133 152         407 my $opt = arghash(@_);
134 152         627 while (my($k,$v) = each %$opt) {
135 215 50       591 next if $k eq 'name'; # segfault??
136 215         1463 $self->{$k} = $v;
137             }
138             }
139 181         474 return $self->value; # needed for @v = $form->field('name')
140             }
141              
142             *override = \&force; # CGI.pm
143             sub force {
144 1245     1245 0 1904 my $self = shift;
145 1245 50       2792 $self->{force} = shift if @_;
146 1245   100     7841 return $self->{force} || $self->{override};
147             }
148              
149             # grab the field_other field if other => 1 specified
150             sub other {
151 2349     2349 0 3280 my $self = shift;
152 2349 50       5095 $self->{other} = shift if @_;
153 2349 100       10804 return unless $self->{other};
154 95 100       256 $self->{other} = {} unless ref $self->{other};
155 95         187 $self->{other}{name} = $self->othername;
156 95 50       645 return wantarray ? %{$self->{other}} : $self->{other};
  0         0  
157             }
158              
159             sub othername {
160 329     329 0 436 my $self = shift;
161 329         1666 return $self->{_form}->othername . '_' . $self->name;
162             }
163              
164             sub othertag {
165 7     7 0 12 my $self = shift;
166 7 50       19 return '' unless $self->other;
167              
168             # add an additional tag for our _other field
169 7         19 my $oa = $self->other; # other attr
170              
171             # default settings
172 7   100     39 $oa->{type} ||= 'text';
173 7         22 my $v = $self->{_form}->cgi_param($self->othername);
174             #$v = $self->tag_value unless defined $v;
175 7 100 66     165 if ($self->sticky and defined $v) {
176 1         3 $oa->{value} = $v;
177             }
178              
179 7 100 100     29 $oa->{disabled} = 'disabled' if $self->javascript && ! defined $v; # fanciness
180 7         25 return htmltag('input', $oa);
181             }
182              
183             sub growname {
184 2     2 0 5 my $self = shift;
185 2         19 return $self->{_form}->growname . '_' . $self->name;
186             }
187              
188             sub cgi_value {
189 1222     1222 1 1445 my $self = shift;
190 1222         14239 debug 2, "$self->{name}: called \$field->cgi_value";
191 1222 50       2728 puke "Cannot set \$field->cgi_value manually" if @_;
192 1222 100       3892 if (my @v = $self->{_form}{params}->param($self->name)) {
193 173         4170 for my $v (@v) {
194 179 100 66     475 if ($self->other && $v eq $self->othername) {
195 6         25 debug 1, "$self->{name}: redoing value from _other field";
196 6         21 $v = $self->{_form}{params}->param($self->othername);
197             }
198             }
199 173         464 local $" = ',';
200 173         753 debug 2, "$self->{name}: cgi value = (@v)";
201 173 50       879 return wantarray ? @v : $v[0];
202             }
203 1049         21411 return;
204             }
205              
206             sub def_value {
207 1181     1181 1 1675 my $self = shift;
208 1181         4395 debug 2, "$self->{name}: called \$field->def_value";
209 1181 50       2882 if (@_) {
210 0         0 $self->{value} = arglist(@_); # manually set
211 0         0 delete $self->{_cache}{type}; # clear auto-type
212             }
213 1181         5111 my @v = autodata $self->{value};
214 1181         2400 local $" = ',';
215 1181         4894 debug 2, "$self->{name}: def value = (@v)";
216 1181         3272 $self->inflate_value(\@v);
217 1181 100       5772 return wantarray ? @v : $v[0];
218             }
219              
220             sub inflate_value {
221 1248     1248 0 2022 my ($self, $v_aref) = @_;
222              
223 1248         4555 debug 2, "$self->{name}: called \$field->inflate_value";
224              
225             # trying to inflate?
226 1248 100       4810 return unless exists $self->{inflate};
227 2         9 debug 2, "$self->{name}: inflate routine exists";
228              
229             # must return real values to the validate() routine:
230 2 50       5 return if grep { ((caller($_))[3] eq 'CGI::FormBuilder::Field::validate') }
  4         27  
231             1..2;
232 2         9 debug 2, "$self->{name}: made sure inflate not called via validate";
233              
234             # must be valid:
235             #return unless exists $self->{invalid} && ! $self->{invalid};
236 2 50       18 return if $self->invalid;
237 2         9 debug 2, "$self->{name}: valid field, inflate proceeding";
238              
239 2         5 my $cache = $self->{inflated_values};
240              
241 2 100 66     16 if ($cache && ref $cache eq 'ARRAY' && @{$cache}) {
  1   66     5  
242             # could have been cached by validate() check
243 1         2 @{ $v_aref } = @{ $self->{inflated_values} };
  1         4  
  1         3  
244 1         10 debug 2, "$self->{name}: using cached inflate "
245             . "value from validate()";
246             }
247             else {
248 1         6 debug 2, "$self->{name}: new inflate";
249              
250 1 50       5 puke("Field $self->{name}: inflate must be a reference to a \\&sub")
251             if ref $self->{inflate} ne 'CODE';
252              
253 1         4 eval { @{ $v_aref } = map $self->{inflate}->($_), @{ $v_aref } };
  1         3  
  1         18  
  1         5  
254              
255             # no choice but to die hard if didn't validate() first
256 1 50       3 puke("Field $self->{name}: inflate failed: $@") if $@;
257              
258             # cache the result:
259 1         2 @{ $self->{inflated_values} } = @{ $v_aref };
  1         4  
  1         2  
260             }
261 2         5 return;
262             }
263              
264             # CGI.pm happiness
265             *default = \&value;
266             *defaults = \&value;
267             *values = \&value;
268             sub value {
269 277     277 1 369 my $self = shift;
270 277         1190 debug 2, "$self->{name}: called \$field->value(@_)";
271 277 50       937 if (@_) {
272 0         0 $self->{value} = arglist(@_); # manually set
273 0         0 delete $self->{_cache}{type}; # clear auto-type
274             }
275 277 100       817 unless ($self->force) {
276             # CGI wins if stickiness is set
277 265         934 debug 2, "$self->{name}: sticky && ! force";
278 265 100       857 if (my @v = $self->cgi_value) {
279 67         104 local $" = ',';
280 67         290 debug 1, "$self->{name}: returning value (@v)";
281 67         210 $self->inflate_value(\@v);
282 67 100       610 return wantarray ? @v : $v[0];
283             }
284             }
285 210         548 debug 2, "no cgi found, returning def_value";
286             # no CGI value, or value was forced, or not sticky
287 210         486 return $self->def_value;
288             }
289              
290             # The value in the may be different than in code (sticky)
291             sub tag_value {
292 1041     1041 1 1299 my $self = shift;
293 1041         3816 debug 2, "$self->{name}: called \$field->tag_value";
294 1041 50       2363 if (@_) {
295             # setting the tag_value manually is odd...
296 0         0 $self->{tag_value} = arglist(@_);
297 0         0 delete $self->{_cache}{type};
298             }
299 1041 50       2290 return $self->{tag_value} if $self->{tag_value};
300              
301 1041 100 100     4727 if ($self->sticky && ! $self->force) {
302             # CGI wins if stickiness is set
303 957         3655 debug 2, "$self->{name}: sticky && ! force";
304 957 100       2685 if (my @v = $self->cgi_value) {
305 106         178 local $" = ',';
306 106         608 debug 1, "$self->{name}: returning value (@v)";
307 106 50       623 return wantarray ? @v : $v[0];
308             }
309             }
310 935         7460 debug 2, "no cgi found, returning def_value";
311             # no CGI value, or value was forced, or not sticky
312 935         2885 return $self->def_value;
313             }
314              
315             # Handle "b:select" and "b:option"
316             sub tag_name {
317 0     0 1 0 my $self = shift;
318 0 0       0 $self->{tag_name} = shift if @_;
319 0 0       0 return $self->{tag_name} if $self->{tag_name};
320             # Try to guess
321 0         0 my($tag) = ref($self) =~ /^CGI::FormBuilder::Field::(.+)/;
322 0 0       0 puke "Can't resolve tag for untyped field '$self->{name}'"
323             unless $tag;
324 0         0 return $tag;
325             }
326              
327             sub type {
328 1334     1334 1 3648 local $^W = 0; # -w sucks
329 1334         1991 my $self = shift;
330 1334 50       3498 if (@_) {
331 0         0 $self->{type} = lc shift;
332 0         0 delete $self->{_cache}{type}; # forces rebless
333 0         0 debug 2, "setting field type to '$self->{type}'";
334             }
335              
336             #
337             # catch for new way of saying static => 1
338             #
339             # confirm() will set ->static but not touch $self->{type},
340             # so make sure it's not a field the user hid themselves
341             #
342 1334 100 66     3109 if ($self->static && $self->{type} ne 'hidden') {
343 36         71 $self->{type} = 'static';
344 36         93 delete $self->{_cache}{type}; # forces rebless
345 36         144 debug 2, "setting field type to '$self->{type}'";
346             }
347              
348             # manually set
349 1334         6467 debug 2, "$self->{name}: called \$field->type (manual = '$self->{type}')";
350              
351             # The $field->type method is called so often that it really slows
352             # things down. As such, we cache the type and use it *unless* the
353             # value has been updated manually (we assume one CGI instance).
354             # See value() for its deletion of this cache
355 1334 100       8725 return $self->{_cache}{type} if $self->{_cache}{type};
356              
357 234         422 my $name = $self->{name};
358 234         314 my $type;
359 234 100       864 unless ($type = lc $self->{type}) {
360             #
361             # Unless the type has been set explicitly, we make a guess
362             # based on how many items there are to display, which is
363             # basically, how many options we have. Our 'jsclick' option
364             # is now changed down in the javascript section, fixing a bug
365             #
366 166 50       967 if ($self->{_form}->smartness) {
367 166         601 debug 1, "$name: input type not set, checking for options";
368 166 100       653 if (my $n = $self->options) {
    50          
369 51         216 debug 2, "$name: has options, so setting to select|radio|checkbox";
370 51 100       260 if ($n >= $self->selectnum) {
371 15         78 debug 2, "$name: has more than selectnum (", $self->selectnum,
372             ") options, setting to 'select'";
373 15         43 $type = 'select';
374             } else {
375             # Something is a checkbox if it is a multi-valued box.
376             # However, it is *also* a checkbox if only single-valued options,
377             # otherwise you can't unselect it.
378 36         276 my @v = $self->def_value; # only on manual, not dubious CGI
379 36 100 66     119 if ($self->multiple || @v > 1 || $n == 1) {
      100        
380 8         44 debug 2, "$name: has multiple select < selectnum, setting to 'checkbox'";
381 8         22 $type = 'checkbox';
382             } else {
383 28         122 debug 2, "$name: has singular select < selectnum, setting to 'radio'";
384 28         72 $type = 'radio';
385             }
386             }
387             } elsif ($self->{_form}->smartness > 1) {
388 0         0 debug 2, "$name: smartness > 1, auto-inferring type based on value";
389             # only autoinfer field types based on values with high smartness
390 0         0 my @v = $self->def_value; # only on manual, not dubious CGI
391 0 0 0     0 if ($name =~ /passw(or)?d/i) {
    0 0        
    0          
392 0         0 $type = 'password';
393             } elsif ($name =~ /(?:details?|comments?)$/i
394             || grep /\n|\r/, @v || $self->cols || $self->rows) {
395 0         0 $type = 'textarea';
396             } elsif ($name =~ /\bfile/i) {
397 0         0 $type = 'file';
398             }
399             } else {
400 115         331 debug 2, "no options found";
401             }
402             }
403 166   100     791 $type ||= 'text'; # default if no fancy settings matched or no smartness
404             }
405 234         901 debug 1, "$name: field set to type '$type' (reblessing)";
406              
407             # Store type in cache for speediness
408 234         730 $self->{_cache}{type} = $type;
409              
410             # Re-bless into the appropriate package
411 234         466 my $pkg = __PACKAGE__ . '::' . $type;
412 234         437 $pkg =~ s/\-/_/g; # handle HTML5 type names ala 'datetime-local'
413 234         18970 eval "require $pkg";
414 234 50       1054 puke "Can't load $pkg for field '$name' (type '$type'): $@" if $@;
415 234         702 bless $self, $pkg;
416              
417 234         744 return $type;
418             }
419              
420             sub label {
421 778     778 1 1108 my $self = shift;
422 778 50       2124 $self->{label} = shift if @_;
423 778 100       2143 return $self->{label} if defined $self->{label}; # manually set
424 692         1467 return toname($self->name);
425             }
426              
427             sub attr {
428 383     383 0 613 my $self = shift;
429 383 50       1018 if (my $k = shift) {
430 0 0       0 $self->{$k} = shift if @_;
431 0 0       0 return exists $self->{$k} ? $self->{$k} : $self->{_form}->$k;
432             } else {
433             # exhaustive expansion, but don't invoke validate().
434 383         765 my %ret;
435 383         4578 for my $k (@TAGATTR, keys %$self) {
436 5082         5547 my $v;
437 5082 100 100     21089 next if $k =~ /^_/ || $k eq 'validate'; # don't invoke validate
438 4208 100       11872 if ($k eq 'jsclick') {
    100          
439             # always has to be a special fucking case
440 18         43 $v = $self->{$k};
441 18         119 $k = $self->jstype;
442             } elsif (exists $self->{$k}) {
443             # flat val
444 3134         4979 $v = $self->{$k};
445 3134 100       12785 $v = lc $v if $k eq 'type';
446             } else {
447 1056         4182 $v = $self->$k;
448             }
449 4208 100       8441 next unless defined $v;
450              
451 3441         13722 debug 3, "$self->{name}: \$attr{$k} = '$v'";
452 3441         16826 $ret{$k} = $v;
453             }
454              
455             # More special cases
456             # 1. disabled field/form
457 383 100       1629 $self->disabled ? $ret{disabled} = 'disabled'
458             : delete $ret{disabled};
459              
460             # 2. setup class for stylesheets and JS vars
461 383 100 66     5397 $ret{class} ||= $self->{_form}->class('_'.
462             ($ret{type} eq 'text' ? 'input' : $ret{type})
463             );
464              
465             # 3. useless in all tags
466 383         699 delete $ret{value};
467              
468 383 50       1586 return wantarray ? %ret : \%ret;
469             }
470             }
471              
472             sub multiple {
473 460     460 0 635 my $self = shift;
474 460 50       1050 if (@_) {
475 0         0 $self->{multiple} = shift; # manually set
476 0         0 delete $self->{_cache}{type}; # clear auto-type
477             }
478 460 100       1316 return 'multiple' if $self->{multiple}; # manually set
479 457         1269 my @v = $self->tag_value;
480 457 100       1340 return 'multiple' if @v > 1;
481 413         1146 return;
482             }
483              
484             sub options {
485 760     760 0 1716 my $self = shift;
486 760 50       1807 if (@_) {
487 0         0 $self->{options} = shift; # manually set
488 0         0 delete $self->{_cache}{type}; # clear auto-type
489             }
490 760 100       3257 return unless $self->{options};
491              
492             # align options per internal settings
493 238         919 my @opt = optalign($self->{options});
494              
495             # scalar is just counting length, so skip sort
496 238 100       883 return @opt unless wantarray;
497              
498             # sort if requested
499 171 100       816 @opt = optsort($self->sortopts, @opt) if $self->sortopts;
500              
501 171         972 return @opt;
502             }
503              
504             # per-field messages
505             sub message {
506 4     4 0 8 my $self = shift;
507 4 50       10 $self->{message} = shift if @_;
508 4         8 my $mess = $self->{message};
509 4 50       14 unless ($mess) {
510 4   33     16 my $type = shift || $self->type;
511 4 50       14 my $et = 'form_invalid_' . ($type eq 'text' ? 'input' : $type);
512 4 50       11 $et = 'form_invalid_input' if $self->other; # other fields assume text
513 4   33     32 $mess = sprintf(($self->{_form}{messages}->$et
514             || $self->{_form}{messages}->form_invalid_default), $self->label);
515             }
516 4 50       29 return $self->{_form}{stylesheet}
517             ? qq($mess)
518             : $mess;
519             }
520              
521             sub jsmessage {
522 400     400 0 534 my $self = shift;
523 400 50       832 $self->{jsmessage} = shift if @_;
524 400   33     1719 my $mess = $self->{jsmessage} || $self->{message};
525 400 50       900 unless ($mess) {
526 400   33     1216 my $type = shift || $self->type;
527 400 100       1085 my $et = 'js_invalid_' . ($type eq 'text' ? 'input' : $type);
528 400 100       839 $et = 'js_invalid_input' if $self->other; # other fields assume text
529 400   33     3040 $mess = sprintf(($self->{_form}{messages}->$et
530             || $self->{_form}{messages}->js_invalid_default),
531             $self->label);
532             }
533 400         1585 return $mess
534             }
535              
536             sub comment {
537 383     383 0 665 my $self = shift;
538 383 50       991 $self->{comment} = shift if @_;
539 383   100     2140 my $mess = $self->{comment} || return '';
540 37 100       340 return $self->{_form}{stylesheet}
541             ? qq($mess)
542             : $mess;
543             }
544              
545             # simple error wrapper (why wasn't this here?)
546             sub error {
547 201     201 0 472 my $self = shift;
548 201 100       918 return $self->invalid ? $self->message : '';
549             }
550              
551             sub jstype {
552 18     18 0 36 my $self = shift;
553 18   33     82 my $type = shift || $self->type;
554 18 100 66     129 return ($type eq 'radio' || $type eq 'checkbox') ? 'onclick' : 'onchange';
555             }
556              
557             sub script {
558 3     3 0 5 my $self = shift;
559             #
560             # An unfortunate hack. Sometimes (often?) we don't know the field
561             # type until render(), in which Javascript is generated first. So,
562             # the grandfather (this) of all script() methods just sets the type
563             # by calling $self->type in a void context (which reblesses the object)
564             # and then calling $self->script again. I think this sucks, but then
565             # again this code shouldn't be called that often. Maybe.
566             #
567 3         15 $self->type;
568 3         20 $self->script;
569             }
570              
571             sub jsfield {
572 323     323 0 439 my $self = shift;
573 323         638 my $name = $self->name;
574 323         569 my $pattern = $self->{validate};
575 323         881 debug 2, "return '' unless ".$self->javascript." && ($pattern || ".$self->required.")";
576 323 100 100     854 return '' unless $self->javascript && ($pattern || $self->required);
      33        
577              
578             # First arg is the script that our children should've included
579 77         183 my($jsfunc, $close_brace, $in) = @_;
580 77 50       176 unless ($jsfunc) {
581 0         0 belch "Missing generated \$jsfunc string for $name->jsfield";
582 0         0 return '';
583             }
584              
585 77         271 debug 1, "$name: generating JavaScript validation code";
586              
587             # Special catch, since many would assume this would work
588 77 50       362 if (ref $pattern eq 'Regexp') {
589 0         0 puke "To use a regex in a 'validate' option you must specify ".
590             "it in single quotes, like '/^\\w+\$/' - failed on '$name' field";
591             }
592              
593             # hashref is a grouping per-language
594 77 50       173 if (ref $pattern eq 'HASH') {
595 0   0     0 $pattern = $pattern->{javascript} || return '';
596             }
597              
598             # Check our hash to see if it's a special pattern
599 77 100       248 $pattern = $VALIDATE{$pattern} if $VALIDATE{$pattern};
600              
601             # Make field name JS-safe
602 77         193 my $jsfield = tovar($name);
603              
604             # Note we have to use form.elements['name'] instead of just form.name
605             # as the JAPH using this module may have defined fields like "u.type"
606 77         189 my $alertstr = escapejs($self->jsmessage); # handle embedded '
607 77         119 $alertstr .= '\n';
608              
609             # Our fields are only required if the required option is set
610             # So, if not set, add a not-null check to the if below
611 77 100       487 my $notnull = $self->required
612             ? qq[$jsfield == null ||] # must have or error
613             : qq[$jsfield != null && $jsfield != "" &&]; # only care if filled in
614              
615 77 100 33     656 if ($pattern =~ m#^m?(\S)(.*)\1$#) {
    100 33        
    50 33        
616             # JavaScript regexp
617 39         135 ($pattern = $2) =~ s/\\\//\//g;
618 39         74 $pattern =~ s/\//\\\//g;
619 39         139 $jsfunc .= qq[${in}if ($notnull ! $jsfield.match(/$pattern/)) {\n];
620             }
621             elsif (ref $pattern eq 'ARRAY') {
622             # Must be w/i this set of values
623             # Can you figure out how this piece of Perl works? No, seriously, I forgot.
624 2         13 $jsfunc .= qq[${in}if ($notnull ($jsfield != ']
625 2         11 . join("' && $jsfield != '", @{$pattern}) . "')) {\n";
626             }
627             elsif (ref $pattern eq 'CODE' || $pattern eq 'VALUE' || ($self->required && ! $pattern)) {
628             # Not null (for required sub refs, just check for a value)
629 36         120 $jsfunc .= qq[${in}if ($notnull $jsfield === "") {\n];
630             }
631             else {
632             # Literal string is literal code to execute, but provide
633             # a warning just in case
634 0 0       0 belch "Validation string '$pattern' may be a typo of a builtin pattern"
635             if $pattern =~ /^[A-Z]+$/;
636 0         0 $jsfunc .= qq[${in}if ($notnull $jsfield $pattern) {\n];
637             }
638              
639             # add on our alert message, but only if it's required
640 77         309 $jsfunc .= <
641             $in alertstr += '$alertstr';
642             $in invalid++;
643             $in invalid_fields.push('$jsfield');
644             $in}$close_brace
645             EOJS
646              
647 77         423 return $jsfunc;
648             }
649              
650             *render = \&tag;
651             sub tag {
652 207     207 1 377 my $self = shift;
653 207         529 $self->type;
654 207         1175 return $self->tag(@_);
655             }
656              
657             sub validate () {
658              
659             # This function does all the validation on the Perl side.
660             # It doesn't generate JavaScript; see render() for that...
661              
662 41     41 1 57 my $self = shift;
663 41         62 my $form = $self->{_form}; # alias for examples (paint-by-numbers)
664 41         108 local $^W = 0; # -w sucks
665              
666 41   66     172 my $pattern = shift || $self->{validate};
667 41         80 my $field = $self->name;
668              
669             # inflation subref?
670 41 50       110 my $inflate = (exists $self->{inflate}) ? $self->{inflate} : undef;
671 41 50 33     102 puke("$field: inflate attribute must be subroutine reference")
672             if defined $inflate && ref $inflate ne 'CODE';
673 41 50 33     93 puke("$field: inflate requires a validation pattern")
674             if defined $inflate && !defined $pattern;
675 41 50       79 $self->{inflated_values} = [ ] if $inflate;
676              
677 41         187 debug 1, "$self->{name}: called \$field->validate(@_) for field '$field'";
678              
679             # Check our hash to see if it's a special pattern
680 41 100       164 ($pattern) = autodata($VALIDATE{$pattern}) if $VALIDATE{$pattern};
681              
682             # Hashref is a grouping per-language
683 41 100       98 if (ref $pattern eq 'HASH') {
684 2   50     9 $pattern = $pattern->{perl} || return 1;
685             }
686              
687             # Counter for fail or success
688 41         50 my $bad = 0;
689              
690             # Loop thru, and if something isn't valid, we tag it
691 41         43 my $atleastone = 0;
692 41   50     169 $self->{invalid} ||= 0;
693 41         91 for my $value ($self->value) {
694 60         79 my $thisfail = 0;
695              
696             # only continue if field is required or filled in
697 60 100       238 if ($self->required) {
698 48         140 debug 1, "$field: is required per 'required' param";
699             } else {
700 12         43 debug 1, "$field: is optional per 'required' param";
701 12 100 100     72 next unless length($value) && defined($pattern);
702 2         10 debug 1, "$field: ...but is defined, so still checking";
703             }
704              
705 50         84 $atleastone++;
706 50         187 debug 1, "$field: validating ($value) against pattern '$pattern'";
707              
708 50 100 66     381 if ($pattern =~ m#^m(\S)(.*)\1$# || $pattern =~ m#^(/)(.*)\1$#) {
    100          
    100          
    100          
    100          
709             # it be a regexp, handle / escaping
710 18         79 (my $tpat = $2) =~ s#\\/#/#g;
711 18         31 $tpat =~ s#/#\\/#g;
712 18         75 debug 2, "$field: does '$value' =~ /$tpat/ ?";
713 18 100       4678 unless ($value =~ /$tpat/) {
714 3         12 $thisfail = ++$bad;
715             }
716             } elsif (ref $pattern eq 'ARRAY') {
717             # must be w/i this set of values
718 8         11 debug 2, "$field: is '$value' in (@{$pattern}) ?";
  8         30  
719 8 100       9 unless (ismember($value, @{$pattern})) {
  8         19  
720 5         6 $thisfail = ++$bad;
721             }
722             } elsif (ref $pattern eq 'CODE') {
723             # eval that mofo, which gives them $form
724 10   33     39 my $extra = $form->{c} || $form;
725 10         56 debug 2, "$field: does $pattern($value, $extra) ret true ?";
726 10 50       14 unless (&{$pattern}($value, $extra)) {
  10         26  
727 0         0 $thisfail = ++$bad;
728             }
729             } elsif ($pattern eq 'VALUE') {
730             # Not null
731 1         6 debug 2, "$field: length '$value' > 0 ?";
732 1 50 33     11 unless (defined($value) && length($value)) {
733 0         0 $thisfail = ++$bad;
734             }
735             } elsif (! defined $pattern) {
736 9         38 debug 2, "$field: length('$value') > 0";
737 9 100       28 $thisfail = ++$bad unless length($value) > 0;
738             } else {
739             # literal string is a literal comparison, but warn of typos...
740 4 50       20 belch "Validation string '$pattern' may be a typo of a builtin pattern"
741             if ($pattern =~ /^[A-Z]+$/);
742             # must reference to prevent serious problem if $value = "'; system 'rm -f /'; '"
743 4         22 debug 2, "$field: '$value' $pattern ? 1 : 0";
744 4 50       452 unless (eval qq(\$value $pattern ? 1 : 0)) {
745 0         0 $thisfail = ++$bad;
746             }
747 4 50       22 belch "Literal code eval error in validate: $@" if $@;
748             }
749              
750             # Just for debugging's sake
751 50 100       338 $thisfail ? debug 2, "$field: pattern FAILED"
752             : debug 2, "$field: pattern passed";
753            
754             # run inflation subref if defined, trap errors and warn
755 50 50       153 if (defined $inflate) {
756 0         0 debug 1, "trying to inflate value '$value'";
757 0         0 my $inflated_value = eval { $inflate->($value) };
  0         0  
758 0 0       0 if ($@) {
759 0         0 belch "Field $field: inflate failed on value '$value' due to '$@'";
760 0         0 $thisfail = ++$bad;
761             }
762             # cache for value():
763 0         0 push @{$self->{inflated_values}}, $inflated_value;
  0         0  
764              
765             # debugging:
766 0 0       0 $thisfail ? debug 2, "$field: inflate FAILED"
767             : debug 2, "$field: inflate passed";
768             }
769             }
770              
771             # If not $atleastone and they asked for validation, then we
772             # know that we have an error since this means no values
773 41 100 66     243 if ($bad || (! $atleastone && $self->required)) {
      66        
774 6         28 debug 1, "$field: validation FAILED";
775 6   50     22 $self->{invalid} = $bad || 1;
776 6         16 $self->{missing} = $atleastone;
777 6         42 return;
778             } else {
779 35         115 debug 1, "$field: validation passed";
780 35         78 delete $self->{invalid}; # in case of previous run
781 35         56 delete $self->{missing}; # ditto
782 35         208 return 1;
783             }
784             }
785              
786             sub static () {
787 1551     1551 0 1876 my $self = shift;
788 1551 50       3330 $self->{static} = shift if @_;
789 1551 100       4159 return $self->{static} if exists $self->{static};
790             # check parent for this as well
791 1543         6118 return $self->{_form}{static};
792             }
793              
794             sub disabled () {
795 383     383 0 614 my $self = shift;
796 383 50       881 $self->{disabled} = shift if @_;
797 383 50       1161 return ($self->{disabled} ? 'disabled' : undef)
    100          
798             if exists $self->{disabled};
799             # check parent for this as well
800 375         1585 return $self->{_form}->disabled;
801             }
802              
803             sub javascript () {
804 688     688 0 787 my $self = shift;
805 688 50       1378 $self->{javascript} = shift if @_;
806 688 50       1592 return $self->{javascript} if exists $self->{javascript};
807             # check parent for this as well
808 688         5423 return $self->{_form}{javascript};
809             }
810              
811             sub growable () {
812 1541     1541 0 2157 my $self = shift;
813 1541 50       2965 $self->{growable} = shift if @_;
814 1541 100       8158 return unless $self->{growable};
815             # check to make sure we're only a text or file type
816 26 50 33     52 unless ($self->type eq 'text' || $self->type eq 'file') {
817 0         0 belch "The 'growable' option only works with 'text' or 'file' fields";
818 0         0 return;
819             }
820 26         150 return $self->{growable};
821             }
822              
823             sub name () {
824 9659     9659 0 12541 my $self = shift;
825 9659 50       26455 $self->{name} = shift if @_;
826 9659 50       20561 confess "[".__PACKAGE__."::name] Fatal: Attempt to manipulate unnamed field"
827             unless exists $self->{name};
828 9659         50700 return $self->{name};
829             }
830              
831 333     333   5345 sub DESTROY { 1 }
832              
833             sub AUTOLOAD {
834             # This allows direct addressing by name, for quicker usage
835 10351     10351   14080 my $self = shift;
836 10351         42629 my($name) = $AUTOLOAD =~ /.*::(.+)/;
837              
838 10351         42836 debug 3, "-> dispatch to \$field->{$name} = @_";
839 10351 50       23988 croak "self not ref in AUTOLOAD" unless ref $self; # nta
840              
841 10351 100       19323 $self->{$name} = shift if @_;
842 10351         52553 return $self->{$name};
843             }
844              
845             1;
846             __END__