refactor the paginator to reincorporate the google style slider.
This commit is contained in:
@@ -54,11 +54,11 @@ class Paginator {
|
||||
protected $appendage;
|
||||
|
||||
/**
|
||||
* The pagination elements that will be generated.
|
||||
* The "dots" element used in the pagination slider.
|
||||
*
|
||||
* @var array
|
||||
* @var string
|
||||
*/
|
||||
protected $elements = array('first', 'previous', 'status', 'next', 'last');
|
||||
protected $dots = '<span class="dots">...</span>';
|
||||
|
||||
/**
|
||||
* Create a new Paginator instance.
|
||||
@@ -91,9 +91,9 @@ class Paginator {
|
||||
{
|
||||
$page = static::page($total, $per_page);
|
||||
|
||||
$last_page = ceil($total / $per_page);
|
||||
$last = ceil($total / $per_page);
|
||||
|
||||
return new static($results, $page, $total, $per_page, $last_page);
|
||||
return new static($results, $page, $total, $per_page, $last);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,198 +116,266 @@ class Paginator {
|
||||
return ($last > 0) ? $last : 1;
|
||||
}
|
||||
|
||||
return ($page < 1 or filter_var($page, FILTER_VALIDATE_INT) === false) ? 1 : $page;
|
||||
return (static::valid($page)) ? $page : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given page number is a valid page.
|
||||
*
|
||||
* A valid page must be greater than or equal to one and a valid integer.
|
||||
*
|
||||
* @param int $page
|
||||
* @return bool
|
||||
*/
|
||||
protected static function valid($page)
|
||||
{
|
||||
return $page >= 1 and filter_var($page, FILTER_VALIDATE_INT) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the HTML pagination links.
|
||||
*
|
||||
* Typically, an intelligent, "sliding" window of links will be rendered based
|
||||
* on the total number of pages, the current page, and the number of adjacent
|
||||
* pages that should rendered. This creates a beautiful paginator similar to
|
||||
* that of Google's.
|
||||
*
|
||||
* Example: 1 2 ... 23 24 25 [26] 27 28 29 ... 51 52
|
||||
*
|
||||
* If you wish to render only certain elements of the pagination control,
|
||||
* explore some of the other public methods available on the instance.
|
||||
*
|
||||
* <code>
|
||||
* // Render the pagination links
|
||||
* echo $paginator->links();
|
||||
*
|
||||
* // Render the pagination links using a given window size
|
||||
* echo $paginator->links(5);
|
||||
* </code>
|
||||
*
|
||||
* @param int $adjacent
|
||||
* @return string
|
||||
*/
|
||||
public function links()
|
||||
public function links($adjacent = 3)
|
||||
{
|
||||
if ($this->last <= 1) return '';
|
||||
|
||||
// Each pagination element is created by an element method. This allows
|
||||
// us to keep this class clean and simple, because pagination code can
|
||||
// become a mess. We would rather keep it simple and beautiful.
|
||||
// The hard-coded seven is to account for all of the constant elements in a
|
||||
// sliding range, such as the current page, the two ellipses, and the two
|
||||
// beginning and ending pages.
|
||||
//
|
||||
// If the page is greater the one, we will render the first and previous
|
||||
// links, otherwise we skip them since we are already on the first page.
|
||||
if ($this->page > 1)
|
||||
// If there are not enough pages to make the creation of a slider possible
|
||||
// based on the adjacent pages, we will simply display all of the pages.
|
||||
// Otherwise, we will create a "truncating" slider which displays a nice
|
||||
// window of pages based on the current page.
|
||||
if ($this->last < 7 + ($adjacent * 2))
|
||||
{
|
||||
$elements[] = $this->first();
|
||||
|
||||
$elements[] = $this->previous();
|
||||
$numbers = $this->range(1, $this->last);
|
||||
}
|
||||
else
|
||||
{
|
||||
$numbers = $this->slider($adjacent);
|
||||
}
|
||||
|
||||
// The status is always rendered regardless of the current page. So we
|
||||
// can simply add it to the array of pagination elements.
|
||||
$elements[] = $this->status();
|
||||
$content = $this->previous().' '.$numbers.' '.$this->next();
|
||||
|
||||
// If the current page is not the last page, we will render the next
|
||||
// and last links. Otherwise we will skip them since we are already
|
||||
// on the last page and can't go any further.
|
||||
if ($this->page < $this->last)
|
||||
return '<div class="pagination">'.$content.'</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build sliding list of HTML numeric page links.
|
||||
*
|
||||
* This method is very similar to the "links" method, only it does not
|
||||
* render the "first" and "last" pagination links, but only the pages.
|
||||
*
|
||||
* <code>
|
||||
* // Render the pagination slider
|
||||
* echo $paginator->slider();
|
||||
*
|
||||
* // Render the pagination slider using a given window size
|
||||
* echo $paginator->slider(5);
|
||||
* </code>
|
||||
*
|
||||
* @param int $adjacent
|
||||
* @return string
|
||||
*/
|
||||
public function slider($adjacent = 3)
|
||||
{
|
||||
$window = $adjacent * 2;
|
||||
|
||||
// Example: 1 [2] 3 4 5 6 ... 23 24
|
||||
if ($this->page <= $window)
|
||||
{
|
||||
$elements[] = $this->next();
|
||||
|
||||
$elements[] = $this->last();
|
||||
return $this->range(1, $window + 2).' '.$this->ending();
|
||||
}
|
||||
|
||||
return '<div class="pagination">'.implode(' ', $elements).'</div>'.PHP_EOL;
|
||||
// Example: 1 2 ... 32 33 34 35 [36] 37
|
||||
elseif ($this->page >= $this->last - $window)
|
||||
{
|
||||
return $this->beginning().' '.$this->range($this->last - $window - 2, $this->last);
|
||||
}
|
||||
|
||||
// Example: 1 2 ... 23 24 25 [26] 27 28 29 ... 51 52
|
||||
$content = $this->range($this->page - $adjacent, $this->page + $adjacent);
|
||||
|
||||
return $this->beginning().' '.$content.' '.$this->ending();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "status" pagination element.
|
||||
* Generate the "previous" HTML link.
|
||||
*
|
||||
* @param string $text
|
||||
* @return string
|
||||
*/
|
||||
public function status($text = null)
|
||||
{
|
||||
if (is_null($text)) $text = Lang::line('pagination.status')->get();
|
||||
|
||||
return str_replace(array(':current', ':last'), array($this->page, $this->last), $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the "first" pagination element.
|
||||
* <code>
|
||||
* // Create the "previous" pagination element
|
||||
* echo $paginator->previous();
|
||||
*
|
||||
* @param string $text
|
||||
* @return string
|
||||
*/
|
||||
public function first($text = null)
|
||||
{
|
||||
return $this->backwards(__FUNCTION__, $text, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the "previous" pagination element.
|
||||
* // Create the "previous" pagination element with custom text
|
||||
* echo $paginator->previous('Go Back');
|
||||
* </code>
|
||||
*
|
||||
* @param string $text
|
||||
* @return string
|
||||
*/
|
||||
public function previous($text = null)
|
||||
{
|
||||
return $this->backwards(__FUNCTION__, $text, $this->page - 1);
|
||||
$disabled = function($page) { return $page <= 1; };
|
||||
|
||||
return $this->element(__FUNCTION__, $this->page - 1, $text, $disabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the "next" pagination element.
|
||||
* Generate the "next" HTML link.
|
||||
*
|
||||
* <code>
|
||||
* // Create the "next" pagination element
|
||||
* echo $paginator->next();
|
||||
*
|
||||
* // Create the "next" pagination element with custom text
|
||||
* echo $paginator->next('Skip Forwards');
|
||||
* </code>
|
||||
*
|
||||
* @param string $text
|
||||
* @return string
|
||||
*/
|
||||
public function next($text = null)
|
||||
{
|
||||
return $this->forwards(__FUNCTION__, $text, $this->page + 1);
|
||||
$disabled = function($page, $last) { return $page >= $last; };
|
||||
|
||||
return $this->element(__FUNCTION__, $this->page + 1, $text, $disabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the "last" pagination element.
|
||||
*
|
||||
* @param string $text
|
||||
* @return string
|
||||
*/
|
||||
public function last($text = null)
|
||||
{
|
||||
return $this->forwards(__FUNCTION__, $text, $this->last);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a "backwards" paginatino element.
|
||||
*
|
||||
* This function handles the creation of the first and previous elements.
|
||||
*
|
||||
* @param string $element
|
||||
* @param string $text
|
||||
* @param int $last
|
||||
* @return string
|
||||
*/
|
||||
protected function backwards($element, $text, $last)
|
||||
{
|
||||
$disabler = function($page) { return $page <= 1; };
|
||||
|
||||
return $this->element($element, $text, $last, $disabler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a "forwards" paginatino element.
|
||||
*
|
||||
* This function handles the creation of the next and last elements.
|
||||
*
|
||||
* @param string $element
|
||||
* @param string $text
|
||||
* @param int $last
|
||||
* @return string
|
||||
*/
|
||||
protected function forwards($element, $text, $last)
|
||||
{
|
||||
$disabler = function($page, $last) { return $page >= $last; };
|
||||
|
||||
return $this->element($element, $text, $last, $disabler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a chronological pagination element.
|
||||
* Create a chronological pagination element, such as a "previous" or "next" link.
|
||||
*
|
||||
* @param string $element
|
||||
* @param string $text
|
||||
* @param int $page
|
||||
* @param Closure $disabler
|
||||
* @param string $text
|
||||
* @param Closure $disabled
|
||||
* @return string
|
||||
*/
|
||||
protected function element($element, $text, $page, $disabler)
|
||||
protected function element($element, $page, $text, $disabled)
|
||||
{
|
||||
$class = "{$element}_page";
|
||||
|
||||
if (is_null($text)) $text = Lang::line("pagination.{$element}")->get();
|
||||
|
||||
if ($disabler($this->page, $this->last))
|
||||
// Each consumer of this method provides a "disabled" Closure which can
|
||||
// be used to determine if the element should be a span element or an
|
||||
// actual link. For example, if the current page is the first page,
|
||||
// the "first" element should be a span instead of a link.
|
||||
if ($disabled($this->page, $this->last))
|
||||
{
|
||||
return HTML::span($text, array('class' => "disabled {$class}"));
|
||||
return HTML::span($text, array('class' => "{$class} disabled"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// We will assume the page links should use HTTPS if the current request
|
||||
// is also using HTTPS. Since pagination links automatically point to
|
||||
// the current URI, this makes pretty good sense.
|
||||
list($uri, $secure) = array(Request::uri(), Request::secure());
|
||||
|
||||
$appendage = '?page='.$page.$this->appendage($element, $page);
|
||||
|
||||
return HTML::link($uri.$appendage, $text, array('class' => $class), $secure);
|
||||
return $this->link($page, $text, $class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the pagination link "appendage" for an element.
|
||||
* Build the first two page links for a sliding page range.
|
||||
*
|
||||
* @param string $element
|
||||
* @param int $page
|
||||
* @return string
|
||||
*/
|
||||
protected function appendage($element, $page)
|
||||
protected function beginning()
|
||||
{
|
||||
if ( ! is_null($this->appendage)) return $this->appendage;
|
||||
return $this->range(1, 2).' '.$this->dots;
|
||||
}
|
||||
|
||||
$appendage = '';
|
||||
/**
|
||||
* Build the last two page links for a sliding page range.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function ending()
|
||||
{
|
||||
return $this->dots.' '.$this->range($this->last - 1, $this->last);
|
||||
}
|
||||
|
||||
if (count($this->appends) > 0)
|
||||
/**
|
||||
* Build a range of numeric pagination links.
|
||||
*
|
||||
* For the current page, an HTML span element will be generated instead of a link.
|
||||
*
|
||||
* @param int $start
|
||||
* @param int $end
|
||||
* @return string
|
||||
*/
|
||||
protected function range($start, $end)
|
||||
{
|
||||
$pages = array();
|
||||
|
||||
for ($page = $start; $page <= $end; $page++)
|
||||
{
|
||||
$appendage .= '&'.http_build_query($this->appends);
|
||||
if ($this->page == $page)
|
||||
{
|
||||
$pages[] = HTML::span($page, array('class' => 'current'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$pages[] = $this->link($page, $page, null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->appendage = $appendage;
|
||||
return implode(' ', $pages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a HTML page link.
|
||||
*
|
||||
* @param int $page
|
||||
* @param string $text
|
||||
* @param string $attributes
|
||||
* @return string
|
||||
*/
|
||||
protected function link($page, $text, $class)
|
||||
{
|
||||
$url = URI::current().'?page='.$page.$this->appendage($this->appends);
|
||||
|
||||
return HTML::link($url, $text, compact('class'), Request::secure());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the "appendage" that should be attached to every pagination link.
|
||||
*
|
||||
* The developer may assign an array of values that will be converted to a
|
||||
* query string and attached to every pagination link. This allows simple
|
||||
* implementation of sorting or other things the developer may need.
|
||||
*
|
||||
* @param array $appends
|
||||
* @return string
|
||||
*/
|
||||
protected function appendage($appends)
|
||||
{
|
||||
if ( ! is_null($this->appendage))
|
||||
{
|
||||
return $this->appendage;
|
||||
}
|
||||
|
||||
return $this->appendage = (count($appends) > 0) ? '&'.http_build_query($appends) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the items that should be appended to the link query strings.
|
||||
*
|
||||
* This provides a convenient method of maintaining sort or passing other
|
||||
* information to the route handling pagination.
|
||||
*
|
||||
* @param array $values
|
||||
* @return Paginator
|
||||
*/
|
||||
@@ -317,18 +385,4 @@ class Paginator {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the elements that should be included when creating the pagination links.
|
||||
*
|
||||
* The available elements are "first", "previous", "status", "next", and "last".
|
||||
*
|
||||
* @param array $elements
|
||||
* @return string
|
||||
*/
|
||||
public function elements($elements)
|
||||
{
|
||||
$this->elements = $elements;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user