LoadHtml

The README is used to introduce the module and provide instructions on
how to install the module, any machine dependencies it may have (for
example C compilers and installed libraries) and any other information
that should be provided before the module is installed.

A README file is required for CPAN modules since CPAN extracts the README
file from a module distribution so that people browsing the archive
can use it get an idea of the modules uses. It is usually a good idea
to provide version information here so that people can decide whether
fixes for the module are worth downloading.

INSTALLATION

To install this module, run the following commands:

    perl Makefile.PL
    make
    make test
    make install

SYNOPSIS

     use LoadHtml;
     print "Content-type: text/html", "\n";
     &loadhtml('mytemplate_file.html',
        -ascalararg => 'Display this string',
        -anarrayarg => ['string1', 'string2', 'string3'],
        -ahasharg => {'key1' => 10, 'key2' => 20, 'key3' => 30},
        -amatrix => [[1, 2, 3], [4, 5, 6]]
     );

COPYRIGHT AND LICENCE

Copyright (C) 1996-2007 by Jim Turner

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.


Documentation Updated: 09/07/2007

The LoadHtml Home Page

LoadHtml - Dynamic HTML Generation Library, by Jim Turner (turnerjw784 att yahoo .dot. com).
LoadHtml is a Perl library to enable Perl CGI programs to dynamically generate HTML pages from HTML page templates.  LoadHtml includes the following special features:

          o I) Special, nestable HTML control statements (IF-THEN-ELSE, LOOP, INCLUDE, SELECTLIST, etc.)!
          o II) HTML templates can be valid stand-alone HTML pages (with default values) for rapid prototyping.
          o III) Perl code and variables can be optionally embedded or prohibited (for security reasons) on a page-by-page basis.
          o IV) HTML pages can be generated and later displayed or saved using the "buildhtml" or "dohtml" functions.
          o V) Easy, dynamic table, select, checkbox and radio-button construct- creation using Perl variables, lists and hashes.
          o VII) Multiple ways to drive loops of HTML generation (by arrays, hashes, and traditional Perl/C FOR loops, ie. "1 to 100 by 5".

LoadHtml is written completely in Perl, a modern, high-performance scripting language.  CGI web applications are completely portable across all platforms which support Perl and CGI, including Unix and Windows.

Click for System Requirements.
I) Overview / User-callable Function List.
The following functions are user-callable:

&loadhtml($htmlfile,@args)
my $htmlstring = &buildhtml($htmlfile,@args)
my $htmlstring = &dohtml($htmltemplate_string,@args)
&AllowEvals(1|0)
&set_poc($poc_name)
&SetRegices()
&SetListSeperator($separator_string)
&SetHtmlHome($htmlhome, $roothtmlhome, $hrefhtmlhome, $hrefcase)
&loadhtml_package($package_name)

The Perl CGI program calls loadhtml() when it is ready to generate and display an HTML page.  The 1st argument is the path and file-name of the html template file to be used to generate the page.  The remaining arguments are the data values to be substituted in the html page based on special HTML codes within the template page before the final page is displayed.  When loadhtml is called, the template html file is loaded and parsed, all argument/parameter substitutions are made, all dynamic html is generated, and the final html is sent to the browser to be displayed.  NOTE:  It is the calling program's responisibility to print any needed HTML headers BEFORE calling loadhtml.

By default, embedded perl code and variables in HTML templates are not evaluated for security reasons.  To enable loadhtml to process these, first call "AllowEvals(1)".  To turn back off, call "AllowEvals(0)".

Call "set_poc" at the beginning of your CGI script to set a point-of-contact name to be displayed on any error screens generated by LoadHtml.

By default, any Perl list arguments passed to loadhtml, where the corresponding html code in the template file is not within a "LOOP" or "SELECTLIST" construct; will print out all values of the list separated by a comma, followed by a space.  Call "SetListSeperator" to change this string to something else.  Within the "LOOP" and "SELECTLIST" constructs, html is dynamically generated for each element within the resulting list.
II) Basic Parameter Substitution:
loadhtml is called with the 1st argument being the filename of the HTML template file to load.  Each subsequent argument corresponds to a data-value to be added to the HTML via parameter substitution.  The simplest parameter substitution is accomplished by placing the argument number preceeded by a colon in the desired location for the corresponding data-value argument in the HTML template file.  For example, if an HTML template file named "myhtml.htm" in directory "/usr/htdocs/" looked like the following:

<HTML>
<BR>Roses are :1, violets are :2.<BR>
</HTML>

The following call to loadhtml would supply the proper values:

    loadhtml('/usr/htdocs/myhtml.htm','red','blue');

and would display the following HTML page:

<HTML>
<BR>Roses are red, violets are blue.<BR>
</HTML>

":1" is replaced by the 1st argument after the file-name, and ":2" with the second one.

NOTE: It is now possible and preferrable to call loadhtml with NAMED parameters as follows:

The above example using Named Parameters:

