WebLord

WebLord 1.2.3

The Site Construction Power Tool

Tutorial

In this section you will find a ready-made website with two pages to get you started. Most importantly, everything is carefully documented with running commentary to really help you put the whole thing together.


Getting Started

You can cut-and-paste the fixed-pitch text directly from your browser's window into your favorite text editor. Name the file "1.wl" (.wl meaning "weblord") though you are welcome to name the file anything you want: WebLord doesn't care what file extensions you use. Consistency is the key, though!

Let's include the pre-packaged utility files. WebLord will look for these in the current directory. Since these filenames have no directory and/or volume symbols, WebLord will, if not found in the current directory, look for them in the PROGDIR: directory (from where the WebLord program was loaded, wherever that might happen to be) and next in the WebLord: directory (if you have this assigned). If not found in any of these spots, WebLord will complain and stop.


	#include "global.wl"
	#include "tools.wl"

As you've noticed I sort of like tables because they give me a lot of control over placement of specific things on the page without compromising the markup ideas of HTML. Let us create a page layout using tables:


	text = page-pattern
	{
		value	= "<table cellpadding=8 width="100%" align=left>n"
			  "<tr>"   table-logo-area    table-heading-area    "</tr>n"
			  "<tr>"   table-navigation   body                  "</tr>n"
			  "<tr>"   table-about-area   table-footnote-area   "</tr>n"
			  "</table>n"
	}

The table above has three rows (TR elements). Each row has two columns (TD elements). Notice that each of the resulting cells on this page have a fairly mnemonic (memorable) name. Let's do something crazy and move the entire left column to the right side:


	text = page-pattern
	{
		value	= "<table cellpadding=8 width="100%" align=left>n"
			  "<tr>"   table-heading-area    table-logo-area    "</tr>n"
			  "<tr>"   body                  table-navigation   "</tr>n"
			  "<tr>"   table-footnote-area   table-about-area   "</tr>n"
			  "</table>n"
	}

Ok, that seems easy enough, but try that with a finished page. And then decide that the result sucks and undo the work (but you would have made a backup first, right? Good for you! :-)

But what this demonstrates is that we merely had to move the references for the objects, not make any major changes. This starts to hint at what WebLord can do for you. Just wait, this is only the proverbial tip of the proverbial iceberg!

Let's use the first version of the table (for tradition's sake) and define each of the six cell elements:

table-logo-area

The "table-logo-area" object defines the contents of the upper left cell where you can often find the company or product logo:


	text = table-logo-area
	{
		value	= "<td valign=top width=140>" product-logo "</td>"
	}

And the "product-logo" is defined this way:


	text = product-logo
	{
		value	= »<img src=product-logo.gif width=140 height=48 alt="Logo">«
	}

There's something weird in the product-logo, isn't there? What's with these » and « symbols?! Well, you don't have to use these symbols, but they function as a pair just like the " and ' symbols. If you have lots of ' and " symbols in a string, you would ordinarily have to escape the meaning of an embedded quote by preceding it with a \ symbol (as with a \" or \' sequence); the »...« sequence is another option.

There is something else with the product-logo specification that can be improved. What, you have no idea? Are you admitting you have not read the rest of the documentation yet? ;-)

But of course, you have. The answer is that the product-logo is an image, and WebLord has specific HTML support for images. You are by no means forced to use this support, but it is somewhat handy.

NOTE: In the interest of demonstration, a fully functional definition for an image object has been included in the file html-image.wl for your enlightenment. This definition is every bit as functional as the internal image object type provided by WebLord. In fact, the definition produces HTML 3.2 compliant image definitions, even allows images that act as links. Study that file!

But now, back to the "product-logo"... Let's convert this from a text object to an image object. We'll highlight the important changes:


	image = product-logo
	{
		image-url	= "product-logo.gif";
		width		= "140";
		height		= "48";
		alt		= "Logo";
	}

