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