oowebtools: open-source project
oowebtools is a software toolkit for creating websites from simple to complex as requirements demand. oowebtools is written in Tcl and like Tcl oowebtools is a "platform" to build on, making all kinds of websites possible. oowebtools is perfectly suitable for producing fully static sites, but is also capable of generating pages on the fly. Content can be added dynamically, for example via AJAX/fetch APIs or standard server response. oowebtools includes its own backend server specifically for handling dynamic content.
This site, Thinairarts.com is an example since it was developed and is maintained using oowebtools. The job of managing busy websites for thriving businesses or enthusiastic communities of interest is a good problem to have! But keeping pace with demands for revision means frequently regenerating single pages up to entire sites.
Many tools are available to automate website maintenance. oowebtools includes a make-like utility pmake which can be set up to render site pages. Writing "rules" for a Pmakefile differs from typical makefiles though it's generally simpler. Running pmake is an easy way to manage generating site updates for deployment.
Tcl's tremendous adaptability and rock-steady reliability make it an ideal language for implementing this project. Website generation is naturally an off-line, time-tolerant task. Nonetheless, oowebtools operations aren't sluggish. Generating this website's 75 pages conpletes in just over two seconds, a decent performance for this type of application.
Download oowebtools!
You can access the latest version of oowebtools using our oowebtools fossil repository
Or if you prefer, go directly to the repo download page: oowebtools Downloads
You can find the oowebtools documentation here: oowebtools documentation
One option is installing fossil and cloning the repo, or just get the archive in tar.gz or zip format—it really couldn't be simpler!
The oowebtools Tools
oowebtools is a versatile construction kit originally developed for building websites. However it's also extremely useful in many other kinds of Tcl projects.
First let's look at how oowebtools works for websites.
Installing oowebtools
Installation is pretty straightforward. Once the archive is downloaded and decompressed, you'll have a single directory. Copy the directory to the usual location for extensions. Generally that's will be something like: /path/to/Tcl/lib/oowebtools.
Note that oowebtools has a few dependencies. First it uses: features of Tcl8.7 or 9.0. oowebtools uses the sqlite3 and tcllib extensions. Currently installing these on 9.0 is possible but both sqlite3 and tcllib need modifications to run on 9.0 so using 8.7 is therefore recommended.
Once installed, use oowebtools by putting the usual declaration in Tcl source files: package require oowebtools.
What's in the oowebtools Toolkit?
The oowebtools extension directory contains 20 files that begin with "oo...". These are TclOO classes that define the working elements of HTML (and other important functionality). There are also 11 non-TclOO utility files containing namespaces with procedures useful in a variety of contexts.
Html elements
-
Html
Html (defined in oo.html.tcl) provides the <html> tag. The Html constructor expects its $nxargs variable to have lists of TclOO objects that write out the head and body elements of the web page.
Like all element classes in oowebtools, Html inherits the "write" method. In Html, calling "write" outputs everything in <html> to the file specified in the file descriptor fed to write, or previously handed to the html object constructor.
-
Head
The Head class (oo.head.tcl) defines objects that write <head> elements for a web page. Head contains classes for the usual <head> elements such as links, meta, preload, title, script, style, description, charset, etc.. These elements have unique constructor signatures reflecting their uses.
-
Body
The Body class and body tag classes are derived from the Element abstract class. While a large number of body element classes are available it's also easy to define additional tag classes by subclassing Element directly, or adding a new tag to the list of tags in oo.element.tcl.
Composite elements
These are convenient prewritten but highly configurable compound elements. This list provides a general description of the element's capabilities and usage. See documentation site for more details.
-
Menu
The Menu class (in oo.menu.tcl) defines a menu system for website pages.
Menus consist of a main menu block, submenu and submenu blocks, button text and menu buttons with associated actions.
As it's designed the menu is instantiates a configuration supplied as as nested Tcl objects. For example:
-
WebImg
WebImg encloses an image in a <figure> element. This allows WebImg to have great flexibility re: placement, size and specification of other attributes via a large number of configuration options. It makes precise control of image rendering relatively easy and convenient.
Furthermore WebImg is fully componentized so that it generates corresponding CSS which is never confounded with any other element on a page no matter how many WebImgs are used. Thus WebImgs are ideal for building galleries of all sorts. This example shows typical instantiation of WebImg objects:
In this example the object (camB) calls its "css" method which generates CSS according to input values, then writes CSS to the file previously opened for writing. The unique ID inserted into CSS declarations are also used automatically in corresponding html elements.
-
Slider
Slider displays several images in sequence, with a fade-in-out transition. It's highly configurable beginning with instantiation of the class taking a list of WebImg objects to be displayed. Size and placement of the Slider and vertical size of images can be given as arguments as well.
Setup begins with creating the WebImg objects and their generated CSS. A list of these objects is needed for Slider's invocation along with other Slider options.
Like all other oowebtools elements Slider is easy to use. A typical invocation is like this:
A set of WebImgs is made in mkSliderImgs, each WebImg set to 18.15em height and CSS written into the open file with descriptor $fdcss. Slider creates the object "sldr" which calls Slider methods writing out its CSS to the page CSS file and producing a finished Slider ready to be placed in a parent html element.
Sliders don't automatically transition among images. However this behavior is easily accomplished using a simple javascript "driver" (included as the sliderJS method).
A predefined page
-
Contact (html page)
A prepared page designed to accept visitors' messages (and page-specific comments). Implemention of contact.html permits dynamic feedback to the visitor, and also sending notification via email to a site administrator re: visitor's submitted message. Visitor messages are stored in a specific sqlite3 database.
Contact.html is also where visitor comments are entered. This works by using the referring page to differentiate origins of comments. The comment's info is stored in a sqlite3 database. Comment submissions also trigger notification to the designated administrator. By default comments are moderated and must be approved. The class (oo.approve.tcl) provides an interface for this function. (See below section describing "shell scripts".)
Custom versions of the Contact class can be made by subclassing Contact. Most likely all that needs to be done is provide methods mkHead and mkBody in the derived class, and including whatever changes or improvements deemed appropriate. (The derived class needs to be given a name other than Contact, but keeping "contact.html" as the generated output is OK.)
Utilities (class-based)
-
Log
The Log class implements logging for oowebtools programs. While fairly simple it's important since several classes rely on a Log object. A program could have more than one log and multiple logs could write to the same log file or separate files.
Log takes one argument, name of the logfile to write to. If logfile is omitted or empty string, logging goes to the location specified via the Config object.
There's one method, "writelog", which writes formatted output to the log file. Output lines start with date-time followed by whatever is in the arguments. A "special" argument is "-nonl" which suppresses end-of-line newlines. Other arguments are joined and output as a string.
-
Component
Component is class implementing unique IDs for CSS and html markup such that similar entities are kept distinct on a given page. Examples were mentioned above in the sections covering the WebImg and Slider classes.
Component works by assigning pseudorandom identifiers to named entities, and using the unique (within a given page) ID in both CSS declarations and attribute lists for corresponding html elements. This idea is also applied to javascript code such that a page could contain more than one instance of an item using the same js code but needing a separate script (or particular parts, e.g., storage) to work cleanly.
The constructor takes as arguments a name list of entities (e.g., CSS class names) to be "componentized". The ClassDict keeps the "database" within Component and thus can retrieve the ID for a name. Calling method "selector" with the css class name returns "class.name[s12345]" for use in CSS files. Method "attr" or "html" returns 'class ... s12345=""'. Method "ident" works for js, returning id_s12345.
As a TclOO class, Component encapsulates the ClassDict therefore enables multiple Components to exist in the same page without interfering with one another. That may arise infrequently but very useful when it does.
-
Comment System
oowebtools provides a basic "comment system". It means pages can activate a comment dialog for visitors' use. This is a simple type of comment interface without threaded comments, reply buttons, etc. It's similar to commenting on many blog sites.
Activating comments requires classes CommDiv and CommScript. CommScript is normally output at the end of the html body. CommDiv is placed at the end of the main div of the page where the comment feature is rendered.
Commenting is a dynamic feature using javascript AJAX calls to get comment info from the server. As a dynamic service it requires the oowebtools backend server to be running. This is readily accomplished using nginx and other web servers. Server configuration is builtin to oowebtools, but should not be difficult to support web servers other than nginx.
Routing is handled on the server through the CommentRecv class which is a subclass of the abstract Dynpage. CommentRecv is by default one of the dynamic pages configured by the backend server class ooWTserv, described below. Fortunately, using comments is easier than this brief overview might suggest.
-
Approve
Approve is a simple class which interaces with CommentDb to provide a way for administrators to approve (or not) comments left by visitors. By default, comments are subject to moderation. Administrators can log on to the server (via SSH) and use the approve utility to list pending comments and approve those waiting. Functionality is basic but sufficient for the simple oowebtools system. Of course it can be developed further as needed to meet website requirements.
-
ooWTserv
The oowebtools server class, ooWTserv is elaborate in construction, but even so is quite easy to use. All that's necessary is setting configuration options via the Config class. (Described below.) The server is started by calling "server", and it's up and running.
While ooWTserv can be used as a standalone server during website development, it's intended as a backend server for dynamic pages via reverse proxy in nginx. An example configuration is included in the repository.
-
Smtp
Smtp is another complex class with numerous configuration options. It's purpose in oowebtools is primarily for sending email notification to a site administrator when messages or comments are made by visitors. However Smtp can also be used as a standalone mailer which could be beneficial for users.
Configuring Smtp requires establishing a file with default options. This is well described in oo.smtp.tcl. Config contains an option for pointing at the correct file.
Utilities (namespace-based)
-
Config
Basically the Config class consists of many variables and methods. However variables are by default set to generic values and must be overridden by setting correct values via local config files and included where necessary.
Variables to override are operating system and environment dependent. In Config no assumptions are made regarding file locations. Customarily a local configuration file is named "localconfig.tcl" but the name is arbitrary.
A customization file could look like this:
Once localconfig.tcl is complete, starting the oowebtools server is simple:
-
Resource
The Resource class contains methods used in ooWTserv and Dynpage. Chances are oowebtools users won't have a need to use Resource directly unless modifying the server or using Dynpage (or subclass) in some novel way.
-
Util
Like Resource, the Util class defines methods used internally. However one that oowebtools users conceivably could employ is \[my fileType\] which takes a file path and returns a list of two items, the file's mime type and a boolean value (true if file is binary).
Subdirectories (css/, js/, shell/)
-
js/, css/
These directories contain js and css files needed for full functionality of several components of oowebtools. These files ordinarily should be copied to the working webroot for your site under directories with the same names (js,css). (That's a common convention and unlikely to be a problem.)
-
shell/
The shell directory has several files that can be used (with some revisions) locally to activate command-line functions. These include pmake.ps1/pmake.tcl, hsmtp.ps1/hsmtp.tcl ( standalone emailer), expandCss.ps1/.tcl, expand-minifyCss.ps1/.tcl, approve.tcl. Because of the wide variability of file system layout among different systems and users, specific guidance can't be given regarding modifications to make.However examining the files it should be clear enough to users how to modify paths and names of executables in order to get these working.
oowebtools for websites
Using oowebtools classes
Except for Html, all html elements are represented by a subclass of the abstract class <Element>. To create a page, begin by deriving from Html:
There are a few things of note in this example. In several places nxconstructor, nxmethod is used providing named-arguments, very useful for configuring objects.
Also note the general layout of element calls. For example, the "tag" name, Body is followed by new (or :), then -->. Here --> takes a list of -elements that are contained within the body elememt. In this case there's an h2, then a div with its own list of elements to be rendered within it. It should be obvious this follows the normal flow of html markup.
An advantage of this way of creating pages is the clean separation of logic among computing values and displaying them. Data flow is then more understandable which contributes to effective site maintenance.
Using the Tag namespace
oowebtools provides the Tag namespace as an alternative way to use objects for page creation. Consider this example:
This example looks a lot like the previous one. Only here we're using an ordinary namespace and procs to implement the page. Notice that the prior "Head:" is now just "Head:". Every html tag class is present in the ::Tag namespace as class name + : (colon). Thus "Head:" is the same as "Head:". IOW "Head:" is a proc that returns an object that can be used directly. Just remember to put "namespace import ::Tag::*" at the top of the namespace where tags will be used.
Of course Tag::* elements can also be use in pages written as classes. Syntax is the same, Tag class followed by a colon:
The only issue with this is where to put the "namespace import ::Tag::*" line. It doesn't work to put it at the top of the class definition. However it usually works if put in the constructor, or in the first method.
oowebtools: for websites, and more...
This overview of oowebtools' many capabilities can only hit the highlights. But we hope the descriptions of the toolkit's basic functions are at least clear enough to pique your interest in what it really can do! Give it a try, let us know your impressions, your feedback is valuable. A prime goal is making constant improvement to oowebtools. Your input helps us get there and that is definitely appreciated!