Tcllib html

Description

The html module of Tcllib provides tools to generate HTML programmatically. Related modules are ncgi, javascript, and htmlparse.

Documentation

official reference

See also

Examples

Html Table , comp.lang.tcl, 2002-04-06
a really small example using tDOM

Basic Example

Some example code from comp.lang.tcl :

> Hi,

> I'm just starting to work with the html generation package of tcllib (ver > 1.2.2). Can anyone point me to some examples of how the tcllib html > generation package is used?

Quick taste,

(bin) 15 % package require html
1.1
(bin) 16 % html::textInput first_name
<input type="text" name="first_name" value="" size="45">

(bin) 17 % html::textInputRow "MY LABEL" test_row
<tr>
       <td>MY LABEL</td>
       <td><input type="text" name="test_row" value="" size="45">
       </td>
</tr>

(bin) 24 % set people {John Doe Mary Poppins Jack {B. Nimble}}
John Doe Mary Poppins Jack {B. Nimble}
(bin) 25 % html::tableFromList $people
<TABLE ><tr>
       <td>John</td>
       <td>Doe</td>
</tr>
<tr>
       <td>Mary</td>
       <td>Poppins</td>
</tr>
<tr>
       <td>Jack</td>
       <td>B. Nimble</td>
</tr>
</TABLE>

similarly there's html::tableFromArray, proc html::checkbox etc...
Using the html package with tclhttpd templates makes form/page
generation quite simple;-)
- HTML Generation From tcllib , comp.lang.tcl, 2003-09-10

RLH 2006-02-20: It probably shouldn't spit out uppercase tags like <TABLE>.

Example

booksandlibros - 2010-01-16 02:44:20

Using the html module in tcllib is not straight forward given the documentation. However, if you are familiar with HTML, and prehaps written your own HTMLizing modules, it will make more sense.

The real shift in thinking is that Tcl is list-based, and HTML is stack-based; so it can be confusing. As such, the most important calls are ::html::openTag and ::html::closeTag - note the pairing, almost begging to be stacked. On closer examination of the library note - no calls for important HTML tags such as <BODY>, <HTML>, <TABLE>, or <FORM>.

Hopefully these examples will illuminate.

#!/usr/local/bin/tclsh8.4
#
#

package require html

