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) = @_; 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] ? 'disabled' : '', ); } 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 provides useful helper functions and validator cheks and filter for L 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 =head1 NOTICE This package is part of JWebmail.