Merge branch 'master' of git://github.com/callowayproject/django-pagination
[django-pagination.git] / linaro_django_pagination / templatetags / pagination_tags.py
index 38dfc43..a78c790 100644 (file)
@@ -1,27 +1,50 @@
-try:
-    set
-except NameError:
-    from sets import Set as set
+# Copyright (c) 2008, Eric Florenzano
+# Copyright (c) 2010, 2011 Linaro Limited
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+# 
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of the author nor the names of other
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-from django import template
-from django.template import TOKEN_BLOCK
-from django.http import Http404
-from django.core.paginator import Paginator, InvalidPage
-from django.conf import settings
 
-register = template.Library()
+from django.conf import settings
+from django.core.exceptions import ImproperlyConfigured
+from django.core.paginator import Paginator, InvalidPage
+from django.http import Http404
+from django.template import (
+    Context,
+    Library,
+    Node,
+    TOKEN_BLOCK,
+    TemplateSyntaxError,
+    Variable,
+)
+from django.template.loader import select_template
 
-DEFAULT_PAGINATION = getattr(settings, 'PAGINATION_DEFAULT_PAGINATION', 20)
-DEFAULT_WINDOW = getattr(settings, 'PAGINATION_DEFAULT_WINDOW', 4)
-DEFAULT_MARGIN = getattr(settings, 'PAGINATION_DEFAULT_MARGIN', DEFAULT_WINDOW)
-DEFAULT_ORPHANS = getattr(settings, 'PAGINATION_DEFAULT_ORPHANS', 0)
-INVALID_PAGE_RAISES_404 = getattr(settings,
-    'PAGINATION_INVALID_PAGE_RAISES_404', False)
-DISPLAY_PAGE_LINKS = getattr(settings, 'PAGINATION_DISPLAY_PAGE_LINKS', True)
-PREVIOUS_LINK_DECORATOR = getattr(settings, 'PAGINATION_PREVIOUS_LINK_DECORATOR', "‹‹ ")
-NEXT_LINK_DECORATOR = getattr(settings, 'PAGINATION_NEXT_LINK_DECORATOR', " ››")
-DISPLAY_DISABLED_PREVIOUS_LINK = getattr(settings, 'PAGINATION_DISPLAY_DISABLED_PREVIOUS_LINK', False)
-DISPLAY_DISABLED_NEXT_LINK = getattr(settings, 'PAGINATION_DISPLAY_DISABLED_NEXT_LINK', False)
+# TODO, import this normally later on
+from linaro_django_pagination.settings import *
 
 
 def do_autopaginate(parser, token):
@@ -67,7 +90,7 @@ def do_autopaginate(parser, token):
     except StopIteration:
         pass
     if queryset_var is None:
