summaryrefslogtreecommitdiff
path: root/lib/JWebmail/Plugin/Paginate.pm
blob: b4564b7e0cd1246594fb5593e3b572de14defcf9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package JWebmail::Plugin::Paginate;

use Mojo::Base Mojolicious::Plugin;

use List::Util qw(any max);
use POSIX 'ceil';


sub _clamp {
    my ($x, $y, $z) = @_;

    die '!($x <= $z)' unless $x <= $z;

    if ($x <= $y && $y <= $z) {
        return $y;
    }

    return $x if ($y < $x);
    return $z if ($z < $y);
}

sub _paginate {
    my %args = @_;

    my $first_item  = $args{first_item};
    my $page_size   = $args{page_size};
    my $total_items = $args{total_items};

    my $current_page = ceil($first_item/$page_size);
    my $total_pages  = ceil($total_items/$page_size);

    my $page = sub {
        my $page_ = shift;
        return [0, 0] unless $total_items;
        $page_ = _clamp(0, $page_, $total_pages-1);
        [_clamp(0, $page_*$page_size, $total_items-1), _clamp(0, ($page_+1)*$page_size, $total_items)]
    };

    my $ret = {
        total_items => $total_items,
        page_size   => $page_size,

        total_pages  => $total_pages,
        current_page => $current_page,

        first_page => $page->(0),
        prev_page  => $page->($current_page-1),
        this_page  => $page->($current_page),
        next_page  => $page->($current_page+1),
        last_page  => $page->($total_pages-1),
    };

    if ($total_items) {
        $ret->{first_item} = $first_item;
        $ret->{last_item} = _clamp($first_item, $first_item+$page_size-1, $total_items-1);
    }

    return $ret;
}

sub paginate {
    my $c = shift;
    my ($count) = @_;

    my $v = $c->validation;
    my $start = $v->optional('start')->num(0, undef)->param // 0;
    my $psize = $v->optional('page_size')->num(1, undef)->param // 50;

    $start = _clamp(0, $start, max($count-1, 0));
    my $end = _clamp($start, $start+$psize, max($count, 0));

    $c->stash(pgn => _paginate(
        first_item  => int($start/$psize)*$psize,
        page_size   => $psize,
        total_items => $count,
    ));

    return $start, $end;
}

sub make_link {
    my ($c, $txt, $to, %args) = @_;

    return $c->link_to(
        $txt => $c->url_with->query({start => $c->stash('pgn')->{$to}[0]}),
        class => ($c->param('start')//0) == $c->stash('pgn')->{$to}[0] ? join(' ', $args{class}, $args{class_disabled}) : $args{class},
    );
}

sub register {
    my ($self, $app, $conf) = @_;
    $conf //= {};

    $app->helper(paginate => \&paginate);
    $app->helper('_paginate.make_link' => \&make_link);
}


1

__END__

=encoding utf-8

=head1 NAME

JWebmail::Plugin::Paginate

=head1 SYNOPSIS

  sub my_route {
    my ($c) = @_;

    $c->stash($c->paginate(1234));
  }

=head1 DESCRIPTION

L<JWebmail::Helper> provides useful helper functions and validator cheks and filter for
L<JWebmail::Controller::All> and various templates.

=head1 HELPERS

=head2 paginate

A helper for calculating page bounds.

Takes the total number of items as argument.

Reads in 'start' and 'page_size' query arguments.
start is 0 based.

Returns the calculated start and end points as 0 based inclusive range.

Sets the stash values (all 1 based inclusive):

  first_item
  last_item
  total_items
  page_size
  total_pages
  current_page
  first_page
  prev_page
  next_page
  last_page

=head1 SEE ALSO

L<JWebmail>

=head1 NOTICE

This package is part of JWebmail.