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   1205 use Mojo::Base 'Mojolicious::Plugin';
  2         4  
  2         12  
3              
4 2     2   328 use POSIX ();
  2         3  
  2         32  
5              
6 2     2   8 use constant PAGE_PARAM => 'page_param_name';
  2         4  
  2         159  
7 2     2   11 use constant SHOW_PREV_AND_NEXT => 'pager.show_prev_next';
  2         4  
  2         1546  
8              
9             our $VERSION = '0.05';
10              
11             sub pager_link {
12 165     165 1 343 my ($self, $c, $page, @args) = @_;
13 165         681 my $url = $c->url_with;
14 165 100 66     56592 my @text = (@args and ref $args[-1] eq 'CODE') ? () : ($page->{n});
15 165         288 my (@extra, @classes);
16              
17 165 100       352 push @classes, $self->{classes}{current} if $page->{current};
18 165 100       283 push @classes, $self->{classes}{first} if $page->{first};
19 165 100       289 push @classes, $self->{classes}{last} if $page->{last};
20 165 100       273 push @classes, $self->{classes}{next} if $page->{next};
21 165 100       314 push @classes, $self->{classes}{prev} if $page->{prev};
22 165 100       378 push @classes, $self->{classes}{normal} unless @classes;
23 165 100       302 push @extra, rel => 'next' if $page->{next};
24 165 100       296 push @extra, rel => 'prev' if $page->{prev};
25              
26 165   50     304 $url->query->param($c->stash(PAGE_PARAM) => $page->{n} || 1);
27 165         8455 return $c->link_to(@text, $url, class => join(' ', @classes), @extra, @args);
28             }
29              
30             sub pages_for {
31 22     22 1 323032 my $c = shift;
32 22 100 50     125 my $args = ref $_[0] ? shift : {total_pages => @_ ? shift // 1 : undef};
    50          
33 22   100     108 my $current_page = $args->{current} || $c->param($c->stash(PAGE_PARAM)) || 1;
34 22   50     5451 my $pager_size = $args->{size} || 8;
35 22         69 my $window_size = ($pager_size / 2) - 1;
36 22         44 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     159 / ($args->{items_per_page} || $c->stash('items_per_page') || 20));
      50        
      100        
      66        
42              
43 22 100       185 if ($current_page < $window_size) {
    100          
44 7         15 $start_page = 1;
45             }
46             elsif ($current_page + $pager_size - $window_size > $total_pages) {
47 7         60 $start_page = 1 + $total_pages - $pager_size;
48             }
49             else {
50 8         13 $start_page = 1 + $current_page - $window_size;
51             }
52              
53 22 100       62 $start_page = 1 if $start_page < 1;
54 22         57 for my $n ($start_page .. $total_pages) {
55 152 100       235 last if @pages >= $pager_size;
56 144         287 push @pages, {n => $n};
57 144 100       241 $pages[-1]{first} = 1 if $n == 1;
58 144 100       212 $pages[-1]{last} = 1 if $n == $total_pages;
59 144 100       240 $pages[-1]{current} = 1 if $n == $current_page;
60             }
61              
62 22 0       55 return $c->stash('pages_as_array_ref') ? \@pages : @pages unless @pages;
    50          
63 22 100 100     75 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       97 unshift @pages, {prev => 1, n => $current_page - 1} if $current_page > 1;
67 17 100       76 push @pages, {next => 1, n => $current_page + 1} if $current_page < $total_pages;
68              
69 17 50       55 return $c->stash('pages_as_array_ref') ? \@pages : @pages;
70             }
71              
72             sub register {
73 2     2 1 62 my ($self, $app, $config) = @_;
74              
75 2   50     25 $app->defaults(PAGE_PARAM, $config->{param_name} || 'page');
76 2   100     48 $app->defaults(SHOW_PREV_AND_NEXT, $config->{always_show_prev_next} || 0);
77              
78 2   50     35 $self->{classes}{current} = $config->{classes}{current} || 'active';
79 2   50     8 $self->{classes}{first} = $config->{classes}{first} || 'first';
80 2   50     8 $self->{classes}{last} = $config->{classes}{last} || 'last';
81 2   50     7 $self->{classes}{next} = $config->{classes}{next} || 'next';
82 2   50     10 $self->{classes}{prev} = $config->{classes}{prev} || 'prev';
83 2   50     8 $self->{classes}{normal} = $config->{classes}{normal} || 'page';
84              
85 2     165   14 $app->helper(pager_link => sub { $self->pager_link(@_) });
  165         66731  
86 2         55 $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             Note that this plugin is currently EXPERIMENTAL.
    134              
    135             =head1 HELPERS
    136              
    137             =head2 pager_link
    138              
    139             $bytestream = $c->pager_link(\%page, @args);
    140             $bytestream = $c->pager_link(\%page, @args, sub { int(rand 100) });
    141              
    142             Takes a C<%page> hash and creates an anchor using
    143             L. C<@args> is passed on, without
    144             modification, to C. The anchor generated has some classes added.
    145              
    146             See L for detail about C<%page>.
    147              
    148             Examples output:
    149              
    150            
    151             1
    152             2
    153             3
    154             4
    155             5
    156             6
    157            
    158              
    159             =head2 pages_for
    160              
    161             @pages = $self->pages_for($total_pages);
    162             @pages = $self->pages_for(\%args)
    163             @pages = $self->pages_for;
    164              
    165             Returns a list of C<%page> hash-refs, that can be passed on to L.
    166              
    167             Example C<%page>:
    168              
    169             {
    170             n => 2, # page number
    171             current => 1, # if page number matches "page" query parameter
    172             first => 1, # if this is the first page
    173             last => 1, # if this is the last page
    174             next => 1, # if this is last, that brings you to the next page
    175             prev => 1, # if this is first, that brings you to the previous page
    176             }
    177              
    178             C<%args> can contain:
    179              
    180             =over 2
    181              
    182             =item * current
    183              
    184             Default to the "page" query param or "1".
    185              
    186             =item * items_per_page
    187              
    188             Only useful unless C is specified. Default to 20.
    189              
    190             =item * size
    191              
    192             The max number of pages to show in the pagination. Default to 8 + "Previous"
    193             and "Next" links.
    194              
    195             =item * total
    196              
    197             The total number of pages. Default to "1" or...
    198              
    199             $total = $args->{total_items} / $args->{items_per_page}
    200             $total = $c->stash('total_items') / $c->stash('items_per_page')
    201              
    202             =back
    203              
    204             =head1 METHODS
    205              
    206             =head2 register
    207              
    208             $app->plugin(pager => \%config);
    209              
    210             Used to register this plugin and the L above. C<%config> can be:
    211              
    212             =over 4
    213              
    214             =item * classes
    215              
    216             Used to set default class names, used by L.
    217              
    218             Default:
    219              
    220             {
    221             current => "active",
    222             first => "first",
    223             last => "last",
    224             next => "next",
    225             prev => "prev",
    226             normal => "page",
    227             }
    228              
    229             =item * param_name
    230              
    231             The query parameter that will be looked up to figure out which page you are on.
    232             Can also be set in L on each request under the
    233             name "page_param_name".
    234              
    235             Default: "page"
    236              
    237             =back
    238              
    239             =head1 AUTHOR
    240              
    241             Jan Henning Thorsen
    242              
    243             =head1 COPYRIGHT AND LICENSE
    244              
    245             Copyright (C) 2017, Jan Henning Thorsen
    246              
    247             This program is free software, you can redistribute it and/or modify it under
    248             the terms of the Artistic License version 2.0.
    249              
    250             =cut