has plugins => (is => 'ro', default => sub { [] });
+has root_dir => (is => 'lazy');
+
+sub _build_root_dir {
+ my ($self) = @_;
+ io->dir(io->dir($self->config->{root_dir})->absolute);
+}
+
+has share_dir => (is => 'lazy');
+
+sub _build_share_dir {
+ my ($self) = @_;
+ io->dir($self->config->{share_dir}||$self->root_dir->catdir('share'));
+}
+
+has page_plugin_config => (is => 'lazy');
+
+sub _build_page_plugin_config {
+ my ($self) = @_;
+ return {
+ plugin_map => {
+ do {
+ my %map = map $_->page_plugins, reverse @{$self->plugins};
+ ref($_) or $_ = { class => $_, config => sub {} } for values %map;
+ %map;
+ }
+ },
+ defaults => [
+ map $_->default_page_plugins, @{$self->plugins}
+ ],
+ };
+}
+
has pages => (is => 'lazy');
sub _build_pages {
my ($self) = @_;
return use_module('App::SCS::PageSet')->new(
- base_dir => io->dir($self->config->{share_dir})->catdir('pages'),
- plugin_config => {
- plugin_map => {
- map $_->page_plugins, reverse @{$self->plugins}
- },
- defaults => [
- map $_->default_page_plugins, @{$self->plugins}
- ],
- }
+ base_dir => $self->share_dir->catdir('pages'),
+ plugin_config => $self->page_plugin_config,
);
}
use Time::Local qw(timelocal);
use Data::Pond qw(pond_read_datum pond_write_datum);
use List::Util qw(reduce);
+use Module::Runtime qw(use_module);
use Moo;
with 'App::SCS::Role::PageChildren';
sub _build__page_plugins {
my ($self) = @_;
my $plugin_config = $self->plugin_config;
- my ($plugin_map, $defaults) = @{$self->_page_set}{qw(plugin_map defaults)};
-
+ my ($plugin_map, $defaults) = @{$self->_page_set->plugin_config}
+ {qw(plugin_map defaults)};
my @spec = (@$defaults, @$plugin_config);
my @plugins;
while (my ($name, $config) = splice @spec, 0, 2) {
my $info = $plugin_map->{$name};
push @plugins,
use_module($info->{class})->new(
- %{$info->{config}||{}}, %$config, page => $self
+ ($info->{config}||sub{})->(), %$config, page => $self
);
}
return \@plugins;
sub _build__psgi_response {
my ($self) = @_;
- my @plugins = @{$self->page_plugins};
-
- my $html_zoom = reduce {
- $b->filter_html_zoom($a)
- } HTML::Zoom->from_html($self->html), @plugins;
-
- my $content_zoom = reduce {
- $b->filter_content_zoom($a)
- } $html_zoom, @plugins;
-
my $psgi_res = [
- 200, [ 'Content-type' => 'text/html' ], $content_zoom->to_fh
+ 200, [ 'Content-type' => 'text/html' ], $self->_content_zoom->to_fh
];
return reduce {
$b->filter_psgi_response($a)
- } $psgi_res, @plugins;
+ } $psgi_res, @{$self->_page_plugins};
+}
+
+sub _content_zoom {
+ my ($self) = @_;
+ return reduce {
+ $b->filter_content_zoom($a)
+ } $self->_html_zoom, @{$self->_page_plugins};
+}
+
+sub _html_zoom {
+ my ($self) = @_;
+ return reduce {
+ $b->filter_html_zoom($a)
+ } HTML::Zoom->from_html($self->html), @{$self->_page_plugins};
}
no Moo;
use IO::All;
use Try::Tiny;
use List::Util qw(reduce);
+use Module::Runtime qw(use_module);
use JSON;
use Moo;
sub latest {
my ($self, $max) = @_;
- require SCSite::LatestPageSet;
- SCSite::LatestPageSet->new(
+ use_module('App::SCS::LatestPageSet')->new(
parent => $self,
max_entries => $max,
);
}
sub _new_page {
- SCSite::Page->new({ path => $_[1], page_set => $_[0], %{$_[2]} })
+ use_module('App::SCS::Page')->new(
+ path => $_[1], page_set => $_[0], %{$_[2]}
+ );
}
sub _types_re { qw/\.(html|md)/ }
package App::SCS::Plugin::Core;
+use Module::Runtime qw(use_module);
+use IO::All;
use Moo;
no warnings::illegalproto;
use Safe::Isa;
sub _build_templates {
my ($self) = @_;
return use_module('App::SCS::PageSet')->new(
- base_dir => io->dir($self->app->config->{share_dir})->catdir('templates'),
+ base_dir => io->dir($self->app->share_dir)->catdir('templates'),
+ plugin_config => {
+ plugin_map => $self->app->page_plugin_config->{plugin_map}
+ }
);
}
PageList => 'App::SCS::Plugin::Core::PagePlugin::PageList',
Template => {
class => 'App::SCS::Plugin::Core::PagePlugin::Template',
- config => { templates => $self->templates },
+ config => sub { templates => $self->templates },
},
Include => {
class => 'App::SCS::Plugin::Core::PagePlugin::Include',
- config => { includes => $self->includes },
+ config => sub { includes => $self->includes },
},
PageData => 'App::SCS::Plugin::Core::PagePlugin::PageData',
}
or die "No such template ${\$self->name}";
my $template_zoom = HTML::Zoom->from_html($template_page->html);
my @ev;
- $template_zoom->collect('*[data-replace]', { into => \@ev })
+ $template_zoom->select('*[data-replace]')
+ ->collect({ into => \@ev, passthrough => 1 })
->then
- ->${\sub {
+ ->replace(sub {
my $sel = $ev[0]->{attrs}{'data-replace'};
- $zoom->collect($self, { into => \my @replace })->run;
- shift->replace(\@replace);
- }}
+ $zoom->collect($sel, { into => \my @replace })->run;
+ HTML::Zoom::ArrayStream->new({ array => \@replace })
+ });
}
1;
sub extra_pages { () }
-sub filter_html_zoom { shift }
+sub filter_html_zoom { $_[1] }
-sub filter_content_zoom { shift }
+sub filter_content_zoom { $_[1] }
-sub filter_psgi_response { shift }
+sub filter_psgi_response { $_[1] }
1;
--- /dev/null
+use strictures 1;
+use Test::More;
+use App::SCS;
+use IO::All;
+
+my $app = App::SCS->new(
+ config => { root_dir => 't/data' }
+);
+
+my $simple1 = $app->pages->get({ path => 'simple/1' });
+
+ok($simple1, 'Got a page object');
+
+is(
+ $simple1->html,
+ io->file('t/data/share/pages/simple/1.html')->all,
+ "Correct file loaded"
+);
+
+my @page_plugins = @{$simple1->_page_plugins};
+
+is(scalar(@page_plugins), 2, 'Two plugins applied');
+
+my ($tp, $pdp) = @page_plugins;
+
+ok(
+ $tp->isa('App::SCS::Plugin::Core::PagePlugin::Template'),
+ 'Template plugin'
+);
+
+is($tp->name, 'layout', 'Template name');
+
+ok(
+ $pdp->isa('App::SCS::Plugin::Core::PagePlugin::PageData'),
+ 'PageData plugin'
+);
+
+like(
+ $simple1->_html_zoom->to_html,
+ qr{<div id="content">.*<h1>Hello world}s,
+ 'Layout woven correctly'
+);
+
+warn $simple1->_content_zoom->to_html;
+
+done_testing;
--- /dev/null
+{"keywords":"","created":"","subtitle":"","plugins":"","html":"<html>\n <head>\n <title>Simple 1</title>\n </head>\n <body>\n <h1>Hello world</h1>\n </body>\n</html>\n","title":"Simple 1","description":""}
\ No newline at end of file
--- /dev/null
+<html>
+ <head>
+ <title>Simple 1</title>
+ </head>
+ <body>
+ <h1>Hello world</h1>
+ </body>
+</html>
--- /dev/null
+{"keywords":"","created":"","subtitle":"","plugins":"","html":"<html data-wrap=\"html\">\n <head data-replace=\"head\" />\n <body>\n <div id=\"content\">\n <div data-replace=\"h1\" />\n </div>\n </body>\n</html>\n","title":"","description":""}
\ No newline at end of file
--- /dev/null
+<html data-wrap="html">
+ <head data-replace="head" />
+ <body>
+ <div id="content">
+ <div data-replace="h1" />
+ </div>
+ </body>
+</html>