Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

wickline (135)

wickline
  (email not shown publicly)

Journal of wickline (135)

Tuesday July 08, 2003
10:52 PM

re-inventing the pageset wheel

[ #13340 ]

Matts asked about page set code, and use.perl.org decided that my reply was sufficiently compressible that it probably wasn't meaninfull content... so I'm posting it here to see if I'm allowed to put meaningless things in my own journal ;)

-matt

=item C<prepare_resultset_paging>( I<$set_size>, I<$page_size>, I<$curr_page>, I<$url> )
 
Given the size of a current result set (number of hits), the size of our result
pages (ie: showing a list of ten hits per page), and the number of our current
page (zero indexed: ie 0 for the first page in the result set), and the initial
URL (to which the zero-indexed page numbers will be appeneded)... Returns HTML for
links allowing the user to page through the result set. The links will include
a 'previous' and 'next' link where applicable, and will include links to jump
to up to eight other result pages by page number. Generally, the script will
prefer to show four pages before and four after, but for pages near either end
of the result set, that view may be shifted to continue showing eight other
pages.
 
For a general idea, here's a textual representation of different output for
all of the pages in a twenty-page result set (_underlined_ items are links
and whitespace is only added to hilight patterns in the output)
 
             _next_ page[      1   _2_  _3_  _4_  _5_  _6_  _7_  _8_  _9..._ ]
    _prev_ , _next_ page[     _1_   2   _3_  _4_  _5_  _6_  _7_  _8_  _9..._ ]
    _prev_ , _next_ page[     _1_  _2_   3   _4_  _5_  _6_  _7_  _8_  _9..._ ]
    _prev_ , _next_ page[     _1_  _2_  _3_   4   _5_  _6_  _7_  _8_  _9..._ ]
    _prev_ , _next_ page[     _1_  _2_  _3_  _4_   5   _6_  _7_  _8_  _9..._ ]
    _prev_ , _next_ page[  _...2_  _3_  _4_  _5_   6   _7_  _8_  _9_ _10..._ ]
    _prev_ , _next_ page[  _...3_  _4_  _5_  _6_   7   _8_  _9_ _10_ _11..._ ]
    _prev_ , _next_ page[  _...4_  _5_  _6_  _7_   8   _9_ _10_ _11_ _12..._ ]
    _prev_ , _next_ page[  _...5_  _6_  _7_  _8_   9  _10_ _11_ _12_ _13..._ ]
    _prev_ , _next_ page[  _...6_  _7_  _8_  _9_  10  _11_ _12_ _13_ _14..._ ]
    _prev_ , _next_ page[  _...7_  _8_  _9_ _10_  11  _12_ _13_ _14_ _15..._ ]
    _prev_ , _next_ page[  _...8_  _9_ _10_ _11_  12  _13_ _14_ _15_ _16..._ ]
    _prev_ , _next_ page[  _...9_ _10_ _11_ _12_  13  _14_ _15_ _16_ _17..._ ]
    _prev_ , _next_ page[ _...10_ _11_ _12_ _13_  14  _15_ _16_ _17_ _18..._ ]
    _prev_ , _next_ page[ _...11_ _12_ _13_ _14_  15  _16_ _17_ _18_ _19..._ ]
    _prev_ , _next_ page[ _...12_ _13_ _14_ _15_  16  _17_ _18_ _19_ _20_    ]
    _prev_ , _next_ page[ _...12_ _13_ _14_ _15_ _16_  17  _18_ _19_ _20_    ]
    _prev_ , _next_ page[ _...12_ _13_ _14_ _15_ _16_ _17_  18  _19_ _20_    ]
    _prev_ , _next_ page[ _...12_ _13_ _14_ _15_ _16_ _17_ _18_  19  _20_    ]
    _prev_          page[ _...12_ _13_ _14_ _15_ _16_ _17_ _18_ _19_  20     ]
 
Note that the output reflects one-based indices even though the input
page number is zero-based and the href values will reference zero-based
indices. Also note that the url prefix arg should be HTML escaped if it
needs it. This method just slaps an int on the end and considers the
result to be valid for an href value.
 
For sufficiently small result sets, fewer than eight links may be shown.
 
For results sets having only three pages, only the prev/next links need to be
shown for the second page (as numbered 1/3 links are overly redundant). Result
sets having only (one or) two pages need not show numbered pages links either.
 
Input is not validated. Caller is expected to have ensured sensible args.
The set size must be positive. The page size must be positive. The current
page must be non-negative and less than number of pages (which is calculated
from the set size and page size... and note that 'less than' is accurate
because the current page is zero-indexed).
 
=cut
 
sub prepare_resultset_paging {
    my( $set_size, $page_size, $curr_page, $url ) = @_;
    my $margin = 4; # in the midst of a large list, keep this many links on
        # either side of our current page. Shift things about if we're near
        # either end of our large list to keep 2*$margin links available
        # for sufficiently short lists, the margin becomes less relevant
        # and we just show as many links as there are
    # determine how many pages are in the result set
    my $num_pages = int( $set_size / $page_size );
    $num_pages++ if $set_size % $page_size;
    my $max_page = $num_pages - 1; # zero-indexed
    return '' if $curr_page > $max_page; # docs warn that caller shouldn't do this
    my $l_margin = $margin;
    my $r_margin = $margin;
    if ( $curr_page < $l_margin ) {
        my $diff = $l_margin - $curr_page;
        $l_margin -= $diff;
        $r_margin += $diff;
    }
    if ( $curr_page + $r_margin > $max_page ) {
        my $diff = $curr_page + $r_margin - $max_page;
        $r_margin -= $diff;
        while (  $diff--  and  ( $curr_page-$l_margin > 0)  ) {
            $l_margin++;
        }
    }
    my @window = ($curr_page - $l_margin) .. ($curr_page + $r_margin);
    my( $win_links, $prev, $next ) = ( '','','' );
    if (  @window > 3  or  (@window == 3 and $curr_page != 1)  ) {
        $win_links = join( ' ', map {
            $_ == $curr_page
                ? qq{<strong>@{[$_+1]}</strong>}
                : qq{<a href="$url$_#resultset">@{[$_+1]}</a>}
        } @window);
        $win_links =~ s{^(<a [^>]+>)}{$1...} if $window[0];
        $win_links =~ s{</a>\z}{...</a>} if $window[-1] < $max_page;
        $win_links = "; page[<small> $win_links </small>]";
    }
    $prev = qq{<a href="$url@{[$curr_page-1]}#resultset">previous&#160;page</a>} if $curr_page;
    $next = qq{<a href="$url@{[$curr_page+1]}#resultset">next&#160;page</a>} if $curr_page < $max_page;
    return join( ', ', grep {$_} ($prev, $next) ).$win_links
}

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.