Files
@ r7855:3936f5cc4c58
Branch filter:
Location: public/kallithea/kallithea/lib/page.py
r7855:3936f5cc4c58
6.7 KiB
text/x-python
page: replace RepoPage with Page given the reverse collection
That seems to be all RepoPage did ...
We must still take care to make sure the collection works correctly, even when
filtered so indices might be higher than repo length. vcs module takes care of
that by internally creating a list of hashes (which it can reverse), while the
Changeset instances are only created on demand. We can save some resources by
not retrieving the whole list of Changesets just to reverse it so we can use a
few entries.
That seems to be all RepoPage did ...
We must still take care to make sure the collection works correctly, even when
filtered so indices might be higher than repo length. vcs module takes care of
that by internally creating a list of hashes (which it can reverse), while the
Changeset instances are only created on demand. We can save some resources by
not retrieving the whole list of Changesets just to reverse it so we can use a
few entries.
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 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | # -*- coding: utf-8 -*-
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Custom paging classes
"""
import logging
import re
from webhelpers2.html import HTML, literal
from webhelpers.paginate import Page as _Page
from kallithea.config.routing import url
log = logging.getLogger(__name__)
class Page(_Page):
"""
Custom pager emitting Bootstrap paginators
"""
def __init__(self, *args, **kwargs):
kwargs.setdefault('url', url.current)
_Page.__init__(self, *args, **kwargs)
def _get_pos(self, cur_page, max_page, items):
edge = (items / 2) + 1
if (cur_page <= edge):
radius = max(items / 2, items - cur_page)
elif (max_page - cur_page) < edge:
radius = (items - 1) - (max_page - cur_page)
else:
radius = items / 2
left = max(1, (cur_page - (radius)))
right = min(max_page, cur_page + (radius))
return left, cur_page, right
def _range(self, regexp_match):
"""
Return range of linked pages (e.g. '1 2 [3] 4 5 6 7 8').
Arguments:
regexp_match
A "re" (regular expressions) match object containing the
radius of linked pages around the current page in
regexp_match.group(1) as a string
This function is supposed to be called as a callable in
re.sub.
"""
radius = int(regexp_match.group(1))
# Compute the first and last page number within the radius
# e.g. '1 .. 5 6 [7] 8 9 .. 12'
# -> leftmost_page = 5
# -> rightmost_page = 9
leftmost_page, _cur, rightmost_page = self._get_pos(self.page,
self.last_page,
(radius * 2) + 1)
nav_items = []
# Create a link to the first page (unless we are on the first page
# or there would be no need to insert '..' spacers)
if self.page != self.first_page and self.first_page < leftmost_page:
nav_items.append(HTML.li(self._pagerlink(self.first_page, self.first_page)))
# Insert dots if there are pages between the first page
# and the currently displayed page range
if leftmost_page - self.first_page > 1:
# Wrap in a SPAN tag if nolink_attr is set
text_ = '..'
if self.dotdot_attr:
text_ = HTML.span(c=text_, **self.dotdot_attr)
nav_items.append(HTML.li(text_))
for thispage in xrange(leftmost_page, rightmost_page + 1):
# Highlight the current page number and do not use a link
text_ = str(thispage)
if thispage == self.page:
# Wrap in a SPAN tag if nolink_attr is set
if self.curpage_attr:
text_ = HTML.li(HTML.span(c=text_), **self.curpage_attr)
nav_items.append(text_)
# Otherwise create just a link to that page
else:
nav_items.append(HTML.li(self._pagerlink(thispage, text_)))
# Insert dots if there are pages between the displayed
# page numbers and the end of the page range
if self.last_page - rightmost_page > 1:
text_ = '..'
# Wrap in a SPAN tag if nolink_attr is set
if self.dotdot_attr:
text_ = HTML.span(c=text_, **self.dotdot_attr)
nav_items.append(HTML.li(text_))
# Create a link to the very last page (unless we are on the last
# page or there would be no need to insert '..' spacers)
if self.page != self.last_page and rightmost_page < self.last_page:
nav_items.append(HTML.li(self._pagerlink(self.last_page, self.last_page)))
#_page_link = url.current()
#nav_items.append(literal('<link rel="prerender" href="%s?page=%s">' % (_page_link, str(int(self.page)+1))))
#nav_items.append(literal('<link rel="prefetch" href="%s?page=%s">' % (_page_link, str(int(self.page)+1))))
return self.separator.join(nav_items)
def pager(self, format='<ul class="pagination">$link_previous ~2~ $link_next</ul>', page_param='page', partial_param='partial',
show_if_single_page=False, separator=' ', onclick=None,
symbol_first='<<', symbol_last='>>',
symbol_previous='<', symbol_next='>',
link_attr=None,
curpage_attr=None,
dotdot_attr=None, **kwargs
):
self.curpage_attr = curpage_attr or {'class': 'active'}
self.separator = separator
self.pager_kwargs = kwargs
self.page_param = page_param
self.partial_param = partial_param
self.onclick = onclick
self.link_attr = link_attr or {'class': 'pager_link', 'rel': 'prerender'}
self.dotdot_attr = dotdot_attr or {'class': 'pager_dotdot'}
# Don't show navigator if there is no more than one page
if self.page_count == 0 or (self.page_count == 1 and not show_if_single_page):
return ''
from string import Template
# Replace ~...~ in token format by range of pages
result = re.sub(r'~(\d+)~', self._range, format)
# Interpolate '%' variables
result = Template(result).safe_substitute({
'first_page': self.first_page,
'last_page': self.last_page,
'page': self.page,
'page_count': self.page_count,
'items_per_page': self.items_per_page,
'first_item': self.first_item,
'last_item': self.last_item,
'item_count': self.item_count,
'link_first': self.page > self.first_page and
self._pagerlink(self.first_page, symbol_first) or '',
'link_last': self.page < self.last_page and
self._pagerlink(self.last_page, symbol_last) or '',
'link_previous': HTML.li(self.previous_page and
self._pagerlink(self.previous_page, symbol_previous)
or HTML.a(symbol_previous)),
'link_next': HTML.li(self.next_page and
self._pagerlink(self.next_page, symbol_next)
or HTML.a(symbol_next)),
})
return literal(result)
|