From c55f6da7d921b6b7033b398d4f7d81231ee0dec2 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Alberto=20Garc=C3=ADa=20Hierro?= <fiam@rm-fr.net>
Date: Sun, 23 Mar 2008 05:18:27 +0100
Subject: [PATCH] Improve the new paginator.

Add methods for storing the base_url and retrieving it,
displaying the page list as ul or div (taking the
current page into account) as well as for obtaining
the links for the previous and next pages.
---
 django/core/paginator.py |  106 +++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 105 insertions(+), 1 deletions(-)

diff --git a/django/core/paginator.py b/django/core/paginator.py
index dabd20d..ba3ed18 100644
--- a/django/core/paginator.py
+++ b/django/core/paginator.py
@@ -1,12 +1,95 @@
+from django.utils.translation import ugettext as _
+from django.utils.safestring import mark_safe
+from django.http import Http404
+
 class InvalidPage(Exception):
     pass
 
+class PageList(object):
+    def __init__(self, paginator):
+        self.curpage = paginator.page(paginator.curpage)
+        self.adjacent_count = paginator.adjacent_count
+
+    def __repr__(self):
+        return '<PageList current: %d - total:%d>' % \
+            (self.curpage.paginator.curpage, self.curpage.paginator.num_pages)
+
+    def _add_range_as_element(self, open, close, start, end):
+        markup = ''
+        for i in range(start, end + 1):
+            page = self.curpage.paginator.page(i)
+            if self.curpage.number == i:
+                markup += '%s<a class="curpage">%d</a>%s' % \
+                    (open, i, close)
+            else:
+                markup += '%s<a href="%s">%d</a>%s' % \
+                    (open, page.url(), i, close)
+        return markup
+
+    def _as_html(self, el, subel_open, subel_close):
+        markup = '<%s class="pagelist">' % el
+        if self.curpage.has_previous() or self.curpage.has_next():
+            markup += '%s<%s class="prev-next">' % (subel_open, el)
+            if self.curpage.has_previous():
+                markup += '%s<a href="%s">&laquo; %s</a>%s' % \
+                        (subel_open, self.curpage.previous_page_url(),
+                         _('Previous'), subel_close)
+            if self.curpage.has_next():
+                markup += '%s<a href="%s">%s &raquo;</a>%s' % \
+                        (subel_open, self.curpage.next_page_url(),
+                        _('Next'), subel_close)
+            markup += '</%s>%s' % (el, subel_close)
+        else:
+            return u''
+
+        markup += '%s<%s class="start">' % (subel_open, el)
+        end = self.adjacent_count + 1
+        if end > self.curpage.paginator.num_pages:
+            end = self.curpage.paginator.num_pages
+        if end == self.curpage.number:
+            end -= 1
+        markup += self._add_range_as_element(subel_open, subel_close, 1, end)
+        markup += '</%s>%s' % (el, subel_close)
+
+        if self.curpage.number > self.adjacent_count:
+            midstart = self.curpage.number - self.adjacent_count
+            if midstart <= self.adjacent_count:
+                midstart = self.adjacent_count + 1
+            midend = self.curpage.number + self.adjacent_count
+            if midend > self.curpage.paginator.num_pages:
+                midend = self.curpage.paginator.num_pages
+            markup += '%s<%s class="middle">' % (subel_open, el)
+            markup += self._add_range_as_element(subel_open, subel_close,
+                    midstart, midend)
+            markup += '</%s>%s' % (el, subel_close)
+
+
+        start = self.curpage.paginator.num_pages - self.adjacent_count
+        if start > self.adjacent_count and start > self.curpage.number + self.adjacent_count:
+            markup += '%s<%s class="end">' % (subel_open, el)
+            markup += self._add_range_as_element(subel_open, subel_close,
+                    start, self.curpage.paginator.num_pages)
+            markup += '</%s>%s' % (el, subel_close)
+        markup += '</%s>' % el
+
+        return mark_safe(markup)
+
+    def as_ul(self):
+        return self._as_html('ul', '<li>', '</li>')
+
+    def as_div(self):
+        return self._as_html('div', '', '')
+
+
 class Paginator(object):
-    def __init__(self, object_list, per_page, orphans=0, allow_empty_first_page=True):
+    def __init__(self, object_list, per_page, orphans=0, allow_empty_first_page=True, base_url=None, adjacent_count=2, current=None):
         self.object_list = object_list
         self.per_page = per_page
         self.orphans = orphans
         self.allow_empty_first_page = allow_empty_first_page
+        self.base_url = base_url
+        self.curpage = current
+        self.adjacent_count = adjacent_count
         self._num_pages = self._count = None
 
     def validate_number(self, number):
@@ -31,8 +114,16 @@ class Paginator(object):
         top = bottom + self.per_page
         if top + self.orphans >= self.count:
             top = self.count
+        if self.curpage is None:
+            self.curpage = number
         return Page(self.object_list[bottom:top], number, self)
 
+    def page_or_404(self, number):
+        try:
+            return self.page(number)
+        except InvalidPage:
+            raise Http404(_('Invalid page'))
+
     def _get_count(self):
         "Returns the total number of objects, across all pages."
         if self._count is None:
@@ -61,6 +152,10 @@ class Paginator(object):
         return range(1, self.num_pages + 1)
     page_range = property(_get_page_range)
 
+    def _get_page_list(self):
+        return PageList(self)
+    page_list = property(_get_page_list)
+
 class QuerySetPaginator(Paginator):
     """
     Like Paginator, but works on QuerySets.
@@ -95,6 +190,15 @@ class Page(object):
     def previous_page_number(self):
         return self.number - 1
 
+    def next_page_url(self):
+        return self.paginator.base_url % self.next_page_number()
+
+    def previous_page_url(self):
+        return self.paginator.base_url % self.previous_page_number()
+
+    def url(self):
+        return self.paginator.base_url % self.number
+
     def start_index(self):
         """
         Returns the 1-based index of the first object on this page,
-- 
1.5.2.5

