=pod

=head1 NAME

Bric::AdvTemplates - Template Producing: Advanced Topics

=head1 VERSION

$LastChangedRevision$

=head1 DATE

$LastChangedDate: 2004-05-24 18:17:44 -0700 (Mon, 24 May 2004) $

=head1 INTRODUCTION

This document discusses some templating techniques that require existing
knowledge of the Bricolage publishing system. The text and examples will assume
the reader has already read and understood the first template document,
'Producing Templates on the Bricolage System'.

=head1 AUTOHANDLER TEMPLATES

It is possible not to associate a template with an Element. Doing so creates a
template that will be used for every type of Story in a particular category and
output channel. These are called "Autohandler Templates" or just "Autohandlers".

Autohandlers usually provide wrapper HTML for normal Templates, such as a
standard site header and footer. Unlike normal templates that display particular
fields of a story, autohandlers will usually just have some HTML along with a
line of code that says "put all remaining output here". This line of code is the
'chain_next' method of the $burner object passed into all templates. It is
called like this:

    % $burner->chain_next;

Autohandlers do have access to the $story and $element objects as well. You
might use these if you want to add some customization based on the story.

Autohandlers run before any normal template is run, and if there is more than
one autohandler in a directory tree, they will each run in order from the top of
the directory tree down.

For example, let's say we publish a Column story in the News/Politics category,
and there is a Root category autohandler and a News category autohandler:

    /News/Politics/column.mc
    /autohandler
    /News/autohandler

When this Story is published, the system searches for any autohandlers, starting
at '/' working its way down to the publish category '/News/Politics'. In this
example, the templates will run in the following order:

    /autohandler
    /News/autohandler
    /News/Politics/column.mc

Here is some very simple code to illustrate the above publish. Here is the code
for the root level autohandler:

    <!-- Code for /autohandler -->
    <html>
        <head><title>The Site</title></head>
        <body bgcolor='white'>

    % $burner->chain_next;

        </body>
    </html>

Here is some code for the 'News' category autohandler:

    <!-- Code for /News/autohandler -->
    <h1>Weekly News</h1>

    <table><tr><td width=570>

    % $burner->chain_next;

    </td></tr></table>

Here is some code for the 'Column' template:

    <!-- Code for /News/Politics/column.mc -->
    <b><% $story->get_title %></b>

    % my $n = 1;
    % while (my $p = $element->get_data('paragraph', $n++)) {

    <p><% $p %></p>

    % }

Now, if we publish a Column story that has a title 'Man Bites Dog' and contains
two paragraphs of text, the resulting published story would look like:

    <!-- Code for /autohandler -->
    <html>
        <head><title>The Site</title></head>
        <body bgcolor='white'>

        <!-- Code for /News/autohandler -->
        <h1>Weekly News</h1>

        <table><tr><td width=570>

            <!-- Code for /News/Politics/column.mc -->
            <b>Man Bites Dog</b>

            <p>Earlier today a man was reported biting a dog</p>

            <p>The dog was unavailable for comment</p>

        </td></tr></table>

        </body>
    </html>


=head1 MULTI-PAGE STORIES

Elements in the Bricolage system can be marked as "paginated". Such Elements can
be used to re-execute templates over successive pages, automatically outputting
a new file each time. All templates output to a file named for the "File Name"
and "File Extension" properties of the current Output Channel. Templates based
on paginated Elements will simply append a number to the output file for each
additional time they run. So a story containing 4 paginated elements will
(assuming that the "File Name" and "File Extension" properties are set to
"index" and "html", respectively), upon publication, produce the files:

=over 4

=item index.html

=item index1.html

=item index2.html

=item index3.html

=back

There are two ways to display templates based on paginated elements. The first
is the normal 'display_element' method that is used to display all elements. The
second is by using the 'display_pages' method.

=head2 Using 'display_element'

When displaying a paginated element using 'display_element', the output of the
page elements will B<not> trigger output of the data to a new file. Thus
display_element() handles paginated Elements in the same way it handled all
other Elements. Use this approach to output all pages on a single page --
in print versions of a story, for example.

For example, say we have a 'Column' story that contains 'Page' elements. These
'Page' elements are paginated elements. Here is some template code for 'Page'
(assume page contains just paragraphs):

        <!-- Code for 'page.mc' -->
    % my $n = 1;
    % while (my $p = $element->get_data('paragraph', $n++)) {
        <p><% $p %></p>
    % }

