diff --git a/rhodecode/apps/home/tests/test_home.py b/rhodecode/apps/home/tests/test_home.py
--- a/rhodecode/apps/home/tests/test_home.py
+++ b/rhodecode/apps/home/tests/test_home.py
@@ -123,5 +123,5 @@ class TestHomeController(TestController)
def test_logout_form_contains_csrf(self, autologin_user, csrf_token):
response = self.app.get(route_path('home'))
assert_response = response.assert_response()
- element = assert_response.get_element('.logout #csrf_token')
+ element = assert_response.get_element('.logout [name=csrf_token]')
assert element.value == csrf_token
diff --git a/rhodecode/apps/search/views.py b/rhodecode/apps/search/views.py
--- a/rhodecode/apps/search/views.py
+++ b/rhodecode/apps/search/views.py
@@ -21,7 +21,7 @@
import logging
import urllib
from pyramid.view import view_config
-from webhelpers.util import update_params
+from webhelpers2.html.tools import update_params
from rhodecode.apps._base import BaseAppView, RepoAppView, RepoGroupAppView
from rhodecode.lib.auth import (
diff --git a/rhodecode/integrations/views.py b/rhodecode/integrations/views.py
--- a/rhodecode/integrations/views.py
+++ b/rhodecode/integrations/views.py
@@ -21,13 +21,13 @@
import deform
import logging
import peppercorn
-import webhelpers.paginate
from pyramid.httpexceptions import HTTPFound, HTTPForbidden, HTTPNotFound
from rhodecode.integrations import integration_type_registry
from rhodecode.apps._base import BaseAppView
from rhodecode.apps._base.navigation import navigation_list
+from rhodecode.lib.paginate import PageURL
from rhodecode.lib.auth import (
LoginRequired, CSRFRequired, HasPermissionAnyDecorator,
HasRepoPermissionAnyDecorator, HasRepoGroupPermissionAnyDecorator)
@@ -219,8 +219,7 @@ class IntegrationSettingsViewBase(BaseAp
key=lambda x: getattr(x[1], sort_field),
reverse=(sort_dir == 'desc'))
- page_url = webhelpers.paginate.PageURL(
- self.request.path, self.request.GET)
+ page_url = PageURL(self.request.path, self.request.GET)
page = safe_int(self.request.GET.get('page', 1), 1)
integrations = h.Page(
diff --git a/rhodecode/lib/action_parser.py b/rhodecode/lib/action_parser.py
--- a/rhodecode/lib/action_parser.py
+++ b/rhodecode/lib/action_parser.py
@@ -20,8 +20,8 @@
import logging
-from webhelpers.html.builder import literal
-from webhelpers.html.tags import link_to
+from webhelpers2.html.builder import literal
+from webhelpers2.html.tags import link_to
from rhodecode.lib.utils2 import AttributeDict
from rhodecode.lib.vcs.backends.base import BaseCommit
diff --git a/rhodecode/lib/auth.py b/rhodecode/lib/auth.py
--- a/rhodecode/lib/auth.py
+++ b/rhodecode/lib/auth.py
@@ -1540,11 +1540,10 @@ class CSRFRequired(object):
http://en.wikipedia.org/wiki/Cross-site_request_forgery for more
information).
- For use with the ``webhelpers.secure_form`` helper functions.
+ For use with the ``secure_form`` helper functions.
"""
- def __init__(self, token=csrf_token_key, header='X-CSRF-Token',
- except_methods=None):
+ def __init__(self, token=csrf_token_key, header='X-CSRF-Token', except_methods=None):
self.token = token
self.header = header
self.except_methods = except_methods or []
diff --git a/rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py b/rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py
--- a/rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py
+++ b/rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py
@@ -2334,7 +2334,7 @@ class RepoGroup(Base, BaseModel):
@classmethod
def _generate_choice(cls, repo_group):
- from webhelpers.html import literal as _literal
+ from webhelpers2.html import literal as _literal
_name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
return repo_group.group_id, _name(repo_group.full_path_splitted)
diff --git a/rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py b/rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py
--- a/rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py
+++ b/rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py
@@ -2400,7 +2400,7 @@ class RepoGroup(Base, BaseModel):
@classmethod
def _generate_choice(cls, repo_group):
- from webhelpers.html import literal as _literal
+ from webhelpers2.html import literal as _literal
_name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
return repo_group.group_id, _name(repo_group.full_path_splitted)
diff --git a/rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py b/rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py
--- a/rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py
+++ b/rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py
@@ -2474,7 +2474,7 @@ class RepoGroup(Base, BaseModel):
@classmethod
def _generate_choice(cls, repo_group):
- from webhelpers.html import literal as _literal
+ from webhelpers2.html import literal as _literal
_name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
return repo_group.group_id, _name(repo_group.full_path_splitted)
diff --git a/rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py b/rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py
--- a/rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py
+++ b/rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py
@@ -2497,7 +2497,7 @@ class RepoGroup(Base, BaseModel):
@classmethod
def _generate_choice(cls, repo_group):
- from webhelpers.html import literal as _literal
+ from webhelpers2.html import literal as _literal
_name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
return repo_group.group_id, _name(repo_group.full_path_splitted)
diff --git a/rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py b/rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py
--- a/rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py
+++ b/rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py
@@ -2497,7 +2497,7 @@ class RepoGroup(Base, BaseModel):
@classmethod
def _generate_choice(cls, repo_group):
- from webhelpers.html import literal as _literal
+ from webhelpers2.html import literal as _literal
_name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
return repo_group.group_id, _name(repo_group.full_path_splitted)
diff --git a/rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py b/rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py
--- a/rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py
+++ b/rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py
@@ -52,7 +52,7 @@ from sqlalchemy.dialects.mysql import LO
from zope.cachedescriptors.property import Lazy as LazyProperty
from pyramid import compat
from pyramid.threadlocal import get_current_request
-from webhelpers.text import collapse, remove_formatting
+from webhelpers2.text import collapse, remove_formatting
from rhodecode.translation import _
from rhodecode.lib.vcs import get_vcs_instance
@@ -2624,7 +2624,7 @@ class RepoGroup(Base, BaseModel):
@classmethod
def _generate_choice(cls, repo_group):
- from webhelpers.html import literal as _literal
+ from webhelpers2.html import literal as _literal
_name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
return repo_group.group_id, _name(repo_group.full_path_splitted)
diff --git a/rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py b/rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py
--- a/rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py
+++ b/rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py
@@ -2037,7 +2037,7 @@ class RepoGroup(Base, BaseModel):
@classmethod
def _generate_choice(cls, repo_group):
- from webhelpers.html import literal as _literal
+ from webhelpers2.html import literal as _literal
_name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
return repo_group.group_id, _name(repo_group.full_path_splitted)
diff --git a/rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py b/rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py
--- a/rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py
+++ b/rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py
@@ -2029,7 +2029,7 @@ class RepoGroup(Base, BaseModel):
@classmethod
def _generate_choice(cls, repo_group):
- from webhelpers.html import literal as _literal
+ from webhelpers2.html import literal as _literal
_name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
return repo_group.group_id, _name(repo_group.full_path_splitted)
diff --git a/rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py b/rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py
--- a/rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py
+++ b/rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py
@@ -2028,7 +2028,7 @@ class RepoGroup(Base, BaseModel):
@classmethod
def _generate_choice(cls, repo_group):
- from webhelpers.html import literal as _literal
+ from webhelpers2.html import literal as _literal
_name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
return repo_group.group_id, _name(repo_group.full_path_splitted)
diff --git a/rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py b/rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py
--- a/rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py
+++ b/rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py
@@ -2032,7 +2032,7 @@ class RepoGroup(Base, BaseModel):
@classmethod
def _generate_choice(cls, repo_group):
- from webhelpers.html import literal as _literal
+ from webhelpers2.html import literal as _literal
_name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
return repo_group.group_id, _name(repo_group.full_path_splitted)
diff --git a/rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py b/rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py
--- a/rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py
+++ b/rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py
@@ -2032,7 +2032,7 @@ class RepoGroup(Base, BaseModel):
@classmethod
def _generate_choice(cls, repo_group):
- from webhelpers.html import literal as _literal
+ from webhelpers2.html import literal as _literal
_name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
return repo_group.group_id, _name(repo_group.full_path_splitted)
diff --git a/rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py b/rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py
--- a/rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py
+++ b/rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py
@@ -2076,7 +2076,7 @@ class RepoGroup(Base, BaseModel):
@classmethod
def _generate_choice(cls, repo_group):
- from webhelpers.html import literal as _literal
+ from webhelpers2.html import literal as _literal
_name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
return repo_group.group_id, _name(repo_group.full_path_splitted)
diff --git a/rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py b/rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py
--- a/rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py
+++ b/rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py
@@ -2077,7 +2077,7 @@ class RepoGroup(Base, BaseModel):
@classmethod
def _generate_choice(cls, repo_group):
- from webhelpers.html import literal as _literal
+ from webhelpers2.html import literal as _literal
_name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
return repo_group.group_id, _name(repo_group.full_path_splitted)
diff --git a/rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py b/rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py
--- a/rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py
+++ b/rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py
@@ -2270,7 +2270,7 @@ class RepoGroup(Base, BaseModel):
@classmethod
def _generate_choice(cls, repo_group):
- from webhelpers.html import literal as _literal
+ from webhelpers2.html import literal as _literal
_name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
return repo_group.group_id, _name(repo_group.full_path_splitted)
diff --git a/rhodecode/lib/helpers.py b/rhodecode/lib/helpers.py
--- a/rhodecode/lib/helpers.py
+++ b/rhodecode/lib/helpers.py
@@ -53,25 +53,29 @@ from pygments.lexers import (
from pyramid.threadlocal import get_current_request
-from webhelpers.html import literal, HTML, escape
-from webhelpers.html.tools import *
-from webhelpers.html.builder import make_tag
-from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
- end_form, file, form as wh_form, hidden, image, javascript_link, link_to, \
- link_to_if, link_to_unless, ol, required_legend, select, stylesheet_link, \
- submit, text, password, textarea, title, ul, xml_declaration, radio
-from webhelpers.html.tools import auto_link, button_to, highlight, \
- js_obfuscate, mail_to, strip_links, strip_tags, tag_re
-from webhelpers.text import chop_at, collapse, convert_accented_entities, \
- 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
+from webhelpers2.html import literal, HTML, escape
+from webhelpers2.html._autolink import _auto_link_urls
+from webhelpers2.html.tools import (
+ button_to, highlight, js_obfuscate, strip_links, strip_tags)
+
+from webhelpers2.text import (
+ chop_at, collapse, convert_accented_entities,
+ convert_misc_entities, lchop, plural, rchop, remove_formatting,
+ replace_whitespace, urlify, truncate, wrap_paragraphs)
+from webhelpers2.date import time_ago_in_words
+
+from webhelpers2.html.tags import (
+ _input, NotGiven, _make_safe_id_component as safeid,
+ form as insecure_form,
+ auto_discovery_link, checkbox, end_form, file,
+ hidden, image, javascript_link, link_to, link_to_if, link_to_unless, ol,
+ select as raw_select, stylesheet_link, submit, text, password, textarea,
+ ul, radio, Options)
+
from webhelpers2.number import format_byte_size
from rhodecode.lib.action_parser import action_parser
+from rhodecode.lib.paginate import Page
from rhodecode.lib.ext_json import json
from rhodecode.lib.utils import repo_name_slug, get_custom_lexer
from rhodecode.lib.utils2 import (
@@ -162,17 +166,42 @@ def shorter(text, size=20, prefix=False)
return text
-def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
+def reset(name, value=None, id=NotGiven, type="reset", **attrs):
"""
Reset button
"""
- _set_input_attrs(attrs, type, name, value)
- _set_id_attr(attrs, id, name)
- convert_boolean_attrs(attrs, ["disabled"])
- return HTML.input(**attrs)
+ return _input(type, name, value, id, attrs)
+
+
+def select(name, selected_values, options, id=NotGiven, **attrs):
-reset = _reset
-safeid = _make_safe_id_component
+ if isinstance(options, (list, tuple)):
+ options_iter = options
+ # Handle old value,label lists ... where value also can be value,label lists
+ options = Options()
+ for opt in options_iter:
+ if isinstance(opt, tuple) and len(opt) == 2:
+ value, label = opt
+ elif isinstance(opt, basestring):
+ value = label = opt
+ else:
+ raise ValueError('invalid select option type %r' % type(opt))
+
+ if isinstance(value, (list, tuple)):
+ option_group = options.add_optgroup(label)
+ for opt2 in value:
+ if isinstance(opt2, tuple) and len(opt2) == 2:
+ group_value, group_label = opt
+ elif isinstance(opt2, basestring):
+ group_value = group_label = opt2
+ else:
+ raise ValueError('invalid select option type %r' % type(opt2))
+
+ option_group.add_option(group_label, group_value)
+ else:
+ options.add_option(label, value)
+
+ return raw_select(name, selected_values, options, id=id, **attrs)
def branding(name, length=40):
@@ -1280,145 +1309,6 @@ def gravatar_url(email_address, size=30,
return initials_gravatar(email_address, '', '', size=size)
-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('' % (_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={'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)
#==============================================================================
@@ -1564,11 +1454,9 @@ def format_byte_size_binary(file_size):
return formatted_size
-def urlify_text(text_, safe=True):
+def urlify_text(text_, safe=True, **href_attrs):
"""
- Extrac urls from text and make html links out of them
-
- :param text_:
+ Extract urls from text and make html links out of them
"""
url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@#.&+]'''
@@ -1576,8 +1464,13 @@ def urlify_text(text_, safe=True):
def url_func(match_obj):
url_full = match_obj.groups()[0]
- return '%(url)s' % ({'url': url_full})
+ a_options = dict(href_attrs)
+ a_options['href'] = url_full
+ a_text = url_full
+ return HTML.tag("a", a_text, **a_options)
+
_new_text = url_pat.sub(url_func, text_)
+
if safe:
return literal(_new_text)
return _new_text
@@ -1939,7 +1832,7 @@ def form(url, method='post', needs_csrf_
'CSRF token. If the endpoint does not require such token you can ' +
'explicitly set the parameter needs_csrf_token to false.')
- return wh_form(url, method=method, **attrs)
+ return insecure_form(url, method=method, **attrs)
def secure_form(form_url, method="POST", multipart=False, **attrs):
@@ -1961,7 +1854,6 @@ def secure_form(form_url, method="POST",
over POST.
"""
- from webhelpers.pylonslib.secure_form import insecure_form
if 'request' in attrs:
session = attrs['request'].session
@@ -1970,12 +1862,12 @@ def secure_form(form_url, method="POST",
raise ValueError(
'Calling this form requires request= to be passed as argument')
- form = insecure_form(form_url, method, multipart, **attrs)
+ _form = insecure_form(form_url, method, multipart, **attrs)
token = literal(
- ''.format(
- csrf_token_key, csrf_token_key, get_csrf_token(session)))
+ ''.format(
+ csrf_token_key, get_csrf_token(session)))
- return literal("%s\n%s" % (form, token))
+ return literal("%s\n%s" % (_form, token))
def dropdownmenu(name, selected, options, enable_filter=False, **attrs):
diff --git a/rhodecode/lib/paginate.py b/rhodecode/lib/paginate.py
new file mode 100644
--- /dev/null
+++ b/rhodecode/lib/paginate.py
@@ -0,0 +1,165 @@
+# -*- 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 .
+#
+# 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('' % (_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={'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)
diff --git a/rhodecode/lib/utils.py b/rhodecode/lib/utils.py
--- a/rhodecode/lib/utils.py
+++ b/rhodecode/lib/utils.py
@@ -39,7 +39,7 @@ from os.path import join as jn
import paste
import pkg_resources
-from webhelpers.text import collapse, remove_formatting, strip_tags
+from webhelpers2.text import collapse, remove_formatting
from mako import exceptions
from pyramid.threadlocal import get_current_registry
from rhodecode.lib.request import Request
diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py
--- a/rhodecode/model/db.py
+++ b/rhodecode/model/db.py
@@ -52,7 +52,7 @@ from sqlalchemy.dialects.mysql import LO
from zope.cachedescriptors.property import Lazy as LazyProperty
from pyramid import compat
from pyramid.threadlocal import get_current_request
-from webhelpers.text import collapse, remove_formatting
+from webhelpers2.text import remove_formatting
from rhodecode.translation import _
from rhodecode.lib.vcs import get_vcs_instance
@@ -2675,7 +2675,7 @@ class RepoGroup(Base, BaseModel):
@classmethod
def _generate_choice(cls, repo_group):
- from webhelpers.html import literal as _literal
+ from webhelpers2.html import literal as _literal
_name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
return repo_group.group_id, _name(repo_group.full_path_splitted)
diff --git a/rhodecode/tests/lib/test_helpers.py b/rhodecode/tests/lib/test_helpers.py
--- a/rhodecode/tests/lib/test_helpers.py
+++ b/rhodecode/tests/lib/test_helpers.py
@@ -29,11 +29,14 @@ from rhodecode.tests import no_newline_i
@pytest.mark.parametrize('url, expected_url', [
- ('http://rc.rc/test', 'http://rc.rc/test'),
- ('http://rc.rc/@foo', 'http://rc.rc/@foo'),
- ('http://rc.rc/!foo', 'http://rc.rc/!foo'),
- ('http://rc.rc/&foo', 'http://rc.rc/&foo'),
- ('http://rc.rc/#foo', 'http://rc.rc/#foo'),
+ ('http://rc.com', 'http://rc.com'),
+ ('http://rc.com/test', 'http://rc.com/test'),
+ ('http://rc.com/!foo', 'http://rc.com/!foo'),
+ ('http://rc.com/&foo', 'http://rc.com/&foo'),
+ ('http://rc.com/?foo-1&bar=1', 'http://rc.com/?foo-1&bar=1'),
+ ('http://rc.com?foo-1&bar=1', 'http://rc.com?foo-1&bar=1'),
+ ('http://rc.com/#foo', 'http://rc.com/#foo'),
+ ('http://rc.com/@foo', 'http://rc.com/@foo'),
])
def test_urlify_text(url, expected_url):
assert helpers.urlify_text(url) == expected_url
diff --git a/rhodecode/tests/load/profile-mem.py b/rhodecode/tests/load/profile-mem.py
--- a/rhodecode/tests/load/profile-mem.py
+++ b/rhodecode/tests/load/profile-mem.py
@@ -43,7 +43,7 @@ import psutil
import logging
import socket
-from webhelpers.number import format_byte_size
+from webhelpers2.number import format_byte_size
logging.basicConfig(level=logging.DEBUG)