oowebtools

Description

oowebtools is an open-source TclOO (object-oriented) toolkit for constructing websites. It's designed to facilitate building web pages even if TclOO features aren't used directly. (Naturally extending oowebtools features will probably require deriving classes or using other TclOO capabilities. The majority of users won't need to do this.)

oowebtools is the successor to jwebtools. While the purpose and general patterns of use are similar, the new toolkit leverages the recently completed nxproc extension and represents a thorough revision of old code along with a great many bug fixes. oowebtools has cleaner syntax and greater ease of use.

While oowebtools offers a number of conveniences and ready-to-use components, it works by encapsulating HTML entities making page construction more compact and flexible. Basically the toolkit enables writing page generators. Since these page generators are written in Tcl, templating can be accomplished simply by inserting Tcl procedure calls or variables.

Sample web page

Before getting into details, a brief example of a web page using oowebtools:

proc page0 {} {
    Html: --> [subst {
        [Head: -title "Example page" \
            -descrip "Demonstrates oowebtools" --> [subst {
            [Preload: --> {href /js/example.js as script}]
            [Preload: --> {href /css/example.css as style}]
            [Link: --> {href /css/example.css rel stylesheet 
                        type text/css}]
        }]]
        [Body: --> [subst {
            [H1: --> "Example Web Page"]
            [Div: --> {class main} [subst {
                [Div: --> {class msgdiv} \
                    {This is the message.}]
                [Div: --> {id imgdiv} [subst {
                    [Img: --> {src /img/big-country.jpg 
                            alt "Wide open fields"}]
                }]]
            }]]
        }]]
    }]
}

The toolkit provides commands corresponding to 42 HTML tags. These are called using a simple syntax:

Tag: <fixed args> <named args> --> {attributes} {text or element list}

Naturally input varies depending on the tag but the pattern is consistent.

In the example, each tag command is called with "-->" followed by one or two lists. The first is a an optional list of attributes. The final (or only list) is either text or list of elements "owned" by the tag. The result is a hierarchical list structure, exactly what HTML is about.

The "page0" command returns the result of running the Html class command. That is, an object itself a command created by "Html:". This object can call the methods defined by Html. The most relevant method is "write". Each tag object knows how to write itself, so when [page0] is called, the web page is written to stdout or possibly another file descriptor.

[page0] write

<!DOCTYPE html>
<html lang="EN-US">
  <head>
    <title>Example page</title>
    <meta name="description" 
          content="Illustrates using oowebtools">    
    <meta charset="UTF-8">
    <meta name="viewport" 
          content="width=device-width, initial-scale=1">
    <link href="/js/example.js" as="script" rel="preload">
    <link href="/css/example.css" as="style" rel="preload">
    <link href="/css/example.css" rel="stylesheet" 
          type="text/css">      
  </head>
  <body>
    <h1>
      Example Web Page
    </h1>
    <div class="main">
      <div class="msgdiv">
       This is the message.
      </div>
      <div id="imgdiv">
        <img src="/img/big-country.jpg" 
             alt="Wide open fields">
      </div>
    </div>
  </body>
</html>

Defined tags

Here is the complete list of HTML classes in the toolkit. Note that these all have upper case first letter.

A Area Article Audio B Base Bdi Blockquote Body Button Canvas Charset Code Datalist Del Description Details Div Em Embed Fieldset Figcaption Figure Footer Form H1 H2 H3 H4 H5 H6 Head Header Hr Html Iframe Img Input Ins Label Legend Li Link Main Map Meta Meter Nav Ol Optgroup Option P Picture Pre Preload Script ScriptSrc Select Source Span Style Sub Summary Sup Textarea Title U Ul Video Viewport

This doesn't cover all possible HTML tags, but sufficient for most users' purposes. If other tags are needed adding them is pretty straightforward to do.

To use these tag classes, either "Tag:" or "Tag new" works. (These are in fact completely equivalent.) The colon form is more convenient and clearer so usually preferred.

Basic tags

A Article B Bdi Blockquote Body Button Canvas Code Datalist Del Details Div Em Fieldset Figure Figcaption Footer Form H1 H2 H3 H4 H5 H6 Header Iframe Ins Legend Li Main Map Meter Nav Ol Optgroup P Picture Pre Select Span Summary Sub Sup Textarea U Ul

# Syntax

Tag: <options> --> {attrib list} {text-or-element list}
<options> 
    -nonl           (bool 0)  "no nl chars around tag"
    -zeroindent     (bool 0)  "no indenting at all"
    -indenting      (bool 0)  "per tag indenting or not"
    -indent         (int 0)   "amount to indent"
    -textoutdent    (int 0)   "move text to left (script,style)"
    -leftmarg       (int 0)   "line starting point"
    -fd             (str "")  "output device"
{attrib list}   (str/list) 
{text/elements} (str/list of objects)

Methods: 
    write ?fd?  "write" is most useful method, avail in all tags.
                Takes one (positional) argument, "fd" or file 
                descriptor (e.g., from "open"). The default 
                empty string causes write to return rendered
                text associated with the tag.

Tags without end tag

Area Base Embed Hr Img Input Option 

# Syntax

Tag: <options> --> {attrib list}
<options>   same as basic tags
{attrib list}   $nxargs contains only <attrib value ...> list

Html tag group

Syntax:

Html: <options> --> {<head object> <body object>}
    -lang   (EN-US)
    -fd     ("")

Head: <options> --> {elements only - NO ATTRIB}
    -title   ("")   "page title"
    -descrip ("")   "page description"

Meta: <options> 
    -name    ("")
    -content ("")

Link: --> {attributes}

Preload: --> {attributes}  

ScriptSrc: -src <URL> ?--> {attributes}?

Script: -outdent <int 0> --> {text}

Style: -outdent <int 1> --> ?{media <value>}? {text}

Other tags

Label Audio Video Source

Syntax:

Label: -for <str> --> ?{attribs}? {text}

Audio: <options> --> ?{attribs}? {element list}
    -src            URL 
    -autoplay       BOOL 0 
    -nocontrols     BOOL 0 
    -loop           BOOL 0 
    -muted          BOOL 0 
    -preload        ENUM {auto metadata none}

Video: <options> --> ?{attribs}? {element list}
    -src            URL 
    -autoplay       BOOL 0 
    -nocontrols     BOOL 0 
    -loop           BOOL 0 
    -muted          BOOL 0
    -preload        ENUM {auto metadata none} 
    -poster         URL
    -width          300 (px)
    -height         150 (px)

Source: <options>
    -src            URL 
    -type           <mime type>
    -media          ""  for <picture>
    -sizes          ""  for <picture> 
    -srcset         ""  for <picture>

Other commands

The toolkit provides a number of object-commands that are not HTML tags but frequently very useful for constructing web pages. These include:

Blist Bsrc Bsrcstub CommentDb CommDiv CommScript CommentRecv Component Contact ContactRecv Dynpage Menu ooWTserv Slider Smtp Srcset WebImg

Several utility classes provide internal support but also have functionality of interest to toolkit users:

Bool Config Log Resource Util Stack

Both groups of commands will be described in later sections.

Architecture

Element is the abstract parent of all tag classes. Element contains generic functionality used by derived classes, on top of which properties are implemented in addition to or replacing what's defined in Element.

Tag constructors in oowebtools use nxconstructor (from nxproc extension) conferring certain advantages. First, nxconstructor (and nxmethod) allow named arguments of the form "-param value" with each "param" becoming a variable in the procedure body. Also nx- procedures have nxunknown and nxargs variables defined in the body. (By default these variables are empty.) These features are widely exploited in oowebtools.

In nxproc, procedures can have fixed (positional) arguments (optionally with defaults), named arguments, unknown arguments or nxargs.

nxproc mycmd {{fixedarg 100} -namedarg "value" **} { ... }
mycmd 200 -namedarg "text input" unknownarg --> mynxargs ...

In this case, "mycmd" body will have variables "fixedarg", "namedarg", "nxunknown" and "nxargs" containing 200, "text input", "unknownarg", and "mynxargs" respectively. The "twostar" (**) symbol means input on the command line not matching named arguments will be saved in the "nxunknown" variable rather than causing an error. (Note that "nxconstructor" and "nxmethod" work the same way as nxproc.)

In oowebtools, nxcontructors may have fixed or named arguments. In any case, they make use of "nxargs" by reading $nxargs and either sending data via "next" to the parent class, or processing $nxargs value as attributes and text/list of elements. The latter are saved in instance variables Attributes, Elements/Text which are used by the "write" method as it renders the variables' data into the target web page.

Toolkit users don't need to be too concerned about nxproc details. (Unless intending to use nxproc commands in their own work.)

TclOO classes as commands produce instance objects with create or new. As a convenience oowebtools has a namespace Tag with commands having the names of tag classes plus a trailing colon. Thus Tag::A: is a command that calls A new. In practice the Tag namespace exports its command names and these are imported into the tag class files.

The toolkit then works as follows: tag classes are defined in toolkit files. When these files are sourced (via package require oowebtools) class objects (e.g., Html, etc.) are created. Class objects are commands which in turn create instance objects that are commands in their own right. Instance commands call methods as defined in the class which do the actual work. Here are 4 instance commands calling "write"— all produce the same output:

package require oowebtools

Html create html0        ; html0 write
Html new (-> oo::Obj127) ; oo::Obj127 write
set html0 [Html new]     ; $html0 write
set html1 [Html: ]       ; $html1 write

If it helps understanding, an instance object/command calling methods is analagous to a namespace ensemble, that is, a command with subcommands. One opinion is the that the class/object structure is easier to organize and more versatile.

Installation

Installing oowebtools is simple. It's only necessary to copy the "oowebtools" directory to a location on Tcl package path. A typical location is /usr/local/lib or /usr/lib. Developers often have multiple Tcl binaries in separate directories, each with its own ./lib. In this case, placing a copy of oowebtools in the "lib" directories enables using with the particular versions of Tcl.

The files in directories css, js, db, util will need to be copies to a directory in the target HTML hierarchy whether in development or final versions. Of course in a particular case not everything in these directories will be needed.

Dependencies

The toolkit has these requirements:

These are available from the following sources:

Obtaining/installing these dependencies is straighforward and mostly painless. Once accomplished install oowebtools per above.

Using component classes and utilities

Element-derived class constructors

Description of class object constructors. HTML tag class constructors are written using nxconstructor from the nxproc package. These constructors use the same basic patterns to initialize object instances. The basic syntax is generic:

<Tagname>(:| new) ?positional_args? \
    ?-option ?value? ...? --> \
    ?{attribute value...}? ?{text|element list}?

Tagname always starts with an upper case letter, followed by ' new' or its abbreviation, a colon.

There can be 0 or more positional/fixed args. Those without default values require a value entered on the command line.

There can be 0 or more named args. These are entered on the command line as ''-option value'' except for boolean types—the option alone toggles the default value. In most cases named arguments are attributes to be appended to the Attribute list for the entity.

Most tags classes are further configured by the ''end of argument'' symbol, -->, followed by one or two lists, an attribute list and/or a text string or list of tag objects.

An attribute list looks like {class main id main ...}. Element lists can be generated by using [list ...], or [subst {...}]. The latter is often less confusing so that style is recommended. In any case everything following -->, is collected in the nxargs variable. nxargs is used in the next command to pass info to the superclass constructor.

next ... --> {*}$nxargs

Element has several named args, including the all-important -tag and -endtag.

next -tag div -endtag 1 --> {*}$nxargs 

nxcontructor defines another args-like variable, nxunknown which collects anything on the command line (before -->) not previously defined. It is also passed to the superclass constructor.

next -tag div -endtag 1 {*}$nxunknown --> {*}$nxargs 

If the tag constructor has named arguments for configuring attributes, the associated variable are used after the next command.

nxconstructor {-class "" -id ""} {
    my variable Attributes
    ...
    next ...
    lappend Attributes class $class id $id
}

Naturally there are variations on the above. Questions are ultimately resolved by the source code for a particular class.

When oowebtools is loaded all files are source'd which creates a class object for each toolkit entity. Class objects are used to create instance objects which call methods to render expected HTML output.

The syntax of Element-derived classes was described above.

Non-Element-derived classes

This section attempts to describe the syntax of composite class objects not derived (or partially derived) from Element.

To be completed…