On Mon, 19 Nov 2001, Mike Futerko wrote:

> I have got an idea to implement one more TAG into template language
> named TMPL_EXEC. For example <TMPL_EXEC NAME="SomeModule"> will execute
> SomeModule.pm file and output of them put instead of this TAG. In this case
> SomeModule.pm must cover some API for TMPL_EXEC TAG. For example SomeModule.pm
> must have at least two methods new, and output.

I had an idea similar to this a while back - I called it
HTML::Template::Component.  I got as far as writing the docs but I never
wrote any code.  It could probably be implemented using filters much like
HTML::Template::Expr.

I've attached the docs - take a look and see what you think.

-sam
From [EMAIL PROTECTED] Mon Nov 19 12:24:33 2001
Date: Sat, 1 Apr 2000 02:40:20 -0500 (EST)
From: Sam Tregar <[EMAIL PROTECTED]>
To: [EMAIL PROTECTED]
Subject: RFC: HTML::Template::Component

I've been stewing over this flame for a few weeks - how to create a
component framework for HTML::Template that is both useful and consistent
with HTML::Template's philosophy.  Here's what I've got - just the docs
for an incomplete idea.  There are definitely holes in this spec and I'd
like to enlist your help in finding them.

Feel free to simply throw up your hands and bellow "No!!!" at the top of
your lungs.  I would far prefer that to silence.

Here it is:

=pod

=head1 NAME

HTML::Template::Component - a component framework for HTML::Template

=head1 DESCRIPTION

This module provides a component framework for HTML::Template.  Simply
put, this allows you to create things called "components" which are
modular, reuseable hunks of perl code and HTML.  You can then use
these components in your HTML templates from with the template itself.

=head1 SYNOPSIS

A component is composed of two things, code in a module and HTML text
in a template.  Here's a short example where we create a "clock"
component that shows the current date and time.

  ### ClockComponent.pm ###
  package ClockComponent;

  # this makes this package a component
  use base 'HTML::Template::Component';

  # declare our template file
  use constant TEMPLATE_FILE => 'clock.tmpl';

  # your output() method gets called when the component is included
  # into a template with a <TMPL_COMP> tag.
  sub output {
    # recieve an HTML::Template object as the first parameter
    my $template = shift;

    # extract hours, minutes and seconds and format them for display
    my $time = join(':', (localtime(time))[2,1,0]);

    # fill in the component's template with the time.
    $template->param(TIME => $time);

    # return the finished clock
    return $template->output();
  }

  1;
  
And the ClockComponent template file, 'clock.tmpl':

  At the sound of the tone, the time will be <TMPL_VAR TIME>.<BR>

To use this component, you need to call it from another template it
from within another template, "clock_user.tmpl":

  <H1>Sam's Amazing Time Page</H1>
  
  Check out my clock!<P>
  <TMPL_COMP NAME="ClockComponent"></TMPL_COMP>

And the script that goes with "clock_user.tmpl", "clock_user.pl":

  use HTML::Template::Component;

  my $template = HTML::Template->new(filename => 'clock_user.tmpl');

  print "Content-Type: text/html\n\n";
  print $template->output();

Notice how the user of the component doesn't do anything differently
in the perl code in order to use the component.  The component is
called from inside the template using the new <TMPL_COMP> tag.

=head1 MOTIVATION

HTML::Template lacks tools for creating reusable thingies.  Call them
"widgets", "objects" or "components" - they are simply associations of
code and template text that get included into larger templates.  It is
possible to create reuseable chunks of template and code with very
careful use of TMPL_INCLUDE and Perl OO, but it's not easy.  Worse,
without a standard framework there's no way to share components
between projects and developers.

Clearly, something needed to be done.  The main problem lay in the
premise of HTML::Template - that code and design should remain
separate.  This would appear to be in direct contradiction with any
sort of component framework.  HTML::Template::Component side-steps
this issue by adding a layer of abstraction.  From the users point of
view the component is a package of code and template in one, but from
the component author's perspective they remain separate.

=head1 SIMPLE USAGE