Here is some template code for 'column':

    <!-- Code for 'column' -->
    <html>
        <head><title><% $story->get_title %></title></head>
        <body>

    % may $n = 1;
    % while (my $pg = $element->get_container('page', $n++)) {
    %     $burner->display_element($pg);
    % }

        </body>
    </html>

These templates will work exactly as you would expect: each page is output as
any other element is output, and the results of all this output are included in
a single page:

index.html :

    <!-- Code for 'column' -->
    <html>
        <head><title>Our Column Title</title></head>
        <body>

        <!-- Code for 'page.mc' -->
        <p>page 1 para 1 content</p>
        <p>page 1 para 2 content</p>

        <!-- Code for 'page.mc' -->
        <p>page 2 para 1 content</p>
        <p>page 2 para 2 content</p>

        <!-- Code for 'page.mc' -->
        <p>page 3 para 1 content</p>
        <p>page 3 para 2 content</p>

        </body>
    </html>


=head2 Using 'display_pages'

Use the C<display_pages()> method to create new files for each page
element. The C<display_pages()> method takes one or more names of paginated
elements:

  % $burner->display_pages('page', 'another_page');

When a story is published, the entire template containing the call to
C<display_pages()> is run once for every instance of the named element passed
to C<display_pages()>. So if we have a 'Column' containing 3 'Page' elements
and no "Another Page" elements, the 'Column' template will be run 3
times. Each time it runs, the C<display_pages()> method will run the 'Page'
template with each succeeding page.

So we can use our earlier example with just a minor change to produce the
output we want:

    <!-- Code for 'column' -->
    <html>
        <head><title><% $story->get_title %></title></head>
        <body>

    % $burner->display_pages('page');

        </body>
    </html>

The code for the 'page' template:

        <!-- Code for 'page.mc' -->
    % my $n = 1;
    % while (my $p = $element->get_data('paragraph', $n++)) {
        <p><% $p %></p>
    % }

This approach will output the following files:

index.html:

    <!-- Code for 'column' -->
    <html>
        <head><title>Our Column Title</title></head>
        <body>

        <!-- Code for 'page.mc' -->
        <p>page 1 para 1 content</p>
        <p>page 1 para 2 content</p>

        </body>
    </html>

index1.html:

    <!-- Code for 'column' -->
    <html>
        <head><title>Our Column Title</title></head>
        <body>

        <!-- Code for 'page.mc' -->
        <p>page 2 para 1 content</p>
        <p>page 2 para 2 content</p>

        </body>
    </html>

index2.html:

    <!-- Code for 'column' -->
    <html>
        <head><title>Our Column Title</title></head>
        <body>

        <!-- Code for 'page.mc' -->
        <p>page 3 para 1 content</p>
        <p>page 3 para 2 content</p>

        </body>
    </html>


=head1 MULTI-PAGE STORIES USING AUTOHANDLERS

Autohandlers will work with multi-page templates using display_pages.

=head1 INCLUDING RELATED STORIES AND MEDIA

Certain types of elements can have other stories or media objects related to
them. If an element has related stories or media you can get those objects using
the methods:

    % my $rel_story = $element->get_related_story;
    % my $rel_media = $element->get_related_media;

The $rel_story object will have all the methods that the exported $story object
has since they are the same object. To get the top element of the story you can
use the method 'get_tile':

    % my $rel_element = $rel_story->get_tile;

The $rel_element object is the same object as the exported $element object and
has all the same methods.

The $rel_media object has the same methods as $story does but adds a few more
specific to media objects. They are:

    % my $uri  = $rel_media->get_uri;
    % my $type = $rel_media->get_media_type;
    % my $size = $rel_media->get_size;

The method 'get_uri' returns the URI of the published media object. This can be
used like:

    <img src="<% $rel_media->get_uri %>">

in your templates. The 'get_media_type' method returns the mime type of the
media object. These are text values of the form 'image/jpeg'.

The 'get_size' method will return the file size of the media file.

=head1 Bricolage HTML::Mason Custom Tags

Bricolage extends HTML::Mason tags so that template developers can write blocks
of code that only run in certain contexts.

There are four contexts in which a template is run and in each context, code
can be executed:

