File Coverage

blib/lib/Mojolicious/Plugin/Pager.pm
Criterion Covered Total %
statement 61 61 100.0
branch 45 50 90.0
condition 26 40 65.0
subroutine 8 8 100.0
pod 3 3 100.0
total 143 162 88.2


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::Pager;
2 2     2   1399 use Mojo::Base 'Mojolicious::Plugin';
  2         4  
  2         14  
3              
4 2     2   417 use POSIX ();
  2         3  
  2         35  
5              
6 2     2   10 use constant PAGE_PARAM => 'page_param_name';
  2         3  
  2         134  
7 2     2   9 use constant SHOW_PREV_AND_NEXT => 'pager.show_prev_next';
  2         4  
  2         1627  
8              
9             our $VERSION = '0.06';
10              
11             sub pager_link {
12 165     165 1 349 my ($self, $c, $page, @args) = @_;
13 165         485 my $url = $c->url_with;
14 165 100 66     57457 my @text = (@args and ref $args[-1] eq 'CODE') ? () : ($page->{n});
15 165         311 my (@extra, @classes);
16              
17 165 100       404 push @classes, $self->{classes}{current} if $page->{current};
18 165 100       343 push @classes, $self->{classes}{first} if $page->{first};
19 165 100       340 push @classes, $self->{classes}{last} if $page->{last};
20 165 100       322 push @classes, $self->{classes}{next} if $page->{next};
21 165 100       361 push @classes, $self->{classes}{prev} if $page->{prev};
22 165 100       442 push @classes, $self->{classes}{normal} unless @classes;
23 165 100       337 push @extra, rel => 'next' if $page->{next};
24 165 100       411 push @extra, rel => 'prev' if $page->{prev};
25              
26 165   50     345 $url->query->param($c->stash(PAGE_PARAM) => $page->{n} || 1);
27 165         8782 return $c->link_to(@text, $url, class => join(' ', @classes), @extra, @args);
28             }
29              
30             sub pages_for {
31 22     22 1 385018 my $c = shift;
32 22 100 50     202 my $args = ref $_[0] ? shift : {total_pages => @_ ? shift // 1 : undef};
    50          
33 22   100     155 my $current_page = $args->{current} || $c->param($c->stash(PAGE_PARAM)) || 1;
34 22   50     7020 my $pager_size = $args->{size} || 8;
35 22         83 my $window_size = ($pager_size / 2) - 1;
36 22         51 my ($start_page, $total_pages, @pages);
37              
38             $total_pages
39             = POSIX::ceil($args->{total} // $args->{total_pages}
40             // ($args->{total_items} || $c->stash('total_items') || 0)
41 22   66     230 / ($args->{items_per_page} || $c->stash('items_per_page') || 20));
      50        
      100        
      66        
42              
43 22 100       216 if ($current_page < $window_size) {
    100          
44 7         16 $start_page = 1;
45             }
46             elsif ($current_page + $pager_size - $window_size > $total_pages) {
47 7         21 $start_page = 1 + $total_pages - $pager_size;
48             }
49             else {
50 8         19 $start_page = 1 + $current_page - $window_size;
51             }
52              
53 22 100       84 $start_page = 1 if $start_page < 1;
54 22         69 for my $n ($start_page .. $total_pages) {
55 152 100       303 last if @pages >= $pager_size;
56 144         307 push @pages, {n => $n};
57 144 100       256 $pages[-1]{first} = 1 if $n == 1;
58 144 100       268 $pages[-1]{last} = 1 if $n == $total_pages;
59 144 100       273 $pages[-1]{current} = 1 if $n == $current_page;
60             }
61              
62 22 0       71 return $c->stash('pages_as_array_ref') ? \@pages : @pages unless @pages;
    50          
63 22 100 100     89 return $c->stash('pages_as_array_ref') ? \@pages : @pages
    100          
64             if $total_pages <= $pager_size and !$c->stash(SHOW_PREV_AND_NEXT);
65              
66 17 100       129 unshift @pages, {prev => 1, n => $current_page - 1} if $current_page > 1;
67 17 100       111 push @pages, {next => 1, n => $current_page + 1} if $current_page < $total_pages;
68              
69 17 50       70 return $c->stash('pages_as_array_ref') ? \@pages : @pages;
70             }
71              
72             sub register {
73 2     2 1 87 my ($self, $app, $config) = @_;
74              
75 2   50     29 $app->defaults(PAGE_PARAM, $config->{param_name} || 'page');
76 2   100     55 $app->defaults(SHOW_PREV_AND_NEXT, $config->{always_show_prev_next} || 0);
77              
78 2   50     39 $self->{classes}{current} = $config->{classes}{current} || 'active';
79 2   50     9 $self->{classes}{first} = $config->{classes}{first} || 'first';
80 2   50     11 $self->{classes}{last} = $config->{classes}{last} || 'last';
81 2   50     8 $self->{classes}{next} = $config->{classes}{next} || 'next';
82 2   50     13 $self->{classes}{prev} = $config->{classes}{prev} || 'prev';
83 2   50     12 $self->{classes}{normal} = $config->{classes}{normal} || 'page';
84              
85 2     165   16 $app->helper(pager_link => sub { $self->pager_link(@_) });
  165         73452  
86 2         270 $app->helper(pages_for => \&pages_for);
87             }
88              
89             1;
90              
91             =encoding utf8
92              
93             =head1 NAME
94              
95             Mojolicious::Plugin::Pager - Pagination plugin for Mojolicious
96              
97             =head1 SYNOPSIS
98              
99             =head2 Example lite app
100              
101             use Mojolicious::Lite;
102              
103             plugin "pager";
104              
105             get "/" => sub {
106             my $c = shift;
107             $c->stash(total_items => 1431, items_per_page => 20);
108             };
109              
110             =head2 Example template
111              
112            
113             % for my $page (pages_for $total_items / $items_per_page) {
114            
  • <%= pager_link $page %>
  • 115             % }
    116            
    117              
    118             =head2 Custom template
    119              
    120            
    121             % for my $page (pages_for $total_items / $items_per_page) {
    122             % my $url = url_with; $url->query->param(x => $page->{n});
    123            
  • <%= link_to "hey!", $url %>
  • 124             % }
    125            
    126              
    127             =head1 DESCRIPTION
    128              
    129             L is a L plugin for creating paged
    130             navigation, without getting in the way. There are other plugins which ship with
    131             complete markup, but this is often not the markup that I want.
    132              
    133             =head1 HELPERS
    134              
    135             =head2 pager_link
    136              
    137             $bytestream = $c->pager_link(\%page, @args);
    138             $bytestream = $c->pager_link(\%page, @args, sub { int(rand 100) });
    139              
    140             Takes a C<%page> hash and creates an anchor using
    141             L. C<@args> is passed on, without
    142             modification, to C. The anchor generated has some classes added.
    143              
    144             See L for detail about C<%page>.
    145              
    146             Examples output:
    147              
    148            
    149             1
    150             2
    151             3
    152             4
    153             5
    154             6
    155            
    156              
    157             =head2 pages_for
    158              
    159             @pages = $self->pages_for($total_pages);
    160             @pages = $self->pages_for(\%args)
    161             @pages = $self->pages_for;
    162              
    163             Returns a list of C<%page> hash-refs, that can be passed on to L.
    164              
    165             Example C<%page>:
    166              
    167             {
    168             n => 2, # page number
    169             current => 1, # if page number matches "page" query parameter
    170             first => 1, # if this is the first page
    171             last => 1, # if this is the last page
    172             next => 1, # if this is last, that brings you to the next page
    173             prev => 1, # if this is first, that brings you to the previous page
    174             }
    175              
    176             C<%args> can contain:
    177              
    178             =over 2
    179              
    180             =item * current
    181              
    182             Default to the "page" query param or "1".
    183              
    184             =item * items_per_page
    185              
    186             Only useful unless C is specified. Default to 20.
    187              
    188             =item * size
    189              
    190             The max number of pages to show in the pagination. Default to 8 + "Previous"
    191             and "Next" links.
    192              
    193             =item * total
    194              
    195             The total number of pages. Default to "1" or...
    196              
    197             $total = $args->{total_items} / $args->{items_per_page}
    198             $total = $c->stash('total_items') / $c->stash('items_per_page')
    199              
    200             =back
    201              
    202             =head1 METHODS
    203              
    204             =head2 register
    205              
    206             $app->plugin(pager => \%config);
    207              
    208             Used to register this plugin and the L above. C<%config> can be:
    209              
    210             =over 4
    211              
    212             =item * classes
    213              
    214             Used to set default class names, used by L.
    215              
    216             Default:
    217              
    218             {
    219             current => "active",
    220             first => "first",
    221             last => "last",
    222             next => "next",
    223             prev => "prev",
    224             normal => "page",
    225             }
    226              
    227             =item * param_name
    228              
    229             The query parameter that will be looked up to figure out which page you are on.
    230             Can also be set in L on each request under the
    231             name "page_param_name".
    232              
    233             Default: "page"
    234              
    235             =back
    236              
    237             =head1 AUTHOR
    238              
    239             Jan Henning Thorsen
    240              
    241             =head1 COPYRIGHT AND LICENSE
    242              
    243             Copyright (C) 2017, Jan Henning Thorsen
    244              
    245             This program is free software, you can redistribute it and/or modify it under
    246             the terms of the Artistic License version 2.0.
    247              
    248             =cut