Does this look more complicated or simpler? Well, it depends on how you look at it. If you use a lot of images on your page (perhaps you have created dozens of navigation buttons, all the same size) then you might want to use a global width and height and leave out these items because the global values will be inherited. What would this look like?


	site = main
	{
		width	= "140";
		height	= "48";
	}

	image = nav-button-1 { image-url = "nav1.gif";   alt = "Products" }
	image = nav-button-2 { image-url = "nav2.gif";   alt = "Support" }
	image = nav-button-3 { image-url = "nav3.gif";   alt = "Email Us" }
	image = nav-button-4 { image-url = "nav4.gif";   alt = "FAQ" }

Do you see how quickly we just defined four buttons, all the same size (140×48 pixels)? This demonstrates one of WebLord's central concepts: inheritance. The width and the height of the images is inherited.

Inherited from where you ask? Excellent question!! Let's take this opportunity to briefly explain what happens when WebLord reads a site description:

  1. WebLord loads the file, including all files that are referenced with #include specifications.
  2. WebLord looks for a SITE object. Notice that the example above had exactly such a SITE object (named "main"). If WebLord finds no SITE object, it cannot continue.
  3. If you did not tell WebLord (with program arguments) what pages are to be generated, then WebLord will look for this list in a "pages" property in the SITE object.
  4. It will then loop through each of these pages, generating each page in turn.

Additional SITE objects are ignored.

Anything defined by the SITE object is inherited by each of the pages, unless the page defines a property of the same name and thus overrides the inheritance. Likewise, any object that a page references will inherit everything that the page defines (or inherits). And again, whatever this object references, it will inherit whatever its parent object inherited.

So if two objects A and B each references object X and object X makes use of a property that it doesn't define, then either A or B provide this value. If this value differs between A and B, then X sees a different value depending which object, A or B, referenced it. X is said to be polymorphic.

You don't need to remember these terms, though you can impress your friends by throwing them into the middle of a conversation. Try this one: "The polymorphic nature of WebLord objects is made possible through fully dynamic inheritance." It will leave them speechless!

But back to our original discussion on creating contents for the six cells that constitute our pages. I believe we've pretty much covered the little logo in the upper left corner. Let us now examine the navigation bar:

table-navigation

The navigation bar usually has a bunch of nice images, text, or both. Let's create a simple navigation bar first, and then go on to a really flexible one:


	text = table-navigation
	{
		value = "<td width=140 align=top>" nav-buttons "</td>";
	}

	text = nav-buttons
	{
		value	= nav-button-1  "<br>"
			  nav-button-2  "<br>"
			  nav-button-3  "<br>"
			  nav-button-4
	}

Remember the discussion about images we had above? Those are the buttons we now use. Alas, these are merely images, not actual links to take us to another page. But don't despair! Add a link property to each image. The new image definitions (starting with what we had defined earlier) become:


	image = nav-button-1 { image-url = "nav1.gif";   alt = "Products"   link = "products.html" }
	image = nav-button-2 { image-url = "nav2.gif";   alt = "Support"    link = "support.html" }
	image = nav-button-3 { image-url = "nav3.gif";   alt = "Email Us"   link = "email.html" }
	image = nav-button-4 { image-url = "nav4.gif";   alt = "FAQ"        link = "faq.html" }

WebLord magically does the rest!

That's all quite nice, you say, but I don't want to define a different navigation bar for each page. I.e. the "nav-buttons" object above would suffice for one page, but the next might not have "nav-button-1" on it, so I'd have to define a new button bar. That's a pain!

True. The easiest way might be to define a new button bar for each page, and it's not like that's so difficult. But there is a solution to your pain, though it gets into some complex stuff. You might want skip this section if you are not inclined to delve too deeply at this time.

A flexible navigation bar

Without meaning to jump too far ahead, it is necessary to mention that the following relies on an (inherited) property named "page-name" which is defined differently for each page. You can choose a different property name, of course, but you'd have to ensure that you make the appropriate changes below and on your pages.

