1 package WebPAC::Output::TT;
6 use base qw/WebPAC::Common/;
9 use List::Util qw/first/;
10 use Data::Dump qw/dump/;
15 WebPAC::Output::TT - use Template Toolkit to produce output
23 our $VERSION = '0.07';
27 Produce output using Template Toolkit.
35 my $tt = new WebPAC::Output::TT(
36 include_path => '/path/to/conf/output/tt',
38 filter_1 => sub { uc(shift) },
42 By default, Template Toolkit will C<EVAL_PERL> if included in templates.
51 my $log = $self->_get_logger;
53 # create Template toolkit instance
54 $self->{'tt'} = Template->new(
55 INCLUDE_PATH => $self->{'include_path'},
56 #FILTERS => $self->{'filters'},
60 $log->logdie("can't create TT object: $Template::ERROR") unless ($self->{'tt'});
62 $log->debug("filters defined: ",dump($self->{'filters'}));
64 $self ? return $self : return undef;
70 Create output from in-memory data structure using Template Toolkit template.
72 my $text = $tt->apply(
73 template => 'text.tt',
75 record_uri => 'database/prefix/mfn',
78 It also has follwing template toolikit filter routies defined:
87 my $log = $self->_get_logger();
89 foreach my $a (qw/template data/) {
90 $log->logconfess("need $a") unless ($args->{$a});
95 filter to return values of specified from $ds, usage from TT template is in form
96 C<d('FieldName','delimiter')>, where C<delimiter> is optional, like this:
104 my ($data,$type) = @_;
106 die "no data?" unless ($data);
109 my $default_delimiter = {
110 'display' => '¶<br/>',
116 my ($name,$join) = @_;
118 die "no data hash" unless ($data->{'data'} && ref($data->{'data'}) eq 'HASH');
119 # Hm? Should we die here?
120 return unless ($name);
122 my $item = $data->{'data'}->{$name} || return;
124 my $v = $item->{$type} || return;
126 if (ref($v) eq 'ARRAY') {
130 $join = $default_delimiter->{$type} unless defined($join);
131 $v = join($join, @{$v});
134 warn("TT filter $type(): field $name values aren't ARRAY, ignoring");
141 $args->{'d'} = tt_filter_type($args, 'display');
142 $args->{'display'} = tt_filter_type($args, 'display');
144 =head3 tt_filter_search
146 filter to return links to search, usage in TT:
148 [% search('FieldToDisplay','FieldToSearch','optional delimiter', 'optional_template.tt') %]
152 sub tt_filter_search {
156 die "no data?" unless ($data);
160 my ($display,$search,$delimiter,$template) = @_;
163 $delimiter ||= '¶<br/>',
165 die "no data hash" unless ($data->{'data'} && ref($data->{'data'}) eq 'HASH');
166 # Hm? Should we die here?
167 return unless ($display);
169 my $item = $data->{'data'}->{$display} || return;
171 return unless($item->{'display'});
172 if (! $item->{'search'}) {
173 warn "error in TT template: field $display didn't insert anything into search, use d('$display') and not search('$display'...)";
178 foreach my $type (qw/display search/) {
179 push @warn, "field $display type $type values aren't ARRAY" unless (ref($item->{$type}) eq 'ARRAY');
183 warn("TT filter search(): " . join(",", @warn) . ", skipping");
188 my $d_el = $#{ $item->{'display'} };
189 my $s_el = $#{ $item->{'search'} };
191 # easy, both fields have same number of elements or there is just
192 # one search and multiple display
193 if ( $d_el == $s_el || $s_el == 0 ) {
195 foreach my $i ( 0 .. $d_el ) {
199 $s = $item->{'search'}->[$i];
200 die "can't find value $i for type search in field $search" unless (defined($s));
202 $s = $item->{'search'}->[0];
204 #$s =~ s/([^\w.-])/sprintf("%%%02X",ord($1))/eg;
205 $s = __quotemeta( $s );
207 my $d = $item->{'display'}->[$i];
208 die "can't find value $i for type display in field $display" unless (defined($d));
210 my $template_arg = '';
211 $template_arg = qq{,'$template'} if ($template);
215 } elsif (! $s && $d) {
219 push @html, qq{<a href="#" onclick="return search_via_link('$search','$s'${template_arg})">$d</a>} if ($s && $d);
222 return join($delimiter, @html);
224 my $html = qq{<div class="notice">WARNING: we should really support if there is $d_el display elements and $s_el search elements, but currently there is no nice way to do so, so we will just display values</div>};
225 my $v = $item->{'display'};
230 $html .= join($delimiter, @{$v});
237 $args->{'search'} = tt_filter_search($args);
241 Used mostly for onClick events like this:
243 <a href="#" onClick="[% load_rec( record_uri, 'template_name.tt') %]>foo</a>
245 It will automatically do sanity checking and create correct JavaScript code.
249 $args->{'load_rec'} = sub {
252 my $record_uri = shift or push @errors, "record_uri missing";
253 my $template = shift or push @errors, "template missing";
255 if ($record_uri !~ m#^[^/]+/[^/]+/[^/]+$#) {
256 push @errors, "invalid format of record_uri: $record_uri";
260 return "Logger.error('errors in load_rec: " . join(", ", @errors) . "'); return false;";
262 return "load_rec('$record_uri','$template'); return false;";
268 Used to re-submit search request and load results in different template
270 <a href="#" onClick="[% load_template( 'template_name.tt' ) %]">bar</a>
274 $args->{'load_template'} = sub {
275 my $template = shift or return "Logger.error('load_template missing template name!'); return false;";
276 return "load_template($template); return false;";
279 if ($self->{filters}) {
280 $args->{f} = $self->{filters};
281 $log->debug("using f.filters");
286 $self->{'tt'}->process(
290 ) || $log->logconfess( "apply can't process template: ", $self->{'tt'}->error() );
297 Create output from in-memory data structure using Template Toolkit template
302 template => 'text.tt',
313 my $log = $self->_get_logger();
315 my $file = $args->{'file'} || $log->logconfess("need file name");
317 $log->debug("creating file ",$file);
319 open(my $fh, ">", $file) || $log->logdie("can't open output file '$file': $!");
320 print $fh $self->output(
321 template => $args->{'template'},
322 data => $args->{'data'},
323 ) || $log->logdie("print: $!");
324 close($fh) || $log->logdie("close: $!");
332 Helper to quote JavaScript-friendly characters
338 # $_ = decode('iso-8859-2', $_);
340 s<([\x{0080}-\x{fffd}]+)>{sprintf '\u%0*v4X', '\u', $1}ge if ( Encode::is_utf8($_) );
343 s<((?:[^ \x21-\x7E]|(?:\\(?!u)))+)>{sprintf '\x%0*v2X', '\x', $1}ge;
357 Dobrica Pavlinusic, C<< <dpavlin@rot13.org> >>
359 =head1 COPYRIGHT & LICENSE
361 Copyright 2005 Dobrica Pavlinusic, All Rights Reserved.
363 This program is free software; you can redistribute it and/or modify it
364 under the same terms as Perl itself.
368 1; # End of WebPAC::Output::TT