bcdbd88334a5e2d5288b77d54729f1621d93a244
[infodrom/hallinta] / lib / functions.js
1 /*
2  * Small AJAX framework
3  */
4 function ajax_request_callback(req)
5 {
6     if (req.readyState == 4 && req.status == 200) {
7         var data = json_parse(req.responseText);
8
9         if (data && typeof data.error == 'string') {
10             if (typeof data.errormsg == 'string')
11                 error(data.errormsg);
12             else
13                 error(data.error);
14             alert(data.error);
15         } else if (req.oncomplete)
16             req.oncomplete(data);
17     }
18 }
19
20 function ajax_request(func,params,oncomplete)
21 {
22     var req = new XMLHttpRequest();
23     if (!req) return;
24
25     var params = 'func=' + func + '&' + params;
26     req.open ("POST", 'ajax/ajax.php');
27     req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
28     req.setRequestHeader("Content-length", params.length);
29     req.setRequestHeader("Connection", "close");
30     req.onreadystatechange = function() { ajax_request_callback(req); }
31     if (typeof oncomplete == 'function')
32         req.oncomplete = oncomplete;
33     req.send(params);
34     info('');
35     reset_logout();
36 }
37
38 var logout_timer = false;
39 window.setTimeout(reset_logout, 4000);
40 function reset_logout()
41 {
42     if (logout_timer)
43         window.clearTimeout(logout_timer);
44
45     logout_timer = window.setTimeout(function() {
46             window.location.href = 'index.php?logout=true';
47         }, parseInt(document.getElementById('logout_refresh').innerHTML)*1000);
48 }
49
50 var edit_hidden = false;
51 var form_file_name = null;
52 var form_file_content = null;
53 function form_file_change_onloadstart(e)
54 {
55     var button = document.getElementById('button_insert');
56     button.disabled = true;
57     info('Upload wird vorbereitet');
58 }
59
60 function form_file_change_onloadend(e)
61 {
62     var button = document.getElementById('button_insert');
63     button.disabled = false;
64     info('');
65 }
66
67 function form_file_change_onload(e)
68 {
69     form_file_content = new Uint8ClampedArray(e.target.result);
70 }
71
72 function form_file_change(e)
73 {
74     var file = e.target.files[0];
75     var reader = new FileReader();
76     reader.onload = form_file_change_onload;
77     reader.onloadend = form_file_change_onloadend;
78     reader.onloadstart = form_file_change_onloadstart;
79     reader.readAsArrayBuffer(file);
80     form_file_filename = file.name;
81 }
82
83 function ajax_form_submit(func,form,oncomplete)
84 {
85     var boundary = "---------------------------" + (new Date).getTime();
86     var CRLF  = "\r\n";
87     var req = new XMLHttpRequest();
88     if (!req) return;
89
90     var parts = new Array();
91
92     if (func && func.length) {
93         var part = 'Content-Disposition: form-data; ';
94         part += 'name="func"' + CRLF + CRLF;
95         part += func + CRLF;
96         parts.push(part);
97     }
98
99     for (var i=0; i < form.childNodes.length; i++) {
100         var part = '';
101         var element = form.childNodes[i];
102         var fieldName = element.name;
103
104         if (element.nodeName.toLowerCase() == 'input' &&
105             element.type.toLowerCase() == 'file') {
106
107             if (typeof element.files[0].getAsBinary != 'function' &&
108                 typeof window.FileReader == 'undefined') {
109                 error('Upload von Dateien nicht möglich');
110                 alert("Upload von Dateien in dieser Version von Firefox nicht möglich.\n" +
111                       "Bitte verwenden Sie Firefox in der Version 3.5.");
112                 return;
113             }
114
115             try {
116                 var binary = element.files[0].getAsBinary();
117                 var filename = element.files[0].fileName;
118             } catch(err) {
119                 if (form_file_content) {
120                     var binary = '';
121
122                     for (var j=0; j < form_file_content.length; j++)
123                         binary += String.fromCharCode(form_file_content[j]);    
124
125                     var filename = form_file_filename;
126                 } else {
127                     error('Problem beim Lesen der Datei');
128                     alert("Problem beim Lesen der Datei\n" +
129                           element.files[0].fileName + "\n" +
130                           "Eventuell stimmt das Encoding nicht\n" +
131                           "Die Daten wurden nicht gespeichert");
132                     return;
133                 }
134             }
135
136             part = 'Content-Disposition: form-data; ';
137             part += 'name="' + fieldName + '"; ';
138             part += 'filename="'+ filename + '"' + CRLF;
139             part += "Content-Type: application/octet-stream" + CRLF + CRLF;
140             part += binary + CRLF;
141         } else if (element.nodeName.toLowerCase() == 'input' ||
142                    element.nodeName.toLowerCase() == 'textarea' ||
143                    element.nodeName.toLowerCase() == 'select') {
144             var value = '';
145             if (element.type.toLowerCase() == 'checkbox') {
146                 if (element.checked) value = 'on';
147                 else value = 'off';
148             } else {
149                 value = element.value;
150             }
151
152             part = 'Content-Disposition: form-data; ';
153             part += 'name="' + element.name + '"' + CRLF + CRLF;
154             part += value + CRLF;
155         } else
156             continue;
157         parts.push(part);
158     }
159
160     var params = "--" + boundary + CRLF;
161     params += parts.join("--" + boundary + CRLF);
162     params += "--" + boundary + "--" + CRLF;
163
164     req.open ("POST", 'ajax/ajax.php');
165     req.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
166     req.setRequestHeader("Connection", "close");
167     req.onreadystatechange = function() { ajax_request_callback(req); }
168     if (typeof oncomplete == 'function')
169         req.oncomplete = oncomplete;
170     req.sendAsBinary(params);
171
172     info('');
173     form_clear(form);
174 }
175
176 function info(msg)
177 {
178     var status = document.getElementById('status');
179     if (!status) return;
180
181     status.innerHTML = msg;
182     status.className = 'status_ok';
183 }
184
185 function error(msg)
186 {
187     var status = document.getElementById('status');
188     if (!status) return;
189
190     status.innerHTML = msg;
191     status.className = 'status_error';
192 }
193
194 function button_enable(id)
195 {
196     var button = document.getElementById(id);
197     if (!button) return;
198
199     button.className = '';
200     button.disabled = false;
201 }
202
203 function button_disable(id)
204 {
205     var button = document.getElementById(id);
206     if (!button) return;
207
208     button.className = 'disabled';
209     button.disabled = true;
210 }
211
212 function set_value(id, value)
213 {
214     var obj = document.getElementById(id);
215     if (!obj) return;
216
217     if (obj.nodeName.toLowerCase() == 'input') {
218         if (obj.type.toLowerCase() == 'checkbox') {
219             if (value) obj.checked = true;
220             else obj.checked = false;
221         } else if (obj.type.toLowerCase() == 'file')
222             return;
223         else
224             obj.value = value;
225     } else if (obj.nodeName.toLowerCase() == 'textarea')
226         obj.value = value;
227     else if (obj.nodeName.toLowerCase() == 'span')
228         obj.innerHTML = value;
229     else if (obj.nodeName.toLowerCase() == 'select') {
230         for (var i=0; i < obj.options.length; i++)
231             if (obj.options[i].value == value)
232                 obj.selectedIndex = i;
233     } else
234         obj.innerHTML = value;
235 }
236
237 function setvar(obj, name, callback, status)
238 {
239     if (!obj.options[obj.selectedIndex].value.length)
240         value = -1;
241     else
242         value = obj.options[obj.selectedIndex].value;
243
244     var source = document.getElementById('source');
245
246     if (!source) return false;
247
248     var parms = 'source=' + source.innerHTML + '&name=' + name + '&value=' + value;
249
250     ajax_request('setvar', parms, callback);
251
252     if (typeof status == 'function')
253         status(obj,value,obj.options[obj.selectedIndex].innerHTML);
254 }
255
256 function get_info(name, values, callback)
257 {
258     var source = document.getElementById('source');
259
260     if (!source) return false;
261
262     var parms = 'source=' + source.innerHTML + '&name=' + name;
263     for (key in values)
264         parms += '&' + key + '=' + values[key];
265
266     ajax_request('info', parms, callback);
267 }
268
269 /*
270  * Form functions
271  */
272 function form_clear(form)
273 {
274     if (!form) return;
275
276     for (var i=0; i < form.childNodes.length; i++)
277         if (form.childNodes[i].nodeName.toLowerCase() == 'input'
278             && (form.childNodes[i].type.toLowerCase() == 'password' ||
279                 form.childNodes[i].type.toLowerCase() == 'file'))
280             form.childNodes[i].value = '';
281
282     var id = document.getElementById('edit_id');
283     if (id) id.value = '';
284 }
285
286 var form_first_use = true;
287 function form_init()
288 {
289     var form = document.getElementById('form_edit');
290
291     if (!form) return;
292
293     form_clear(form);
294
295     var elem = form.findFirstElement();
296     if (elem) elem.activate();
297 }
298
299 function form_elem_error(elem,text)
300 {
301     elem.style.borderColor = 'red';
302     elem.style.borderWidth = '1px';
303     elem.style.borderStyle = 'solid';
304     error(text);
305 }
306
307 function form_elem_ok(elem)
308 {
309     elem.style.borderColor = '';
310     elem.style.borderWidth = '';
311     elem.style.borderStyle = '';
312 }
313
314 function form_reset_errors()
315 {
316    for (name in form_check) {
317         var elem = document.getElementById('edit_' + name);
318         form_elem_ok(elem);
319     }
320 }
321
322 var form_check_regexp = {
323     number: /^\d+$/,
324     decimal: /^\d*([,\.]\d+)?$/,
325     date: /^(\d\d?\.\d\d?\.[1-9]\d\d\d)|([1-9]\d\d\d-\d\d?-\d\d?)$/
326 };
327
328 function form_elem_check(elem,check)
329 {
330     var checks = check.split(',');
331
332     for (var i=0; i < checks.length; i++) {
333         var tagName = elem.tagName.toLowerCase();
334         var label = document.getElementById('label_' + elem.name);
335         if (checks[i] == 'required') {
336             if ((tagName == 'input' ||
337                  tagName == 'textarea') &&
338                 elem.value.length == 0)
339                 return label.innerHTML + ' muss ausgefüllt werden';
340
341             if (tagName == 'select' && elem.value.length == 0)
342                 return label.innerHTML + ' muss ausgewählt werden';
343         } else if (form_check_regexp[checks[i]]) {
344             if (elem.value.length && !form_check_regexp[checks[i]].test(elem.value))
345                 return 'Ungültiger Wert für ' + label.innerHTML;
346         }
347     }
348     form_elem_ok(elem);
349     return '';
350 }
351
352 function form_elem_onblur(e)
353 {
354     var first_use = form_first_use;
355     form_first_use = false;
356
357     var elem = document.getElementById('form_edit').findFirstElement();
358     if (first_use && elem == e.originalTarget && !e.originalTarget.length) return;
359
360     if (form_check[e.originalTarget.name]) {
361         var error = form_elem_check(e.originalTarget, form_check[e.originalTarget.name]);
362         if (error.length)
363             form_elem_error(e.originalTarget, error);
364     }
365 }
366
367 function form_checks(form)
368 {
369     var errors = '';
370     for (name in form_check) {
371         var elem = document.getElementById('edit_' + name);
372         var error = form_elem_check(elem, form_check[name]);
373         if (error.length) {
374             form_elem_error(elem, error);
375             errors += '. ' + error + "\n";
376         }
377     }
378
379     if (errors.length) {
380         alert("Fehler im Formular:\n" + errors);
381         return false;
382     }
383
384     return true;
385 }
386
387 function select_update(id, options, empty)
388 {
389     var obj = document.getElementById(id);
390     if (!obj) return;
391
392     if (typeof empty == 'undefined') empty = 0;
393
394     obj.options.length = empty;
395
396     for (var i=0; i < options.length; i++)
397       obj.options[empty+i] = new Option(options[i].text,options[i].id,false,false);
398 }
399
400 var pre_save = false;
401 var pre_insert = false;
402 var post_save = function() { grid_update(grid); }
403 var post_delete = function() { grid_update(grid); }
404
405 function save_callback(data)
406 {
407     info('Datensatz gespeichert');
408
409     if (typeof post_save == 'function')
410         post_save();
411
412     var form = document.getElementById('form_edit');
413
414     if (!form) return;
415
416     form_clear(form);
417     Form.focusFirstElement(form);
418 }
419
420 function delete_callback(data)
421 {
422     info('Datensatz gelöscht');
423
424     if (typeof post_delete == 'function')
425         post_delete();
426 }
427
428 function form_save(obj)
429 {
430     var id = document.getElementById('edit_id');
431
432     if (!id.value.length)
433         return form_insert(obj);
434
435     if (!form_checks(obj.form))
436         return false;
437
438     info('');
439
440     if (typeof pre_save == 'function')
441         if (!pre_save())
442             return false;
443
444
445     ajax_request('save', Form.serialize(obj.form), save_callback);
446     return false;
447 }
448
449 function form_insert(obj)
450 {
451     if (!form_checks(obj.form))
452         return false;
453
454     info('');
455
456     if (typeof pre_insert == 'function')
457         if (!pre_insert())
458             return false;
459
460     ajax_form_submit('insert', obj.form, save_callback);
461     return false;
462 }
463
464 function form_delete(obj)
465 {
466     var id = document.getElementById('edit_id');
467
468     if (!id.value.length) return false;
469
470     var source = document.getElementById('edit_source');
471     info('');
472     var params = 'id='+id.value + '&source='+source.value;
473     ajax_request('delete', params, delete_callback);
474     return false;
475 }
476
477 /*
478  * Table functions
479  */
480 function details_callback(data)
481 {
482     for (var id in data)
483         set_value('detail_'+id, data[id]);
484 }
485
486 function fetch_callback(data)
487 {
488     for (var id in data)
489         set_value('edit_'+id, data[id]);
490
491     var status = document.getElementById('form_status');
492     status.innerHTML = 'Geändert: ' + data.sys_edit + ' von ' + data.sys_user;
493
494     var form = document.getElementById('form_edit');
495     Form.focusFirstElement(form);
496 }
497
498 /*
499  * Rico functions
500  */
501 function gridDrillDown(e)
502 {
503     if (e.originalTarget && e.originalTarget.target && e.originalTarget.target == '_top')
504         return;
505
506     if (e.originalTarget && 
507         e.originalTarget.tagName.toLowerCase() !== 'span' &&
508         (!e.originalTarget.className || (e.originalTarget.className.split('_'))[0] !== 'ricoLG'))
509         return;
510
511     var id = 0; // Column 0 contains ID
512     var row = grid.edit.drillDown(e,0,0);
513     var cell = grid.columns[id].cell(row);
514     if (!cell) return;
515     var value = cell.innerHTML;
516
517     if (!value.length || value == '&nbsp;') return;
518
519     if (document.getElementById('details')) {
520         var params = 'source=' + grid.tableId.substr(5) + '&id=' + value;
521         ajax_request('details', params, details_callback);
522     }
523
524     if (document.getElementById('form_edit')) {
525         var status = document.getElementById('form_status');
526         if (status.style.display == '') {
527             var params = 'source=' + grid.tableId.substr(5) + '&id=' + value;
528             ajax_request('fetch', params, fetch_callback);
529             form_reset_errors();
530
531             if (edit_hidden) edit_show();
532         }
533     }
534
535     if (second_visible()) {
536         second.buffer.options.requestParameters = ['second_id=' + value];
537         grid_update(second);
538     }
539
540     if (typeof drilldown == 'function')
541         drilldown(e,value);
542 }
543
544 var grid_offset = 0;
545 function gridOnScroll(grid, offset)
546 {
547     if (grid.tableId.substr(-8) !== '__second')
548         grid_offset = grid.buffer.lastOffset;
549     var max = Math.min(offset+grid.pageSize, grid.buffer.totalRows);
550     var info = document.getElementById('info_' + grid.tableId);
551     info.innerHTML = 'Datensatz ' + (offset+1) + ' - ' + max + ' von ' + grid.buffer.totalRows;
552 }
553
554 /* Update an existing grid
555  *
556  * grid is a live grid
557  * filter is the array index of the $table_filters array in mskdef
558  * value is the value applied to the filter
559  */
560 function grid_update(grid, filter, value)
561 {
562     if (grid === undefined)
563         return;
564
565     if (filter !== undefined && filter !== false)
566                 grid.buffer.options.requestParameters = ['w'+filter+'=' + value];
567     grid.buffer.clear();
568     grid.buffer.setTotalRows(0);
569     grid.buffer.foundRowCount = false;
570     grid.cancelMenu();
571     grid.ClearSelection();
572     grid.setImages();
573     if (grid.bookmark) grid.bookmark.innerHTML="&nbsp;";
574     grid.clearRows();
575     if (grid.tableId.substr(-8) !== '__second')
576         grid.buffer.fetch(grid_offset);
577     else
578         grid.buffer.fetch(0);
579 }
580
581 function grid_update_filters(grid)
582 {
583     for (var c=0; c < grid.headerColCnt; c++) {
584         var fmt = grid.columns[c].format;
585         if (typeof fmt.filterUI != 'string') continue;
586         if (fmt.filterUI != 's') continue;
587
588         if (grid.columns[c]._getdesc) continue;
589
590         $(grid.filterId(c)).options.length = 1;
591
592         var options = {};
593         Object.extend(options, grid.buffer.ajaxOptions);
594         var colnum = typeof(fmt.filterCol)=='number' ? fmt.filterCol : c;
595
596         options.parameters = 'id='+grid.tableId+'&distinct='+colnum;
597
598         if (grid.filterCount() > 0) {
599             var cols = grid.columns.length;
600             for (var i = 0; i < cols; i++) {
601                 var column = grid.columns[i];
602                 if (column.filterType == Rico.TableColumn.USERFILTER) {
603                     options.parameters += '&f['+i+'][0]='+column.filterValues;
604                     options.parameters += '&f['+i+'][len]=1';
605                     options.parameters += '&f['+i+'][op]='+column.filterOp;
606                 }
607             }
608         }
609
610         options.onComplete = grid.filterValuesUpdate.bind(grid,c);
611         new Ajax.Request(grid.buffer.dataSource, options);
612     }
613 }
614
615 var grid_column_edit = new Array();
616
617 function grid_cell_save(id,col,value)
618 {
619     var source = document.getElementById('source');
620
621     if (!source) return false;
622
623     var parms = 'source=' + source.innerHTML;
624     parms += '&callback=cellsave';
625     parms += '&id=' + id;
626     parms += '&column=' + col;
627     parms += '&value=' + value;
628
629     ajax_request('function', parms, false);
630 }
631
632 function grid_cell_value()
633 {
634     this.grid.menu.cancelmenu();
635
636     var bufRow = this.row;
637     if (this.grid.lastRowPos > 0) bufRow += this.grid.lastRowPos;
638
639     this.grid.buffer.setValue(bufRow, this.col, this.visible);
640
641     if (this.value == 'prompt') {
642         var value = prompt(this.visible, '');
643         if (value === null)
644             return;
645
646         this.visible = value;
647         this.value = value;
648     }
649
650     var cell = this.grid.cell(this.row,this.col);
651     cell.innerHTML = this.visible;
652
653     grid_cell_save(this.grid.buffer.getCell(bufRow,0), this.col, this.value);
654 }
655
656 function grid_dataMenuHandler(grid,row,col,onBlankRow)
657 {
658     var default_menu = true;
659
660     if (grid_column_edit[col] &&
661         typeof grid_column_edit[col].default_menu !== 'undefined' &&
662         grid_column_edit[col].default_menu == false)
663         default_menu = false;
664
665     if (default_menu && typeof grid.menu.options.dataMenuHandlerOriginal == 'function') {
666         grid.menu.options.dataMenuHandlerOriginal(grid,row,col,onBlankRow);
667         grid.menu.div.style.width = '17em';
668     }
669
670     if (grid_column_edit[col]) {
671         var submenu;
672         if (default_menu) {
673             var submenu = new Rico.Menu(grid_column_edit[col].width);
674             submenu.createDiv();
675         } else
676             submenu = grid.menu;
677
678         for (i=0; i < grid_column_edit[col].values.length; i++)
679             submenu.addMenuItem(grid_column_edit[col].values[i][0],
680                                 grid_cell_value.bind({grid: grid, row: row, col: col,
681                                             visible: grid_column_edit[col].values[i][1],
682                                             value: grid_column_edit[col].values[i][2]}));
683
684         if (!default_menu && typeof grid_column_edit[col].width !== 'undefined')
685             grid.menu.div.style.width = grid_column_edit[col].width;
686
687         if (default_menu)
688             grid.menu.addSubMenuItem('Wert setzen', submenu, true);
689     }
690
691     if (default_menu)
692         return true;
693     else
694         return false;
695 }
696
697 var calendars = new Array();
698 function calendar_callback(value)
699 {
700     this.input.value = value;
701 }
702
703 function calendar(name,event)
704 {
705     var input = document.getElementById(name);
706     if (!input) return;
707
708     if (calendars[name] == undefined) {
709         calendars[name] = new Rico.CalendarControl('calendar_'+name,
710                                                    {startAt: 1,
711                                                     dateFmt: 'dd.mm.yyyy',
712                                                     showWeekNumber: 1});
713         calendars[name].atLoad();
714         calendars[name].returnValue = calendar_callback;
715         RicoUtil.positionCtlOverIcon(calendars[name].container,input);
716         calendars[name].open(input.value);
717         calendars[name].input = input;
718     } else {
719         if (Element.visible(calendars[name].container))
720             calendars[name].close();
721         else
722             calendars[name].open(input.value);
723     }
724     Event.stop(event);
725 }
726
727 function edit_hide()
728 {
729     var col_edit = document.getElementById("column_edit");
730     var col_grid = document.getElementById("column_grid");
731     col_edit.style.display = 'none';
732     col_grid.style.width = '100%';
733
734     edit_hidden = true;
735
736     grid.sizeDivs();
737     grid.resizeWindow();
738 }
739
740 function edit_show()
741 {
742     var col_edit = document.getElementById("column_edit");
743     var col_grid = document.getElementById("column_grid");
744     col_edit.style.display = '';
745     col_grid.style.width = '';
746
747     edit_hidden = false;
748
749     grid.sizeDivs();
750     grid.resizeWindow();
751 }
752
753 function resize_grids()
754 {
755     var div_grid = document.getElementById('div_grid');
756     var info = document.getElementById('info_'+second.tableId);
757     var height = RicoUtil.windowHeight() - (info.offsetTop - div_grid.offsetTop) - 60;
758     div_grid.style.height = height + 'px';
759     grid.resizeWindow();
760 }
761
762 function second_visible()
763 {
764     if (typeof second == 'undefined') return false;
765     var div_second = document.getElementById('second');
766     return div_second.style.display == '';
767 }
768
769 var div_grid_height = '';
770 function second_toggle()
771 {
772     var div_grid = document.getElementById('div_grid');
773     var div_second = document.getElementById('second');
774     var toggle_icon = document.getElementById('icon_toggle');
775
776     if (second_visible()) {
777         div_grid_height = div_grid.style.height;
778         div_second.style.display = 'none';
779
780         var height = RicoUtil.windowHeight() - div_grid.offsetTop - 10;
781         div_grid.style.height = height + 'px';
782         grid.resizeWindow();
783         toggle_icon.style.display = '';
784     } else {
785         div_grid.style.height = div_grid_height;
786         div_second.style.display = '';
787         grid.resizeWindow();
788         second.clearRows();
789         second.resizeWindow();
790         toggle_icon.style.display = 'none';
791     }
792 }