Consider this:


	text = nav-buttons
	{
		value =	nav-products
			nav-support
			nav-email
			nav-faq
	}

	text = nav-products	{ if=page-name "!=" "products";	then=nav-button-1 "<br>" }
	text = nav-support	{ if=page-name "!=" "support";	then=nav-button-2 "<br>" }
	text = nav-email	{ if=page-name "!=" "email";	then=nav-button-3 "<br>" }
	text = nav-faq		{ if=page-name "!=" "faq";	then=nav-button-4 "<br>" }

There is a lot more going on here, though it might look relatively simple at first. To begin with, the "nav-buttons" object has the usual "value" property, consisting of four references. These references, however, do not define a "value" property. Instead, they have this odd combination of "if" and "then" properties.

You have just encountered conditional objects! Just like the "value" property, the "if" and "then" properties are built-in. This is what happens:

  1. A reference, such as to nav-products, is first resolved as a property of the current object, either defined by the object or inherited from its parent. If this fails...
  2. An object by that name is located (provided it exists) and this objects value is used for the reference.

Exactly how an object's value is determined requires an understanding of the following factors:

  1. If an object defines an "ifdef" or "ifndef" property, the object will have no value if evaluating these conditionals indicates a failure. This allows objects to have a value only if properties are defined (inherited) upon which it relies.
  2. If an object defines an "if" property, then the value of the object is either the value of the object's "then" or "else" property, depending if the condition evaluated to true or false.
  3. If an object defines a "select-case" property, then the value of the "select-case" is appended to the string "case:"; the value of the object then becomes the value of the property by that name.
  4. If none of the above hold true, then the value of the object is either derived from the "value" property (TEXT object) or "image-url" property (IMAGE object).

QUIZ #1: Support for the "select-case" property was added with WebLord 1.1. What would WebLord 1.0 do with an object that uses a "select-case"? Click here for the answer.

But back to our flexible navigation bar. What exactly is happening there? First of all, the "nav-buttons" object references all navigation buttons, but not directly. Each of these indirect references uses a condition. The first button ("nav-button-1") is only included if the (inherited) property "page-name" is not equal to "products".

This kind of navigation bar will work for a relatively small site, a dozen pages or so. In the long run, each page could simply have a property (such as "buttons") that lists the buttons to be used (as in "nav-button-1 '<br>' nav-button-4") and your "nav-buttons" object would simply look like this:


	text = nav-buttons
	{
		value = buttons;
	}

In the long run, this would probably be the most flexible way to go.

table-about-area

This area might just be another button, or it might be left blank. We won't concern ourselves with it because our demonstration site will put nothing of significance there.

table-heading-area

We will use this area of the page to display the big page title (and maybe a subtitle). Before we go on, however, it becomes valuable to talk about PAGE objects. As mentioned above, all specifically (or implicitly) named pages for a site are generated one at a time. The contents of a page is built from the "value" property it defines. In this way, a PAGE object is deceptively similar to a TEXT object.

Page objects do not recognize conditionals, however. If you define a "select-case" or an "if" property, it will be ignored without effect. The section on Object Properties describes what each object recognizes.

At the very beginning we included two files: global.wl and tools.wl; The global.wl file defines convenient "header" and "footer" objects. Referencing these (provided no "header" and/or "footer" properties are defined or inherited) provides you with a simple, yet highly effective means of building the framework of an HTML page.


	page = products
	{
		value = header page-pattern footer;
	}

The above defines a PAGE object whose value (ccontents) is the value of the "header" object, followed by the "page-pattern" property (or value of an object by that name), followed by the "footer" object.

When we first launched into this commentary, we began with a TEXT object by the name of "page-pattern". Do you see how this whole thing is beginning to come together? The "page-pattern" referenced here makes various references, among which is "body" and "table-footnote-area".

For the page title, we'll define the "table-heading-area" property thus:


	text = table-heading-area
	{
		ifdef	= title;
		value	= "<td valign=top><h1 align=center>" title "</h1>"
			  "<hr></td>";
	}

If the "title" property is defined for this page, then this object produces a (centered) heading and a horizontal rule (HR) beneath it.

body