<HTML>
<BR>Roses are <!:roses>, violets are <!:violets:>blue normally<!:/violets>.<BR>
</HTML>

The following call to loadhtml would supply the proper values:

    loadhtml('/usr/htdocs/myhtml.htm', -roses => 'red', -violets => 'blue');

and would display the same results. NOTE: If data is not substituted using named parameters, try enclosing each "-parametername" part in single quotes. Also, the format ":{name}" is used in lieu of ":number" in the HTML whenever a value is to be substituted OUTSIDE of a tag, OR within the 'value=":{name}"' part of a tag. Otherwise (within tags), just use the format ":name".

NOTE: In the above example, we show "roses" as a single, unmatched tag. "violets" is shown as a matching tag (note the colon before the closeing >). The text in between ("blue normally") is the default text and is shown if the page is not browsed via LoadHtml.

Now, suppose we want the HTML page to function as a stand-alone page without being called by a CGI script, to demo to a customer before writing the script, you could write:

<HTML>
<BR>Roses are <:1:>red<:/1>, violets are <:violets:>blue<:/violets>.<BR>
</HTML>

This would display the same results as the previous example (note the mixing of numbered and named parameters), if the page is loaded stand-alone directly into the browser, but, if called with:

    loadhtml('/usr/htdocs/myhtml.htm','here', -violets => 'there');

would produce the following dynamically-generated page:

<HTML>
<BR>Roses are here, violets are there.<BR>
</HTML>

If no default values are desired, the template file could be written as:

<HTML>
<BR>Roses are <!:roses>, violets are <!:violets>.<BR>
</HTML>

If a different default value is desired, as when the page is loaded via LoadHtml, but without a value for that specific argument, the template file could be written as:

<HTML>
<BR>Roses are <:roses=pink:>red<:/roses>, violets are <:violets=violet:>blue<:/violets>.<BR>
</HTML>

Now if LoadHtml is called as:

    loadhtml('/usr/htdocs/myhtml.htm', -roses => 'scarlet');

The following page would display:

<HTML>
<BR>Roses are scarlet, violets are violet.<BR>
</HTML>
 
Formatting

LoadHtml also supports the "printf" function familiar to C and Perl programmers for formatting parameter as they are displayed.  If this is not sufficient, user-defined formatting functions are also supported.  For example, to right-justify numeric parameters, one could use the "printf" formatting characters:  "-10.2f" as shown below:

<BR>The results are <!:roses%-10.2f%0.00:>0.00<!:/roses>

This provides that ":roses" will be displayed using "printf" formatting, with defaults of "0.00".

To format currency, one could define a formatting function within the CGI script to place commas every 3 digits, add parenthesis if negative, etc.  For example:

sub cashit
{
    my ($val) = shift;
    my ($iter) = shift;
    my ($lastrow) = shift;

    $val = sprintf('%.2f',$val);
    $val =~ s/(\d)(\d\d\d)$/$1,$2/;
    $val =~ s/(\d)(\d\d\d),/$1,$2,/g;
    $val = '(' . $val . ')'  if ($val =~ s/^\-//);
    return ("$val");
}

Then include the following in the HTML template:

$<!:amount%&main::cashit% 0:>0<!:/amount>

This formats the dollar amount with commas every three digits and adds parenthesis if negative.  Two decimal places are also displayed.

Sometimes, simple parameter substitution is not sufficient.  LoadHtml provides several special control structures to handle more complex dynamic HTML generation.

An alternate way of specifying parameters (namely, within HTML tags) is to enclose the parameter name between ":{ and "}". For example:

<A HREF="<!:roses>">Link to Rose colors</A>

would fail since the closing ">" of the parameter would close the <A> tag! To avoid this, specify the parameter as:

<A HREF=":{roses}">Link to Rose colors</A>

Substituting parameters in places where HTML does not allow special tags:

Sometimes it is necessary to embed a parameter substitution where HTML does not permit a special tag, ie a button with a default name. For example, suppose a page should have a form submit button with a default value of "Create Record":

<input type="submit" value="Create Record">

Now, if the page is loaded via LoadHTML, it is to be set to ":{arg} Record" if parameter "arg" is specified, otherwise, it is to be set to "Add Record". This can be accomplished with the following code:

<!:arg=Add[<input type="submit" value=":{arg} Record"&gt;]:><input type="submit" value="Create Record"><!:/arg>

This hyroglyphics will cause a submit button with the words "Create Record" to be displayed if page is just displayed without LoadHTML, It will be created with the "default" value "Add Record" if loaded by loadhtml() (cgi) but no value for "arg" is passed. If a value is passed to the "arg" parameter, then that value is used, ie. "arg => 'Update'" would yield a button with the displayed value of "Update Record". NOTE the use of "&gt" instead of ">" since html terminates comments with ">". The way this works is the html enclosed in the <!:arg...>...<!:/arg> tag is replaced by what's between the [ ] within the tag. The string "Add" (between the "=" sign and the "[" is the "default" value used in leau of ":{arg}" if no value is passed to that parameter (-arg => 'some value').
III) Control Statement Tags:

