]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/reports/oils_rpt_builder.js
added some folder actions and framework, more to come
[Evergreen.git] / Open-ILS / web / reports / oils_rpt_builder.js
1 /** initializes reports, some basid display settings, 
2   * grabs and builds the IDL tree
3   */
4 function oilsInitReportBuilder() {
5         oilsInitReports();
6         oilsReportBuilderReset();
7         DOM.oils_rpt_table.onclick = 
8                 function(){hideMe(DOM.oils_rpt_column_editor)};
9         //oilsRptBuildCalendars();
10         oilsDrawRptTree(
11                 function() { 
12                         hideMe(DOM.oils_rpt_tree_loading); 
13                         unHideMe(DOM.oils_rpt_table); 
14                 }
15         );
16 }
17
18 function oilsReportBuilderReset() {
19         var n = (oilsRpt) ? oilsRpt.name : "";
20         oilsRpt = new oilsReport();
21         oilsRpt.name = n;
22         oilsRptDisplaySelector  = DOM.oils_rpt_display_selector;
23         oilsRptFilterSelector   = DOM.oils_rpt_filter_selector;
24         removeChildren(oilsRptDisplaySelector);
25         removeChildren(oilsRptFilterSelector);
26         oilsRptDebug();
27         oilsRptResetParams();
28 }
29
30
31 /*
32 function oilsRptBuildCalendars() {
33         Calendar.setup({
34                 inputField  : "oils_rpt_filter_tform_timestamp_input", // id of the input field
35                 ifFormat    : "%Y-%m-%d", // format of the input field
36                 button      : "oils_rpt_filter_tform_timestamp_cal",  // trigger for the calendar (button ID)
37                 align       : "Tl", // alignment (defaults to "Bl")
38                 singleClick : true
39         });
40         Calendar.setup({
41                 inputField  : "oils_rpt_filter_tform_timestamp_input_2", // id of the input field
42                 ifFormat    : "%Y-%m-%d", // format of the input field
43                 button      : "oils_rpt_filter_tform_timestamp_cal2",  // trigger for the calendar (button ID)
44                 align       : "Tl", // alignment (defaults to "Bl")
45                 singleClick : true
46         });
47 }
48 */
49
50
51 /* adds an item to the display window */
52 function oilsAddRptDisplayItem(path, name, tform, params) {
53         if( ! oilsAddSelectorItem(oilsRptDisplaySelector, path, name) ) 
54                 return;
55
56         /* add the selected columns to the report output */
57         name = (name) ? name : oilsRptPathCol(path);
58         var param = oilsRptNextParam();
59
60         /* add this item to the select blob */
61         var sel = {
62                 relation:oilsRptPathRel(path), 
63                 alias:param
64         };
65
66         if( tform ) {
67                 sel.column = {};
68                 if( params ) {
69                         params.unshift(oilsRptPathCol(path));
70                         sel.column[tform] = params;
71                 } else {
72                         sel.column[tform] = oilsRptPathCol(path); 
73                 }
74         } else { sel.column = oilsRptPathCol(path); }
75
76         oilsRpt.def.select.push(sel);
77
78         mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
79         oilsRpt.params[param] = name;
80         oilsRptDebug();
81 }
82
83 /* takes a column path and builds a from-clause object for the path */
84 function oilsRptBuildFromClause(path) {
85
86         /* the path is the full path (relation) from the source 
87                 object to the column in question (e.g. au-home_ou-aou-name)*/
88         var parts = path.split(/-/);
89
90         /* the final from clause */
91         var obj = {}; 
92
93         /* reference to the current position in the from clause */
94         var tobj = obj; 
95
96         var newpath = "";
97
98         /* walk the path, fleshing the from clause as we go */
99         for( var i = 0; i < parts.length; i += 2 ) {
100
101                 var cls = parts[i]; /* class name (id) */
102                 var col = parts[i+1]; /* column name */
103
104                 /* a "node" is a class description from the IDL, it 
105                         contains relevant info, plus a list of "fields",
106                         or column objects */
107                 var node = oilsIDL[cls];
108                 var pkey = oilsRptFindField(node.pkey);
109
110                 /* a "field" is a parsed version of a column from the IDL,
111                         contains datatype, column name, etc. */
112                 var field = oilsRptFindField(node, col);
113
114                 /* re-construct the path as we go so 
115                         we know what all we've seen thus far */
116                 newpath = (newpath) ? newpath + '-'+ cls : cls;
117
118                 /* extract relevant info */
119                 tobj.table = node.table;
120                 tobj.alias = newpath;
121                 _debug('field type is ' + field.type);
122                 if( i == (parts.length - 2) ) break;
123
124                 /* we still have columns left in the path, keep adding join's */
125                 var path_col = col;
126                 if(field.reltype != 'has_a')
127                         col = pkey.name + '-' + col;
128
129                 tobj.join = {};
130                 tobj = tobj.join;
131
132                 tobj[col] = {};
133                 tobj = tobj[col];
134                 if( field.type == 'link' )
135                         tobj.key = field.key;
136
137                 newpath = newpath + '-'+ path_col;
138         }
139
140         _debug("built 'from' clause: path="+path+"\n"+formatJSON(js2JSON(obj)));
141         return obj;
142 }
143
144
145 /* removes a specific item from the display window */
146 function oilsDelDisplayItem(val) {
147         oilsDelSelectorItem(oilsRptDisplaySelector, val);
148 }
149
150 /* removes selected items from the display window */
151 function oilsDelSelectedDisplayItems() {
152         var list = oilsDelSelectedItems(oilsRptDisplaySelector);
153
154         /* remove the de-selected columns from the report output */
155         oilsRpt.def.select = grep( oilsRpt.def.select, 
156                 function(i) {
157                         for( var j = 0; j < list.length; j++ ) {
158                                 var d = list[j];
159                                 var col = i.column;
160
161                                 /* if this columsn has a transform, 
162                                         it will be an object { tform => column } */
163                                 if( typeof col != 'string' ) 
164                                         for( var c in col ) col = col[c];
165
166                                 /* if this transform requires params, the column 
167                                         will be the first item in the param set array */
168                                 if( typeof col != 'string' ) col = col[0];
169
170                                 if( oilsRptPathRel(d) == i.relation && oilsRptPathCol(d) == col ) {
171                                         var param = (i.alias) ? i.alias.match(/::PARAM\d*/) : null;
172                                         if( param ) delete oilsRpt.params[param];
173                                         return false;
174                                 }
175                         }
176                         return true;
177                 }
178         );
179
180         if(!oilsRpt.def.select) {
181                 oilsRpt.def.select = [];
182                 oilsReportBuilderReset();
183
184         } else {
185                 for( var j = 0; j < list.length; j++ ) 
186                         /* if there are no items left in the "select" clause for the given 
187                                 relation, trim this relation from the "from" clause */
188                         if(!grep(oilsRpt.def.select,
189                                         function(i){ return (i.relation == oilsRptPathRel(list[j])); })) 
190                                 oilsRptPruneFromClause(oilsRptPathRel(list[j]));
191         }
192
193         oilsRptDebug();
194 }
195
196 /* for each item in the path list, remove the associated data
197         from the "from" clause */
198
199 function oilsRptPruneFromClause(relation, node) {
200         _debug("removing relation from 'from' clause " + relation);
201         if(!node) node = oilsRpt.def.from.join;
202         for( var i in node ) {
203                 if( node[i].alias == relation ) {
204                         if( node[i].join ) {
205                                 /* if we have subtrees, don't delete our tree node */
206                                 return false;
207                         } else {
208                                 delete node[i];
209                                 return true;
210                         } 
211                 } else {
212                         if( node[i].join ) {
213                                 if( oilsRptPruneFromClause(relation, node[i].join ) ) {
214                                         if(oilsRptObjectKeys(node[i].join).length == 0) {
215                                                 delete node[i].join;
216                                                 /* if there are no items in the select clause with a relation matching
217                                                         this nodes alias, we can safely remove this node from the tree */
218                                                 if(!grep(oilsRpt.def.select,function(r){return (r.relation==node[i].alias)}))
219                                                         delete node[i];
220                                                 return true;
221                                         }
222                                 }
223                         }
224                 }
225         }
226         return false;
227 }
228
229 /* adds an item to the display window */
230 function oilsAddRptFilterItem(val) {
231         oilsAddSelectorItem(oilsRptFilterSelector, val);
232 }
233
234 /* removes a specific item from the display window */
235 function oilsDelFilterItem(val) {
236         oilsDelSelectorItem(oilsRptFilterSelector, val);
237 }
238
239 /* removes selected items from the display window */
240 function oilsDelSelectedFilterItems() {
241         oilsDelSelectedItems(oilsRptFilterSelector);
242 }
243
244
245 /* adds an item to the display window */
246 function oilsAddSelectorItem(sel, val, name) {
247         name = (name) ? name : oilsRptMakeLabel(val);
248         _debug("adding selector item "+name+' = ' +val);
249         for( var i = 0; i < sel.options.length; i++ ) {
250                 var opt = sel.options[i];
251                 if( opt.value == val ) return false;
252         }
253         insertSelectorVal( sel, -1, name, val );
254         return true;
255 }
256
257
258 /* removes a specific item from the display window */
259 function oilsDelSelectorItem(sel, val) {
260         _debug("deleting selector item "+val);
261         var opts = sel.options;
262         for( var i = 0; i < opts.length; i++ ) {
263                 var opt = opts[i];
264                 if( opt.value == val )  {
265                         if( i == opts.length - 1 ) 
266                                 opts[i] = null;
267                         else opts[i] = opts[i+1];
268                         return;
269                 }
270         }
271 }
272
273 /* removes selected items from the display window */
274 function oilsDelSelectedItems(sel) {
275         var list = getSelectedList(sel);
276         for( var i = 0; i < list.length; i++ ) 
277                 oilsDelSelectorItem(sel, list[i]);
278         return list;
279 }
280
281
282 /* hides the different field editor tabs */
283 function oilsRptHideEditorDivs() {
284         hideMe(DOM.oils_rpt_tform_div);
285         hideMe(DOM.oils_rpt_filter_div);
286         hideMe(DOM.oils_rpt_agg_filter_div);
287 }
288
289
290 /**
291   This draws the 3-tabbed window containing the transform,
292   filter, and aggregate filter picker window
293   */
294 function oilsRptDrawDataWindow(path) {
295         var col = oilsRptPathCol(path);
296         var cls = oilsRptPathClass(path);
297         var field = oilsRptFindField(oilsIDL[cls], col);
298
299         appendClear(DOM.oils_rpt_editor_window_label, text(oilsRptMakeLabel(path)));
300         appendClear(DOM.oils_rpt_editor_window_datatype, text(field.datatype));
301
302         _debug("setting update data window for column "+col+' on class '+cls);
303
304         var div = DOM.oils_rpt_column_editor;
305         /* set a preliminary top position so the page won't bounce around */
306         div.setAttribute('style','top:'+oilsMouseX+'px');
307
308         /* unhide the div so we can determine the dimensions */
309         unHideMe(div);
310
311         /* don't let them see the floating div until the position is fully determined */
312         div.style.visibility='hidden'; 
313
314         oilsRptDrawTransformWindow(path, col, cls, field);
315         oilsRptDrawFilterWindow(path, col, cls, field);
316
317         //oilsRptSetFilters(field.datatype);
318
319         //oilsRptDoFilterWidgets();
320
321         //DOM.oils_rpt_filter_tform_selector.onchange = oilsRptDoFilterWidgets;
322
323         buildFloatingDiv(div, 600);
324
325         /* now let them see it */
326         div.style.visibility='visible';
327
328         oilsRptSetDataWindowActions(div);
329 }
330
331
332 function oilsRptSetDataWindowActions(div) {
333         /* give the tab links behavior */
334         DOM.oils_rpt_tform_tab.onclick = 
335                 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_tform_div)};
336         DOM.oils_rpt_filter_tab.onclick = 
337                 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_filter_div)};
338         DOM.oils_rpt_agg_filter_tab.onclick = 
339                 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_agg_filter_div)};
340
341         DOM.oils_rpt_tform_tab.onclick();
342         DOM.oils_rpt_column_editor_close_button.onclick = function(){hideMe(div);};
343 }
344
345
346 function oilsRptDrawFilterWindow(path, col, cls, field) {
347         oilsRptCurrentFilterTform = new oilsRptTFormManager(DOM.oils_rpt_filter_tform_table);
348         oilsRptCurrentFilterTform.build(field.datatype, false, true);
349         oilsRptCurrentFilterOpManager = new oilsRptOpManager(DOM.oils_rpt_filter_op_table);
350 }
351
352
353 /* draws the transform window */
354 function oilsRptDrawTransformWindow(path, col, cls, field) {
355         DOM.oils_rpt_tform_label_input.value = oilsRptMakeLabel(path);
356         var dtype = field.datatype;
357
358         DOM.oils_rpt_tform_submit.onclick = 
359                 function(){ 
360                         /*
361                         var tform = oilsRptGetTform(dtype);
362                         _debug('found tform: ' + js2JSON(tform));
363                         var params = getRptTformParams(dtype, tform);
364                         _debug('found tform params: ' + js2JSON(params));
365                         tform = (tform == 'raw') ? null : tform;
366                         */
367
368                         var tform = oilsRptCurrentTform.getCurrentTForm();
369                         oilsAddRptDisplayItem(path, DOM.oils_rpt_tform_label_input.value, tform.value, tform.params ) 
370                 };
371
372
373         DOM.oils_rpt_tform_label_input.focus();
374         DOM.oils_rpt_tform_label_input.select();
375
376         oilsRptCurrentTform = new oilsRptTFormManager(DOM.oils_rpt_tform_table);
377         oilsRptCurrentTform.build(dtype, true, true);
378
379         /*
380         oilsRptHideTformFields();
381         oilsRptUnHideTformFields(dtype);
382         */
383
384         _debug("Building transiform window for datatype "+dtype);
385
386         /*
387         unHideMe($('oils_rpt_tform_'+dtype+'_div'));
388         $('oils_rpt_tform_all_raw').checked = true;
389         */
390 }
391
392 /*
393 function oilsRptHideTformFields() {
394         var rows = DOM.oils_rpt_tform_tbody.childNodes;
395         for( var i = 0; i < rows.length; i++ )
396                 if( rows[i] && rows[i].nodeType == 1 )
397                         hideMe(rows[i]);
398 }
399
400 function oilsRptUnHideTformFields(dtype) {
401         var rows = DOM.oils_rpt_tform_tbody.childNodes;
402         for( var i = 0; i < rows.length; i++ ) {
403                 var row = rows[i]
404                 if( row && row.nodeType == 1 && 
405                         (row.getAttribute('datatype')=='all' 
406                                 || row.getAttribute('datatype') == dtype)) {
407                         unHideMe(row);
408                 }
409         }
410 }
411
412
413 function oilsRptGetTform(datatype) {
414         for( var i in oilsRptTransforms[datatype] ) 
415                 if( $('oils_rpt_tform_'+datatype+'_'+oilsRptTransforms[datatype][i]).checked )
416                         return oilsRptTransforms[datatype][i];
417         for( var i in oilsRptTransforms.all ) 
418                 if( $('oils_rpt_tform_all_'+oilsRptTransforms.all[i]).checked )
419                         return oilsRptTransforms.all[i];
420         return null;
421 }
422 */
423
424
425 /*
426 function getRptTformParams(type, tform) {
427         switch(type) {
428                 case 'string' :
429                         switch(tform) {
430                                 case 'substring' :
431                                         return [
432                                                 DOM.oils_rpt_tform_string_substring_offset.value, 
433                                                 DOM.oils_rpt_tform_string_substring_length.value];
434                         }
435         }
436 }
437 */
438
439
440 /* given a transform selector, this displays the appropriate 
441         transforms for the given datatype.
442         if aggregate is true, is displays the aggregate transforms */
443 /*
444 function oilsRptSetTransforms(sel, dtype, show_agg, show_noagg) {
445         for( var i = 0; i < sel.options.length; i++ ) {
446                 var opt = sel.options[i];
447                 var t = opt.getAttribute('datatype');
448                 if( t && t != dtype ){
449                         hideMe(opt);
450                 } else {
451                         var ag = opt.getAttribute('aggregate');
452                         if( ag && show_agg )
453                                 unHideMe(opt);
454                         else if( ag && ! show_agg )
455                                 hideMe(opt)
456                         else if( !ag && show_noagg )
457                                 unHideMe(opt);
458                         else
459                                 hideMe(opt);
460                 }
461         }
462 }
463 */
464
465
466 /* displays the correct filter-transforms for the given datatype */
467 /*
468 function oilsRptSetFilters(dtype) {
469
470         DOM.oils_rpt_filter_submit.onclick = function() {
471                 var data = oilsRptDoFilterWidgets();
472                 alert(js2JSON(data));
473         }
474
475         var sel = DOM.oils_rpt_filter_tform_selector;
476         for( var i = 0; i < sel.options.length; i++ ) {
477                 var opt = sel.options[i];
478                 _debug(opt.getAttribute('op'));
479                 var t = opt.getAttribute('datatype');
480                 if( t && t != dtype ) hideMe(opt);
481                 else unHideMe(opt);
482         }
483 }
484 */
485
486 /* hides all of the filter widgets */
487 function oilsRptHideFilterWidgets(node) {
488         if(!node)
489                 node = DOM.oils_rpt_filter_tform_widget_td;
490         if( node.nodeType != 1 ) return;
491         if( node.getAttribute('widget') ) {
492                 hideMe(node);
493         } else {
494                 var cs = node.childNodes;
495                 for( var i = 0; cs && i < cs.length; i++ )
496                         oilsRptHideFilterWidgets(cs[i]);
497         }
498 }
499
500 /* what does this need to do? */
501 function oilsRptSetFilterOpActions() {
502 }
503
504
505
506 /* hides/unhides the appropriate widgets and returns the parameter
507         array appropriate for the selected widget */
508 function oilsRptDoFilterWidgets() {
509         filter = getSelectorVal(DOM.oils_rpt_filter_tform_selector);
510         oilsRptHideFilterWidgets();
511         var op = null;
512         var tform = null;
513         var params = null;
514
515         switch(filter) {
516                 
517                 /* generic transforms */
518                 case 'equals':
519                         if(!op) op = 'equals';
520                 case 'like':
521                         if(!op) op = 'like';
522                 case 'ilike':
523                         if(!op) op = 'ilike';
524                 case 'gt':
525                         if(!op) op = '>';
526                 case 'gte':
527                         if(!op) op = '>=';
528                 case 'lt':
529                         if(!op) op = '<';
530                 case 'lte':
531                         if(!op) op = '<=';
532                 case 'in':
533                         if(!op) op = 'in';
534                 case 'not_in':
535                         if(!op) op = 'not in';
536                 case 'between':
537                         if(!op) op = 'between';
538                 case 'not_between':
539                         if(!op) op = 'not between';
540                         unHideMe(DOM.oils_rpt_filter_tform_input);      
541                         params = [DOM.oils_rpt_filter_tform_input.value];
542                         break;
543
544                 /* timestamp transforms */
545                 case 'date_between':
546                         if(!op) op = 'between';
547                 case 'date_not_between':
548                         if(!op) op = 'not between';
549                         tform = 'date';
550                         var d = new Date();
551                         unHideMe(DOM.oils_rpt_filter_tform_date_1);
552                         unHideMe(DOM.oils_rpt_filter_tform_date_2);
553                         unHideMe(DOM.oils_rpt_filter_tform_date_hint);
554                         DOM.oils_rpt_filter_tform_date_1.value = mkYearMonDay();
555                         DOM.oils_rpt_filter_tform_date_2.value = mkYearMonDay();
556                         params = [
557                                 DOM.oils_rpt_filter_tform_date_1.value,
558                                 DOM.oils_rpt_filter_tform_date_2.value
559                         ];
560                         break;
561
562                 case 'dow_between':
563                         op = 'between';
564                         if(!tform) tform = 'dow';
565                 case 'dow_not_between':
566                         if(!op) op = 'not between';
567                         if(!tform) tform = 'dow';
568                         break;
569
570                 case 'dom_between':
571                         op = 'between';
572                         if(!tform) tform = 'dom';
573                 case 'dom_not_between':
574                         if(!op) op = 'not between';
575                         if(!tform) tform = 'dom';
576                         break;
577
578                 case 'month_between':
579                         op = 'between';
580                         if(!tform) tform = 'moy';
581                 case 'month_not_between':
582                         if(!op) op = 'not between';
583                         if(!tform) tform = 'moy';
584                         break;
585
586                 case 'quarter_between':
587                         op = 'between';
588                         if(!tform) tform = 'qoy';
589                 case 'quarter_not_between':
590                         if(!op) op = 'not between';
591                         if(!tform) tform = 'qoy';
592                         break;
593
594                 case 'year_between':
595                         if(!op) op = 'between';
596                         if(!tform) tform = 'year_trunc';
597                 case 'year_not_between':
598                         if(!op) op = 'not between';
599                         if(!tform) tform = 'year_trunc';
600                         break;
601
602                 case 'age_between':
603                         if(!op) op = 'between';
604                         if(!tform) tform = 'age';
605                 case 'age_not_between':
606                         if(!op) op = 'not between';
607                         if(!tform) tform = 'age';
608                         break;
609
610                 /* string transforms */
611                 case 'substring':
612                         if(!tform) tform = 'substring';
613                         break;
614
615                 case 'lower':
616                         if(!op) op = '';
617                         if(!tform) tform = 'dow';
618
619                 case 'upper':
620                         if(!op) op = '';
621                         if(!tform) tform = 'dow';
622
623                 /* numeric transforms */
624                 case 'round':
625                         if(!op) op = '';
626                         if(!tform) tform = 'dow';
627
628                 case 'int':
629                         if(!op) op = '';
630                         if(!tform) tform = 'dow';
631         }
632
633         return { op : op, params : params, tform : tform };
634 }
635
636
637
638