##// END OF EJS Templates
fix casings
Mads Kiilerich -
r3516:c44645e5 beta
parent child Browse files
Show More
@@ -1,2173 +1,2173 b''
1 1 /**
2 2 RhodeCode JS Files
3 3 **/
4 4
5 5 if (typeof console == "undefined" || typeof console.log == "undefined"){
6 6 console = { log: function() {} }
7 7 }
8 8
9 9
10 10 var str_repeat = function(i, m) {
11 11 for (var o = []; m > 0; o[--m] = i);
12 12 return o.join('');
13 13 };
14 14
15 15 /**
16 16 * INJECT .format function into String
17 17 * Usage: "My name is {0} {1}".format("Johny","Bravo")
18 18 * Return "My name is Johny Bravo"
19 19 * Inspired by https://gist.github.com/1049426
20 20 */
21 21 String.prototype.format = function() {
22 22
23 23 function format() {
24 24 var str = this;
25 25 var len = arguments.length+1;
26 26 var safe = undefined;
27 27 var arg = undefined;
28 28
29 29 // For each {0} {1} {n...} replace with the argument in that position. If
30 30 // the argument is an object or an array it will be stringified to JSON.
31 31 for (var i=0; i < len; arg = arguments[i++]) {
32 32 safe = typeof arg === 'object' ? JSON.stringify(arg) : arg;
33 33 str = str.replace(RegExp('\\{'+(i-1)+'\\}', 'g'), safe);
34 34 }
35 35 return str;
36 36 }
37 37
38 38 // Save a reference of what may already exist under the property native.
39 39 // Allows for doing something like: if("".format.native) { /* use native */ }
40 40 format.native = String.prototype.format;
41 41
42 42 // Replace the prototype property
43 43 return format;
44 44
45 45 }();
46 46
47 47 String.prototype.strip = function(char) {
48 48 if(char === undefined){
49 49 char = '\\s';
50 50 }
51 51 return this.replace(new RegExp('^'+char+'+|'+char+'+$','g'), '');
52 52 }
53 53 String.prototype.lstrip = function(char) {
54 54 if(char === undefined){
55 55 char = '\\s';
56 56 }
57 57 return this.replace(new RegExp('^'+char+'+'),'');
58 58 }
59 59 String.prototype.rstrip = function(char) {
60 60 if(char === undefined){
61 61 char = '\\s';
62 62 }
63 63 return this.replace(new RegExp(''+char+'+$'),'');
64 64 }
65 65
66 66
67 67 if(!Array.prototype.indexOf) {
68 68 Array.prototype.indexOf = function(needle) {
69 69 for(var i = 0; i < this.length; i++) {
70 70 if(this[i] === needle) {
71 71 return i;
72 72 }
73 73 }
74 74 return -1;
75 75 };
76 76 }
77 77
78 78 // IE(CRAP) doesn't support previousElementSibling
79 79 var prevElementSibling = function( el ) {
80 80 if( el.previousElementSibling ) {
81 81 return el.previousElementSibling;
82 82 } else {
83 83 while( el = el.previousSibling ) {
84 84 if( el.nodeType === 1 ) return el;
85 85 }
86 86 }
87 87 }
88 88
89 89 /**
90 90 * SmartColorGenerator
91 91 *
92 92 *usage::
93 93 * var CG = new ColorGenerator();
94 94 * var col = CG.getColor(key); //returns array of RGB
95 95 * 'rgb({0})'.format(col.join(',')
96 96 *
97 97 * @returns {ColorGenerator}
98 98 */
99 99 var ColorGenerator = function(){
100 100 this.GOLDEN_RATIO = 0.618033988749895;
101 101 this.CURRENT_RATIO = 0.22717784590367374 // this can be random
102 102 this.HSV_1 = 0.75;//saturation
103 103 this.HSV_2 = 0.95;
104 104 this.color;
105 105 this.cacheColorMap = {};
106 106 };
107 107
108 108 ColorGenerator.prototype = {
109 109 getColor:function(key){
110 110 if(this.cacheColorMap[key] !== undefined){
111 111 return this.cacheColorMap[key];
112 112 }
113 113 else{
114 114 this.cacheColorMap[key] = this.generateColor();
115 115 return this.cacheColorMap[key];
116 116 }
117 117 },
118 118 _hsvToRgb:function(h,s,v){
119 119 if (s == 0.0)
120 120 return [v, v, v];
121 121 i = parseInt(h * 6.0)
122 122 f = (h * 6.0) - i
123 123 p = v * (1.0 - s)
124 124 q = v * (1.0 - s * f)
125 125 t = v * (1.0 - s * (1.0 - f))
126 126 i = i % 6
127 127 if (i == 0)
128 128 return [v, t, p]
129 129 if (i == 1)
130 130 return [q, v, p]
131 131 if (i == 2)
132 132 return [p, v, t]
133 133 if (i == 3)
134 134 return [p, q, v]
135 135 if (i == 4)
136 136 return [t, p, v]
137 137 if (i == 5)
138 138 return [v, p, q]
139 139 },
140 140 generateColor:function(){
141 141 this.CURRENT_RATIO = this.CURRENT_RATIO+this.GOLDEN_RATIO;
142 142 this.CURRENT_RATIO = this.CURRENT_RATIO %= 1;
143 143 HSV_tuple = [this.CURRENT_RATIO, this.HSV_1, this.HSV_2]
144 144 RGB_tuple = this._hsvToRgb(HSV_tuple[0],HSV_tuple[1],HSV_tuple[2]);
145 145 function toRgb(v){
146 146 return ""+parseInt(v*256)
147 147 }
148 148 return [toRgb(RGB_tuple[0]),toRgb(RGB_tuple[1]),toRgb(RGB_tuple[2])];
149 149
150 150 }
151 151 }
152 152
153 153 /**
154 154 * PyRoutesJS
155 155 *
156 156 * Usage pyroutes.url('mark_error_fixed',{"error_id":error_id}) // /mark_error_fixed/<error_id>
157 157 */
158 158 var pyroutes = (function() {
159 159 // access global map defined in special file pyroutes
160 160 var matchlist = PROUTES_MAP;
161 161 var sprintf = (function() {
162 162 function get_type(variable) {
163 163 return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
164 164 }
165 165 function str_repeat(input, multiplier) {
166 166 for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
167 167 return output.join('');
168 168 }
169 169
170 170 var str_format = function() {
171 171 if (!str_format.cache.hasOwnProperty(arguments[0])) {
172 172 str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
173 173 }
174 174 return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
175 175 };
176 176
177 177 str_format.format = function(parse_tree, argv) {
178 178 var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
179 179 for (i = 0; i < tree_length; i++) {
180 180 node_type = get_type(parse_tree[i]);
181 181 if (node_type === 'string') {
182 182 output.push(parse_tree[i]);
183 183 }
184 184 else if (node_type === 'array') {
185 185 match = parse_tree[i]; // convenience purposes only
186 186 if (match[2]) { // keyword argument
187 187 arg = argv[cursor];
188 188 for (k = 0; k < match[2].length; k++) {
189 189 if (!arg.hasOwnProperty(match[2][k])) {
190 190 throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
191 191 }
192 192 arg = arg[match[2][k]];
193 193 }
194 194 }
195 195 else if (match[1]) { // positional argument (explicit)
196 196 arg = argv[match[1]];
197 197 }
198 198 else { // positional argument (implicit)
199 199 arg = argv[cursor++];
200 200 }
201 201
202 202 if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
203 203 throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
204 204 }
205 205 switch (match[8]) {
206 206 case 'b': arg = arg.toString(2); break;
207 207 case 'c': arg = String.fromCharCode(arg); break;
208 208 case 'd': arg = parseInt(arg, 10); break;
209 209 case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
210 210 case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
211 211 case 'o': arg = arg.toString(8); break;
212 212 case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
213 213 case 'u': arg = Math.abs(arg); break;
214 214 case 'x': arg = arg.toString(16); break;
215 215 case 'X': arg = arg.toString(16).toUpperCase(); break;
216 216 }
217 217 arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
218 218 pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
219 219 pad_length = match[6] - String(arg).length;
220 220 pad = match[6] ? str_repeat(pad_character, pad_length) : '';
221 221 output.push(match[5] ? arg + pad : pad + arg);
222 222 }
223 223 }
224 224 return output.join('');
225 225 };
226 226
227 227 str_format.cache = {};
228 228
229 229 str_format.parse = function(fmt) {
230 230 var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
231 231 while (_fmt) {
232 232 if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
233 233 parse_tree.push(match[0]);
234 234 }
235 235 else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
236 236 parse_tree.push('%');
237 237 }
238 238 else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
239 239 if (match[2]) {
240 240 arg_names |= 1;
241 241 var field_list = [], replacement_field = match[2], field_match = [];
242 242 if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
243 243 field_list.push(field_match[1]);
244 244 while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
245 245 if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
246 246 field_list.push(field_match[1]);
247 247 }
248 248 else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
249 249 field_list.push(field_match[1]);
250 250 }
251 251 else {
252 252 throw('[sprintf] huh?');
253 253 }
254 254 }
255 255 }
256 256 else {
257 257 throw('[sprintf] huh?');
258 258 }
259 259 match[2] = field_list;
260 260 }
261 261 else {
262 262 arg_names |= 2;
263 263 }
264 264 if (arg_names === 3) {
265 265 throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
266 266 }
267 267 parse_tree.push(match);
268 268 }
269 269 else {
270 270 throw('[sprintf] huh?');
271 271 }
272 272 _fmt = _fmt.substring(match[0].length);
273 273 }
274 274 return parse_tree;
275 275 };
276 276
277 277 return str_format;
278 278 })();
279 279
280 280 var vsprintf = function(fmt, argv) {
281 281 argv.unshift(fmt);
282 282 return sprintf.apply(null, argv);
283 283 };
284 284 return {
285 285 'url': function(route_name, params) {
286 286 var result = route_name;
287 287 if (typeof(params) != 'object'){
288 288 params = {};
289 289 }
290 290 if (matchlist.hasOwnProperty(route_name)) {
291 291 var route = matchlist[route_name];
292 292 // param substitution
293 293 for(var i=0; i < route[1].length; i++) {
294 294
295 295 if (!params.hasOwnProperty(route[1][i]))
296 296 throw new Error(route[1][i] + ' missing in "' + route_name + '" route generation');
297 297 }
298 298 result = sprintf(route[0], params);
299 299
300 300 var ret = [];
301 301 //extra params => GET
302 302 for(param in params){
303 303 if (route[1].indexOf(param) == -1){
304 304 ret.push(encodeURIComponent(param) + "=" + encodeURIComponent(params[param]));
305 305 }
306 306 }
307 307 var _parts = ret.join("&");
308 308 if(_parts){
309 309 result = result +'?'+ _parts
310 310 }
311 311 }
312 312
313 313 return result;
314 314 },
315 315 'register': function(route_name, route_tmpl, req_params) {
316 316 if (typeof(req_params) != 'object') {
317 317 req_params = [];
318 318 }
319 319 //fix escape
320 320 route_tmpl = unescape(route_tmpl);
321 321 keys = [];
322 322 for (o in req_params){
323 323 keys.push(req_params[o])
324 324 }
325 325 matchlist[route_name] = [
326 326 route_tmpl,
327 327 keys
328 328 ]
329 329 },
330 330 '_routes': function(){
331 331 return matchlist;
332 332 }
333 333 }
334 334 })();
335 335
336 336
337 337
338 338 /**
339 339 * GLOBAL YUI Shortcuts
340 340 */
341 341 var YUC = YAHOO.util.Connect;
342 342 var YUD = YAHOO.util.Dom;
343 343 var YUE = YAHOO.util.Event;
344 344 var YUQ = YAHOO.util.Selector.query;
345 345
346 346 // defines if push state is enabled for this browser ?
347 347 var push_state_enabled = Boolean(
348 348 window.history && window.history.pushState && window.history.replaceState
349 349 && !( /* disable for versions of iOS before version 4.3 (8F190) */
350 350 (/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i).test(navigator.userAgent)
351 351 /* disable for the mercury iOS browser, or at least older versions of the webkit engine */
352 352 || (/AppleWebKit\/5([0-2]|3[0-2])/i).test(navigator.userAgent)
353 353 )
354 354 );
355 355
356 356 var _run_callbacks = function(callbacks){
357 357 if (callbacks !== undefined){
358 358 var _l = callbacks.length;
359 359 for (var i=0;i<_l;i++){
360 360 var func = callbacks[i];
361 361 if(typeof(func)=='function'){
362 362 try{
363 363 func();
364 364 }catch (err){};
365 365 }
366 366 }
367 367 }
368 368 }
369 369
370 370 /**
371 371 * Partial Ajax Implementation
372 372 *
373 373 * @param url: defines url to make partial request
374 374 * @param container: defines id of container to input partial result
375 375 * @param s_call: success callback function that takes o as arg
376 376 * o.tId
377 377 * o.status
378 378 * o.statusText
379 379 * o.getResponseHeader[ ]
380 380 * o.getAllResponseHeaders
381 381 * o.responseText
382 382 * o.responseXML
383 383 * o.argument
384 384 * @param f_call: failure callback
385 385 * @param args arguments
386 386 */
387 387 function ypjax(url,container,s_call,f_call,args){
388 388 var method='GET';
389 389 if(args===undefined){
390 390 args=null;
391 391 }
392 392
393 393 // Set special header for partial ajax == HTTP_X_PARTIAL_XHR
394 394 YUC.initHeader('X-PARTIAL-XHR',true);
395 395
396 396 // wrapper of passed callback
397 397 var s_wrapper = (function(o){
398 398 return function(o){
399 399 YUD.get(container).innerHTML=o.responseText;
400 400 YUD.setStyle(container,'opacity','1.0');
401 401 //execute the given original callback
402 402 if (s_call !== undefined){
403 403 s_call(o);
404 404 }
405 405 }
406 406 })()
407 407 YUD.setStyle(container,'opacity','0.3');
408 408 YUC.asyncRequest(method,url,{
409 409 success:s_wrapper,
410 410 failure:function(o){
411 411 console.log(o);
412 412 YUD.get(container).innerHTML='<span class="error_red">ERROR: {0}</span>'.format(o.status);
413 413 YUD.setStyle(container,'opacity','1.0');
414 414 },
415 415 cache:false
416 416 },args);
417 417
418 418 };
419 419
420 420 var ajaxGET = function(url,success) {
421 421 // Set special header for ajax == HTTP_X_PARTIAL_XHR
422 422 YUC.initHeader('X-PARTIAL-XHR',true);
423 423
424 424 var sUrl = url;
425 425 var callback = {
426 426 success: success,
427 427 failure: function (o) {
428 428 alert("error");
429 429 },
430 430 };
431 431
432 432 var request = YAHOO.util.Connect.asyncRequest('GET', sUrl, callback);
433 433 return request;
434 434 };
435 435
436 436
437 437
438 438 var ajaxPOST = function(url,postData,success) {
439 439 // Set special header for ajax == HTTP_X_PARTIAL_XHR
440 440 YUC.initHeader('X-PARTIAL-XHR',true);
441 441
442 442 var toQueryString = function(o) {
443 443 if(typeof o !== 'object') {
444 444 return false;
445 445 }
446 446 var _p, _qs = [];
447 447 for(_p in o) {
448 448 _qs.push(encodeURIComponent(_p) + '=' + encodeURIComponent(o[_p]));
449 449 }
450 450 return _qs.join('&');
451 451 };
452 452
453 453 var sUrl = url;
454 454 var callback = {
455 455 success: success,
456 456 failure: function (o) {
457 457 alert("error");
458 458 },
459 459 };
460 460 var postData = toQueryString(postData);
461 461 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
462 462 return request;
463 463 };
464 464
465 465
466 466 /**
467 467 * tooltip activate
468 468 */
469 469 var tooltip_activate = function(){
470 470 yt = YAHOO.yuitip.main;
471 471 YUE.onDOMReady(yt.init);
472 472 };
473 473
474 474 /**
475 475 * show more
476 476 */
477 477 var show_more_event = function(){
478 478 YUE.on(YUD.getElementsByClassName('show_more'),'click',function(e){
479 479 var el = e.target;
480 480 YUD.setStyle(YUD.get(el.id.substring(1)),'display','');
481 481 YUD.setStyle(el.parentNode,'display','none');
482 482 });
483 483 };
484 484
485 485 /**
486 486 * show changeset tooltip
487 487 */
488 488 var show_changeset_tooltip = function(){
489 489 YUE.on(YUD.getElementsByClassName('lazy-cs'), 'mouseover', function(e){
490 490 var target = e.currentTarget;
491 491 var rid = YUD.getAttribute(target,'raw_id');
492 492 var repo_name = YUD.getAttribute(target,'repo_name');
493 493 var ttid = 'tt-'+rid;
494 494 var success = function(o){
495 495 var json = JSON.parse(o.responseText);
496 496 YUD.addClass(target,'tooltip')
497 497 YUD.setAttribute(target, 'title',json['message']);
498 498 YAHOO.yuitip.main.show_yuitip(e, target);
499 499 }
500 500 if(rid && !YUD.hasClass(target, 'tooltip')){
501 501 YUD.setAttribute(target,'id',ttid);
502 502 YUD.setAttribute(target, 'title',_TM['loading...']);
503 503 YAHOO.yuitip.main.set_listeners(target);
504 504 YAHOO.yuitip.main.show_yuitip(e, target);
505 505 var url = pyroutes.url('changeset_info', {"repo_name":repo_name, "revision": rid});
506 506 ajaxGET(url, success)
507 507 }
508 508 });
509 509 };
510 510
511 511 var onSuccessFollow = function(target){
512 512 var f = YUD.get(target.id);
513 513 var f_cnt = YUD.get('current_followers_count');
514 514
515 515 if(YUD.hasClass(f, 'follow')){
516 516 f.setAttribute('class','following');
517 517 f.setAttribute('title',_TM['Stop following this repository']);
518 518
519 519 if(f_cnt){
520 520 var cnt = Number(f_cnt.innerHTML)+1;
521 521 f_cnt.innerHTML = cnt;
522 522 }
523 523 }
524 524 else{
525 525 f.setAttribute('class','follow');
526 526 f.setAttribute('title',_TM['Start following this repository']);
527 527 if(f_cnt){
528 528 var cnt = Number(f_cnt.innerHTML)-1;
529 529 f_cnt.innerHTML = cnt;
530 530 }
531 531 }
532 532 }
533 533
534 534 var toggleFollowingUser = function(target,fallows_user_id,token,user_id){
535 535 args = 'follows_user_id='+fallows_user_id;
536 536 args+= '&amp;auth_token='+token;
537 537 if(user_id != undefined){
538 538 args+="&amp;user_id="+user_id;
539 539 }
540 540 YUC.asyncRequest('POST',TOGGLE_FOLLOW_URL,{
541 541 success:function(o){
542 542 onSuccessFollow(target);
543 543 }
544 544 },args);
545 545 return false;
546 546 }
547 547
548 548 var toggleFollowingRepo = function(target,fallows_repo_id,token,user_id){
549 549
550 550 args = 'follows_repo_id='+fallows_repo_id;
551 551 args+= '&amp;auth_token='+token;
552 552 if(user_id != undefined){
553 553 args+="&amp;user_id="+user_id;
554 554 }
555 555 YUC.asyncRequest('POST',TOGGLE_FOLLOW_URL,{
556 556 success:function(o){
557 557 onSuccessFollow(target);
558 558 }
559 559 },args);
560 560 return false;
561 561 }
562 562
563 563 var showRepoSize = function(target, repo_name, token){
564 564 var args= 'auth_token='+token;
565 565
566 566 if(!YUD.hasClass(target, 'loaded')){
567 YUD.get(target).innerHTML = _TM['loading...'];
567 YUD.get(target).innerHTML = _TM['Loading ...'];
568 568 var url = pyroutes.url('repo_size', {"repo_name":repo_name});
569 569 YUC.asyncRequest('POST',url,{
570 570 success:function(o){
571 571 YUD.get(target).innerHTML = JSON.parse(o.responseText);
572 572 YUD.addClass(target, 'loaded');
573 573 }
574 574 },args);
575 575 }
576 576 return false;
577 577 }
578 578
579 579 /**
580 580 * TOOLTIP IMPL.
581 581 */
582 582 YAHOO.namespace('yuitip');
583 583 YAHOO.yuitip.main = {
584 584
585 585 $: YAHOO.util.Dom.get,
586 586
587 587 bgColor: '#000',
588 588 speed: 0.3,
589 589 opacity: 0.9,
590 590 offset: [15,15],
591 591 useAnim: false,
592 592 maxWidth: 600,
593 593 add_links: false,
594 594 yuitips: [],
595 595
596 596 set_listeners: function(tt){
597 597 YUE.on(tt, 'mouseover', yt.show_yuitip, tt);
598 598 YUE.on(tt, 'mousemove', yt.move_yuitip, tt);
599 599 YUE.on(tt, 'mouseout', yt.close_yuitip, tt);
600 600 },
601 601
602 602 init: function(){
603 603 yt.tipBox = yt.$('tip-box');
604 604 if(!yt.tipBox){
605 605 yt.tipBox = document.createElement('div');
606 606 document.body.appendChild(yt.tipBox);
607 607 yt.tipBox.id = 'tip-box';
608 608 }
609 609
610 610 YUD.setStyle(yt.tipBox, 'display', 'none');
611 611 YUD.setStyle(yt.tipBox, 'position', 'absolute');
612 612 if(yt.maxWidth !== null){
613 613 YUD.setStyle(yt.tipBox, 'max-width', yt.maxWidth+'px');
614 614 }
615 615
616 616 var yuitips = YUD.getElementsByClassName('tooltip');
617 617
618 618 if(yt.add_links === true){
619 619 var links = document.getElementsByTagName('a');
620 620 var linkLen = links.length;
621 621 for(i=0;i<linkLen;i++){
622 622 yuitips.push(links[i]);
623 623 }
624 624 }
625 625
626 626 var yuiLen = yuitips.length;
627 627
628 628 for(i=0;i<yuiLen;i++){
629 629 yt.set_listeners(yuitips[i]);
630 630 }
631 631 },
632 632
633 633 show_yuitip: function(e, el){
634 634 YUE.stopEvent(e);
635 635 if(el.tagName.toLowerCase() === 'img'){
636 636 yt.tipText = el.alt ? el.alt : '';
637 637 } else {
638 638 yt.tipText = el.title ? el.title : '';
639 639 }
640 640
641 641 if(yt.tipText !== ''){
642 642 // save org title
643 643 YUD.setAttribute(el, 'tt_title', yt.tipText);
644 644 // reset title to not show org tooltips
645 645 YUD.setAttribute(el, 'title', '');
646 646
647 647 yt.tipBox.innerHTML = yt.tipText;
648 648 YUD.setStyle(yt.tipBox, 'display', 'block');
649 649 if(yt.useAnim === true){
650 650 YUD.setStyle(yt.tipBox, 'opacity', '0');
651 651 var newAnim = new YAHOO.util.Anim(yt.tipBox,
652 652 {
653 653 opacity: { to: yt.opacity }
654 654 }, yt.speed, YAHOO.util.Easing.easeOut
655 655 );
656 656 newAnim.animate();
657 657 }
658 658 }
659 659 },
660 660
661 661 move_yuitip: function(e, el){
662 662 YUE.stopEvent(e);
663 663 var movePos = YUE.getXY(e);
664 664 YUD.setStyle(yt.tipBox, 'top', (movePos[1] + yt.offset[1]) + 'px');
665 665 YUD.setStyle(yt.tipBox, 'left', (movePos[0] + yt.offset[0]) + 'px');
666 666 },
667 667
668 668 close_yuitip: function(e, el){
669 669 YUE.stopEvent(e);
670 670
671 671 if(yt.useAnim === true){
672 672 var newAnim = new YAHOO.util.Anim(yt.tipBox,
673 673 {
674 674 opacity: { to: 0 }
675 675 }, yt.speed, YAHOO.util.Easing.easeOut
676 676 );
677 677 newAnim.animate();
678 678 } else {
679 679 YUD.setStyle(yt.tipBox, 'display', 'none');
680 680 }
681 681 YUD.setAttribute(el,'title', YUD.getAttribute(el, 'tt_title'));
682 682 }
683 683 }
684 684
685 685 /**
686 686 * Quick filter widget
687 687 *
688 688 * @param target: filter input target
689 689 * @param nodes: list of nodes in html we want to filter.
690 690 * @param display_element function that takes current node from nodes and
691 691 * does hide or show based on the node
692 692 *
693 693 */
694 694 var q_filter = function(target,nodes,display_element){
695 695
696 696 var nodes = nodes;
697 697 var q_filter_field = YUD.get(target);
698 698 var F = YAHOO.namespace(target);
699 699
700 700 YUE.on(q_filter_field,'click',function(){
701 701 q_filter_field.value = '';
702 702 });
703 703
704 704 YUE.on(q_filter_field,'keyup',function(e){
705 705 clearTimeout(F.filterTimeout);
706 706 F.filterTimeout = setTimeout(F.updateFilter,600);
707 707 });
708 708
709 709 F.filterTimeout = null;
710 710
711 711 var show_node = function(node){
712 712 YUD.setStyle(node,'display','')
713 713 }
714 714 var hide_node = function(node){
715 715 YUD.setStyle(node,'display','none');
716 716 }
717 717
718 718 F.updateFilter = function() {
719 719 // Reset timeout
720 720 F.filterTimeout = null;
721 721
722 722 var obsolete = [];
723 723
724 724 var req = q_filter_field.value.toLowerCase();
725 725
726 726 var l = nodes.length;
727 727 var i;
728 728 var showing = 0;
729 729
730 730 for (i=0;i<l;i++ ){
731 731 var n = nodes[i];
732 732 var target_element = display_element(n)
733 733 if(req && n.innerHTML.toLowerCase().indexOf(req) == -1){
734 734 hide_node(target_element);
735 735 }
736 736 else{
737 737 show_node(target_element);
738 738 showing+=1;
739 739 }
740 740 }
741 741
742 742 // if repo_count is set update the number
743 743 var cnt = YUD.get('repo_count');
744 744 if(cnt){
745 745 YUD.get('repo_count').innerHTML = showing;
746 746 }
747 747
748 748 }
749 749 };
750 750
751 751 var tableTr = function(cls, body){
752 752 var _el = document.createElement('div');
753 753 var cont = new YAHOO.util.Element(body);
754 754 var comment_id = fromHTML(body).children[0].id.split('comment-')[1];
755 755 var id = 'comment-tr-{0}'.format(comment_id);
756 756 var _html = ('<table><tbody><tr id="{0}" class="{1}">'+
757 757 '<td class="lineno-inline new-inline"></td>'+
758 758 '<td class="lineno-inline old-inline"></td>'+
759 759 '<td>{2}</td>'+
760 760 '</tr></tbody></table>').format(id, cls, body);
761 761 _el.innerHTML = _html;
762 762 return _el.children[0].children[0].children[0];
763 763 };
764 764
765 765 /** comments **/
766 766 var removeInlineForm = function(form) {
767 767 form.parentNode.removeChild(form);
768 768 };
769 769
770 770 var createInlineForm = function(parent_tr, f_path, line) {
771 771 var tmpl = YUD.get('comment-inline-form-template').innerHTML;
772 772 tmpl = tmpl.format(f_path, line);
773 773 var form = tableTr('comment-form-inline',tmpl)
774 774
775 775 // create event for hide button
776 776 form = new YAHOO.util.Element(form);
777 777 var form_hide_button = new YAHOO.util.Element(YUD.getElementsByClassName('hide-inline-form',null,form)[0]);
778 778 form_hide_button.on('click', function(e) {
779 779 var newtr = e.currentTarget.parentNode.parentNode.parentNode.parentNode.parentNode;
780 780 if(YUD.hasClass(newtr.nextElementSibling,'inline-comments-button')){
781 781 YUD.setStyle(newtr.nextElementSibling,'display','');
782 782 }
783 783 removeInlineForm(newtr);
784 784 YUD.removeClass(parent_tr, 'form-open');
785 785 YUD.removeClass(parent_tr, 'hl-comment');
786 786
787 787 });
788 788
789 789 return form
790 790 };
791 791
792 792 /**
793 793 * Inject inline comment for on given TR this tr should be always an .line
794 794 * tr containing the line. Code will detect comment, and always put the comment
795 795 * block at the very bottom
796 796 */
797 797 var injectInlineForm = function(tr){
798 798 if(!YUD.hasClass(tr, 'line')){
799 799 return
800 800 }
801 801 var submit_url = AJAX_COMMENT_URL;
802 802 var _td = YUD.getElementsByClassName('code',null,tr)[0];
803 803 if(YUD.hasClass(tr,'form-open') || YUD.hasClass(tr,'context') || YUD.hasClass(_td,'no-comment')){
804 804 return
805 805 }
806 806 YUD.addClass(tr,'form-open');
807 807 YUD.addClass(tr,'hl-comment');
808 808 var node = YUD.getElementsByClassName('full_f_path',null,tr.parentNode.parentNode.parentNode)[0];
809 809 var f_path = YUD.getAttribute(node,'path');
810 810 var lineno = getLineNo(tr);
811 811 var form = createInlineForm(tr, f_path, lineno, submit_url);
812 812
813 813 var parent = tr;
814 814 while (1){
815 815 var n = parent.nextElementSibling;
816 816 // next element are comments !
817 817 if(YUD.hasClass(n,'inline-comments')){
818 818 parent = n;
819 819 }
820 820 else{
821 821 break;
822 822 }
823 823 }
824 824 YUD.insertAfter(form,parent);
825 825 var f = YUD.get(form);
826 826 var overlay = YUD.getElementsByClassName('overlay',null,f)[0];
827 827 var _form = YUD.getElementsByClassName('inline-form',null,f)[0];
828 828
829 829 YUE.on(YUD.get(_form), 'submit',function(e){
830 830 YUE.preventDefault(e);
831 831
832 832 //ajax submit
833 833 var text = YUD.get('text_'+lineno).value;
834 834 var postData = {
835 835 'text':text,
836 836 'f_path':f_path,
837 837 'line':lineno
838 838 };
839 839
840 840 if(lineno === undefined){
841 841 alert('missing line !');
842 842 return
843 843 }
844 844 if(f_path === undefined){
845 845 alert('missing file path !');
846 846 return
847 847 }
848 848
849 849 if(text == ""){
850 850 return
851 851 }
852 852
853 853 var success = function(o){
854 854 YUD.removeClass(tr, 'form-open');
855 855 removeInlineForm(f);
856 856 var json_data = JSON.parse(o.responseText);
857 857 renderInlineComment(json_data);
858 858 };
859 859
860 860 if (YUD.hasClass(overlay,'overlay')){
861 861 var w = _form.offsetWidth;
862 862 var h = _form.offsetHeight;
863 863 YUD.setStyle(overlay,'width',w+'px');
864 864 YUD.setStyle(overlay,'height',h+'px');
865 865 }
866 866 YUD.addClass(overlay, 'submitting');
867 867
868 868 ajaxPOST(submit_url, postData, success);
869 869 });
870 870
871 871 setTimeout(function(){
872 872 // callbacks
873 873 tooltip_activate();
874 874 MentionsAutoComplete('text_'+lineno, 'mentions_container_'+lineno,
875 875 _USERS_AC_DATA, _GROUPS_AC_DATA);
876 876 var _e = YUD.get('text_'+lineno);
877 877 if(_e){
878 878 _e.focus();
879 879 }
880 880 },10)
881 881 };
882 882
883 883 var deleteComment = function(comment_id){
884 884 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__',comment_id);
885 885 var postData = {'_method':'delete'};
886 886 var success = function(o){
887 887 var n = YUD.get('comment-tr-'+comment_id);
888 888 var root = prevElementSibling(prevElementSibling(n));
889 889 n.parentNode.removeChild(n);
890 890
891 891 // scann nodes, and attach add button to last one
892 892 placeAddButton(root);
893 893 }
894 894 ajaxPOST(url,postData,success);
895 895 }
896 896
897 897 var createInlineAddButton = function(tr){
898 898
899 var label = TRANSLATION_MAP['add another comment'];
899 var label = TRANSLATION_MAP['Add another comment'];
900 900
901 901 var html_el = document.createElement('div');
902 902 YUD.addClass(html_el, 'add-comment');
903 903 html_el.innerHTML = '<span class="ui-btn">{0}</span>'.format(label);
904 904
905 905 var add = new YAHOO.util.Element(html_el);
906 906 add.on('click', function(e) {
907 907 injectInlineForm(tr);
908 908 });
909 909 return add;
910 910 };
911 911
912 912 var getLineNo = function(tr) {
913 913 var line;
914 914 var o = tr.children[0].id.split('_');
915 915 var n = tr.children[1].id.split('_');
916 916
917 917 if (n.length >= 2) {
918 918 line = n[n.length-1];
919 919 } else if (o.length >= 2) {
920 920 line = o[o.length-1];
921 921 }
922 922
923 923 return line
924 924 };
925 925
926 926 var placeAddButton = function(target_tr){
927 927 if(!target_tr){
928 928 return
929 929 }
930 930 var last_node = target_tr;
931 931 //scann
932 932 while (1){
933 933 var n = last_node.nextElementSibling;
934 934 // next element are comments !
935 935 if(YUD.hasClass(n,'inline-comments')){
936 936 last_node = n;
937 937 //also remove the comment button from previous
938 938 var comment_add_buttons = YUD.getElementsByClassName('add-comment',null,last_node);
939 939 for(var i=0;i<comment_add_buttons.length;i++){
940 940 var b = comment_add_buttons[i];
941 941 b.parentNode.removeChild(b);
942 942 }
943 943 }
944 944 else{
945 945 break;
946 946 }
947 947 }
948 948
949 949 var add = createInlineAddButton(target_tr);
950 950 // get the comment div
951 951 var comment_block = YUD.getElementsByClassName('comment',null,last_node)[0];
952 952 // attach add button
953 953 YUD.insertAfter(add,comment_block);
954 954 }
955 955
956 956 /**
957 957 * Places the inline comment into the changeset block in proper line position
958 958 */
959 959 var placeInline = function(target_container,lineno,html){
960 960 var lineid = "{0}_{1}".format(target_container,lineno);
961 961 var target_line = YUD.get(lineid);
962 962 var comment = new YAHOO.util.Element(tableTr('inline-comments',html))
963 963
964 964 // check if there are comments already !
965 965 var parent = target_line.parentNode;
966 966 var root_parent = parent;
967 967 while (1){
968 968 var n = parent.nextElementSibling;
969 969 // next element are comments !
970 970 if(YUD.hasClass(n,'inline-comments')){
971 971 parent = n;
972 972 }
973 973 else{
974 974 break;
975 975 }
976 976 }
977 977 // put in the comment at the bottom
978 978 YUD.insertAfter(comment,parent);
979 979
980 980 // scann nodes, and attach add button to last one
981 981 placeAddButton(root_parent);
982 982
983 983 return target_line;
984 984 }
985 985
986 986 /**
987 987 * make a single inline comment and place it inside
988 988 */
989 989 var renderInlineComment = function(json_data){
990 990 try{
991 991 var html = json_data['rendered_text'];
992 992 var lineno = json_data['line_no'];
993 993 var target_id = json_data['target_id'];
994 994 placeInline(target_id, lineno, html);
995 995
996 996 }catch(e){
997 997 console.log(e);
998 998 }
999 999 }
1000 1000
1001 1001 /**
1002 1002 * Iterates over all the inlines, and places them inside proper blocks of data
1003 1003 */
1004 1004 var renderInlineComments = function(file_comments){
1005 1005 for (f in file_comments){
1006 1006 // holding all comments for a FILE
1007 1007 var box = file_comments[f];
1008 1008
1009 1009 var target_id = YUD.getAttribute(box,'target_id');
1010 1010 // actually comments with line numbers
1011 1011 var comments = box.children;
1012 1012 for(var i=0; i<comments.length; i++){
1013 1013 var data = {
1014 1014 'rendered_text': comments[i].outerHTML,
1015 1015 'line_no': YUD.getAttribute(comments[i],'line'),
1016 1016 'target_id': target_id
1017 1017 }
1018 1018 renderInlineComment(data);
1019 1019 }
1020 1020 }
1021 1021 }
1022 1022
1023 1023 var fileBrowserListeners = function(current_url, node_list_url, url_base){
1024 1024 var current_url_branch = +"?branch=__BRANCH__";
1025 1025
1026 1026 YUE.on('stay_at_branch','click',function(e){
1027 1027 if(e.target.checked){
1028 1028 var uri = current_url_branch;
1029 1029 uri = uri.replace('__BRANCH__',e.target.value);
1030 1030 window.location = uri;
1031 1031 }
1032 1032 else{
1033 1033 window.location = current_url;
1034 1034 }
1035 1035 })
1036 1036
1037 1037 var n_filter = YUD.get('node_filter');
1038 1038 var F = YAHOO.namespace('node_filter');
1039 1039
1040 1040 F.filterTimeout = null;
1041 1041 var nodes = null;
1042 1042
1043 1043 F.initFilter = function(){
1044 1044 YUD.setStyle('node_filter_box_loading','display','');
1045 1045 YUD.setStyle('search_activate_id','display','none');
1046 1046 YUD.setStyle('add_node_id','display','none');
1047 1047 YUC.initHeader('X-PARTIAL-XHR',true);
1048 1048 YUC.asyncRequest('GET', node_list_url, {
1049 1049 success:function(o){
1050 1050 nodes = JSON.parse(o.responseText).nodes;
1051 1051 YUD.setStyle('node_filter_box_loading','display','none');
1052 1052 YUD.setStyle('node_filter_box','display','');
1053 1053 n_filter.focus();
1054 1054 if(YUD.hasClass(n_filter,'init')){
1055 1055 n_filter.value = '';
1056 1056 YUD.removeClass(n_filter,'init');
1057 1057 }
1058 1058 },
1059 1059 failure:function(o){
1060 1060 console.log('failed to load');
1061 1061 }
1062 1062 },null);
1063 1063 }
1064 1064
1065 1065 F.updateFilter = function(e) {
1066 1066
1067 1067 return function(){
1068 1068 // Reset timeout
1069 1069 F.filterTimeout = null;
1070 1070 var query = e.target.value.toLowerCase();
1071 1071 var match = [];
1072 1072 var matches = 0;
1073 1073 var matches_max = 20;
1074 1074 if (query != ""){
1075 1075 for(var i=0;i<nodes.length;i++){
1076 1076
1077 1077 var pos = nodes[i].name.toLowerCase().indexOf(query)
1078 1078 if(query && pos != -1){
1079 1079
1080 1080 matches++
1081 1081 //show only certain amount to not kill browser
1082 1082 if (matches > matches_max){
1083 1083 break;
1084 1084 }
1085 1085
1086 1086 var n = nodes[i].name;
1087 1087 var t = nodes[i].type;
1088 1088 var n_hl = n.substring(0,pos)
1089 1089 +"<b>{0}</b>".format(n.substring(pos,pos+query.length))
1090 1090 +n.substring(pos+query.length)
1091 1091 var new_url = url_base.replace('__FPATH__',n);
1092 1092 match.push('<tr><td><a class="browser-{0}" href="{1}">{2}</a></td><td colspan="5"></td></tr>'.format(t,new_url,n_hl));
1093 1093 }
1094 1094 if(match.length >= matches_max){
1095 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['search truncated']));
1095 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['Search truncated']));
1096 1096 }
1097 1097 }
1098 1098 }
1099 1099 if(query != ""){
1100 1100 YUD.setStyle('tbody','display','none');
1101 1101 YUD.setStyle('tbody_filtered','display','');
1102 1102
1103 1103 if (match.length==0){
1104 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['no matching files']));
1104 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['No matching files']));
1105 1105 }
1106 1106
1107 1107 YUD.get('tbody_filtered').innerHTML = match.join("");
1108 1108 }
1109 1109 else{
1110 1110 YUD.setStyle('tbody','display','');
1111 1111 YUD.setStyle('tbody_filtered','display','none');
1112 1112 }
1113 1113
1114 1114 }
1115 1115 };
1116 1116
1117 1117 YUE.on(YUD.get('filter_activate'),'click',function(){
1118 1118 F.initFilter();
1119 1119 })
1120 1120 YUE.on(n_filter,'click',function(){
1121 1121 if(YUD.hasClass(n_filter,'init')){
1122 1122 n_filter.value = '';
1123 1123 YUD.removeClass(n_filter,'init');
1124 1124 }
1125 1125 });
1126 1126 YUE.on(n_filter,'keyup',function(e){
1127 1127 clearTimeout(F.filterTimeout);
1128 1128 F.filterTimeout = setTimeout(F.updateFilter(e),600);
1129 1129 });
1130 1130 };
1131 1131
1132 1132
1133 1133 var initCodeMirror = function(textAreadId,resetUrl){
1134 1134 var myCodeMirror = CodeMirror.fromTextArea(YUD.get(textAreadId),{
1135 1135 mode: "null",
1136 1136 lineNumbers:true
1137 1137 });
1138 1138 YUE.on('reset','click',function(e){
1139 1139 window.location=resetUrl
1140 1140 });
1141 1141
1142 1142 YUE.on('file_enable','click',function(){
1143 1143 YUD.setStyle('editor_container','display','');
1144 1144 YUD.setStyle('upload_file_container','display','none');
1145 1145 YUD.setStyle('filename_container','display','');
1146 1146 });
1147 1147
1148 1148 YUE.on('upload_file_enable','click',function(){
1149 1149 YUD.setStyle('editor_container','display','none');
1150 1150 YUD.setStyle('upload_file_container','display','');
1151 1151 YUD.setStyle('filename_container','display','none');
1152 1152 });
1153 1153 };
1154 1154
1155 1155
1156 1156
1157 1157 var getIdentNode = function(n){
1158 1158 //iterate thru nodes untill matched interesting node !
1159 1159
1160 1160 if (typeof n == 'undefined'){
1161 1161 return -1
1162 1162 }
1163 1163
1164 1164 if(typeof n.id != "undefined" && n.id.match('L[0-9]+')){
1165 1165 return n
1166 1166 }
1167 1167 else{
1168 1168 return getIdentNode(n.parentNode);
1169 1169 }
1170 1170 };
1171 1171
1172 1172 var getSelectionLink = function(e) {
1173 1173
1174 1174 //get selection from start/to nodes
1175 1175 if (typeof window.getSelection != "undefined") {
1176 1176 s = window.getSelection();
1177 1177
1178 1178 from = getIdentNode(s.anchorNode);
1179 1179 till = getIdentNode(s.focusNode);
1180 1180
1181 1181 f_int = parseInt(from.id.replace('L',''));
1182 1182 t_int = parseInt(till.id.replace('L',''));
1183 1183
1184 1184 if (f_int > t_int){
1185 1185 //highlight from bottom
1186 1186 offset = -35;
1187 1187 ranges = [t_int,f_int];
1188 1188
1189 1189 }
1190 1190 else{
1191 1191 //highligth from top
1192 1192 offset = 35;
1193 1193 ranges = [f_int,t_int];
1194 1194 }
1195 1195 // if we select more than 2 lines
1196 1196 if (ranges[0] != ranges[1]){
1197 1197 if(YUD.get('linktt') == null){
1198 1198 hl_div = document.createElement('div');
1199 1199 hl_div.id = 'linktt';
1200 1200 }
1201 1201 hl_div.innerHTML = '';
1202 1202
1203 1203 anchor = '#L'+ranges[0]+'-'+ranges[1];
1204 1204 var link = document.createElement('a');
1205 1205 link.href = location.href.substring(0,location.href.indexOf('#'))+anchor;
1206 1206 link.innerHTML = _TM['Selection link'];
1207 1207 hl_div.appendChild(link);
1208 1208 YUD.get('body').appendChild(hl_div);
1209 1209
1210 1210 xy = YUD.getXY(till.id);
1211 1211
1212 1212 YUD.addClass('linktt', 'hl-tip-box');
1213 1213 YUD.setStyle('linktt','top',xy[1]+offset+'px');
1214 1214 YUD.setStyle('linktt','left',xy[0]+'px');
1215 1215 YUD.setStyle('linktt','visibility','visible');
1216 1216
1217 1217 }
1218 1218 else{
1219 1219 YUD.setStyle('linktt','visibility','hidden');
1220 1220 }
1221 1221 }
1222 1222 };
1223 1223
1224 1224 var deleteNotification = function(url, notification_id,callbacks){
1225 1225 var callback = {
1226 1226 success:function(o){
1227 1227 var obj = YUD.get(String("notification_"+notification_id));
1228 1228 if(obj.parentNode !== undefined){
1229 1229 obj.parentNode.removeChild(obj);
1230 1230 }
1231 1231 _run_callbacks(callbacks);
1232 1232 },
1233 1233 failure:function(o){
1234 1234 alert("error");
1235 1235 },
1236 1236 };
1237 1237 var postData = '_method=delete';
1238 1238 var sUrl = url.replace('__NOTIFICATION_ID__',notification_id);
1239 1239 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl,
1240 1240 callback, postData);
1241 1241 };
1242 1242
1243 1243 var readNotification = function(url, notification_id,callbacks){
1244 1244 var callback = {
1245 1245 success:function(o){
1246 1246 var obj = YUD.get(String("notification_"+notification_id));
1247 1247 YUD.removeClass(obj, 'unread');
1248 1248 var r_button = YUD.getElementsByClassName('read-notification',null,obj.children[0])[0];
1249 1249
1250 1250 if(r_button.parentNode !== undefined){
1251 1251 r_button.parentNode.removeChild(r_button);
1252 1252 }
1253 1253 _run_callbacks(callbacks);
1254 1254 },
1255 1255 failure:function(o){
1256 1256 alert("error");
1257 1257 },
1258 1258 };
1259 1259 var postData = '_method=put';
1260 1260 var sUrl = url.replace('__NOTIFICATION_ID__',notification_id);
1261 1261 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl,
1262 1262 callback, postData);
1263 1263 };
1264 1264
1265 1265 /** MEMBERS AUTOCOMPLETE WIDGET **/
1266 1266
1267 1267 var MembersAutoComplete = function (divid, cont, users_list, groups_list) {
1268 1268 var myUsers = users_list;
1269 1269 var myGroups = groups_list;
1270 1270
1271 1271 // Define a custom search function for the DataSource of users
1272 1272 var matchUsers = function (sQuery) {
1273 1273 // Case insensitive matching
1274 1274 var query = sQuery.toLowerCase();
1275 1275 var i = 0;
1276 1276 var l = myUsers.length;
1277 1277 var matches = [];
1278 1278
1279 1279 // Match against each name of each contact
1280 1280 for (; i < l; i++) {
1281 1281 contact = myUsers[i];
1282 1282 if (((contact.fname+"").toLowerCase().indexOf(query) > -1) ||
1283 1283 ((contact.lname+"").toLowerCase().indexOf(query) > -1) ||
1284 1284 ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
1285 1285 matches[matches.length] = contact;
1286 1286 }
1287 1287 }
1288 1288 return matches;
1289 1289 };
1290 1290
1291 1291 // Define a custom search function for the DataSource of userGroups
1292 1292 var matchGroups = function (sQuery) {
1293 1293 // Case insensitive matching
1294 1294 var query = sQuery.toLowerCase();
1295 1295 var i = 0;
1296 1296 var l = myGroups.length;
1297 1297 var matches = [];
1298 1298
1299 1299 // Match against each name of each contact
1300 1300 for (; i < l; i++) {
1301 1301 matched_group = myGroups[i];
1302 1302 if (matched_group.grname.toLowerCase().indexOf(query) > -1) {
1303 1303 matches[matches.length] = matched_group;
1304 1304 }
1305 1305 }
1306 1306 return matches;
1307 1307 };
1308 1308
1309 1309 //match all
1310 1310 var matchAll = function (sQuery) {
1311 1311 u = matchUsers(sQuery);
1312 1312 g = matchGroups(sQuery);
1313 1313 return u.concat(g);
1314 1314 };
1315 1315
1316 1316 // DataScheme for members
1317 1317 var memberDS = new YAHOO.util.FunctionDataSource(matchAll);
1318 1318 memberDS.responseSchema = {
1319 1319 fields: ["id", "fname", "lname", "nname", "grname", "grmembers", "gravatar_lnk"]
1320 1320 };
1321 1321
1322 1322 // DataScheme for owner
1323 1323 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
1324 1324 ownerDS.responseSchema = {
1325 1325 fields: ["id", "fname", "lname", "nname", "gravatar_lnk"]
1326 1326 };
1327 1327
1328 1328 // Instantiate AutoComplete for perms
1329 1329 var membersAC = new YAHOO.widget.AutoComplete(divid, cont, memberDS);
1330 1330 membersAC.useShadow = false;
1331 1331 membersAC.resultTypeList = false;
1332 1332 membersAC.animVert = false;
1333 1333 membersAC.animHoriz = false;
1334 1334 membersAC.animSpeed = 0.1;
1335 1335
1336 1336 // Instantiate AutoComplete for owner
1337 1337 var ownerAC = new YAHOO.widget.AutoComplete("user", "owner_container", ownerDS);
1338 1338 ownerAC.useShadow = false;
1339 1339 ownerAC.resultTypeList = false;
1340 1340 ownerAC.animVert = false;
1341 1341 ownerAC.animHoriz = false;
1342 1342 ownerAC.animSpeed = 0.1;
1343 1343
1344 1344 // Helper highlight function for the formatter
1345 1345 var highlightMatch = function (full, snippet, matchindex) {
1346 1346 return full.substring(0, matchindex)
1347 1347 + "<span class='match'>"
1348 1348 + full.substr(matchindex, snippet.length)
1349 1349 + "</span>" + full.substring(matchindex + snippet.length);
1350 1350 };
1351 1351
1352 1352 // Custom formatter to highlight the matching letters
1353 1353 var custom_formatter = function (oResultData, sQuery, sResultMatch) {
1354 1354 var query = sQuery.toLowerCase();
1355 1355 var _gravatar = function(res, em, group){
1356 1356 if (group !== undefined){
1357 1357 em = '/images/icons/group.png'
1358 1358 }
1359 1359 tmpl = '<div class="ac-container-wrap"><img class="perm-gravatar-ac" src="{0}"/>{1}</div>'
1360 1360 return tmpl.format(em,res)
1361 1361 }
1362 1362 // group
1363 1363 if (oResultData.grname != undefined) {
1364 1364 var grname = oResultData.grname;
1365 1365 var grmembers = oResultData.grmembers;
1366 1366 var grnameMatchIndex = grname.toLowerCase().indexOf(query);
1367 1367 var grprefix = "{0}: ".format(_TM['Group']);
1368 1368 var grsuffix = " (" + grmembers + " )";
1369 1369 var grsuffix = " ({0} {1})".format(grmembers, _TM['members']);
1370 1370
1371 1371 if (grnameMatchIndex > -1) {
1372 1372 return _gravatar(grprefix + highlightMatch(grname, query, grnameMatchIndex) + grsuffix,null,true);
1373 1373 }
1374 1374 return _gravatar(grprefix + oResultData.grname + grsuffix, null,true);
1375 1375 // Users
1376 1376 } else if (oResultData.nname != undefined) {
1377 1377 var fname = oResultData.fname || "";
1378 1378 var lname = oResultData.lname || "";
1379 1379 var nname = oResultData.nname;
1380 1380
1381 1381 // Guard against null value
1382 1382 var fnameMatchIndex = fname.toLowerCase().indexOf(query),
1383 1383 lnameMatchIndex = lname.toLowerCase().indexOf(query),
1384 1384 nnameMatchIndex = nname.toLowerCase().indexOf(query),
1385 1385 displayfname, displaylname, displaynname;
1386 1386
1387 1387 if (fnameMatchIndex > -1) {
1388 1388 displayfname = highlightMatch(fname, query, fnameMatchIndex);
1389 1389 } else {
1390 1390 displayfname = fname;
1391 1391 }
1392 1392
1393 1393 if (lnameMatchIndex > -1) {
1394 1394 displaylname = highlightMatch(lname, query, lnameMatchIndex);
1395 1395 } else {
1396 1396 displaylname = lname;
1397 1397 }
1398 1398
1399 1399 if (nnameMatchIndex > -1) {
1400 1400 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
1401 1401 } else {
1402 1402 displaynname = nname ? "(" + nname + ")" : "";
1403 1403 }
1404 1404
1405 1405 return _gravatar(displayfname + " " + displaylname + " " + displaynname, oResultData.gravatar_lnk);
1406 1406 } else {
1407 1407 return '';
1408 1408 }
1409 1409 };
1410 1410 membersAC.formatResult = custom_formatter;
1411 1411 ownerAC.formatResult = custom_formatter;
1412 1412
1413 1413 var myHandler = function (sType, aArgs) {
1414 1414 var nextId = divid.split('perm_new_member_name_')[1];
1415 1415 var myAC = aArgs[0]; // reference back to the AC instance
1416 1416 var elLI = aArgs[1]; // reference to the selected LI element
1417 1417 var oData = aArgs[2]; // object literal of selected item's result data
1418 1418 //fill the autocomplete with value
1419 1419 if (oData.nname != undefined) {
1420 1420 //users
1421 1421 myAC.getInputEl().value = oData.nname;
1422 1422 YUD.get('perm_new_member_type_'+nextId).value = 'user';
1423 1423 } else {
1424 1424 //groups
1425 1425 myAC.getInputEl().value = oData.grname;
1426 1426 YUD.get('perm_new_member_type_'+nextId).value = 'users_group';
1427 1427 }
1428 1428 };
1429 1429
1430 1430 membersAC.itemSelectEvent.subscribe(myHandler);
1431 1431 if(ownerAC.itemSelectEvent){
1432 1432 ownerAC.itemSelectEvent.subscribe(myHandler);
1433 1433 }
1434 1434
1435 1435 return {
1436 1436 memberDS: memberDS,
1437 1437 ownerDS: ownerDS,
1438 1438 membersAC: membersAC,
1439 1439 ownerAC: ownerAC,
1440 1440 };
1441 1441 }
1442 1442
1443 1443
1444 1444 var MentionsAutoComplete = function (divid, cont, users_list, groups_list) {
1445 1445 var myUsers = users_list;
1446 1446 var myGroups = groups_list;
1447 1447
1448 1448 // Define a custom search function for the DataSource of users
1449 1449 var matchUsers = function (sQuery) {
1450 1450 var org_sQuery = sQuery;
1451 1451 if(this.mentionQuery == null){
1452 1452 return []
1453 1453 }
1454 1454 sQuery = this.mentionQuery;
1455 1455 // Case insensitive matching
1456 1456 var query = sQuery.toLowerCase();
1457 1457 var i = 0;
1458 1458 var l = myUsers.length;
1459 1459 var matches = [];
1460 1460
1461 1461 // Match against each name of each contact
1462 1462 for (; i < l; i++) {
1463 1463 contact = myUsers[i];
1464 1464 if (((contact.fname+"").toLowerCase().indexOf(query) > -1) ||
1465 1465 ((contact.lname+"").toLowerCase().indexOf(query) > -1) ||
1466 1466 ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
1467 1467 matches[matches.length] = contact;
1468 1468 }
1469 1469 }
1470 1470 return matches
1471 1471 };
1472 1472
1473 1473 //match all
1474 1474 var matchAll = function (sQuery) {
1475 1475 u = matchUsers(sQuery);
1476 1476 return u
1477 1477 };
1478 1478
1479 1479 // DataScheme for owner
1480 1480 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
1481 1481
1482 1482 ownerDS.responseSchema = {
1483 1483 fields: ["id", "fname", "lname", "nname", "gravatar_lnk"]
1484 1484 };
1485 1485
1486 1486 // Instantiate AutoComplete for mentions
1487 1487 var ownerAC = new YAHOO.widget.AutoComplete(divid, cont, ownerDS);
1488 1488 ownerAC.useShadow = false;
1489 1489 ownerAC.resultTypeList = false;
1490 1490 ownerAC.suppressInputUpdate = true;
1491 1491 ownerAC.animVert = false;
1492 1492 ownerAC.animHoriz = false;
1493 1493 ownerAC.animSpeed = 0.1;
1494 1494
1495 1495 // Helper highlight function for the formatter
1496 1496 var highlightMatch = function (full, snippet, matchindex) {
1497 1497 return full.substring(0, matchindex)
1498 1498 + "<span class='match'>"
1499 1499 + full.substr(matchindex, snippet.length)
1500 1500 + "</span>" + full.substring(matchindex + snippet.length);
1501 1501 };
1502 1502
1503 1503 // Custom formatter to highlight the matching letters
1504 1504 ownerAC.formatResult = function (oResultData, sQuery, sResultMatch) {
1505 1505 var org_sQuery = sQuery;
1506 1506 if(this.dataSource.mentionQuery != null){
1507 1507 sQuery = this.dataSource.mentionQuery;
1508 1508 }
1509 1509
1510 1510 var query = sQuery.toLowerCase();
1511 1511 var _gravatar = function(res, em, group){
1512 1512 if (group !== undefined){
1513 1513 em = '/images/icons/group.png'
1514 1514 }
1515 1515 tmpl = '<div class="ac-container-wrap"><img class="perm-gravatar-ac" src="{0}"/>{1}</div>'
1516 1516 return tmpl.format(em,res)
1517 1517 }
1518 1518 if (oResultData.nname != undefined) {
1519 1519 var fname = oResultData.fname || "";
1520 1520 var lname = oResultData.lname || "";
1521 1521 var nname = oResultData.nname;
1522 1522
1523 1523 // Guard against null value
1524 1524 var fnameMatchIndex = fname.toLowerCase().indexOf(query),
1525 1525 lnameMatchIndex = lname.toLowerCase().indexOf(query),
1526 1526 nnameMatchIndex = nname.toLowerCase().indexOf(query),
1527 1527 displayfname, displaylname, displaynname;
1528 1528
1529 1529 if (fnameMatchIndex > -1) {
1530 1530 displayfname = highlightMatch(fname, query, fnameMatchIndex);
1531 1531 } else {
1532 1532 displayfname = fname;
1533 1533 }
1534 1534
1535 1535 if (lnameMatchIndex > -1) {
1536 1536 displaylname = highlightMatch(lname, query, lnameMatchIndex);
1537 1537 } else {
1538 1538 displaylname = lname;
1539 1539 }
1540 1540
1541 1541 if (nnameMatchIndex > -1) {
1542 1542 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
1543 1543 } else {
1544 1544 displaynname = nname ? "(" + nname + ")" : "";
1545 1545 }
1546 1546
1547 1547 return _gravatar(displayfname + " " + displaylname + " " + displaynname, oResultData.gravatar_lnk);
1548 1548 } else {
1549 1549 return '';
1550 1550 }
1551 1551 };
1552 1552
1553 1553 if(ownerAC.itemSelectEvent){
1554 1554 ownerAC.itemSelectEvent.subscribe(function (sType, aArgs) {
1555 1555
1556 1556 var myAC = aArgs[0]; // reference back to the AC instance
1557 1557 var elLI = aArgs[1]; // reference to the selected LI element
1558 1558 var oData = aArgs[2]; // object literal of selected item's result data
1559 1559 //fill the autocomplete with value
1560 1560 if (oData.nname != undefined) {
1561 1561 //users
1562 1562 //Replace the mention name with replaced
1563 1563 var re = new RegExp();
1564 1564 var org = myAC.getInputEl().value;
1565 1565 var chunks = myAC.dataSource.chunks
1566 1566 // replace middle chunk(the search term) with actuall match
1567 1567 chunks[1] = chunks[1].replace('@'+myAC.dataSource.mentionQuery,
1568 1568 '@'+oData.nname+' ');
1569 1569 myAC.getInputEl().value = chunks.join('')
1570 1570 YUD.get(myAC.getInputEl()).focus(); // Y U NO WORK !?
1571 1571 } else {
1572 1572 //groups
1573 1573 myAC.getInputEl().value = oData.grname;
1574 1574 YUD.get('perm_new_member_type').value = 'users_group';
1575 1575 }
1576 1576 });
1577 1577 }
1578 1578
1579 1579 // in this keybuffer we will gather current value of search !
1580 1580 // since we need to get this just when someone does `@` then we do the
1581 1581 // search
1582 1582 ownerAC.dataSource.chunks = [];
1583 1583 ownerAC.dataSource.mentionQuery = null;
1584 1584
1585 1585 ownerAC.get_mention = function(msg, max_pos) {
1586 1586 var org = msg;
1587 1587 var re = new RegExp('(?:^@|\s@)([a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+)$')
1588 1588 var chunks = [];
1589 1589
1590 1590
1591 1591 // cut first chunk until curret pos
1592 1592 var to_max = msg.substr(0, max_pos);
1593 1593 var at_pos = Math.max(0,to_max.lastIndexOf('@')-1);
1594 1594 var msg2 = to_max.substr(at_pos);
1595 1595
1596 1596 chunks.push(org.substr(0,at_pos))// prefix chunk
1597 1597 chunks.push(msg2) // search chunk
1598 1598 chunks.push(org.substr(max_pos)) // postfix chunk
1599 1599
1600 1600 // clean up msg2 for filtering and regex match
1601 1601 var msg2 = msg2.lstrip(' ').lstrip('\n');
1602 1602
1603 1603 if(re.test(msg2)){
1604 1604 var unam = re.exec(msg2)[1];
1605 1605 return [unam, chunks];
1606 1606 }
1607 1607 return [null, null];
1608 1608 };
1609 1609
1610 1610 if (ownerAC.textboxKeyUpEvent){
1611 1611 ownerAC.textboxKeyUpEvent.subscribe(function(type, args){
1612 1612
1613 1613 var ac_obj = args[0];
1614 1614 var currentMessage = args[1];
1615 1615 var currentCaretPosition = args[0]._elTextbox.selectionStart;
1616 1616
1617 1617 var unam = ownerAC.get_mention(currentMessage, currentCaretPosition);
1618 1618 var curr_search = null;
1619 1619 if(unam[0]){
1620 1620 curr_search = unam[0];
1621 1621 }
1622 1622
1623 1623 ownerAC.dataSource.chunks = unam[1];
1624 1624 ownerAC.dataSource.mentionQuery = curr_search;
1625 1625
1626 1626 })
1627 1627 }
1628 1628 return {
1629 1629 ownerDS: ownerDS,
1630 1630 ownerAC: ownerAC,
1631 1631 };
1632 1632 }
1633 1633
1634 1634 var addReviewMember = function(id,fname,lname,nname,gravatar_link){
1635 1635 var members = YUD.get('review_members');
1636 1636 var tmpl = '<li id="reviewer_{2}">'+
1637 1637 '<div class="reviewers_member">'+
1638 1638 '<div class="gravatar"><img alt="gravatar" src="{0}"/> </div>'+
1639 1639 '<div style="float:left">{1}</div>'+
1640 1640 '<input type="hidden" value="{2}" name="review_members" />'+
1641 1641 '<span class="delete_icon action_button" onclick="removeReviewMember({2})"></span>'+
1642 1642 '</div>'+
1643 1643 '</li>' ;
1644 1644 var displayname = "{0} {1} ({2})".format(fname,lname,nname);
1645 1645 var element = tmpl.format(gravatar_link,displayname,id);
1646 1646 // check if we don't have this ID already in
1647 1647 var ids = [];
1648 1648 var _els = YUQ('#review_members li');
1649 1649 for (el in _els){
1650 1650 ids.push(_els[el].id)
1651 1651 }
1652 1652 if(ids.indexOf('reviewer_'+id) == -1){
1653 1653 //only add if it's not there
1654 1654 members.innerHTML += element;
1655 1655 }
1656 1656
1657 1657 }
1658 1658
1659 1659 var removeReviewMember = function(reviewer_id, repo_name, pull_request_id){
1660 1660 var el = YUD.get('reviewer_{0}'.format(reviewer_id));
1661 1661 if (el.parentNode !== undefined){
1662 1662 el.parentNode.removeChild(el);
1663 1663 }
1664 1664 }
1665 1665
1666 1666 var updateReviewers = function(reviewers_ids, repo_name, pull_request_id){
1667 1667 if (reviewers_ids === undefined){
1668 1668 var reviewers_ids = [];
1669 1669 var ids = YUQ('#review_members input');
1670 1670 for(var i=0; i<ids.length;i++){
1671 1671 var id = ids[i].value
1672 1672 reviewers_ids.push(id);
1673 1673 }
1674 1674 }
1675 1675 var url = pyroutes.url('pullrequest_update', {"repo_name":repo_name,
1676 1676 "pull_request_id": pull_request_id});
1677 1677 var postData = {'_method':'put',
1678 1678 'reviewers_ids': reviewers_ids};
1679 1679 var success = function(o){
1680 1680 window.location.reload();
1681 1681 }
1682 1682 ajaxPOST(url,postData,success);
1683 1683 }
1684 1684
1685 1685 var PullRequestAutoComplete = function (divid, cont, users_list, groups_list) {
1686 1686 var myUsers = users_list;
1687 1687 var myGroups = groups_list;
1688 1688
1689 1689 // Define a custom search function for the DataSource of users
1690 1690 var matchUsers = function (sQuery) {
1691 1691 // Case insensitive matching
1692 1692 var query = sQuery.toLowerCase();
1693 1693 var i = 0;
1694 1694 var l = myUsers.length;
1695 1695 var matches = [];
1696 1696
1697 1697 // Match against each name of each contact
1698 1698 for (; i < l; i++) {
1699 1699 contact = myUsers[i];
1700 1700 if (((contact.fname+"").toLowerCase().indexOf(query) > -1) ||
1701 1701 ((contact.lname+"").toLowerCase().indexOf(query) > -1) ||
1702 1702 ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
1703 1703 matches[matches.length] = contact;
1704 1704 }
1705 1705 }
1706 1706 return matches;
1707 1707 };
1708 1708
1709 1709 // Define a custom search function for the DataSource of userGroups
1710 1710 var matchGroups = function (sQuery) {
1711 1711 // Case insensitive matching
1712 1712 var query = sQuery.toLowerCase();
1713 1713 var i = 0;
1714 1714 var l = myGroups.length;
1715 1715 var matches = [];
1716 1716
1717 1717 // Match against each name of each contact
1718 1718 for (; i < l; i++) {
1719 1719 matched_group = myGroups[i];
1720 1720 if (matched_group.grname.toLowerCase().indexOf(query) > -1) {
1721 1721 matches[matches.length] = matched_group;
1722 1722 }
1723 1723 }
1724 1724 return matches;
1725 1725 };
1726 1726
1727 1727 //match all
1728 1728 var matchAll = function (sQuery) {
1729 1729 u = matchUsers(sQuery);
1730 1730 return u
1731 1731 };
1732 1732
1733 1733 // DataScheme for owner
1734 1734 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
1735 1735
1736 1736 ownerDS.responseSchema = {
1737 1737 fields: ["id", "fname", "lname", "nname", "gravatar_lnk"]
1738 1738 };
1739 1739
1740 1740 // Instantiate AutoComplete for mentions
1741 1741 var reviewerAC = new YAHOO.widget.AutoComplete(divid, cont, ownerDS);
1742 1742 reviewerAC.useShadow = false;
1743 1743 reviewerAC.resultTypeList = false;
1744 1744 reviewerAC.suppressInputUpdate = true;
1745 1745 reviewerAC.animVert = false;
1746 1746 reviewerAC.animHoriz = false;
1747 1747 reviewerAC.animSpeed = 0.1;
1748 1748
1749 1749 // Helper highlight function for the formatter
1750 1750 var highlightMatch = function (full, snippet, matchindex) {
1751 1751 return full.substring(0, matchindex)
1752 1752 + "<span class='match'>"
1753 1753 + full.substr(matchindex, snippet.length)
1754 1754 + "</span>" + full.substring(matchindex + snippet.length);
1755 1755 };
1756 1756
1757 1757 // Custom formatter to highlight the matching letters
1758 1758 reviewerAC.formatResult = function (oResultData, sQuery, sResultMatch) {
1759 1759 var org_sQuery = sQuery;
1760 1760 if(this.dataSource.mentionQuery != null){
1761 1761 sQuery = this.dataSource.mentionQuery;
1762 1762 }
1763 1763
1764 1764 var query = sQuery.toLowerCase();
1765 1765 var _gravatar = function(res, em, group){
1766 1766 if (group !== undefined){
1767 1767 em = '/images/icons/group.png'
1768 1768 }
1769 1769 tmpl = '<div class="ac-container-wrap"><img class="perm-gravatar-ac" src="{0}"/>{1}</div>'
1770 1770 return tmpl.format(em,res)
1771 1771 }
1772 1772 if (oResultData.nname != undefined) {
1773 1773 var fname = oResultData.fname || "";
1774 1774 var lname = oResultData.lname || "";
1775 1775 var nname = oResultData.nname;
1776 1776
1777 1777 // Guard against null value
1778 1778 var fnameMatchIndex = fname.toLowerCase().indexOf(query),
1779 1779 lnameMatchIndex = lname.toLowerCase().indexOf(query),
1780 1780 nnameMatchIndex = nname.toLowerCase().indexOf(query),
1781 1781 displayfname, displaylname, displaynname;
1782 1782
1783 1783 if (fnameMatchIndex > -1) {
1784 1784 displayfname = highlightMatch(fname, query, fnameMatchIndex);
1785 1785 } else {
1786 1786 displayfname = fname;
1787 1787 }
1788 1788
1789 1789 if (lnameMatchIndex > -1) {
1790 1790 displaylname = highlightMatch(lname, query, lnameMatchIndex);
1791 1791 } else {
1792 1792 displaylname = lname;
1793 1793 }
1794 1794
1795 1795 if (nnameMatchIndex > -1) {
1796 1796 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
1797 1797 } else {
1798 1798 displaynname = nname ? "(" + nname + ")" : "";
1799 1799 }
1800 1800
1801 1801 return _gravatar(displayfname + " " + displaylname + " " + displaynname, oResultData.gravatar_lnk);
1802 1802 } else {
1803 1803 return '';
1804 1804 }
1805 1805 };
1806 1806
1807 1807 //members cache to catch duplicates
1808 1808 reviewerAC.dataSource.cache = [];
1809 1809 // hack into select event
1810 1810 if(reviewerAC.itemSelectEvent){
1811 1811 reviewerAC.itemSelectEvent.subscribe(function (sType, aArgs) {
1812 1812
1813 1813 var myAC = aArgs[0]; // reference back to the AC instance
1814 1814 var elLI = aArgs[1]; // reference to the selected LI element
1815 1815 var oData = aArgs[2]; // object literal of selected item's result data
1816 1816
1817 1817 //fill the autocomplete with value
1818 1818
1819 1819 if (oData.nname != undefined) {
1820 1820 addReviewMember(oData.id, oData.fname, oData.lname, oData.nname,
1821 1821 oData.gravatar_lnk);
1822 1822 myAC.dataSource.cache.push(oData.id);
1823 1823 YUD.get('user').value = ''
1824 1824 }
1825 1825 });
1826 1826 }
1827 1827 return {
1828 1828 ownerDS: ownerDS,
1829 1829 reviewerAC: reviewerAC,
1830 1830 };
1831 1831 }
1832 1832
1833 1833 /**
1834 1834 * QUICK REPO MENU
1835 1835 */
1836 1836 var quick_repo_menu = function(){
1837 1837 YUE.on(YUQ('.quick_repo_menu'),'mouseenter',function(e){
1838 1838 var menu = e.currentTarget.firstElementChild.firstElementChild;
1839 1839 if(YUD.hasClass(menu,'hidden')){
1840 1840 YUD.replaceClass(e.currentTarget,'hidden', 'active');
1841 1841 YUD.replaceClass(menu, 'hidden', 'active');
1842 1842 }
1843 1843 })
1844 1844 YUE.on(YUQ('.quick_repo_menu'),'mouseleave',function(e){
1845 1845 var menu = e.currentTarget.firstElementChild.firstElementChild;
1846 1846 if(YUD.hasClass(menu,'active')){
1847 1847 YUD.replaceClass(e.currentTarget, 'active', 'hidden');
1848 1848 YUD.replaceClass(menu, 'active', 'hidden');
1849 1849 }
1850 1850 })
1851 1851 };
1852 1852
1853 1853
1854 1854 /**
1855 1855 * TABLE SORTING
1856 1856 */
1857 1857
1858 1858 // returns a node from given html;
1859 1859 var fromHTML = function(html){
1860 1860 var _html = document.createElement('element');
1861 1861 _html.innerHTML = html;
1862 1862 return _html;
1863 1863 }
1864 1864 var get_rev = function(node){
1865 1865 var n = node.firstElementChild.firstElementChild;
1866 1866
1867 1867 if (n===null){
1868 1868 return -1
1869 1869 }
1870 1870 else{
1871 1871 out = n.firstElementChild.innerHTML.split(':')[0].replace('r','');
1872 1872 return parseInt(out);
1873 1873 }
1874 1874 }
1875 1875
1876 1876 var get_name = function(node){
1877 1877 var name = node.firstElementChild.children[2].innerHTML;
1878 1878 return name
1879 1879 }
1880 1880 var get_group_name = function(node){
1881 1881 var name = node.firstElementChild.children[1].innerHTML;
1882 1882 return name
1883 1883 }
1884 1884 var get_date = function(node){
1885 1885 var date_ = YUD.getAttribute(node.firstElementChild,'date');
1886 1886 return date_
1887 1887 }
1888 1888
1889 1889 var get_age = function(node){
1890 1890 return node
1891 1891 }
1892 1892
1893 1893 var get_link = function(node){
1894 1894 return node.firstElementChild.text;
1895 1895 }
1896 1896
1897 1897 var revisionSort = function(a, b, desc, field) {
1898 1898
1899 1899 var a_ = fromHTML(a.getData(field));
1900 1900 var b_ = fromHTML(b.getData(field));
1901 1901
1902 1902 // extract revisions from string nodes
1903 1903 a_ = get_rev(a_)
1904 1904 b_ = get_rev(b_)
1905 1905
1906 1906 var comp = YAHOO.util.Sort.compare;
1907 1907 var compState = comp(a_, b_, desc);
1908 1908 return compState;
1909 1909 };
1910 1910 var ageSort = function(a, b, desc, field) {
1911 1911 var a_ = fromHTML(a.getData(field));
1912 1912 var b_ = fromHTML(b.getData(field));
1913 1913
1914 1914 // extract name from table
1915 1915 a_ = get_date(a_)
1916 1916 b_ = get_date(b_)
1917 1917
1918 1918 var comp = YAHOO.util.Sort.compare;
1919 1919 var compState = comp(a_, b_, desc);
1920 1920 return compState;
1921 1921 };
1922 1922
1923 1923 var lastLoginSort = function(a, b, desc, field) {
1924 1924 var a_ = a.getData('last_login_raw') || 0;
1925 1925 var b_ = b.getData('last_login_raw') || 0;
1926 1926
1927 1927 var comp = YAHOO.util.Sort.compare;
1928 1928 var compState = comp(a_, b_, desc);
1929 1929 return compState;
1930 1930 };
1931 1931
1932 1932 var nameSort = function(a, b, desc, field) {
1933 1933 var a_ = fromHTML(a.getData(field));
1934 1934 var b_ = fromHTML(b.getData(field));
1935 1935
1936 1936 // extract name from table
1937 1937 a_ = get_name(a_)
1938 1938 b_ = get_name(b_)
1939 1939
1940 1940 var comp = YAHOO.util.Sort.compare;
1941 1941 var compState = comp(a_, b_, desc);
1942 1942 return compState;
1943 1943 };
1944 1944
1945 1945 var permNameSort = function(a, b, desc, field) {
1946 1946 var a_ = fromHTML(a.getData(field));
1947 1947 var b_ = fromHTML(b.getData(field));
1948 1948 // extract name from table
1949 1949
1950 1950 a_ = a_.children[0].innerHTML;
1951 1951 b_ = b_.children[0].innerHTML;
1952 1952
1953 1953 var comp = YAHOO.util.Sort.compare;
1954 1954 var compState = comp(a_, b_, desc);
1955 1955 return compState;
1956 1956 };
1957 1957
1958 1958 var groupNameSort = function(a, b, desc, field) {
1959 1959 var a_ = fromHTML(a.getData(field));
1960 1960 var b_ = fromHTML(b.getData(field));
1961 1961
1962 1962 // extract name from table
1963 1963 a_ = get_group_name(a_)
1964 1964 b_ = get_group_name(b_)
1965 1965
1966 1966 var comp = YAHOO.util.Sort.compare;
1967 1967 var compState = comp(a_, b_, desc);
1968 1968 return compState;
1969 1969 };
1970 1970 var dateSort = function(a, b, desc, field) {
1971 1971 var a_ = fromHTML(a.getData(field));
1972 1972 var b_ = fromHTML(b.getData(field));
1973 1973
1974 1974 // extract name from table
1975 1975 a_ = get_date(a_)
1976 1976 b_ = get_date(b_)
1977 1977
1978 1978 var comp = YAHOO.util.Sort.compare;
1979 1979 var compState = comp(a_, b_, desc);
1980 1980 return compState;
1981 1981 };
1982 1982
1983 1983 var linkSort = function(a, b, desc, field) {
1984 1984 var a_ = fromHTML(a.getData(field));
1985 1985 var b_ = fromHTML(a.getData(field));
1986 1986
1987 1987 // extract url text from string nodes
1988 1988 a_ = get_link(a_)
1989 1989 b_ = get_link(b_)
1990 1990
1991 1991 var comp = YAHOO.util.Sort.compare;
1992 1992 var compState = comp(a_, b_, desc);
1993 1993 return compState;
1994 1994 }
1995 1995
1996 1996 var addPermAction = function(_html, users_list, groups_list){
1997 1997 var elmts = YUD.getElementsByClassName('last_new_member');
1998 1998 var last_node = elmts[elmts.length-1];
1999 1999 if (last_node){
2000 2000 var next_id = (YUD.getElementsByClassName('new_members')).length;
2001 2001 _html = _html.format(next_id);
2002 2002 last_node.innerHTML = _html;
2003 2003 YUD.setStyle(last_node, 'display', '');
2004 2004 YUD.removeClass(last_node, 'last_new_member');
2005 2005 MembersAutoComplete("perm_new_member_name_"+next_id,
2006 2006 "perm_container_"+next_id, users_list, groups_list);
2007 2007 //create new last NODE
2008 2008 var el = document.createElement('tr');
2009 2009 el.id = 'add_perm_input';
2010 2010 YUD.addClass(el,'last_new_member');
2011 2011 YUD.addClass(el,'new_members');
2012 2012 YUD.insertAfter(el, last_node);
2013 2013 }
2014 2014 }
2015 2015
2016 2016 /* Multi selectors */
2017 2017
2018 2018 var MultiSelectWidget = function(selected_id, available_id, form_id){
2019 2019
2020 2020
2021 2021 //definition of containers ID's
2022 2022 var selected_container = selected_id;
2023 2023 var available_container = available_id;
2024 2024
2025 2025 //temp container for selected storage.
2026 2026 var cache = new Array();
2027 2027 var av_cache = new Array();
2028 2028 var c = YUD.get(selected_container);
2029 2029 var ac = YUD.get(available_container);
2030 2030
2031 2031 //get only selected options for further fullfilment
2032 2032 for(var i = 0;node =c.options[i];i++){
2033 2033 if(node.selected){
2034 2034 //push selected to my temp storage left overs :)
2035 2035 cache.push(node);
2036 2036 }
2037 2037 }
2038 2038
2039 2039 //get all available options to cache
2040 2040 for(var i = 0;node =ac.options[i];i++){
2041 2041 //push selected to my temp storage left overs :)
2042 2042 av_cache.push(node);
2043 2043 }
2044 2044
2045 2045 //fill available only with those not in choosen
2046 2046 ac.options.length=0;
2047 2047 tmp_cache = new Array();
2048 2048
2049 2049 for(var i = 0;node = av_cache[i];i++){
2050 2050 var add = true;
2051 2051 for(var i2 = 0;node_2 = cache[i2];i2++){
2052 2052 if(node.value == node_2.value){
2053 2053 add=false;
2054 2054 break;
2055 2055 }
2056 2056 }
2057 2057 if(add){
2058 2058 tmp_cache.push(new Option(node.text, node.value, false, false));
2059 2059 }
2060 2060 }
2061 2061
2062 2062 for(var i = 0;node = tmp_cache[i];i++){
2063 2063 ac.options[i] = node;
2064 2064 }
2065 2065
2066 2066 function prompts_action_callback(e){
2067 2067
2068 2068 var choosen = YUD.get(selected_container);
2069 2069 var available = YUD.get(available_container);
2070 2070
2071 2071 //get checked and unchecked options from field
2072 2072 function get_checked(from_field){
2073 2073 //temp container for storage.
2074 2074 var sel_cache = new Array();
2075 2075 var oth_cache = new Array();
2076 2076
2077 2077 for(var i = 0;node = from_field.options[i];i++){
2078 2078 if(node.selected){
2079 2079 //push selected fields :)
2080 2080 sel_cache.push(node);
2081 2081 }
2082 2082 else{
2083 2083 oth_cache.push(node)
2084 2084 }
2085 2085 }
2086 2086
2087 2087 return [sel_cache,oth_cache]
2088 2088 }
2089 2089
2090 2090 //fill the field with given options
2091 2091 function fill_with(field,options){
2092 2092 //clear firtst
2093 2093 field.options.length=0;
2094 2094 for(var i = 0;node = options[i];i++){
2095 2095 field.options[i]=new Option(node.text, node.value,
2096 2096 false, false);
2097 2097 }
2098 2098
2099 2099 }
2100 2100 //adds to current field
2101 2101 function add_to(field,options){
2102 2102 for(var i = 0;node = options[i];i++){
2103 2103 field.appendChild(new Option(node.text, node.value,
2104 2104 false, false));
2105 2105 }
2106 2106 }
2107 2107
2108 2108 // add action
2109 2109 if (this.id=='add_element'){
2110 2110 var c = get_checked(available);
2111 2111 add_to(choosen,c[0]);
2112 2112 fill_with(available,c[1]);
2113 2113 }
2114 2114 // remove action
2115 2115 if (this.id=='remove_element'){
2116 2116 var c = get_checked(choosen);
2117 2117 add_to(available,c[0]);
2118 2118 fill_with(choosen,c[1]);
2119 2119 }
2120 2120 // add all elements
2121 2121 if(this.id=='add_all_elements'){
2122 2122 for(var i=0; node = available.options[i];i++){
2123 2123 choosen.appendChild(new Option(node.text,
2124 2124 node.value, false, false));
2125 2125 }
2126 2126 available.options.length = 0;
2127 2127 }
2128 2128 //remove all elements
2129 2129 if(this.id=='remove_all_elements'){
2130 2130 for(var i=0; node = choosen.options[i];i++){
2131 2131 available.appendChild(new Option(node.text,
2132 2132 node.value, false, false));
2133 2133 }
2134 2134 choosen.options.length = 0;
2135 2135 }
2136 2136
2137 2137 }
2138 2138
2139 2139 YUE.addListener(['add_element','remove_element',
2140 2140 'add_all_elements','remove_all_elements'],'click',
2141 2141 prompts_action_callback)
2142 2142 if (form_id !== undefined) {
2143 2143 YUE.addListener(form_id,'submit',function(){
2144 2144 var choosen = YUD.get(selected_container);
2145 2145 for (var i = 0; i < choosen.options.length; i++) {
2146 2146 choosen.options[i].selected = 'selected';
2147 2147 }
2148 2148 });
2149 2149 }
2150 2150 }
2151 2151
2152 2152
2153 2153 // global hooks after DOM is loaded
2154 2154
2155 2155 YUE.onDOMReady(function(){
2156 2156 YUE.on(YUQ('.diff-collapse-button'), 'click', function(e){
2157 2157 var button = e.currentTarget;
2158 2158 var t = YUD.get(button).getAttribute('target');
2159 2159 console.log(t);
2160 2160 if(YUD.hasClass(t, 'hidden')){
2161 2161 YUD.removeClass(t, 'hidden');
2162 YUD.get(button).innerHTML = "&uarr; {0} &uarr;".format(_TM['collapse diff']);
2162 YUD.get(button).innerHTML = "&uarr; {0} &uarr;".format(_TM['Collapse diff']);
2163 2163 }
2164 2164 else if(!YUD.hasClass(t, 'hidden')){
2165 2165 YUD.addClass(t, 'hidden');
2166 YUD.get(button).innerHTML = "&darr; {0} &darr;".format(_TM['expand diff']);
2166 YUD.get(button).innerHTML = "&darr; {0} &darr;".format(_TM['Expand diff']);
2167 2167 }
2168 2168 });
2169 2169
2170 2170
2171 2171
2172 2172 });
2173 2173
@@ -1,114 +1,114 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <!DOCTYPE html>
3 3 <html xmlns="http://www.w3.org/1999/xhtml">
4 4 <head>
5 5 <title>${self.title()}</title>
6 6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 7 <meta name="robots" content="index, nofollow"/>
8 8 <link rel="icon" href="${h.url('/images/icons/database_gear.png')}" type="image/png" />
9 9
10 10 ## CSS ###
11 11 <%def name="css()">
12 12 <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css', ver=c.rhodecode_version)}" media="screen"/>
13 13 <link rel="stylesheet" type="text/css" href="${h.url('/css/pygments.css', ver=c.rhodecode_version)}"/>
14 14 ## EXTRA FOR CSS
15 15 ${self.css_extra()}
16 16 </%def>
17 17 <%def name="css_extra()">
18 18 </%def>
19 19
20 20 ${self.css()}
21 21
22 22 %if c.ga_code:
23 23 <!-- Analytics -->
24 24 <script type="text/javascript">
25 25 var _gaq = _gaq || [];
26 26 _gaq.push(['_setAccount', '${c.ga_code}']);
27 27 _gaq.push(['_trackPageview']);
28 28
29 29 (function() {
30 30 var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
31 31 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
32 32 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
33 33 })();
34 34 </script>
35 35 %endif
36 36
37 37 ## JAVASCRIPT ##
38 38 <%def name="js()">
39 39 <script type="text/javascript">
40 40 //JS translations map
41 41 var TRANSLATION_MAP = {
42 'add another comment':'${_("add another comment")}',
42 'Add another comment':'${_("Add another comment")}',
43 43 'Stop following this repository':"${_('Stop following this repository')}",
44 44 'Start following this repository':"${_('Start following this repository')}",
45 45 'Group':"${_('Group')}",
46 46 'members':"${_('members')}",
47 'loading...':"${_('loading...')}",
48 'search truncated': "${_('search truncated')}",
49 'no matching files': "${_('no matching files')}",
47 'Loading ...':"${_('Loading ...')}",
48 'Search truncated': "${_('Search truncated')}",
49 'No matching files': "${_('No matching files')}",
50 50 'Open new pull request': "${_('Open new pull request')}",
51 51 'Open new pull request for selected changesets': "${_('Open new pull request for selected changesets')}",
52 52 'Show selected changes __S -> __E': "${_('Show selected changes __S -> __E')}",
53 53 'Show selected change __S': "${_('Show selected change __S')}",
54 54 'Selection link': "${_('Selection link')}",
55 'collapse diff': "${_('collapse diff')}",
56 'expand diff': "${_('expand diff')}"
55 'Collapse diff': "${_('Collapse diff')}",
56 'Expand diff': "${_('Expand diff')}"
57 57 };
58 58 var _TM = TRANSLATION_MAP;
59 59
60 60 var TOGGLE_FOLLOW_URL = "${h.url('toggle_following')}";
61 61
62 62 </script>
63 63 <script type="text/javascript" src="${h.url('/js/yui.2.9.js', ver=c.rhodecode_version)}"></script>
64 64 <!--[if lt IE 9]>
65 65 <script language="javascript" type="text/javascript" src="${h.url('/js/excanvas.min.js')}"></script>
66 66 <![endif]-->
67 67 <script type="text/javascript" src="${h.url('/js/yui.flot.js', ver=c.rhodecode_version)}"></script>
68 68 <script type="text/javascript" src="${h.url('/js/native.history.js', ver=c.rhodecode_version)}"></script>
69 69 <script type="text/javascript" src="${h.url('/js/pyroutes_map.js', ver=c.rhodecode_version)}"></script>
70 70 <script type="text/javascript" src="${h.url('/js/rhodecode.js', ver=c.rhodecode_version)}"></script>
71 71 ## EXTRA FOR JS
72 72 ${self.js_extra()}
73 73 <script type="text/javascript">
74 74 (function(window,undefined){
75 75 // Prepare
76 76 var History = window.History; // Note: We are using a capital H instead of a lower h
77 77 if ( !History.enabled ) {
78 78 // History.js is disabled for this browser.
79 79 // This is because we can optionally choose to support HTML4 browsers or not.
80 80 return false;
81 81 }
82 82 })(window);
83 83
84 84 YUE.onDOMReady(function(){
85 85 tooltip_activate();
86 86 show_more_event();
87 87 show_changeset_tooltip();
88 88 // routes registration
89 89 pyroutes.register('toggle_following', "${h.url('toggle_following')}");
90 90 pyroutes.register('changeset_info', "${h.url('changeset_info', repo_name='%(repo_name)s', revision='%(revision)s')}", ['repo_name', 'revision']);
91 91 pyroutes.register('repo_size', "${h.url('repo_size', repo_name='%(repo_name)s')}", ['repo_name']);
92 92 })
93 93 </script>
94 94 </%def>
95 95 <%def name="js_extra()"></%def>
96 96 ${self.js()}
97 97 <%def name="head_extra()"></%def>
98 98 ${self.head_extra()}
99 99 </head>
100 100 <body id="body">
101 101 ## IE hacks
102 102 <!--[if IE 7]>
103 103 <script>YUD.addClass(document.body,'ie7')</script>
104 104 <![endif]-->
105 105 <!--[if IE 8]>
106 106 <script>YUD.addClass(document.body,'ie8')</script>
107 107 <![endif]-->
108 108 <!--[if IE 9]>
109 109 <script>YUD.addClass(document.body,'ie9')</script>
110 110 <![endif]-->
111 111
112 112 ${next.body()}
113 113 </body>
114 114 </html>
@@ -1,209 +1,209 b''
1 1 <%inherit file="/base/base.html"/>
2 2
3 3 <%def name="title()">
4 4 ${c.repo_name} ${_('New pull request')}
5 5 </%def>
6 6
7 7 <%def name="breadcrumbs_links()">
8 8 ${h.link_to(_(u'Home'),h.url('/'))}
9 9 &raquo;
10 10 ${h.repo_link(c.rhodecode_db_repo.groups_and_repo)}
11 11 &raquo;
12 12 ${_('new pull request')}
13 13 </%def>
14 14
15 15 <%def name="main()">
16 16
17 17 <div class="box">
18 18 <!-- box / title -->
19 19 <div class="title">
20 20 ${self.breadcrumbs()}
21 21 </div>
22 22 ${h.form(url('pullrequest', repo_name=c.repo_name), method='post', id='pull_request_form')}
23 23 <div style="float:left;padding:0px 30px 30px 30px">
24 24 ##ORG
25 25 <div style="float:left">
26 26 <div>
27 27 <span style="font-size: 20px">
28 28 ${h.select('org_repo','',c.org_repos,class_='refs')}:${h.select('org_ref',c.default_org_ref,c.org_refs,class_='refs')}
29 29 </span>
30 30 <div style="padding:5px 3px 3px 20px;">${c.rhodecode_db_repo.description}</div>
31 31 </div>
32 32 <div style="clear:both;padding-top: 10px"></div>
33 33 </div>
34 34 <div style="float:left;font-size:24px;padding:0px 20px">
35 35 <img height=32 width=32 src="${h.url('/images/arrow_right_64.png')}"/>
36 36 </div>
37 37
38 38 ##OTHER, most Probably the PARENT OF THIS FORK
39 39 <div style="float:left">
40 40 <div>
41 41 <span style="font-size: 20px">
42 42 ${h.select('other_repo',c.default_other_repo,c.other_repos,class_='refs')}:${h.select('other_ref',c.default_other_ref,c.default_other_refs,class_='refs')}
43 43 </span>
44 44 <div id="other_repo_desc" style="padding:5px 3px 3px 20px;"></div>
45 45 </div>
46 46 <div style="clear:both;padding-top: 10px"></div>
47 47 </div>
48 48 <div style="clear:both;padding-top: 10px"></div>
49 49 ## overview pulled by ajax
50 50 <div style="float:left" id="pull_request_overview"></div>
51 51 <div style="float:left;clear:both;padding:10px 10px 10px 0px;display:none">
52 52 <a id="pull_request_overview_url" href="#">${_('Detailed compare view')}</a>
53 53 </div>
54 54 </div>
55 55 <div style="float:left; border-left:1px dashed #eee">
56 56 <h4>${_('Pull request reviewers')}</h4>
57 57 <div id="reviewers" style="padding:0px 0px 0px 15px">
58 58 ## members goes here !
59 59 <div class="group_members_wrap">
60 60 <ul id="review_members" class="group_members">
61 61 %for member in c.review_members:
62 62 <li id="reviewer_${member.user_id}">
63 63 <div class="reviewers_member">
64 64 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(member.email,14)}"/> </div>
65 65 <div style="float:left">${member.full_name} (${_('owner')})</div>
66 66 <input type="hidden" value="${member.user_id}" name="review_members" />
67 67 <span class="delete_icon action_button" onclick="removeReviewMember(${member.user_id})"></span>
68 68 </div>
69 69 </li>
70 70 %endfor
71 71 </ul>
72 72 </div>
73 73
74 74 <div class='ac'>
75 75 <div class="reviewer_ac">
76 76 ${h.text('user', class_='yui-ac-input')}
77 77 <span class="help-block">${_('Add reviewer to this pull request.')}</span>
78 78 <div id="reviewers_container"></div>
79 79 </div>
80 80 </div>
81 81 </div>
82 82 </div>
83 83 <h3>${_('Create new pull request')}</h3>
84 84
85 85 <div class="form">
86 86 <!-- fields -->
87 87
88 88 <div class="fields">
89 89
90 90 <div class="field">
91 91 <div class="label">
92 92 <label for="pullrequest_title">${_('Title')}:</label>
93 93 </div>
94 94 <div class="input">
95 95 ${h.text('pullrequest_title',size=30)}
96 96 </div>
97 97 </div>
98 98
99 99 <div class="field">
100 100 <div class="label label-textarea">
101 <label for="pullrequest_desc">${_('description')}:</label>
101 <label for="pullrequest_desc">${_('Description')}:</label>
102 102 </div>
103 103 <div class="textarea text-area editor">
104 104 ${h.textarea('pullrequest_desc',size=30)}
105 105 </div>
106 106 </div>
107 107
108 108 <div class="buttons">
109 109 ${h.submit('save',_('Send pull request'),class_="ui-btn large")}
110 110 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
111 111 </div>
112 112 </div>
113 113 </div>
114 114 ${h.end_form()}
115 115
116 116 </div>
117 117
118 118 <script type="text/javascript">
119 119 var _USERS_AC_DATA = ${c.users_array|n};
120 120 var _GROUPS_AC_DATA = ${c.users_groups_array|n};
121 121 PullRequestAutoComplete('user', 'reviewers_container', _USERS_AC_DATA, _GROUPS_AC_DATA);
122 122
123 123 var other_repos_info = ${c.other_repos_info|n};
124 124
125 125 var otherrepoChanged = function(){
126 126 var sel_box = YUQ('#pull_request_form #other_repo')[0];
127 127 var repo_name = sel_box.options[sel_box.selectedIndex].value;
128 128
129 129 YUD.get('other_repo_desc').innerHTML = other_repos_info[repo_name]['description'];
130 130 // replace options of other_ref with the ones for the current other_repo
131 131 var other_ref_selector = YUD.get('other_ref');
132 132 var new_select = YUD.createElementFromMarkup(other_repos_info[repo_name]['revs']);
133 133 var new_selectedIndex = new_select.selectedIndex;
134 134 other_ref_selector.innerHTML = ""; // clear old options
135 135 while (new_select.length > 0){ // children will be popped when appened to other_ref_selector
136 136 other_ref_selector.appendChild(new_select.children[0]);
137 137 }
138 138 // browsers lost track of selected when appendChild was used
139 139 other_ref_selector.selectedIndex = new_selectedIndex;
140 140
141 141 // reset && add the reviewer based on selected repo
142 142 var _data = other_repos_info[repo_name];
143 143 YUD.get('review_members').innerHTML = '';
144 144 addReviewMember(_data.user.user_id, _data.user.firstname,
145 145 _data.user.lastname, _data.user.username,
146 146 _data.user.gravatar_link);
147 147 }
148 148
149 149 var loadPreview = function(){
150 150 //url template
151 151 var url = "${h.url('compare_url',
152 152 repo_name='__other_repo__',
153 153 org_ref_type='__other_ref_type__',
154 154 org_ref='__other_ref__',
155 155 other_repo='__org_repo__',
156 156 other_ref_type='__org_ref_type__',
157 157 other_ref='__org_ref__',
158 158 as_form=True,
159 159 merge=True,
160 160 )}";
161 161 var org_repo = YUQ('#pull_request_form #org_repo')[0].value;
162 162 var org_ref = YUQ('#pull_request_form #org_ref')[0].value.split(':');
163 163
164 164 var other_repo = YUQ('#pull_request_form #other_repo')[0].value;
165 165 var other_ref = YUQ('#pull_request_form #other_ref')[0].value.split(':');
166 166
167 167 var select_refs = YUQ('#pull_request_form select.refs')
168 168 var rev_data = {
169 169 'org_repo': org_repo,
170 170 'org_ref': org_ref[2],
171 171 'org_ref_type': 'rev',
172 172 'other_repo': other_repo,
173 173 'other_ref': other_ref[2],
174 174 'other_ref_type': 'rev',
175 175 }; // gather the org/other ref and repo here
176 176
177 177 for (k in rev_data){
178 178 url = url.replace('__'+k+'__',rev_data[k]);
179 179 }
180 180
181 181 YUD.get('pull_request_overview').innerHTML = "${_('Loading ...')}";
182 182 ypjax(url,'pull_request_overview');
183 183
184 184 YUD.get('pull_request_overview_url').href = url; // shouldn't have as_form ... but ...
185 185 YUD.setStyle(YUD.get('pull_request_overview_url').parentElement,'display','');
186 186 }
187 187
188 188 ## refresh automatically when something changes (org_repo can't change)
189 189
190 190 YUE.on('org_ref', 'change', function(e){
191 191 loadPreview();
192 192 });
193 193
194 194 YUE.on('other_repo', 'change', function(e){
195 195 otherrepoChanged();
196 196 loadPreview();
197 197 });
198 198
199 199 YUE.on('other_ref', 'change', function(e){
200 200 loadPreview();
201 201 });
202 202
203 203 otherrepoChanged();
204 204 //lazy load overview after 0.5s
205 205 setTimeout(loadPreview, 500);
206 206
207 207 </script>
208 208
209 209 </%def>
@@ -1,248 +1,248 b''
1 1 <%inherit file="/base/base.html"/>
2 2
3 3 <%def name="title()">
4 4 ${c.repo_name} ${_('Pull request #%s') % c.pull_request.pull_request_id}
5 5 </%def>
6 6
7 7 <%def name="breadcrumbs_links()">
8 8 ${h.link_to(_(u'Home'),h.url('/'))}
9 9 &raquo;
10 10 ${h.repo_link(c.rhodecode_db_repo.groups_and_repo)}
11 11 &raquo;
12 12 ${_('Pull request #%s') % c.pull_request.pull_request_id}
13 13 </%def>
14 14
15 15 <%def name="main()">
16 16
17 17 <div class="box">
18 18 <!-- box / title -->
19 19 <div class="title">
20 20 ${self.breadcrumbs()}
21 21 </div>
22 22 %if c.pull_request.is_closed():
23 23 <div style="padding:10px; font-size:22px;width:100%;text-align: center; color:#88D882">${_('Closed %s') % (h.age(c.pull_request.updated_on))} ${_('with status %s') % h.changeset_status_lbl(c.current_changeset_status)}</div>
24 24 %endif
25 25 <h3>
26 26 %if c.pull_request.is_closed():
27 27 <img src="${h.url('/images/icons/lock_go.png')}" title="${_('Closed')}"/>
28 28 %endif
29 29 <img src="${h.url('/images/icons/flag_status_%s.png' % str(c.pull_request.last_review_status))}" />
30 30 ${_('Title')}: ${c.pull_request.title}</h3>
31 31
32 32 <div class="form">
33 33 <div id="summary" class="fields">
34 34 <div class="field">
35 35 <div class="label-summary">
36 36 <label>${_('Review status')}:</label>
37 37 </div>
38 38 <div class="input">
39 39 <div class="changeset-status-container" style="float:none;clear:both">
40 40 %if c.current_changeset_status:
41 41 <div title="${_('Pull request status')}" class="changeset-status-lbl">${h.changeset_status_lbl(c.current_changeset_status)}</div>
42 42 <div class="changeset-status-ico" style="padding:1px 4px"><img src="${h.url('/images/icons/flag_status_%s.png' % c.current_changeset_status)}" /></div>
43 43 %endif
44 44 </div>
45 45 </div>
46 46 </div>
47 47 <div class="field">
48 48 <div class="label-summary">
49 49 <label>${_('Still not reviewed by')}:</label>
50 50 </div>
51 51 <div class="input">
52 52 % if len(c.pull_request_pending_reviewers) > 0:
53 53 <div class="tooltip" title="${h.tooltip(','.join([x.username for x in c.pull_request_pending_reviewers]))}">${ungettext('%d reviewer', '%d reviewers',len(c.pull_request_pending_reviewers)) % len(c.pull_request_pending_reviewers)}</div>
54 54 %else:
55 55 <div>${_('pull request was reviewed by all reviewers')}</div>
56 56 %endif
57 57 </div>
58 58 </div>
59 59 <div class="field">
60 60 <div class="label-summary">
61 61 <label>${_('Origin repository')}:</label>
62 62 </div>
63 63 <div class="input">
64 64 <div>
65 65 ##%if h.is_hg(c.pull_request.org_repo):
66 66 ## <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
67 67 ##%elif h.is_git(c.pull_request.org_repo):
68 68 ## <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
69 69 ##%endif
70 70 <span class="spantag">${c.pull_request.org_ref_parts[0]}: ${c.pull_request.org_ref_parts[1]}</span>
71 71 <span><a href="${h.url('summary_home', repo_name=c.pull_request.org_repo.repo_name)}">${c.pull_request.org_repo.clone_url()}</a></span>
72 72 </div>
73 73 </div>
74 74 </div>
75 75 <div class="field">
76 76 <div class="label-summary">
77 77 <label>${_('Summary')}:</label>
78 78 </div>
79 79 <div class="input">
80 80 <div style="white-space:pre-wrap">${h.literal(c.pull_request.description)}</div>
81 81 </div>
82 82 </div>
83 83 <div class="field">
84 84 <div class="label-summary">
85 85 <label>${_('Created on')}:</label>
86 86 </div>
87 87 <div class="input">
88 88 <div>${h.fmt_date(c.pull_request.created_on)}</div>
89 89 </div>
90 90 </div>
91 91 </div>
92 92 </div>
93 93
94 94 <div style="overflow: auto;">
95 95 ##DIFF
96 96 <div class="table" style="float:left;clear:none">
97 97 <div id="body" class="diffblock">
98 98 <div style="white-space:pre-wrap;padding:5px">${_('Compare view')}</div>
99 99 </div>
100 100 <div id="changeset_compare_view_content">
101 101 ##CS
102 102 <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${ungettext('Showing %s commit','Showing %s commits', len(c.cs_ranges)) % len(c.cs_ranges)}</div>
103 103 <%include file="/compare/compare_cs.html" />
104 104
105 105 ## FILES
106 106 <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">
107 107
108 108 % if c.limited_diff:
109 109 ${ungettext('%s file changed', '%s files changed', len(c.files)) % len(c.files)}
110 110 % else:
111 111 ${ungettext('%s file changed with %s insertions and %s deletions','%s files changed with %s insertions and %s deletions', len(c.files)) % (len(c.files),c.lines_added,c.lines_deleted)}:
112 112 %endif
113 113
114 114 </div>
115 115 <div class="cs_files">
116 116 %if not c.files:
117 117 <span class="empty_data">${_('No files')}</span>
118 118 %endif
119 119 %for fid, change, f, stat in c.files:
120 120 <div class="cs_${change}">
121 121 <div class="node">${h.link_to(h.safe_unicode(f),h.url.current(anchor=fid))}</div>
122 122 <div class="changes">${h.fancy_file_stats(stat)}</div>
123 123 </div>
124 124 %endfor
125 125 </div>
126 126 % if c.limited_diff:
127 127 <h5>${_('Changeset was too big and was cut off...')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}" onclick="return confirm('${_("confirm to show potentially huge diff")}')">${_('Show full diff')}</a></h5>
128 128 % endif
129 129 </div>
130 130 </div>
131 131 ## REVIEWERS
132 132 <div style="float:left; border-left:1px dashed #eee">
133 133 <h4>${_('Pull request reviewers')}</h4>
134 134 <div id="reviewers" style="padding:0px 0px 5px 10px">
135 135 ## members goes here !
136 136 <div class="group_members_wrap" style="min-height:45px">
137 137 <ul id="review_members" class="group_members">
138 138 %for member,status in c.pull_request_reviewers:
139 139 <li id="reviewer_${member.user_id}">
140 140 <div class="reviewers_member">
141 141 <div style="float:left;padding:0px 3px 0px 0px" class="tooltip" title="${h.tooltip(h.changeset_status_lbl(status[0][1].status if status else 'not_reviewed'))}">
142 142 <img src="${h.url(str('/images/icons/flag_status_%s.png' % (status[0][1].status if status else 'not_reviewed')))}"/>
143 143 </div>
144 144 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(member.email,14)}"/> </div>
145 145 <div style="float:left">${member.full_name} (${_('owner') if c.pull_request.user_id == member.user_id else _('reviewer')})</div>
146 146 <input type="hidden" value="${member.user_id}" name="review_members" />
147 147 %if not c.pull_request.is_closed() and (h.HasPermissionAny('hg.admin', 'repository.admin')() or c.pull_request.user_id == c.rhodecode_user.user_id):
148 148 <span class="delete_icon action_button" onclick="removeReviewMember(${member.user_id})"></span>
149 149 %endif
150 150 </div>
151 151 </li>
152 152 %endfor
153 153 </ul>
154 154 </div>
155 155 %if not c.pull_request.is_closed():
156 156 <div class='ac'>
157 157 %if h.HasPermissionAny('hg.admin', 'repository.admin')() or c.pull_request.author.user_id == c.rhodecode_user.user_id:
158 158 <div class="reviewer_ac">
159 159 ${h.text('user', class_='yui-ac-input')}
160 160 <span class="help-block">${_('Add or remove reviewer to this pull request.')}</span>
161 161 <div id="reviewers_container"></div>
162 162 </div>
163 163 <div style="padding:0px 10px">
164 <span id="update_pull_request" class="ui-btn xsmall">${_('save changes')}</span>
164 <span id="update_pull_request" class="ui-btn xsmall">${_('Save changes')}</span>
165 165 </div>
166 166 %endif
167 167 </div>
168 168 %endif
169 169 </div>
170 170 </div>
171 171 </div>
172 172 <script>
173 173 var _USERS_AC_DATA = ${c.users_array|n};
174 174 var _GROUPS_AC_DATA = ${c.users_groups_array|n};
175 175 // TODO: switch this to pyroutes
176 176 AJAX_COMMENT_URL = "${url('pullrequest_comment',repo_name=c.repo_name,pull_request_id=c.pull_request.pull_request_id)}";
177 177 AJAX_COMMENT_DELETE_URL = "${url('pullrequest_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}";
178 178
179 179 pyroutes.register('pullrequest_comment', "${url('pullrequest_comment',repo_name='%(repo_name)s',pull_request_id='%(pull_request_id)s')}", ['repo_name', 'pull_request_id']);
180 180 pyroutes.register('pullrequest_comment_delete', "${url('pullrequest_comment_delete',repo_name='%(repo_name)s',comment_id='%(comment_id)s')}", ['repo_name', 'comment_id']);
181 181 pyroutes.register('pullrequest_update', "${url('pullrequest_update',repo_name='%(repo_name)s',pull_request_id='%(pull_request_id)s')}", ['repo_name', 'pull_request_id']);
182 182
183 183 </script>
184 184
185 185 ## diff block
186 186 <%namespace name="diff_block" file="/changeset/diff_block.html"/>
187 187 %for fid, change, f, stat in c.files:
188 188 ${diff_block.diff_block_simple([c.changes[fid]])}
189 189 %endfor
190 190 % if c.limited_diff:
191 191 <h4>${_('Changeset was too big and was cut off...')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}" onclick="return confirm('${_("confirm to show potentially huge diff")}')">${_('Show full diff')}</a></h4>
192 192 % endif
193 193
194 194
195 195 ## template for inline comment form
196 196 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
197 197 ${comment.comment_inline_form()}
198 198
199 199 ## render comments and inlines
200 200 ${comment.generate_comments(include_pr=True)}
201 201
202 202 % if not c.pull_request.is_closed():
203 203 ## main comment form and it status
204 204 ${comment.comments(h.url('pullrequest_comment', repo_name=c.repo_name,
205 205 pull_request_id=c.pull_request.pull_request_id),
206 206 c.current_changeset_status,
207 207 close_btn=True, change_status=c.allowed_to_change_status)}
208 208 %endif
209 209
210 210 <script type="text/javascript">
211 211 YUE.onDOMReady(function(){
212 212 PullRequestAutoComplete('user', 'reviewers_container', _USERS_AC_DATA, _GROUPS_AC_DATA);
213 213
214 214 YUE.on(YUQ('.show-inline-comments'),'change',function(e){
215 215 var show = 'none';
216 216 var target = e.currentTarget;
217 217 if(target.checked){
218 218 var show = ''
219 219 }
220 220 var boxid = YUD.getAttribute(target,'id_for');
221 221 var comments = YUQ('#{0} .inline-comments'.format(boxid));
222 222 for(c in comments){
223 223 YUD.setStyle(comments[c],'display',show);
224 224 }
225 225 var btns = YUQ('#{0} .inline-comments-button'.format(boxid));
226 226 for(c in btns){
227 227 YUD.setStyle(btns[c],'display',show);
228 228 }
229 229 })
230 230
231 231 YUE.on(YUQ('.line'),'click',function(e){
232 232 var tr = e.currentTarget;
233 233 injectInlineForm(tr);
234 234 });
235 235
236 236 // inject comments into they proper positions
237 237 var file_comments = YUQ('.inline-comment-placeholder');
238 238 renderInlineComments(file_comments);
239 239
240 240 YUE.on(YUD.get('update_pull_request'),'click',function(e){
241 241 updateReviewers(undefined, "${c.repo_name}", "${c.pull_request.pull_request_id}");
242 242 })
243 243 })
244 244 </script>
245 245
246 246 </div>
247 247
248 248 </%def>
General Comments 0
You need to be logged in to leave comments. Login now