=over 4

=item Syntax checking

=item Preview

=item Publish

=item Frontend serving the page

=back

A template developer would like that all code will be syntax checked, have
some special debug messages to appear to the story editor previewing the
article; have some special code that only runs at publish time; have some
cookie handling code that only runs in realtime, when an actual user is
requesting the page.

With HTML::Mason a developer could use C<< <%text> >> tags, but they would
not get syntax checked by Bricolage, and could only run in the frontend
servers.

With Bricolage Custom Tags, tags are processed according to the context.

Bricolage supports the following Mason Custom tags:

=over 4

=item C<< <%chk_syntax> >>

Only runs in syntax checking. Useful to comment out codes that you still
want to check as valid Perl code, but not to be used in any other context.

=item C<< <%preview> >>

Code inside a C<< <%preview> >> tag gets removed when published, but gets
executed when a preview is done.

=item C<< <%publish> >>

This is equivalent to the default Bricolage behaviour, since the code
is run in preview and publish mode. Can be quite useful in complex templates
where a developer wants to explicitly tell the context.

=item C<< <%realtime> >>

Code kept during the publish process, runs in preview mode.

=back

=head1 USING XML

In order to simplify the template developer's life to some degree, we've created
configuration directives that, when turned on, will add a global variable to all
templates called $writer. This variable contains an XML::Writer object that can
be used to output XML from your templates. Of course one can simply use Mason
for outputting XML, but if one needs to output a B<lot> of XML, one may wish to
take advantage of the convenience interface provided by XML::Writer.

To use $writer, simply set the INCLUDE_XML_WRITER configuration to "Yes" in
bricolage.conf. Another directive, XML_WRITER_ARGS, can be used to pass extra
arguments to the XML::Writer instantiator (see L<XML::Writer> for details of the
arguments it accepts -- just don't use the OUTPUT argument, as Bricolage needs
to set this argument in order to ensure that all XML is properly output). Then
all you need do is use $writer inside a %perl section. Here's an example:

  <%perl>
  $writer->startTag("greeting",
                    "class" => "simple");
  $writer->characters("Hello, world!");
  $writer->endTag("greeting");
  $writer->end();
  </%perl>

For more details on how to use XML::Writer, see L<XML::Writer>.

=head1 USING OTHER PERL MODULES

Since Bricolage's templates are all Perl-based, it's of course possible to load
Perl modules and use them in your templates. You might want to use DBI to pull
data in from another database, or use XML::RSS to burn in headlines from another
site. This is one of the great strengths of Bricolage's templating architecture,
and we strongly urge you to exploit this strength.

However, it's not efficient to load modules directly in your templates, since
every time they're run, they'll load the template into a separate Apache process,
and therefore use more system resources (memory). It would be better to load all of
the modules you'll need at Bricolage startup time, so that they get shared across
processes and therefore use less memory.

With the PERL_LOADER configuration directive in bricolage.conf, you can do just
that. The PERL_LOADER directive takes, on a single line, an arbitrary line of
Perl code, and executes it in the namespace reserved for Mason templates (sorry,
this functionality isn't available for HTML::Template templates at this time). So
you can execute a whole bunch of Perl C<use> statements here, and all the modules
will be available to you in your templates without needing to reload them there.
Here's an example:

  PERL_LOADER = use XML::RSS; use CGI qw(:standard); use Apache::DBI;

=head1 AUTHOR

Garth Webb <garth@perijove.com>

=head1 SEE ALSO

L<Bric|Bric>,
L<Bric::AdvTemplates|Bric::AdvTemplates>,
L<Bric::Biz::AssetType|Bric::Biz::AssetType>,
L<Bric::Biz::Asset::Formatting|Bric::Biz::Asset::Formatting>,
L<Bric::Biz::Asset::Business::Story|Bric::Biz::Asset::Business::Story>,
L<Bric::Biz::Asset::Business::Parts::Tile|Bric::Biz::Asset::Business::Parts::Tile>,
L<Bric::Biz::Asset::Business::Parts::Tile::Data|Bric::Biz::Asset::Business::Parts::Tile::Data>,
L<Bric::Biz::Asset::Business::Parts::Tile::Container|Bric::Biz::Asset::Business::Parts::Tile::Container>,
L<Bric::Util::Burner|Bric::Util::Burner>

=cut
