##// END OF EJS Templates
Fixed: No warning if unsaved text has not lost focus (#8468)....
Jean-Philippe Lang -
r5849:206a36704f37
parent child
Show More
@@ -1,371 +1,372
1 /* redMine - project management software
1 /* redMine - project management software
2 Copyright (C) 2006-2008 Jean-Philippe Lang */
2 Copyright (C) 2006-2008 Jean-Philippe Lang */
3
3
4 function checkAll (id, checked) {
4 function checkAll (id, checked) {
5 var els = Element.descendants(id);
5 var els = Element.descendants(id);
6 for (var i = 0; i < els.length; i++) {
6 for (var i = 0; i < els.length; i++) {
7 if (els[i].disabled==false) {
7 if (els[i].disabled==false) {
8 els[i].checked = checked;
8 els[i].checked = checked;
9 }
9 }
10 }
10 }
11 }
11 }
12
12
13 function toggleCheckboxesBySelector(selector) {
13 function toggleCheckboxesBySelector(selector) {
14 boxes = $$(selector);
14 boxes = $$(selector);
15 var all_checked = true;
15 var all_checked = true;
16 for (i = 0; i < boxes.length; i++) { if (boxes[i].checked == false) { all_checked = false; } }
16 for (i = 0; i < boxes.length; i++) { if (boxes[i].checked == false) { all_checked = false; } }
17 for (i = 0; i < boxes.length; i++) { boxes[i].checked = !all_checked; }
17 for (i = 0; i < boxes.length; i++) { boxes[i].checked = !all_checked; }
18 }
18 }
19
19
20 function setCheckboxesBySelector(checked, selector) {
20 function setCheckboxesBySelector(checked, selector) {
21 var boxes = $$(selector);
21 var boxes = $$(selector);
22 boxes.each(function(ele) {
22 boxes.each(function(ele) {
23 ele.checked = checked;
23 ele.checked = checked;
24 });
24 });
25 }
25 }
26
26
27 function showAndScrollTo(id, focus) {
27 function showAndScrollTo(id, focus) {
28 Element.show(id);
28 Element.show(id);
29 if (focus!=null) { Form.Element.focus(focus); }
29 if (focus!=null) { Form.Element.focus(focus); }
30 Element.scrollTo(id);
30 Element.scrollTo(id);
31 }
31 }
32
32
33 function toggleRowGroup(el) {
33 function toggleRowGroup(el) {
34 var tr = Element.up(el, 'tr');
34 var tr = Element.up(el, 'tr');
35 var n = Element.next(tr);
35 var n = Element.next(tr);
36 tr.toggleClassName('open');
36 tr.toggleClassName('open');
37 while (n != undefined && !n.hasClassName('group')) {
37 while (n != undefined && !n.hasClassName('group')) {
38 Element.toggle(n);
38 Element.toggle(n);
39 n = Element.next(n);
39 n = Element.next(n);
40 }
40 }
41 }
41 }
42
42
43 function collapseAllRowGroups(el) {
43 function collapseAllRowGroups(el) {
44 var tbody = Element.up(el, 'tbody');
44 var tbody = Element.up(el, 'tbody');
45 tbody.childElements('tr').each(function(tr) {
45 tbody.childElements('tr').each(function(tr) {
46 if (tr.hasClassName('group')) {
46 if (tr.hasClassName('group')) {
47 tr.removeClassName('open');
47 tr.removeClassName('open');
48 } else {
48 } else {
49 tr.hide();
49 tr.hide();
50 }
50 }
51 })
51 })
52 }
52 }
53
53
54 function expandAllRowGroups(el) {
54 function expandAllRowGroups(el) {
55 var tbody = Element.up(el, 'tbody');
55 var tbody = Element.up(el, 'tbody');
56 tbody.childElements('tr').each(function(tr) {
56 tbody.childElements('tr').each(function(tr) {
57 if (tr.hasClassName('group')) {
57 if (tr.hasClassName('group')) {
58 tr.addClassName('open');
58 tr.addClassName('open');
59 } else {
59 } else {
60 tr.show();
60 tr.show();
61 }
61 }
62 })
62 })
63 }
63 }
64
64
65 function toggleAllRowGroups(el) {
65 function toggleAllRowGroups(el) {
66 var tr = Element.up(el, 'tr');
66 var tr = Element.up(el, 'tr');
67 if (tr.hasClassName('open')) {
67 if (tr.hasClassName('open')) {
68 collapseAllRowGroups(el);
68 collapseAllRowGroups(el);
69 } else {
69 } else {
70 expandAllRowGroups(el);
70 expandAllRowGroups(el);
71 }
71 }
72 }
72 }
73
73
74 function toggleFieldset(el) {
74 function toggleFieldset(el) {
75 var fieldset = Element.up(el, 'fieldset');
75 var fieldset = Element.up(el, 'fieldset');
76 fieldset.toggleClassName('collapsed');
76 fieldset.toggleClassName('collapsed');
77 Effect.toggle(fieldset.down('div'), 'slide', {duration:0.2});
77 Effect.toggle(fieldset.down('div'), 'slide', {duration:0.2});
78 }
78 }
79
79
80 function hideFieldset(el) {
80 function hideFieldset(el) {
81 var fieldset = Element.up(el, 'fieldset');
81 var fieldset = Element.up(el, 'fieldset');
82 fieldset.toggleClassName('collapsed');
82 fieldset.toggleClassName('collapsed');
83 fieldset.down('div').hide();
83 fieldset.down('div').hide();
84 }
84 }
85
85
86 var fileFieldCount = 1;
86 var fileFieldCount = 1;
87
87
88 function addFileField() {
88 function addFileField() {
89 if (fileFieldCount >= 10) return false
89 if (fileFieldCount >= 10) return false
90 fileFieldCount++;
90 fileFieldCount++;
91 var f = document.createElement("input");
91 var f = document.createElement("input");
92 f.type = "file";
92 f.type = "file";
93 f.name = "attachments[" + fileFieldCount + "][file]";
93 f.name = "attachments[" + fileFieldCount + "][file]";
94 f.size = 30;
94 f.size = 30;
95 var d = document.createElement("input");
95 var d = document.createElement("input");
96 d.type = "text";
96 d.type = "text";
97 d.name = "attachments[" + fileFieldCount + "][description]";
97 d.name = "attachments[" + fileFieldCount + "][description]";
98 d.size = 60;
98 d.size = 60;
99 var dLabel = new Element('label');
99 var dLabel = new Element('label');
100 dLabel.addClassName('inline');
100 dLabel.addClassName('inline');
101 // Pulls the languge value used for Optional Description
101 // Pulls the languge value used for Optional Description
102 dLabel.update($('attachment_description_label_content').innerHTML)
102 dLabel.update($('attachment_description_label_content').innerHTML)
103 p = document.getElementById("attachments_fields");
103 p = document.getElementById("attachments_fields");
104 p.appendChild(document.createElement("br"));
104 p.appendChild(document.createElement("br"));
105 p.appendChild(f);
105 p.appendChild(f);
106 p.appendChild(dLabel);
106 p.appendChild(dLabel);
107 dLabel.appendChild(d);
107 dLabel.appendChild(d);
108
108
109 }
109 }
110
110
111 function showTab(name) {
111 function showTab(name) {
112 var f = $$('div#content .tab-content');
112 var f = $$('div#content .tab-content');
113 for(var i=0; i<f.length; i++){
113 for(var i=0; i<f.length; i++){
114 Element.hide(f[i]);
114 Element.hide(f[i]);
115 }
115 }
116 var f = $$('div.tabs a');
116 var f = $$('div.tabs a');
117 for(var i=0; i<f.length; i++){
117 for(var i=0; i<f.length; i++){
118 Element.removeClassName(f[i], "selected");
118 Element.removeClassName(f[i], "selected");
119 }
119 }
120 Element.show('tab-content-' + name);
120 Element.show('tab-content-' + name);
121 Element.addClassName('tab-' + name, "selected");
121 Element.addClassName('tab-' + name, "selected");
122 return false;
122 return false;
123 }
123 }
124
124
125 function moveTabRight(el) {
125 function moveTabRight(el) {
126 var lis = Element.up(el, 'div.tabs').down('ul').childElements();
126 var lis = Element.up(el, 'div.tabs').down('ul').childElements();
127 var tabsWidth = 0;
127 var tabsWidth = 0;
128 var i;
128 var i;
129 for (i=0; i<lis.length; i++) {
129 for (i=0; i<lis.length; i++) {
130 if (lis[i].visible()) {
130 if (lis[i].visible()) {
131 tabsWidth += lis[i].getWidth() + 6;
131 tabsWidth += lis[i].getWidth() + 6;
132 }
132 }
133 }
133 }
134 if (tabsWidth < Element.up(el, 'div.tabs').getWidth() - 60) {
134 if (tabsWidth < Element.up(el, 'div.tabs').getWidth() - 60) {
135 return;
135 return;
136 }
136 }
137 i=0;
137 i=0;
138 while (i<lis.length && !lis[i].visible()) {
138 while (i<lis.length && !lis[i].visible()) {
139 i++;
139 i++;
140 }
140 }
141 lis[i].hide();
141 lis[i].hide();
142 }
142 }
143
143
144 function moveTabLeft(el) {
144 function moveTabLeft(el) {
145 var lis = Element.up(el, 'div.tabs').down('ul').childElements();
145 var lis = Element.up(el, 'div.tabs').down('ul').childElements();
146 var i = 0;
146 var i = 0;
147 while (i<lis.length && !lis[i].visible()) {
147 while (i<lis.length && !lis[i].visible()) {
148 i++;
148 i++;
149 }
149 }
150 if (i>0) {
150 if (i>0) {
151 lis[i-1].show();
151 lis[i-1].show();
152 }
152 }
153 }
153 }
154
154
155 function displayTabsButtons() {
155 function displayTabsButtons() {
156 var lis;
156 var lis;
157 var tabsWidth = 0;
157 var tabsWidth = 0;
158 var i;
158 var i;
159 $$('div.tabs').each(function(el) {
159 $$('div.tabs').each(function(el) {
160 lis = el.down('ul').childElements();
160 lis = el.down('ul').childElements();
161 for (i=0; i<lis.length; i++) {
161 for (i=0; i<lis.length; i++) {
162 if (lis[i].visible()) {
162 if (lis[i].visible()) {
163 tabsWidth += lis[i].getWidth() + 6;
163 tabsWidth += lis[i].getWidth() + 6;
164 }
164 }
165 }
165 }
166 if ((tabsWidth < el.getWidth() - 60) && (lis[0].visible())) {
166 if ((tabsWidth < el.getWidth() - 60) && (lis[0].visible())) {
167 el.down('div.tabs-buttons').hide();
167 el.down('div.tabs-buttons').hide();
168 } else {
168 } else {
169 el.down('div.tabs-buttons').show();
169 el.down('div.tabs-buttons').show();
170 }
170 }
171 });
171 });
172 }
172 }
173
173
174 function setPredecessorFieldsVisibility() {
174 function setPredecessorFieldsVisibility() {
175 relationType = $('relation_relation_type');
175 relationType = $('relation_relation_type');
176 if (relationType && (relationType.value == "precedes" || relationType.value == "follows")) {
176 if (relationType && (relationType.value == "precedes" || relationType.value == "follows")) {
177 Element.show('predecessor_fields');
177 Element.show('predecessor_fields');
178 } else {
178 } else {
179 Element.hide('predecessor_fields');
179 Element.hide('predecessor_fields');
180 }
180 }
181 }
181 }
182
182
183 function promptToRemote(text, param, url) {
183 function promptToRemote(text, param, url) {
184 value = prompt(text + ':');
184 value = prompt(text + ':');
185 if (value) {
185 if (value) {
186 new Ajax.Request(url + '?' + param + '=' + encodeURIComponent(value), {asynchronous:true, evalScripts:true});
186 new Ajax.Request(url + '?' + param + '=' + encodeURIComponent(value), {asynchronous:true, evalScripts:true});
187 return false;
187 return false;
188 }
188 }
189 }
189 }
190
190
191 function collapseScmEntry(id) {
191 function collapseScmEntry(id) {
192 var els = document.getElementsByClassName(id, 'browser');
192 var els = document.getElementsByClassName(id, 'browser');
193 for (var i = 0; i < els.length; i++) {
193 for (var i = 0; i < els.length; i++) {
194 if (els[i].hasClassName('open')) {
194 if (els[i].hasClassName('open')) {
195 collapseScmEntry(els[i].id);
195 collapseScmEntry(els[i].id);
196 }
196 }
197 Element.hide(els[i]);
197 Element.hide(els[i]);
198 }
198 }
199 $(id).removeClassName('open');
199 $(id).removeClassName('open');
200 }
200 }
201
201
202 function expandScmEntry(id) {
202 function expandScmEntry(id) {
203 var els = document.getElementsByClassName(id, 'browser');
203 var els = document.getElementsByClassName(id, 'browser');
204 for (var i = 0; i < els.length; i++) {
204 for (var i = 0; i < els.length; i++) {
205 Element.show(els[i]);
205 Element.show(els[i]);
206 if (els[i].hasClassName('loaded') && !els[i].hasClassName('collapsed')) {
206 if (els[i].hasClassName('loaded') && !els[i].hasClassName('collapsed')) {
207 expandScmEntry(els[i].id);
207 expandScmEntry(els[i].id);
208 }
208 }
209 }
209 }
210 $(id).addClassName('open');
210 $(id).addClassName('open');
211 }
211 }
212
212
213 function scmEntryClick(id) {
213 function scmEntryClick(id) {
214 el = $(id);
214 el = $(id);
215 if (el.hasClassName('open')) {
215 if (el.hasClassName('open')) {
216 collapseScmEntry(id);
216 collapseScmEntry(id);
217 el.addClassName('collapsed');
217 el.addClassName('collapsed');
218 return false;
218 return false;
219 } else if (el.hasClassName('loaded')) {
219 } else if (el.hasClassName('loaded')) {
220 expandScmEntry(id);
220 expandScmEntry(id);
221 el.removeClassName('collapsed');
221 el.removeClassName('collapsed');
222 return false;
222 return false;
223 }
223 }
224 if (el.hasClassName('loading')) {
224 if (el.hasClassName('loading')) {
225 return false;
225 return false;
226 }
226 }
227 el.addClassName('loading');
227 el.addClassName('loading');
228 return true;
228 return true;
229 }
229 }
230
230
231 function scmEntryLoaded(id) {
231 function scmEntryLoaded(id) {
232 Element.addClassName(id, 'open');
232 Element.addClassName(id, 'open');
233 Element.addClassName(id, 'loaded');
233 Element.addClassName(id, 'loaded');
234 Element.removeClassName(id, 'loading');
234 Element.removeClassName(id, 'loading');
235 }
235 }
236
236
237 function randomKey(size) {
237 function randomKey(size) {
238 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');
238 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');
239 var key = '';
239 var key = '';
240 for (i = 0; i < size; i++) {
240 for (i = 0; i < size; i++) {
241 key += chars[Math.floor(Math.random() * chars.length)];
241 key += chars[Math.floor(Math.random() * chars.length)];
242 }
242 }
243 return key;
243 return key;
244 }
244 }
245
245
246 function observeParentIssueField(url) {
246 function observeParentIssueField(url) {
247 new Ajax.Autocompleter('issue_parent_issue_id',
247 new Ajax.Autocompleter('issue_parent_issue_id',
248 'parent_issue_candidates',
248 'parent_issue_candidates',
249 url,
249 url,
250 { minChars: 3,
250 { minChars: 3,
251 frequency: 0.5,
251 frequency: 0.5,
252 paramName: 'q',
252 paramName: 'q',
253 updateElement: function(value) {
253 updateElement: function(value) {
254 document.getElementById('issue_parent_issue_id').value = value.id;
254 document.getElementById('issue_parent_issue_id').value = value.id;
255 }});
255 }});
256 }
256 }
257
257
258 function observeRelatedIssueField(url) {
258 function observeRelatedIssueField(url) {
259 new Ajax.Autocompleter('relation_issue_to_id',
259 new Ajax.Autocompleter('relation_issue_to_id',
260 'related_issue_candidates',
260 'related_issue_candidates',
261 url,
261 url,
262 { minChars: 3,
262 { minChars: 3,
263 frequency: 0.5,
263 frequency: 0.5,
264 paramName: 'q',
264 paramName: 'q',
265 updateElement: function(value) {
265 updateElement: function(value) {
266 document.getElementById('relation_issue_to_id').value = value.id;
266 document.getElementById('relation_issue_to_id').value = value.id;
267 },
267 },
268 parameters: 'scope=all'
268 parameters: 'scope=all'
269 });
269 });
270 }
270 }
271
271
272 function setVisible(id, visible) {
272 function setVisible(id, visible) {
273 var el = $(id);
273 var el = $(id);
274 if (el) {if (visible) {el.show();} else {el.hide();}}
274 if (el) {if (visible) {el.show();} else {el.hide();}}
275 }
275 }
276
276
277 function observeProjectModules() {
277 function observeProjectModules() {
278 var f = function() {
278 var f = function() {
279 /* Hides trackers and issues custom fields on the new project form when issue_tracking module is disabled */
279 /* Hides trackers and issues custom fields on the new project form when issue_tracking module is disabled */
280 var c = ($('project_enabled_module_names_issue_tracking').checked == true);
280 var c = ($('project_enabled_module_names_issue_tracking').checked == true);
281 setVisible('project_trackers', c);
281 setVisible('project_trackers', c);
282 setVisible('project_issue_custom_fields', c);
282 setVisible('project_issue_custom_fields', c);
283 };
283 };
284
284
285 Event.observe(window, 'load', f);
285 Event.observe(window, 'load', f);
286 Event.observe('project_enabled_module_names_issue_tracking', 'change', f);
286 Event.observe('project_enabled_module_names_issue_tracking', 'change', f);
287 }
287 }
288
288
289 /*
289 /*
290 * Class used to warn user when leaving a page with unsaved textarea
290 * Class used to warn user when leaving a page with unsaved textarea
291 * Author: mathias.fischer@berlinonline.de
291 * Author: mathias.fischer@berlinonline.de
292 */
292 */
293
293
294 var WarnLeavingUnsaved = Class.create({
294 var WarnLeavingUnsaved = Class.create({
295 observedForms: false,
295 observedForms: false,
296 observedElements: false,
296 observedElements: false,
297 changedForms: false,
297 changedForms: false,
298 message: null,
298 message: null,
299
299
300 initialize: function(message){
300 initialize: function(message){
301 this.observedForms = $$('form');
301 this.observedForms = $$('form');
302 this.observedElements = $$('textarea');
302 this.observedElements = $$('textarea');
303 this.message = message;
303 this.message = message;
304
304
305 this.observedElements.each(this.observeChange.bind(this));
305 this.observedElements.each(this.observeChange.bind(this));
306 this.observedForms.each(this.submitAction.bind(this));
306 this.observedForms.each(this.submitAction.bind(this));
307
307
308 window.onbeforeunload = this.unload.bind(this);
308 window.onbeforeunload = this.unload.bind(this);
309 },
309 },
310
310
311 unload: function(){
311 unload: function(){
312 this.observedElements.each(function(el) {el.blur();})
312 if(this.changedForms)
313 if(this.changedForms)
313 return this.message;
314 return this.message;
314 },
315 },
315
316
316 setChanged: function(){
317 setChanged: function(){
317 this.changedForms = true;
318 this.changedForms = true;
318 },
319 },
319
320
320 setUnchanged: function(){
321 setUnchanged: function(){
321 this.changedForms = false;
322 this.changedForms = false;
322 },
323 },
323
324
324 observeChange: function(element){
325 observeChange: function(element){
325 element.observe('change',this.setChanged.bindAsEventListener(this));
326 element.observe('change',this.setChanged.bindAsEventListener(this));
326 },
327 },
327
328
328 submitAction: function(element){
329 submitAction: function(element){
329 element.observe('submit',this.setUnchanged.bindAsEventListener(this));
330 element.observe('submit',this.setUnchanged.bindAsEventListener(this));
330 }
331 }
331 });
332 });
332
333
333 /*
334 /*
334 * 1 - registers a callback which copies the csrf token into the
335 * 1 - registers a callback which copies the csrf token into the
335 * X-CSRF-Token header with each ajax request. Necessary to
336 * X-CSRF-Token header with each ajax request. Necessary to
336 * work with rails applications which have fixed
337 * work with rails applications which have fixed
337 * CVE-2011-0447
338 * CVE-2011-0447
338 * 2 - shows and hides ajax indicator
339 * 2 - shows and hides ajax indicator
339 */
340 */
340 Ajax.Responders.register({
341 Ajax.Responders.register({
341 onCreate: function(request){
342 onCreate: function(request){
342 var csrf_meta_tag = $$('meta[name=csrf-token]')[0];
343 var csrf_meta_tag = $$('meta[name=csrf-token]')[0];
343
344
344 if (csrf_meta_tag) {
345 if (csrf_meta_tag) {
345 var header = 'X-CSRF-Token',
346 var header = 'X-CSRF-Token',
346 token = csrf_meta_tag.readAttribute('content');
347 token = csrf_meta_tag.readAttribute('content');
347
348
348 if (!request.options.requestHeaders) {
349 if (!request.options.requestHeaders) {
349 request.options.requestHeaders = {};
350 request.options.requestHeaders = {};
350 }
351 }
351 request.options.requestHeaders[header] = token;
352 request.options.requestHeaders[header] = token;
352 }
353 }
353
354
354 if ($('ajax-indicator') && Ajax.activeRequestCount > 0) {
355 if ($('ajax-indicator') && Ajax.activeRequestCount > 0) {
355 Element.show('ajax-indicator');
356 Element.show('ajax-indicator');
356 }
357 }
357 },
358 },
358 onComplete: function(){
359 onComplete: function(){
359 if ($('ajax-indicator') && Ajax.activeRequestCount == 0) {
360 if ($('ajax-indicator') && Ajax.activeRequestCount == 0) {
360 Element.hide('ajax-indicator');
361 Element.hide('ajax-indicator');
361 }
362 }
362 }
363 }
363 });
364 });
364
365
365 function hideOnLoad() {
366 function hideOnLoad() {
366 $$('.hol').each(function(el) {
367 $$('.hol').each(function(el) {
367 el.hide();
368 el.hide();
368 });
369 });
369 }
370 }
370
371
371 Event.observe(window, 'load', hideOnLoad);
372 Event.observe(window, 'load', hideOnLoad);
General Comments 0
You need to be logged in to leave comments. Login now