package WebGUI::Form;
=head1 LEGAL
-------------------------------------------------------------------
WebGUI is Copyright 2001-2005 Plain Black Corporation.
-------------------------------------------------------------------
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 Tie::IxHash;
use WebGUI::Asset;
use WebGUI::Asset::RichEdit;
use WebGUI::Asset::Template;
use WebGUI::DateTime;
use WebGUI::International;
use WebGUI::Session;
use WebGUI::SQL;
use WebGUI::Style;
use WebGUI::URL;
use WebGUI::Utility;
=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::asset({value=>$assetId});
$html = WebGUI::Form::button({value=>"Click me!", extras=>qq|onclick="alert('Aaaaggggghhh!!!')"|});
$html = WebGUI::Form::checkbox({name=>"whichOne", value=>"red"});
$html = WebGUI::Form::checkList({name=>"dayOfWeek", options=>\%days});
$html = WebGUI::Form::codearea({name=>"stylesheet"});
$html = WebGUI::Form::color({name=>"highlightColor"});
$html = WebGUI::Form::combo({name=>"fruit",options=>\%fruit});
$html = WebGUI::Form::contentType({name=>"contentType");
$html = WebGUI::Form::databaseLink();
$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");
$html = WebGUI::Form::file({name=>"image"});
$html = WebGUI::Form::formFooter();
$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;
}
#-------------------------------------------------------------------
=head2 asset ( hashref )
Returns an asset picker control.
=head3 value
The asset ID assigned to this control.
=head3 name
The name of this field. Defaults to "asset".
=head3 defaultValue
If no value is specified, use this value.
=head3 class
Limit options to a specific class type such as "WebGUI::Asset::Wobject::Article"
=head3 extras
Assign extra things like javascript events to this form element.
=cut
sub asset {
my $params = shift;
my $value = defined($params->{value}) ? $params->{value} : $params->{defaultValue};
my $name = $params->{name} || "asset";
my $asset = WebGUI::Asset->newByDynamicClass($value) || WebGUI::Asset->getRoot;
return hidden({
name=>$name,
extras=>'id="'.$name.'" '.$params->{extras},
value=>$asset->getId
})
.text({
name=>$name."_display",
extras=>'id="'.$name."_display".'" readonly="1"',
value=>$asset->get("title")
})
.button({
value=>"...",
extras=>'onclick="window.open(\''.$asset->getUrl("op=formAssetTree&classLimiter=".$params->{class}."&formId=".$name).'\',\'assetPicker\',\'toolbar=no, location=no, status=no, directories=no, width=400, height=400\');"'
});
}
#-------------------------------------------------------------------
=head2 button ( hashRef )
Returns a button. Use it in combination with scripting code to make the button perform an action.
=head3 value
The button text for this submit button. Defaults to "save".
=head3 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:
'onClick="alert(\'You've just pushed me !\')"'
=head3 defaultValue
This will be used if no value is specified.
=cut
sub button {
my $params = shift;
my $value = $params->{value} || $params->{defaultValue} || WebGUI::International::get(62);
$value = _fixQuotes($value);
return '{extras}.' />';
}
#-------------------------------------------------------------------
=head2 checkbox ( hashRef )
Returns a checkbox form element.
=head3 name
The name field for this form element.
=head3 checked
If you'd like this box to be defaultly checked, set this to "1".
=head3 value
The default value for this form element.
=head3 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()"'
=head3 defaultValue
This will be used if no value is specified. Defaults to 1.
=cut
sub checkbox {
my $params = shift;
my $checkedText = ' checked="1"' if ($params->{checked});
my $value = $params->{value} || $params->{defaultValue} || 1;
return '{extras}.' />';
}
#-------------------------------------------------------------------
=head2 checkList ( hashRef )
Returns checkbox list.
=head3 name
The name field for this form element.
=head3 options
The list of options for this list. Should be passed as a hash reference.
=head3 value
The default value(s) for this form element. This should be passed as an array reference.
=head3 vertical
If set to "1" the radio button elements will be laid out horizontally. Defaults to "0".
=head3 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()"'
=head3 defaultValue
This will be used if no value is specified. Should be passed as an array reference.
=cut
sub checkList {
my $params = shift;
my ($output, $checked, $key, $item);
my $values = $params->{value} || $params->{defaultValue};
foreach $key (keys %{$params->{options}}) {
$checked = 0;
foreach $item (@{$values}) {
if ($item eq $key) {
$checked = 1;
}
}
$output .= checkbox({
name=>$params->{name},
value=>$key,
extras=>$params->{extras},
checked=>$checked
});
$output .= ${$params->{options}}{$key};
if ($params->{vertical}) {
$output .= "
\n";
} else {
$output .= " \n";
}
}
return $output;
}
sub codearea {
my $params = shift;
WebGUI::Style::setScript($session{config}{extrasURL}.'/TabFix.js',{type=>"text/javascript"});
$params->{extras} = 'style="width: 99%; min-width: 440px; height: 400px" onkeypress="return TabFix_keyPress(event)" onkeydown="return TabFix_keyDown(event)"';
my $output = textarea($params);
return $output;
}
#-------------------------------------------------------------------
=head2 color ( hashRef )
Returns a color picker field.
=head3 name
The name field for this form element.
=head3 value
The value for this form element. This should be a scalar containing a hex color like "#000000".
=head3 defaultValue
This will be used if no value is specified.
=cut
sub color {
my $params = shift;
WebGUI::Style::setScript($session{config}{extrasURL}.'/colorPicker.js',{ type=>'text/javascript' });
return '';
}
#-------------------------------------------------------------------
=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.
=head3 name
The name field for this form element.
=head3 options
The list of options for the select list. Should be passed as a hash reference.
=head3 value
The default value(s) for this form element. This should be passed as an array reference.
=head3 size
The number of characters tall this form element should be. Defaults to "1".
=head3 multiple
A boolean value for whether this select list should allow multiple selections. Defaults to "0".
=head3 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()"'
=head3 defaultValue
This will be used if no value is specified. Should be passed as an array reference.
=cut
sub combo {
my $params = shift;
$params->{options}->{''} = '['.WebGUI::International::get(582).']';
$params->{options}->{_new_} = WebGUI::International::get(581).'->';
my $output = selectList({
name=>$params->{name},
options=>$params->{options},
value=>$params->{value} || $params->{defaultValue},
multiple=>$params->{multiple},
extras=>$params->{extras}
});
my $size = $session{setting}{textBoxSize}-5;
$output .= text({name=>$params->{name}."_new",size=>$size});
return $output;
}
#-------------------------------------------------------------------
=head2 contentType ( hashRef )
Returns a content type select list field. This is usually used to help tell WebGUI how to treat posted content.
=head3 name
The name field for this form element.
=head3 types
An array reference of field types to be displayed. The types are "mixed", "html", "code", and "text". Defaults to all.
=head3 value
The default value for this form element.
=head3 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()"'
=head3 defaultValue
This will be used if no value is specified. Defaults to "mixed".
=cut
sub contentType {
my $params = shift;
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(mixed html code text);
$params->{types} = \@types unless ($params->{types});
foreach $type (@{$params->{types}}) {
if ($type eq "text") {
$hash{text} = WebGUI::International::get(1010);
} elsif ($type eq "mixed") {
$hash{mixed} = WebGUI::International::get(1008);
} elsif ($type eq "code") {
$hash{code} = WebGUI::International::get(1011);
} elsif ($type eq "html") {
$hash{html} = WebGUI::International::get(1009);
}
}
return selectList({
options=>\%hash,
name=>$params->{name},
value=>[$params->{value}],
extras=>$params->{extras},
defaultValue=>[$params->{defaultValue}]
});
}
#-------------------------------------------------------------------
=head2 databaseLink ( hashRef )
Returns a select list of database links.
=head3 name
The name field for this form element. Defaults to "databaseLinkId".
=head3 value
The unique identifier for the selected template.
=head3 defaultValue
This will be used if no value is specified. Defaults to 0 (the WebGUI database).
=cut
sub databaseLink {
my $params = shift;
my $value = $params->{value} || $params->{defaultValue} || 0;
my $name = $params->{name} || "databaseLinkId";
return selectList({
name=>$name,
options=>WebGUI::DatabaseLink::getList(),
value=>[$value]
});
}
#-------------------------------------------------------------------
=head2 date ( hashRef )
Returns a date field.
=head3 name
The name field for this form element.
=head3 value
The default date. Pass as an epoch value. Defaults to today.
=head3 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()"'
=head3 size
The number of characters wide this form element should be. There should be no reason for anyone to specify this.
=head3 noDate
By default a date is placed in the "value" field. Set this to "1" to turn off the default date.
=head3 defaultValue
This will be used if no value is specified. Defaults to today.
=cut
sub date {
my $params = shift;
my $value = epochToSet($params->{value}||$params->{defaultValue}) unless ($params->{noDate} && $params->{value} eq '');
my $size = $params->{size} || 10;
WebGUI::Style::setScript($session{config}{extrasURL}.'/calendar/calendar.js',{ type=>'text/javascript' });
WebGUI::Style::setScript($session{config}{extrasURL}.'/calendar/lang/calendar-en.js',{ type=>'text/javascript' });
WebGUI::Style::setScript($session{config}{extrasURL}.'/calendar/calendar-setup.js',{ type=>'text/javascript' });
WebGUI::Style::setLink($session{config}{extrasURL}.'/calendar/calendar-win2k-1.css', { rel=>"stylesheet", type=>"text/css", media=>"all" });
return text({
name=>$params->{name},
value=>$value,
size=>$size,
extras=>'id="'.$params->{name}.'Id" '.$params->{extras},
maxlength=>10
}) . '';
}
#-------------------------------------------------------------------
=head2 dateTime ( hashRef )
Returns a date/time field.
=head3 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.
=head3 value
The date and time. Pass as an epoch value. Defaults to today and now.
=head3 extras
Extra parameters to add to the date/time form element such as javascript or stylesheet information.
=head3 defaultValue
This will be used if no value is specified. Defaults to today and now.
=cut
sub dateTime {
my $params = shift;
my $value = epochToSet($params->{value}||$params->{defaultValue},1);
WebGUI::Style::setScript($session{config}{extrasURL}.'/calendar/calendar.js',{ type=>'text/javascript' });
WebGUI::Style::setScript($session{config}{extrasURL}.'/calendar/lang/calendar-en.js',{ type=>'text/javascript' });
WebGUI::Style::setScript($session{config}{extrasURL}.'/calendar/calendar-setup.js',{ type=>'text/javascript' });
WebGUI::Style::setLink($session{config}{extrasURL}.'/calendar/calendar-win2k-1.css', { rel=>"stylesheet", type=>"text/css", media=>"all" });
return text({
name=>$params->{name},
value=>$value,
size=>19,
extras=>'id="'.$params->{name}.'Id" '.$params->{extras},
maxlength=>19
}) . '';
}
#-------------------------------------------------------------------
=head2 dynamicField ( fieldType , hashRef )
Returns a dynamic configurable field.
=head3 fieldType
The field type to use. The field name is the name of the method from this forms package.
=head3 options
The field options. See the documentation for the desired field for more information.
=cut
sub dynamicField {
my $fieldType = shift;
my $param = shift;
# Set options for fields that use a list.
if (isIn($fieldType,qw(selectList checkList radioList))) {
delete $param->{size};
my %options;
tie %options, 'Tie::IxHash';
foreach (split(/\n/, $param->{possibleValues})) {
s/\s+$//; # remove trailing spaces
$options{$_} = $_;
}
if (exists $param->{options} && ref($param->{options}) eq "HASH") {
%options = (%{$param->{options}} , %options);
}
$param->{options} = \%options;
}
# Convert value to list for selectList / checkList
if (isIn($fieldType,qw(selectList checkList)) && ref $param->{value} ne "ARRAY") {
my @defaultValues;
foreach (split(/\n/, $param->{value})) {
s/\s+$//; # remove trailing spaces
push(@defaultValues, $_);
}
$param->{value} = \@defaultValues;
}
# Return the appropriate field.
no strict 'refs';
return &$fieldType($param);
}
#-------------------------------------------------------------------
=head2 email ( hashRef )
Returns an email address field.
=head3 name
The name field for this form element.
=head3 value
The default value for this form element.
=head3 maxlength
The maximum number of characters to allow in this form element.
=head3 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()"'
=head3 size
The number of characters wide this form element should be. There should be no reason for anyone to specify this.
=head3 defaultValue
This will be used if no value is specified.
=cut
sub email {
my $params = shift;
WebGUI::Style::setScript($session{config}{extrasURL}.'/emailCheck.js',{ type=>'text/javascript' });
my $output .= text({
name=>$params->{name},
value=>$params->{value},
size=>$params->{size},
extras=>' onChange="emailCheck(this.value)" '.$params->{extras},
defaultValue=>$params->{defaultValue}
});
return $output;
}
#-------------------------------------------------------------------
=head2 fieldType ( hashRef )
Returns a field type select list field. This is primarily useful for building dynamic form builders.
=head3 name
The name field for this form element.
=head3 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.
=head3 value
The default value for this form element.
=head3 size
The number of characters tall this form element should be. Defaults to "1".
=head3 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()"'
=head3 defaultValue
This will be used if no value is specified.
=cut
sub fieldType {
my $params = shift;
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. =)
my @types = qw(dateTime time float zipcode text textarea HTMLArea url date email phone integer yesNo selectList radioList checkList);
$params->{types} = \@types unless ($params->{types});
foreach $type (@{$params->{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 "float") {
$hash{float} = WebGUI::International::get("float");
} 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);
}
}
return selectList({
options=>\%hash,
name=>$params->{name},
value=>[$params->{value}],
extras=>$params->{extras},
size=>$params->{size},
defaultValue=>[$params->{defaultValue}]
});
}
#-------------------------------------------------------------------
=head2 file ( hashRef )
Returns a file upload field.
=head3 name
The name field for this form element.
=head3 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()"'
=head3 size
The number of characters wide this form element should be. There should be no reason for anyone to specify this.
=cut
sub file {
my $params = shift;
my $size = $params->{size} || $session{setting}{textBoxSize} || 30;
return '{extras}.' />';
}
#-------------------------------------------------------------------
=head2 files ( hashRef )
Returns a multiple file upload control.
=head3 name
The name field for this form element.
=cut
sub files {
WebGUI::Style::setScript($session{config}{extrasURL}.'/FileUploadControl.js',{type=>"text/javascript"});
my $uploadControl = '