blib/lib/HTML/FormHighlight.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 9 | 73 | 12.3 |
branch | 0 | 34 | 0.0 |
condition | 0 | 50 | 0.0 |
subroutine | 3 | 12 | 25.0 |
pod | 2 | 2 | 100.0 |
total | 14 | 171 | 8.1 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | ################################################################################ | ||||||
2 | # HTML::FormHighlight | ||||||
3 | # | ||||||
4 | # A module used to highlight fields in an HTML form. | ||||||
5 | # | ||||||
6 | # Author: Adekunle Olonoh | ||||||
7 | # Date: March 2001 | ||||||
8 | ################################################################################ | ||||||
9 | |||||||
10 | |||||||
11 | package HTML::FormHighlight; | ||||||
12 | |||||||
13 | |||||||
14 | ################################################################################ | ||||||
15 | # - Modules and Libraries | ||||||
16 | ################################################################################ | ||||||
17 | 1 | 1 | 684 | use strict; | |||
1 | 2 | ||||||
1 | 25 | ||||||
18 | 1 | 1 | 5 | use Carp; | |||
1 | 1 | ||||||
1 | 74 | ||||||
19 | 1 | 1 | 877 | use HTML::Parser; | |||
1 | 5805 | ||||||
1 | 1097 | ||||||
20 | |||||||
21 | |||||||
22 | |||||||
23 | ################################################################################ | ||||||
24 | # - Global Constants and Variables | ||||||
25 | ################################################################################ | ||||||
26 | $HTML::FormHighlight::VERSION = '0.03'; | ||||||
27 | |||||||
28 | |||||||
29 | ################################################################################ | ||||||
30 | # - Subroutines | ||||||
31 | ################################################################################ | ||||||
32 | |||||||
33 | |||||||
34 | ################################################################################ | ||||||
35 | # new() | ||||||
36 | ################################################################################ | ||||||
37 | sub new { | ||||||
38 | 0 | 0 | 1 | my ($proto, %options) = @_; | |||
39 | |||||||
40 | 0 | 0 | my $class = ref($proto) || $proto; | ||||
41 | |||||||
42 | 0 | my $self = bless {}, $class; | |||||
43 | |||||||
44 | 0 | return $self; | |||||
45 | } | ||||||
46 | |||||||
47 | |||||||
48 | ################################################################################ | ||||||
49 | # highlight() | ||||||
50 | ################################################################################ | ||||||
51 | sub highlight { | ||||||
52 | 0 | 0 | 1 | my ($self, %options) = @_; | |||
53 | |||||||
54 | # Initialize the fields option with a blank array ref | ||||||
55 | 0 | 0 | $options{'fields'} ||= []; | ||||
56 | |||||||
57 | # Buld a hash containing each of the field names pointing to a true value | ||||||
58 | 0 | $self->{'fields'} = { map { $_ => 1 } @{$options{'fields'}} }; | |||||
0 | |||||||
0 | |||||||
59 | |||||||
60 | # Initialize fields with parameters or defaults | ||||||
61 | 0 | 0 | $self->{'highlight'} = $options{'highlight'} || '*'; | ||||
62 | 0 | 0 | $self->{'mark'} = $options{'mark'} || ''; | ||||
63 | 0 | 0 | $self->{'all_in_group'} = $options{'all_in_group'} || 0; | ||||
64 | |||||||
65 | # Initialize private variables | ||||||
66 | 0 | $self->{'_output'} = ''; | |||||
67 | 0 | $self->{'_highlighted'} = {}; | |||||
68 | 0 | $self->{'_field_filled'} = {}; | |||||
69 | 0 | $self->{'_buffer'} = ''; | |||||
70 | |||||||
71 | # Create a regular expression for mark replacement | ||||||
72 | 0 | $self->{'_mark_regex'} = qr/^(.*)($self->{'mark'})((?!$self->{'mark'}).*)$/s; | |||||
73 | |||||||
74 | # Check for a CGI.pm (or equivalent) object | ||||||
75 | 0 | 0 | if ($options{'fobject'}) { | ||||
76 | # Die if the param() method isn't defined for the form object | ||||||
77 | 0 | 0 | croak('HTML::FormHighlight->highlight called with fobject option, containing object of type '.ref($options{'fobject'}).' which lacks a param() method.') unless defined($options{'fobject'}->can('param')); | ||||
78 | |||||||
79 | # Iterate over each form value | ||||||
80 | 0 | foreach my $key ($options{'fobject'}->param()) { | |||||
81 | # Indicate that the field has been filled in if it contains a true value | ||||||
82 | 0 | 0 | $self->{'_field_filled'}->{$key} = 1 if $options{'fobject'}->param($key); | ||||
83 | } | ||||||
84 | } | ||||||
85 | |||||||
86 | # Check for a hash reference containing form data | ||||||
87 | 0 | 0 | if ($options{'fdat'}){ | ||||
88 | # Iterate over each key | ||||||
89 | 0 | foreach my $key (keys %{$options{'fdat'}}) { | |||||
0 | |||||||
90 | # Indicate that the field has been filled in if it contains a true value | ||||||
91 | 0 | 0 | $self->{'_field_filled'}->{$key} = 1 if $options{'fdat'}->{$key}; | ||||
92 | } | ||||||
93 | } | ||||||
94 | |||||||
95 | |||||||
96 | # Create a new HTML::Parser object | ||||||
97 | my $parser = HTML::Parser->new( | ||||||
98 | api_version => 3, | ||||||
99 | 0 | 0 | start_h => [ sub { _start($self, @_) }, 'tagname, attr, text' ], | ||||
100 | 0 | 0 | end_h => [ sub { _end($self, @_) }, 'tagname, text' ], | ||||
101 | 0 | 0 | default_h => [ sub { _default($self, @_) }, 'text' ], | ||||
0 | |||||||
102 | ); | ||||||
103 | |||||||
104 | |||||||
105 | # Check for the parse method, and use HTML::Parser appropriately | ||||||
106 | 0 | 0 | if ($options{'file'}) { | ||||
0 | |||||||
0 | |||||||
107 | # Parse from file | ||||||
108 | 0 | $parser->parse_file($options{'file'}); | |||||
109 | } | ||||||
110 | elsif ($options{'scalarref'}) { | ||||||
111 | # Parse from scalar reference | ||||||
112 | 0 | $parser->parse(${$options{'scalarref'}}); | |||||
0 | |||||||
113 | } | ||||||
114 | elsif ($options{'arrayref'}) { | ||||||
115 | # Parse from array reference, iterating over each line | ||||||
116 | 0 | for (@{$options{'arrayref'}}) { | |||||
0 | |||||||
117 | 0 | $parser->parse($_); | |||||
118 | } | ||||||
119 | } | ||||||
120 | |||||||
121 | # Signal EOF to HTML::Parser | ||||||
122 | 0 | $parser->eof(); | |||||
123 | |||||||
124 | # Append the last of the buffered text to the output variable | ||||||
125 | 0 | $self->{'_output'} .= $self->{'_buffer'}; | |||||
126 | 0 | $self->{'_buffer'} = undef; | |||||
127 | |||||||
128 | # Return the generated output | ||||||
129 | 0 | return $self->{'_output'}; | |||||
130 | } | ||||||
131 | |||||||
132 | |||||||
133 | ################################################################################ | ||||||
134 | # _start() | ||||||
135 | ################################################################################ | ||||||
136 | sub _start { | ||||||
137 | 0 | 0 | my($self, $tagname, $attr, $origtext) = @_; | ||||
138 | |||||||
139 | # Check to make sure the current tag is a form field | ||||||
140 | 0 | 0 | 0 | if ( | |||
0 | |||||||
0 | |||||||
141 | ($tagname eq 'input') or | ||||||
142 | ($tagname eq 'textarea') or | ||||||
143 | ($tagname eq 'select') or | ||||||
144 | ($tagname eq 'option') | ||||||
145 | ){ | ||||||
146 | |||||||
147 | # Make sure the field has a name and that the field wasn't filled in | ||||||
148 | 0 | 0 | 0 | if ($self->{'fields'}->{$attr->{'name'}} and !$self->{'_field_filled'}->{$attr->{'name'}}) { | |||
149 | |||||||
150 | # Check for all input tags | ||||||
151 | 0 | 0 | 0 | if ($tagname eq 'input') { | |||
0 | |||||||
152 | |||||||
153 | # Check for text, password and file tags | ||||||
154 | 0 | 0 | 0 | if (($attr->{'type'} eq 'text') or ($attr->{'type'} eq 'password') or ($attr->{'type'} eq 'file')) { | |||
0 | 0 | ||||||
0 | |||||||
155 | |||||||
156 | # Insert the highlight | ||||||
157 | 0 | $self->_insert_highlight(); | |||||
158 | } | ||||||
159 | # Check for radio and checkbox tags | ||||||
160 | elsif (($attr->{'type'} eq 'radio') or ($attr->{'type'} eq 'checkbox')) { | ||||||
161 | |||||||
162 | # Check if all options in a group should be highlighted, | ||||||
163 | # or if an option in the group hasn't already been highlighted | ||||||
164 | 0 | 0 | 0 | if ($self->{'all_in_group'} or (!$self->{'_highlighted'}->{$attr->{'name'}})) { | |||
165 | |||||||
166 | # Insert the highlight | ||||||
167 | 0 | $self->_insert_highlight(); | |||||
168 | |||||||
169 | # Indicate that an option in the group has been highlighted | ||||||
170 | 0 | $self->{'_highlighted'}->{$attr->{'name'}} = 1; | |||||
171 | } | ||||||
172 | } | ||||||
173 | } | ||||||
174 | # Check for textarea or select tags | ||||||
175 | elsif (($tagname eq 'textarea') or ($tagname eq 'select')) { | ||||||
176 | # Insert the highlight | ||||||
177 | 0 | $self->_insert_highlight(); | |||||
178 | } | ||||||
179 | } | ||||||
180 | |||||||
181 | # Add the buffer and original text to output | ||||||
182 | 0 | $self->{'_output'} .= $self->{'_buffer'}.$origtext; | |||||
183 | |||||||
184 | # Clear the buffer | ||||||
185 | 0 | $self->{'_buffer'} = ''; | |||||
186 | } | ||||||
187 | else { | ||||||
188 | # Add the original text to the buffer | ||||||
189 | 0 | $self->{'_buffer'} .= $origtext; | |||||
190 | } | ||||||
191 | } | ||||||
192 | |||||||
193 | |||||||
194 | ################################################################################ | ||||||
195 | # _end() | ||||||
196 | ################################################################################ | ||||||
197 | sub _end { | ||||||
198 | 0 | 0 | my($self, $tagname, $origtext) = @_; | ||||
199 | |||||||
200 | # Check if the current tag is a form tag | ||||||
201 | 0 | 0 | 0 | if ( | |||
0 | |||||||
202 | ($tagname eq 'textarea') or | ||||||
203 | ($tagname eq 'select') or | ||||||
204 | ($tagname eq 'option') | ||||||
205 | ){ | ||||||
206 | # Add the buffer and original text to output | ||||||
207 | 0 | $self->{'_output'} .= $self->{'_buffer'}.$origtext; | |||||
208 | |||||||
209 | # Clear the buffer | ||||||
210 | 0 | $self->{'_buffer'} = ''; | |||||
211 | } | ||||||
212 | else { | ||||||
213 | # Add the original text to the buffer | ||||||
214 | 0 | $self->{'_buffer'} .= $origtext; | |||||
215 | } | ||||||
216 | } | ||||||
217 | |||||||
218 | |||||||
219 | ################################################################################ | ||||||
220 | # _default() | ||||||
221 | ################################################################################ | ||||||
222 | sub _default { | ||||||
223 | 0 | 0 | my($self, $origtext) = @_; | ||||
224 | |||||||
225 | # Add the original text to the buffer | ||||||
226 | 0 | $self->{'_buffer'} .= $origtext; | |||||
227 | } | ||||||
228 | |||||||
229 | |||||||
230 | ################################################################################ | ||||||
231 | # _insert_highlight() | ||||||
232 | ################################################################################ | ||||||
233 | sub _insert_highlight { | ||||||
234 | 0 | 0 | my $self = shift; | ||||
235 | |||||||
236 | # Check to make sure the buffer and mark exist, and that the buffer contains the mark | ||||||
237 | 0 | 0 | 0 | if (($self->{'_buffer'}) and ($self->{'mark'}) and ($self->{'_buffer'} =~ $self->{'_mark_regex'})) { | |||
0 | |||||||
238 | # Replace the last occurence of the mark with the highlight | ||||||
239 | 0 | $self->{'_buffer'} =~ s/$self->{'_mark_regex'}/$1$2$self->{'highlight'}$3/; | |||||
240 | } | ||||||
241 | else { | ||||||
242 | # Just append the highlight to the buffer | ||||||
243 | 0 | $self->{'_buffer'} .= $self->{'highlight'}; | |||||
244 | } | ||||||
245 | } | ||||||
246 | |||||||
247 | |||||||
248 | 1; | ||||||
249 | |||||||
250 | |||||||
251 | =head1 NAME | ||||||
252 | |||||||
253 | HTML::FormHighlight - Highlights fields in an HTML form. | ||||||
254 | |||||||
255 | |||||||
256 | =head1 SYNOPSIS | ||||||
257 | |||||||
258 | use HTML::FormHighlight; | ||||||
259 | |||||||
260 | my $h = new HTML::FormHighlight; | ||||||
261 | |||||||
262 | print $h->highlight( | ||||||
263 | scalarref => \$form, | ||||||
264 | fields => [ 'A', 'B', 'C' ], | ||||||
265 | ); | ||||||
266 | |||||||
267 | print $h->highlight( | ||||||
268 | scalarref => \$form, | ||||||
269 | fields => [ 'A', 'B', 'C' ], | ||||||
270 | highlight => '*', | ||||||
271 | mark => '', | ||||||
272 | all_in_group => 1, | ||||||
273 | ); | ||||||
274 | |||||||
275 | |||||||
276 | =head1 DESCRIPTION | ||||||
277 | |||||||
278 | HTML::FormHighlight can be used to highlight fields in an HTML form. It uses HTML::Parser to parse the HTML form, and then places text somewhere before each field to highlight the field. You can specify which fields to highlight, and optionally supply a CGI object for it to check whether or not an input value exists before highlighting the field. | ||||||
279 | |||||||
280 | It can be used when displaying forms where a user hasn't filled out a required field. The indicator can make it easier for a user to locate the fields that they've missed. If you're interested in more advanced form validation, see L |
||||||
281 | |||||||
282 | =head1 METHODS | ||||||
283 | |||||||
284 | |||||||
285 | =head2 new() | ||||||
286 | |||||||
287 | Create a new HTML::FormHighlight object. Example: | ||||||
288 | |||||||
289 | $h = new HTML::FormHighlight; | ||||||
290 | |||||||
291 | |||||||
292 | =head2 highlight() | ||||||
293 | |||||||
294 | Parse through the HTML form and highlight fields. The method returns a scalar containing the parsed form. Here are a few examples: | ||||||
295 | |||||||
296 | To highlight the fields 'A', 'B' and 'C' (form on disk): | ||||||
297 | |||||||
298 | $h->highlight( | ||||||
299 | file => 'form.html', | ||||||
300 | fields => [ 'A', 'B', 'C' ], | ||||||
301 | ); | ||||||
302 | |||||||
303 | To highlight the fields 'A' and 'B' with a smiley face | ||||||
304 | (form as a scalar): | ||||||
305 | |||||||
306 | $h->highlight( | ||||||
307 | scalarref => \$form, | ||||||
308 | fields => [ 'A', 'B' ], | ||||||
309 | highlight => '', | ||||||
310 | ); | ||||||
311 | |||||||
312 | To highlight the fields 'A' and 'B' if they haven't been supplied | ||||||
313 | by form input (form as an array of lines): | ||||||
314 | |||||||
315 | $q = new CGI; | ||||||
316 | |||||||
317 | $h->highlight( | ||||||
318 | arrayref => \@form, | ||||||
319 | fields => [ 'A', 'B' ], | ||||||
320 | fobject => $q, | ||||||
321 | ); | ||||||
322 | |||||||
323 | Note: highlight() will only highlight the first option in a radio or select group unless the all_in_group flag is set to a true value. | ||||||
324 | |||||||
325 | Here's a list of possible parameters for highlight() and their descriptions: | ||||||
326 | |||||||
327 | =over 4 | ||||||
328 | |||||||
329 | =item * | ||||||
330 | |||||||
331 | scalarref - a reference to a scalar that contains the text of the form. | ||||||
332 | |||||||
333 | =item * | ||||||
334 | |||||||
335 | arrayref - a reference to an array of lines that contain the text of the form. | ||||||
336 | |||||||
337 | =item * | ||||||
338 | |||||||
339 | file - a scalar that contains the file name where the form is kept. | ||||||
340 | |||||||
341 | =item * | ||||||
342 | |||||||
343 | fields - a reference to an array that lists the fields to be highlighted. If used in conjunction with "fobject" or "fdat", only the fields listed that are empty will be highlighted. | ||||||
344 | |||||||
345 | =item * | ||||||
346 | |||||||
347 | highlight - a scalar that contains the highlight indicator. Defaults to a red asterisk (*). | ||||||
348 | |||||||
349 | =item * | ||||||
350 | |||||||
351 | mark - a regex specifying where to place the highlight indicator. If this is empty, the indicator will be inserted directly before the form field. The HTML form does not need to contain the text specified in the regex before each form field. highlight() will only use a mark for a field if there is no other form field before the field it's highlighting. If there is more than one mark before a field, it will only highlight the last mark. If it doesn't find a mark, it will insert the indicator directly before the form field. Here are a few examples: | ||||||
352 | |||||||
353 | code: | ||||||
354 | ===== | ||||||
355 | |||||||
356 | $h->highlight( | ||||||
357 | file => 'form.html', | ||||||
358 | fields => [ 'A', 'B', 'C' ], | ||||||
359 | mark => '' | ||||||
360 | highlight => '***', | ||||||
361 | ); | ||||||
362 | |||||||
363 | |||||||
364 | input: | ||||||
365 | ====== | ||||||
366 | |||||||
367 | |||||||
368 | Field B: | ||||||
369 | |||||||
370 | |||||||
371 | output: | ||||||
372 | ======= | ||||||
373 | |||||||
374 | *** | ||||||
375 | *** Field B: | ||||||
376 | *** | ||||||
377 | |||||||
378 | |||||||
379 | input: | ||||||
380 | ====== | ||||||
381 | |||||||
382 | Field A: |
||||||
383 | Field B: | ||||||
384 | Field C: | ||||||
385 | |||||||
386 | |||||||
387 | |||||||
388 | |||||||
389 | output: | ||||||
390 | ======= | ||||||
391 | |||||||
392 | Field A: *** |
||||||
393 | Field B: *** | ||||||
394 | Field C: | ||||||
395 | |||||||
396 | *** | ||||||
397 | |||||||
398 | |||||||
399 | |||||||
400 | input: | ||||||
401 | ====== | ||||||
402 | |||||||
403 | Field A: | ||||||
404 | Foo... |
||||||
405 | Bar... |
||||||
406 | |||||||
407 | |||||||
408 | Field B: | ||||||
409 | |||||||
410 | |||||||
411 | Field C: | ||||||
412 | |||||||
413 | |||||||
414 | |||||||
415 | |||||||
416 | |||||||
417 | output: | ||||||
418 | ======= | ||||||
419 | |||||||
420 | Field A: | ||||||
421 | Foo... |
||||||
422 | *** Bar... |
||||||
423 | |||||||
424 | |||||||
425 | Field B: | ||||||
426 | *** | ||||||
427 | |||||||
428 | Field C: | ||||||
429 | |||||||
430 | |||||||
431 | *** | ||||||
432 | |||||||
433 | |||||||
434 | |||||||
435 | Warning: Since the mark field is a regular expression, make sure to escape it appropriately. "\s" will insert the highlight after the last space character. To replace all occurrences of a backslash followed by the letter s, use "\\\s". | ||||||
436 | |||||||
437 | =item * | ||||||
438 | |||||||
439 | all_in_group - set this to 1 if you want all options in a radio or checkbox group to be highlighted. It's set to 0 by default. | ||||||
440 | |||||||
441 | =item * | ||||||
442 | |||||||
443 | fobject - a CGI.pm object, or another object which has a param() method that works like CGI.pm's. HTML::FormHighlight will check to see if a parameter does not have a value before highlighting the field. | ||||||
444 | |||||||
445 | =item * | ||||||
446 | |||||||
447 | fdat - a hash reference, with the field names as keys. HTML::FormHighlight will check to see if a parameter does not have a value before highlighting the field. | ||||||
448 | |||||||
449 | =back 4 | ||||||
450 | |||||||
451 | =head1 BUGS | ||||||
452 | |||||||
453 | =over 4 | ||||||
454 | |||||||
455 | =item * | ||||||
456 | |||||||
457 | highlight() will add the highlight indicator inside an HTML tag if you're not careful. | ||||||
458 | |||||||
459 | For example, if you use "\s" as your mark and "***" as your indicator, | ||||||
460 | |||||||
461 | A: | ||||||
462 | |||||||
463 | will result in: | ||||||
464 | |||||||
465 | A: | ||||||
466 | |||||||
467 | not: | ||||||
468 | |||||||
469 | A: *** | ||||||
470 | |||||||
471 | =back 4 | ||||||
472 | |||||||
473 | |||||||
474 | =head1 VERSION | ||||||
475 | |||||||
476 | 0.03 | ||||||
477 | |||||||
478 | =head1 AUTHOR | ||||||
479 | |||||||
480 | Adekunle Olonoh, ade@bottledsoftware.com | ||||||
481 | |||||||
482 | =head1 CREDITS | ||||||
483 | |||||||
484 | Hiroki Chalfant | ||||||
485 | |||||||
486 | =head1 COPYRIGHT | ||||||
487 | |||||||
488 | Copyright (c) 2000 Adekunle Olonoh. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. | ||||||
489 | |||||||
490 | =head1 SEE ALSO | ||||||
491 | |||||||
492 | L |
||||||
493 | |||||||
494 | =cut |