The definition for the page begins to take shape based on these requirements:


	page = products
	{
		value		= header page-pattern footer;
		page-name	= "products";
		body		= "This is the contents of page 1. "
				  "Easy, don't you think?";

		title		= "The Products Page";
	}

Notice that the "body" property consists of two (quoted) constant strings. WebLord will simply concatenate everything. Quoted text is taken as-is. Unquoted names are evaluated as property or object references. Everything is strung together in the end.

It is now clear that "page-pattern" is a polymorphic object. It "changes" depending on which page references it. In fact, the "header" object is a polymorphic object, too. It makes use of a whole bunch of inherited properties, combining them into a properer HTML 3.2 compliant header. I'll leave it to you to look through the global.wl file, but here is yet another version of the "products" PAGE object with properties added that the "header" reference in the PAGE object's "value" property will use.


	page = products
	{
		value		= header page-pattern footer;
		page-name	= "products";
		body		= "This is the contents of page 1. "
				  "Easy, don't you think?";

		title		= "The Products Page";		# also used by "header"
		description	= "Product and price listings with ordering information";
		keywords	= "mordorsoft sloth widgets product price ordering";
		author		= "J.Hendrix";

		nav-buttons	= nav-button-2 "<br>"
				  nav-button-3 "<br>"
				  nav-button-4;
	}

At the beginning, of course, I promised you two pages. It would be cheating, of course, if I merely copied the "products" page and changed a few things. Instead, we'll make this a dynamic page! Consider this:


	page = faq
	{
		value		= heeader page-pattern footer;
		page-name	= "faq";
		body		= faq-body;

		title		= "Frequently Asked/Answered Questions";
		description	= "This page is needed because too few people RTFM...";

		nav-buttons	= nav-button-1 "<br>"
				  nav-button-2 "<br>"
				  nav-button-3;
	}

What's different? The "body" property, of course. It references a "faq-body" object (or property.) Let's define this object:


	text = faq-body
	{
		value			= "temp.file";
		exec			= "Work:www-tools/build-faq >" value;
		exec-cleanup		= "c:delete " value;
		value-in-file		= "1";		# any value will do
		file-has-variables	= "1";		# any value will do
	}

You're probably a bit confused now, aren't you? At first glance, it would appear that the "faq-body" object simply has a value of "temp.file", right? Yes, but only at first glance!

The meaning of the "value" property is changed, however, by the presence of the "value-in-file" property. The object's value, therefore is actually the contents of the file named by the "value" property.

But things don't end there!! The "exec" property first executes the command that it defines. In this case this works out to the Unix shell prompt command Work:www-tools/build-faq >temp.file

This actually executes a command (build-faq in the "Work:www-tools/" directory) and redirects the output to the file named by the object's "value" property.

After that has happened, the contents of the file is read to become the value of the "faq-body" object. And then the "exec-cleanup" command is executed to perform a cleanup operation (delete the temporary file.)

But wait, there is more! The "file-has-variables" property indicates that the value from the file contains special sequences of characters beginning with ${ and ending with the } symbol. The text between these is... a property or object reference!!

Naturally, you could leave off the "exec" and "exec-cleanup" portions in this "faq-body" object. The value of the object would then always come from the file named in the "value" property. The hints section has some more examples on this topic.

table-footnote-area

We'll leave it to you to define or leave blank the "table-footnote-area" property. You should have enough material at this point to come up with something, even if it is little more than a (small font) version of the (hint hint!) "table-heading-area"...


Answers to Quizzes

Answer to Quiz #1: WebLord 1.0 would ignore the "select-case" property, skipping to the next step in the list and expecting to find a "value" (or "image-url") property. Finding none, it would complain. There are more subtle problems that can stem from using older versions of WebLord with files that rely on newer features. For this reason, the "requires-version" property in the SITE object should indicate the minimum version of WebLord that can successfully process the file!


WebLord is Copyright © 1997,1998 Udo K Schuermann. The latest versions of the software and (this) documentation can be obtained from the WebLord Home Page (the link will only function if you are connected to the internet.) This page has last been updated on Wednesday, January 21, 1998.