X-Git-Url: https://git.mdrn.pl/django-pagination.git/blobdiff_plain/86caf150984733eb5a0bb07af26cd8fc0a8d8496..abf535d21fd19b257e5d6fecfd60e470cc12de7f:/linaro_django_pagination/templatetags/pagination_tags.py diff --git a/linaro_django_pagination/templatetags/pagination_tags.py b/linaro_django_pagination/templatetags/pagination_tags.py deleted file mode 100644 index f106942..0000000 --- a/linaro_django_pagination/templatetags/pagination_tags.py +++ /dev/null @@ -1,346 +0,0 @@ -# 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.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, - TemplateSyntaxError, - Variable, - loader, -) - -try: - from django.template.base import TOKEN_BLOCK -except ImportError: # Django < 1.8 - from django.template import TOKEN_BLOCK - -from django.template.loader import select_template -from django.utils.text import unescape_string_literal - -# TODO, import this normally later on -from linaro_django_pagination.settings import * - - -def do_autopaginate(parser, token): - """ - Splits the arguments to the autopaginate tag and formats them correctly. - - Syntax is: - - autopaginate QUERYSET [PAGINATE_BY] [ORPHANS] [as NAME] - """ - # Check whether there are any other autopaginations are later in this template - expr = lambda obj: (obj.token_type == TOKEN_BLOCK and \ - len(obj.split_contents()) > 0 and obj.split_contents()[0] == "autopaginate") - multiple_paginations = len([tok for tok in parser.tokens if expr(tok)]) > 0 - - i = iter(token.split_contents()) - paginate_by = None - queryset_var = None - context_var = None - orphans = None - word = None - try: - word = next(i) - assert word == "autopaginate" - queryset_var = next(i) - word = next(i) - if word != "as": - paginate_by = word - try: - paginate_by = int(paginate_by) - except ValueError: - pass - word = next(i) - if word != "as": - orphans = word - try: - orphans = int(orphans) - except ValueError: - pass - word = next(i) - assert word == "as" - context_var = next(i) - except StopIteration: - pass - if queryset_var is None: - raise TemplateSyntaxError( - "Invalid syntax. Proper usage of this tag is: " - "{% autopaginate QUERYSET [PAGINATE_BY] [ORPHANS]" - " [as CONTEXT_VAR_NAME] %}") - return AutoPaginateNode(queryset_var, multiple_paginations, paginate_by, orphans, context_var) - - -class AutoPaginateNode(Node): - """ - Emits the required objects to allow for Digg-style pagination. - - First, it looks in the current context for the variable specified, and using - that object, it emits a simple ``Paginator`` and the current page object - into the context names ``paginator`` and ``page_obj``, respectively. - - It will then replace the variable specified with only the objects for the - current page. - - .. note:: - - It is recommended to use *{% paginate %}* after using the autopaginate - tag. If you choose not to use *{% paginate %}*, make sure to display the - list of available pages, or else the application may seem to be buggy. - """ - def __init__(self, queryset_var, multiple_paginations, paginate_by=None, - orphans=None, context_var=None): - if paginate_by is None: - paginate_by = DEFAULT_PAGINATION - if orphans is None: - orphans = DEFAULT_ORPHANS - self.queryset_var = Variable(queryset_var) - if isinstance(paginate_by, int): - self.paginate_by = paginate_by - else: - self.paginate_by = Variable(paginate_by) - if isinstance(orphans, int): - self.orphans = orphans - else: - self.orphans = Variable(orphans) - self.context_var = context_var - self.multiple_paginations = multiple_paginations - - def render(self, context): - # Save multiple_paginations state in context - if self.multiple_paginations and 'multiple_paginations' not in context: - context['multiple_paginations'] = True - - if context.get('multiple_paginations') or getattr(context, "paginator", None): - page_suffix = '_%s' % self.queryset_var - else: - page_suffix = '' - - key = self.queryset_var.var - value = self.queryset_var.resolve(context) - if isinstance(self.paginate_by, int): - paginate_by = self.paginate_by - else: - paginate_by = self.paginate_by.resolve(context) - if isinstance(self.orphans, int): - orphans = self.orphans - else: - orphans = self.orphans.resolve(context) - paginator = Paginator(value, paginate_by, orphans) - try: - 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 ' + - 'False, an HTTP 404 page would have been shown instead.') - context[key] = [] - context['invalid_page'] = True - return '' - if self.context_var is not None: - context[self.context_var] = page_obj.object_list - else: - context[key] = page_obj.object_list - context['paginator'] = paginator - context['page_obj'] = page_obj - context['page_suffix'] = page_suffix - return '' - - -class PaginateNode(Node): - - def __init__(self, template=None): - self.template = template - - def render(self, context): - template_list = ['pagination/pagination.html'] - new_context = paginate(context) - if self.template: - template_list.insert(0, self.template) - return loader.render_to_string(template_list, new_context, - context_instance = context) - - - -def do_paginate(parser, token): - """ - Emits the pagination control for the most recent autopaginate list - - Syntax is: - - paginate [using "TEMPLATE"] - - Where TEMPLATE is a quoted template name. If missing the default template - is used (paginate/pagination.html). - """ - argv = token.split_contents() - argc = len(argv) - if argc == 1: - template = None - elif argc == 3 and argv[1] == 'using': - template = unescape_string_literal(argv[2]) - else: - raise TemplateSyntaxError( - "Invalid syntax. Proper usage of this tag is: " - "{% paginate [using \"TEMPLATE\"] %}") - return PaginateNode(template) - - -def paginate(context, window=DEFAULT_WINDOW, margin=DEFAULT_MARGIN): - """ - Renders the ``pagination/pagination.html`` template, resulting in a - Digg-like display of the available pages, given the current page. If there - are too many pages to be displayed before and after the current page, then - elipses will be used to indicate the undisplayed gap between page numbers. - - Requires one argument, ``context``, which should be a dictionary-like data - structure and must contain the following keys: - - ``paginator`` - A ``Paginator`` or ``QuerySetPaginator`` object. - - ``page_obj`` - This should be the result of calling the page method on the - aforementioned ``Paginator`` or ``QuerySetPaginator`` object, given - the current page. - - This same ``context`` dictionary-like data structure may also include: - - ``getvars`` - 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. - - 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. - - Argument ``margin``` is number of pages on start/end of pagination. - Example: - window=2, margin=1, current=6 1 ... 4 5 [6] 7 8 ... 11 - window=2, margin=0, current=1 [1] 2 3 4 5 ... - window=2, margin=0, current=5 ... 3 4 [5] 6 7 ... - window=2, margin=0, current=11 ... 7 8 9 10 [11] - """ - - if window < 0: - raise ValueError('Parameter "window" cannot be less than zero') - if margin < 0: - raise ValueError('Parameter "margin" cannot be less than zero') - try: - paginator = context['paginator'] - page_obj = context['page_obj'] - page_suffix = context.get('page_suffix', '') - page_range = list(paginator.page_range) - # 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 - if records['last'] + paginator.orphans >= paginator.count: - records['last'] = paginator.count - - # figure window - window_start = page_obj.number - window - 1 - window_end = page_obj.number + window - - # solve if window exceeded page range - if window_start < 0: - window_end = window_end - window_start - window_start = 0 - if window_end > paginator.num_pages: - window_start = max(0, window_start - (window_end - paginator.num_pages)) - window_end = paginator.num_pages - pages = page_range[window_start:window_end] - - # figure margin and add elipses - if margin > 0: - # figure margin - tmp_pages = set(pages) - tmp_pages = tmp_pages.union(page_range[:margin]) - tmp_pages = tmp_pages.union(page_range[-margin:]) - tmp_pages = list(tmp_pages) - tmp_pages.sort() - pages = [] - pages.append(tmp_pages[0]) - for i in range(1, len(tmp_pages)): - # figure gap size => add elipses or fill in gap - gap = tmp_pages[i] - tmp_pages[i - 1] - if gap >= 3: - pages.append(None) - elif gap == 2: - pages.append(tmp_pages[i] - 1) - pages.append(tmp_pages[i]) - else: - if pages[0] != 1: - pages.insert(0, None) - if pages[-1] != paginator.num_pages: - pages.append(None) - - new_context = { - 'MEDIA_URL': settings.MEDIA_URL, - 'STATIC_URL': getattr(settings, "STATIC_URL", None), - 'disable_link_for_first_page': DISABLE_LINK_FOR_FIRST_PAGE, - 'display_disabled_next_link': DISPLAY_DISABLED_NEXT_LINK, - 'display_disabled_previous_link': DISPLAY_DISABLED_PREVIOUS_LINK, - 'display_page_links': DISPLAY_PAGE_LINKS, - 'is_paginated': paginator.count > paginator.per_page, - 'next_link_decorator': NEXT_LINK_DECORATOR, - 'page_obj': page_obj, - 'page_suffix': page_suffix, - 'pages': pages, - 'paginator': paginator, - 'previous_link_decorator': PREVIOUS_LINK_DECORATOR, - 'records': records, - } - if 'request' in context: - getvars = context['request'].GET.copy() - if 'page%s' % page_suffix in getvars: - del getvars['page%s' % page_suffix] - if len(getvars.keys()) > 0: - new_context['getvars'] = "&%s" % getvars.urlencode() - else: - new_context['getvars'] = '' - return new_context - except (KeyError, AttributeError): - return {} - - -register = Library() -register.tag('paginate', do_paginate) -register.tag('autopaginate', do_autopaginate)