blib/lib/XAO/DO/Web/FilloutForm.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 54 | 426 | 12.6 |
branch | 15 | 346 | 4.3 |
condition | 4 | 252 | 1.5 |
subroutine | 7 | 27 | 25.9 |
pod | 11 | 17 | 64.7 |
total | 91 | 1068 | 8.5 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | =head1 NAME | ||||||
2 | |||||||
3 | XAO::DO::Web::FilloutForm - support for HTML forms | ||||||
4 | |||||||
5 | =head1 DESCRIPTION | ||||||
6 | |||||||
7 | Fill out form object. Helps to create fill-out forms for registration | ||||||
8 | and so on. Checks that parameters are Ok and then displays either form | ||||||
9 | or thanks. | ||||||
10 | |||||||
11 | Must be overriden with something which will put 'fields' parameter | ||||||
12 | into $self. Format is as array of hash references reference of the | ||||||
13 | following structure: | ||||||
14 | |||||||
15 | [ { name => field name, | ||||||
16 | required => 0 || 1, | ||||||
17 | style => selection || text || textarea || email || phone || | ||||||
18 | integer || dollars || real, | ||||||
19 | maxlength => maximum length, | ||||||
20 | minlength => minimum length, | ||||||
21 | param => name of parameter for form substitution, | ||||||
22 | text => description of parameter, | ||||||
23 | }, | ||||||
24 | { ... } | ||||||
25 | ] | ||||||
26 | |||||||
27 | If you do not care in what order fields are checked you can also | ||||||
28 | supply 'fields' as a hash reference: | ||||||
29 | |||||||
30 | { name => { | ||||||
31 | required => 0 || 1, | ||||||
32 | style => selection || text || textarea || email || phone || | ||||||
33 | integer || dollars || real, | ||||||
34 | maxlength => maximum length, | ||||||
35 | minlength => minimum length, | ||||||
36 | param => name of parameter for form substitution, | ||||||
37 | text => description of parameter, | ||||||
38 | }, | ||||||
39 | name1 => { ... } | ||||||
40 | } | ||||||
41 | |||||||
42 | When form filled out "form_ok" method is called, which must be | ||||||
43 | overridden in inherited object to do something good with | ||||||
44 | results. Alternatively reference to subroutine can be given through | ||||||
45 | 'setup' method. This is suitable for using FilloutForm object without | ||||||
46 | overriding it. | ||||||
47 | |||||||
48 | Displays form with PARAM.VALUE set to value, PARAM.NAME - to name, | ||||||
49 | PARAM.TEXT - to text, PARAM.REQUIRED to the 0/1 required flag, and | ||||||
50 | PARAM.HTML - to piece of HTML code if applicable (Country selection for | ||||||
51 | example). | ||||||
52 | |||||||
53 | =head1 METHODS | ||||||
54 | |||||||
55 | =over | ||||||
56 | |||||||
57 | =cut | ||||||
58 | |||||||
59 | ############################################################################### | ||||||
60 | package XAO::DO::Web::FilloutForm; | ||||||
61 | 1 | 1 | 738 | use strict; | |||
1 | 2 | ||||||
1 | 29 | ||||||
62 | 1 | 1 | 5 | use XAO::Utils qw(:args :debug :html); | |||
1 | 1 | ||||||
1 | 219 | ||||||
63 | 1 | 1 | 6 | use XAO::Errors qw(XAO::DO::Web::FilloutForm); | |||
1 | 1 | ||||||
1 | 6 | ||||||
64 | 1 | 1 | 337 | use base XAO::Objects->load(objname => 'Web::Page'); | |||
1 | 2 | ||||||
1 | 4 | ||||||
65 | |||||||
66 | our $VERSION='2.029'; | ||||||
67 | |||||||
68 | sub setup ($%); | ||||||
69 | sub field_desc ($$;$); | ||||||
70 | sub field_names ($); | ||||||
71 | sub display ($;%); | ||||||
72 | sub form_ok ($%); | ||||||
73 | sub form_phase ($); | ||||||
74 | sub check_form ($%); | ||||||
75 | sub pre_check_form ($%); | ||||||
76 | sub countries_list (); | ||||||
77 | sub us_continental_states_list (); | ||||||
78 | sub us_states_list (); | ||||||
79 | sub cc_list ($); | ||||||
80 | sub cc_validate ($%); | ||||||
81 | sub calculate_year ($$); | ||||||
82 | |||||||
83 | ############################################################################### | ||||||
84 | |||||||
85 | =item new (%) | ||||||
86 | |||||||
87 | Overrided new method for those who prefer to use inheritance style. | ||||||
88 | |||||||
89 | =cut | ||||||
90 | |||||||
91 | sub new ($%) { | ||||||
92 | 1 | 1 | 1 | 16 | my $proto=shift; | ||
93 | 1 | 33 | 5 | my $class=ref($proto) || $proto; | |||
94 | 1 | 4 | my $args=get_args(\@_); | ||||
95 | 1 | 17 | my $self=$proto->SUPER::new($args); | ||||
96 | |||||||
97 | # Setting up fields if required | ||||||
98 | # | ||||||
99 | $self->setup_fields(fields => $args->{'fields'}, | ||||||
100 | 1 | 50 | 27 | values => $args->{'values'}) if $args->{'fields'}; | |||
101 | |||||||
102 | # Done | ||||||
103 | # | ||||||
104 | 1 | 2 | $self; | ||||
105 | } | ||||||
106 | |||||||
107 | |||||||
108 | ############################################################################### | ||||||
109 | |||||||
110 | # Setting object up for use as embedded form checker from other | ||||||
111 | # non-derived objects. | ||||||
112 | # | ||||||
113 | # Arguments are: | ||||||
114 | # fields => fields descriptions | ||||||
115 | # values => values for fields, unless this is set all values | ||||||
116 | # are cleaned | ||||||
117 | # extra_data => reference to any data, subroutines will then be | ||||||
118 | # able to access it. | ||||||
119 | # form_ok => form_ok subroutine reference (mandatory) | ||||||
120 | # pre_check_form => pre_check_form subroutine reference | ||||||
121 | # check_form => check_form subroutine reference | ||||||
122 | # submit_name => name of the submit button | ||||||
123 | # keep_form => display form template even when the form is complete | ||||||
124 | # | ||||||
125 | # Call to this subroutine is not required from derived objects, use | ||||||
126 | # method overriding instead when possible! | ||||||
127 | # | ||||||
128 | |||||||
129 | sub setup ($%) { | ||||||
130 | 0 | 0 | 0 | 0 | my $self=shift; | ||
131 | 0 | 0 | my $args=get_args(\@_); | ||||
132 | |||||||
133 | # Fields and values | ||||||
134 | # | ||||||
135 | $self->setup_fields( | ||||||
136 | fields => $args->{'fields'}, | ||||||
137 | 0 | 0 | values => $args->{'values'}, | ||||
138 | ); | ||||||
139 | |||||||
140 | # Handlers and special data: | ||||||
141 | # extra_data - passed to handlers as is. | ||||||
142 | # submit_name - name of submit button for pre-filled forms (change form). | ||||||
143 | # dont_sanitize - don't remove <> from CGI input | ||||||
144 | # | ||||||
145 | 0 | 0 | my @names=qw(extra_data submit_name form_ok pre_check_form check_form keep_form dont_sanitize); | ||||
146 | 0 | 0 | @{$self}{@names}=@{$args}{@names}; | ||||
0 | 0 | ||||||
0 | 0 | ||||||
147 | |||||||
148 | 0 | 0 | 0 | my $values=$args->{'values'} || {}; | |||
149 | 0 | 0 | foreach my $fdata (@{$self->{'fields'}}) { | ||||
0 | 0 | ||||||
150 | 0 | 0 | $fdata->{'value'}=$values->{$fdata->{'name'}}; | ||||
151 | } | ||||||
152 | } | ||||||
153 | |||||||
154 | ############################################################################### | ||||||
155 | |||||||
156 | =item setup_fields (%) | ||||||
157 | |||||||
158 | Copying fields descriptions. We copy entire structure here because it | ||||||
159 | could be persistent and we do not want original data to be modified. | ||||||
160 | |||||||
161 | =cut | ||||||
162 | |||||||
163 | sub setup_fields ($%) { | ||||||
164 | 0 | 0 | 1 | 0 | my $self=shift; | ||
165 | 0 | 0 | my $args=get_args(\@_); | ||||
166 | 0 | 0 | my $fields=$args->{'fields'}; | ||||
167 | 0 | 0 | 0 | 0 | return unless $fields && ref($fields); | ||
168 | |||||||
169 | 0 | 0 | my $values=$args->{'values'}; | ||||
170 | 0 | 0 | my @copy; | ||||
171 | 0 | 0 | 0 | foreach my $fdata (ref($fields) eq 'ARRAY' ? @{$fields} | |||
0 | 0 | ||||||
172 | 0 | 0 | : keys %{$fields}) { | ||||
173 | 0 | 0 | my $name; | ||||
174 | 0 | 0 | 0 | if(! ref($fdata)) { | |||
175 | 0 | 0 | $name=$fdata; | ||||
176 | 0 | 0 | $fdata=$fields->{$name}; | ||||
177 | 0 | 0 | $fdata->{'name'}=$name; | ||||
178 | } | ||||||
179 | else { | ||||||
180 | 0 | 0 | $name=$fdata->{'name'}; | ||||
181 | } | ||||||
182 | |||||||
183 | 0 | 0 | my %cd; | ||||
184 | 0 | 0 | @cd{keys %{$fdata}}=values %{$fdata}; | ||||
0 | 0 | ||||||
0 | 0 | ||||||
185 | 0 | 0 | 0 | 0 | $cd{'value'}=$values->{$name} if $values && $values->{$name}; | ||
186 | 0 | 0 | push(@copy,\%cd); | ||||
187 | } | ||||||
188 | |||||||
189 | 0 | 0 | $self->{'fields'}=\@copy; | ||||
190 | } | ||||||
191 | |||||||
192 | ############################################################################### | ||||||
193 | |||||||
194 | =item display (%) | ||||||
195 | |||||||
196 | Displaying the form. | ||||||
197 | |||||||
198 | =cut | ||||||
199 | |||||||
200 | sub display ($;%) { | ||||||
201 | 0 | 0 | 1 | 0 | my $self=shift; | ||
202 | 0 | 0 | my $args=get_args(\@_); | ||||
203 | 0 | 0 | my $cgi=$self->cgi; | ||||
204 | 0 | 0 | my $fields=$self->{'fields'}; | ||||
205 | 0 | 0 | 0 | $fields || throw XAO::E::DO::Web::FilloutForm | |||
206 | "display - has not set fields for FilloutForm"; | ||||||
207 | 0 | 0 | my $phase=$self->{'phase'}=$args->{'phase'}; | ||||
208 | 0 | 0 | 0 | $self->{'submit_name'}=$args->{'submit_name'} if $args->{'submit_name'}; | |||
209 | |||||||
210 | # Checking the type of fields argument we have - hash or | ||||||
211 | # array? Converting to array if it is a hash. | ||||||
212 | # | ||||||
213 | 0 | 0 | 0 | if(ref($fields) eq 'HASH') { | |||
214 | 0 | 0 | my @newf; | ||||
215 | 0 | 0 | foreach my $name (keys %{$fields}) { | ||||
0 | 0 | ||||||
216 | 0 | 0 | $fields->{$name}->{'name'}=$name; | ||||
217 | 0 | 0 | push @newf,$fields->{$name}; | ||||
218 | } | ||||||
219 | 0 | 0 | $self->{'fields'}=$fields=\@newf; | ||||
220 | } | ||||||
221 | |||||||
222 | # Pre-checking form with external overridable function. | ||||||
223 | # | ||||||
224 | 0 | 0 | $self->pre_check_form($args); | ||||
225 | |||||||
226 | # Displayable object | ||||||
227 | # | ||||||
228 | 0 | 0 | my $obj=$self->object; | ||||
229 | |||||||
230 | # Special parameter named 'submit_name' contains submit button name | ||||||
231 | # and used for pre-filled forms - these forms usually already have | ||||||
232 | # valid data and we need some way to know when the form was really | ||||||
233 | # checked and corrected by user. | ||||||
234 | # | ||||||
235 | 0 | 0 | my $have_cgivalues=0; | ||||
236 | 0 | 0 | my $have_submit=1; | ||||
237 | 0 | 0 | 0 | if($self->{'submit_name'}) { | |||
238 | $have_submit=($cgi->param($self->{'submit_name'}) || | ||||||
239 | $cgi->param($self->{'submit_name'}.'.x') || | ||||||
240 | 0 | 0 | 0 | 0 | $cgi->param($self->{'submit_name'}.'.y') | ||
241 | ) ? 1 : 0; | ||||||
242 | 0 | 0 | $have_cgivalues=$have_submit; | ||||
243 | } | ||||||
244 | |||||||
245 | # First checking all parameters and collecting mistakes into errstr. | ||||||
246 | # | ||||||
247 | # Also creating hash with parameters for form diplaying while we are | ||||||
248 | # going through fields anyway. | ||||||
249 | # | ||||||
250 | 0 | 0 | my $errstr; | ||||
251 | my %formparams; | ||||||
252 | |||||||
253 | 0 | 0 | 0 | my $dont_sanitize=$self->{'dont_sanitize'} || $args->{'dont_sanitize'}; | |||
254 | |||||||
255 | 0 | 0 | foreach my $fdata (@{$fields}) { | ||||
0 | 0 | ||||||
256 | 0 | 0 | my $name=$fdata->{'name'}; | ||||
257 | |||||||
258 | 0 | 0 | my $cgivalue=$cgi->param($name); | ||||
259 | 0 | 0 | 0 | $have_cgivalues++ if defined($cgivalue); | |||
260 | |||||||
261 | # Unless we have a 'dont_sanitize' argument we remove angle | ||||||
262 | # brackets to prevent XSS attacks. | ||||||
263 | # | ||||||
264 | 0 | 0 | 0 | 0 | if(defined $cgivalue && !$dont_sanitize) { | ||
265 | 0 | 0 | $cgivalue=~s/[<>]/ /sg; | ||||
266 | } | ||||||
267 | |||||||
268 | # Checking form phase for multi-phased forms if required. | ||||||
269 | # | ||||||
270 | 0 | 0 | 0 | 0 | next if defined($fdata->{'phase'}) && $phase<$fdata->{'phase'}; | ||
271 | |||||||
272 | 0 | 0 | my $value=$fdata->{'newvalue'}; | ||||
273 | 0 | 0 | 0 | $value=$cgivalue unless defined($value); | |||
274 | 0 | 0 | 0 | if(!$have_cgivalues) { | |||
275 | 0 | 0 | 0 | $value=$fdata->{'value'} unless defined($value); | |||
276 | 0 | 0 | 0 | $value=$fdata->{'default'} unless defined($value); | |||
277 | } | ||||||
278 | |||||||
279 | # Empty value is the same as undefined. Spaces are trimmed from the | ||||||
280 | # beginning and the end of the string. | ||||||
281 | # | ||||||
282 | 0 | 0 | 0 | $value="" unless defined $value; | |||
283 | 0 | 0 | $value=~s/^\s*(.*?)\s*$/$1/g; | ||||
284 | |||||||
285 | # Various checks depending on field style. | ||||||
286 | # | ||||||
287 | 0 | 0 | my $newerr; | ||||
288 | 0 | 0 | 0 | my $style=$fdata->{'style'} || $fdata->{'type'} || | |||
289 | throw $self "display - no style or type in field '$name'"; | ||||||
290 | 0 | 0 | 0 | 0 | if(!length($value) && $fdata->{'required'}) { | ||
0 | 0 | ||||||
0 | 0 | ||||||
0 | 0 | ||||||
0 | 0 | ||||||
0 | 0 | ||||||
0 | 0 | ||||||
0 | |||||||
0 | |||||||
0 | |||||||
0 | |||||||
0 | |||||||
0 | |||||||
0 | |||||||
0 | |||||||
0 | |||||||
0 | |||||||
0 | |||||||
0 | |||||||
0 | |||||||
291 | 0 | 0 | $newerr=$self->Tx('Required field!'); | ||||
292 | } | ||||||
293 | elsif($fdata->{'maxlength'} && length($value) > $fdata->{'maxlength'}) { | ||||||
294 | 0 | 0 | $newerr=$self->Tx('Value is too long!'); | ||||
295 | } | ||||||
296 | elsif($fdata->{'minlength'} && length($value) && | ||||||
297 | length($value) < $fdata->{'minlength'}) { | ||||||
298 | 0 | 0 | $newerr=$self->Tx("Value is too short!"); | ||||
299 | } | ||||||
300 | elsif($style eq 'text') { | ||||||
301 | # No checks for text | ||||||
302 | } | ||||||
303 | elsif($style eq 'textarea') { | ||||||
304 | # No checks for textarea | ||||||
305 | } | ||||||
306 | elsif($style eq 'file') { | ||||||
307 | 0 | 0 | 0 | if(!$value) { | |||
308 | 0 | 0 | $newerr=$self->Tx("No filename given"); | ||||
309 | } | ||||||
310 | } | ||||||
311 | elsif($style eq 'email') { | ||||||
312 | 0 | 0 | 0 | 0 | if(length($value) && $value !~ /^[\w\.\+\/\$\%\&\`{}'=-]+\@([a-z0-9-]+\.)+[a-z]+$/i) { | ||
313 | 0 | 0 | $newerr=$self->Tx("Value is not in the form of user\@host.domain!"); | ||||
314 | } | ||||||
315 | } | ||||||
316 | elsif($style eq 'usphone') { | ||||||
317 | 0 | 0 | 0 | $fdata->{'maxlength'}=15 unless $fdata->{'maxlength'}; | |||
318 | 0 | 0 | 0 | if(length($value)) { | |||
319 | 0 | 0 | $value =~ s/\D//g; | ||||
320 | 0 | 0 | 0 | if(length($value) == 7) { | |||
0 | |||||||
0 | |||||||
321 | 0 | 0 | $newerr=$self->Tx("Needs area code!"); | ||||
322 | } | ||||||
323 | elsif(length($value) == 11) { | ||||||
324 | 0 | 0 | 0 | if(substr($value,0,1) ne '1') { | |||
325 | 0 | 0 | $newerr=$self->Tx("Must be a US phone!"); | ||||
326 | } | ||||||
327 | } | ||||||
328 | elsif(length($value) != 10) { | ||||||
329 | 0 | 0 | $newerr=$self->Tx("Does not look like a right phone!"); | ||||
330 | } | ||||||
331 | else { | ||||||
332 | 0 | 0 | $value=~s/^.?(...)(...)(....)/($1) $2-$3/; | ||||
333 | } | ||||||
334 | } | ||||||
335 | } | ||||||
336 | elsif($style eq 'phone') { # +99 (123) 456-78-90 x 123 | ||||||
337 | 0 | 0 | 0 | $fdata->{'maxlength'}=30 unless $fdata->{'maxlength'}; | |||
338 | 0 | 0 | 0 | if(length($value)) { | |||
339 | 0 | 0 | my ($p,$e)=split(/[a-zA-Z]+/,$value); | ||||
340 | |||||||
341 | 0 | 0 | $p=~s/\D//g; | ||||
342 | 0 | 0 | 0 | $e||=''; | |||
343 | 0 | 0 | $e=~s/\D//g; | ||||
344 | |||||||
345 | 0 | 0 | 0 | if(length($p)<10) { | |||
0 | |||||||
0 | |||||||
346 | 0 | 0 | $newerr=$self->Tx("Needs area code!"); | ||||
347 | } | ||||||
348 | elsif(length($p)==10) { | ||||||
349 | 0 | 0 | $p='1' . $p; | ||||
350 | } | ||||||
351 | elsif(length($p)>13) { | ||||||
352 | 0 | 0 | $newerr=$self->Tx("Too many digits!"); | ||||
353 | } | ||||||
354 | |||||||
355 | 0 | 0 | 0 | if(!$newerr) { | |||
356 | 0 | 0 | ($value=$p)=~s/^(.+)(...)(...)(....)$/+$1 ($2) $3-$4/; | ||||
357 | 0 | 0 | 0 | $value.=" ext. $e" if $e; | |||
358 | } | ||||||
359 | } | ||||||
360 | } | ||||||
361 | elsif($style eq 'int' || $style eq 'integer' || $style eq 'number') { | ||||||
362 | 0 | 0 | 0 | if(length($value)) { | |||
363 | 0 | 0 | 0 | if($value =~ /^-?[\d,']+$/) { | |||
364 | 0 | 0 | $value=~s/[,']+//g; | ||||
365 | 0 | 0 | 0 | 0 | if(defined($fdata->{'minvalue'}) && $value<$fdata->{'minvalue'}) { | ||
366 | $newerr=$self->Tx("Value is less than {{min}}", | ||||||
367 | 0 | 0 | { min => $fdata->{'minvalue'} }); | ||||
368 | } | ||||||
369 | 0 | 0 | 0 | 0 | if(defined($fdata->{'maxvalue'}) && $value>$fdata->{'maxvalue'}) { | ||
370 | $newerr=$self->Tx("Value is greater than {{max}}", | ||||||
371 | 0 | 0 | { max => $fdata->{'maxvalue'} }); | ||||
372 | } | ||||||
373 | } | ||||||
374 | else { | ||||||
375 | 0 | 0 | $newerr=$self->Tx("Is not an integer!"); | ||||
376 | } | ||||||
377 | } | ||||||
378 | } | ||||||
379 | elsif($style eq 'real') { | ||||||
380 | 0 | 0 | 0 | if(length($value)) { | |||
381 | 0 | 0 | 0 | if($value =~ /^-?[\d,'\.]+$/) { | |||
382 | 0 | 0 | $value=~s/[,']+//g; | ||||
383 | 0 | 0 | 0 | 0 | if(defined($fdata->{'minvalue'}) && $value<$fdata->{'minvalue'}) { | ||
384 | $newerr=$self->Tx("Value is less than {{min}}", | ||||||
385 | 0 | 0 | { min => $fdata->{'minvalue'} }); | ||||
386 | } | ||||||
387 | 0 | 0 | 0 | 0 | if(defined($fdata->{'maxvalue'}) && $value>$fdata->{'maxvalue'}) { | ||
388 | $newerr=$self->Tx("Value is greater than {{max}}", | ||||||
389 | 0 | 0 | { max => $fdata->{'maxvalue'} }); | ||||
390 | } | ||||||
391 | } | ||||||
392 | else { | ||||||
393 | 0 | 0 | $newerr=$self->Tx("Is not a number!"); | ||||
394 | } | ||||||
395 | } | ||||||
396 | } | ||||||
397 | elsif($style eq 'password') { | ||||||
398 | 0 | 0 | 0 | 0 | if(length($value) && $fdata->{'pair'} && | ||
0 | |||||||
399 | $value ne $cgi->param($fdata->{'pair'})) { | ||||||
400 | 0 | 0 | $newerr=$self->Tx("Does not match the copy!"); | ||||
401 | } | ||||||
402 | } | ||||||
403 | elsif($style eq 'country') { | ||||||
404 | 0 | 0 | my @cl=$self->countries_list(); | ||||
405 | 0 | 0 | my $match=0; | ||||
406 | 0 | 0 | foreach my $c (@cl) { | ||||
407 | 0 | 0 | $match=lc($c) eq lc($value); | ||||
408 | 0 | 0 | 0 | last if $match; | |||
409 | } | ||||||
410 | 0 | 0 | 0 | 0 | if(length($value) && !$match) { | ||
411 | 0 | 0 | $newerr=$self->Tx("Unknown country"); | ||||
412 | } | ||||||
413 | } | ||||||
414 | elsif($style eq 'usstate' || $style eq 'uscontst') { | ||||||
415 | 0 | 0 | 0 | my @cl=$style eq 'usstate' ? $self->us_states_list() | |||
416 | : $self->us_continental_states_list(); | ||||||
417 | 0 | 0 | my $match=0; | ||||
418 | 0 | 0 | 0 | my $sv=substr($value || '',0,2); | |||
419 | 0 | 0 | foreach my $c (@cl) { | ||||
420 | 0 | 0 | $match=lc(substr($c,0,2)) eq lc($sv); | ||||
421 | 0 | 0 | 0 | last if $match; | |||
422 | } | ||||||
423 | 0 | 0 | 0 | 0 | if(length($value) && !$match) { | ||
424 | 0 | 0 | $newerr=$self->Tx("Unknown state"); | ||||
425 | } | ||||||
426 | } | ||||||
427 | elsif($style eq 'cctype') { | ||||||
428 | 0 | 0 | my @cl=$self->cc_list(); | ||||
429 | 0 | 0 | my $match=0; | ||||
430 | 0 | 0 | foreach my $c (@cl) { | ||||
431 | 0 | 0 | $match=lc($c) eq lc($value); | ||||
432 | 0 | 0 | 0 | last if $match; | |||
433 | } | ||||||
434 | 0 | 0 | 0 | 0 | if(length($value) && !$match) { | ||
435 | 0 | 0 | $newerr=$self->Tx("Unknown credit card type"); | ||||
436 | } | ||||||
437 | } | ||||||
438 | elsif($style eq 'ccnum') { | ||||||
439 | 0 | 0 | 0 | if(length($value)) { | |||
440 | 0 | 0 | 0 | my $type=$fdata->{'pair'} ? $cgi->param($fdata->{'pair'}) : ''; | |||
441 | 0 | 0 | $newerr=$self->cc_validate(type => $type, number => $value, validated => \$value); | ||||
442 | } | ||||||
443 | } | ||||||
444 | elsif($style eq 'month') { | ||||||
445 | 0 | 0 | 0 | if(length($value)) { | |||
446 | 0 | 0 | $value=int($value); | ||||
447 | 0 | 0 | 0 | 0 | if($value<1 || $value>12) { | ||
448 | 0 | 0 | $newerr=$self->Tx('Invalid month!'); | ||||
449 | } | ||||||
450 | } | ||||||
451 | } | ||||||
452 | elsif($style eq 'year') { | ||||||
453 | 0 | 0 | 0 | 0 | if($fdata->{'minyear'} && $fdata->{'maxyear'}) { | ||
0 | |||||||
454 | 0 | 0 | my $minyear=$self->calculate_year($fdata->{'minyear'}); | ||||
455 | 0 | 0 | my $maxyear=$self->calculate_year($fdata->{'maxyear'}); | ||||
456 | 0 | 0 | 0 | if(length($value)) { | |||
457 | 0 | 0 | $value=$self->calculate_year($value); | ||||
458 | 0 | 0 | 0 | if($value<$minyear) { | |||
0 | |||||||
459 | 0 | 0 | $newerr=$self->Tx("Must be after {{year}}", | ||||
460 | { year => $minyear }); | ||||||
461 | } | ||||||
462 | elsif($value>$maxyear) { | ||||||
463 | 0 | 0 | $newerr=$self->Tx("Must be before {{year}}", | ||||
464 | { year => $maxyear }); | ||||||
465 | } | ||||||
466 | } | ||||||
467 | } | ||||||
468 | elsif(length($value)) { | ||||||
469 | 0 | 0 | $value=$self->calculate_year($value); | ||||
470 | 0 | 0 | 0 | 0 | if($value<1900 || $value>2099) { | ||
471 | 0 | 0 | $newerr=$self->Tx('Invalid year!'); | ||||
472 | } | ||||||
473 | } | ||||||
474 | } | ||||||
475 | elsif($style eq 'checkbox') { | ||||||
476 | |||||||
477 | # If checkbox is not checked we don't get any info about it | ||||||
478 | # in the cgi parameters. So we have to take a guess if the | ||||||
479 | # form was generally filled in, but we have an unchecked | ||||||
480 | # checkbox or this is the first display and form was not | ||||||
481 | # submitted yet. | ||||||
482 | # | ||||||
483 | 0 | 0 | 0 | if($have_cgivalues) { | |||
484 | 0 | 0 | 0 | $value=(defined $fdata->{'newvalue'} ? $fdata->{'newvalue'} : $cgivalue) ? 1 : 0; | |||
0 | |||||||
485 | } | ||||||
486 | else { | ||||||
487 | 0 | 0 | 0 | $value=(defined($fdata->{'value'}) ? $fdata->{'value'} : $fdata->{'default'}) ? 1 : 0; | |||
0 | |||||||
488 | } | ||||||
489 | } | ||||||
490 | elsif($style eq 'selection') { | ||||||
491 | 0 | 0 | 0 | if(length($value)) { | |||
492 | 0 | 0 | my $opt=$fdata->{'options'}; | ||||
493 | 0 | 0 | 0 | if(ref($opt) eq 'HASH') { | |||
0 | |||||||
494 | 0 | 0 | 0 | if(!defined $opt->{$value}) { | |||
495 | 0 | 0 | $newerr=$self->Tx('Bad option value!'); | ||||
496 | } | ||||||
497 | } | ||||||
498 | elsif(ref($opt) eq 'ARRAY') { | ||||||
499 | 0 | 0 | my $found; | ||||
500 | 0 | 0 | for(my $i=0; $i<@$opt; $i+=2) { | ||||
501 | 0 | 0 | 0 | next unless defined($opt->[$i+1]); | |||
502 | 0 | 0 | 0 | if($opt->[$i] eq $value) { | |||
503 | 0 | 0 | $found=1; | ||||
504 | 0 | 0 | last; | ||||
505 | } | ||||||
506 | } | ||||||
507 | 0 | 0 | 0 | if(!$found) { | |||
508 | 0 | 0 | $newerr=$self->Tx('Bad option value!'); | ||||
509 | } | ||||||
510 | } | ||||||
511 | else { | ||||||
512 | 0 | 0 | $newerr=$self->Tx('Unknown data in options!'); | ||||
513 | } | ||||||
514 | } | ||||||
515 | } | ||||||
516 | else { | ||||||
517 | 0 | 0 | $self->throw("display - unknown style '$style'"); | ||||
518 | } | ||||||
519 | |||||||
520 | # If the form is not filled at all we empty the errstr | ||||||
521 | # | ||||||
522 | 0 | 0 | 0 | 0 | if($newerr && (!$have_submit || !$have_cgivalues)) { | ||
0 | |||||||
523 | 0 | 0 | $newerr = ''; | ||||
524 | } | ||||||
525 | |||||||
526 | # Generating HTML for some field styles. | ||||||
527 | # | ||||||
528 | 0 | 0 | 0 | my $param=$fdata->{'param'} || uc($name); | |||
529 | 0 | 0 | my $seloptions; | ||||
530 | my $selcompare; | ||||||
531 | 0 | 0 | 0 | 0 | if($style eq 'country') { | ||
0 | 0 | ||||||
0 | 0 | ||||||
0 | 0 | ||||||
0 | 0 | ||||||
0 | 0 | ||||||
0 | 0 | ||||||
0 | 0 | ||||||
0 | 0 | ||||||
0 | 0 | ||||||
0 | 0 | ||||||
0 | |||||||
0 | |||||||
532 | 0 | 0 | my @cl=$self->countries_list(); | ||||
533 | $seloptions=[ | ||||||
534 | '' => 'Select Country', | ||||||
535 | 0 | 0 | (map { $_ => $_ } @cl), | ||||
0 | 0 | ||||||
536 | ]; | ||||||
537 | 0 | 0 | 0 | $selcompare=sub { return uc($_[0]) eq uc($_[1]) }; | |||
0 | 0 | ||||||
538 | } | ||||||
539 | elsif($style eq 'usstate' || $style eq 'uscontst') { | ||||||
540 | 0 | 0 | 0 | my @cl=$style eq 'usstate' ? $self->us_states_list() | |||
541 | : $self->us_continental_states_list(); | ||||||
542 | $seloptions=[ | ||||||
543 | '' => 'Select State', | ||||||
544 | 0 | 0 | (map { uc(substr($_,0,2)) => $_ } @cl), | ||||
0 | 0 | ||||||
545 | ]; | ||||||
546 | 0 | 0 | 0 | $selcompare=sub { return uc($_[0]) eq uc($_[1]) }; | |||
0 | 0 | ||||||
547 | } | ||||||
548 | elsif($style eq 'cctype') { | ||||||
549 | 0 | 0 | my @cl=$self->cc_list(); | ||||
550 | $seloptions=[ | ||||||
551 | '' => 'Select Card Type', | ||||||
552 | 0 | 0 | (map { $_ => $_ } @cl), | ||||
0 | 0 | ||||||
553 | ]; | ||||||
554 | 0 | 0 | 0 | $selcompare=sub { return uc($_[0]) eq uc($_[1]) }; | |||
0 | 0 | ||||||
555 | } | ||||||
556 | elsif($style eq 'month') { | ||||||
557 | 0 | 0 | my @cl=qw(January February March April May June July | ||||
558 | August September October November December); | ||||||
559 | $seloptions=[ | ||||||
560 | '' => 'Select Month', | ||||||
561 | 0 | 0 | (map { sprintf('%02u',$_) => sprintf('%02u - %s',$_,$cl[$_-1]) } (1..12)), | ||||
0 | 0 | ||||||
562 | ]; | ||||||
563 | 0 | 0 | 0 | 0 | $selcompare=sub { return defined $_[0] && length $_[0] && length $_[1] && $_[0] == $_[1] }; | ||
0 | 0 | ||||||
564 | } | ||||||
565 | elsif($style eq 'year' && !$fdata->{'maxlength'} && $fdata->{'minyear'} && $fdata->{'maxyear'}) { | ||||||
566 | 0 | 0 | my $minyear=$self->calculate_year($fdata->{'minyear'}); | ||||
567 | 0 | 0 | my $maxyear=$self->calculate_year($fdata->{'maxyear'}); | ||||
568 | $seloptions=[ | ||||||
569 | '' => 'Select Year', | ||||||
570 | 0 | 0 | (map { sprintf('%04u',$_) => sprintf('%04u',$_) } ($minyear..$maxyear)), | ||||
0 | 0 | ||||||
571 | ]; | ||||||
572 | 0 | 0 | 0 | 0 | $selcompare=sub { return defined $_[0] && length $_[0] && length $_[1] && $_[0] == $_[1] }; | ||
0 | 0 | ||||||
573 | } | ||||||
574 | elsif($style eq 'checkbox') { | ||||||
575 | $fdata->{'html'}=$obj->expand( | ||||||
576 | path => '/bits/fillout-form/html-checkbox', | ||||||
577 | NAME => $name, | ||||||
578 | VALUE => $fdata->{'value'} || '', | ||||||
579 | CHECKED => $value ? ' checked' : '', | ||||||
580 | 0 | 0 | 0 | 0 | HTMLID => $fdata->{'htmlid'} || $name, | ||
0 | |||||||
0 | |||||||
581 | ERRSTR => $newerr || '' | ||||||
582 | ); | ||||||
583 | } | ||||||
584 | elsif($style eq 'selection') { | ||||||
585 | 0 | 0 | 0 | $seloptions=$fdata->{'options'} || | |||
586 | $self->throw("display - no 'options' for '$name' selection"); | ||||||
587 | } | ||||||
588 | elsif($style eq 'text' || $style eq 'phone' || $style eq 'usphone' || | ||||||
589 | $style eq 'ccnum' || $style eq 'email' || $style eq 'year' || | ||||||
590 | $style eq 'number' || $style eq 'int' || $style eq 'integer' || | ||||||
591 | $style eq 'real' ) { | ||||||
592 | $fdata->{'html'}=$obj->expand( | ||||||
593 | path => '/bits/fillout-form/html-text', | ||||||
594 | NAME => $name, | ||||||
595 | VALUE => defined($value) ? $value : '', | ||||||
596 | MAXLENGTH => $fdata->{'maxlength'} || 100, | ||||||
597 | 0 | 0 | 0 | 0 | SIZE => $fdata->{'size'} || 30, | ||
0 | 0 | ||||||
598 | ERRSTR => defined($newerr) ? $newerr : '' | ||||||
599 | ); | ||||||
600 | } | ||||||
601 | elsif($style eq 'textarea') { | ||||||
602 | $fdata->{'html'}=$obj->expand( | ||||||
603 | path => '/bits/fillout-form/html-textarea', | ||||||
604 | NAME => $name, | ||||||
605 | VALUE => defined($value) ? $value : '', | ||||||
606 | SIZE => $fdata->{'size'} || 30, | ||||||
607 | 0 | 0 | 0 | 0 | ROWS => $fdata->{'rows'} || 8, | ||
0 | 0 | ||||||
608 | ERRSTR => defined($newerr) ? $newerr : '' | ||||||
609 | ); | ||||||
610 | } | ||||||
611 | elsif($style eq 'file') { | ||||||
612 | $fdata->{'html'}=$obj->expand( | ||||||
613 | path => '/bits/fillout-form/html-file', | ||||||
614 | NAME => $name, | ||||||
615 | 0 | 0 | 0 | 0 | SIZE => $fdata->{'size'} || 30, | ||
616 | ERRSTR => defined($newerr) ? $newerr : '' | ||||||
617 | ); | ||||||
618 | } | ||||||
619 | elsif($style eq 'password') { | ||||||
620 | $fdata->{'html'}=$obj->expand( | ||||||
621 | path => '/bits/fillout-form/html-password', | ||||||
622 | NAME => $name, | ||||||
623 | VALUE => defined $value ? $value : '', | ||||||
624 | MAXLENGTH => $fdata->{'maxlength'} || 100, | ||||||
625 | 0 | 0 | 0 | 0 | SIZE => $fdata->{'size'} || 30, | ||
0 | |||||||
0 | |||||||
626 | ERRSTR => $newerr || '' | ||||||
627 | ); | ||||||
628 | } | ||||||
629 | |||||||
630 | # Various selection fields above just set seloptions for uniform build. | ||||||
631 | # | ||||||
632 | 0 | 0 | 0 | if($seloptions) { | |||
633 | 0 | 0 | my $has_empty; | ||||
634 | my $used_selected; | ||||||
635 | 0 | 0 | my $html=''; | ||||
636 | my $html_sub=sub { | ||||||
637 | 0 | 0 | 0 | my ($v,$t)=@_; | |||
638 | 0 | 0 | 0 | 0 | $has_empty=1 if !defined($v) || !length($v); | ||
639 | 0 | 0 | 0 | return unless defined($t); | |||
640 | 0 | 0 | my $sel=''; | ||||
641 | 0 | 0 | 0 | if(!$used_selected) { | |||
642 | 0 | 0 | 0 | my $equal=$selcompare ? $selcompare->($v,$value) : ($v eq $value); | |||
643 | 0 | 0 | 0 | if($equal) { | |||
644 | 0 | 0 | $sel=' selected'; | ||||
645 | 0 | 0 | $used_selected=1; | ||||
646 | } | ||||||
647 | } | ||||||
648 | 0 | 0 | $html.=$obj->expand( | ||||
649 | path => '/bits/fillout-form/html-select-option', | ||||||
650 | NAME => $name, | ||||||
651 | VALUE => $v, | ||||||
652 | TEXT => $t, | ||||||
653 | SELECTED=> $sel, | ||||||
654 | ); | ||||||
655 | 0 | 0 | 0 | $formparams{"$param.RV_CURRENT_$v"}=$sel ? 1 : 0; | |||
656 | 0 | 0 | $formparams{"$param.RV_VALUE_$v"}=$v; | ||||
657 | 0 | 0 | $formparams{"$param.RV_TEXT_$v"}=$t; | ||||
658 | 0 | 0 | }; | ||||
659 | |||||||
660 | 0 | 0 | 0 | if(ref($seloptions) eq 'HASH') { | |||
0 | |||||||
661 | 0 | 0 | foreach my $v (sort { $seloptions->{$a} cmp $seloptions->{$b} } keys %$seloptions) { | ||||
0 | 0 | ||||||
662 | 0 | 0 | &{$html_sub}($v,$seloptions->{$v}); | ||||
0 | 0 | ||||||
663 | } | ||||||
664 | } | ||||||
665 | elsif(ref($seloptions) eq 'ARRAY') { | ||||||
666 | 0 | 0 | for(my $i=0; $i<@$seloptions; $i+=2) { | ||||
667 | 0 | 0 | &{$html_sub}($seloptions->[$i],$seloptions->[$i+1]); | ||||
0 | 0 | ||||||
668 | } | ||||||
669 | } | ||||||
670 | else { | ||||||
671 | 0 | 0 | throw $self "Unknown data type in 'options' name=$name"; | ||||
672 | }; | ||||||
673 | |||||||
674 | # We do not display 'Please select' if there is an empty | ||||||
675 | # value in the list, we assume that that empty value is a | ||||||
676 | # prompt of some sort. | ||||||
677 | # | ||||||
678 | # If there is no need for empty value and no need for a | ||||||
679 | # prompt -- use ('' => undef) as an indicator of that. | ||||||
680 | # | ||||||
681 | 0 | 0 | $formparams{"$param.HTML_OPTIONS"}=$html; | ||||
682 | |||||||
683 | # For compatibility with older code this is not included in | ||||||
684 | # HTML_OPTIONS | ||||||
685 | # | ||||||
686 | 0 | 0 | 0 | if(!$has_empty) { | |||
687 | 0 | 0 | $html=' | ||||
688 | t2ht($self->Tx('Please select')) . | ||||||
689 | ''.$html; | ||||||
690 | } | ||||||
691 | |||||||
692 | # Final code | ||||||
693 | # | ||||||
694 | 0 | 0 | 0 | 0 | $fdata->{'html'}=$obj->expand( | ||
695 | path => '/bits/fillout-form/html-select', | ||||||
696 | NAME => $name, | ||||||
697 | VALUE => defined $value ? $value : '', | ||||||
698 | OPTIONS => $html, | ||||||
699 | ERRSTR => $newerr || '' | ||||||
700 | ); | ||||||
701 | } | ||||||
702 | |||||||
703 | # Adding error description to the list if there was an | ||||||
704 | # error. Storing value otherwise. | ||||||
705 | # | ||||||
706 | 0 | 0 | 0 | if($newerr) { | |||
707 | 0 | 0 | 0 | $errstr.=($fdata->{'text'} || $name) . ": " . $newerr . " \n"; |
|||
708 | 0 | 0 | $fdata->{'errstr'}=$newerr; | ||||
709 | } | ||||||
710 | else { | ||||||
711 | 0 | 0 | $fdata->{'value'}=$value; | ||||
712 | } | ||||||
713 | |||||||
714 | # Filling formparams hash | ||||||
715 | # | ||||||
716 | 0 | 0 | 0 | $formparams{"$param.VALUE"}=defined($value) ? $value : ""; | |||
717 | 0 | 0 | 0 | $formparams{"$param.TEXT"}=$fdata->{'text'} || $name; | |||
718 | 0 | 0 | $formparams{"$param.NAME"}=$name; | ||||
719 | 0 | 0 | 0 | $formparams{"$param.HTML"}=$fdata->{'html'} || ""; | |||
720 | 0 | 0 | 0 | $formparams{"$param.REQUIRED"}=$fdata->{'required'} ? 1 : 0; | |||
721 | 0 | 0 | 0 | $formparams{"$param.SIZE"}=$fdata->{'size'} || 30; | |||
722 | 0 | 0 | 0 | $formparams{"$param.ROWS"}=$fdata->{'rows'} || 1; | |||
723 | 0 | 0 | 0 | $formparams{"$param.MAXLENGTH"}=$fdata->{'maxlength'} || 100; | |||
724 | 0 | 0 | 0 | $formparams{"$param.MINLENGTH"}=$fdata->{'minlength'} || 0; | |||
725 | 0 | 0 | 0 | $formparams{"$param.ERRSTR"}=$fdata->{'errstr'} || ''; | |||
726 | } | ||||||
727 | |||||||
728 | # Checking content for general compatibility by overriden | ||||||
729 | # method. Called only if data are basicly good. | ||||||
730 | # | ||||||
731 | 0 | 0 | 0 | 0 | if($have_submit && $have_cgivalues && !$errstr) { | ||
0 | |||||||
732 | 0 | 0 | my @rc=$self->check_form(merge_refs($args,\%formparams)); | ||||
733 | 0 | 0 | 0 | if(@rc<2) { | |||
0 | |||||||
734 | 0 | 0 | 0 | $formparams{"ERRSTR.CHECK_FORM"}=$errstr=($rc[0] || ''); | |||
735 | } | ||||||
736 | elsif(scalar(@rc)%2 == 0) { | ||||||
737 | 0 | 0 | for(my $i=0; $i<@rc; $i+=2) { | ||||
738 | 0 | 0 | 0 | my $e=($rc[$i] || ''); | |||
739 | 0 | 0 | 0 | next unless $e; | |||
740 | 0 | 0 | my $fname=$rc[$i+1]; | ||||
741 | 0 | 0 | 0 | if($fname) { | |||
742 | 0 | 0 | my $fdata=$self->field_desc($fname); | ||||
743 | 0 | 0 | 0 | my $param=$fdata->{'param'} || uc($fdata->{'name'}); | |||
744 | |||||||
745 | 0 | 0 | 0 | if($fdata->{'errstr'}) { | |||
746 | 0 | 0 | 0 | $fdata->{'errstr'}.=($fdata->{'errstr'} =~ /\.\s*$/ ? ' ' : '; ') . $e; | |||
747 | 0 | 0 | $formparams{"$param.ERRSTR"}=$fdata->{'errstr'}; | ||||
748 | } | ||||||
749 | else { | ||||||
750 | 0 | 0 | $fdata->{'errstr'}=$formparams{"$param.ERRSTR"}=$e; | ||||
751 | } | ||||||
752 | |||||||
753 | 0 | 0 | 0 | $errstr.="\n " if $errstr; |
|||
754 | 0 | 0 | $errstr.=$e; | ||||
755 | } | ||||||
756 | else { | ||||||
757 | 0 | 0 | 0 | $errstr.="\n " if $errstr; |
|||
758 | 0 | 0 | 0 | $formparams{'ERRSTR.CHECK_FORM'}.="\n " if $errstr; |
|||
759 | 0 | 0 | $errstr.=$e; | ||||
760 | 0 | 0 | $formparams{'ERRSTR.CHECK_FORM'}.=$e; | ||||
761 | } | ||||||
762 | } | ||||||
763 | } | ||||||
764 | else { | ||||||
765 | 0 | 0 | throw $self "display - wrong number of results (".join('|',@rc).")"; | ||||
766 | } | ||||||
767 | } | ||||||
768 | 0 | 0 | 0 | $formparams{"ERRSTR.CHECK_FORM"}||=''; | |||
769 | |||||||
770 | # If the form is not filled at all we remove errstr's from | ||||||
771 | # individual fields. | ||||||
772 | # | ||||||
773 | 0 | 0 | 0 | 0 | if(!$have_submit || !$have_cgivalues) { | ||
774 | 0 | 0 | $errstr=''; | ||||
775 | 0 | 0 | foreach my $fdata (@{$fields}) { | ||||
0 | 0 | ||||||
776 | 0 | 0 | 0 | my $param=$fdata->{'param'} || uc($fdata->{'name'}); | |||
777 | 0 | 0 | $formparams{"$param.ERRSTR"}=''; | ||||
778 | } | ||||||
779 | } | ||||||
780 | |||||||
781 | # If there were errors then displaying the form. We also display | ||||||
782 | # the form here if it is not yet filled out and if it is, but we we | ||||||
783 | # asked to keep displaying it using 'keep_form' setup parameter. | ||||||
784 | # | ||||||
785 | 0 | 0 | my $keep_form=$self->{'keep_form'}; | ||||
786 | 0 | 0 | 0 | 0 | if(!$have_submit || !$have_cgivalues || $errstr || $keep_form) { | ||
0 | |||||||
0 | |||||||
787 | 0 | 0 | my $eh; | ||||
788 | my $et; | ||||||
789 | 0 | 0 | 0 | 0 | if($errstr && $have_cgivalues) { | ||
790 | $eh=$obj->expand( | ||||||
791 | path => '/bits/fillout-form/errstr', | ||||||
792 | ERRSTR => $errstr, | ||||||
793 | 0 | 0 | 'ERRSTR.CHECK_FORM' => $formparams{"ERRSTR.CHECK_FORM"}, | ||||
794 | ); | ||||||
795 | 0 | 0 | $et=$errstr; | ||||
796 | |||||||
797 | } | ||||||
798 | $obj->display($args,\%formparams,{ | ||||||
799 | path => $args->{'form.path'}, | ||||||
800 | 0 | 0 | 0 | template => $args->{'form.template'}, | |||
0 | |||||||
801 | ERRSTR => $et || '', | ||||||
802 | 'ERRSTR.HTML' => $eh || '', | ||||||
803 | }); | ||||||
804 | 0 | 0 | 0 | 0 | return unless $keep_form && !$errstr && $have_cgivalues && $have_submit; | ||
0 | |||||||
0 | |||||||
805 | } | ||||||
806 | |||||||
807 | # Our form is correct! | ||||||
808 | # | ||||||
809 | 0 | 0 | $self->form_ok(merge_refs($args,\%formparams)); | ||||
810 | } | ||||||
811 | |||||||
812 | ############################################################################### | ||||||
813 | |||||||
814 | =item field_desc ($) | ||||||
815 | |||||||
816 | Returns field description by name. This is the correct way to get to the | ||||||
817 | value of a field from check_form() or form_ok() methods. | ||||||
818 | |||||||
819 | If the optional second parameter set to true then on failure to find the | ||||||
820 | field the method will return undef instead of throwing an error. | ||||||
821 | |||||||
822 | =cut | ||||||
823 | |||||||
824 | sub field_desc ($$;$) { | ||||||
825 | 0 | 0 | 1 | 0 | my ($self,$name,$soft_failure)=@_; | ||
826 | |||||||
827 | 0 | 0 | 0 | my $fields=$self->{'fields'} || | |||
828 | throw $self "field_desc - has not set fields for FilloutForm"; | ||||||
829 | |||||||
830 | 0 | 0 | 0 | if(ref($fields) eq 'ARRAY') { | |||
831 | 0 | 0 | foreach my $fdata (@{$fields}) { | ||||
0 | 0 | ||||||
832 | 0 | 0 | 0 | return $fdata if $fdata->{'name'} eq $name; | |||
833 | } | ||||||
834 | } | ||||||
835 | else { | ||||||
836 | 0 | 0 | 0 | return $fields->{$name} if $fields->{$name}; | |||
837 | } | ||||||
838 | |||||||
839 | 0 | 0 | 0 | return undef if $soft_failure; | |||
840 | |||||||
841 | 0 | 0 | throw $self "field_desc - unknown field '$name' referred"; | ||||
842 | } | ||||||
843 | |||||||
844 | ############################################################################### | ||||||
845 | |||||||
846 | =item field_names ($) | ||||||
847 | |||||||
848 | Returns field a list of all field names in the current form. | ||||||
849 | |||||||
850 | =cut | ||||||
851 | |||||||
852 | sub field_names ($) { | ||||||
853 | 0 | 0 | 1 | 0 | my $self=shift; | ||
854 | |||||||
855 | 0 | 0 | 0 | my $fields=$self->{'fields'} || | |||
856 | throw $self "field_names - has not set fields for FilloutForm"; | ||||||
857 | |||||||
858 | 0 | 0 | 0 | if(ref($fields) eq 'ARRAY') { | |||
859 | 0 | 0 | return map { $_->{'name'} } @$fields; | ||||
0 | 0 | ||||||
860 | } | ||||||
861 | else { | ||||||
862 | 0 | 0 | return map { $_->{'name'} } keys %$fields; | ||||
0 | 0 | ||||||
863 | } | ||||||
864 | } | ||||||
865 | |||||||
866 | ############################################################################### | ||||||
867 | |||||||
868 | =item form_ok | ||||||
869 | |||||||
870 | Default handler for filled out form. Must be overriden! | ||||||
871 | |||||||
872 | =cut | ||||||
873 | |||||||
874 | sub form_ok ($%) { | ||||||
875 | 0 | 0 | 1 | 0 | my $self=shift; | ||
876 | 0 | 0 | 0 | if($self->{'form_ok'}) { | |||
877 | my $na=merge_refs(get_args(\@_),{ | ||||||
878 | 0 | 0 | extra_data => $self->{'extra_data'}, | ||||
879 | }); | ||||||
880 | 0 | 0 | return &{$self->{'form_ok'}}($self,$na); | ||||
0 | 0 | ||||||
881 | } | ||||||
882 | 0 | 0 | throw $self 'form_ok - must be overriden in derived class or using form_ok parameter'; | ||||
883 | } | ||||||
884 | |||||||
885 | ## | ||||||
886 | # High-level form content check. Should be overriden for real checks. | ||||||
887 | # Returns '' if there were no error or error text otherwise. | ||||||
888 | # | ||||||
889 | sub check_form ($%) { | ||||||
890 | 0 | 0 | 0 | 0 | my $self=shift; | ||
891 | 0 | 0 | 0 | if($self->{'check_form'}) { | |||
892 | 0 | 0 | my %na=%{get_args(\@_)}; | ||||
0 | 0 | ||||||
893 | 0 | 0 | $na{'extra_data'}=$self->{'extra_data'}; | ||||
894 | 0 | 0 | return &{$self->{'check_form'}}($self,\%na); | ||||
0 | 0 | ||||||
895 | } | ||||||
896 | 0 | 0 | ''; | ||||
897 | } | ||||||
898 | |||||||
899 | ############################################################################### | ||||||
900 | |||||||
901 | =item pre_check_form (%) | ||||||
902 | |||||||
903 | Pre-checking form. May be used if some values are calculated or copied | ||||||
904 | from another and should be checked later. | ||||||
905 | |||||||
906 | Should stuff generated values into {'newvalue'} parameter. | ||||||
907 | |||||||
908 | =cut | ||||||
909 | |||||||
910 | sub pre_check_form ($%) { | ||||||
911 | 0 | 0 | 1 | 0 | my $self=shift; | ||
912 | 0 | 0 | 0 | if($self->{'pre_check_form'}) { | |||
913 | 0 | 0 | my $na=get_args(\@_); | ||||
914 | 0 | 0 | $na->{'extra_data'}=$self->{'extra_data'}; | ||||
915 | 0 | 0 | return &{$self->{'pre_check_form'}}($self,$na); | ||||
0 | 0 | ||||||
916 | } | ||||||
917 | } | ||||||
918 | |||||||
919 | ############################################################################### | ||||||
920 | |||||||
921 | =item countries_list () | ||||||
922 | |||||||
923 | Returns list of countries for selection. May be overriden if site | ||||||
924 | needs only a fraction of that. | ||||||
925 | |||||||
926 | =cut | ||||||
927 | |||||||
928 | sub countries_list () { | ||||||
929 | 0 | 0 | 1 | 0 | split(/\n/,<<'END_OF_LIST'); | ||
930 | United States | ||||||
931 | Afghanistan | ||||||
932 | Albania | ||||||
933 | Algeria | ||||||
934 | American Samoa | ||||||
935 | Andorra | ||||||
936 | Angola | ||||||
937 | Anguilla | ||||||
938 | Antarctica | ||||||
939 | Antigua | ||||||
940 | Antilles | ||||||
941 | Arab Emirates | ||||||
942 | Argentina | ||||||
943 | Armenia | ||||||
944 | Aruba | ||||||
945 | Australia | ||||||
946 | Austria | ||||||
947 | Azerbaidjan | ||||||
948 | Bahamas | ||||||
949 | Bahrain | ||||||
950 | Bangladesh | ||||||
951 | Barbados | ||||||
952 | Barbuda | ||||||
953 | Belarus | ||||||
954 | Belgium | ||||||
955 | Belize | ||||||
956 | Benin | ||||||
957 | Bermuda | ||||||
958 | Bhutan | ||||||
959 | Bolivia | ||||||
960 | Bosnia Herz. | ||||||
961 | Botswana | ||||||
962 | Bouvet Isl. | ||||||
963 | Brazil | ||||||
964 | Brunei Dar. | ||||||
965 | Bulgaria | ||||||
966 | Burkina Faso | ||||||
967 | Burundi | ||||||
968 | C. African Rep. | ||||||
969 | Cambodia | ||||||
970 | Cameroon | ||||||
971 | Cambodia | ||||||
972 | Cameroon | ||||||
973 | Canada | ||||||
974 | Cape Verde | ||||||
975 | Cayman Islands | ||||||
976 | Chad | ||||||
977 | Chile | ||||||
978 | China | ||||||
979 | Christmas Isl. | ||||||
980 | Cocos Islands | ||||||
981 | Colombia | ||||||
982 | Comoros | ||||||
983 | Congo | ||||||
984 | Cook Islands | ||||||
985 | Costa Rica | ||||||
986 | Croatia | ||||||
987 | Cuba | ||||||
988 | Cyprus | ||||||
989 | Czech Republic | ||||||
990 | Denmark | ||||||
991 | Djibouti | ||||||
992 | Dominica | ||||||
993 | Dominican Rep. | ||||||
994 | East Timor | ||||||
995 | Ecuador | ||||||
996 | Egypt | ||||||
997 | England | ||||||
998 | El Salvador | ||||||
999 | Equat. Guinea | ||||||
1000 | Eritrea | ||||||
1001 | Estonia | ||||||
1002 | Ethiopia | ||||||
1003 | Falkland Isl. | ||||||
1004 | Faroe Islands | ||||||
1005 | Fiji | ||||||
1006 | Finland | ||||||
1007 | Former Czech. | ||||||
1008 | Former USSR | ||||||
1009 | France | ||||||
1010 | French Guyana | ||||||
1011 | French S. Terr. | ||||||
1012 | Gabon | ||||||
1013 | Gambia | ||||||
1014 | Georgia | ||||||
1015 | Germany | ||||||
1016 | Ghana | ||||||
1017 | Gibraltar | ||||||
1018 | Great Britain | ||||||
1019 | Greece | ||||||
1020 | Greenland | ||||||
1021 | Grenada | ||||||
1022 | Guadeloupe | ||||||
1023 | Grenada | ||||||
1024 | Guadeloupe | ||||||
1025 | Guam (USA) | ||||||
1026 | Guatemala | ||||||
1027 | Guinea | ||||||
1028 | Guinea Bissau | ||||||
1029 | Guyana | ||||||
1030 | Haiti | ||||||
1031 | Heard/McDonald | ||||||
1032 | Honduras | ||||||
1033 | Hong Kong | ||||||
1034 | Hungary | ||||||
1035 | Iceland | ||||||
1036 | India | ||||||
1037 | Indonesia | ||||||
1038 | Iran | ||||||
1039 | Iraq | ||||||
1040 | Ireland | ||||||
1041 | Israel | ||||||
1042 | Italy | ||||||
1043 | Ivory Coast | ||||||
1044 | Jamaica | ||||||
1045 | Japan | ||||||
1046 | Jordan | ||||||
1047 | Kazakhstan | ||||||
1048 | Kenya | ||||||
1049 | Kiribati | ||||||
1050 | Kuwait | ||||||
1051 | Kyrgyzstan | ||||||
1052 | Laos | ||||||
1053 | Latvia | ||||||
1054 | Lebanon | ||||||
1055 | Lesotho | ||||||
1056 | Liberia | ||||||
1057 | Libya | ||||||
1058 | Liechtenstein | ||||||
1059 | Lithuania | ||||||
1060 | Luxembourg | ||||||
1061 | Macau | ||||||
1062 | Macedonia | ||||||
1063 | Madagascar | ||||||
1064 | Malawi | ||||||
1065 | Malaysia | ||||||
1066 | Maldives | ||||||
1067 | Mali | ||||||
1068 | Malta | ||||||
1069 | Marshall Isl. | ||||||
1070 | Martinique | ||||||
1071 | Mauritania | ||||||
1072 | Mauritius | ||||||
1073 | Mayotte | ||||||
1074 | Mexico | ||||||
1075 | Mayotte | ||||||
1076 | Mexico | ||||||
1077 | Micronesia | ||||||
1078 | Moldavia | ||||||
1079 | Monaco | ||||||
1080 | Mongolia | ||||||
1081 | Montserrat | ||||||
1082 | Morocco | ||||||
1083 | Mozambique | ||||||
1084 | Myanmar | ||||||
1085 | N. Mariana Isl. | ||||||
1086 | Namibia | ||||||
1087 | Nauru | ||||||
1088 | Nepal | ||||||
1089 | Netherlands | ||||||
1090 | Neutral Zone | ||||||
1091 | New Caledonia | ||||||
1092 | New Zealand | ||||||
1093 | Nicaragua | ||||||
1094 | Niger | ||||||
1095 | Nigeria | ||||||
1096 | Niue | ||||||
1097 | Norfolk Island | ||||||
1098 | Northern Ireland | ||||||
1099 | North Korea | ||||||
1100 | Norway | ||||||
1101 | Oman | ||||||
1102 | Pakistan | ||||||
1103 | Palau | ||||||
1104 | Panama | ||||||
1105 | Papua New Guinea | ||||||
1106 | Paraguay | ||||||
1107 | Peru | ||||||
1108 | Philippines | ||||||
1109 | Pitcairn Isl. | ||||||
1110 | Poland | ||||||
1111 | Polynesia | ||||||
1112 | Portugal | ||||||
1113 | Puerto Rico | ||||||
1114 | Qatar | ||||||
1115 | Reunion | ||||||
1116 | Romania | ||||||
1117 | Russia | ||||||
1118 | Rwanda | ||||||
1119 | Samoa | ||||||
1120 | San Marino | ||||||
1121 | Saudi Arabia | ||||||
1122 | Scotland | ||||||
1123 | Senegal | ||||||
1124 | Seychelles | ||||||
1125 | Sierra Leone | ||||||
1126 | Singapore | ||||||
1127 | Sierra Leone | ||||||
1128 | Singapore | ||||||
1129 | Slovak Rep. | ||||||
1130 | Slovenia | ||||||
1131 | Solomon Isl. | ||||||
1132 | Somalia | ||||||
1133 | South Africa | ||||||
1134 | South Korea | ||||||
1135 | Spain | ||||||
1136 | Sri Lanka | ||||||
1137 | St Helena | ||||||
1138 | St Lucia | ||||||
1139 | St Pierre | ||||||
1140 | St Tome | ||||||
1141 | St Vincent | ||||||
1142 | Sudan | ||||||
1143 | Suriname | ||||||
1144 | Swaziland | ||||||
1145 | Sweden | ||||||
1146 | Switzerland | ||||||
1147 | Syrian Arab Republic | ||||||
1148 | Tadjikistan | ||||||
1149 | Taiwan | ||||||
1150 | Tanzania | ||||||
1151 | Thailand | ||||||
1152 | Tobago | ||||||
1153 | Togo | ||||||
1154 | Tokelau | ||||||
1155 | Tonga | ||||||
1156 | Trinidad & Tobago | ||||||
1157 | Tunisia | ||||||
1158 | Turopaque | ||||||
1159 | Turkmenistan | ||||||
1160 | Turks/Caicos Isl. | ||||||
1161 | Tuvalu | ||||||
1162 | Uganda | ||||||
1163 | Ukraine | ||||||
1164 | Uruguay | ||||||
1165 | Uzbekistan | ||||||
1166 | Vanuatu | ||||||
1167 | Vatican City | ||||||
1168 | Venezuela | ||||||
1169 | Vietnam | ||||||
1170 | Virg.Isl. (UK) | ||||||
1171 | Virg.Isl. (US) | ||||||
1172 | Wales | ||||||
1173 | Western Sahara | ||||||
1174 | Yemen | ||||||
1175 | Yugoslavia | ||||||
1176 | Zaire | ||||||
1177 | Zambia | ||||||
1178 | Zimbabwe | ||||||
1179 | END_OF_LIST | ||||||
1180 | } | ||||||
1181 | |||||||
1182 | ############################################################################### | ||||||
1183 | |||||||
1184 | =item us_continental_states_list () | ||||||
1185 | |||||||
1186 | Returns list of US continental states for selection. May be overriden | ||||||
1187 | if site needs only a fraction of that. | ||||||
1188 | |||||||
1189 | =cut | ||||||
1190 | |||||||
1191 | sub us_continental_states_list () { | ||||||
1192 | 0 | 0 | 1 | 0 | my $self=shift; | ||
1193 | 0 | 0 | my @list; | ||||
1194 | 0 | 0 | foreach my $st ($self->us_states_list) { | ||||
1195 | 0 | 0 | 0 | next if $st =~ /^AK/; | |||
1196 | 0 | 0 | 0 | next if $st =~ /^AS/; | |||
1197 | 0 | 0 | 0 | next if $st =~ /^FM/; | |||
1198 | 0 | 0 | 0 | next if $st =~ /^GU/; | |||
1199 | 0 | 0 | 0 | next if $st =~ /^HI/; | |||
1200 | 0 | 0 | 0 | next if $st =~ /^MH/; | |||
1201 | 0 | 0 | 0 | next if $st =~ /^MP/; | |||
1202 | 0 | 0 | 0 | next if $st =~ /^VI/; | |||
1203 | 0 | 0 | push(@list,$st); | ||||
1204 | } | ||||||
1205 | 0 | 0 | @list; | ||||
1206 | } | ||||||
1207 | |||||||
1208 | ############################################################################### | ||||||
1209 | |||||||
1210 | =item us_states_list () | ||||||
1211 | |||||||
1212 | Returns list of US states for selection. May be overriden if site | ||||||
1213 | needs only a fraction of that. | ||||||
1214 | |||||||
1215 | =cut | ||||||
1216 | |||||||
1217 | sub us_states_list () { | ||||||
1218 | 0 | 0 | 1 | 0 | split(/\n/,<<'END_OF_LIST'); | ||
1219 | AL - Alabama | ||||||
1220 | AK - Alaska | ||||||
1221 | AS - American Samoa | ||||||
1222 | AZ - Arizona | ||||||
1223 | AR - Arkansas | ||||||
1224 | CA - California | ||||||
1225 | CO - Colorado | ||||||
1226 | CT - Connecticut | ||||||
1227 | DE - Delaware | ||||||
1228 | DC - District Of Columbia | ||||||
1229 | FM - Federated States Of Micronesia | ||||||
1230 | FL - Florida | ||||||
1231 | GA - Georgia | ||||||
1232 | GU - Guam | ||||||
1233 | HI - Hawaii | ||||||
1234 | ID - Idaho | ||||||
1235 | IL - Illinois | ||||||
1236 | IN - Indiana | ||||||
1237 | IA - Iowa | ||||||
1238 | KS - Kansas | ||||||
1239 | KY - Kentucky | ||||||
1240 | LA - Louisiana | ||||||
1241 | ME - Maine | ||||||
1242 | MH - Marshall Islands | ||||||
1243 | MD - Maryland | ||||||
1244 | MA - Massachusetts | ||||||
1245 | MI - Michigan | ||||||
1246 | MN - Minnesota | ||||||
1247 | MS - Mississippi | ||||||
1248 | MO - Missouri | ||||||
1249 | MT - Montana | ||||||
1250 | NE - Nebraska | ||||||
1251 | NV - Nevada | ||||||
1252 | NH - New Hampshire | ||||||
1253 | NJ - New Jersey | ||||||
1254 | NM - New Mexico | ||||||
1255 | NY - New York | ||||||
1256 | NC - North Carolina | ||||||
1257 | ND - North Dakota | ||||||
1258 | MP - Northern Mariana Islands | ||||||
1259 | OH - Ohio | ||||||
1260 | OK - Oklahoma | ||||||
1261 | OR - Oregon | ||||||
1262 | PW - Palau | ||||||
1263 | PA - Pennsylvania | ||||||
1264 | PR - Puerto Rico | ||||||
1265 | RI - Rhode Island | ||||||
1266 | SC - South Carolina | ||||||
1267 | SD - South Dakota | ||||||
1268 | TN - Tennessee | ||||||
1269 | TX - Texas | ||||||
1270 | UT - Utah | ||||||
1271 | VT - Vermont | ||||||
1272 | VI - Virgin Islands | ||||||
1273 | VA - Virginia | ||||||
1274 | WA - Washington | ||||||
1275 | WV - West Virginia | ||||||
1276 | WI - Wisconsin | ||||||
1277 | WY - Wyoming | ||||||
1278 | END_OF_LIST | ||||||
1279 | } | ||||||
1280 | |||||||
1281 | ## | ||||||
1282 | # Returns a list of known Credit Card types. May be overriden. Should be | ||||||
1283 | # consistent with cc_validate. | ||||||
1284 | # | ||||||
1285 | sub cc_list ($) { | ||||||
1286 | 0 | 0 | 0 | 0 | split(/\n/,<<'END_OF_LIST'); | ||
1287 | Visa | ||||||
1288 | American Express | ||||||
1289 | MasterCard | ||||||
1290 | Discover | ||||||
1291 | Diner's Club | ||||||
1292 | END_OF_LIST | ||||||
1293 | } | ||||||
1294 | |||||||
1295 | ############################################################################### | ||||||
1296 | |||||||
1297 | =item cc_validate (%) | ||||||
1298 | |||||||
1299 | Returns error text if card number is invalid. Only checksum and | ||||||
1300 | consistence with card type is checked. | ||||||
1301 | |||||||
1302 | Card number is taken from 'number' argument and card type from 'type' | ||||||
1303 | argument (optionally). | ||||||
1304 | |||||||
1305 | Will store card number into a scalar reference given by 'validated' | ||||||
1306 | argument, if it exists and the card validates. Will store card type code | ||||||
1307 | into scalar reference given by 'typecode' argument if it exists and the | ||||||
1308 | card validates. Codes are: | ||||||
1309 | |||||||
1310 | VI -- Visa | ||||||
1311 | AE -- American Express | ||||||
1312 | MC -- Mastercard | ||||||
1313 | DC -- Discover | ||||||
1314 | |||||||
1315 | =cut | ||||||
1316 | |||||||
1317 | sub cc_validate ($%) { | ||||||
1318 | 4 | 4 | 1 | 184 | my $self=shift; | ||
1319 | 4 | 14 | my $args=get_args(\@_); | ||||
1320 | |||||||
1321 | 4 | 40 | my $number=$args->{'number'}; | ||||
1322 | 4 | 6 | my $type=$args->{'type'}; | ||||
1323 | |||||||
1324 | # General corrections and checks first. | ||||||
1325 | # | ||||||
1326 | 4 | 16 | $number=~s/\D//g; | ||||
1327 | 4 | 50 | 9 | if(length($number)<13) { | |||
1328 | 0 | 0 | return $self->Tx('Number is too short!'); | ||||
1329 | } | ||||||
1330 | |||||||
1331 | # Checksum first | ||||||
1332 | # | ||||||
1333 | 4 | 6 | my $sum=0; | ||||
1334 | 4 | 9 | for(my $i=0; $i!=length($number)-1; $i++) { | ||||
1335 | 60 | 75 | my $weight = substr($number, -1 * ($i + 2), 1) * (2 - ($i % 2)); | ||||
1336 | 60 | 100 | 101 | $sum += (($weight < 10) ? $weight : ($weight - 9)); | |||
1337 | } | ||||||
1338 | 4 | 50 | 9 | if(substr($number,-1) ne (10-$sum%10)%10) { | |||
1339 | ### dprint "have ".substr($number,-1)." want ".(10-$sum%10)%10; | ||||||
1340 | 0 | 0 | return $self->Tx('Invalid number!'); | ||||
1341 | } | ||||||
1342 | |||||||
1343 | # Guessing card type. | ||||||
1344 | # | ||||||
1345 | 4 | 5 | my $typecode; | ||||
1346 | 4 | 6 | my $realtype=''; | ||||
1347 | 4 | 4 | my $reqlen; | ||||
1348 | 4 | 100 | 14 | if($number =~ /^(?:34|37)/) { | |||
50 | |||||||
0 | |||||||
0 | |||||||
1349 | 1 | 2 | $realtype='american express'; | ||||
1350 | 1 | 2 | $typecode='AE'; | ||||
1351 | 1 | 2 | $reqlen=[15]; | ||||
1352 | } | ||||||
1353 | elsif($number =~ /^4/) { | ||||||
1354 | 3 | 5 | $realtype='visa'; | ||||
1355 | 3 | 3 | $typecode='VI'; | ||||
1356 | 3 | 4 | $reqlen=[13,16]; | ||||
1357 | } | ||||||
1358 | elsif($number =~ /^5/) { | ||||||
1359 | 0 | 0 | $realtype='master\s?card'; | ||||
1360 | 0 | 0 | $typecode='MC'; | ||||
1361 | 0 | 0 | $reqlen=[16]; | ||||
1362 | } | ||||||
1363 | elsif($number =~ /^6/) { | ||||||
1364 | 0 | 0 | $realtype='discover'; | ||||
1365 | 0 | 0 | $typecode='DC'; | ||||
1366 | 0 | 0 | $reqlen=[16]; | ||||
1367 | } | ||||||
1368 | else { | ||||||
1369 | 0 | 0 | return $self->Tx('Unknown card type!'); | ||||
1370 | } | ||||||
1371 | 4 | 50 | 7 | if($reqlen) { | |||
1372 | 4 | 100 | 8 | scalar(grep { length($number)==$_ } @$reqlen) || | |||
7 | 22 | ||||||
1373 | return $self->Tx('Invalid number length!'); | ||||||
1374 | } | ||||||
1375 | |||||||
1376 | # Checking guessed type against the given type. | ||||||
1377 | # | ||||||
1378 | 3 | 50 | 66 | 19 | if($type && lc($type) !~ $realtype) { | ||
1379 | 0 | 0 | return $self->Tx('Number does not match card type!'); | ||||
1380 | } | ||||||
1381 | |||||||
1382 | # Storing values if we were given these references. | ||||||
1383 | # | ||||||
1384 | 3 | 50 | 7 | ${$args->{'validated'}}=$number if $args->{'validated'}; | |||
3 | 4 | ||||||
1385 | 3 | 50 | 7 | ${$args->{'typecode'}}=$typecode if $args->{'typecode'}; | |||
3 | 4 | ||||||
1386 | |||||||
1387 | 3 | 10 | return ''; | ||||
1388 | } | ||||||
1389 | |||||||
1390 | ## | ||||||
1391 | # Calculates year - accepts value, +N, -N. | ||||||
1392 | # | ||||||
1393 | sub calculate_year ($$) { | ||||||
1394 | 0 | 0 | 0 | 0 | my $self=shift; | ||
1395 | 0 | 0 | my $year=shift; | ||||
1396 | 0 | 0 | 0 | if(substr($year,0,1) eq '+') { | |||
0 | |||||||
0 | |||||||
0 | |||||||
1397 | 0 | 0 | $year=(localtime)[5]+1900+substr($year,1); | ||||
1398 | } | ||||||
1399 | elsif(substr($year,0,1) eq '-') { | ||||||
1400 | 0 | 0 | $year=(localtime)[5]+1900-substr($year,1); | ||||
1401 | } | ||||||
1402 | elsif($year < 20) { | ||||||
1403 | 0 | 0 | $year+=2000; | ||||
1404 | } | ||||||
1405 | elsif($year < 100) { | ||||||
1406 | 0 | 0 | $year+=1900; | ||||
1407 | } | ||||||
1408 | 0 | 0 | $year; | ||||
1409 | } | ||||||
1410 | |||||||
1411 | ## | ||||||
1412 | # Returns form phase for multi-page forms. Taken from 'phase' argument | ||||||
1413 | # to 'display' method. | ||||||
1414 | # | ||||||
1415 | sub form_phase ($) { | ||||||
1416 | 0 | 0 | 0 | 0 | my $self=shift; | ||
1417 | 0 | 0 | 0 | return $self->{'phase'} || 1; | |||
1418 | } | ||||||
1419 | |||||||
1420 | ############################################################################### | ||||||
1421 | |||||||
1422 | sub Tx ($$;$) { | ||||||
1423 | 1 | 1 | 0 | 3 | my $self=shift; | ||
1424 | 1 | 2 | my $text=shift; | ||||
1425 | 1 | 50 | 4 | my $values=shift || { }; | |||
1426 | |||||||
1427 | 1 | 50 | 7 | if($self->can('Tx_translate')) { | |||
1428 | 0 | 0 | $text=$self->Tx_translate($text,$values); | ||||
1429 | } | ||||||
1430 | |||||||
1431 | 1 | 2 | $text=~s/ | ||||
1432 | \{\{(\w+)\}\} | ||||||
1433 | / | ||||||
1434 | 0 | 0 | 0 | exists $values->{$1} ? $values->{$1} : ' |
|||
1435 | /xesg; | ||||||
1436 | |||||||
1437 | 1 | 5 | return $text; | ||||
1438 | } | ||||||
1439 | |||||||
1440 | ############################################################################### | ||||||
1441 | 1; | ||||||
1442 | __END__ |