Commit | Line | Data |
5cc6d9e2 |
1 | package SCSite; |
2 | |
3 | use IO::All; |
4 | use SCSite::PageSet; |
5 | use Web::Simple; |
6 | |
7 | { |
8 | package SCSite::Link; use Moo; has $_ => (is => 'ro') for qw(title to); |
9 | } |
10 | |
11 | has _topbar => (is => 'ro', default => sub { [ |
12 | map SCSite::Link->new(title => $_->[0], to => $_->[1] ), |
13 | map [ /^(.*?)\s+(\S+)$/ ], |
14 | split("\n", <<'ENDBAR') |
15 | Home / |
16 | About /about |
17 | News /news |
18 | Catalyst /catalyst |
19 | Servers /servers |
20 | Professional Services /services |
21 | Blogs /blog |
22 | ENDBAR |
23 | ] } |
24 | ); |
25 | |
26 | has pages => (is => 'lazy'); |
27 | |
28 | has _layout_zoom => (is => 'lazy'); |
29 | |
30 | sub default_config { |
31 | ( |
32 | pages_dir => 'share/content', |
33 | template_dir => 'share/skin', |
34 | ) |
35 | } |
36 | |
37 | sub _build_pages { |
38 | my ($self) = @_; |
39 | SCSite::PageSet->new(base_dir => $self->config->{pages_dir}) |
40 | } |
41 | |
42 | sub 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 | |
61 | sub _error_page { |
62 | my ($self, $code) = @_; |
63 | $self->_find_page("error_${code}"); |
64 | } |
65 | |
66 | sub _find_page { |
67 | my ($self, $path) = @_; |
68 | $self->pages->get({ path => $path }); |
69 | } |
70 | |
71 | sub _http_response { |
72 | my ($self, $code, $type, $content) = @_; |
73 | [ $code, [ 'Content-type' => $type ], [ $content ] ]; |
74 | } |
75 | |
76 | sub _page_http_response { |
77 | my ($self, $code, $page) = @_; |
78 | [ $code, [ 'Content-type' => 'text/html' ], $self->_render_page($page) ]; |
79 | } |
80 | |
81 | sub _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 | |
97 | sub _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 | |
104 | sub 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; |