File Coverage

blib/lib/Statocles/Page/List.pm
Criterion Covered Total %
statement 45 45 100.0
branch 16 16 100.0
condition 10 11 90.9
subroutine 8 8 100.0
pod 2 2 100.0
total 81 82 98.7


line stmt bran cond sub pod time code
1             package Statocles::Page::List;
2             our $VERSION = '0.086';
3             # ABSTRACT: A page presenting a list of other pages
4              
5 25     25   1800 use Statocles::Base 'Class';
  25         60  
  25         217  
6             with 'Statocles::Page';
7 25     25   170484 use List::Util qw( reduce );
  25         65  
  25         1866  
8 25     25   623 use Statocles::Template;
  25         54  
  25         504  
9 25     25   11113 use Statocles::Page::ListItem;
  25         80  
  25         976  
10 25     25   261 use Statocles::Util qw( uniq_by );
  25         57  
  25         21502  
11              
12             #pod =attr pages
13             #pod
14             #pod The pages that should be shown in this list.
15             #pod
16             #pod =cut
17              
18             has _pages => (
19             is => 'ro',
20             isa => ArrayRef[ConsumerOf['Statocles::Page']],
21             init_arg => 'pages',
22             );
23              
24             sub pages {
25 1131     1131 1 7666 my ( $self ) = @_;
26              
27 1131         1863 my %rewrite;
28 1131 100 100     18344 if ( $self->type eq 'application/rss+xml' || $self->type eq 'application/atom+xml' ) {
29 388         8825 %rewrite = ( rewrite_mode => 'full' );
30             }
31              
32 1131         25925 my @pages;
33 1131         1828 for my $page ( @{ $self->_pages } ) {
  1131         3814  
34             # Always re-wrap the page, even if it's already wrapped,
35             # to change the rewrite_mode
36 1787 100       132644 push @pages, Statocles::Page::ListItem->new(
37             %rewrite,
38             page => $page->isa( 'Statocles::Page::ListItem' ) ? $page->page : $page,
39             );
40             }
41              
42 1131         116253 return \@pages;
43             }
44              
45             #pod =attr next
46             #pod
47             #pod The path to the next page in the pagination series.
48             #pod
49             #pod =attr prev
50             #pod
51             #pod The path to the previous page in the pagination series.
52             #pod
53             #pod =cut
54              
55             has [qw( next prev )] => (
56             is => 'rw',
57             isa => Path,
58             coerce => Path->coercion,
59             );
60              
61             #pod =attr date
62             #pod
63             #pod Get the date of this list. By default, this is the latest date of the first
64             #pod page in the list of pages.
65             #pod
66             #pod =cut
67              
68             has '+date' => (
69             lazy => 1,
70             default => sub {
71             my ( $self ) = @_;
72             my $date = reduce { $a->epoch gt $b->epoch ? $a : $b }
73             map { $_->date }
74             @{ $self->pages };
75             return $date;
76             },
77             );
78              
79             #pod =attr search_change_frequency
80             #pod
81             #pod Override the default L<search_change_frequency|Statocles::Page/search_change_frequency>
82             #pod to C<daily>, because these pages aggregate other pages.
83             #pod
84             #pod =cut
85              
86             has '+search_change_frequency' => (
87             default => sub { 'daily' },
88             );
89              
90             #pod =attr search_priority
91             #pod
92             #pod Override the default L<search_priority|Statocles::Page/search_priority> to reduce
93             #pod the rank of list pages to C<0.3>.
94             #pod
95             #pod It is more important for users to get to the full page than
96             #pod to get to this list page, which may contain truncated content, and whose relevant
97             #pod content may appear 3-4 items down the page.
98             #pod
99             #pod =cut
100              
101             has '+search_priority' => (
102             default => sub { 0.3 },
103             );
104              
105             #pod =method paginate
106             #pod
107             #pod my @pages = Statocles::Page::List->paginate( %args );
108             #pod
109             #pod Build a paginated list of L<Statocles::Page::List> objects.
110             #pod
111             #pod Takes a list of key-value pairs with the following keys:
112             #pod
113             #pod path - An sprintf format string to build the path, like '/page-%i.html'.
114             #pod Pages are indexed started at 1.
115             #pod index - The special, unique path for the first page. Optional.
116             #pod pages - The arrayref of Statocles::Page::Document objects to paginate.
117             #pod after - The number of items per page. Defaults to 5.
118             #pod
119             #pod Return a list of Statocles::Page::List objects in numerical order, the index
120             #pod page first (if any).
121             #pod
122             #pod =cut
123              
124             sub paginate {
125 246     246 1 136480 my ( $class, %args ) = @_;
126              
127             # Unpack the args so we can pass the rest to new()
128 246   50     860 my $after = delete $args{after} // 5;
129 246         504 my $pages = delete $args{pages};
130 246         447 my $path_format = delete $args{path};
131 246         443 my $index = delete $args{index};
132              
133             # The date is the max of all input pages, since input pages get moved between
134             # all the list pages
135 241 100   241   3203 my $date = reduce { $a->epoch gt $b->epoch ? $a : $b }
136 246         1321 map { $_->date }
  486         8111  
137             @$pages;
138              
139 246         2919 my @sets;
140 246         379 for my $i ( 0..$#{$pages} ) {
  246         766  
141 486         674 push @{ $sets[ int( $i / $after ) ] }, $pages->[ $i ];
  486         1485  
142             }
143              
144 246         398 my @retval;
145 246         511 for my $i ( 0..$#sets ) {
146 315 100 100     4638 my $path = $index && $i == 0 ? $index : sprintf( $path_format, $i + 1 );
147 315 100 100     2019 my $prev = $index && $i == 1 ? $index : sprintf( $path_format, $i );
148 315 100       920 my $next = $i != $#sets ? sprintf( $path_format, $i + 2 ) : '';
149              
150             # Remove index.html from link URLs
151 315         2166 s{/index[.]html$}{/} for ( $prev, $next );
152              
153 315 100       6225 push @retval, $class->new(
    100          
154             path => $path,
155             pages => $sets[$i],
156             ( $next ? ( next => $next ) : () ),
157             ( $i > 0 ? ( prev => $prev ) : () ),
158             date => $date,
159             %args,
160             );
161             }
162              
163 246         10807 return @retval;
164             }
165              
166             #pod =method vars
167             #pod
168             #pod my %vars = $page->vars;
169             #pod
170             #pod Get the template variables for this page.
171             #pod
172             #pod =cut
173              
174             around vars => sub {
175             my ( $orig, $self ) = @_;
176             return (
177             $self->$orig,
178             pages => $self->pages,
179             );
180             };
181              
182             #pod =method links
183             #pod
184             #pod my @links = $page->links( $key );
185             #pod
186             #pod Get the given set of links for this page. See L<the links
187             #pod attribute|Statocles::Page/links> for some commonly-used keys.
188             #pod
189             #pod For List pages, C<stylesheet> and C<script> links are also collected
190             #pod from the L<inner pages|/pages>, to ensure that content in those pages
191             #pod works correctly.
192             #pod
193             #pod =cut
194              
195             around links => sub {
196             my ( $orig, $self, @args ) = @_;
197              
198             if ( @args > 1 || $args[0] !~ /^(?:stylesheet|script)$/ ) {
199             return $self->$orig( @args );
200             }
201              
202             my @links;
203             for my $page ( @{ $self->pages } ) {
204             push @links, $page->links( @args );
205             }
206             push @links, $self->$orig( @args );
207             return uniq_by { $_->href } @links;
208             };
209              
210             1;
211              
212             __END__
213              
214             =pod
215              
216             =encoding UTF-8
217              
218             =head1 NAME
219              
220             Statocles::Page::List - A page presenting a list of other pages
221              
222             =head1 VERSION
223              
224             version 0.086
225              
226             =head1 DESCRIPTION
227              
228             A List page contains a set of other pages. These are frequently used for index
229             pages.
230              
231             =head1 ATTRIBUTES
232              
233             =head2 pages
234              
235             The pages that should be shown in this list.
236              
237             =head2 next
238              
239             The path to the next page in the pagination series.
240              
241             =head2 prev
242              
243             The path to the previous page in the pagination series.
244              
245             =head2 date
246              
247             Get the date of this list. By default, this is the latest date of the first
248             page in the list of pages.
249              
250             =head2 search_change_frequency
251              
252             Override the default L<search_change_frequency|Statocles::Page/search_change_frequency>
253             to C<daily>, because these pages aggregate other pages.
254              
255             =head2 search_priority
256              
257             Override the default L<search_priority|Statocles::Page/search_priority> to reduce
258             the rank of list pages to C<0.3>.
259              
260             It is more important for users to get to the full page than
261             to get to this list page, which may contain truncated content, and whose relevant
262             content may appear 3-4 items down the page.
263              
264             =head1 METHODS
265              
266             =head2 paginate
267              
268             my @pages = Statocles::Page::List->paginate( %args );
269              
270             Build a paginated list of L<Statocles::Page::List> objects.
271              
272             Takes a list of key-value pairs with the following keys:
273              
274             path - An sprintf format string to build the path, like '/page-%i.html'.
275             Pages are indexed started at 1.
276             index - The special, unique path for the first page. Optional.
277             pages - The arrayref of Statocles::Page::Document objects to paginate.
278             after - The number of items per page. Defaults to 5.
279              
280             Return a list of Statocles::Page::List objects in numerical order, the index
281             page first (if any).
282              
283             =head2 vars
284              
285             my %vars = $page->vars;
286              
287             Get the template variables for this page.
288              
289             =head2 links
290              
291             my @links = $page->links( $key );
292              
293             Get the given set of links for this page. See L<the links
294             attribute|Statocles::Page/links> for some commonly-used keys.
295              
296             For List pages, C<stylesheet> and C<script> links are also collected
297             from the L<inner pages|/pages>, to ensure that content in those pages
298             works correctly.
299              
300             =head1 AUTHOR
301              
302             Doug Bell <preaction@cpan.org>
303              
304             =head1 COPYRIGHT AND LICENSE
305              
306             This software is copyright (c) 2016 by Doug Bell.
307              
308             This is free software; you can redistribute it and/or modify it under
309             the same terms as the Perl 5 programming language system itself.
310              
311             =cut