File Coverage

lib/CGI/FormBuilder/Field.pm
Criterion Covered Total %
statement 348 397 87.6
branch 185 268 69.0
condition 72 128 56.2
subroutine 42 44 95.4
pod 11 32 34.3
total 658 869 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   72 use Carp; # confess used manually in this pkg
  11         21  
  11         838  
47 11     11   88 use strict;
  11         19  
  11         267  
48 11     11   48 use warnings;
  11         16  
  11         535  
49 11     11   49 no warnings 'uninitialized';
  11         20  
  11         536  
50              
51 11     11   59 use CGI::FormBuilder::Util;
  11         16  
  11         4148  
52              
53             our $VERSION = '3.20';
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   13204 use overload '""' => sub { $_[0]->name },
102             #'.' => sub { $_[0]->name },
103 0     0   0 '0+' => sub { $_[0]->name },
104 226     226   462 'bool' => sub { $_[0]->name },
105 11     11   6847 'eq' => sub { $_[0]->name eq $_[1] };
  11     3   18822  
  11         162  
  3         6  
106              
107             sub new {
108 346 50   346 1 801 puke "Not enough arguments for Field->new()" unless @_ > 1;
109 346         552 my $self = shift;
110              
111 346         543 my $form = shift; # need for top-level attr
112 346         783 my $opt = arghash(@_);
113 346         788 $opt->{_form} = $form; # parental ptr
114             puke "Missing name for field() in Field->new()"
115 346 50       880 unless $opt->{name};
116              
117 346   33     1052 my $class = ref($self) || $self;
118 346         821 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         863 return $f;
126             }
127              
128             sub field {
129 181     181 1 305 my $self = shift;
130              
131 181 100 66     758 if (ref $_[0] || @_ > 1) {
132 152         395 my $opt = arghash(@_);
133 152         699 while (my($k,$v) = each %$opt) {
134 215 50       502 next if $k eq 'name'; # segfault??
135 215         1056 $self->{$k} = $v;
136             }
137             }
138 181         480 return $self->value; # needed for @v = $form->field('name')
139             }
140              
141             *override = \&force; # CGI.pm
142             sub force {
143 1245     1245 0 2037 my $self = shift;
144 1245 50       2448 $self->{force} = shift if @_;
145 1245   66     5862 return $self->{force} || $self->{override};
146             }
147              
148             # grab the field_other field if other => 1 specified
149             sub other {
150 2349     2349 0 3641 my $self = shift;
151 2349 50       4685 $self->{other} = shift if @_;
152 2349 100       8384 return unless $self->{other};
153 95 100       181 $self->{other} = {} unless ref $self->{other};
154 95         167 $self->{other}{name} = $self->othername;
155 95 50       394 return wantarray ? %{$self->{other}} : $self->{other};
  0         0  
156             }
157              
158             sub othername {
159 329     329 0 461 my $self = shift;
160 329         1390 return $self->{_form}->othername . '_' . $self->name;
161             }
162              
163             sub othertag {
164 7     7 0 13 my $self = shift;
165 7 50       13 return '' unless $self->other;
166              
167             # add an additional tag for our _other field
168 7         13 my $oa = $self->other; # other attr
169              
170             # default settings
171 7   100     33 $oa->{type} ||= 'text';
172 7         15 my $v = $self->{_form}->cgi_param($self->othername);
173             #$v = $self->tag_value unless defined $v;
174 7 100 66     139 if ($self->sticky and defined $v) {
175 1         3 $oa->{value} = $v;
176             }
177              
178 7 100 100     18 $oa->{disabled} = 'disabled' if $self->javascript && ! defined $v; # fanciness
179 7         18 return htmltag('input', $oa);
180             }
181              
182             sub growname {
183 2     2 0 2 my $self = shift;
184 2         16 return $self->{_form}->growname . '_' . $self->name;
185             }
186              
187             sub cgi_value {
188 1222     1222 1 2005 my $self = shift;
189 1222         3655 debug 2, "$self->{name}: called \$field->cgi_value";
190 1222 50       2666 puke "Cannot set \$field->cgi_value manually" if @_;
191 1222 50       7162 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         6230 for my $v (@v) {
193 179 100 66     456 if ($self->other && $v eq $self->othername) {
194 6         18 debug 1, "$self->{name}: redoing value from _other field";
195 6         16 $v = $self->{_form}{params}->param($self->othername);
196             }
197             }
198 173         416 local $" = ',';
199 173         684 debug 2, "$self->{name}: cgi value = (@v)";
200 173 50       691 return wantarray ? @v : $v[0];
201             }
202 1049         33837 return;
203             }
204              
205             sub def_value {
206 1181     1181 1 1952 my $self = shift;
207 1181         3806 debug 2, "$self->{name}: called \$field->def_value";
208 1181 50       2513 if (@_) {
209 0         0 $self->{value} = arglist(@_); # manually set
210 0         0 delete $self->{_cache}{type}; # clear auto-type
211             }
212 1181         3912 my @v = autodata $self->{value};
213 1181         3382 local $" = ',';
214 1181         4595 debug 2, "$self->{name}: def value = (@v)";
215 1181         3725 $self->inflate_value(\@v);
216 1181 100       4686 return wantarray ? @v : $v[0];
217             }
218              
219             sub inflate_value {
220 1248     1248 0 2694 my ($self, $v_aref) = @_;
221              
222 1248         3791 debug 2, "$self->{name}: called \$field->inflate_value";
223              
224             # trying to inflate?
225 1248 100       3044 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       4 return if grep { ((caller($_))[3] eq 'CGI::FormBuilder::Field::validate') }
  4         20  
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       10 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     24 if ($cache && ref $cache eq 'ARRAY' && @{$cache}) {
  1   66     3  
241             # could have been cached by validate() check
242 1         2 @{ $v_aref } = @{ $self->{inflated_values} };
  1         3  
  1         1  
243 1         13 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       4 if ref $self->{inflate} ne 'CODE';
251              
252 1         2 eval { @{ $v_aref } = map $self->{inflate}->($_), @{ $v_aref } };
  1         1  
  1         12  
  1         5  
253              
254             # no choice but to die hard if didn't validate() first
255 1 50       2 puke("Field $self->{name}: inflate failed: $@") if $@;
256              
257             # cache the result:
258 1         2 @{ $self->{inflated_values} } = @{ $v_aref };
  1         3  
  1         1  
259             }
260 2         4 return;
261             }
262              
263             # CGI.pm happiness
264             *default = \&value;
265             *defaults = \&value;
266             *values = \&value;
267             sub value {
268 277     277 1 469 my $self = shift;
269 277         1112 debug 2, "$self->{name}: called \$field->value(@_)";
270 277 50       616 if (@_) {
271 0         0 $self->{value} = arglist(@_); # manually set
272 0         0 delete $self->{_cache}{type}; # clear auto-type
273             }
274 277 100       685 unless ($self->force) {
275             # CGI wins if stickiness is set
276 265         831 debug 2, "$self->{name}: sticky && ! force";
277 265 100       612 if (my @v = $self->cgi_value) {
278 67         99 local $" = ',';
279 67         206 debug 1, "$self->{name}: returning value (@v)";
280 67         178 $self->inflate_value(\@v);
281 67 100       331 return wantarray ? @v : $v[0];
282             }
283             }
284 210         616 debug 2, "no cgi found, returning def_value";
285             # no CGI value, or value was forced, or not sticky
286 210         540 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 1807 my $self = shift;
292 1041         3408 debug 2, "$self->{name}: called \$field->tag_value";
293 1041 50       2383 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       2508 return $self->{tag_value} if $self->{tag_value};
299              
300 1041 100 100     4800 if ($self->sticky && ! $self->force) {
301             # CGI wins if stickiness is set
302 957         4444 debug 2, "$self->{name}: sticky && ! force";
303 957 100       2650 if (my @v = $self->cgi_value) {
304 106         229 local $" = ',';
305 106         475 debug 1, "$self->{name}: returning value (@v)";
306 106 50       591 return wantarray ? @v : $v[0];
307             }
308             }
309 935         2987 debug 2, "no cgi found, returning def_value";
310             # no CGI value, or value was forced, or not sticky
311 935         2321 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 4257 local $^W = 0; # -w sucks
328 1334         2128 my $self = shift;
329 1334 50       2885 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     3255 if ($self->static && $self->{type} ne 'hidden') {
342 36         95 $self->{type} = 'static';
343 36         101 delete $self->{_cache}{type}; # forces rebless
344 36         144 debug 2, "setting field type to '$self->{type}'";
345             }
346              
347             # manually set
348 1334         5239 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       6597 return $self->{_cache}{type} if $self->{_cache}{type};
355              
356 234         521 my $name = $self->{name};
357 234         393 my $type;
358 234 100       824 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       1041 if ($self->{_form}->smartness) {
366 166         521 debug 1, "$name: input type not set, checking for options";
367 166 100       448 if (my $n = $self->options) {
    50          
368 51         386 debug 2, "$name: has options, so setting to select|radio|checkbox";
369 51 100       262 if ($n >= $self->selectnum) {
370 15         64 debug 2, "$name: has more than selectnum (", $self->selectnum,
371             ") options, setting to 'select'";
372 15         34 $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         117 my @v = $self->def_value; # only on manual, not dubious CGI
378 36 100 66     121 if ($self->multiple || @v > 1 || $n == 1) {
      100        
379 8         36 debug 2, "$name: has multiple select < selectnum, setting to 'checkbox'";
380 8         21 $type = 'checkbox';
381             } else {
382 28         110 debug 2, "$name: has singular select < selectnum, setting to 'radio'";
383 28         67 $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         267 debug 2, "no options found";
400             }
401             }
402 166   100     611 $type ||= 'text'; # default if no fancy settings matched or no smartness
403             }
404 234         851 debug 1, "$name: field set to type '$type' (reblessing)";
405              
406             # Store type in cache for speediness
407 234         669 $self->{_cache}{type} = $type;
408              
409             # Re-bless into the appropriate package
410 234         421 my $pkg = __PACKAGE__ . '::' . $type;
411 234         586 $pkg =~ s/\-/_/g; # handle HTML5 type names ala 'datetime-local'
412 234         20112 eval "require $pkg";
413 234 50       1195 puke "Can't load $pkg for field '$name' (type '$type'): $@" if $@;
414 234         670 bless $self, $pkg;
415              
416 234         932 return $type;
417             }
418              
419             sub label {
420 774     774 1 1304 my $self = shift;
421 774 50       1639 $self->{label} = shift if @_;
422 774 100       2099 return $self->{label} if defined $self->{label}; # manually set
423 692         1480 return toname($self->name);
424             }
425              
426             sub attr {
427 383     383 0 740 my $self = shift;
428 383 50       949 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         615 my %ret;
434 383         2935 for my $k (@TAGATTR, keys %$self) {
435 5082         7318 my $v;
436 5082 100 100     16899 next if $k =~ /^_/ || $k eq 'validate'; # don't invoke validate
437 4208 100       9815 if ($k eq 'jsclick') {
    100          
438             # always has to be a special fucking case
439 18         37 $v = $self->{$k};
440 18         88 $k = $self->jstype;
441             } elsif (exists $self->{$k}) {
442             # flat val
443 3134         5679 $v = $self->{$k};
444 3134 100       6426 $v = lc $v if $k eq 'type';
445             } else {
446 1056         3839 $v = $self->$k;
447             }
448 4208 100       8545 next unless defined $v;
449              
450 3441         11489 debug 3, "$self->{name}: \$attr{$k} = '$v'";
451 3441         9093 $ret{$k} = $v;
452             }
453              
454             # More special cases
455             # 1. disabled field/form
456             $self->disabled ? $ret{disabled} = 'disabled'
457 383 100       1494 : 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     2892 );
463              
464             # 3. useless in all tags
465 383         821 delete $ret{value};
466              
467 383 50       1626 return wantarray ? %ret : \%ret;
468             }
469             }
470              
471             sub multiple {
472 460     460 0 768 my $self = shift;
473 460 50       1043 if (@_) {
474 0         0 $self->{multiple} = shift; # manually set
475 0         0 delete $self->{_cache}{type}; # clear auto-type
476             }
477 460 100       1185 return 'multiple' if $self->{multiple}; # manually set
478 457         1267 my @v = $self->tag_value;
479 457 100       1140 return 'multiple' if @v > 1;
480 413         1159 return;
481             }
482              
483             sub options {
484 760     760 0 1408 my $self = shift;
485 760 50       1594 if (@_) {
486 0         0 $self->{options} = shift; # manually set
487 0         0 delete $self->{_cache}{type}; # clear auto-type
488             }
489 760 100       2688 return unless $self->{options};
490              
491             # align options per internal settings
492 238         713 my @opt = optalign($self->{options});
493              
494             # scalar is just counting length, so skip sort
495 238 100       689 return @opt unless wantarray;
496              
497             # sort if requested
498 171 100       898 @opt = optsort($self->sortopts, @opt) if $self->sortopts;
499              
500 171         803 return @opt;
501             }
502              
503             # per-field messages
504             sub message {
505 4     4 0 9 my $self = shift;
506 4 50       11 $self->{message} = shift if @_;
507 4         12 my $mess = $self->{message};
508 4 50       12 unless ($mess) {
509 4   33     17 my $type = shift || $self->type;
510 4 50       12 my $et = 'form_invalid_' . ($type eq 'text' ? 'input' : $type);
511 4 50       14 $et = 'form_invalid_input' if $self->other; # other fields assume text
512             $mess = $self->{_form}{messages}->$et
513 4   33     29 || $self->{_form}{messages}->form_invalid_default;
514 4 50       17 $mess = sprintf($mess, $self->label) if $mess =~ /%/;
515             }
516             return $self->{_form}{stylesheet}
517 4 50       23 ? qq($mess)
518             : $mess;
519             }
520              
521             sub jsmessage {
522 400     400 0 764 my $self = shift;
523 400 50       866 $self->{jsmessage} = shift if @_;
524 400   33     1533 my $mess = $self->{jsmessage} || $self->{message};
525 400 50       876 unless ($mess) {
526 400   33     1279 my $type = shift || $self->type;
527 400 100       1089 my $et = 'js_invalid_' . ($type eq 'text' ? 'input' : $type);
528 400 100       940 $et = 'js_invalid_input' if $self->other; # other fields assume text
529             $mess = sprintf(($self->{_form}{messages}->$et
530 400   33     2418 || $self->{_form}{messages}->js_invalid_default),
531             $self->label);
532             }
533 400         1346 return $mess
534             }
535              
536             sub comment {
537 383     383 0 647 my $self = shift;
538 383 50       868 $self->{comment} = shift if @_;
539 383   100     2030 my $mess = $self->{comment} || return '';
540             return $self->{_form}{stylesheet}
541 37 100       189 ? qq($mess)
542             : $mess;
543             }
544              
545             # simple error wrapper (why wasn't this here?)
546             sub error {
547 201     201 0 375 my $self = shift;
548 201 100       844 return $self->invalid ? $self->message : '';
549             }
550              
551             sub jstype {
552 18     18 0 32 my $self = shift;
553 18   33     73 my $type = shift || $self->type;
554 18 100 66     95 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         14 $self->type;
568 3         14 $self->script;
569             }
570              
571             sub jsfield {
572 323     323 0 507 my $self = shift;
573 323         648 my $name = $self->name;
574 323         700 my $pattern = $self->{validate};
575 323         864 debug 2, "return '' unless ".$self->javascript." && ($pattern || ".$self->required.")";
576 323 100 100     887 return '' unless $self->javascript && ($pattern || $self->required);
      66        
577              
578             # First arg is the script that our children should've included
579 77         232 my($jsfunc, $close_brace, $in) = @_;
580 77 50       223 unless ($jsfunc) {
581 0         0 belch "Missing generated \$jsfunc string for $name->jsfield";
582 0         0 return '';
583             }
584              
585 77         277 debug 1, "$name: generating JavaScript validation code";
586              
587             # Special catch, since many would assume this would work
588 77 50       195 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       178 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       280 $pattern = $VALIDATE{$pattern} if $VALIDATE{$pattern};
600              
601             # Make field name JS-safe
602 77         191 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         308 my $alertstr = escapejs($self->jsmessage); # handle embedded '
607 77         166 $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       375 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     634 if ($pattern =~ m#^m?(\S)(.*)\1([gimsu]+)?$#) {
    100 33        
    50 33        
616             # JavaScript regexp
617 39         179 ($pattern = $2) =~ s/\\\//\//g;
618 39         110 $pattern =~ s/\//\\\//g;
619 39         241 $jsfunc .= qq[${in}if ($notnull ! $jsfield.match(/$pattern/$3)) {\n];
620             }
621             elsif (ref $pattern eq 'ARRAY') {
622             # Must be w/i this set of values
623             # escape single-quotes in option values
624 2         4 my @options = @{$pattern}; # clone values, don't modify original
  2         8  
625 2         8 s{'}{\\'}g for @options;
626             # the third argument to jsfield,
627             # then check it is not null or empty string,
628             # then make sure it is one of the provided options
629 2         11 $jsfunc .= qq[${in}if ($notnull ($jsfield != ']
630             . join("' && $jsfield != '", @options) . "')) {\n";
631             }
632             elsif (ref $pattern eq 'CODE' || $pattern eq 'VALUE' || ($self->required && ! $pattern)) {
633             # Not null (for required sub refs, just check for a value)
634 36         115 $jsfunc .= qq[${in}if ($notnull $jsfield === "") {\n];
635             }
636             else {
637             # Literal string is literal code to execute, but provide
638             # a warning just in case
639 0 0       0 belch "Validation string '$pattern' may be a typo of a builtin pattern"
640             if $pattern =~ /^[A-Z]+$/;
641 0         0 $jsfunc .= qq[${in}if ($notnull $jsfield $pattern) {\n];
642             }
643              
644             # add on our alert message, but only if it's required
645 77         263 $jsfunc .= <
646             $in alertstr += '$alertstr';
647             $in invalid++;
648             $in invalid_fields.push('$jsfield');
649             $in}$close_brace
650             EOJS
651              
652 77         436 return $jsfunc;
653             }
654              
655             *render = \&tag;
656             sub tag {
657 207     207 1 428 my $self = shift;
658 207         623 $self->type;
659 207         975 return $self->tag(@_);
660             }
661              
662             sub validate () {
663              
664             # This function does all the validation on the Perl side.
665             # It doesn't generate JavaScript; see render() for that...
666              
667 41     41 1 64 my $self = shift;
668 41         77 my $form = $self->{_form}; # alias for examples (paint-by-numbers)
669 41         109 local $^W = 0; # -w sucks
670              
671 41   66     152 my $pattern = shift || $self->{validate};
672 41         78 my $field = $self->name;
673              
674             # inflation subref?
675 41 50       127 my $inflate = (exists $self->{inflate}) ? $self->{inflate} : undef;
676 41 50 33     98 puke("$field: inflate attribute must be subroutine reference")
677             if defined $inflate && ref $inflate ne 'CODE';
678 41 50 33     86 puke("$field: inflate requires a validation pattern")
679             if defined $inflate && !defined $pattern;
680 41 50       76 $self->{inflated_values} = [ ] if $inflate;
681              
682 41         172 debug 1, "$self->{name}: called \$field->validate(@_) for field '$field'";
683              
684             # Check our hash to see if it's a special pattern
685 41 100       141 ($pattern) = autodata($VALIDATE{$pattern}) if $VALIDATE{$pattern};
686              
687             # Hashref is a grouping per-language
688 41 100       90 if (ref $pattern eq 'HASH') {
689 2   50     9 $pattern = $pattern->{perl} || return 1;
690             }
691              
692             # Counter for fail or success
693 41         58 my $bad = 0;
694              
695             # Loop thru, and if something isn't valid, we tag it
696 41         71 my $atleastone = 0;
697 41   50     174 $self->{invalid} ||= 0;
698 41         85 for my $value ($self->value) {
699 60         90 my $thisfail = 0;
700              
701             # only continue if field is required or filled in
702 60 100       243 if ($self->required) {
703 48         120 debug 1, "$field: is required per 'required' param";
704             } else {
705 12         30 debug 1, "$field: is optional per 'required' param";
706 12 100 100     56 next unless length($value) && defined($pattern);
707 2         8 debug 1, "$field: ...but is defined, so still checking";
708             }
709              
710 50         98 $atleastone++;
711 50         200 debug 1, "$field: validating ($value) against pattern '$pattern'";
712              
713 50 100 66     370 if ($pattern =~ m#^m(\S)(.*)\1$# || $pattern =~ m#^(/)(.*)\1$#) {
    100          
    100          
    100          
    100          
714             # it be a regexp, handle / escaping
715 18         75 (my $tpat = $2) =~ s#\\/#/#g;
716 18         43 $tpat =~ s#/#\\/#g;
717 18         59 debug 2, "$field: does '$value' =~ /$tpat/ ?";
718 18 100       1563 unless ($value =~ /$tpat/) {
719 3         12 $thisfail = ++$bad;
720             }
721             } elsif (ref $pattern eq 'ARRAY') {
722             # must be w/i this set of values
723 8         17 debug 2, "$field: is '$value' in (@{$pattern}) ?";
  8         43  
724 8 100       41 unless (ismember($value, @{$pattern})) {
  8         24  
725 5         11 $thisfail = ++$bad;
726             }
727             } elsif (ref $pattern eq 'CODE') {
728             # eval that mofo, which gives them $form
729 10   33     38 my $extra = $form->{c} || $form;
730 10         42 debug 2, "$field: does $pattern($value, $extra) ret true ?";
731 10 50       15 unless (&{$pattern}($value, $extra)) {
  10         30  
732 0         0 $thisfail = ++$bad;
733             }
734             } elsif ($pattern eq 'VALUE') {
735             # Not null
736 1         7 debug 2, "$field: length '$value' > 0 ?";
737 1 50 33     8 unless (defined($value) && length($value)) {
738 0         0 $thisfail = ++$bad;
739             }
740             } elsif (! defined $pattern) {
741 9         30 debug 2, "$field: length('$value') > 0";
742 9 100       25 $thisfail = ++$bad unless length($value) > 0;
743             } else {
744             # literal string is a literal comparison, but warn of typos...
745 4 50       18 belch "Validation string '$pattern' may be a typo of a builtin pattern"
746             if ($pattern =~ /^[A-Z]+$/);
747             # must reference to prevent serious problem if $value = "'; system 'rm -f /'; '"
748 4         20 debug 2, "$field: '$value' $pattern ? 1 : 0";
749 4 50       387 unless (eval qq(\$value $pattern ? 1 : 0)) {
750 0         0 $thisfail = ++$bad;
751             }
752 4 50       22 belch "Literal code eval error in validate: $@" if $@;
753             }
754              
755             # Just for debugging's sake
756 50 100       276 $thisfail ? debug 2, "$field: pattern FAILED"
757             : debug 2, "$field: pattern passed";
758            
759             # run inflation subref if defined, trap errors and warn
760 50 50       172 if (defined $inflate) {
761 0         0 debug 1, "trying to inflate value '$value'";
762 0         0 my $inflated_value = eval { $inflate->($value) };
  0         0  
763 0 0       0 if ($@) {
764 0         0 belch "Field $field: inflate failed on value '$value' due to '$@'";
765 0         0 $thisfail = ++$bad;
766             }
767             # cache for value():
768 0         0 push @{$self->{inflated_values}}, $inflated_value;
  0         0  
769              
770             # debugging:
771 0 0       0 $thisfail ? debug 2, "$field: inflate FAILED"
772             : debug 2, "$field: inflate passed";
773             }
774             }
775              
776             # If not $atleastone and they asked for validation, then we
777             # know that we have an error since this means no values
778 41 100 66     216 if ($bad || (! $atleastone && $self->required)) {
      66        
779 6         23 debug 1, "$field: validation FAILED";
780 6   50     19 $self->{invalid} = $bad || 1;
781 6         20 $self->{missing} = $atleastone;
782 6         33 return;
783             } else {
784 35         116 debug 1, "$field: validation passed";
785 35         77 delete $self->{invalid}; # in case of previous run
786 35         55 delete $self->{missing}; # ditto
787 35         166 return 1;
788             }
789             }
790              
791             sub static () {
792 1551     1551 0 2399 my $self = shift;
793 1551 50       3272 $self->{static} = shift if @_;
794 1551 100       3545 return $self->{static} if exists $self->{static};
795             # check parent for this as well
796 1543         5057 return $self->{_form}{static};
797             }
798              
799             sub disabled () {
800 383     383 0 698 my $self = shift;
801 383 50       840 $self->{disabled} = shift if @_;
802             return ($self->{disabled} ? 'disabled' : undef)
803 383 50       912 if exists $self->{disabled};
    100          
804             # check parent for this as well
805 375         1448 return $self->{_form}->disabled;
806             }
807              
808             sub javascript () {
809 688     688 0 1014 my $self = shift;
810 688 50       1377 $self->{javascript} = shift if @_;
811 688 50       1458 return $self->{javascript} if exists $self->{javascript};
812             # check parent for this as well
813 688         3582 return $self->{_form}{javascript};
814             }
815              
816             sub growable () {
817 1541     1541 0 2428 my $self = shift;
818 1541 50       6385 $self->{growable} = shift if @_;
819 1541 100       5908 return unless $self->{growable};
820             # check to make sure we're only a text or file type
821 26 50 33     53 unless ($self->type eq 'text' || $self->type eq 'file') {
822 0         0 belch "The 'growable' option only works with 'text' or 'file' fields";
823 0         0 return;
824             }
825 26         106 return $self->{growable};
826             }
827              
828             sub name () {
829 9659     9659 0 14308 my $self = shift;
830 9659 50       18724 $self->{name} = shift if @_;
831             confess "[".__PACKAGE__."::name] Fatal: Attempt to manipulate unnamed field"
832 9659 50       19542 unless exists $self->{name};
833 9659         33500 return $self->{name};
834             }
835              
836 333     333   2891 sub DESTROY { 1 }
837              
838             sub AUTOLOAD {
839             # This allows direct addressing by name, for quicker usage
840 10351     10351   16401 my $self = shift;
841 10351         41637 my($name) = $AUTOLOAD =~ /.*::(.+)/;
842              
843 10351         35607 debug 3, "-> dispatch to \$field->{$name} = @_";
844 10351 50       20821 croak "self not ref in AUTOLOAD" unless ref $self; # nta
845              
846 10351 100       19528 $self->{$name} = shift if @_;
847 10351         39231 return $self->{$name};
848             }
849              
850             1;
851             __END__