Tags:
archive_me1Add my vote for this tag create new tag
view all tags

TWiki Templating System

Introduction

We have a need for more advanced template handling. As JohnTalintyre pointed out in CommonHeaderFooterTemplate it makes sense to separate the header and footer into one file so that it can be easily altered (or even overloaded by a skin). Also the oops dialog messages are all identical except for a few variables like heading, and so on.

Using external modules like the TemplateToolkit would be one way to go, but this will add a lot of baggage to TWiki.

Needs of the TWiki templating system

  • Separate common parts into one (or more) base template file(s) and include that from other template files like view.tmpl.
  • Define common variables like a "|" separator in the base template and use them in other template files
  • Define variable text in templates (i.e. view.tmpl) and pass them to the base template

Functional Spec

I tried to define a simple but powerful solution that can be extended over time. Here we go:

  • Special template directives (or preprocessor commands) are embedded in normal templates.
  • Use of template directives is optional, templates work without them.
  • All template preprocessing is done in &TWiki::Store::readTemplate() so that the caller simply gets an expanded template file (the same as before)
  • Directives are of form %TMPL:<key>% and %TMPL:<key>{"attr"}%.
  • Initial set of directives:
    • %TMPL:INCLUDE{"file"}%: Includes a template file. The usual search path is applied.
    • %TMPL:DEF{"var"}%: Define a variable. Text between this and the END directive is not returned, but put into a hash for later use.
    • %TMPL:END%: Ends variable definition.
    • %TMPL:P{"var"}%: Prints a previously defined variable.
  • New directives can be added over time when needed, i.e. IF-THEN-ELSE.
  • Variables live in a global name space, there is no parameter passing.
  • Two pass processing, so that you can use a variable before declaring it or after.
  • Templates and skins work transparently and interchangeably. You could for example define a new skin just for the header & footer and keep the other template files unchanged.
  • Note: The template directive work only for templates, they do not get processed in topic text.

Examples

Attached is an example of an oops base template oopsbase.tmpl and a example oops dialog oopstest.tmpl which is based on the base template. This is not the version that will go into the release, it is just a quick hack.

Base template oopsbase.tmpl

The first line declares the delimiter variable called "sep", used to separate multiple link items. The variable can be called anywhere by writing %TMPL:P{"sep"}%

Note: Added a dot to escape rendering of variables, i.e. read %.WEB% as %WEB%.

%TMPL:DEF{"sep"}% | %TMPL:END%
<html>
<head>
  <title> %WIKITOOLNAME% . %WEB% . %TOPIC% %.TMPL:P{"titleaction"}%</title>
  <base href="%SCRIPTURL%/view%SCRIPTSUFFIX%/%WEB%/%TOPIC%">
  <meta name="robots" content="noindex">
</head>
<body bgcolor="#FFFFFF">
<table width="100%" border="0" cellpadding="3" cellspacing="0">
  <tr>
    <td bgcolor="%WEBBGCOLOR%" rowspan="2" valign="top" width="1%">
      <a href="%WIKIHOMEURL%">
      <img src="%PUBURLPATH%/wikiHome.gif" border="0"></a>
    </td>
    <td>
      <b>%WIKITOOLNAME% . %WEB% . </b><font size="+2">
      <B>%TOPIC%</b> %TMPL:P{"titleaction"}%</font>
    </td>
  </tr>
  <tr bgcolor="%WEBBGCOLOR%">
    <td colspan="2">
      %TMPL:P{"webaction"}%
    </td>
  </tr>
</table>
--- ++ %TMPL:P{"heading"}%
%TMPL:P{"message"}%
<table width="100%" border="0" cellpadding="3" cellspacing="0">
  <tr bgcolor="%WEBBGCOLOR%">
    <td valign="top">
      Topic <b>%TOPIC%</b> . {
        %TMPL:P{"topicaction"}%
      }
    </td>
  </tr>
</table>
</body>

Test template oopstest.tmpl

Each oops template basically just defines some variables and includes the base template that does the layout work.

</table >

Sample screen shot of oopstest.tmpl

With URL: .../bin/oops/Test/TestTopic2?template=oopstest&param1=WebHome&param2=WebNotify

%.TMPL:DEF{"titleaction"}% (test =titleaction=) %.TMPL:END%
%.TMPL:DEF{"webaction"}% test =webaction= %.TMPL:END%
%.TMPL:DEF{"heading"}%
Test heading %.TMPL:END%
%.TMPL:DEF{"message"}%
Test =message=. Blah blah blah blah blah blah blah blah blah blah blah...

   * Some more blah blah blah blah blah blah blah blah blah blah...
   * Param1: %PARAM1%
   * Param2: %PARAM2%
   * Param3: %PARAM3%
   * Param4: %PARAM4%
%.TMPL:END%
%.TMPL:DEF{"topicaction"}%
Test =topicaction=:
[[%.WEB%.%TOPIC%][OK]] %.TMPL:P{"sep"}%
[[%.TWIKIWEB%.TWikiRegistration][Register]] %.TMPL:END%
%.TMPL:INCLUDE{"oopsbase"}%
testscreen.gif

Comments and feedback

... is appreciated.

  • The itching factor to put this into the upcoming release is to easy the pending converstion of the templates into XHTML format and to have a more flexible solution for templates and skins.
  • Is the terminology OK?
  • Is the spec OK?
  • Are there any other directives that are needed urgently?
  • One drawback by using the directives is that you can only test a template from within TWiki. This is because you don't have a text that has a linear flow when you use TMPL:DEF, TMPL:P and TMPL:INCLUDE.

-- PeterThoeny - 21 Jul 2001

Looks pretty good - we have a new intranet web designer who wants to put a standard look onto all our intranet sites, including TWiki, so the ability to define modular templates is of great interest! A few comments:

  • It's probably more readable to enforce variables being defined before use, which would avoid need for slower two-pass processing.
    • [ PeterThoeny ] You need two-pass processing because you need to define the "|" separator in the included template onone side, and on the other side define variables for the included template. The processing happens as regex in memory, so there is no mesurable speed penalty.
  • It would be nice to simplify the syntax a bit, e.g. not using "" around variable names (they don't really need it, unlike filenames), and not using braces - however, this is not a big deal and there is some merit in keeping consistent with the current TWiki syntax.
    • [ PeterThoeny ] The templating system uses the standard internal TWiki function to parse variable attributes. The "" can be skipped (is possible but is not documented).
  • Mixed-case keyword names would be nice, as it would be with the current TWiki variables - although upper case is probably more readable.

Also, see VerbatimExpandsVariables for my views on making VERBATIM not expand %-variables! Fixing this would make discussions of templates easier.

-- RichardDonkin - 22 Jul 2001

Looks good. Can do much more than the CommonHeaderFooterTemplate approach I proposed. TWiki has a fair bit of embedded HTML in it, it might be possible to replace some of this if the variables defined during template read are made available, possible in a name space that can be overridden by TWiki variables.

If/Then/Else could help keep html in templates rather than in Perl. Is there are way of using Perl for the expression in If without compromising security?

-- JohnTalintyre - 23 Jul 2001

This looks great. Just to prove it I coded up our drkw headerfooter example using these directives - it seems to be much more powerful. This exercise did bring a couple of questions/issues to mind:

  • TWiki currently has a set of templates that are structured something like...
    • skin
      • view
      • preview
      • attach
      • rdiff
      • search
        • rename
      • rename
      • oops
        • test
        • attach
        • ...
  • ...so is it intended for the %INCLUDE directive to be recursive? The current template set would suggest that 2 deep recursion is some kind of minimum (do we need a max?).
    • [ PeterThoeny ] Recursion can be of any depth, however for perforance it is better to include just one.

On a slightly less constructive note :), it strikes me that this kind of "template" programming style results in long lists of declarations in some parts of the source and then the occasional embedded "print" statement buried in the HTML. I was wondering whether we could come up with a more concise syntax that toggles between "code" and "data" - something like:

