basic page rendering
[scpubgit/SCS.git] / lib / SCSite.pm
CommitLineData
5cc6d9e2 1package SCSite;
2
3use IO::All;
4use SCSite::PageSet;
5use Web::Simple;
6
7{
8 package SCSite::Link; use Moo; has $_ => (is => 'ro') for qw(title to);
9}
10
11has _topbar => (is => 'ro', default => sub { [
12 map SCSite::Link->new(title => $_->[0], to => $_->[1] ),
13 map [ /^(.*?)\s+(\S+)$/ ],
14 split("\n", <<'ENDBAR')
15Home /
16About /about
17News /news
18Catalyst /catalyst
19Servers /servers
20Professional Services /services
21Blogs /blog
22ENDBAR
23 ] }
24);
25
26has pages => (is => 'lazy');
27
28has _layout_zoom => (is => 'lazy');
29
30sub default_config {
31 (
32 pages_dir => 'share/content',
33 template_dir => 'share/skin',
34 )
35}
36
37sub _build_pages {
38 my ($self) = @_;
39 SCSite::PageSet->new(base_dir => $self->config->{pages_dir})
40}
41
42sub dispatch_request {
43 my $self = shift;
44 sub (/feed/**/) {
45 $self->_http_response(500 => 'text/plain' => 'Not implemented');
46 },
47 sub (/) {
48 $self->_page_http_response(200 => $self->_find_page('index'));
49 },
50 sub (/**) {
51 [ 302, [ 'Location' => "/$_[1]/" ], [] ]
52 },
53 sub (/**/) {
54 my ($code, $page) = map {
55 $_ ? (200, $_) : (404, $self->_error_page(404))
56 } $self->_find_page($_[1]);
57 $self->_page_http_response($code => $page);
58 }
59}
60
61sub _error_page {
62 my ($self, $code) = @_;
63 $self->_find_page("error_${code}");
64}
65
66sub _find_page {
67 my ($self, $path) = @_;
68 $self->pages->get({ path => $path });
69}
70
71sub _http_response {
72 my ($self, $code, $type, $content) = @_;
73 [ $code, [ 'Content-type' => $type ], [ $content ] ];
74}
75
76sub _page_http_response {
77 my ($self, $code, $page) = @_;
78 [ $code, [ 'Content-type' => 'text/html' ], $self->_render_page($page) ];
79}
80
81sub _render_page {
82 my ($self, $page) = @_;
83 my $zoom = $self->_layout_zoom;
84 $zoom->select('.title')->replace_content($page->title)
85 ->select('meta[name=description]')->replace_content($page->description)
86 ->select('meta[name=keywords]')->replace_content($page->keywords)
87 ->select('.topbar_entries')->repeat_content([
88 map { my $e = $_; sub {
89 $_->select('.entry')->replace_content($e->title)
90 ->then->set_attribute(href => $e->to)
91 } } @{$self->_topbar}
92 ])
93 ->select('.main')->replace_content(\$page->body)
94 ->to_fh
95}
96
97sub _build__layout_zoom {
98 my ($self) = @_;
99 HTML::Zoom->from_file(
100 io->dir($self->config->{template_dir})->catfile('layout.html')
101 )->memoize;
102}
103
104sub run_if_script {
105 return $_[0]->to_psgi_app if caller(1);
106 my $class = shift;
107 my @config_keys = keys %{{$class->default_config}};
108 require Getopt::Long;
109 my %config;
110 Getopt::Long::GetOptions(
111 map +("$_=s" => \$config{$_}), @config_keys
112 );
113 delete $config{$_} for grep !defined($config{$_}), keys %config;
114 my $new = $class->new(config => \%config);
115 $new->run(@_)
116}
117
118__PACKAGE__->run_if_script;