1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 | import re
from django import template
from django.http import QueryDict
ADJACENT = 3
CAPS = 1
RE_URL = re.compile('(.*)1(.*)')
register = template.Library()
def page_separator(current, count, adjacent=ADJACENT, caps=CAPS):
if current < adjacent + 1:
adjacent += adjacent - current + 1
elif count - current < adjacent:
adjacent += adjacent - (count - current)
bits = []
if current > (1 + adjacent + caps):
if caps:
bits.append(range(1, caps+1))
start = current - adjacent
else:
start = 1
if current + adjacent < count - caps:
end = current + adjacent
else:
end = count
bits.append(range(start, end+1))
if end != count:
if caps:
bits.append(range(count-caps+1, count+1))
return bits
def get_page_context(page, url_func, adjacent, caps):
if not page:
return {}
current = page.number
count = page.paginator.num_pages
if count < 2:
return {}
pages = []
for page_group in page_separator(current, count, adjacent, caps):
group = []
for number in page_group:
url = url_func(number)
if not url:
return {}
group.append({'url': url, 'number': number,
'current': page.number==number})
pages.append(group)
c = {'pages': pages}
if current > 1:
c['previous_url'] = url_func(current-1)
if current < count:
c['next_url'] = url_func(current+1)
return c
@register.inclusion_tag('pagination-nav.html')
def pagination_nav(page, url, first_page_url=None, adjacent=ADJACENT, caps=CAPS):
"""
Generate Digg-like pagination navigation for URLs like "/entries/page/5/".
Required arguments:
page
A ``django.core.paginator`` ``Page`` object
url
An example URL to navigate to page 1 (the last character ``"1"`` in the
URL gets replaced with the actual page number)
Optional arguments:
first_page_url
An alternate first page exact URL
adjacent
The minimum number of pages to show either side of the current page
(defaults to ``3``)
caps
The number of pages to show at either end (defaults to ``1``)
"""
def make_url(number):
if number == 1 and first_page_url:
return first_page_url
match = RE_URL.match(url)
if not match:
raise template.TemplateSyntaxError(
'URL did not contain the character "1" (which gets replaced with '
'the actual page number).'
)
start, end = match.groups()
return '%s%s%s' % (start, number, end)
return get_page_context(page, make_url, adjacent, caps)
@register.inclusion_tag('pagination-nav.html')
def pagination_nav_qs(page, url='', querydict=None, url_attr='page',
adjacent=ADJACENT, caps=CAPS):
"""
Generate Digg-like pagination navigation for URLs like "/entries/?page=5".
Required arguments:
page
A django.core.paginator Page object
Optional arguments:
url
The base url (defaults to a blank string)
querydict
Usually ``request.GET`` (defaults to an empty ``QueryDict``)
url_attr
The querystring attribute to change (defaults to ``'page'``)
adjacent
The minimum number of pages to show either side of the current page
(defaults to ``3``)
caps
The number of pages to show at either end (defaults to ``1``)
"""
querydict = querydict or QueryDict('')
def make_url(number):
qs = querydict.copy()
if number == 1:
qs.pop(url_attr, None)
else:
qs[url_attr] = number
qs = qs.urlencode()
if qs:
qs = '?%s' % qs
if not url and not qs:
return '.'
return '%s%s' % (url or '', qs)
return get_page_context(page, make_url, adjacent, caps)
|
Comments