File Coverage

blib/lib/Data/Pageset.pm
Criterion Covered Total %
statement 88 90 97.7
branch 51 54 94.4
condition 5 6 83.3
subroutine 11 11 100.0
pod 6 6 100.0
total 161 167 96.4


line stmt bran cond sub pod time code
1             package Data::Pageset;
2              
3 1     1   25440 use strict;
  1         2  
  1         44  
4 1     1   6 use Carp;
  1         2  
  1         115  
5              
6 1     1   1116 use Data::Page;
  1         7819  
  1         11  
7              
8 1     1   31 use vars qw(@ISA $VERSION);
  1         1  
  1         1135  
9              
10             @ISA = qw(Data::Page);
11              
12             $VERSION = '1.06';
13              
14             =head1 NAME
15              
16             Data::Pageset - Page numbering and page sets
17              
18             =head1 SYNOPSIS
19              
20             use Data::Pageset;
21             my $page_info = Data::Pageset->new({
22             'total_entries' => $total_entries,
23             'entries_per_page' => $entries_per_page,
24             # Optional, will use defaults otherwise.
25             'current_page' => $current_page,
26             'pages_per_set' => $pages_per_set,
27             'mode' => 'fixed', # default, or 'slide'
28             });
29              
30             # General page information
31             print " First page: ", $page_info->first_page, "\n";
32             print " Last page: ", $page_info->last_page, "\n";
33             print " Next page: ", $page_info->next_page, "\n";
34             print " Previous page: ", $page_info->previous_page, "\n";
35              
36             # Results on current page
37             print "First entry on page: ", $page_info->first, "\n";
38             print " Last entry on page: ", $page_info->last, "\n";
39              
40             # Can add in the pages per set after the object is created
41             $page_info->pages_per_set($pages_per_set);
42            
43             # Page set information
44             print "First page of previous page set: ", $page_info->previous_set, "\n";
45             print " First page of next page set: ", $page_info->next_set, "\n";
46            
47             # Print the page numbers of the current set
48             foreach my $page (@{$page_info->pages_in_set()}) {
49             if($page == $page_info->current_page()) {
50             print "$page ";
51             } else {
52             print "$page ";
53             }
54             }
55              
56             =head1 DESCRIPTION
57              
58             The object produced by Data::Pageset can be used to create page
59             navigation, it inherits from Data::Page and has access to all
60             methods from this object.
61              
62             In addition it also provides methods for dealing with set of pages,
63             so that if there are too many pages you can easily break them
64             into chunks for the user to browse through.
65              
66             You can even choose to view page numbers in your set in a 'sliding'
67             fassion.
68              
69             The object can easily be passed to a templating system
70             such as Template Toolkit or be used within a script.
71              
72             =head1 METHODS
73              
74             =head2 new()
75              
76             use Data::Pageset;
77             my $page_info = Data::Pageset->new({
78             'total_entries' => $total_entries,
79             'entries_per_page' => $entries_per_page,
80             # Optional, will use defaults otherwise.
81             'current_page' => $current_page,
82             'pages_per_set' => $pages_per_set,
83             'mode' => 'slide', # default fixed
84             });
85              
86             This is the constructor of the object, it requires an anonymous
87             hash containing the 'total_entries', how many data units you have,
88             and the number of 'entries_per_page' to display. Optionally
89             the 'current_page' (defaults to page 1) and pages_per_set (how
90             many pages to display, defaults to 10) can be added.
91              
92             The mode (which defaults to 'fixed') determins how the paging
93             will work, for example with 10 pages_per_set and the current_page
94             set to 18 you will get the following results:
95              
96             =head3 Fixed:
97              
98             =over 4
99              
100             =item Pages in set:
101              
102             11,12,13,14,15,16,17,18,19,20
103              
104             =item Previous page set:
105              
106             1
107              
108             =item Next page set:
109              
110             21
111              
112             =back 4
113              
114             =head3 Slide:
115              
116             =over 4
117              
118             =item Pages in set:
119              
120             14,15,16,17,18,19,20,21,22,23
121              
122             =item Previous page set:
123              
124             9
125              
126             =item Next page set:
127              
128             24
129              
130             =back 4
131              
132             You can not change modes once the object is created.
133              
134             =cut
135              
136             sub new {
137 60     60 1 26330 my ( $class, $conf ) = @_;
138 60         117 my $self = {};
139              
140 60 100 100     1058 croak "total_entries and entries_per_page must be supplied"
141             unless defined $conf->{'total_entries'}
142             && defined $conf->{'entries_per_page'};
143              
144 57 100       178 $conf->{'current_page'} = 1 unless defined $conf->{'current_page'};
145 57 100       163 $conf->{pages_per_set} = 10 unless defined $conf->{'pages_per_set'};
146 57 100 66     271 if ( defined $conf->{'mode'} && $conf->{'mode'} eq 'slide' ) {
147 15         47 $self->{mode} = 'slide';
148             } else {
149 42         95 $self->{mode} = 'fixed';
150             }
151 57         165 bless( $self, $class );
152              
153 57         234 $self->total_entries( $conf->{'total_entries'} );
154 57         784 $self->entries_per_page( $conf->{'entries_per_page'} );
155 56         774 $self->current_page( $conf->{'current_page'} );
156              
157 56         440 $self->pages_per_set( $conf->{'pages_per_set'} );
158              
159 56         563 return $self;
160             }
161              
162             =head2 current_page()
163              
164             $page_info->current_page($page_num);
165              
166             This method sets the current_page to the argument supplied, it can also be
167             set in the constructor, but you may want to reuse the object if printing out
168             multiple pages. It will then return the page number once set.
169              
170             If this method is called without any arguments it returns the current page number.
171              
172             =cut
173              
174             sub current_page {
175 665     665 1 169945 my $self = shift;
176              
177 665 100       1684 if (@_) {
178              
179             # Set current page
180 56         173 $self->_current_page_accessor(@_);
181              
182             # Redo calculations, using current pages_per_set value
183 56         416 $self->pages_per_set( $self->pages_per_set() );
184             }
185              
186             # Not sure if there is some cleaver way of calling SUPER here,
187             # think it would have to be wrapped in an eval
188 665 100       1885 return $self->first_page
189             if $self->_current_page_accessor < $self->first_page;
190 662 100       15409 return $self->last_page
191             if $self->_current_page_accessor > $self->last_page;
192 653         49380 return $self->_current_page_accessor();
193             }
194              
195             =head2 pages_per_set()
196              
197             $page_info->pages_per_set($number_of_pages_per_set);
198              
199             Calling this method initalises the calculations required to use
200             the paging methods below. The value can also be passed into
201             the constructor method new().
202              
203             If called without any arguments it will return the current
204             number of pages per set.
205              
206             =cut
207              
208             sub pages_per_set {
209 171     171 1 905 my $self = shift;
210 171         194 my $max_pages_per_set = shift;
211              
212             # set as undef so it at least exists
213 171 100       451 $self->{PAGE_SET_PAGES_PER_SET} = undef
214             unless exists $self->{PAGE_SET_PAGES_PER_SET};
215              
216             # Not trying to set, so return current number;
217 171 100       477 return $self->{PAGE_SET_PAGES_PER_SET} unless $max_pages_per_set;
218              
219 57         116 $self->{PAGE_SET_PAGES_PER_SET} = $max_pages_per_set;
220              
221 57 100       132 unless ( $max_pages_per_set > 1 ) {
222              
223             # Only have one page in the set, must be page 1
224 3 100       8 $self->{PAGE_SET_PREVIOUS} = $self->current_page() - 1
225             if $self->current_page != 1;
226 3         65 $self->{PAGE_SET_PAGES} = [1];
227 3 100       8 $self->{PAGE_SET_NEXT} = $self->current_page() + 1
228             if $self->current_page() < $self->last_page();
229             } else {
230 54 100       140 if ( $self->{mode} eq 'fixed' ) {
231 39         94 my $starting_page = $self->_calc_start_page($max_pages_per_set);
232 39         64 my $end_page = $starting_page + $max_pages_per_set - 1;
233              
234 39 100       669 if ( $end_page < $self->last_page() ) {
235 6         186 $self->{PAGE_SET_NEXT} = $end_page + 1;
236             }
237              
238 39 100       779 if ( $starting_page > 1 ) {
239 3         6 $self->{PAGE_SET_PREVIOUS}
240             = $starting_page - $max_pages_per_set;
241              
242             # I can't see a reason for this to be here!
243             #$self->{PAGE_SET_PREVIOUS} = 1 if $self->{PAGE_SET_PREVIOUS} < 1;
244             }
245              
246 39 100       100 $end_page = $self->last_page() if $self->last_page() < $end_page;
247 39         1559 $self->{PAGE_SET_PAGES} = [ $starting_page .. $end_page ];
248             } else {
249              
250             # We're in slide mode
251              
252             # See if we have enough pages to slide
253 15 100       49 if ( $max_pages_per_set >= $self->last_page() ) {
254              
255             # No sliding, no next/prev pageset
256 5         123 $self->{PAGE_SET_PAGES} = [ '1' .. $self->last_page() ];
257             } else {
258              
259             # Find the middle rounding down - we want more pages after, than before
260 10         770 my $middle = int( $max_pages_per_set / 2 );
261              
262             # offset for extra value right of center on even numbered sets
263 10         18 my $offset = 1;
264 10 100       39 if ( $max_pages_per_set % 2 != 0 ) {
265              
266             # must have been an odd number, add one
267 9         15 $middle++;
268 9         13 $offset = 0;
269             }
270              
271 10         22 my $starting_page = $self->current_page() - $middle + 1;
272 10 50       187 $starting_page = 1 if $starting_page < 1;
273 10         22 my $end_page = $starting_page + $max_pages_per_set - 1;
274 10 100       25 $end_page = $self->last_page()
275             if $self->last_page() < $end_page;
276              
277 10 50       286 if ( $self->current_page() <= $middle ) {
    100          
278              
279             # near the start of the page numbers
280 0         0 $self->{PAGE_SET_NEXT}
281             = $max_pages_per_set + $middle - $offset;
282 0         0 $self->{PAGE_SET_PAGES} = [ '1' .. $max_pages_per_set ];
283             } elsif ( $self->current_page()
284             > ( $self->last_page() - $middle - $offset ) )
285             {
286              
287             # near the end of the page numbers
288 4         116 $self->{PAGE_SET_PREVIOUS}
289             = $self->last_page()
290             - $max_pages_per_set
291             - $middle + 1;
292 4         351 $self->{PAGE_SET_PAGES}
293             = [ ( $self->last_page() - $max_pages_per_set + 1 )
294             .. $self->last_page() ];
295             } else {
296              
297             # Start scrolling baby!
298 6         176 $self->{PAGE_SET_PAGES} = [ $starting_page .. $end_page ];
299 6         17 $self->{PAGE_SET_PREVIOUS}
300             = $starting_page - $middle - $offset;
301 6 100       18 $self->{PAGE_SET_PREVIOUS} = 1
302             if $self->{PAGE_SET_PREVIOUS} < 1;
303 6         28 $self->{PAGE_SET_NEXT} = $end_page + $middle;
304             }
305             }
306             }
307             }
308              
309             }
310              
311             =head2 previous_set()
312              
313             print "Back to previous set which starts at ", $page_info->previous_set(), "\n";
314              
315             This method returns the page number at the start of the previous page set.
316             undef is return if pages_per_set has not been set.
317              
318             =cut
319              
320             sub previous_set {
321 50     50 1 189 my $self = shift;
322 50 100       212 return $self->{PAGE_SET_PREVIOUS} if defined $self->{PAGE_SET_PREVIOUS};
323 37         169 return undef;
324             }
325              
326             =head2 next_set()
327              
328             print "Next set starts at ", $page_info->next_set(), "\n";
329              
330             This method returns the page number at the start of the next page set.
331             undef is return if pages_per_set has not been set.
332              
333             =cut
334              
335             sub next_set {
336 50     50 1 42094 my $self = shift;
337 50 100       199 return $self->{PAGE_SET_NEXT} if defined $self->{PAGE_SET_NEXT};
338 40         208 return undef;
339             }
340              
341             =head2 pages_in_set()
342              
343             foreach my $page_num (@{$page_info->pages_in_set()}) {
344             print "Page: $page_num \n";
345             }
346              
347             This method returns an array ref of the the page numbers within
348             the current set. undef is return if pages_per_set has not been set.
349              
350             =cut
351              
352             sub pages_in_set {
353 50     50 1 1527 my $self = shift;
354 50         209 return $self->{PAGE_SET_PAGES};
355             }
356              
357             # Calc the first page in the current set
358             sub _calc_start_page {
359 39     39   56 my ( $self, $max_page_links_per_page ) = @_;
360 39         42 my $start_page;
361              
362 39         65 my $current_page = $self->current_page();
363 39         1987 my $max_pages_per_set;
364              
365 39         47 my $current_page_set = 0;
366              
367 39 50       96 if ( $max_page_links_per_page > 0 ) {
368 39         57 $current_page_set = int( $current_page / $max_page_links_per_page );
369              
370 39 100       120 if ( $current_page % $max_page_links_per_page == 0 ) {
371 2         4 $current_page_set = $current_page_set - 1;
372             }
373             }
374              
375 39         58 $start_page = ( $current_page_set * $max_page_links_per_page ) + 1;
376              
377 39         69 return $start_page;
378             }
379              
380             =head1 EXPORT
381              
382             None by default.
383              
384             =head1 AUTHOR
385              
386             Leo Lapworth C<< >>
387              
388             =head1 REPOSITORY
389              
390             http://github.com/ranguard/data-pageset
391              
392             =head1 CONTRIBUTORS
393              
394             Ryan D Johnson C<< >>
395             PLOBBES
396              
397             =head1 SEE ALSO
398              
399             L.
400              
401             =head1 COPYRIGHT
402              
403             Copyright (C) 2007, Leo Lapworth
404              
405             This module is free software; you can redistribute it or modify it
406             under the same terms as Perl itself.
407              
408             =cut
409              
410             1;
411