##// END OF EJS Templates
Added a translatable date formatter for every date displayed.
Vincent Duvert -
r2416:44f328d6 beta
parent child Browse files
Show More
@@ -1,972 +1,980
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 import StringIO
8 import StringIO
9 import urllib
9 import urllib
10 import math
10 import math
11 import logging
11 import logging
12
12
13 from datetime import datetime
13 from datetime import datetime
14 from pygments.formatters.html import HtmlFormatter
14 from pygments.formatters.html import HtmlFormatter
15 from pygments import highlight as code_highlight
15 from pygments import highlight as code_highlight
16 from pylons import url, request, config
16 from pylons import url, request, config
17 from pylons.i18n.translation import _, ungettext
17 from pylons.i18n.translation import _, ungettext
18 from hashlib import md5
18 from hashlib import md5
19
19
20 from webhelpers.html import literal, HTML, escape
20 from webhelpers.html import literal, HTML, escape
21 from webhelpers.html.tools import *
21 from webhelpers.html.tools import *
22 from webhelpers.html.builder import make_tag
22 from webhelpers.html.builder import make_tag
23 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
23 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
24 end_form, file, form, hidden, image, javascript_link, link_to, \
24 end_form, file, form, hidden, image, javascript_link, link_to, \
25 link_to_if, link_to_unless, ol, required_legend, select, stylesheet_link, \
25 link_to_if, link_to_unless, ol, required_legend, select, stylesheet_link, \
26 submit, text, password, textarea, title, ul, xml_declaration, radio
26 submit, text, password, textarea, title, ul, xml_declaration, radio
27 from webhelpers.html.tools import auto_link, button_to, highlight, \
27 from webhelpers.html.tools import auto_link, button_to, highlight, \
28 js_obfuscate, mail_to, strip_links, strip_tags, tag_re
28 js_obfuscate, mail_to, strip_links, strip_tags, tag_re
29 from webhelpers.number import format_byte_size, format_bit_size
29 from webhelpers.number import format_byte_size, format_bit_size
30 from webhelpers.pylonslib import Flash as _Flash
30 from webhelpers.pylonslib import Flash as _Flash
31 from webhelpers.pylonslib.secure_form import secure_form
31 from webhelpers.pylonslib.secure_form import secure_form
32 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
32 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
33 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
33 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
34 replace_whitespace, urlify, truncate, wrap_paragraphs
34 replace_whitespace, urlify, truncate, wrap_paragraphs
35 from webhelpers.date import time_ago_in_words
35 from webhelpers.date import time_ago_in_words
36 from webhelpers.paginate import Page
36 from webhelpers.paginate import Page
37 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
37 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
38 convert_boolean_attrs, NotGiven, _make_safe_id_component
38 convert_boolean_attrs, NotGiven, _make_safe_id_component
39
39
40 from rhodecode.lib.annotate import annotate_highlight
40 from rhodecode.lib.annotate import annotate_highlight
41 from rhodecode.lib.utils import repo_name_slug
41 from rhodecode.lib.utils import repo_name_slug
42 from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \
42 from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \
43 get_changeset_safe
43 get_changeset_safe
44 from rhodecode.lib.markup_renderer import MarkupRenderer
44 from rhodecode.lib.markup_renderer import MarkupRenderer
45 from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
45 from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
46 from rhodecode.lib.vcs.backends.base import BaseChangeset
46 from rhodecode.lib.vcs.backends.base import BaseChangeset
47 from rhodecode.model.db import URL_SEP
47 from rhodecode.model.db import URL_SEP
48
48
49 log = logging.getLogger(__name__)
49 log = logging.getLogger(__name__)
50
50
51
51
52 def shorter(text, size=20):
52 def shorter(text, size=20):
53 postfix = '...'
53 postfix = '...'
54 if len(text) > size:
54 if len(text) > size:
55 return text[:size - len(postfix)] + postfix
55 return text[:size - len(postfix)] + postfix
56 return text
56 return text
57
57
58
58
59 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
59 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
60 """
60 """
61 Reset button
61 Reset button
62 """
62 """
63 _set_input_attrs(attrs, type, name, value)
63 _set_input_attrs(attrs, type, name, value)
64 _set_id_attr(attrs, id, name)
64 _set_id_attr(attrs, id, name)
65 convert_boolean_attrs(attrs, ["disabled"])
65 convert_boolean_attrs(attrs, ["disabled"])
66 return HTML.input(**attrs)
66 return HTML.input(**attrs)
67
67
68 reset = _reset
68 reset = _reset
69 safeid = _make_safe_id_component
69 safeid = _make_safe_id_component
70
70
71
71
72 def FID(raw_id, path):
72 def FID(raw_id, path):
73 """
73 """
74 Creates a uniqe ID for filenode based on it's hash of path and revision
74 Creates a uniqe ID for filenode based on it's hash of path and revision
75 it's safe to use in urls
75 it's safe to use in urls
76
76
77 :param raw_id:
77 :param raw_id:
78 :param path:
78 :param path:
79 """
79 """
80
80
81 return 'C-%s-%s' % (short_id(raw_id), md5(safe_str(path)).hexdigest()[:12])
81 return 'C-%s-%s' % (short_id(raw_id), md5(safe_str(path)).hexdigest()[:12])
82
82
83
83
84 def get_token():
84 def get_token():
85 """Return the current authentication token, creating one if one doesn't
85 """Return the current authentication token, creating one if one doesn't
86 already exist.
86 already exist.
87 """
87 """
88 token_key = "_authentication_token"
88 token_key = "_authentication_token"
89 from pylons import session
89 from pylons import session
90 if not token_key in session:
90 if not token_key in session:
91 try:
91 try:
92 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
92 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
93 except AttributeError: # Python < 2.4
93 except AttributeError: # Python < 2.4
94 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
94 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
95 session[token_key] = token
95 session[token_key] = token
96 if hasattr(session, 'save'):
96 if hasattr(session, 'save'):
97 session.save()
97 session.save()
98 return session[token_key]
98 return session[token_key]
99
99
100
100
101 class _GetError(object):
101 class _GetError(object):
102 """Get error from form_errors, and represent it as span wrapped error
102 """Get error from form_errors, and represent it as span wrapped error
103 message
103 message
104
104
105 :param field_name: field to fetch errors for
105 :param field_name: field to fetch errors for
106 :param form_errors: form errors dict
106 :param form_errors: form errors dict
107 """
107 """
108
108
109 def __call__(self, field_name, form_errors):
109 def __call__(self, field_name, form_errors):
110 tmpl = """<span class="error_msg">%s</span>"""
110 tmpl = """<span class="error_msg">%s</span>"""
111 if form_errors and form_errors.has_key(field_name):
111 if form_errors and form_errors.has_key(field_name):
112 return literal(tmpl % form_errors.get(field_name))
112 return literal(tmpl % form_errors.get(field_name))
113
113
114 get_error = _GetError()
114 get_error = _GetError()
115
115
116
116
117 class _ToolTip(object):
117 class _ToolTip(object):
118
118
119 def __call__(self, tooltip_title, trim_at=50):
119 def __call__(self, tooltip_title, trim_at=50):
120 """Special function just to wrap our text into nice formatted
120 """Special function just to wrap our text into nice formatted
121 autowrapped text
121 autowrapped text
122
122
123 :param tooltip_title:
123 :param tooltip_title:
124 """
124 """
125 return escape(tooltip_title)
125 return escape(tooltip_title)
126 tooltip = _ToolTip()
126 tooltip = _ToolTip()
127
127
128
128
129 class _FilesBreadCrumbs(object):
129 class _FilesBreadCrumbs(object):
130
130
131 def __call__(self, repo_name, rev, paths):
131 def __call__(self, repo_name, rev, paths):
132 if isinstance(paths, str):
132 if isinstance(paths, str):
133 paths = safe_unicode(paths)
133 paths = safe_unicode(paths)
134 url_l = [link_to(repo_name, url('files_home',
134 url_l = [link_to(repo_name, url('files_home',
135 repo_name=repo_name,
135 repo_name=repo_name,
136 revision=rev, f_path=''))]
136 revision=rev, f_path=''))]
137 paths_l = paths.split('/')
137 paths_l = paths.split('/')
138 for cnt, p in enumerate(paths_l):
138 for cnt, p in enumerate(paths_l):
139 if p != '':
139 if p != '':
140 url_l.append(link_to(p,
140 url_l.append(link_to(p,
141 url('files_home',
141 url('files_home',
142 repo_name=repo_name,
142 repo_name=repo_name,
143 revision=rev,
143 revision=rev,
144 f_path='/'.join(paths_l[:cnt + 1])
144 f_path='/'.join(paths_l[:cnt + 1])
145 )
145 )
146 )
146 )
147 )
147 )
148
148
149 return literal('/'.join(url_l))
149 return literal('/'.join(url_l))
150
150
151 files_breadcrumbs = _FilesBreadCrumbs()
151 files_breadcrumbs = _FilesBreadCrumbs()
152
152
153
153
154 class CodeHtmlFormatter(HtmlFormatter):
154 class CodeHtmlFormatter(HtmlFormatter):
155 """
155 """
156 My code Html Formatter for source codes
156 My code Html Formatter for source codes
157 """
157 """
158
158
159 def wrap(self, source, outfile):
159 def wrap(self, source, outfile):
160 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
160 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
161
161
162 def _wrap_code(self, source):
162 def _wrap_code(self, source):
163 for cnt, it in enumerate(source):
163 for cnt, it in enumerate(source):
164 i, t = it
164 i, t = it
165 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
165 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
166 yield i, t
166 yield i, t
167
167
168 def _wrap_tablelinenos(self, inner):
168 def _wrap_tablelinenos(self, inner):
169 dummyoutfile = StringIO.StringIO()
169 dummyoutfile = StringIO.StringIO()
170 lncount = 0
170 lncount = 0
171 for t, line in inner:
171 for t, line in inner:
172 if t:
172 if t:
173 lncount += 1
173 lncount += 1
174 dummyoutfile.write(line)
174 dummyoutfile.write(line)
175
175
176 fl = self.linenostart
176 fl = self.linenostart
177 mw = len(str(lncount + fl - 1))
177 mw = len(str(lncount + fl - 1))
178 sp = self.linenospecial
178 sp = self.linenospecial
179 st = self.linenostep
179 st = self.linenostep
180 la = self.lineanchors
180 la = self.lineanchors
181 aln = self.anchorlinenos
181 aln = self.anchorlinenos
182 nocls = self.noclasses
182 nocls = self.noclasses
183 if sp:
183 if sp:
184 lines = []
184 lines = []
185
185
186 for i in range(fl, fl + lncount):
186 for i in range(fl, fl + lncount):
187 if i % st == 0:
187 if i % st == 0:
188 if i % sp == 0:
188 if i % sp == 0:
189 if aln:
189 if aln:
190 lines.append('<a href="#%s%d" class="special">%*d</a>' %
190 lines.append('<a href="#%s%d" class="special">%*d</a>' %
191 (la, i, mw, i))
191 (la, i, mw, i))
192 else:
192 else:
193 lines.append('<span class="special">%*d</span>' % (mw, i))
193 lines.append('<span class="special">%*d</span>' % (mw, i))
194 else:
194 else:
195 if aln:
195 if aln:
196 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
196 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
197 else:
197 else:
198 lines.append('%*d' % (mw, i))
198 lines.append('%*d' % (mw, i))
199 else:
199 else:
200 lines.append('')
200 lines.append('')
201 ls = '\n'.join(lines)
201 ls = '\n'.join(lines)
202 else:
202 else:
203 lines = []
203 lines = []
204 for i in range(fl, fl + lncount):
204 for i in range(fl, fl + lncount):
205 if i % st == 0:
205 if i % st == 0:
206 if aln:
206 if aln:
207 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
207 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
208 else:
208 else:
209 lines.append('%*d' % (mw, i))
209 lines.append('%*d' % (mw, i))
210 else:
210 else:
211 lines.append('')
211 lines.append('')
212 ls = '\n'.join(lines)
212 ls = '\n'.join(lines)
213
213
214 # in case you wonder about the seemingly redundant <div> here: since the
214 # in case you wonder about the seemingly redundant <div> here: since the
215 # content in the other cell also is wrapped in a div, some browsers in
215 # content in the other cell also is wrapped in a div, some browsers in
216 # some configurations seem to mess up the formatting...
216 # some configurations seem to mess up the formatting...
217 if nocls:
217 if nocls:
218 yield 0, ('<table class="%stable">' % self.cssclass +
218 yield 0, ('<table class="%stable">' % self.cssclass +
219 '<tr><td><div class="linenodiv" '
219 '<tr><td><div class="linenodiv" '
220 'style="background-color: #f0f0f0; padding-right: 10px">'
220 'style="background-color: #f0f0f0; padding-right: 10px">'
221 '<pre style="line-height: 125%">' +
221 '<pre style="line-height: 125%">' +
222 ls + '</pre></div></td><td id="hlcode" class="code">')
222 ls + '</pre></div></td><td id="hlcode" class="code">')
223 else:
223 else:
224 yield 0, ('<table class="%stable">' % self.cssclass +
224 yield 0, ('<table class="%stable">' % self.cssclass +
225 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
225 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
226 ls + '</pre></div></td><td id="hlcode" class="code">')
226 ls + '</pre></div></td><td id="hlcode" class="code">')
227 yield 0, dummyoutfile.getvalue()
227 yield 0, dummyoutfile.getvalue()
228 yield 0, '</td></tr></table>'
228 yield 0, '</td></tr></table>'
229
229
230
230
231 def pygmentize(filenode, **kwargs):
231 def pygmentize(filenode, **kwargs):
232 """pygmentize function using pygments
232 """pygmentize function using pygments
233
233
234 :param filenode:
234 :param filenode:
235 """
235 """
236
236
237 return literal(code_highlight(filenode.content,
237 return literal(code_highlight(filenode.content,
238 filenode.lexer, CodeHtmlFormatter(**kwargs)))
238 filenode.lexer, CodeHtmlFormatter(**kwargs)))
239
239
240
240
241 def pygmentize_annotation(repo_name, filenode, **kwargs):
241 def pygmentize_annotation(repo_name, filenode, **kwargs):
242 """
242 """
243 pygmentize function for annotation
243 pygmentize function for annotation
244
244
245 :param filenode:
245 :param filenode:
246 """
246 """
247
247
248 color_dict = {}
248 color_dict = {}
249
249
250 def gen_color(n=10000):
250 def gen_color(n=10000):
251 """generator for getting n of evenly distributed colors using
251 """generator for getting n of evenly distributed colors using
252 hsv color and golden ratio. It always return same order of colors
252 hsv color and golden ratio. It always return same order of colors
253
253
254 :returns: RGB tuple
254 :returns: RGB tuple
255 """
255 """
256
256
257 def hsv_to_rgb(h, s, v):
257 def hsv_to_rgb(h, s, v):
258 if s == 0.0:
258 if s == 0.0:
259 return v, v, v
259 return v, v, v
260 i = int(h * 6.0) # XXX assume int() truncates!
260 i = int(h * 6.0) # XXX assume int() truncates!
261 f = (h * 6.0) - i
261 f = (h * 6.0) - i
262 p = v * (1.0 - s)
262 p = v * (1.0 - s)
263 q = v * (1.0 - s * f)
263 q = v * (1.0 - s * f)
264 t = v * (1.0 - s * (1.0 - f))
264 t = v * (1.0 - s * (1.0 - f))
265 i = i % 6
265 i = i % 6
266 if i == 0:
266 if i == 0:
267 return v, t, p
267 return v, t, p
268 if i == 1:
268 if i == 1:
269 return q, v, p
269 return q, v, p
270 if i == 2:
270 if i == 2:
271 return p, v, t
271 return p, v, t
272 if i == 3:
272 if i == 3:
273 return p, q, v
273 return p, q, v
274 if i == 4:
274 if i == 4:
275 return t, p, v
275 return t, p, v
276 if i == 5:
276 if i == 5:
277 return v, p, q
277 return v, p, q
278
278
279 golden_ratio = 0.618033988749895
279 golden_ratio = 0.618033988749895
280 h = 0.22717784590367374
280 h = 0.22717784590367374
281
281
282 for _ in xrange(n):
282 for _ in xrange(n):
283 h += golden_ratio
283 h += golden_ratio
284 h %= 1
284 h %= 1
285 HSV_tuple = [h, 0.95, 0.95]
285 HSV_tuple = [h, 0.95, 0.95]
286 RGB_tuple = hsv_to_rgb(*HSV_tuple)
286 RGB_tuple = hsv_to_rgb(*HSV_tuple)
287 yield map(lambda x: str(int(x * 256)), RGB_tuple)
287 yield map(lambda x: str(int(x * 256)), RGB_tuple)
288
288
289 cgenerator = gen_color()
289 cgenerator = gen_color()
290
290
291 def get_color_string(cs):
291 def get_color_string(cs):
292 if cs in color_dict:
292 if cs in color_dict:
293 col = color_dict[cs]
293 col = color_dict[cs]
294 else:
294 else:
295 col = color_dict[cs] = cgenerator.next()
295 col = color_dict[cs] = cgenerator.next()
296 return "color: rgb(%s)! important;" % (', '.join(col))
296 return "color: rgb(%s)! important;" % (', '.join(col))
297
297
298 def url_func(repo_name):
298 def url_func(repo_name):
299
299
300 def _url_func(changeset):
300 def _url_func(changeset):
301 author = changeset.author
301 author = changeset.author
302 date = changeset.date
302 date = changeset.date
303 message = tooltip(changeset.message)
303 message = tooltip(changeset.message)
304
304
305 tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>"
305 tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>"
306 " %s<br/><b>Date:</b> %s</b><br/><b>Message:"
306 " %s<br/><b>Date:</b> %s</b><br/><b>Message:"
307 "</b> %s<br/></div>")
307 "</b> %s<br/></div>")
308
308
309 tooltip_html = tooltip_html % (author, date, message)
309 tooltip_html = tooltip_html % (author, date, message)
310 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
310 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
311 short_id(changeset.raw_id))
311 short_id(changeset.raw_id))
312 uri = link_to(
312 uri = link_to(
313 lnk_format,
313 lnk_format,
314 url('changeset_home', repo_name=repo_name,
314 url('changeset_home', repo_name=repo_name,
315 revision=changeset.raw_id),
315 revision=changeset.raw_id),
316 style=get_color_string(changeset.raw_id),
316 style=get_color_string(changeset.raw_id),
317 class_='tooltip',
317 class_='tooltip',
318 title=tooltip_html
318 title=tooltip_html
319 )
319 )
320
320
321 uri += '\n'
321 uri += '\n'
322 return uri
322 return uri
323 return _url_func
323 return _url_func
324
324
325 return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs))
325 return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs))
326
326
327
327
328 def is_following_repo(repo_name, user_id):
328 def is_following_repo(repo_name, user_id):
329 from rhodecode.model.scm import ScmModel
329 from rhodecode.model.scm import ScmModel
330 return ScmModel().is_following_repo(repo_name, user_id)
330 return ScmModel().is_following_repo(repo_name, user_id)
331
331
332 flash = _Flash()
332 flash = _Flash()
333
333
334 #==============================================================================
334 #==============================================================================
335 # SCM FILTERS available via h.
335 # SCM FILTERS available via h.
336 #==============================================================================
336 #==============================================================================
337 from rhodecode.lib.vcs.utils import author_name, author_email
337 from rhodecode.lib.vcs.utils import author_name, author_email
338 from rhodecode.lib.utils2 import credentials_filter, age as _age
338 from rhodecode.lib.utils2 import credentials_filter, age as _age
339 from rhodecode.model.db import User
339 from rhodecode.model.db import User
340
340
341 age = lambda x: _age(x)
341 age = lambda x: _age(x)
342 capitalize = lambda x: x.capitalize()
342 capitalize = lambda x: x.capitalize()
343 email = author_email
343 email = author_email
344 short_id = lambda x: x[:12]
344 short_id = lambda x: x[:12]
345 hide_credentials = lambda x: ''.join(credentials_filter(x))
345 hide_credentials = lambda x: ''.join(credentials_filter(x))
346
346
347
347
348 def fmt_date(date):
349 if date:
350 return (date.strftime(_(u"%a, %d %b %Y %H:%M:%S").encode('utf8'))
351 .decode('utf8'))
352
353 return ""
354
355
348 def is_git(repository):
356 def is_git(repository):
349 if hasattr(repository, 'alias'):
357 if hasattr(repository, 'alias'):
350 _type = repository.alias
358 _type = repository.alias
351 elif hasattr(repository, 'repo_type'):
359 elif hasattr(repository, 'repo_type'):
352 _type = repository.repo_type
360 _type = repository.repo_type
353 else:
361 else:
354 _type = repository
362 _type = repository
355 return _type == 'git'
363 return _type == 'git'
356
364
357
365
358 def is_hg(repository):
366 def is_hg(repository):
359 if hasattr(repository, 'alias'):
367 if hasattr(repository, 'alias'):
360 _type = repository.alias
368 _type = repository.alias
361 elif hasattr(repository, 'repo_type'):
369 elif hasattr(repository, 'repo_type'):
362 _type = repository.repo_type
370 _type = repository.repo_type
363 else:
371 else:
364 _type = repository
372 _type = repository
365 return _type == 'hg'
373 return _type == 'hg'
366
374
367
375
368 def email_or_none(author):
376 def email_or_none(author):
369 _email = email(author)
377 _email = email(author)
370 if _email != '':
378 if _email != '':
371 return _email
379 return _email
372
380
373 # See if it contains a username we can get an email from
381 # See if it contains a username we can get an email from
374 user = User.get_by_username(author_name(author), case_insensitive=True,
382 user = User.get_by_username(author_name(author), case_insensitive=True,
375 cache=True)
383 cache=True)
376 if user is not None:
384 if user is not None:
377 return user.email
385 return user.email
378
386
379 # No valid email, not a valid user in the system, none!
387 # No valid email, not a valid user in the system, none!
380 return None
388 return None
381
389
382
390
383 def person(author):
391 def person(author):
384 # attr to return from fetched user
392 # attr to return from fetched user
385 person_getter = lambda usr: usr.username
393 person_getter = lambda usr: usr.username
386
394
387 # Valid email in the attribute passed, see if they're in the system
395 # Valid email in the attribute passed, see if they're in the system
388 _email = email(author)
396 _email = email(author)
389 if _email != '':
397 if _email != '':
390 user = User.get_by_email(_email, case_insensitive=True, cache=True)
398 user = User.get_by_email(_email, case_insensitive=True, cache=True)
391 if user is not None:
399 if user is not None:
392 return person_getter(user)
400 return person_getter(user)
393 return _email
401 return _email
394
402
395 # Maybe it's a username?
403 # Maybe it's a username?
396 _author = author_name(author)
404 _author = author_name(author)
397 user = User.get_by_username(_author, case_insensitive=True,
405 user = User.get_by_username(_author, case_insensitive=True,
398 cache=True)
406 cache=True)
399 if user is not None:
407 if user is not None:
400 return person_getter(user)
408 return person_getter(user)
401
409
402 # Still nothing? Just pass back the author name then
410 # Still nothing? Just pass back the author name then
403 return _author
411 return _author
404
412
405
413
406 def bool2icon(value):
414 def bool2icon(value):
407 """Returns True/False values represented as small html image of true/false
415 """Returns True/False values represented as small html image of true/false
408 icons
416 icons
409
417
410 :param value: bool value
418 :param value: bool value
411 """
419 """
412
420
413 if value is True:
421 if value is True:
414 return HTML.tag('img', src=url("/images/icons/accept.png"),
422 return HTML.tag('img', src=url("/images/icons/accept.png"),
415 alt=_('True'))
423 alt=_('True'))
416
424
417 if value is False:
425 if value is False:
418 return HTML.tag('img', src=url("/images/icons/cancel.png"),
426 return HTML.tag('img', src=url("/images/icons/cancel.png"),
419 alt=_('False'))
427 alt=_('False'))
420
428
421 return value
429 return value
422
430
423
431
424 def action_parser(user_log, feed=False):
432 def action_parser(user_log, feed=False):
425 """
433 """
426 This helper will action_map the specified string action into translated
434 This helper will action_map the specified string action into translated
427 fancy names with icons and links
435 fancy names with icons and links
428
436
429 :param user_log: user log instance
437 :param user_log: user log instance
430 :param feed: use output for feeds (no html and fancy icons)
438 :param feed: use output for feeds (no html and fancy icons)
431 """
439 """
432
440
433 action = user_log.action
441 action = user_log.action
434 action_params = ' '
442 action_params = ' '
435
443
436 x = action.split(':')
444 x = action.split(':')
437
445
438 if len(x) > 1:
446 if len(x) > 1:
439 action, action_params = x
447 action, action_params = x
440
448
441 def get_cs_links():
449 def get_cs_links():
442 revs_limit = 3 # display this amount always
450 revs_limit = 3 # display this amount always
443 revs_top_limit = 50 # show upto this amount of changesets hidden
451 revs_top_limit = 50 # show upto this amount of changesets hidden
444 revs_ids = action_params.split(',')
452 revs_ids = action_params.split(',')
445 deleted = user_log.repository is None
453 deleted = user_log.repository is None
446 if deleted:
454 if deleted:
447 return ','.join(revs_ids)
455 return ','.join(revs_ids)
448
456
449 repo_name = user_log.repository.repo_name
457 repo_name = user_log.repository.repo_name
450
458
451 repo = user_log.repository.scm_instance
459 repo = user_log.repository.scm_instance
452
460
453 def lnk(rev, repo_name):
461 def lnk(rev, repo_name):
454
462
455 if isinstance(rev, BaseChangeset):
463 if isinstance(rev, BaseChangeset):
456 lbl = 'r%s:%s' % (rev.revision, rev.short_id)
464 lbl = 'r%s:%s' % (rev.revision, rev.short_id)
457 _url = url('changeset_home', repo_name=repo_name,
465 _url = url('changeset_home', repo_name=repo_name,
458 revision=rev.raw_id)
466 revision=rev.raw_id)
459 title = tooltip(rev.message)
467 title = tooltip(rev.message)
460 else:
468 else:
461 lbl = '%s' % rev
469 lbl = '%s' % rev
462 _url = '#'
470 _url = '#'
463 title = _('Changeset not found')
471 title = _('Changeset not found')
464
472
465 return link_to(lbl, _url, title=title, class_='tooltip',)
473 return link_to(lbl, _url, title=title, class_='tooltip',)
466
474
467 revs = []
475 revs = []
468 if len(filter(lambda v: v != '', revs_ids)) > 0:
476 if len(filter(lambda v: v != '', revs_ids)) > 0:
469 for rev in revs_ids[:revs_top_limit]:
477 for rev in revs_ids[:revs_top_limit]:
470 try:
478 try:
471 rev = repo.get_changeset(rev)
479 rev = repo.get_changeset(rev)
472 revs.append(rev)
480 revs.append(rev)
473 except ChangesetDoesNotExistError:
481 except ChangesetDoesNotExistError:
474 log.error('cannot find revision %s in this repo' % rev)
482 log.error('cannot find revision %s in this repo' % rev)
475 revs.append(rev)
483 revs.append(rev)
476 continue
484 continue
477 cs_links = []
485 cs_links = []
478 cs_links.append(" " + ', '.join(
486 cs_links.append(" " + ', '.join(
479 [lnk(rev, repo_name) for rev in revs[:revs_limit]]
487 [lnk(rev, repo_name) for rev in revs[:revs_limit]]
480 )
488 )
481 )
489 )
482
490
483 compare_view = (
491 compare_view = (
484 ' <div class="compare_view tooltip" title="%s">'
492 ' <div class="compare_view tooltip" title="%s">'
485 '<a href="%s">%s</a> </div>' % (
493 '<a href="%s">%s</a> </div>' % (
486 _('Show all combined changesets %s->%s') % (
494 _('Show all combined changesets %s->%s') % (
487 revs_ids[0], revs_ids[-1]
495 revs_ids[0], revs_ids[-1]
488 ),
496 ),
489 url('changeset_home', repo_name=repo_name,
497 url('changeset_home', repo_name=repo_name,
490 revision='%s...%s' % (revs_ids[0], revs_ids[-1])
498 revision='%s...%s' % (revs_ids[0], revs_ids[-1])
491 ),
499 ),
492 _('compare view')
500 _('compare view')
493 )
501 )
494 )
502 )
495
503
496 # if we have exactly one more than normally displayed
504 # if we have exactly one more than normally displayed
497 # just display it, takes less space than displaying
505 # just display it, takes less space than displaying
498 # "and 1 more revisions"
506 # "and 1 more revisions"
499 if len(revs_ids) == revs_limit + 1:
507 if len(revs_ids) == revs_limit + 1:
500 rev = revs[revs_limit]
508 rev = revs[revs_limit]
501 cs_links.append(", " + lnk(rev, repo_name))
509 cs_links.append(", " + lnk(rev, repo_name))
502
510
503 # hidden-by-default ones
511 # hidden-by-default ones
504 if len(revs_ids) > revs_limit + 1:
512 if len(revs_ids) > revs_limit + 1:
505 uniq_id = revs_ids[0]
513 uniq_id = revs_ids[0]
506 html_tmpl = (
514 html_tmpl = (
507 '<span> %s <a class="show_more" id="_%s" '
515 '<span> %s <a class="show_more" id="_%s" '
508 'href="#more">%s</a> %s</span>'
516 'href="#more">%s</a> %s</span>'
509 )
517 )
510 if not feed:
518 if not feed:
511 cs_links.append(html_tmpl % (
519 cs_links.append(html_tmpl % (
512 _('and'),
520 _('and'),
513 uniq_id, _('%s more') % (len(revs_ids) - revs_limit),
521 uniq_id, _('%s more') % (len(revs_ids) - revs_limit),
514 _('revisions')
522 _('revisions')
515 )
523 )
516 )
524 )
517
525
518 if not feed:
526 if not feed:
519 html_tmpl = '<span id="%s" style="display:none">, %s </span>'
527 html_tmpl = '<span id="%s" style="display:none">, %s </span>'
520 else:
528 else:
521 html_tmpl = '<span id="%s"> %s </span>'
529 html_tmpl = '<span id="%s"> %s </span>'
522
530
523 morelinks = ', '.join(
531 morelinks = ', '.join(
524 [lnk(rev, repo_name) for rev in revs[revs_limit:]]
532 [lnk(rev, repo_name) for rev in revs[revs_limit:]]
525 )
533 )
526
534
527 if len(revs_ids) > revs_top_limit:
535 if len(revs_ids) > revs_top_limit:
528 morelinks += ', ...'
536 morelinks += ', ...'
529
537
530 cs_links.append(html_tmpl % (uniq_id, morelinks))
538 cs_links.append(html_tmpl % (uniq_id, morelinks))
531 if len(revs) > 1:
539 if len(revs) > 1:
532 cs_links.append(compare_view)
540 cs_links.append(compare_view)
533 return ''.join(cs_links)
541 return ''.join(cs_links)
534
542
535 def get_fork_name():
543 def get_fork_name():
536 repo_name = action_params
544 repo_name = action_params
537 return _('fork name ') + str(link_to(action_params, url('summary_home',
545 return _('fork name ') + str(link_to(action_params, url('summary_home',
538 repo_name=repo_name,)))
546 repo_name=repo_name,)))
539
547
540 def get_user_name():
548 def get_user_name():
541 user_name = action_params
549 user_name = action_params
542 return user_name
550 return user_name
543
551
544 def get_users_group():
552 def get_users_group():
545 group_name = action_params
553 group_name = action_params
546 return group_name
554 return group_name
547
555
548 # action : translated str, callback(extractor), icon
556 # action : translated str, callback(extractor), icon
549 action_map = {
557 action_map = {
550 'user_deleted_repo': (_('[deleted] repository'),
558 'user_deleted_repo': (_('[deleted] repository'),
551 None, 'database_delete.png'),
559 None, 'database_delete.png'),
552 'user_created_repo': (_('[created] repository'),
560 'user_created_repo': (_('[created] repository'),
553 None, 'database_add.png'),
561 None, 'database_add.png'),
554 'user_created_fork': (_('[created] repository as fork'),
562 'user_created_fork': (_('[created] repository as fork'),
555 None, 'arrow_divide.png'),
563 None, 'arrow_divide.png'),
556 'user_forked_repo': (_('[forked] repository'),
564 'user_forked_repo': (_('[forked] repository'),
557 get_fork_name, 'arrow_divide.png'),
565 get_fork_name, 'arrow_divide.png'),
558 'user_updated_repo': (_('[updated] repository'),
566 'user_updated_repo': (_('[updated] repository'),
559 None, 'database_edit.png'),
567 None, 'database_edit.png'),
560 'admin_deleted_repo': (_('[delete] repository'),
568 'admin_deleted_repo': (_('[delete] repository'),
561 None, 'database_delete.png'),
569 None, 'database_delete.png'),
562 'admin_created_repo': (_('[created] repository'),
570 'admin_created_repo': (_('[created] repository'),
563 None, 'database_add.png'),
571 None, 'database_add.png'),
564 'admin_forked_repo': (_('[forked] repository'),
572 'admin_forked_repo': (_('[forked] repository'),
565 None, 'arrow_divide.png'),
573 None, 'arrow_divide.png'),
566 'admin_updated_repo': (_('[updated] repository'),
574 'admin_updated_repo': (_('[updated] repository'),
567 None, 'database_edit.png'),
575 None, 'database_edit.png'),
568 'admin_created_user': (_('[created] user'),
576 'admin_created_user': (_('[created] user'),
569 get_user_name, 'user_add.png'),
577 get_user_name, 'user_add.png'),
570 'admin_updated_user': (_('[updated] user'),
578 'admin_updated_user': (_('[updated] user'),
571 get_user_name, 'user_edit.png'),
579 get_user_name, 'user_edit.png'),
572 'admin_created_users_group': (_('[created] users group'),
580 'admin_created_users_group': (_('[created] users group'),
573 get_users_group, 'group_add.png'),
581 get_users_group, 'group_add.png'),
574 'admin_updated_users_group': (_('[updated] users group'),
582 'admin_updated_users_group': (_('[updated] users group'),
575 get_users_group, 'group_edit.png'),
583 get_users_group, 'group_edit.png'),
576 'user_commented_revision': (_('[commented] on revision in repository'),
584 'user_commented_revision': (_('[commented] on revision in repository'),
577 get_cs_links, 'comment_add.png'),
585 get_cs_links, 'comment_add.png'),
578 'push': (_('[pushed] into'),
586 'push': (_('[pushed] into'),
579 get_cs_links, 'script_add.png'),
587 get_cs_links, 'script_add.png'),
580 'push_local': (_('[committed via RhodeCode] into repository'),
588 'push_local': (_('[committed via RhodeCode] into repository'),
581 get_cs_links, 'script_edit.png'),
589 get_cs_links, 'script_edit.png'),
582 'push_remote': (_('[pulled from remote] into repository'),
590 'push_remote': (_('[pulled from remote] into repository'),
583 get_cs_links, 'connect.png'),
591 get_cs_links, 'connect.png'),
584 'pull': (_('[pulled] from'),
592 'pull': (_('[pulled] from'),
585 None, 'down_16.png'),
593 None, 'down_16.png'),
586 'started_following_repo': (_('[started following] repository'),
594 'started_following_repo': (_('[started following] repository'),
587 None, 'heart_add.png'),
595 None, 'heart_add.png'),
588 'stopped_following_repo': (_('[stopped following] repository'),
596 'stopped_following_repo': (_('[stopped following] repository'),
589 None, 'heart_delete.png'),
597 None, 'heart_delete.png'),
590 }
598 }
591
599
592 action_str = action_map.get(action, action)
600 action_str = action_map.get(action, action)
593 if feed:
601 if feed:
594 action = action_str[0].replace('[', '').replace(']', '')
602 action = action_str[0].replace('[', '').replace(']', '')
595 else:
603 else:
596 action = action_str[0]\
604 action = action_str[0]\
597 .replace('[', '<span class="journal_highlight">')\
605 .replace('[', '<span class="journal_highlight">')\
598 .replace(']', '</span>')
606 .replace(']', '</span>')
599
607
600 action_params_func = lambda: ""
608 action_params_func = lambda: ""
601
609
602 if callable(action_str[1]):
610 if callable(action_str[1]):
603 action_params_func = action_str[1]
611 action_params_func = action_str[1]
604
612
605 def action_parser_icon():
613 def action_parser_icon():
606 action = user_log.action
614 action = user_log.action
607 action_params = None
615 action_params = None
608 x = action.split(':')
616 x = action.split(':')
609
617
610 if len(x) > 1:
618 if len(x) > 1:
611 action, action_params = x
619 action, action_params = x
612
620
613 tmpl = """<img src="%s%s" alt="%s"/>"""
621 tmpl = """<img src="%s%s" alt="%s"/>"""
614 ico = action_map.get(action, ['', '', ''])[2]
622 ico = action_map.get(action, ['', '', ''])[2]
615 return literal(tmpl % ((url('/images/icons/')), ico, action))
623 return literal(tmpl % ((url('/images/icons/')), ico, action))
616
624
617 # returned callbacks we need to call to get
625 # returned callbacks we need to call to get
618 return [lambda: literal(action), action_params_func, action_parser_icon]
626 return [lambda: literal(action), action_params_func, action_parser_icon]
619
627
620
628
621
629
622 #==============================================================================
630 #==============================================================================
623 # PERMS
631 # PERMS
624 #==============================================================================
632 #==============================================================================
625 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
633 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
626 HasRepoPermissionAny, HasRepoPermissionAll
634 HasRepoPermissionAny, HasRepoPermissionAll
627
635
628
636
629 #==============================================================================
637 #==============================================================================
630 # GRAVATAR URL
638 # GRAVATAR URL
631 #==============================================================================
639 #==============================================================================
632
640
633 def gravatar_url(email_address, size=30):
641 def gravatar_url(email_address, size=30):
634 if (not str2bool(config['app_conf'].get('use_gravatar')) or
642 if (not str2bool(config['app_conf'].get('use_gravatar')) or
635 not email_address or email_address == 'anonymous@rhodecode.org'):
643 not email_address or email_address == 'anonymous@rhodecode.org'):
636 f = lambda a, l: min(l, key=lambda x: abs(x - a))
644 f = lambda a, l: min(l, key=lambda x: abs(x - a))
637 return url("/images/user%s.png" % f(size, [14, 16, 20, 24, 30]))
645 return url("/images/user%s.png" % f(size, [14, 16, 20, 24, 30]))
638
646
639 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
647 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
640 default = 'identicon'
648 default = 'identicon'
641 baseurl_nossl = "http://www.gravatar.com/avatar/"
649 baseurl_nossl = "http://www.gravatar.com/avatar/"
642 baseurl_ssl = "https://secure.gravatar.com/avatar/"
650 baseurl_ssl = "https://secure.gravatar.com/avatar/"
643 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
651 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
644
652
645 if isinstance(email_address, unicode):
653 if isinstance(email_address, unicode):
646 #hashlib crashes on unicode items
654 #hashlib crashes on unicode items
647 email_address = safe_str(email_address)
655 email_address = safe_str(email_address)
648 # construct the url
656 # construct the url
649 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
657 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
650 gravatar_url += urllib.urlencode({'d': default, 's': str(size)})
658 gravatar_url += urllib.urlencode({'d': default, 's': str(size)})
651
659
652 return gravatar_url
660 return gravatar_url
653
661
654
662
655 #==============================================================================
663 #==============================================================================
656 # REPO PAGER, PAGER FOR REPOSITORY
664 # REPO PAGER, PAGER FOR REPOSITORY
657 #==============================================================================
665 #==============================================================================
658 class RepoPage(Page):
666 class RepoPage(Page):
659
667
660 def __init__(self, collection, page=1, items_per_page=20,
668 def __init__(self, collection, page=1, items_per_page=20,
661 item_count=None, url=None, **kwargs):
669 item_count=None, url=None, **kwargs):
662
670
663 """Create a "RepoPage" instance. special pager for paging
671 """Create a "RepoPage" instance. special pager for paging
664 repository
672 repository
665 """
673 """
666 self._url_generator = url
674 self._url_generator = url
667
675
668 # Safe the kwargs class-wide so they can be used in the pager() method
676 # Safe the kwargs class-wide so they can be used in the pager() method
669 self.kwargs = kwargs
677 self.kwargs = kwargs
670
678
671 # Save a reference to the collection
679 # Save a reference to the collection
672 self.original_collection = collection
680 self.original_collection = collection
673
681
674 self.collection = collection
682 self.collection = collection
675
683
676 # The self.page is the number of the current page.
684 # The self.page is the number of the current page.
677 # The first page has the number 1!
685 # The first page has the number 1!
678 try:
686 try:
679 self.page = int(page) # make it int() if we get it as a string
687 self.page = int(page) # make it int() if we get it as a string
680 except (ValueError, TypeError):
688 except (ValueError, TypeError):
681 self.page = 1
689 self.page = 1
682
690
683 self.items_per_page = items_per_page
691 self.items_per_page = items_per_page
684
692
685 # Unless the user tells us how many items the collections has
693 # Unless the user tells us how many items the collections has
686 # we calculate that ourselves.
694 # we calculate that ourselves.
687 if item_count is not None:
695 if item_count is not None:
688 self.item_count = item_count
696 self.item_count = item_count
689 else:
697 else:
690 self.item_count = len(self.collection)
698 self.item_count = len(self.collection)
691
699
692 # Compute the number of the first and last available page
700 # Compute the number of the first and last available page
693 if self.item_count > 0:
701 if self.item_count > 0:
694 self.first_page = 1
702 self.first_page = 1
695 self.page_count = int(math.ceil(float(self.item_count) /
703 self.page_count = int(math.ceil(float(self.item_count) /
696 self.items_per_page))
704 self.items_per_page))
697 self.last_page = self.first_page + self.page_count - 1
705 self.last_page = self.first_page + self.page_count - 1
698
706
699 # Make sure that the requested page number is the range of
707 # Make sure that the requested page number is the range of
700 # valid pages
708 # valid pages
701 if self.page > self.last_page:
709 if self.page > self.last_page:
702 self.page = self.last_page
710 self.page = self.last_page
703 elif self.page < self.first_page:
711 elif self.page < self.first_page:
704 self.page = self.first_page
712 self.page = self.first_page
705
713
706 # Note: the number of items on this page can be less than
714 # Note: the number of items on this page can be less than
707 # items_per_page if the last page is not full
715 # items_per_page if the last page is not full
708 self.first_item = max(0, (self.item_count) - (self.page *
716 self.first_item = max(0, (self.item_count) - (self.page *
709 items_per_page))
717 items_per_page))
710 self.last_item = ((self.item_count - 1) - items_per_page *
718 self.last_item = ((self.item_count - 1) - items_per_page *
711 (self.page - 1))
719 (self.page - 1))
712
720
713 self.items = list(self.collection[self.first_item:self.last_item + 1])
721 self.items = list(self.collection[self.first_item:self.last_item + 1])
714
722
715 # Links to previous and next page
723 # Links to previous and next page
716 if self.page > self.first_page:
724 if self.page > self.first_page:
717 self.previous_page = self.page - 1
725 self.previous_page = self.page - 1
718 else:
726 else:
719 self.previous_page = None
727 self.previous_page = None
720
728
721 if self.page < self.last_page:
729 if self.page < self.last_page:
722 self.next_page = self.page + 1
730 self.next_page = self.page + 1
723 else:
731 else:
724 self.next_page = None
732 self.next_page = None
725
733
726 # No items available
734 # No items available
727 else:
735 else:
728 self.first_page = None
736 self.first_page = None
729 self.page_count = 0
737 self.page_count = 0
730 self.last_page = None
738 self.last_page = None
731 self.first_item = None
739 self.first_item = None
732 self.last_item = None
740 self.last_item = None
733 self.previous_page = None
741 self.previous_page = None
734 self.next_page = None
742 self.next_page = None
735 self.items = []
743 self.items = []
736
744
737 # This is a subclass of the 'list' type. Initialise the list now.
745 # This is a subclass of the 'list' type. Initialise the list now.
738 list.__init__(self, reversed(self.items))
746 list.__init__(self, reversed(self.items))
739
747
740
748
741 def changed_tooltip(nodes):
749 def changed_tooltip(nodes):
742 """
750 """
743 Generates a html string for changed nodes in changeset page.
751 Generates a html string for changed nodes in changeset page.
744 It limits the output to 30 entries
752 It limits the output to 30 entries
745
753
746 :param nodes: LazyNodesGenerator
754 :param nodes: LazyNodesGenerator
747 """
755 """
748 if nodes:
756 if nodes:
749 pref = ': <br/> '
757 pref = ': <br/> '
750 suf = ''
758 suf = ''
751 if len(nodes) > 30:
759 if len(nodes) > 30:
752 suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
760 suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
753 return literal(pref + '<br/> '.join([safe_unicode(x.path)
761 return literal(pref + '<br/> '.join([safe_unicode(x.path)
754 for x in nodes[:30]]) + suf)
762 for x in nodes[:30]]) + suf)
755 else:
763 else:
756 return ': ' + _('No Files')
764 return ': ' + _('No Files')
757
765
758
766
759 def repo_link(groups_and_repos):
767 def repo_link(groups_and_repos):
760 """
768 """
761 Makes a breadcrumbs link to repo within a group
769 Makes a breadcrumbs link to repo within a group
762 joins &raquo; on each group to create a fancy link
770 joins &raquo; on each group to create a fancy link
763
771
764 ex::
772 ex::
765 group >> subgroup >> repo
773 group >> subgroup >> repo
766
774
767 :param groups_and_repos:
775 :param groups_and_repos:
768 """
776 """
769 groups, repo_name = groups_and_repos
777 groups, repo_name = groups_and_repos
770
778
771 if not groups:
779 if not groups:
772 return repo_name
780 return repo_name
773 else:
781 else:
774 def make_link(group):
782 def make_link(group):
775 return link_to(group.name, url('repos_group_home',
783 return link_to(group.name, url('repos_group_home',
776 group_name=group.group_name))
784 group_name=group.group_name))
777 return literal(' &raquo; '.join(map(make_link, groups)) + \
785 return literal(' &raquo; '.join(map(make_link, groups)) + \
778 " &raquo; " + repo_name)
786 " &raquo; " + repo_name)
779
787
780
788
781 def fancy_file_stats(stats):
789 def fancy_file_stats(stats):
782 """
790 """
783 Displays a fancy two colored bar for number of added/deleted
791 Displays a fancy two colored bar for number of added/deleted
784 lines of code on file
792 lines of code on file
785
793
786 :param stats: two element list of added/deleted lines of code
794 :param stats: two element list of added/deleted lines of code
787 """
795 """
788
796
789 a, d, t = stats[0], stats[1], stats[0] + stats[1]
797 a, d, t = stats[0], stats[1], stats[0] + stats[1]
790 width = 100
798 width = 100
791 unit = float(width) / (t or 1)
799 unit = float(width) / (t or 1)
792
800
793 # needs > 9% of width to be visible or 0 to be hidden
801 # needs > 9% of width to be visible or 0 to be hidden
794 a_p = max(9, unit * a) if a > 0 else 0
802 a_p = max(9, unit * a) if a > 0 else 0
795 d_p = max(9, unit * d) if d > 0 else 0
803 d_p = max(9, unit * d) if d > 0 else 0
796 p_sum = a_p + d_p
804 p_sum = a_p + d_p
797
805
798 if p_sum > width:
806 if p_sum > width:
799 #adjust the percentage to be == 100% since we adjusted to 9
807 #adjust the percentage to be == 100% since we adjusted to 9
800 if a_p > d_p:
808 if a_p > d_p:
801 a_p = a_p - (p_sum - width)
809 a_p = a_p - (p_sum - width)
802 else:
810 else:
803 d_p = d_p - (p_sum - width)
811 d_p = d_p - (p_sum - width)
804
812
805 a_v = a if a > 0 else ''
813 a_v = a if a > 0 else ''
806 d_v = d if d > 0 else ''
814 d_v = d if d > 0 else ''
807
815
808 def cgen(l_type):
816 def cgen(l_type):
809 mapping = {'tr': 'top-right-rounded-corner-mid',
817 mapping = {'tr': 'top-right-rounded-corner-mid',
810 'tl': 'top-left-rounded-corner-mid',
818 'tl': 'top-left-rounded-corner-mid',
811 'br': 'bottom-right-rounded-corner-mid',
819 'br': 'bottom-right-rounded-corner-mid',
812 'bl': 'bottom-left-rounded-corner-mid'}
820 'bl': 'bottom-left-rounded-corner-mid'}
813 map_getter = lambda x: mapping[x]
821 map_getter = lambda x: mapping[x]
814
822
815 if l_type == 'a' and d_v:
823 if l_type == 'a' and d_v:
816 #case when added and deleted are present
824 #case when added and deleted are present
817 return ' '.join(map(map_getter, ['tl', 'bl']))
825 return ' '.join(map(map_getter, ['tl', 'bl']))
818
826
819 if l_type == 'a' and not d_v:
827 if l_type == 'a' and not d_v:
820 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
828 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
821
829
822 if l_type == 'd' and a_v:
830 if l_type == 'd' and a_v:
823 return ' '.join(map(map_getter, ['tr', 'br']))
831 return ' '.join(map(map_getter, ['tr', 'br']))
824
832
825 if l_type == 'd' and not a_v:
833 if l_type == 'd' and not a_v:
826 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
834 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
827
835
828 d_a = '<div class="added %s" style="width:%s%%">%s</div>' % (
836 d_a = '<div class="added %s" style="width:%s%%">%s</div>' % (
829 cgen('a'), a_p, a_v
837 cgen('a'), a_p, a_v
830 )
838 )
831 d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % (
839 d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % (
832 cgen('d'), d_p, d_v
840 cgen('d'), d_p, d_v
833 )
841 )
834 return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
842 return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
835
843
836
844
837 def urlify_text(text_):
845 def urlify_text(text_):
838 import re
846 import re
839
847
840 url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'''
848 url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'''
841 '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''')
849 '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''')
842
850
843 def url_func(match_obj):
851 def url_func(match_obj):
844 url_full = match_obj.groups()[0]
852 url_full = match_obj.groups()[0]
845 return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
853 return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
846
854
847 return literal(url_pat.sub(url_func, text_))
855 return literal(url_pat.sub(url_func, text_))
848
856
849
857
850 def urlify_changesets(text_, repository):
858 def urlify_changesets(text_, repository):
851 """
859 """
852 Extract revision ids from changeset and make link from them
860 Extract revision ids from changeset and make link from them
853
861
854 :param text_:
862 :param text_:
855 :param repository:
863 :param repository:
856 """
864 """
857 import re
865 import re
858 URL_PAT = re.compile(r'([0-9a-fA-F]{12,})')
866 URL_PAT = re.compile(r'([0-9a-fA-F]{12,})')
859
867
860 def url_func(match_obj):
868 def url_func(match_obj):
861 rev = match_obj.groups()[0]
869 rev = match_obj.groups()[0]
862 pref = ''
870 pref = ''
863 if match_obj.group().startswith(' '):
871 if match_obj.group().startswith(' '):
864 pref = ' '
872 pref = ' '
865 tmpl = (
873 tmpl = (
866 '%(pref)s<a class="%(cls)s" href="%(url)s">'
874 '%(pref)s<a class="%(cls)s" href="%(url)s">'
867 '%(rev)s'
875 '%(rev)s'
868 '</a>'
876 '</a>'
869 )
877 )
870 return tmpl % {
878 return tmpl % {
871 'pref': pref,
879 'pref': pref,
872 'cls': 'revision-link',
880 'cls': 'revision-link',
873 'url': url('changeset_home', repo_name=repository, revision=rev),
881 'url': url('changeset_home', repo_name=repository, revision=rev),
874 'rev': rev,
882 'rev': rev,
875 }
883 }
876
884
877 newtext = URL_PAT.sub(url_func, text_)
885 newtext = URL_PAT.sub(url_func, text_)
878
886
879 return newtext
887 return newtext
880
888
881
889
882 def urlify_commit(text_, repository=None, link_=None):
890 def urlify_commit(text_, repository=None, link_=None):
883 """
891 """
884 Parses given text message and makes proper links.
892 Parses given text message and makes proper links.
885 issues are linked to given issue-server, and rest is a changeset link
893 issues are linked to given issue-server, and rest is a changeset link
886 if link_ is given, in other case it's a plain text
894 if link_ is given, in other case it's a plain text
887
895
888 :param text_:
896 :param text_:
889 :param repository:
897 :param repository:
890 :param link_: changeset link
898 :param link_: changeset link
891 """
899 """
892 import re
900 import re
893 import traceback
901 import traceback
894
902
895 def escaper(string):
903 def escaper(string):
896 return string.replace('<', '&lt;').replace('>', '&gt;')
904 return string.replace('<', '&lt;').replace('>', '&gt;')
897
905
898 def linkify_others(t, l):
906 def linkify_others(t, l):
899 urls = re.compile(r'(\<a.*?\<\/a\>)',)
907 urls = re.compile(r'(\<a.*?\<\/a\>)',)
900 links = []
908 links = []
901 for e in urls.split(t):
909 for e in urls.split(t):
902 if not urls.match(e):
910 if not urls.match(e):
903 links.append('<a class="message-link" href="%s">%s</a>' % (l, e))
911 links.append('<a class="message-link" href="%s">%s</a>' % (l, e))
904 else:
912 else:
905 links.append(e)
913 links.append(e)
906
914
907 return ''.join(links)
915 return ''.join(links)
908
916
909 # urlify changesets - extrac revisions and make link out of them
917 # urlify changesets - extrac revisions and make link out of them
910 text_ = urlify_changesets(escaper(text_), repository)
918 text_ = urlify_changesets(escaper(text_), repository)
911
919
912 try:
920 try:
913 conf = config['app_conf']
921 conf = config['app_conf']
914
922
915 URL_PAT = re.compile(r'%s' % conf.get('issue_pat'))
923 URL_PAT = re.compile(r'%s' % conf.get('issue_pat'))
916
924
917 if URL_PAT:
925 if URL_PAT:
918 ISSUE_SERVER_LNK = conf.get('issue_server_link')
926 ISSUE_SERVER_LNK = conf.get('issue_server_link')
919 ISSUE_PREFIX = conf.get('issue_prefix')
927 ISSUE_PREFIX = conf.get('issue_prefix')
920
928
921 def url_func(match_obj):
929 def url_func(match_obj):
922 pref = ''
930 pref = ''
923 if match_obj.group().startswith(' '):
931 if match_obj.group().startswith(' '):
924 pref = ' '
932 pref = ' '
925
933
926 issue_id = ''.join(match_obj.groups())
934 issue_id = ''.join(match_obj.groups())
927 tmpl = (
935 tmpl = (
928 '%(pref)s<a class="%(cls)s" href="%(url)s">'
936 '%(pref)s<a class="%(cls)s" href="%(url)s">'
929 '%(issue-prefix)s%(id-repr)s'
937 '%(issue-prefix)s%(id-repr)s'
930 '</a>'
938 '</a>'
931 )
939 )
932 url = ISSUE_SERVER_LNK.replace('{id}', issue_id)
940 url = ISSUE_SERVER_LNK.replace('{id}', issue_id)
933 if repository:
941 if repository:
934 url = url.replace('{repo}', repository)
942 url = url.replace('{repo}', repository)
935 repo_name = repository.split(URL_SEP)[-1]
943 repo_name = repository.split(URL_SEP)[-1]
936 url = url.replace('{repo_name}', repo_name)
944 url = url.replace('{repo_name}', repo_name)
937 return tmpl % {
945 return tmpl % {
938 'pref': pref,
946 'pref': pref,
939 'cls': 'issue-tracker-link',
947 'cls': 'issue-tracker-link',
940 'url': url,
948 'url': url,
941 'id-repr': issue_id,
949 'id-repr': issue_id,
942 'issue-prefix': ISSUE_PREFIX,
950 'issue-prefix': ISSUE_PREFIX,
943 'serv': ISSUE_SERVER_LNK,
951 'serv': ISSUE_SERVER_LNK,
944 }
952 }
945
953
946 newtext = URL_PAT.sub(url_func, text_)
954 newtext = URL_PAT.sub(url_func, text_)
947
955
948 if link_:
956 if link_:
949 # wrap not links into final link => link_
957 # wrap not links into final link => link_
950 newtext = linkify_others(newtext, link_)
958 newtext = linkify_others(newtext, link_)
951
959
952 return literal(newtext)
960 return literal(newtext)
953 except:
961 except:
954 log.error(traceback.format_exc())
962 log.error(traceback.format_exc())
955 pass
963 pass
956
964
957 return text_
965 return text_
958
966
959
967
960 def rst(source):
968 def rst(source):
961 return literal('<div class="rst-block">%s</div>' %
969 return literal('<div class="rst-block">%s</div>' %
962 MarkupRenderer.rst(source))
970 MarkupRenderer.rst(source))
963
971
964
972
965 def rst_w_mentions(source):
973 def rst_w_mentions(source):
966 """
974 """
967 Wrapped rst renderer with @mention highlighting
975 Wrapped rst renderer with @mention highlighting
968
976
969 :param source:
977 :param source:
970 """
978 """
971 return literal('<div class="rst-block">%s</div>' %
979 return literal('<div class="rst-block">%s</div>' %
972 MarkupRenderer.rst_with_mentions(source))
980 MarkupRenderer.rst_with_mentions(source))
@@ -1,54 +1,54
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 %if c.users_log:
2 %if c.users_log:
3 <table>
3 <table>
4 <tr>
4 <tr>
5 <th class="left">${_('Username')}</th>
5 <th class="left">${_('Username')}</th>
6 <th class="left">${_('Action')}</th>
6 <th class="left">${_('Action')}</th>
7 <th class="left">${_('Repository')}</th>
7 <th class="left">${_('Repository')}</th>
8 <th class="left">${_('Date')}</th>
8 <th class="left">${_('Date')}</th>
9 <th class="left">${_('From IP')}</th>
9 <th class="left">${_('From IP')}</th>
10 </tr>
10 </tr>
11
11
12 %for cnt,l in enumerate(c.users_log):
12 %for cnt,l in enumerate(c.users_log):
13 <tr class="parity${cnt%2}">
13 <tr class="parity${cnt%2}">
14 <td>${h.link_to(l.user.username,h.url('edit_user', id=l.user.user_id))}</td>
14 <td>${h.link_to(l.user.username,h.url('edit_user', id=l.user.user_id))}</td>
15 <td>${h.action_parser(l)[0]()}
15 <td>${h.action_parser(l)[0]()}
16 <div class="journal_action_params">
16 <div class="journal_action_params">
17 ${h.literal(h.action_parser(l)[1]())}
17 ${h.literal(h.action_parser(l)[1]())}
18 </div>
18 </div>
19 </td>
19 </td>
20 <td>
20 <td>
21 %if l.repository is not None:
21 %if l.repository is not None:
22 ${h.link_to(l.repository.repo_name,h.url('summary_home',repo_name=l.repository.repo_name))}
22 ${h.link_to(l.repository.repo_name,h.url('summary_home',repo_name=l.repository.repo_name))}
23 %else:
23 %else:
24 ${l.repository_name}
24 ${l.repository_name}
25 %endif
25 %endif
26 </td>
26 </td>
27
27
28 <td>${l.action_date}</td>
28 <td>${h.fmt_date(l.action_date)}</td>
29 <td>${l.user_ip}</td>
29 <td>${l.user_ip}</td>
30 </tr>
30 </tr>
31 %endfor
31 %endfor
32 </table>
32 </table>
33
33
34 <script type="text/javascript">
34 <script type="text/javascript">
35 YUE.onDOMReady(function(){
35 YUE.onDOMReady(function(){
36 YUE.delegate("user_log","click",function(e, matchedEl, container){
36 YUE.delegate("user_log","click",function(e, matchedEl, container){
37 ypjax(e.target.href,"user_log",function(){show_more_event();tooltip_activate();});
37 ypjax(e.target.href,"user_log",function(){show_more_event();tooltip_activate();});
38 YUE.preventDefault(e);
38 YUE.preventDefault(e);
39 },'.pager_link');
39 },'.pager_link');
40
40
41 YUE.delegate("user_log","click",function(e,matchedEl,container){
41 YUE.delegate("user_log","click",function(e,matchedEl,container){
42 var el = e.target;
42 var el = e.target;
43 YUD.setStyle(YUD.get(el.id.substring(1)),'display','');
43 YUD.setStyle(YUD.get(el.id.substring(1)),'display','');
44 YUD.setStyle(el.parentNode,'display','none');
44 YUD.setStyle(el.parentNode,'display','none');
45 },'.show_more');
45 },'.show_more');
46 });
46 });
47 </script>
47 </script>
48
48
49 <div class="pagination-wh pagination-left">
49 <div class="pagination-wh pagination-left">
50 ${c.users_log.pager('$link_previous ~2~ $link_next')}
50 ${c.users_log.pager('$link_previous ~2~ $link_next')}
51 </div>
51 </div>
52 %else:
52 %else:
53 ${_('No actions yet')}
53 ${_('No actions yet')}
54 %endif
54 %endif
@@ -1,65 +1,65
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Users administration')} - ${c.rhodecode_name}
5 ${_('Users administration')} - ${c.rhodecode_name}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
9 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; ${_('Users')}
9 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; ${_('Users')}
10 </%def>
10 </%def>
11
11
12 <%def name="page_nav()">
12 <%def name="page_nav()">
13 ${self.menu('admin')}
13 ${self.menu('admin')}
14 </%def>
14 </%def>
15
15
16 <%def name="main()">
16 <%def name="main()">
17 <div class="box">
17 <div class="box">
18 <!-- box / title -->
18 <!-- box / title -->
19 <div class="title">
19 <div class="title">
20 ${self.breadcrumbs()}
20 ${self.breadcrumbs()}
21 <ul class="links">
21 <ul class="links">
22 <li>
22 <li>
23 <span>${h.link_to(_(u'ADD NEW USER'),h.url('new_user'))}</span>
23 <span>${h.link_to(_(u'ADD NEW USER'),h.url('new_user'))}</span>
24 </li>
24 </li>
25
25
26 </ul>
26 </ul>
27 </div>
27 </div>
28 <!-- end box / title -->
28 <!-- end box / title -->
29 <div class="table">
29 <div class="table">
30 <table class="table_disp">
30 <table class="table_disp">
31 <tr class="header">
31 <tr class="header">
32 <th></th>
32 <th></th>
33 <th class="left">${_('username')}</th>
33 <th class="left">${_('username')}</th>
34 <th class="left">${_('name')}</th>
34 <th class="left">${_('name')}</th>
35 <th class="left">${_('lastname')}</th>
35 <th class="left">${_('lastname')}</th>
36 <th class="left">${_('last login')}</th>
36 <th class="left">${_('last login')}</th>
37 <th class="left">${_('active')}</th>
37 <th class="left">${_('active')}</th>
38 <th class="left">${_('admin')}</th>
38 <th class="left">${_('admin')}</th>
39 <th class="left">${_('ldap')}</th>
39 <th class="left">${_('ldap')}</th>
40 <th class="left">${_('action')}</th>
40 <th class="left">${_('action')}</th>
41 </tr>
41 </tr>
42 %for cnt,user in enumerate(c.users_list):
42 %for cnt,user in enumerate(c.users_list):
43 %if user.username !='default':
43 %if user.username !='default':
44 <tr class="parity${cnt%2}">
44 <tr class="parity${cnt%2}">
45 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(user.email,24)}"/> </div></td>
45 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(user.email,24)}"/> </div></td>
46 <td>${h.link_to(user.username,h.url('edit_user', id=user.user_id))}</td>
46 <td>${h.link_to(user.username,h.url('edit_user', id=user.user_id))}</td>
47 <td>${user.name}</td>
47 <td>${user.name}</td>
48 <td>${user.lastname}</td>
48 <td>${user.lastname}</td>
49 <td>${user.last_login}</td>
49 <td>${h.fmt_date(user.last_login)}</td>
50 <td>${h.bool2icon(user.active)}</td>
50 <td>${h.bool2icon(user.active)}</td>
51 <td>${h.bool2icon(user.admin)}</td>
51 <td>${h.bool2icon(user.admin)}</td>
52 <td>${h.bool2icon(bool(user.ldap_dn))}</td>
52 <td>${h.bool2icon(bool(user.ldap_dn))}</td>
53 <td>
53 <td>
54 ${h.form(url('delete_user', id=user.user_id),method='delete')}
54 ${h.form(url('delete_user', id=user.user_id),method='delete')}
55 ${h.submit('remove_',_('delete'),id="remove_user_%s" % user.user_id,
55 ${h.submit('remove_',_('delete'),id="remove_user_%s" % user.user_id,
56 class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this user: %s') % user.username+"');")}
56 class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this user: %s') % user.username+"');")}
57 ${h.end_form()}
57 ${h.end_form()}
58 </td>
58 </td>
59 </tr>
59 </tr>
60 %endif
60 %endif
61 %endfor
61 %endfor
62 </table>
62 </table>
63 </div>
63 </div>
64 </div>
64 </div>
65 </%def>
65 </%def>
@@ -1,33 +1,33
1 %if c.repo_bookmarks:
1 %if c.repo_bookmarks:
2 <div id="table_wrap" class="yui-skin-sam">
2 <div id="table_wrap" class="yui-skin-sam">
3 <table id="bookmarks_data">
3 <table id="bookmarks_data">
4 <thead>
4 <thead>
5 <tr>
5 <tr>
6 <th class="left">${_('Name')}</th>
6 <th class="left">${_('Name')}</th>
7 <th class="left">${_('Date')}</th>
7 <th class="left">${_('Date')}</th>
8 <th class="left">${_('Author')}</th>
8 <th class="left">${_('Author')}</th>
9 <th class="left">${_('Revision')}</th>
9 <th class="left">${_('Revision')}</th>
10 </tr>
10 </tr>
11 </thead>
11 </thead>
12 %for cnt,book in enumerate(c.repo_bookmarks.items()):
12 %for cnt,book in enumerate(c.repo_bookmarks.items()):
13 <tr class="parity${cnt%2}">
13 <tr class="parity${cnt%2}">
14 <td>
14 <td>
15 <span class="logbooks">
15 <span class="logbooks">
16 <span class="bookbook">${h.link_to(book[0],
16 <span class="bookbook">${h.link_to(book[0],
17 h.url('files_home',repo_name=c.repo_name,revision=book[1].raw_id))}</span>
17 h.url('files_home',repo_name=c.repo_name,revision=book[1].raw_id))}</span>
18 </span>
18 </span>
19 </td>
19 </td>
20 <td><span class="tooltip" title="${h.age(book[1].date)}">${book[1].date}</span></td>
20 <td><span class="tooltip" title="${h.age(book[1].date)}">${h.fmt_date(book[1].date)}</span></td>
21 <td title="${book[1].author}">${h.person(book[1].author)}</td>
21 <td title="${book[1].author}">${h.person(book[1].author)}</td>
22 <td>
22 <td>
23 <div>
23 <div>
24 <pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=book[1].raw_id)}">r${book[1].revision}:${h.short_id(book[1].raw_id)}</a></pre>
24 <pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=book[1].raw_id)}">r${book[1].revision}:${h.short_id(book[1].raw_id)}</a></pre>
25 </div>
25 </div>
26 </td>
26 </td>
27 </tr>
27 </tr>
28 %endfor
28 %endfor
29 </table>
29 </table>
30 </div>
30 </div>
31 %else:
31 %else:
32 ${_('There are no bookmarks yet')}
32 ${_('There are no bookmarks yet')}
33 %endif
33 %endif
@@ -1,52 +1,52
1 %if c.repo_branches:
1 %if c.repo_branches:
2 <div id="table_wrap" class="yui-skin-sam">
2 <div id="table_wrap" class="yui-skin-sam">
3 <table id="branches_data">
3 <table id="branches_data">
4 <thead>
4 <thead>
5 <tr>
5 <tr>
6 <th class="left">${_('name')}</th>
6 <th class="left">${_('name')}</th>
7 <th class="left">${_('date')}</th>
7 <th class="left">${_('date')}</th>
8 <th class="left">${_('author')}</th>
8 <th class="left">${_('author')}</th>
9 <th class="left">${_('revision')}</th>
9 <th class="left">${_('revision')}</th>
10 </tr>
10 </tr>
11 </thead>
11 </thead>
12 %for cnt,branch in enumerate(c.repo_branches.items()):
12 %for cnt,branch in enumerate(c.repo_branches.items()):
13 <tr class="parity${cnt%2}">
13 <tr class="parity${cnt%2}">
14 <td>
14 <td>
15 <span class="logtags">
15 <span class="logtags">
16 <span class="branchtag">${h.link_to(branch[0],
16 <span class="branchtag">${h.link_to(branch[0],
17 h.url('files_home',repo_name=c.repo_name,revision=branch[1].raw_id))}</span>
17 h.url('files_home',repo_name=c.repo_name,revision=branch[1].raw_id))}</span>
18 </span>
18 </span>
19 </td>
19 </td>
20 <td><span class="tooltip" title="${h.age(branch[1].date)}">${branch[1].date}</span></td>
20 <td><span class="tooltip" title="${h.age(branch[1].date)}">${h.fmt_date(branch[1].date)}</span></td>
21 <td title="${branch[1].author}">${h.person(branch[1].author)}</td>
21 <td title="${branch[1].author}">${h.person(branch[1].author)}</td>
22 <td>
22 <td>
23 <div>
23 <div>
24 <pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=branch[1].raw_id)}">r${branch[1].revision}:${h.short_id(branch[1].raw_id)}</a></pre>
24 <pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=branch[1].raw_id)}">r${branch[1].revision}:${h.short_id(branch[1].raw_id)}</a></pre>
25 </div>
25 </div>
26 </td>
26 </td>
27 </tr>
27 </tr>
28 %endfor
28 %endfor
29 % if hasattr(c,'repo_closed_branches') and c.repo_closed_branches:
29 % if hasattr(c,'repo_closed_branches') and c.repo_closed_branches:
30 %for cnt,branch in enumerate(c.repo_closed_branches.items()):
30 %for cnt,branch in enumerate(c.repo_closed_branches.items()):
31 <tr class="parity${cnt%2}">
31 <tr class="parity${cnt%2}">
32 <td>
32 <td>
33 <span class="logtags">
33 <span class="logtags">
34 <span class="branchtag">${h.link_to(branch[0]+' [closed]',
34 <span class="branchtag">${h.link_to(branch[0]+' [closed]',
35 h.url('changeset_home',repo_name=c.repo_name,revision=branch[1].raw_id))}</span>
35 h.url('changeset_home',repo_name=c.repo_name,revision=branch[1].raw_id))}</span>
36 </span>
36 </span>
37 </td>
37 </td>
38 <td><span class="tooltip" title="${h.age(branch[1].date)}">${branch[1].date}</span></td>
38 <td><span class="tooltip" title="${h.age(branch[1].date)}">${h.fmt_date(branch[1].date)}</span></td>
39 <td title="${branch[1].author}">${h.person(branch[1].author)}</td>
39 <td title="${branch[1].author}">${h.person(branch[1].author)}</td>
40 <td>
40 <td>
41 <div>
41 <div>
42 <pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=branch[1].raw_id)}">r${branch[1].revision}:${h.short_id(branch[1].raw_id)}</a></pre>
42 <pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=branch[1].raw_id)}">r${branch[1].revision}:${h.short_id(branch[1].raw_id)}</a></pre>
43 </div>
43 </div>
44 </td>
44 </td>
45 </tr>
45 </tr>
46 %endfor
46 %endfor
47 %endif
47 %endif
48 </table>
48 </table>
49 </div>
49 </div>
50 %else:
50 %else:
51 ${_('There are no branches yet')}
51 ${_('There are no branches yet')}
52 %endif
52 %endif
@@ -1,239 +1,239
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2
2
3 <%inherit file="/base/base.html"/>
3 <%inherit file="/base/base.html"/>
4
4
5 <%def name="title()">
5 <%def name="title()">
6 ${c.repo_name} ${_('Changelog')} - ${c.rhodecode_name}
6 ${c.repo_name} ${_('Changelog')} - ${c.rhodecode_name}
7 </%def>
7 </%def>
8
8
9 <%def name="breadcrumbs_links()">
9 <%def name="breadcrumbs_links()">
10 ${h.link_to(u'Home',h.url('/'))}
10 ${h.link_to(u'Home',h.url('/'))}
11 &raquo;
11 &raquo;
12 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
12 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
13 &raquo;
13 &raquo;
14 <% size = c.size if c.size <= c.total_cs else c.total_cs %>
14 <% size = c.size if c.size <= c.total_cs else c.total_cs %>
15 ${_('Changelog')} - ${ungettext('showing %d out of %d revision', 'showing %d out of %d revisions', size) % (size, c.total_cs)}
15 ${_('Changelog')} - ${ungettext('showing %d out of %d revision', 'showing %d out of %d revisions', size) % (size, c.total_cs)}
16 </%def>
16 </%def>
17
17
18 <%def name="page_nav()">
18 <%def name="page_nav()">
19 ${self.menu('changelog')}
19 ${self.menu('changelog')}
20 </%def>
20 </%def>
21
21
22 <%def name="main()">
22 <%def name="main()">
23 <div class="box">
23 <div class="box">
24 <!-- box / title -->
24 <!-- box / title -->
25 <div class="title">
25 <div class="title">
26 ${self.breadcrumbs()}
26 ${self.breadcrumbs()}
27 </div>
27 </div>
28 <div class="table">
28 <div class="table">
29 % if c.pagination:
29 % if c.pagination:
30 <div id="graph">
30 <div id="graph">
31 <div id="graph_nodes">
31 <div id="graph_nodes">
32 <canvas id="graph_canvas"></canvas>
32 <canvas id="graph_canvas"></canvas>
33 </div>
33 </div>
34 <div id="graph_content">
34 <div id="graph_content">
35 <div class="container_header">
35 <div class="container_header">
36 ${h.form(h.url.current(),method='get')}
36 ${h.form(h.url.current(),method='get')}
37 <div class="info_box" style="float:left">
37 <div class="info_box" style="float:left">
38 ${h.submit('set',_('Show'),class_="ui-btn")}
38 ${h.submit('set',_('Show'),class_="ui-btn")}
39 ${h.text('size',size=1,value=c.size)}
39 ${h.text('size',size=1,value=c.size)}
40 ${_('revisions')}
40 ${_('revisions')}
41 </div>
41 </div>
42 ${h.end_form()}
42 ${h.end_form()}
43 <div id="rev_range_container" style="display:none"></div>
43 <div id="rev_range_container" style="display:none"></div>
44 <div style="float:right">${h.select('branch_filter',c.branch_name,c.branch_filters)}</div>
44 <div style="float:right">${h.select('branch_filter',c.branch_name,c.branch_filters)}</div>
45 </div>
45 </div>
46
46
47 %for cnt,cs in enumerate(c.pagination):
47 %for cnt,cs in enumerate(c.pagination):
48 <div id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}">
48 <div id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}">
49 <div class="left">
49 <div class="left">
50 <div>
50 <div>
51 ${h.checkbox(cs.short_id,class_="changeset_range")}
51 ${h.checkbox(cs.short_id,class_="changeset_range")}
52 <span class="tooltip" title="${h.age(cs.date)}"><a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}"><span class="changeset_id">${cs.revision}:<span class="changeset_hash">${h.short_id(cs.raw_id)}</span></span></a></span>
52 <span class="tooltip" title="${h.age(cs.date)}"><a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}"><span class="changeset_id">${cs.revision}:<span class="changeset_hash">${h.short_id(cs.raw_id)}</span></span></a></span>
53 </div>
53 </div>
54 <div class="author">
54 <div class="author">
55 <div class="gravatar">
55 <div class="gravatar">
56 <img alt="gravatar" src="${h.gravatar_url(h.email(cs.author),16)}"/>
56 <img alt="gravatar" src="${h.gravatar_url(h.email(cs.author),16)}"/>
57 </div>
57 </div>
58 <div title="${cs.author}" class="user">${h.shorter(h.person(cs.author),22)}</div>
58 <div title="${cs.author}" class="user">${h.shorter(h.person(cs.author),22)}</div>
59 </div>
59 </div>
60 <div class="date">${cs.date}</div>
60 <div class="date">${h.fmt_date(cs.date)}</div>
61 </div>
61 </div>
62 <div class="mid">
62 <div class="mid">
63 <div class="message">${h.urlify_commit(h.wrap_paragraphs(cs.message),c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
63 <div class="message">${h.urlify_commit(h.wrap_paragraphs(cs.message),c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
64 <div class="expand"><span class="expandtext">&darr; ${_('show more')} &darr;</span></div>
64 <div class="expand"><span class="expandtext">&darr; ${_('show more')} &darr;</span></div>
65 </div>
65 </div>
66 <div class="right">
66 <div class="right">
67 <div class="changes">
67 <div class="changes">
68 <div id="${cs.raw_id}" style="float:right;" class="changed_total tooltip" title="${_('Affected number of files, click to show more details')}">${len(cs.affected_files)}</div>
68 <div id="${cs.raw_id}" style="float:right;" class="changed_total tooltip" title="${_('Affected number of files, click to show more details')}">${len(cs.affected_files)}</div>
69 <div class="comments-container">
69 <div class="comments-container">
70 %if len(c.comments.get(cs.raw_id,[])) > 0:
70 %if len(c.comments.get(cs.raw_id,[])) > 0:
71 <div class="comments-cnt" title="${('comments')}">
71 <div class="comments-cnt" title="${('comments')}">
72 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
72 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
73 <div class="comments-cnt">${len(c.comments[cs.raw_id])}</div>
73 <div class="comments-cnt">${len(c.comments[cs.raw_id])}</div>
74 <img src="${h.url('/images/icons/comments.png')}">
74 <img src="${h.url('/images/icons/comments.png')}">
75 </a>
75 </a>
76 </div>
76 </div>
77 %endif
77 %endif
78 </div>
78 </div>
79 </div>
79 </div>
80 %if cs.parents:
80 %if cs.parents:
81 %for p_cs in reversed(cs.parents):
81 %for p_cs in reversed(cs.parents):
82 <div class="parent">${_('Parent')}
82 <div class="parent">${_('Parent')}
83 <span class="changeset_id">${p_cs.revision}:<span class="changeset_hash">${h.link_to(h.short_id(p_cs.raw_id),
83 <span class="changeset_id">${p_cs.revision}:<span class="changeset_hash">${h.link_to(h.short_id(p_cs.raw_id),
84 h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}</span></span>
84 h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}</span></span>
85 </div>
85 </div>
86 %endfor
86 %endfor
87 %else:
87 %else:
88 <div class="parent">${_('No parents')}</div>
88 <div class="parent">${_('No parents')}</div>
89 %endif
89 %endif
90
90
91 <span class="logtags">
91 <span class="logtags">
92 %if len(cs.parents)>1:
92 %if len(cs.parents)>1:
93 <span class="merge">${_('merge')}</span>
93 <span class="merge">${_('merge')}</span>
94 %endif
94 %endif
95 %if cs.branch:
95 %if cs.branch:
96 <span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}">
96 <span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}">
97 ${h.link_to(h.shorter(cs.branch),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
97 ${h.link_to(h.shorter(cs.branch),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
98 </span>
98 </span>
99 %endif
99 %endif
100 %if h.is_hg(c.rhodecode_repo):
100 %if h.is_hg(c.rhodecode_repo):
101 %for book in cs.bookmarks:
101 %for book in cs.bookmarks:
102 <span class="bookbook" title="${'%s %s' % (_('bookmark'),book)}">
102 <span class="bookbook" title="${'%s %s' % (_('bookmark'),book)}">
103 ${h.link_to(h.shorter(book),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
103 ${h.link_to(h.shorter(book),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
104 </span>
104 </span>
105 %endfor
105 %endfor
106 %endif
106 %endif
107 %for tag in cs.tags:
107 %for tag in cs.tags:
108 <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
108 <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
109 ${h.link_to(h.shorter(tag),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
109 ${h.link_to(h.shorter(tag),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
110 %endfor
110 %endfor
111 </span>
111 </span>
112 </div>
112 </div>
113 </div>
113 </div>
114
114
115 %endfor
115 %endfor
116 <div class="pagination-wh pagination-left">
116 <div class="pagination-wh pagination-left">
117 ${c.pagination.pager('$link_previous ~2~ $link_next')}
117 ${c.pagination.pager('$link_previous ~2~ $link_next')}
118 </div>
118 </div>
119 </div>
119 </div>
120 </div>
120 </div>
121
121
122 <script type="text/javascript" src="${h.url('/js/graph.js')}"></script>
122 <script type="text/javascript" src="${h.url('/js/graph.js')}"></script>
123 <script type="text/javascript">
123 <script type="text/javascript">
124 YAHOO.util.Event.onDOMReady(function(){
124 YAHOO.util.Event.onDOMReady(function(){
125
125
126 //Monitor range checkboxes and build a link to changesets
126 //Monitor range checkboxes and build a link to changesets
127 //ranges
127 //ranges
128 var checkboxes = YUD.getElementsByClassName('changeset_range');
128 var checkboxes = YUD.getElementsByClassName('changeset_range');
129 var url_tmpl = "${h.url('changeset_home',repo_name=c.repo_name,revision='__REVRANGE__')}";
129 var url_tmpl = "${h.url('changeset_home',repo_name=c.repo_name,revision='__REVRANGE__')}";
130 YUE.on(checkboxes,'click',function(e){
130 YUE.on(checkboxes,'click',function(e){
131 var checked_checkboxes = [];
131 var checked_checkboxes = [];
132 for (pos in checkboxes){
132 for (pos in checkboxes){
133 if(checkboxes[pos].checked){
133 if(checkboxes[pos].checked){
134 checked_checkboxes.push(checkboxes[pos]);
134 checked_checkboxes.push(checkboxes[pos]);
135 }
135 }
136 }
136 }
137 if(checked_checkboxes.length>1){
137 if(checked_checkboxes.length>1){
138 var rev_end = checked_checkboxes[0].name;
138 var rev_end = checked_checkboxes[0].name;
139 var rev_start = checked_checkboxes[checked_checkboxes.length-1].name;
139 var rev_start = checked_checkboxes[checked_checkboxes.length-1].name;
140
140
141 var url = url_tmpl.replace('__REVRANGE__',
141 var url = url_tmpl.replace('__REVRANGE__',
142 rev_start+'...'+rev_end);
142 rev_start+'...'+rev_end);
143
143
144 var link = "<a href="+url+">${_('Show selected changes __S -> __E')}</a>"
144 var link = "<a href="+url+">${_('Show selected changes __S -> __E')}</a>"
145 link = link.replace('__S',rev_start);
145 link = link.replace('__S',rev_start);
146 link = link.replace('__E',rev_end);
146 link = link.replace('__E',rev_end);
147 YUD.get('rev_range_container').innerHTML = link;
147 YUD.get('rev_range_container').innerHTML = link;
148 YUD.setStyle('rev_range_container','display','');
148 YUD.setStyle('rev_range_container','display','');
149 }
149 }
150 else{
150 else{
151 YUD.setStyle('rev_range_container','display','none');
151 YUD.setStyle('rev_range_container','display','none');
152
152
153 }
153 }
154 });
154 });
155
155
156 var msgs = YUQ('.message');
156 var msgs = YUQ('.message');
157 // get first element height
157 // get first element height
158 var el = YUQ('#graph_content .container')[0];
158 var el = YUQ('#graph_content .container')[0];
159 var row_h = el.clientHeight;
159 var row_h = el.clientHeight;
160 for(var i=0;i<msgs.length;i++){
160 for(var i=0;i<msgs.length;i++){
161 var m = msgs[i];
161 var m = msgs[i];
162
162
163 var h = m.clientHeight;
163 var h = m.clientHeight;
164 var pad = YUD.getStyle(m,'padding');
164 var pad = YUD.getStyle(m,'padding');
165 if(h > row_h){
165 if(h > row_h){
166 var offset = row_h - (h+12);
166 var offset = row_h - (h+12);
167 YUD.setStyle(m.nextElementSibling,'display','block');
167 YUD.setStyle(m.nextElementSibling,'display','block');
168 YUD.setStyle(m.nextElementSibling,'margin-top',offset+'px');
168 YUD.setStyle(m.nextElementSibling,'margin-top',offset+'px');
169 };
169 };
170 }
170 }
171 YUE.on(YUQ('.expand'),'click',function(e){
171 YUE.on(YUQ('.expand'),'click',function(e){
172 var elem = e.currentTarget.parentNode.parentNode;
172 var elem = e.currentTarget.parentNode.parentNode;
173 YUD.setStyle(e.currentTarget,'display','none');
173 YUD.setStyle(e.currentTarget,'display','none');
174 YUD.setStyle(elem,'height','auto');
174 YUD.setStyle(elem,'height','auto');
175
175
176 //redraw the graph, max_w and jsdata are global vars
176 //redraw the graph, max_w and jsdata are global vars
177 set_canvas(max_w);
177 set_canvas(max_w);
178
178
179 var r = new BranchRenderer();
179 var r = new BranchRenderer();
180 r.render(jsdata,max_w);
180 r.render(jsdata,max_w);
181
181
182 })
182 })
183
183
184 // Fetch changeset details
184 // Fetch changeset details
185 YUE.on(YUD.getElementsByClassName('changed_total'),'click',function(e){
185 YUE.on(YUD.getElementsByClassName('changed_total'),'click',function(e){
186 var id = e.currentTarget.id
186 var id = e.currentTarget.id
187 var url = "${h.url('changelog_details',repo_name=c.repo_name,cs='__CS__')}"
187 var url = "${h.url('changelog_details',repo_name=c.repo_name,cs='__CS__')}"
188 var url = url.replace('__CS__',id);
188 var url = url.replace('__CS__',id);
189 ypjax(url,id,function(){tooltip_activate()});
189 ypjax(url,id,function(){tooltip_activate()});
190 });
190 });
191
191
192 // change branch filter
192 // change branch filter
193 YUE.on(YUD.get('branch_filter'),'change',function(e){
193 YUE.on(YUD.get('branch_filter'),'change',function(e){
194 var selected_branch = e.currentTarget.options[e.currentTarget.selectedIndex].value;
194 var selected_branch = e.currentTarget.options[e.currentTarget.selectedIndex].value;
195 var url_main = "${h.url('changelog_home',repo_name=c.repo_name)}";
195 var url_main = "${h.url('changelog_home',repo_name=c.repo_name)}";
196 var url = "${h.url('changelog_home',repo_name=c.repo_name,branch='__BRANCH__')}";
196 var url = "${h.url('changelog_home',repo_name=c.repo_name,branch='__BRANCH__')}";
197 var url = url.replace('__BRANCH__',selected_branch);
197 var url = url.replace('__BRANCH__',selected_branch);
198 if(selected_branch != ''){
198 if(selected_branch != ''){
199 window.location = url;
199 window.location = url;
200 }else{
200 }else{
201 window.location = url_main;
201 window.location = url_main;
202 }
202 }
203
203
204 });
204 });
205
205
206 function set_canvas(heads) {
206 function set_canvas(heads) {
207 var c = document.getElementById('graph_nodes');
207 var c = document.getElementById('graph_nodes');
208 var t = document.getElementById('graph_content');
208 var t = document.getElementById('graph_content');
209 canvas = document.getElementById('graph_canvas');
209 canvas = document.getElementById('graph_canvas');
210 var div_h = t.clientHeight;
210 var div_h = t.clientHeight;
211 c.style.height=div_h+'px';
211 c.style.height=div_h+'px';
212 canvas.setAttribute('height',div_h);
212 canvas.setAttribute('height',div_h);
213 c.style.height=max_w+'px';
213 c.style.height=max_w+'px';
214 canvas.setAttribute('width',max_w);
214 canvas.setAttribute('width',max_w);
215 };
215 };
216 var heads = 1;
216 var heads = 1;
217 var max_heads = 0;
217 var max_heads = 0;
218 var jsdata = ${c.jsdata|n};
218 var jsdata = ${c.jsdata|n};
219
219
220 for( var i=0;i<jsdata.length;i++){
220 for( var i=0;i<jsdata.length;i++){
221 var m = Math.max.apply(Math, jsdata[i][1]);
221 var m = Math.max.apply(Math, jsdata[i][1]);
222 if (m>max_heads){
222 if (m>max_heads){
223 max_heads = m;
223 max_heads = m;
224 }
224 }
225 }
225 }
226 var max_w = Math.max(100,max_heads*25);
226 var max_w = Math.max(100,max_heads*25);
227 set_canvas(max_w);
227 set_canvas(max_w);
228
228
229 var r = new BranchRenderer();
229 var r = new BranchRenderer();
230 r.render(jsdata,max_w);
230 r.render(jsdata,max_w);
231
231
232 });
232 });
233 </script>
233 </script>
234 %else:
234 %else:
235 ${_('There are no changes yet')}
235 ${_('There are no changes yet')}
236 %endif
236 %endif
237 </div>
237 </div>
238 </div>
238 </div>
239 </%def>
239 </%def>
@@ -1,167 +1,167
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2
2
3 <%inherit file="/base/base.html"/>
3 <%inherit file="/base/base.html"/>
4
4
5 <%def name="title()">
5 <%def name="title()">
6 ${c.repo_name} ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)} - ${c.rhodecode_name}
6 ${c.repo_name} ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)} - ${c.rhodecode_name}
7 </%def>
7 </%def>
8
8
9 <%def name="breadcrumbs_links()">
9 <%def name="breadcrumbs_links()">
10 ${h.link_to(u'Home',h.url('/'))}
10 ${h.link_to(u'Home',h.url('/'))}
11 &raquo;
11 &raquo;
12 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
12 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
13 &raquo;
13 &raquo;
14 ${_('Changeset')} - <span class='hash'>r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}</span>
14 ${_('Changeset')} - <span class='hash'>r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}</span>
15 </%def>
15 </%def>
16
16
17 <%def name="page_nav()">
17 <%def name="page_nav()">
18 ${self.menu('changelog')}
18 ${self.menu('changelog')}
19 </%def>
19 </%def>
20
20
21 <%def name="main()">
21 <%def name="main()">
22 <div class="box">
22 <div class="box">
23 <!-- box / title -->
23 <!-- box / title -->
24 <div class="title">
24 <div class="title">
25 ${self.breadcrumbs()}
25 ${self.breadcrumbs()}
26 </div>
26 </div>
27 <div class="table">
27 <div class="table">
28 <div class="diffblock">
28 <div class="diffblock">
29 <div class="code-header">
29 <div class="code-header">
30 <div class="hash">
30 <div class="hash">
31 r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
31 r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
32 </div>
32 </div>
33 <div class="date">
33 <div class="date">
34 ${c.changeset.date}
34 ${h.fmt_date(c.changeset.date)}
35 </div>
35 </div>
36 <div class="diff-actions">
36 <div class="diff-actions">
37 <a href="${h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='show')}" title="${_('raw diff')}" class="tooltip"><img class="icon" src="${h.url('/images/icons/page_white.png')}"/></a>
37 <a href="${h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='show')}" title="${_('raw diff')}" class="tooltip"><img class="icon" src="${h.url('/images/icons/page_white.png')}"/></a>
38 <a href="${h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='download')}" title="${_('download diff')}" class="tooltip"><img class="icon" src="${h.url('/images/icons/page_white_get.png')}"/></a>
38 <a href="${h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='download')}" title="${_('download diff')}" class="tooltip"><img class="icon" src="${h.url('/images/icons/page_white_get.png')}"/></a>
39 ${c.ignorews_url(request.GET)}
39 ${c.ignorews_url(request.GET)}
40 ${c.context_url(request.GET)}
40 ${c.context_url(request.GET)}
41 </div>
41 </div>
42 <div class="comments-number" style="float:right;padding-right:5px">${ungettext("%d comment", "%d comments", len(c.comments)) % len(c.comments)} ${ungettext("(%d inline)", "(%d inline)", c.inline_cnt) % c.inline_cnt}</div>
42 <div class="comments-number" style="float:right;padding-right:5px">${ungettext("%d comment", "%d comments", len(c.comments)) % len(c.comments)} ${ungettext("(%d inline)", "(%d inline)", c.inline_cnt) % c.inline_cnt}</div>
43 </div>
43 </div>
44 </div>
44 </div>
45 <div id="changeset_content">
45 <div id="changeset_content">
46 <div class="container">
46 <div class="container">
47 <div class="left">
47 <div class="left">
48 <div class="author">
48 <div class="author">
49 <div class="gravatar">
49 <div class="gravatar">
50 <img alt="gravatar" src="${h.gravatar_url(h.email(c.changeset.author),20)}"/>
50 <img alt="gravatar" src="${h.gravatar_url(h.email(c.changeset.author),20)}"/>
51 </div>
51 </div>
52 <span>${h.person(c.changeset.author)}</span><br/>
52 <span>${h.person(c.changeset.author)}</span><br/>
53 <span><a href="mailto:${h.email_or_none(c.changeset.author)}">${h.email_or_none(c.changeset.author)}</a></span><br/>
53 <span><a href="mailto:${h.email_or_none(c.changeset.author)}">${h.email_or_none(c.changeset.author)}</a></span><br/>
54 </div>
54 </div>
55 <div class="message">${h.urlify_commit(h.wrap_paragraphs(c.changeset.message),c.repo_name)}</div>
55 <div class="message">${h.urlify_commit(h.wrap_paragraphs(c.changeset.message),c.repo_name)}</div>
56 </div>
56 </div>
57 <div class="right">
57 <div class="right">
58 <div class="changes">
58 <div class="changes">
59 % if len(c.changeset.affected_files) <= c.affected_files_cut_off:
59 % if len(c.changeset.affected_files) <= c.affected_files_cut_off:
60 <span class="removed" title="${_('removed')}">${len(c.changeset.removed)}</span>
60 <span class="removed" title="${_('removed')}">${len(c.changeset.removed)}</span>
61 <span class="changed" title="${_('changed')}">${len(c.changeset.changed)}</span>
61 <span class="changed" title="${_('changed')}">${len(c.changeset.changed)}</span>
62 <span class="added" title="${_('added')}">${len(c.changeset.added)}</span>
62 <span class="added" title="${_('added')}">${len(c.changeset.added)}</span>
63 % else:
63 % else:
64 <span class="removed" title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
64 <span class="removed" title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
65 <span class="changed" title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
65 <span class="changed" title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
66 <span class="added" title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
66 <span class="added" title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
67 % endif
67 % endif
68 </div>
68 </div>
69
69
70 %if c.changeset.parents:
70 %if c.changeset.parents:
71 %for p_cs in reversed(c.changeset.parents):
71 %for p_cs in reversed(c.changeset.parents):
72 <div class="parent">${_('Parent')}
72 <div class="parent">${_('Parent')}
73 <span class="changeset_id">${p_cs.revision}:<span class="changeset_hash">${h.link_to(h.short_id(p_cs.raw_id),
73 <span class="changeset_id">${p_cs.revision}:<span class="changeset_hash">${h.link_to(h.short_id(p_cs.raw_id),
74 h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}</span></span>
74 h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}</span></span>
75 </div>
75 </div>
76 %endfor
76 %endfor
77 %else:
77 %else:
78 <div class="parent">${_('No parents')}</div>
78 <div class="parent">${_('No parents')}</div>
79 %endif
79 %endif
80 <span class="logtags">
80 <span class="logtags">
81 %if len(c.changeset.parents)>1:
81 %if len(c.changeset.parents)>1:
82 <span class="merge">${_('merge')}</span>
82 <span class="merge">${_('merge')}</span>
83 %endif
83 %endif
84 %if c.changeset.branch:
84 %if c.changeset.branch:
85 <span class="branchtag" title="${'%s %s' % (_('branch'),c.changeset.branch)}">
85 <span class="branchtag" title="${'%s %s' % (_('branch'),c.changeset.branch)}">
86 ${h.link_to(c.changeset.branch,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}
86 ${h.link_to(c.changeset.branch,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}
87 </span>
87 </span>
88 %endif
88 %endif
89 %for tag in c.changeset.tags:
89 %for tag in c.changeset.tags:
90 <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
90 <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
91 ${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span>
91 ${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span>
92 %endfor
92 %endfor
93 </span>
93 </span>
94 </div>
94 </div>
95 </div>
95 </div>
96 <span>
96 <span>
97 ${_('%s files affected with %s insertions and %s deletions:') % (len(c.changeset.affected_files),c.lines_added,c.lines_deleted)}
97 ${_('%s files affected with %s insertions and %s deletions:') % (len(c.changeset.affected_files),c.lines_added,c.lines_deleted)}
98 </span>
98 </span>
99 <div class="cs_files">
99 <div class="cs_files">
100 %for change,filenode,diff,cs1,cs2,stat in c.changes:
100 %for change,filenode,diff,cs1,cs2,stat in c.changes:
101 <div class="cs_${change}">
101 <div class="cs_${change}">
102 <div class="node">
102 <div class="node">
103 %if change != 'removed':
103 %if change != 'removed':
104 ${h.link_to(h.safe_unicode(filenode.path),c.anchor_url(filenode.changeset.raw_id,filenode.path,request.GET)+"_target")}
104 ${h.link_to(h.safe_unicode(filenode.path),c.anchor_url(filenode.changeset.raw_id,filenode.path,request.GET)+"_target")}
105 %else:
105 %else:
106 ${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor=h.FID('',filenode.path)))}
106 ${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor=h.FID('',filenode.path)))}
107 %endif
107 %endif
108 </div>
108 </div>
109 <div class="changes">${h.fancy_file_stats(stat)}</div>
109 <div class="changes">${h.fancy_file_stats(stat)}</div>
110 </div>
110 </div>
111 %endfor
111 %endfor
112 % if c.cut_off:
112 % if c.cut_off:
113 ${_('Changeset was too big and was cut off...')}
113 ${_('Changeset was too big and was cut off...')}
114 % endif
114 % endif
115 </div>
115 </div>
116 </div>
116 </div>
117
117
118 </div>
118 </div>
119 <script>
119 <script>
120 var _USERS_AC_DATA = ${c.users_array|n};
120 var _USERS_AC_DATA = ${c.users_array|n};
121 var _GROUPS_AC_DATA = ${c.users_groups_array|n};
121 var _GROUPS_AC_DATA = ${c.users_groups_array|n};
122 </script>
122 </script>
123 ## diff block
123 ## diff block
124 <%namespace name="diff_block" file="/changeset/diff_block.html"/>
124 <%namespace name="diff_block" file="/changeset/diff_block.html"/>
125 ${diff_block.diff_block(c.changes)}
125 ${diff_block.diff_block(c.changes)}
126
126
127 ## template for inline comment form
127 ## template for inline comment form
128 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
128 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
129 ${comment.comment_inline_form(c.changeset)}
129 ${comment.comment_inline_form(c.changeset)}
130
130
131 ## render comments
131 ## render comments
132 ${comment.comments(c.changeset)}
132 ${comment.comments(c.changeset)}
133 <script type="text/javascript">
133 <script type="text/javascript">
134 YUE.onDOMReady(function(){
134 YUE.onDOMReady(function(){
135 AJAX_COMMENT_URL = "${url('changeset_comment',repo_name=c.repo_name,revision=c.changeset.raw_id)}";
135 AJAX_COMMENT_URL = "${url('changeset_comment',repo_name=c.repo_name,revision=c.changeset.raw_id)}";
136 AJAX_COMMENT_DELETE_URL = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}"
136 AJAX_COMMENT_DELETE_URL = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}"
137 YUE.on(YUQ('.show-inline-comments'),'change',function(e){
137 YUE.on(YUQ('.show-inline-comments'),'change',function(e){
138 var show = 'none';
138 var show = 'none';
139 var target = e.currentTarget;
139 var target = e.currentTarget;
140 if(target.checked){
140 if(target.checked){
141 var show = ''
141 var show = ''
142 }
142 }
143 var boxid = YUD.getAttribute(target,'id_for');
143 var boxid = YUD.getAttribute(target,'id_for');
144 var comments = YUQ('#{0} .inline-comments'.format(boxid));
144 var comments = YUQ('#{0} .inline-comments'.format(boxid));
145 for(c in comments){
145 for(c in comments){
146 YUD.setStyle(comments[c],'display',show);
146 YUD.setStyle(comments[c],'display',show);
147 }
147 }
148 var btns = YUQ('#{0} .inline-comments-button'.format(boxid));
148 var btns = YUQ('#{0} .inline-comments-button'.format(boxid));
149 for(c in btns){
149 for(c in btns){
150 YUD.setStyle(btns[c],'display',show);
150 YUD.setStyle(btns[c],'display',show);
151 }
151 }
152 })
152 })
153
153
154 YUE.on(YUQ('.line'),'click',function(e){
154 YUE.on(YUQ('.line'),'click',function(e){
155 var tr = e.currentTarget;
155 var tr = e.currentTarget;
156 injectInlineForm(tr);
156 injectInlineForm(tr);
157 });
157 });
158
158
159 // inject comments into they proper positions
159 // inject comments into they proper positions
160 var file_comments = YUQ('.inline-comment-placeholder');
160 var file_comments = YUQ('.inline-comment-placeholder');
161 renderInlineComments(file_comments);
161 renderInlineComments(file_comments);
162 })
162 })
163
163
164 </script>
164 </script>
165
165
166 </div>
166 </div>
167 </%def>
167 </%def>
@@ -1,89 +1,89
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${c.repo_name} ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)} - ${c.rhodecode_name}
5 ${c.repo_name} ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)} - ${c.rhodecode_name}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
9 ${h.link_to(u'Home',h.url('/'))}
9 ${h.link_to(u'Home',h.url('/'))}
10 &raquo;
10 &raquo;
11 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
11 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
12 &raquo;
12 &raquo;
13 ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)}
13 ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)}
14 </%def>
14 </%def>
15
15
16 <%def name="page_nav()">
16 <%def name="page_nav()">
17 ${self.menu('changelog')}
17 ${self.menu('changelog')}
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
21 <div class="box">
21 <div class="box">
22 <!-- box / title -->
22 <!-- box / title -->
23 <div class="title">
23 <div class="title">
24 ${self.breadcrumbs()}
24 ${self.breadcrumbs()}
25 </div>
25 </div>
26 <div class="table">
26 <div class="table">
27 <div id="body" class="diffblock">
27 <div id="body" class="diffblock">
28 <div class="code-header cv">
28 <div class="code-header cv">
29 <h3 class="code-header-title">${_('Compare View')}</h3>
29 <h3 class="code-header-title">${_('Compare View')}</h3>
30 <div>
30 <div>
31 ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)}
31 ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)}
32 </div>
32 </div>
33 </div>
33 </div>
34 </div>
34 </div>
35 <div id="changeset_compare_view_content">
35 <div id="changeset_compare_view_content">
36 <div class="container">
36 <div class="container">
37 <table class="compare_view_commits noborder">
37 <table class="compare_view_commits noborder">
38 %for cs in c.cs_ranges:
38 %for cs in c.cs_ranges:
39 <tr>
39 <tr>
40 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(h.email(cs.author),14)}"/></div></td>
40 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(h.email(cs.author),14)}"/></div></td>
41 <td>${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</td>
41 <td>${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</td>
42 <td><div class="author">${h.person(cs.author)}</div></td>
42 <td><div class="author">${h.person(cs.author)}</div></td>
43 <td><span class="tooltip" title="${h.age(cs.date)}">${cs.date}</span></td>
43 <td><span class="tooltip" title="${h.age(cs.date)}">${h.fmt_date(cs.date)}</span></td>
44 <td><div class="message">${h.urlify_commit(h.wrap_paragraphs(cs.message),c.repo_name)}</div></td>
44 <td><div class="message">${h.urlify_commit(h.wrap_paragraphs(cs.message),c.repo_name)}</div></td>
45 </tr>
45 </tr>
46 %endfor
46 %endfor
47 </table>
47 </table>
48 </div>
48 </div>
49 <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Files affected')}</div>
49 <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Files affected')}</div>
50 <div class="cs_files">
50 <div class="cs_files">
51 %for cs in c.cs_ranges:
51 %for cs in c.cs_ranges:
52 <div class="cur_cs">r${cs}</div>
52 <div class="cur_cs">r${cs}</div>
53 %for change,filenode,diff,cs1,cs2,st in c.changes[cs.raw_id]:
53 %for change,filenode,diff,cs1,cs2,st in c.changes[cs.raw_id]:
54 <div class="cs_${change}">${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor=h.FID(cs.raw_id,filenode.path)))}</div>
54 <div class="cs_${change}">${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor=h.FID(cs.raw_id,filenode.path)))}</div>
55 %endfor
55 %endfor
56 %endfor
56 %endfor
57 </div>
57 </div>
58 </div>
58 </div>
59
59
60 </div>
60 </div>
61 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
61 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
62 <%namespace name="diff_block" file="/changeset/diff_block.html"/>
62 <%namespace name="diff_block" file="/changeset/diff_block.html"/>
63 %for cs in c.cs_ranges:
63 %for cs in c.cs_ranges:
64 ##${comment.comment_inline_form(cs)}
64 ##${comment.comment_inline_form(cs)}
65 ## diff block
65 ## diff block
66 <h3 style="border:none;padding-top:8px;">${'r%s:%s' % (cs.revision,h.short_id(cs.raw_id))}</h3>
66 <h3 style="border:none;padding-top:8px;">${'r%s:%s' % (cs.revision,h.short_id(cs.raw_id))}</h3>
67 ${diff_block.diff_block(c.changes[cs.raw_id])}
67 ${diff_block.diff_block(c.changes[cs.raw_id])}
68 ##${comment.comments(cs)}
68 ##${comment.comments(cs)}
69
69
70 %endfor
70 %endfor
71 <script type="text/javascript">
71 <script type="text/javascript">
72
72
73 YUE.onDOMReady(function(){
73 YUE.onDOMReady(function(){
74
74
75 YUE.on(YUQ('.diff-menu-activate'),'click',function(e){
75 YUE.on(YUQ('.diff-menu-activate'),'click',function(e){
76 var act = e.currentTarget.nextElementSibling;
76 var act = e.currentTarget.nextElementSibling;
77
77
78 if(YUD.hasClass(act,'active')){
78 if(YUD.hasClass(act,'active')){
79 YUD.removeClass(act,'active');
79 YUD.removeClass(act,'active');
80 YUD.setStyle(act,'display','none');
80 YUD.setStyle(act,'display','none');
81 }else{
81 }else{
82 YUD.addClass(act,'active');
82 YUD.addClass(act,'active');
83 YUD.setStyle(act,'display','');
83 YUD.setStyle(act,'display','');
84 }
84 }
85 });
85 });
86 })
86 })
87 </script>
87 </script>
88 </div>
88 </div>
89 </%def>
89 </%def>
@@ -1,116 +1,116
1 <%def name="file_class(node)">
1 <%def name="file_class(node)">
2 %if node.is_file():
2 %if node.is_file():
3 <%return "browser-file" %>
3 <%return "browser-file" %>
4 %else:
4 %else:
5 <%return "browser-dir"%>
5 <%return "browser-dir"%>
6 %endif
6 %endif
7 </%def>
7 </%def>
8 <div id="body" class="browserblock">
8 <div id="body" class="browserblock">
9 <div class="browser-header">
9 <div class="browser-header">
10 <div class="browser-nav">
10 <div class="browser-nav">
11 ${h.form(h.url.current())}
11 ${h.form(h.url.current())}
12 <div class="info_box">
12 <div class="info_box">
13 <span class="rev">${_('view')}@rev</span>
13 <span class="rev">${_('view')}@rev</span>
14 <a class="ui-btn" href="${c.url_prev}" title="${_('previous revision')}">&laquo;</a>
14 <a class="ui-btn" href="${c.url_prev}" title="${_('previous revision')}">&laquo;</a>
15 ${h.text('at_rev',value=c.changeset.revision,size=5)}
15 ${h.text('at_rev',value=c.changeset.revision,size=5)}
16 <a class="ui-btn" href="${c.url_next}" title="${_('next revision')}">&raquo;</a>
16 <a class="ui-btn" href="${c.url_next}" title="${_('next revision')}">&raquo;</a>
17 ## ${h.submit('view',_('view'),class_="ui-btn")}
17 ## ${h.submit('view',_('view'),class_="ui-btn")}
18 </div>
18 </div>
19 ${h.end_form()}
19 ${h.end_form()}
20 </div>
20 </div>
21 <div class="browser-branch">
21 <div class="browser-branch">
22 ${h.checkbox('stay_at_branch',c.changeset.branch,c.changeset.branch==c.branch)}
22 ${h.checkbox('stay_at_branch',c.changeset.branch,c.changeset.branch==c.branch)}
23 <label>${_('follow current branch')}</label>
23 <label>${_('follow current branch')}</label>
24 </div>
24 </div>
25 <div class="browser-search">
25 <div class="browser-search">
26 <div id="search_activate_id" class="search_activate">
26 <div id="search_activate_id" class="search_activate">
27 <a class="ui-btn" id="filter_activate" href="#">${_('search file list')}</a>
27 <a class="ui-btn" id="filter_activate" href="#">${_('search file list')}</a>
28 </div>
28 </div>
29 % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
29 % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
30 <div id="add_node_id" class="add_node">
30 <div id="add_node_id" class="add_node">
31 <a class="ui-btn" href="${h.url('files_add_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path)}">${_('add new file')}</a>
31 <a class="ui-btn" href="${h.url('files_add_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path)}">${_('add new file')}</a>
32 </div>
32 </div>
33 % endif
33 % endif
34 <div>
34 <div>
35 <div id="node_filter_box_loading" style="display:none">${_('Loading file list...')}</div>
35 <div id="node_filter_box_loading" style="display:none">${_('Loading file list...')}</div>
36 <div id="node_filter_box" style="display:none">
36 <div id="node_filter_box" style="display:none">
37 ${h.files_breadcrumbs(c.repo_name,c.changeset.raw_id,c.file.path)}/<input class="init" type="text" value="type to search..." name="filter" size="25" id="node_filter" autocomplete="off">
37 ${h.files_breadcrumbs(c.repo_name,c.changeset.raw_id,c.file.path)}/<input class="init" type="text" value="type to search..." name="filter" size="25" id="node_filter" autocomplete="off">
38 </div>
38 </div>
39 </div>
39 </div>
40 </div>
40 </div>
41 </div>
41 </div>
42
42
43 <div class="browser-body">
43 <div class="browser-body">
44 <table class="code-browser">
44 <table class="code-browser">
45 <thead>
45 <thead>
46 <tr>
46 <tr>
47 <th>${_('Name')}</th>
47 <th>${_('Name')}</th>
48 <th>${_('Size')}</th>
48 <th>${_('Size')}</th>
49 <th>${_('Mimetype')}</th>
49 <th>${_('Mimetype')}</th>
50 <th>${_('Last Revision')}</th>
50 <th>${_('Last Revision')}</th>
51 <th>${_('Last modified')}</th>
51 <th>${_('Last modified')}</th>
52 <th>${_('Last commiter')}</th>
52 <th>${_('Last commiter')}</th>
53 </tr>
53 </tr>
54 </thead>
54 </thead>
55
55
56 <tbody id="tbody">
56 <tbody id="tbody">
57 %if c.file.parent:
57 %if c.file.parent:
58 <tr class="parity0">
58 <tr class="parity0">
59 <td>
59 <td>
60 ${h.link_to('..',h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.file.parent.path),class_="browser-dir ypjax-link")}
60 ${h.link_to('..',h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.file.parent.path),class_="browser-dir ypjax-link")}
61 </td>
61 </td>
62 <td></td>
62 <td></td>
63 <td></td>
63 <td></td>
64 <td></td>
64 <td></td>
65 <td></td>
65 <td></td>
66 <td></td>
66 <td></td>
67 </tr>
67 </tr>
68 %endif
68 %endif
69
69
70 %for cnt,node in enumerate(c.file):
70 %for cnt,node in enumerate(c.file):
71 <tr class="parity${cnt%2}">
71 <tr class="parity${cnt%2}">
72 <td>
72 <td>
73 %if node.is_submodule():
73 %if node.is_submodule():
74 ${h.link_to(node.name,node.url or '#',class_="submodule-dir ypjax-link")}
74 ${h.link_to(node.name,node.url or '#',class_="submodule-dir ypjax-link")}
75 %else:
75 %else:
76 ${h.link_to(node.name, h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=h.safe_unicode(node.path)),class_=file_class(node)+" ypjax-link")}
76 ${h.link_to(node.name, h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=h.safe_unicode(node.path)),class_=file_class(node)+" ypjax-link")}
77 %endif:
77 %endif:
78 </td>
78 </td>
79 <td>
79 <td>
80 %if node.is_file():
80 %if node.is_file():
81 ${h.format_byte_size(node.size,binary=True)}
81 ${h.format_byte_size(node.size,binary=True)}
82 %endif
82 %endif
83 </td>
83 </td>
84 <td>
84 <td>
85 %if node.is_file():
85 %if node.is_file():
86 ${node.mimetype}
86 ${node.mimetype}
87 %endif
87 %endif
88 </td>
88 </td>
89 <td>
89 <td>
90 %if node.is_file():
90 %if node.is_file():
91 <div class="tooltip" title="${node.last_changeset.message}">
91 <div class="tooltip" title="${node.last_changeset.message}">
92 <pre>${'r%s:%s' % (node.last_changeset.revision,node.last_changeset.short_id)}</pre>
92 <pre>${'r%s:%s' % (node.last_changeset.revision,node.last_changeset.short_id)}</pre>
93 </div>
93 </div>
94 %endif
94 %endif
95 </td>
95 </td>
96 <td>
96 <td>
97 %if node.is_file():
97 %if node.is_file():
98 <span class="tooltip" title="${node.last_changeset.date}">
98 <span class="tooltip" title="${h.fmt_date(node.last_changeset.date)}">
99 ${h.age(node.last_changeset.date)}</span>
99 ${h.age(node.last_changeset.date)}</span>
100 %endif
100 %endif
101 </td>
101 </td>
102 <td>
102 <td>
103 %if node.is_file():
103 %if node.is_file():
104 <span title="${node.last_changeset.author}">
104 <span title="${node.last_changeset.author}">
105 ${h.person(node.last_changeset.author)}
105 ${h.person(node.last_changeset.author)}
106 </span>
106 </span>
107 %endif
107 %endif
108 </td>
108 </td>
109 </tr>
109 </tr>
110 %endfor
110 %endfor
111 </tbody>
111 </tbody>
112 <tbody id="tbody_filtered" style="display:none">
112 <tbody id="tbody_filtered" style="display:none">
113 </tbody>
113 </tbody>
114 </table>
114 </table>
115 </div>
115 </div>
116 </div>
116 </div>
@@ -1,114 +1,114
1 <dl>
1 <dl>
2 <dt style="padding-top:10px;font-size:16px">${_('History')}</dt>
2 <dt style="padding-top:10px;font-size:16px">${_('History')}</dt>
3 <dd>
3 <dd>
4 <div>
4 <div>
5 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
5 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
6 ${h.hidden('diff2',c.file.changeset.raw_id)}
6 ${h.hidden('diff2',c.file.changeset.raw_id)}
7 ${h.select('diff1',c.file.changeset.raw_id,c.file_history)}
7 ${h.select('diff1',c.file.changeset.raw_id,c.file_history)}
8 ${h.submit('diff','diff to revision',class_="ui-btn")}
8 ${h.submit('diff','diff to revision',class_="ui-btn")}
9 ${h.submit('show_rev','show at revision',class_="ui-btn")}
9 ${h.submit('show_rev','show at revision',class_="ui-btn")}
10 ${h.end_form()}
10 ${h.end_form()}
11 </div>
11 </div>
12 </dd>
12 </dd>
13 </dl>
13 </dl>
14
14
15 <div id="body" class="codeblock">
15 <div id="body" class="codeblock">
16 <div class="code-header">
16 <div class="code-header">
17 <div class="stats">
17 <div class="stats">
18 <div class="left img"><img src="${h.url('/images/icons/file.png')}"/></div>
18 <div class="left img"><img src="${h.url('/images/icons/file.png')}"/></div>
19 <div class="left item"><pre class="tooltip" title="${c.file.changeset.date}">${h.link_to("r%s:%s" % (c.file.changeset.revision,h.short_id(c.file.changeset.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id))}</pre></div>
19 <div class="left item"><pre class="tooltip" title="${h.fmt_date(c.file.changeset.date)}">${h.link_to("r%s:%s" % (c.file.changeset.revision,h.short_id(c.file.changeset.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id))}</pre></div>
20 <div class="left item"><pre>${h.format_byte_size(c.file.size,binary=True)}</pre></div>
20 <div class="left item"><pre>${h.format_byte_size(c.file.size,binary=True)}</pre></div>
21 <div class="left item last"><pre>${c.file.mimetype}</pre></div>
21 <div class="left item last"><pre>${c.file.mimetype}</pre></div>
22 <div class="buttons">
22 <div class="buttons">
23 %if c.annotate:
23 %if c.annotate:
24 ${h.link_to(_('show source'), h.url('files_home', repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
24 ${h.link_to(_('show source'), h.url('files_home', repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
25 %else:
25 %else:
26 ${h.link_to(_('show annotation'),h.url('files_annotate_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
26 ${h.link_to(_('show annotation'),h.url('files_annotate_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
27 %endif
27 %endif
28 ${h.link_to(_('show as raw'),h.url('files_raw_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
28 ${h.link_to(_('show as raw'),h.url('files_raw_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
29 ${h.link_to(_('download as raw'),h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
29 ${h.link_to(_('download as raw'),h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
30 % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
30 % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
31 % if not c.file.is_binary:
31 % if not c.file.is_binary:
32 ${h.link_to(_('edit'),h.url('files_edit_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
32 ${h.link_to(_('edit'),h.url('files_edit_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
33 % endif
33 % endif
34 % endif
34 % endif
35 </div>
35 </div>
36 </div>
36 </div>
37 <div class="author">
37 <div class="author">
38 <div class="gravatar">
38 <div class="gravatar">
39 <img alt="gravatar" src="${h.gravatar_url(h.email(c.file.changeset.author),16)}"/>
39 <img alt="gravatar" src="${h.gravatar_url(h.email(c.file.changeset.author),16)}"/>
40 </div>
40 </div>
41 <div title="${c.file.changeset.author}" class="user">${h.person(c.file.changeset.author)}</div>
41 <div title="${c.file.changeset.author}" class="user">${h.person(c.file.changeset.author)}</div>
42 </div>
42 </div>
43 <div class="commit">${h.urlify_commit(c.file.changeset.message,c.repo_name)}</div>
43 <div class="commit">${h.urlify_commit(c.file.changeset.message,c.repo_name)}</div>
44 </div>
44 </div>
45 <div class="code-body">
45 <div class="code-body">
46 %if c.file.is_binary:
46 %if c.file.is_binary:
47 ${_('Binary file (%s)') % c.file.mimetype}
47 ${_('Binary file (%s)') % c.file.mimetype}
48 %else:
48 %else:
49 % if c.file.size < c.cut_off_limit:
49 % if c.file.size < c.cut_off_limit:
50 %if c.annotate:
50 %if c.annotate:
51 ${h.pygmentize_annotation(c.repo_name,c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
51 ${h.pygmentize_annotation(c.repo_name,c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
52 %else:
52 %else:
53 ${h.pygmentize(c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
53 ${h.pygmentize(c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
54 %endif
54 %endif
55 %else:
55 %else:
56 ${_('File is too big to display')} ${h.link_to(_('show as raw'),
56 ${_('File is too big to display')} ${h.link_to(_('show as raw'),
57 h.url('files_raw_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path))}
57 h.url('files_raw_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path))}
58 %endif
58 %endif
59 %endif
59 %endif
60 </div>
60 </div>
61 </div>
61 </div>
62
62
63 <script type="text/javascript">
63 <script type="text/javascript">
64 YUE.onDOMReady(function(){
64 YUE.onDOMReady(function(){
65 function highlight_lines(lines){
65 function highlight_lines(lines){
66 for(pos in lines){
66 for(pos in lines){
67 YUD.setStyle('L'+lines[pos],'background-color','#FFFFBE');
67 YUD.setStyle('L'+lines[pos],'background-color','#FFFFBE');
68 }
68 }
69 }
69 }
70 page_highlights = location.href.substring(location.href.indexOf('#')+1).split('L');
70 page_highlights = location.href.substring(location.href.indexOf('#')+1).split('L');
71 if (page_highlights.length == 2){
71 if (page_highlights.length == 2){
72 highlight_ranges = page_highlights[1].split(",");
72 highlight_ranges = page_highlights[1].split(",");
73
73
74 var h_lines = [];
74 var h_lines = [];
75 for (pos in highlight_ranges){
75 for (pos in highlight_ranges){
76 var _range = highlight_ranges[pos].split('-');
76 var _range = highlight_ranges[pos].split('-');
77 if(_range.length == 2){
77 if(_range.length == 2){
78 var start = parseInt(_range[0]);
78 var start = parseInt(_range[0]);
79 var end = parseInt(_range[1]);
79 var end = parseInt(_range[1]);
80 if (start < end){
80 if (start < end){
81 for(var i=start;i<=end;i++){
81 for(var i=start;i<=end;i++){
82 h_lines.push(i);
82 h_lines.push(i);
83 }
83 }
84 }
84 }
85 }
85 }
86 else{
86 else{
87 h_lines.push(parseInt(highlight_ranges[pos]));
87 h_lines.push(parseInt(highlight_ranges[pos]));
88 }
88 }
89 }
89 }
90 highlight_lines(h_lines);
90 highlight_lines(h_lines);
91
91
92 //remember original location
92 //remember original location
93 var old_hash = location.href.substring(location.href.indexOf('#'));
93 var old_hash = location.href.substring(location.href.indexOf('#'));
94
94
95 // this makes a jump to anchor moved by 3 posstions for padding
95 // this makes a jump to anchor moved by 3 posstions for padding
96 window.location.hash = '#L'+Math.max(parseInt(h_lines[0])-3,1);
96 window.location.hash = '#L'+Math.max(parseInt(h_lines[0])-3,1);
97
97
98 //sets old anchor
98 //sets old anchor
99 window.location.hash = old_hash;
99 window.location.hash = old_hash;
100
100
101 }
101 }
102 YUE.on('show_rev','click',function(e){
102 YUE.on('show_rev','click',function(e){
103 YUE.preventDefault(e);
103 YUE.preventDefault(e);
104 var cs = YUD.get('diff1').value;
104 var cs = YUD.get('diff1').value;
105 %if c.annotate:
105 %if c.annotate:
106 var url = "${h.url('files_annotate_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
106 var url = "${h.url('files_annotate_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
107 %else:
107 %else:
108 var url = "${h.url('files_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
108 var url = "${h.url('files_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
109 %endif
109 %endif
110 window.location = url;
110 window.location = url;
111 });
111 });
112 YUE.on('hlcode','mouseup',getSelectionLink("${_('Selection link')}"))
112 YUE.on('hlcode','mouseup',getSelectionLink("${_('Selection link')}"))
113 });
113 });
114 </script>
114 </script>
@@ -1,201 +1,201
1 <%page args="parent" />
1 <%page args="parent" />
2 <div class="box">
2 <div class="box">
3 <!-- box / title -->
3 <!-- box / title -->
4 <div class="title">
4 <div class="title">
5 <h5>
5 <h5>
6 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/> ${parent.breadcrumbs()} <span id="repo_count">0</span> ${_('repositories')}
6 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/> ${parent.breadcrumbs()} <span id="repo_count">0</span> ${_('repositories')}
7 </h5>
7 </h5>
8 %if c.rhodecode_user.username != 'default':
8 %if c.rhodecode_user.username != 'default':
9 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
9 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
10 <ul class="links">
10 <ul class="links">
11 <li>
11 <li>
12 %if c.group:
12 %if c.group:
13 <span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository',parent_group=c.group.group_id))}</span>
13 <span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository',parent_group=c.group.group_id))}</span>
14 %else:
14 %else:
15 <span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository'))}</span>
15 <span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository'))}</span>
16 %endif
16 %endif
17 </li>
17 </li>
18 </ul>
18 </ul>
19 %endif
19 %endif
20 %endif
20 %endif
21 </div>
21 </div>
22 <!-- end box / title -->
22 <!-- end box / title -->
23 <div class="table">
23 <div class="table">
24 % if c.groups:
24 % if c.groups:
25 <div id='groups_list_wrap' class="yui-skin-sam">
25 <div id='groups_list_wrap' class="yui-skin-sam">
26 <table id="groups_list">
26 <table id="groups_list">
27 <thead>
27 <thead>
28 <tr>
28 <tr>
29 <th class="left"><a href="#">${_('Group name')}</a></th>
29 <th class="left"><a href="#">${_('Group name')}</a></th>
30 <th class="left"><a href="#">${_('Description')}</a></th>
30 <th class="left"><a href="#">${_('Description')}</a></th>
31 ##<th class="left"><a href="#">${_('Number of repositories')}</a></th>
31 ##<th class="left"><a href="#">${_('Number of repositories')}</a></th>
32 </tr>
32 </tr>
33 </thead>
33 </thead>
34
34
35 ## REPO GROUPS
35 ## REPO GROUPS
36 % for gr in c.groups:
36 % for gr in c.groups:
37 <tr>
37 <tr>
38 <td>
38 <td>
39 <div style="white-space: nowrap">
39 <div style="white-space: nowrap">
40 <img class="icon" alt="${_('Repositories group')}" src="${h.url('/images/icons/database_link.png')}"/>
40 <img class="icon" alt="${_('Repositories group')}" src="${h.url('/images/icons/database_link.png')}"/>
41 ${h.link_to(gr.name,url('repos_group_home',group_name=gr.group_name))}
41 ${h.link_to(gr.name,url('repos_group_home',group_name=gr.group_name))}
42 </div>
42 </div>
43 </td>
43 </td>
44 <td>${gr.group_description}</td>
44 <td>${gr.group_description}</td>
45 ## this is commented out since for multi nested repos can be HEAVY!
45 ## this is commented out since for multi nested repos can be HEAVY!
46 ## in number of executed queries during traversing uncomment at will
46 ## in number of executed queries during traversing uncomment at will
47 ##<td><b>${gr.repositories_recursive_count}</b></td>
47 ##<td><b>${gr.repositories_recursive_count}</b></td>
48 </tr>
48 </tr>
49 % endfor
49 % endfor
50
50
51 </table>
51 </table>
52 </div>
52 </div>
53 <div style="height: 20px"></div>
53 <div style="height: 20px"></div>
54 % endif
54 % endif
55 <div id="welcome" style="display:none;text-align:center">
55 <div id="welcome" style="display:none;text-align:center">
56 <h1><a href="${h.url('home')}">${c.rhodecode_name} ${c.rhodecode_version}</a></h1>
56 <h1><a href="${h.url('home')}">${c.rhodecode_name} ${c.rhodecode_version}</a></h1>
57 </div>
57 </div>
58 <div id='repos_list_wrap' class="yui-skin-sam">
58 <div id='repos_list_wrap' class="yui-skin-sam">
59 <%cnt=0%>
59 <%cnt=0%>
60 <%namespace name="dt" file="/data_table/_dt_elements.html"/>
60 <%namespace name="dt" file="/data_table/_dt_elements.html"/>
61
61
62 <table id="repos_list">
62 <table id="repos_list">
63 <thead>
63 <thead>
64 <tr>
64 <tr>
65 <th class="left"></th>
65 <th class="left"></th>
66 <th class="left">${_('Name')}</th>
66 <th class="left">${_('Name')}</th>
67 <th class="left">${_('Description')}</th>
67 <th class="left">${_('Description')}</th>
68 <th class="left">${_('Last change')}</th>
68 <th class="left">${_('Last change')}</th>
69 <th class="left">${_('Tip')}</th>
69 <th class="left">${_('Tip')}</th>
70 <th class="left">${_('Owner')}</th>
70 <th class="left">${_('Owner')}</th>
71 <th class="left">${_('RSS')}</th>
71 <th class="left">${_('RSS')}</th>
72 <th class="left">${_('Atom')}</th>
72 <th class="left">${_('Atom')}</th>
73 </tr>
73 </tr>
74 </thead>
74 </thead>
75 <tbody>
75 <tbody>
76 %for cnt,repo in enumerate(c.repos_list):
76 %for cnt,repo in enumerate(c.repos_list):
77 <tr class="parity${(cnt+1)%2}">
77 <tr class="parity${(cnt+1)%2}">
78 ##QUICK MENU
78 ##QUICK MENU
79 <td class="quick_repo_menu">
79 <td class="quick_repo_menu">
80 ${dt.quick_menu(repo['name'])}
80 ${dt.quick_menu(repo['name'])}
81 </td>
81 </td>
82 ##REPO NAME AND ICONS
82 ##REPO NAME AND ICONS
83 <td class="reponame">
83 <td class="reponame">
84 ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],repo['dbrepo_fork'].get('repo_name'),pageargs.get('short_repo_names'))}
84 ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],repo['dbrepo_fork'].get('repo_name'),pageargs.get('short_repo_names'))}
85 </td>
85 </td>
86 ##DESCRIPTION
86 ##DESCRIPTION
87 <td><span class="tooltip" title="${h.tooltip(repo['description'])}">
87 <td><span class="tooltip" title="${h.tooltip(repo['description'])}">
88 ${h.truncate(repo['description'],60)}</span>
88 ${h.truncate(repo['description'],60)}</span>
89 </td>
89 </td>
90 ##LAST CHANGE DATE
90 ##LAST CHANGE DATE
91 <td>
91 <td>
92 <span class="tooltip" title="${repo['last_change']}">${h.age(repo['last_change'])}</span>
92 <span class="tooltip" title="${h.fmt_date(repo['last_change'])}">${h.age(repo['last_change'])}</span>
93 </td>
93 </td>
94 ##LAST REVISION
94 ##LAST REVISION
95 <td>
95 <td>
96 ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])}
96 ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])}
97 </td>
97 </td>
98 ##
98 ##
99 <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
99 <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
100 <td>
100 <td>
101 %if c.rhodecode_user.username != 'default':
101 %if c.rhodecode_user.username != 'default':
102 <a title="${_('Subscribe to %s rss feed')%repo['name']}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=repo['name'],api_key=c.rhodecode_user.api_key)}"></a>
102 <a title="${_('Subscribe to %s rss feed')%repo['name']}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=repo['name'],api_key=c.rhodecode_user.api_key)}"></a>
103 %else:
103 %else:
104 <a title="${_('Subscribe to %s rss feed')%repo['name']}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=repo['name'])}"></a>
104 <a title="${_('Subscribe to %s rss feed')%repo['name']}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=repo['name'])}"></a>
105 %endif:
105 %endif:
106 </td>
106 </td>
107 <td>
107 <td>
108 %if c.rhodecode_user.username != 'default':
108 %if c.rhodecode_user.username != 'default':
109 <a title="${_('Subscribe to %s atom feed')%repo['name']}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=repo['name'],api_key=c.rhodecode_user.api_key)}"></a>
109 <a title="${_('Subscribe to %s atom feed')%repo['name']}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=repo['name'],api_key=c.rhodecode_user.api_key)}"></a>
110 %else:
110 %else:
111 <a title="${_('Subscribe to %s atom feed')%repo['name']}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=repo['name'])}"></a>
111 <a title="${_('Subscribe to %s atom feed')%repo['name']}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=repo['name'])}"></a>
112 %endif:
112 %endif:
113 </td>
113 </td>
114 </tr>
114 </tr>
115 %endfor
115 %endfor
116 </tbody>
116 </tbody>
117 </table>
117 </table>
118 </div>
118 </div>
119 </div>
119 </div>
120 </div>
120 </div>
121 <script>
121 <script>
122 YUD.get('repo_count').innerHTML = ${cnt+1};
122 YUD.get('repo_count').innerHTML = ${cnt+1};
123 var func = function(node){
123 var func = function(node){
124 return node.parentNode.parentNode.parentNode.parentNode;
124 return node.parentNode.parentNode.parentNode.parentNode;
125 }
125 }
126
126
127
127
128 // groups table sorting
128 // groups table sorting
129 var myColumnDefs = [
129 var myColumnDefs = [
130 {key:"name",label:"${_('Group Name')}",sortable:true,
130 {key:"name",label:"${_('Group Name')}",sortable:true,
131 sortOptions: { sortFunction: groupNameSort }},
131 sortOptions: { sortFunction: groupNameSort }},
132 {key:"desc",label:"${_('Description')}",sortable:true},
132 {key:"desc",label:"${_('Description')}",sortable:true},
133 ];
133 ];
134
134
135 var myDataSource = new YAHOO.util.DataSource(YUD.get("groups_list"));
135 var myDataSource = new YAHOO.util.DataSource(YUD.get("groups_list"));
136
136
137 myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
137 myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
138 myDataSource.responseSchema = {
138 myDataSource.responseSchema = {
139 fields: [
139 fields: [
140 {key:"name"},
140 {key:"name"},
141 {key:"desc"},
141 {key:"desc"},
142 ]
142 ]
143 };
143 };
144
144
145 var myDataTable = new YAHOO.widget.DataTable("groups_list_wrap", myColumnDefs, myDataSource,
145 var myDataTable = new YAHOO.widget.DataTable("groups_list_wrap", myColumnDefs, myDataSource,
146 {
146 {
147 sortedBy:{key:"name",dir:"asc"},
147 sortedBy:{key:"name",dir:"asc"},
148 MSG_SORTASC:"${_('Click to sort ascending')}",
148 MSG_SORTASC:"${_('Click to sort ascending')}",
149 MSG_SORTDESC:"${_('Click to sort descending')}"
149 MSG_SORTDESC:"${_('Click to sort descending')}"
150 }
150 }
151 );
151 );
152
152
153 // main table sorting
153 // main table sorting
154 var myColumnDefs = [
154 var myColumnDefs = [
155 {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
155 {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
156 {key:"name",label:"${_('Name')}",sortable:true,
156 {key:"name",label:"${_('Name')}",sortable:true,
157 sortOptions: { sortFunction: nameSort }},
157 sortOptions: { sortFunction: nameSort }},
158 {key:"desc",label:"${_('Description')}",sortable:true},
158 {key:"desc",label:"${_('Description')}",sortable:true},
159 {key:"last_change",label:"${_('Last Change')}",sortable:true,
159 {key:"last_change",label:"${_('Last Change')}",sortable:true,
160 sortOptions: { sortFunction: ageSort }},
160 sortOptions: { sortFunction: ageSort }},
161 {key:"tip",label:"${_('Tip')}",sortable:true,
161 {key:"tip",label:"${_('Tip')}",sortable:true,
162 sortOptions: { sortFunction: revisionSort }},
162 sortOptions: { sortFunction: revisionSort }},
163 {key:"owner",label:"${_('Owner')}",sortable:true},
163 {key:"owner",label:"${_('Owner')}",sortable:true},
164 {key:"rss",label:"",sortable:false},
164 {key:"rss",label:"",sortable:false},
165 {key:"atom",label:"",sortable:false},
165 {key:"atom",label:"",sortable:false},
166 ];
166 ];
167
167
168 var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list"));
168 var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list"));
169
169
170 myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
170 myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
171
171
172 myDataSource.responseSchema = {
172 myDataSource.responseSchema = {
173 fields: [
173 fields: [
174 {key:"menu"},
174 {key:"menu"},
175 {key:"name"},
175 {key:"name"},
176 {key:"desc"},
176 {key:"desc"},
177 {key:"last_change"},
177 {key:"last_change"},
178 {key:"tip"},
178 {key:"tip"},
179 {key:"owner"},
179 {key:"owner"},
180 {key:"rss"},
180 {key:"rss"},
181 {key:"atom"},
181 {key:"atom"},
182 ]
182 ]
183 };
183 };
184
184
185 var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,
185 var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,
186 {
186 {
187 sortedBy:{key:"name",dir:"asc"},
187 sortedBy:{key:"name",dir:"asc"},
188 MSG_SORTASC:"${_('Click to sort ascending')}",
188 MSG_SORTASC:"${_('Click to sort ascending')}",
189 MSG_SORTDESC:"${_('Click to sort descending')}",
189 MSG_SORTDESC:"${_('Click to sort descending')}",
190 MSG_EMPTY:"${_('No records found.')}",
190 MSG_EMPTY:"${_('No records found.')}",
191 MSG_ERROR:"${_('Data error.')}",
191 MSG_ERROR:"${_('Data error.')}",
192 MSG_LOADING:"${_('Loading...')}",
192 MSG_LOADING:"${_('Loading...')}",
193 }
193 }
194 );
194 );
195 myDataTable.subscribe('postRenderEvent',function(oArgs) {
195 myDataTable.subscribe('postRenderEvent',function(oArgs) {
196 tooltip_activate();
196 tooltip_activate();
197 quick_repo_menu();
197 quick_repo_menu();
198 q_filter('q_filter',YUQ('div.table tr td a.repo_name'),func);
198 q_filter('q_filter',YUQ('div.table tr td a.repo_name'),func);
199 });
199 });
200
200
201 </script>
201 </script>
@@ -1,49 +1,49
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2
2
3 %if c.journal_day_aggreagate:
3 %if c.journal_day_aggreagate:
4 %for day,items in c.journal_day_aggreagate:
4 %for day,items in c.journal_day_aggreagate:
5 <div class="journal_day">${day}</div>
5 <div class="journal_day">${day}</div>
6 % for user,entries in items:
6 % for user,entries in items:
7 <div class="journal_container">
7 <div class="journal_container">
8 <div class="gravatar">
8 <div class="gravatar">
9 <img alt="gravatar" src="${h.gravatar_url(user.email,24)}"/>
9 <img alt="gravatar" src="${h.gravatar_url(user.email,24)}"/>
10 </div>
10 </div>
11 <div class="journal_user">${user.name} ${user.lastname}</div>
11 <div class="journal_user">${user.name} ${user.lastname}</div>
12 <div class="journal_action_container">
12 <div class="journal_action_container">
13 % for entry in entries:
13 % for entry in entries:
14 <div class="journal_icon"> ${h.action_parser(entry)[2]()}</div>
14 <div class="journal_icon"> ${h.action_parser(entry)[2]()}</div>
15 <div class="journal_action">${h.action_parser(entry)[0]()}</div>
15 <div class="journal_action">${h.action_parser(entry)[0]()}</div>
16 <div class="journal_repo">
16 <div class="journal_repo">
17 <span class="journal_repo_name">
17 <span class="journal_repo_name">
18 %if entry.repository is not None:
18 %if entry.repository is not None:
19 ${h.link_to(entry.repository.repo_name,
19 ${h.link_to(entry.repository.repo_name,
20 h.url('summary_home',repo_name=entry.repository.repo_name))}
20 h.url('summary_home',repo_name=entry.repository.repo_name))}
21 %else:
21 %else:
22 ${entry.repository_name}
22 ${entry.repository_name}
23 %endif
23 %endif
24 </span>
24 </span>
25 </div>
25 </div>
26 <div class="journal_action_params">${h.literal(h.action_parser(entry)[1]())}</div>
26 <div class="journal_action_params">${h.literal(h.action_parser(entry)[1]())}</div>
27 <div class="date"><span class="tooltip" title="${entry.action_date}">${h.age(entry.action_date)}</span></div>
27 <div class="date"><span class="tooltip" title="${h.fmt_date(entry.action_date)}">${h.age(entry.action_date)}</span></div>
28 %endfor
28 %endfor
29 </div>
29 </div>
30 </div>
30 </div>
31 %endfor
31 %endfor
32 %endfor
32 %endfor
33
33
34 <div class="pagination-wh pagination-left">
34 <div class="pagination-wh pagination-left">
35 <script type="text/javascript">
35 <script type="text/javascript">
36 YUE.onDOMReady(function(){
36 YUE.onDOMReady(function(){
37 YUE.delegate("journal","click",function(e, matchedEl, container){
37 YUE.delegate("journal","click",function(e, matchedEl, container){
38 ypjax(e.target.href,"journal",function(){show_more_event();tooltip_activate();});
38 ypjax(e.target.href,"journal",function(){show_more_event();tooltip_activate();});
39 YUE.preventDefault(e);
39 YUE.preventDefault(e);
40 },'.pager_link');
40 },'.pager_link');
41 });
41 });
42 </script>
42 </script>
43 ${c.journal_pager.pager('$link_previous ~2~ $link_next')}
43 ${c.journal_pager.pager('$link_previous ~2~ $link_next')}
44 </div>
44 </div>
45 %else:
45 %else:
46 <div style="padding:5px 0px 10px 10px;">
46 <div style="padding:5px 0px 10px 10px;">
47 ${_('No entries yet')}
47 ${_('No entries yet')}
48 </div>
48 </div>
49 %endif
49 %endif
@@ -1,83 +1,83
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 %if c.repo_changesets:
2 %if c.repo_changesets:
3 <table class="table_disp">
3 <table class="table_disp">
4 <tr>
4 <tr>
5 <th class="left">${_('revision')}</th>
5 <th class="left">${_('revision')}</th>
6 <th class="left">${_('commit message')}</th>
6 <th class="left">${_('commit message')}</th>
7 <th class="left">${_('age')}</th>
7 <th class="left">${_('age')}</th>
8 <th class="left">${_('author')}</th>
8 <th class="left">${_('author')}</th>
9 <th class="left">${_('branch')}</th>
9 <th class="left">${_('branch')}</th>
10 <th class="left">${_('tags')}</th>
10 <th class="left">${_('tags')}</th>
11 </tr>
11 </tr>
12 %for cnt,cs in enumerate(c.repo_changesets):
12 %for cnt,cs in enumerate(c.repo_changesets):
13 <tr class="parity${cnt%2}">
13 <tr class="parity${cnt%2}">
14 <td>
14 <td>
15 <div><pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id)}">r${cs.revision}:${h.short_id(cs.raw_id)}</a></pre></div>
15 <div><pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id)}">r${cs.revision}:${h.short_id(cs.raw_id)}</a></pre></div>
16 </td>
16 </td>
17 <td>
17 <td>
18 ${h.link_to(h.truncate(cs.message,50) or _('No commit message'),
18 ${h.link_to(h.truncate(cs.message,50) or _('No commit message'),
19 h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id),
19 h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id),
20 title=cs.message)}
20 title=cs.message)}
21 </td>
21 </td>
22 <td><span class="tooltip" title="${cs.date}">
22 <td><span class="tooltip" title="${h.fmt_date(cs.date)}">
23 ${h.age(cs.date)}</span>
23 ${h.age(cs.date)}</span>
24 </td>
24 </td>
25 <td title="${cs.author}">${h.person(cs.author)}</td>
25 <td title="${cs.author}">${h.person(cs.author)}</td>
26 <td>
26 <td>
27 <span class="logtags">
27 <span class="logtags">
28 %if cs.branch:
28 %if cs.branch:
29 <span class="branchtag">
29 <span class="branchtag">
30 ${cs.branch}
30 ${cs.branch}
31 </span>
31 </span>
32 %endif
32 %endif
33 </span>
33 </span>
34 </td>
34 </td>
35 <td>
35 <td>
36 <span class="logtags">
36 <span class="logtags">
37 %for tag in cs.tags:
37 %for tag in cs.tags:
38 <span class="tagtag">${tag}</span>
38 <span class="tagtag">${tag}</span>
39 %endfor
39 %endfor
40 </span>
40 </span>
41 </td>
41 </td>
42 </tr>
42 </tr>
43 %endfor
43 %endfor
44
44
45 </table>
45 </table>
46
46
47 <script type="text/javascript">
47 <script type="text/javascript">
48 YUE.onDOMReady(function(){
48 YUE.onDOMReady(function(){
49 YUE.delegate("shortlog_data","click",function(e, matchedEl, container){
49 YUE.delegate("shortlog_data","click",function(e, matchedEl, container){
50 ypjax(e.target.href,"shortlog_data",function(){tooltip_activate();});
50 ypjax(e.target.href,"shortlog_data",function(){tooltip_activate();});
51 YUE.preventDefault(e);
51 YUE.preventDefault(e);
52 },'.pager_link');
52 },'.pager_link');
53 });
53 });
54 </script>
54 </script>
55
55
56 <div class="pagination-wh pagination-left">
56 <div class="pagination-wh pagination-left">
57 ${c.repo_changesets.pager('$link_previous ~2~ $link_next')}
57 ${c.repo_changesets.pager('$link_previous ~2~ $link_next')}
58 </div>
58 </div>
59 %else:
59 %else:
60
60
61 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
61 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
62 <h4>${_('Add or upload files directly via RhodeCode')}</h4>
62 <h4>${_('Add or upload files directly via RhodeCode')}</h4>
63 <div style="margin: 20px 30px;">
63 <div style="margin: 20px 30px;">
64 <div id="add_node_id" class="add_node">
64 <div id="add_node_id" class="add_node">
65 <a class="ui-btn" href="${h.url('files_add_home',repo_name=c.repo_name,revision=0,f_path='')}">${_('add new file')}</a>
65 <a class="ui-btn" href="${h.url('files_add_home',repo_name=c.repo_name,revision=0,f_path='')}">${_('add new file')}</a>
66 </div>
66 </div>
67 </div>
67 </div>
68 %endif
68 %endif
69
69
70
70
71 <h4>${_('Push new repo')}</h4>
71 <h4>${_('Push new repo')}</h4>
72 <pre>
72 <pre>
73 ${c.rhodecode_repo.alias} clone ${c.clone_repo_url}
73 ${c.rhodecode_repo.alias} clone ${c.clone_repo_url}
74 ${c.rhodecode_repo.alias} add README # add first file
74 ${c.rhodecode_repo.alias} add README # add first file
75 ${c.rhodecode_repo.alias} commit -m "Initial" # commit with message
75 ${c.rhodecode_repo.alias} commit -m "Initial" # commit with message
76 ${c.rhodecode_repo.alias} push ${'origin master' if h.is_git(c.rhodecode_repo) else ''} # push changes back
76 ${c.rhodecode_repo.alias} push ${'origin master' if h.is_git(c.rhodecode_repo) else ''} # push changes back
77 </pre>
77 </pre>
78
78
79 <h4>${_('Existing repository?')}</h4>
79 <h4>${_('Existing repository?')}</h4>
80 <pre>
80 <pre>
81 ${c.rhodecode_repo.alias} push ${c.clone_repo_url}
81 ${c.rhodecode_repo.alias} push ${c.clone_repo_url}
82 </pre>
82 </pre>
83 %endif
83 %endif
@@ -1,34 +1,34
1 %if c.repo_tags:
1 %if c.repo_tags:
2 <div id="table_wrap" class="yui-skin-sam">
2 <div id="table_wrap" class="yui-skin-sam">
3 <table id="tags_data">
3 <table id="tags_data">
4 <thead>
4 <thead>
5 <tr>
5 <tr>
6 <th class="left">${_('Name')}</th>
6 <th class="left">${_('Name')}</th>
7 <th class="left">${_('Date')}</th>
7 <th class="left">${_('Date')}</th>
8 <th class="left">${_('Author')}</th>
8 <th class="left">${_('Author')}</th>
9 <th class="left">${_('Revision')}</th>
9 <th class="left">${_('Revision')}</th>
10 </tr>
10 </tr>
11 </thead>
11 </thead>
12 %for cnt,tag in enumerate(c.repo_tags.items()):
12 %for cnt,tag in enumerate(c.repo_tags.items()):
13 <tr class="parity${cnt%2}">
13 <tr class="parity${cnt%2}">
14 <td>
14 <td>
15 <span class="logtags">
15 <span class="logtags">
16 <span class="tagtag">${h.link_to(tag[0],
16 <span class="tagtag">${h.link_to(tag[0],
17 h.url('files_home',repo_name=c.repo_name,revision=tag[1].raw_id))}
17 h.url('files_home',repo_name=c.repo_name,revision=tag[1].raw_id))}
18 </span>
18 </span>
19 </span>
19 </span>
20 </td>
20 </td>
21 <td><span class="tooltip" title="${h.age(tag[1].date)}">${tag[1].date}</span></td>
21 <td><span class="tooltip" title="${h.age(tag[1].date)}">${h.fmt_date(tag[1].date)}</span></td>
22 <td title="${tag[1].author}">${h.person(tag[1].author)}</td>
22 <td title="${tag[1].author}">${h.person(tag[1].author)}</td>
23 <td>
23 <td>
24 <div>
24 <div>
25 <pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=tag[1].raw_id)}">r${tag[1].revision}:${h.short_id(tag[1].raw_id)}</a></pre>
25 <pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=tag[1].raw_id)}">r${tag[1].revision}:${h.short_id(tag[1].raw_id)}</a></pre>
26 </div>
26 </div>
27 </td>
27 </td>
28 </tr>
28 </tr>
29 %endfor
29 %endfor
30 </table>
30 </table>
31 </div>
31 </div>
32 %else:
32 %else:
33 ${_('There are no tags yet')}
33 ${_('There are no tags yet')}
34 %endif
34 %endif
General Comments 0
You need to be logged in to leave comments. Login now