Services · Blog · Demo
Get on the scene
13 Dec 2006 – 09:00 in tagged , , , by Sven Dowideit
Sven Dowideit takes a closer look at a couple of existing TWiki skins and how they work.

Sadly, they are not much help for new skin developers and web designers, as they set no real consistency that can be built on. To try to resolve this, I have altered the default skin to offer better reusablility – initially as a base for the new TWiki CssZengardenSkin.

Industry Romance

The documentation in TWikiTemplates defines the twiki.SKIN.tmpl file to be a convenience container, rather than a high level layout that can then be specialized by the HTML Page Template. The TMPL:P directives suggest to me another approach – one that gives HTML conversant designers a single entry point into the TWiki skins system.

After successfully creating the proof of concept CssZengarden Skin (and using it on my Blog/Website) a month ago, work stalled. At that point, the TWiki Skin comprised only of a single twiki.zengarden.tmpl file and some css – all other template definition being inherited from the TWiki default skin. What I hope to do is to define the overall look and feel in one file, and then inherit the twiki specific parts from the default skin – but this is turning out to be impossible without changing the way that the default TWiki skin is implemented.

Trouble spots

Reading the TWikiTemplates page with a programmers viewpoint, makes it clear why its not so simple.
  1. The Master Template (twiki.SKIN.tmpl) defines some common named blocks
    • defines only a few TWiki specific sections, with few contextual cues for the non-TWikSkinMaster
    • the TWikiTemplates description suggests that there is no pre-defined Master template, only a tradition of using twiki.SKIN.tmpl. NatSkin and PatternSkin have dispensed with the twiki.SKIN.tmpl file, replacing it with body.SKIN.tmpl, page.SKIN.tmpl, constants.SKIN.tmpl etc.
  2. Every top level tmpl file (HTML Page Template) defines its own final output
    • Which prevents you from knowing that your highlevel layout is used, and makes reuse harder
    • This is historical, originally, templates were simple HTML files, one for each cgi script.
  3. Lack of predefined sections
    • Users don't know what sections you need to over-ride to achieve a local modification in all applicable skins
  4. Unknown number of resultant outputs – I can't find a list of tmpl files that must exist for TWiki!
    • How can anyone know that all customized screens are done? How to test it?
  5. very complex seeming Skin path for resolving what defines a template.

TWiki Template Directives

Resolving these issues requires an analysis of the tools (template directives) available to the skin developer.

  1. %TMPL:INCLUDE{'othertemplate'}%
    • The simplest seeming template directive, but with a non-trivial twist. This directive attempts to import in-place the contents of another template by the specified name, using the Skin path. (will look for othertemplate.zengarden.tmpl, and if it does not exist, othertemplate.tmpl.)
    • All TMPL:INCLUDE statements are recursively evaluated until there are none remaining
  2. %TMPL:DEF{'element'}% … %TMPL:END%
    • defines an named 'block' of text that is later used via the %TMPL:P% directive below.
    • if there are multiple blocks with the same name, the last one in the INCLUDE processed template wins
    • All %TMPL:DEF{'element'}%'s are parsed and loaded into TWiki before the next step
  3. %TMPL:P{'element' parameter='...'}%
    • with reserved parameters context, then and else
    • finally, all TMPL:P's are replaced recursively with the TMPL:DEF's defined in the previous phase.
  4. Literal text – any text not within a TMPL:DEF .. TMPL:END section makes up the resultant output seen by the user.

TWiki.TWikiTemplates guides the potential skin designer to create many different HTML Page templates each defining the Literal Text (is there a canonical list of required templates?), and then to push commonly used blocks up into the Master Template. This essentially ensures an inability of skins to interoperate, as the creation of named blocks is necessarily ad-hoc and specific to the skin.

There are many examples of named blocks that should be created that aren't, and many local to Page Template blocks, that only differ slightly from their equivalent blocks in other Page Templates. This approach makes it hard for new skin developers, who are forced to understand the entire system, and then to reproduce it. It also means that you cannot TMPL:INCLUDE HTML Page Templates, as this results in duplication of Literal Texts

A possible solution

If we treat the Master Template as a true master, with the HTML Page templates only defining named blocks that differ, we might improve re-use, and simplify the creation of new skins. This inversion is done, by moving all 'Literal Text' into the twiki.SKIN.tmpl, and TMPL:DEF-ing Page specific elements in the HTML Page template. This also has the benefit that there can be a standardized set of sections that become the default starting point for skin developers. Frustratingly, both NatSkin and PatternSkin go part of the way, defining page.nat.tmpl, default*.nat.tmpl etc, but not seemingly to re-use parts of the default skin, or to make it easier to integrate custom skin changes into multiple skins. Worse, they deviate totally from the advise given to other skin developers, in not defining a twiki.pattern.tmpl file at all.