"IF-THEN-ELSE" statement:

<!IF[statement_name] condition>
    -body-
<ELSE[statement_name]>
    -body-
<!/IF[statement_name]>

The "ELSE" part is optional. The "statement_name" is optional, but should always be used if nesting IF statements. Consider the following HTML template file:

<HTML>
<H3>Jim's Joke Page!</H3>
<BR>
<!IF :flora =~ /flowers/i>
    <BR>Roses are <!:arg1>, violets are <!:arg2>.<BR>
<!ELSE>
    <BR>Knock Knock, who's there? <!:arg1>, <!:arg1> who?, <!:arg2>, that's who!
<!/IF>
</HTML>

This example will generate two different joke-lines, depending on the value passed as argument #1.

    loadhtml('/usr/htdocs/myhtml.htm', -flora => 'FLOWERS', -arg1 => 'red', -arg2 => 'blue');

will produce:

<HTML>
<H3>Jim's Joke Page!</H3>
<BR>
<BR>Roses are red, violets are blue.
</HTML>

whereas:

    loadhtml('/usr/htdocs/myhtml.htm', -flora => 'VEGETABLES', -arg1 => 'Foold', -arg2 => 'Fooled You!');

will produce:
<HTML>
<H3>Jim's Joke Page!</H3>
<BR>
<BR>Knock Knock, who's there? Foold, Foold who?, Fooled You!, that's who!
</HTML>

NOTE:  The "ELSE" portion is not required.

