##// END OF EJS Templates
#107 added single line highlight
marcink -
r965:5da1286d beta
parent child Browse files
Show More
@@ -1,528 +1,528 b''
1 """Helper functions
1 """Helper functions
2
2
3 Consists of functions to typically be used within templates, but also
3 Consists of functions to typically be used within templates, but also
4 available to Controllers. This module is available to both as 'h'.
4 available to Controllers. This module is available to both as 'h'.
5 """
5 """
6 import random
6 import random
7 import hashlib
7 import hashlib
8 from pygments.formatters import HtmlFormatter
8 from pygments.formatters import HtmlFormatter
9 from pygments import highlight as code_highlight
9 from pygments import highlight as code_highlight
10 from pylons import url, app_globals as g
10 from pylons import url, app_globals as g
11 from pylons.i18n.translation import _, ungettext
11 from pylons.i18n.translation import _, ungettext
12 from vcs.utils.annotate import annotate_highlight
12 from vcs.utils.annotate import annotate_highlight
13 from webhelpers.html import literal, HTML, escape
13 from webhelpers.html import literal, HTML, escape
14 from webhelpers.html.tools import *
14 from webhelpers.html.tools import *
15 from webhelpers.html.builder import make_tag
15 from webhelpers.html.builder import make_tag
16 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
16 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
17 end_form, file, form, hidden, image, javascript_link, link_to, link_to_if, \
17 end_form, file, form, hidden, image, javascript_link, link_to, link_to_if, \
18 link_to_unless, ol, required_legend, select, stylesheet_link, submit, text, \
18 link_to_unless, ol, required_legend, select, stylesheet_link, submit, text, \
19 password, textarea, title, ul, xml_declaration, radio
19 password, textarea, title, ul, xml_declaration, radio
20 from webhelpers.html.tools import auto_link, button_to, highlight, js_obfuscate, \
20 from webhelpers.html.tools import auto_link, button_to, highlight, js_obfuscate, \
21 mail_to, strip_links, strip_tags, tag_re
21 mail_to, strip_links, strip_tags, tag_re
22 from webhelpers.number import format_byte_size, format_bit_size
22 from webhelpers.number import format_byte_size, format_bit_size
23 from webhelpers.pylonslib import Flash as _Flash
23 from webhelpers.pylonslib import Flash as _Flash
24 from webhelpers.pylonslib.secure_form import secure_form
24 from webhelpers.pylonslib.secure_form import secure_form
25 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
25 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
26 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
26 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
27 replace_whitespace, urlify, truncate, wrap_paragraphs
27 replace_whitespace, urlify, truncate, wrap_paragraphs
28 from webhelpers.date import time_ago_in_words
28 from webhelpers.date import time_ago_in_words
29
29
30 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
30 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
31 convert_boolean_attrs, NotGiven
31 convert_boolean_attrs, NotGiven
32
32
33 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
33 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
34 """Reset button
34 """Reset button
35 """
35 """
36 _set_input_attrs(attrs, type, name, value)
36 _set_input_attrs(attrs, type, name, value)
37 _set_id_attr(attrs, id, name)
37 _set_id_attr(attrs, id, name)
38 convert_boolean_attrs(attrs, ["disabled"])
38 convert_boolean_attrs(attrs, ["disabled"])
39 return HTML.input(**attrs)
39 return HTML.input(**attrs)
40
40
41 reset = _reset
41 reset = _reset
42
42
43
43
44 def get_token():
44 def get_token():
45 """Return the current authentication token, creating one if one doesn't
45 """Return the current authentication token, creating one if one doesn't
46 already exist.
46 already exist.
47 """
47 """
48 token_key = "_authentication_token"
48 token_key = "_authentication_token"
49 from pylons import session
49 from pylons import session
50 if not token_key in session:
50 if not token_key in session:
51 try:
51 try:
52 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
52 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
53 except AttributeError: # Python < 2.4
53 except AttributeError: # Python < 2.4
54 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
54 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
55 session[token_key] = token
55 session[token_key] = token
56 if hasattr(session, 'save'):
56 if hasattr(session, 'save'):
57 session.save()
57 session.save()
58 return session[token_key]
58 return session[token_key]
59
59
60 class _GetError(object):
60 class _GetError(object):
61 """Get error from form_errors, and represent it as span wrapped error
61 """Get error from form_errors, and represent it as span wrapped error
62 message
62 message
63
63
64 :param field_name: field to fetch errors for
64 :param field_name: field to fetch errors for
65 :param form_errors: form errors dict
65 :param form_errors: form errors dict
66 """
66 """
67
67
68 def __call__(self, field_name, form_errors):
68 def __call__(self, field_name, form_errors):
69 tmpl = """<span class="error_msg">%s</span>"""
69 tmpl = """<span class="error_msg">%s</span>"""
70 if form_errors and form_errors.has_key(field_name):
70 if form_errors and form_errors.has_key(field_name):
71 return literal(tmpl % form_errors.get(field_name))
71 return literal(tmpl % form_errors.get(field_name))
72
72
73 get_error = _GetError()
73 get_error = _GetError()
74
74
75 def recursive_replace(str, replace=' '):
75 def recursive_replace(str, replace=' '):
76 """Recursive replace of given sign to just one instance
76 """Recursive replace of given sign to just one instance
77
77
78 :param str: given string
78 :param str: given string
79 :param replace: char to find and replace multiple instances
79 :param replace: char to find and replace multiple instances
80
80
81 Examples::
81 Examples::
82 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
82 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
83 'Mighty-Mighty-Bo-sstones'
83 'Mighty-Mighty-Bo-sstones'
84 """
84 """
85
85
86 if str.find(replace * 2) == -1:
86 if str.find(replace * 2) == -1:
87 return str
87 return str
88 else:
88 else:
89 str = str.replace(replace * 2, replace)
89 str = str.replace(replace * 2, replace)
90 return recursive_replace(str, replace)
90 return recursive_replace(str, replace)
91
91
92 class _ToolTip(object):
92 class _ToolTip(object):
93
93
94 def __call__(self, tooltip_title, trim_at=50):
94 def __call__(self, tooltip_title, trim_at=50):
95 """Special function just to wrap our text into nice formatted
95 """Special function just to wrap our text into nice formatted
96 autowrapped text
96 autowrapped text
97
97
98 :param tooltip_title:
98 :param tooltip_title:
99 """
99 """
100
100
101 return wrap_paragraphs(escape(tooltip_title), trim_at)\
101 return wrap_paragraphs(escape(tooltip_title), trim_at)\
102 .replace('\n', '<br/>')
102 .replace('\n', '<br/>')
103
103
104 def activate(self):
104 def activate(self):
105 """Adds tooltip mechanism to the given Html all tooltips have to have
105 """Adds tooltip mechanism to the given Html all tooltips have to have
106 set class `tooltip` and set attribute `tooltip_title`.
106 set class `tooltip` and set attribute `tooltip_title`.
107 Then a tooltip will be generated based on that. All with yui js tooltip
107 Then a tooltip will be generated based on that. All with yui js tooltip
108 """
108 """
109
109
110 js = '''
110 js = '''
111 YAHOO.util.Event.onDOMReady(function(){
111 YAHOO.util.Event.onDOMReady(function(){
112 function toolTipsId(){
112 function toolTipsId(){
113 var ids = [];
113 var ids = [];
114 var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
114 var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
115
115
116 for (var i = 0; i < tts.length; i++) {
116 for (var i = 0; i < tts.length; i++) {
117 //if element doesn't not have and id autogenerate one for tooltip
117 //if element doesn't not have and id autogenerate one for tooltip
118
118
119 if (!tts[i].id){
119 if (!tts[i].id){
120 tts[i].id='tt'+i*100;
120 tts[i].id='tt'+i*100;
121 }
121 }
122 ids.push(tts[i].id);
122 ids.push(tts[i].id);
123 }
123 }
124 return ids
124 return ids
125 };
125 };
126 var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
126 var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
127 context: toolTipsId(),
127 context: toolTipsId(),
128 monitorresize:false,
128 monitorresize:false,
129 xyoffset :[0,0],
129 xyoffset :[0,0],
130 autodismissdelay:300000,
130 autodismissdelay:300000,
131 hidedelay:5,
131 hidedelay:5,
132 showdelay:20,
132 showdelay:20,
133 });
133 });
134
134
135 // Set the text for the tooltip just before we display it. Lazy method
135 // Set the text for the tooltip just before we display it. Lazy method
136 myToolTips.contextTriggerEvent.subscribe(
136 myToolTips.contextTriggerEvent.subscribe(
137 function(type, args) {
137 function(type, args) {
138
138
139 var context = args[0];
139 var context = args[0];
140
140
141 //positioning of tooltip
141 //positioning of tooltip
142 var tt_w = this.element.clientWidth;//tooltip width
142 var tt_w = this.element.clientWidth;//tooltip width
143 var tt_h = this.element.clientHeight;//tooltip height
143 var tt_h = this.element.clientHeight;//tooltip height
144
144
145 var context_w = context.offsetWidth;
145 var context_w = context.offsetWidth;
146 var context_h = context.offsetHeight;
146 var context_h = context.offsetHeight;
147
147
148 var pos_x = YAHOO.util.Dom.getX(context);
148 var pos_x = YAHOO.util.Dom.getX(context);
149 var pos_y = YAHOO.util.Dom.getY(context);
149 var pos_y = YAHOO.util.Dom.getY(context);
150
150
151 var display_strategy = 'right';
151 var display_strategy = 'right';
152 var xy_pos = [0,0];
152 var xy_pos = [0,0];
153 switch (display_strategy){
153 switch (display_strategy){
154
154
155 case 'top':
155 case 'top':
156 var cur_x = (pos_x+context_w/2)-(tt_w/2);
156 var cur_x = (pos_x+context_w/2)-(tt_w/2);
157 var cur_y = (pos_y-tt_h-4);
157 var cur_y = (pos_y-tt_h-4);
158 xy_pos = [cur_x,cur_y];
158 xy_pos = [cur_x,cur_y];
159 break;
159 break;
160 case 'bottom':
160 case 'bottom':
161 var cur_x = (pos_x+context_w/2)-(tt_w/2);
161 var cur_x = (pos_x+context_w/2)-(tt_w/2);
162 var cur_y = pos_y+context_h+4;
162 var cur_y = pos_y+context_h+4;
163 xy_pos = [cur_x,cur_y];
163 xy_pos = [cur_x,cur_y];
164 break;
164 break;
165 case 'left':
165 case 'left':
166 var cur_x = (pos_x-tt_w-4);
166 var cur_x = (pos_x-tt_w-4);
167 var cur_y = pos_y-((tt_h/2)-context_h/2);
167 var cur_y = pos_y-((tt_h/2)-context_h/2);
168 xy_pos = [cur_x,cur_y];
168 xy_pos = [cur_x,cur_y];
169 break;
169 break;
170 case 'right':
170 case 'right':
171 var cur_x = (pos_x+context_w+4);
171 var cur_x = (pos_x+context_w+4);
172 var cur_y = pos_y-((tt_h/2)-context_h/2);
172 var cur_y = pos_y-((tt_h/2)-context_h/2);
173 xy_pos = [cur_x,cur_y];
173 xy_pos = [cur_x,cur_y];
174 break;
174 break;
175 default:
175 default:
176 var cur_x = (pos_x+context_w/2)-(tt_w/2);
176 var cur_x = (pos_x+context_w/2)-(tt_w/2);
177 var cur_y = pos_y-tt_h-4;
177 var cur_y = pos_y-tt_h-4;
178 xy_pos = [cur_x,cur_y];
178 xy_pos = [cur_x,cur_y];
179 break;
179 break;
180
180
181 }
181 }
182
182
183 this.cfg.setProperty("xy",xy_pos);
183 this.cfg.setProperty("xy",xy_pos);
184
184
185 });
185 });
186
186
187 //Mouse out
187 //Mouse out
188 myToolTips.contextMouseOutEvent.subscribe(
188 myToolTips.contextMouseOutEvent.subscribe(
189 function(type, args) {
189 function(type, args) {
190 var context = args[0];
190 var context = args[0];
191
191
192 });
192 });
193 });
193 });
194 '''
194 '''
195 return literal(js)
195 return literal(js)
196
196
197 tooltip = _ToolTip()
197 tooltip = _ToolTip()
198
198
199 class _FilesBreadCrumbs(object):
199 class _FilesBreadCrumbs(object):
200
200
201 def __call__(self, repo_name, rev, paths):
201 def __call__(self, repo_name, rev, paths):
202 if isinstance(paths, str):
202 if isinstance(paths, str):
203 paths = paths.decode('utf-8')
203 paths = paths.decode('utf-8')
204 url_l = [link_to(repo_name, url('files_home',
204 url_l = [link_to(repo_name, url('files_home',
205 repo_name=repo_name,
205 repo_name=repo_name,
206 revision=rev, f_path=''))]
206 revision=rev, f_path=''))]
207 paths_l = paths.split('/')
207 paths_l = paths.split('/')
208 for cnt, p in enumerate(paths_l):
208 for cnt, p in enumerate(paths_l):
209 if p != '':
209 if p != '':
210 url_l.append(link_to(p, url('files_home',
210 url_l.append(link_to(p, url('files_home',
211 repo_name=repo_name,
211 repo_name=repo_name,
212 revision=rev,
212 revision=rev,
213 f_path='/'.join(paths_l[:cnt + 1]))))
213 f_path='/'.join(paths_l[:cnt + 1]))))
214
214
215 return literal('/'.join(url_l))
215 return literal('/'.join(url_l))
216
216
217 files_breadcrumbs = _FilesBreadCrumbs()
217 files_breadcrumbs = _FilesBreadCrumbs()
218
218
219 class CodeHtmlFormatter(HtmlFormatter):
219 class CodeHtmlFormatter(HtmlFormatter):
220
220
221 def wrap(self, source, outfile):
221 def wrap(self, source, outfile):
222 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
222 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
223
223
224 def _wrap_code(self, source):
224 def _wrap_code(self, source):
225 for cnt, it in enumerate(source):
225 for cnt, it in enumerate(source):
226 i, t = it
226 i, t = it
227 t = '<div id="#S-%s">%s</div>' % (cnt + 1, t)
227 t = '<div id="L-%s">%s</div>' % (cnt + 1, t)
228 yield i, t
228 yield i, t
229 def pygmentize(filenode, **kwargs):
229 def pygmentize(filenode, **kwargs):
230 """pygmentize function using pygments
230 """pygmentize function using pygments
231
231
232 :param filenode:
232 :param filenode:
233 """
233 """
234
234
235 return literal(code_highlight(filenode.content,
235 return literal(code_highlight(filenode.content,
236 filenode.lexer, CodeHtmlFormatter(**kwargs)))
236 filenode.lexer, CodeHtmlFormatter(**kwargs)))
237
237
238 def pygmentize_annotation(filenode, **kwargs):
238 def pygmentize_annotation(filenode, **kwargs):
239 """pygmentize function for annotation
239 """pygmentize function for annotation
240
240
241 :param filenode:
241 :param filenode:
242 """
242 """
243
243
244 color_dict = {}
244 color_dict = {}
245 def gen_color(n=10000):
245 def gen_color(n=10000):
246 """generator for getting n of evenly distributed colors using
246 """generator for getting n of evenly distributed colors using
247 hsv color and golden ratio. It always return same order of colors
247 hsv color and golden ratio. It always return same order of colors
248
248
249 :returns: RGB tuple
249 :returns: RGB tuple
250 """
250 """
251 import colorsys
251 import colorsys
252 golden_ratio = 0.618033988749895
252 golden_ratio = 0.618033988749895
253 h = 0.22717784590367374
253 h = 0.22717784590367374
254
254
255 for c in xrange(n):
255 for c in xrange(n):
256 h += golden_ratio
256 h += golden_ratio
257 h %= 1
257 h %= 1
258 HSV_tuple = [h, 0.95, 0.95]
258 HSV_tuple = [h, 0.95, 0.95]
259 RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple)
259 RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple)
260 yield map(lambda x:str(int(x * 256)), RGB_tuple)
260 yield map(lambda x:str(int(x * 256)), RGB_tuple)
261
261
262 cgenerator = gen_color()
262 cgenerator = gen_color()
263
263
264 def get_color_string(cs):
264 def get_color_string(cs):
265 if color_dict.has_key(cs):
265 if color_dict.has_key(cs):
266 col = color_dict[cs]
266 col = color_dict[cs]
267 else:
267 else:
268 col = color_dict[cs] = cgenerator.next()
268 col = color_dict[cs] = cgenerator.next()
269 return "color: rgb(%s)! important;" % (', '.join(col))
269 return "color: rgb(%s)! important;" % (', '.join(col))
270
270
271 def url_func(changeset):
271 def url_func(changeset):
272 tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \
272 tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \
273 " %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
273 " %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
274
274
275 tooltip_html = tooltip_html % (changeset.author,
275 tooltip_html = tooltip_html % (changeset.author,
276 changeset.date,
276 changeset.date,
277 tooltip(changeset.message))
277 tooltip(changeset.message))
278 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
278 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
279 short_id(changeset.raw_id))
279 short_id(changeset.raw_id))
280 uri = link_to(
280 uri = link_to(
281 lnk_format,
281 lnk_format,
282 url('changeset_home', repo_name=changeset.repository.name,
282 url('changeset_home', repo_name=changeset.repository.name,
283 revision=changeset.raw_id),
283 revision=changeset.raw_id),
284 style=get_color_string(changeset.raw_id),
284 style=get_color_string(changeset.raw_id),
285 class_='tooltip',
285 class_='tooltip',
286 title=tooltip_html
286 title=tooltip_html
287 )
287 )
288
288
289 uri += '\n'
289 uri += '\n'
290 return uri
290 return uri
291 return literal(annotate_highlight(filenode, url_func, **kwargs))
291 return literal(annotate_highlight(filenode, url_func, **kwargs))
292
292
293 def repo_name_slug(value):
293 def repo_name_slug(value):
294 """Return slug of name of repository
294 """Return slug of name of repository
295 This function is called on each creation/modification
295 This function is called on each creation/modification
296 of repository to prevent bad names in repo
296 of repository to prevent bad names in repo
297 """
297 """
298
298
299 slug = remove_formatting(value)
299 slug = remove_formatting(value)
300 slug = strip_tags(slug)
300 slug = strip_tags(slug)
301
301
302 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
302 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
303 slug = slug.replace(c, '-')
303 slug = slug.replace(c, '-')
304 slug = recursive_replace(slug, '-')
304 slug = recursive_replace(slug, '-')
305 slug = collapse(slug, '-')
305 slug = collapse(slug, '-')
306 return slug
306 return slug
307
307
308 def get_changeset_safe(repo, rev):
308 def get_changeset_safe(repo, rev):
309 from vcs.backends.base import BaseRepository
309 from vcs.backends.base import BaseRepository
310 from vcs.exceptions import RepositoryError
310 from vcs.exceptions import RepositoryError
311 if not isinstance(repo, BaseRepository):
311 if not isinstance(repo, BaseRepository):
312 raise Exception('You must pass an Repository '
312 raise Exception('You must pass an Repository '
313 'object as first argument got %s', type(repo))
313 'object as first argument got %s', type(repo))
314
314
315 try:
315 try:
316 cs = repo.get_changeset(rev)
316 cs = repo.get_changeset(rev)
317 except RepositoryError:
317 except RepositoryError:
318 from rhodecode.lib.utils import EmptyChangeset
318 from rhodecode.lib.utils import EmptyChangeset
319 cs = EmptyChangeset()
319 cs = EmptyChangeset()
320 return cs
320 return cs
321
321
322
322
323 flash = _Flash()
323 flash = _Flash()
324
324
325
325
326 #==============================================================================
326 #==============================================================================
327 # MERCURIAL FILTERS available via h.
327 # MERCURIAL FILTERS available via h.
328 #==============================================================================
328 #==============================================================================
329 from mercurial import util
329 from mercurial import util
330 from mercurial.templatefilters import person as _person
330 from mercurial.templatefilters import person as _person
331
331
332 def _age(curdate):
332 def _age(curdate):
333 """turns a datetime into an age string."""
333 """turns a datetime into an age string."""
334
334
335 if not curdate:
335 if not curdate:
336 return ''
336 return ''
337
337
338 from datetime import timedelta, datetime
338 from datetime import timedelta, datetime
339
339
340 agescales = [("year", 3600 * 24 * 365),
340 agescales = [("year", 3600 * 24 * 365),
341 ("month", 3600 * 24 * 30),
341 ("month", 3600 * 24 * 30),
342 ("day", 3600 * 24),
342 ("day", 3600 * 24),
343 ("hour", 3600),
343 ("hour", 3600),
344 ("minute", 60),
344 ("minute", 60),
345 ("second", 1), ]
345 ("second", 1), ]
346
346
347 age = datetime.now() - curdate
347 age = datetime.now() - curdate
348 age_seconds = (age.days * agescales[2][1]) + age.seconds
348 age_seconds = (age.days * agescales[2][1]) + age.seconds
349 pos = 1
349 pos = 1
350 for scale in agescales:
350 for scale in agescales:
351 if scale[1] <= age_seconds:
351 if scale[1] <= age_seconds:
352 if pos == 6:pos = 5
352 if pos == 6:pos = 5
353 return time_ago_in_words(curdate, agescales[pos][0]) + ' ' + _('ago')
353 return time_ago_in_words(curdate, agescales[pos][0]) + ' ' + _('ago')
354 pos += 1
354 pos += 1
355
355
356 return _('just now')
356 return _('just now')
357
357
358 age = lambda x:_age(x)
358 age = lambda x:_age(x)
359 capitalize = lambda x: x.capitalize()
359 capitalize = lambda x: x.capitalize()
360 email = util.email
360 email = util.email
361 email_or_none = lambda x: util.email(x) if util.email(x) != x else None
361 email_or_none = lambda x: util.email(x) if util.email(x) != x else None
362 person = lambda x: _person(x)
362 person = lambda x: _person(x)
363 short_id = lambda x: x[:12]
363 short_id = lambda x: x[:12]
364
364
365
365
366 def bool2icon(value):
366 def bool2icon(value):
367 """Returns True/False values represented as small html image of true/false
367 """Returns True/False values represented as small html image of true/false
368 icons
368 icons
369
369
370 :param value: bool value
370 :param value: bool value
371 """
371 """
372
372
373 if value is True:
373 if value is True:
374 return HTML.tag('img', src="/images/icons/accept.png", alt=_('True'))
374 return HTML.tag('img', src="/images/icons/accept.png", alt=_('True'))
375
375
376 if value is False:
376 if value is False:
377 return HTML.tag('img', src="/images/icons/cancel.png", alt=_('False'))
377 return HTML.tag('img', src="/images/icons/cancel.png", alt=_('False'))
378
378
379 return value
379 return value
380
380
381
381
382 def action_parser(user_log):
382 def action_parser(user_log):
383 """This helper will map the specified string action into translated
383 """This helper will map the specified string action into translated
384 fancy names with icons and links
384 fancy names with icons and links
385
385
386 :param user_log: user log instance
386 :param user_log: user log instance
387 """
387 """
388
388
389 action = user_log.action
389 action = user_log.action
390 action_params = ' '
390 action_params = ' '
391
391
392 x = action.split(':')
392 x = action.split(':')
393
393
394 if len(x) > 1:
394 if len(x) > 1:
395 action, action_params = x
395 action, action_params = x
396
396
397 def get_cs_links():
397 def get_cs_links():
398 revs_limit = 5 #display this amount always
398 revs_limit = 5 #display this amount always
399 revs_top_limit = 50 #show upto this amount of changesets hidden
399 revs_top_limit = 50 #show upto this amount of changesets hidden
400 revs = action_params.split(',')
400 revs = action_params.split(',')
401 repo_name = user_log.repository.repo_name
401 repo_name = user_log.repository.repo_name
402 from rhodecode.model.scm import ScmModel
402 from rhodecode.model.scm import ScmModel
403
403
404 message = lambda rev: get_changeset_safe(ScmModel().get(repo_name),
404 message = lambda rev: get_changeset_safe(ScmModel().get(repo_name),
405 rev).message
405 rev).message
406
406
407 cs_links = " " + ', '.join ([link_to(rev,
407 cs_links = " " + ', '.join ([link_to(rev,
408 url('changeset_home',
408 url('changeset_home',
409 repo_name=repo_name,
409 repo_name=repo_name,
410 revision=rev), title=tooltip(message(rev)),
410 revision=rev), title=tooltip(message(rev)),
411 class_='tooltip') for rev in revs[:revs_limit] ])
411 class_='tooltip') for rev in revs[:revs_limit] ])
412 if len(revs) > revs_limit:
412 if len(revs) > revs_limit:
413 uniq_id = revs[0]
413 uniq_id = revs[0]
414 html_tmpl = ('<span> %s '
414 html_tmpl = ('<span> %s '
415 '<a class="show_more" id="_%s" href="#">%s</a> '
415 '<a class="show_more" id="_%s" href="#">%s</a> '
416 '%s</span>')
416 '%s</span>')
417 cs_links += html_tmpl % (_('and'), uniq_id, _('%s more') \
417 cs_links += html_tmpl % (_('and'), uniq_id, _('%s more') \
418 % (len(revs) - revs_limit),
418 % (len(revs) - revs_limit),
419 _('revisions'))
419 _('revisions'))
420
420
421 html_tmpl = '<span id="%s" style="display:none"> %s </span>'
421 html_tmpl = '<span id="%s" style="display:none"> %s </span>'
422 cs_links += html_tmpl % (uniq_id, ', '.join([link_to(rev,
422 cs_links += html_tmpl % (uniq_id, ', '.join([link_to(rev,
423 url('changeset_home',
423 url('changeset_home',
424 repo_name=repo_name, revision=rev),
424 repo_name=repo_name, revision=rev),
425 title=message(rev), class_='tooltip')
425 title=message(rev), class_='tooltip')
426 for rev in revs[revs_limit:revs_top_limit]]))
426 for rev in revs[revs_limit:revs_top_limit]]))
427
427
428 return cs_links
428 return cs_links
429
429
430 def get_fork_name():
430 def get_fork_name():
431 from rhodecode.model.scm import ScmModel
431 from rhodecode.model.scm import ScmModel
432 repo_name = action_params
432 repo_name = action_params
433 repo = ScmModel().get(repo_name)
433 repo = ScmModel().get(repo_name)
434 if repo is None:
434 if repo is None:
435 return repo_name
435 return repo_name
436 return link_to(action_params, url('summary_home',
436 return link_to(action_params, url('summary_home',
437 repo_name=repo.name,),
437 repo_name=repo.name,),
438 title=repo.dbrepo.description)
438 title=repo.dbrepo.description)
439
439
440 map = {'user_deleted_repo':(_('User [deleted] repository'), None),
440 map = {'user_deleted_repo':(_('User [deleted] repository'), None),
441 'user_created_repo':(_('User [created] repository'), None),
441 'user_created_repo':(_('User [created] repository'), None),
442 'user_forked_repo':(_('User [forked] repository as:'), get_fork_name),
442 'user_forked_repo':(_('User [forked] repository as:'), get_fork_name),
443 'user_updated_repo':(_('User [updated] repository'), None),
443 'user_updated_repo':(_('User [updated] repository'), None),
444 'admin_deleted_repo':(_('Admin [delete] repository'), None),
444 'admin_deleted_repo':(_('Admin [delete] repository'), None),
445 'admin_created_repo':(_('Admin [created] repository'), None),
445 'admin_created_repo':(_('Admin [created] repository'), None),
446 'admin_forked_repo':(_('Admin [forked] repository'), None),
446 'admin_forked_repo':(_('Admin [forked] repository'), None),
447 'admin_updated_repo':(_('Admin [updated] repository'), None),
447 'admin_updated_repo':(_('Admin [updated] repository'), None),
448 'push':(_('[Pushed]'), get_cs_links),
448 'push':(_('[Pushed]'), get_cs_links),
449 'pull':(_('[Pulled]'), None),
449 'pull':(_('[Pulled]'), None),
450 'started_following_repo':(_('User [started following] repository'), None),
450 'started_following_repo':(_('User [started following] repository'), None),
451 'stopped_following_repo':(_('User [stopped following] repository'), None),
451 'stopped_following_repo':(_('User [stopped following] repository'), None),
452 }
452 }
453
453
454 action_str = map.get(action, action)
454 action_str = map.get(action, action)
455 action = action_str[0].replace('[', '<span class="journal_highlight">')\
455 action = action_str[0].replace('[', '<span class="journal_highlight">')\
456 .replace(']', '</span>')
456 .replace(']', '</span>')
457 if action_str[1] is not None:
457 if action_str[1] is not None:
458 action = action + " " + action_str[1]()
458 action = action + " " + action_str[1]()
459
459
460 return literal(action)
460 return literal(action)
461
461
462 def action_parser_icon(user_log):
462 def action_parser_icon(user_log):
463 action = user_log.action
463 action = user_log.action
464 action_params = None
464 action_params = None
465 x = action.split(':')
465 x = action.split(':')
466
466
467 if len(x) > 1:
467 if len(x) > 1:
468 action, action_params = x
468 action, action_params = x
469
469
470 tmpl = """<img src="/images/icons/%s" alt="%s"/>"""
470 tmpl = """<img src="/images/icons/%s" alt="%s"/>"""
471 map = {'user_deleted_repo':'database_delete.png',
471 map = {'user_deleted_repo':'database_delete.png',
472 'user_created_repo':'database_add.png',
472 'user_created_repo':'database_add.png',
473 'user_forked_repo':'arrow_divide.png',
473 'user_forked_repo':'arrow_divide.png',
474 'user_updated_repo':'database_edit.png',
474 'user_updated_repo':'database_edit.png',
475 'admin_deleted_repo':'database_delete.png',
475 'admin_deleted_repo':'database_delete.png',
476 'admin_created_repo':'database_add.png',
476 'admin_created_repo':'database_add.png',
477 'admin_forked_repo':'arrow_divide.png',
477 'admin_forked_repo':'arrow_divide.png',
478 'admin_updated_repo':'database_edit.png',
478 'admin_updated_repo':'database_edit.png',
479 'push':'script_add.png',
479 'push':'script_add.png',
480 'pull':'down_16.png',
480 'pull':'down_16.png',
481 'started_following_repo':'heart_add.png',
481 'started_following_repo':'heart_add.png',
482 'stopped_following_repo':'heart_delete.png',
482 'stopped_following_repo':'heart_delete.png',
483 }
483 }
484 return literal(tmpl % (map.get(action, action), action))
484 return literal(tmpl % (map.get(action, action), action))
485
485
486
486
487 #==============================================================================
487 #==============================================================================
488 # PERMS
488 # PERMS
489 #==============================================================================
489 #==============================================================================
490 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
490 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
491 HasRepoPermissionAny, HasRepoPermissionAll
491 HasRepoPermissionAny, HasRepoPermissionAll
492
492
493 #==============================================================================
493 #==============================================================================
494 # GRAVATAR URL
494 # GRAVATAR URL
495 #==============================================================================
495 #==============================================================================
496 import hashlib
496 import hashlib
497 import urllib
497 import urllib
498 from pylons import request
498 from pylons import request
499
499
500 def gravatar_url(email_address, size=30):
500 def gravatar_url(email_address, size=30):
501 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
501 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
502 default = 'identicon'
502 default = 'identicon'
503 baseurl_nossl = "http://www.gravatar.com/avatar/"
503 baseurl_nossl = "http://www.gravatar.com/avatar/"
504 baseurl_ssl = "https://secure.gravatar.com/avatar/"
504 baseurl_ssl = "https://secure.gravatar.com/avatar/"
505 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
505 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
506
506
507
507
508 # construct the url
508 # construct the url
509 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
509 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
510 gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
510 gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
511
511
512 return gravatar_url
512 return gravatar_url
513
513
514 def safe_unicode(str):
514 def safe_unicode(str):
515 """safe unicode function. In case of UnicodeDecode error we try to return
515 """safe unicode function. In case of UnicodeDecode error we try to return
516 unicode with errors replace, if this failes we return unicode with
516 unicode with errors replace, if this failes we return unicode with
517 string_escape decoding """
517 string_escape decoding """
518
518
519 try:
519 try:
520 u_str = unicode(str)
520 u_str = unicode(str)
521 except UnicodeDecodeError:
521 except UnicodeDecodeError:
522 try:
522 try:
523 u_str = unicode(str, 'utf-8', 'replace')
523 u_str = unicode(str, 'utf-8', 'replace')
524 except UnicodeDecodeError:
524 except UnicodeDecodeError:
525 #incase we have a decode error just represent as byte string
525 #incase we have a decode error just represent as byte string
526 u_str = unicode(str(str).encode('string_escape'))
526 u_str = unicode(str(str).encode('string_escape'))
527
527
528 return u_str
528 return u_str
@@ -1,119 +1,123 b''
1 div.codeblock {
1 div.codeblock {
2 overflow: auto;
2 overflow: auto;
3 padding: 0px;
3 padding: 0px;
4 border: 1px solid #ccc;
4 border: 1px solid #ccc;
5 background: #f8f8f8;
5 background: #f8f8f8;
6 font-size: 100%;
6 font-size: 100%;
7 line-height: 100%;
7 line-height: 100%;
8 /* new */
8 /* new */
9 line-height: 125%;
9 line-height: 125%;
10 }
10 }
11 div.codeblock .code-header{
11 div.codeblock .code-header{
12 border-bottom: 1px solid #CCCCCC;
12 border-bottom: 1px solid #CCCCCC;
13 background: #EEEEEE;
13 background: #EEEEEE;
14 padding:10px 0 10px 0;
14 padding:10px 0 10px 0;
15 }
15 }
16 div.codeblock .code-header .revision{
16 div.codeblock .code-header .revision{
17 margin-left:25px;
17 margin-left:25px;
18 font-weight: bold;
18 font-weight: bold;
19 }
19 }
20 div.codeblock .code-header .commit{
20 div.codeblock .code-header .commit{
21 margin-left:25px;
21 margin-left:25px;
22 font-weight: normal;
22 font-weight: normal;
23 white-space:pre;
23 white-space:pre;
24 }
24 }
25
25
26 div.codeblock .code-body table{
26 div.codeblock .code-body table{
27 width: 0 !important;
27 width: 0 !important;
28 }
28 }
29 div.code-body {
29 div.code-body {
30 background-color: #FFFFFF;
30 background-color: #FFFFFF;
31 }
31 }
32 div.code-body pre .match{
32 div.code-body pre .match{
33 background-color: #FAFFA6;
33 background-color: #FAFFA6;
34 }
34 }
35 div.code-body pre .break{
35 div.code-body pre .break{
36 background-color: #DDE7EF;
36 background-color: #DDE7EF;
37 width: 100%;
37 width: 100%;
38 color: #747474;
38 color: #747474;
39 display: block;
39 display: block;
40
40
41 }
41 }
42 div.annotatediv{
42 div.annotatediv{
43 margin-left:2px;
43 margin-left:2px;
44 margin-right:4px;
44 margin-right:4px;
45 }
45 }
46 .code-highlight {
46 .code-highlight {
47 padding: 0px;
47 padding: 0px;
48 margin-top: 5px;
48 margin-top: 5px;
49 margin-bottom: 5px;
49 margin-bottom: 5px;
50 border-left: 2px solid #ccc;
50 border-left: 2px solid #ccc;
51 }
51 }
52 .code-highlight pre, .linenodiv pre {
52 .code-highlight pre, .linenodiv pre {
53 padding: 5px;
53 padding: 5px;
54 margin: 0;
54 margin: 0;
55 }
55 }
56 .code-highlight pre div:target {
57 background-color: #FFFFBE !important;
58 }
59
56 .linenos a { text-decoration: none; }
60 .linenos a { text-decoration: none; }
57
61
58 .code { display: block; }
62 .code { display: block; }
59 .code-highlight .hll { background-color: #ffffcc }
63 .code-highlight .hll { background-color: #ffffcc }
60 .code-highlight .c { color: #408080; font-style: italic } /* Comment */
64 .code-highlight .c { color: #408080; font-style: italic } /* Comment */
61 .code-highlight .err { border: 1px solid #FF0000 } /* Error */
65 .code-highlight .err { border: 1px solid #FF0000 } /* Error */
62 .code-highlight .k { color: #008000; font-weight: bold } /* Keyword */
66 .code-highlight .k { color: #008000; font-weight: bold } /* Keyword */
63 .code-highlight .o { color: #666666 } /* Operator */
67 .code-highlight .o { color: #666666 } /* Operator */
64 .code-highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
68 .code-highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
65 .code-highlight .cp { color: #BC7A00 } /* Comment.Preproc */
69 .code-highlight .cp { color: #BC7A00 } /* Comment.Preproc */
66 .code-highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
70 .code-highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
67 .code-highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
71 .code-highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
68 .code-highlight .gd { color: #A00000 } /* Generic.Deleted */
72 .code-highlight .gd { color: #A00000 } /* Generic.Deleted */
69 .code-highlight .ge { font-style: italic } /* Generic.Emph */
73 .code-highlight .ge { font-style: italic } /* Generic.Emph */
70 .code-highlight .gr { color: #FF0000 } /* Generic.Error */
74 .code-highlight .gr { color: #FF0000 } /* Generic.Error */
71 .code-highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
75 .code-highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
72 .code-highlight .gi { color: #00A000 } /* Generic.Inserted */
76 .code-highlight .gi { color: #00A000 } /* Generic.Inserted */
73 .code-highlight .go { color: #808080 } /* Generic.Output */
77 .code-highlight .go { color: #808080 } /* Generic.Output */
74 .code-highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
78 .code-highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
75 .code-highlight .gs { font-weight: bold } /* Generic.Strong */
79 .code-highlight .gs { font-weight: bold } /* Generic.Strong */
76 .code-highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
80 .code-highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
77 .code-highlight .gt { color: #0040D0 } /* Generic.Traceback */
81 .code-highlight .gt { color: #0040D0 } /* Generic.Traceback */
78 .code-highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
82 .code-highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
79 .code-highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
83 .code-highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
80 .code-highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
84 .code-highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
81 .code-highlight .kp { color: #008000 } /* Keyword.Pseudo */
85 .code-highlight .kp { color: #008000 } /* Keyword.Pseudo */
82 .code-highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
86 .code-highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
83 .code-highlight .kt { color: #B00040 } /* Keyword.Type */
87 .code-highlight .kt { color: #B00040 } /* Keyword.Type */
84 .code-highlight .m { color: #666666 } /* Literal.Number */
88 .code-highlight .m { color: #666666 } /* Literal.Number */
85 .code-highlight .s { color: #BA2121 } /* Literal.String */
89 .code-highlight .s { color: #BA2121 } /* Literal.String */
86 .code-highlight .na { color: #7D9029 } /* Name.Attribute */
90 .code-highlight .na { color: #7D9029 } /* Name.Attribute */
87 .code-highlight .nb { color: #008000 } /* Name.Builtin */
91 .code-highlight .nb { color: #008000 } /* Name.Builtin */
88 .code-highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
92 .code-highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
89 .code-highlight .no { color: #880000 } /* Name.Constant */
93 .code-highlight .no { color: #880000 } /* Name.Constant */
90 .code-highlight .nd { color: #AA22FF } /* Name.Decorator */
94 .code-highlight .nd { color: #AA22FF } /* Name.Decorator */
91 .code-highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
95 .code-highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
92 .code-highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
96 .code-highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
93 .code-highlight .nf { color: #0000FF } /* Name.Function */
97 .code-highlight .nf { color: #0000FF } /* Name.Function */
94 .code-highlight .nl { color: #A0A000 } /* Name.Label */
98 .code-highlight .nl { color: #A0A000 } /* Name.Label */
95 .code-highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
99 .code-highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
96 .code-highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
100 .code-highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
97 .code-highlight .nv { color: #19177C } /* Name.Variable */
101 .code-highlight .nv { color: #19177C } /* Name.Variable */
98 .code-highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
102 .code-highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
99 .code-highlight .w { color: #bbbbbb } /* Text.Whitespace */
103 .code-highlight .w { color: #bbbbbb } /* Text.Whitespace */
100 .code-highlight .mf { color: #666666 } /* Literal.Number.Float */
104 .code-highlight .mf { color: #666666 } /* Literal.Number.Float */
101 .code-highlight .mh { color: #666666 } /* Literal.Number.Hex */
105 .code-highlight .mh { color: #666666 } /* Literal.Number.Hex */
102 .code-highlight .mi { color: #666666 } /* Literal.Number.Integer */
106 .code-highlight .mi { color: #666666 } /* Literal.Number.Integer */
103 .code-highlight .mo { color: #666666 } /* Literal.Number.Oct */
107 .code-highlight .mo { color: #666666 } /* Literal.Number.Oct */
104 .code-highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
108 .code-highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
105 .code-highlight .sc { color: #BA2121 } /* Literal.String.Char */
109 .code-highlight .sc { color: #BA2121 } /* Literal.String.Char */
106 .code-highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
110 .code-highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
107 .code-highlight .s2 { color: #BA2121 } /* Literal.String.Double */
111 .code-highlight .s2 { color: #BA2121 } /* Literal.String.Double */
108 .code-highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
112 .code-highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
109 .code-highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
113 .code-highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
110 .code-highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
114 .code-highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
111 .code-highlight .sx { color: #008000 } /* Literal.String.Other */
115 .code-highlight .sx { color: #008000 } /* Literal.String.Other */
112 .code-highlight .sr { color: #BB6688 } /* Literal.String.Regex */
116 .code-highlight .sr { color: #BB6688 } /* Literal.String.Regex */
113 .code-highlight .s1 { color: #BA2121 } /* Literal.String.Single */
117 .code-highlight .s1 { color: #BA2121 } /* Literal.String.Single */
114 .code-highlight .ss { color: #19177C } /* Literal.String.Symbol */
118 .code-highlight .ss { color: #19177C } /* Literal.String.Symbol */
115 .code-highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
119 .code-highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
116 .code-highlight .vc { color: #19177C } /* Name.Variable.Class */
120 .code-highlight .vc { color: #19177C } /* Name.Variable.Class */
117 .code-highlight .vg { color: #19177C } /* Name.Variable.Global */
121 .code-highlight .vg { color: #19177C } /* Name.Variable.Global */
118 .code-highlight .vi { color: #19177C } /* Name.Variable.Instance */
122 .code-highlight .vi { color: #19177C } /* Name.Variable.Instance */
119 .code-highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
123 .code-highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
@@ -1,57 +1,57 b''
1 <dl>
1 <dl>
2 <dt>${_('Revision')}</dt>
2 <dt>${_('Revision')}</dt>
3 <dd>
3 <dd>
4 ${h.link_to("r%s:%s" % (c.files_list.last_changeset.revision,h.short_id(c.files_list.last_changeset.raw_id)),
4 ${h.link_to("r%s:%s" % (c.files_list.last_changeset.revision,h.short_id(c.files_list.last_changeset.raw_id)),
5 h.url('changeset_home',repo_name=c.repo_name,revision=c.files_list.last_changeset.raw_id))}
5 h.url('changeset_home',repo_name=c.repo_name,revision=c.files_list.last_changeset.raw_id))}
6 </dd>
6 </dd>
7 <dt>${_('Size')}</dt>
7 <dt>${_('Size')}</dt>
8 <dd>${h.format_byte_size(c.files_list.size,binary=True)}</dd>
8 <dd>${h.format_byte_size(c.files_list.size,binary=True)}</dd>
9 <dt>${_('Mimetype')}</dt>
9 <dt>${_('Mimetype')}</dt>
10 <dd>${c.files_list.mimetype}</dd>
10 <dd>${c.files_list.mimetype}</dd>
11 <dt>${_('Options')}</dt>
11 <dt>${_('Options')}</dt>
12 <dd>${h.link_to(_('show annotation'),
12 <dd>${h.link_to(_('show annotation'),
13 h.url('files_annotate_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
13 h.url('files_annotate_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
14 / ${h.link_to(_('show as raw'),
14 / ${h.link_to(_('show as raw'),
15 h.url('files_raw_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
15 h.url('files_raw_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
16 / ${h.link_to(_('download as raw'),
16 / ${h.link_to(_('download as raw'),
17 h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
17 h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
18 </dd>
18 </dd>
19 <dt>${_('History')}</dt>
19 <dt>${_('History')}</dt>
20 <dd>
20 <dd>
21 <div>
21 <div>
22 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
22 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
23 ${h.hidden('diff2',c.files_list.last_changeset.raw_id)}
23 ${h.hidden('diff2',c.files_list.last_changeset.raw_id)}
24 ${h.select('diff1',c.files_list.last_changeset.raw_id,c.file_history)}
24 ${h.select('diff1',c.files_list.last_changeset.raw_id,c.file_history)}
25 ${h.submit('diff','diff to revision',class_="ui-button")}
25 ${h.submit('diff','diff to revision',class_="ui-button")}
26 ${h.submit('show_rev','show at revision',class_="ui-button")}
26 ${h.submit('show_rev','show at revision',class_="ui-button")}
27 ${h.end_form()}
27 ${h.end_form()}
28 </div>
28 </div>
29 </dd>
29 </dd>
30 </dl>
30 </dl>
31
31
32
32
33 <div id="body" class="codeblock">
33 <div id="body" class="codeblock">
34 <div class="code-header">
34 <div class="code-header">
35 <div class="revision">${c.files_list.name}@r${c.files_list.last_changeset.revision}:${h.short_id(c.files_list.last_changeset.raw_id)}</div>
35 <div class="revision">${c.files_list.name}@r${c.files_list.last_changeset.revision}:${h.short_id(c.files_list.last_changeset.raw_id)}</div>
36 <div class="commit">"${c.files_list.last_changeset.message}"</div>
36 <div class="commit">"${c.files_list.last_changeset.message}"</div>
37 </div>
37 </div>
38 <div class="code-body">
38 <div class="code-body">
39 % if c.files_list.size < c.cut_off_limit:
39 % if c.files_list.size < c.cut_off_limit:
40 ${h.pygmentize(c.files_list,linenos=True,anchorlinenos=True,lineanchors='S',cssclass="code-highlight")}
40 ${h.pygmentize(c.files_list,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
41 %else:
41 %else:
42 ${_('File is to big to display')} ${h.link_to(_('show as raw'),
42 ${_('File is to big to display')} ${h.link_to(_('show as raw'),
43 h.url('files_raw_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
43 h.url('files_raw_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
44 %endif
44 %endif
45 </div>
45 </div>
46 </div>
46 </div>
47
47
48 <script type="text/javascript">
48 <script type="text/javascript">
49 YAHOO.util.Event.onDOMReady(function(){
49 YAHOO.util.Event.onDOMReady(function(){
50 YAHOO.util.Event.addListener('show_rev','click',function(e){
50 YAHOO.util.Event.addListener('show_rev','click',function(e){
51 YAHOO.util.Event.preventDefault(e);
51 YAHOO.util.Event.preventDefault(e);
52 var cs = YAHOO.util.Dom.get('diff1').value;
52 var cs = YAHOO.util.Dom.get('diff1').value;
53 var url = "${h.url('files_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
53 var url = "${h.url('files_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
54 window.location = url;
54 window.location = url;
55 });
55 });
56 });
56 });
57 </script> No newline at end of file
57 </script>
General Comments 0
You need to be logged in to leave comments. Login now