@@ -10,389 +10,390 @@ from pygments import highlight as code_h
from pylons import url, app_globals as g
from pylons.i18n.translation import _, ungettext
from vcs.utils.annotate import annotate_highlight
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, 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.number import format_byte_size, format_bit_size
from webhelpers.pylonslib import Flash as _Flash
from webhelpers.pylonslib.secure_form import secure_form
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.html.tags import _set_input_attrs, _set_id_attr, \
convert_boolean_attrs, NotGiven
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)
reset = _reset
def get_token():
"""Return the current authentication token, creating one if one doesn't
already exist.
token_key = "_authentication_token"
from pylons import session
if not token_key in session:
try:
token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
except AttributeError: # Python < 2.4
token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
session[token_key] = token
if hasattr(session, 'save'):
session.save()
return session[token_key]
class _GetError(object):
"""Get error from form_errors, and represent it as span wrapped error
message
:param field_name: field to fetch errors for
:param form_errors: form errors dict
def __call__(self, field_name, form_errors):
tmpl = """<span class="error_msg">%s</span>"""
if form_errors and form_errors.has_key(field_name):
return literal(tmpl % form_errors.get(field_name))
get_error = _GetError()
def recursive_replace(str, replace=' '):
"""Recursive replace of given sign to just one instance
:param str: given string
:param replace: char to find and replace multiple instances
Examples::
>>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
'Mighty-Mighty-Bo-sstones'
if str.find(replace * 2) == -1:
return str
else:
str = str.replace(replace * 2, replace)
return recursive_replace(str, replace)
class _ToolTip(object):
def __call__(self, tooltip_title, trim_at=50):
"""Special function just to wrap our text into nice formatted
autowrapped text
:param tooltip_title:
return wrap_paragraphs(escape(tooltip_title), trim_at)\
.replace('\n', '<br/>')
def activate(self):
"""Adds tooltip mechanism to the given Html all tooltips have to have
set class `tooltip` and set attribute `tooltip_title`.
Then a tooltip will be generated based on that. All with yui js tooltip
js = '''
YAHOO.util.Event.onDOMReady(function(){
function toolTipsId(){
var ids = [];
var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
for (var i = 0; i < tts.length; i++) {
//if element doesn't not have and id autogenerate one for tooltip
if (!tts[i].id){
tts[i].id='tt'+i*100;
}
ids.push(tts[i].id);
return ids
};
var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
context: toolTipsId(),
monitorresize:false,
xyoffset :[0,0],
autodismissdelay:300000,
hidedelay:5,
showdelay:20,
});
// Set the text for the tooltip just before we display it. Lazy method
myToolTips.contextTriggerEvent.subscribe(
function(type, args) {
var context = args[0];
//positioning of tooltip
var tt_w = this.element.clientWidth;//tooltip width
var tt_h = this.element.clientHeight;//tooltip height
var context_w = context.offsetWidth;
var context_h = context.offsetHeight;
var pos_x = YAHOO.util.Dom.getX(context);
var pos_y = YAHOO.util.Dom.getY(context);
var display_strategy = 'right';
var xy_pos = [0,0];
switch (display_strategy){
case 'top':
var cur_x = (pos_x+context_w/2)-(tt_w/2);
var cur_y = (pos_y-tt_h-4);
xy_pos = [cur_x,cur_y];
break;
case 'bottom':
var cur_y = pos_y+context_h+4;
case 'left':
var cur_x = (pos_x-tt_w-4);
var cur_y = pos_y-((tt_h/2)-context_h/2);
case 'right':
var cur_x = (pos_x+context_w+4);
default:
var cur_y = pos_y-tt_h-4;
this.cfg.setProperty("xy",xy_pos);
//Mouse out
myToolTips.contextMouseOutEvent.subscribe(
'''
return literal(js)
tooltip = _ToolTip()
class _FilesBreadCrumbs(object):
def __call__(self, repo_name, rev, paths):
if isinstance(paths, str):
paths = paths.decode('utf-8')
url_l = [link_to(repo_name, url('files_home',
repo_name=repo_name,
revision=rev, f_path=''))]
paths_l = paths.split('/')
for cnt, p in enumerate(paths_l):
if p != '':
url_l.append(link_to(p, url('files_home',
revision=rev,
f_path='/'.join(paths_l[:cnt + 1]))))
return literal('/'.join(url_l))
files_breadcrumbs = _FilesBreadCrumbs()
class CodeHtmlFormatter(HtmlFormatter):
def wrap(self, source, outfile):
return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
def _wrap_code(self, source):
for cnt, it in enumerate(source):
i, t = it
t = '<div id="#S-%s">%s</div>' % (cnt + 1, t)
yield i, t
def pygmentize(filenode, **kwargs):
"""pygmentize function using pygments
:param filenode:
return literal(code_highlight(filenode.content,
filenode.lexer, CodeHtmlFormatter(**kwargs)))
def pygmentize_annotation(filenode, **kwargs):
"""pygmentize function for annotation
color_dict = {}
def gen_color(n=10000):
"""generator for getting n of evenly distributed colors using
hsv color and golden ratio. It always return same order of colors
:returns: RGB tuple
import colorsys
golden_ratio = 0.618033988749895
h = 0.22717784590367374
for c in xrange(n):
h += golden_ratio
h %= 1
HSV_tuple = [h, 0.95, 0.95]
RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple)
yield map(lambda x:str(int(x * 256)), RGB_tuple)
cgenerator = gen_color()
def get_color_string(cs):
if color_dict.has_key(cs):
col = color_dict[cs]
col = color_dict[cs] = cgenerator.next()
return "color: rgb(%s)! important;" % (', '.join(col))
def url_func(changeset):
tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \
" %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
tooltip_html = tooltip_html % (changeset.author,
changeset.date,
tooltip(changeset.message))
lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
short_id(changeset.raw_id))
uri = link_to(
lnk_format,
url('changeset_home', repo_name=changeset.repository.name,
revision=changeset.raw_id),
style=get_color_string(changeset.raw_id),
class_='tooltip',
title=tooltip_html
)
uri += '\n'
return uri
return literal(annotate_highlight(filenode, url_func, **kwargs))
def repo_name_slug(value):
"""Return slug of name of repository
This function is called on each creation/modification
of repository to prevent bad names in repo
slug = remove_formatting(value)
slug = strip_tags(slug)
for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
slug = slug.replace(c, '-')
slug = recursive_replace(slug, '-')
slug = collapse(slug, '-')
return slug
def get_changeset_safe(repo, rev):
from vcs.backends.base import BaseRepository
from vcs.exceptions import RepositoryError
if not isinstance(repo, BaseRepository):
raise Exception('You must pass an Repository '
'object as first argument got %s', type(repo))
cs = repo.get_changeset(rev)
except RepositoryError:
from rhodecode.lib.utils import EmptyChangeset
cs = EmptyChangeset()
return cs
flash = _Flash()
#==============================================================================
# MERCURIAL FILTERS available via h.
from mercurial import util
from mercurial.templatefilters import person as _person
def _age(curdate):
"""turns a datetime into an age string."""
if not curdate:
return ''
from datetime import timedelta, datetime
agescales = [("year", 3600 * 24 * 365),
("month", 3600 * 24 * 30),
("day", 3600 * 24),
("hour", 3600),
("minute", 60),
("second", 1), ]
age = datetime.now() - curdate
age_seconds = (age.days * agescales[2][1]) + age.seconds
pos = 1
for scale in agescales:
if scale[1] <= age_seconds:
if pos == 6:pos = 5
return time_ago_in_words(curdate, agescales[pos][0]) + ' ' + _('ago')
pos += 1
return _('just now')
age = lambda x:_age(x)
capitalize = lambda x: x.capitalize()
email = util.email
email_or_none = lambda x: util.email(x) if util.email(x) != x else None
person = lambda x: _person(x)
short_id = lambda x: x[:12]
def bool2icon(value):
"""Returns True/False values represented as small html image of true/false
icons
:param value: bool value
if value is True:
return HTML.tag('img', src="/images/icons/accept.png", alt=_('True'))
if value is False:
return HTML.tag('img', src="/images/icons/cancel.png", alt=_('False'))
return value
def action_parser(user_log):
"""This helper will map the specified string action into translated
fancy names with icons and links
:param user_log: user log instance
action = user_log.action
action_params = ' '
x = action.split(':')
if len(x) > 1:
action, action_params = x
def get_cs_links():
revs_limit = 5 #display this amount always
revs_top_limit = 50 #show upto this amount of changesets hidden
Status change: