eXtropia: the open web technology company
Technology | Support | Tutorials | Development | About Us | Users | Contact Us
Free support
 ::   Support forums
 ::   Frequently asked questions
 ::   Functional Specifications
 ::   eXtropia Tutorials
 ::   Books by eXtropia
 ::   Other books
 ::   Offsite resources
eXtropia ADT Documentation

Look and Feel


[ TOC ]
[ TOC ]

Intro

This document explains how the output of ADT is rendered and how you can adjust it for you particular needs.

[ TOC ]


The View Model

Our ADT follows the concept of separation between content generation and output rendering phases. Therefore we use Action Handlers to process the request and generate the data which later on will be rendered by the view code. This enables us to use the same data for different output formats. Think about user submitting his personal information and the program needing to send the same response by email and to the browser. We want the same data to be rendered in a different ways and different actions to be taken according to the need.

Our view module uses templates to generate the output. There are many Perl templating solutions out there. We believe that Template Toolkit, the solution that we have chosen suits our users needs the best, since it allows to perform easy things easily and complex things possible. Another benefit of using Template Toolkit is an extensive documentation it comes with. The documentation includes manuals, tutorials and other reference material. You can access this material from http://template-toolkit.org/. Note that we supply a copy of Template toolkit distribution, so you don't have to do anything additional to start using our ADT. However, if you want to use the latest Template Toolkit version, get it from the URL, we have just mentioned. The Template Toolkit package is also available from http://cpan.org/.

Since the templating system that we use is well documented, we will document here only things specific for our ADT view model.

[ TOC ]


Templates and Data.

Templates are used for rendering data created in the Action Handlers.

[ TOC ]


Simple Introduction into Template Toolkit

A simple template might look like this:

 
  Hello [% data.user.first_name %] [% data.user.last_name %].
  Today is [% data.date.string %].

Which could be written in Perl as:

 
  print "Hello $data{user}{first_name} $data{user}{last_name}.\n";
  print "Today is $data{date}{string}.\n";

So the data is templates can be a nested hash. Or a list:

 
  [% FOREACH index = 0..data.total_disks %]
      Disc  : #[% index %]
      Title : [% data.disks.$index.title  %]
      Artist: [% data.disks.$index.artist %]
  [% END %]

which in Perl can be represented as:

 
  foreach my $index ( 0..@{ $data{total_disks} } ){
      print << "__INPUT__";
      Disc  : #$index
      Title : $data{disks}[$index]{title}
      Artist: $data{disks}[$index]{artist}
  __INPUT__
  }

So you just use '.' to access the members of the nested hash or array by using the key names and indexes.

Of course you have simple scalars:

 
  Hello [% name %]

which in Perl would be:

 
  print "hello $name\n";

[ TOC ]


Setting Data for the Templates

You can make any data structure visible to the template from within Action Handlers, by using the $app->setAdditionalViewDisplayParam method.

For example you have a hash data structure with records' data (%my_records). Let's say that you want it to be visible under the 'records' key. After you add the following snippet to your Action Handler:

 
  $app->setAdditionalViewDisplayParam
     (
      -PARAM_NAME  => "-RECORDS",
      -PARAM_VALUE => \%my_records,
     );

Templates can access the data in the records hash as:

 
  [% FOREACH $key = data.records.keys %]
      key [% $key %], value [% data.records.$key %]
  [% END %]

Note that the leading '-' stripped and the key becomes lowercase. The leading '-' has to be removed since Template Toolkit doesn't allow keys to start with '-'. The keys become lowercase to make it easier to distinguish them from the Template Toolkit's language constructs which uses upper case.

[ TOC ]


Template's Local Data

You can create your local data in the templates. For example:

 
  [% who = "eXtropia" %]
  [% who %] rules

will print:

 
  eXtropia rules

data is special container which protects the data created outside the templates from the local template variables.. For this reason you should never set any values inside the data container from within the templates. The following practice is very undesirable:

 
  [% data.user = { fname => 'Gunther', lname => 'Birznieks'} %]

Since you don't know whether some Action Handler has set this key already for some other template. In this case you may destroy some data that other templates rely on. Hence if you need to create local variables you shouldn't use the data container.

[ TOC ]


Configuration Data

In additional to the data you set from within the Action Handlers, all the configuration data from the .cgi file is available through the same data container. Just like the data from the Action Handler, in order to access the configuration data (in @ACTION_HANDLER_ACTION_PARAMS) you should take the configuration key, strip the leading - and lowercase it. For example to access the key -SORT_FIELD1 from the @ACTION_HANDLER_ACTION_PARAMS you can write:

 
  The sort field is [% data.sort_field1 %]

[ TOC ]


Nesting Templates

The templates are highly reusable pieces of representation. You can build many little components and stack them together to build the final look and feel. This means that you can use the same component in many places. The simplest example is the use of the header and the footer. Usually the same header and footer are used for all pages of the site. Headers usually have different titles, but the rest is usually the same. So let's look at the header and footer templates. Let's call these components header and footer.

All the templates have the extension .ttml. And we don't supply this extension when we use the template. So the two components will reside in the header.ttml and footer.ttml files respectively. Let's also create a template body.ttml, which will represent the real body and use the other two templates.

