package WebGUI::Form;
=head1 LEGAL
-------------------------------------------------------------------
WebGUI is Copyright 2001-2003 Plain Black LLC.
-------------------------------------------------------------------
Please read the legal notices (docs/legal.txt) and the license
(docs/license.txt) that came with this distribution before using
this software.
-------------------------------------------------------------------
http://www.plainblack.com info@plainblack.com
-------------------------------------------------------------------
=cut
use strict;
use HTTP::BrowserDetect;
use WebGUI::DateTime;
use WebGUI::International;
use WebGUI::Session;
use WebGUI::SQL;
use WebGUI::Template;
use WebGUI::URL;
=head1 NAME
Package WebGUI::Form
=head1 DESCRIPTION
Base forms package. Eliminates some of the normal code work that goes along with creating forms. Used by the HTMLForm package.
=head1 SYNOPSIS
use WebGUI::Form;
$html = WebGUI::Form::checkbox({name=>"whichOne", value=>"red"});
$html = WebGUI::Form::checkList({name=>"dayOfWeek", options=>\%days});
$html = WebGUI::Form::combo({name=>"fruit",options=>\%fruit});
$html = WebGUI::Form::date({name=>"endDate", value=>$endDate});
$html = WebGUI::Form::dateTime({name=>"begin", value=>$begin});
$html = WebGUI::Form::email({name=>"emailAddress"});
$html = WebGUI::Form::fieldType({name=>"fieldType",types=>\%supportedTypes});
$html = WebGUI::Form::file({name=>"image"});
$html = WebGUI::Form::formHeader();
$html = WebGUI::Form::filterContent({value=>"javascript"});
$html = WebGUI::Form::float({name=>"distance"});
$html = WebGUI::Form::group({name=>"groupToPost"});
$html = WebGUI::Form::hidden({name=>"wid",value=>"55"});
$html = WebGUI::Form::hiddenList({name=>"wid",value=>"55",options=>\%options});
$html = WebGUI::Form::HTMLArea({name=>"description"});
$html = WebGUI::Form::integer({name=>"size"});
$html = WebGUI::Form::interval({name=>"timeToLive", interval=>12, units=>"hours"});
$html = WebGUI::Form::password({name=>"identifier"});
$html = WebGUI::Form::phone({name=>"cellPhone"});
$html = WebGUI::Form::radio({name=>"whichOne", value=>"red"});
$html = WebGUI::Form::radioList({name="dayOfWeek", options=>\%days});
$html = WebGUI::Form::selectList({name=>"dayOfWeek", options=>\%days, value=>\@array"});
$html = WebGUI::Form::submit();
$html = WebGUI::Form::template({name=>"templateId"});
$html = WebGUI::Form::text({name=>"firstName"});
$html = WebGUI::Form::textarea({name=>"emailMessage"});
$html = WebGUI::Form::timeField({name=>"begin", value=>$begin});
$html = WebGUI::Form::url({name=>"homepage"});
$html = WebGUI::Form::yesNo({name=>"happy"});
$html = WebGUI::Form::zipcode({name=>"workZip"});
=head1 METHODS
All of the functions in this package accept the input of a hash reference containing the parameters to populate the form element. These functions are available from this package:
=cut
#-------------------------------------------------------------------
sub _fixMacros {
my $value = shift;
$value =~ s/\^/\&\#94\;/g;
return $value;
}
#-------------------------------------------------------------------
sub _fixQuotes {
my $value = shift;
$value =~ s/\"/\"\;/g;
return $value;
}
#-------------------------------------------------------------------
sub _fixSpecialCharacters {
my $value = shift;
$value =~ s/\&/\&\;/g;
return $value;
}
#-------------------------------------------------------------------
sub _fixTags {
my $value = shift;
$value =~ s/\\<\;/g;
$value =~ s/\>/\>\;/g;
return $value;
}
#-------------------------------------------------------------------
sub _javascriptFile {
return ''."\n";
}
#-------------------------------------------------------------------
=head2 checkbox ( hashRef )
Returns a checkbox form element.
=over
=item name
The name field for this form element.
=item checked
If you'd like this box to be defaultly checked, set this to "1".
=item value
The default value for this form element. Defaults to "1".
=item extras
If you want to add anything special to this form element like javascript actions, or stylesheet information, you'd add it in here as follows:
'onChange="this.form.submit()"'
=back
=cut
sub checkbox {
my ($checkedText, $value);
$checkedText = ' checked="1"' if ($_[0]->{checked});
$value = $_[0]->{value} || 1;
return '{extras}.'>';
}
#-------------------------------------------------------------------
=head2 checkList ( hashRef )
Returns checkbox list.
=over
=item name
The name field for this form element.
=item options
The list of options for this list. Should be passed as a hash reference.
=item value
The default value(s) for this form element. This should be passed as an array reference.
=item vertical
If set to "1" the radio button elements will be laid out horizontally. Defaults to "0".
=item extras
If you want to add anything special to this form element like javascript actions, or stylesheet information, you'd add it in here as follows:
'onChange="this.form.submit()"'
=back
=cut
sub checkList {
my ($output, $checked, $key, $item);
foreach $key (keys %{$_[0]->{options}}) {
$checked = 0;
foreach $item (@{$_[0]->{value}}) {
if ($item eq $key) {
$checked = 1;
}
}
$output .= checkbox({
name=>$_[0]->{name},
value=>$key,
extras=>$_[0]->{extras},
checked=>$checked
});
$output .= ${$_[0]->{options}}{$key};
if ($_[0]->{vertical}) {
$output .= "
\n";
} else {
$output .= " \n";
}
}
return $output;
}
#-------------------------------------------------------------------
=head2 combo ( hashRef )
Returns a select list and a text field. If the text box is filled out it will have a value stored in "name"_new.
=over
=item name
The name field for this form element.
=item options
The list of options for the select list. Should be passed as a hash reference.
=item value
The default value(s) for this form element. This should be passed as an array reference.
=item size
The number of characters tall this form element should be. Defaults to "1".
=item multiple
A boolean value for whether this select list should allow multiple selections. Defaults to "0".
=item extras
If you want to add anything special to this form element like javascript actions, or stylesheet information, you'd add it in here as follows:
'onChange="this.form.submit()"'
=back
=cut
sub combo {
my ($output, $size);
$_[0]->{options}->{''} = '['.WebGUI::International::get(582).']';
$_[0]->{options}->{_new_} = WebGUI::International::get(581).'->';
$output = selectList({
name=>$_[0]->{name},
options=>$_[0]->{options},
value=>$_[0]->{value},
multiple=>$_[0]->{multiple},
extras=>$_[0]->{extras}
});
$size = $session{setting}{textBoxSize}-5;
$output .= text({name=>$_[0]->{name}."_new",size=>$size});
return $output;
}
#-------------------------------------------------------------------
=head2 date ( hashRef )
Returns a date field.
=over
=item name
The name field for this form element.
=item value
The default date. Pass as an epoch value. Defaults to today.
=item extras
If you want to add anything special to this form element like javascript actions, or stylesheet information, you'd add it in here as follows:
'onChange="this.form.submit()"'
=item size
The number of characters wide this form element should be. There should be no reason for anyone to specify this.
=item noDate
By default a date is placed in the "value" field. Set this to "1" to turn off the default date.
=back
=cut
sub date {
my ($subtext, $noDate, $class, $name, $label, $extras, $size, $value);
$value = epochToSet($_[0]->{value});
$size = $_[0]->{size} || 10;
$value = "" if ($_[0]->{noDate});
my $output = _javascriptFile('inputCheck.js');
$output .= text({
name=>$_[0]->{name},
value=>$value,
size=>$size,
extras=>'onKeyUp="doInputCheck(this.form.'.$_[0]->{name}.',\'0123456789/\')" '.$_[0]->{extras},
maxlength=>10
});
$output .= '';
return $output;
}
#-------------------------------------------------------------------
=head2 dateTime ( hashRef )
Returns a date/time field.
=over
=item name
The the base name for this form element. This form element actually returns two values under different names. They are name_date and name_time.
=item value
The date and time. Pass as an epoch value. Defaults to today and now.
=item dateExtras
Extra parameters to add to the date form element such as javascript or stylesheet information.
=item timeExtras
Extra parameters to add to the time form element such as javascript or stylesheet information.
=back
=cut
sub dateTime {
my $output = date({
name=>$_[0]->{name}."_date",
value=>$_[0]->{value},
extras=>$_[0]->{dateExtras}
});
$output .= timeField({
name=>$_[0]->{name}."_time",
value=>WebGUI::DateTime::getSecondsFromEpoch($_[0]->{value}),
extras=>$_[0]->{timeExtras}
});
return $output;
}
#-------------------------------------------------------------------
=head2 email ( hashRef )
Returns an email address field.
=over
=item name
The name field for this form element.
=item value
The default value for this form element.
=item maxlength
The maximum number of characters to allow in this form element.
=item extras
If you want to add anything special to this form element like javascript actions, or stylesheet information, you'd add it in here as follows:
'onChange="this.form.submit()"'
=item size
The number of characters wide this form element should be. There should be no reason for anyone to specify this.
=back
=cut
sub email {
my ($output);
$output = _javascriptFile('emailCheck.js');;
$output .= text({
name=>$_[0]->{name},
value=>$_[0]->{value},
extras=>' onChange="emailCheck(this.value)" '.$_[0]->{extras}
});
return $output;
}
#-------------------------------------------------------------------
=head2 fieldType ( hashRef )
Returns a field type select list field. This is primarily useful for building dynamic form builders.
=over
=item name
The name field for this form element.
=item types
An array reference of field types to be displayed. The field names are the names of the methods from this forms package. Note that not all field types are supported. Defaults to all.
=item value
The default value for this form element.
=item size
The number of characters tall this form element should be. Defaults to "1".
=item extras
If you want to add anything special to this form element like javascript actions, or stylesheet information, you'd add it in here as follows:
'onChange="this.form.submit()"'
=back
=cut
sub fieldType {
my (%hash, $output, $type);
tie %hash, 'Tie::IxHash';
# NOTE: What you are about to see is bad code. Do not attempt this
# without adult supervision. =) It was done this way because a huge
# if/elsif construct executes much more quickly than a bunch of
# unnecessary database hits.
my @types = qw(dateTime time zipcode text textarea HTMLArea url date email phone integer yesNo selectList radioList checkList);
$_[0]->{types} = \@types unless ($_[0]->{types});
foreach $type (@{$_[0]->{types}}) {
if ($type eq "text") {
$hash{text} = WebGUI::International::get(475);
} elsif ($type eq "timeField") {
$hash{timeField} = WebGUI::International::get(971);
} elsif ($type eq "dateTime") {
$hash{dateTime} = WebGUI::International::get(972);
} elsif ($type eq "textarea") {
$hash{textarea} = WebGUI::International::get(476);
} elsif ($type eq "HTMLArea") {
$hash{HTMLArea} = WebGUI::International::get(477);
} elsif ($type eq "url") {
$hash{url} = WebGUI::International::get(478);
} elsif ($type eq "date") {
$hash{date} = WebGUI::International::get(479);
} elsif ($type eq "email") {
$hash{email} = WebGUI::International::get(480);
} elsif ($type eq "phone") {
$hash{phone} = WebGUI::International::get(481);
} elsif ($type eq "integer") {
$hash{integer} = WebGUI::International::get(482);
} elsif ($type eq "yesNo") {
$hash{yesNo} = WebGUI::International::get(483);
} elsif ($type eq "selectList") {
$hash{selectList} = WebGUI::International::get(484);
} elsif ($type eq "radioList") {
$hash{radioList} = WebGUI::International::get(942);
} elsif ($type eq "checkList") {
$hash{checkList} = WebGUI::International::get(941);
} elsif ($type eq "zipcode") {
$hash{zipcode} = WebGUI::International::get(944);
} elsif ($type eq "checkbox") {
$hash{checkbox} = WebGUI::International::get(943);
}
}
# This is a hack for reverse compatibility with a bug where this field used to allow an array ref.
my $value = $_[0]->{value};
unless ($value eq "ARRAY") {
$value = [$value];
}
return selectList({
options=>\%hash,
name=>$_[0]->{name},
value=>$_[0]->{value},
extras=>$_[0]->{extras},
size=>$_[0]->{size}
});
}
#-------------------------------------------------------------------
=head2 file ( hashRef )
Returns a file upload field.
=over
=item name
The name field for this form element.
=item extras
If you want to add anything special to this form element like javascript actions, or stylesheet information, you'd add it in here as follows:
'onChange="this.form.submit()"'
=item size
The number of characters wide this form element should be. There should be no reason for anyone to specify this.
=back
=cut
sub file {
my ($size);
$size = $_[0]->{size} || $session{setting}{textBoxSize} || 30;
return '{extras}.'>';
}
#-------------------------------------------------------------------
=head2 filterContent ( hashRef )
Returns a select list containing the content filter options. This is for use with WebGUI::HTML::filter().
=over
=item name
The name field for this form element. This defaults to "filterContent".
=item value
The default value for this form element.
=item extras
If you want to add anything special to this form element like javascript actions, or stylesheet information, you'd add it in here as follows:
'onChange="this.form.submit()"'
=back
=cut
sub filterContent {
my %filter;
tie %filter, 'Tie::IxHash';
%filter = (
'none'=>WebGUI::International::get(420),
'macros'=>WebGUI::International::get(891),
'javascript'=>WebGUI::International::get(526),
'most'=>WebGUI::International::get(421),
'all'=>WebGUI::International::get(419)
);
my $name = $_[0]->{name} || "filterContent";
return selectList({
name=>$name,
options=>\%filter,
value=>[$_[0]->{value}],
extras=>$_[0]->{extras}
});
}
#-------------------------------------------------------------------
=head2 formHeader ( hashRef )
Returns a form header.
=over
=item action
The form action. Defaults to the current page.
=item method
The form method. Defaults to "POST".
=item enctype
The form enctype. Defaults to "multipart/form-data".
=item extras
If you want to add anything special to the form header like javascript actions or stylesheet info, then use this.
=back
=cut
sub formHeader {
my ($action, $method, $enctype);
$action = $_[0]->{action} || WebGUI::URL::page();
$method = $_[0]->{method} || "POST";
$enctype = $_[0]->{enctype} || "multipart/form-data";
return '