Adding some code into TWiki::Templates, we can study what is currently happening.

I've attached a patch for TWiki::Templates, and a script to that can be used to create the reports below. They show:
  1. the results after TMPL:INCLUDE processing is done, and record what templates the skin path code has used, and thus from where the named blocks come (templates_postinclude)
  2. the results after template expansion is done (templates_cache)
  3. analyze commonalities in the named blocks, and where they could best be re-used

Inspecting the output (from templates_postinclude) of all the skins installable from svn, shows that no skin author is re-using the building blocks from the default skins. The following is a count of TMPL:DEF, TMPL:P and TMPL:INCLUDE elements that are used to make the view template for each skin. Note how even though ClassicSkin and DefaultSkin look very similar, as ClassicSkin totally duplicates the files in the DefaultSkin, and how NatSkin and PatternSkins also, have nothing in common with the more basic skins.

svens-computer:~/src/MAIN/templates_postinclude sven$ ../template_stats.pl view__pattern__.tmpl 
=========
view__pattern__.tmpl 
P (91) : 
DEF (89) : 
INCLUDED (12) : 
   %{ INCLUDED(/Users/sven/src/MAIN/templates/view.pattern.tmpl) view, pattern, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/page.pattern.tmpl) page, pattern, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/constants.pattern.tmpl) constants, pattern, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/javascript.pattern.tmpl) javascript, pattern, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/styles.pattern.tmpl) styles, pattern, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/stylesdynamic.pattern.tmpl) stylesdynamic, pattern, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/body.pattern.tmpl) body, pattern, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/viewtopbar.pattern.tmpl) viewtopbar, pattern, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/viewtoolbar.pattern.tmpl) viewtoolbar, pattern, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/viewleftbar.pattern.tmpl) viewleftbar, pattern, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/viewrightbar.pattern.tmpl) viewrightbar, pattern, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/viewtopicactionbuttons.pattern.tmpl) viewtopicactionbuttons, pattern, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/viewbottombar.pattern.tmpl) viewbottombar, pattern, TWiki }% 
svens-computer:~/src/MAIN/templates_postinclude sven$ ../template_stats.pl view__zengarden__.tmpl 
=========
view__zengarden__.tmpl 
P (63) : 
DEF (55) : 
INCLUDED (3) : 
   %{ INCLUDED(/Users/sven/src/MAIN/templates/view.tmpl) view, zengarden, Sandbox }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/twiki.zengarden.tmpl) twiki, zengarden, Sandbox }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/twiki.tmpl) twiki.tmpl, zengarden, Sandbox }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/css.tmpl) css.tmpl, zengarden, Sandbox }% 
svens-computer:~/src/MAIN/templates_postinclude sven$ ../template_stats.pl view__classic__.tmpl 
=========
view__classic__.tmpl 
P (46) : 
DEF (43) : 
INCLUDED (2) : 
   %{ INCLUDED(/Users/sven/src/MAIN/templates/view.classic.tmpl) view, classic, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/twiki.classic.tmpl) twiki, classic, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/css.tmpl) css.tmpl, classic, TWiki }% 
svens-computer:~/src/MAIN/templates_postinclude sven$ ../template_stats.pl view__default__.tmpl 
=========
view__default__.tmpl 
P (44) : 
DEF (40) : 
INCLUDED (2) : 
   %{ INCLUDED(/Users/sven/src/MAIN/templates/view.tmpl) view, default, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/twiki.tmpl) twiki, default, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/css.tmpl) css.tmpl, default, TWiki }% 
svens-computer:~/src/MAIN/templates_postinclude sven$ ../template_stats.pl view__nat__.tmpl 
=========
view__nat__.tmpl 
P (17) : 
DEF (40) : 
INCLUDED (8) : 
   %{ INCLUDED(/Users/sven/src/MAIN/templates/view.nat.tmpl) view, nat, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/page.nat.tmpl) page, nat, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/strings.nat.tmpl) strings, nat, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/defaultbody.nat.tmpl) defaultbody, nat, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/defaultsidebar.nat.tmpl) defaultsidebar, nat, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/defaulttopbar.nat.tmpl) defaulttopbar, nat, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/defaultjavascript.nat.tmpl) defaultjavascript, nat, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/viewtopicactions.nat.tmpl) viewtopicactions, nat, TWiki }%
   %{ INCLUDED(/Users/sven/src/MAIN/templates/searchbox.nat.tmpl) searchbox, nat, TWiki }% 

