#native_company# #native_desc#
#native_cta#

Pager For Lots o’ Data

By Dustin Voss
on March 11, 2005

Version: 1.0

Type: Function

Category: HTML

License: GNU General Public License

Description: This function echo’s a pager. The pager looks like this:
< 1 … 4 … 7 8 9 10 11 … 14 … 17 >

The ellipses are collapsed when needed. It works for any size dataset. It builds URLs that have a query parameter indicating the item (not page) number at the top of the current page. It preserves all other query parameters of the current URL.

This function requires the ReplaceQueryValue function from https://phpbuilder.com/snippet/download.php?type=snippet&id=1923 in order to construct the queries.

/**
 * Display a pager. It constructs URLs with a "skip" query parameter.
 *
 * The pager shows the left arrow, first page, right arrow, last page, and
 * 3 pages around the middle, with a half-way page towards the start and the
 * end. If the pager is too close to the start/end for a half-way page, then
 * the half-way page is not shown.
 *
 * $skip    Index of first item on page, 0-based.
 * $count   Count of total items.
 * $length  Count of items on a page.
 * Returns nothing. The HTML is echo'd out.
 */
function EchoPager ($skip, $count, $length)
{
    $prevStr = 'Prev';
    $nextStr = 'Next';
    $elideStr = '... '; // Include trailing space.
    $pageSpan = 3;      // How many pages to the left and right of current.
    $getParam = 'skip'; // Query parameter for URL.
    
    // The mod expression accounts for whether there needs to be another page
    // to pick up the remaining elements. 
    $pageCount = (int)floor ($count / $length) + ($count % $length != 0);
    $lastPage = $pageCount - 1;
    $page = (int)floor ($skip / $length);
    
    // These define the 7 pages in the middle, including the current page.
    $rangeFirst = ($page - $pageSpan);
    $rangeLast = ($page + $pageSpan);
    if ($rangeFirst < 0) $rangeFirst = 0;
    if ($rangeLast > $lastPage) $rangeLast = $lastPage;
    
    // These define the halfway pages.
    $prevHalfway = (int)floor ($rangeFirst / 2);
    $nextHalfway = (int)ceil (($rangeLast + $lastPage) / 2);
    
    // Can move forward or backward?
    $canPrev = ($page > 0);
    $canNext = ($page < $lastPage);
    
    // Range does not include first or last pages?
    $canFirst = ($rangeFirst > 0);
    $canLast = ($rangeLast < $lastPage);
    
    // Range does not include half-way pages?
    $canPrevHalfway = ($prevHalfway > 0 && $prevHalfway < $rangeFirst);
    $canNextHalfway = ($nextHalfway < $lastPage && $nextHalfway > $rangeLast);
    
    // Pages missing before/after half-way pages?
    $elideBeforePrevHalf = ($canPrevHalfway && $prevHalfway > 1);
    $elideAfterPrevHalf = ($canPrevHalfway && ($rangeFirst - $prevHalfway) > 1);
    $elideBeforeNextHalf = ($canNextHalfway && ($nextHalfway - $rangeLast) > 1);
    $elideAfterNextHalf = ($canNextHalfway && $nextHalfway < ($lastPage - 1));
    
    // No half-way pages, but pages missing before/after range?
    $elideBeforeRange = (!$canPrevHalfway && $rangeFirst > 1);
    $elideAfterRange = (!$canNextHalfway && ($lastPage - $rangeLast) > 1);
    
    // Pre-figure part of the new links.
    $baseLink = '<a href="' . $_SERVER['PHP_SELF'] . '?';
    $query = $_SERVER['QUERY_STRING'];

    // Do prev arrow.
    if ($canPrev) echo $baseLink .
        htmlspecialchars(ReplaceQueryValue ($query, $getParam, $skip - $length)) .
        '">';
    echo $prevStr;
    if ($canPrev) echo '</a>';
    echo ' ';
    
    // Do first page.
    if ($canFirst) echo $baseLink .
        htmlspecialchars(ReplaceQueryValue ($query, $getParam, 0)) .
        '">1</a> ';
    
    // Do prev halfway point.
    if ($elideBeforePrevHalf) echo $elideStr;
    if ($canPrevHalfway) echo $baseLink .
        htmlspecialchars(ReplaceQueryValue ($query, $getParam, $prevHalfway * $length)) .
        '">' . ($prevHalfway + 1) . '</a> ';
    if ($elideAfterPrevHalf) echo $elideStr;
    
    // Do range.
    if ($elideBeforeRange) echo $elideStr;
    for ($i = $rangeFirst; $i <= $rangeLast; ++$i)
    {
        if ($i != $page) echo $baseLink .
            htmlspecialchars(ReplaceQueryValue ($query, $getParam, $i * $length)) .
            '">';
        echo ($i + 1);
        if ($i != $page) echo '</a>';
        echo ' ';
    }
    if ($elideAfterRange) echo $elideStr;
    
    // Do next halfway point.
    if ($elideBeforeNextHalf) echo $elideStr;
    if ($canNextHalfway) echo $baseLink .
        htmlspecialchars(ReplaceQueryValue ($query, $getParam, $nextHalfway * $length)) .
        '">' . ($nextHalfway + 1) . '</a> ';
    if ($elideAfterNextHalf) echo $elideStr;
    
    // Do last page.
    if ($canLast) echo $baseLink .
        htmlspecialchars(ReplaceQueryValue ($query, $getParam, $lastPage * $length)) .
        '">' . ($lastPage + 1) . '</a> ';
        
    // Do next arrow.
    if ($canNext) echo $baseLink .
        htmlspecialchars(ReplaceQueryValue ($query, $getParam, $skip + $length)) .
        '">';
    echo $nextStr;
    if ($canNext) echo '</a>';
}