##// END OF EJS Templates
optimized speed for browsing git changesets
marcink -
r1959:7a7ffe24 beta
parent child Browse files
Show More
@@ -1,846 +1,870 b''
1 """Helper functions
1 """Helper functions
2
2
3 Consists of functions to typically be used within templates, but also
3 Consists of functions to typically be used within templates, but also
4 available to Controllers. This module is available to both as 'h'.
4 available to Controllers. This module is available to both as 'h'.
5 """
5 """
6 import random
6 import random
7 import hashlib
7 import hashlib
8 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 import str2bool, safe_unicode, safe_str, get_changeset_safe
42 from rhodecode.lib import str2bool, safe_unicode, safe_str, get_changeset_safe
43 from rhodecode.lib.markup_renderer import MarkupRenderer
43 from rhodecode.lib.markup_renderer import MarkupRenderer
44
44
45 log = logging.getLogger(__name__)
45 log = logging.getLogger(__name__)
46
46
47
47
48 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
48 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
49 """
49 """
50 Reset button
50 Reset button
51 """
51 """
52 _set_input_attrs(attrs, type, name, value)
52 _set_input_attrs(attrs, type, name, value)
53 _set_id_attr(attrs, id, name)
53 _set_id_attr(attrs, id, name)
54 convert_boolean_attrs(attrs, ["disabled"])
54 convert_boolean_attrs(attrs, ["disabled"])
55 return HTML.input(**attrs)
55 return HTML.input(**attrs)
56
56
57 reset = _reset
57 reset = _reset
58 safeid = _make_safe_id_component
58 safeid = _make_safe_id_component
59
59
60
60
61 def FID(raw_id, path):
61 def FID(raw_id, path):
62 """
62 """
63 Creates a uniqe ID for filenode based on it's hash of path and revision
63 Creates a uniqe ID for filenode based on it's hash of path and revision
64 it's safe to use in urls
64 it's safe to use in urls
65
65
66 :param raw_id:
66 :param raw_id:
67 :param path:
67 :param path:
68 """
68 """
69
69
70 return 'C-%s-%s' % (short_id(raw_id), md5(path).hexdigest()[:12])
70 return 'C-%s-%s' % (short_id(raw_id), md5(path).hexdigest()[:12])
71
71
72
72
73 def get_token():
73 def get_token():
74 """Return the current authentication token, creating one if one doesn't
74 """Return the current authentication token, creating one if one doesn't
75 already exist.
75 already exist.
76 """
76 """
77 token_key = "_authentication_token"
77 token_key = "_authentication_token"
78 from pylons import session
78 from pylons import session
79 if not token_key in session:
79 if not token_key in session:
80 try:
80 try:
81 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
81 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
82 except AttributeError: # Python < 2.4
82 except AttributeError: # Python < 2.4
83 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
83 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
84 session[token_key] = token
84 session[token_key] = token
85 if hasattr(session, 'save'):
85 if hasattr(session, 'save'):
86 session.save()
86 session.save()
87 return session[token_key]
87 return session[token_key]
88
88
89 class _GetError(object):
89 class _GetError(object):
90 """Get error from form_errors, and represent it as span wrapped error
90 """Get error from form_errors, and represent it as span wrapped error
91 message
91 message
92
92
93 :param field_name: field to fetch errors for
93 :param field_name: field to fetch errors for
94 :param form_errors: form errors dict
94 :param form_errors: form errors dict
95 """
95 """
96
96
97 def __call__(self, field_name, form_errors):
97 def __call__(self, field_name, form_errors):
98 tmpl = """<span class="error_msg">%s</span>"""
98 tmpl = """<span class="error_msg">%s</span>"""
99 if form_errors and form_errors.has_key(field_name):
99 if form_errors and form_errors.has_key(field_name):
100 return literal(tmpl % form_errors.get(field_name))
100 return literal(tmpl % form_errors.get(field_name))
101
101
102 get_error = _GetError()
102 get_error = _GetError()
103
103
104 class _ToolTip(object):
104 class _ToolTip(object):
105
105
106 def __call__(self, tooltip_title, trim_at=50):
106 def __call__(self, tooltip_title, trim_at=50):
107 """Special function just to wrap our text into nice formatted
107 """Special function just to wrap our text into nice formatted
108 autowrapped text
108 autowrapped text
109
109
110 :param tooltip_title:
110 :param tooltip_title:
111 """
111 """
112 return escape(tooltip_title)
112 return escape(tooltip_title)
113 tooltip = _ToolTip()
113 tooltip = _ToolTip()
114
114
115 class _FilesBreadCrumbs(object):
115 class _FilesBreadCrumbs(object):
116
116
117 def __call__(self, repo_name, rev, paths):
117 def __call__(self, repo_name, rev, paths):
118 if isinstance(paths, str):
118 if isinstance(paths, str):
119 paths = safe_unicode(paths)
119 paths = safe_unicode(paths)
120 url_l = [link_to(repo_name, url('files_home',
120 url_l = [link_to(repo_name, url('files_home',
121 repo_name=repo_name,
121 repo_name=repo_name,
122 revision=rev, f_path=''))]
122 revision=rev, f_path=''))]
123 paths_l = paths.split('/')
123 paths_l = paths.split('/')
124 for cnt, p in enumerate(paths_l):
124 for cnt, p in enumerate(paths_l):
125 if p != '':
125 if p != '':
126 url_l.append(link_to(p,
126 url_l.append(link_to(p,
127 url('files_home',
127 url('files_home',
128 repo_name=repo_name,
128 repo_name=repo_name,
129 revision=rev,
129 revision=rev,
130 f_path='/'.join(paths_l[:cnt + 1])
130 f_path='/'.join(paths_l[:cnt + 1])
131 )
131 )
132 )
132 )
133 )
133 )
134
134
135 return literal('/'.join(url_l))
135 return literal('/'.join(url_l))
136
136
137 files_breadcrumbs = _FilesBreadCrumbs()
137 files_breadcrumbs = _FilesBreadCrumbs()
138
138
139 class CodeHtmlFormatter(HtmlFormatter):
139 class CodeHtmlFormatter(HtmlFormatter):
140 """My code Html Formatter for source codes
140 """My code Html Formatter for source codes
141 """
141 """
142
142
143 def wrap(self, source, outfile):
143 def wrap(self, source, outfile):
144 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
144 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
145
145
146 def _wrap_code(self, source):
146 def _wrap_code(self, source):
147 for cnt, it in enumerate(source):
147 for cnt, it in enumerate(source):
148 i, t = it
148 i, t = it
149 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
149 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
150 yield i, t
150 yield i, t
151
151
152 def _wrap_tablelinenos(self, inner):
152 def _wrap_tablelinenos(self, inner):
153 dummyoutfile = StringIO.StringIO()
153 dummyoutfile = StringIO.StringIO()
154 lncount = 0
154 lncount = 0
155 for t, line in inner:
155 for t, line in inner:
156 if t:
156 if t:
157 lncount += 1
157 lncount += 1
158 dummyoutfile.write(line)
158 dummyoutfile.write(line)
159
159
160 fl = self.linenostart
160 fl = self.linenostart
161 mw = len(str(lncount + fl - 1))
161 mw = len(str(lncount + fl - 1))
162 sp = self.linenospecial
162 sp = self.linenospecial
163 st = self.linenostep
163 st = self.linenostep
164 la = self.lineanchors
164 la = self.lineanchors
165 aln = self.anchorlinenos
165 aln = self.anchorlinenos
166 nocls = self.noclasses
166 nocls = self.noclasses
167 if sp:
167 if sp:
168 lines = []
168 lines = []
169
169
170 for i in range(fl, fl + lncount):
170 for i in range(fl, fl + lncount):
171 if i % st == 0:
171 if i % st == 0:
172 if i % sp == 0:
172 if i % sp == 0:
173 if aln:
173 if aln:
174 lines.append('<a href="#%s%d" class="special">%*d</a>' %
174 lines.append('<a href="#%s%d" class="special">%*d</a>' %
175 (la, i, mw, i))
175 (la, i, mw, i))
176 else:
176 else:
177 lines.append('<span class="special">%*d</span>' % (mw, i))
177 lines.append('<span class="special">%*d</span>' % (mw, i))
178 else:
178 else:
179 if aln:
179 if aln:
180 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
180 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
181 else:
181 else:
182 lines.append('%*d' % (mw, i))
182 lines.append('%*d' % (mw, i))
183 else:
183 else:
184 lines.append('')
184 lines.append('')
185 ls = '\n'.join(lines)
185 ls = '\n'.join(lines)
186 else:
186 else:
187 lines = []
187 lines = []
188 for i in range(fl, fl + lncount):
188 for i in range(fl, fl + lncount):
189 if i % st == 0:
189 if i % st == 0:
190 if aln:
190 if aln:
191 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
191 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
192 else:
192 else:
193 lines.append('%*d' % (mw, i))
193 lines.append('%*d' % (mw, i))
194 else:
194 else:
195 lines.append('')
195 lines.append('')
196 ls = '\n'.join(lines)
196 ls = '\n'.join(lines)
197
197
198 # in case you wonder about the seemingly redundant <div> here: since the
198 # in case you wonder about the seemingly redundant <div> here: since the
199 # content in the other cell also is wrapped in a div, some browsers in
199 # content in the other cell also is wrapped in a div, some browsers in
200 # some configurations seem to mess up the formatting...
200 # some configurations seem to mess up the formatting...
201 if nocls:
201 if nocls:
202 yield 0, ('<table class="%stable">' % self.cssclass +
202 yield 0, ('<table class="%stable">' % self.cssclass +
203 '<tr><td><div class="linenodiv" '
203 '<tr><td><div class="linenodiv" '
204 'style="background-color: #f0f0f0; padding-right: 10px">'
204 'style="background-color: #f0f0f0; padding-right: 10px">'
205 '<pre style="line-height: 125%">' +
205 '<pre style="line-height: 125%">' +
206 ls + '</pre></div></td><td id="hlcode" class="code">')
206 ls + '</pre></div></td><td id="hlcode" class="code">')
207 else:
207 else:
208 yield 0, ('<table class="%stable">' % self.cssclass +
208 yield 0, ('<table class="%stable">' % self.cssclass +
209 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
209 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
210 ls + '</pre></div></td><td id="hlcode" class="code">')
210 ls + '</pre></div></td><td id="hlcode" class="code">')
211 yield 0, dummyoutfile.getvalue()
211 yield 0, dummyoutfile.getvalue()
212 yield 0, '</td></tr></table>'
212 yield 0, '</td></tr></table>'
213
213
214
214
215 def pygmentize(filenode, **kwargs):
215 def pygmentize(filenode, **kwargs):
216 """pygmentize function using pygments
216 """pygmentize function using pygments
217
217
218 :param filenode:
218 :param filenode:
219 """
219 """
220
220
221 return literal(code_highlight(filenode.content,
221 return literal(code_highlight(filenode.content,
222 filenode.lexer, CodeHtmlFormatter(**kwargs)))
222 filenode.lexer, CodeHtmlFormatter(**kwargs)))
223
223
224
224
225 def pygmentize_annotation(repo_name, filenode, **kwargs):
225 def pygmentize_annotation(repo_name, filenode, **kwargs):
226 """
226 """
227 pygmentize function for annotation
227 pygmentize function for annotation
228
228
229 :param filenode:
229 :param filenode:
230 """
230 """
231
231
232 color_dict = {}
232 color_dict = {}
233
233
234 def gen_color(n=10000):
234 def gen_color(n=10000):
235 """generator for getting n of evenly distributed colors using
235 """generator for getting n of evenly distributed colors using
236 hsv color and golden ratio. It always return same order of colors
236 hsv color and golden ratio. It always return same order of colors
237
237
238 :returns: RGB tuple
238 :returns: RGB tuple
239 """
239 """
240
240
241 def hsv_to_rgb(h, s, v):
241 def hsv_to_rgb(h, s, v):
242 if s == 0.0:
242 if s == 0.0:
243 return v, v, v
243 return v, v, v
244 i = int(h * 6.0) # XXX assume int() truncates!
244 i = int(h * 6.0) # XXX assume int() truncates!
245 f = (h * 6.0) - i
245 f = (h * 6.0) - i
246 p = v * (1.0 - s)
246 p = v * (1.0 - s)
247 q = v * (1.0 - s * f)
247 q = v * (1.0 - s * f)
248 t = v * (1.0 - s * (1.0 - f))
248 t = v * (1.0 - s * (1.0 - f))
249 i = i % 6
249 i = i % 6
250 if i == 0:
250 if i == 0:
251 return v, t, p
251 return v, t, p
252 if i == 1:
252 if i == 1:
253 return q, v, p
253 return q, v, p
254 if i == 2:
254 if i == 2:
255 return p, v, t
255 return p, v, t
256 if i == 3:
256 if i == 3:
257 return p, q, v
257 return p, q, v
258 if i == 4:
258 if i == 4:
259 return t, p, v
259 return t, p, v
260 if i == 5:
260 if i == 5:
261 return v, p, q
261 return v, p, q
262
262
263 golden_ratio = 0.618033988749895
263 golden_ratio = 0.618033988749895
264 h = 0.22717784590367374
264 h = 0.22717784590367374
265
265
266 for _ in xrange(n):
266 for _ in xrange(n):
267 h += golden_ratio
267 h += golden_ratio
268 h %= 1
268 h %= 1
269 HSV_tuple = [h, 0.95, 0.95]
269 HSV_tuple = [h, 0.95, 0.95]
270 RGB_tuple = hsv_to_rgb(*HSV_tuple)
270 RGB_tuple = hsv_to_rgb(*HSV_tuple)
271 yield map(lambda x: str(int(x * 256)), RGB_tuple)
271 yield map(lambda x: str(int(x * 256)), RGB_tuple)
272
272
273 cgenerator = gen_color()
273 cgenerator = gen_color()
274
274
275 def get_color_string(cs):
275 def get_color_string(cs):
276 if cs in color_dict:
276 if cs in color_dict:
277 col = color_dict[cs]
277 col = color_dict[cs]
278 else:
278 else:
279 col = color_dict[cs] = cgenerator.next()
279 col = color_dict[cs] = cgenerator.next()
280 return "color: rgb(%s)! important;" % (', '.join(col))
280 return "color: rgb(%s)! important;" % (', '.join(col))
281
281
282 def url_func(repo_name):
282 def url_func(repo_name):
283
283
284 def _url_func(changeset):
284 def _url_func(changeset):
285 author = changeset.author
285 author = changeset.author
286 date = changeset.date
286 date = changeset.date
287 message = tooltip(changeset.message)
287 message = tooltip(changeset.message)
288
288
289 tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>"
289 tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>"
290 " %s<br/><b>Date:</b> %s</b><br/><b>Message:"
290 " %s<br/><b>Date:</b> %s</b><br/><b>Message:"
291 "</b> %s<br/></div>")
291 "</b> %s<br/></div>")
292
292
293 tooltip_html = tooltip_html % (author, date, message)
293 tooltip_html = tooltip_html % (author, date, message)
294 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
294 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
295 short_id(changeset.raw_id))
295 short_id(changeset.raw_id))
296 uri = link_to(
296 uri = link_to(
297 lnk_format,
297 lnk_format,
298 url('changeset_home', repo_name=repo_name,
298 url('changeset_home', repo_name=repo_name,
299 revision=changeset.raw_id),
299 revision=changeset.raw_id),
300 style=get_color_string(changeset.raw_id),
300 style=get_color_string(changeset.raw_id),
301 class_='tooltip',
301 class_='tooltip',
302 title=tooltip_html
302 title=tooltip_html
303 )
303 )
304
304
305 uri += '\n'
305 uri += '\n'
306 return uri
306 return uri
307 return _url_func
307 return _url_func
308
308
309 return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs))
309 return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs))
310
310
311
311
312 def is_following_repo(repo_name, user_id):
312 def is_following_repo(repo_name, user_id):
313 from rhodecode.model.scm import ScmModel
313 from rhodecode.model.scm import ScmModel
314 return ScmModel().is_following_repo(repo_name, user_id)
314 return ScmModel().is_following_repo(repo_name, user_id)
315
315
316 flash = _Flash()
316 flash = _Flash()
317
317
318 #==============================================================================
318 #==============================================================================
319 # SCM FILTERS available via h.
319 # SCM FILTERS available via h.
320 #==============================================================================
320 #==============================================================================
321 from vcs.utils import author_name, author_email
321 from vcs.utils import author_name, author_email
322 from rhodecode.lib import credentials_filter, age as _age
322 from rhodecode.lib import credentials_filter, age as _age
323 from rhodecode.model.db import User
323 from rhodecode.model.db import User
324
324
325 age = lambda x: _age(x)
325 age = lambda x: _age(x)
326 capitalize = lambda x: x.capitalize()
326 capitalize = lambda x: x.capitalize()
327 email = author_email
327 email = author_email
328 short_id = lambda x: x[:12]
328 short_id = lambda x: x[:12]
329 hide_credentials = lambda x: ''.join(credentials_filter(x))
329 hide_credentials = lambda x: ''.join(credentials_filter(x))
330
330
331
331
332 def is_git(repository):
333 if hasattr(repository, 'alias'):
334 _type = repository.alias
335 elif hasattr(repository, 'repo_type'):
336 _type = repository.repo_type
337 else:
338 _type = repository
339 return _type == 'git'
340
341
342 def is_hg(repository):
343 if hasattr(repository, 'alias'):
344 _type = repository.alias
345 elif hasattr(repository, 'repo_type'):
346 _type = repository.repo_type
347 else:
348 _type = repository
349 return _type == 'hg'
350
351
332 def email_or_none(author):
352 def email_or_none(author):
333 _email = email(author)
353 _email = email(author)
334 if _email != '':
354 if _email != '':
335 return _email
355 return _email
336
356
337 # See if it contains a username we can get an email from
357 # See if it contains a username we can get an email from
338 user = User.get_by_username(author_name(author), case_insensitive=True,
358 user = User.get_by_username(author_name(author), case_insensitive=True,
339 cache=True)
359 cache=True)
340 if user is not None:
360 if user is not None:
341 return user.email
361 return user.email
342
362
343 # No valid email, not a valid user in the system, none!
363 # No valid email, not a valid user in the system, none!
344 return None
364 return None
345
365
346
366
347 def person(author):
367 def person(author):
348 # attr to return from fetched user
368 # attr to return from fetched user
349 person_getter = lambda usr: usr.username
369 person_getter = lambda usr: usr.username
350
370
351 # Valid email in the attribute passed, see if they're in the system
371 # Valid email in the attribute passed, see if they're in the system
352 _email = email(author)
372 _email = email(author)
353 if _email != '':
373 if _email != '':
354 user = User.get_by_email(_email, case_insensitive=True, cache=True)
374 user = User.get_by_email(_email, case_insensitive=True, cache=True)
355 if user is not None:
375 if user is not None:
356 return person_getter(user)
376 return person_getter(user)
357 return _email
377 return _email
358
378
359 # Maybe it's a username?
379 # Maybe it's a username?
360 _author = author_name(author)
380 _author = author_name(author)
361 user = User.get_by_username(_author, case_insensitive=True,
381 user = User.get_by_username(_author, case_insensitive=True,
362 cache=True)
382 cache=True)
363 if user is not None:
383 if user is not None:
364 return person_getter(user)
384 return person_getter(user)
365
385
366 # Still nothing? Just pass back the author name then
386 # Still nothing? Just pass back the author name then
367 return _author
387 return _author
368
388
389
369 def bool2icon(value):
390 def bool2icon(value):
370 """Returns True/False values represented as small html image of true/false
391 """Returns True/False values represented as small html image of true/false
371 icons
392 icons
372
393
373 :param value: bool value
394 :param value: bool value
374 """
395 """
375
396
376 if value is True:
397 if value is True:
377 return HTML.tag('img', src=url("/images/icons/accept.png"),
398 return HTML.tag('img', src=url("/images/icons/accept.png"),
378 alt=_('True'))
399 alt=_('True'))
379
400
380 if value is False:
401 if value is False:
381 return HTML.tag('img', src=url("/images/icons/cancel.png"),
402 return HTML.tag('img', src=url("/images/icons/cancel.png"),
382 alt=_('False'))
403 alt=_('False'))
383
404
384 return value
405 return value
385
406
386
407
387 def action_parser(user_log, feed=False):
408 def action_parser(user_log, feed=False):
388 """This helper will action_map the specified string action into translated
409 """This helper will action_map the specified string action into translated
389 fancy names with icons and links
410 fancy names with icons and links
390
411
391 :param user_log: user log instance
412 :param user_log: user log instance
392 :param feed: use output for feeds (no html and fancy icons)
413 :param feed: use output for feeds (no html and fancy icons)
393 """
414 """
394
415
395 action = user_log.action
416 action = user_log.action
396 action_params = ' '
417 action_params = ' '
397
418
398 x = action.split(':')
419 x = action.split(':')
399
420
400 if len(x) > 1:
421 if len(x) > 1:
401 action, action_params = x
422 action, action_params = x
402
423
403 def get_cs_links():
424 def get_cs_links():
404 revs_limit = 3 #display this amount always
425 revs_limit = 3 #display this amount always
405 revs_top_limit = 50 #show upto this amount of changesets hidden
426 revs_top_limit = 50 #show upto this amount of changesets hidden
406 revs = action_params.split(',')
427 revs = action_params.split(',')
407 repo_name = user_log.repository.repo_name
428 repo_name = user_log.repository.repo_name
408
429
409 from rhodecode.model.scm import ScmModel
430 from rhodecode.model.scm import ScmModel
410 repo = user_log.repository.scm_instance
431 repo = user_log.repository.scm_instance
411
432
412 message = lambda rev: get_changeset_safe(repo, rev).message
433 message = lambda rev: get_changeset_safe(repo, rev).message
413 cs_links = []
434 cs_links = []
414 cs_links.append(" " + ', '.join ([link_to(rev,
435 cs_links.append(" " + ', '.join ([link_to(rev,
415 url('changeset_home',
436 url('changeset_home',
416 repo_name=repo_name,
437 repo_name=repo_name,
417 revision=rev), title=tooltip(message(rev)),
438 revision=rev), title=tooltip(message(rev)),
418 class_='tooltip') for rev in revs[:revs_limit] ]))
439 class_='tooltip') for rev in revs[:revs_limit] ]))
419
440
420 compare_view = (' <div class="compare_view tooltip" title="%s">'
441 compare_view = (' <div class="compare_view tooltip" title="%s">'
421 '<a href="%s">%s</a> '
442 '<a href="%s">%s</a> '
422 '</div>' % (_('Show all combined changesets %s->%s' \
443 '</div>' % (_('Show all combined changesets %s->%s' \
423 % (revs[0], revs[-1])),
444 % (revs[0], revs[-1])),
424 url('changeset_home', repo_name=repo_name,
445 url('changeset_home', repo_name=repo_name,
425 revision='%s...%s' % (revs[0], revs[-1])
446 revision='%s...%s' % (revs[0], revs[-1])
426 ),
447 ),
427 _('compare view'))
448 _('compare view'))
428 )
449 )
429
450
430 if len(revs) > revs_limit:
451 if len(revs) > revs_limit:
431 uniq_id = revs[0]
452 uniq_id = revs[0]
432 html_tmpl = ('<span> %s '
453 html_tmpl = ('<span> %s '
433 '<a class="show_more" id="_%s" href="#more">%s</a> '
454 '<a class="show_more" id="_%s" href="#more">%s</a> '
434 '%s</span>')
455 '%s</span>')
435 if not feed:
456 if not feed:
436 cs_links.append(html_tmpl % (_('and'), uniq_id, _('%s more') \
457 cs_links.append(html_tmpl % (_('and'), uniq_id, _('%s more') \
437 % (len(revs) - revs_limit),
458 % (len(revs) - revs_limit),
438 _('revisions')))
459 _('revisions')))
439
460
440 if not feed:
461 if not feed:
441 html_tmpl = '<span id="%s" style="display:none"> %s </span>'
462 html_tmpl = '<span id="%s" style="display:none"> %s </span>'
442 else:
463 else:
443 html_tmpl = '<span id="%s"> %s </span>'
464 html_tmpl = '<span id="%s"> %s </span>'
444
465
445 cs_links.append(html_tmpl % (uniq_id, ', '.join([link_to(rev,
466 cs_links.append(html_tmpl % (uniq_id, ', '.join([link_to(rev,
446 url('changeset_home',
467 url('changeset_home',
447 repo_name=repo_name, revision=rev),
468 repo_name=repo_name, revision=rev),
448 title=message(rev), class_='tooltip')
469 title=message(rev), class_='tooltip')
449 for rev in revs[revs_limit:revs_top_limit]])))
470 for rev in revs[revs_limit:revs_top_limit]])))
450 if len(revs) > 1:
471 if len(revs) > 1:
451 cs_links.append(compare_view)
472 cs_links.append(compare_view)
452 return ''.join(cs_links)
473 return ''.join(cs_links)
453
474
454 def get_fork_name():
475 def get_fork_name():
455 repo_name = action_params
476 repo_name = action_params
456 return _('fork name ') + str(link_to(action_params, url('summary_home',
477 return _('fork name ') + str(link_to(action_params, url('summary_home',
457 repo_name=repo_name,)))
478 repo_name=repo_name,)))
458
479
459 action_map = {'user_deleted_repo':(_('[deleted] repository'), None),
480 action_map = {'user_deleted_repo':(_('[deleted] repository'), None),
460 'user_created_repo':(_('[created] repository'), None),
481 'user_created_repo':(_('[created] repository'), None),
461 'user_created_fork':(_('[created] repository as fork'), None),
482 'user_created_fork':(_('[created] repository as fork'), None),
462 'user_forked_repo':(_('[forked] repository'), get_fork_name),
483 'user_forked_repo':(_('[forked] repository'), get_fork_name),
463 'user_updated_repo':(_('[updated] repository'), None),
484 'user_updated_repo':(_('[updated] repository'), None),
464 'admin_deleted_repo':(_('[delete] repository'), None),
485 'admin_deleted_repo':(_('[delete] repository'), None),
465 'admin_created_repo':(_('[created] repository'), None),
486 'admin_created_repo':(_('[created] repository'), None),
466 'admin_forked_repo':(_('[forked] repository'), None),
487 'admin_forked_repo':(_('[forked] repository'), None),
467 'admin_updated_repo':(_('[updated] repository'), None),
488 'admin_updated_repo':(_('[updated] repository'), None),
468 'push':(_('[pushed] into'), get_cs_links),
489 'push':(_('[pushed] into'), get_cs_links),
469 'push_local':(_('[committed via RhodeCode] into'), get_cs_links),
490 'push_local':(_('[committed via RhodeCode] into'), get_cs_links),
470 'push_remote':(_('[pulled from remote] into'), get_cs_links),
491 'push_remote':(_('[pulled from remote] into'), get_cs_links),
471 'pull':(_('[pulled] from'), None),
492 'pull':(_('[pulled] from'), None),
472 'started_following_repo':(_('[started following] repository'), None),
493 'started_following_repo':(_('[started following] repository'), None),
473 'stopped_following_repo':(_('[stopped following] repository'), None),
494 'stopped_following_repo':(_('[stopped following] repository'), None),
474 }
495 }
475
496
476 action_str = action_map.get(action, action)
497 action_str = action_map.get(action, action)
477 if feed:
498 if feed:
478 action = action_str[0].replace('[', '').replace(']', '')
499 action = action_str[0].replace('[', '').replace(']', '')
479 else:
500 else:
480 action = action_str[0].replace('[', '<span class="journal_highlight">')\
501 action = action_str[0].replace('[', '<span class="journal_highlight">')\
481 .replace(']', '</span>')
502 .replace(']', '</span>')
482
503
483 action_params_func = lambda :""
504 action_params_func = lambda :""
484
505
485 if callable(action_str[1]):
506 if callable(action_str[1]):
486 action_params_func = action_str[1]
507 action_params_func = action_str[1]
487
508
488 return [literal(action), action_params_func]
509 return [literal(action), action_params_func]
489
510
511
490 def action_parser_icon(user_log):
512 def action_parser_icon(user_log):
491 action = user_log.action
513 action = user_log.action
492 action_params = None
514 action_params = None
493 x = action.split(':')
515 x = action.split(':')
494
516
495 if len(x) > 1:
517 if len(x) > 1:
496 action, action_params = x
518 action, action_params = x
497
519
498 tmpl = """<img src="%s%s" alt="%s"/>"""
520 tmpl = """<img src="%s%s" alt="%s"/>"""
499 map = {'user_deleted_repo':'database_delete.png',
521 map = {'user_deleted_repo':'database_delete.png',
500 'user_created_repo':'database_add.png',
522 'user_created_repo':'database_add.png',
501 'user_created_fork':'arrow_divide.png',
523 'user_created_fork':'arrow_divide.png',
502 'user_forked_repo':'arrow_divide.png',
524 'user_forked_repo':'arrow_divide.png',
503 'user_updated_repo':'database_edit.png',
525 'user_updated_repo':'database_edit.png',
504 'admin_deleted_repo':'database_delete.png',
526 'admin_deleted_repo':'database_delete.png',
505 'admin_created_repo':'database_add.png',
527 'admin_created_repo':'database_add.png',
506 'admin_forked_repo':'arrow_divide.png',
528 'admin_forked_repo':'arrow_divide.png',
507 'admin_updated_repo':'database_edit.png',
529 'admin_updated_repo':'database_edit.png',
508 'push':'script_add.png',
530 'push':'script_add.png',
509 'push_local':'script_edit.png',
531 'push_local':'script_edit.png',
510 'push_remote':'connect.png',
532 'push_remote':'connect.png',
511 'pull':'down_16.png',
533 'pull':'down_16.png',
512 'started_following_repo':'heart_add.png',
534 'started_following_repo':'heart_add.png',
513 'stopped_following_repo':'heart_delete.png',
535 'stopped_following_repo':'heart_delete.png',
514 }
536 }
515 return literal(tmpl % ((url('/images/icons/')),
537 return literal(tmpl % ((url('/images/icons/')),
516 map.get(action, action), action))
538 map.get(action, action), action))
517
539
518
540
519 #==============================================================================
541 #==============================================================================
520 # PERMS
542 # PERMS
521 #==============================================================================
543 #==============================================================================
522 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
544 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
523 HasRepoPermissionAny, HasRepoPermissionAll
545 HasRepoPermissionAny, HasRepoPermissionAll
524
546
547
525 #==============================================================================
548 #==============================================================================
526 # GRAVATAR URL
549 # GRAVATAR URL
527 #==============================================================================
550 #==============================================================================
528
551
529 def gravatar_url(email_address, size=30):
552 def gravatar_url(email_address, size=30):
530 if (not str2bool(config['app_conf'].get('use_gravatar')) or
553 if (not str2bool(config['app_conf'].get('use_gravatar')) or
531 not email_address or email_address == 'anonymous@rhodecode.org'):
554 not email_address or email_address == 'anonymous@rhodecode.org'):
532 f=lambda a,l:min(l,key=lambda x:abs(x-a))
555 f=lambda a,l:min(l,key=lambda x:abs(x-a))
533 return url("/images/user%s.png" % f(size, [14, 16, 20, 24, 30]))
556 return url("/images/user%s.png" % f(size, [14, 16, 20, 24, 30]))
534
557
535 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
558 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
536 default = 'identicon'
559 default = 'identicon'
537 baseurl_nossl = "http://www.gravatar.com/avatar/"
560 baseurl_nossl = "http://www.gravatar.com/avatar/"
538 baseurl_ssl = "https://secure.gravatar.com/avatar/"
561 baseurl_ssl = "https://secure.gravatar.com/avatar/"
539 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
562 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
540
563
541 if isinstance(email_address, unicode):
564 if isinstance(email_address, unicode):
542 #hashlib crashes on unicode items
565 #hashlib crashes on unicode items
543 email_address = safe_str(email_address)
566 email_address = safe_str(email_address)
544 # construct the url
567 # construct the url
545 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
568 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
546 gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
569 gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
547
570
548 return gravatar_url
571 return gravatar_url
549
572
550
573
551 #==============================================================================
574 #==============================================================================
552 # REPO PAGER, PAGER FOR REPOSITORY
575 # REPO PAGER, PAGER FOR REPOSITORY
553 #==============================================================================
576 #==============================================================================
554 class RepoPage(Page):
577 class RepoPage(Page):
555
578
556 def __init__(self, collection, page=1, items_per_page=20,
579 def __init__(self, collection, page=1, items_per_page=20,
557 item_count=None, url=None, **kwargs):
580 item_count=None, url=None, **kwargs):
558
581
559 """Create a "RepoPage" instance. special pager for paging
582 """Create a "RepoPage" instance. special pager for paging
560 repository
583 repository
561 """
584 """
562 self._url_generator = url
585 self._url_generator = url
563
586
564 # Safe the kwargs class-wide so they can be used in the pager() method
587 # Safe the kwargs class-wide so they can be used in the pager() method
565 self.kwargs = kwargs
588 self.kwargs = kwargs
566
589
567 # Save a reference to the collection
590 # Save a reference to the collection
568 self.original_collection = collection
591 self.original_collection = collection
569
592
570 self.collection = collection
593 self.collection = collection
571
594
572 # The self.page is the number of the current page.
595 # The self.page is the number of the current page.
573 # The first page has the number 1!
596 # The first page has the number 1!
574 try:
597 try:
575 self.page = int(page) # make it int() if we get it as a string
598 self.page = int(page) # make it int() if we get it as a string
576 except (ValueError, TypeError):
599 except (ValueError, TypeError):
577 self.page = 1
600 self.page = 1
578
601
579 self.items_per_page = items_per_page
602 self.items_per_page = items_per_page
580
603
581 # Unless the user tells us how many items the collections has
604 # Unless the user tells us how many items the collections has
582 # we calculate that ourselves.
605 # we calculate that ourselves.
583 if item_count is not None:
606 if item_count is not None:
584 self.item_count = item_count
607 self.item_count = item_count
585 else:
608 else:
586 self.item_count = len(self.collection)
609 self.item_count = len(self.collection)
587
610
588 # Compute the number of the first and last available page
611 # Compute the number of the first and last available page
589 if self.item_count > 0:
612 if self.item_count > 0:
590 self.first_page = 1
613 self.first_page = 1
591 self.page_count = int(math.ceil(float(self.item_count) /
614 self.page_count = int(math.ceil(float(self.item_count) /
592 self.items_per_page))
615 self.items_per_page))
593 self.last_page = self.first_page + self.page_count - 1
616 self.last_page = self.first_page + self.page_count - 1
594
617
595 # Make sure that the requested page number is the range of
618 # Make sure that the requested page number is the range of
596 # valid pages
619 # valid pages
597 if self.page > self.last_page:
620 if self.page > self.last_page:
598 self.page = self.last_page
621 self.page = self.last_page
599 elif self.page < self.first_page:
622 elif self.page < self.first_page:
600 self.page = self.first_page
623 self.page = self.first_page
601
624
602 # Note: the number of items on this page can be less than
625 # Note: the number of items on this page can be less than
603 # items_per_page if the last page is not full
626 # items_per_page if the last page is not full
604 self.first_item = max(0, (self.item_count) - (self.page *
627 self.first_item = max(0, (self.item_count) - (self.page *
605 items_per_page))
628 items_per_page))
606 self.last_item = ((self.item_count - 1) - items_per_page *
629 self.last_item = ((self.item_count - 1) - items_per_page *
607 (self.page - 1))
630 (self.page - 1))
608
631
609 self.items = list(self.collection[self.first_item:self.last_item + 1])
632 self.items = list(self.collection[self.first_item:self.last_item + 1])
610
633
611 # Links to previous and next page
634 # Links to previous and next page
612 if self.page > self.first_page:
635 if self.page > self.first_page:
613 self.previous_page = self.page - 1
636 self.previous_page = self.page - 1
614 else:
637 else:
615 self.previous_page = None
638 self.previous_page = None
616
639
617 if self.page < self.last_page:
640 if self.page < self.last_page:
618 self.next_page = self.page + 1
641 self.next_page = self.page + 1
619 else:
642 else:
620 self.next_page = None
643 self.next_page = None
621
644
622 # No items available
645 # No items available
623 else:
646 else:
624 self.first_page = None
647 self.first_page = None
625 self.page_count = 0
648 self.page_count = 0
626 self.last_page = None
649 self.last_page = None
627 self.first_item = None
650 self.first_item = None
628 self.last_item = None
651 self.last_item = None
629 self.previous_page = None
652 self.previous_page = None
630 self.next_page = None
653 self.next_page = None
631 self.items = []
654 self.items = []
632
655
633 # This is a subclass of the 'list' type. Initialise the list now.
656 # This is a subclass of the 'list' type. Initialise the list now.
634 list.__init__(self, reversed(self.items))
657 list.__init__(self, reversed(self.items))
635
658
636
659
637 def changed_tooltip(nodes):
660 def changed_tooltip(nodes):
638 """
661 """
639 Generates a html string for changed nodes in changeset page.
662 Generates a html string for changed nodes in changeset page.
640 It limits the output to 30 entries
663 It limits the output to 30 entries
641
664
642 :param nodes: LazyNodesGenerator
665 :param nodes: LazyNodesGenerator
643 """
666 """
644 if nodes:
667 if nodes:
645 pref = ': <br/> '
668 pref = ': <br/> '
646 suf = ''
669 suf = ''
647 if len(nodes) > 30:
670 if len(nodes) > 30:
648 suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
671 suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
649 return literal(pref + '<br/> '.join([safe_unicode(x.path)
672 return literal(pref + '<br/> '.join([safe_unicode(x.path)
650 for x in nodes[:30]]) + suf)
673 for x in nodes[:30]]) + suf)
651 else:
674 else:
652 return ': ' + _('No Files')
675 return ': ' + _('No Files')
653
676
654
677
655
656 def repo_link(groups_and_repos):
678 def repo_link(groups_and_repos):
657 """
679 """
658 Makes a breadcrumbs link to repo within a group
680 Makes a breadcrumbs link to repo within a group
659 joins &raquo; on each group to create a fancy link
681 joins &raquo; on each group to create a fancy link
660
682
661 ex::
683 ex::
662 group >> subgroup >> repo
684 group >> subgroup >> repo
663
685
664 :param groups_and_repos:
686 :param groups_and_repos:
665 """
687 """
666 groups, repo_name = groups_and_repos
688 groups, repo_name = groups_and_repos
667
689
668 if not groups:
690 if not groups:
669 return repo_name
691 return repo_name
670 else:
692 else:
671 def make_link(group):
693 def make_link(group):
672 return link_to(group.name, url('repos_group_home',
694 return link_to(group.name, url('repos_group_home',
673 group_name=group.group_name))
695 group_name=group.group_name))
674 return literal(' &raquo; '.join(map(make_link, groups)) + \
696 return literal(' &raquo; '.join(map(make_link, groups)) + \
675 " &raquo; " + repo_name)
697 " &raquo; " + repo_name)
676
698
699
677 def fancy_file_stats(stats):
700 def fancy_file_stats(stats):
678 """
701 """
679 Displays a fancy two colored bar for number of added/deleted
702 Displays a fancy two colored bar for number of added/deleted
680 lines of code on file
703 lines of code on file
681
704
682 :param stats: two element list of added/deleted lines of code
705 :param stats: two element list of added/deleted lines of code
683 """
706 """
684
707
685 a, d, t = stats[0], stats[1], stats[0] + stats[1]
708 a, d, t = stats[0], stats[1], stats[0] + stats[1]
686 width = 100
709 width = 100
687 unit = float(width) / (t or 1)
710 unit = float(width) / (t or 1)
688
711
689 # needs > 9% of width to be visible or 0 to be hidden
712 # needs > 9% of width to be visible or 0 to be hidden
690 a_p = max(9, unit * a) if a > 0 else 0
713 a_p = max(9, unit * a) if a > 0 else 0
691 d_p = max(9, unit * d) if d > 0 else 0
714 d_p = max(9, unit * d) if d > 0 else 0
692 p_sum = a_p + d_p
715 p_sum = a_p + d_p
693
716
694 if p_sum > width:
717 if p_sum > width:
695 #adjust the percentage to be == 100% since we adjusted to 9
718 #adjust the percentage to be == 100% since we adjusted to 9
696 if a_p > d_p:
719 if a_p > d_p:
697 a_p = a_p - (p_sum - width)
720 a_p = a_p - (p_sum - width)
698 else:
721 else:
699 d_p = d_p - (p_sum - width)
722 d_p = d_p - (p_sum - width)
700
723
701 a_v = a if a > 0 else ''
724 a_v = a if a > 0 else ''
702 d_v = d if d > 0 else ''
725 d_v = d if d > 0 else ''
703
726
704
705 def cgen(l_type):
727 def cgen(l_type):
706 mapping = {'tr':'top-right-rounded-corner',
728 mapping = {'tr': 'top-right-rounded-corner',
707 'tl':'top-left-rounded-corner',
729 'tl': 'top-left-rounded-corner',
708 'br':'bottom-right-rounded-corner',
730 'br': 'bottom-right-rounded-corner',
709 'bl':'bottom-left-rounded-corner'}
731 'bl': 'bottom-left-rounded-corner'}
710 map_getter = lambda x:mapping[x]
732 map_getter = lambda x: mapping[x]
711
733
712 if l_type == 'a' and d_v:
734 if l_type == 'a' and d_v:
713 #case when added and deleted are present
735 #case when added and deleted are present
714 return ' '.join(map(map_getter, ['tl', 'bl']))
736 return ' '.join(map(map_getter, ['tl', 'bl']))
715
737
716 if l_type == 'a' and not d_v:
738 if l_type == 'a' and not d_v:
717 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
739 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
718
740
719 if l_type == 'd' and a_v:
741 if l_type == 'd' and a_v:
720 return ' '.join(map(map_getter, ['tr', 'br']))
742 return ' '.join(map(map_getter, ['tr', 'br']))
721
743
722 if l_type == 'd' and not a_v:
744 if l_type == 'd' and not a_v:
723 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
745 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
724
746
725
747 d_a = '<div class="added %s" style="width:%s%%">%s</div>' % (
726
748 cgen('a'),a_p, a_v
727 d_a = '<div class="added %s" style="width:%s%%">%s</div>' % (cgen('a'),
749 )
728 a_p, a_v)
750 d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % (
729 d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % (cgen('d'),
751 cgen('d'),d_p, d_v
730 d_p, d_v)
752 )
731 return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
753 return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
732
754
733
755
734 def urlify_text(text_):
756 def urlify_text(text_):
735 import re
757 import re
736
758
737 url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'''
759 url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'''
738 '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''')
760 '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''')
739
761
740 def url_func(match_obj):
762 def url_func(match_obj):
741 url_full = match_obj.groups()[0]
763 url_full = match_obj.groups()[0]
742 return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
764 return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
743
765
744 return literal(url_pat.sub(url_func, text_))
766 return literal(url_pat.sub(url_func, text_))
745
767
768
746 def urlify_changesets(text_, repository):
769 def urlify_changesets(text_, repository):
747 import re
770 import re
748 URL_PAT = re.compile(r'([0-9a-fA-F]{12,})')
771 URL_PAT = re.compile(r'([0-9a-fA-F]{12,})')
749
772
750 def url_func(match_obj):
773 def url_func(match_obj):
751 rev = match_obj.groups()[0]
774 rev = match_obj.groups()[0]
752 pref = ''
775 pref = ''
753 if match_obj.group().startswith(' '):
776 if match_obj.group().startswith(' '):
754 pref = ' '
777 pref = ' '
755 tmpl = (
778 tmpl = (
756 '%(pref)s<a class="%(cls)s" href="%(url)s">'
779 '%(pref)s<a class="%(cls)s" href="%(url)s">'
757 '%(rev)s'
780 '%(rev)s'
758 '</a>'
781 '</a>'
759 )
782 )
760 return tmpl % {
783 return tmpl % {
761 'pref': pref,
784 'pref': pref,
762 'cls': 'revision-link',
785 'cls': 'revision-link',
763 'url': url('changeset_home', repo_name=repository, revision=rev),
786 'url': url('changeset_home', repo_name=repository, revision=rev),
764 'rev': rev,
787 'rev': rev,
765 }
788 }
766
789
767 newtext = URL_PAT.sub(url_func, text_)
790 newtext = URL_PAT.sub(url_func, text_)
768
791
769 return newtext
792 return newtext
770
793
794
771 def urlify_commit(text_, repository=None, link_=None):
795 def urlify_commit(text_, repository=None, link_=None):
772 import re
796 import re
773 import traceback
797 import traceback
774
798
775 # urlify changesets
799 # urlify changesets
776 text_ = urlify_changesets(text_, repository)
800 text_ = urlify_changesets(text_, repository)
777
801
778 def linkify_others(t,l):
802 def linkify_others(t,l):
779 urls = re.compile(r'(\<a.*?\<\/a\>)',)
803 urls = re.compile(r'(\<a.*?\<\/a\>)',)
780 links = []
804 links = []
781 for e in urls.split(t):
805 for e in urls.split(t):
782 if not urls.match(e):
806 if not urls.match(e):
783 links.append('<a class="message-link" href="%s">%s</a>' % (l,e))
807 links.append('<a class="message-link" href="%s">%s</a>' % (l,e))
784 else:
808 else:
785 links.append(e)
809 links.append(e)
786
810
787 return ''.join(links)
811 return ''.join(links)
788 try:
812 try:
789 conf = config['app_conf']
813 conf = config['app_conf']
790
814
791 URL_PAT = re.compile(r'%s' % conf.get('issue_pat'))
815 URL_PAT = re.compile(r'%s' % conf.get('issue_pat'))
792
816
793 if URL_PAT:
817 if URL_PAT:
794 ISSUE_SERVER_LNK = conf.get('issue_server_link')
818 ISSUE_SERVER_LNK = conf.get('issue_server_link')
795 ISSUE_PREFIX = conf.get('issue_prefix')
819 ISSUE_PREFIX = conf.get('issue_prefix')
796
820
797 def url_func(match_obj):
821 def url_func(match_obj):
798 pref = ''
822 pref = ''
799 if match_obj.group().startswith(' '):
823 if match_obj.group().startswith(' '):
800 pref = ' '
824 pref = ' '
801
825
802 issue_id = ''.join(match_obj.groups())
826 issue_id = ''.join(match_obj.groups())
803 tmpl = (
827 tmpl = (
804 '%(pref)s<a class="%(cls)s" href="%(url)s">'
828 '%(pref)s<a class="%(cls)s" href="%(url)s">'
805 '%(issue-prefix)s%(id-repr)s'
829 '%(issue-prefix)s%(id-repr)s'
806 '</a>'
830 '</a>'
807 )
831 )
808 url = ISSUE_SERVER_LNK.replace('{id}', issue_id)
832 url = ISSUE_SERVER_LNK.replace('{id}', issue_id)
809 if repository:
833 if repository:
810 url = url.replace('{repo}', repository)
834 url = url.replace('{repo}', repository)
811
835
812 return tmpl % {
836 return tmpl % {
813 'pref': pref,
837 'pref': pref,
814 'cls': 'issue-tracker-link',
838 'cls': 'issue-tracker-link',
815 'url': url,
839 'url': url,
816 'id-repr': issue_id,
840 'id-repr': issue_id,
817 'issue-prefix': ISSUE_PREFIX,
841 'issue-prefix': ISSUE_PREFIX,
818 'serv': ISSUE_SERVER_LNK,
842 'serv': ISSUE_SERVER_LNK,
819 }
843 }
820
844
821 newtext = URL_PAT.sub(url_func, text_)
845 newtext = URL_PAT.sub(url_func, text_)
822
846
823 # wrap not links into final link => link_
847 # wrap not links into final link => link_
824 newtext = linkify_others(newtext, link_)
848 newtext = linkify_others(newtext, link_)
825
849
826 return literal(newtext)
850 return literal(newtext)
827 except:
851 except:
828 log.error(traceback.format_exc())
852 log.error(traceback.format_exc())
829 pass
853 pass
830
854
831 return text_
855 return text_
832
856
833
857
834 def rst(source):
858 def rst(source):
835 return literal('<div class="rst-block">%s</div>' %
859 return literal('<div class="rst-block">%s</div>' %
836 MarkupRenderer.rst(source))
860 MarkupRenderer.rst(source))
837
861
838
862
839 def rst_w_mentions(source):
863 def rst_w_mentions(source):
840 """
864 """
841 Wrapped rst renderer with @mention highlighting
865 Wrapped rst renderer with @mention highlighting
842
866
843 :param source:
867 :param source:
844 """
868 """
845 return literal('<div class="rst-block">%s</div>' %
869 return literal('<div class="rst-block">%s</div>' %
846 MarkupRenderer.rst_with_mentions(source))
870 MarkupRenderer.rst_with_mentions(source))
@@ -1,78 +1,78 b''
1 ## DATA TABLE RE USABLE ELEMENTS
1 ## DATA TABLE RE USABLE ELEMENTS
2 ## usage:
2 ## usage:
3 ## <%namespace name="dt" file="/_data_table/_dt_elements.html"/>
3 ## <%namespace name="dt" file="/_data_table/_dt_elements.html"/>
4
4
5 <%def name="quick_menu(repo_name)">
5 <%def name="quick_menu(repo_name)">
6 <ul class="menu_items hidden">
6 <ul class="menu_items hidden">
7 <li style="border-top:1px solid #003367;margin-left:18px;padding-left:-99px"></li>
7 <li style="border-top:1px solid #003367;margin-left:18px;padding-left:-99px"></li>
8 <li>
8 <li>
9 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=repo_name)}">
9 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=repo_name)}">
10 <span class="icon">
10 <span class="icon">
11 <img src="${h.url('/images/icons/clipboard_16.png')}" alt="${_('Summary')}" />
11 <img src="${h.url('/images/icons/clipboard_16.png')}" alt="${_('Summary')}" />
12 </span>
12 </span>
13 <span>${_('Summary')}</span>
13 <span>${_('Summary')}</span>
14 </a>
14 </a>
15 </li>
15 </li>
16 <li>
16 <li>
17 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=repo_name)}">
17 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=repo_name)}">
18 <span class="icon">
18 <span class="icon">
19 <img src="${h.url('/images/icons/time.png')}" alt="${_('Changelog')}" />
19 <img src="${h.url('/images/icons/time.png')}" alt="${_('Changelog')}" />
20 </span>
20 </span>
21 <span>${_('Changelog')}</span>
21 <span>${_('Changelog')}</span>
22 </a>
22 </a>
23 </li>
23 </li>
24 <li>
24 <li>
25 <a title="${_('Files')}" href="${h.url('files_home',repo_name=repo_name)}">
25 <a title="${_('Files')}" href="${h.url('files_home',repo_name=repo_name)}">
26 <span class="icon">
26 <span class="icon">
27 <img src="${h.url('/images/icons/file.png')}" alt="${_('Files')}" />
27 <img src="${h.url('/images/icons/file.png')}" alt="${_('Files')}" />
28 </span>
28 </span>
29 <span>${_('Files')}</span>
29 <span>${_('Files')}</span>
30 </a>
30 </a>
31 </li>
31 </li>
32 <li>
32 <li>
33 <a title="${_('Fork')}" href="${h.url('repo_fork_home',repo_name=repo_name)}">
33 <a title="${_('Fork')}" href="${h.url('repo_fork_home',repo_name=repo_name)}">
34 <span class="icon">
34 <span class="icon">
35 <img src="${h.url('/images/icons/arrow_divide.png')}" alt="${_('Fork')}" />
35 <img src="${h.url('/images/icons/arrow_divide.png')}" alt="${_('Fork')}" />
36 </span>
36 </span>
37 <span>${_('Fork')}</span>
37 <span>${_('Fork')}</span>
38 </a>
38 </a>
39 </li>
39 </li>
40 </ul>
40 </ul>
41 </%def>
41 </%def>
42
42
43 <%def name="repo_name(name,rtype,private,fork_of)">
43 <%def name="repo_name(name,rtype,private,fork_of)">
44 <div style="white-space: nowrap">
44 <div style="white-space: nowrap">
45 ##TYPE OF REPO
45 ##TYPE OF REPO
46 %if rtype =='hg':
46 %if h.is_hg(rtype):
47 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
47 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
48 %elif rtype =='git':
48 %elif h.is_git(rtype):
49 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
49 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
50 %endif
50 %endif
51
51
52 ##PRIVATE/PUBLIC
52 ##PRIVATE/PUBLIC
53 %if private:
53 %if private:
54 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
54 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
55 %else:
55 %else:
56 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
56 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
57 %endif
57 %endif
58
58
59 ##NAME
59 ##NAME
60 ${h.link_to(name,h.url('summary_home',repo_name=name),class_="repo_name")}
60 ${h.link_to(name,h.url('summary_home',repo_name=name),class_="repo_name")}
61 %if fork_of:
61 %if fork_of:
62 <a href="${h.url('summary_home',repo_name=fork_of)}">
62 <a href="${h.url('summary_home',repo_name=fork_of)}">
63 <img class="icon" alt="${_('fork')}" title="${_('Fork of')} ${fork_of}" src="${h.url('/images/icons/arrow_divide.png')}"/></a>
63 <img class="icon" alt="${_('fork')}" title="${_('Fork of')} ${fork_of}" src="${h.url('/images/icons/arrow_divide.png')}"/></a>
64 %endif
64 %endif
65 </div>
65 </div>
66 </%def>
66 </%def>
67
67
68
68
69
69
70 <%def name="revision(name,rev,tip,author,last_msg)">
70 <%def name="revision(name,rev,tip,author,last_msg)">
71 <div>
71 <div>
72 %if rev >= 0:
72 %if rev >= 0:
73 <pre><a title="${h.tooltip('%s:\n\n%s' % (author,last_msg))}" class="tooltip" href="${h.url('changeset_home',repo_name=name,revision=tip)}">${'r%s:%s' % (rev,h.short_id(tip))}</a></pre>
73 <pre><a title="${h.tooltip('%s:\n\n%s' % (author,last_msg))}" class="tooltip" href="${h.url('changeset_home',repo_name=name,revision=tip)}">${'r%s:%s' % (rev,h.short_id(tip))}</a></pre>
74 %else:
74 %else:
75 ${_('No changesets yet')}
75 ${_('No changesets yet')}
76 %endif
76 %endif
77 </div>
77 </div>
78 </%def>
78 </%def>
@@ -1,230 +1,230 b''
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 ${_('Changelog')} - ${_('showing ')} ${c.size if c.size <= c.total_cs else c.total_cs} ${_('out of')} ${c.total_cs} ${_('revisions')}
14 ${_('Changelog')} - ${_('showing ')} ${c.size if c.size <= c.total_cs else c.total_cs} ${_('out of')} ${c.total_cs} ${_('revisions')}
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 % if c.pagination:
28 % if c.pagination:
29 <div id="graph">
29 <div id="graph">
30 <div id="graph_nodes">
30 <div id="graph_nodes">
31 <canvas id="graph_canvas"></canvas>
31 <canvas id="graph_canvas"></canvas>
32 </div>
32 </div>
33 <div id="graph_content">
33 <div id="graph_content">
34 <div class="container_header">
34 <div class="container_header">
35 ${h.form(h.url.current(),method='get')}
35 ${h.form(h.url.current(),method='get')}
36 <div class="info_box" style="float:left">
36 <div class="info_box" style="float:left">
37 ${h.submit('set',_('Show'),class_="ui-btn")}
37 ${h.submit('set',_('Show'),class_="ui-btn")}
38 ${h.text('size',size=1,value=c.size)}
38 ${h.text('size',size=1,value=c.size)}
39 ${_('revisions')}
39 ${_('revisions')}
40 </div>
40 </div>
41 ${h.end_form()}
41 ${h.end_form()}
42 <div id="rev_range_container" style="display:none"></div>
42 <div id="rev_range_container" style="display:none"></div>
43 <div style="float:right">${h.select('branch_filter',c.branch_name,c.branch_filters)}</div>
43 <div style="float:right">${h.select('branch_filter',c.branch_name,c.branch_filters)}</div>
44 </div>
44 </div>
45
45
46 %for cnt,cs in enumerate(c.pagination):
46 %for cnt,cs in enumerate(c.pagination):
47 <div id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}">
47 <div id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}">
48 <div class="left">
48 <div class="left">
49 <div>
49 <div>
50 ${h.checkbox(cs.short_id,class_="changeset_range")}
50 ${h.checkbox(cs.short_id,class_="changeset_range")}
51 <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>
51 <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 </div>
52 </div>
53 <div class="author">
53 <div class="author">
54 <div class="gravatar">
54 <div class="gravatar">
55 <img alt="gravatar" src="${h.gravatar_url(h.email(cs.author),16)}"/>
55 <img alt="gravatar" src="${h.gravatar_url(h.email(cs.author),16)}"/>
56 </div>
56 </div>
57 <div title="${cs.author}" class="user">${h.person(cs.author)}</div>
57 <div title="${cs.author}" class="user">${h.person(cs.author)}</div>
58 </div>
58 </div>
59 <div class="date">${cs.date}</div>
59 <div class="date">${cs.date}</div>
60 </div>
60 </div>
61 <div class="mid">
61 <div class="mid">
62 <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>
62 <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="expand"><span class="expandtext">&darr; ${_('show more')} &darr;</span></div>
63 <div class="expand"><span class="expandtext">&darr; ${_('show more')} &darr;</span></div>
64 </div>
64 </div>
65 <div class="right">
65 <div class="right">
66 <div id="${cs.raw_id}_changes_info" class="changes">
66 <div id="${cs.raw_id}_changes_info" class="changes">
67 <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>
67 <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 class="comments-container">
68 <div class="comments-container">
69 %if len(c.comments.get(cs.raw_id,[])) > 0:
69 %if len(c.comments.get(cs.raw_id,[])) > 0:
70 <div class="comments-cnt" title="${('comments')}">
70 <div class="comments-cnt" title="${('comments')}">
71 <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)}">
71 <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 <div class="comments-cnt">${len(c.comments[cs.raw_id])}</div>
72 <div class="comments-cnt">${len(c.comments[cs.raw_id])}</div>
73 <img src="${h.url('/images/icons/comments.png')}">
73 <img src="${h.url('/images/icons/comments.png')}">
74 </a>
74 </a>
75 </div>
75 </div>
76 %endif
76 %endif
77 </div>
77 </div>
78 </div>
78 </div>
79 %if cs.parents:
79 %if cs.parents:
80 %for p_cs in reversed(cs.parents):
80 %for p_cs in reversed(cs.parents):
81 <div class="parent">${_('Parent')}
81 <div class="parent">${_('Parent')}
82 <span class="changeset_id">${p_cs.revision}:<span class="changeset_hash">${h.link_to(h.short_id(p_cs.raw_id),
82 <span class="changeset_id">${p_cs.revision}:<span class="changeset_hash">${h.link_to(h.short_id(p_cs.raw_id),
83 h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}</span></span>
83 h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}</span></span>
84 </div>
84 </div>
85 %endfor
85 %endfor
86 %else:
86 %else:
87 <div class="parent">${_('No parents')}</div>
87 <div class="parent">${_('No parents')}</div>
88 %endif
88 %endif
89
89
90 <span class="logtags">
90 <span class="logtags">
91 %if len(cs.parents)>1:
91 %if len(cs.parents)>1:
92 <span class="merge">${_('merge')}</span>
92 <span class="merge">${_('merge')}</span>
93 %endif
93 %endif
94 %if cs.branch:
94 %if h.is_hg(c.rhodecode_repo) and cs.branch:
95 <span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}">
95 <span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}">
96 ${h.link_to(cs.branch,h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
96 ${h.link_to(cs.branch,h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
97 %endif
97 %endif
98 %for tag in cs.tags:
98 %for tag in cs.tags:
99 <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
99 <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
100 ${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
100 ${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
101 %endfor
101 %endfor
102 </span>
102 </span>
103 </div>
103 </div>
104 </div>
104 </div>
105
105
106 %endfor
106 %endfor
107 <div class="pagination-wh pagination-left">
107 <div class="pagination-wh pagination-left">
108 ${c.pagination.pager('$link_previous ~2~ $link_next')}
108 ${c.pagination.pager('$link_previous ~2~ $link_next')}
109 </div>
109 </div>
110 </div>
110 </div>
111 </div>
111 </div>
112
112
113 <script type="text/javascript" src="${h.url('/js/graph.js')}"></script>
113 <script type="text/javascript" src="${h.url('/js/graph.js')}"></script>
114 <script type="text/javascript">
114 <script type="text/javascript">
115 YAHOO.util.Event.onDOMReady(function(){
115 YAHOO.util.Event.onDOMReady(function(){
116
116
117 //Monitor range checkboxes and build a link to changesets
117 //Monitor range checkboxes and build a link to changesets
118 //ranges
118 //ranges
119 var checkboxes = YUD.getElementsByClassName('changeset_range');
119 var checkboxes = YUD.getElementsByClassName('changeset_range');
120 var url_tmpl = "${h.url('changeset_home',repo_name=c.repo_name,revision='__REVRANGE__')}";
120 var url_tmpl = "${h.url('changeset_home',repo_name=c.repo_name,revision='__REVRANGE__')}";
121 YUE.on(checkboxes,'click',function(e){
121 YUE.on(checkboxes,'click',function(e){
122 var checked_checkboxes = [];
122 var checked_checkboxes = [];
123 for (pos in checkboxes){
123 for (pos in checkboxes){
124 if(checkboxes[pos].checked){
124 if(checkboxes[pos].checked){
125 checked_checkboxes.push(checkboxes[pos]);
125 checked_checkboxes.push(checkboxes[pos]);
126 }
126 }
127 }
127 }
128 if(checked_checkboxes.length>1){
128 if(checked_checkboxes.length>1){
129 var rev_end = checked_checkboxes[0].name;
129 var rev_end = checked_checkboxes[0].name;
130 var rev_start = checked_checkboxes[checked_checkboxes.length-1].name;
130 var rev_start = checked_checkboxes[checked_checkboxes.length-1].name;
131
131
132 var url = url_tmpl.replace('__REVRANGE__',
132 var url = url_tmpl.replace('__REVRANGE__',
133 rev_start+'...'+rev_end);
133 rev_start+'...'+rev_end);
134
134
135 var link = "<a href="+url+">${_('Show selected changes __S -> __E')}</a>"
135 var link = "<a href="+url+">${_('Show selected changes __S -> __E')}</a>"
136 link = link.replace('__S',rev_start);
136 link = link.replace('__S',rev_start);
137 link = link.replace('__E',rev_end);
137 link = link.replace('__E',rev_end);
138 YUD.get('rev_range_container').innerHTML = link;
138 YUD.get('rev_range_container').innerHTML = link;
139 YUD.setStyle('rev_range_container','display','');
139 YUD.setStyle('rev_range_container','display','');
140 }
140 }
141 else{
141 else{
142 YUD.setStyle('rev_range_container','display','none');
142 YUD.setStyle('rev_range_container','display','none');
143
143
144 }
144 }
145 });
145 });
146
146
147 var msgs = YUQ('.message');
147 var msgs = YUQ('.message');
148 // get first element height
148 // get first element height
149 var el = YUQ('#graph_content .container')[0];
149 var el = YUQ('#graph_content .container')[0];
150 var row_h = el.clientHeight;
150 var row_h = el.clientHeight;
151 for(var i=0;i<msgs.length;i++){
151 for(var i=0;i<msgs.length;i++){
152 var m = msgs[i];
152 var m = msgs[i];
153
153
154 var h = m.clientHeight;
154 var h = m.clientHeight;
155 var pad = YUD.getStyle(m,'padding');
155 var pad = YUD.getStyle(m,'padding');
156 if(h > row_h){
156 if(h > row_h){
157 var offset = row_h - (h+12);
157 var offset = row_h - (h+12);
158 YUD.setStyle(m.nextElementSibling,'display','block');
158 YUD.setStyle(m.nextElementSibling,'display','block');
159 YUD.setStyle(m.nextElementSibling,'margin-top',offset+'px');
159 YUD.setStyle(m.nextElementSibling,'margin-top',offset+'px');
160 };
160 };
161 }
161 }
162 YUE.on(YUQ('.expand'),'click',function(e){
162 YUE.on(YUQ('.expand'),'click',function(e){
163 var elem = e.currentTarget.parentNode.parentNode;
163 var elem = e.currentTarget.parentNode.parentNode;
164 YUD.setStyle(e.currentTarget,'display','none');
164 YUD.setStyle(e.currentTarget,'display','none');
165 YUD.setStyle(elem,'height','auto');
165 YUD.setStyle(elem,'height','auto');
166
166
167 //redraw the graph, max_w and jsdata are global vars
167 //redraw the graph, max_w and jsdata are global vars
168 set_canvas(max_w);
168 set_canvas(max_w);
169
169
170 var r = new BranchRenderer();
170 var r = new BranchRenderer();
171 r.render(jsdata,max_w);
171 r.render(jsdata,max_w);
172
172
173 })
173 })
174
174
175 // Fetch changeset details
175 // Fetch changeset details
176 YUE.on(YUD.getElementsByClassName('changed_total'),'click',function(e){
176 YUE.on(YUD.getElementsByClassName('changed_total'),'click',function(e){
177 var id = e.currentTarget.id
177 var id = e.currentTarget.id
178 var url = "${h.url('changelog_details',repo_name=c.repo_name,cs='__CS__')}"
178 var url = "${h.url('changelog_details',repo_name=c.repo_name,cs='__CS__')}"
179 var url = url.replace('__CS__',id);
179 var url = url.replace('__CS__',id);
180 ypjax(url,id+'_changes_info',function(){tooltip_activate()});
180 ypjax(url,id+'_changes_info',function(){tooltip_activate()});
181 });
181 });
182
182
183 // change branch filter
183 // change branch filter
184 YUE.on(YUD.get('branch_filter'),'change',function(e){
184 YUE.on(YUD.get('branch_filter'),'change',function(e){
185 var selected_branch = e.currentTarget.options[e.currentTarget.selectedIndex].value;
185 var selected_branch = e.currentTarget.options[e.currentTarget.selectedIndex].value;
186 var url_main = "${h.url('changelog_home',repo_name=c.repo_name)}";
186 var url_main = "${h.url('changelog_home',repo_name=c.repo_name)}";
187 var url = "${h.url('changelog_home',repo_name=c.repo_name,branch='__BRANCH__')}";
187 var url = "${h.url('changelog_home',repo_name=c.repo_name,branch='__BRANCH__')}";
188 var url = url.replace('__BRANCH__',selected_branch);
188 var url = url.replace('__BRANCH__',selected_branch);
189 if(selected_branch != ''){
189 if(selected_branch != ''){
190 window.location = url;
190 window.location = url;
191 }else{
191 }else{
192 window.location = url_main;
192 window.location = url_main;
193 }
193 }
194
194
195 });
195 });
196
196
197 function set_canvas(heads) {
197 function set_canvas(heads) {
198 var c = document.getElementById('graph_nodes');
198 var c = document.getElementById('graph_nodes');
199 var t = document.getElementById('graph_content');
199 var t = document.getElementById('graph_content');
200 canvas = document.getElementById('graph_canvas');
200 canvas = document.getElementById('graph_canvas');
201 var div_h = t.clientHeight;
201 var div_h = t.clientHeight;
202 c.style.height=div_h+'px';
202 c.style.height=div_h+'px';
203 canvas.setAttribute('height',div_h);
203 canvas.setAttribute('height',div_h);
204 c.style.height=max_w+'px';
204 c.style.height=max_w+'px';
205 canvas.setAttribute('width',max_w);
205 canvas.setAttribute('width',max_w);
206 };
206 };
207 var heads = 1;
207 var heads = 1;
208 var max_heads = 0;
208 var max_heads = 0;
209 var jsdata = ${c.jsdata|n};
209 var jsdata = ${c.jsdata|n};
210
210
211 for( var i=0;i<jsdata.length;i++){
211 for( var i=0;i<jsdata.length;i++){
212 var m = Math.max.apply(Math, jsdata[i][1]);
212 var m = Math.max.apply(Math, jsdata[i][1]);
213 if (m>max_heads){
213 if (m>max_heads){
214 max_heads = m;
214 max_heads = m;
215 }
215 }
216 }
216 }
217 var max_w = Math.max(100,max_heads*25);
217 var max_w = Math.max(100,max_heads*25);
218 set_canvas(max_w);
218 set_canvas(max_w);
219
219
220 var r = new BranchRenderer();
220 var r = new BranchRenderer();
221 r.render(jsdata,max_w);
221 r.render(jsdata,max_w);
222
222
223 });
223 });
224 </script>
224 </script>
225 %else:
225 %else:
226 ${_('There are no changes yet')}
226 ${_('There are no changes yet')}
227 %endif
227 %endif
228 </div>
228 </div>
229 </div>
229 </div>
230 </%def>
230 </%def>
@@ -1,220 +1,220 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3 <%def name="title()">
3 <%def name="title()">
4 ${_('Journal')} - ${c.rhodecode_name}
4 ${_('Journal')} - ${c.rhodecode_name}
5 </%def>
5 </%def>
6 <%def name="breadcrumbs()">
6 <%def name="breadcrumbs()">
7 ${c.rhodecode_name}
7 ${c.rhodecode_name}
8 </%def>
8 </%def>
9 <%def name="page_nav()">
9 <%def name="page_nav()">
10 ${self.menu('home')}
10 ${self.menu('home')}
11 </%def>
11 </%def>
12 <%def name="main()">
12 <%def name="main()">
13
13
14 <div class="box box-left">
14 <div class="box box-left">
15 <!-- box / title -->
15 <!-- box / title -->
16 <div class="title">
16 <div class="title">
17 <h5>${_('Journal')}</h5>
17 <h5>${_('Journal')}</h5>
18 <ul class="links">
18 <ul class="links">
19 <li>
19 <li>
20 <span><a id="refresh" href="${h.url('journal')}"><img class="icon" title="${_('Refresh')}" alt="${_('Refresh')}" src="${h.url('/images/icons/arrow_refresh.png')}"/>
20 <span><a id="refresh" href="${h.url('journal')}"><img class="icon" title="${_('Refresh')}" alt="${_('Refresh')}" src="${h.url('/images/icons/arrow_refresh.png')}"/>
21 </a></span>
21 </a></span>
22 </li>
22 </li>
23 </ul>
23 </ul>
24 </div>
24 </div>
25 <div id="journal">${c.journal_data}</div>
25 <div id="journal">${c.journal_data}</div>
26 </div>
26 </div>
27 <div class="box box-right">
27 <div class="box box-right">
28 <!-- box / title -->
28 <!-- box / title -->
29 <div class="title">
29 <div class="title">
30 <h5>
30 <h5>
31 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/>
31 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/>
32 <a id="show_my" class="link-white" href="#my">${_('My repos')}</a> / <a id="show_watched" class="link-white" href="#watched">${_('Watched')}</a>
32 <a id="show_my" class="link-white" href="#my">${_('My repos')}</a> / <a id="show_watched" class="link-white" href="#watched">${_('Watched')}</a>
33 </h5>
33 </h5>
34 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
34 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
35 <ul class="links">
35 <ul class="links">
36 <li>
36 <li>
37 <span>${h.link_to(_('ADD'),h.url('admin_settings_create_repository'))}</span>
37 <span>${h.link_to(_('ADD'),h.url('admin_settings_create_repository'))}</span>
38 </li>
38 </li>
39 </ul>
39 </ul>
40 %endif
40 %endif
41 </div>
41 </div>
42 <!-- end box / title -->
42 <!-- end box / title -->
43 <div id="my" class="table">
43 <div id="my" class="table">
44 %if c.user_repos:
44 %if c.user_repos:
45 <div id='repos_list_wrap' class="yui-skin-sam">
45 <div id='repos_list_wrap' class="yui-skin-sam">
46 <table id="repos_list">
46 <table id="repos_list">
47 <thead>
47 <thead>
48 <tr>
48 <tr>
49 <th></th>
49 <th></th>
50 <th class="left">${_('Name')}</th>
50 <th class="left">${_('Name')}</th>
51 <th class="left">${_('Tip')}</th>
51 <th class="left">${_('Tip')}</th>
52 <th class="left">${_('Action')}</th>
52 <th class="left">${_('Action')}</th>
53 <th class="left">${_('Action')}</th>
53 <th class="left">${_('Action')}</th>
54 </thead>
54 </thead>
55 <tbody>
55 <tbody>
56 <%namespace name="dt" file="/_data_table/_dt_elements.html"/>
56 <%namespace name="dt" file="/_data_table/_dt_elements.html"/>
57 %for repo in c.user_repos:
57 %for repo in c.user_repos:
58 <tr>
58 <tr>
59 ##QUICK MENU
59 ##QUICK MENU
60 <td class="quick_repo_menu">
60 <td class="quick_repo_menu">
61 ${dt.quick_menu(repo['name'])}
61 ${dt.quick_menu(repo['name'])}
62 </td>
62 </td>
63 ##REPO NAME AND ICONS
63 ##REPO NAME AND ICONS
64 <td class="reponame">
64 <td class="reponame">
65 ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],repo['dbrepo_fork'].get('repo_name'))}
65 ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],repo['dbrepo_fork'].get('repo_name'))}
66 </td>
66 </td>
67 ##LAST REVISION
67 ##LAST REVISION
68 <td>
68 <td>
69 ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])}
69 ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])}
70 </td>
70 </td>
71 ##
71 ##
72 <td><a href="${h.url('repo_settings_home',repo_name=repo['name'])}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="${h.url('/images/icons/application_form_edit.png')}"/></a></td>
72 <td><a href="${h.url('repo_settings_home',repo_name=repo['name'])}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="${h.url('/images/icons/application_form_edit.png')}"/></a></td>
73 <td>
73 <td>
74 ${h.form(url('repo_settings_delete', repo_name=repo['name']),method='delete')}
74 ${h.form(url('repo_settings_delete', repo_name=repo['name']),method='delete')}
75 ${h.submit('remove_%s' % repo['name'],'',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
75 ${h.submit('remove_%s' % repo['name'],'',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
76 ${h.end_form()}
76 ${h.end_form()}
77 </td>
77 </td>
78 </tr>
78 </tr>
79 %endfor
79 %endfor
80 </tbody>
80 </tbody>
81 </table>
81 </table>
82 </div>
82 </div>
83 %else:
83 %else:
84 <div style="padding:5px 0px 10px 0px;">
84 <div style="padding:5px 0px 10px 0px;">
85 ${_('No repositories yet')}
85 ${_('No repositories yet')}
86 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
86 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
87 ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'),class_="ui-btn")}
87 ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'),class_="ui-btn")}
88 %endif
88 %endif
89 </div>
89 </div>
90 %endif
90 %endif
91 </div>
91 </div>
92
92
93 <div id="watched" class="table" style="display:none">
93 <div id="watched" class="table" style="display:none">
94 %if c.following:
94 %if c.following:
95 <table>
95 <table>
96 <thead>
96 <thead>
97 <tr>
97 <tr>
98 <th class="left">${_('Name')}</th>
98 <th class="left">${_('Name')}</th>
99 </thead>
99 </thead>
100 <tbody>
100 <tbody>
101 %for entry in c.following:
101 %for entry in c.following:
102 <tr>
102 <tr>
103 <td>
103 <td>
104 %if entry.follows_user_id:
104 %if entry.follows_user_id:
105 <img title="${_('following user')}" alt="${_('user')}" src="${h.url('/images/icons/user.png')}"/>
105 <img title="${_('following user')}" alt="${_('user')}" src="${h.url('/images/icons/user.png')}"/>
106 ${entry.follows_user.full_contact}
106 ${entry.follows_user.full_contact}
107 %endif
107 %endif
108
108
109 %if entry.follows_repo_id:
109 %if entry.follows_repo_id:
110 <div style="float:right;padding-right:5px">
110 <div style="float:right;padding-right:5px">
111 <span id="follow_toggle_${entry.follows_repository.repo_id}" class="following" title="${_('Stop following this repository')}"
111 <span id="follow_toggle_${entry.follows_repository.repo_id}" class="following" title="${_('Stop following this repository')}"
112 onclick="javascript:toggleFollowingRepo(this,${entry.follows_repository.repo_id},'${str(h.get_token())}')">
112 onclick="javascript:toggleFollowingRepo(this,${entry.follows_repository.repo_id},'${str(h.get_token())}')">
113 </span>
113 </span>
114 </div>
114 </div>
115
115
116 %if entry.follows_repository.repo_type == 'hg':
116 %if h.is_hg(entry.follows_repository):
117 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
117 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
118 %elif entry.follows_repository.repo_type == 'git':
118 %elif h.is_git(entry.follows_repository):
119 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
119 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
120 %endif
120 %endif
121
121
122 %if entry.follows_repository.private:
122 %if entry.follows_repository.private:
123 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
123 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
124 %else:
124 %else:
125 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
125 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
126 %endif
126 %endif
127 <span class="watched_repo">
127 <span class="watched_repo">
128 ${h.link_to(entry.follows_repository.repo_name,h.url('summary_home',repo_name=entry.follows_repository.repo_name))}
128 ${h.link_to(entry.follows_repository.repo_name,h.url('summary_home',repo_name=entry.follows_repository.repo_name))}
129 </span>
129 </span>
130 %endif
130 %endif
131 </td>
131 </td>
132 </tr>
132 </tr>
133 %endfor
133 %endfor
134 </tbody>
134 </tbody>
135 </table>
135 </table>
136 %else:
136 %else:
137 <div style="padding:5px 0px 10px 0px;">
137 <div style="padding:5px 0px 10px 0px;">
138 ${_('You are not following any users or repositories')}
138 ${_('You are not following any users or repositories')}
139 </div>
139 </div>
140 %endif
140 %endif
141 </div>
141 </div>
142 </div>
142 </div>
143
143
144 <script type="text/javascript">
144 <script type="text/javascript">
145
145
146 YUE.on('show_my','click',function(e){
146 YUE.on('show_my','click',function(e){
147 YUD.setStyle('watched','display','none');
147 YUD.setStyle('watched','display','none');
148 YUD.setStyle('my','display','');
148 YUD.setStyle('my','display','');
149 var nodes = YUQ('#my tr td a.repo_name');
149 var nodes = YUQ('#my tr td a.repo_name');
150 var target = 'q_filter';
150 var target = 'q_filter';
151 var func = function(node){
151 var func = function(node){
152 return node.parentNode.parentNode.parentNode.parentNode;
152 return node.parentNode.parentNode.parentNode.parentNode;
153 }
153 }
154 q_filter(target,nodes,func);
154 q_filter(target,nodes,func);
155 YUE.preventDefault(e);
155 YUE.preventDefault(e);
156 })
156 })
157 YUE.on('show_watched','click',function(e){
157 YUE.on('show_watched','click',function(e){
158 YUD.setStyle('my','display','none');
158 YUD.setStyle('my','display','none');
159 YUD.setStyle('watched','display','');
159 YUD.setStyle('watched','display','');
160 var nodes = YUQ('#watched .watched_repo a');
160 var nodes = YUQ('#watched .watched_repo a');
161 var target = 'q_filter';
161 var target = 'q_filter';
162 var func = function(node){
162 var func = function(node){
163 return node.parentNode.parentNode;
163 return node.parentNode.parentNode;
164 }
164 }
165 q_filter(target,nodes,func);
165 q_filter(target,nodes,func);
166 YUE.preventDefault(e);
166 YUE.preventDefault(e);
167 })
167 })
168 YUE.on('refresh','click',function(e){
168 YUE.on('refresh','click',function(e){
169 ypjax(e.currentTarget.href,"journal",function(){show_more_event();tooltip_activate();});
169 ypjax(e.currentTarget.href,"journal",function(){show_more_event();tooltip_activate();});
170 YUE.preventDefault(e);
170 YUE.preventDefault(e);
171 });
171 });
172
172
173
173
174 // main table sorting
174 // main table sorting
175 var myColumnDefs = [
175 var myColumnDefs = [
176 {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
176 {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
177 {key:"name",label:"${_('Name')}",sortable:true,
177 {key:"name",label:"${_('Name')}",sortable:true,
178 sortOptions: { sortFunction: nameSort }},
178 sortOptions: { sortFunction: nameSort }},
179 {key:"tip",label:"${_('Tip')}",sortable:true,
179 {key:"tip",label:"${_('Tip')}",sortable:true,
180 sortOptions: { sortFunction: revisionSort }},
180 sortOptions: { sortFunction: revisionSort }},
181 {key:"action1",label:"",sortable:false},
181 {key:"action1",label:"",sortable:false},
182 {key:"action2",label:"",sortable:false},
182 {key:"action2",label:"",sortable:false},
183 ];
183 ];
184
184
185 var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list"));
185 var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list"));
186
186
187 myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
187 myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
188
188
189 myDataSource.responseSchema = {
189 myDataSource.responseSchema = {
190 fields: [
190 fields: [
191 {key:"menu"},
191 {key:"menu"},
192 {key:"name"},
192 {key:"name"},
193 {key:"tip"},
193 {key:"tip"},
194 {key:"action1"},
194 {key:"action1"},
195 {key:"action2"}
195 {key:"action2"}
196 ]
196 ]
197 };
197 };
198
198
199 var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,
199 var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,
200 {
200 {
201 sortedBy:{key:"name",dir:"asc"},
201 sortedBy:{key:"name",dir:"asc"},
202 MSG_SORTASC:"${_('Click to sort ascending')}",
202 MSG_SORTASC:"${_('Click to sort ascending')}",
203 MSG_SORTDESC:"${_('Click to sort descending')}",
203 MSG_SORTDESC:"${_('Click to sort descending')}",
204 MSG_EMPTY:"${_('No records found.')}",
204 MSG_EMPTY:"${_('No records found.')}",
205 MSG_ERROR:"${_('Data error.')}",
205 MSG_ERROR:"${_('Data error.')}",
206 MSG_LOADING:"${_('Loading...')}",
206 MSG_LOADING:"${_('Loading...')}",
207 }
207 }
208 );
208 );
209 myDataTable.subscribe('postRenderEvent',function(oArgs) {
209 myDataTable.subscribe('postRenderEvent',function(oArgs) {
210 tooltip_activate();
210 tooltip_activate();
211 quick_repo_menu();
211 quick_repo_menu();
212 var func = function(node){
212 var func = function(node){
213 return node.parentNode.parentNode.parentNode.parentNode;
213 return node.parentNode.parentNode.parentNode.parentNode;
214 }
214 }
215 q_filter('q_filter',YUQ('#my tr td a.repo_name'),func);
215 q_filter('q_filter',YUQ('#my tr td a.repo_name'),func);
216 });
216 });
217
217
218
218
219 </script>
219 </script>
220 </%def>
220 </%def>
@@ -1,77 +1,83 b''
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.urlify_commit(h.truncate(cs.message,50),c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}
18 ${h.link_to(h.truncate(cs.message,50),
19 h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id),
20 title=cs.message)}
19 </td>
21 </td>
20 <td><span class="tooltip" title="${cs.date}">
22 <td><span class="tooltip" title="${cs.date}">
21 ${h.age(cs.date)}</span>
23 ${h.age(cs.date)}</span>
22 </td>
24 </td>
23 <td title="${cs.author}">${h.person(cs.author)}</td>
25 <td title="${cs.author}">${h.person(cs.author)}</td>
24 <td>
26 <td>
25 <span class="logtags">
27 <span class="logtags">
26 <span class="branchtag">${cs.branch}</span>
28 <span class="branchtag">
29 %if h.is_hg(c.rhodecode_repo):
30 ${cs.branch}
31 %endif
32 </span>
27 </span>
33 </span>
28 </td>
34 </td>
29 <td>
35 <td>
30 <span class="logtags">
36 <span class="logtags">
31 %for tag in cs.tags:
37 %for tag in cs.tags:
32 <span class="tagtag">${tag}</span>
38 <span class="tagtag">${tag}</span>
33 %endfor
39 %endfor
34 </span>
40 </span>
35 </td>
41 </td>
36 </tr>
42 </tr>
37 %endfor
43 %endfor
38
44
39 </table>
45 </table>
40
46
41 <script type="text/javascript">
47 <script type="text/javascript">
42 YUE.onDOMReady(function(){
48 YUE.onDOMReady(function(){
43 YUE.delegate("shortlog_data","click",function(e, matchedEl, container){
49 YUE.delegate("shortlog_data","click",function(e, matchedEl, container){
44 ypjax(e.target.href,"shortlog_data",function(){tooltip_activate();});
50 ypjax(e.target.href,"shortlog_data",function(){tooltip_activate();});
45 YUE.preventDefault(e);
51 YUE.preventDefault(e);
46 },'.pager_link');
52 },'.pager_link');
47 });
53 });
48 </script>
54 </script>
49
55
50 <div class="pagination-wh pagination-left">
56 <div class="pagination-wh pagination-left">
51 ${c.repo_changesets.pager('$link_previous ~2~ $link_next')}
57 ${c.repo_changesets.pager('$link_previous ~2~ $link_next')}
52 </div>
58 </div>
53 %else:
59 %else:
54
60
55 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
61 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
56 <h4>${_('Add or upload files directly via RhodeCode')}</h4>
62 <h4>${_('Add or upload files directly via RhodeCode')}</h4>
57 <div style="margin: 20px 30px;">
63 <div style="margin: 20px 30px;">
58 <div id="add_node_id" class="add_node">
64 <div id="add_node_id" class="add_node">
59 <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>
60 </div>
66 </div>
61 </div>
67 </div>
62 %endif
68 %endif
63
69
64
70
65 <h4>${_('Push new repo')}</h4>
71 <h4>${_('Push new repo')}</h4>
66 <pre>
72 <pre>
67 ${c.rhodecode_repo.alias} clone ${c.clone_repo_url}
73 ${c.rhodecode_repo.alias} clone ${c.clone_repo_url}
68 ${c.rhodecode_repo.alias} add README # add first file
74 ${c.rhodecode_repo.alias} add README # add first file
69 ${c.rhodecode_repo.alias} commit -m "Initial" # commit with message
75 ${c.rhodecode_repo.alias} commit -m "Initial" # commit with message
70 ${c.rhodecode_repo.alias} push # push changes back
76 ${c.rhodecode_repo.alias} push # push changes back
71 </pre>
77 </pre>
72
78
73 <h4>${_('Existing repository?')}</h4>
79 <h4>${_('Existing repository?')}</h4>
74 <pre>
80 <pre>
75 ${c.rhodecode_repo.alias} push ${c.clone_repo_url}
81 ${c.rhodecode_repo.alias} push ${c.clone_repo_url}
76 </pre>
82 </pre>
77 %endif
83 %endif
@@ -1,698 +1,698 b''
1 <%inherit file="/base/base.html"/>
1 <%inherit file="/base/base.html"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${c.repo_name} ${_('Summary')} - ${c.rhodecode_name}
4 ${c.repo_name} ${_('Summary')} - ${c.rhodecode_name}
5 </%def>
5 </%def>
6
6
7 <%def name="breadcrumbs_links()">
7 <%def name="breadcrumbs_links()">
8 ${h.link_to(u'Home',h.url('/'))}
8 ${h.link_to(u'Home',h.url('/'))}
9 &raquo;
9 &raquo;
10 ${h.link_to(c.dbrepo.just_name,h.url('summary_home',repo_name=c.repo_name))}
10 ${h.link_to(c.dbrepo.just_name,h.url('summary_home',repo_name=c.repo_name))}
11 &raquo;
11 &raquo;
12 ${_('summary')}
12 ${_('summary')}
13 </%def>
13 </%def>
14
14
15 <%def name="page_nav()">
15 <%def name="page_nav()">
16 ${self.menu('summary')}
16 ${self.menu('summary')}
17 </%def>
17 </%def>
18
18
19 <%def name="main()">
19 <%def name="main()">
20 <%
20 <%
21 summary = lambda n:{False:'summary-short'}.get(n)
21 summary = lambda n:{False:'summary-short'}.get(n)
22 %>
22 %>
23 %if c.show_stats:
23 %if c.show_stats:
24 <div class="box box-left">
24 <div class="box box-left">
25 %else:
25 %else:
26 <div class="box">
26 <div class="box">
27 %endif
27 %endif
28 <!-- box / title -->
28 <!-- box / title -->
29 <div class="title">
29 <div class="title">
30 ${self.breadcrumbs()}
30 ${self.breadcrumbs()}
31 </div>
31 </div>
32 <!-- end box / title -->
32 <!-- end box / title -->
33 <div class="form">
33 <div class="form">
34 <div id="summary" class="fields">
34 <div id="summary" class="fields">
35
35
36 <div class="field">
36 <div class="field">
37 <div class="label-summary">
37 <div class="label-summary">
38 <label>${_('Name')}:</label>
38 <label>${_('Name')}:</label>
39 </div>
39 </div>
40 <div class="input ${summary(c.show_stats)}">
40 <div class="input ${summary(c.show_stats)}">
41 <div style="float:right;padding:5px 0px 0px 5px">
41 <div style="float:right;padding:5px 0px 0px 5px">
42 %if c.rhodecode_user.username != 'default':
42 %if c.rhodecode_user.username != 'default':
43 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='rss_icon')}
43 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='rss_icon')}
44 ${h.link_to(_('ATOM'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='atom_icon')}
44 ${h.link_to(_('ATOM'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='atom_icon')}
45 %else:
45 %else:
46 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name),class_='rss_icon')}
46 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name),class_='rss_icon')}
47 ${h.link_to(_('ATOM'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name),class_='atom_icon')}
47 ${h.link_to(_('ATOM'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name),class_='atom_icon')}
48 %endif
48 %endif
49 </div>
49 </div>
50 %if c.rhodecode_user.username != 'default':
50 %if c.rhodecode_user.username != 'default':
51 %if c.following:
51 %if c.following:
52 <span id="follow_toggle" class="following" title="${_('Stop following this repository')}"
52 <span id="follow_toggle" class="following" title="${_('Stop following this repository')}"
53 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
53 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
54 </span>
54 </span>
55 %else:
55 %else:
56 <span id="follow_toggle" class="follow" title="${_('Start following this repository')}"
56 <span id="follow_toggle" class="follow" title="${_('Start following this repository')}"
57 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
57 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
58 </span>
58 </span>
59 %endif
59 %endif
60 %endif:
60 %endif:
61 ##REPO TYPE
61 ##REPO TYPE
62 %if c.dbrepo.repo_type =='hg':
62 %if h.is_hg(c.dbrepo):
63 <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
63 <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
64 %endif
64 %endif
65 %if c.dbrepo.repo_type =='git':
65 %if h.is_git(c.dbrepo):
66 <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
66 <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
67 %endif
67 %endif
68
68
69 ##PUBLIC/PRIVATE
69 ##PUBLIC/PRIVATE
70 %if c.dbrepo.private:
70 %if c.dbrepo.private:
71 <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
71 <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
72 %else:
72 %else:
73 <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
73 <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
74 %endif
74 %endif
75
75
76 ##REPO NAME
76 ##REPO NAME
77 <span class="repo_name" title="${_('Non changable ID %s') % c.dbrepo.repo_id}">${h.repo_link(c.dbrepo.groups_and_repo)}</span>
77 <span class="repo_name" title="${_('Non changable ID %s') % c.dbrepo.repo_id}">${h.repo_link(c.dbrepo.groups_and_repo)}</span>
78
78
79 ##FORK
79 ##FORK
80 %if c.dbrepo.fork:
80 %if c.dbrepo.fork:
81 <div style="margin-top:5px;clear:both"">
81 <div style="margin-top:5px;clear:both"">
82 <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}"><img class="icon" alt="${_('public')}" title="${_('Fork of')} ${c.dbrepo.fork.repo_name}" src="${h.url('/images/icons/arrow_divide.png')}"/>
82 <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}"><img class="icon" alt="${_('public')}" title="${_('Fork of')} ${c.dbrepo.fork.repo_name}" src="${h.url('/images/icons/arrow_divide.png')}"/>
83 ${_('Fork of')} ${c.dbrepo.fork.repo_name}
83 ${_('Fork of')} ${c.dbrepo.fork.repo_name}
84 </a>
84 </a>
85 </div>
85 </div>
86 %endif
86 %endif
87 ##REMOTE
87 ##REMOTE
88 %if c.dbrepo.clone_uri:
88 %if c.dbrepo.clone_uri:
89 <div style="margin-top:5px;clear:both">
89 <div style="margin-top:5px;clear:both">
90 <a href="${h.url(str(h.hide_credentials(c.dbrepo.clone_uri)))}"><img class="icon" alt="${_('remote clone')}" title="${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}" src="${h.url('/images/icons/connect.png')}"/>
90 <a href="${h.url(str(h.hide_credentials(c.dbrepo.clone_uri)))}"><img class="icon" alt="${_('remote clone')}" title="${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}" src="${h.url('/images/icons/connect.png')}"/>
91 ${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}
91 ${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}
92 </a>
92 </a>
93 </div>
93 </div>
94 %endif
94 %endif
95 </div>
95 </div>
96 </div>
96 </div>
97
97
98 <div class="field">
98 <div class="field">
99 <div class="label-summary">
99 <div class="label-summary">
100 <label>${_('Description')}:</label>
100 <label>${_('Description')}:</label>
101 </div>
101 </div>
102 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div>
102 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div>
103 </div>
103 </div>
104
104
105 <div class="field">
105 <div class="field">
106 <div class="label-summary">
106 <div class="label-summary">
107 <label>${_('Contact')}:</label>
107 <label>${_('Contact')}:</label>
108 </div>
108 </div>
109 <div class="input ${summary(c.show_stats)}">
109 <div class="input ${summary(c.show_stats)}">
110 <div class="gravatar">
110 <div class="gravatar">
111 <img alt="gravatar" src="${h.gravatar_url(c.dbrepo.user.email)}"/>
111 <img alt="gravatar" src="${h.gravatar_url(c.dbrepo.user.email)}"/>
112 </div>
112 </div>
113 ${_('Username')}: ${c.dbrepo.user.username}<br/>
113 ${_('Username')}: ${c.dbrepo.user.username}<br/>
114 ${_('Name')}: ${c.dbrepo.user.name} ${c.dbrepo.user.lastname}<br/>
114 ${_('Name')}: ${c.dbrepo.user.name} ${c.dbrepo.user.lastname}<br/>
115 ${_('Email')}: <a href="mailto:${c.dbrepo.user.email}">${c.dbrepo.user.email}</a>
115 ${_('Email')}: <a href="mailto:${c.dbrepo.user.email}">${c.dbrepo.user.email}</a>
116 </div>
116 </div>
117 </div>
117 </div>
118
118
119 <div class="field">
119 <div class="field">
120 <div class="label-summary">
120 <div class="label-summary">
121 <label>${_('Clone url')}:</label>
121 <label>${_('Clone url')}:</label>
122 </div>
122 </div>
123 <div class="input ${summary(c.show_stats)}">
123 <div class="input ${summary(c.show_stats)}">
124 <div style="display:none" id="clone_by_name" class="ui-btn clone">${_('Show by Name')}</div>
124 <div style="display:none" id="clone_by_name" class="ui-btn clone">${_('Show by Name')}</div>
125 <div id="clone_by_id" class="ui-btn clone">${_('Show by ID')}</div>
125 <div id="clone_by_id" class="ui-btn clone">${_('Show by ID')}</div>
126 <input style="width:80%;margin-left:105px" type="text" id="clone_url" readonly="readonly" value="${c.clone_repo_url}"/>
126 <input style="width:80%;margin-left:105px" type="text" id="clone_url" readonly="readonly" value="${c.clone_repo_url}"/>
127 <input style="display:none;width:80%;margin-left:105px" type="text" id="clone_url_id" readonly="readonly" value="${c.clone_repo_url_id}"/>
127 <input style="display:none;width:80%;margin-left:105px" type="text" id="clone_url_id" readonly="readonly" value="${c.clone_repo_url_id}"/>
128 </div>
128 </div>
129 </div>
129 </div>
130
130
131 <div class="field">
131 <div class="field">
132 <div class="label-summary">
132 <div class="label-summary">
133 <label>${_('Trending files')}:</label>
133 <label>${_('Trending files')}:</label>
134 </div>
134 </div>
135 <div class="input ${summary(c.show_stats)}">
135 <div class="input ${summary(c.show_stats)}">
136 %if c.show_stats:
136 %if c.show_stats:
137 <div id="lang_stats"></div>
137 <div id="lang_stats"></div>
138 %else:
138 %else:
139 ${_('Statistics are disabled for this repository')}
139 ${_('Statistics are disabled for this repository')}
140 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
140 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
141 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
141 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
142 %endif
142 %endif
143 %endif
143 %endif
144 </div>
144 </div>
145 </div>
145 </div>
146
146
147 <div class="field">
147 <div class="field">
148 <div class="label-summary">
148 <div class="label-summary">
149 <label>${_('Download')}:</label>
149 <label>${_('Download')}:</label>
150 </div>
150 </div>
151 <div class="input ${summary(c.show_stats)}">
151 <div class="input ${summary(c.show_stats)}">
152 %if len(c.rhodecode_repo.revisions) == 0:
152 %if len(c.rhodecode_repo.revisions) == 0:
153 ${_('There are no downloads yet')}
153 ${_('There are no downloads yet')}
154 %elif c.enable_downloads is False:
154 %elif c.enable_downloads is False:
155 ${_('Downloads are disabled for this repository')}
155 ${_('Downloads are disabled for this repository')}
156 %if h.HasPermissionAll('hg.admin')('enable downloads on from summary'):
156 %if h.HasPermissionAll('hg.admin')('enable downloads on from summary'):
157 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
157 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
158 %endif
158 %endif
159 %else:
159 %else:
160 ${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)}
160 ${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)}
161 <span id="${'zip_link'}">${h.link_to('Download as zip',h.url('files_archive_home',repo_name=c.dbrepo.repo_name,fname='tip.zip'),class_="archive_icon ui-btn")}</span>
161 <span id="${'zip_link'}">${h.link_to('Download as zip',h.url('files_archive_home',repo_name=c.dbrepo.repo_name,fname='tip.zip'),class_="archive_icon ui-btn")}</span>
162 <span style="vertical-align: bottom">
162 <span style="vertical-align: bottom">
163 <input id="archive_subrepos" type="checkbox" name="subrepos" />
163 <input id="archive_subrepos" type="checkbox" name="subrepos" />
164 <label for="archive_subrepos" class="tooltip" title="${_('Check this to download archive with subrepos')}" >${_('with subrepos')}</label>
164 <label for="archive_subrepos" class="tooltip" title="${_('Check this to download archive with subrepos')}" >${_('with subrepos')}</label>
165 </span>
165 </span>
166 %endif
166 %endif
167 </div>
167 </div>
168 </div>
168 </div>
169 </div>
169 </div>
170 </div>
170 </div>
171 </div>
171 </div>
172
172
173 %if c.show_stats:
173 %if c.show_stats:
174 <div class="box box-right" style="min-height:455px">
174 <div class="box box-right" style="min-height:455px">
175 <!-- box / title -->
175 <!-- box / title -->
176 <div class="title">
176 <div class="title">
177 <h5>${_('Commit activity by day / author')}</h5>
177 <h5>${_('Commit activity by day / author')}</h5>
178 </div>
178 </div>
179
179
180 <div class="graph">
180 <div class="graph">
181 <div style="padding:0 10px 10px 15px;font-size: 1.2em;">
181 <div style="padding:0 10px 10px 15px;font-size: 1.2em;">
182 %if c.no_data:
182 %if c.no_data:
183 ${c.no_data_msg}
183 ${c.no_data_msg}
184 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
184 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
185 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
185 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
186 %endif
186 %endif
187 %else:
187 %else:
188 ${_('Loaded in')} ${c.stats_percentage} %
188 ${_('Loaded in')} ${c.stats_percentage} %
189 %endif
189 %endif
190 </div>
190 </div>
191 <div id="commit_history" style="width:450px;height:300px;float:left"></div>
191 <div id="commit_history" style="width:450px;height:300px;float:left"></div>
192 <div style="clear: both;height: 10px"></div>
192 <div style="clear: both;height: 10px"></div>
193 <div id="overview" style="width:450px;height:100px;float:left"></div>
193 <div id="overview" style="width:450px;height:100px;float:left"></div>
194
194
195 <div id="legend_data" style="clear:both;margin-top:10px;">
195 <div id="legend_data" style="clear:both;margin-top:10px;">
196 <div id="legend_container"></div>
196 <div id="legend_container"></div>
197 <div id="legend_choices">
197 <div id="legend_choices">
198 <table id="legend_choices_tables" class="noborder" style="font-size:smaller;color:#545454"></table>
198 <table id="legend_choices_tables" class="noborder" style="font-size:smaller;color:#545454"></table>
199 </div>
199 </div>
200 </div>
200 </div>
201 </div>
201 </div>
202 </div>
202 </div>
203 %endif
203 %endif
204
204
205 <div class="box">
205 <div class="box">
206 <div class="title">
206 <div class="title">
207 <div class="breadcrumbs">
207 <div class="breadcrumbs">
208 %if c.repo_changesets:
208 %if c.repo_changesets:
209 ${h.link_to(_('Shortlog'),h.url('shortlog_home',repo_name=c.repo_name))}
209 ${h.link_to(_('Shortlog'),h.url('shortlog_home',repo_name=c.repo_name))}
210 %else:
210 %else:
211 ${_('Quick start')}
211 ${_('Quick start')}
212 %endif
212 %endif
213 </div>
213 </div>
214 </div>
214 </div>
215 <div class="table">
215 <div class="table">
216 <div id="shortlog_data">
216 <div id="shortlog_data">
217 <%include file='../shortlog/shortlog_data.html'/>
217 <%include file='../shortlog/shortlog_data.html'/>
218 </div>
218 </div>
219 </div>
219 </div>
220 </div>
220 </div>
221
221
222 %if c.readme_data:
222 %if c.readme_data:
223 <div class="box" style="background-color: #FAFAFA">
223 <div class="box" style="background-color: #FAFAFA">
224 <div class="title">
224 <div class="title">
225 <div class="breadcrumbs"><a href="${h.url('files_home',repo_name=c.repo_name,revision='tip',f_path=c.readme_file)}">${c.readme_file}</a></div>
225 <div class="breadcrumbs"><a href="${h.url('files_home',repo_name=c.repo_name,revision='tip',f_path=c.readme_file)}">${c.readme_file}</a></div>
226 </div>
226 </div>
227 <div class="readme">
227 <div class="readme">
228 <div class="readme_box">
228 <div class="readme_box">
229 ${c.readme_data|n}
229 ${c.readme_data|n}
230 </div>
230 </div>
231 </div>
231 </div>
232 </div>
232 </div>
233 %endif
233 %endif
234
234
235 <script type="text/javascript">
235 <script type="text/javascript">
236 var clone_url = 'clone_url';
236 var clone_url = 'clone_url';
237 YUE.on(clone_url,'click',function(e){
237 YUE.on(clone_url,'click',function(e){
238 if(YUD.hasClass(clone_url,'selected')){
238 if(YUD.hasClass(clone_url,'selected')){
239 return
239 return
240 }
240 }
241 else{
241 else{
242 YUD.addClass(clone_url,'selected');
242 YUD.addClass(clone_url,'selected');
243 YUD.get(clone_url).select();
243 YUD.get(clone_url).select();
244 }
244 }
245 })
245 })
246
246
247 YUE.on('clone_by_name','click',function(e){
247 YUE.on('clone_by_name','click',function(e){
248 // show url by name and hide name button
248 // show url by name and hide name button
249 YUD.setStyle('clone_url','display','');
249 YUD.setStyle('clone_url','display','');
250 YUD.setStyle('clone_by_name','display','none');
250 YUD.setStyle('clone_by_name','display','none');
251
251
252 // hide url by id and show name button
252 // hide url by id and show name button
253 YUD.setStyle('clone_by_id','display','');
253 YUD.setStyle('clone_by_id','display','');
254 YUD.setStyle('clone_url_id','display','none');
254 YUD.setStyle('clone_url_id','display','none');
255
255
256 })
256 })
257 YUE.on('clone_by_id','click',function(e){
257 YUE.on('clone_by_id','click',function(e){
258
258
259 // show url by id and hide id button
259 // show url by id and hide id button
260 YUD.setStyle('clone_by_id','display','none');
260 YUD.setStyle('clone_by_id','display','none');
261 YUD.setStyle('clone_url_id','display','');
261 YUD.setStyle('clone_url_id','display','');
262
262
263 // hide url by name and show id button
263 // hide url by name and show id button
264 YUD.setStyle('clone_by_name','display','');
264 YUD.setStyle('clone_by_name','display','');
265 YUD.setStyle('clone_url','display','none');
265 YUD.setStyle('clone_url','display','none');
266 })
266 })
267
267
268
268
269 var tmpl_links = {};
269 var tmpl_links = {};
270 %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()):
270 %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()):
271 tmpl_links["${archive['type']}"] = '${h.link_to('__NAME__', h.url('files_archive_home',repo_name=c.dbrepo.repo_name, fname='__CS__'+archive['extension'],subrepos='__SUB__'),class_='archive_icon ui-btn')}';
271 tmpl_links["${archive['type']}"] = '${h.link_to('__NAME__', h.url('files_archive_home',repo_name=c.dbrepo.repo_name, fname='__CS__'+archive['extension'],subrepos='__SUB__'),class_='archive_icon ui-btn')}';
272 %endfor
272 %endfor
273
273
274 YUE.on(['download_options','archive_subrepos'],'change',function(e){
274 YUE.on(['download_options','archive_subrepos'],'change',function(e){
275 var sm = YUD.get('download_options');
275 var sm = YUD.get('download_options');
276 var new_cs = sm.options[sm.selectedIndex];
276 var new_cs = sm.options[sm.selectedIndex];
277
277
278 for(k in tmpl_links){
278 for(k in tmpl_links){
279 var s = YUD.get(k+'_link');
279 var s = YUD.get(k+'_link');
280 if(s){
280 if(s){
281 var title_tmpl = "${_('Download %s as %s') % ('__CS_NAME__','__CS_EXT__')}";
281 var title_tmpl = "${_('Download %s as %s') % ('__CS_NAME__','__CS_EXT__')}";
282 title_tmpl= title_tmpl.replace('__CS_NAME__',new_cs.text);
282 title_tmpl= title_tmpl.replace('__CS_NAME__',new_cs.text);
283 title_tmpl = title_tmpl.replace('__CS_EXT__',k);
283 title_tmpl = title_tmpl.replace('__CS_EXT__',k);
284
284
285 var url = tmpl_links[k].replace('__CS__',new_cs.value);
285 var url = tmpl_links[k].replace('__CS__',new_cs.value);
286 var subrepos = YUD.get('archive_subrepos').checked;
286 var subrepos = YUD.get('archive_subrepos').checked;
287 url = url.replace('__SUB__',subrepos);
287 url = url.replace('__SUB__',subrepos);
288 url = url.replace('__NAME__',title_tmpl);
288 url = url.replace('__NAME__',title_tmpl);
289 s.innerHTML = url
289 s.innerHTML = url
290 }
290 }
291 }
291 }
292 });
292 });
293 </script>
293 </script>
294 %if c.show_stats:
294 %if c.show_stats:
295 <script type="text/javascript">
295 <script type="text/javascript">
296 var data = ${c.trending_languages|n};
296 var data = ${c.trending_languages|n};
297 var total = 0;
297 var total = 0;
298 var no_data = true;
298 var no_data = true;
299 var tbl = document.createElement('table');
299 var tbl = document.createElement('table');
300 tbl.setAttribute('class','trending_language_tbl');
300 tbl.setAttribute('class','trending_language_tbl');
301 var cnt = 0;
301 var cnt = 0;
302 for (var i=0;i<data.length;i++){
302 for (var i=0;i<data.length;i++){
303 total+= data[i][1].count;
303 total+= data[i][1].count;
304 }
304 }
305 for (var i=0;i<data.length;i++){
305 for (var i=0;i<data.length;i++){
306 cnt += 1;
306 cnt += 1;
307 no_data = false;
307 no_data = false;
308
308
309 var hide = cnt>2;
309 var hide = cnt>2;
310 var tr = document.createElement('tr');
310 var tr = document.createElement('tr');
311 if (hide){
311 if (hide){
312 tr.setAttribute('style','display:none');
312 tr.setAttribute('style','display:none');
313 tr.setAttribute('class','stats_hidden');
313 tr.setAttribute('class','stats_hidden');
314 }
314 }
315 var k = data[i][0];
315 var k = data[i][0];
316 var obj = data[i][1];
316 var obj = data[i][1];
317 var percentage = Math.round((obj.count/total*100),2);
317 var percentage = Math.round((obj.count/total*100),2);
318
318
319 var td1 = document.createElement('td');
319 var td1 = document.createElement('td');
320 td1.width = 150;
320 td1.width = 150;
321 var trending_language_label = document.createElement('div');
321 var trending_language_label = document.createElement('div');
322 trending_language_label.innerHTML = obj.desc+" ("+k+")";
322 trending_language_label.innerHTML = obj.desc+" ("+k+")";
323 td1.appendChild(trending_language_label);
323 td1.appendChild(trending_language_label);
324
324
325 var td2 = document.createElement('td');
325 var td2 = document.createElement('td');
326 td2.setAttribute('style','padding-right:14px !important');
326 td2.setAttribute('style','padding-right:14px !important');
327 var trending_language = document.createElement('div');
327 var trending_language = document.createElement('div');
328 var nr_files = obj.count+" ${_('files')}";
328 var nr_files = obj.count+" ${_('files')}";
329
329
330 trending_language.title = k+" "+nr_files;
330 trending_language.title = k+" "+nr_files;
331
331
332 if (percentage>22){
332 if (percentage>22){
333 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>";
333 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>";
334 }
334 }
335 else{
335 else{
336 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>";
336 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>";
337 }
337 }
338
338
339 trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
339 trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
340 trending_language.style.width=percentage+"%";
340 trending_language.style.width=percentage+"%";
341 td2.appendChild(trending_language);
341 td2.appendChild(trending_language);
342
342
343 tr.appendChild(td1);
343 tr.appendChild(td1);
344 tr.appendChild(td2);
344 tr.appendChild(td2);
345 tbl.appendChild(tr);
345 tbl.appendChild(tr);
346 if(cnt == 3){
346 if(cnt == 3){
347 var show_more = document.createElement('tr');
347 var show_more = document.createElement('tr');
348 var td = document.createElement('td');
348 var td = document.createElement('td');
349 lnk = document.createElement('a');
349 lnk = document.createElement('a');
350
350
351 lnk.href='#';
351 lnk.href='#';
352 lnk.innerHTML = "${_('show more')}";
352 lnk.innerHTML = "${_('show more')}";
353 lnk.id='code_stats_show_more';
353 lnk.id='code_stats_show_more';
354 td.appendChild(lnk);
354 td.appendChild(lnk);
355
355
356 show_more.appendChild(td);
356 show_more.appendChild(td);
357 show_more.appendChild(document.createElement('td'));
357 show_more.appendChild(document.createElement('td'));
358 tbl.appendChild(show_more);
358 tbl.appendChild(show_more);
359 }
359 }
360
360
361 }
361 }
362
362
363 YUD.get('lang_stats').appendChild(tbl);
363 YUD.get('lang_stats').appendChild(tbl);
364 YUE.on('code_stats_show_more','click',function(){
364 YUE.on('code_stats_show_more','click',function(){
365 l = YUD.getElementsByClassName('stats_hidden')
365 l = YUD.getElementsByClassName('stats_hidden')
366 for (e in l){
366 for (e in l){
367 YUD.setStyle(l[e],'display','');
367 YUD.setStyle(l[e],'display','');
368 };
368 };
369 YUD.setStyle(YUD.get('code_stats_show_more'),
369 YUD.setStyle(YUD.get('code_stats_show_more'),
370 'display','none');
370 'display','none');
371 });
371 });
372 </script>
372 </script>
373 <script type="text/javascript">
373 <script type="text/javascript">
374 /**
374 /**
375 * Plots summary graph
375 * Plots summary graph
376 *
376 *
377 * @class SummaryPlot
377 * @class SummaryPlot
378 * @param {from} initial from for detailed graph
378 * @param {from} initial from for detailed graph
379 * @param {to} initial to for detailed graph
379 * @param {to} initial to for detailed graph
380 * @param {dataset}
380 * @param {dataset}
381 * @param {overview_dataset}
381 * @param {overview_dataset}
382 */
382 */
383 function SummaryPlot(from,to,dataset,overview_dataset) {
383 function SummaryPlot(from,to,dataset,overview_dataset) {
384 var initial_ranges = {
384 var initial_ranges = {
385 "xaxis":{
385 "xaxis":{
386 "from":from,
386 "from":from,
387 "to":to,
387 "to":to,
388 },
388 },
389 };
389 };
390 var dataset = dataset;
390 var dataset = dataset;
391 var overview_dataset = [overview_dataset];
391 var overview_dataset = [overview_dataset];
392 var choiceContainer = YUD.get("legend_choices");
392 var choiceContainer = YUD.get("legend_choices");
393 var choiceContainerTable = YUD.get("legend_choices_tables");
393 var choiceContainerTable = YUD.get("legend_choices_tables");
394 var plotContainer = YUD.get('commit_history');
394 var plotContainer = YUD.get('commit_history');
395 var overviewContainer = YUD.get('overview');
395 var overviewContainer = YUD.get('overview');
396
396
397 var plot_options = {
397 var plot_options = {
398 bars: {show:true,align:'center',lineWidth:4},
398 bars: {show:true,align:'center',lineWidth:4},
399 legend: {show:true, container:"legend_container"},
399 legend: {show:true, container:"legend_container"},
400 points: {show:true,radius:0,fill:false},
400 points: {show:true,radius:0,fill:false},
401 yaxis: {tickDecimals:0,},
401 yaxis: {tickDecimals:0,},
402 xaxis: {
402 xaxis: {
403 mode: "time",
403 mode: "time",
404 timeformat: "%d/%m",
404 timeformat: "%d/%m",
405 min:from,
405 min:from,
406 max:to,
406 max:to,
407 },
407 },
408 grid: {
408 grid: {
409 hoverable: true,
409 hoverable: true,
410 clickable: true,
410 clickable: true,
411 autoHighlight:true,
411 autoHighlight:true,
412 color: "#999"
412 color: "#999"
413 },
413 },
414 //selection: {mode: "x"}
414 //selection: {mode: "x"}
415 };
415 };
416 var overview_options = {
416 var overview_options = {
417 legend:{show:false},
417 legend:{show:false},
418 bars: {show:true,barWidth: 2,},
418 bars: {show:true,barWidth: 2,},
419 shadowSize: 0,
419 shadowSize: 0,
420 xaxis: {mode: "time", timeformat: "%d/%m/%y",},
420 xaxis: {mode: "time", timeformat: "%d/%m/%y",},
421 yaxis: {ticks: 3, min: 0,tickDecimals:0,},
421 yaxis: {ticks: 3, min: 0,tickDecimals:0,},
422 grid: {color: "#999",},
422 grid: {color: "#999",},
423 selection: {mode: "x"}
423 selection: {mode: "x"}
424 };
424 };
425
425
426 /**
426 /**
427 *get dummy data needed in few places
427 *get dummy data needed in few places
428 */
428 */
429 function getDummyData(label){
429 function getDummyData(label){
430 return {"label":label,
430 return {"label":label,
431 "data":[{"time":0,
431 "data":[{"time":0,
432 "commits":0,
432 "commits":0,
433 "added":0,
433 "added":0,
434 "changed":0,
434 "changed":0,
435 "removed":0,
435 "removed":0,
436 }],
436 }],
437 "schema":["commits"],
437 "schema":["commits"],
438 "color":'#ffffff',
438 "color":'#ffffff',
439 }
439 }
440 }
440 }
441
441
442 /**
442 /**
443 * generate checkboxes accordindly to data
443 * generate checkboxes accordindly to data
444 * @param keys
444 * @param keys
445 * @returns
445 * @returns
446 */
446 */
447 function generateCheckboxes(data) {
447 function generateCheckboxes(data) {
448 //append checkboxes
448 //append checkboxes
449 var i = 0;
449 var i = 0;
450 choiceContainerTable.innerHTML = '';
450 choiceContainerTable.innerHTML = '';
451 for(var pos in data) {
451 for(var pos in data) {
452
452
453 data[pos].color = i;
453 data[pos].color = i;
454 i++;
454 i++;
455 if(data[pos].label != ''){
455 if(data[pos].label != ''){
456 choiceContainerTable.innerHTML +=
456 choiceContainerTable.innerHTML +=
457 '<tr><td><input type="checkbox" id="id_user_{0}" name="{0}" checked="checked" /> \
457 '<tr><td><input type="checkbox" id="id_user_{0}" name="{0}" checked="checked" /> \
458 <label for="id_user_{0}">{0}</label></td></tr>'.format(data[pos].label);
458 <label for="id_user_{0}">{0}</label></td></tr>'.format(data[pos].label);
459 }
459 }
460 }
460 }
461 }
461 }
462
462
463 /**
463 /**
464 * ToolTip show
464 * ToolTip show
465 */
465 */
466 function showTooltip(x, y, contents) {
466 function showTooltip(x, y, contents) {
467 var div=document.getElementById('tooltip');
467 var div=document.getElementById('tooltip');
468 if(!div) {
468 if(!div) {
469 div = document.createElement('div');
469 div = document.createElement('div');
470 div.id="tooltip";
470 div.id="tooltip";
471 div.style.position="absolute";
471 div.style.position="absolute";
472 div.style.border='1px solid #fdd';
472 div.style.border='1px solid #fdd';
473 div.style.padding='2px';
473 div.style.padding='2px';
474 div.style.backgroundColor='#fee';
474 div.style.backgroundColor='#fee';
475 document.body.appendChild(div);
475 document.body.appendChild(div);
476 }
476 }
477 YUD.setStyle(div, 'opacity', 0);
477 YUD.setStyle(div, 'opacity', 0);
478 div.innerHTML = contents;
478 div.innerHTML = contents;
479 div.style.top=(y + 5) + "px";
479 div.style.top=(y + 5) + "px";
480 div.style.left=(x + 5) + "px";
480 div.style.left=(x + 5) + "px";
481
481
482 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
482 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
483 anim.animate();
483 anim.animate();
484 }
484 }
485
485
486 /**
486 /**
487 * This function will detect if selected period has some changesets
487 * This function will detect if selected period has some changesets
488 for this user if it does this data is then pushed for displaying
488 for this user if it does this data is then pushed for displaying
489 Additionally it will only display users that are selected by the checkbox
489 Additionally it will only display users that are selected by the checkbox
490 */
490 */
491 function getDataAccordingToRanges(ranges) {
491 function getDataAccordingToRanges(ranges) {
492
492
493 var data = [];
493 var data = [];
494 var new_dataset = {};
494 var new_dataset = {};
495 var keys = [];
495 var keys = [];
496 var max_commits = 0;
496 var max_commits = 0;
497 for(var key in dataset){
497 for(var key in dataset){
498
498
499 for(var ds in dataset[key].data){
499 for(var ds in dataset[key].data){
500 commit_data = dataset[key].data[ds];
500 commit_data = dataset[key].data[ds];
501 if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
501 if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
502
502
503 if(new_dataset[key] === undefined){
503 if(new_dataset[key] === undefined){
504 new_dataset[key] = {data:[],schema:["commits"],label:key};
504 new_dataset[key] = {data:[],schema:["commits"],label:key};
505 }
505 }
506 new_dataset[key].data.push(commit_data);
506 new_dataset[key].data.push(commit_data);
507 }
507 }
508 }
508 }
509 if (new_dataset[key] !== undefined){
509 if (new_dataset[key] !== undefined){
510 data.push(new_dataset[key]);
510 data.push(new_dataset[key]);
511 }
511 }
512 }
512 }
513
513
514 if (data.length > 0){
514 if (data.length > 0){
515 return data;
515 return data;
516 }
516 }
517 else{
517 else{
518 //just return dummy data for graph to plot itself
518 //just return dummy data for graph to plot itself
519 return [getDummyData('')];
519 return [getDummyData('')];
520 }
520 }
521 }
521 }
522
522
523 /**
523 /**
524 * redraw using new checkbox data
524 * redraw using new checkbox data
525 */
525 */
526 function plotchoiced(e,args){
526 function plotchoiced(e,args){
527 var cur_data = args[0];
527 var cur_data = args[0];
528 var cur_ranges = args[1];
528 var cur_ranges = args[1];
529
529
530 var new_data = [];
530 var new_data = [];
531 var inputs = choiceContainer.getElementsByTagName("input");
531 var inputs = choiceContainer.getElementsByTagName("input");
532
532
533 //show only checked labels
533 //show only checked labels
534 for(var i=0; i<inputs.length; i++) {
534 for(var i=0; i<inputs.length; i++) {
535 var checkbox_key = inputs[i].name;
535 var checkbox_key = inputs[i].name;
536
536
537 if(inputs[i].checked){
537 if(inputs[i].checked){
538 for(var d in cur_data){
538 for(var d in cur_data){
539 if(cur_data[d].label == checkbox_key){
539 if(cur_data[d].label == checkbox_key){
540 new_data.push(cur_data[d]);
540 new_data.push(cur_data[d]);
541 }
541 }
542 }
542 }
543 }
543 }
544 else{
544 else{
545 //push dummy data to not hide the label
545 //push dummy data to not hide the label
546 new_data.push(getDummyData(checkbox_key));
546 new_data.push(getDummyData(checkbox_key));
547 }
547 }
548 }
548 }
549
549
550 var new_options = YAHOO.lang.merge(plot_options, {
550 var new_options = YAHOO.lang.merge(plot_options, {
551 xaxis: {
551 xaxis: {
552 min: cur_ranges.xaxis.from,
552 min: cur_ranges.xaxis.from,
553 max: cur_ranges.xaxis.to,
553 max: cur_ranges.xaxis.to,
554 mode:"time",
554 mode:"time",
555 timeformat: "%d/%m",
555 timeformat: "%d/%m",
556 },
556 },
557 });
557 });
558 if (!new_data){
558 if (!new_data){
559 new_data = [[0,1]];
559 new_data = [[0,1]];
560 }
560 }
561 // do the zooming
561 // do the zooming
562 plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
562 plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
563
563
564 plot.subscribe("plotselected", plotselected);
564 plot.subscribe("plotselected", plotselected);
565
565
566 //resubscribe plothover
566 //resubscribe plothover
567 plot.subscribe("plothover", plothover);
567 plot.subscribe("plothover", plothover);
568
568
569 // don't fire event on the overview to prevent eternal loop
569 // don't fire event on the overview to prevent eternal loop
570 overview.setSelection(cur_ranges, true);
570 overview.setSelection(cur_ranges, true);
571
571
572 }
572 }
573
573
574 /**
574 /**
575 * plot only selected items from overview
575 * plot only selected items from overview
576 * @param ranges
576 * @param ranges
577 * @returns
577 * @returns
578 */
578 */
579 function plotselected(ranges,cur_data) {
579 function plotselected(ranges,cur_data) {
580 //updates the data for new plot
580 //updates the data for new plot
581 var data = getDataAccordingToRanges(ranges);
581 var data = getDataAccordingToRanges(ranges);
582 generateCheckboxes(data);
582 generateCheckboxes(data);
583
583
584 var new_options = YAHOO.lang.merge(plot_options, {
584 var new_options = YAHOO.lang.merge(plot_options, {
585 xaxis: {
585 xaxis: {
586 min: ranges.xaxis.from,
586 min: ranges.xaxis.from,
587 max: ranges.xaxis.to,
587 max: ranges.xaxis.to,
588 mode:"time",
588 mode:"time",
589 timeformat: "%d/%m",
589 timeformat: "%d/%m",
590 },
590 },
591 });
591 });
592 // do the zooming
592 // do the zooming
593 plot = YAHOO.widget.Flot(plotContainer, data, new_options);
593 plot = YAHOO.widget.Flot(plotContainer, data, new_options);
594
594
595 plot.subscribe("plotselected", plotselected);
595 plot.subscribe("plotselected", plotselected);
596
596
597 //resubscribe plothover
597 //resubscribe plothover
598 plot.subscribe("plothover", plothover);
598 plot.subscribe("plothover", plothover);
599
599
600 // don't fire event on the overview to prevent eternal loop
600 // don't fire event on the overview to prevent eternal loop
601 overview.setSelection(ranges, true);
601 overview.setSelection(ranges, true);
602
602
603 //resubscribe choiced
603 //resubscribe choiced
604 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
604 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
605 }
605 }
606
606
607 var previousPoint = null;
607 var previousPoint = null;
608
608
609 function plothover(o) {
609 function plothover(o) {
610 var pos = o.pos;
610 var pos = o.pos;
611 var item = o.item;
611 var item = o.item;
612
612
613 //YUD.get("x").innerHTML = pos.x.toFixed(2);
613 //YUD.get("x").innerHTML = pos.x.toFixed(2);
614 //YUD.get("y").innerHTML = pos.y.toFixed(2);
614 //YUD.get("y").innerHTML = pos.y.toFixed(2);
615 if (item) {
615 if (item) {
616 if (previousPoint != item.datapoint) {
616 if (previousPoint != item.datapoint) {
617 previousPoint = item.datapoint;
617 previousPoint = item.datapoint;
618
618
619 var tooltip = YUD.get("tooltip");
619 var tooltip = YUD.get("tooltip");
620 if(tooltip) {
620 if(tooltip) {
621 tooltip.parentNode.removeChild(tooltip);
621 tooltip.parentNode.removeChild(tooltip);
622 }
622 }
623 var x = item.datapoint.x.toFixed(2);
623 var x = item.datapoint.x.toFixed(2);
624 var y = item.datapoint.y.toFixed(2);
624 var y = item.datapoint.y.toFixed(2);
625
625
626 if (!item.series.label){
626 if (!item.series.label){
627 item.series.label = 'commits';
627 item.series.label = 'commits';
628 }
628 }
629 var d = new Date(x*1000);
629 var d = new Date(x*1000);
630 var fd = d.toDateString()
630 var fd = d.toDateString()
631 var nr_commits = parseInt(y);
631 var nr_commits = parseInt(y);
632
632
633 var cur_data = dataset[item.series.label].data[item.dataIndex];
633 var cur_data = dataset[item.series.label].data[item.dataIndex];
634 var added = cur_data.added;
634 var added = cur_data.added;
635 var changed = cur_data.changed;
635 var changed = cur_data.changed;
636 var removed = cur_data.removed;
636 var removed = cur_data.removed;
637
637
638 var nr_commits_suffix = " ${_('commits')} ";
638 var nr_commits_suffix = " ${_('commits')} ";
639 var added_suffix = " ${_('files added')} ";
639 var added_suffix = " ${_('files added')} ";
640 var changed_suffix = " ${_('files changed')} ";
640 var changed_suffix = " ${_('files changed')} ";
641 var removed_suffix = " ${_('files removed')} ";
641 var removed_suffix = " ${_('files removed')} ";
642
642
643
643
644 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
644 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
645 if(added==1){added_suffix=" ${_('file added')} ";}
645 if(added==1){added_suffix=" ${_('file added')} ";}
646 if(changed==1){changed_suffix=" ${_('file changed')} ";}
646 if(changed==1){changed_suffix=" ${_('file changed')} ";}
647 if(removed==1){removed_suffix=" ${_('file removed')} ";}
647 if(removed==1){removed_suffix=" ${_('file removed')} ";}
648
648
649 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
649 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
650 +'<br/>'+
650 +'<br/>'+
651 nr_commits + nr_commits_suffix+'<br/>'+
651 nr_commits + nr_commits_suffix+'<br/>'+
652 added + added_suffix +'<br/>'+
652 added + added_suffix +'<br/>'+
653 changed + changed_suffix + '<br/>'+
653 changed + changed_suffix + '<br/>'+
654 removed + removed_suffix + '<br/>');
654 removed + removed_suffix + '<br/>');
655 }
655 }
656 }
656 }
657 else {
657 else {
658 var tooltip = YUD.get("tooltip");
658 var tooltip = YUD.get("tooltip");
659
659
660 if(tooltip) {
660 if(tooltip) {
661 tooltip.parentNode.removeChild(tooltip);
661 tooltip.parentNode.removeChild(tooltip);
662 }
662 }
663 previousPoint = null;
663 previousPoint = null;
664 }
664 }
665 }
665 }
666
666
667 /**
667 /**
668 * MAIN EXECUTION
668 * MAIN EXECUTION
669 */
669 */
670
670
671 var data = getDataAccordingToRanges(initial_ranges);
671 var data = getDataAccordingToRanges(initial_ranges);
672 generateCheckboxes(data);
672 generateCheckboxes(data);
673
673
674 //main plot
674 //main plot
675 var plot = YAHOO.widget.Flot(plotContainer,data,plot_options);
675 var plot = YAHOO.widget.Flot(plotContainer,data,plot_options);
676
676
677 //overview
677 //overview
678 var overview = YAHOO.widget.Flot(overviewContainer,
678 var overview = YAHOO.widget.Flot(overviewContainer,
679 overview_dataset, overview_options);
679 overview_dataset, overview_options);
680
680
681 //show initial selection on overview
681 //show initial selection on overview
682 overview.setSelection(initial_ranges);
682 overview.setSelection(initial_ranges);
683
683
684 plot.subscribe("plotselected", plotselected);
684 plot.subscribe("plotselected", plotselected);
685 plot.subscribe("plothover", plothover)
685 plot.subscribe("plothover", plothover)
686
686
687 overview.subscribe("plotselected", function (ranges) {
687 overview.subscribe("plotselected", function (ranges) {
688 plot.setSelection(ranges);
688 plot.setSelection(ranges);
689 });
689 });
690
690
691 // user choices on overview
691 // user choices on overview
692 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
692 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
693 }
693 }
694 SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});
694 SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});
695 </script>
695 </script>
696 %endif
696 %endif
697
697
698 </%def>
698 </%def>
General Comments 0
You need to be logged in to leave comments. Login now