Back to documentation
package Statocles::Page::Document;
our $VERSION = '0.094';
# ABSTRACT: Render document objects into HTML
use Statocles::Base 'Class';
with 'Statocles::Page';
use Statocles::Template;
use Statocles::Store;
=attr document
The L<document|Statocles::Document> this page will render.
=cut
has document => (
is => 'ro',
isa => InstanceOf['Statocles::Document'],
required => 1,
);
=attr title
The title of the page.
=cut
has '+title' => (
lazy => 1,
default => sub { $_[0]->document->title || '' },
);
=attr author
The author of the page.
=cut
around _build_author => sub {
my ( $orig, $self ) = @_;
return $self->document->author || $self->$orig;
};
=attr date
Get the date of this page by checking the document.
=cut
has '+date' => (
lazy => 1,
default => sub {
my ( $self ) = @_;
$self->document->date || DateTime::Moonpig->now( time_zone => 'local' );
},
);
=attr 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
=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( @_ );
}
=attr data
The C<data> hash for this page. Defaults to the C<data> attribute from the Document.
=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 {};
},
);
=attr 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>).
=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;
}
=method 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.
=cut
sub content {
my ( $self, %vars ) = @_;
my $content = $self->document->content;
my $rendered = $self->_render_content_template( $content, \%vars );
return $self->markdown->markdown( $rendered );
}
=method vars
my %vars = $page->vars;
Get the template variables for this page.
=cut
around vars => sub {
my ( $orig, $self ) = @_;
return (
$self->$orig,
doc => $self->document,
);
};
=method 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 ) %>
% }
=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 /\n---\n/,
$self->document->content;
$self->_rendered_sections( \@sections );
}
return @indexes ? @sections[ @indexes ] : @sections;
}
=method tags
my @tags = $page->tags;
Get the list of tags for this page.
=cut
sub tags {
my ( $self, $new_tags ) = @_;
if ( $new_tags ) {
return $self->_tags( $new_tags );
}
return @{ $self->_tags };
}
=method 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.
=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 );
};
=method 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.
=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 );
};
=attr 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.
=cut
has next => (
is => 'rw',
lazy => 1,
isa => PagePath|Undef,
coerce => PagePath->coercion,
default => sub { $_[0]->_page_path('next_page') },
);
=attr 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.
=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;
}
=attr next_page
The L<Statocles::Page::Document> instance of the next document if it is part of a list.
=attr prev_page
The L<Statocles::Page::Document> instance of the previous document if it is part of a list.
=cut
has [qw( next_page prev_page )] => (
is => 'rw',
isa => InstanceOf['Statocles::Page::Document'],
);
1;
__END__
=head1 DESCRIPTION
This page class takes a single L<document|Statocles::Document> and renders it as HTML.