diff --git a/kallithea/controllers/admin/admin.py b/kallithea/controllers/admin/admin.py
--- a/kallithea/controllers/admin/admin.py
+++ b/kallithea/controllers/admin/admin.py
@@ -41,7 +41,7 @@ from kallithea.lib.auth import LoginRequ
from kallithea.lib.base import BaseController, render
from kallithea.lib.utils2 import safe_int, remove_prefix, remove_suffix
from kallithea.lib.indexers import JOURNAL_SCHEMA
-from kallithea.lib.helpers import Page
+from kallithea.lib.page import Page
log = logging.getLogger(__name__)
diff --git a/kallithea/controllers/admin/gists.py b/kallithea/controllers/admin/gists.py
--- a/kallithea/controllers/admin/gists.py
+++ b/kallithea/controllers/admin/gists.py
@@ -44,7 +44,7 @@ from kallithea.lib.base import BaseContr
from kallithea.lib.auth import LoginRequired, NotAnonymous
from kallithea.lib.utils import jsonify
from kallithea.lib.utils2 import safe_int, safe_unicode, time_to_datetime
-from kallithea.lib.helpers import Page
+from kallithea.lib.page import Page
from sqlalchemy.sql.expression import or_
from kallithea.lib.vcs.exceptions import VCSError, NodeNotChangedError
diff --git a/kallithea/controllers/admin/notifications.py b/kallithea/controllers/admin/notifications.py
--- a/kallithea/controllers/admin/notifications.py
+++ b/kallithea/controllers/admin/notifications.py
@@ -38,7 +38,7 @@ from kallithea.model.meta import Session
from kallithea.lib.auth import LoginRequired, NotAnonymous
from kallithea.lib.base import BaseController, render
from kallithea.lib import helpers as h
-from kallithea.lib.helpers import Page
+from kallithea.lib.page import Page
from kallithea.lib.utils2 import safe_int
diff --git a/kallithea/controllers/changelog.py b/kallithea/controllers/changelog.py
--- a/kallithea/controllers/changelog.py
+++ b/kallithea/controllers/changelog.py
@@ -36,9 +36,9 @@ import kallithea.lib.helpers as h
from kallithea.config.routing import url
from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
from kallithea.lib.base import BaseRepoController, render
-from kallithea.lib.helpers import RepoPage
from kallithea.lib.compat import json
from kallithea.lib.graphmod import graph_data
+from kallithea.lib.page import RepoPage
from kallithea.lib.vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
ChangesetError, NodeDoesNotExistError, EmptyRepositoryError
from kallithea.lib.utils2 import safe_int, safe_str
diff --git a/kallithea/controllers/followers.py b/kallithea/controllers/followers.py
--- a/kallithea/controllers/followers.py
+++ b/kallithea/controllers/followers.py
@@ -29,11 +29,11 @@ import logging
from pylons import tmpl_context as c, request
-from kallithea.lib.helpers import Page
from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
from kallithea.lib.base import BaseRepoController, render
+from kallithea.lib.page import Page
+from kallithea.lib.utils2 import safe_int
from kallithea.model.db import UserFollowing
-from kallithea.lib.utils2 import safe_int
log = logging.getLogger(__name__)
diff --git a/kallithea/controllers/forks.py b/kallithea/controllers/forks.py
--- a/kallithea/controllers/forks.py
+++ b/kallithea/controllers/forks.py
@@ -37,15 +37,15 @@ from webob.exc import HTTPFound
import kallithea.lib.helpers as h
from kallithea.config.routing import url
-from kallithea.lib.helpers import Page
from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \
NotAnonymous, HasRepoPermissionAny, HasPermissionAnyDecorator, HasPermissionAny
from kallithea.lib.base import BaseRepoController, render
+from kallithea.lib.page import Page
+from kallithea.lib.utils2 import safe_int
from kallithea.model.db import Repository, UserFollowing, User, Ui
from kallithea.model.repo import RepoModel
from kallithea.model.forms import RepoForkForm
from kallithea.model.scm import ScmModel, AvailableRepoGroupChoices
-from kallithea.lib.utils2 import safe_int
log = logging.getLogger(__name__)
diff --git a/kallithea/controllers/journal.py b/kallithea/controllers/journal.py
--- a/kallithea/controllers/journal.py
+++ b/kallithea/controllers/journal.py
@@ -46,11 +46,11 @@ from kallithea.model.db import UserLog,
from kallithea.model.meta import Session
from kallithea.model.repo import RepoModel
import kallithea.lib.helpers as h
-from kallithea.lib.helpers import Page
from kallithea.lib.auth import LoginRequired, NotAnonymous
from kallithea.lib.base import BaseController, render
+from kallithea.lib.compat import json
+from kallithea.lib.page import Page
from kallithea.lib.utils2 import safe_int, AttributeDict
-from kallithea.lib.compat import json
log = logging.getLogger(__name__)
diff --git a/kallithea/controllers/pullrequests.py b/kallithea/controllers/pullrequests.py
--- a/kallithea/controllers/pullrequests.py
+++ b/kallithea/controllers/pullrequests.py
@@ -35,19 +35,19 @@ from pylons.i18n.translation import _
from webob.exc import HTTPFound, HTTPNotFound, HTTPForbidden, HTTPBadRequest
from kallithea.config.routing import url
-from kallithea.lib.vcs.utils.hgcompat import unionrepo
-from kallithea.lib.compat import json, OrderedDict
-from kallithea.lib.base import BaseRepoController, render
+from kallithea.lib import helpers as h
+from kallithea.lib import diffs
from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \
NotAnonymous
-from kallithea.lib.helpers import Page
-from kallithea.lib import helpers as h
-from kallithea.lib import diffs
+from kallithea.lib.base import BaseRepoController, render
+from kallithea.lib.compat import json, OrderedDict
+from kallithea.lib.diffs import LimitedDiffContainer
from kallithea.lib.exceptions import UserInvalidException
+from kallithea.lib.page import Page
from kallithea.lib.utils import action_logger, jsonify
+from kallithea.lib.vcs.exceptions import EmptyRepositoryError, ChangesetDoesNotExistError
from kallithea.lib.vcs.utils import safe_str
-from kallithea.lib.vcs.exceptions import EmptyRepositoryError, ChangesetDoesNotExistError
-from kallithea.lib.diffs import LimitedDiffContainer
+from kallithea.lib.vcs.utils.hgcompat import unionrepo
from kallithea.model.db import PullRequest, ChangesetStatus, ChangesetComment, \
PullRequestReviewers, User
from kallithea.model.pull_request import PullRequestModel
diff --git a/kallithea/controllers/search.py b/kallithea/controllers/search.py
--- a/kallithea/controllers/search.py
+++ b/kallithea/controllers/search.py
@@ -40,9 +40,9 @@ from kallithea.lib.auth import LoginRequ
from kallithea.lib.base import BaseRepoController, render
from kallithea.lib.indexers import CHGSETS_SCHEMA, SCHEMA, CHGSET_IDX_NAME, \
IDX_NAME, WhooshResultWrapper
-from kallithea.model.repo import RepoModel
+from kallithea.lib.page import Page
from kallithea.lib.utils2 import safe_str, safe_int
-from kallithea.lib.helpers import Page
+from kallithea.model.repo import RepoModel
log = logging.getLogger(__name__)
diff --git a/kallithea/lib/helpers.py b/kallithea/lib/helpers.py
--- a/kallithea/lib/helpers.py
+++ b/kallithea/lib/helpers.py
@@ -19,7 +19,6 @@ available to Controllers. This module is
"""
import hashlib
import StringIO
-import math
import logging
import re
import urlparse
@@ -47,7 +46,6 @@ from webhelpers.text import chop_at, col
convert_misc_entities, lchop, plural, rchop, remove_formatting, \
replace_whitespace, urlify, truncate, wrap_paragraphs
from webhelpers.date import time_ago_in_words
-from webhelpers.paginate import Page as _Page
from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
convert_boolean_attrs, NotGiven, _make_safe_id_component
@@ -885,234 +883,6 @@ def gravatar_url(email_address, size=30,
.replace('{size}', safe_str(size))
return url
-class Page(_Page):
- """
- Custom pager to match rendering style with YUI paginator
- """
-
- 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(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):
- # 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.span(c=text_, **self.curpage_attr)
- nav_items.append(text_)
- # Otherwise create just a link to that page
- else:
- 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))
-
- #_page_link = url.current()
- #nav_items.append(literal('' % (_page_link, str(int(self.page)+1))))
- #nav_items.append(literal('' % (_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=None,
- curpage_attr=None,
- dotdot_attr=None, **kwargs):
- self.curpage_attr = curpage_attr or {'class': 'pager_curpage'}
- 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': self.previous_page and \
- self._pagerlink(self.previous_page, symbol_previous) \
- or HTML.span(symbol_previous, class_="yui-pg-previous"),
- 'link_next': self.next_page and \
- self._pagerlink(self.next_page, symbol_next) \
- or HTML.span(symbol_next, class_="yui-pg-next")
- })
-
- return literal(result)
-
-
-#==============================================================================
-# REPO PAGER, PAGER FOR REPOSITORY
-#==============================================================================
-class RepoPage(Page):
-
- def __init__(self, collection, page=1, items_per_page=20,
- item_count=None, **kwargs):
-
- """Create a "RepoPage" instance. special pager for paging
- repository
- """
- # TODO: call baseclass __init__
- self._url_generator = kwargs.pop('url', url.current)
-
- # Safe the kwargs class-wide so they can be used in the pager() method
- self.kwargs = kwargs
-
- # Save a reference to the collection
- self.original_collection = collection
-
- self.collection = collection
-
- # The self.page is the number of the current page.
- # The first page has the number 1!
- try:
- self.page = int(page) # make it int() if we get it as a string
- except (ValueError, TypeError):
- self.page = 1
-
- self.items_per_page = items_per_page
-
- # Unless the user tells us how many items the collections has
- # we calculate that ourselves.
- if item_count is not None:
- self.item_count = item_count
- else:
- self.item_count = len(self.collection)
-
- # Compute the number of the first and last available page
- if self.item_count > 0:
- self.first_page = 1
- self.page_count = int(math.ceil(float(self.item_count) /
- self.items_per_page))
- self.last_page = self.first_page + self.page_count - 1
-
- # Make sure that the requested page number is the range of
- # valid pages
- if self.page > self.last_page:
- self.page = self.last_page
- elif self.page < self.first_page:
- self.page = self.first_page
-
- # Note: the number of items on this page can be less than
- # items_per_page if the last page is not full
- self.first_item = max(0, (self.item_count) - (self.page *
- items_per_page))
- self.last_item = ((self.item_count - 1) - items_per_page *
- (self.page - 1))
-
- self.items = list(self.collection[self.first_item:self.last_item + 1])
-
- # Links to previous and next page
- if self.page > self.first_page:
- self.previous_page = self.page - 1
- else:
- self.previous_page = None
-
- if self.page < self.last_page:
- self.next_page = self.page + 1
- else:
- self.next_page = None
-
- # No items available
- else:
- self.first_page = None
- self.page_count = 0
- self.last_page = None
- self.first_item = None
- self.last_item = None
- self.previous_page = None
- self.next_page = None
- self.items = []
-
- # This is a subclass of the 'list' type. Initialise the list now.
- list.__init__(self, reversed(self.items))
-
def changed_tooltip(nodes):
"""
diff --git a/kallithea/lib/page.py b/kallithea/lib/page.py
new file mode 100644
--- /dev/null
+++ b/kallithea/lib/page.py
@@ -0,0 +1,247 @@
+# -*- 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 .
+"""
+Custom paging classes
+"""
+
+import math
+import re
+from kallithea.config.routing import url
+from webhelpers.html import literal, HTML
+from webhelpers.paginate import Page as _Page
+
+class Page(_Page):
+ """
+ Custom pager to match rendering style with YUI paginator
+ """
+
+ 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(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):
+ # 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.span(c=text_, **self.curpage_attr)
+ nav_items.append(text_)
+ # Otherwise create just a link to that page
+ else:
+ 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))
+
+ #_page_link = url.current()
+ #nav_items.append(literal('' % (_page_link, str(int(self.page)+1))))
+ #nav_items.append(literal('' % (_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=None,
+ curpage_attr=None,
+ dotdot_attr=None, **kwargs):
+ self.curpage_attr = curpage_attr or {'class': 'pager_curpage'}
+ 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': self.previous_page and \
+ self._pagerlink(self.previous_page, symbol_previous) \
+ or HTML.span(symbol_previous, class_="yui-pg-previous"),
+ 'link_next': self.next_page and \
+ self._pagerlink(self.next_page, symbol_next) \
+ or HTML.span(symbol_next, class_="yui-pg-next")
+ })
+
+ return literal(result)
+
+
+class RepoPage(Page):
+
+ def __init__(self, collection, page=1, items_per_page=20,
+ item_count=None, **kwargs):
+
+ """Create a "RepoPage" instance. special pager for paging
+ repository
+ """
+ # TODO: call baseclass __init__
+ self._url_generator = kwargs.pop('url', url.current)
+
+ # Safe the kwargs class-wide so they can be used in the pager() method
+ self.kwargs = kwargs
+
+ # Save a reference to the collection
+ self.original_collection = collection
+
+ self.collection = collection
+
+ # The self.page is the number of the current page.
+ # The first page has the number 1!
+ try:
+ self.page = int(page) # make it int() if we get it as a string
+ except (ValueError, TypeError):
+ self.page = 1
+
+ self.items_per_page = items_per_page
+
+ # Unless the user tells us how many items the collections has
+ # we calculate that ourselves.
+ if item_count is not None:
+ self.item_count = item_count
+ else:
+ self.item_count = len(self.collection)
+
+ # Compute the number of the first and last available page
+ if self.item_count > 0:
+ self.first_page = 1
+ self.page_count = int(math.ceil(float(self.item_count) /
+ self.items_per_page))
+ self.last_page = self.first_page + self.page_count - 1
+
+ # Make sure that the requested page number is the range of
+ # valid pages
+ if self.page > self.last_page:
+ self.page = self.last_page
+ elif self.page < self.first_page:
+ self.page = self.first_page
+
+ # Note: the number of items on this page can be less than
+ # items_per_page if the last page is not full
+ self.first_item = max(0, (self.item_count) - (self.page *
+ items_per_page))
+ self.last_item = ((self.item_count - 1) - items_per_page *
+ (self.page - 1))
+
+ self.items = list(self.collection[self.first_item:self.last_item + 1])
+
+ # Links to previous and next page
+ if self.page > self.first_page:
+ self.previous_page = self.page - 1
+ else:
+ self.previous_page = None
+
+ if self.page < self.last_page:
+ self.next_page = self.page + 1
+ else:
+ self.next_page = None
+
+ # No items available
+ else:
+ self.first_page = None
+ self.page_count = 0
+ self.last_page = None
+ self.first_item = None
+ self.last_item = None
+ self.previous_page = None
+ self.next_page = None
+ self.items = []
+
+ # This is a subclass of the 'list' type. Initialise the list now.
+ list.__init__(self, reversed(self.items))