##// END OF EJS Templates
fixes #65, Added reset buttons to edit forms
marcink -
r698:4cd0709b beta
parent child Browse files
Show More
@@ -1,447 +1,458 b''
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 from pygments.formatters import HtmlFormatter
7 7 from pygments import highlight as code_highlight
8 8 from pylons import url, app_globals as g
9 9 from pylons.i18n.translation import _, ungettext
10 10 from vcs.utils.annotate import annotate_highlight
11 11 from webhelpers.html import literal, HTML, escape
12 12 from webhelpers.html.tools import *
13 13 from webhelpers.html.builder import make_tag
14 14 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
15 15 end_form, file, form, hidden, image, javascript_link, link_to, link_to_if, \
16 16 link_to_unless, ol, required_legend, select, stylesheet_link, submit, text, \
17 17 password, textarea, title, ul, xml_declaration, radio
18 18 from webhelpers.html.tools import auto_link, button_to, highlight, js_obfuscate, \
19 19 mail_to, strip_links, strip_tags, tag_re
20 20 from webhelpers.number import format_byte_size, format_bit_size
21 21 from webhelpers.pylonslib import Flash as _Flash
22 22 from webhelpers.pylonslib.secure_form import secure_form
23 23 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
24 24 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
25 25 replace_whitespace, urlify, truncate, wrap_paragraphs
26 26 from webhelpers.date import time_ago_in_words
27 27
28 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
29 convert_boolean_attrs, NotGiven
30
31 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
32 _set_input_attrs(attrs, type, name, value)
33 _set_id_attr(attrs, id, name)
34 convert_boolean_attrs(attrs, ["disabled"])
35 return HTML.input(**attrs)
36
37 reset = _reset
38
28 39 #Custom helpers here :)
29 40 class _Link(object):
30 41 '''
31 42 Make a url based on label and url with help of url_for
32 43 :param label:name of link if not defined url is used
33 44 :param url: the url for link
34 45 '''
35 46
36 47 def __call__(self, label='', *url_, **urlargs):
37 48 if label is None or '':
38 49 label = url
39 50 link_fn = link_to(label, url(*url_, **urlargs))
40 51 return link_fn
41 52
42 53 link = _Link()
43 54
44 55 class _GetError(object):
45 56
46 57 def __call__(self, field_name, form_errors):
47 58 tmpl = """<span class="error_msg">%s</span>"""
48 59 if form_errors and form_errors.has_key(field_name):
49 60 return literal(tmpl % form_errors.get(field_name))
50 61
51 62 get_error = _GetError()
52 63
53 64 def recursive_replace(str, replace=' '):
54 65 """
55 66 Recursive replace of given sign to just one instance
56 67 :param str: given string
57 68 :param replace:char to find and replace multiple instances
58 69
59 70 Examples::
60 71 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
61 72 'Mighty-Mighty-Bo-sstones'
62 73 """
63 74
64 75 if str.find(replace * 2) == -1:
65 76 return str
66 77 else:
67 78 str = str.replace(replace * 2, replace)
68 79 return recursive_replace(str, replace)
69 80
70 81 class _ToolTip(object):
71 82
72 83 def __call__(self, tooltip_title, trim_at=50):
73 84 """
74 85 Special function just to wrap our text into nice formatted autowrapped
75 86 text
76 87 :param tooltip_title:
77 88 """
78 89
79 90 return wrap_paragraphs(escape(tooltip_title), trim_at)\
80 91 .replace('\n', '<br/>')
81 92
82 93 def activate(self):
83 94 """
84 95 Adds tooltip mechanism to the given Html all tooltips have to have
85 96 set class tooltip and set attribute tooltip_title.
86 97 Then a tooltip will be generated based on that
87 98 All with yui js tooltip
88 99 """
89 100
90 101 js = '''
91 102 YAHOO.util.Event.onDOMReady(function(){
92 103 function toolTipsId(){
93 104 var ids = [];
94 105 var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
95 106
96 107 for (var i = 0; i < tts.length; i++) {
97 108 //if element doesn't not have and id autgenerate one for tooltip
98 109
99 110 if (!tts[i].id){
100 111 tts[i].id='tt'+i*100;
101 112 }
102 113 ids.push(tts[i].id);
103 114 }
104 115 return ids
105 116 };
106 117 var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
107 118 context: toolTipsId(),
108 119 monitorresize:false,
109 120 xyoffset :[0,0],
110 121 autodismissdelay:300000,
111 122 hidedelay:5,
112 123 showdelay:20,
113 124 });
114 125
115 126 //Mouse Over event disabled for new repositories since they don't
116 127 //have last commit message
117 128 myToolTips.contextMouseOverEvent.subscribe(
118 129 function(type, args) {
119 130 var context = args[0];
120 131 var txt = context.getAttribute('tooltip_title');
121 132 if(txt){
122 133 return true;
123 134 }
124 135 else{
125 136 return false;
126 137 }
127 138 });
128 139
129 140
130 141 // Set the text for the tooltip just before we display it. Lazy method
131 142 myToolTips.contextTriggerEvent.subscribe(
132 143 function(type, args) {
133 144
134 145
135 146 var context = args[0];
136 147
137 148 var txt = context.getAttribute('tooltip_title');
138 149 this.cfg.setProperty("text", txt);
139 150
140 151
141 152 // positioning of tooltip
142 153 var tt_w = this.element.clientWidth;
143 154 var tt_h = this.element.clientHeight;
144 155
145 156 var context_w = context.offsetWidth;
146 157 var context_h = context.offsetHeight;
147 158
148 159 var pos_x = YAHOO.util.Dom.getX(context);
149 160 var pos_y = YAHOO.util.Dom.getY(context);
150 161
151 162 var display_strategy = 'top';
152 163 var xy_pos = [0,0];
153 164 switch (display_strategy){
154 165
155 166 case 'top':
156 167 var cur_x = (pos_x+context_w/2)-(tt_w/2);
157 168 var cur_y = pos_y-tt_h-4;
158 169 xy_pos = [cur_x,cur_y];
159 170 break;
160 171 case 'bottom':
161 172 var cur_x = (pos_x+context_w/2)-(tt_w/2);
162 173 var cur_y = pos_y+context_h+4;
163 174 xy_pos = [cur_x,cur_y];
164 175 break;
165 176 case 'left':
166 177 var cur_x = (pos_x-tt_w-4);
167 178 var cur_y = pos_y-((tt_h/2)-context_h/2);
168 179 xy_pos = [cur_x,cur_y];
169 180 break;
170 181 case 'right':
171 182 var cur_x = (pos_x+context_w+4);
172 183 var cur_y = pos_y-((tt_h/2)-context_h/2);
173 184 xy_pos = [cur_x,cur_y];
174 185 break;
175 186 default:
176 187 var cur_x = (pos_x+context_w/2)-(tt_w/2);
177 188 var cur_y = pos_y-tt_h-4;
178 189 xy_pos = [cur_x,cur_y];
179 190 break;
180 191
181 192 }
182 193
183 194 this.cfg.setProperty("xy",xy_pos);
184 195
185 196 });
186 197
187 198 //Mouse out
188 199 myToolTips.contextMouseOutEvent.subscribe(
189 200 function(type, args) {
190 201 var context = args[0];
191 202
192 203 });
193 204 });
194 205 '''
195 206 return literal(js)
196 207
197 208 tooltip = _ToolTip()
198 209
199 210 class _FilesBreadCrumbs(object):
200 211
201 212 def __call__(self, repo_name, rev, paths):
202 213 url_l = [link_to(repo_name, url('files_home',
203 214 repo_name=repo_name,
204 215 revision=rev, f_path=''))]
205 216 paths_l = paths.split('/')
206 217
207 218 for cnt, p in enumerate(paths_l, 1):
208 219 if p != '':
209 220 url_l.append(link_to(p, url('files_home',
210 221 repo_name=repo_name,
211 222 revision=rev,
212 223 f_path='/'.join(paths_l[:cnt]))))
213 224
214 225 return literal('/'.join(url_l))
215 226
216 227 files_breadcrumbs = _FilesBreadCrumbs()
217 228 class CodeHtmlFormatter(HtmlFormatter):
218 229
219 230 def wrap(self, source, outfile):
220 231 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
221 232
222 233 def _wrap_code(self, source):
223 234 for cnt, it in enumerate(source, 1):
224 235 i, t = it
225 236 t = '<div id="#S-%s">%s</div>' % (cnt, t)
226 237 yield i, t
227 238 def pygmentize(filenode, **kwargs):
228 239 """
229 240 pygmentize function using pygments
230 241 :param filenode:
231 242 """
232 243 return literal(code_highlight(filenode.content,
233 244 filenode.lexer, CodeHtmlFormatter(**kwargs)))
234 245
235 246 def pygmentize_annotation(filenode, **kwargs):
236 247 """
237 248 pygmentize function for annotation
238 249 :param filenode:
239 250 """
240 251
241 252 color_dict = {}
242 253 def gen_color():
243 254 """generator for getting 10k of evenly distibuted colors using hsv color
244 255 and golden ratio.
245 256 """
246 257 import colorsys
247 258 n = 10000
248 259 golden_ratio = 0.618033988749895
249 260 h = 0.22717784590367374
250 261 #generate 10k nice web friendly colors in the same order
251 262 for c in xrange(n):
252 263 h += golden_ratio
253 264 h %= 1
254 265 HSV_tuple = [h, 0.95, 0.95]
255 266 RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple)
256 267 yield map(lambda x:str(int(x * 256)), RGB_tuple)
257 268
258 269 cgenerator = gen_color()
259 270
260 271 def get_color_string(cs):
261 272 if color_dict.has_key(cs):
262 273 col = color_dict[cs]
263 274 else:
264 275 col = color_dict[cs] = cgenerator.next()
265 276 return "color: rgb(%s)! important;" % (', '.join(col))
266 277
267 278 def url_func(changeset):
268 279 tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \
269 280 " %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
270 281
271 282 tooltip_html = tooltip_html % (changeset.author,
272 283 changeset.date,
273 284 tooltip(changeset.message))
274 285 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
275 286 short_id(changeset.raw_id))
276 287 uri = link_to(
277 288 lnk_format,
278 289 url('changeset_home', repo_name=changeset.repository.name,
279 290 revision=changeset.raw_id),
280 291 style=get_color_string(changeset.raw_id),
281 292 class_='tooltip',
282 293 tooltip_title=tooltip_html
283 294 )
284 295
285 296 uri += '\n'
286 297 return uri
287 298 return literal(annotate_highlight(filenode, url_func, **kwargs))
288 299
289 300 def repo_name_slug(value):
290 301 """Return slug of name of repository
291 302 This function is called on each creation/modification
292 303 of repository to prevent bad names in repo
293 304 """
294 305 slug = remove_formatting(value)
295 306 slug = strip_tags(slug)
296 307
297 308 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
298 309 slug = slug.replace(c, '-')
299 310 slug = recursive_replace(slug, '-')
300 311 slug = collapse(slug, '-')
301 312 return slug
302 313
303 314 def get_changeset_safe(repo, rev):
304 315 from vcs.backends.base import BaseRepository
305 316 from vcs.exceptions import RepositoryError
306 317 if not isinstance(repo, BaseRepository):
307 318 raise Exception('You must pass an Repository '
308 319 'object as first argument got %s', type(repo))
309 320
310 321 try:
311 322 cs = repo.get_changeset(rev)
312 323 except RepositoryError:
313 324 from rhodecode.lib.utils import EmptyChangeset
314 325 cs = EmptyChangeset()
315 326 return cs
316 327
317 328
318 329 flash = _Flash()
319 330
320 331
321 332 #==============================================================================
322 333 # MERCURIAL FILTERS available via h.
323 334 #==============================================================================
324 335 from mercurial import util
325 336 from mercurial.templatefilters import person as _person
326 337
327 338
328 339
329 340 def _age(curdate):
330 341 """turns a datetime into an age string."""
331 342
332 343 if not curdate:
333 344 return ''
334 345
335 346 from datetime import timedelta, datetime
336 347
337 348 agescales = [("year", 3600 * 24 * 365),
338 349 ("month", 3600 * 24 * 30),
339 350 ("day", 3600 * 24),
340 351 ("hour", 3600),
341 352 ("minute", 60),
342 353 ("second", 1), ]
343 354
344 355 age = datetime.now() - curdate
345 356 age_seconds = (age.days * agescales[2][1]) + age.seconds
346 357 pos = 1
347 358 for scale in agescales:
348 359 if scale[1] <= age_seconds:
349 360 if pos == 6:pos = 5
350 361 return time_ago_in_words(curdate, agescales[pos][0]) + ' ' + _('ago')
351 362 pos += 1
352 363
353 364 return _('just now')
354 365
355 366 age = lambda x:_age(x)
356 367 capitalize = lambda x: x.capitalize()
357 368 email = util.email
358 369 email_or_none = lambda x: util.email(x) if util.email(x) != x else None
359 370 person = lambda x: _person(x)
360 371 short_id = lambda x: x[:12]
361 372
362 373
363 374 def action_parser(user_log):
364 375 """
365 376 This helper will map the specified string action into translated
366 377 fancy names with icons and links
367 378
368 379 @param action:
369 380 """
370 381 action = user_log.action
371 382 action_params = None
372 383 cs_links = ''
373 384
374 385 x = action.split(':')
375 386
376 387 if len(x) > 1:
377 388 action, action_params = x
378 389
379 390 if action == 'push':
380 391 revs_limit = 5
381 392 revs = action_params.split(',')
382 393 cs_links = " " + ', '.join ([link(rev,
383 394 url('changeset_home',
384 395 repo_name=user_log.repository.repo_name,
385 396 revision=rev)) for rev in revs[:revs_limit] ])
386 397 if len(revs) > revs_limit:
387 398 html_tmpl = '<span title="%s"> %s </span>'
388 399 cs_links += html_tmpl % (', '.join(r for r in revs[revs_limit:]),
389 400 _('and %s more revisions') % (len(revs) - revs_limit))
390 401
391 402 map = {'user_deleted_repo':_('User deleted repository'),
392 403 'user_created_repo':_('User created repository'),
393 404 'user_forked_repo':_('User forked repository'),
394 405 'user_updated_repo':_('User updated repository'),
395 406 'admin_deleted_repo':_('Admin delete repository'),
396 407 'admin_created_repo':_('Admin created repository'),
397 408 'admin_forked_repo':_('Admin forked repository'),
398 409 'admin_updated_repo':_('Admin updated repository'),
399 410 'push':_('Pushed') + literal(cs_links),
400 411 'pull':_('Pulled'), }
401 412
402 413 print action, action_params
403 414 return map.get(action, action)
404 415
405 416
406 417 #==============================================================================
407 418 # PERMS
408 419 #==============================================================================
409 420 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
410 421 HasRepoPermissionAny, HasRepoPermissionAll
411 422
412 423 #==============================================================================
413 424 # GRAVATAR URL
414 425 #==============================================================================
415 426 import hashlib
416 427 import urllib
417 428 from pylons import request
418 429
419 430 def gravatar_url(email_address, size=30):
420 431 ssl_enabled = 'https' == request.environ.get('HTTP_X_URL_SCHEME')
421 432 default = 'identicon'
422 433 baseurl_nossl = "http://www.gravatar.com/avatar/"
423 434 baseurl_ssl = "https://secure.gravatar.com/avatar/"
424 435 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
425 436
426 437
427 438 # construct the url
428 439 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
429 440 gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
430 441
431 442 return gravatar_url
432 443
433 444 def safe_unicode(str):
434 445 """safe unicode function. In case of UnicodeDecode error we try to return
435 446 unicode with errors replace, if this failes we return unicode with
436 447 string_escape decoding """
437 448
438 449 try:
439 450 u_str = unicode(str)
440 451 except UnicodeDecodeError:
441 452 try:
442 453 u_str = unicode(str, 'utf-8', 'replace')
443 454 except UnicodeDecodeError:
444 455 #incase we have a decode error just represent as byte string
445 456 u_str = unicode(str(str).encode('string_escape'))
446 457
447 458 return u_str
@@ -1,282 +1,283 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('Edit repository')} ${c.repo_info.repo_name} - ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 ${h.link_to(_('Admin'),h.url('admin_home'))}
10 10 &raquo;
11 11 ${h.link_to(_('Repositories'),h.url('repos'))}
12 12 &raquo;
13 13 ${_('edit')} "${c.repo_name}"
14 14 </%def>
15 15
16 16 <%def name="page_nav()">
17 17 ${self.menu('admin')}
18 18 </%def>
19 19
20 20 <%def name="main()">
21 21 <div class="box">
22 22 <!-- box / title -->
23 23 <div class="title">
24 24 ${self.breadcrumbs()}
25 25 </div>
26 26 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
27 27 <div class="form">
28 28 <!-- fields -->
29 29 <div class="fields">
30 30 <div class="field">
31 31 <div class="label">
32 32 <label for="repo_name">${_('Name')}:</label>
33 33 </div>
34 34 <div class="input input-medium">
35 35 ${h.text('repo_name',class_="small")}
36 36 </div>
37 37 </div>
38 38 <div class="field">
39 39 <div class="label">
40 40 <label for="repo_type">${_('Type')}:</label>
41 41 </div>
42 42 <div class="input">
43 43 ${h.select('repo_type','hg',c.backends,class_="small")}
44 44 </div>
45 45 </div>
46 46 <div class="field">
47 47 <div class="label label-textarea">
48 48 <label for="description">${_('Description')}:</label>
49 49 </div>
50 50 <div class="textarea text-area editor">
51 51 ${h.textarea('description',cols=23,rows=5)}
52 52 </div>
53 53 </div>
54 54
55 55 <div class="field">
56 56 <div class="label label-checkbox">
57 57 <label for="private">${_('Private')}:</label>
58 58 </div>
59 59 <div class="checkboxes">
60 60 ${h.checkbox('private',value="True")}
61 61 </div>
62 62 </div>
63 63
64 64 <div class="field">
65 65 <div class="label">
66 66 <label for="user">${_('Owner')}:</label>
67 67 </div>
68 68 <div class="input input-small ac">
69 69 <div class="perm_ac">
70 70 ${h.text('user',class_='yui-ac-input')}
71 71 <div id="owner_container"></div>
72 72 </div>
73 73 </div>
74 74 </div>
75 75
76 76 <div class="field">
77 77 <div class="label">
78 78 <label for="input">${_('Permissions')}:</label>
79 79 </div>
80 80 <div class="input">
81 81 <table id="permissions_manage">
82 82 <tr>
83 83 <td>${_('none')}</td>
84 84 <td>${_('read')}</td>
85 85 <td>${_('write')}</td>
86 86 <td>${_('admin')}</td>
87 87 <td>${_('user')}</td>
88 88 <td></td>
89 89 </tr>
90 90
91 91 %for r2p in c.repo_info.repo_to_perm:
92 92 %if r2p.user.username =='default' and c.repo_info.private:
93 93 <tr>
94 94 <td colspan="4">
95 95 <span class="private_repo_msg">
96 96 ${_('private repository')}
97 97 </span>
98 98 </td>
99 99 <td class="private_repo_msg">${r2p.user.username}</td>
100 100 </tr>
101 101 %else:
102 102 <tr id="id${id(r2p.user.username)}">
103 103 <td>${h.radio('perm_%s' % r2p.user.username,'repository.none')}</td>
104 104 <td>${h.radio('perm_%s' % r2p.user.username,'repository.read')}</td>
105 105 <td>${h.radio('perm_%s' % r2p.user.username,'repository.write')}</td>
106 106 <td>${h.radio('perm_%s' % r2p.user.username,'repository.admin')}</td>
107 107 <td>${r2p.user.username}</td>
108 108 <td>
109 109 %if r2p.user.username !='default':
110 110 <span class="delete_icon action_button" onclick="ajaxAction(${r2p.user.user_id},'${'id%s'%id(r2p.user.username)}')">
111 111 <script type="text/javascript">
112 112 function ajaxAction(user_id,field_id){
113 113 var sUrl = "${h.url('delete_repo_user',repo_name=c.repo_name)}";
114 114 var callback = { success:function(o){
115 115 var tr = YAHOO.util.Dom.get(String(field_id));
116 116 tr.parentNode.removeChild(tr);},failure:function(o){
117 117 alert("${_('Failed to remove user')}");},};
118 118 var postData = '_method=delete&user_id='+user_id;
119 119 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);};
120 120 </script>
121 121 </span>
122 122 %endif
123 123 </td>
124 124 </tr>
125 125 %endif
126 126 %endfor
127 127
128 128 <tr id="add_perm_input">
129 129 <td>${h.radio('perm_new_user','repository.none')}</td>
130 130 <td>${h.radio('perm_new_user','repository.read')}</td>
131 131 <td>${h.radio('perm_new_user','repository.write')}</td>
132 132 <td>${h.radio('perm_new_user','repository.admin')}</td>
133 133 <td class='ac'>
134 134 <div class="perm_ac" id="perm_ac">
135 135 ${h.text('perm_new_user_name',class_='yui-ac-input')}
136 136 <div id="perm_container"></div>
137 137 </div>
138 138 </td>
139 139 <td></td>
140 140 </tr>
141 141 <tr>
142 142 <td colspan="6">
143 143 <span id="add_perm" class="add_icon" style="cursor: pointer;">
144 144 ${_('Add another user')}
145 145 </span>
146 146 </td>
147 147 </tr>
148 148 </table>
149 149 </div>
150 150
151 151 <div class="buttons">
152 ${h.submit('save','save',class_="ui-button ui-widget ui-state-default ui-corner-all")}
152 ${h.submit('save','Save',class_="ui-button ui-widget ui-state-default ui-corner-all")}
153 ${h.reset('reset','Reset',class_="ui-button ui-widget ui-state-default ui-corner-all")}
153 154 </div>
154 155 </div>
155 156 </div>
156 157 </div>
157 158 ${h.end_form()}
158 159 <script type="text/javascript">
159 160 YAHOO.util.Event.onDOMReady(function(){
160 161 var D = YAHOO.util.Dom;
161 162 if(!D.hasClass('perm_new_user_name','error')){
162 163 D.setStyle('add_perm_input','display','none');
163 164 }
164 165 YAHOO.util.Event.addListener('add_perm','click',function(){
165 166 D.setStyle('add_perm_input','display','');
166 167 D.setStyle('add_perm','opacity','0.6');
167 168 D.setStyle('add_perm','cursor','default');
168 169 });
169 170 });
170 171 </script>
171 172 <script type="text/javascript">
172 173 YAHOO.example.FnMultipleFields = function(){
173 174 var myContacts = ${c.users_array|n}
174 175
175 176 // Define a custom search function for the DataSource
176 177 var matchNames = function(sQuery) {
177 178 // Case insensitive matching
178 179 var query = sQuery.toLowerCase(),
179 180 contact,
180 181 i=0,
181 182 l=myContacts.length,
182 183 matches = [];
183 184
184 185 // Match against each name of each contact
185 186 for(; i<l; i++) {
186 187 contact = myContacts[i];
187 188 if((contact.fname.toLowerCase().indexOf(query) > -1) ||
188 189 (contact.lname.toLowerCase().indexOf(query) > -1) ||
189 190 (contact.nname && (contact.nname.toLowerCase().indexOf(query) > -1))) {
190 191 matches[matches.length] = contact;
191 192 }
192 193 }
193 194
194 195 return matches;
195 196 };
196 197
197 198 // Use a FunctionDataSource
198 199 var oDS = new YAHOO.util.FunctionDataSource(matchNames);
199 200 oDS.responseSchema = {
200 201 fields: ["id", "fname", "lname", "nname"]
201 202 }
202 203
203 204 // Instantiate AutoComplete for perms
204 205 var oAC_perms = new YAHOO.widget.AutoComplete("perm_new_user_name", "perm_container", oDS);
205 206 oAC_perms.useShadow = false;
206 207 oAC_perms.resultTypeList = false;
207 208
208 209 // Instantiate AutoComplete for owner
209 210 var oAC_owner = new YAHOO.widget.AutoComplete("user", "owner_container", oDS);
210 211 oAC_owner.useShadow = false;
211 212 oAC_owner.resultTypeList = false;
212 213
213 214
214 215 // Custom formatter to highlight the matching letters
215 216 var custom_formatter = function(oResultData, sQuery, sResultMatch) {
216 217 var query = sQuery.toLowerCase(),
217 218 fname = oResultData.fname,
218 219 lname = oResultData.lname,
219 220 nname = oResultData.nname || "", // Guard against null value
220 221 query = sQuery.toLowerCase(),
221 222 fnameMatchIndex = fname.toLowerCase().indexOf(query),
222 223 lnameMatchIndex = lname.toLowerCase().indexOf(query),
223 224 nnameMatchIndex = nname.toLowerCase().indexOf(query),
224 225 displayfname, displaylname, displaynname;
225 226
226 227 if(fnameMatchIndex > -1) {
227 228 displayfname = highlightMatch(fname, query, fnameMatchIndex);
228 229 }
229 230 else {
230 231 displayfname = fname;
231 232 }
232 233
233 234 if(lnameMatchIndex > -1) {
234 235 displaylname = highlightMatch(lname, query, lnameMatchIndex);
235 236 }
236 237 else {
237 238 displaylname = lname;
238 239 }
239 240
240 241 if(nnameMatchIndex > -1) {
241 242 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
242 243 }
243 244 else {
244 245 displaynname = nname ? "(" + nname + ")" : "";
245 246 }
246 247
247 248 return displayfname + " " + displaylname + " " + displaynname;
248 249
249 250 };
250 251 oAC_perms.formatResult = custom_formatter;
251 252 oAC_owner.formatResult = custom_formatter;
252 253
253 254 // Helper function for the formatter
254 255 var highlightMatch = function(full, snippet, matchindex) {
255 256 return full.substring(0, matchindex) +
256 257 "<span class='match'>" +
257 258 full.substr(matchindex, snippet.length) +
258 259 "</span>" +
259 260 full.substring(matchindex + snippet.length);
260 261 };
261 262
262 263 var myHandler = function(sType, aArgs) {
263 264 var myAC = aArgs[0]; // reference back to the AC instance
264 265 var elLI = aArgs[1]; // reference to the selected LI element
265 266 var oData = aArgs[2]; // object literal of selected item's result data
266 267 myAC.getInputEl().value = oData.nname;
267 268 };
268 269
269 270 oAC_perms.itemSelectEvent.subscribe(myHandler);
270 271 oAC_owner.itemSelectEvent.subscribe(myHandler);
271 272
272 273 return {
273 274 oDS: oDS,
274 275 oAC_perms: oAC_perms,
275 276 oAC_owner: oAC_owner,
276 277 };
277 278 }();
278 279
279 280 </script>
280 281
281 282 </div>
282 283 </%def> No newline at end of file
@@ -1,178 +1,180 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('Settings administration')} - ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; ${_('Settings')}
10 10 </%def>
11 11
12 12 <%def name="page_nav()">
13 13 ${self.menu('admin')}
14 14 </%def>
15 15
16 16 <%def name="main()">
17 17 <div class="box">
18 18 <!-- box / title -->
19 19 <div class="title">
20 20 ${self.breadcrumbs()}
21 21 </div>
22 22 <!-- end box / title -->
23 23
24 24 <h3>${_('Remap and rescan repositories')}</h3>
25 25 ${h.form(url('admin_setting', setting_id='mapping'),method='put')}
26 26 <div class="form">
27 27 <!-- fields -->
28 28
29 29 <div class="fields">
30 30 <div class="field">
31 31 <div class="label label-checkbox">
32 32 <label for="destroy">${_('rescan option')}:</label>
33 33 </div>
34 34 <div class="checkboxes">
35 35 <div class="checkbox">
36 36 ${h.checkbox('destroy',True)}
37 37 <label for="checkbox-1">
38 38 <span class="tooltip" tooltip_title="${h.tooltip(_('In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it.'))}">
39 39 ${_('destroy old data')}</span> </label>
40 40 </div>
41 41 </div>
42 42 </div>
43 43
44 44 <div class="buttons">
45 ${h.submit('rescan','rescan repositories',class_="ui-button ui-widget ui-state-default ui-corner-all")}
45 ${h.submit('rescan','Rescan repositories',class_="ui-button ui-widget ui-state-default ui-corner-all")}
46 46 </div>
47 47 </div>
48 48 </div>
49 49 ${h.end_form()}
50 50
51 51 <h3>${_('Whoosh indexing')}</h3>
52 52 ${h.form(url('admin_setting', setting_id='whoosh'),method='put')}
53 53 <div class="form">
54 54 <!-- fields -->
55 55
56 56 <div class="fields">
57 57 <div class="field">
58 58 <div class="label label-checkbox">
59 59 <label for="destroy">${_('index build option')}:</label>
60 60 </div>
61 61 <div class="checkboxes">
62 62 <div class="checkbox">
63 63 ${h.checkbox('full_index',True)}
64 64 <label for="checkbox-1">${_('build from scratch')}</label>
65 65 </div>
66 66 </div>
67 67 </div>
68 68
69 69 <div class="buttons">
70 ${h.submit('reindex','reindex',class_="ui-button ui-widget ui-state-default ui-corner-all")}
70 ${h.submit('reindex','Reindex',class_="ui-button ui-widget ui-state-default ui-corner-all")}
71 71 </div>
72 72 </div>
73 73 </div>
74 74 ${h.end_form()}
75 75
76 76 <h3>${_('Global application settings')}</h3>
77 77 ${h.form(url('admin_setting', setting_id='global'),method='put')}
78 78 <div class="form">
79 79 <!-- fields -->
80 80
81 81 <div class="fields">
82 82
83 83 <div class="field">
84 84 <div class="label">
85 85 <label for="rhodecode_title">${_('Application name')}:</label>
86 86 </div>
87 87 <div class="input">
88 88 ${h.text('rhodecode_title',size=30)}
89 89 </div>
90 90 </div>
91 91
92 92 <div class="field">
93 93 <div class="label">
94 94 <label for="rhodecode_realm">${_('Realm text')}:</label>
95 95 </div>
96 96 <div class="input">
97 97 ${h.text('rhodecode_realm',size=30)}
98 98 </div>
99 99 </div>
100 100
101 101 <div class="buttons">
102 ${h.submit('save','save settings',class_="ui-button ui-widget ui-state-default ui-corner-all")}
102 ${h.submit('save','Save settings',class_="ui-button ui-widget ui-state-default ui-corner-all")}
103 ${h.reset('reset','Reset',class_="ui-button ui-widget ui-state-default ui-corner-all")}
103 104 </div>
104 105 </div>
105 106 </div>
106 107 ${h.end_form()}
107 108
108 109 <h3>${_('Mercurial settings')}</h3>
109 110 ${h.form(url('admin_setting', setting_id='mercurial'),method='put')}
110 111 <div class="form">
111 112 <!-- fields -->
112 113
113 114 <div class="fields">
114 115
115 116 <div class="field">
116 117 <div class="label label-checkbox">
117 118 <label for="web_push_ssl">${_('Web')}:</label>
118 119 </div>
119 120 <div class="checkboxes">
120 121 <div class="checkbox">
121 122 ${h.checkbox('web_push_ssl','true')}
122 123 <label for="web_push_ssl">${_('require ssl for pushing')}</label>
123 124 </div>
124 125 </div>
125 126 </div>
126 127
127 128 <div class="field">
128 129 <div class="label label-checkbox">
129 130 <label for="web_push_ssl">${_('Hooks')}:</label>
130 131 </div>
131 132 <div class="checkboxes">
132 133 <div class="checkbox">
133 134 ${h.checkbox('hooks_changegroup_update','True')}
134 135 <label for="hooks_changegroup_update">${_('Update repository after push (hg update)')}</label>
135 136 </div>
136 137 <div class="checkbox">
137 138 ${h.checkbox('hooks_changegroup_repo_size','True')}
138 139 <label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
139 140 </div>
140 141 <div class="checkbox">
141 142 ${h.checkbox('hooks_pretxnchangegroup_push_logger','True')}
142 143 <label for="hooks_pretxnchangegroup_push_logger">${_('Log user push commands')}</label>
143 144 </div>
144 145 <div class="checkbox">
145 146 ${h.checkbox('hooks_preoutgoing_pull_logger','True')}
146 147 <label for="hooks_preoutgoing_pull_logger">${_('Log user pull commands')}</label>
147 148 </div>
148 149 </div>
149 150 </div>
150 151
151 152 <div class="field">
152 153 <div class="label">
153 154 <label for="paths_root_path">${_('Repositories location')}:</label>
154 155 </div>
155 156 <div class="input">
156 157 ${h.text('paths_root_path',size=30,readonly="readonly")}
157 158 <span id="path_unlock" class="tooltip"
158 159 tooltip_title="${h.tooltip(_('This a crucial application setting. If You really sure you need to change this, you must restart application in order to make this settings take effect. Click this label to unlock.'))}">
159 160 ${_('unlock')}</span>
160 161 </div>
161 162 </div>
162 163
163 164 <div class="buttons">
164 ${h.submit('save','save settings',class_="ui-button ui-widget ui-state-default ui-corner-all")}
165 ${h.submit('save','Save settings',class_="ui-button ui-widget ui-state-default ui-corner-all")}
166 ${h.reset('reset','Reset',class_="ui-button ui-widget ui-state-default ui-corner-all")}
165 167 </div>
166 168 </div>
167 169 </div>
168 170 ${h.end_form()}
169 171
170 172 <script type="text/javascript">
171 173 YAHOO.util.Event.onDOMReady(function(){
172 174 YAHOO.util.Event.addListener('path_unlock','click',function(){
173 175 YAHOO.util.Dom.get('paths_root_path').removeAttribute('readonly');
174 176 });
175 177 });
176 178 </script>
177 179 </div>
178 180 </%def>
@@ -1,110 +1,111 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('Edit user')} ${c.user.username} - ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 ${h.link_to(_('Admin'),h.url('admin_home'))}
10 10 &raquo;
11 11 ${h.link_to(_('Users'),h.url('users'))}
12 12 &raquo;
13 13 ${_('edit')} "${c.user.username}"
14 14 </%def>
15 15
16 16 <%def name="page_nav()">
17 17 ${self.menu('admin')}
18 18 </%def>
19 19
20 20 <%def name="main()">
21 21 <div class="box">
22 22 <!-- box / title -->
23 23 <div class="title">
24 24 ${self.breadcrumbs()}
25 25 </div>
26 26 <!-- end box / title -->
27 27 ${h.form(url('user', id=c.user.user_id),method='put')}
28 28 <div class="form">
29 29 <!-- fields -->
30 30 <div class="fields">
31 31 <div class="field">
32 32 <div class="gravatar_box">
33 33 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
34 34 <p>
35 35 <strong>Change your avatar at <a href="http://gravatar.com">gravatar.com</a></strong><br/>
36 36 ${_('Using')} ${c.user.email}
37 37 </p>
38 38 </div>
39 39 </div>
40 40
41 41 <div class="field">
42 42 <div class="label">
43 43 <label for="username">${_('Username')}:</label>
44 44 </div>
45 45 <div class="input">
46 46 ${h.text('username',class_='small')}
47 47 </div>
48 48 </div>
49 49
50 50 <div class="field">
51 51 <div class="label">
52 52 <label for="new_password">${_('New password')}:</label>
53 53 </div>
54 54 <div class="input">
55 55 ${h.password('new_password',class_='small')}
56 56 </div>
57 57 </div>
58 58
59 59 <div class="field">
60 60 <div class="label">
61 61 <label for="name">${_('First Name')}:</label>
62 62 </div>
63 63 <div class="input">
64 64 ${h.text('name',class_='small')}
65 65 </div>
66 66 </div>
67 67
68 68 <div class="field">
69 69 <div class="label">
70 70 <label for="lastname">${_('Last Name')}:</label>
71 71 </div>
72 72 <div class="input">
73 73 ${h.text('lastname',class_='small')}
74 74 </div>
75 75 </div>
76 76
77 77 <div class="field">
78 78 <div class="label">
79 79 <label for="email">${_('Email')}:</label>
80 80 </div>
81 81 <div class="input">
82 82 ${h.text('email',class_='small')}
83 83 </div>
84 84 </div>
85 85
86 86 <div class="field">
87 87 <div class="label label-checkbox">
88 88 <label for="active">${_('Active')}:</label>
89 89 </div>
90 90 <div class="checkboxes">
91 91 ${h.checkbox('active',value=True)}
92 92 </div>
93 93 </div>
94 94
95 95 <div class="field">
96 96 <div class="label label-checkbox">
97 97 <label for="admin">${_('Admin')}:</label>
98 98 </div>
99 99 <div class="checkboxes">
100 100 ${h.checkbox('admin',value=True)}
101 101 </div>
102 102 </div>
103 103 <div class="buttons">
104 ${h.submit('save','save',class_="ui-button ui-widget ui-state-default ui-corner-all")}
104 ${h.submit('save','Save',class_="ui-button ui-widget ui-state-default ui-corner-all")}
105 ${h.reset('reset','Reset',class_="ui-button ui-widget ui-state-default ui-corner-all")}
105 106 </div>
106 107 </div>
107 108 </div>
108 109 ${h.end_form()}
109 110 </div>
110 111 </%def> No newline at end of file
@@ -1,188 +1,192 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('My account')} ${c.rhodecode_user.username} - ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 ${_('My Account')}
10 10 </%def>
11 11
12 12 <%def name="page_nav()">
13 13 ${self.menu('admin')}
14 14 </%def>
15 15
16 16 <%def name="main()">
17 17
18 18 <div class="box box-left">
19 19 <!-- box / title -->
20 20 <div class="title">
21 21 ${self.breadcrumbs()}
22 22 </div>
23 23 <!-- end box / title -->
24 24 <div class="ui-tabs-panel ui-widget-content ui-corner-bottom">
25 25 ${h.form(url('admin_settings_my_account_update'),method='put')}
26 26 <div class="form">
27 27 <div class="fields">
28 28 <div class="field">
29 29 <div class="label">
30 30 <label for="username">${_('Username')}:</label>
31 31 </div>
32 32 <div class="input">
33 33 ${h.text('username')}
34 34 </div>
35 35 </div>
36 36
37 37 <div class="field">
38 38 <div class="label">
39 39 <label for="new_password">${_('New password')}:</label>
40 40 </div>
41 41 <div class="input">
42 42 ${h.password('new_password')}
43 43 </div>
44 44 </div>
45 45
46 46 <div class="field">
47 47 <div class="label">
48 48 <label for="name">${_('First Name')}:</label>
49 49 </div>
50 50 <div class="input">
51 51 ${h.text('name')}
52 52 </div>
53 53 </div>
54 54
55 55 <div class="field">
56 56 <div class="label">
57 57 <label for="lastname">${_('Last Name')}:</label>
58 58 </div>
59 59 <div class="input">
60 60 ${h.text('lastname')}
61 61 </div>
62 62 </div>
63 63
64 64 <div class="field">
65 65 <div class="label">
66 66 <label for="email">${_('Email')}:</label>
67 67 </div>
68 68 <div class="input">
69 69 ${h.text('email')}
70 70 </div>
71 71 </div>
72 72
73 73 <div class="buttons">
74 ${h.submit('save','save',class_="ui-button ui-widget ui-state-default ui-corner-all")}
74 ${h.submit('save','Save',class_="ui-button ui-widget ui-state-default ui-corner-all")}
75 ${h.reset('reset','Reset',class_="ui-button ui-widget ui-state-default ui-corner-all")}
76
77
78
75 79 </div>
76 80 </div>
77 81 </div>
78 82 ${h.end_form()}
79 83 </div>
80 84 </div>
81 85
82 86 <div class="box box-right">
83 87 <!-- box / title -->
84 88 <div class="title">
85 89 <h5>${_('My repositories')}
86 90 <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...')}"/>
87 91 </h5>
88 92 </div>
89 93 <!-- end box / title -->
90 94 <div class="table">
91 95 <table>
92 96 <thead>
93 97 <tr>
94 98 <th class="left">${_('Name')}</th>
95 99 <th class="left">${_('revision')}</th>
96 100 <th colspan="2" class="left">${_('action')}</th>
97 101 </thead>
98 102 <tbody>
99 103 %if c.user_repos:
100 104 %for repo in c.user_repos:
101 105 <tr>
102 106 <td>
103 107 %if repo['repo'].dbrepo.repo_type =='hg':
104 108 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
105 109 %elif repo['repo'].dbrepo.repo_type =='git':
106 110 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
107 111 %else:
108 112
109 113 %endif
110 114 %if repo['repo'].dbrepo.private:
111 115 <img class="icon" alt="${_('private')}" src="/images/icons/lock.png"/>
112 116 %else:
113 117 <img class="icon" alt="${_('public')}" src="/images/icons/lock_open.png"/>
114 118 %endif
115 119
116 120 ${h.link_to(repo['repo'].name, h.url('summary_home',repo_name=repo['repo'].name),class_="repo_name")}
117 121 %if repo['repo'].dbrepo.fork:
118 122 <a href="${h.url('summary_home',repo_name=repo['repo'].dbrepo.fork.repo_name)}">
119 123 <img class="icon" alt="${_('public')}"
120 124 title="${_('Fork of')} ${repo['repo'].dbrepo.fork.repo_name}"
121 125 src="/images/icons/arrow_divide.png"/></a>
122 126 %endif
123 127 </td>
124 128 <td><span class="tooltip" tooltip_title="${repo['repo'].last_change}">${("r%s:%s") % (h.get_changeset_safe(repo['repo'],'tip').revision,h.short_id(h.get_changeset_safe(repo['repo'],'tip').raw_id))}</span></td>
125 129 <td><a href="${h.url('repo_settings_home',repo_name=repo['repo'].name)}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="/images/icons/application_form_edit.png"/></a></td>
126 130 <td>
127 131 ${h.form(url('repo_settings_delete', repo_name=repo['repo'].name),method='delete')}
128 132 ${h.submit('remove_%s' % repo['repo'].name,'',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
129 133 ${h.end_form()}
130 134 </td>
131 135 </tr>
132 136 %endfor
133 137 %else:
134 138 ${_('No repositories yet')}
135 139 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
136 140 ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'))}
137 141 %endif
138 142 %endif
139 143 </tbody>
140 144 </table>
141 145 </div>
142 146
143 147 </div>
144 148 <script type="text/javascript">
145 149 var D = YAHOO.util.Dom;
146 150 var E = YAHOO.util.Event;
147 151 var S = YAHOO.util.Selector;
148 152
149 153 var q_filter = D.get('q_filter');
150 154 var F = YAHOO.namespace('q_filter');
151 155
152 156 E.on(q_filter,'click',function(){
153 157 q_filter.value = '';
154 158 });
155 159
156 160 F.filterTimeout = null;
157 161
158 162 F.updateFilter = function() {
159 163 // Reset timeout
160 164 F.filterTimeout = null;
161 165
162 166 var obsolete = [];
163 167 var nodes = S.query('div.table tr td a.repo_name');
164 168 var req = D.get('q_filter').value;
165 169 for (n in nodes){
166 170 D.setStyle(nodes[n].parentNode.parentNode,'display','')
167 171 }
168 172 if (req){
169 173 for (n in nodes){
170 174 if (nodes[n].innerHTML.toLowerCase().indexOf(req) == -1) {
171 175 obsolete.push(nodes[n]);
172 176 }
173 177 }
174 178 if(obsolete){
175 179 for (n in obsolete){
176 180 D.setStyle(obsolete[n].parentNode.parentNode,'display','none');
177 181 }
178 182 }
179 183 }
180 184 }
181 185
182 186 E.on(q_filter,'keyup',function(e){
183 187 clearTimeout(F.filterTimeout);
184 188 setTimeout(F.updateFilter,600);
185 189 });
186 190
187 191 </script>
188 192 </%def> No newline at end of file
@@ -1,262 +1,263 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${c.repo_name} ${_('Settings')} - ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 ${h.link_to(c.repo_info.repo_name,h.url('summary_home',repo_name=c.repo_info.repo_name))}
10 10 &raquo;
11 11 ${_('Settings')}
12 12 </%def>
13 13
14 14 <%def name="page_nav()">
15 15 ${self.menu('settings')}
16 16 </%def>
17 17 <%def name="main()">
18 18 <div class="box">
19 19 <!-- box / title -->
20 20 <div class="title">
21 21 ${self.breadcrumbs()}
22 22 </div>
23 23 ${h.form(url('repo_settings_update', repo_name=c.repo_info.repo_name),method='put')}
24 24 <div class="form">
25 25 <!-- fields -->
26 26 <div class="fields">
27 27 <div class="field">
28 28 <div class="label">
29 29 <label for="repo_name">${_('Name')}:</label>
30 30 </div>
31 31 <div class="input input-medium">
32 32 ${h.text('repo_name',class_="small")}
33 33 </div>
34 34 </div>
35 35
36 36 <div class="field">
37 37 <div class="label label-textarea">
38 38 <label for="description">${_('Description')}:</label>
39 39 </div>
40 40 <div class="textarea text-area editor">
41 41 ${h.textarea('description',cols=23,rows=5)}
42 42 </div>
43 43 </div>
44 44
45 45 <div class="field">
46 46 <div class="label label-checkbox">
47 47 <label for="private">${_('Private')}:</label>
48 48 </div>
49 49 <div class="checkboxes">
50 50 ${h.checkbox('private',value="True")}
51 51 </div>
52 52 </div>
53 53
54 54 <div class="field">
55 55 <div class="label">
56 56 <label for="">${_('Permissions')}:</label>
57 57 </div>
58 58 <div class="input">
59 59 <table id="permissions_manage">
60 60 <tr>
61 61 <td>${_('none')}</td>
62 62 <td>${_('read')}</td>
63 63 <td>${_('write')}</td>
64 64 <td>${_('admin')}</td>
65 65 <td>${_('user')}</td>
66 66 <td></td>
67 67 </tr>
68 68
69 69 %for r2p in c.repo_info.repo_to_perm:
70 70 %if r2p.user.username =='default' and c.repo_info.private:
71 71 <tr>
72 72 <td colspan="4">
73 73 <span class="private_repo_msg">
74 74 ${_('private repository')}
75 75 </span>
76 76 </td>
77 77 <td class="private_repo_msg">${r2p.user.username}</td>
78 78 </tr>
79 79 %else:
80 80 <tr id="id${id(r2p.user.username)}">
81 81 <td>${h.radio('perm_%s' % r2p.user.username,'repository.none')}</td>
82 82 <td>${h.radio('perm_%s' % r2p.user.username,'repository.read')}</td>
83 83 <td>${h.radio('perm_%s' % r2p.user.username,'repository.write')}</td>
84 84 <td>${h.radio('perm_%s' % r2p.user.username,'repository.admin')}</td>
85 85 <td>${r2p.user.username}</td>
86 86 <td>
87 87 %if r2p.user.username !='default':
88 88 <span class="delete_icon action_button" onclick="ajaxAction(${r2p.user.user_id},'${'id%s'%id(r2p.user.username)}')">
89 89 <script type="text/javascript">
90 90 function ajaxAction(user_id,field_id){
91 91 var sUrl = "${h.url('delete_repo_user',repo_name=c.repo_name)}";
92 92 var callback = { success:function(o){
93 93 var tr = YAHOO.util.Dom.get(String(field_id));
94 94 tr.parentNode.removeChild(tr);},failure:function(o){
95 95 alert("${_('Failed to remove user')}");},};
96 96 var postData = '_method=delete&user_id='+user_id;
97 97 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);};
98 98 </script>
99 99 </span>
100 100 %endif
101 101 </td>
102 102 </tr>
103 103 %endif
104 104 %endfor
105 105
106 106
107 107 <tr id="add_perm_input">
108 108 <td>${h.radio('perm_new_user','repository.none')}</td>
109 109 <td>${h.radio('perm_new_user','repository.read')}</td>
110 110 <td>${h.radio('perm_new_user','repository.write')}</td>
111 111 <td>${h.radio('perm_new_user','repository.admin')}</td>
112 112 <td class='ac'>
113 113 <div class="perm_ac" id="perm_ac">
114 114 ${h.text('perm_new_user_name',class_='yui-ac-input')}
115 115 <div id="perm_container"></div>
116 116 </div>
117 117 </td>
118 118 <td></td>
119 119 </tr>
120 120 <tr>
121 121 <td colspan="6">
122 122 <span id="add_perm" class="add_icon" style="cursor: pointer;">
123 123 ${_('Add another user')}
124 124 </span>
125 125 </td>
126 126 </tr>
127 127 </table>
128 128 </div>
129 129
130 130 <div class="buttons">
131 ${h.submit('update','update',class_="ui-button ui-widget ui-state-default ui-corner-all")}
131 ${h.submit('update','Update',class_="ui-button ui-widget ui-state-default ui-corner-all")}
132 ${h.reset('reset','Reset',class_="ui-button ui-widget ui-state-default ui-corner-all")}
132 133 </div>
133 134 </div>
134 135 </div>
135 136 ${h.end_form()}
136 137 <script type="text/javascript">
137 138 YAHOO.util.Event.onDOMReady(function(){
138 139 var D = YAHOO.util.Dom;
139 140 if(!D.hasClass('perm_new_user_name','error')){
140 141 D.setStyle('add_perm_input','display','none');
141 142 }
142 143 YAHOO.util.Event.addListener('add_perm','click',function(){
143 144 D.setStyle('add_perm_input','display','');
144 145 D.setStyle('add_perm','opacity','0.6');
145 146 D.setStyle('add_perm','cursor','default');
146 147 });
147 148 });
148 149 </script>
149 150 <script type="text/javascript">
150 151 YAHOO.example.FnMultipleFields = function(){
151 152 var myContacts = ${c.users_array|n}
152 153
153 154 // Define a custom search function for the DataSource
154 155 var matchNames = function(sQuery) {
155 156 // Case insensitive matching
156 157 var query = sQuery.toLowerCase(),
157 158 contact,
158 159 i=0,
159 160 l=myContacts.length,
160 161 matches = [];
161 162
162 163 // Match against each name of each contact
163 164 for(; i<l; i++) {
164 165 contact = myContacts[i];
165 166 if((contact.fname.toLowerCase().indexOf(query) > -1) ||
166 167 (contact.lname.toLowerCase().indexOf(query) > -1) ||
167 168 (contact.nname && (contact.nname.toLowerCase().indexOf(query) > -1))) {
168 169 matches[matches.length] = contact;
169 170 }
170 171 }
171 172
172 173 return matches;
173 174 };
174 175
175 176 // Use a FunctionDataSource
176 177 var oDS = new YAHOO.util.FunctionDataSource(matchNames);
177 178 oDS.responseSchema = {
178 179 fields: ["id", "fname", "lname", "nname"]
179 180 }
180 181
181 182 // Instantiate AutoComplete for perms
182 183 var oAC_perms = new YAHOO.widget.AutoComplete("perm_new_user_name", "perm_container", oDS);
183 184 oAC_perms.useShadow = false;
184 185 oAC_perms.resultTypeList = false;
185 186
186 187 // Instantiate AutoComplete for owner
187 188 var oAC_owner = new YAHOO.widget.AutoComplete("user", "owner_container", oDS);
188 189 oAC_owner.useShadow = false;
189 190 oAC_owner.resultTypeList = false;
190 191
191 192
192 193 // Custom formatter to highlight the matching letters
193 194 var custom_formatter = function(oResultData, sQuery, sResultMatch) {
194 195 var query = sQuery.toLowerCase(),
195 196 fname = oResultData.fname,
196 197 lname = oResultData.lname,
197 198 nname = oResultData.nname || "", // Guard against null value
198 199 query = sQuery.toLowerCase(),
199 200 fnameMatchIndex = fname.toLowerCase().indexOf(query),
200 201 lnameMatchIndex = lname.toLowerCase().indexOf(query),
201 202 nnameMatchIndex = nname.toLowerCase().indexOf(query),
202 203 displayfname, displaylname, displaynname;
203 204
204 205 if(fnameMatchIndex > -1) {
205 206 displayfname = highlightMatch(fname, query, fnameMatchIndex);
206 207 }
207 208 else {
208 209 displayfname = fname;
209 210 }
210 211
211 212 if(lnameMatchIndex > -1) {
212 213 displaylname = highlightMatch(lname, query, lnameMatchIndex);
213 214 }
214 215 else {
215 216 displaylname = lname;
216 217 }
217 218
218 219 if(nnameMatchIndex > -1) {
219 220 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
220 221 }
221 222 else {
222 223 displaynname = nname ? "(" + nname + ")" : "";
223 224 }
224 225
225 226 return displayfname + " " + displaylname + " " + displaynname;
226 227
227 228 };
228 229 oAC_perms.formatResult = custom_formatter;
229 230 oAC_owner.formatResult = custom_formatter;
230 231
231 232 // Helper function for the formatter
232 233 var highlightMatch = function(full, snippet, matchindex) {
233 234 return full.substring(0, matchindex) +
234 235 "<span class='match'>" +
235 236 full.substr(matchindex, snippet.length) +
236 237 "</span>" +
237 238 full.substring(matchindex + snippet.length);
238 239 };
239 240
240 241 var myHandler = function(sType, aArgs) {
241 242 var myAC = aArgs[0]; // reference back to the AC instance
242 243 var elLI = aArgs[1]; // reference to the selected LI element
243 244 var oData = aArgs[2]; // object literal of selected item's result data
244 245 myAC.getInputEl().value = oData.nname;
245 246 };
246 247
247 248 oAC_perms.itemSelectEvent.subscribe(myHandler);
248 249 //oAC_owner.itemSelectEvent.subscribe(myHandler);
249 250
250 251 return {
251 252 oDS: oDS,
252 253 oAC_perms: oAC_perms,
253 254 oAC_owner: oAC_owner,
254 255 };
255 256 }();
256 257
257 258 </script>
258 259 </div>
259 260 </div>
260 261 </%def>
261 262
262 263
General Comments 0
You need to be logged in to leave comments. Login now