diff --git a/laravel/paginator.php b/laravel/paginator.php
index 990e1cd2..53c258f4 100644
--- a/laravel/paginator.php
+++ b/laravel/paginator.php
@@ -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 = '...';
/**
* Create a new Paginator instance.
@@ -91,9 +91,9 @@ public static function make($results, $total, $per_page)
{
$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 @@ public static function page($total, $per_page)
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.
+ *
+ *
+ * // Render the pagination links
+ * echo $paginator->links();
+ *
+ * // Render the pagination links using a given window size
+ * echo $paginator->links(5);
+ *
+ *
+ * @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 '
+ * // Render the pagination slider
+ * echo $paginator->slider();
+ *
+ * // Render the pagination slider using a given window size
+ * echo $paginator->slider(5);
+ *
+ *
+ * @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 '
+ * // 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');
+ *
*
- * @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.
+ *
+ *
+ * // Create the "next" pagination element
+ * echo $paginator->next();
+ *
+ * // Create the "next" pagination element with custom text
+ * echo $paginator->next('Skip Forwards');
+ *
*
- * @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 @@ public function appends($values)
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;
- }
-
}
\ No newline at end of file