| 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__ |