This template renders the menu itself. It's separate from
the header so that it can be relocated elsewhere, including in
a Slashbox. This is the only template not assigned to the
wiki page, simply to make it available everywhere.
This is mostly an HTML form, though it does offer a link to the
current page's revision list, if there's a current Wiki page.
If the current page is a preview of a Wiki update, there's no
good reason to display revisions, as that could drop an
important change. In this case, the
parameter will evaluate to a true value:
[% UNLESS page; page = form.page; END %] [% IF page and ! form.preview %] <a href="[% "$constants.rootdir/wiki.pl?page=$page&op=list" %]">Revisions</a> of [% page %] [% END %]
The rest is mostly bare HTML, with another link to the list of recently modified Wiki pages:
<a href="[% "$constants.rootdir/wiki.pl?op=list" %]">Recent Changes</a> <br /> <form method="POST"> Search for: <input type="text" name="page" /> <input type="hidden" name="op" value="display" /> <input type="hidden" name="version" value='' /> <br /> <input type="submit" value="Go!" /> </form>
Be sure to notice the interpolation of the
rootdir configuration variable into the ``Recent
By far the most complex of the templates, this takes several variables and displays them somewhat nicely. Most of the code simply interpolates passed-in variables into HTML formatting constructs. It has a few complications, namely that it can display empty pages, several variables are optional, previews should be marked, and that it must suppress the editing widgets for the readonly mode described earlier.
After displaying the page title, the template checks to see
if there's anything in the
raw variable. If this
is empty, we reasonably assume that this is a new page, and so
display the contents of the
[% INCLUDE wikiEmptyPage %]
If there's something in
raw (we could also
cooked, for that matter), there's Wiki page
metadata to be displayed:
<p><strong> [% IF nickname -%] by <a href="[% "$constants.rootdir/~$nickname" | fixurl %]"> [% nickname == user.nickname ? 'you' : nickname %]</> [% END -%]
on [% date %]
[%- IF version -%] , version [% version %] [%- END -%]
[%- IF description -%] (<em>[% description %]</em>) [% END %].</strong>
</p> <hr /> [% IF form.preview -%] <h1>Unsaved Preview!</h1> [% END %] [% cooked %]
If you're not familiar with Template Toolkit semantics, that looks pretty imposing, but it's almost readable as English. (Or you could read Appendix C.) If there's a nickname, we compare it to the user's nickname. If they match, we'll change the author to ``you'' instead of to the user's nickname. It's more personal that way. Whatever we display, we'll link to the user's homepage on the system. The assumption here is that my esteemed coauthor Brian's clever hack for username homepage redirections works. It's a default feature.
We expect a
date parameter, and
description will probably be
there, but if they aren't, we won't display any empty fields.
One final nice feature is to label previews clearly. If there's
preview parameter passed to the applet, it's
probably because the user hit the preview button. We'll show a
nice reminder that nothing has been saved.
Some of the template directives have extra dashes. This is simply to suppress any whitespace between the HTML and the results of the directive. If this weren't there, we'd have to smash everything together in tag soup. It looks much nicer this way.
At the very of this snippet, the cooked (HTML formatted)
version of the page is displayed. It might be clearer to check
cooked in this case.
The rest of the template is a simple form, which provides
the required parameters, like
(set to ``update''), the page
raw text, and the
description along with
the preview and save buttons. The whole thing is wrapped in a
[% IF readonly %] <a href="[% "$constants.rootdir/wiki.pl?page=$title" %]"> latest version</a> [% ELSE %] big old form [% END %]
Again, the only out of the ordinary thing is the interpolated link, and that idiom has cropped up before.
This template only needs to loop through the
pagelist array (array reference, though Template Toolkit
handles dereferencing transparently), displaying the
nickname of the last user to
modify the page, the modification
date, and, if
number of each of the changes.
To avoid presenting an empty page if something is horribly wrong, there's one little trick at the top of the template:
[% UNLESS pagelist.0 %] No recent changes. Think tabula rasa. [% END %]
Unless the array reference has at least one member (at index 0), nothing will be displayed by the loop. We'll refer to the theories of John Locke, who admittedly didn't have hyperlinks in mind. It beats no feedback anyway.
This template is very similar to
it must display similar information. There are two differences.
The links from this page must take into account version numbers
(so they add the
version parameter), and the start
of the template lists the name of the page for which it lists
<p>The last several revisions of '[% pagelist.0.title %]' are:</p>
Provided there's at least one element of the array
pagelist, that's all we need. Aside
from the slightly different formatting, these two templates
could be merged very easily.
It is possible that the user could request the revision list
of a nonexistent page, for whatever reason -- perhaps having
clicked on the "Revisions" link for an empty page. It's hard to
prevent this from happening due to the way the
wikiMenu is produced. Of course, it's also possible
someone could construct a URI with the appropriate parameters,
or there could be a database error. In any case, the template
needs to handle the possibility that there are no revisions. We
wrap everything so far in a case statement:
[% IF pagelist.0.title %] <p>The last several revisions of '[% pagelist.0.title %]' are:</p> ( continue as before ) [% ELSE %] There appear to be no revisions of this page. It probably doesn't exist. [% END %]
The final and simplest template is a simple message displayed when a user requests a Wiki page that doesn't yet exist. It's worth knowing that templates don't have to contain code to be useful -- they're also handy for storing changeable text (especially things that could be translated):
This page has not yet been created. Here's your chance to make your mark.
There are several pieces of data to insert into the database to get things up and running -- we need a default Wiki page, and the applet refers to several configuration variables. It's not a real problem if they're not there, but it's more professional if they are.
Since the installation process calls the schema file,
tables, adding data is a snap:
INSERT INTO wikipage VALUES('default', 1, 1); INSERT INTO wikitext VALUES(1, now(), 1, 2, 'this is the default Wiki page', 'default page', 'this is the default Wiki page');
The values follow the order given in the schema. If these commands succeed, the database will have one page named ``default'', ready and raring to go.
The configuration variables are also easy. They are added to
vars table in the order
INSERT INTO vars VALUES('wikiRevisionLimit', 25, 'the default number of wiki page revisions to list');
The other variables include
wikiExtendedLinks. These all have sane default
values, though they can easily be modified by the standard
There are lots of potential enhancements, and the Slash Wiki may not be as simple architecturally as a monolithic 500-line program, but it integrates nicely with Slash and has a lot of cool features. It only took a few days to write, and data persistence, templating, user accounts, configuration variables, form parsing, and installation came, basically, for free.
Though it began as simple software to run a Web site, the current version of Slash is a powerful application platform. It'll just take a few developers to come up with a killer application to show off some amazing new technique you can't live without. Maybe it's an XML-RPC interface to the Stories List, or an NNTP gateway. Maybe it's something completely unrelated to Weblogs. Whatever it is, someone out there has it in mind, and just needs a little information and a little push to send us all off on interesting new tangents.