For example to insert the template header.ttml into the template body.ttml you can write:

 
  [% embed('header') %]
  This is the body
  [% embed('footer') %]

where a footer.ttml can be:

 
  <HR>
  Created by eXtropia

and header.ttml:

 
  title: hello world

As you can see we use a special function supplied by ADT to embed one template into another. We don't use the standard INCLUDE and PROCESS Template Toolkit functions, since we do some work behind the scenes as we will explain in the moment.

This will generate the following page:

 
  title: hello world
  This is the body
  <HR>
  Created by eXtropia

But as we said before, we want to be able to have different titles in different pages. This is solved very easily with the same embed() function.

 
  [% embed('header', 
           {-TITLE => 'A new title'}
          ) %]
  This is the body
  [% embed('footer') %]

now we adjust the header.ttml to be:

 
  title: [% data.title %]

and we get the output:

 
  title: A new title
  This is the body
  <HR>
  Created by eXtropia

embed() accepts the template name as a first argument (without the .ttml extension), and a reference to an array or hash as a second argument. This second argument can pass as many key-value pairs as wanted. They all will be available inside data. container in the nested templates. Just remember that the key should start with '-'.

[ TOC ]


HTML templates

The following notes are specific to the HTML templates.

[ TOC ]


Setting HTTP Headers

No HTTP headers get send until all templates get processed. Therefore you can override the default HTTP headers with your own from any template. You can use the set_headers() function, which accepts a ref to hash with headers as a single argument. For example to redirect the response to http://example.com/ you can say:

 
  [% set_headers( { Location => 'http://example.com/' } ) %]

Note that if you set the same header twice the previous header setting will be overridden with the new value.

[ TOC ]


Default ADT versus Custom Templates

Every .cgi defined the @TEMPLATES_SEARCH_PATH array. This array specifies the search path for the templates. For example in addressbook.cgi you will see:

 
  my @TEMPLATES_SEARCH_PATH = 
    qw(HTMLTemplates/AddressBook
       HTMLTemplates/Default);

By default the templates are searched: first in the HTMLTemplates/AddressBook so we can provide customized templates for the application and if the template is not found it'll be searched in HTMLTemplates/Default. If still not find the application will print an error and die.

Let's say that you want to set up a few identical application but for them to have a different look and feel. One way to do that is to have two .cgi files where you specify in the first one:

 
  my @TEMPLATES_SEARCH_PATH = 
    qw(HTMLTemplates/CustomOne
       HTMLTemplates/AddressBook
       HTMLTemplates/Default);

and in the second:

 
  my @TEMPLATES_SEARCH_PATH = 
    qw(HTMLTemplates/CustomTwo
       HTMLTemplates/AddressBook
       HTMLTemplates/Default);

So you can have two different sets of template for those templates that you want to override. Those templates that weren't overridden can be still found in either HTMLTemplates/AddressBook or HTMLTemplates/Default.

Remember that any template can be overridden. You don't have to copy all the templates into your custom directory if you don't intend to customize them all.

[ TOC ]


Using Cascading Style Sheets

In order to make easy look-n-feel changes ADT now uses Cascading Style Sheets (CSS). You specify the look and feel in the CSS file, which is then used for all web-pages. For more information about CSS please refer to http://www.w3.org/Style/CSS/.

ADT comes with our generic CSS file which is places inside a template HTMLTemplates/Default/CSSView.ttml. You are urged to customize this template to create a unique look-n-feel for your own version of the eXtropia application that you run.

To improve the performance you probably want to convert this template into a normal CSS file, so it can be cached in the browsers. For example if you have moved the style definitions into a CSS file which can be accessed as /myproject.css, you have to adjust .cgi files to point to this new location:

 
  my $CSS_VIEW_URL = "/myproject.css";

[ TOC ]


...

[GB: Would like to see some example usage sections....from simple to complex for example, explain the snippet of code that webdb uses to generate the CGI.pm widgets for the modify form as a complex example and explain how to print a simple iterative data structure as a more simple example]

[SB: Why duplicating the so well written template toolkit documentation? Of course it makes nicer for users to have all the documentation in one place, but if they are planning on actually messing with templates (other than changing the HTML) they *have* to read the real template-toolkit tutorial and/or manual. If we duplicate the already written documentation who is going to make sure that it stays in sync?

I've covered here only the things specific to ADT which aren't covered by the tt tutorial. ]

[GB: I have to disagree. Although it may seem like duplication, it is not.

I think that examples are needed that are specific to eXtropia. Actually maybe the best place for it (and you can reference it) is to change configbyexample.pod so that the changing of the views and the email views is made up to date.

This was an invaluable section that was personally tested by Hsien so she could even make the simplest changes she wanted on the scripts without being too technical 1 1/2 years ago] [ TOC ]


[ TOC ]


[ TOC ]
Master Copy URL: http://www.extropia.com/support/docs/adt/
Copyright © 2000-2001 Extropia. All rights reserved.
[ TOC ]
Written by eXtropia.
Last Modified at 09/06/2001