- HTML - 
%<nop>.{
#a comment
use "filename";
$name "value";
$name qq(
valuelineone
valuelinetwo
);
print $name;
}%
- HTML -

and

- HTML - %{print $name}% - HTML - 

This example maps fairly closely to the original suggestion:

This... becomes...
%TMPL:DEF{"name"}%value%TMPL:END% %.{$name value}%
%TMPL:DEF{"name"}% %{$name qq(
%TMPL:END% )}%
%TMPL:INCLUDE{"filename"}% %.{use "filename"}%

This then lead me to think that doing some kind of pre-parsed eval{} of the code inside the toggles may be a very powerful way to quickly extend the reach of the TWiki template system to do things like if/then and regexps. For example, what if we allowed template code to (just) call the functions in Func.pm? [Of course, this would make TWiki templates more locked to perl compared to building a new (XHTML) set of intepreted template tags...]

-- SteveRoe - 23 Jul 2001

It's worth noting that Peter's suggested syntax is %TMPL:foo%, i.e. no '.' after the '%' - the use of '.' is purely due to VerbatimExpandsVariables - please comment there, as I'd like to see this aspect of <VERBATIM> fixed. Hence, your attached example doesn't need to use '%.'.

However, in your suggested new syntax, it might be useful to use '%.' as the intro sequence, as you have done.

-- RichardDonkin - 23 Jul 2001

Thanks - fixed!

-- SteveRoe - 23 Jul 2001

Please have a look at the latest templates in the TWikiAlphaRelease. There is now one master template called twiki.tmpl that all other templates include (well, will include when all done). The idea is to define all common parts of the templates in twiki.tmpl and simply use that from all other templates.

