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