package HTML::Template::Extension;
$VERSION = "0.26";
sub Version { $VERSION; }
use HTML::Template;
@HTML::Template::Extension::ISA = qw(HTML::Template);
use Carp;
use Data::Dumper;
use FileHandle;
use vars qw($DEBUG $DEBUG_FILE_PATH);
use strict;
$DEBUG = 0;
$DEBUG_FILE_PATH = '/tmp/HTML-Template-Extension.debug.txt';
my %fields =
(
plugins => {},
plugins_cid => {},
filename => undef,
scalarref=>undef,
arrayref=>undef,
filehandle=>undef,
filter_internal => [],
);
my @fields_req = qw//;
my $DEBUG_FH;
sub new
{
my $proto = shift;
my $class = ref($proto) || $proto;
# aggiungo il filtro
my $self = {};
# I like %TAG_NAME% syntax
push @_,('vanguard_compatibility_mode' => 1);
# no error if a tag present in html was not set
push @_,('die_on_bad_params' => 0);
# enable loop variable items
push @_,('loop_context_vars' => 1);
# if don't exists neither filename, nor filehandle, nor scalarref,
# nor arrayref, add an empty scalarref to correct init HTML::Template
my %check = @_;
push @_,('scalarref' => \'') unless ( exists $check{'filename'} ||
exists $check{'filehandle'} ||
exists $check{'scalarref'} ||
exists $check{'arrayref'});
bless $self,$class;
$self->_init_local(@_);
# $self->_loadDynamicModule;
# $self->_reloadFilter;
my $htmpl = $class->HTML::Template::new(@_);
foreach (keys(%{$htmpl})) {
$self->{$_} = $htmpl->{$_};
}
bless $self,$class;
return $self;
}
sub _init_local {
my $self = shift;
my (%options) = @_;
# add plugins
# Assign default options
while (my ($key,$value) = each(%fields)) {
$self->{$key} = $self->{$key} || $value;
}
# add plugins
foreach (@{$options{plugins}}) {
$self->plugin_add($_);
}
delete $options{plugins};
# Assign options
while (my ($key,$value) = each(%options)) {
$self->{$key} = $value
}
# Check required params
foreach (@fields_req) {
croak "You must declare '$_' in " . ref($self) . "::new"
if (!defined $self->{$_});
}
$self->{DEBUG_FH} = new FileHandle ">>$DEBUG_FILE_PATH" if ($DEBUG);
#$self->push_filter;
}
sub output {
# redefine standard output function
my $self = shift;
my %args = @_;
if ($self->{_auto_parse}) {
$self->reloadFile();
}
if (exists $args{as}) {
# delete old params settings
$self->SUPER::clear_params();
my %as = %{$args{as}};
foreach (keys %as) {
$self->SUPER::param($_ => $as{$_});
}
}
my $output = $self->SUPER::output(%args);
print {$self->{'DEBUG_FH'}} Data::Dumper::Dumper($self) if ($DEBUG);
return $output;
}
sub html {
my $self = shift;
my %args = (defined $_[0]) ? %{$_[0]} : ();
$self->{filename}= $_[1] if (defined $_[1]);
if ( defined $self->{filename}
&& (
!defined $self->{options}->{filename}
|| $self->{filename} ne $self->{options}->{filename}
)
|| $self->{_auto_parse}
) {
$self->reloadFile();
}
return $self->output('as' => \%args);
}
sub filename {
my $s=shift;
if (@_) {
my $new_file = shift;
if ($s->{filename} ne $new_file) {
$s->{filename} = $new_file;
# reload local file
$s->{_auto_parse} = 1;
# remove other text storage
delete($s->{scalarref});
delete($s->{arrayref});
delete($s->{filehandle});
}
};
return $s->{filename};
}
sub scalarref {
my $s=shift;
if (@_) {
$s->{scalarref} = shift;
# reload local file
$s->{_auto_parse} = 1;
delete($s->{filename});
delete($s->{options}->{filename});
delete($s->{arrayref});
delete($s->{filehandle});
};
# remove other text storage
return $s->{scalarref};
}
sub arrayref {
my $s=shift;
if (@_) {
$s->{arrayref} = shift;
# reload local file
$s->{_auto_parse} = 1;
# remove other text storage
delete($s->{scalarref});
delete($s->{filename});
delete($s->{options}->{filename});
delete($s->{filehandle});
};
return $s->{arrayref};
}
sub filehandle {
my $s=shift;
if (@_) {
$s->{filehandle} = shift;
# reload local file
$s->{_auto_parse} = 1;
# remove other text storage
delete($s->{scalarref});
delete($s->{arrayref});
delete($s->{filename});
delete($s->{options}->{filename});
};
return $s->{filehandle};
}
sub reloadFile {
my $self = shift;
$self->{_auto_parse} = 0;
if ( defined $self->{filename}
&& ( !defined $self->{options}->{filename}
|| $self->{filename} ne $self->{options}->{filename}
)
) {
$self->{options}->{filename} = $self->{filename};
my $filepath = $self->_find_file($self->{filename});
$self->{options}->{filepath} = $self->{filename};
} elsif (exists($self->{scalarref})) {
$self->{options}->{scalarref} = $self->{scalarref};
} elsif (exists($self->{arrayref})) {
$self->{options}->{arrayref}=$self->{arrayref};
} elsif (exists($self->{filehandle})) {
$self->{options}->{filehandle} = $self->{filehandle};
}
$self->{filter} = $self->{filter_internal};
$self->{options}->{filter}= $self->{filter};
$self->_init_template();
# local caching params
my %params;
my @parname = $self->param();
foreach (@parname) {
$params{$_} = $self->param($_);
}
$self->_parse();
# reassign params
foreach (keys(%params)) {
$self->param($_=> $params{$_});
}
# now that we have a full init, cache the structures if cacheing is
# on. shared cache is already cool.
if($self->{options}->{file_cache}){
$self->_commit_to_file_cache();
}
$self->_commit_to_cache() if (($self->{options}->{cache}
and not $self->{options}->{shared_cache}
and not $self->{options}->{file_cache}) or
($self->{options}->{double_cache}) or
($self->{options}->{double_file_cache}));
}
sub _reloadFilter {
my $self = shift;
undef $self->{filter_internal} ;
$self->{plugins_cid} = {};
# plugin priority filter
{
foreach (values %{$self->{plugins}}) {
$self->_pushModule($_);
}
}
}
#sub _loadDynamicModule {
# my $self = shift;
# {
# foreach (keys %{$self->{plugins}}) {
# $self->_initModule($_);
# }
# }
#}
sub _importModule {
my $self = shift;
my $module_name = shift;
$module_name =~s/::/\//g;
require $module_name . ".pm";
}
sub _initModule {
my $self = shift;
my $module = shift;
if (ref($module) eq '') {
$self->_importModule($module);
no strict "refs";
&{$module . "::init"}($self);
} else {
$module->init($self);
}
}
sub _pushModule {
my $self = shift;
my ($module, $module_name) = $self->_module_info(shift);
if (exists $self->{plugins_cid}->{$module_name}) {
# esiste gia' qualcosa di caricato...lo devo scaricare
# prima di poter fare qualsiasi cosa
my @code_ids = @{$self->{plugins_cid}->{$module_name}};
foreach (@code_ids) {
$self->_remove_filter_id($_);
}
delete $self->{plugins_cid}->{$module_name};
}
# count coderef items
my $pre_code_count = $self->{filter_internal} ? scalar(@{$self->{filter_internal}})-1 : -1 ;
if (ref($module) eq '') {
no strict "refs";
&{$module . "::push_filter"}($self);
} else {
$module->push_filter($self);
}
# count coderef items after push_filter
my $post_code_count = $self->{filter_internal} ? scalar(@{$self->{filter_internal}})-1 : -1;
return if ($post_code_count == $pre_code_count);
return if ($post_code_count <0);
$pre_code_count++;
# so this module as add post-pre code items
if (exists($self->{plugins_cid}->{$module_name})) {
push @{$self->{plugins_cid}->{$module_name}},($pre_code_count ..
$post_code_count)
} else {
$self->{plugins_cid}->{$module_name} = [$pre_code_count ..
$post_code_count];
}
}
sub filter { my $s=shift; return @_ ? ($s->{filter_internal}=shift) : $s->{filter_internal} }
sub plugin_add {
my $s = shift;
if (@_) {
my ($module, $module_name) = $s->_module_info(shift);
# plugin gia caricato
return if (exists $s->{plugins}->{$module_name});
$s->{plugins}->{$module_name} = $module;
# init module
$s->_initModule($module);
# add filter from added module to me
$s->_pushModule($module);
# add the array id of added code
$s->{_auto_parse} = 1;
};
return $s->{plugins}
}
sub plugin_remove {
my $s = shift;
my ($module, $module_name) = $s->_module_info(shift);
delete $s->{plugins}->{$module_name};
if (exists $s->{plugins_cid}->{$module_name}) {
my @code_ids = @{$s->{plugins_cid}->{$module_name}};
foreach (@code_ids) {
$s->_remove_filter_id($_);
}
}
delete $s->{plugins_cid}->{$module_name};
$s->{_auto_parse} = 1;
}
sub _remove_filter_id {
my $s = shift;
my $f_id = shift;
my @a = ();
push @a, @{$s->{filter_internal}}[0 .. $f_id-1] if ($f_id>0);
push @a, @{$s->{filter_internal}}[$f_id+1 .. $#{$s->{filter_internal}}]
if ($f_id< $#{$s->{filter_internal}});
$s->{filter_internal} = \@a;
}
sub plugins_clear {
my $s = shift;
undef $s->{plugins};
undef $s->{options}->{plugins};
undef $s->{filter_internal};
$s->{plugins_cid} = {};
return $s->{plugins};
}
sub DESTROY {
}
sub AUTOLOAD {
my $self = shift;
my @procs = split(/::/,$HTML::Template::Extension::AUTOLOAD);
return if (scalar(@procs)<3);
my $proc = $procs[-1];
my $value;
no strict "refs";
foreach my $module (values %{$self->{plugins}}) {
my $ret;
if (ref($module)) {
#$ret = eval { return $module->
} else {
$ret= eval { return &{"${module}::$proc"}($self,@_) };
}
if (!$@) { return $ret };
};
}
sub _module_info {
my $self = shift;
my $module = shift;
my $module_name;
if (ref($module)) {
$module_name = ref($module);
} else {
$module = "HTML::Template::Extension::$module"
if ($module!~/::/);
$module_name = $module;
}
return ($module,$module_name);
}
1;