comparison public/javascripts/application.js @ 1115:433d4f72a19b redmine-2.2

Update to Redmine SVN revision 11137 on 2.2-stable branch
author Chris Cannam
date Mon, 07 Jan 2013 12:01:42 +0000
parents cbb26bc654de
children bb32da3bea34 622f24f53b42 261b3d9a4903
comparison
equal deleted inserted replaced
929:5f33065ddc4b 1115:433d4f72a19b
1 /* redMine - project management software 1 /* Redmine - project management software
2 Copyright (C) 2006-2008 Jean-Philippe Lang */ 2 Copyright (C) 2006-2012 Jean-Philippe Lang */
3 3
4 function checkAll (id, checked) { 4 function checkAll(id, checked) {
5 var els = Element.descendants(id); 5 if (checked) {
6 for (var i = 0; i < els.length; i++) { 6 $('#'+id).find('input[type=checkbox]').attr('checked', true);
7 if (els[i].disabled==false) { 7 } else {
8 els[i].checked = checked; 8 $('#'+id).find('input[type=checkbox]').removeAttr('checked');
9 } 9 }
10 }
11 } 10 }
12 11
13 function toggleCheckboxesBySelector(selector) { 12 function toggleCheckboxesBySelector(selector) {
14 boxes = $$(selector); 13 var all_checked = true;
15 var all_checked = true; 14 $(selector).each(function(index) {
16 for (i = 0; i < boxes.length; i++) { if (boxes[i].checked == false) { all_checked = false; } } 15 if (!$(this).is(':checked')) { all_checked = false; }
17 for (i = 0; i < boxes.length; i++) { boxes[i].checked = !all_checked; } 16 });
18 } 17 $(selector).attr('checked', !all_checked)
19
20 function setCheckboxesBySelector(checked, selector) {
21 var boxes = $$(selector);
22 boxes.each(function(ele) {
23 ele.checked = checked;
24 });
25 } 18 }
26 19
27 function showAndScrollTo(id, focus) { 20 function showAndScrollTo(id, focus) {
28 Element.show(id); 21 $('#'+id).show();
29 if (focus!=null) { Form.Element.focus(focus); } 22 if (focus!=null) {
30 Element.scrollTo(id); 23 $('#'+focus).focus();
24 }
25 $('html, body').animate({scrollTop: $('#'+id).offset().top}, 100);
31 } 26 }
32 27
33 function toggleRowGroup(el) { 28 function toggleRowGroup(el) {
34 var tr = Element.up(el, 'tr'); 29 var tr = $(el).parents('tr').first();
35 var n = Element.next(tr); 30 var n = tr.next();
36 tr.toggleClassName('open'); 31 tr.toggleClass('open');
37 while (n != undefined && !n.hasClassName('group')) { 32 while (n.length && !n.hasClass('group')) {
38 Element.toggle(n); 33 n.toggle();
39 n = Element.next(n); 34 n = n.next('tr');
40 } 35 }
41 } 36 }
42 37
43 function collapseAllRowGroups(el) { 38 function collapseAllRowGroups(el) {
44 var tbody = Element.up(el, 'tbody'); 39 var tbody = $(el).parents('tbody').first();
45 tbody.childElements('tr').each(function(tr) { 40 tbody.children('tr').each(function(index) {
46 if (tr.hasClassName('group')) { 41 if ($(this).hasClass('group')) {
47 tr.removeClassName('open'); 42 $(this).removeClass('open');
48 } else { 43 } else {
49 tr.hide(); 44 $(this).hide();
50 } 45 }
51 }) 46 });
52 } 47 }
53 48
54 function expandAllRowGroups(el) { 49 function expandAllRowGroups(el) {
55 var tbody = Element.up(el, 'tbody'); 50 var tbody = $(el).parents('tbody').first();
56 tbody.childElements('tr').each(function(tr) { 51 tbody.children('tr').each(function(index) {
57 if (tr.hasClassName('group')) { 52 if ($(this).hasClass('group')) {
58 tr.addClassName('open'); 53 $(this).addClass('open');
59 } else { 54 } else {
60 tr.show(); 55 $(this).show();
61 } 56 }
62 }) 57 });
63 } 58 }
64 59
65 function toggleAllRowGroups(el) { 60 function toggleAllRowGroups(el) {
66 var tr = Element.up(el, 'tr'); 61 var tr = $(el).parents('tr').first();
67 if (tr.hasClassName('open')) { 62 if (tr.hasClass('open')) {
68 collapseAllRowGroups(el); 63 collapseAllRowGroups(el);
69 } else { 64 } else {
70 expandAllRowGroups(el); 65 expandAllRowGroups(el);
71 } 66 }
72 } 67 }
73 68
74 function toggleFieldset(el) { 69 function toggleFieldset(el) {
75 var fieldset = Element.up(el, 'fieldset'); 70 var fieldset = $(el).parents('fieldset').first();
76 fieldset.toggleClassName('collapsed'); 71 fieldset.toggleClass('collapsed');
77 Effect.toggle(fieldset.down('div'), 'slide', {duration:0.2}); 72 fieldset.children('div').toggle();
78 } 73 }
79 74
80 function hideFieldset(el) { 75 function hideFieldset(el) {
81 var fieldset = Element.up(el, 'fieldset'); 76 var fieldset = $(el).parents('fieldset').first();
82 fieldset.toggleClassName('collapsed'); 77 fieldset.toggleClass('collapsed');
83 fieldset.down('div').hide(); 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 "w":
246 case "o":
247 case "c":
248 enableValues(field, []);
249 break;
250 case "><":
251 enableValues(field, [0,1]);
252 break;
253 case "<t+":
254 case ">t+":
255 case "><t+":
256 case "t+":
257 case ">t-":
258 case "<t-":
259 case "><t-":
260 case "t-":
261 enableValues(field, [2]);
262 break;
263 case "=p":
264 case "=!p":
265 case "!p":
266 enableValues(field, [1]);
267 break;
268 default:
269 enableValues(field, [0]);
270 break;
271 }
272 }
273
274 function toggleMultiSelect(el) {
275 if (el.attr('multiple')) {
276 el.removeAttr('multiple');
277 } else {
278 el.attr('multiple', true);
279 }
280 }
281
282 function submit_query_form(id) {
283 selectAllOptions("selected_columns");
284 $('#'+id).submit();
84 } 285 }
85 286
86 var fileFieldCount = 1; 287 var fileFieldCount = 1;
87
88 function addFileField() { 288 function addFileField() {
89 var fields = $('attachments_fields'); 289 var fields = $('#attachments_fields');
90 if (fields.childElements().length >= 10) return false; 290 if (fields.children().length >= 10) return false;
91 fileFieldCount++; 291 fileFieldCount++;
92 var s = new Element('span'); 292 var s = fields.children('span').first().clone();
93 s.update(fields.down('span').innerHTML); 293 s.children('input.file').attr('name', "attachments[" + fileFieldCount + "][file]").val('');
94 s.down('input.file').name = "attachments[" + fileFieldCount + "][file]"; 294 s.children('input.description').attr('name', "attachments[" + fileFieldCount + "][description]").val('');
95 s.down('input.description').name = "attachments[" + fileFieldCount + "][description]"; 295 fields.append(s);
96 fields.appendChild(s);
97 } 296 }
98 297
99 function removeFileField(el) { 298 function removeFileField(el) {
100 var fields = $('attachments_fields'); 299 var fields = $('#attachments_fields');
101 var s = Element.up(el, 'span'); 300 var s = $(el).parents('span').first();
102 if (fields.childElements().length > 1) { 301 if (fields.children().length > 1) {
103 s.remove(); 302 s.remove();
104 } else { 303 } else {
105 s.update(s.innerHTML); 304 s.children('input.file').val('');
106 } 305 s.children('input.description').val('');
306 }
107 } 307 }
108 308
109 function checkFileSize(el, maxSize, message) { 309 function checkFileSize(el, maxSize, message) {
110 var files = el.files; 310 var files = el.files;
111 if (files) { 311 if (files) {
117 } 317 }
118 } 318 }
119 } 319 }
120 320
121 function showTab(name) { 321 function showTab(name) {
122 var f = $$('div#content .tab-content'); 322 $('div#content .tab-content').hide();
123 for(var i=0; i<f.length; i++){ 323 $('div.tabs a').removeClass('selected');
124 Element.hide(f[i]); 324 $('#tab-content-' + name).show();
125 } 325 $('#tab-' + name).addClass('selected');
126 var f = $$('div.tabs a'); 326 return false;
127 for(var i=0; i<f.length; i++){
128 Element.removeClassName(f[i], "selected");
129 }
130 Element.show('tab-content-' + name);
131 Element.addClassName('tab-' + name, "selected");
132 return false;
133 } 327 }
134 328
135 function moveTabRight(el) { 329 function moveTabRight(el) {
136 var lis = Element.up(el, 'div.tabs').down('ul').childElements(); 330 var lis = $(el).parents('div.tabs').first().find('ul').children();
137 var tabsWidth = 0; 331 var tabsWidth = 0;
138 var i; 332 var i = 0;
139 for (i=0; i<lis.length; i++) { 333 lis.each(function(){
140 if (lis[i].visible()) { 334 if ($(this).is(':visible')) {
141 tabsWidth += lis[i].getWidth() + 6; 335 tabsWidth += $(this).width() + 6;
142 } 336 }
143 } 337 });
144 if (tabsWidth < Element.up(el, 'div.tabs').getWidth() - 60) { 338 if (tabsWidth < $(el).parents('div.tabs').first().width() - 60) { return; }
145 return; 339 while (i<lis.length && !lis.eq(i).is(':visible')) { i++; }
146 } 340 lis.eq(i).hide();
147 i=0;
148 while (i<lis.length && !lis[i].visible()) {
149 i++;
150 }
151 lis[i].hide();
152 } 341 }
153 342
154 function moveTabLeft(el) { 343 function moveTabLeft(el) {
155 var lis = Element.up(el, 'div.tabs').down('ul').childElements(); 344 var lis = $(el).parents('div.tabs').first().find('ul').children();
156 var i = 0; 345 var i = 0;
157 while (i<lis.length && !lis[i].visible()) { 346 while (i<lis.length && !lis.eq(i).is(':visible')) { i++; }
158 i++; 347 if (i>0) {
159 } 348 lis.eq(i-1).show();
160 if (i>0) { 349 }
161 lis[i-1].show();
162 }
163 } 350 }
164 351
165 function displayTabsButtons() { 352 function displayTabsButtons() {
166 var lis; 353 var lis;
167 var tabsWidth = 0; 354 var tabsWidth = 0;
168 var i; 355 var el;
169 $$('div.tabs').each(function(el) { 356 $('div.tabs').each(function() {
170 lis = el.down('ul').childElements(); 357 el = $(this);
171 for (i=0; i<lis.length; i++) { 358 lis = el.find('ul').children();
172 if (lis[i].visible()) { 359 lis.each(function(){
173 tabsWidth += lis[i].getWidth() + 6; 360 if ($(this).is(':visible')) {
174 } 361 tabsWidth += $(this).width() + 6;
175 } 362 }
176 if ((tabsWidth < el.getWidth() - 60) && (lis[0].visible())) { 363 });
177 el.down('div.tabs-buttons').hide(); 364 if ((tabsWidth < el.width() - 60) && (lis.first().is(':visible'))) {
178 } else { 365 el.find('div.tabs-buttons').hide();
179 el.down('div.tabs-buttons').show(); 366 } else {
180 } 367 el.find('div.tabs-buttons').show();
181 }); 368 }
369 });
182 } 370 }
183 371
184 function setPredecessorFieldsVisibility() { 372 function setPredecessorFieldsVisibility() {
185 relationType = $('relation_relation_type'); 373 var relationType = $('#relation_relation_type');
186 if (relationType && (relationType.value == "precedes" || relationType.value == "follows")) { 374 if (relationType.val() == "precedes" || relationType.val() == "follows") {
187 Element.show('predecessor_fields'); 375 $('#predecessor_fields').show();
188 } else { 376 } else {
189 Element.hide('predecessor_fields'); 377 $('#predecessor_fields').hide();
190 } 378 }
191 } 379 }
192 380
193 function promptToRemote(text, param, url) { 381 function showModal(id, width) {
194 value = prompt(text + ':'); 382 var el = $('#'+id).first();
195 if (value) { 383 if (el.length == 0 || el.is(':visible')) {return;}
196 new Ajax.Request(url + '?' + param + '=' + encodeURIComponent(value), {asynchronous:true, evalScripts:true}); 384 var title = el.find('h3.title').text();
385 el.dialog({
386 width: width,
387 modal: true,
388 resizable: false,
389 dialogClass: 'modal',
390 title: title
391 });
392 el.find("input[type=text], input[type=submit]").first().focus();
393 }
394
395 function hideModal(el) {
396 var modal;
397 if (el) {
398 modal = $(el).parents('.ui-dialog-content');
399 } else {
400 modal = $('#ajax-modal');
401 }
402 modal.dialog("close");
403 }
404
405 function submitPreview(url, form, target) {
406 $.ajax({
407 url: url,
408 type: 'post',
409 data: $('#'+form).serialize(),
410 success: function(data){
411 $('#'+target).html(data);
412 }
413 });
414 }
415
416 function collapseScmEntry(id) {
417 $('.'+id).each(function() {
418 if ($(this).hasClass('open')) {
419 collapseScmEntry($(this).attr('id'));
420 }
421 $(this).hide();
422 });
423 $('#'+id).removeClass('open');
424 }
425
426 function expandScmEntry(id) {
427 $('.'+id).each(function() {
428 $(this).show();
429 if ($(this).hasClass('loaded') && !$(this).hasClass('collapsed')) {
430 expandScmEntry($(this).attr('id'));
431 }
432 });
433 $('#'+id).addClass('open');
434 }
435
436 function scmEntryClick(id, url) {
437 el = $('#'+id);
438 if (el.hasClass('open')) {
439 collapseScmEntry(id);
440 el.addClass('collapsed');
197 return false; 441 return false;
198 } 442 } else if (el.hasClass('loaded')) {
199 } 443 expandScmEntry(id);
200 444 el.removeClass('collapsed');
201 function showModal(id, width) {
202 el = $(id);
203 if (el == undefined || el.visible()) {return;}
204 var h = $$('body')[0].getHeight();
205 var d = document.createElement("div");
206 d.id = 'modalbg';
207 $('main').appendChild(d);
208 $('modalbg').setStyle({ width: '100%', height: h + 'px' });
209 $('modalbg').show();
210
211 var pageWidth = document.viewport.getWidth();
212 el.setStyle({'width': width});
213 el.setStyle({'left': (((pageWidth - el.getWidth())/2 *100) / pageWidth) + '%'});
214 el.addClassName('modal');
215 el.show();
216
217 var submit = el.down("input[type=submit]");
218 if (submit) {
219 submit.focus();
220 }
221 }
222
223 function hideModal(el) {
224 var modal = Element.up(el, 'div.modal');
225 if (modal) {
226 modal.hide();
227 }
228 var bg = $('modalbg');
229 if (bg) {
230 bg.remove();
231 }
232 }
233
234 function collapseScmEntry(id) {
235 var els = document.getElementsByClassName(id, 'browser');
236 for (var i = 0; i < els.length; i++) {
237 if (els[i].hasClassName('open')) {
238 collapseScmEntry(els[i].id);
239 }
240 Element.hide(els[i]);
241 }
242 $(id).removeClassName('open');
243 }
244
245 function expandScmEntry(id) {
246 var els = document.getElementsByClassName(id, 'browser');
247 for (var i = 0; i < els.length; i++) {
248 Element.show(els[i]);
249 if (els[i].hasClassName('loaded') && !els[i].hasClassName('collapsed')) {
250 expandScmEntry(els[i].id);
251 }
252 }
253 $(id).addClassName('open');
254 }
255
256 function scmEntryClick(id) {
257 el = $(id);
258 if (el.hasClassName('open')) {
259 collapseScmEntry(id);
260 el.addClassName('collapsed');
261 return false; 445 return false;
262 } else if (el.hasClassName('loaded')) { 446 }
263 expandScmEntry(id); 447 if (el.hasClass('loading')) {
264 el.removeClassName('collapsed');
265 return false; 448 return false;
266 } 449 }
267 if (el.hasClassName('loading')) { 450 el.addClass('loading');
268 return false; 451 $.ajax({
269 } 452 url: url,
270 el.addClassName('loading'); 453 success: function(data){
454 el.after(data);
455 el.addClass('open').addClass('loaded').removeClass('loading');
456 }
457 });
271 return true; 458 return true;
272 } 459 }
273 460
274 function scmEntryLoaded(id) {
275 Element.addClassName(id, 'open');
276 Element.addClassName(id, 'loaded');
277 Element.removeClassName(id, 'loading');
278 }
279
280 function randomKey(size) { 461 function randomKey(size) {
281 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'); 462 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');
282 var key = ''; 463 var key = '';
283 for (i = 0; i < size; i++) { 464 for (i = 0; i < size; i++) {
284 key += chars[Math.floor(Math.random() * chars.length)]; 465 key += chars[Math.floor(Math.random() * chars.length)];
285 } 466 }
286 return key; 467 return key;
287 } 468 }
288 469
289 function observeParentIssueField(url) { 470 // Can't use Rails' remote select because we need the form data
290 new Ajax.Autocompleter('issue_parent_issue_id', 471 function updateIssueFrom(url) {
291 'parent_issue_candidates', 472 $.ajax({
292 url, 473 url: url,
293 { minChars: 3, 474 type: 'post',
294 frequency: 0.5, 475 data: $('#issue-form').serialize()
295 paramName: 'q', 476 });
296 method: 'get', 477 }
297 updateElement: function(value) { 478
298 document.getElementById('issue_parent_issue_id').value = value.id; 479 function updateBulkEditFrom(url) {
299 }}); 480 $.ajax({
300 } 481 url: url,
301 482 type: 'post',
302 function observeRelatedIssueField(url) { 483 data: $('#bulk_edit_form').serialize()
303 new Ajax.Autocompleter('relation_issue_to_id', 484 });
304 'related_issue_candidates', 485 }
305 url, 486
306 { minChars: 3, 487 function observeAutocompleteField(fieldId, url) {
307 frequency: 0.5, 488 $(document).ready(function() {
308 paramName: 'q', 489 $('#'+fieldId).autocomplete({
309 method: 'get', 490 source: url,
310 updateElement: function(value) { 491 minLength: 2
311 document.getElementById('relation_issue_to_id').value = value.id; 492 });
312 }, 493 });
313 parameters: 'scope=all' 494 }
314 }); 495
315 } 496 function observeSearchfield(fieldId, targetId, url) {
316 497 $('#'+fieldId).each(function() {
317 function setVisible(id, visible) { 498 var $this = $(this);
318 var el = $(id); 499 $this.attr('data-value-was', $this.val());
319 if (el) {if (visible) {el.show();} else {el.hide();}} 500 var check = function() {
501 var val = $this.val();
502 if ($this.attr('data-value-was') != val){
503 $this.attr('data-value-was', val);
504 $.ajax({
505 url: url,
506 type: 'get',
507 data: {q: $this.val()},
508 success: function(data){ $('#'+targetId).html(data); },
509 beforeSend: function(){ $this.addClass('ajax-loading'); },
510 complete: function(){ $this.removeClass('ajax-loading'); }
511 });
512 }
513 };
514 var reset = function() {
515 if (timer) {
516 clearInterval(timer);
517 timer = setInterval(check, 300);
518 }
519 };
520 var timer = setInterval(check, 300);
521 $this.bind('keyup click mousemove', reset);
522 });
320 } 523 }
321 524
322 function observeProjectModules() { 525 function observeProjectModules() {
323 var f = function() { 526 var f = function() {
324 /* Hides trackers and issues custom fields on the new project form when issue_tracking module is disabled */ 527 /* Hides trackers and issues custom fields on the new project form when issue_tracking module is disabled */
325 var c = ($('project_enabled_module_names_issue_tracking').checked == true); 528 if ($('#project_enabled_module_names_issue_tracking').attr('checked')) {
326 setVisible('project_trackers', c); 529 $('#project_trackers').show();
327 setVisible('project_issue_custom_fields', c); 530 }else{
531 $('#project_trackers').hide();
532 }
328 }; 533 };
329 534
330 Event.observe(window, 'load', f); 535 $(window).load(f);
331 Event.observe('project_enabled_module_names_issue_tracking', 'change', f); 536 $('#project_enabled_module_names_issue_tracking').change(f);
332 } 537 }
333 538
334 /* 539 function initMyPageSortable(list, url) {
335 * Class used to warn user when leaving a page with unsaved textarea 540 $('#list-'+list).sortable({
336 * Author: mathias.fischer@berlinonline.de 541 connectWith: '.block-receiver',
337 */ 542 tolerance: 'pointer',
338 543 update: function(){
339 var WarnLeavingUnsaved = Class.create({ 544 $.ajax({
340 observedForms: false, 545 url: url,
341 observedElements: false, 546 type: 'post',
342 changedForms: false, 547 data: {'blocks': $.map($('#list-'+list).children(), function(el){return $(el).attr('id');})}
343 message: null, 548 });
344 549 }
345 initialize: function(message){ 550 });
346 this.observedForms = $$('form'); 551 $("#list-top, #list-left, #list-right").disableSelection();
347 this.observedElements = $$('textarea'); 552 }
348 this.message = message; 553
349 554 var warnLeavingUnsavedMessage;
350 this.observedElements.each(this.observeChange.bind(this)); 555 function warnLeavingUnsaved(message) {
351 this.observedForms.each(this.submitAction.bind(this)); 556 warnLeavingUnsavedMessage = message;
352 557
353 window.onbeforeunload = this.unload.bind(this); 558 $('form').submit(function(){
354 }, 559 $('textarea').removeData('changed');
355 560 });
356 unload: function(){ 561 $('textarea').change(function(){
357 this.observedElements.each(function(el) {el.blur();}) 562 $(this).data('changed', 'changed');
358 if(this.changedForms) 563 });
359 return this.message; 564 window.onbeforeunload = function(){
360 }, 565 var warn = false;
361 566 $('textarea').blur().each(function(){
362 setChanged: function(){ 567 if ($(this).data('changed')) {
363 this.changedForms = true; 568 warn = true;
364 }, 569 }
365 570 });
366 setUnchanged: function(){ 571 if (warn) {return warnLeavingUnsavedMessage;}
367 this.changedForms = false; 572 };
368 }, 573 };
369 574
370 observeChange: function(element){ 575 $(document).ready(function(){
371 element.observe('change',this.setChanged.bindAsEventListener(this)); 576 $('#ajax-indicator').bind('ajaxSend', function(){
372 }, 577 if ($('.ajax-loading').length == 0) {
373 578 $('#ajax-indicator').show();
374 submitAction: function(element){ 579 }
375 element.observe('submit',this.setUnchanged.bindAsEventListener(this)); 580 });
376 } 581 $('#ajax-indicator').bind('ajaxStop', function(){
582 $('#ajax-indicator').hide();
583 });
377 }); 584 });
378 585
379 /* 586 function hideOnLoad() {
380 * 1 - registers a callback which copies the csrf token into the 587 $('.hol').hide();
381 * X-CSRF-Token header with each ajax request. Necessary to 588 }
382 * work with rails applications which have fixed 589
383 * CVE-2011-0447 590 function addFormObserversForDoubleSubmit() {
384 * 2 - shows and hides ajax indicator 591 $('form[method=post]').each(function() {
385 */ 592 if (!$(this).hasClass('multiple-submit')) {
386 Ajax.Responders.register({ 593 $(this).submit(function(form_submission) {
387 onCreate: function(request){ 594 if ($(form_submission.target).attr('data-submitted')) {
388 var csrf_meta_tag = $$('meta[name=csrf-token]')[0]; 595 form_submission.preventDefault();
389 596 } else {
390 if (csrf_meta_tag) { 597 $(form_submission.target).attr('data-submitted', true);
391 var header = 'X-CSRF-Token',
392 token = csrf_meta_tag.readAttribute('content');
393
394 if (!request.options.requestHeaders) {
395 request.options.requestHeaders = {};
396 }
397 request.options.requestHeaders[header] = token;
398 }
399
400 if ($('ajax-indicator') && Ajax.activeRequestCount > 0) {
401 Element.show('ajax-indicator');
402 } 598 }
403 }, 599 });
404 onComplete: function(){ 600 }
405 if ($('ajax-indicator') && Ajax.activeRequestCount == 0) { 601 });
406 Element.hide('ajax-indicator'); 602 }
407 } 603
408 } 604 $(document).ready(hideOnLoad);
409 }); 605 $(document).ready(addFormObserversForDoubleSubmit);
410
411 function hideOnLoad() {
412 $$('.hol').each(function(el) {
413 el.hide();
414 });
415 }
416
417 Event.observe(window, 'load', hideOnLoad);