If one of the parts is desired for a standalone (no CGI) default, the other can be commented out with HTML comments, for example (NOTE: the "statement_name" is included and is "_STMT1":

<!IF_STMT1 :condition>normal text<!ELSE_STMT1><!-- special-case text --><!/IF_STMT1>

If invoked as a stand-alone HTML page or if ":condition" is non-null and non-zero, "normal text" will print, otherwise, "special-case text" will print.  The HTML comments will be removed automatically for the text, if the corresponding condition evaluates to true.

"LOOP" Statement:

Another, more powerful construct is the "LOOP".  A LOOP repeatedly generates its HTML body for each value in a Perl list.  The LOOP construct has the following general format:

<!LOOP[loopname] [first..last[|increment]] [index-list] [list-parm [, listparm...]]>
    -body-
<!/LOOP[loopname]>

For example:

<HTML>
<H3>Dallas Cowboy's Star Roster</H3>
<P><TABLE>
<TR><TH>No.</TH><TH>Name</TH><TH>Jersey</TH></TR>
<!LOOP names, numbers>
    <TR><TD>:#+1</TD><TD><!:names></TD><TD><!:numbers></TD></TR>
<!/LOOP>
</TABLE>
</HTML>

If called with:

  loadhtml('/usr/htdocs/myhtml.htm',
    -names => ['Troy Ackman', 'Emmit Smith', 'Michael Irvin'],
    -numbers => [8,22,88]);

would produce:

<HTML>
<H3>Dallas Cowboy's Star Roster</H3>
<P><TABLE>
<TR><TH>Name</TH><TH>Jersey</TH></TR>
    <TR><TD>1</TD><TD>Troy Ackman</TD><TD>8</TD></TR>
    <TR><TD>2</TD><TD>Emmit Smith</TD><TD>22</TD></TR>
    <TR><TD>3</TD><TD>Michael Irvin</TD><TD>88</TD></TR>
</TABLE>
</HTML>

The values: names, and numbers in the "LOOP" statement refer to those parameters which refer to perl list references instead of scaler values.  The ":#" represents a special value -- the iteration number of the loop being processed (starting with zero).  We use ":#+1" (":#_LOOPNAME+1) to cause this value to start with one instead of zero). If loops are nested (and thus named, the name can be appended to the ":# variable, ie:

<!LOOP_LOOPNAME argument1>
    <BR>Now in iteration:  :#_LOOPNAME+1; next arg1 value=<!argument1>
<!/LOOP_LOOPNAME>

By default, the loop executes with ":#" starting with zero, incrementing by one and continuing through the last value of the 1st list parameter specified.  This can be overridden by specifying an increment expression with starting and ending values and optionally, an increment value; -AND/OR- an index-list.  For example (start with 10, stop at 100, and increment by 5):

<!LOOP 10..100|5 argument1>
    <BR>The list value for argument1[:#] is: <!:argument1>.
<!/LOOP>

This would produce 19 lines of output, the value printed for ":#" would be 10, then 15, 20, ...100.  The tenth, 15th, 20th, 25th, ... and 100th elements of the list passed as argument 2 to LoadHtml() would be displayed.  If that list contained less than 100 elements, empty strings would print for the missing elements.  This is also useful to reverse the order of a list, for example:

<!LOOP 20..1|-1>
    ...
<!/LOOP>
 

<!LOOP 1..:argument1 argument2, argument3>

This specifies that the loop should execute argument1 times. Each iteration will correspond to a value of argument2 and argument3 starting with element [1]. argument1 should contain a scaler integer and argument2 and argument3 should be references to arrays with at least "argument1" + 1 elements.

<!LOOP  5..  argument2, argument3>

This specifies that the loop should execute once for each element of argument2 starting with the 6th one ([5]) and continuing through the last one.

<!LOOP 1,5,2,7 argument1, argument2>

This specifies that the loop should execute 4 times using the 2nd, 6th, 3rd, and 8th values of argument1 and argument2.

<!LOOP index-list argument1, argument2>

This specifies that the loop should execute once for each element in the array-reference passed to "index-list". Each value of index-list will become the subscript to use for argument1 and argument2 in it's respective iteration.

NOTE: If argument1 is a hash-reference instead of an array-reference, then the keys used for argument1 will be based on the relative position within an imaginary array built on the fly as "sort(keys(%{$argument1))". For example if the keys for argument1 (sorted) were "AA", "BB", "CC", and "DD"; and array referenced by index-list contained the values (in this order): (1, 3, 2, 0), then the loop would iterate through the keys in the order of: "BB", then "DD", then "CC", and finally "AA". This allows hashes to be iterated through in an order other than sorted by key!

LoadHTML can also emulate Template::Toolkit's ability to reference subcomponents of a reference by name. For example:

    my @v ;
    push (@v, {id => 100, name => 'Jack'});
    push (@v, {id => 101, name => 'Jill'});
    push (@v, {id => 102, name => 'Jerry'});
    &loadhtml('template.html', -hashref => \@v);

template.html contains:

<table>
    <tr><td>ID</td><td>Name</td></tr>
    <!LOOP hashref, id, name>
        <tr><td><!:id></td><td><!:name></td></tr>
    <!/LOOP>
</table>

This would produce:

<table>
    <tr><td>ID</td><td>Name</td></tr>
    <tr><td>100</td><td>Jack</td></tr>
    <tr><td>101</td><td>Jill</td></tr>
    <tr><td>102</td><td>Jerry</td></tr>
</table>

NOTE: "id" and "name" are parameters in the LOOP statement that are NOT DEFINED - (no argument is passed to them in the call to "loadhtml()"! This results in the subcomponents of the hashrefs passed to "hashref" (from @v) being used! This is similar to the way Template::Toolkit works and permits easier conversion of templates and scripts from that package. Also NOTE: a HASH could have been used in leau of "@v"!

There are four special variables that have meaning within a loop construct:

    * :# Current increment value. If no increment expression or index list is specified, the loop is driven by the 1st array or hash argument. In that case, the increment value is the zero-based iteration of the loop. This value is always numeric and represents the index subscript of the vectors for the current iteration.
    * :* Always the current zero-based iteration of the loop (numeric). Normally, this is the same as :#, but if an increment expression or index list is specified before the parameters, then :# is set to each element of the increment expression/index list, whereas :* is ALWAYS 0,1,...
    * :% Current key value of the 1st (driving) hash (if the 1st argument is a hash-reference). Otherwise, this variable is empty (ie. if the loop is driven by an array).
    * :^ Always contains the number of iterations (one-based) that the loop will perform. 

Naming and nesting IF and LOOP constructs.

IF and LOOP constructs can be nested with each other.  If nested within the same construct, however, they must be named (in order for the parser to match up the proper closing tags).  This allows for qualifying the special variables (:#, :*, etc.) to the desired loop. To name an "IF" or "LOOP" constuct, simply append an alphanumeric string to the keyword, for example:

<!IF2>...<!ELSE2>...<!/IF2>

    -or-

<!LOOP_OUTER>...<!/LOOP_OUTER>

The "IF" is named "2", and the "LOOP" is named "_OUTER".

Multi-loop Matrix example:

Consider the following code:


    my $data = $dbh->selectall_arrayref('select name, address, phone from some_database.table');
    ...
    &loadhtml('rate_specials.html',
        -colHeaders => [qw(Name Address Phone)],
        -matrix => $data,
        -names => '$matrix->[*][0]', #THIS IS AN EXAMPLE OF A COLUMN "Slice"!
    );

Now consider the following template code:


    <table>
         <TR class="heading"><TH>Link</TH><!LOOP_HEADERS colHeaders><TH><!:colHeaders:>Field Header<!:/colHeaders></TH><!/LOOP_HEADERS></TR>
         <!LOOP_ROWS matrix, names>
             <!IF_ODDEVEN1 :#_ROWS % 2><TR class="oddrow"><!ELSE_ODDEVEN1><TR class="evenrow"><!/IF_ODDEVEN1>
                 <TD align="center"><A HREF="cgi-bin/someotherpgm.cgi?name=:{names}"><!:names></A></td>
                 <!LOOP_COLS matrix><TD><!:matrix:>Field Value<!:/matrix></TD><!/LOOP_COLS>
             </TR>
         <!/LOOP_ROWS>
    </table>

This illustrates how simple it is to combine LoadHTML with DBI (the single call to DBI::selectall_arrayref fetches all the data from a database query into a two-dimentional row-major array referenced by $data). This HTML template could handle a variety of queries, since the number of columns (headers) is also driven by a loop. The "ODDEVEN1" IF-statement is optional and simply allows the table rows to have alternating colors for readability. Note the nested loops "_ROWS" (outer) and "_COLS" (inner), both are driven by the two-dimentional array- referencing parameter "matrix". This will produce a table showing a row for each record read by the query and each row will contain all three column values.

An extra, but unnecessary level of complexity was added to this example to illustrate another feature - the column "slice". Note that the 1st column header is "Link", and the 1st column of each row is a URL link to "someotherpgm.cgi". The reason for this example is to show access to the entire column of data represented by the field "names". By specifying an additional parameter called "-names" containing the literal value string "$matrix->[*][0]", one can unroll a specific column within a multi-dimentional array in the outter (row) loop. This means that the "names" parameter refers to the 1st ([0]'th) slice of the two-dimentional array referenced by the "matrix" parameter. For each row in the loop, the asterisk is replaced by the increment number, so that in the 1st row "names" refers to $data->[0][0] (The 1st name returned by the query). In the 2nd row, "names" refers to $data->[1][0], etc. This permits the row-major data returned by the query to be handled in a column-major way (allowing the programmer to get at the individual elements of a specified column), which would normally require an inner loop to access.

Note also, that is is not limited to 2 dimensions or to array-references. The number of dimensions is not physically limited, but can be any number and combination of array and or hash-references. The trick is that there normally must be a nested loop refering to the same parameter for each dimension to be unrolled (unless a column slice is used). When hash-references are used, they are sorted by key unless an index-list is specified.

The above example could have also been acomplished without the slice by using an inner loop (called "NAMES" below) that only referenced the desired (zero-th) element (only iterates once (0..0) unrolling the zeroth column (inner dimension) element of "matrix" for each iteration of the outer ("ROWS") LOOP as follows: (You could replace the "0..0" with the number of the column you wish to use for the slice).


    <table>
         <TR class="heading"><TH>Link</TH><!LOOP_HEADERS colHeaders><TH><!:colHeaders:>Field Header<!:/colHeaders></TH><!/LOOP_HEADERS></TR>
         <!LOOP_ROWS matrix>
             <!IF_ODDEVEN1 :#_ROWS % 2><TR class="oddrow"><!ELSE_ODDEVEN1><TR class="evenrow"><!/IF_ODDEVEN1>
                 <!LOOP_NAMES 0..0 matrix><TD align="center"><A HREF="cgi-bin/someotherpgm.cgi?name=:{matrix}"><!:matrix></A></td><!/LOOP_NAMES>/
                 <!LOOP_COLS matrix><TD><!:matrix:>Field Value<!:/matrix></TD><!/LOOP_COLS>
             </TR>
         <!/LOOP_ROWS>
    </table>

"SELECTLIST" Statement:

Another compound construct is the "SELECTLIST".  It generates an HTML "SELECT" statement using the elements of a Perl list or hash, generating an "OPTION" line for each element in the list or hash.  The general format is:

<!SELECTLIST NAME=select_name [VALUE[S]=value_list] [DEFAULT[SEL]=default_value] [(BYKEY)|BYVALUE] [REVERSE[D]] :list_parameter>
    [...HTML to display if page invoked standalone...]
<!/SELECTLIST>

The NAME and any options other than "VALUE", "DEFAULT", "DEFAULTSEL", "BYKEY", "BYVALUE", and "REVERSE" are added (passed) to the generated SELECT statement.  The "list_parameter" (required), by default, becomes the values for the generated "OPTION" lines.  If "list_parameter" is a Perl hash, then the keys of the hash become the arguments for the "VALUE=" part of each OPTION line, and the values become the displayed items in the listbox. The values are then character-sorted by key (BYKEY) unless "BYVALUE" is specified. "REVERSE" reversed the order.   If "list_parameter" is a list and a second list is supplied via the "VALUE" option, then the second list becomes the "VALUE=" part of each OPTION line and the "list_parameter" list items are displayed. They are displayed in the order they appear in the list(s), unless "REVERSE" is specified.   If no "VALUE" option is given and "list_parameter" is a list, then no "VALUE=" option is generated and the values become both the actual values and the displayed values for the listbox.  The DEFAULT option, if specified, is a value which is to be the initially highlighted value in the select-list.  If the "MULTIPLE" select option is specified, then the "DEFAULT=" value may be either a scalar or a list-reference. Each value in the "DEFAULT" list (if a list reference) is matched against the "VALUE" list and those that match are "SELECTED" by default. If "DEFAULTSEL=" is specified, the default list values are compared with the SELECT values instead the "VALUES" values.  Note that the resulting selection-list items are sorted in character-sequence order when the list parameter is a hash  To get a true numeric sort, one must left-pad the hash keys with spaces. 

Example:

<!SELECTLIST NAME="id" DEFAULT=":thisid" :employees><INPUT NAME=id TYPE=TEXT><!/SELECTLIST>

...

    $mydefault = 123;
    %employeehash = (110 => 'John Smith', 145 => 'Richard Adams', 123 => 'Mike Cox', 132 => 'Eddy Jones');
    &loadhtml('/usr/htdocs/myhtml.htm', -thisid => $mydefault, -employees => \%employeehash);

This would replace the "id" TEXT box field with the following HTML:

<SELECT NAME="id">
    <OPTION VALUE="110">John Smith
    <OPTION SELECTED VALUE="123">Mike Cox
    <OPTION VALUE="132">Eddy Jones
    <OPTION VALUE="145">Richard Adams
</SELECT>

Checkboxes and radio-buttons:

Checkboxes and radio-buttons also require special handling.  A default value is specified in the HTML via a parameter.  The parameter will be replaced by the word "CHECKED" if it's value matches the value specified for the checkbox or radio-button.  for example:

    <BR><INPUT TYPE=CHECKBOX NAME="checkit" :ischecked>Check here if True!<BR>

If the value passed to ":ischecked" is "true" in Perl (not zero, empty string, or whitespace), the HTML will be generated with ":ischecked" replaced with the word "CHECKED", otherwise, the ":ischecked" it will be removed. NOTE: If the word "CHECKED" is already in the HTML, it will be removed if the value for ":ischecked" is false, but will remain if no argument is defined for ":ischecked".

    <INPUT TYPE=RADIO NAME="topings" VALUE="meat" :ischecked>Give me Meat and Cheese
    <INPUT TYPE=RADIO NAME="topings" VALUE="veggies" :ischecked>Give me Veggies, please

If the argument passed to ":ischecked" is equal 'meat' or 'veggies', then the corresponding radio-button will be marked "CHECKED", otherwise, neither will be checked.

"INCLUDE" statement:

Additional HTML files can be loaded and processed within an HTML file via the "INCLUDE" statement.  All files loaded via the "INCLUDE" statement are also parsed and modified the same way the initial HTML file is.  The include file can be specified as either a server file-name or a url.  Examples:

    <!INCLUDE /user/htdocs>
    <!INCLUDE http://domain/path/myhtml.htm>
 

You can also include a portion of another html template file without including the endire file by using tags

For example:

    <!INCLUDE http://domain/path/myhtml.htm:header>

This assumes the template file myhtml.htm contains the following block tag:

<!-- BEGIN header -->
... stuff to be included ...
<!-- END header -->

You can also force different default values for parameters by including them in the include, ie.:

    <!INCLUDE http://domain/path/myhtml.htm:header(roses=red,violets=blue)> -or-
    <!INCLUDE /user/htdocs(arg1=:{another_arg})>

Providing default values for form items.

LoadHtml provides special ways to assign default values to HTML "INPUT" statements.  Consider the following for putting a default value into a TEXT field:

    <INPUT NAME=name TYPE=TEXT VALUE=":{default}">

This will work, but LoadHtml provides a better way.  If done this way and the form is invoked stand-alone, the input box will show a literal ":{default}", which is probably not desired for demos.  The preferred way is:

    <INPUT NAME=name TYPE=TEXT VALUE="standalone-default" :default=somestring>

This provides a value "standalone-default", if the page is invoked as stand-alone HTML and a value of "somestring", if no argument or "undef" is passed for the corresponding argument.  If the "=somestring" string is omitted, the box will show as empty, if no argument is passed for ":{default}".  NOTE:  If an empty string is passed as an argument, the box will be empty regardless of any default values specified!  This option also applies to "HIDDEN" input fields.

    <SELECT NAME=myselect :default>...</SELECT>

This permits the default (initially selected) value of the SELECT statement to be specified by the value referenced by argument "default".

    <TEXTAREA... :default=somestring>stand-alone default</TEXTAREA>

This works similar to the "<INPUT TYPE=TEXT...>" input field described previously.
 IV). Other Special Tags:

Embedding Perl variables:

If "AllowEvals(1)" is called before calling "loadhtml", then any embedded Perl variables of the format:  ":$scaler  or :$array[index] or :$hash{index} or :$package::variable  will be replaced by it's value current at the time LoadHtml is called.

Embedding Perl code (the "EVAL" Statement):

If "AllowEvals(1)" is called before calling "loadhtml", then any Perl code between the tag: "<!EVAL.../EVAL>" will be evaluated and any returned results will replace the EVAL tag.  Consider the following example:

     <!EVAL
    my (@t) = localtime(time);
    return ($t[3] . '-' . (qw(JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC))[$t[4]] . '-' .  $t[5] . '.');
    /EVAL>

This tiny Perl program calls Perl's "localtime" function, and returns the current date with the month formated into it's proper three-character abbreviation.  The more complicated example below generates a dynamic url link:

    <!EVAL
    my ($homepage) = ":0";
    $homepage =~ s/userpage/pp:4/;
    if (-e "$homepage")
    {
    $homepage = 'http://myhost.domain.com/cgi-bin/loadtext.pl?link='
    . $homepage . '&args=:1,:2,:3,:4,:5,:6,:7,:8,:9,:10,:11,:12,:13,:14,:15,:16,:17,:18,:19,:20,:21,:22';
    return ('<CENTER&gt<BR&gt<A HREF=' . $homepage . '&gtGo to my Personal Homepage</A&gt</CENTER&gt<BR&gt<HR SIZE=5&gt');
    }
    /EVAL>

Note that parameter substitutions take place within this code.  Also note the use of "&gt" in lieu of the ">" symbol.  This is required to prevent the HTML processor from closing the "<!EVAL" tag before the end of the "EVAL" code!  The special parameter ":0" contains the name of the html template file.

Embedding Perl code (the "PERL" Statement):

You can also embed the results of a separate Perl script file using the "PERL" tag.

The format is: <!PERL file="/path/to/perlscript.pl"><!-- "Default String" --><!/PERL>

The script must be "eval"-able (last expression's results are returned) by Perl. Also, "-perls => 1" must be passed to SetRegices() and AllowEvals(1) must be called - since THIS IS A SECURITY RISK - if the Perl script is malicious! NOTE: how the "Default String" is enclosed in quotes, since this is fed to Perl's eval() fn also (if the script can't be eval'ed), so must be a valid Perl result also!

Of course, one can be even more dangerous, ie: "<!PERL file=":{variable}"><!/PERL>"!

Embedding hash-definitions within HTML pages:

Hash tables can now be defined within an HTML page for creating lookup tables, etc. To create a hash table, use the "<!HASH> tag. For example:

<!HASH attbdescs>
    'any' => 'Any attribute',
    'di' => 'Direct/Indirect',
    'dgr' => 'Education (Degree)',
    'ins' => 'Education (Institution)',
    'maj' => 'Education (Major)',
    'exl' => 'Experience (LM)',
    'ex' => 'Experience (Total)',
    'flv' => 'Foreign Language',
    'flw' => 'Foreign Language',
    'fpt' => 'Full/Part Time',
    'ou' => 'Organization',
    'pos' => 'Title',
    'sg' => 'Salary Grade',
    'sc' => 'Security Clearance',
    'sk' => 'Skills and Knowledge',
    'tr' => 'Training'
<!/HASH attbdescs>

This defines a lookup table for several codes and gives each a description. The hash can be any valid Perl hash-definition. The hash will be referred to within the HTML by the name "attbdescs". To cause a hash's value to be displayed, use its name in the special tag in the format:

    <!%hashname{key}default>

For example to display the following tag:

    <!%attbdescs{pos}>

would be replaced with "Title". The real use for this is specifying the key dynamically, ie:

    <!%attbdescs{:1}-NO SUCH VALUE!->

The result depends on the value of ":1". If the value of ":1" does not match any of the key values, then "-NO SUCH VALUE!-> is displayed.

If the template page is also being used stand-alone, the entire hash definition (between "<!HASH...>" and "<!/HASH>) can be enclosed as a comment ("<!-- ... -->").

Other Tags:

    <!POC> (or <!POC:>replace this standalone default text<!/POC>)

Generates the point-of-contact's name (whatever value passed to the set_poc() function. The default value is the string "your website administrator". NOTE: "-pocs => 1" must be passed to &SetRegices() first!

    <!TODAY> (or <!TODAY:>replace this standalone default text<!/TODAY>)

    <!TODAY="yyyy-mm-dd hh:mm"> (or <!TODAY="mm/yyyy":>replace this standalone default text<!/TODAY>)

Generates today's date (default format is "mm/dd/yy" if DBD::Sprite is installed and the "to_char" function from that library is available, otherwise, the format is: scalar(localtime($mtime).

    <!FILEDATE> (or <!FILEDATE:>replace this standalone default text<!/FILEDATE>)

    <!FILEDATE="yyyy-mm-dd"> (or <!FILEDATE="mm/yyyy":>replace this standalone default text<!/FILEDATE>)

Generates the last-modified date/time of the template file (default format is "mm/dd/yy" if DBD::Sprite is installed and the "to_char" function from that library is available, otherwise, the format is: scalar(localtime($mtime).

 V). User-callable Functions (Details):

    &loadhtml($htmlfile, @args)

Main function to read/process a specified template file / url ($htmlfile) and prints out the resulting html page to STDOUT. @args represents a list of values. Each argument value replaces any occurrance of the corresponding parameter number (ie. ":1", ":2", etc.). If the first, third, fifth, etc. are valid Perl "words" starting with a hyphen, then the next argument (ie. the 2nd, fourth, sixth, etc.) represents a value that will replace every occurrance of the parameter with the same name, ie. "-parm => 'value', converts :{parm} or <!:parm> or <!:parm:>...<!:/parm> to 'value' everywhere it occurrs. For each parameter that is used in a LOOP or SELECTLIST construct, the value should be an array reference or a hash referehce, rather than a scalar value. If successful, loadhtml returns 1 (true) if fails, ie. could not open the template file, <undef>. The special parameter ":0" is replaced with the name of the template file (1st argument).

You can also convert programs that use Template::Toolkit by changing:

    $template_object->process($template_file, $template_hashref);

to:

    &loadhtml($template_file, %{$template_hashref});

    &loadhtml($htmlfile, @args);

is equivalent to:

    print &buildhtml($htmlfile, @args);

    my $html = &buildhtml($htmlfile, @args);

Same as loadhtml, except returns the generated webpage as a string instead of writing it to STDOUT;

    print &dohtml($htmlstring, @args);

    my $html = &dohtml($htmlstring, @args);

Same as buildhtml, except processes a input string instead of a template file or url.

    &AllowEvals(1|0);

Toggles whether or not embedded Perl variables and expressions are performed, namely the <!PERL> and <EVAL> constructs and Perl variables in the format: "<!:$variable>".
Default is 0.

    &set_poc($str);

Sets the string to replace the special "<POCS>" construct. Default is to ignore this tag. If called without a string or an empty string, the string is set to "your website administrator".

    &SetRegices(%optionshash);

Sets special control options. The currently defined options (with their default values) are: -hashes => 0, -CGIScript => 0, -includes => 1, -embeds => 0, -loops => 1, -numbers => 1, -pocs => 0, -perls => 0)

These options allow speeding up processing when turned off (not needed).

    -hashes: Allows the <!HASH> tag sto be processed if on, otherwise ignored.

    -CGIScript: Causes s special hidden form variable called "CGIScript" to be added at
the bottom of the first form with the value set to "$ENV{SCRIPT_NAME}" if on, otherwise not added.

    -includes: Allows the <!INCLUDE> tags to be processed if on, otherwise ignored.

    -embeds: Allows the <!EMBED> tags to be processed if on, otherwise ignored.

    -loops: Allows the <!LOOP> tags to be processed if on, otherwise ignored.

    -numbers: Allows the classic numeric parameter (":1", ":2", etc.) tags to be processed if on, otherwise ignored.

    -pocs: Allows the <!POC> tags to be processed if on, otherwise ignored.

    -perls: Allows the <!PERL> tags to be processed if on, otherwise ignored.

&SetListSeperator($separator_string);

Sets the separator string to be used if an array-reference is passed to a parameter that appears outside of a loop (where a scalar value is expected) Such values are automatically converted to a string of values ala Perl's "join()" function. The default string is ", ".

    &SetHtmlHome($htmlhome, $roothtmlhome, $hrefhtmlhome, $hrefcase);

This allows certain embedded links within a document to be "converted" for proper handling. Relative links refer to a different path when the document is loaded via CGI/LoadHTML than then they are loaded directly as urls by a browser, for example, the document root usually becomes the directory the CGI script is in. Anyway, this is an attempt to allow valid HTML pages to also be loaded as templates within a CGI script and maintain their links properly.

$htmlhome - specifies the URL path to append to relative links in SRC=, HREF=, CL=, HT=, GROUND=, and window.open() arguments.

$roothtmlhome specifies the filesystem path to append to relative file names in <INCLUDE> tags.

$hrefhtmlhome - similar to $htmlhome, but only applies to HREF= links, if it is necessary to redirect them to a different path, ie. a cgi-script for pre-processing. If both $hrefhtmlhome and $htmlhome are specified and non-empty, the former will override for HREF= links and the other will applie to the other link types, ie. SRC=, etc.

$hrefcase - used to limit the substitutions of $htmlhome and $hrefhtmlhome to specific links. It can be set to 'l' (Lower-case links only), left undefined for all links, or set to anything else for Upper-case links only. For purposes of case, a "Lower-case" link would be "href=", an "Upper-case" link would be "HREF=".

    &loadhtml_package($package_name);

Change the default package LoadHTML uses for embedded Perl variables. Default is main. Best way to set this is to call "loadhtml_package(__PACKAGE__);".
 VI). Minimum System Requirements:

    * 1) Any system supporting Perl and CGI.
    * 2) Perl, v. 5.003 or better.
    * 3) Perl's "LWP" module (not an absolute requirement, but VERY useful) and required prerequesites:  MIME-Base64 (MIME), HTML-Parser (HTML), libnet (Net), MD5, and Data-Dumper (Data).  All of these are available for download from CPAN. 