To use HTML::Template::Component you need to create a package to hold
your component code.  The name of the package will be the name of your
component; choose carefully.  You must implement one subroutine -
output() - in your package.  You must also declare a few constants
that describe your component.  Here is a minimal, legal, component:

  package MinimalistComponent;           # declare the package name
  use base 'HTML::Template::Component';  # required to be a component

  # declare the template file name.
  use constant TEMPLATE_FILE => 'minimal_component.tmpl';

  # the output() method gets called when the component is used
  sub output {
    my $template = shift;
    return $tempate->output();
  }

  1;

The component's template is simply an HTML::Template - it can use any
HTML::Template syntax, including using other components.

To use this component, the user employs the <TMPL_COMP> tag.  This tag
is a block tag, meaning that it requires an ending </TMPL_COMP>.  In
the simplest case nothing is between the tags:

   # user_of_minimal_component.tmpl
   This is the component: <TMPL_COMP NAME="MinimalComponent"></TMPL_COMP>

This alone is enough to create powerful, reusable components that
encapsulate code and template text.  Read on to see how more
complicated components can be created.

=head1 ADVANCED USAGE

The <TMPL_COMP> tag can enclose a block of template text.  This text
is passed to output() as the second arguement.  This allows the
component to accept arguements.  Additionally, it allows a component
to act as a filter for template text.

Here's an example of a component that takes two arguements, the font
size and the font color for a headline:

  package Component::Headline;
  use base 'HTML::Template::Component';
 
  use constant TEMPLATE_FILE => 'headline.tmpl';
 
  sub output {
    my $template = shift;
    my $args = shift;

    # break out size and color from $args text
    my ($size, $color) = split(',', $args);

    $template->param(SIZE => $size,
                     COLOR => $color);

    return $template->output();
  }

  1;
  
And headline.tmpl, the component's template:

  <H1>
    <FONT SIZE="<TMPL_VAR SIZE>" COLOR="<TMPL_VAR COLOR>">
        HTML::Template::Component Is Made Of People!
    </FONT>
  </H1>  

The user of this component uses it like this:

  <TMPL_COMP NAME="Component::Headline">1,red</TMPL_COMP>

Notice how Component::Headline's output() mode had to split out the
arguements manually.  This allows you to use any arguement passing
notation you want.  It also allows for the creation of components that
act as filters for template text.  Here's a component that does
HTML-style quoting on its arguements.

  package Component::Quote;
  use base 'HTML::Template::Component';

  # this component doesn't use a template file, so it sets
  # TEMPLATE_FILE to 0.
  use constant TEMPLATE_FILE => 0;
 
  sub output {
    my $text = shift;  # since TEMPLATE_FILE is 0, no template is
                       # passed in.
    
    # do the quoting (ripped from CGI.pm!)
    $text =~ s/&/&amp;/g;
    $text =~ s/\"/&quot;/g; #"
    $text =~ s/>/&gt;/g;
    $text =~ s/</&lt;/g;

    # and return the quoted text as output.
    return $text;
  }

Notice that this component doesn't have a template.  You must set
TEMPLATE_FILE to 0 for this to work, otherwise you'll get an error
message about a missing TEMPLATE_FILE constant.

To use this component, the user does:

  <TMPL_COMP NAME="Component::Quote">
    Some stuff that gets quoted... <>&""<><>
  </TMPL_COMP>

=head1 DETAILS

=head2 REQUIRED CONSTANTS

There is only one required constant - TEMPLATE_FILE.  This constant
must contain either the name of a template file or 0 to indicate no
template.

=head2 OPTIONAL CONSTANTS

TEMPLATE_OPTIONS specifies the options that are used when opening the
template file specified by TEMPLATE_FILE.  They are specified using an
array ref and may contain any valid HTML::Template option except
"filename", "scalaref" and "arrayref".  Example:

   use constant TEMPLATE_OPTIONS => [ cache => 1,
                                      die_on_bad_params => 0 ];

=head1 AUTHOR

Sam Tregar, [EMAIL PROTECTED] (you can also find me on the mailing list
at [EMAIL PROTECTED] - join it by sending a blank message to
[EMAIL PROTECTED]).

=head1 LICENSE

HTML::Template::Component : a component framework for HTML::Template
Copyright (C) 2000 Sam Tregar ([EMAIL PROTECTED])

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA

=cut




---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to