::html::init
puts [::html::openTag html]
puts [::html::openTag body]
puts [::html::openTag form [::html::formValue myform testvalue]]
puts [::html::radioSet test1 "<br>\n" [list {number #1} value1 {test #2} value2 {yeah yeah} value3 ]]
puts [::html::closeTag]
puts [::html::closeTag]
puts [::html::closeTag]

puts [::html::tableFromList {test test1 test2 test3} ]


array set testarray {test test1 test2 test3}

puts [::html::tableFromArray testarray ]

Output:

<html>
<body>
<form name="myform" value="testvalue">
<input type="radio" name="test1" value="value1"> number #1<br>
<input type="radio" name="test1" value="value2"> test #2<br>
<input type="radio" name="test1" value="value3"> yeah yeah
</form>
</body>
</html>
<table ><tr>
        <td>test</td>
        <td>test1</td>
</tr>
<tr>
        <td>test2</td>
        <td>test3</td>
</tr>
</table>
<table >
<tr><th colspan=2>testarray</th></tr>
<tr>
        <td>test</td>
        <td>test1</td>
</tr>
<tr>
        <td>test2</td>
        <td>test3</td>
</tr>
</table>

booksandlibros - 2010-01-16 03:37:27

A Simpler Example - The Minimum

Oh, Geeezz. Hello World!

#!/usr/local/bin/tclsh8.4
#
#

package require html

::html::init
# SEE, READ, Fill
puts [::html::head {this is a test title}]
puts [::html::bodyTag]
puts {Hello World!}
puts [::html::end]

Outputs

<html><head>
        <title>this is a test title</title>
</head>

<body>

Hello World!
</body>
</html>

LEG 2016-12-09: The documentation talks about procedures being "called from an HTML template". It was mentioned above, that this can be used from tclhttpd. Here is the almost simplest approach I can imagine to do HTML templates with the html module.

First step: A Tcl script to parse a HTML template, given as the first argument on its commandline (html.tcl).

#/bin/sh
# the next line restarts using tclsh \
    exec tclsh "$0" ${1+"$@"}

interp create html
html eval {
    package require html
    namespace eval ::html {
        init
        # add things here, you want to go into the header,
        # but not into the template.
    }
}

set fd [open [lindex $::argv 0]]
html eval set template [list [read $fd]]
close $fd
puts -nonewline [html eval {
    namespace eval ::html {
        subst $template
    }
}]

Things to note:

  • The template parser is just the subst $template line. The rest is setting things up.
  • We use a slave interpreter called html for parsing, the benefits are explained in interp and Safe Interps. For production use the latter, however it is not shown here how to do this.

Second Step: The almost simplest template possible (html.tpl):

[head {Tcllibs html package demo}]
[bodyTag]
[h1 [getTitle]]
Hello World!
[end]

Third Step: Let's run it like this:

$ chmod +x html.tcl
$ ./html.tcl html.tpl

And it will output:

<html><head>
        <title>Tcllibs html package demo</title>
</head>

<body>

<h1>Tcllibs html package demo</h1>

Hello World!
</body>
</html>


mw 2013-02-10: I suggest the following function:

proc % {args} {
    if {[llength $args]==0} {
        puts [html::closeTag]
    } else {
        puts [html::openTag {*}$args]
    }
}

It makes generating HTML from e.g. a CGI script easy as pie:

% table
        % thead
                % tr
                        % th
                                puts "Description"
                        %
                        % th align='right'
                                puts "Total"
                        %
                %
        %
        % tbody
                % tr
                        % td
                                puts "Apple pie"
                        %
                        % th align='right'
                                puts "500"
                        %
                %
                % tr
                        % td
                                puts "Custard pie"
                        %
                        % th align='right'
                                puts "12"
                        %
                %

        %
%

Historical

MHo: Calling e.g.

::html::textInput test1 value1 size="30"

leads to the following result:

<input type="text" name="test1" value="value1" size="45" size=30>

So the requested size-specification does not take place (it seems here that the first parameter wins).

I don't know why size="45" is included as a default. If I want to have the ability to specify sizes with html::textInput, I have to call

html::init {text.size ""}

first; then:

::html::textInput test1 value1 size="30"

gives

<input type="text" name="test1" value="value1" size=30>

as expected.

I don't know if and why this behaviour takes place... Can someone please tell me???

schlenk: Its a bug. See http://sourceforge.net/tracker/index.php?func=detail&aid=1230699&group_id=12883&atid=112883 . It is fixed in CVS and will be included in the new tcllib version, which is currently in feature freeze mode, and should be released just before the Tcl conference in October. Mho: Thanx!

Here's another one:

html::checkbox uses html::checkValue to control the CHECKED-State.

But html::radioValue 1) only formats one name value-pair and 2) is not used by html::radioSet and therefore little of use and 3) shows an help text which does not match the online help:

% html::radioValue
wrong # args: should be "html::radioValue name value ?defaultSelection?"

What's the meaning of ?defaultSelection? here???

Also it seems that radioValue name value does not mark the element with CHECKED if a cgivar name exist with value value....

Or did I missunderstand the whole stuff completely? Perhaps... However, I build myself some procs which do what I (perhaps by mistake) expected from the original routines.

proc radioSet2 {name current sep args} {
    foreach {lbl val} $args {
        append ret "<input type=\"radio\" [html::radioValue $name $val $current] />$lbl$sep\n"
    }
    return $ret
}

proc checkSet2 {prefix sep args} {
   set ix 0
   foreach {lbl val} $args {
       incr ix
       append ret "[html::checkbox $prefix$ix $val]$lbl$sep\n"
   }
   return $ret
}

schlenk Please file a bug report at the tcllib bugtracker for this, so the issue is not forgotten.

MHo 2009-10-09: From the description, I thought that ::html::openTag brings the additional tag argument list into the proper format, that is keyword1="value1" keyword2="value2" and so on, but if I do, e.g. ::html::openTag form {name test1 action abcd}, the following is returned: <form name test1 action abcd> which is, of course, not what I want... So I had to code me the following trivial function:

proc nameValParms {args} {
    foreach {name val} $args {
        append ret "$name=\"$val\" "
    }
    return $ret
}

which does the stupid work, but requires an additional step nearly each time ::html::openTag is used... The same applies to ::html::textInput. And, again (see below), I see size="45" if I don't specify additional tag parms with textInput...