To me, this is totally unexpected, because in my conversations with people about defining tmpl's we've discussed inheritance, over-riding, and specialization – none of which seem to be taking place. I had hoped that common issues, like the html, head, body tags, copywrite, would be dealt with in the default skin, and then shared out. Nope – just looking to see where the <html> tag is defined :

svens-computer:~/src/MAIN/templates sven$ grep -i '<html' *
actionnotify.tmpl:<html>
createtopic.tmpl:<HTML>
edit.wikiwyg.tmpl:<html>
page.nat.tmpl:<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="%LANG%" lang="%LANG%">
page.pattern.tmpl:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="%LANG%" lang="%LANG%">
twiki.classic.tmpl:<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="%LANG%" lang="%LANG%"> %TMPL:END%
twiki.dandruff.tmpl:<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
twiki.quickmenu.tmpl:<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="%LANG%" lang="%LANG%">%TMPL:END%
twiki.see.tmpl:<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> %TMPL:END%
twiki.seneca.tmpl:<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
twiki.simpleblue.tmpl:<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="%LANG%" lang="%LANG%">%TMPL:END%
twiki.tiger.tmpl:<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> %TMPL:END%
twiki.tmpl:<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="%LANG%" lang="%LANG%"> %TMPL:END%
view.cc-movabletype.tmpl:<html xmlns="http://www.w3.org/1999/xhtml">
view.dallas.tmpl:<HTML>
view.nav.tmpl:<html>
view.plain.nat.tmpl:<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="%LANG%" lang="%LANG%">
view.print.nat.tmpl:<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="%LANG%" lang="%LANG%">
view.slidy.tmpl:<html>
view.tiger.tmpl:<html>

Implementing the 'Possible Solution'

To show what I'm talking about, I'm refactoring the default skin so that twiki.tmpl contains most of the HTML based definition, and each of the <script >.tmpl files contain only changes specific to those scripts.

What I changed:

  • The <script>.tmpl files contain currently all contain some trivial variation of the following. These I moved into twiki.tmpl
    %TMPL:P{"htmldoctype"}%
    %TMPL:P{"head"}%
    %TMPL:P{"bodystart"}%
    %TMPL:P{"main"}%
    %TMPL:P{"bodyend"}%
    
  • There seems to be no clear definition of what belongs in TMPL:DEF{content} vs TMPL:DEF{main}
    • I'm going to refactor based on the idea that the TMPL:DEF{heading} is not part of the TMPL:DEF{content} – I'm moving it into the definition of main
  • TMPL:DEF{message} is used in the oops templates in a similar way to TMPL:DEF{content}
    • replace message with content
  • TMPL:DEF{topicinfo} is a bad mix of topicactions and htmlfooter – containing copyright etc
    • will need to separate this out
  • There's a lot of definition of bodystart, and almost all identical

zen garden now skins all TWiki functions

Progress, without changing Zen

I now have a second revision of the CssZengardenContrib running on home.org.au – with very few changes in the twiki.zengarden.tmpl. Everything else is inherited from the default TWiki skin's templates – for which there is a patch file attached.. This means that we have a fully functional skin (last time, only view script worked well), with mostly tweaking and fixes to go.

The following code changes were made –

More Zengarden demo urls using CssZenGardenContrib at my personal blog site (note the Next design links to browse):


Leave a Reply

You may have to login or register to comment if you haven't already.
  Attachment Action Size Date Who Comment
else Template_cache_patch props, move 4.9 K 12 Dec 2006 – 23:38 Main.SvenDowideit add caching of partial and full template evaluation
else Template_defaultskin_patch props, move 25.4 K 11 Dec 2006 – 22:47 Main.SvenDowideit Default skin inversion patch
txt template_stats.pl.txt props, move 0.8 K 11 Dec 2006 – 22:49 Main.SvenDowideit generate stats from template_postinclude files
jpg zen-Attach.jpg props, move 20.9 K 12 Dec 2006 – 22:07 Main.SvenDowideit  
r14 – 17 Dec 2006 – 17:52:46 – Main.MichaelDaum
Copyright © 1999-2008 WikiRing Partnership – Contact us