blib/lib/WWW/Offline/Toolkit.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 18 | 243 | 7.4 |
branch | 0 | 100 | 0.0 |
condition | 0 | 27 | 0.0 |
subroutine | 6 | 30 | 20.0 |
pod | 0 | 18 | 0.0 |
total | 24 | 418 | 5.7 |
line | stmt | bran | cond | sub | pod | time | code | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | package WWW::Offline::Toolkit; | |||||||||||||
2 | ||||||||||||||
3 | 1 | 1 | 23717 | use 5.010000; | ||||||||||
1 | 4 | |||||||||||||
1 | 30 | |||||||||||||
4 | 1 | 1 | 5 | use strict; | ||||||||||
1 | 1 | |||||||||||||
1 | 26 | |||||||||||||
5 | 1 | 1 | 4 | use warnings; | ||||||||||
1 | 5 | |||||||||||||
1 | 31 | |||||||||||||
6 | 1 | 1 | 870 | use Data::Dumper; | ||||||||||
1 | 12050 | |||||||||||||
1 | 107 | |||||||||||||
7 | 1 | 1 | 2054 | use Parse::RecDescent; | ||||||||||
1 | 58098 | |||||||||||||
1 | 9 | |||||||||||||
8 | 1 | 1 | 53 | use File::Find qw(finddepth); | ||||||||||
1 | 3 | |||||||||||||
1 | 4494 | |||||||||||||
9 | ||||||||||||||
10 | our $VERSION = '0.01'; | |||||||||||||
11 | ||||||||||||||
12 | sub new | |||||||||||||
13 | { | |||||||||||||
14 | 0 | 0 | 0 | my ($class, @args) = @_; | ||||||||||
15 | 0 | my $self = bless {}, $class; | ||||||||||||
16 | 0 | return $self->init(@args); | ||||||||||||
17 | } | |||||||||||||
18 | ||||||||||||||
19 | sub init | |||||||||||||
20 | { | |||||||||||||
21 | 0 | 0 | 0 | my ($self, %options) = @_; | ||||||||||
22 | ||||||||||||||
23 | 0 | $self->{'DataDirectory'} = './data'; | ||||||||||||
24 | 0 | $self->{'OnlineDirectory'} = './online'; | ||||||||||||
25 | 0 | $self->{'IndexFile'} = $self->{'OnlineDirectory'}.'/index.html'; | ||||||||||||
26 | ||||||||||||||
27 | 0 | $self->{'PostsDirectory'} = $self->{'OnlineDirectory'}.'/posts'; | ||||||||||||
28 | 0 | $self->{'CategoriesDirectory'} = $self->{'OnlineDirectory'}.'/categories'; | ||||||||||||
29 | ||||||||||||||
30 | 0 | $self->{'MainCategoryId'} = 'cat-Main'; | ||||||||||||
31 | 0 | $self->{'CategoryPageTemplateId'} = 'tmpl-Main'; | ||||||||||||
32 | 0 | $self->{'PostTeaserTemplateId'} = 'tmpl-Teaser'; | ||||||||||||
33 | 0 | $self->{'ImageTemplateId'} = 'tmpl-Image'; | ||||||||||||
34 | ||||||||||||||
35 | 0 | 0 | map { $self->{$_} = $options{$_} if exists $self->{$_} } | |||||||||||
0 | ||||||||||||||
36 | keys %options; | |||||||||||||
37 | ||||||||||||||
38 | 0 | $self->{'Objects'} = {}; | ||||||||||||
39 | ||||||||||||||
40 | 0 | return $self; | ||||||||||||
41 | } | |||||||||||||
42 | ||||||||||||||
43 | #------------------------------------------------------------------------------- | |||||||||||||
44 | sub process | |||||||||||||
45 | { | |||||||||||||
46 | 0 | 0 | 0 | my ($self) = @_; | ||||||||||
47 | ||||||||||||||
48 | #------------------------------------------------------------------------------- | |||||||||||||
49 | # find data files | |||||||||||||
50 | ||||||||||||||
51 | 0 | my @Files; | ||||||||||||
52 | finddepth( | |||||||||||||
53 | sub { | |||||||||||||
54 | 0 | 0 | 0 | push @Files, $File::Find::name | ||||||||||
55 | if $File::Find::name =~ /\.txt$/; | |||||||||||||
56 | }, | |||||||||||||
57 | 0 | $self->{'DataDirectory'}); | ||||||||||||
58 | ||||||||||||||
59 | #------------------------------------------------------------------------------- | |||||||||||||
60 | # parse concatenated file contents | |||||||||||||
61 | ||||||||||||||
62 | 0 | my $Source = ''; | ||||||||||||
63 | 0 | foreach my $file (@Files) { | ||||||||||||
64 | 0 | print "reading $file\n"; | ||||||||||||
65 | 0 | $Source .= read_file($file); | ||||||||||||
66 | } | |||||||||||||
67 | ||||||||||||||
68 | 0 | $::RD_ERRORS = 1; | ||||||||||||
69 | #$::RD_WARN = 1; | |||||||||||||
70 | #$::RD_HINT = 1; | |||||||||||||
71 | #$::RD_TRACE = 1; | |||||||||||||
72 | 0 | $::RD_AUTOSTUB = 1; | ||||||||||||
73 | ||||||||||||||
74 | 0 | my $Grammar = q( | ||||||||||||
75 | ||||||||||||||
76 | |
|||||||||||||
77 | ||||||||||||||
78 | file: |
|||||||||||||
79 | { [@{$item[2]}] } | |||||||||||||
80 | ||||||||||||||
81 | object: "(" type id hash ")" | |||||||||||||
82 | { ['object', $item[2], $item[3], $item[4]] } | |||||||||||||
83 | ||||||||||||||
84 | hash: pair(s) | |||||||||||||
85 | { | |||||||||||||
86 | my %hash; | |||||||||||||
87 | foreach my $pair (@{$item[1]}) { | |||||||||||||
88 | my $value = $pair->[1]; | |||||||||||||
89 | $value = $value->[1] if $value->[0] eq 'value'; | |||||||||||||
90 | $hash{$pair->[0]} = $value; | |||||||||||||
91 | } | |||||||||||||
92 | \%hash; | |||||||||||||
93 | } | |||||||||||||
94 | ||||||||||||||
95 | pair: key ":" value | |||||||||||||
96 | { [$item[1], $item[3]] } | |||||||||||||
97 | ||||||||||||||
98 | value: object | ref | string | list | |||||||||||||
99 | { $item[1] } | |||||||||||||
100 | ||||||||||||||
101 | ref: id | |||||||||||||
102 | ||||||||||||||
103 | id: "#" symbol | |||||||||||||
104 | { $item[2] } | |||||||||||||
105 | ||||||||||||||
106 | type: symbol | |||||||||||||
107 | { $item[1] } | |||||||||||||
108 | ||||||||||||||
109 | key: symbol | |||||||||||||
110 | { $item[1] } | |||||||||||||
111 | ||||||||||||||
112 | symbol: /[A-Za-z0-9\_\-]+/ | |||||||||||||
113 | { $item[1] } | |||||||||||||
114 | ||||||||||||||
115 | string: "{" /[^\{\}]*/ "}" | |||||||||||||
116 | { ['string', $item[2]] } | |||||||||||||
117 | ||||||||||||||
118 | list: "[" value(s) "]" | |||||||||||||
119 | { [map { $_->[1] } @{$item[2]}] } | |||||||||||||
120 | ||||||||||||||
121 | ); | |||||||||||||
122 | ||||||||||||||
123 | 0 | my $Parser = new Parse::RecDescent($Grammar); | ||||||||||||
124 | 0 | my $AST = $Parser->file($Source); | ||||||||||||
125 | ||||||||||||||
126 | #------------------------------------------------------------------------------- | |||||||||||||
127 | # create objects from AST | |||||||||||||
128 | ||||||||||||||
129 | 0 | foreach my $object (@{$AST}) { | ||||||||||||
0 | ||||||||||||||
130 | 0 | $self->create_object($object, $self->{'Objects'}); | ||||||||||||
131 | } | |||||||||||||
132 | ||||||||||||||
133 | 0 | my $MainCategory = $self->{'Objects'}->{$self->{'MainCategoryId'}}; | ||||||||||||
134 | 0 | my $PostsDirectory = $self->{'PostsDirectory'}; | ||||||||||||
135 | 0 | my $CategoriesDirectory = $self->{'CategoriesDirectory'}; | ||||||||||||
136 | 0 | my $CategoryPageTemplate = $self->{'Objects'}->{$self->{'CategoryPageTemplateId'}}; | ||||||||||||
137 | 0 | my $PostTeaserTemplate = $self->{'Objects'}->{$self->{'PostTeaserTemplateId'}}; | ||||||||||||
138 | 0 | my $ImageTemplate = $self->{'Objects'}->{$self->{'ImageTemplateId'}}; | ||||||||||||
139 | ||||||||||||||
140 | #------------------------------------------------------------------------------- | |||||||||||||
141 | # check object references | |||||||||||||
142 | ||||||||||||||
143 | 0 | while ($self->has_unresolved_references()) { | ||||||||||||
144 | 0 | foreach my $id (keys %{$self->{'Objects'}}) { | ||||||||||||
0 | ||||||||||||||
145 | 0 | $self->resolve_object_references($id); | ||||||||||||
146 | } | |||||||||||||
147 | } | |||||||||||||
148 | ||||||||||||||
149 | 0 | print "building website...\n"; | ||||||||||||
150 | ||||||||||||||
151 | #------------------------------------------------------------------------------- | |||||||||||||
152 | # build index.html | |||||||||||||
153 | ||||||||||||||
154 | 0 | write_file($self->{'IndexFile'}, | ||||||||||||
155 | ''. | |||||||||||||
156 | ''. | |||||||||||||
157 | ' 158 | to_filename($self->{'Objects'}->{'Home'}->{'title'}).'.html">'. | ||||||||||||
159 | ''. | |||||||||||||
160 | ''. | |||||||||||||
161 | ''); | |||||||||||||
162 | ||||||||||||||
163 | #------------------------------------------------------------------------------- | |||||||||||||
164 | # build post pages | |||||||||||||
165 | ||||||||||||||
166 | 0 | 0 | unless (-d $PostsDirectory) { | |||||||||||
167 | 0 | 0 | mkdir($PostsDirectory) | |||||||||||
168 | or die "failed to create directory '$PostsDirectory': $!\n"; | |||||||||||||
169 | } | |||||||||||||
170 | ||||||||||||||
171 | $self->map_objects_of_type( | |||||||||||||
172 | 'post', sub { | |||||||||||||
173 | 0 | 0 | my ($post) = @_; | |||||||||||
174 | ||||||||||||||
175 | # add navigation to post | |||||||||||||
176 | 0 | $post->{'nav'} = | ||||||||||||
177 | $self->render_category_navigation( | |||||||||||||
178 | $MainCategory, $post->{'category'}); | |||||||||||||
179 | 0 | $post->{'breadcrumb'} = $self->render_breadcrumb($MainCategory, $post->{'category'}, $post); | ||||||||||||
180 | ||||||||||||||
181 | 0 | $post->{'path'} = '../'; | ||||||||||||
182 | ||||||||||||||
183 | 0 | my $outfile = $PostsDirectory.'/'.to_filename($post->{'title'}).'.html'; | ||||||||||||
184 | 0 | print "writing $outfile\n"; | ||||||||||||
185 | 0 | write_file($outfile, $self->fill_template($post->{'template'}, $post)); | ||||||||||||
186 | 0 | }); | ||||||||||||
187 | ||||||||||||||
188 | #------------------------------------------------------------------------------- | |||||||||||||
189 | # build category pages | |||||||||||||
190 | ||||||||||||||
191 | 0 | 0 | unless (-d $CategoriesDirectory) { | |||||||||||
192 | 0 | 0 | mkdir($CategoriesDirectory) | |||||||||||
193 | or die "failed to create directory '$CategoriesDirectory': $!\n"; | |||||||||||||
194 | } | |||||||||||||
195 | ||||||||||||||
196 | $self->map_objects_of_type( | |||||||||||||
197 | 'category', sub { | |||||||||||||
198 | 0 | 0 | my ($cat) = @_; | |||||||||||
199 | ||||||||||||||
200 | # find posts of that category | |||||||||||||
201 | 0 | my @posts; | ||||||||||||
202 | $self->map_objects_of_type( | |||||||||||||
203 | 'post', sub { | |||||||||||||
204 | 0 | my ($post) = @_; | ||||||||||||
205 | 0 | 0 | 0 | push @posts, $post | ||||||||||
206 | if $post->{'category'}->{'_id_'} eq $cat->{'_id_'} || | |||||||||||||
207 | $self->is_in_category($cat, $post->{'category'}); | |||||||||||||
208 | 0 | }, 'date'); | ||||||||||||
209 | ||||||||||||||
210 | 0 | my $albums = $self->render_albums_in_category($cat); | ||||||||||||
211 | ||||||||||||||
212 | 0 | $cat->{'nav'} = $self->render_category_navigation($MainCategory, $cat); | ||||||||||||
213 | 0 | $cat->{'breadcrumb'} = $self->render_breadcrumb($MainCategory, $cat); | ||||||||||||
214 | 0 | $cat->{'path'} = '../'; | ||||||||||||
215 | 0 | $cat->{'content'} = | ||||||||||||
216 | ''.$cat->{'title'}.''. |
|||||||||||||
217 | # links to all posts in that category | |||||||||||||
218 | (scalar @posts ? | |||||||||||||
219 | '
|
|||||||||||||
220 | join('', map { | |||||||||||||
221 | 0 | 0 | $_->{'url'} = '../posts/'.to_filename($_->{'title'}).'.html'; | |||||||||||
0 | ||||||||||||||
222 | 0 | ' |
||||||||||||
223 | } @posts). | |||||||||||||
224 | '' | |||||||||||||
225 | : ' Nothing in this category, yet.'). |
|||||||||||||
226 | # photo albums | |||||||||||||
227 | (length $albums ? | |||||||||||||
228 | 'Photo albums'. |
|||||||||||||
229 | $albums | |||||||||||||
230 | : ''); | |||||||||||||
231 | ||||||||||||||
232 | 0 | my $outfile = $CategoriesDirectory.'/'.to_filename($cat->{'title'}).'.html'; | ||||||||||||
233 | 0 | print "writing $outfile\n"; | ||||||||||||
234 | 0 | write_file($outfile, $self->fill_template($CategoryPageTemplate, $cat)); | ||||||||||||
235 | 0 | }); | ||||||||||||
236 | ||||||||||||||
237 | 0 | return 1; | ||||||||||||
238 | } | |||||||||||||
239 | ||||||||||||||
240 | #------------------------------------------------------------------------------- | |||||||||||||
241 | sub has_unresolved_references | |||||||||||||
242 | { | |||||||||||||
243 | 0 | 0 | 0 | my ($self) = @_; | ||||||||||
244 | 0 | foreach my $id (keys %{$self->{'Objects'}}) { | ||||||||||||
0 | ||||||||||||||
245 | 0 | foreach my $key (keys %{$self->{'Objects'}->{$id}}) { | ||||||||||||
0 | ||||||||||||||
246 | 0 | my $value = $self->{'Objects'}->{$id}->{$key}; | ||||||||||||
247 | 0 | 0 | 0 | return 1 | ||||||||||
248 | if ref $value eq 'HASH' && exists $value->{'_ref_'}; | |||||||||||||
249 | } | |||||||||||||
250 | } | |||||||||||||
251 | 0 | return 0; | ||||||||||||
252 | } | |||||||||||||
253 | ||||||||||||||
254 | #------------------------------------------------------------------------------- | |||||||||||||
255 | sub resolve_object_references | |||||||||||||
256 | { | |||||||||||||
257 | 0 | 0 | 0 | my ($self, $id) = @_; | ||||||||||
258 | #dmp($id); | |||||||||||||
259 | 0 | foreach my $key (keys %{$self->{'Objects'}->{$id}}) { | ||||||||||||
0 | ||||||||||||||
260 | #dmp(' - '.$key); | |||||||||||||
261 | 0 | my $value = $self->{'Objects'}->{$id}->{$key}; | ||||||||||||
262 | 0 | 0 | 0 | if (ref $value eq 'ARRAY') { | ||||||||||
0 | ||||||||||||||
263 | # list of objects | |||||||||||||
264 | 0 | foreach my $num (0..scalar(@{$value})-1) { | ||||||||||||
0 | ||||||||||||||
265 | 0 | 0 | 0 | if (ref $value->[$num] eq 'HASH' && exists $value->[$num]->{'_ref_'}) { | ||||||||||
266 | #dmp(' --- '.$num); | |||||||||||||
267 | #print "$id / $key / $num\n"; | |||||||||||||
268 | 0 | $self->_resolve_object_reference($id, $key, $num); | ||||||||||||
269 | } | |||||||||||||
270 | } | |||||||||||||
271 | } | |||||||||||||
272 | elsif (ref $value eq 'HASH' && exists $value->{'_ref_'}) { | |||||||||||||
273 | #print "$id / $key\n"; | |||||||||||||
274 | # reference to object | |||||||||||||
275 | 0 | $self->_resolve_object_reference($id, $key); | ||||||||||||
276 | } | |||||||||||||
277 | } | |||||||||||||
278 | ||||||||||||||
279 | sub _resolve_object_reference | |||||||||||||
280 | { | |||||||||||||
281 | 0 | 0 | my ($self, $id, $key, $num) = @_; | |||||||||||
282 | 0 | 0 | my $value = (defined $num ? $self->{'Objects'}->{$id}->{$key}->[$num] : $self->{'Objects'}->{$id}->{$key}); | |||||||||||
283 | #dmp($value); | |||||||||||||
284 | 0 | 0 | if (defined $num) { | |||||||||||
285 | 0 | 0 | die "could not find referenced object with id '".$value->{'_ref_'}."'.\n" | |||||||||||
286 | unless exists $self->{'Objects'}->{$value->{'_ref_'}}; | |||||||||||||
287 | 0 | $self->{'Objects'}->{$id}->{$key}->[$num] = $self->{'Objects'}->{$value->{'_ref_'}}; | ||||||||||||
288 | } else { | |||||||||||||
289 | 0 | 0 | die "could not find referenced object with id '".$value->{'_ref_'}."'.\n" | |||||||||||
290 | unless exists $self->{'Objects'}->{$value->{'_ref_'}}; | |||||||||||||
291 | 0 | $self->{'Objects'}->{$id}->{$key} = $self->{'Objects'}->{$value->{'_ref_'}}; | ||||||||||||
292 | } | |||||||||||||
293 | } | |||||||||||||
294 | } | |||||||||||||
295 | ||||||||||||||
296 | #------------------------------------------------------------------------------- | |||||||||||||
297 | sub render_albums_in_category | |||||||||||||
298 | { | |||||||||||||
299 | 0 | 0 | 0 | my ($self, $cat) = @_; | ||||||||||
300 | 0 | my $s = ''; | ||||||||||||
301 | $self->map_objects_of_type( | |||||||||||||
302 | 'album', sub { | |||||||||||||
303 | 0 | 0 | my ($album) = @_; | |||||||||||
304 | 0 | 0 | 0 | if ($album->{'category'}->{'_id_'} eq $cat->{'_id_'} || | ||||||||||
305 | $self->is_in_category($cat, $album->{'category'})) { | |||||||||||||
306 | ||||||||||||||
307 | 0 | $s .= ' |
||||||||||||
308 | } | |||||||||||||
309 | 0 | }, 'date'); | ||||||||||||
310 | 0 | 0 | return (length $s ? '
|
|||||||||||
311 | } | |||||||||||||
312 | ||||||||||||||
313 | #------------------------------------------------------------------------------- | |||||||||||||
314 | sub render_album | |||||||||||||
315 | { | |||||||||||||
316 | 0 | 0 | 0 | my ($self, $album) = @_; | ||||||||||
317 | 0 | my $s = ''; | ||||||||||||
318 | # find images in album | |||||||||||||
319 | 0 | my $first = 1; | ||||||||||||
320 | 0 | $album->{'firstimage'} = ''; | ||||||||||||
321 | 0 | $album->{'restimages'} = ''; | ||||||||||||
322 | 0 | foreach my $img (@{$album->{'images'}}) { | ||||||||||||
0 | ||||||||||||||
323 | 0 | $img->{'path'} = '../'; | ||||||||||||
324 | 0 | $img->{'albumname'} = '['.$album->{'title'}.']'; | ||||||||||||
325 | 0 | 0 | if ($first) { | |||||||||||
326 | 0 | $album->{'thumbnail'}->{'path'} = '../'; | ||||||||||||
327 | 0 | my $first = { | ||||||||||||
328 | 'path' => $img->{'path'}, | |||||||||||||
329 | 'file' => $img->{'file'}, | |||||||||||||
330 | 'albumname' => '['.$album->{'title'}.']', | |||||||||||||
331 | 'title' => $self->fill_template($self->{'Objects'}->{'tmpl-Image'}, $album->{'thumbnail'}), | |||||||||||||
332 | 'description' => $album->{'description'}, | |||||||||||||
333 | 'date' => $album->{'date'}, | |||||||||||||
334 | }; | |||||||||||||
335 | 0 | $album->{'firstimage'} = $self->fill_template($self->{'Objects'}->{'tmpl-AlbumImage'}, $first); | ||||||||||||
336 | } else { | |||||||||||||
337 | 0 | $album->{'restimages'} .= $self->fill_template($self->{'Objects'}->{'tmpl-AlbumImageNoName'}, $img); | ||||||||||||
338 | } | |||||||||||||
339 | 0 | $first = 0; | ||||||||||||
340 | } | |||||||||||||
341 | 0 | $s .= $self->fill_template($self->{'Objects'}->{'tmpl-Album'}, $album); | ||||||||||||
342 | 0 | return $s; | ||||||||||||
343 | } | |||||||||||||
344 | ||||||||||||||
345 | #------------------------------------------------------------------------------- | |||||||||||||
346 | sub map_objects_of_type | |||||||||||||
347 | { | |||||||||||||
348 | 0 | 0 | 0 | my ($self, $type, $function, $order_by) = @_; | ||||||||||
349 | 0 | foreach my $id | ||||||||||||
0 | ||||||||||||||
350 | (reverse | |||||||||||||
351 | 0 | 0 | 0 | map { $_->{'_id_'} } | ||||||||||
352 | 0 | sort { (defined $order_by && defined $a->{$order_by} && defined $b->{$order_by} ? | ||||||||||||
353 | ($a->{$order_by} cmp $b->{$order_by}) : 0) } | |||||||||||||
354 | values %{$self->{'Objects'}}) { | |||||||||||||
355 | ||||||||||||||
356 | 0 | my $object = $self->{'Objects'}->{$id}; | ||||||||||||
357 | 0 | 0 | if ($object->{'_type_'} eq $type) { | |||||||||||
358 | 0 | $function->($object); | ||||||||||||
359 | } | |||||||||||||
360 | } | |||||||||||||
361 | } | |||||||||||||
362 | ||||||||||||||
363 | #------------------------------------------------------------------------------- | |||||||||||||
364 | sub render_breadcrumb | |||||||||||||
365 | { | |||||||||||||
366 | 0 | 0 | 0 | my ($self, $top_category, $current_category, $post) = @_; | ||||||||||
367 | ||||||||||||||
368 | 0 | my ($crumbs, $last_link) = $self->_render_breadcrumb($top_category, $current_category); | ||||||||||||
369 | 0 | my $home_link = '../posts/'.to_filename($self->{'Objects'}->{'Home'}->{'title'}).'.html'; | ||||||||||||
370 | 0 | 0 | my $post_link = (defined $post ? '../posts/'.to_filename($post->{'title'}).'.html' : ''); | |||||||||||
371 | 0 | 0 | 0 | my $s = | ||||||||||
0 | ||||||||||||||
372 | '
|
|||||||||||||
373 | ' |
|||||||||||||
374 | ($home_link ne $last_link ? | |||||||||||||
375 | ' |
|||||||||||||
376 | $self->{'Objects'}->{'Home'}->{'title'}. | |||||||||||||
377 | '' : ''). | |||||||||||||
378 | $crumbs. | |||||||||||||
379 | (defined $post && $post_link ne $last_link ? | |||||||||||||
380 | ' |
|||||||||||||
381 | $post->{'title'}. | |||||||||||||
382 | '' : ''). | |||||||||||||
383 | ''; | |||||||||||||
384 | ||||||||||||||
385 | sub _render_breadcrumb | |||||||||||||
386 | { | |||||||||||||
387 | 0 | 0 | my ($self, $top_category, $current_category) = @_; | |||||||||||
388 | ||||||||||||||
389 | 0 | my $s = ''; | ||||||||||||
390 | 0 | my $last_link = ''; | ||||||||||||
391 | 0 | 0 | if (exists $top_category->{'subcategories'}) { | |||||||||||
392 | 0 | my @subs = @{$top_category->{'subcategories'}}; | ||||||||||||
0 | ||||||||||||||
393 | 0 | foreach my $item (@subs) { | ||||||||||||
394 | 0 | 0 | 0 | if ($self->is_in_category($item, $current_category) || | ||||||||||
395 | $item->{'_id_'} eq $current_category->{'_id_'}) { | |||||||||||||
396 | ||||||||||||||
397 | 0 | 0 | $last_link = | |||||||||||
398 | (exists $item->{'targetpost'} ? | |||||||||||||
399 | '../posts/'.to_filename($item->{'targetpost'}->{'title'}): | |||||||||||||
400 | '../categories/'.to_filename($item->{'title'})).'.html'; | |||||||||||||
401 | 0 | $s .= | ||||||||||||
402 | ' |
|||||||||||||
403 | ''. | |||||||||||||
404 | $item->{'title'}. | |||||||||||||
405 | ' '. | |||||||||||||
406 | ''; | |||||||||||||
407 | } | |||||||||||||
408 | } | |||||||||||||
409 | } | |||||||||||||
410 | 0 | return ($s, $last_link); | ||||||||||||
411 | } | |||||||||||||
412 | } | |||||||||||||
413 | ||||||||||||||
414 | #------------------------------------------------------------------------------- | |||||||||||||
415 | sub render_category_navigation | |||||||||||||
416 | { | |||||||||||||
417 | 0 | 0 | 0 | my ($self, $top_category, $current_category) = @_; | ||||||||||
418 | #dmp($top_category); | |||||||||||||
419 | 0 | my $s = ''; | ||||||||||||
420 | 0 | 0 | if (exists $top_category->{'subcategories'}) { | |||||||||||
421 | 0 | my @subs = @{$top_category->{'subcategories'}}; | ||||||||||||
0 | ||||||||||||||
422 | 0 | 0 | $s = (scalar @subs ? '
|
|||||||||||
423 | 0 | foreach my $item (@subs) { | ||||||||||||
424 | #dmp($item); | |||||||||||||
425 | 0 | 0 | my $current = | |||||||||||
426 | $self->is_in_category($item, $current_category) || | |||||||||||||
427 | $item->{'_id_'} eq $current_category->{'_id_'}; | |||||||||||||
428 | #print $item->{'_id_'}." ($current)\n"; | |||||||||||||
429 | 0 | 0 | $s .= | |||||||||||
0 | ||||||||||||||
430 | ' |
|||||||||||||
431 | ' 432 | (exists $item->{'targetpost'} ? | ||||||||||||
433 | '../posts/'.to_filename($item->{'targetpost'}->{'title'}): | |||||||||||||
434 | '../categories/'.to_filename($item->{'title'})). | |||||||||||||
435 | '.html">'. | |||||||||||||
436 | $item->{'title'}. | |||||||||||||
437 | ' '. | |||||||||||||
438 | $self->render_category_navigation($self->{'Objects'}->{$item->{'_id_'}}, $current_category). | |||||||||||||
439 | ''; | |||||||||||||
440 | } | |||||||||||||
441 | 0 | 0 | $s .= (scalar @subs ? '' : ''); | |||||||||||
442 | } | |||||||||||||
443 | #dmp($s); | |||||||||||||
444 | 0 | return $s; | ||||||||||||
445 | } | |||||||||||||
446 | ||||||||||||||
447 | #------------------------------------------------------------------------------- | |||||||||||||
448 | sub is_in_category | |||||||||||||
449 | { | |||||||||||||
450 | 0 | 0 | 0 | my ($self, $cat, $current_cat) = @_; | ||||||||||
451 | 0 | 0 | if (exists $cat->{'subcategories'}) { | |||||||||||
452 | # check subcats | |||||||||||||
453 | 0 | return scalar(grep { $self->is_in_category($_, $current_cat) } @{$cat->{'subcategories'}}); | ||||||||||||
0 | ||||||||||||||
0 | ||||||||||||||
454 | } | |||||||||||||
455 | else { | |||||||||||||
456 | 0 | 0 | if ($cat->{'_id_'} eq $current_cat->{'_id_'}) { | |||||||||||
457 | 0 | return 1; | ||||||||||||
458 | } else { | |||||||||||||
459 | 0 | return 0; | ||||||||||||
460 | } | |||||||||||||
461 | } | |||||||||||||
462 | } | |||||||||||||
463 | ||||||||||||||
464 | #------------------------------------------------------------------------------- | |||||||||||||
465 | sub to_filename | |||||||||||||
466 | { | |||||||||||||
467 | 0 | 0 | 0 | my ($s) = @_; | ||||||||||
468 | 0 | $s =~ s/[\n\r]/ /g; | ||||||||||||
469 | 0 | $s =~ s/[\s\t]+/ /g; | ||||||||||||
470 | 0 | $s =~ s/\s/-/g; | ||||||||||||
471 | 0 | $s =~ s/[^a-zA-Z0-9\-\.\_]//g; | ||||||||||||
472 | 0 | return $s; | ||||||||||||
473 | } | |||||||||||||
474 | ||||||||||||||
475 | #------------------------------------------------------------------------------- | |||||||||||||
476 | sub dmp | |||||||||||||
477 | { | |||||||||||||
478 | 0 | 0 | 0 | print Dumper(@_); | ||||||||||
479 | } | |||||||||||||
480 | ||||||||||||||
481 | sub render_sound | |||||||||||||
482 | { | |||||||||||||
483 | 0 | 0 | 0 | my ($self, $sound) = @_; | ||||||||||
484 | return | |||||||||||||
485 | 0 | 0 | ' '. |
|||||||||||
486 | ' | |||||||||||||
487 | 'codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0" '. | |||||||||||||
488 | 'width="165" height="38" id="niftyPlayer1" align="">'. | |||||||||||||
489 | ''. | |||||||||||||
490 | ''. | |||||||||||||
491 | ''. | |||||||||||||
492 | ' | |||||||||||||
493 | 'quality=high bgcolor=#FFFFFF width="165" height="38" '. | |||||||||||||
494 | 'name="niftyPlayer1" align="" type="application/x-shockwave-flash" '. | |||||||||||||
495 | 'pluginspage="http://www.macromedia.com/go/getflashplayer">'. | |||||||||||||
496 | ''. | |||||||||||||
497 | ''. | |||||||||||||
498 | ' |
|||||||||||||
499 | (length $sound->{'artist'} ? ''.$sound->{'artist'}.'' : 'unknown').''. | |||||||||||||
500 | ''; | |||||||||||||
501 | } | |||||||||||||
502 | ||||||||||||||
503 | #------------------------------------------------------------------------------- | |||||||||||||
504 | sub fill_template | |||||||||||||
505 | { | |||||||||||||
506 | 0 | 0 | 0 | my ($self, $tmpl_object, $data_object) = @_; | ||||||||||
507 | 0 | my $s = $tmpl_object->{'content'}; | ||||||||||||
508 | ||||||||||||||
509 | 0 | foreach my $key (keys %{$data_object}) { | ||||||||||||
0 | ||||||||||||||
510 | 0 | my $value = $data_object->{$key}; | ||||||||||||
511 | 0 | 0 | if (!ref $value) { | |||||||||||
512 | 0 | my $k = quotemeta $key; | ||||||||||||
513 | 0 | $s =~ s/\[$k\]/$value/g; | ||||||||||||
514 | } | |||||||||||||
515 | } | |||||||||||||
516 | ||||||||||||||
517 | # replace embedded objects | |||||||||||||
518 | 0 | while ($s =~ /\[\#([a-zA-Z0-9\.\-\_]+)\]/) { | ||||||||||||
519 | 0 | my $id = $1; | ||||||||||||
520 | 0 | 0 | if (exists $self->{'Objects'}->{$id}) { | |||||||||||
521 | 0 | my $object = $self->{'Objects'}->{$id}; | ||||||||||||
522 | 0 | my $value = ''; | ||||||||||||
523 | 0 | 0 | if ($object->{'_type_'} eq 'album') { | |||||||||||
0 | ||||||||||||||
0 | ||||||||||||||
0 | ||||||||||||||
0 | ||||||||||||||
524 | 0 | $value = $self->render_album($object); | ||||||||||||
525 | } | |||||||||||||
526 | elsif ($object->{'_type_'} eq 'category') { | |||||||||||||
527 | 0 | $value = ''.$object->{'title'}.''; | ||||||||||||
528 | } | |||||||||||||
529 | elsif ($object->{'_type_'} eq 'post') { | |||||||||||||
530 | 0 | $value = ''.$object->{'title'}.''; | ||||||||||||
531 | } | |||||||||||||
532 | elsif ($object->{'_type_'} eq 'image') { | |||||||||||||
533 | 0 | $value = $self->fill_template($self->{'Objects'}->{'tmpl-Image'}, $object); | ||||||||||||
534 | } | |||||||||||||
535 | elsif ($object->{'_type_'} eq 'sound') { | |||||||||||||
536 | 0 | $value = $self->render_sound($object); | ||||||||||||
537 | } | |||||||||||||
538 | 0 | $s =~ s/\[\#$id\]/$value/g; | ||||||||||||
539 | } | |||||||||||||
540 | } | |||||||||||||
541 | ||||||||||||||
542 | # replace empty undefined placeholders with empty string | |||||||||||||
543 | 0 | $s =~ s/\[\#?[a-zA-Z0-9\.\-\_]+\]//g; | ||||||||||||
544 | 0 | return $s; | ||||||||||||
545 | } | |||||||||||||
546 | ||||||||||||||
547 | #------------------------------------------------------------------------------- | |||||||||||||
548 | sub create_object | |||||||||||||
549 | { | |||||||||||||
550 | 0 | 0 | 0 | my ($self, $astobj, $objects) = @_; | ||||||||||
551 | 0 | 0 | if (ref $astobj->[0] eq 'ARRAY') { | |||||||||||
552 | # list of objects | |||||||||||||
553 | 0 | return [ map { $self->create_object($_, $objects) } @{$astobj} ]; | ||||||||||||
0 | ||||||||||||||
0 | ||||||||||||||
554 | } | |||||||||||||
555 | else { | |||||||||||||
556 | # single object | |||||||||||||
557 | 0 | my ($asttype, @parts) = @{$astobj}; | ||||||||||||
0 | ||||||||||||||
558 | ||||||||||||||
559 | 0 | 0 | if ($asttype eq 'object') { | |||||||||||
0 | ||||||||||||||
0 | ||||||||||||||
560 | 0 | my ($objtype, $id, $hash) = @parts; | ||||||||||||
561 | 0 | foreach my $key (keys %{$hash}) { | ||||||||||||
0 | ||||||||||||||
562 | 0 | $hash->{$key} = $self->create_object($hash->{$key}, $objects); | ||||||||||||
563 | } | |||||||||||||
564 | 0 | 0 | die "cannot redefine object with id '$id'.\n" | |||||||||||
565 | if exists $objects->{$id}; | |||||||||||||
566 | 0 | $hash->{'_type_'} = $objtype; | ||||||||||||
567 | 0 | $hash->{'_id_'} = $id; | ||||||||||||
568 | 0 | $objects->{$id} = $hash; | ||||||||||||
569 | 0 | return $objects->{$id}; | ||||||||||||
570 | } | |||||||||||||
571 | elsif ($asttype eq 'string') { | |||||||||||||
572 | 0 | return $astobj->[1]; | ||||||||||||
573 | } | |||||||||||||
574 | elsif ($asttype eq 'ref') { | |||||||||||||
575 | 0 | return {'_ref_' => $astobj->[1]}; | ||||||||||||
576 | } | |||||||||||||
577 | } | |||||||||||||
578 | } | |||||||||||||
579 | ||||||||||||||
580 | #------------------------------------------------------------------------------- | |||||||||||||
581 | sub read_file | |||||||||||||
582 | { | |||||||||||||
583 | 0 | 0 | 0 | my ($filename) = @_; | ||||||||||
584 | 0 | 0 | open(FILE, "<$filename") || die "failed to read file '$filename': $!\n"; | |||||||||||
585 | 0 | my $content = join '', |
||||||||||||
586 | 0 | close FILE; | ||||||||||||
587 | 0 | return $content; | ||||||||||||
588 | } | |||||||||||||
589 | ||||||||||||||
590 | #------------------------------------------------------------------------------- | |||||||||||||
591 | sub write_file | |||||||||||||
592 | { | |||||||||||||
593 | 0 | 0 | 0 | my ($filename, $string) = @_; | ||||||||||
594 | 0 | 0 | open(FILE, ">$filename") || die "failed to write to file '$filename': $!\n"; | |||||||||||
595 | 0 | print FILE $string; | ||||||||||||
596 | 0 | close FILE; | ||||||||||||
597 | } | |||||||||||||
598 | ||||||||||||||
599 | 1; | |||||||||||||
600 | __END__ |