|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
# Copyright (C) 2010-2019 RhodeCode GmbH
|
|
|
#
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
# it under the terms of the GNU Affero General Public License, version 3
|
|
|
# (only), as published by the Free Software Foundation.
|
|
|
#
|
|
|
# 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 Affero General Public License
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
#
|
|
|
# This program is dual-licensed. If you wish to learn more about the
|
|
|
# RhodeCode Enterprise Edition, including its added features, Support services,
|
|
|
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
|
|
import re
|
|
|
|
|
|
from webhelpers.paginate import Page as _Page
|
|
|
from webhelpers.paginate import PageURL
|
|
|
from webhelpers2.html import literal, HTML
|
|
|
|
|
|
|
|
|
class Page(_Page):
|
|
|
"""
|
|
|
Custom pager to match rendering style with paginator
|
|
|
"""
|
|
|
|
|
|
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(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(text)
|
|
|
|
|
|
for thispage in xrange(leftmost_page, rightmost_page + 1):
|
|
|
# Hilight the current page number and do not use a link
|
|
|
if thispage == self.page:
|
|
|
text = '%s' % (thispage,)
|
|
|
# Wrap in a SPAN tag if nolink_attr is set
|
|
|
if self.curpage_attr:
|
|
|
text = HTML.span(c=text, **self.curpage_attr)
|
|
|
nav_items.append(text)
|
|
|
# Otherwise create just a link to that page
|
|
|
else:
|
|
|
text = '%s' % (thispage,)
|
|
|
nav_items.append(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(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(self._pagerlink(self.last_page, self.last_page))
|
|
|
|
|
|
## prerender links
|
|
|
#_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='~2~', page_param='page', partial_param='partial',
|
|
|
show_if_single_page=False, separator=' ', onclick=None,
|
|
|
symbol_first='<<', symbol_last='>>',
|
|
|
symbol_previous='<', symbol_next='>',
|
|
|
link_attr={'class': 'pager_link', 'rel': 'prerender'},
|
|
|
curpage_attr={'class': 'pager_curpage'},
|
|
|
dotdot_attr={'class': 'pager_dotdot'}, **kwargs):
|
|
|
|
|
|
self.curpage_attr = curpage_attr
|
|
|
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
|
|
|
self.dotdot_attr = dotdot_attr
|
|
|
|
|
|
# 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': self.previous_page and \
|
|
|
self._pagerlink(self.previous_page, symbol_previous) \
|
|
|
or HTML.span(symbol_previous, class_="pg-previous disabled"),
|
|
|
'link_next': self.next_page and \
|
|
|
self._pagerlink(self.next_page, symbol_next) \
|
|
|
or HTML.span(symbol_next, class_="pg-next disabled")
|
|
|
})
|
|
|
|
|
|
return literal(result)
|
|
|
|