package CGI::Ex::Fill;
=head1 NAME
CGI::Ex::Fill - Fast but compliant regex based form filler
=cut
###----------------------------------------------------------------###
# Copyright 2007 - Paul Seamons #
# Distributed under the Perl Artistic License without warranty #
###----------------------------------------------------------------###
use strict;
use vars qw($VERSION
@EXPORT @EXPORT_OK
$REMOVE_SCRIPT
$REMOVE_COMMENT
$MARKER_SCRIPT
$MARKER_COMMENT
$OBJECT_METHOD
$_TEMP_TARGET
);
use base qw(Exporter);
BEGIN {
$VERSION = '2.16';
@EXPORT = qw(form_fill);
@EXPORT_OK = qw(fill form_fill html_escape get_tagval_by_key swap_tagval_by_key);
};
### These directives are used to determine whether or not to
### remove html comments and script sections while filling in
### a form. Default is on. This may give some trouble if you
### have a javascript section with form elements that you would
### like filled in.
BEGIN {
$REMOVE_SCRIPT = 1;
$REMOVE_COMMENT = 1;
$MARKER_SCRIPT = "\0SCRIPT\0";
$MARKER_COMMENT = "\0COMMENT\0";
$OBJECT_METHOD = "param";
};
###----------------------------------------------------------------###
### Regex based filler - as opposed to HTML::Parser based HTML::FillInForm
### arguments are positional
### pos1 - text or textref - if textref it is modified in place
### pos2 - hash or cgi obj ref, or array ref of hash and cgi obj refs
### pos3 - target - to be used for choosing a specific form - default undef
### pos4 - boolean fill in password fields - default is true
### pos5 - hashref or arrayref of fields to ignore
sub form_fill {
my $text = shift;
my $ref = ref($text) ? $text : \$text;
my $form = shift;
my $target = shift;
my $fill_password = shift;
my $ignore = shift || {};
fill({
text => $ref,
form => $form,
target => $target,
fill_password => $fill_password,
ignore_fields => $ignore,
});
return ref($text) ? 1 : $$ref;
}
sub fill {
my $args = shift;
my $ref = $args->{'text'};
my $form = $args->{'form'};
my $target = $args->{'target'};
my $ignore = $args->{'ignore_fields'};
my $fill_password = $args->{'fill_password'};
my $forms = UNIVERSAL::isa($form, 'ARRAY') ? $form : [$form];
$ignore = {map {$_ => 1} @$ignore} if UNIVERSAL::isa($ignore, 'ARRAY');
$fill_password = 1 if ! defined $fill_password;
### allow for optionally removing comments and script
my @comment;
my @script;
if (defined($args->{'remove_script'}) ? $args->{'remove_script'} : $REMOVE_SCRIPT) {
$$ref =~ s|( tags which often cause problems for
parsers.
=item remove_comment
Defaults to the package global $REMOVE_COMMENT which defaults to true.
Removes anything in tags which can sometimes cause problems for
parsers.
=item object_method
The method to call on objects passed to the form argument. Default value
is the package global $OBJECT_METHOD which defaults to 'param'. If a
CGI object is passed, it would call param on that object passing
the desired keyname as an argument.
=back
=head1 ARGUMENTS TO form_fill
The following are the arguments to the legacy function C.
=over 4
=item C<\$html>
A reference to an html string that includes one or more forms or form
entities.
=item C<\%FORM>
A form hash, or CGI query object, or an arrayref of multiple hash refs
and/or CGI query objects that will supply values for the form.
=item C<$form_name>
The name of the form to fill in values for. The default is undef
which indicates that all forms are to be filled in.
=item C<$swap_pass>
Default true. Indicates that C<input type="password"> fields
are to be swapped as well. Set to false to disable this behavior.
=item C<\%IGNORE_FIELDS> OR C<\@IGNORE_FIELDS>
A hash ref of key names or an array ref of key names that will be
ignored during the fill in of the form.
=back
=head1 BEHAVIOR
fill and form_fill will attempt to DWYM when filling in values. The following behaviors
are used on the following types of form elements.
=over 4
=item Cinput type="text"E>
The following rules are used when matching this type:
1) Get the value from the form that matches the input's "name".
2) If the value is defined - it adds or replaces the existing value.
3) If the value is not defined and the existing value is not defined,
a value of "" is added.
For example:
my $form = {foo => "FOO", bar => "BAR", baz => "BAZ"};
my $html = '
';
form_fill(\$html, $form);
$html eq '
';
If the value returned from the form is an array ref, the values of the array ref
will be sequentially used for each input found by that name until the values
run out. If the value is not an array ref - it will be used to fill in any values
by that name. For example:
$form = {foo => ['aaaa', 'bbbb', 'cccc']};
$html = '
';
form_fill(\$html, $form);
$html eq '
';
=item Cinput type="hidden"E>
Same as Cinput type="text"E>.
=item Cinput type="password"E>
Same as Cinput type="text"E>.
=item Cinput type="file"E>
Same as Cinput type="text"E>. (Note - this is subject
to browser support for pre-population)
=item Cinput type="checkbox"E>
As each checkbox is found the following rules are applied:
1) Get the values from the form (do nothing if no values found)
2) Remove any existing "checked=checked" or "checked" markup from the tag.
3) Compare the "value" field to the values and mark with checked="checked"
if there is a match.
If no "value" field is found in the html, a default value of "on" will be used (which is
what most browsers will send as the default value for checked boxes without
"value" fields).
$form = {foo => 'FOO', bar => ['aaaa', 'bbbb', 'cccc'], baz => 'on'};
$html = '
';
form_fill(\$html, $form);
$html eq '
';
=item Cinput type="radio"E>
Same as Cinput type="checkbox"E>.
=item CselectE>
As each select box is found the following rules are applied (these rules are
applied regardless of if the box is a select-one or a select-multi - if multiple
values are selected on a select-one it is up to the browser to choose which one
to highlight):
1) Get the values from the form (do nothing if no values found)
2) Remove any existing "selected=selected" or "selected" markup from the tag.
3) Compare the "value" field to the values and mark with selected="selected"
if there is a match.
4) If there is no "value" field - use the text in between the "option" tags.
(Note: There does not need to be a closing "select" tag or closing "option" tag)
$form = {foo => 'FOO', bar => ['aaaa', 'bbbb', 'cccc']};
$html = '