package Statocles::Page::Document;
our $VERSION = '0.098';
# ABSTRACT: Render document objects into HTML
use Statocles::Base 'Class';
with 'Statocles::Page';
use Statocles::Template;
use Statocles::Store;
#pod =attr document
#pod
#pod The L<document|Statocles::Document> this page will render.
#pod
#pod =cut
has document => (
is => 'ro',
isa => InstanceOf['Statocles::Document'],
required => 1,
);
#pod =attr title
#pod
#pod The title of the page.
#pod
#pod =cut
has '+title' => (
lazy => 1,
default => sub { $_[0]->document->title || '' },
);
#pod =attr author
#pod
#pod The author of the page.
#pod
#pod =cut
around _build_author => sub {
my ( $orig, $self ) = @_;
return $self->document->author || $self->$orig;
};
#pod =attr date
#pod
#pod Get the date of this page by checking the document.
#pod
#pod =cut
has '+date' => (
lazy => 1,
default => sub {
my ( $self ) = @_;
$self->document->date || DateTime::Moonpig->now( time_zone => 'local' );
},
);
#pod =attr tags
#pod
#pod The tag links for this document. An array of L<link objects|Statocles::Link>. The
#pod most important attributes are:
#pod
#pod text - The text of the link
#pod href - The page of the link
#pod
#pod =cut
has _tags => (
is => 'rw',
isa => LinkArray,
default => sub { [] },
coerce => LinkArray->coercion,
init_arg => 'tags',
);
sub links {
shift->document->links( @_ );
}
sub images {
shift->document->images( @_ );
}
#pod =attr data
#pod
#pod The C<data> hash for this page. Defaults to the C<data> attribute from the Document.
#pod
#pod =cut
has '+data' => (
lazy => 1,
default => sub {
my ( $self ) = @_;
# Only allow hashref data attributes to come through.
# Non-hashref data attributes are deprecated and will be removed
# in v2.0. When that happens, remove this check as well
my $data = $self->document->data;
if ( $data && ref $data eq 'HASH' ) {
return $data;
}
return {};
},
);
#pod =attr disable_content_template
#pod
#pod If true, disables the processing of the content as a template. This will
#pod improve performance if you're not using any template directives in your content.
#pod
#pod This can be set in the document (L<Statocles::Document/disable_content_template>),
#pod the application (L<Statocles::App/disable_content_template>), or the site
#pod (L<Statocles::Site/disable_content_template>).
#pod
#pod =cut
has disable_content_template => (
is => 'ro',
isa => Str,
lazy => 1,
default => sub {
my ( $self ) = @_;
return $self->document && $self->document->has_disable_content_template ? $self->document->disable_content_template && "document"
: $self->app && $self->app->has_disable_content_template ? $self->app->disable_content_template && "application"
: $self->site && $self->site->has_disable_content_template ? $self->site->disable_content_template && "site"
: "";
},
);
sub _render_content_template {
my ( $self, $content, $vars ) = @_;
if ( my $by = $self->disable_content_template ) {
$self->site->log->debug( $self->path . ' content template processing disabled by ' . $by );
return $content;
}
$self->site->log->debug( $self->path . ' processing content template ' );
my $tmpl = $self->site->theme->build_template( $self->path, $content );
my $doc = $self->document;
if ( $doc->store ) {
my $document_path = $doc->store->path->child( $doc->path )->parent;
push @{ $tmpl->include_stores }, Statocles::Store->new( path => $document_path );
}
my $rendered = $tmpl->render( %$vars, $self->vars, self => $doc, page => $self );
return $rendered;
}
#pod =method content
#pod
#pod my $html = $page->content( %vars );
#pod
#pod Generate the document HTML by processing template directives and converting
#pod Markdown. C<vars> is a set of name-value pairs to give to the template.
#pod
#pod =cut
sub content {
my ( $self, %vars ) = @_;
my $content = $self->document->content;
my $rendered = $self->_render_content_template( $content, \%vars );
return $self->markdown->markdown( $rendered );
}
#pod =method vars
#pod
#pod my %vars = $page->vars;
#pod
#pod Get the template variables for this page.
#pod
#pod =cut
around vars => sub {
my ( $orig, $self ) = @_;
return (
$self->$orig,
doc => $self->document,
);
};
#pod =method sections
#pod
#pod my @sections = $page->sections;
#pod my $number_of_sections = $page->sections;
#pod my @first_sections = $page->sections( 0, 1 );
#pod
#pod Get a list of rendered HTML content divided into sections. The Markdown "---"
#pod marker divides sections. In scalar context, returns the number of sections.
#pod You can also pass the indexes of the sections you want as arguments.
#pod
#pod For example, to loop over sections in the template:
#pod
#pod % for my $i ( 0..$page->sections ) {
#pod <%= $page->sections( $i ) %>
#pod % }
#pod
#pod =cut
has _rendered_sections => (
is => 'rw',
isa => ArrayRef,
predicate => '_has_rendered_sections',
);
sub sections {
my ( $self, @indexes ) = @_;
my @sections;
if ( $self->_has_rendered_sections ) {
@sections = @{ $self->_rendered_sections };
}
else {
@sections =
map { $self->markdown->markdown( $_ ) }
map { $self->_render_content_template( $_, {} ) }
split /\R---\R/,
$self->document->content;
$self->_rendered_sections( \@sections );
}
return @indexes ? @sections[ @indexes ] : @sections;
}
#pod =method tags
#pod
#pod my @tags = $page->tags;
#pod
#pod Get the list of tags for this page.
#pod
#pod =cut
sub tags {
my ( $self, $new_tags ) = @_;
if ( $new_tags ) {
return $self->_tags( $new_tags );
}
return @{ $self->_tags };
}
#pod =method template
#pod
#pod my $tmpl = $page->template;
#pod
#pod The L<template object|Statocles::Template> for this page. If the document has a template,
#pod it will be used. Otherwise, the L<template attribute|Statocles::Page/template> will
#pod be used.
#pod
#pod =cut
around template => sub {
my ( $orig, $self, @args ) = @_;
if ( $self->document->has_template ) {
return $self->site->theme->template( @{ $self->document->template } );
}
return $self->$orig( @args );
};
#pod =method layout
#pod
#pod my $tmpl = $page->layout;
#pod
#pod The L<layout template object|Statocles::Template> for this page. If the document has a layout,
#pod it will be used. Otherwise, the L<layout attribute|Statocles::Page/layout> will
#pod be used.
#pod
#pod =cut
around layout => sub {
my ( $orig, $self, @args ) = @_;
if ( $self->document->has_layout ) {
return $self->site->theme->template( @{ $self->document->layout } );
}
return $self->$orig( @args );
};
#pod =attr next
#pod
#pod The path to the next document if it is part of a list.
#pod Defaults to the L<Statocles::Document/path> from L</next_page> if it exists.
#pod
#pod =cut
has next => (
is => 'rw',
lazy => 1,
isa => PagePath|Undef,
coerce => PagePath->coercion,
default => sub { $_[0]->_page_path('next_page') },
);
#pod =attr prev
#pod
#pod The path to the previous document if it is part of a list.
#pod Defaults to the L<Statocles::Document/path> from L</prev_page> if it exists.
#pod
#pod =cut
has prev => (
is => 'rw',
lazy => 1,
isa => PagePath|Undef,
coerce => PagePath->coercion,
default => sub { $_[0]->_page_path('prev_page') },
);
sub _page_path {
my ( $self, $method ) = @_;
if ( my $page = $self->$method() ) {
return $page->path;
}
return undef;
}
#pod =attr next_page
#pod
#pod The L<Statocles::Page::Document> instance of the next document if it is part of a list.
#pod
#pod =attr prev_page
#pod
#pod The L<Statocles::Page::Document> instance of the previous document if it is part of a list.
#pod
#pod =cut
has [qw( next_page prev_page )] => (
is => 'rw',
isa => InstanceOf['Statocles::Page::Document'],
);
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Statocles::Page::Document - Render document objects into HTML
=head1 VERSION
version 0.098
=head1 DESCRIPTION
This page class takes a single L<document|Statocles::Document> and renders it as HTML.
=head1 ATTRIBUTES
=head2 document
The L<document|Statocles::Document> this page will render.
=head2 title
The title of the page.
=head2 author
The author of the page.
=head2 date
Get the date of this page by checking the document.
=head2 tags
The tag links for this document. An array of L<link objects|Statocles::Link>. The
most important attributes are:
text - The text of the link
href - The page of the link
=head2 data
The C<data> hash for this page. Defaults to the C<data> attribute from the Document.
=head2 disable_content_template
If true, disables the processing of the content as a template. This will
improve performance if you're not using any template directives in your content.
This can be set in the document (L<Statocles::Document/disable_content_template>),
the application (L<Statocles::App/disable_content_template>), or the site
(L<Statocles::Site/disable_content_template>).
=head2 next
The path to the next document if it is part of a list.
Defaults to the L<Statocles::Document/path> from L</next_page> if it exists.
=head2 prev
The path to the previous document if it is part of a list.
Defaults to the L<Statocles::Document/path> from L</prev_page> if it exists.
=head2 next_page
The L<Statocles::Page::Document> instance of the next document if it is part of a list.
=head2 prev_page
The L<Statocles::Page::Document> instance of the previous document if it is part of a list.
=head1 METHODS
=head2 content
my $html = $page->content( %vars );
Generate the document HTML by processing template directives and converting
Markdown. C<vars> is a set of name-value pairs to give to the template.
=head2 vars
my %vars = $page->vars;
Get the template variables for this page.
=head2 sections
my @sections = $page->sections;
my $number_of_sections = $page->sections;
my @first_sections = $page->sections( 0, 1 );
Get a list of rendered HTML content divided into sections. The Markdown "---"
marker divides sections. In scalar context, returns the number of sections.
You can also pass the indexes of the sections you want as arguments.
For example, to loop over sections in the template:
% for my $i ( 0..$page->sections ) {
<%= $page->sections( $i ) %>
% }
=head2 tags
my @tags = $page->tags;
Get the list of tags for this page.
=head2 template
my $tmpl = $page->template;
The L<template object|Statocles::Template> for this page. If the document has a template,
it will be used. Otherwise, the L<template attribute|Statocles::Page/template> will
be used.
=head2 layout
my $tmpl = $page->layout;
The L<layout template object|Statocles::Template> for this page. If the document has a layout,
it will be used. Otherwise, the L<layout attribute|Statocles::Page/layout> will
be used.
=head1 AUTHOR
Doug Bell <preaction@cpan.org>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2016 by Doug Bell.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut