##// END OF EJS Templates
implements #293 gravatar link should be disabled when use_gravatar = false
marcink -
r1629:2196aa27 beta
parent child Browse files
Show More
@@ -1,91 +1,93 b''
1 """The base Controller API
1 """The base Controller API
2
2
3 Provides the BaseController class for subclassing.
3 Provides the BaseController class for subclassing.
4 """
4 """
5 import logging
5 import logging
6 import time
6 import time
7 from pylons import config, tmpl_context as c, request, session, url
7 from pylons import config, tmpl_context as c, request, session, url
8 from pylons.controllers import WSGIController
8 from pylons.controllers import WSGIController
9 from pylons.controllers.util import redirect
9 from pylons.controllers.util import redirect
10 from pylons.templating import render_mako as render
10 from pylons.templating import render_mako as render
11 from paste.deploy.converters import asbool
11 from paste.deploy.converters import asbool
12
12
13 from rhodecode import __version__
13 from rhodecode import __version__
14 from rhodecode.lib import str2bool
14 from rhodecode.lib.auth import AuthUser, get_container_username
15 from rhodecode.lib.auth import AuthUser, get_container_username
15 from rhodecode.lib.utils import get_repo_slug
16 from rhodecode.lib.utils import get_repo_slug
16 from rhodecode.model import meta
17 from rhodecode.model import meta
17 from rhodecode.model.scm import ScmModel
18 from rhodecode.model.scm import ScmModel
18 from rhodecode import BACKENDS
19 from rhodecode import BACKENDS
19 from rhodecode.model.db import Repository
20 from rhodecode.model.db import Repository
20
21
21 log = logging.getLogger(__name__)
22 log = logging.getLogger(__name__)
22
23
23 class BaseController(WSGIController):
24 class BaseController(WSGIController):
24
25
25 def __before__(self):
26 def __before__(self):
26 c.rhodecode_version = __version__
27 c.rhodecode_version = __version__
27 c.rhodecode_name = config.get('rhodecode_title')
28 c.rhodecode_name = config.get('rhodecode_title')
29 c.use_gravatar = str2bool(config.get('use_gravatar'))
28 c.ga_code = config.get('rhodecode_ga_code')
30 c.ga_code = config.get('rhodecode_ga_code')
29 c.repo_name = get_repo_slug(request)
31 c.repo_name = get_repo_slug(request)
30 c.backends = BACKENDS.keys()
32 c.backends = BACKENDS.keys()
31 self.cut_off_limit = int(config.get('cut_off_limit'))
33 self.cut_off_limit = int(config.get('cut_off_limit'))
32
34
33 self.sa = meta.Session()
35 self.sa = meta.Session()
34 self.scm_model = ScmModel(self.sa)
36 self.scm_model = ScmModel(self.sa)
35
37
36 def __call__(self, environ, start_response):
38 def __call__(self, environ, start_response):
37 """Invoke the Controller"""
39 """Invoke the Controller"""
38 # WSGIController.__call__ dispatches to the Controller method
40 # WSGIController.__call__ dispatches to the Controller method
39 # the request is routed to. This routing information is
41 # the request is routed to. This routing information is
40 # available in environ['pylons.routes_dict']
42 # available in environ['pylons.routes_dict']
41 start = time.time()
43 start = time.time()
42 try:
44 try:
43 # make sure that we update permissions each time we call controller
45 # make sure that we update permissions each time we call controller
44 api_key = request.GET.get('api_key')
46 api_key = request.GET.get('api_key')
45 user_id = getattr(session.get('rhodecode_user'), 'user_id', None)
47 user_id = getattr(session.get('rhodecode_user'), 'user_id', None)
46 if asbool(config.get('container_auth_enabled', False)):
48 if asbool(config.get('container_auth_enabled', False)):
47 username = get_container_username(environ)
49 username = get_container_username(environ)
48 else:
50 else:
49 username = None
51 username = None
50 auth_user = AuthUser(user_id, api_key, username)
52 auth_user = AuthUser(user_id, api_key, username)
51 self.rhodecode_user = c.rhodecode_user = auth_user
53 self.rhodecode_user = c.rhodecode_user = auth_user
52 if not self.rhodecode_user.is_authenticated and \
54 if not self.rhodecode_user.is_authenticated and \
53 self.rhodecode_user.user_id is not None:
55 self.rhodecode_user.user_id is not None:
54 self.rhodecode_user.set_authenticated(
56 self.rhodecode_user.set_authenticated(
55 getattr(session.get('rhodecode_user'),
57 getattr(session.get('rhodecode_user'),
56 'is_authenticated', False))
58 'is_authenticated', False))
57 session['rhodecode_user'] = self.rhodecode_user
59 session['rhodecode_user'] = self.rhodecode_user
58 session.save()
60 session.save()
59 return WSGIController.__call__(self, environ, start_response)
61 return WSGIController.__call__(self, environ, start_response)
60 finally:
62 finally:
61 log.debug('Request time: %.3fs' % (time.time()-start))
63 log.debug('Request time: %.3fs' % (time.time()-start))
62 meta.Session.remove()
64 meta.Session.remove()
63
65
64
66
65 class BaseRepoController(BaseController):
67 class BaseRepoController(BaseController):
66 """
68 """
67 Base class for controllers responsible for loading all needed data for
69 Base class for controllers responsible for loading all needed data for
68 repository loaded items are
70 repository loaded items are
69
71
70 c.rhodecode_repo: instance of scm repository
72 c.rhodecode_repo: instance of scm repository
71 c.rhodecode_db_repo: instance of db
73 c.rhodecode_db_repo: instance of db
72 c.repository_followers: number of followers
74 c.repository_followers: number of followers
73 c.repository_forks: number of forks
75 c.repository_forks: number of forks
74 """
76 """
75
77
76 def __before__(self):
78 def __before__(self):
77 super(BaseRepoController, self).__before__()
79 super(BaseRepoController, self).__before__()
78 if c.repo_name:
80 if c.repo_name:
79
81
80 c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
82 c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
81 c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
83 c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
82
84
83 if c.rhodecode_repo is None:
85 if c.rhodecode_repo is None:
84 log.error('%s this repository is present in database but it '
86 log.error('%s this repository is present in database but it '
85 'cannot be created as an scm instance', c.repo_name)
87 'cannot be created as an scm instance', c.repo_name)
86
88
87 redirect(url('home'))
89 redirect(url('home'))
88
90
89 c.repository_followers = self.scm_model.get_followers(c.repo_name)
91 c.repository_followers = self.scm_model.get_followers(c.repo_name)
90 c.repository_forks = self.scm_model.get_forks(c.repo_name)
92 c.repository_forks = self.scm_model.get_forks(c.repo_name)
91
93
@@ -1,673 +1,672 b''
1 """Helper functions
1 """Helper functions
2
2
3 Consists of functions to typically be used within templates, but also
3 Consists of functions to typically be used within templates, but also
4 available to Controllers. This module is available to both as 'h'.
4 available to Controllers. This module is available to both as 'h'.
5 """
5 """
6 import random
6 import random
7 import hashlib
7 import hashlib
8 import StringIO
8 import StringIO
9 import urllib
9 import urllib
10 import math
10 import math
11
11
12 from datetime import datetime
12 from datetime import datetime
13 from pygments.formatters import HtmlFormatter
13 from pygments.formatters import HtmlFormatter
14 from pygments import highlight as code_highlight
14 from pygments import highlight as code_highlight
15 from pylons import url, request, config
15 from pylons import url, request, config
16 from pylons.i18n.translation import _, ungettext
16 from pylons.i18n.translation import _, ungettext
17
17
18 from webhelpers.html import literal, HTML, escape
18 from webhelpers.html import literal, HTML, escape
19 from webhelpers.html.tools import *
19 from webhelpers.html.tools import *
20 from webhelpers.html.builder import make_tag
20 from webhelpers.html.builder import make_tag
21 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
21 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
22 end_form, file, form, hidden, image, javascript_link, link_to, link_to_if, \
22 end_form, file, form, hidden, image, javascript_link, link_to, link_to_if, \
23 link_to_unless, ol, required_legend, select, stylesheet_link, submit, text, \
23 link_to_unless, ol, required_legend, select, stylesheet_link, submit, text, \
24 password, textarea, title, ul, xml_declaration, radio
24 password, textarea, title, ul, xml_declaration, radio
25 from webhelpers.html.tools import auto_link, button_to, highlight, js_obfuscate, \
25 from webhelpers.html.tools import auto_link, button_to, highlight, js_obfuscate, \
26 mail_to, strip_links, strip_tags, tag_re
26 mail_to, strip_links, strip_tags, tag_re
27 from webhelpers.number import format_byte_size, format_bit_size
27 from webhelpers.number import format_byte_size, format_bit_size
28 from webhelpers.pylonslib import Flash as _Flash
28 from webhelpers.pylonslib import Flash as _Flash
29 from webhelpers.pylonslib.secure_form import secure_form
29 from webhelpers.pylonslib.secure_form import secure_form
30 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
30 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
31 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
31 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
32 replace_whitespace, urlify, truncate, wrap_paragraphs
32 replace_whitespace, urlify, truncate, wrap_paragraphs
33 from webhelpers.date import time_ago_in_words
33 from webhelpers.date import time_ago_in_words
34 from webhelpers.paginate import Page
34 from webhelpers.paginate import Page
35 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
35 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
36 convert_boolean_attrs, NotGiven
36 convert_boolean_attrs, NotGiven
37
37
38 from vcs.utils.annotate import annotate_highlight
38 from vcs.utils.annotate import annotate_highlight
39 from rhodecode.lib.utils import repo_name_slug
39 from rhodecode.lib.utils import repo_name_slug
40 from rhodecode.lib import str2bool, safe_unicode, safe_str,get_changeset_safe
40 from rhodecode.lib import str2bool, safe_unicode, safe_str,get_changeset_safe
41
41
42 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
42 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
43 """
43 """
44 Reset button
44 Reset button
45 """
45 """
46 _set_input_attrs(attrs, type, name, value)
46 _set_input_attrs(attrs, type, name, value)
47 _set_id_attr(attrs, id, name)
47 _set_id_attr(attrs, id, name)
48 convert_boolean_attrs(attrs, ["disabled"])
48 convert_boolean_attrs(attrs, ["disabled"])
49 return HTML.input(**attrs)
49 return HTML.input(**attrs)
50
50
51 reset = _reset
51 reset = _reset
52
52
53
53
54 def get_token():
54 def get_token():
55 """Return the current authentication token, creating one if one doesn't
55 """Return the current authentication token, creating one if one doesn't
56 already exist.
56 already exist.
57 """
57 """
58 token_key = "_authentication_token"
58 token_key = "_authentication_token"
59 from pylons import session
59 from pylons import session
60 if not token_key in session:
60 if not token_key in session:
61 try:
61 try:
62 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
62 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
63 except AttributeError: # Python < 2.4
63 except AttributeError: # Python < 2.4
64 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
64 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
65 session[token_key] = token
65 session[token_key] = token
66 if hasattr(session, 'save'):
66 if hasattr(session, 'save'):
67 session.save()
67 session.save()
68 return session[token_key]
68 return session[token_key]
69
69
70 class _GetError(object):
70 class _GetError(object):
71 """Get error from form_errors, and represent it as span wrapped error
71 """Get error from form_errors, and represent it as span wrapped error
72 message
72 message
73
73
74 :param field_name: field to fetch errors for
74 :param field_name: field to fetch errors for
75 :param form_errors: form errors dict
75 :param form_errors: form errors dict
76 """
76 """
77
77
78 def __call__(self, field_name, form_errors):
78 def __call__(self, field_name, form_errors):
79 tmpl = """<span class="error_msg">%s</span>"""
79 tmpl = """<span class="error_msg">%s</span>"""
80 if form_errors and form_errors.has_key(field_name):
80 if form_errors and form_errors.has_key(field_name):
81 return literal(tmpl % form_errors.get(field_name))
81 return literal(tmpl % form_errors.get(field_name))
82
82
83 get_error = _GetError()
83 get_error = _GetError()
84
84
85 class _ToolTip(object):
85 class _ToolTip(object):
86
86
87 def __call__(self, tooltip_title, trim_at=50):
87 def __call__(self, tooltip_title, trim_at=50):
88 """Special function just to wrap our text into nice formatted
88 """Special function just to wrap our text into nice formatted
89 autowrapped text
89 autowrapped text
90
90
91 :param tooltip_title:
91 :param tooltip_title:
92 """
92 """
93 return escape(tooltip_title)
93 return escape(tooltip_title)
94 tooltip = _ToolTip()
94 tooltip = _ToolTip()
95
95
96 class _FilesBreadCrumbs(object):
96 class _FilesBreadCrumbs(object):
97
97
98 def __call__(self, repo_name, rev, paths):
98 def __call__(self, repo_name, rev, paths):
99 if isinstance(paths, str):
99 if isinstance(paths, str):
100 paths = safe_unicode(paths)
100 paths = safe_unicode(paths)
101 url_l = [link_to(repo_name, url('files_home',
101 url_l = [link_to(repo_name, url('files_home',
102 repo_name=repo_name,
102 repo_name=repo_name,
103 revision=rev, f_path=''))]
103 revision=rev, f_path=''))]
104 paths_l = paths.split('/')
104 paths_l = paths.split('/')
105 for cnt, p in enumerate(paths_l):
105 for cnt, p in enumerate(paths_l):
106 if p != '':
106 if p != '':
107 url_l.append(link_to(p, url('files_home',
107 url_l.append(link_to(p, url('files_home',
108 repo_name=repo_name,
108 repo_name=repo_name,
109 revision=rev,
109 revision=rev,
110 f_path='/'.join(paths_l[:cnt + 1]))))
110 f_path='/'.join(paths_l[:cnt + 1]))))
111
111
112 return literal('/'.join(url_l))
112 return literal('/'.join(url_l))
113
113
114 files_breadcrumbs = _FilesBreadCrumbs()
114 files_breadcrumbs = _FilesBreadCrumbs()
115
115
116 class CodeHtmlFormatter(HtmlFormatter):
116 class CodeHtmlFormatter(HtmlFormatter):
117 """My code Html Formatter for source codes
117 """My code Html Formatter for source codes
118 """
118 """
119
119
120 def wrap(self, source, outfile):
120 def wrap(self, source, outfile):
121 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
121 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
122
122
123 def _wrap_code(self, source):
123 def _wrap_code(self, source):
124 for cnt, it in enumerate(source):
124 for cnt, it in enumerate(source):
125 i, t = it
125 i, t = it
126 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
126 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
127 yield i, t
127 yield i, t
128
128
129 def _wrap_tablelinenos(self, inner):
129 def _wrap_tablelinenos(self, inner):
130 dummyoutfile = StringIO.StringIO()
130 dummyoutfile = StringIO.StringIO()
131 lncount = 0
131 lncount = 0
132 for t, line in inner:
132 for t, line in inner:
133 if t:
133 if t:
134 lncount += 1
134 lncount += 1
135 dummyoutfile.write(line)
135 dummyoutfile.write(line)
136
136
137 fl = self.linenostart
137 fl = self.linenostart
138 mw = len(str(lncount + fl - 1))
138 mw = len(str(lncount + fl - 1))
139 sp = self.linenospecial
139 sp = self.linenospecial
140 st = self.linenostep
140 st = self.linenostep
141 la = self.lineanchors
141 la = self.lineanchors
142 aln = self.anchorlinenos
142 aln = self.anchorlinenos
143 nocls = self.noclasses
143 nocls = self.noclasses
144 if sp:
144 if sp:
145 lines = []
145 lines = []
146
146
147 for i in range(fl, fl + lncount):
147 for i in range(fl, fl + lncount):
148 if i % st == 0:
148 if i % st == 0:
149 if i % sp == 0:
149 if i % sp == 0:
150 if aln:
150 if aln:
151 lines.append('<a href="#%s%d" class="special">%*d</a>' %
151 lines.append('<a href="#%s%d" class="special">%*d</a>' %
152 (la, i, mw, i))
152 (la, i, mw, i))
153 else:
153 else:
154 lines.append('<span class="special">%*d</span>' % (mw, i))
154 lines.append('<span class="special">%*d</span>' % (mw, i))
155 else:
155 else:
156 if aln:
156 if aln:
157 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
157 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
158 else:
158 else:
159 lines.append('%*d' % (mw, i))
159 lines.append('%*d' % (mw, i))
160 else:
160 else:
161 lines.append('')
161 lines.append('')
162 ls = '\n'.join(lines)
162 ls = '\n'.join(lines)
163 else:
163 else:
164 lines = []
164 lines = []
165 for i in range(fl, fl + lncount):
165 for i in range(fl, fl + lncount):
166 if i % st == 0:
166 if i % st == 0:
167 if aln:
167 if aln:
168 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
168 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
169 else:
169 else:
170 lines.append('%*d' % (mw, i))
170 lines.append('%*d' % (mw, i))
171 else:
171 else:
172 lines.append('')
172 lines.append('')
173 ls = '\n'.join(lines)
173 ls = '\n'.join(lines)
174
174
175 # in case you wonder about the seemingly redundant <div> here: since the
175 # in case you wonder about the seemingly redundant <div> here: since the
176 # content in the other cell also is wrapped in a div, some browsers in
176 # content in the other cell also is wrapped in a div, some browsers in
177 # some configurations seem to mess up the formatting...
177 # some configurations seem to mess up the formatting...
178 if nocls:
178 if nocls:
179 yield 0, ('<table class="%stable">' % self.cssclass +
179 yield 0, ('<table class="%stable">' % self.cssclass +
180 '<tr><td><div class="linenodiv" '
180 '<tr><td><div class="linenodiv" '
181 'style="background-color: #f0f0f0; padding-right: 10px">'
181 'style="background-color: #f0f0f0; padding-right: 10px">'
182 '<pre style="line-height: 125%">' +
182 '<pre style="line-height: 125%">' +
183 ls + '</pre></div></td><td id="hlcode" class="code">')
183 ls + '</pre></div></td><td id="hlcode" class="code">')
184 else:
184 else:
185 yield 0, ('<table class="%stable">' % self.cssclass +
185 yield 0, ('<table class="%stable">' % self.cssclass +
186 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
186 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
187 ls + '</pre></div></td><td id="hlcode" class="code">')
187 ls + '</pre></div></td><td id="hlcode" class="code">')
188 yield 0, dummyoutfile.getvalue()
188 yield 0, dummyoutfile.getvalue()
189 yield 0, '</td></tr></table>'
189 yield 0, '</td></tr></table>'
190
190
191
191
192 def pygmentize(filenode, **kwargs):
192 def pygmentize(filenode, **kwargs):
193 """pygmentize function using pygments
193 """pygmentize function using pygments
194
194
195 :param filenode:
195 :param filenode:
196 """
196 """
197
197
198 return literal(code_highlight(filenode.content,
198 return literal(code_highlight(filenode.content,
199 filenode.lexer, CodeHtmlFormatter(**kwargs)))
199 filenode.lexer, CodeHtmlFormatter(**kwargs)))
200
200
201 def pygmentize_annotation(repo_name, filenode, **kwargs):
201 def pygmentize_annotation(repo_name, filenode, **kwargs):
202 """pygmentize function for annotation
202 """pygmentize function for annotation
203
203
204 :param filenode:
204 :param filenode:
205 """
205 """
206
206
207 color_dict = {}
207 color_dict = {}
208 def gen_color(n=10000):
208 def gen_color(n=10000):
209 """generator for getting n of evenly distributed colors using
209 """generator for getting n of evenly distributed colors using
210 hsv color and golden ratio. It always return same order of colors
210 hsv color and golden ratio. It always return same order of colors
211
211
212 :returns: RGB tuple
212 :returns: RGB tuple
213 """
213 """
214
214
215 def hsv_to_rgb(h, s, v):
215 def hsv_to_rgb(h, s, v):
216 if s == 0.0: return v, v, v
216 if s == 0.0: return v, v, v
217 i = int(h * 6.0) # XXX assume int() truncates!
217 i = int(h * 6.0) # XXX assume int() truncates!
218 f = (h * 6.0) - i
218 f = (h * 6.0) - i
219 p = v * (1.0 - s)
219 p = v * (1.0 - s)
220 q = v * (1.0 - s * f)
220 q = v * (1.0 - s * f)
221 t = v * (1.0 - s * (1.0 - f))
221 t = v * (1.0 - s * (1.0 - f))
222 i = i % 6
222 i = i % 6
223 if i == 0: return v, t, p
223 if i == 0: return v, t, p
224 if i == 1: return q, v, p
224 if i == 1: return q, v, p
225 if i == 2: return p, v, t
225 if i == 2: return p, v, t
226 if i == 3: return p, q, v
226 if i == 3: return p, q, v
227 if i == 4: return t, p, v
227 if i == 4: return t, p, v
228 if i == 5: return v, p, q
228 if i == 5: return v, p, q
229
229
230 golden_ratio = 0.618033988749895
230 golden_ratio = 0.618033988749895
231 h = 0.22717784590367374
231 h = 0.22717784590367374
232
232
233 for _ in xrange(n):
233 for _ in xrange(n):
234 h += golden_ratio
234 h += golden_ratio
235 h %= 1
235 h %= 1
236 HSV_tuple = [h, 0.95, 0.95]
236 HSV_tuple = [h, 0.95, 0.95]
237 RGB_tuple = hsv_to_rgb(*HSV_tuple)
237 RGB_tuple = hsv_to_rgb(*HSV_tuple)
238 yield map(lambda x:str(int(x * 256)), RGB_tuple)
238 yield map(lambda x:str(int(x * 256)), RGB_tuple)
239
239
240 cgenerator = gen_color()
240 cgenerator = gen_color()
241
241
242 def get_color_string(cs):
242 def get_color_string(cs):
243 if color_dict.has_key(cs):
243 if color_dict.has_key(cs):
244 col = color_dict[cs]
244 col = color_dict[cs]
245 else:
245 else:
246 col = color_dict[cs] = cgenerator.next()
246 col = color_dict[cs] = cgenerator.next()
247 return "color: rgb(%s)! important;" % (', '.join(col))
247 return "color: rgb(%s)! important;" % (', '.join(col))
248
248
249 def url_func(repo_name):
249 def url_func(repo_name):
250
250
251 def _url_func(changeset):
251 def _url_func(changeset):
252 author = changeset.author
252 author = changeset.author
253 date = changeset.date
253 date = changeset.date
254 message = tooltip(changeset.message)
254 message = tooltip(changeset.message)
255
255
256 tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>"
256 tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>"
257 " %s<br/><b>Date:</b> %s</b><br/><b>Message:"
257 " %s<br/><b>Date:</b> %s</b><br/><b>Message:"
258 "</b> %s<br/></div>")
258 "</b> %s<br/></div>")
259
259
260 tooltip_html = tooltip_html % (author, date, message)
260 tooltip_html = tooltip_html % (author, date, message)
261 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
261 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
262 short_id(changeset.raw_id))
262 short_id(changeset.raw_id))
263 uri = link_to(
263 uri = link_to(
264 lnk_format,
264 lnk_format,
265 url('changeset_home', repo_name=repo_name,
265 url('changeset_home', repo_name=repo_name,
266 revision=changeset.raw_id),
266 revision=changeset.raw_id),
267 style=get_color_string(changeset.raw_id),
267 style=get_color_string(changeset.raw_id),
268 class_='tooltip',
268 class_='tooltip',
269 title=tooltip_html
269 title=tooltip_html
270 )
270 )
271
271
272 uri += '\n'
272 uri += '\n'
273 return uri
273 return uri
274 return _url_func
274 return _url_func
275
275
276 return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs))
276 return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs))
277
277
278 def is_following_repo(repo_name, user_id):
278 def is_following_repo(repo_name, user_id):
279 from rhodecode.model.scm import ScmModel
279 from rhodecode.model.scm import ScmModel
280 return ScmModel().is_following_repo(repo_name, user_id)
280 return ScmModel().is_following_repo(repo_name, user_id)
281
281
282 flash = _Flash()
282 flash = _Flash()
283
283
284 #==============================================================================
284 #==============================================================================
285 # SCM FILTERS available via h.
285 # SCM FILTERS available via h.
286 #==============================================================================
286 #==============================================================================
287 from vcs.utils import author_name, author_email
287 from vcs.utils import author_name, author_email
288 from rhodecode.lib import credentials_filter, age as _age
288 from rhodecode.lib import credentials_filter, age as _age
289
289
290 age = lambda x:_age(x)
290 age = lambda x:_age(x)
291 capitalize = lambda x: x.capitalize()
291 capitalize = lambda x: x.capitalize()
292 email = author_email
292 email = author_email
293 email_or_none = lambda x: email(x) if email(x) != x else None
293 email_or_none = lambda x: email(x) if email(x) != x else None
294 person = lambda x: author_name(x)
294 person = lambda x: author_name(x)
295 short_id = lambda x: x[:12]
295 short_id = lambda x: x[:12]
296 hide_credentials = lambda x: ''.join(credentials_filter(x))
296 hide_credentials = lambda x: ''.join(credentials_filter(x))
297
297
298 def bool2icon(value):
298 def bool2icon(value):
299 """Returns True/False values represented as small html image of true/false
299 """Returns True/False values represented as small html image of true/false
300 icons
300 icons
301
301
302 :param value: bool value
302 :param value: bool value
303 """
303 """
304
304
305 if value is True:
305 if value is True:
306 return HTML.tag('img', src=url("/images/icons/accept.png"),
306 return HTML.tag('img', src=url("/images/icons/accept.png"),
307 alt=_('True'))
307 alt=_('True'))
308
308
309 if value is False:
309 if value is False:
310 return HTML.tag('img', src=url("/images/icons/cancel.png"),
310 return HTML.tag('img', src=url("/images/icons/cancel.png"),
311 alt=_('False'))
311 alt=_('False'))
312
312
313 return value
313 return value
314
314
315
315
316 def action_parser(user_log, feed=False):
316 def action_parser(user_log, feed=False):
317 """This helper will action_map the specified string action into translated
317 """This helper will action_map the specified string action into translated
318 fancy names with icons and links
318 fancy names with icons and links
319
319
320 :param user_log: user log instance
320 :param user_log: user log instance
321 :param feed: use output for feeds (no html and fancy icons)
321 :param feed: use output for feeds (no html and fancy icons)
322 """
322 """
323
323
324 action = user_log.action
324 action = user_log.action
325 action_params = ' '
325 action_params = ' '
326
326
327 x = action.split(':')
327 x = action.split(':')
328
328
329 if len(x) > 1:
329 if len(x) > 1:
330 action, action_params = x
330 action, action_params = x
331
331
332 def get_cs_links():
332 def get_cs_links():
333 revs_limit = 3 #display this amount always
333 revs_limit = 3 #display this amount always
334 revs_top_limit = 50 #show upto this amount of changesets hidden
334 revs_top_limit = 50 #show upto this amount of changesets hidden
335 revs = action_params.split(',')
335 revs = action_params.split(',')
336 repo_name = user_log.repository.repo_name
336 repo_name = user_log.repository.repo_name
337
337
338 from rhodecode.model.scm import ScmModel
338 from rhodecode.model.scm import ScmModel
339 repo = user_log.repository.scm_instance
339 repo = user_log.repository.scm_instance
340
340
341 message = lambda rev: get_changeset_safe(repo, rev).message
341 message = lambda rev: get_changeset_safe(repo, rev).message
342 cs_links = []
342 cs_links = []
343 cs_links.append(" " + ', '.join ([link_to(rev,
343 cs_links.append(" " + ', '.join ([link_to(rev,
344 url('changeset_home',
344 url('changeset_home',
345 repo_name=repo_name,
345 repo_name=repo_name,
346 revision=rev), title=tooltip(message(rev)),
346 revision=rev), title=tooltip(message(rev)),
347 class_='tooltip') for rev in revs[:revs_limit] ]))
347 class_='tooltip') for rev in revs[:revs_limit] ]))
348
348
349 compare_view = (' <div class="compare_view tooltip" title="%s">'
349 compare_view = (' <div class="compare_view tooltip" title="%s">'
350 '<a href="%s">%s</a> '
350 '<a href="%s">%s</a> '
351 '</div>' % (_('Show all combined changesets %s->%s' \
351 '</div>' % (_('Show all combined changesets %s->%s' \
352 % (revs[0], revs[-1])),
352 % (revs[0], revs[-1])),
353 url('changeset_home', repo_name=repo_name,
353 url('changeset_home', repo_name=repo_name,
354 revision='%s...%s' % (revs[0], revs[-1])
354 revision='%s...%s' % (revs[0], revs[-1])
355 ),
355 ),
356 _('compare view'))
356 _('compare view'))
357 )
357 )
358
358
359 if len(revs) > revs_limit:
359 if len(revs) > revs_limit:
360 uniq_id = revs[0]
360 uniq_id = revs[0]
361 html_tmpl = ('<span> %s '
361 html_tmpl = ('<span> %s '
362 '<a class="show_more" id="_%s" href="#more">%s</a> '
362 '<a class="show_more" id="_%s" href="#more">%s</a> '
363 '%s</span>')
363 '%s</span>')
364 if not feed:
364 if not feed:
365 cs_links.append(html_tmpl % (_('and'), uniq_id, _('%s more') \
365 cs_links.append(html_tmpl % (_('and'), uniq_id, _('%s more') \
366 % (len(revs) - revs_limit),
366 % (len(revs) - revs_limit),
367 _('revisions')))
367 _('revisions')))
368
368
369 if not feed:
369 if not feed:
370 html_tmpl = '<span id="%s" style="display:none"> %s </span>'
370 html_tmpl = '<span id="%s" style="display:none"> %s </span>'
371 else:
371 else:
372 html_tmpl = '<span id="%s"> %s </span>'
372 html_tmpl = '<span id="%s"> %s </span>'
373
373
374 cs_links.append(html_tmpl % (uniq_id, ', '.join([link_to(rev,
374 cs_links.append(html_tmpl % (uniq_id, ', '.join([link_to(rev,
375 url('changeset_home',
375 url('changeset_home',
376 repo_name=repo_name, revision=rev),
376 repo_name=repo_name, revision=rev),
377 title=message(rev), class_='tooltip')
377 title=message(rev), class_='tooltip')
378 for rev in revs[revs_limit:revs_top_limit]])))
378 for rev in revs[revs_limit:revs_top_limit]])))
379 if len(revs) > 1:
379 if len(revs) > 1:
380 cs_links.append(compare_view)
380 cs_links.append(compare_view)
381 return ''.join(cs_links)
381 return ''.join(cs_links)
382
382
383 def get_fork_name():
383 def get_fork_name():
384 repo_name = action_params
384 repo_name = action_params
385 return _('fork name ') + str(link_to(action_params, url('summary_home',
385 return _('fork name ') + str(link_to(action_params, url('summary_home',
386 repo_name=repo_name,)))
386 repo_name=repo_name,)))
387
387
388 action_map = {'user_deleted_repo':(_('[deleted] repository'), None),
388 action_map = {'user_deleted_repo':(_('[deleted] repository'), None),
389 'user_created_repo':(_('[created] repository'), None),
389 'user_created_repo':(_('[created] repository'), None),
390 'user_forked_repo':(_('[forked] repository'), get_fork_name),
390 'user_forked_repo':(_('[forked] repository'), get_fork_name),
391 'user_updated_repo':(_('[updated] repository'), None),
391 'user_updated_repo':(_('[updated] repository'), None),
392 'admin_deleted_repo':(_('[delete] repository'), None),
392 'admin_deleted_repo':(_('[delete] repository'), None),
393 'admin_created_repo':(_('[created] repository'), None),
393 'admin_created_repo':(_('[created] repository'), None),
394 'admin_forked_repo':(_('[forked] repository'), None),
394 'admin_forked_repo':(_('[forked] repository'), None),
395 'admin_updated_repo':(_('[updated] repository'), None),
395 'admin_updated_repo':(_('[updated] repository'), None),
396 'push':(_('[pushed] into'), get_cs_links),
396 'push':(_('[pushed] into'), get_cs_links),
397 'push_local':(_('[committed via RhodeCode] into'), get_cs_links),
397 'push_local':(_('[committed via RhodeCode] into'), get_cs_links),
398 'push_remote':(_('[pulled from remote] into'), get_cs_links),
398 'push_remote':(_('[pulled from remote] into'), get_cs_links),
399 'pull':(_('[pulled] from'), None),
399 'pull':(_('[pulled] from'), None),
400 'started_following_repo':(_('[started following] repository'), None),
400 'started_following_repo':(_('[started following] repository'), None),
401 'stopped_following_repo':(_('[stopped following] repository'), None),
401 'stopped_following_repo':(_('[stopped following] repository'), None),
402 }
402 }
403
403
404 action_str = action_map.get(action, action)
404 action_str = action_map.get(action, action)
405 if feed:
405 if feed:
406 action = action_str[0].replace('[', '').replace(']', '')
406 action = action_str[0].replace('[', '').replace(']', '')
407 else:
407 else:
408 action = action_str[0].replace('[', '<span class="journal_highlight">')\
408 action = action_str[0].replace('[', '<span class="journal_highlight">')\
409 .replace(']', '</span>')
409 .replace(']', '</span>')
410
410
411 action_params_func = lambda :""
411 action_params_func = lambda :""
412
412
413 if callable(action_str[1]):
413 if callable(action_str[1]):
414 action_params_func = action_str[1]
414 action_params_func = action_str[1]
415
415
416 return [literal(action), action_params_func]
416 return [literal(action), action_params_func]
417
417
418 def action_parser_icon(user_log):
418 def action_parser_icon(user_log):
419 action = user_log.action
419 action = user_log.action
420 action_params = None
420 action_params = None
421 x = action.split(':')
421 x = action.split(':')
422
422
423 if len(x) > 1:
423 if len(x) > 1:
424 action, action_params = x
424 action, action_params = x
425
425
426 tmpl = """<img src="%s%s" alt="%s"/>"""
426 tmpl = """<img src="%s%s" alt="%s"/>"""
427 map = {'user_deleted_repo':'database_delete.png',
427 map = {'user_deleted_repo':'database_delete.png',
428 'user_created_repo':'database_add.png',
428 'user_created_repo':'database_add.png',
429 'user_forked_repo':'arrow_divide.png',
429 'user_forked_repo':'arrow_divide.png',
430 'user_updated_repo':'database_edit.png',
430 'user_updated_repo':'database_edit.png',
431 'admin_deleted_repo':'database_delete.png',
431 'admin_deleted_repo':'database_delete.png',
432 'admin_created_repo':'database_add.png',
432 'admin_created_repo':'database_add.png',
433 'admin_forked_repo':'arrow_divide.png',
433 'admin_forked_repo':'arrow_divide.png',
434 'admin_updated_repo':'database_edit.png',
434 'admin_updated_repo':'database_edit.png',
435 'push':'script_add.png',
435 'push':'script_add.png',
436 'push_local':'script_edit.png',
436 'push_local':'script_edit.png',
437 'push_remote':'connect.png',
437 'push_remote':'connect.png',
438 'pull':'down_16.png',
438 'pull':'down_16.png',
439 'started_following_repo':'heart_add.png',
439 'started_following_repo':'heart_add.png',
440 'stopped_following_repo':'heart_delete.png',
440 'stopped_following_repo':'heart_delete.png',
441 }
441 }
442 return literal(tmpl % ((url('/images/icons/')),
442 return literal(tmpl % ((url('/images/icons/')),
443 map.get(action, action), action))
443 map.get(action, action), action))
444
444
445
445
446 #==============================================================================
446 #==============================================================================
447 # PERMS
447 # PERMS
448 #==============================================================================
448 #==============================================================================
449 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
449 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
450 HasRepoPermissionAny, HasRepoPermissionAll
450 HasRepoPermissionAny, HasRepoPermissionAll
451
451
452 #==============================================================================
452 #==============================================================================
453 # GRAVATAR URL
453 # GRAVATAR URL
454 #==============================================================================
454 #==============================================================================
455
455
456 def gravatar_url(email_address, size=30):
456 def gravatar_url(email_address, size=30):
457 if not str2bool(config['app_conf'].get('use_gravatar')) or \
457 if (not str2bool(config['app_conf'].get('use_gravatar')) or
458 not email_address or \
458 not email_address or email_address == 'anonymous@rhodecode.org'):
459 email_address == 'anonymous@rhodecode.org':
460 return url("/images/user%s.png" % size)
459 return url("/images/user%s.png" % size)
461
460
462 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
461 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
463 default = 'identicon'
462 default = 'identicon'
464 baseurl_nossl = "http://www.gravatar.com/avatar/"
463 baseurl_nossl = "http://www.gravatar.com/avatar/"
465 baseurl_ssl = "https://secure.gravatar.com/avatar/"
464 baseurl_ssl = "https://secure.gravatar.com/avatar/"
466 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
465 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
467
466
468 if isinstance(email_address, unicode):
467 if isinstance(email_address, unicode):
469 #hashlib crashes on unicode items
468 #hashlib crashes on unicode items
470 email_address = safe_str(email_address)
469 email_address = safe_str(email_address)
471 # construct the url
470 # construct the url
472 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
471 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
473 gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
472 gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
474
473
475 return gravatar_url
474 return gravatar_url
476
475
477
476
478 #==============================================================================
477 #==============================================================================
479 # REPO PAGER, PAGER FOR REPOSITORY
478 # REPO PAGER, PAGER FOR REPOSITORY
480 #==============================================================================
479 #==============================================================================
481 class RepoPage(Page):
480 class RepoPage(Page):
482
481
483 def __init__(self, collection, page=1, items_per_page=20,
482 def __init__(self, collection, page=1, items_per_page=20,
484 item_count=None, url=None, branch_name=None, **kwargs):
483 item_count=None, url=None, branch_name=None, **kwargs):
485
484
486 """Create a "RepoPage" instance. special pager for paging
485 """Create a "RepoPage" instance. special pager for paging
487 repository
486 repository
488 """
487 """
489 self._url_generator = url
488 self._url_generator = url
490
489
491 # Safe the kwargs class-wide so they can be used in the pager() method
490 # Safe the kwargs class-wide so they can be used in the pager() method
492 self.kwargs = kwargs
491 self.kwargs = kwargs
493
492
494 # Save a reference to the collection
493 # Save a reference to the collection
495 self.original_collection = collection
494 self.original_collection = collection
496
495
497 self.collection = collection
496 self.collection = collection
498
497
499 # The self.page is the number of the current page.
498 # The self.page is the number of the current page.
500 # The first page has the number 1!
499 # The first page has the number 1!
501 try:
500 try:
502 self.page = int(page) # make it int() if we get it as a string
501 self.page = int(page) # make it int() if we get it as a string
503 except (ValueError, TypeError):
502 except (ValueError, TypeError):
504 self.page = 1
503 self.page = 1
505
504
506 self.items_per_page = items_per_page
505 self.items_per_page = items_per_page
507
506
508 # Unless the user tells us how many items the collections has
507 # Unless the user tells us how many items the collections has
509 # we calculate that ourselves.
508 # we calculate that ourselves.
510 if item_count is not None:
509 if item_count is not None:
511 self.item_count = item_count
510 self.item_count = item_count
512 else:
511 else:
513 self.item_count = len(self.collection)
512 self.item_count = len(self.collection)
514
513
515 # Compute the number of the first and last available page
514 # Compute the number of the first and last available page
516 if self.item_count > 0:
515 if self.item_count > 0:
517 self.first_page = 1
516 self.first_page = 1
518 self.page_count = int(math.ceil(float(self.item_count) /
517 self.page_count = int(math.ceil(float(self.item_count) /
519 self.items_per_page))
518 self.items_per_page))
520 self.last_page = self.first_page + self.page_count - 1
519 self.last_page = self.first_page + self.page_count - 1
521
520
522 # Make sure that the requested page number is the range of valid pages
521 # Make sure that the requested page number is the range of valid pages
523 if self.page > self.last_page:
522 if self.page > self.last_page:
524 self.page = self.last_page
523 self.page = self.last_page
525 elif self.page < self.first_page:
524 elif self.page < self.first_page:
526 self.page = self.first_page
525 self.page = self.first_page
527
526
528 # Note: the number of items on this page can be less than
527 # Note: the number of items on this page can be less than
529 # items_per_page if the last page is not full
528 # items_per_page if the last page is not full
530 self.first_item = max(0, (self.item_count) - (self.page *
529 self.first_item = max(0, (self.item_count) - (self.page *
531 items_per_page))
530 items_per_page))
532 self.last_item = ((self.item_count - 1) - items_per_page *
531 self.last_item = ((self.item_count - 1) - items_per_page *
533 (self.page - 1))
532 (self.page - 1))
534
533
535 iterator = self.collection.get_changesets(start=self.first_item,
534 iterator = self.collection.get_changesets(start=self.first_item,
536 end=self.last_item,
535 end=self.last_item,
537 reverse=True,
536 reverse=True,
538 branch_name=branch_name)
537 branch_name=branch_name)
539 self.items = list(iterator)
538 self.items = list(iterator)
540
539
541 # Links to previous and next page
540 # Links to previous and next page
542 if self.page > self.first_page:
541 if self.page > self.first_page:
543 self.previous_page = self.page - 1
542 self.previous_page = self.page - 1
544 else:
543 else:
545 self.previous_page = None
544 self.previous_page = None
546
545
547 if self.page < self.last_page:
546 if self.page < self.last_page:
548 self.next_page = self.page + 1
547 self.next_page = self.page + 1
549 else:
548 else:
550 self.next_page = None
549 self.next_page = None
551
550
552 # No items available
551 # No items available
553 else:
552 else:
554 self.first_page = None
553 self.first_page = None
555 self.page_count = 0
554 self.page_count = 0
556 self.last_page = None
555 self.last_page = None
557 self.first_item = None
556 self.first_item = None
558 self.last_item = None
557 self.last_item = None
559 self.previous_page = None
558 self.previous_page = None
560 self.next_page = None
559 self.next_page = None
561 self.items = []
560 self.items = []
562
561
563 # This is a subclass of the 'list' type. Initialise the list now.
562 # This is a subclass of the 'list' type. Initialise the list now.
564 list.__init__(self, self.items)
563 list.__init__(self, self.items)
565
564
566
565
567 def changed_tooltip(nodes):
566 def changed_tooltip(nodes):
568 """
567 """
569 Generates a html string for changed nodes in changeset page.
568 Generates a html string for changed nodes in changeset page.
570 It limits the output to 30 entries
569 It limits the output to 30 entries
571
570
572 :param nodes: LazyNodesGenerator
571 :param nodes: LazyNodesGenerator
573 """
572 """
574 if nodes:
573 if nodes:
575 pref = ': <br/> '
574 pref = ': <br/> '
576 suf = ''
575 suf = ''
577 if len(nodes) > 30:
576 if len(nodes) > 30:
578 suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
577 suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
579 return literal(pref + '<br/> '.join([safe_unicode(x.path)
578 return literal(pref + '<br/> '.join([safe_unicode(x.path)
580 for x in nodes[:30]]) + suf)
579 for x in nodes[:30]]) + suf)
581 else:
580 else:
582 return ': ' + _('No Files')
581 return ': ' + _('No Files')
583
582
584
583
585
584
586 def repo_link(groups_and_repos):
585 def repo_link(groups_and_repos):
587 """
586 """
588 Makes a breadcrumbs link to repo within a group
587 Makes a breadcrumbs link to repo within a group
589 joins &raquo; on each group to create a fancy link
588 joins &raquo; on each group to create a fancy link
590
589
591 ex::
590 ex::
592 group >> subgroup >> repo
591 group >> subgroup >> repo
593
592
594 :param groups_and_repos:
593 :param groups_and_repos:
595 """
594 """
596 groups, repo_name = groups_and_repos
595 groups, repo_name = groups_and_repos
597
596
598 if not groups:
597 if not groups:
599 return repo_name
598 return repo_name
600 else:
599 else:
601 def make_link(group):
600 def make_link(group):
602 return link_to(group.name, url('repos_group_home',
601 return link_to(group.name, url('repos_group_home',
603 group_name=group.group_name))
602 group_name=group.group_name))
604 return literal(' &raquo; '.join(map(make_link, groups)) + \
603 return literal(' &raquo; '.join(map(make_link, groups)) + \
605 " &raquo; " + repo_name)
604 " &raquo; " + repo_name)
606
605
607 def fancy_file_stats(stats):
606 def fancy_file_stats(stats):
608 """
607 """
609 Displays a fancy two colored bar for number of added/deleted
608 Displays a fancy two colored bar for number of added/deleted
610 lines of code on file
609 lines of code on file
611
610
612 :param stats: two element list of added/deleted lines of code
611 :param stats: two element list of added/deleted lines of code
613 """
612 """
614
613
615 a, d, t = stats[0], stats[1], stats[0] + stats[1]
614 a, d, t = stats[0], stats[1], stats[0] + stats[1]
616 width = 100
615 width = 100
617 unit = float(width) / (t or 1)
616 unit = float(width) / (t or 1)
618
617
619 # needs > 9% of width to be visible or 0 to be hidden
618 # needs > 9% of width to be visible or 0 to be hidden
620 a_p = max(9, unit * a) if a > 0 else 0
619 a_p = max(9, unit * a) if a > 0 else 0
621 d_p = max(9, unit * d) if d > 0 else 0
620 d_p = max(9, unit * d) if d > 0 else 0
622 p_sum = a_p + d_p
621 p_sum = a_p + d_p
623
622
624 if p_sum > width:
623 if p_sum > width:
625 #adjust the percentage to be == 100% since we adjusted to 9
624 #adjust the percentage to be == 100% since we adjusted to 9
626 if a_p > d_p:
625 if a_p > d_p:
627 a_p = a_p - (p_sum - width)
626 a_p = a_p - (p_sum - width)
628 else:
627 else:
629 d_p = d_p - (p_sum - width)
628 d_p = d_p - (p_sum - width)
630
629
631 a_v = a if a > 0 else ''
630 a_v = a if a > 0 else ''
632 d_v = d if d > 0 else ''
631 d_v = d if d > 0 else ''
633
632
634
633
635 def cgen(l_type):
634 def cgen(l_type):
636 mapping = {'tr':'top-right-rounded-corner',
635 mapping = {'tr':'top-right-rounded-corner',
637 'tl':'top-left-rounded-corner',
636 'tl':'top-left-rounded-corner',
638 'br':'bottom-right-rounded-corner',
637 'br':'bottom-right-rounded-corner',
639 'bl':'bottom-left-rounded-corner'}
638 'bl':'bottom-left-rounded-corner'}
640 map_getter = lambda x:mapping[x]
639 map_getter = lambda x:mapping[x]
641
640
642 if l_type == 'a' and d_v:
641 if l_type == 'a' and d_v:
643 #case when added and deleted are present
642 #case when added and deleted are present
644 return ' '.join(map(map_getter, ['tl', 'bl']))
643 return ' '.join(map(map_getter, ['tl', 'bl']))
645
644
646 if l_type == 'a' and not d_v:
645 if l_type == 'a' and not d_v:
647 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
646 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
648
647
649 if l_type == 'd' and a_v:
648 if l_type == 'd' and a_v:
650 return ' '.join(map(map_getter, ['tr', 'br']))
649 return ' '.join(map(map_getter, ['tr', 'br']))
651
650
652 if l_type == 'd' and not a_v:
651 if l_type == 'd' and not a_v:
653 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
652 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
654
653
655
654
656
655
657 d_a = '<div class="added %s" style="width:%s%%">%s</div>' % (cgen('a'),
656 d_a = '<div class="added %s" style="width:%s%%">%s</div>' % (cgen('a'),
658 a_p, a_v)
657 a_p, a_v)
659 d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % (cgen('d'),
658 d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % (cgen('d'),
660 d_p, d_v)
659 d_p, d_v)
661 return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
660 return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
662
661
663
662
664 def urlify_text(text):
663 def urlify_text(text):
665 import re
664 import re
666
665
667 url_pat = re.compile(r'(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)')
666 url_pat = re.compile(r'(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)')
668
667
669 def url_func(match_obj):
668 def url_func(match_obj):
670 url_full = match_obj.groups()[0]
669 url_full = match_obj.groups()[0]
671 return '<a href="%(url)s">%(url)s</a>' % ({'url':url_full})
670 return '<a href="%(url)s">%(url)s</a>' % ({'url':url_full})
672
671
673 return literal(url_pat.sub(url_func, text))
672 return literal(url_pat.sub(url_func, text))
@@ -1,158 +1,161 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Edit user')} ${c.user.username} - ${c.rhodecode_name}
5 ${_('Edit user')} ${c.user.username} - ${c.rhodecode_name}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
9 ${h.link_to(_('Admin'),h.url('admin_home'))}
9 ${h.link_to(_('Admin'),h.url('admin_home'))}
10 &raquo;
10 &raquo;
11 ${h.link_to(_('Users'),h.url('users'))}
11 ${h.link_to(_('Users'),h.url('users'))}
12 &raquo;
12 &raquo;
13 ${_('edit')} "${c.user.username}"
13 ${_('edit')} "${c.user.username}"
14 </%def>
14 </%def>
15
15
16 <%def name="page_nav()">
16 <%def name="page_nav()">
17 ${self.menu('admin')}
17 ${self.menu('admin')}
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
21 <div class="box box-left">
21 <div class="box box-left">
22 <!-- box / title -->
22 <!-- box / title -->
23 <div class="title">
23 <div class="title">
24 ${self.breadcrumbs()}
24 ${self.breadcrumbs()}
25 </div>
25 </div>
26 <!-- end box / title -->
26 <!-- end box / title -->
27 ${h.form(url('update_user', id=c.user.user_id),method='put')}
27 ${h.form(url('update_user', id=c.user.user_id),method='put')}
28 <div class="form">
28 <div class="form">
29 <div class="field">
29 <div class="field">
30 <div class="gravatar_box">
30 <div class="gravatar_box">
31 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
31 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
32 <p>
32 <p>
33 <strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong><br/>
33 %if c.use_gravatar:
34 ${_('Using')} ${c.user.email}
34 <strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong>
35 </p>
35 <br/>${_('Using')} ${c.user.email}
36 %else:
37 <br/>${c.user.email}
38 %endif
36 </div>
39 </div>
37 </div>
40 </div>
38 <div class="field">
41 <div class="field">
39 <div class="label">
42 <div class="label">
40 <label>${_('API key')}</label> ${c.user.api_key}
43 <label>${_('API key')}</label> ${c.user.api_key}
41 </div>
44 </div>
42 </div>
45 </div>
43
46
44 <div class="fields">
47 <div class="fields">
45 <div class="field">
48 <div class="field">
46 <div class="label">
49 <div class="label">
47 <label for="username">${_('Username')}:</label>
50 <label for="username">${_('Username')}:</label>
48 </div>
51 </div>
49 <div class="input">
52 <div class="input">
50 ${h.text('username',class_='medium')}
53 ${h.text('username',class_='medium')}
51 </div>
54 </div>
52 </div>
55 </div>
53
56
54 <div class="field">
57 <div class="field">
55 <div class="label">
58 <div class="label">
56 <label for="ldap_dn">${_('LDAP DN')}:</label>
59 <label for="ldap_dn">${_('LDAP DN')}:</label>
57 </div>
60 </div>
58 <div class="input">
61 <div class="input">
59 ${h.text('ldap_dn',class_='medium')}
62 ${h.text('ldap_dn',class_='medium')}
60 </div>
63 </div>
61 </div>
64 </div>
62
65
63 <div class="field">
66 <div class="field">
64 <div class="label">
67 <div class="label">
65 <label for="new_password">${_('New password')}:</label>
68 <label for="new_password">${_('New password')}:</label>
66 </div>
69 </div>
67 <div class="input">
70 <div class="input">
68 ${h.password('new_password',class_='medium',autocomplete="off")}
71 ${h.password('new_password',class_='medium',autocomplete="off")}
69 </div>
72 </div>
70 </div>
73 </div>
71
74
72 <div class="field">
75 <div class="field">
73 <div class="label">
76 <div class="label">
74 <label for="password_confirmation">${_('New password confirmation')}:</label>
77 <label for="password_confirmation">${_('New password confirmation')}:</label>
75 </div>
78 </div>
76 <div class="input">
79 <div class="input">
77 ${h.password('password_confirmation',class_="medium",autocomplete="off")}
80 ${h.password('password_confirmation',class_="medium",autocomplete="off")}
78 </div>
81 </div>
79 </div>
82 </div>
80
83
81 <div class="field">
84 <div class="field">
82 <div class="label">
85 <div class="label">
83 <label for="name">${_('First Name')}:</label>
86 <label for="name">${_('First Name')}:</label>
84 </div>
87 </div>
85 <div class="input">
88 <div class="input">
86 ${h.text('name',class_='medium')}
89 ${h.text('name',class_='medium')}
87 </div>
90 </div>
88 </div>
91 </div>
89
92
90 <div class="field">
93 <div class="field">
91 <div class="label">
94 <div class="label">
92 <label for="lastname">${_('Last Name')}:</label>
95 <label for="lastname">${_('Last Name')}:</label>
93 </div>
96 </div>
94 <div class="input">
97 <div class="input">
95 ${h.text('lastname',class_='medium')}
98 ${h.text('lastname',class_='medium')}
96 </div>
99 </div>
97 </div>
100 </div>
98
101
99 <div class="field">
102 <div class="field">
100 <div class="label">
103 <div class="label">
101 <label for="email">${_('Email')}:</label>
104 <label for="email">${_('Email')}:</label>
102 </div>
105 </div>
103 <div class="input">
106 <div class="input">
104 ${h.text('email',class_='medium')}
107 ${h.text('email',class_='medium')}
105 </div>
108 </div>
106 </div>
109 </div>
107
110
108 <div class="field">
111 <div class="field">
109 <div class="label label-checkbox">
112 <div class="label label-checkbox">
110 <label for="active">${_('Active')}:</label>
113 <label for="active">${_('Active')}:</label>
111 </div>
114 </div>
112 <div class="checkboxes">
115 <div class="checkboxes">
113 ${h.checkbox('active',value=True)}
116 ${h.checkbox('active',value=True)}
114 </div>
117 </div>
115 </div>
118 </div>
116
119
117 <div class="field">
120 <div class="field">
118 <div class="label label-checkbox">
121 <div class="label label-checkbox">
119 <label for="admin">${_('Admin')}:</label>
122 <label for="admin">${_('Admin')}:</label>
120 </div>
123 </div>
121 <div class="checkboxes">
124 <div class="checkboxes">
122 ${h.checkbox('admin',value=True)}
125 ${h.checkbox('admin',value=True)}
123 </div>
126 </div>
124 </div>
127 </div>
125 <div class="buttons">
128 <div class="buttons">
126 ${h.submit('save',_('Save'),class_="ui-button")}
129 ${h.submit('save',_('Save'),class_="ui-button")}
127 ${h.reset('reset',_('Reset'),class_="ui-button")}
130 ${h.reset('reset',_('Reset'),class_="ui-button")}
128 </div>
131 </div>
129 </div>
132 </div>
130 </div>
133 </div>
131 ${h.end_form()}
134 ${h.end_form()}
132 </div>
135 </div>
133 <div class="box box-right">
136 <div class="box box-right">
134 <!-- box / title -->
137 <!-- box / title -->
135 <div class="title">
138 <div class="title">
136 <h5>${_('Permissions')}</h5>
139 <h5>${_('Permissions')}</h5>
137 </div>
140 </div>
138 ${h.form(url('user_perm', id=c.user.user_id),method='put')}
141 ${h.form(url('user_perm', id=c.user.user_id),method='put')}
139 <div class="form">
142 <div class="form">
140 <!-- fields -->
143 <!-- fields -->
141 <div class="fields">
144 <div class="fields">
142 <div class="field">
145 <div class="field">
143 <div class="label label-checkbox">
146 <div class="label label-checkbox">
144 <label for="create_repo_perm">${_('Create repositories')}:</label>
147 <label for="create_repo_perm">${_('Create repositories')}:</label>
145 </div>
148 </div>
146 <div class="checkboxes">
149 <div class="checkboxes">
147 ${h.checkbox('create_repo_perm',value=True)}
150 ${h.checkbox('create_repo_perm',value=True)}
148 </div>
151 </div>
149 </div>
152 </div>
150 <div class="buttons">
153 <div class="buttons">
151 ${h.submit('save',_('Save'),class_="ui-button")}
154 ${h.submit('save',_('Save'),class_="ui-button")}
152 ${h.reset('reset',_('Reset'),class_="ui-button")}
155 ${h.reset('reset',_('Reset'),class_="ui-button")}
153 </div>
156 </div>
154 </div>
157 </div>
155 </div>
158 </div>
156 ${h.end_form()}
159 ${h.end_form()}
157 </div>
160 </div>
158 </%def>
161 </%def>
@@ -1,222 +1,226 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('My account')} ${c.rhodecode_user.username} - ${c.rhodecode_name}
5 ${_('My account')} ${c.rhodecode_user.username} - ${c.rhodecode_name}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
9 ${_('My Account')}
9 ${_('My Account')}
10 </%def>
10 </%def>
11
11
12 <%def name="page_nav()">
12 <%def name="page_nav()">
13 ${self.menu('admin')}
13 ${self.menu('admin')}
14 </%def>
14 </%def>
15
15
16 <%def name="main()">
16 <%def name="main()">
17
17
18 <div class="box box-left">
18 <div class="box box-left">
19 <!-- box / title -->
19 <!-- box / title -->
20 <div class="title">
20 <div class="title">
21 ${self.breadcrumbs()}
21 ${self.breadcrumbs()}
22 </div>
22 </div>
23 <!-- end box / title -->
23 <!-- end box / title -->
24 <div>
24 <div>
25 ${h.form(url('admin_settings_my_account_update'),method='put')}
25 ${h.form(url('admin_settings_my_account_update'),method='put')}
26 <div class="form">
26 <div class="form">
27
27
28 <div class="field">
28 <div class="field">
29 <div class="gravatar_box">
29 <div class="gravatar_box">
30 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
30 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
31 <p>
31 <p>
32 <strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong><br/>
32 %if c.use_gravatar:
33 ${_('Using')} ${c.user.email}
33 <strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong>
34 <br/>${_('Using')} ${c.user.email}
35 %else:
36 <br/>${c.user.email}
37 %endif
34 </p>
38 </p>
35 </div>
39 </div>
36 </div>
40 </div>
37 <div class="field">
41 <div class="field">
38 <div class="label">
42 <div class="label">
39 <label>${_('API key')}</label> ${c.user.api_key}
43 <label>${_('API key')}</label> ${c.user.api_key}
40 </div>
44 </div>
41 </div>
45 </div>
42 <div class="fields">
46 <div class="fields">
43 <div class="field">
47 <div class="field">
44 <div class="label">
48 <div class="label">
45 <label for="username">${_('Username')}:</label>
49 <label for="username">${_('Username')}:</label>
46 </div>
50 </div>
47 <div class="input">
51 <div class="input">
48 ${h.text('username',class_="medium")}
52 ${h.text('username',class_="medium")}
49 </div>
53 </div>
50 </div>
54 </div>
51
55
52 <div class="field">
56 <div class="field">
53 <div class="label">
57 <div class="label">
54 <label for="new_password">${_('New password')}:</label>
58 <label for="new_password">${_('New password')}:</label>
55 </div>
59 </div>
56 <div class="input">
60 <div class="input">
57 ${h.password('new_password',class_="medium",autocomplete="off")}
61 ${h.password('new_password',class_="medium",autocomplete="off")}
58 </div>
62 </div>
59 </div>
63 </div>
60
64
61 <div class="field">
65 <div class="field">
62 <div class="label">
66 <div class="label">
63 <label for="password_confirmation">${_('New password confirmation')}:</label>
67 <label for="password_confirmation">${_('New password confirmation')}:</label>
64 </div>
68 </div>
65 <div class="input">
69 <div class="input">
66 ${h.password('password_confirmation',class_="medium",autocomplete="off")}
70 ${h.password('password_confirmation',class_="medium",autocomplete="off")}
67 </div>
71 </div>
68 </div>
72 </div>
69
73
70 <div class="field">
74 <div class="field">
71 <div class="label">
75 <div class="label">
72 <label for="name">${_('First Name')}:</label>
76 <label for="name">${_('First Name')}:</label>
73 </div>
77 </div>
74 <div class="input">
78 <div class="input">
75 ${h.text('name',class_="medium")}
79 ${h.text('name',class_="medium")}
76 </div>
80 </div>
77 </div>
81 </div>
78
82
79 <div class="field">
83 <div class="field">
80 <div class="label">
84 <div class="label">
81 <label for="lastname">${_('Last Name')}:</label>
85 <label for="lastname">${_('Last Name')}:</label>
82 </div>
86 </div>
83 <div class="input">
87 <div class="input">
84 ${h.text('lastname',class_="medium")}
88 ${h.text('lastname',class_="medium")}
85 </div>
89 </div>
86 </div>
90 </div>
87
91
88 <div class="field">
92 <div class="field">
89 <div class="label">
93 <div class="label">
90 <label for="email">${_('Email')}:</label>
94 <label for="email">${_('Email')}:</label>
91 </div>
95 </div>
92 <div class="input">
96 <div class="input">
93 ${h.text('email',class_="medium")}
97 ${h.text('email',class_="medium")}
94 </div>
98 </div>
95 </div>
99 </div>
96
100
97 <div class="buttons">
101 <div class="buttons">
98 ${h.submit('save',_('Save'),class_="ui-button")}
102 ${h.submit('save',_('Save'),class_="ui-button")}
99 ${h.reset('reset',_('Reset'),class_="ui-button")}
103 ${h.reset('reset',_('Reset'),class_="ui-button")}
100 </div>
104 </div>
101 </div>
105 </div>
102 </div>
106 </div>
103 ${h.end_form()}
107 ${h.end_form()}
104 </div>
108 </div>
105 </div>
109 </div>
106
110
107 <div class="box box-right">
111 <div class="box box-right">
108 <!-- box / title -->
112 <!-- box / title -->
109 <div class="title">
113 <div class="title">
110 <h5>${_('My repositories')}
114 <h5>${_('My repositories')}
111 <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...')}"/>
115 <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...')}"/>
112 </h5>
116 </h5>
113 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
117 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
114 <ul class="links">
118 <ul class="links">
115 <li>
119 <li>
116 <span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository'))}</span>
120 <span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository'))}</span>
117 </li>
121 </li>
118 </ul>
122 </ul>
119 %endif
123 %endif
120 </div>
124 </div>
121 <!-- end box / title -->
125 <!-- end box / title -->
122 <div class="table">
126 <div class="table">
123 <table>
127 <table>
124 <thead>
128 <thead>
125 <tr>
129 <tr>
126 <th class="left">${_('Name')}</th>
130 <th class="left">${_('Name')}</th>
127 <th class="left">${_('revision')}</th>
131 <th class="left">${_('revision')}</th>
128 <th colspan="2" class="left">${_('action')}</th>
132 <th colspan="2" class="left">${_('action')}</th>
129 </thead>
133 </thead>
130 <tbody>
134 <tbody>
131 %if c.user_repos:
135 %if c.user_repos:
132 %for repo in c.user_repos:
136 %for repo in c.user_repos:
133 <tr>
137 <tr>
134 <td>
138 <td>
135 %if repo['dbrepo']['repo_type'] =='hg':
139 %if repo['dbrepo']['repo_type'] =='hg':
136 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url("/images/icons/hgicon.png")}"/>
140 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url("/images/icons/hgicon.png")}"/>
137 %elif repo['dbrepo']['repo_type'] =='git':
141 %elif repo['dbrepo']['repo_type'] =='git':
138 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url("/images/icons/giticon.png")}"/>
142 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url("/images/icons/giticon.png")}"/>
139 %else:
143 %else:
140
144
141 %endif
145 %endif
142 %if repo['dbrepo']['private']:
146 %if repo['dbrepo']['private']:
143 <img class="icon" alt="${_('private')}" src="${h.url("/images/icons/lock.png")}"/>
147 <img class="icon" alt="${_('private')}" src="${h.url("/images/icons/lock.png")}"/>
144 %else:
148 %else:
145 <img class="icon" alt="${_('public')}" src="${h.url("/images/icons/lock_open.png")}"/>
149 <img class="icon" alt="${_('public')}" src="${h.url("/images/icons/lock_open.png")}"/>
146 %endif
150 %endif
147
151
148 ${h.link_to(repo['name'], h.url('summary_home',repo_name=repo['name']),class_="repo_name")}
152 ${h.link_to(repo['name'], h.url('summary_home',repo_name=repo['name']),class_="repo_name")}
149 %if repo['dbrepo_fork']:
153 %if repo['dbrepo_fork']:
150 <a href="${h.url('summary_home',repo_name=repo['dbrepo_fork']['repo_name'])}">
154 <a href="${h.url('summary_home',repo_name=repo['dbrepo_fork']['repo_name'])}">
151 <img class="icon" alt="${_('public')}"
155 <img class="icon" alt="${_('public')}"
152 title="${_('Fork of')} ${repo['dbrepo_fork']['repo_name']}"
156 title="${_('Fork of')} ${repo['dbrepo_fork']['repo_name']}"
153 src="${h.url('/images/icons/arrow_divide.png')}"/></a>
157 src="${h.url('/images/icons/arrow_divide.png')}"/></a>
154 %endif
158 %endif
155 </td>
159 </td>
156 <td><span class="tooltip" title="${repo['last_change']}">${("r%s:%s") % (repo['rev'],h.short_id(repo['tip']))}</span></td>
160 <td><span class="tooltip" title="${repo['last_change']}">${("r%s:%s") % (repo['rev'],h.short_id(repo['tip']))}</span></td>
157 <td><a href="${h.url('repo_settings_home',repo_name=repo['name'])}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="${h.url('/images/icons/application_form_edit.png')}"/></a></td>
161 <td><a href="${h.url('repo_settings_home',repo_name=repo['name'])}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="${h.url('/images/icons/application_form_edit.png')}"/></a></td>
158 <td>
162 <td>
159 ${h.form(url('repo_settings_delete', repo_name=repo['name']),method='delete')}
163 ${h.form(url('repo_settings_delete', repo_name=repo['name']),method='delete')}
160 ${h.submit('remove_%s' % repo['name'],'',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
164 ${h.submit('remove_%s' % repo['name'],'',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
161 ${h.end_form()}
165 ${h.end_form()}
162 </td>
166 </td>
163 </tr>
167 </tr>
164 %endfor
168 %endfor
165 %else:
169 %else:
166 <div style="padding:5px 0px 10px 0px;">
170 <div style="padding:5px 0px 10px 0px;">
167 ${_('No repositories yet')}
171 ${_('No repositories yet')}
168 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
172 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
169 ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'),class_="ui-button-small")}
173 ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'),class_="ui-button-small")}
170 %endif
174 %endif
171 </div>
175 </div>
172 %endif
176 %endif
173 </tbody>
177 </tbody>
174 </table>
178 </table>
175 </div>
179 </div>
176
180
177 </div>
181 </div>
178 <script type="text/javascript">
182 <script type="text/javascript">
179 var D = YAHOO.util.Dom;
183 var D = YAHOO.util.Dom;
180 var E = YAHOO.util.Event;
184 var E = YAHOO.util.Event;
181 var S = YAHOO.util.Selector;
185 var S = YAHOO.util.Selector;
182
186
183 var q_filter = D.get('q_filter');
187 var q_filter = D.get('q_filter');
184 var F = YAHOO.namespace('q_filter');
188 var F = YAHOO.namespace('q_filter');
185
189
186 E.on(q_filter,'click',function(){
190 E.on(q_filter,'click',function(){
187 q_filter.value = '';
191 q_filter.value = '';
188 });
192 });
189
193
190 F.filterTimeout = null;
194 F.filterTimeout = null;
191
195
192 F.updateFilter = function() {
196 F.updateFilter = function() {
193 // Reset timeout
197 // Reset timeout
194 F.filterTimeout = null;
198 F.filterTimeout = null;
195
199
196 var obsolete = [];
200 var obsolete = [];
197 var nodes = S.query('div.table tr td a.repo_name');
201 var nodes = S.query('div.table tr td a.repo_name');
198 var req = q_filter.value.toLowerCase();
202 var req = q_filter.value.toLowerCase();
199 for (n in nodes){
203 for (n in nodes){
200 D.setStyle(nodes[n].parentNode.parentNode,'display','')
204 D.setStyle(nodes[n].parentNode.parentNode,'display','')
201 }
205 }
202 if (req){
206 if (req){
203 for (n in nodes){
207 for (n in nodes){
204 if (nodes[n].innerHTML.toLowerCase().indexOf(req) == -1) {
208 if (nodes[n].innerHTML.toLowerCase().indexOf(req) == -1) {
205 obsolete.push(nodes[n]);
209 obsolete.push(nodes[n]);
206 }
210 }
207 }
211 }
208 if(obsolete){
212 if(obsolete){
209 for (n in obsolete){
213 for (n in obsolete){
210 D.setStyle(obsolete[n].parentNode.parentNode,'display','none');
214 D.setStyle(obsolete[n].parentNode.parentNode,'display','none');
211 }
215 }
212 }
216 }
213 }
217 }
214 }
218 }
215
219
216 E.on(q_filter,'keyup',function(e){
220 E.on(q_filter,'keyup',function(e){
217 clearTimeout(F.filterTimeout);
221 clearTimeout(F.filterTimeout);
218 F.filterTimeout = setTimeout(F.updateFilter,600);
222 F.filterTimeout = setTimeout(F.updateFilter,600);
219 });
223 });
220
224
221 </script>
225 </script>
222 </%def>
226 </%def>
General Comments 0
You need to be logged in to leave comments. Login now