-        raise template.TemplateSyntaxError(
+        raise TemplateSyntaxError(
             "Invalid syntax. Proper usage of this tag is: "
             "{%% autopaginate QUERYSET [PAGINATE_BY] [ORPHANS]"
             " [as CONTEXT_VAR_NAME] %%}"
@@ -75,7 +98,7 @@ def do_autopaginate(parser, token):
     return AutoPaginateNode(queryset_var, multiple_paginations, paginate_by, orphans, context_var)
 
 
-class AutoPaginateNode(template.Node):
+class AutoPaginateNode(Node):
     """
     Emits the required objects to allow for Digg-style pagination.
     
@@ -98,20 +121,20 @@ class AutoPaginateNode(template.Node):
             paginate_by = DEFAULT_PAGINATION
         if orphans is None:
             orphans = DEFAULT_ORPHANS
-        self.queryset_var = template.Variable(queryset_var)
+        self.queryset_var = Variable(queryset_var)
         if isinstance(paginate_by, int):
             self.paginate_by = paginate_by
         else:
-            self.paginate_by = template.Variable(paginate_by)
+            self.paginate_by = Variable(paginate_by)
         if isinstance(orphans, int):
             self.orphans = orphans
         else:
-            self.orphans = template.Variable(orphans)
+            self.orphans = Variable(orphans)
         self.context_var = context_var
         self.multiple_paginations = multiple_paginations
 
     def render(self, context):
-        if self.multiple_paginations or context.has_key('paginator'):
+        if self.multiple_paginations or "paginator" in context:
             page_suffix = '_%s' % self.queryset_var
         else:
             page_suffix = ''
@@ -128,7 +151,13 @@ class AutoPaginateNode(template.Node):
             orphans = self.orphans.resolve(context)
         paginator = Paginator(value, paginate_by, orphans)
         try:
-            page_obj = paginator.page(context['request'].page(page_suffix))
+            request = context['request']
+        except KeyError:
+            raise ImproperlyConfigured(
+                "You need to enable 'django.core.context_processors.request'."
+                " See linaro-django-pagination/README file for TEMPLATE_CONTEXT_PROCESSORS details")
+        try:
+            page_obj = paginator.page(request.page(page_suffix))
         except InvalidPage:
             if INVALID_PAGE_RAISES_404:
                 raise Http404('Invalid page requested.  If DEBUG were set to ' +
@@ -146,6 +175,41 @@ class AutoPaginateNode(template.Node):
         return u''
 
 
+class PaginateNode(Node):
+
+    def __init__(self, template=None):
+        self.template = template
+        
+    def render(self, context):
+        template_list = ['pagination/pagination.html']
+        to_return = paginate(context)
+        if self.template:
+            template_list.insert(0, self.template)
+        t = select_template(template_list)
+        if not t: 
+            return None
+        context = Context(to_return)
+        return t.render(context)
+        
+
+def do_paginate(parser, token):
+    """
+    {% paginate [using] [template] %}
+    
+    {% paginate %}
+    {% paginate using paginations/custom_pagination.html %}
+    """
+    argv = token.contents.split()
+    argc = len(argv)
+    if argc > 3:
+        raise TemplateSyntaxError("Tag %s takes at most 2 argument." % argv[0])
+    if argc == 1:
+        return PaginateNode()
+    if argc == 3 and argv[1] == 'using':
+        return PaginateNode(template=argv[2])
+    raise TemplateSyntaxError("Tag %s is invalid. Please check the syntax" % argv[0])
+
+
 def paginate(context, window=DEFAULT_WINDOW, margin=DEFAULT_MARGIN):
     """
     Renders the ``pagination/pagination.html`` template, resulting in a
@@ -170,10 +234,6 @@ def paginate(context, window=DEFAULT_WINDOW, margin=DEFAULT_MARGIN):
         A dictionary of all of the **GET** parameters in the current request.
         This is useful to maintain certain types of state, even when requesting
         a different page.
-    
-    ``pagination_template``
-        A custom template to include in place of the default ``pagination/default.html`` 
-        contents.
         
     Argument ``window`` is number to pages before/after current page. If window
     exceeds pagination border (1 and end), window is moved to left or right.
@@ -195,7 +255,6 @@ def paginate(context, window=DEFAULT_WINDOW, margin=DEFAULT_MARGIN):
         page_obj = context['page_obj']
         page_suffix = context.get('page_suffix', '')
         page_range = paginator.page_range
-        pagination_template = context.get('pagination_template', 'pagination/default.html')
         # Calculate the record range in the current page for display.
         records = {'first': 1 + (page_obj.number - 1) * paginator.per_page}
         records['last'] = records['first'] + paginator.per_page - 1
@@ -250,7 +309,6 @@ def paginate(context, window=DEFAULT_WINDOW, margin=DEFAULT_MARGIN):
             'page_obj': page_obj,
             'page_suffix': page_suffix,
             'pages': pages,
-            'pagination_template': pagination_template,
             'paginator': paginator,
             'previous_link_decorator': PREVIOUS_LINK_DECORATOR,
             'records': records,
@@ -268,7 +326,6 @@ def paginate(context, window=DEFAULT_WINDOW, margin=DEFAULT_MARGIN):
         return {}
 
 
-register.inclusion_tag(
-    'pagination/pagination.html', takes_context=True)(paginate)
-
+register = Library()
+register.tag('paginate', do_paginate)
 register.tag('autopaginate', do_autopaginate)