File Coverage

lib/CGI/FormBuilder/Field.pm
Criterion Covered Total %
statement 345 394 87.5
branch 184 266 69.1
condition 70 128 54.6
subroutine 42 44 95.4
pod 11 32 34.3
total 652 864 75.4


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