##// END OF EJS Templates
added wrapping of long tooltips in index page
marcink -
r905:1294f2ba beta
parent child Browse files
Show More
@@ -1,525 +1,525
1 """Helper functions
1 """Helper functions
2
2
3 Consists of functions to typically be used within templates, but also
3 Consists of functions to typically be used within templates, but also
4 available to Controllers. This module is available to both as 'h'.
4 available to Controllers. This module is available to both as 'h'.
5 """
5 """
6 import random
6 import random
7 import hashlib
7 import hashlib
8 from pygments.formatters import HtmlFormatter
8 from pygments.formatters import HtmlFormatter
9 from pygments import highlight as code_highlight
9 from pygments import highlight as code_highlight
10 from pylons import url, app_globals as g
10 from pylons import url, app_globals as g
11 from pylons.i18n.translation import _, ungettext
11 from pylons.i18n.translation import _, ungettext
12 from vcs.utils.annotate import annotate_highlight
12 from vcs.utils.annotate import annotate_highlight
13 from webhelpers.html import literal, HTML, escape
13 from webhelpers.html import literal, HTML, escape
14 from webhelpers.html.tools import *
14 from webhelpers.html.tools import *
15 from webhelpers.html.builder import make_tag
15 from webhelpers.html.builder import make_tag
16 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
16 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
17 end_form, file, form, hidden, image, javascript_link, link_to, link_to_if, \
17 end_form, file, form, hidden, image, javascript_link, link_to, link_to_if, \
18 link_to_unless, ol, required_legend, select, stylesheet_link, submit, text, \
18 link_to_unless, ol, required_legend, select, stylesheet_link, submit, text, \
19 password, textarea, title, ul, xml_declaration, radio
19 password, textarea, title, ul, xml_declaration, radio
20 from webhelpers.html.tools import auto_link, button_to, highlight, js_obfuscate, \
20 from webhelpers.html.tools import auto_link, button_to, highlight, js_obfuscate, \
21 mail_to, strip_links, strip_tags, tag_re
21 mail_to, strip_links, strip_tags, tag_re
22 from webhelpers.number import format_byte_size, format_bit_size
22 from webhelpers.number import format_byte_size, format_bit_size
23 from webhelpers.pylonslib import Flash as _Flash
23 from webhelpers.pylonslib import Flash as _Flash
24 from webhelpers.pylonslib.secure_form import secure_form
24 from webhelpers.pylonslib.secure_form import secure_form
25 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
25 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
26 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
26 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
27 replace_whitespace, urlify, truncate, wrap_paragraphs
27 replace_whitespace, urlify, truncate, wrap_paragraphs
28 from webhelpers.date import time_ago_in_words
28 from webhelpers.date import time_ago_in_words
29
29
30 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
30 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
31 convert_boolean_attrs, NotGiven
31 convert_boolean_attrs, NotGiven
32
32
33 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
33 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
34 """Reset button
34 """Reset button
35 """
35 """
36 _set_input_attrs(attrs, type, name, value)
36 _set_input_attrs(attrs, type, name, value)
37 _set_id_attr(attrs, id, name)
37 _set_id_attr(attrs, id, name)
38 convert_boolean_attrs(attrs, ["disabled"])
38 convert_boolean_attrs(attrs, ["disabled"])
39 return HTML.input(**attrs)
39 return HTML.input(**attrs)
40
40
41 reset = _reset
41 reset = _reset
42
42
43
43
44 def get_token():
44 def get_token():
45 """Return the current authentication token, creating one if one doesn't
45 """Return the current authentication token, creating one if one doesn't
46 already exist.
46 already exist.
47 """
47 """
48 token_key = "_authentication_token"
48 token_key = "_authentication_token"
49 from pylons import session
49 from pylons import session
50 if not token_key in session:
50 if not token_key in session:
51 try:
51 try:
52 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
52 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
53 except AttributeError: # Python < 2.4
53 except AttributeError: # Python < 2.4
54 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
54 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
55 session[token_key] = token
55 session[token_key] = token
56 if hasattr(session, 'save'):
56 if hasattr(session, 'save'):
57 session.save()
57 session.save()
58 return session[token_key]
58 return session[token_key]
59
59
60 class _GetError(object):
60 class _GetError(object):
61 """Get error from form_errors, and represent it as span wrapped error
61 """Get error from form_errors, and represent it as span wrapped error
62 message
62 message
63
63
64 :param field_name: field to fetch errors for
64 :param field_name: field to fetch errors for
65 :param form_errors: form errors dict
65 :param form_errors: form errors dict
66 """
66 """
67
67
68 def __call__(self, field_name, form_errors):
68 def __call__(self, field_name, form_errors):
69 tmpl = """<span class="error_msg">%s</span>"""
69 tmpl = """<span class="error_msg">%s</span>"""
70 if form_errors and form_errors.has_key(field_name):
70 if form_errors and form_errors.has_key(field_name):
71 return literal(tmpl % form_errors.get(field_name))
71 return literal(tmpl % form_errors.get(field_name))
72
72
73 get_error = _GetError()
73 get_error = _GetError()
74
74
75 def recursive_replace(str, replace=' '):
75 def recursive_replace(str, replace=' '):
76 """Recursive replace of given sign to just one instance
76 """Recursive replace of given sign to just one instance
77
77
78 :param str: given string
78 :param str: given string
79 :param replace: char to find and replace multiple instances
79 :param replace: char to find and replace multiple instances
80
80
81 Examples::
81 Examples::
82 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
82 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
83 'Mighty-Mighty-Bo-sstones'
83 'Mighty-Mighty-Bo-sstones'
84 """
84 """
85
85
86 if str.find(replace * 2) == -1:
86 if str.find(replace * 2) == -1:
87 return str
87 return str
88 else:
88 else:
89 str = str.replace(replace * 2, replace)
89 str = str.replace(replace * 2, replace)
90 return recursive_replace(str, replace)
90 return recursive_replace(str, replace)
91
91
92 class _ToolTip(object):
92 class _ToolTip(object):
93
93
94 def __call__(self, tooltip_title, trim_at=50):
94 def __call__(self, tooltip_title, trim_at=50):
95 """
95 """Special function just to wrap our text into nice formatted
96 Special function just to wrap our text into nice formatted autowrapped
96 autowrapped text
97 text
97
98 :param tooltip_title:
98 :param tooltip_title:
99 """
99 """
100
100
101 return wrap_paragraphs(escape(tooltip_title), trim_at)\
101 return wrap_paragraphs(escape(tooltip_title), trim_at)\
102 .replace('\n', '<br/>')
102 .replace('\n', '<br/>')
103
103
104 def activate(self):
104 def activate(self):
105 """Adds tooltip mechanism to the given Html all tooltips have to have
105 """Adds tooltip mechanism to the given Html all tooltips have to have
106 set class `tooltip` and set attribute `tooltip_title`.
106 set class `tooltip` and set attribute `tooltip_title`.
107 Then a tooltip will be generated based on that. All with yui js tooltip
107 Then a tooltip will be generated based on that. All with yui js tooltip
108 """
108 """
109
109
110 js = '''
110 js = '''
111 YAHOO.util.Event.onDOMReady(function(){
111 YAHOO.util.Event.onDOMReady(function(){
112 function toolTipsId(){
112 function toolTipsId(){
113 var ids = [];
113 var ids = [];
114 var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
114 var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
115
115
116 for (var i = 0; i < tts.length; i++) {
116 for (var i = 0; i < tts.length; i++) {
117 //if element doesn't not have and id autogenerate one for tooltip
117 //if element doesn't not have and id autogenerate one for tooltip
118
118
119 if (!tts[i].id){
119 if (!tts[i].id){
120 tts[i].id='tt'+i*100;
120 tts[i].id='tt'+i*100;
121 }
121 }
122 ids.push(tts[i].id);
122 ids.push(tts[i].id);
123 }
123 }
124 return ids
124 return ids
125 };
125 };
126 var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
126 var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
127 context: toolTipsId(),
127 context: toolTipsId(),
128 monitorresize:false,
128 monitorresize:false,
129 xyoffset :[0,0],
129 xyoffset :[0,0],
130 autodismissdelay:300000,
130 autodismissdelay:300000,
131 hidedelay:5,
131 hidedelay:5,
132 showdelay:20,
132 showdelay:20,
133 });
133 });
134
134
135 // Set the text for the tooltip just before we display it. Lazy method
135 // Set the text for the tooltip just before we display it. Lazy method
136 myToolTips.contextTriggerEvent.subscribe(
136 myToolTips.contextTriggerEvent.subscribe(
137 function(type, args) {
137 function(type, args) {
138
138
139 var context = args[0];
139 var context = args[0];
140
140
141 //positioning of tooltip
141 //positioning of tooltip
142 var tt_w = this.element.clientWidth;//tooltip width
142 var tt_w = this.element.clientWidth;//tooltip width
143 var tt_h = this.element.clientHeight;//tooltip height
143 var tt_h = this.element.clientHeight;//tooltip height
144
144
145 var context_w = context.offsetWidth;
145 var context_w = context.offsetWidth;
146 var context_h = context.offsetHeight;
146 var context_h = context.offsetHeight;
147
147
148 var pos_x = YAHOO.util.Dom.getX(context);
148 var pos_x = YAHOO.util.Dom.getX(context);
149 var pos_y = YAHOO.util.Dom.getY(context);
149 var pos_y = YAHOO.util.Dom.getY(context);
150
150
151 var display_strategy = 'right';
151 var display_strategy = 'right';
152 var xy_pos = [0,0];
152 var xy_pos = [0,0];
153 switch (display_strategy){
153 switch (display_strategy){
154
154
155 case 'top':
155 case 'top':
156 var cur_x = (pos_x+context_w/2)-(tt_w/2);
156 var cur_x = (pos_x+context_w/2)-(tt_w/2);
157 var cur_y = (pos_y-tt_h-4);
157 var cur_y = (pos_y-tt_h-4);
158 xy_pos = [cur_x,cur_y];
158 xy_pos = [cur_x,cur_y];
159 break;
159 break;
160 case 'bottom':
160 case 'bottom':
161 var cur_x = (pos_x+context_w/2)-(tt_w/2);
161 var cur_x = (pos_x+context_w/2)-(tt_w/2);
162 var cur_y = pos_y+context_h+4;
162 var cur_y = pos_y+context_h+4;
163 xy_pos = [cur_x,cur_y];
163 xy_pos = [cur_x,cur_y];
164 break;
164 break;
165 case 'left':
165 case 'left':
166 var cur_x = (pos_x-tt_w-4);
166 var cur_x = (pos_x-tt_w-4);
167 var cur_y = pos_y-((tt_h/2)-context_h/2);
167 var cur_y = pos_y-((tt_h/2)-context_h/2);
168 xy_pos = [cur_x,cur_y];
168 xy_pos = [cur_x,cur_y];
169 break;
169 break;
170 case 'right':
170 case 'right':
171 var cur_x = (pos_x+context_w+4);
171 var cur_x = (pos_x+context_w+4);
172 var cur_y = pos_y-((tt_h/2)-context_h/2);
172 var cur_y = pos_y-((tt_h/2)-context_h/2);
173 xy_pos = [cur_x,cur_y];
173 xy_pos = [cur_x,cur_y];
174 break;
174 break;
175 default:
175 default:
176 var cur_x = (pos_x+context_w/2)-(tt_w/2);
176 var cur_x = (pos_x+context_w/2)-(tt_w/2);
177 var cur_y = pos_y-tt_h-4;
177 var cur_y = pos_y-tt_h-4;
178 xy_pos = [cur_x,cur_y];
178 xy_pos = [cur_x,cur_y];
179 break;
179 break;
180
180
181 }
181 }
182
182
183 this.cfg.setProperty("xy",xy_pos);
183 this.cfg.setProperty("xy",xy_pos);
184
184
185 });
185 });
186
186
187 //Mouse out
187 //Mouse out
188 myToolTips.contextMouseOutEvent.subscribe(
188 myToolTips.contextMouseOutEvent.subscribe(
189 function(type, args) {
189 function(type, args) {
190 var context = args[0];
190 var context = args[0];
191
191
192 });
192 });
193 });
193 });
194 '''
194 '''
195 return literal(js)
195 return literal(js)
196
196
197 tooltip = _ToolTip()
197 tooltip = _ToolTip()
198
198
199 class _FilesBreadCrumbs(object):
199 class _FilesBreadCrumbs(object):
200
200
201 def __call__(self, repo_name, rev, paths):
201 def __call__(self, repo_name, rev, paths):
202 url_l = [link_to(repo_name, url('files_home',
202 url_l = [link_to(repo_name, url('files_home',
203 repo_name=repo_name,
203 repo_name=repo_name,
204 revision=rev, f_path=''))]
204 revision=rev, f_path=''))]
205 paths_l = paths.split('/')
205 paths_l = paths.split('/')
206
206
207 for cnt, p in enumerate(paths_l):
207 for cnt, p in enumerate(paths_l):
208 if p != '':
208 if p != '':
209 url_l.append(link_to(p, url('files_home',
209 url_l.append(link_to(p, url('files_home',
210 repo_name=repo_name,
210 repo_name=repo_name,
211 revision=rev,
211 revision=rev,
212 f_path='/'.join(paths_l[:cnt + 1]))))
212 f_path='/'.join(paths_l[:cnt + 1]))))
213
213
214 return literal('/'.join(url_l))
214 return literal('/'.join(url_l))
215
215
216 files_breadcrumbs = _FilesBreadCrumbs()
216 files_breadcrumbs = _FilesBreadCrumbs()
217
217
218 class CodeHtmlFormatter(HtmlFormatter):
218 class CodeHtmlFormatter(HtmlFormatter):
219
219
220 def wrap(self, source, outfile):
220 def wrap(self, source, outfile):
221 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
221 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
222
222
223 def _wrap_code(self, source):
223 def _wrap_code(self, source):
224 for cnt, it in enumerate(source):
224 for cnt, it in enumerate(source):
225 i, t = it
225 i, t = it
226 t = '<div id="#S-%s">%s</div>' % (cnt + 1, t)
226 t = '<div id="#S-%s">%s</div>' % (cnt + 1, t)
227 yield i, t
227 yield i, t
228 def pygmentize(filenode, **kwargs):
228 def pygmentize(filenode, **kwargs):
229 """pygmentize function using pygments
229 """pygmentize function using pygments
230
230
231 :param filenode:
231 :param filenode:
232 """
232 """
233
233
234 return literal(code_highlight(filenode.content,
234 return literal(code_highlight(filenode.content,
235 filenode.lexer, CodeHtmlFormatter(**kwargs)))
235 filenode.lexer, CodeHtmlFormatter(**kwargs)))
236
236
237 def pygmentize_annotation(filenode, **kwargs):
237 def pygmentize_annotation(filenode, **kwargs):
238 """pygmentize function for annotation
238 """pygmentize function for annotation
239
239
240 :param filenode:
240 :param filenode:
241 """
241 """
242
242
243 color_dict = {}
243 color_dict = {}
244 def gen_color():
244 def gen_color():
245 """generator for getting 10k of evenly distibuted colors using hsv color
245 """generator for getting 10k of evenly distibuted colors using hsv color
246 and golden ratio.
246 and golden ratio.
247 """
247 """
248 import colorsys
248 import colorsys
249 n = 10000
249 n = 10000
250 golden_ratio = 0.618033988749895
250 golden_ratio = 0.618033988749895
251 h = 0.22717784590367374
251 h = 0.22717784590367374
252 #generate 10k nice web friendly colors in the same order
252 #generate 10k nice web friendly colors in the same order
253 for c in xrange(n):
253 for c in xrange(n):
254 h += golden_ratio
254 h += golden_ratio
255 h %= 1
255 h %= 1
256 HSV_tuple = [h, 0.95, 0.95]
256 HSV_tuple = [h, 0.95, 0.95]
257 RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple)
257 RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple)
258 yield map(lambda x:str(int(x * 256)), RGB_tuple)
258 yield map(lambda x:str(int(x * 256)), RGB_tuple)
259
259
260 cgenerator = gen_color()
260 cgenerator = gen_color()
261
261
262 def get_color_string(cs):
262 def get_color_string(cs):
263 if color_dict.has_key(cs):
263 if color_dict.has_key(cs):
264 col = color_dict[cs]
264 col = color_dict[cs]
265 else:
265 else:
266 col = color_dict[cs] = cgenerator.next()
266 col = color_dict[cs] = cgenerator.next()
267 return "color: rgb(%s)! important;" % (', '.join(col))
267 return "color: rgb(%s)! important;" % (', '.join(col))
268
268
269 def url_func(changeset):
269 def url_func(changeset):
270 tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \
270 tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \
271 " %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
271 " %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
272
272
273 tooltip_html = tooltip_html % (changeset.author,
273 tooltip_html = tooltip_html % (changeset.author,
274 changeset.date,
274 changeset.date,
275 tooltip(changeset.message))
275 tooltip(changeset.message))
276 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
276 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
277 short_id(changeset.raw_id))
277 short_id(changeset.raw_id))
278 uri = link_to(
278 uri = link_to(
279 lnk_format,
279 lnk_format,
280 url('changeset_home', repo_name=changeset.repository.name,
280 url('changeset_home', repo_name=changeset.repository.name,
281 revision=changeset.raw_id),
281 revision=changeset.raw_id),
282 style=get_color_string(changeset.raw_id),
282 style=get_color_string(changeset.raw_id),
283 class_='tooltip',
283 class_='tooltip',
284 title=tooltip_html
284 title=tooltip_html
285 )
285 )
286
286
287 uri += '\n'
287 uri += '\n'
288 return uri
288 return uri
289 return literal(annotate_highlight(filenode, url_func, **kwargs))
289 return literal(annotate_highlight(filenode, url_func, **kwargs))
290
290
291 def repo_name_slug(value):
291 def repo_name_slug(value):
292 """Return slug of name of repository
292 """Return slug of name of repository
293 This function is called on each creation/modification
293 This function is called on each creation/modification
294 of repository to prevent bad names in repo
294 of repository to prevent bad names in repo
295 """
295 """
296
296
297 slug = remove_formatting(value)
297 slug = remove_formatting(value)
298 slug = strip_tags(slug)
298 slug = strip_tags(slug)
299
299
300 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
300 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
301 slug = slug.replace(c, '-')
301 slug = slug.replace(c, '-')
302 slug = recursive_replace(slug, '-')
302 slug = recursive_replace(slug, '-')
303 slug = collapse(slug, '-')
303 slug = collapse(slug, '-')
304 return slug
304 return slug
305
305
306 def get_changeset_safe(repo, rev):
306 def get_changeset_safe(repo, rev):
307 from vcs.backends.base import BaseRepository
307 from vcs.backends.base import BaseRepository
308 from vcs.exceptions import RepositoryError
308 from vcs.exceptions import RepositoryError
309 if not isinstance(repo, BaseRepository):
309 if not isinstance(repo, BaseRepository):
310 raise Exception('You must pass an Repository '
310 raise Exception('You must pass an Repository '
311 'object as first argument got %s', type(repo))
311 'object as first argument got %s', type(repo))
312
312
313 try:
313 try:
314 cs = repo.get_changeset(rev)
314 cs = repo.get_changeset(rev)
315 except RepositoryError:
315 except RepositoryError:
316 from rhodecode.lib.utils import EmptyChangeset
316 from rhodecode.lib.utils import EmptyChangeset
317 cs = EmptyChangeset()
317 cs = EmptyChangeset()
318 return cs
318 return cs
319
319
320
320
321 flash = _Flash()
321 flash = _Flash()
322
322
323
323
324 #==============================================================================
324 #==============================================================================
325 # MERCURIAL FILTERS available via h.
325 # MERCURIAL FILTERS available via h.
326 #==============================================================================
326 #==============================================================================
327 from mercurial import util
327 from mercurial import util
328 from mercurial.templatefilters import person as _person
328 from mercurial.templatefilters import person as _person
329
329
330 def _age(curdate):
330 def _age(curdate):
331 """turns a datetime into an age string."""
331 """turns a datetime into an age string."""
332
332
333 if not curdate:
333 if not curdate:
334 return ''
334 return ''
335
335
336 from datetime import timedelta, datetime
336 from datetime import timedelta, datetime
337
337
338 agescales = [("year", 3600 * 24 * 365),
338 agescales = [("year", 3600 * 24 * 365),
339 ("month", 3600 * 24 * 30),
339 ("month", 3600 * 24 * 30),
340 ("day", 3600 * 24),
340 ("day", 3600 * 24),
341 ("hour", 3600),
341 ("hour", 3600),
342 ("minute", 60),
342 ("minute", 60),
343 ("second", 1), ]
343 ("second", 1), ]
344
344
345 age = datetime.now() - curdate
345 age = datetime.now() - curdate
346 age_seconds = (age.days * agescales[2][1]) + age.seconds
346 age_seconds = (age.days * agescales[2][1]) + age.seconds
347 pos = 1
347 pos = 1
348 for scale in agescales:
348 for scale in agescales:
349 if scale[1] <= age_seconds:
349 if scale[1] <= age_seconds:
350 if pos == 6:pos = 5
350 if pos == 6:pos = 5
351 return time_ago_in_words(curdate, agescales[pos][0]) + ' ' + _('ago')
351 return time_ago_in_words(curdate, agescales[pos][0]) + ' ' + _('ago')
352 pos += 1
352 pos += 1
353
353
354 return _('just now')
354 return _('just now')
355
355
356 age = lambda x:_age(x)
356 age = lambda x:_age(x)
357 capitalize = lambda x: x.capitalize()
357 capitalize = lambda x: x.capitalize()
358 email = util.email
358 email = util.email
359 email_or_none = lambda x: util.email(x) if util.email(x) != x else None
359 email_or_none = lambda x: util.email(x) if util.email(x) != x else None
360 person = lambda x: _person(x)
360 person = lambda x: _person(x)
361 short_id = lambda x: x[:12]
361 short_id = lambda x: x[:12]
362
362
363
363
364 def bool2icon(value):
364 def bool2icon(value):
365 """Returns True/False values represented as small html image of true/false
365 """Returns True/False values represented as small html image of true/false
366 icons
366 icons
367
367
368 :param value: bool value
368 :param value: bool value
369 """
369 """
370
370
371 if value is True:
371 if value is True:
372 return HTML.tag('img', src="/images/icons/accept.png", alt=_('True'))
372 return HTML.tag('img', src="/images/icons/accept.png", alt=_('True'))
373
373
374 if value is False:
374 if value is False:
375 return HTML.tag('img', src="/images/icons/cancel.png", alt=_('False'))
375 return HTML.tag('img', src="/images/icons/cancel.png", alt=_('False'))
376
376
377 return value
377 return value
378
378
379
379
380 def action_parser(user_log):
380 def action_parser(user_log):
381 """This helper will map the specified string action into translated
381 """This helper will map the specified string action into translated
382 fancy names with icons and links
382 fancy names with icons and links
383
383
384 :param user_log: user log instance
384 :param user_log: user log instance
385 """
385 """
386
386
387 action = user_log.action
387 action = user_log.action
388 action_params = ' '
388 action_params = ' '
389
389
390 x = action.split(':')
390 x = action.split(':')
391
391
392 if len(x) > 1:
392 if len(x) > 1:
393 action, action_params = x
393 action, action_params = x
394
394
395 def get_cs_links():
395 def get_cs_links():
396 if action == 'push':
396 if action == 'push':
397 revs_limit = 5 #display this amount always
397 revs_limit = 5 #display this amount always
398 revs_top_limit = 50 #show upto this amount of changesets hidden
398 revs_top_limit = 50 #show upto this amount of changesets hidden
399 revs = action_params.split(',')
399 revs = action_params.split(',')
400 repo_name = user_log.repository.repo_name
400 repo_name = user_log.repository.repo_name
401 from rhodecode.model.scm import ScmModel
401 from rhodecode.model.scm import ScmModel
402
402
403 message = lambda rev: get_changeset_safe(ScmModel().get(repo_name),
403 message = lambda rev: get_changeset_safe(ScmModel().get(repo_name),
404 rev).message
404 rev).message
405
405
406 cs_links = " " + ', '.join ([link_to(rev,
406 cs_links = " " + ', '.join ([link_to(rev,
407 url('changeset_home',
407 url('changeset_home',
408 repo_name=repo_name,
408 repo_name=repo_name,
409 revision=rev), title=message(rev),
409 revision=rev), title=message(rev),
410 class_='tooltip') for rev in revs[:revs_limit] ])
410 class_='tooltip') for rev in revs[:revs_limit] ])
411 if len(revs) > revs_limit:
411 if len(revs) > revs_limit:
412 uniq_id = revs[0]
412 uniq_id = revs[0]
413 html_tmpl = ('<span> %s '
413 html_tmpl = ('<span> %s '
414 '<a class="show_more" id="_%s" href="#">%s</a> '
414 '<a class="show_more" id="_%s" href="#">%s</a> '
415 '%s</span>')
415 '%s</span>')
416 cs_links += html_tmpl % (_('and'), uniq_id, _('%s more') \
416 cs_links += html_tmpl % (_('and'), uniq_id, _('%s more') \
417 % (len(revs) - revs_limit),
417 % (len(revs) - revs_limit),
418 _('revisions'))
418 _('revisions'))
419
419
420 html_tmpl = '<span id="%s" style="display:none"> %s </span>'
420 html_tmpl = '<span id="%s" style="display:none"> %s </span>'
421 cs_links += html_tmpl % (uniq_id, ', '.join([link_to(rev,
421 cs_links += html_tmpl % (uniq_id, ', '.join([link_to(rev,
422 url('changeset_home',
422 url('changeset_home',
423 repo_name=repo_name, revision=rev),
423 repo_name=repo_name, revision=rev),
424 title=message(rev), class_='tooltip')
424 title=message(rev), class_='tooltip')
425 for rev in revs[revs_limit:revs_top_limit]]))
425 for rev in revs[revs_limit:revs_top_limit]]))
426
426
427 return cs_links
427 return cs_links
428 return ''
428 return ''
429
429
430 def get_fork_name():
430 def get_fork_name():
431 if action == 'user_forked_repo':
431 if action == 'user_forked_repo':
432 from rhodecode.model.scm import ScmModel
432 from rhodecode.model.scm import ScmModel
433 repo_name = action_params
433 repo_name = action_params
434 repo = ScmModel().get(repo_name)
434 repo = ScmModel().get(repo_name)
435 if repo is None:
435 if repo is None:
436 return repo_name
436 return repo_name
437 return link_to(action_params, url('summary_home',
437 return link_to(action_params, url('summary_home',
438 repo_name=repo.name,),
438 repo_name=repo.name,),
439 title=repo.dbrepo.description)
439 title=repo.dbrepo.description)
440 return ''
440 return ''
441 map = {'user_deleted_repo':_('User [deleted] repository'),
441 map = {'user_deleted_repo':_('User [deleted] repository'),
442 'user_created_repo':_('User [created] repository'),
442 'user_created_repo':_('User [created] repository'),
443 'user_forked_repo':_('User [forked] repository as: %s') % get_fork_name(),
443 'user_forked_repo':_('User [forked] repository as: %s') % get_fork_name(),
444 'user_updated_repo':_('User [updated] repository'),
444 'user_updated_repo':_('User [updated] repository'),
445 'admin_deleted_repo':_('Admin [delete] repository'),
445 'admin_deleted_repo':_('Admin [delete] repository'),
446 'admin_created_repo':_('Admin [created] repository'),
446 'admin_created_repo':_('Admin [created] repository'),
447 'admin_forked_repo':_('Admin [forked] repository'),
447 'admin_forked_repo':_('Admin [forked] repository'),
448 'admin_updated_repo':_('Admin [updated] repository'),
448 'admin_updated_repo':_('Admin [updated] repository'),
449 'push':_('[Pushed] %s') % get_cs_links(),
449 'push':_('[Pushed] %s') % get_cs_links(),
450 'pull':_('[Pulled]'),
450 'pull':_('[Pulled]'),
451 'started_following_repo':_('User [started following] repository'),
451 'started_following_repo':_('User [started following] repository'),
452 'stopped_following_repo':_('User [stopped following] repository'),
452 'stopped_following_repo':_('User [stopped following] repository'),
453 }
453 }
454
454
455 action_str = map.get(action, action)
455 action_str = map.get(action, action)
456 return literal(action_str.replace('[', '<span class="journal_highlight">')\
456 return literal(action_str.replace('[', '<span class="journal_highlight">')\
457 .replace(']', '</span>'))
457 .replace(']', '</span>'))
458
458
459 def action_parser_icon(user_log):
459 def action_parser_icon(user_log):
460 action = user_log.action
460 action = user_log.action
461 action_params = None
461 action_params = None
462 x = action.split(':')
462 x = action.split(':')
463
463
464 if len(x) > 1:
464 if len(x) > 1:
465 action, action_params = x
465 action, action_params = x
466
466
467 tmpl = """<img src="/images/icons/%s" alt="%s"/>"""
467 tmpl = """<img src="/images/icons/%s" alt="%s"/>"""
468 map = {'user_deleted_repo':'database_delete.png',
468 map = {'user_deleted_repo':'database_delete.png',
469 'user_created_repo':'database_add.png',
469 'user_created_repo':'database_add.png',
470 'user_forked_repo':'arrow_divide.png',
470 'user_forked_repo':'arrow_divide.png',
471 'user_updated_repo':'database_edit.png',
471 'user_updated_repo':'database_edit.png',
472 'admin_deleted_repo':'database_delete.png',
472 'admin_deleted_repo':'database_delete.png',
473 'admin_created_repo':'database_add.png',
473 'admin_created_repo':'database_add.png',
474 'admin_forked_repo':'arrow_divide.png',
474 'admin_forked_repo':'arrow_divide.png',
475 'admin_updated_repo':'database_edit.png',
475 'admin_updated_repo':'database_edit.png',
476 'push':'script_add.png',
476 'push':'script_add.png',
477 'pull':'down_16.png',
477 'pull':'down_16.png',
478 'started_following_repo':'heart_add.png',
478 'started_following_repo':'heart_add.png',
479 'stopped_following_repo':'heart_delete.png',
479 'stopped_following_repo':'heart_delete.png',
480 }
480 }
481 return literal(tmpl % (map.get(action, action), action))
481 return literal(tmpl % (map.get(action, action), action))
482
482
483
483
484 #==============================================================================
484 #==============================================================================
485 # PERMS
485 # PERMS
486 #==============================================================================
486 #==============================================================================
487 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
487 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
488 HasRepoPermissionAny, HasRepoPermissionAll
488 HasRepoPermissionAny, HasRepoPermissionAll
489
489
490 #==============================================================================
490 #==============================================================================
491 # GRAVATAR URL
491 # GRAVATAR URL
492 #==============================================================================
492 #==============================================================================
493 import hashlib
493 import hashlib
494 import urllib
494 import urllib
495 from pylons import request
495 from pylons import request
496
496
497 def gravatar_url(email_address, size=30):
497 def gravatar_url(email_address, size=30):
498 ssl_enabled = 'https' == request.environ.get('HTTP_X_URL_SCHEME')
498 ssl_enabled = 'https' == request.environ.get('HTTP_X_URL_SCHEME')
499 default = 'identicon'
499 default = 'identicon'
500 baseurl_nossl = "http://www.gravatar.com/avatar/"
500 baseurl_nossl = "http://www.gravatar.com/avatar/"
501 baseurl_ssl = "https://secure.gravatar.com/avatar/"
501 baseurl_ssl = "https://secure.gravatar.com/avatar/"
502 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
502 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
503
503
504
504
505 # construct the url
505 # construct the url
506 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
506 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
507 gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
507 gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
508
508
509 return gravatar_url
509 return gravatar_url
510
510
511 def safe_unicode(str):
511 def safe_unicode(str):
512 """safe unicode function. In case of UnicodeDecode error we try to return
512 """safe unicode function. In case of UnicodeDecode error we try to return
513 unicode with errors replace, if this failes we return unicode with
513 unicode with errors replace, if this failes we return unicode with
514 string_escape decoding """
514 string_escape decoding """
515
515
516 try:
516 try:
517 u_str = unicode(str)
517 u_str = unicode(str)
518 except UnicodeDecodeError:
518 except UnicodeDecodeError:
519 try:
519 try:
520 u_str = unicode(str, 'utf-8', 'replace')
520 u_str = unicode(str, 'utf-8', 'replace')
521 except UnicodeDecodeError:
521 except UnicodeDecodeError:
522 #incase we have a decode error just represent as byte string
522 #incase we have a decode error just represent as byte string
523 u_str = unicode(str(str).encode('string_escape'))
523 u_str = unicode(str(str).encode('string_escape'))
524
524
525 return u_str
525 return u_str
@@ -1,381 +1,381
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
4 <head>
4 <head>
5 <title>${next.title()}</title>
5 <title>${next.title()}</title>
6 <link rel="icon" href="/images/icons/database_gear.png" type="image/png" />
6 <link rel="icon" href="/images/icons/database_gear.png" type="image/png" />
7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
8 <meta name="robots" content="index, nofollow"/>
8 <meta name="robots" content="index, nofollow"/>
9 <!-- stylesheets -->
9 <!-- stylesheets -->
10 ${self.css()}
10 ${self.css()}
11 <!-- scripts -->
11 <!-- scripts -->
12 ${self.js()}
12 ${self.js()}
13 %if c.ga_code:
13 %if c.ga_code:
14 <script type="text/javascript">
14 <script type="text/javascript">
15
15
16 var _gaq = _gaq || [];
16 var _gaq = _gaq || [];
17 _gaq.push(['_setAccount', '${c.ga_code}']);
17 _gaq.push(['_setAccount', '${c.ga_code}']);
18 _gaq.push(['_trackPageview']);
18 _gaq.push(['_trackPageview']);
19
19
20 (function() {
20 (function() {
21 var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
21 var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
22 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
22 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
23 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
23 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
24 })();
24 })();
25
25
26
26
27 </script>
27 </script>
28 %endif
28 %endif
29 </head>
29 </head>
30 <body>
30 <body>
31 <!-- header -->
31 <!-- header -->
32 <div id="header">
32 <div id="header">
33 <!-- user -->
33 <!-- user -->
34 <ul id="logged-user">
34 <ul id="logged-user">
35 <li class="first">
35 <li class="first">
36 <div class="gravatar">
36 <div class="gravatar">
37 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,20)}" />
37 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,20)}" />
38 </div>
38 </div>
39 <div class="account">
39 <div class="account">
40 %if c.rhodecode_user.username == 'default':
40 %if c.rhodecode_user.username == 'default':
41 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
41 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
42 ${h.link_to('anonymous',h.url('register'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
42 ${h.link_to('anonymous',h.url('register'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
43 %else:
43 %else:
44 ${h.link_to('anonymous',h.url('#'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
44 ${h.link_to('anonymous',h.url('#'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
45 %endif
45 %endif
46
46
47 %else:
47 %else:
48 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
48 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
49 %endif
49 %endif
50 </div>
50 </div>
51 </li>
51 </li>
52 <li>
52 <li>
53 <a href="${h.url('home')}">${_('Home')}</a>
53 <a href="${h.url('home')}">${_('Home')}</a>
54 </li>
54 </li>
55 %if c.rhodecode_user.username != 'default':
55 %if c.rhodecode_user.username != 'default':
56 <li>
56 <li>
57 <a href="${h.url('journal')}">${_('Journal')}</a>
57 <a href="${h.url('journal')}">${_('Journal')}</a>
58 ##(${c.unread_journal})</a>
58 ##(${c.unread_journal})</a>
59 </li>
59 </li>
60 %endif
60 %endif
61 %if c.rhodecode_user.username == 'default':
61 %if c.rhodecode_user.username == 'default':
62 <li class="last highlight">${h.link_to(u'Login',h.url('login_home'))}</li>
62 <li class="last highlight">${h.link_to(u'Login',h.url('login_home'))}</li>
63 %else:
63 %else:
64 <li class="last highlight">${h.link_to(u'Log Out',h.url('logout_home'))}</li>
64 <li class="last highlight">${h.link_to(u'Log Out',h.url('logout_home'))}</li>
65 %endif
65 %endif
66 </ul>
66 </ul>
67 <!-- end user -->
67 <!-- end user -->
68 <div id="header-inner" class="title top-left-rounded-corner top-right-rounded-corner">
68 <div id="header-inner" class="title top-left-rounded-corner top-right-rounded-corner">
69 <!-- logo -->
69 <!-- logo -->
70 <div id="logo">
70 <div id="logo">
71 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
71 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
72 </div>
72 </div>
73 <!-- end logo -->
73 <!-- end logo -->
74 <!-- menu -->
74 <!-- menu -->
75 ${self.page_nav()}
75 ${self.page_nav()}
76 <!-- quick -->
76 <!-- quick -->
77 </div>
77 </div>
78 </div>
78 </div>
79 <!-- end header -->
79 <!-- end header -->
80
80
81 <!-- CONTENT -->
81 <!-- CONTENT -->
82 <div id="content">
82 <div id="content">
83 <div class="flash_msg">
83 <div class="flash_msg">
84 <% messages = h.flash.pop_messages() %>
84 <% messages = h.flash.pop_messages() %>
85 % if messages:
85 % if messages:
86 <ul id="flash-messages">
86 <ul id="flash-messages">
87 % for message in messages:
87 % for message in messages:
88 <li class="${message.category}_msg">${message}</li>
88 <li class="${message.category}_msg">${message}</li>
89 % endfor
89 % endfor
90 </ul>
90 </ul>
91 % endif
91 % endif
92 </div>
92 </div>
93 <div id="main">
93 <div id="main">
94 ${next.main()}
94 ${next.main()}
95 </div>
95 </div>
96 </div>
96 </div>
97 <!-- END CONTENT -->
97 <!-- END CONTENT -->
98
98
99 <!-- footer -->
99 <!-- footer -->
100 <div id="footer">
100 <div id="footer">
101 <div id="footer-inner" class="title bottom-left-rounded-corner bottom-right-rounded-corner">
101 <div id="footer-inner" class="title bottom-left-rounded-corner bottom-right-rounded-corner">
102 <div>
102 <div>
103 <p class="footer-link">${h.link_to(_('Submit a bug'),h.url('bugtracker'))}</p>
103 <p class="footer-link">${h.link_to(_('Submit a bug'),h.url('bugtracker'))}</p>
104 <p class="footer-link">${h.link_to(_('GPL license'),h.url('gpl_license'))}</p>
104 <p class="footer-link">${h.link_to(_('GPL license'),h.url('gpl_license'))}</p>
105 <p>RhodeCode ${c.rhodecode_version} &copy; 2010 by Marcin Kuzminski</p>
105 <p>RhodeCode ${c.rhodecode_version} &copy; 2010 by Marcin Kuzminski</p>
106 </div>
106 </div>
107 </div>
107 </div>
108 <script type="text/javascript">${h.tooltip.activate()}</script>
108 <script type="text/javascript">${h.tooltip.activate()}</script>
109 </div>
109 </div>
110 <!-- end footer -->
110 <!-- end footer -->
111 </body>
111 </body>
112
112
113 </html>
113 </html>
114
114
115 ### MAKO DEFS ###
115 ### MAKO DEFS ###
116 <%def name="page_nav()">
116 <%def name="page_nav()">
117 ${self.menu()}
117 ${self.menu()}
118 </%def>
118 </%def>
119
119
120 <%def name="menu(current=None)">
120 <%def name="menu(current=None)">
121 <%
121 <%
122 def is_current(selected):
122 def is_current(selected):
123 if selected == current:
123 if selected == current:
124 return h.literal('class="current"')
124 return h.literal('class="current"')
125 %>
125 %>
126 %if current not in ['home','admin']:
126 %if current not in ['home','admin']:
127 ##REGULAR MENU
127 ##REGULAR MENU
128 <ul id="quick">
128 <ul id="quick">
129 <!-- repo switcher -->
129 <!-- repo switcher -->
130 <li>
130 <li>
131 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
131 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
132 <span class="icon">
132 <span class="icon">
133 <img src="/images/icons/database.png" alt="${_('Products')}" />
133 <img src="/images/icons/database.png" alt="${_('Products')}" />
134 </span>
134 </span>
135 <span>&darr;</span>
135 <span>&darr;</span>
136 </a>
136 </a>
137 <ul class="repo_switcher">
137 <ul class="repo_switcher">
138 %for repo in c.cached_repo_list:
138 %for repo in c.cached_repo_list:
139
139
140 %if repo['repo'].dbrepo.private:
140 %if repo['repo'].dbrepo.private:
141 <li><img src="/images/icons/lock.png" alt="${_('Private repository')}" class="repo_switcher_type"/>${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
141 <li><img src="/images/icons/lock.png" alt="${_('Private repository')}" class="repo_switcher_type"/>${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
142 %else:
142 %else:
143 <li><img src="/images/icons/lock_open.png" alt="${_('Public repository')}" class="repo_switcher_type" />${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
143 <li><img src="/images/icons/lock_open.png" alt="${_('Public repository')}" class="repo_switcher_type" />${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
144 %endif
144 %endif
145 %endfor
145 %endfor
146 </ul>
146 </ul>
147 </li>
147 </li>
148
148
149 <li ${is_current('summary')}>
149 <li ${is_current('summary')}>
150 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
150 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
151 <span class="icon">
151 <span class="icon">
152 <img src="/images/icons/clipboard_16.png" alt="${_('Summary')}" />
152 <img src="/images/icons/clipboard_16.png" alt="${_('Summary')}" />
153 </span>
153 </span>
154 <span>${_('Summary')}</span>
154 <span>${_('Summary')}</span>
155 </a>
155 </a>
156 </li>
156 </li>
157 ##<li ${is_current('shortlog')}>
157 ##<li ${is_current('shortlog')}>
158 ## <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
158 ## <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
159 ## <span class="icon">
159 ## <span class="icon">
160 ## <img src="/images/icons/application_view_list.png" alt="${_('Shortlog')}" />
160 ## <img src="/images/icons/application_view_list.png" alt="${_('Shortlog')}" />
161 ## </span>
161 ## </span>
162 ## <span>${_('Shortlog')}</span>
162 ## <span>${_('Shortlog')}</span>
163 ## </a>
163 ## </a>
164 ##</li>
164 ##</li>
165 <li ${is_current('changelog')}>
165 <li ${is_current('changelog')}>
166 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
166 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
167 <span class="icon">
167 <span class="icon">
168 <img src="/images/icons/time.png" alt="${_('Changelog')}" />
168 <img src="/images/icons/time.png" alt="${_('Changelog')}" />
169 </span>
169 </span>
170 <span>${_('Changelog')}</span>
170 <span>${_('Changelog')}</span>
171 </a>
171 </a>
172 </li>
172 </li>
173
173
174 <li ${is_current('switch_to')}>
174 <li ${is_current('switch_to')}>
175 <a title="${_('Switch to')}" href="#">
175 <a title="${_('Switch to')}" href="#">
176 <span class="icon">
176 <span class="icon">
177 <img src="/images/icons/arrow_switch.png" alt="${_('Switch to')}" />
177 <img src="/images/icons/arrow_switch.png" alt="${_('Switch to')}" />
178 </span>
178 </span>
179 <span>${_('Switch to')}</span>
179 <span>${_('Switch to')}</span>
180 </a>
180 </a>
181 <ul>
181 <ul>
182 <li>
182 <li>
183 ${h.link_to('%s (%s)' % (_('branches'),len(c.repository_branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
183 ${h.link_to('%s (%s)' % (_('branches'),len(c.repository_branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
184 <ul>
184 <ul>
185 %if c.repository_branches.values():
185 %if c.repository_branches.values():
186 %for cnt,branch in enumerate(c.repository_branches.items()):
186 %for cnt,branch in enumerate(c.repository_branches.items()):
187 <li>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
187 <li>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
188 %endfor
188 %endfor
189 %else:
189 %else:
190 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
190 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
191 %endif
191 %endif
192 </ul>
192 </ul>
193 </li>
193 </li>
194 <li>
194 <li>
195 ${h.link_to('%s (%s)' % (_('tags'),len(c.repository_tags.values()),),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
195 ${h.link_to('%s (%s)' % (_('tags'),len(c.repository_tags.values()),),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
196 <ul>
196 <ul>
197 %if c.repository_tags.values():
197 %if c.repository_tags.values():
198 %for cnt,tag in enumerate(c.repository_tags.items()):
198 %for cnt,tag in enumerate(c.repository_tags.items()):
199 <li>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
199 <li>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
200 %endfor
200 %endfor
201 %else:
201 %else:
202 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
202 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
203 %endif
203 %endif
204 </ul>
204 </ul>
205 </li>
205 </li>
206 </ul>
206 </ul>
207 </li>
207 </li>
208 <li ${is_current('files')}>
208 <li ${is_current('files')}>
209 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
209 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
210 <span class="icon">
210 <span class="icon">
211 <img src="/images/icons/file.png" alt="${_('Files')}" />
211 <img src="/images/icons/file.png" alt="${_('Files')}" />
212 </span>
212 </span>
213 <span>${_('Files')}</span>
213 <span>${_('Files')}</span>
214 </a>
214 </a>
215 </li>
215 </li>
216
216
217 <li ${is_current('options')}>
217 <li ${is_current('options')}>
218 <a title="${_('Options')}" href="#">
218 <a title="${_('Options')}" href="#">
219 <span class="icon">
219 <span class="icon">
220 <img src="/images/icons/table_gear.png" alt="${_('Admin')}" />
220 <img src="/images/icons/table_gear.png" alt="${_('Admin')}" />
221 </span>
221 </span>
222 <span>${_('Options')}</span>
222 <span>${_('Options')}</span>
223 </a>
223 </a>
224 <ul>
224 <ul>
225 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
225 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
226 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
226 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
227 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
227 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
228 %endif
228 %endif
229 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
229 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
230
230
231 %if h.HasPermissionAll('hg.admin')('access admin main page'):
231 %if h.HasPermissionAll('hg.admin')('access admin main page'):
232 <li>
232 <li>
233 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
233 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
234 <%def name="admin_menu()">
234 <%def name="admin_menu()">
235 <ul>
235 <ul>
236 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
236 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
237 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
237 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
238 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
238 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
239 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
239 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
240 <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
240 <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
241 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
241 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
242 </ul>
242 </ul>
243 </%def>
243 </%def>
244
244
245 ${admin_menu()}
245 ${admin_menu()}
246 </li>
246 </li>
247 %endif
247 %endif
248
248
249 </ul>
249 </ul>
250 </li>
250 </li>
251
251
252 <li>
252 <li>
253 <a title="${_('Followers')}" href="#">
253 <a title="${_('Followers')}" href="#">
254 <span class="icon_short">
254 <span class="icon_short">
255 <img src="/images/icons/heart.png" alt="${_('Followers')}" />
255 <img src="/images/icons/heart.png" alt="${_('Followers')}" />
256 </span>
256 </span>
257 <span class="short">${c.repository_followers}</span>
257 <span class="short">${c.repository_followers}</span>
258 </a>
258 </a>
259 </li>
259 </li>
260 <li>
260 <li>
261 <a title="${_('Forks')}" href="#">
261 <a title="${_('Forks')}" href="#">
262 <span class="icon_short">
262 <span class="icon_short">
263 <img src="/images/icons/arrow_divide.png" alt="${_('Forks')}" />
263 <img src="/images/icons/arrow_divide.png" alt="${_('Forks')}" />
264 </span>
264 </span>
265 <span class="short">${c.repository_forks}</span>
265 <span class="short">${c.repository_forks}</span>
266 </a>
266 </a>
267 </li>
267 </li>
268
268
269
269
270
270
271 </ul>
271 </ul>
272 %else:
272 %else:
273 ##ROOT MENU
273 ##ROOT MENU
274 <ul id="quick">
274 <ul id="quick">
275 <li>
275 <li>
276 <a title="${_('Home')}" href="${h.url('home')}">
276 <a title="${_('Home')}" href="${h.url('home')}">
277 <span class="icon">
277 <span class="icon">
278 <img src="/images/icons/home_16.png" alt="${_('Home')}" />
278 <img src="/images/icons/home_16.png" alt="${_('Home')}" />
279 </span>
279 </span>
280 <span>${_('Home')}</span>
280 <span>${_('Home')}</span>
281 </a>
281 </a>
282 </li>
282 </li>
283 %if c.rhodecode_user.username != 'default':
283 %if c.rhodecode_user.username != 'default':
284 <li>
284 <li>
285 <a title="${_('Journal')}" href="${h.url('journal')}">
285 <a title="${_('Journal')}" href="${h.url('journal')}">
286 <span class="icon">
286 <span class="icon">
287 <img src="/images/icons/book.png" alt="${_('Journal')}" />
287 <img src="/images/icons/book.png" alt="${_('Journal')}" />
288 </span>
288 </span>
289 <span>${_('Journal')}</span>
289 <span>${_('Journal')}</span>
290 </a>
290 </a>
291 </li>
291 </li>
292 %endif
292 %endif
293 <li>
293 <li>
294 <a title="${_('Search')}" href="${h.url('search')}">
294 <a title="${_('Search')}" href="${h.url('search')}">
295 <span class="icon">
295 <span class="icon">
296 <img src="/images/icons/search_16.png" alt="${_('Search')}" />
296 <img src="/images/icons/search_16.png" alt="${_('Search')}" />
297 </span>
297 </span>
298 <span>${_('Search')}</span>
298 <span>${_('Search')}</span>
299 </a>
299 </a>
300 </li>
300 </li>
301
301
302 %if h.HasPermissionAll('hg.admin')('access admin main page'):
302 %if h.HasPermissionAll('hg.admin')('access admin main page'):
303 <li ${is_current('admin')}>
303 <li ${is_current('admin')}>
304 <a title="${_('Admin')}" href="${h.url('admin_home')}">
304 <a title="${_('Admin')}" href="${h.url('admin_home')}">
305 <span class="icon">
305 <span class="icon">
306 <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
306 <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
307 </span>
307 </span>
308 <span>${_('Admin')}</span>
308 <span>${_('Admin')}</span>
309 </a>
309 </a>
310 ${admin_menu()}
310 ${admin_menu()}
311 </li>
311 </li>
312 %endif
312 %endif
313 </ul>
313 </ul>
314 %endif
314 %endif
315 </%def>
315 </%def>
316
316
317
317
318 <%def name="css()">
318 <%def name="css()">
319 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
319 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
320 <link rel="stylesheet" type="text/css" href="/css/pygments.css" />
320 <link rel="stylesheet" type="text/css" href="/css/pygments.css" />
321 <link rel="stylesheet" type="text/css" href="/css/diff.css" />
321 <link rel="stylesheet" type="text/css" href="/css/diff.css" />
322 </%def>
322 </%def>
323
323
324 <%def name="js()">
324 <%def name="js()">
325 ##<script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
325 ##<script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
326 ##<script type="text/javascript" src="/js/yui/container/container.js"></script>
326 ##<script type="text/javascript" src="/js/yui/container/container.js"></script>
327 ##<script type="text/javascript" src="/js/yui/datasource/datasource.js"></script>
327 ##<script type="text/javascript" src="/js/yui/datasource/datasource.js"></script>
328 ##<script type="text/javascript" src="/js/yui/autocomplete/autocomplete.js"></script>
328 ##<script type="text/javascript" src="/js/yui/autocomplete/autocomplete.js"></script>
329 ##<script type="text/javascript" src="/js/yui/selector/selector-min.js"></script>
329 ##<script type="text/javascript" src="/js/yui/selector/selector-min.js"></script>
330
330
331 <script type="text/javascript" src="/js/yui2a.js"></script>
331 <script type="text/javascript" src="/js/yui2a.js"></script>
332 <!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
332 <!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
333 <script type="text/javascript" src="/js/yui.flot.js"></script>
333 <script type="text/javascript" src="/js/yui.flot.js"></script>
334
334
335 <script type="text/javascript">
335 <script type="text/javascript">
336 var base_url ='/_admin/toggle_following';
336 var base_url ='/_admin/toggle_following';
337 var YUC = YAHOO.util.Connect;
337 var YUC = YAHOO.util.Connect;
338 var YUD = YAHOO.util.Dom;
338 var YUD = YAHOO.util.Dom;
339 var YUE = YAHOO.util.Event;
339 var YUE = YAHOO.util.Event;
340
340
341 function onSuccess(){
341 function onSuccess(){
342
342
343 var f = YUD.get('follow_toggle');
343 var f = YUD.get('follow_toggle');
344 if(f.getAttribute('class')=='follow'){
344 if(f.getAttribute('class')=='follow'){
345 f.setAttribute('class','following');
345 f.setAttribute('class','following');
346 f.setAttribute('title',"${_('Stop following this repository')}");
346 f.setAttribute('title',"${_('Stop following this repository')}");
347 }
347 }
348 else{
348 else{
349 f.setAttribute('class','follow');
349 f.setAttribute('class','follow');
350 f.setAttribute('title',"${_('Start following this repository')}");
350 f.setAttribute('title',"${_('Start following this repository')}");
351 }
351 }
352 }
352 }
353
353
354 function toggleFollowingUser(fallows_user_id,token){
354 function toggleFollowingUser(fallows_user_id,token){
355 args = 'follows_user_id='+fallows_user_id;
355 args = 'follows_user_id='+fallows_user_id;
356 args+= '&auth_token='+token;
356 args+= '&amp;auth_token='+token;
357 YUC.asyncRequest('POST',base_url,{
357 YUC.asyncRequest('POST',base_url,{
358 success:function(o){
358 success:function(o){
359 onSuccess();
359 onSuccess();
360 }
360 }
361 },args); return false;
361 },args); return false;
362 }
362 }
363
363
364 function toggleFollowingRepo(fallows_repo_id,token){
364 function toggleFollowingRepo(fallows_repo_id,token){
365 args = 'follows_repo_id='+fallows_repo_id;
365 args = 'follows_repo_id='+fallows_repo_id;
366 args+= '&auth_token='+token;
366 args+= '&amp;auth_token='+token;
367 YUC.asyncRequest('POST',base_url,{
367 YUC.asyncRequest('POST',base_url,{
368 success:function(o){
368 success:function(o){
369 onSuccess();
369 onSuccess();
370 }
370 }
371 },args); return false;
371 },args); return false;
372 }
372 }
373 </script>
373 </script>
374
374
375 </%def>
375 </%def>
376
376
377 <%def name="breadcrumbs()">
377 <%def name="breadcrumbs()">
378 <div class="breadcrumbs">
378 <div class="breadcrumbs">
379 ${self.breadcrumbs_links()}
379 ${self.breadcrumbs_links()}
380 </div>
380 </div>
381 </%def> No newline at end of file
381 </%def>
@@ -1,168 +1,168
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 ${_('Dashboard')} - ${c.rhodecode_name}
4 ${_('Dashboard')} - ${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 <%def name="get_sort(name)">
13 <%def name="get_sort(name)">
14 <%name_slug = name.lower().replace(' ','_') %>
14 <%name_slug = name.lower().replace(' ','_') %>
15
15
16 %if name_slug == c.sort_slug:
16 %if name_slug == c.sort_slug:
17 %if c.sort_by.startswith('-'):
17 %if c.sort_by.startswith('-'):
18 <a href="?sort=${name_slug}">${name}&uarr;</a>
18 <a href="?sort=${name_slug}">${name}&uarr;</a>
19 %else:
19 %else:
20 <a href="?sort=-${name_slug}">${name}&darr;</a>
20 <a href="?sort=-${name_slug}">${name}&darr;</a>
21 %endif:
21 %endif:
22 %else:
22 %else:
23 <a href="?sort=${name_slug}">${name}</a>
23 <a href="?sort=${name_slug}">${name}</a>
24 %endif
24 %endif
25 </%def>
25 </%def>
26
26
27 <div class="box">
27 <div class="box">
28 <!-- box / title -->
28 <!-- box / title -->
29 <div class="title">
29 <div class="title">
30 <h5>${_('Dashboard')}
30 <h5>${_('Dashboard')}
31 <input class="top-right-rounded-corner top-left-rounded-corner bottom-left-rounded-corner bottom-right-rounded-corner" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/>
31 <input class="top-right-rounded-corner top-left-rounded-corner bottom-left-rounded-corner bottom-right-rounded-corner" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/>
32 </h5>
32 </h5>
33 %if c.rhodecode_user.username != 'default':
33 %if c.rhodecode_user.username != 'default':
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 NEW REPOSITORY'),h.url('admin_settings_create_repository'))}</span>
37 <span>${h.link_to(_('ADD NEW REPOSITORY'),h.url('admin_settings_create_repository'))}</span>
38 </li>
38 </li>
39 </ul>
39 </ul>
40 %endif
40 %endif
41 %endif
41 %endif
42 </div>
42 </div>
43 <!-- end box / title -->
43 <!-- end box / title -->
44 <div class="table">
44 <div class="table">
45 <table>
45 <table>
46 <thead>
46 <thead>
47 <tr>
47 <tr>
48 <th class="left">${get_sort(_('Name'))}</th>
48 <th class="left">${get_sort(_('Name'))}</th>
49 <th class="left">${get_sort(_('Description'))}</th>
49 <th class="left">${get_sort(_('Description'))}</th>
50 <th class="left">${get_sort(_('Last change'))}</th>
50 <th class="left">${get_sort(_('Last change'))}</th>
51 <th class="left">${get_sort(_('Tip'))}</th>
51 <th class="left">${get_sort(_('Tip'))}</th>
52 <th class="left">${get_sort(_('Owner'))}</th>
52 <th class="left">${get_sort(_('Owner'))}</th>
53 <th class="left">${_('RSS')}</th>
53 <th class="left">${_('RSS')}</th>
54 <th class="left">${_('Atom')}</th>
54 <th class="left">${_('Atom')}</th>
55 </tr>
55 </tr>
56 </thead>
56 </thead>
57 <tbody>
57 <tbody>
58 %for cnt,repo in enumerate(c.repos_list):
58 %for cnt,repo in enumerate(c.repos_list):
59 <tr class="parity${cnt%2}">
59 <tr class="parity${cnt%2}">
60 <td>
60 <td>
61 <div style="white-space: nowrap">
61 <div style="white-space: nowrap">
62 ## TYPE OF REPO
62 ## TYPE OF REPO
63 %if repo['repo'].dbrepo.repo_type =='hg':
63 %if repo['repo'].dbrepo.repo_type =='hg':
64 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
64 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
65 %elif repo['repo'].dbrepo.repo_type =='git':
65 %elif repo['repo'].dbrepo.repo_type =='git':
66 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
66 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
67 %else:
67 %else:
68
68
69 %endif
69 %endif
70
70
71 ##PRIVATE/PUBLIC
71 ##PRIVATE/PUBLIC
72 %if repo['repo'].dbrepo.private:
72 %if repo['repo'].dbrepo.private:
73 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="/images/icons/lock.png"/>
73 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="/images/icons/lock.png"/>
74 %else:
74 %else:
75 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="/images/icons/lock_open.png"/>
75 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="/images/icons/lock_open.png"/>
76 %endif
76 %endif
77
77
78 ##NAME
78 ##NAME
79 ${h.link_to(repo['name'],
79 ${h.link_to(repo['name'],
80 h.url('summary_home',repo_name=repo['name']),class_="repo_name")}
80 h.url('summary_home',repo_name=repo['name']),class_="repo_name")}
81 %if repo['repo'].dbrepo.fork:
81 %if repo['repo'].dbrepo.fork:
82 <a href="${h.url('summary_home',repo_name=repo['repo'].dbrepo.fork.repo_name)}">
82 <a href="${h.url('summary_home',repo_name=repo['repo'].dbrepo.fork.repo_name)}">
83 <img class="icon" alt="${_('fork')}"
83 <img class="icon" alt="${_('fork')}"
84 title="${_('Fork of')} ${repo['repo'].dbrepo.fork.repo_name}"
84 title="${_('Fork of')} ${repo['repo'].dbrepo.fork.repo_name}"
85 src="/images/icons/arrow_divide.png"/></a>
85 src="/images/icons/arrow_divide.png"/></a>
86 %endif
86 %endif
87 </div>
87 </div>
88 </td>
88 </td>
89 ##DESCRIPTION
89 ##DESCRIPTION
90 <td><span class="tooltip" title="${repo['description']}">
90 <td><span class="tooltip" title="${h.tooltip(repo['description'])}">
91 ${h.truncate(repo['description'],60)}</span>
91 ${h.truncate(repo['description'],60)}</span>
92 </td>
92 </td>
93 ##LAST CHANGE
93 ##LAST CHANGE
94 <td>
94 <td>
95 <span class="tooltip" title="${repo['last_change']}">
95 <span class="tooltip" title="${repo['last_change']}">
96 ${h.age(repo['last_change'])}</span>
96 ${h.age(repo['last_change'])}</span>
97 </td>
97 </td>
98 <td>
98 <td>
99 %if repo['rev']>=0:
99 %if repo['rev']>=0:
100 ${h.link_to('r%s:%s' % (repo['rev'],h.short_id(repo['tip'])),
100 ${h.link_to('r%s:%s' % (repo['rev'],h.short_id(repo['tip'])),
101 h.url('changeset_home',repo_name=repo['name'],revision=repo['tip']),
101 h.url('changeset_home',repo_name=repo['name'],revision=repo['tip']),
102 class_="tooltip",
102 class_="tooltip",
103 title=h.tooltip(repo['last_msg']))}
103 title=h.tooltip(repo['last_msg']))}
104 %else:
104 %else:
105 ${_('No changesets yet')}
105 ${_('No changesets yet')}
106 %endif
106 %endif
107 </td>
107 </td>
108 <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
108 <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
109 <td>
109 <td>
110 <a title="${_('Subscribe to %s rss feed')%repo['name']}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=repo['name'])}"></a>
110 <a title="${_('Subscribe to %s rss feed')%repo['name']}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=repo['name'])}"></a>
111 </td>
111 </td>
112 <td>
112 <td>
113 <a title="${_('Subscribe to %s atom feed')%repo['name']}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=repo['name'])}"></a>
113 <a title="${_('Subscribe to %s atom feed')%repo['name']}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=repo['name'])}"></a>
114 </td>
114 </td>
115 </tr>
115 </tr>
116 %endfor
116 %endfor
117 </tbody>
117 </tbody>
118 </table>
118 </table>
119 </div>
119 </div>
120 </div>
120 </div>
121
121
122
122
123 <script type="text/javascript">
123 <script type="text/javascript">
124 var D = YAHOO.util.Dom;
124 var D = YAHOO.util.Dom;
125 var E = YAHOO.util.Event;
125 var E = YAHOO.util.Event;
126 var S = YAHOO.util.Selector;
126 var S = YAHOO.util.Selector;
127
127
128 var q_filter = D.get('q_filter');
128 var q_filter = D.get('q_filter');
129 var F = YAHOO.namespace('q_filter');
129 var F = YAHOO.namespace('q_filter');
130
130
131 E.on(q_filter,'click',function(){
131 E.on(q_filter,'click',function(){
132 q_filter.value = '';
132 q_filter.value = '';
133 });
133 });
134
134
135 F.filterTimeout = null;
135 F.filterTimeout = null;
136
136
137 F.updateFilter = function() {
137 F.updateFilter = function() {
138 // Reset timeout
138 // Reset timeout
139 F.filterTimeout = null;
139 F.filterTimeout = null;
140
140
141 var obsolete = [];
141 var obsolete = [];
142 var nodes = S.query('div.table tr td div a.repo_name');
142 var nodes = S.query('div.table tr td div a.repo_name');
143 var req = D.get('q_filter').value;
143 var req = D.get('q_filter').value;
144 for (n in nodes){
144 for (n in nodes){
145 D.setStyle(nodes[n].parentNode.parentNode.parentNode,'display','')
145 D.setStyle(nodes[n].parentNode.parentNode.parentNode,'display','')
146 }
146 }
147 if (req){
147 if (req){
148 for (n in nodes){
148 for (n in nodes){
149 if (nodes[n].innerHTML.toLowerCase().indexOf(req) == -1) {
149 if (nodes[n].innerHTML.toLowerCase().indexOf(req) == -1) {
150 obsolete.push(nodes[n]);
150 obsolete.push(nodes[n]);
151 }
151 }
152 }
152 }
153 if(obsolete){
153 if(obsolete){
154 for (n in obsolete){
154 for (n in obsolete){
155 D.setStyle(obsolete[n].parentNode.parentNode.parentNode,'display','none');
155 D.setStyle(obsolete[n].parentNode.parentNode.parentNode,'display','none');
156 }
156 }
157 }
157 }
158 }
158 }
159 }
159 }
160
160
161 E.on(q_filter,'keyup',function(e){
161 E.on(q_filter,'keyup',function(e){
162 clearTimeout(F.filterTimeout);
162 clearTimeout(F.filterTimeout);
163 setTimeout(F.updateFilter,600);
163 setTimeout(F.updateFilter,600);
164 });
164 });
165
165
166 </script>
166 </script>
167
167
168 </%def>
168 </%def>
General Comments 0
You need to be logged in to leave comments. Login now