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