a05c5e97b4a98512dc98d9068df08e762a926c5d
[scpubgit/App-SCS.git] / lib / App / SCS / Page.pm
1 package App::SCS::Page;
2
3 use IO::All;
4 use Time::Local qw(timelocal);
5 use Data::Pond qw(pond_read_datum pond_write_datum);
6 use List::Util qw(reduce);
7 use Module::Runtime qw(use_module);
8 use Moo;
9
10 with 'App::SCS::Role::PageChildren';
11
12 has $_ => (is => 'ro') for qw(
13   title subtitle description keywords plugins html created path
14 );
15
16 has plugin_config => (is => 'lazy');
17
18 sub _build_plugin_config {
19   my ($self) = @_;
20   $self->plugins
21     ? pond_read_datum('[ '.$self->plugins.' ]')
22     : []
23 }
24
25 sub has_plugin_config { exists $_[0]->plugin_config->{$_[1]} }
26
27 sub with_plugin_config {
28   my ($self, $with_name, $with_config) = @_;
29   my @orig = @{$self->plugin_config};
30   my @new;
31   while (my ($name, $config) = splice @orig, 0, 2) {
32     push @new, (
33       $name eq $with_name
34         ? ($name, { %$config, %$with_config })
35         : ($name, $config)
36     );
37   }
38   return $self->with(plugins => pond_write_datum(\@new));
39 }
40
41 has _page_plugins => (is => 'lazy');
42
43 sub _build__page_plugins {
44   my ($self) = @_;
45   my $plugin_config = $self->plugin_config;
46   my ($plugin_map, $defaults) = @{$self->_page_set->plugin_config}
47                                  {qw(plugin_map defaults)};
48   my @spec = (@$defaults, @$plugin_config);
49   my @plugins;
50   while (my ($name, $config) = splice @spec, 0, 2) {
51     my $info = $plugin_map->{$name};
52     push @plugins,
53       use_module($info->{class})->new(
54         ($info->{config}||sub{})->(), %$config, page => $self
55       );
56   }
57   return \@plugins;
58 }
59
60 sub published_at {
61   $_[0]->created
62     ? scalar localtime timelocal
63         map +(@{$_}[0..3], $_->[4]-1, $_->[5]-1900),
64           [ reverse split '\D+', $_[0]->created ]
65     : ''
66 }
67
68 has "_$_" => (is => 'ro', init_arg => $_) for qw(page_set);
69
70 sub _page_set_class { ref($_[0]->_page_set) }
71 sub _top_dir { $_[0]->_page_set->top_dir }
72 sub _my_path { io->dir($_[0]->_top_dir)->catdir($_[0]->path) }
73
74 sub to_app {
75   my ($self) = @_;
76   return sub { $self->to_psgi_response(@_) };
77 }
78
79 sub to_psgi_response {
80   my ($self, $env) = @_;
81
82   if (my $cb = $env->{'App::SCS::Command::Generate.extra_pages'}) {
83     $cb->($_->extra_pages) for @{$self->page_plugins};
84   }
85
86   $self->_psgi_response;
87 }
88
89 has _psgi_response => (is => 'lazy');
90
91 sub _build__psgi_response {
92   my ($self) = @_;
93
94   my $psgi_res = [
95     200, [ 'Content-type' => 'text/html' ], $self->_content_zoom->to_fh
96   ];
97
98   return reduce {
99     $b->filter_psgi_response($a)
100   } $psgi_res, @{$self->_page_plugins};
101 }
102
103 sub _content_zoom {
104   my ($self) = @_;
105   return reduce {
106     $b->filter_content_zoom($a)
107   } $self->_html_zoom, @{$self->_page_plugins};
108 }
109
110 sub _html_zoom {
111   my ($self) = @_;
112   return reduce {
113     $b->filter_html_zoom($a)
114   } HTML::Zoom->from_html($self->html), @{$self->_page_plugins};
115 }
116
117 no Moo;
118
119 sub with {
120   my $self = shift;
121   return ref($self)->new(%$self, @_);
122 }
123
124 1;