I'm currently working on an application where we've run into the same type of problem. The app itself is minimal and impliments the core functionality; whereas all the nifty features are implimented in small, modular plugins. So far, this is working for me:

1. It is THE LAW that all Perl code returns data structures only, and never any HTML. All HTML exists in templates only.
2. The pages in our app are built from lots of little pieces of data that may originate from many different methods. We try to have a one-to-one correspondence between these methods and templates, so we end up with lots of little template files. Each method knows what its own template is called and returns a structure like this:

sub foo_data {
    ...
    return { tmpl => 'tmpl/foo_data.tt',
             data ="" { foo => 1, bar => 2, baz => 3 }
    };
}

3. All of these foo_data type methods are called by a given CGIapp runmode and their resultant hashrefs appended to @includes. Finally the "master" template is called:

    $self->tt_process( 'tmpl/master.tt', { D => { tmpl => 'tmpl/some_runmode.tt',
                                                    data ="" { narf => 42 }, includes => [EMAIL PROTECTED] } } );

4. The master template is the same for every runmode and contains the common header/footer stuff, and then includes the runmode template:

<html>
...
[% tmpl = D.tmpl; data = "" %]
[% INCLUDE $tmpl D = data %]
...
</html>

5. The runmode template does its thing and then includes its list of sub-templates:

[% FOREACH incl IN D.includes %]
  [% tmpl = incl.tmpl; data = "" %]
  [% INCLUDE $tmpl D = data %]
[% END %]

The nice thing about this is that it can work recursively; all the little sub-templates can have their own local @includes for sub-sub templates and so on.

All of this is a lot of work. Our plugin interface allows the plugin authors to hook into the various data-returning methods and get their resultant hashrefs to modify before they're passed back to the calling method. So they can do one of a few things:

1. Simply add or modify data in the 'data' part of the hash.
2. Create or modify that chunk's includes hash
3. Change the value of that chunk's 'tmpl' field to point to the plugin author's template instead of the core one

Number 3 is important for cases where simply modifying the data isn't enough, but we still want to keep the plugin version of the template separate from the core version.

One caveat is that our system does not currently account for a scenario where two plugins may want to modify data coming back from the same method. Currently, both plugin hooks will be called (the order is not guaranteed) and as long as their data doesn't clobber each other, fine. But if they both want to change the 'tmpl' field to their own local template, we're kinda screwed.

We haven't run into that problem yet, but I'm confident we will eventually. In which case we'll probably have to come up with some plugin priority rules or something.


Mike

On 9/27/06, Nik Clayton <[EMAIL PROTECTED]> wrote:
Can anyone recommend any particular "design patterns" for creating
modular templates that make it easy for third parties to create "plugins"?

To be more specific -- I'm the maintainer of SVN::Web.  Output is fully
templated, using TT2.  The application itself is modular, and broken
down in to actions carried out by plugins.

This works well -- adding new actions is a case of installing the plugin
and updating the application config file.

The only problem is that if a plugin needs to change the output for some
reason then the only mechanism I've got for that at the moment is to
tell the person installing the plugin

    ... When you've finished installing, you need to edit the following
    templates by hand, and include some HTML.  That HTML should look
    something like this ...

For example, if you take a look at http://jc.ngo.org.uk/svnweb/jc/
you'll see a "View timeline" link.  That's not there in the default
SVN::Web install.  You need to install SVN::Web::Timeline (which I'll
get around to releasing once I've resolved this issue to my
satisfaction), and then edit the template.

Or consider SVN::Web::Search, which I'll get around to releasing one of
these days.  The installation section of the documentation

http://jc.ngo.org.uk/svnweb/jc/view/nik/CPAN/SVN-Web-Search/trunk/lib/SVN/Web/Search.pm

has a big glob of HTML for the user to cut/paste.  I'm not sure that's
really acceptable.

I can solve this in an SVN::Web specific way, but I'm casting around for
an approach that might be a bit more generic.

Any thoughts?

N

_______________________________________________
templates mailing list
[email protected]
http://lists.template-toolkit.org/mailman/listinfo/templates

Reply via email to