Template variable: Defines:
%TMPL:DEF{"sep"}% %TMPL:END% "|" separator
%TMPL:DEF{"htmldoctype"}% Start of all HTML pages
%TMPL:DEF{"standardheader"}% Standard header (for view, rdiff, ...
%TMPL:DEF{"simpleheader"}% Simple header with reduced links (for edit, attach, oops,...)
%TMPL:DEF{"standardfooter"}% Footer, excluding revision part and copyright part
%TMPL:DEF{"oops"}% Skeleton of oops dialog

I.e. the preview.tmpl template is now simply:

%TMPL:INCLUDE{"twiki"}%
%TMPL:DEF{"titleaction"}% (oops) %TMPL:END%
%TMPL:DEF{"webaction"}% *Attention* %TMPL:END%
%TMPL:DEF{"heading"}% Topic is not saved yet %TMPL:END%
%TMPL:DEF{"message"}%
  Please go back in your browser and save the topic. %TMPL:END%
%TMPL:DEF{"topicaction"}% %TMPL:END%
%TMPL:P{"oops"}%

With this it should be possible to create a skin that overloads just the twiki.tmpl, i.e. a twiki.print.tmpl that redefines the header and footer.

In regards to Steve's idea of toggling between "code" and "data", this is certainly powerful. This is what ASP, JSP and TemplateToolkit is all about. I do not favor this approach for these reasons:

  • Mixing code and presentation is not so good because designers are not programmers and vice versa. I.e. a $name qq( valuelineone valuelinetwo ); command is harder to grasp for a designer then some simple directives. Better let programmers write plugins and designers write templates.
  • Security. It is challenging to ensure that no loop holes are in the system when you eval user specified Perl code.

-- PeterThoeny - 23 Jul 2001

I suppose given the recent cvs posts on the mailing list, that this is a bit late, but isn't the whole template mechanism distinct from storing and managing revisions? I kind of see it as:

  • TWiki:Store gets the latest revision. (Current file store.pm.)
  • TWiki:Tmpl does all variable substition. (New file Template.pm?)
  • TWiki:Render converts structured text to (x)html. (Currently subs in TWiki.pm.)

I don't know the TWiki code body well enough to know if this is feasible at this point. Sorry if this is noise at this point.

Just my $.02 worth...

-- DavidLeBlanc - 23 Jul 2001

Good feedback David. TWiki currently has a different internal structure for historical reasons, not as simple as you point out. We will change the internal structure of TWiki over time.

-- PeterThoeny - 24 Jul 2001

Re Steve's suggested new syntax - I tend to agree with Peter for both usability (by designers, who may not know Perl) and security. I'd particularly like to avoid introducing new security issues - TWiki has some security problems already (see SecureSetup - it's quite hard to avoid open permissions on all files if you are not the webmaster and don't have root access, because it's hard to manipulate files owned by 'nobody').

-- RichardDonkin - 24 Jul 2001

I've been playing with this new templating system. Certainly powerful, but a bit confusing. A few thoughts:

  • Change the name of webaction
    • [ PeterThoeny - 24 Jul 2001 ] This might be a confusing term for the oops dialogs, but is the correct term for all other templates, e.g. the acions you can do on the current web.
  • Move oops template definition from twiki.tmpl i.e. try and keep definition of snippets of html separate from whole pages
    • [ PeterThoeny ] I was considering this. Technically it is possible to have two level includes, the first one an %TMPL:INCLUDE{"oops"}%, and from oops.tmpl an %TMPL:INCLUDE{"twiki"}%. I decided to put all in one twiki.tmpl file for performance reasons.
  • Consider an additional syntax for definition inline with print statement - see example below.
    • [ PeterThoeny ] Your proposed %TMPL:P{"oops" titleaction="(oops)"}% syntax is a shorter version of saying %TMPL:DEF{"titleaction"}% (oops) %TMPL:END% %TMPL:P{"oops"}%. This could be a useful addition.
  • Slightly different form for DEF e.g. %TMPL:DEF:xxx{% ... %}TMPL:DEF%, as block nature of current form is somewhat hidden, some editors will even help point out missing braces. Could make it even shorted e.g. %xxx{% ... %}xxx%
    • [ PeterThoeny ] Questions if we should do it. With the current spec you can indent the text so that you can see the structure visually. Also, there is no nesting possible, so the braces are of questionable value. I opt for the current spec.
  • Move copyright information into a footer (might be alternative footers without it)
    • [ PeterThoeny ] This is not so simple with the current layout because there are many differences. View and diff have rev info + copyright info; preview has a colored bar + check boxes + copyright info; edit and other scripts have copyright info only.

ooptauth.tmpl currently:

%TMPL:INCLUDE{"twiki"}%
%TMPL:DEF{"titleaction"}% (oops) %TMPL:END%
%TMPL:DEF{"webaction"}% *Attention* %TMPL:END%
%TMPL:DEF{"heading"}% Either you need to register or the authentication failed %TMPL:END%
%TMPL:DEF{"message"}%

To edit topics on this TWiki collaborative web, you must be registered as a user.

---+++ If you expected to be logged in at this point:

   * Did you type in your login name and password correctly? Remeber, both are case sensitive.
   * If you want to try again, back arrow and hit edit again. 
   * If you have forgotton your password, please contact info@twiki.org who will reset it for you. 
   * __Note:__ You can also login anonymously as user *TWikiGuest* with password *guest*.

---+++ To register as a new user:

   * Simply fill out the *[[%TWIKIWEB%.TWikiRegistration][TWikiRegistration]]* form. It only takes a minute.%TMPL:END%
%TMPL:DEF{"topicaction"}%
[[%WEB%.TWikiTemplatingSystem][OK]] %TMPL:P{"sep"}%
[[%TWIKIWEB%.TWikiRegistration][Register]] %TMPL:END%
%TMPL:P{"oops"}%

Suggest changing to:

%TMPL:INCLUDE{"oopsbase"}%

%TMPL:DEF{"message"}%

To edit topics on this TWiki collaborative web, you must be registered as a user.

---+++ If you expected to be logged in at this point:

   * Did you type in your login name and password correctly? Remeber, both are case sensitive.
   * If you want to try again, back arrow and hit edit again. 
   * If you have forgotton your password, please contact info@twiki.org who will reset it for you. 
   * __Note:__ You can also login anonymously as user *TWikiGuest* with password *guest*.

---+++ To register as a new user:

   * Simply fill out the *[[%TWIKIWEB%.TWikiRegistration][TWikiRegistration]]* form. It only takes a minute.%TMPL:END%
%TMPL:DEF{"topicaction"}%
[[%WEB%.TWikiTemplatingSystem][OK]]  | 
[[%TWIKIWEB%.TWikiRegistration][Register]] %TMPL:END%
%TMPL:P{"oops" titleaction="(oops)" action="*Attention*" heading="Either you need to register or the authentication failed"}%

-- JohnTalintyre - 24 Jul 2001

I guess that the concerns about security and complexity in the templates are valid etc. And I have a lot of respect for the caution not to overengineer this kind of thing. Certainly the controls seem to be very powerful as they are...

...I have now modified all of the templates on Codev to use the new TMPL facility. Hopefully this will save someone else the pain. This uses the standardheader, standardfooter and oops declarations as per the first rev of twiki.tmpl - the results are zipped and attached and hopefully can be put into CVS (?) to get everyone jump started on this.

  • [ PeterThoeny - 03 Aug 2001 ] Thanks Steve for the modified template files, saved time! All template files are now updated and in TWikiAlphaRelease.

-- SteveRoe - 25 Jul 2001

I'd like to suggest a new template print to be used within the header section of pages e.g. "INHEAD". twiki.skin.tmpl could define this to include scripts and style that should not be rendered, and in any case head is the standard place, not body (although this usually seems to work).

-- JohnTalintyre - 31 Jul 2001

If I understand you correctly, you would like to have this change (in red) in twiki.tmpl:

%TMPL:DEF{"htmldoctype"}%
<!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="en" lang="en">
%TMPL:P{"inhead"}% %TMPL:END%

Is that correct? Where would you define "inhead"?

-- PeterThoeny - 03 Aug 2001

Every template that was printing out an html heading would use this. Alternatively, being able to fully escape twiki processing (outside of the <head> section could have a similar effect).

-- JohnTalintyre - 07 Aug 2001

Topic attachments
I Attachment History Action Size Date Who Comment
Unknown file formattmpl oopsbase.tmpl   manage 1.0 K 2001-07-21 - 09:08 UnknownUser Opps base template
Unknown file formattmpl oopstest.tmpl   manage 0.6 K 2001-07-21 - 09:09 UnknownUser Example opps template based on oopsbase.tmpl
GIFgif testscreen.gif   manage 9.2 K 2001-07-21 - 09:09 UnknownUser Screen shot of example opps template
Compressed Zip archivezip tmpltemplates.zip   manage 29.7 K 2001-07-25 - 15:22 UnknownUser Standard twiki skin - 46 files now incl twiki.tmpl
Unknown file formatext twikitemphfexample   manage 3.9 K 2001-07-23 - 09:52 UnknownUser drkwexample
Edit | Attach | Watch | Print version | History: r19 < r18 < r17 < r16 < r15 | Backlinks | Raw View | Raw edit | More topic actions
Topic revision: r19 - 2001-10-05 - MikeMannix
 
  • Learn about TWiki  
  • Download TWiki
This site is powered by the TWiki collaboration platform Powered by Perl Hosted by OICcam.com Ideas, requests, problems regarding TWiki? Send feedback. Ask community in the support forum.
Copyright © 1999-2026 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.