NAME
HTML::FormEngine - create,validate and control html/xhtml forms
DEPENDENCIES
Perl Version
5.004
Standard Modules
Carp
Nonstandard Modules
Clone 0.13
Hash::Merge 0.07
Locale::gettext 1.01
Date::Pcalc 1.2
Digest::MD5 2.24
HTML::Entities 1.27
SYNOPSIS
Example Code
#!/usr/bin/perl -w
use strict;
use CGI;
use HTML::FormEngine;
#use POSIX; # for setlocale
#setlocale(LC_MESSAGES, 'german'); # for german error messages
my $q = new CGI;
print $q->header;
my $Form = HTML::FormEngine->new(scalar $q->Vars);
my @form = (
{
templ => 'select',
NAME => 'Salutation',
OPTION => [[['mr.','mrs.']]],
},
{
templ => 'hidden_no_title',
NAME => 'test123',
VALUE => 'test',
},
{
SIZE => 10,
MAXLEN => 20,
PREFIX => [[' ', ' / ']],
NAME => 'name',
TITLE => 'For- / Surname ',
ERROR_IN => 'not_null'
},
{
MAXLEN => 30,
NAME => 'Email',
ERROR => ['not_null', ['rfc822'], ['match', 'matched net!']] # rfc822 defines the email address standard
},
{
templ => 'radio',
TITLE => 'Subscribe to newsletter?',
NAME => 'newsletter',
OPT_VAL => [[1, 2, 3]],
OPTION => [['Yes', 'No', 'Perhaps']],
VALUE => 1
},
{
templ => 'check',
OPTION => 'I agree to the terms of condition!',
NAME => "agree",
TITLE => '',
ERROR => sub{ return("you've to agree!") if(! shift); }
}
);
$Form->set_seperate(1);
$Form->conf(\@form);
$Form->make();
print $q->start_html('FormEngine example: Registration');
if($Form->ok){
$Form->clear();
print "<center>You've successfully subscribed!</center><br>";
}
print $Form->get,
$q->end_html;
Example Output
This output is produced by FormEngine when using the example code and no data was submitted:
<form action="/cgi-bin/formengine/registration.cgi" method="post" name="FormEngine" accept="*" enctype="application/x-www-form-urlencoded" target="_self" id="FormEngine" >
<table border=0 cellspacing=1 cellpadding=1 align="center" >
<tr >
<td valign="top" align="left" ><label for="Salutation" accesskey="">Salutation</label><span ></span></td>
<td >
<table border=0 cellspacing=0 cellpadding=0 >
<tr >
<td valign="top" >
<table border=0 cellspacing=0 cellpadding=0 >
<tr >
<td align="" valign="" > </td>
<td >
<select size="" name="Salutation" id="Salutation" >
<option value="mr." label="mr." >mr.</option>
<option value="mrs." label="mrs." >mrs.</option>
</select>
</td>
<td > </td>
</tr>
<tr ><td ></td><td style="color:#FF0000"></td></tr>
</table>
</td>
</tr>
</table>
</td>
<td align="left" valign="bottom" style="color:#FF0000"></td><input type="hidden" name="Salutation" value="f29e202fda026b18561398f7879cdf37" />
</tr>
<tr ></tr>
<tr >
<td valign="top" align="left" ><label for="name" accesskey="">For- / Surname </label><span ></span></td>
<td >
<table border=0 cellspacing=0 cellpadding=0 >
<tr >
<td valign="top" >
<table border=0 cellspacing=0 cellpadding=0 >
<tr >
<td align="" valign="" > </td>
<td >
<input type="text" value="" name="name" id="name" maxlength="20" size="10" />
</td>
<td > </td>
</tr>
<tr ><td ></td><td style="color:#FF0000"></td></tr>
</table>
</td>
<td valign="top" >
<table border=0 cellspacing=0 cellpadding=0 >
<tr >
<td align="" valign="" > / </td>
<td >
<input type="text" value="" name="name" id="name" maxlength="20" size="10" />
</td>
<td > </td>
</tr>
<tr ><td ></td><td style="color:#FF0000"></td></tr>
</table>
</td>
</tr>
</table>
</td>
<td align="left" valign="bottom" style="color:#FF0000"></td><input type="hidden" name="name" value="f29e202fda026b18561398f7879cdf37" />
</tr>
<tr >
<td valign="top" align="left" ><label for="Email" accesskey="">Email</label><span ></span></td>
<td >
<table border=0 cellspacing=0 cellpadding=0 >
<tr >
<td valign="top" >
<table border=0 cellspacing=0 cellpadding=0 >
<tr >
<td align="" valign="" > </td>
<td >
<input type="text" value="" name="Email" id="Email" maxlength="30" size="20" />
</td>
<td > </td>
</tr>
<tr ><td ></td><td style="color:#FF0000"></td></tr>
</table>
</td>
</tr>
</table>
</td>
<td align="left" valign="bottom" style="color:#FF0000"></td><input type="hidden" name="Email" value="f29e202fda026b18561398f7879cdf37" />
</tr>
<tr >
<td valign="top" align="left" ><label for="newsletter" accesskey="">Subscribe to newsletter?</label><span ></span></td>
<td >
<table border=0 cellspacing=0 cellpadding=0 >
<tr >
<td valign="top" >
<table border=0 cellspacing=0 cellpadding=0 >
<tr >
<td align="" valign="" > </td>
<td >
<input type="radio" value="1" name="newsletter" id="newsletter" checked />Yes
</td>
<td > </td>
</tr>
<tr ><td ></td><td style="color:#FF0000"></td></tr>
</table>
</td>
<td valign="top" >
<table border=0 cellspacing=0 cellpadding=0 >
<tr >
<td align="" valign="" > </td>
<td >
<input type="radio" value="2" name="newsletter" id="newsletter" />No
</td>
<td > </td>
</tr>
<tr ><td ></td><td style="color:#FF0000"></td></tr>
</table>
</td>
<td valign="top" >
<table border=0 cellspacing=0 cellpadding=0 >
<tr >
<td align="" valign="" > </td>
<td >
<input type="radio" value="3" name="newsletter" id="newsletter" />Perhaps
</td>
<td > </td>
</tr>
<tr ><td ></td><td style="color:#FF0000"></td></tr>
</table>
</td>
</tr>
</table>
</td>
<td align="left" valign="bottom" style="color:#FF0000"></td><input type="hidden" name="newsletter" value="f29e202fda026b18561398f7879cdf37" />
</tr>
<tr >
<td valign="top" align="left" ></td>
<td >
<table border=0 cellspacing=0 cellpadding=0 >
<tr >
<td valign="top" >
<table border=0 cellspacing=0 cellpadding=0 >
<tr >
<td align="" valign="" > </td>
<td >
<input type="checkbox" value="I agree to the terms of condition!" name="agree" id="agree" />I agree to the terms of condition!
</td>
<td > </td>
</tr>
<tr ><td ></td><td style="color:#FF0000"></td></tr>
</table>
</td>
</tr>
</table>
</td>
<td align="left" valign="bottom" style="color:#FF0000"></td><input type="hidden" name="agree" value="f29e202fda026b18561398f7879cdf37" />
</tr>
<tr >
<td align="right" colspan=3 >
<input type="submit" value="Ok" name="FormEngine" />
</td>
</tr>
</table>
</form>
DESCRIPTION
FormEngine.pm is a Perl 5 object class which provides an api for managing html/xhtml forms. FormEngine has its own, very flexible template system for defining form skins. A default skin and a more flexible one is provided. This should be sufficent in most cases, but extending the skins or making your own isn't difficult (please send them to me!).
FormEngine also provides a set of functions for checking the form input, it is very easy to define your own check methods or to adapt the given.
gettext is used for internationalization (e.g. error messages). So use setlocale(LC_MESSAGES, 'german')
if you want to have german error messages, butten lables and so on (there isn't support for any other language yet, but it shouldn't be difficult to translate the .po file, don't hesitate!).
Another usefull feature is the confirm
method which forces the user to read through his input once again before submitting it.
FormEngine is designed to make extension writing an easy task!
OVERVIEW
Start with calling the new
method, it will return an FormEngine object. As argument you should pass a reference to a hash of input values (calling set_input
is also possible, environments like mod_perl or CGI.pm offer already a hash of input values, see set_input
for more). Now define an array which contains the form configuration and pass a reference to conf
. Then call make
, this will generate the html code. Next you can use ok
to check if the form was submitted and all input values are correct. If this is the case, you can e.g. display a success message and call get_input(fieldname)
for getting the value of a certain field and e.g. write it in a database. Else you should call get
(which will return the html form code) or print
which will directly print the form.
If you want the form to be always displayed, you can use clear
to empty it (resp. display the defaults) when the transmission was successfull.
USING FORMENGINE
The easiest way to define your form is to create an array of hash references:
my @form = (
{
templ => 'select',
NAME => 'Salutation',
OPTION => [[['mr.','mrs.']]],
},
{
templ => 'hidden_no_title',
NAME => 'test123',
VALUE => 'test',
},
{
SIZE => 10,
MAXLEN => 20,
PREFIX => [[' ', ' / ']],
NAME => 'name',
TITLE => 'For- / Surname ',
ERROR_IN => 'not_null'
},
{
MAXLEN => 30,
NAME => 'Email',
ERROR => ['not_null', ['rfc822'], ['match', 'matched net!']] # rfc822 defines the email address standard
},
{
templ => 'radio',
TITLE => 'Subscribe to newsletter?',
NAME => 'newsletter',
OPT_VAL => [[1, 2, 3]],
OPTION => [['Yes', 'No', 'Perhaps']],
VALUE => 1
},
{
templ => 'check',
OPTION => 'I agree to the terms of condition!',
NAME => "agree",
TITLE => '',
ERROR => sub{ return("you've to agree!") if(! shift); }
}
);
This was taken out of the example above. The templ key defines the field type (resp. template), the capital written keys are explained below. If templ is not defined, it is expected to be text
.
Then pass a reference to that array to the conf
method like this:
$Form->conf(\@form);
Another possibility is to define a hash of hash references and pass a reference on that to conf
. This is seldom needed, but has the advantage that you can define low level variables:
my %form = (
METHOD => 'get',
FORMNAME => 'myform',
SUBMIT => 'Yea! I want that!',
'sub' => [
# Here you place your form definition (see above)
]
);
$Form->conf(\%form);
The meaning of the keys is explained below. You can call set_main_vars
for setting low level (main) variables as well, the only difference is that the variables set through "set_main_vars ( HASHREF )" are persistend, that means even if you call the "conf ( FORMCONF )" method again they're still set if not overwritten.
The Default Skin (FormEngine)
If you want to use the same fieldname several times (e.g. for a group of checkboxes or for two textfields like name and forename), you have to call set_seperate
and pass 1 (for true). See set_seperate
for more.
The following templates are known by the default skin:
text - text input field(s), one row
textarea - text input field(s), several rows
radio - check box list (one can be selected)
select - pull down menu or a box with options (one or several can be selected)
check - check box list (several can be selected)
hidden - invisible field(s), can be used for passing data
button - displays a standard, submit or a reset button
print - this template simply prints out the submitted value but also saves it because it contains a hidden field
The following templates are also known by the default skin but perhaps a bit more difficult to understand and not so often used:
select_optgroup - like select but lets you subdevide the options in groups (see examples/namechooser.cgi)
select_flexible - lets you mix optgroup,optgroup_flexible and option (see examples/namechooser.cgi)
optgroup - has to be placed in
select_flexible
,optgroup_flexible
or similar (see examples/namechooser.cgi)optgroup_flexible - lets you nest option groups, cannot exist on the first level (see examples/namechooser.cgi)
option - has to be placed in
select_flexible
,optgroup_flexible
or similar (see examples/namechooser.cgi)fieldset - can be used for grouping fields (see examples/feedback_fieldset.cgi)
These fields are normally only used automatically for generating the confirmation form but could be that they're also for some individual usage:
print_option - like
print
but for printing out a list of submitted optionstempl - just used to print a list of other templates
If you want to nest templates resp. place a template in another template you have to call it with a leading '_' (underscore). So use _text instead of text and so on.
Add _notitle to the templates name if you don't want to have a title, add _noerror if you don't want to check for errors, add _notitle_noerror if you don't want both and simply add a 2 if you want the error messages to stand under the field and not next to it. Read and run the examples for more information.
NOTE: All information given here about templates and variables is only valid for the default skin and for SkinComplex. Other skins should bring their own documentation.
Variables
Note that if you don't use the default skin, things might be diffrent. But mostly only the layout changes. A skin which doesn't fit to the following conventiones should have its own documentation.
These Variables are always available:
NAME - the form fields name (this must be passed to "get_input ( FIELDNAME )" for getting the complying value)
TITLE - the displayed title of the field, by default the value of NAME
VALUE - the default (or initial) value of the field
ERROR - accepts name of an FormEngine check routine (see Config.pm and Checks.pm), an anonymous function or an reference to a named method. If an array reference is passed, a list of the above mentioned values is expected. FormEngine will then call these routines one after another until an error message is returned or the end of the list is reached. If you want to alter the default error messages or you want to pass arguments to it, you can do so by passing arrays like [checkmethod, "error message", arg1, arg2], see
namechooser.cgi
for an example.
These variables are available for the text template only:
SIZE - the physical length of the field (in characters) [default: 20]
MAXLEN - max. count of characters that can be put into the field [default: no limit]
TYPE - if set to password for each character a * is printed (instead of the character) [default: text]
These variables are available for selection templates (radio
, select
, check
and all similar ones) only:
OPTION - accepts an reference to an array with options
OPT_VAL - accepts an reference to an array with values for the options (by default the value of OPTION is used)
These variables are available for the optgroup template and all similar ones:
OPTGROUP - defines the titles of the option groups
These variables are available for the textarea template only:
COLS - the width of the text input area [default: 27]
ROWS - the height of the text input area [default: 10]
These variables are available for the button template only:
TYPE - can be 'button', 'submit' or 'reset' [default: 'button']
These variables are so called main variables, they can be set by using the hash notation (see "USING FORMENGINE") or by calling "set_main_vars ( HASHREF )":
ACTION - the url of the page to which the form data should be submitted [default: $ENV{REQUEST_URI}, that means: the script calls itself]. Normally it doesn't make sense to change this value, but when you use mod_perl, you should set it to $r-uri>.
METHOD - can be 'post' (transmit the data in HTTP header) or 'get' (transmit the data by appeding it to the url) [default: post].
SUBMIT - the text that should be displayed on the submit button [default: Ok]
FORMNAME - the string by which this form should be identified [default: FormEngine]. You must change this if you have more than one FormEngine-made form on a page. Else FormEngine won't be able to distinguish which form was submitted.
Note: only NAME must be set, all other variables are optional.
Please also run the example scripts and read their code (they're very short), it'll help you a lot understanding how to use FormEngine.
To really understand the skin system, how it works and what possibilites there are you'll have to read the documentation of and the code in the following files: Skin.pm, SkinComplex.pm, SkinClassic.pm, SkinClassicConfirm.pm. These files are related to each other in exactly this order, there's also SkinClassicConfirm.pm which inherits everythings from SkinComplex but besides that it looks the same like SkinClassicConfirm.pm.
There are many more variables and possibilites than documented above, you have to read the template definitions in the skin packages to know more!
Methods For Creating Forms
new ([ HASHREF ])
This method is the constructor. It returns an FormEngine object. You should pass the form input in a hash reference to it, but you can use "set_input ( HASHREF )" as well.
set_input ( HASHREF )
You have to pass a reference to a hash with input values. You can pass this hash reference to the constructor (new
) as well, then you don't need this function. If you use mod_perl you can get this reference by calling 'scalar $m->request_args'. If you use CGI.pm you get it by calling 'scalar $q->Vars'.
conf ( FORMCONF )
You have to pass the configuration of your form as array or hash reference (see "USING FORMENGINE").
set_seperate ( BOOLEAN )
You've to pass true in case you want to use the same field name in diffrent template calls. Its turned off by default because you won't be able to set field values with java-script once it is enabled (which doesn't matter in most cases).
set_main_vars ( HASHREF )
You can use this method for setting the values of the main template variables (e.g. SUBMIT). Another possibility to do that is using the hash notation when configuring the form (see "USING FORMENGINE"). The diffrence is that the object saves the settings made through this method so that they're automatically reset when calling the "conf ( FORMCONF )" method again. If you set the variables directly throught the hash notation they're not persistent.
This method doesn't overwrite all settings which where probably already made before, it only overwrites the variables which are defined in the given HASH! So you can call this method several times to complete your configuration or overwrite certain values.
To delete main variable settings use "del_main_vars ( ARRAY )".
del_main_vars ( ARRAY )
Use this method to unset so called main variables. They're not only removed out of the form configuration but also out of the cache so that you can get rid of settings that you once made with "set_main_vars ( HASHREF )" but which you don't want anymore, in fact this is the real purpose of this method. Just pass the names of the variables which should not be defined anymore.
clear ( )
If the form was submitted, this method simply calls "set_use_input ( VALUE )" and "set_error_chk ( VALUE )". It sets both to false. If make was already called, it calls it again, so that no user input is shown and no error checking is done. Use it to reset the form.
set_error_chk ( VALUE )
Sets whether the error handler should be called or not. Default is true (1).
set_use_input ( VALUE )
Sets whether the given input should be displayed in the form fields or not. Default is true (1).
make ( )
Creates the html/xhtml output, but doesn't return it (see "get ( )" and "print ( )"). Every method call which influences this output must be called before calling make!
print ( )
Sends the html/xhtml output directly to STDOUT. "make ( )" must be called first!
get ( )
Returns the html/xhtml form code in a string. "make ( )" must be called first!
ok ( )
Returns true (1) if the form was submitted and no errors were found! Else it returns false (0).
This method simply calls "is_submitted ( )" and "get_error_count ( )" but also checks whether a confirmation was canceled ("confirmation_canceled ( )"). So normally you'll use this method instead of calling all 3 functions, especially if you deal with the confirmation feature of FormEngine (see "confirm ( [CONFIRMMSG] )").
"make ( )" must be called before calling this method!
get_error_count ( )
Returns the count of errors which where found by the error handler. "make ( )" must be called first!
is_submitted ( )
Returns true (1) if the form was submitted, false (0) if not.
errors ( )
Returns true if the form was submitted and errors where found.
confirmation_canceled ( )
Returns true if the user pressed Cancel when he was asked to confirm the given input.
get_input ( FIELDNAME )
Returns the input value of the corresponding field. If it has only one value a scalar, if it has several values an array is returned. If set_seperate
was called with 1 (true) it packs the values which belong together into subarrays.
confirm ( [CONFIRMMSG] )
Calling this method will print the users input data and ask him to click 'Ok' or 'Cancel'. 'Ok' will submit the data once again and then is_confirmed
will return true (1). 'Cancel' will display the form, so that the user can change the data.
By default the message defined for CONFIRMSG in Skin.pm will be displayed, but you can also pass your own text.
is_confirmed ( )
This method returns true (1) when the form input was affirmed by the user (see "confirm ( [CONFIRMSG] )").
Methods For Configuring FormEngine
set_skin_obj ( OBJECT )
If you want to use an alternative skin, call this method. You've to pass a valid skin object.
An example: $form-
set_skin_obj(new HTML::FormEngine::SkinComplex)>.
The default skin object is an instance of HTML::FormEngine::SkinClassic
.
For more information please read HTML::FormEngine::Skin.
Of course this method has to be called before calling "make ( )".
get_skin_obj ( )
Returns the currently used skin object.
Debug Methods
set_debug ( DEBUGLEVEL )
Sets the debug level. The higher the value the more output is printed (to STDERR).
get_method ( )
Returns the value of mains METHOD variable (should be get or post).
get_formname ( )
Returns the value of mains FORMNAME variable. If you have several FormEngine forms on one page, these forms mustn't have the same FORMNAME value! You can set it with "set_main_vars ( HASHREF )".
get_conf ( )
Returns a reference to a hash with the current form configuration. Changing this hash doesn't influence the configuration, because it is just a copy.
print_conf ( HASHREF )
Prints the given form configuration to STDERR.
Special Features
nesting templates
There are two ways how you can nest templates. The first one is to put a handler call in the template definition. This is a less flexible solution, but it might be very usefull. See HTML::FormEngine::Skin for more information.
The second and flexible way is, to assign a handler call to a template variable (see HTML::FormEngine::Skin for more information about handler calls). A good example for this way is hobbies.cgi. There you have a option called other and an input field to put in the name of this alternative hobby. When you look at the form definition below, you see that the value of the OPTION variable of this option is simply <&_text&>, this is a handler call. So the handler is called and its return value (in this case the processed _text
template) is assigned to the variable.
The form definition of hobbies.cgi:
my @form = (
{
templ => 'check',
NAME => 'hobbie',
TITLE => 'Hobbies',
OPTION => [['Parachute Jumping', 'Playing Video Games'], ['Doing Nothing', 'Soak'], ['Head Banging', 'Cat Hunting'], "Don't Know", '<&_text&>'],
OPT_VAL => [[1,2], [3,4], [5,6], 7, 8],
VALUE => [1,2,7],
'sub' => {'_text' => {'NAME' => 'Other', 'VALUE' => '', ERROR => ''}},
ERROR_IN => sub{if(shift eq 4) { return "That's not a faithfull hobby!" }}
}
);
If you have a closer look at the form definition above, you'll recognize that there is a key called 'sub'. With help of this key you can define the variables of the nested templates. If the nested templates don't use the same variable names as their parents, you don't need that, because then you can assign these variables on the same level with the parents template variables.
EXTENDING FORMENGINE
Modify A Skin
To set the current skin, use the method "set_skin_obj ( OBJECT )". To Modify it you should have a look at HTML::FormEngine::Skin.
Extending Or Writing A Skin
Have a look at HTML::FormEngine::Skin for this task and especially read its source code and the code and documentation of the other skin packages. You can easily change the layout by copying the skin hash, fitting the html code to your needs and then using "set_skin_obj ( OBJECT )" to overwrite the default. Please send me your skins.
Write A Handler
Read HTML::FormEngine::Handler. Also read HTML::FormEngine::Skin on how to make the handler available. To make it persistent see "Extending Or Writing A Skin".
Write A Check Routine
The design of a check routine is explained in HTML::FormEngine::Checks. You can easily refer to it by reference or even define it in line as an anonymous function (see the ERROR template variable). If your new written routine is of general usage, you should make it part of FormEngine by placing it in Checks.pm and refering to it from Skin.pm. For more read HTML::FormEngine::Skin. Please send me your check methods!
MORE INFORMATION
Have a look at ...
HTML::FormEngine::Skin, HTML::FormEngine::SkinComplex, HTML::FormEngine::SkinClassic, HTML::FormEngine::SkinComplexConfirm, HTML::FormEngine::SkinClassicConfirm and the modules source code for information about FormEngines template and skin system.
HTML::FormEngine::Handler and the modules source code for information about FormEngines handler architecture.
HTML::FormEngine::Checks and the modules source code for information about FormEngines check methods.
BUGS
Please use http://rt.cpan.org/NoAuth/Bugs.html?Dist=HTML-FormEngine to inform you about reported bugs and to report bugs.
If it doesn't work feel free to email directly to moritz@freesources.org.
Thanks!
AUTHOR
(c) 2003-2004, Moritz Sinn. This module is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (see http://www.gnu.org/licenses/gpl.txt) as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This module is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
I am always interested in knowing how my work helps others, so if you put this module to use in any of your own code please send me the URL. If you make modifications to the module because it doesn't work the way you need, please send me a copy so that I can roll desirable changes into the main release.
Please use http://rt.cpan.org/NoAuth/Bugs.html?Dist=HTML-FormEngine for comments, suggestions and bug reports. If it doesn't work feel free to mail to moritz@freesources.org.
CREDITS
Special thanks go to Darren Duncan. His HTML::FormTemplate module gave me a good example how to write a documentation. There are several similarities between HTML::FormEngine and HTML::FormTemplate, we both came to an related API design, the internal processes are completly diffrent. It wasn't my purpose to have these api design decisions in common with HTML::FormTemplate. When i wrote the php version of HTML::FormEngine, i didn't know anything about HTML::FormTemplate. Later i just ported this php class to perl. I think we both came to an likewise API because its just the most obvious solution.
Features which FormEngine has and FormTemplate hasn't:
Skinsystem
More flexible validation and error message report
Common checking methods are predefined, others can be added on the fly
Internationalization with help of gettext
Due to the handler system and the modular design FormEngine can easily be extended
A flexible set of methods to let the user confirm his input
Features which FormTemplate has and FormEngine hasn't:
This list will be filled in later.
(I asked the author to send me some notes, he told me he'll do so at opportunity.)
SEE ALSO
HTML::FormTemplate by Darren Duncan