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