/[webpac2]/Webpacus/lib/Webpacus/Model/Record.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /Webpacus/lib/Webpacus/Model/Record.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 378 - (show annotations)
Sat Jan 21 23:27:16 2006 UTC (18 years, 3 months ago) by dpavlin
File size: 7689 byte(s)
 r423@llin:  dpavlin | 2006-01-22 00:29:57 +0100
 begin of refactoring: move html record creation to Model::Record

1 package Webpacus::Model::Record;
2
3 use warnings;
4 use strict;
5
6 use base qw/Catalyst::Model/;
7
8 use Template;
9 use List::Util qw/first/;
10 use Data::Dumper;
11 use Encode;
12
13 =head1 NAME
14
15 Webpacus::Model::Record - produce html from one record
16
17 =head1 SYNOPSIS
18
19 Produce output using Template Toolkit.
20
21 =head1 FUNCTIONS
22
23 =cut
24
25 sub new {
26 my ( $self, $c, $config ) = @_;
27
28 $self = $self->NEXT::new($c, $config);
29 $self->config($config);
30
31 $self->{log} = $c->log;
32
33 # create Template toolkit instance
34 $self->{'tt'} = Template->new(
35 INCLUDE_PATH => $c->config->{webpac}->{template},
36 FILTERS => {
37 dump_html => sub {
38 return unless (@_);
39 my $out;
40 my $i = 1;
41 foreach my $v (@_) {
42 $out .= qq{<div id="dump_$i">} .
43 Data::HTMLDumper->Dump([ $v ],[ "v$i" ]) .
44 qq{</div>};
45 $i++;
46 }
47 $out =~ s!<table[^>/]*>!<table class="dump">!gis if ($out);
48 return $out;
49 }
50 },
51 EVAL_PERL => 1,
52 );
53
54 $self->{log}->logdie("can't create TT object: $Template::ERROR") unless ($self->{'tt'});
55
56 $self->{log}->debug("filters defined: ",Dumper($self->{'filter'}));
57
58 $self ? return $self : return undef;
59 }
60
61
62 =head2 apply
63
64 Create output from in-memory data structure using Template Toolkit template.
65
66 my $text = $tt->apply(
67 template => 'text.tt',
68 data => $ds,
69 record_uri => 'database/prefix/mfn',
70 );
71
72 It also has follwing template toolikit filter routies defined:
73
74 =cut
75
76 sub apply {
77 my $self = shift;
78
79 my $args = {@_};
80
81 my $log = $self->{log} || die "no log?";
82
83 foreach my $a (qw/template data/) {
84 $log->logconfess("need $a") unless ($args->{$a});
85 }
86
87 =head3 tt_filter_type
88
89 filter to return values of specified from $ds, usage from TT template is in form
90 C<d('FieldName','delimiter')>, where C<delimiter> is optional, like this:
91
92 [% d('Title') %]
93 [% d('Author',', ' %]
94
95 =cut
96
97 sub tt_filter_type {
98 my ($data,$type) = @_;
99
100 die "no data?" unless ($data);
101 $type ||= 'display';
102
103 my $default_delimiter = {
104 'display' => '&#182;<br/>',
105 'index' => '\n',
106 };
107
108 return sub {
109
110 my ($name,$join) = @_;
111
112 die "no data hash" unless ($data->{'data'} && ref($data->{'data'}) eq 'HASH');
113 # Hm? Should we die here?
114 return unless ($name);
115
116 my $item = $data->{'data'}->{$name} || return;
117
118 my $v = $item->{$type} || return;
119
120 if (ref($v) eq 'ARRAY') {
121 if ($#{$v} == 0) {
122 $v = $v->[0];
123 } else {
124 $join = $default_delimiter->{$type} unless defined($join);
125 $v = join($join, @{$v});
126 }
127 } else {
128 warn("TT filter $type(): field $name values aren't ARRAY, ignoring");
129 }
130
131 return $v;
132 }
133 }
134
135 $args->{'d'} = tt_filter_type($args, 'display');
136 $args->{'display'} = tt_filter_type($args, 'display');
137
138 =head3 tt_filter_search
139
140 filter to return links to search, usage in TT:
141
142 [% search('FieldToDisplay','FieldToSearch','optional delimiter', 'optional_template.tt') %]
143
144 =cut
145
146 sub tt_filter_search {
147
148 my ($data) = @_;
149
150 die "no data?" unless ($data);
151
152 return sub {
153
154 my ($display,$search,$delimiter,$template) = @_;
155
156 # default delimiter
157 $delimiter ||= '&#182;<br/>',
158
159 die "no data hash" unless ($data->{'data'} && ref($data->{'data'}) eq 'HASH');
160 # Hm? Should we die here?
161 return unless ($display);
162
163 my $item = $data->{'data'}->{$display} || return;
164
165 return unless($item->{'display'});
166 if (! $item->{'search'}) {
167 warn "error in TT template: field $display didn't insert anything into search, use d('$display') and not search('$display'...)";
168 return;
169 }
170
171 my @warn;
172 foreach my $type (qw/display search/) {
173 push @warn, "field $display type $type values aren't ARRAY" unless (ref($item->{$type}) eq 'ARRAY');
174 }
175
176 if (@warn) {
177 warn("TT filter search(): " . join(",", @warn) . ", skipping");
178 return;
179 }
180 my @html;
181
182 my $d_el = $#{ $item->{'display'} };
183 my $s_el = $#{ $item->{'search'} };
184
185 # easy, both fields have same number of elements or there is just
186 # one search and multiple display
187 if ( $d_el == $s_el || $s_el == 0 ) {
188
189 foreach my $i ( 0 .. $d_el ) {
190
191 my $s;
192 if ($s_el > 0) {
193 $s = $item->{'search'}->[$i] || die "can't find value $i for type search in field $search";
194 } else {
195 $s = $item->{'search'}->[0];
196 }
197 #$s =~ s/([^\w.-])/sprintf("%%%02X",ord($1))/eg;
198 $s = __quotemeta( $s );
199
200 my $d = $item->{'display'}->[$i] || die "can't find value $i for type display in field $display";
201
202 my $template_arg = '';
203 $template_arg = qq{,'$template'} if ($template);
204
205 push @html, qq{<a href="#" onclick="return search_via_link('$search','$s'${template_arg})">$d</a>};
206 }
207
208 return join($delimiter, @html);
209 } else {
210 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>};
211 my $v = $item->{'display'};
212
213 if ($#{$v} == 0) {
214 $html .= $v->[0];
215 } else {
216 $html .= join($delimiter, @{$v});
217 }
218 return $html;
219 }
220 }
221 }
222
223 $args->{'search'} = tt_filter_search($args);
224
225 =head3 load_rec
226
227 Used mostly for onClick events like this:
228
229 <a href="#" onClick="[% load_rec( record_uri, 'template_name.tt') %]>foo</a>
230
231 It will automatically do sanity checking and create correct JavaScript code.
232
233 =cut
234
235 $args->{'load_rec'} = sub {
236 my @errors;
237
238 my $record_uri = shift or push @errors, "record_uri missing";
239 my $template = shift or push @errors, "template missing";
240
241 if ($record_uri !~ m#^[^/]+/[^/]+/[^/]+$#) {
242 push @errors, "invalid format of record_uri: $record_uri";
243 }
244
245 if (@errors) {
246 return "Logger.error('errors in load_rec: " . join(", ", @errors) . "'); return false;";
247 } else {
248 return "load_rec('$record_uri','$template'); return false;";
249 }
250 };
251
252 =head3 load_template
253
254 Used to re-submit search request and load results in different template
255
256 <a href="#" onClick="[% load_template( 'template_name.tt' ) %]">bar</a>
257
258 =cut
259
260 $args->{'load_template'} = sub {
261 my $template = shift or return "Logger.error('load_template missing template name!'); return false;";
262 return "load_template($template); return false;";
263 };
264
265 my $out;
266
267 $self->{'tt'}->process(
268 $args->{'template'},
269 $args,
270 \$out
271 ) || $log->logconfess( "apply can't process template: ", $self->{'tt'}->error() );
272
273 return $out;
274 }
275
276 =head2 to_file
277
278 Create output from in-memory data structure using Template Toolkit template
279 to a file.
280
281 $tt->to_file(
282 file => 'out.txt',
283 template => 'text.tt',
284 data => $ds
285 );
286
287 =cut
288
289 sub to_file {
290 my $self = shift;
291
292 my $args = {@_};
293
294 my $log = $self->{log} || die "no log?";
295
296 my $file = $args->{'file'} || $log->logconfess("need file name");
297
298 $log->debug("creating file ",$file);
299
300 open(my $fh, ">", $file) || $log->logdie("can't open output file '$file': $!");
301 print $fh $self->output(
302 template => $args->{'template'},
303 data => $args->{'data'},
304 ) || $log->logdie("print: $!");
305 close($fh) || $log->logdie("close: $!");
306
307 return 1;
308 }
309
310
311 =head2 __quotemeta
312
313 Helper to quote JavaScript-friendly characters
314
315 =cut
316
317 sub __quotemeta {
318 local $_ = shift;
319 $_ = decode('iso-8859-2', $_);
320
321 s<([\x{0080}-\x{fffd}]+)>{sprintf '\u%0*v4X', '\u', $1}ge if ( Encode::is_utf8($_) );
322 {
323 use bytes;
324 s<((?:[^ \x21-\x7E]|(?:\\(?!u)))+)>{sprintf '\x%0*v2X', '\x', $1}ge;
325 }
326
327 s/\\x09/\\t/g;
328 s/\\x0A/\\n/g;
329 s/\\x0D/\\r/g;
330 s/"/\\"/g;
331 s/\\x5C/\\\\/g;
332
333 return $_;
334 }
335
336 =head1 AUTHOR
337
338 Dobrica Pavlinusic, C<< <dpavlin@rot13.org> >>
339
340 =head1 COPYRIGHT & LICENSE
341
342 Copyright 2005 Dobrica Pavlinusic, All Rights Reserved.
343
344 This program is free software; you can redistribute it and/or modify it
345 under the same terms as Perl itself.
346
347 =cut
348
349 1; # End of WebPAC::Output::TT

  ViewVC Help
Powered by ViewVC 1.1.26