webhelpers: replaced paginate library with custom lib
dan -
r4091:4e2f3dca default
Not Reviewed
Show More
Add another comment
TODOs: 0 unresolved 0 Resolved
COMMENTS: 0 General 0 Inline
@@ -1829,7 +1829,6
1829 self."venusian"
1829 self."venusian"
1830 self."weberror"
1830 self."weberror"
1831 self."webhelpers2"
1831 self."webhelpers2"
1832 self."webhelpers"
1833 self."webob"
1832 self."webob"
1834 self."whoosh"
1833 self."whoosh"
1835 self."wsgiref"
1834 self."wsgiref"
@@ -2212,20 +2211,6
2212 license = [ pkgs.lib.licenses.mit ];
2211 license = [ pkgs.lib.licenses.mit ];
2213 };
2212 };
2214 };
2213 };
2215 "webhelpers" = super.buildPythonPackage {
2216 name = "webhelpers-1.3";
2217 doCheck = false;
2218 propagatedBuildInputs = [
2219 self."markupsafe"
2220 ];
2221 src = fetchurl {
2222 url = "https://files.pythonhosted.org/packages/ee/68/4d07672821d514184357f1552f2dad923324f597e722de3b016ca4f7844f/WebHelpers-1.3.tar.gz";
2223 sha256 = "10x5i82qdkrvyw18gsybwggfhfpl869siaab89vnndi9x62g51pa";
2224 };
2225 meta = {
2226 license = [ pkgs.lib.licenses.bsdOriginal ];
2227 };
2228 };
2229 "webhelpers2" = super.buildPythonPackage {
2214 "webhelpers2" = super.buildPythonPackage {
2230 name = "webhelpers2-2.0";
2215 name = "webhelpers2-2.0";
2231 doCheck = false;
2216 doCheck = false;
@@ -71,7 +71,6
71 venusian==1.2.0
71 venusian==1.2.0
72 weberror==0.10.3
72 weberror==0.10.3
73 webhelpers2==2.0
73 webhelpers2==2.0
74 webhelpers==1.3
75 webob==1.8.5
74 webob==1.8.5
76 whoosh==2.7.4
75 whoosh==2.7.4
77 wsgiref==0.1.2
76 wsgiref==0.1.2
@@ -28,7 +28,7
28 from rhodecode.lib.user_log_filter import user_log_filter
28 from rhodecode.lib.user_log_filter import user_log_filter
29 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
29 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
30 from rhodecode.lib.utils2 import safe_int
30 from rhodecode.lib.utils2 import safe_int
31 from rhodecode.lib.helpers import Page
31 from rhodecode.lib.helpers import SqlPage
32
32
33 log = logging.getLogger(__name__)
33 log = logging.getLogger(__name__)
34
34
@@ -62,13 +62,16
62
62
63 p = safe_int(self.request.GET.get('page', 1), 1)
63 p = safe_int(self.request.GET.get('page', 1), 1)
64
64
65 def url_generator(**kw):
65 def url_generator(page_num):
66 query_params = {
67 'page': page_num
68 }
66 if c.search_term:
69 if c.search_term:
67 kw['filter'] = c.search_term
70 query_params['filter'] = c.search_term
68 return self.request.current_route_path(_query=kw)
71 return self.request.current_route_path(_query=query_params)
69
72
70 c.audit_logs = Page(users_log, page=p, items_per_page=10,
73 c.audit_logs = SqlPage(users_log, page=p, items_per_page=10,
71 url=url_generator)
74 url_maker=url_generator)
72 return self._get_template_context(c)
75 return self._get_template_context(c)
73
76
74 @LoginRequired()
77 @LoginRequired()
@@ -44,6 +44,7
44 from rhodecode.lib.auth import (
44 from rhodecode.lib.auth import (
45 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
45 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
46 from rhodecode.lib import helpers as h
46 from rhodecode.lib import helpers as h
47 from rhodecode.lib.helpers import SqlPage
47 from rhodecode.lib.utils2 import safe_int, safe_unicode, AttributeDict
48 from rhodecode.lib.utils2 import safe_int, safe_unicode, AttributeDict
48 from rhodecode.model.auth_token import AuthTokenModel
49 from rhodecode.model.auth_token import AuthTokenModel
49 from rhodecode.model.forms import (
50 from rhodecode.model.forms import (
@@ -1228,13 +1229,16
1228 filter_term = self.request.GET.get('filter')
1229 filter_term = self.request.GET.get('filter')
1229 user_log = UserModel().get_user_log(c.user, filter_term)
1230 user_log = UserModel().get_user_log(c.user, filter_term)
1230
1231
1231 def url_generator(**kw):
1232 def url_generator(page_num):
1233 query_params = {
1234 'page': page_num
1235 }
1232 if filter_term:
1236 if filter_term:
1233 kw['filter'] = filter_term
1237 query_params['filter'] = filter_term
1234 return self.request.current_route_path(_query=kw)
1238 return self.request.current_route_path(_query=query_params)
1235
1239
1236 c.audit_logs = h.Page(
1240 c.audit_logs = SqlPage(
1237 user_log, page=p, items_per_page=10, url=url_generator)
1241 user_log, page=p, items_per_page=10, url_maker=url_generator)
1238 c.filter_term = filter_term
1242 c.filter_term = filter_term
1239 return self._get_template_context(c)
1243 return self._get_template_context(c)
1240
1244
@@ -34,7 +34,7
34 or_, joinedload, Repository, UserLog, UserFollowing, User, UserApiKeys)
34 or_, joinedload, Repository, UserLog, UserFollowing, User, UserApiKeys)
35 from rhodecode.model.meta import Session
35 from rhodecode.model.meta import Session
36 import rhodecode.lib.helpers as h
36 import rhodecode.lib.helpers as h
37 from rhodecode.lib.helpers import Page
37 from rhodecode.lib.helpers import SqlPage
38 from rhodecode.lib.user_log_filter import user_log_filter
38 from rhodecode.lib.user_log_filter import user_log_filter
39 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired, HasRepoPermissionAny
39 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired, HasRepoPermissionAny
40 from rhodecode.lib.utils2 import safe_int, AttributeDict, md5_safe
40 from rhodecode.lib.utils2 import safe_int, AttributeDict, md5_safe
@@ -232,15 +232,15
232
232
233 journal = self._get_journal_data(following, c.search_term)
233 journal = self._get_journal_data(following, c.search_term)
234
234
235 def url_generator(**kw):
235 def url_generator(page_num):
236 query_params = {
236 query_params = {
237 'page': page_num,
237 'filter': c.search_term
238 'filter': c.search_term
238 }
239 }
239 query_params.update(kw)
240 return self.request.current_route_path(_query=query_params)
240 return self.request.current_route_path(_query=query_params)
241
241
242 c.journal_pager = Page(
242 c.journal_pager = SqlPage(
243 journal, page=p, items_per_page=20, url=url_generator)
243 journal, page=p, items_per_page=20, url_maker=url_generator)
244 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
244 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
245
245
246 c.journal_data = render(
246 c.journal_data = render(
@@ -333,13 +333,14
333
333
334 journal = self._get_journal_data(c.following, c.search_term)
334 journal = self._get_journal_data(c.following, c.search_term)
335
335
336 def url_generator(**kw):
336 def url_generator(page_num):
337 query_params = {}
337 query_params = {
338 query_params.update(kw)
338 'page': page_num
339 }
339 return self.request.current_route_path(_query=query_params)
340 return self.request.current_route_path(_query=query_params)
340
341
341 c.journal_pager = Page(
342 c.journal_pager = SqlPage(
342 journal, page=p, items_per_page=20, url=url_generator)
343 journal, page=p, items_per_page=20, url_maker=url_generator)
343 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
344 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
344
345
345 c.journal_data = render(
346 c.journal_data = render(
@@ -28,7 +28,7
28 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired
28 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired
29
29
30 from rhodecode.lib import helpers as h
30 from rhodecode.lib import helpers as h
31 from rhodecode.lib.helpers import Page
31 from rhodecode.lib.helpers import SqlPage
32 from rhodecode.lib.utils2 import safe_int
32 from rhodecode.lib.utils2 import safe_int
33 from rhodecode.model.db import Notification
33 from rhodecode.model.db import Notification
34 from rhodecode.model.notification import NotificationModel
34 from rhodecode.model.notification import NotificationModel
@@ -74,13 +74,16
74
74
75 p = safe_int(self.request.GET.get('page', 1), 1)
75 p = safe_int(self.request.GET.get('page', 1), 1)
76
76
77 def url_generator(**kw):
77 def url_generator(page_num):
78 query_params = {
79 'page': page_num
80 }
78 _query = self.request.GET.mixed()
81 _query = self.request.GET.mixed()
79 _query.update(kw)
82 query_params.update(_query)
80 return self.request.current_route_path(_query=_query)
83 return self.request.current_route_path(_query=query_params)
81
84
82 c.notifications = Page(notifications, page=p, items_per_page=10,
85 c.notifications = SqlPage(notifications, page=p, items_per_page=10,
83 url=url_generator)
86 url_maker=url_generator)
84
87
85 c.unread_type = 'unread'
88 c.unread_type = 'unread'
86 c.all_type = 'all'
89 c.all_type = 'all'
@@ -22,6 +22,7
22 from pyramid.view import view_config
22 from pyramid.view import view_config
23
23
24 from rhodecode.apps._base import RepoAppView
24 from rhodecode.apps._base import RepoAppView
25 from rhodecode.lib.helpers import SqlPage
25 from rhodecode.lib import helpers as h
26 from rhodecode.lib import helpers as h
26 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
27 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
27 from rhodecode.lib.utils2 import safe_int
28 from rhodecode.lib.utils2 import safe_int
@@ -33,8 +34,6
33 class AuditLogsView(RepoAppView):
34 class AuditLogsView(RepoAppView):
34 def load_default_context(self):
35 def load_default_context(self):
35 c = self._get_local_tmpl_context()
36 c = self._get_local_tmpl_context()
36
37
38 return c
37 return c
39
38
40 @LoginRequired()
39 @LoginRequired()
@@ -54,12 +53,15
54 filter_term = self.request.GET.get('filter')
53 filter_term = self.request.GET.get('filter')
55 user_log = RepoModel().get_repo_log(c.db_repo, filter_term)
54 user_log = RepoModel().get_repo_log(c.db_repo, filter_term)
56
55
57 def url_generator(**kw):
56 def url_generator(page_num):
57 query_params = {
58 'page': page_num
59 }
58 if filter_term:
60 if filter_term:
59 kw['filter'] = filter_term
61 query_params['filter'] = filter_term
60 return self.request.current_route_path(_query=kw)
62 return self.request.current_route_path(_query=query_params)
61
63
62 c.audit_logs = h.Page(
64 c.audit_logs = SqlPage(
63 user_log, page=p, items_per_page=10, url=url_generator)
65 user_log, page=p, items_per_page=10, url_maker=url_generator)
64 c.filter_term = filter_term
66 c.filter_term = filter_term
65 return self._get_template_context(c)
67 return self._get_template_context(c)
@@ -121,9 +121,16
121 self, c, collection, page, chunk_size, branch_name=None,
121 self, c, collection, page, chunk_size, branch_name=None,
122 dynamic=False, f_path=None, commit_id=None):
122 dynamic=False, f_path=None, commit_id=None):
123
123
124 def url_generator(**kw):
124 def url_generator(page_num):
125 query_params = {}
125 query_params = {
126 query_params.update(kw)
126 'page': page_num
127 }
128
129 if branch_name:
130 query_params.update({
131 'branch': branch_name
132 })
133
127 if f_path:
134 if f_path:
128 # changelog for file
135 # changelog for file
129 return h.route_path(
136 return h.route_path(
@@ -139,8 +146,7
139 c.total_cs = len(collection)
146 c.total_cs = len(collection)
140 c.showing_commits = min(chunk_size, c.total_cs)
147 c.showing_commits = min(chunk_size, c.total_cs)
141 c.pagination = RepoPage(collection, page=page, item_count=c.total_cs,
148 c.pagination = RepoPage(collection, page=page, item_count=c.total_cs,
142 items_per_page=chunk_size, branch=branch_name,
149 items_per_page=chunk_size, url_maker=url_generator)
143 url=url_generator)
144
150
145 c.next_page = c.pagination.next_page
151 c.next_page = c.pagination.next_page
146 c.prev_page = c.pagination.previous_page
152 c.prev_page = c.pagination.previous_page
@@ -56,11 +56,11
56 p = safe_int(self.request.GET.get('page'), 1)
56 p = safe_int(self.request.GET.get('page'), 1)
57 size = safe_int(self.request.GET.get('size'), 10)
57 size = safe_int(self.request.GET.get('size'), 10)
58
58
59 def url_generator(**kw):
59 def url_generator(page_num):
60 query_params = {
60 query_params = {
61 'page': page_num,
61 'size': size
62 'size': size
62 }
63 }
63 query_params.update(kw)
64 return h.route_path(
64 return h.route_path(
65 'repo_summary_commits',
65 'repo_summary_commits',
66 repo_name=c.rhodecode_db_repo.repo_name, _query=query_params)
66 repo_name=c.rhodecode_db_repo.repo_name, _query=query_params)
@@ -73,7 +73,7
73 collection = self.rhodecode_vcs_repo
73 collection = self.rhodecode_vcs_repo
74
74
75 c.repo_commits = h.RepoPage(
75 c.repo_commits = h.RepoPage(
76 collection, page=p, items_per_page=size, url=url_generator)
76 collection, page=p, items_per_page=size, url_maker=url_generator)
77 page_ids = [x.raw_id for x in c.repo_commits]
77 page_ids = [x.raw_id for x in c.repo_commits]
78 c.comments = self.db_repo.get_comments(page_ids)
78 c.comments = self.db_repo.get_comments(page_ids)
79 c.statuses = self.db_repo.statuses(page_ids)
79 c.statuses = self.db_repo.statuses(page_ids)
@@ -59,11 +59,19
59 except validation_schema.Invalid as e:
59 except validation_schema.Invalid as e:
60 errors = e.children
60 errors = e.children
61
61
62 def url_generator(**kw):
62 def url_generator(page_num):
63 q = urllib.quote(safe_str(search_query))
63 q = urllib.quote(safe_str(search_query))
64 return update_params(
64
65 "?q=%s&type=%s&max_lines=%s&sort=%s" % (
65 query_params = {
66 q, safe_str(search_type), search_max_lines, search_sort), **kw)
66 'page': page_num,
67 'q': q,
68 'type': safe_str(search_type),
69 'max_lines': search_max_lines,
70 'sort': search_sort
71 }
72
73 return '?' + urllib.urlencode(query_params)
74
67
75
68 c = tmpl_context
76 c = tmpl_context
69 search_query = search_params.get('search_query')
77 search_query = search_params.get('search_query')
@@ -82,7 +90,7
82 formatted_results = Page(
90 formatted_results = Page(
83 search_result['results'], page=requested_page,
91 search_result['results'], page=requested_page,
84 item_count=search_result['count'],
92 item_count=search_result['count'],
85 items_per_page=page_limit, url=url_generator)
93 items_per_page=page_limit, url_maker=url_generator)
86 finally:
94 finally:
87 searcher.cleanup()
95 searcher.cleanup()
88
96
@@ -100,7 +108,6
100 c.perm_user = c.auth_user
108 c.perm_user = c.auth_user
101 c.repo_name = repo_name
109 c.repo_name = repo_name
102 c.repo_group_name = repo_group_name
110 c.repo_group_name = repo_group_name
103 c.url_generator = url_generator
104 c.errors = errors
111 c.errors = errors
105 c.formatted_results = formatted_results
112 c.formatted_results = formatted_results
106 c.runtime = execution_time
113 c.runtime = execution_time
@@ -27,11 +27,11
27 from rhodecode.integrations import integration_type_registry
27 from rhodecode.integrations import integration_type_registry
28 from rhodecode.apps._base import BaseAppView
28 from rhodecode.apps._base import BaseAppView
29 from rhodecode.apps._base.navigation import navigation_list
29 from rhodecode.apps._base.navigation import navigation_list
30 from rhodecode.lib.paginate import PageURL
31 from rhodecode.lib.auth import (
30 from rhodecode.lib.auth import (
32 LoginRequired, CSRFRequired, HasPermissionAnyDecorator,
31 LoginRequired, CSRFRequired, HasPermissionAnyDecorator,
33 HasRepoPermissionAnyDecorator, HasRepoGroupPermissionAnyDecorator)
32 HasRepoPermissionAnyDecorator, HasRepoGroupPermissionAnyDecorator)
34 from rhodecode.lib.utils2 import safe_int
33 from rhodecode.lib.utils2 import safe_int
34 from rhodecode.lib.helpers import Page
35 from rhodecode.lib import helpers as h
35 from rhodecode.lib import helpers as h
36 from rhodecode.model.db import Repository, RepoGroup, Session, Integration
36 from rhodecode.model.db import Repository, RepoGroup, Session, Integration
37 from rhodecode.model.scm import ScmModel
37 from rhodecode.model.scm import ScmModel
@@ -219,11 +219,16
219 key=lambda x: getattr(x[1], sort_field),
219 key=lambda x: getattr(x[1], sort_field),
220 reverse=(sort_dir == 'desc'))
220 reverse=(sort_dir == 'desc'))
221
221
222 page_url = PageURL(self.request.path, self.request.GET)
222 def url_generator(page_num):
223 query_params = {
224 'page': page_num
225 }
226 return self.request.current_route_path(_query=query_params)
227
223 page = safe_int(self.request.GET.get('page', 1), 1)
228 page = safe_int(self.request.GET.get('page', 1), 1)
224
229
225 integrations = h.Page(
230 integrations = Page(
226 integrations, page=page, items_per_page=10, url=page_url)
231 integrations, page=page, items_per_page=10, url_maker=url_generator)
227
232
228 c.rev_sort_dir = sort_dir != 'desc' and 'desc' or 'asc'
233 c.rev_sort_dir = sort_dir != 'desc' and 'desc' or 'asc'
229
234
@@ -75,7 +75,7
75 from webhelpers2.number import format_byte_size
75 from webhelpers2.number import format_byte_size
76
76
77 from rhodecode.lib.action_parser import action_parser
77 from rhodecode.lib.action_parser import action_parser
78 from rhodecode.lib.paginate import Page
78 from rhodecode.lib.pagination import Page, RepoPage, SqlPage
79 from rhodecode.lib.ext_json import json
79 from rhodecode.lib.ext_json import json
80 from rhodecode.lib.utils import repo_name_slug, get_custom_lexer
80 from rhodecode.lib.utils import repo_name_slug, get_custom_lexer
81 from rhodecode.lib.utils2 import (
81 from rhodecode.lib.utils2 import (
@@ -1309,94 +1309,6
1309 return initials_gravatar(email_address, '', '', size=size)
1309 return initials_gravatar(email_address, '', '', size=size)
1310
1310
1311
1311
1312
1313
1314 #==============================================================================
1315 # REPO PAGER, PAGER FOR REPOSITORY
1316 #==============================================================================
1317 class RepoPage(Page):
1318
1319 def __init__(self, collection, page=1, items_per_page=20,
1320 item_count=None, url=None, **kwargs):
1321
1322 """Create a "RepoPage" instance. special pager for paging
1323 repository
1324 """
1325 self._url_generator = url
1326
1327 # Safe the kwargs class-wide so they can be used in the pager() method
1328 self.kwargs = kwargs
1329
1330 # Save a reference to the collection
1331 self.original_collection = collection
1332
1333 self.collection = collection
1334
1335 # The self.page is the number of the current page.
1336 # The first page has the number 1!
1337 try:
1338 self.page = int(page) # make it int() if we get it as a string
1339 except (ValueError, TypeError):
1340 self.page = 1
1341
1342 self.items_per_page = items_per_page
1343
1344 # Unless the user tells us how many items the collections has
1345 # we calculate that ourselves.
1346 if item_count is not None:
1347 self.item_count = item_count
1348 else:
1349 self.item_count = len(self.collection)
1350
1351 # Compute the number of the first and last available page
1352 if self.item_count > 0:
1353 self.first_page = 1
1354 self.page_count = int(math.ceil(float(self.item_count) /
1355 self.items_per_page))
1356 self.last_page = self.first_page + self.page_count - 1
1357
1358 # Make sure that the requested page number is the range of
1359 # valid pages
1360 if self.page > self.last_page:
1361 self.page = self.last_page
1362 elif self.page < self.first_page:
1363 self.page = self.first_page
1364
1365 # Note: the number of items on this page can be less than
1366 # items_per_page if the last page is not full
1367 self.first_item = max(0, (self.item_count) - (self.page *
1368 items_per_page))
1369 self.last_item = ((self.item_count - 1) - items_per_page *
1370 (self.page - 1))
1371
1372 self.items = list(self.collection[self.first_item:self.last_item + 1])
1373
1374 # Links to previous and next page
1375 if self.page > self.first_page:
1376 self.previous_page = self.page - 1
1377 else:
1378 self.previous_page = None
1379
1380 if self.page < self.last_page:
1381 self.next_page = self.page + 1
1382 else:
1383 self.next_page = None
1384
1385 # No items available
1386 else:
1387 self.first_page = None
1388 self.page_count = 0
1389 self.last_page = None
1390 self.first_item = None
1391 self.last_item = None
1392 self.previous_page = None
1393 self.next_page = None
1394 self.items = []
1395
1396 # This is a subclass of the 'list' type. Initialise the list now.
1397 list.__init__(self, reversed(self.items))
1398
1399
1400 def breadcrumb_repo_link(repo):
1312 def breadcrumb_repo_link(repo):
1401 """
1313 """
1402 Makes a breadcrumbs path link to repo
1314 Makes a breadcrumbs path link to repo
This diff has been collapsed as it changes many lines, (1143 lines changed) Show them Hide them
@@ -1,5 +1,882
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (c) 2007-2012 Christoph Haas <email@christoph-haas.de>
4 # NOTE: MIT license based code, backported and edited by RhodeCode GmbH
5
6 """
7 paginate: helps split up large collections into individual pages
8 ================================================================
9
10 What is pagination?
11 ---------------------
12
13 This module helps split large lists of items into pages. The user is shown one page at a time and
14 can navigate to other pages. Imagine you are offering a company phonebook and let the user search
15 the entries. The entire search result may contains 23 entries but you want to display no more than
16 10 entries at once. The first page contains entries 1-10, the second 11-20 and the third 21-23.
17 Each "Page" instance represents the items of one of these three pages.
18
19 See the documentation of the "Page" class for more information.
20
21 How do I use it?
22 ------------------
23
24 A page of items is represented by the *Page* object. A *Page* gets initialized with these arguments:
25
26 - The collection of items to pick a range from. Usually just a list.
27 - The page number you want to display. Default is 1: the first page.
28
29 Now we can make up a collection and create a Page instance of it::
30
31 # Create a sample collection of 1000 items
32 >> my_collection = range(1000)
33
34 # Create a Page object for the 3rd page (20 items per page is the default)
35 >> my_page = Page(my_collection, page=3)
36
37 # The page object can be printed as a string to get its details
38 >> str(my_page)
39 Page:
40 Collection type: <type 'range'>
41 Current page: 3
42 First item: 41
43 Last item: 60
44 First page: 1
45 Last page: 50
46 Previous page: 2
47 Next page: 4
48 Items per page: 20
49 Number of items: 1000
50 Number of pages: 50
51
52 # Print a list of items on the current page
53 >> my_page.items
54 [40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59]
55
56 # The *Page* object can be used as an iterator:
57 >> for my_item in my_page: print(my_item)
58 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
59
60 # The .pager() method returns an HTML fragment with links to surrounding pages.
61 >> my_page.pager(url="http://example.org/foo/page=$page")
62
63 <a href="http://example.org/foo/page=1">1</a>
64 <a href="http://example.org/foo/page=2">2</a>
65 3
66 <a href="http://example.org/foo/page=4">4</a>
67 <a href="http://example.org/foo/page=5">5</a>
68 ..
69 <a href="http://example.org/foo/page=50">50</a>'
70
71 # Without the HTML it would just look like:
72 # 1 2 [3] 4 5 .. 50
73
74 # The pager can be customized:
75 >> my_page.pager('$link_previous ~3~ $link_next (Page $page of $page_count)',
76 url="http://example.org/foo/page=$page")
77
78 <a href="http://example.org/foo/page=2">&lt;</a>
79 <a href="http://example.org/foo/page=1">1</a>
80 <a href="http://example.org/foo/page=2">2</a>
81 3
82 <a href="http://example.org/foo/page=4">4</a>
83 <a href="http://example.org/foo/page=5">5</a>
84 <a href="http://example.org/foo/page=6">6</a>
85 ..
86 <a href="http://example.org/foo/page=50">50</a>
87 <a href="http://example.org/foo/page=4">&gt;</a>
88 (Page 3 of 50)
89
90 # Without the HTML it would just look like:
91 # 1 2 [3] 4 5 6 .. 50 > (Page 3 of 50)
92
93 # The url argument to the pager method can be omitted when an url_maker is
94 # given during instantiation:
95 >> my_page = Page(my_collection, page=3,
96 url_maker=lambda p: "http://example.org/%s" % p)
97 >> page.pager()
98
99 There are some interesting parameters that customize the Page's behavior. See the documentation on
100 ``Page`` and ``Page.pager()``.
101
102
103 Notes
104 -------
105
106 Page numbers and item numbers start at 1. This concept has been used because users expect that the
107 first page has number 1 and the first item on a page also has number 1. So if you want to use the
108 page's items by their index number please note that you have to subtract 1.
109 """
110
111 import re
112 import sys
113 from string import Template
114 from webhelpers2.html import literal
115
116 # are we running at least python 3.x ?
117 PY3 = sys.version_info[0] >= 3
118
119 if PY3:
120 unicode = str
121
122
123 def make_html_tag(tag, text=None, **params):
124 """Create an HTML tag string.
125
126 tag
127 The HTML tag to use (e.g. 'a', 'span' or 'div')
128
129 text
130 The text to enclose between opening and closing tag. If no text is specified then only
131 the opening tag is returned.
132
133 Example::
134 make_html_tag('a', text="Hello", href="/another/page")
135 -> <a href="/another/page">Hello</a>
136
137 To use reserved Python keywords like "class" as a parameter prepend it with
138 an underscore. Instead of "class='green'" use "_class='green'".
139
140 Warning: Quotes and apostrophes are not escaped."""
141 params_string = ""
142
143 # Parameters are passed. Turn the dict into a string like "a=1 b=2 c=3" string.
144 for key, value in sorted(params.items()):
145 # Strip off a leading underscore from the attribute's key to allow attributes like '_class'
146 # to be used as a CSS class specification instead of the reserved Python keyword 'class'.
147 key = key.lstrip("_")
148
149 params_string += u' {0}="{1}"'.format(key, value)
150
151 # Create the tag string
152 tag_string = u"<{0}{1}>".format(tag, params_string)
153
154 # Add text and closing tag if required.
155 if text:
156 tag_string += u"{0}</{1}>".format(text, tag)
157
158 return tag_string
159
160
161 # Since the items on a page are mainly a list we subclass the "list" type
162 class _Page(list):
163 """A list/iterator representing the items on one page of a larger collection.
164
165 An instance of the "Page" class is created from a _collection_ which is any
166 list-like object that allows random access to its elements.
167
168 The instance works as an iterator running from the first item to the last item on the given
169 page. The Page.pager() method creates a link list allowing the user to go to other pages.
170
171 A "Page" does not only carry the items on a certain page. It gives you additional information
172 about the page in these "Page" object attributes:
173
174 item_count
175 Number of items in the collection
176
177 **WARNING:** Unless you pass in an item_count, a count will be
178 performed on the collection every time a Page instance is created.
179
180 page
181 Number of the current page
182
183 items_per_page
184 Maximal number of items displayed on a page
185
186 first_page
187 Number of the first page - usually 1 :)
188
189 last_page
190 Number of the last page
191
192 previous_page
193 Number of the previous page. If this is the first page it returns None.
194
195 next_page
196 Number of the next page. If this is the last page it returns None.
197
198 page_count
199 Number of pages
200
201 items