Project

General

Profile

Defect #13811 ยป application.js

Partially cleaned up application.js (from POV of JSHint) - Adrian Wilkins, 2013-04-18 18:27

 
1
/* Redmine - project management software
2
   Copyright (C) 2006-2013  Jean-Philippe Lang */
3

    
4
function checkAll(id, checked) {
5
  if (checked) {
6
    $('#'+id).find('input[type=checkbox]').attr('checked', true);
7
  } else {
8
    $('#'+id).find('input[type=checkbox]').removeAttr('checked');
9
  }
10
}
11

    
12
function toggleCheckboxesBySelector(selector) {
13
  var all_checked = true;
14
  $(selector).each(function(index) {
15
    if (!$(this).is(':checked')) { all_checked = false; }
16
  });
17
  $(selector).attr('checked', !all_checked);
18
}
19

    
20
function showAndScrollTo(id, focus) {
21
  $('#'+id).show();
22
  if (focus !== null) {
23
    $('#'+focus).focus();
24
  }
25
  $('html, body').animate({scrollTop: $('#'+id).offset().top}, 100);
26
}
27

    
28
function toggleRowGroup(el) {
29
  var tr = $(el).parents('tr').first();
30
  var n = tr.next();
31
  tr.toggleClass('open');
32
  while (n.length && !n.hasClass('group')) {
33
    n.toggle();
34
    n = n.next('tr');
35
  }
36
}
37

    
38
function collapseAllRowGroups(el) {
39
  var tbody = $(el).parents('tbody').first();
40
  tbody.children('tr').each(function(index) {
41
    if ($(this).hasClass('group')) {
42
      $(this).removeClass('open');
43
    } else {
44
      $(this).hide();
45
    }
46
  });
47
}
48

    
49
function expandAllRowGroups(el) {
50
  var tbody = $(el).parents('tbody').first();
51
  tbody.children('tr').each(function(index) {
52
    if ($(this).hasClass('group')) {
53
      $(this).addClass('open');
54
    } else {
55
      $(this).show();
56
    }
57
  });
58
}
59

    
60
function toggleAllRowGroups(el) {
61
  var tr = $(el).parents('tr').first();
62
  if (tr.hasClass('open')) {
63
    collapseAllRowGroups(el);
64
  } else {
65
    expandAllRowGroups(el);
66
  }
67
}
68

    
69
function toggleFieldset(el) {
70
  var fieldset = $(el).parents('fieldset').first();
71
  fieldset.toggleClass('collapsed');
72
  fieldset.children('div').toggle();
73
}
74

    
75
function hideFieldset(el) {
76
  var fieldset = $(el).parents('fieldset').first();
77
  fieldset.toggleClass('collapsed');
78
  fieldset.children('div').hide();
79
}
80

    
81
function initFilters(){
82
  $('#add_filter_select').change(function(){
83
    addFilter($(this).val(), '', []);
84
  });
85
  $('#filters-table td.field input[type=checkbox]').each(function(){
86
    toggleFilter($(this).val());
87
  });
88
  $('#filters-table td.field input[type=checkbox]').live('click',function(){
89
    toggleFilter($(this).val());
90
  });
91
  $('#filters-table .toggle-multiselect').live('click',function(){
92
    toggleMultiSelect($(this).siblings('select'));
93
  });
94
  $('#filters-table input[type=text]').live('keypress', function(e){
95
    if (e.keyCode == 13) submit_query_form("query_form");
96
  });
97
}
98

    
99
function addFilter(field, operator, values) {
100
  var fieldId = field.replace('.', '_');
101
  var tr = $('#tr_'+fieldId);
102
  if (tr.length > 0) {
103
    tr.show();
104
  } else {
105
    buildFilterRow(field, operator, values);
106
  }
107
  $('#cb_'+fieldId).attr('checked', true);
108
  toggleFilter(field);
109
  $('#add_filter_select').val('').children('option').each(function(){
110
    if ($(this).attr('value') == field) {
111
      $(this).attr('disabled', true);
112
    }
113
  });
114
}
115

    
116
function buildFilterRow(field, operator, values) {
117
  var fieldId = field.replace('.', '_');
118
  var filterTable = $("#filters-table");
119
  var filterOptions = availableFilters[field];
120
  var operators = operatorByType[filterOptions['type']];
121
  var filterValues = filterOptions['values'];
122
  var i, select;
123

    
124
  var tr = $('<tr class="filter">').attr('id', 'tr_'+fieldId).html(
125
    '<td class="field"><input checked="checked" id="cb_'+fieldId+'" name="f[]" value="'+field+'" type="checkbox"><label for="cb_'+fieldId+'"> '+filterOptions['name']+'</label></td>' +
126
    '<td class="operator"><select id="operators_'+fieldId+'" name="op['+field+']"></td>' +
127
    '<td class="values"></td>'
128
  );
129
  filterTable.append(tr);
130

    
131
  select = tr.find('td.operator select');
132
  for (i=0;i<operators.length;i++){
133
    var option = $('<option>').val(operators[i]).text(operatorLabels[operators[i]]);
134
    if (operators[i] == operator) { option.attr('selected', true); }
135
    select.append(option);
136
  }
137
  select.change(function(){ toggleOperator(field); });
138

    
139
  switch (filterOptions['type']){
140
  case "list":
141
  case "list_optional":
142
  case "list_status":
143
  case "list_subprojects":
144
    tr.find('td.values').append(
145
      '<span style="display:none;"><select class="value" id="values_'+fieldId+'_1" name="v['+field+'][]"></select>' +
146
      ' <span class="toggle-multiselect">&nbsp;</span></span>'
147
    );
148
    select = tr.find('td.values select');
149
    if (values.length > 1) { select.attr('multiple', true); }
150
    for (i=0;i<filterValues.length;i++){
151
      var filterValue = filterValues[i];
152
      var option = $('<option>');
153
      if ($.isArray(filterValue)) {
154
        option.val(filterValue[1]).text(filterValue[0]);
155
        if ($.inArray(filterValue[1], values) > -1) {option.attr('selected', true);}
156
      } else {
157
        option.val(filterValue).text(filterValue);
158
        if ($.inArray(filterValue, values) > -1) {option.attr('selected', true);}
159
      }
160
      select.append(option);
161
    }
162
    break;
163
  case "date":
164
  case "date_past":
165
    tr.find('td.values').append(
166
      '<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_1" size="10" class="value date_value" /></span>' +
167
      ' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_2" size="10" class="value date_value" /></span>' +
168
      ' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="3" class="value" /> '+labelDayPlural+'</span>'
169
    );
170
    $('#values_'+fieldId+'_1').val(values[0]).datepicker(datepickerOptions);
171
    $('#values_'+fieldId+'_2').val(values[1]).datepicker(datepickerOptions);
172
    $('#values_'+fieldId).val(values[0]);
173
    break;
174
  case "string":
175
  case "text":
176
    tr.find('td.values').append(
177
      '<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="30" class="value" /></span>'
178
    );
179
    $('#values_'+fieldId).val(values[0]);
180
    break;
181
  case "relation":
182
    tr.find('td.values').append(
183
      '<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="6" class="value" /></span>' +
184
      '<span style="display:none;"><select class="value" name="v['+field+'][]" id="values_'+fieldId+'_1"></select></span>'
185
    );
186
    $('#values_'+fieldId).val(values[0]);
187
    select = tr.find('td.values select');
188
    for (i=0;i<allProjects.length;i++){
189
      var filterValue = allProjects[i];
190
      var option = $('<option>');
191
      option.val(filterValue[1]).text(filterValue[0]);
192
      if (values[0] == filterValue[1]) { option.attr('selected', true); }
193
      select.append(option);
194
    }
195
  case "integer":
196
  case "float":
197
    tr.find('td.values').append(
198
      '<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_1" size="6" class="value" /></span>' +
199
      ' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_2" size="6" class="value" /></span>'
200
    );
201
    $('#values_'+fieldId+'_1').val(values[0]);
202
    $('#values_'+fieldId+'_2').val(values[1]);
203
    break;
204
  }
205
}
206

    
207
function toggleFilter(field) {
208
  var fieldId = field.replace('.', '_');
209
  if ($('#cb_' + fieldId).is(':checked')) {
210
    $("#operators_" + fieldId).show().removeAttr('disabled');
211
    toggleOperator(field);
212
  } else {
213
    $("#operators_" + fieldId).hide().attr('disabled', true);
214
    enableValues(field, []);
215
  }
216
}
217

    
218
function enableValues(field, indexes) {
219
  var fieldId = field.replace('.', '_');
220
  $('#tr_'+fieldId+' td.values .value').each(function(index) {
221
    if ($.inArray(index, indexes) >= 0) {
222
      $(this).removeAttr('disabled');
223
      $(this).parents('span').first().show();
224
    } else {
225
      $(this).val('');
226
      $(this).attr('disabled', true);
227
      $(this).parents('span').first().hide();
228
    }
229

    
230
    if ($(this).hasClass('group')) {
231
      $(this).addClass('open');
232
    } else {
233
      $(this).show();
234
    }
235
  });
236
}
237

    
238
function toggleOperator(field) {
239
  var fieldId = field.replace('.', '_');
240
  var operator = $("#operators_" + fieldId);
241
  switch (operator.val()) {
242
    case "!*":
243
    case "*":
244
    case "t":
245
    case "ld":
246
    case "w":
247
    case "lw":
248
    case "l2w":
249
    case "m":
250
    case "lm":
251
    case "y":
252
    case "o":
253
    case "c":
254
      enableValues(field, []);
255
      break;
256
    case "><":
257
      enableValues(field, [0,1]);
258
      break;
259
    case "<t+":
260
    case ">t+":
261
    case "><t+":
262
    case "t+":
263
    case ">t-":
264
    case "<t-":
265
    case "><t-":
266
    case "t-":
267
      enableValues(field, [2]);
268
      break;
269
    case "=p":
270
    case "=!p":
271
    case "!p":
272
      enableValues(field, [1]);
273
      break;
274
    default:
275
      enableValues(field, [0]);
276
      break;
277
  }
278
}
279

    
280
function toggleMultiSelect(el) {
281
  if (el.attr('multiple')) {
282
    el.removeAttr('multiple');
283
  } else {
284
    el.attr('multiple', true);
285
  }
286
}
287

    
288
function submit_query_form(id) {
289
  selectAllOptions("selected_columns");
290
  $('#'+id).submit();
291
}
292

    
293
function showTab(name) {
294
  $('div#content .tab-content').hide();
295
  $('div.tabs a').removeClass('selected');
296
  $('#tab-content-' + name).show();
297
  $('#tab-' + name).addClass('selected');
298
  return false;
299
}
300

    
301
function moveTabRight(el) {
302
  var lis = $(el).parents('div.tabs').first().find('ul').children();
303
  var tabsWidth = 0;
304
  var i = 0;
305
  lis.each(function(){
306
    if ($(this).is(':visible')) {
307
      tabsWidth += $(this).width() + 6;
308
    }
309
  });
310
  if (tabsWidth < $(el).parents('div.tabs').first().width() - 60) { return; }
311
  while (i<lis.length && !lis.eq(i).is(':visible')) { i++; }
312
  lis.eq(i).hide();
313
}
314

    
315
function moveTabLeft(el) {
316
  var lis = $(el).parents('div.tabs').first().find('ul').children();
317
  var i = 0;
318
  while (i<lis.length && !lis.eq(i).is(':visible')) { i++; }
319
  if (i>0) {
320
    lis.eq(i-1).show();
321
  }
322
}
323

    
324
function displayTabsButtons() {
325
  var lis;
326
  var tabsWidth = 0;
327
  var el;
328
  $('div.tabs').each(function() {
329
    el = $(this);
330
    lis = el.find('ul').children();
331
    lis.each(function(){
332
      if ($(this).is(':visible')) {
333
        tabsWidth += $(this).width() + 6;
334
      }
335
    });
336
    if ((tabsWidth < el.width() - 60) && (lis.first().is(':visible'))) {
337
      el.find('div.tabs-buttons').hide();
338
    } else {
339
      el.find('div.tabs-buttons').show();
340
    }
341
  });
342
}
343

    
344
function setPredecessorFieldsVisibility() {
345
  var relationType = $('#relation_relation_type');
346
  if (relationType.val() == "precedes" || relationType.val() == "follows") {
347
    $('#predecessor_fields').show();
348
  } else {
349
    $('#predecessor_fields').hide();
350
  }
351
}
352

    
353
function showModal(id, width) {
354
  var el = $('#'+id).first();
355
  if (el.length === 0 || el.is(':visible')) {return;}
356
  var title = el.find('h3.title').text();
357
  el.dialog({
358
    width: width,
359
    modal: true,
360
    resizable: false,
361
    dialogClass: 'modal',
362
    title: title
363
  });
364
  el.find("input[type=text], input[type=submit]").first().focus();
365
}
366

    
367
function hideModal(el) {
368
  var modal;
369
  if (el) {
370
    modal = $(el).parents('.ui-dialog-content');
371
  } else {
372
    modal = $('#ajax-modal');
373
  }
374
  modal.dialog("close");
375
}
376

    
377
function submitPreview(url, form, target) {
378
  $.ajax({
379
    url: url,
380
    type: 'post',
381
    data: $('#'+form).serialize(),
382
    success: function(data){
383
      $('#'+target).html(data);
384
    }
385
  });
386
}
387

    
388
function collapseScmEntry(id) {
389
  $('.'+id).each(function() {
390
    if ($(this).hasClass('open')) {
391
      collapseScmEntry($(this).attr('id'));
392
    }
393
    $(this).hide();
394
  });
395
  $('#'+id).removeClass('open');
396
}
397

    
398
function expandScmEntry(id) {
399
  $('.'+id).each(function() {
400
    $(this).show();
401
    if ($(this).hasClass('loaded') && !$(this).hasClass('collapsed')) {
402
      expandScmEntry($(this).attr('id'));
403
    }
404
  });
405
  $('#'+id).addClass('open');
406
}
407

    
408
function scmEntryClick(id, url) {
409
    el = $('#'+id);
410
    if (el.hasClass('open')) {
411
        collapseScmEntry(id);
412
        el.addClass('collapsed');
413
        return false;
414
    } else if (el.hasClass('loaded')) {
415
        expandScmEntry(id);
416
        el.removeClass('collapsed');
417
        return false;
418
    }
419
    if (el.hasClass('loading')) {
420
        return false;
421
    }
422
    el.addClass('loading');
423
    $.ajax({
424
      url: url,
425
      success: function(data){
426
        el.after(data);
427
        el.addClass('open').addClass('loaded').removeClass('loading');
428
      }
429
    });
430
    return true;
431
}
432

    
433
function randomKey(size) {
434
  var chars = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z');
435
  var key = '';
436
  for (i = 0; i < size; i++) {
437
    key += chars[Math.floor(Math.random() * chars.length)];
438
  }
439
  return key;
440
}
441

    
442
// Can't use Rails' remote select because we need the form data
443
function updateIssueFrom(url) {
444
  $.ajax({
445
    url: url,
446
    type: 'post',
447
    data: $('#issue-form').serialize()
448
  });
449
}
450

    
451
function updateBulkEditFrom(url) {
452
  $.ajax({
453
    url: url,
454
    type: 'post',
455
    data: $('#bulk_edit_form').serialize()
456
  });
457
}
458

    
459
function observeAutocompleteField(fieldId, url, options) {
460
  $(document).ready(function() {
461
    $('#'+fieldId).autocomplete($.extend({
462
      source: url,
463
      minLength: 2,
464
      search: function(){$('#'+fieldId).addClass('ajax-loading');},
465
      response: function(){$('#'+fieldId).removeClass('ajax-loading');}
466
    }, options));
467
    $('#'+fieldId).addClass('autocomplete');
468
  });
469
}
470

    
471
function observeSearchfield(fieldId, targetId, url) {
472
  $('#'+fieldId).each(function() {
473
    var $this = $(this);
474
    $this.addClass('autocomplete');
475
    $this.attr('data-value-was', $this.val());
476
    var check = function() {
477
      var val = $this.val();
478
      if ($this.attr('data-value-was') != val){
479
        $this.attr('data-value-was', val);
480
        $.ajax({
481
          url: url,
482
          type: 'get',
483
          data: {q: $this.val()},
484
          success: function(data){ if(targetId) $('#'+targetId).html(data); },
485
          beforeSend: function(){ $this.addClass('ajax-loading'); },
486
          complete: function(){ $this.removeClass('ajax-loading'); }
487
        });
488
      }
489
    };
490
    var reset = function() {
491
      if (timer) {
492
        clearInterval(timer);
493
        timer = setInterval(check, 300);
494
      }
495
    };
496
    var timer = setInterval(check, 300);
497
    $this.bind('keyup click mousemove', reset);
498
  });
499
}
500

    
501
function observeProjectModules() {
502
  var f = function() {
503
    /* Hides trackers and issues custom fields on the new project form when issue_tracking module is disabled */
504
    if ($('#project_enabled_module_names_issue_tracking').attr('checked')) {
505
      $('#project_trackers').show();
506
    }else{
507
      $('#project_trackers').hide();
508
    }
509
  };
510

    
511
  $(window).load(f);
512
  $('#project_enabled_module_names_issue_tracking').change(f);
513
}
514

    
515
function initMyPageSortable(list, url) {
516
  $('#list-'+list).sortable({
517
    connectWith: '.block-receiver',
518
    tolerance: 'pointer',
519
    update: function(){
520
      $.ajax({
521
        url: url,
522
        type: 'post',
523
        data: {'blocks': $.map($('#list-'+list).children(), function(el){return $(el).attr('id');})}
524
      });
525
    }
526
  });
527
  $("#list-top, #list-left, #list-right").disableSelection();
528
}
529

    
530
var warnLeavingUnsavedMessage;
531
function warnLeavingUnsaved(message) {
532
  warnLeavingUnsavedMessage = message;
533

    
534
  $('form').submit(function(){
535
    $('textarea').removeData('changed');
536
  });
537
  $('textarea').change(function(){
538
    $(this).data('changed', 'changed');
539
  });
540
  window.onbeforeunload = function(){
541
    var warn = false;
542
    $('textarea').blur().each(function(){
543
      if ($(this).data('changed')) {
544
        warn = true;
545
      }
546
    });
547
    if (warn) {return warnLeavingUnsavedMessage;}
548
  };
549
}
550

    
551
function setupAjaxIndicator() {
552

    
553
  $('#ajax-indicator').bind('ajaxSend', function(event, xhr, settings) {
554
  
555
    if ($('.ajax-loading').length === 0 && settings.contentType != 'application/octet-stream') {
556
      $('#ajax-indicator').show();
557
    }
558
  });
559
  
560
  $('#ajax-indicator').bind('ajaxStop', function() {
561
    $('#ajax-indicator').hide();
562
  });
563
}
564

    
565
function hideOnLoad() {
566
  $('.hol').hide();
567
}
568

    
569
function addFormObserversForDoubleSubmit() {
570
  $('form[method=post]').each(function() {
571
    if (!$(this).hasClass('multiple-submit')) {
572
      $(this).submit(function(form_submission) {
573
        if ($(form_submission.target).attr('data-submitted')) {
574
          form_submission.preventDefault();
575
        } else {
576
          $(form_submission.target).attr('data-submitted', true);
577
        }
578
      });
579
    }
580
  });
581
}
582

    
583
function blockEventPropagation(event) {
584
  event.stopPropagation();
585
  event.preventDefault();
586
}
587

    
588
$(document).ready(setupAjaxIndicator);
589
$(document).ready(hideOnLoad);
590
$(document).ready(addFormObserversForDoubleSubmit);
    (1-1/1)