1 /** initializes reports, some basid display settings,
2 * grabs and builds the IDL tree
4 function oilsInitReportBuilder() {
5 if(!oilsInitReports()) return false;
6 oilsReportBuilderReset();
7 DOM.oils_rpt_table.onclick =
8 function(){hideMe(DOM.oils_rpt_column_editor)};
11 hideMe(DOM.oils_rpt_tree_loading);
12 unHideMe(DOM.oils_rpt_table);
16 DOM.oils_rpt_builder_save_template.onclick = oilsReportBuilderSave;
19 function oilsReportBuilderReset() {
20 var n = (oilsRpt) ? oilsRpt.name : "";
21 oilsRpt = new oilsReport();
23 oilsRptDisplaySelector = DOM.oils_rpt_display_selector;
24 oilsRptFilterSelector = DOM.oils_rpt_filter_selector;
25 oilsRptAggFilterSelector= DOM.oils_rpt_agg_filter_selector;
26 removeChildren(oilsRptDisplaySelector);
27 removeChildren(oilsRptFilterSelector);
28 removeChildren(oilsRptAggFilterSelector);
33 function oilsReportBuilderSave() {
36 tmpl.name(DOM.oils_rpt_builder_new_name.value);
37 tmpl.description(DOM.oils_rpt_builder_new_desc.value);
38 tmpl.owner(USER.id());
39 tmpl.folder(new CGI().param('folder'));
40 tmpl.data(js2JSON(oilsRpt.def));
42 if(!confirm('Name : '+tmpl.name() + '\nDescription: ' + tmpl.description()+'\nSave Template?'))
49 var req = new Request(OILS_RPT_CREATE_TEMPLATE, SESSION, tmpl);
52 var res = r.getResultObject();
54 oilsRptAlertSuccess();
65 /* adds an item to the display window */
66 function oilsAddRptDisplayItem(path, name, tform, params) {
67 if( ! oilsAddSelectorItem(oilsRptDisplaySelector, path, name) )
70 /* add the selected columns to the report output */
71 name = (name) ? name : oilsRptPathCol(path);
72 if( !tform ) tform = 'Bare';
74 /* add this item to the select blob */
76 relation: oilsRptPathRel(path),
78 column: { transform: tform, colname: oilsRptPathCol(path) }
81 if( params ) sel.column.params = params;
82 oilsRpt.def.select.push(sel);
84 mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
88 /* takes a column path and builds a from-clause object for the path */
89 function oilsRptBuildFromClause(path) {
91 /* the path is the full path (relation) from the source
92 object to the column in question (e.g. au-home_ou-aou-name)*/
93 var parts = path.split(/-/);
95 /* the final from clause */
98 /* reference to the current position in the from clause */
103 /* walk the path, fleshing the from clause as we go */
104 for( var i = 0; i < parts.length; i += 2 ) {
106 var cls = parts[i]; /* class name (id) */
107 var col = parts[i+1]; /* column name */
109 /* a "node" is a class description from the IDL, it
110 contains relevant info, plus a list of "fields",
112 var node = oilsIDL[cls];
113 var pkey = oilsRptFindField(node, node.pkey);
115 /* a "field" is a parsed version of a column from the IDL,
116 contains datatype, column name, etc. */
117 var field = oilsRptFindField(node, col);
119 /* re-construct the path as we go so
120 we know what all we've seen thus far */
121 newpath = (newpath) ? newpath + '-'+ cls : cls;
123 /* extract relevant info */
124 tobj.table = node.table;
125 tobj.alias = newpath;
126 _debug('field type is ' + field.type);
127 if( i == (parts.length - 2) ) break;
129 /* we still have columns left in the path, keep adding join's */
131 if(field.reltype != 'has_a')
132 col = pkey.name + '-' + col;
139 if( field.type == 'link' )
140 tobj.key = field.key;
142 newpath = newpath + '-'+ path_col;
145 _debug("built 'from' clause: path="+path+"\n"+formatJSON(js2JSON(obj)));
150 /* removes a specific item from the display window */
151 function oilsDelDisplayItem(val) {
152 oilsDelSelectorItem(oilsRptDisplaySelector, val);
155 /* removes selected items from the display window */
156 function oilsDelSelectedDisplayItems() {
157 var list = oilsDelSelectedItems(oilsRptDisplaySelector);
159 /* remove the de-selected columns from the report output */
160 oilsRpt.def.select = grep( oilsRpt.def.select,
162 for( var j = 0; j < list.length; j++ ) {
166 if( oilsRptPathRel(d) == i.relation && oilsRptPathCol(d) == col.colname ) {
167 //var param = (i.alias) ? i.alias.match(/::PARAM\d*/) : null;
168 // if( param ) delete oilsRpt.params[param];
176 if(!oilsRpt.def.select) {
177 oilsRpt.def.select = [];
178 //oilsReportBuilderReset();
181 for( var j = 0; j < list.length; j++ )
182 /* if there are no items left in the "select", "where", or "having" clauses
183 for the given relation, trim this relation from the "from" clause */
184 if( !grep(oilsRpt.def.select,
185 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
186 && !grep(oilsRpt.def.where,
187 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
188 && !grep(oilsRpt.def.having,
189 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
190 ) oilsRptPruneFromClause(oilsRptPathRel(list[j]));
197 /* for each item in the path list, remove the associated data
198 from the "from" clause */
200 function oilsRptPruneFromClause(relation, node) {
201 _debug("removing relation from 'from' clause " + relation);
202 if(!node) node = oilsRpt.def.from.join;
203 for( var i in node ) {
204 _debug("looking at node "+node[i].alias);
205 // first, descend into the tree, and prune leaves first
207 oilsRptPruneFromClause(relation, node[i].join);
208 if(oilsRptObjectKeys(node[i].join).length == 0) delete node[i].join;
212 // if we're at an unused empty leaf, remove it
213 if( !node[i].join ) {
214 if( !grep(oilsRpt.def.select,
215 function(i){ return (i.relation == node[i].alias)})
216 && !grep(oilsRpt.def.where,
217 function(i){ return (i.relation == node[i].alias)})
218 && !grep(oilsRpt.def.having,
219 function(i){ return (i.relation == node[i].alias)})
229 function oilsRptMkFilterTags(path, tform, filter) {
230 var name = oilsRptMakeLabel(path);
231 if(tform) name += ' ('+tform+')';
232 name += ' "' + filter + '"';
233 var epath = path + ':'+filter+':';
234 if(tform) epath += tform;
236 return [ name, epath ];
240 /* adds an item to the display window */
241 function oilsAddRptFilterItem(path, tform, filter) {
242 _debug("Adding filter item for "+path+" tform="+tform+" filter="+filter);
244 var name = oilsRptMkFilterTags(path, tform, filter);
248 if( ! oilsAddSelectorItem(oilsRptFilterSelector, epath, name) )
252 relation: oilsRptPathRel(path),
253 column: { transform: tform, colname: oilsRptPathCol(path) },
256 where.condition[filter] = oilsRptNextParam();
259 case 'substring' : where.column.params = oilsRptNextParam();
262 oilsRpt.def.where.push(where);
263 mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
267 /* removes a specific item from the display window */
268 //function oilsDelFilterItem(path) {
269 //oilsDelSelectorItem(oilsRptFilterSelector, path);
272 /* removes selected items from the display window */
273 function oilsDelSelectedFilterItems() {
275 /* the values in this list are formed: <path>:<operation>:<transform> */
276 var list = oilsDelSelectedItems(oilsRptFilterSelector);
280 for( var i = 0; i < list.length; i++ ) {
283 path: item.replace(/:.*/,''),
284 operation: item.replace(/.*:(.*):.*/,'$1'),
285 tform: item.replace(/.*?:.*?:(.*)/,'$1')
290 /* XXX refactor the below to take operation and transform into account
291 since the same path can be used multiple times as long as a different
292 filter and/or transform is used */
294 /* remove the de-selected columns from the report output */
295 oilsRpt.def.where = grep( oilsRpt.def.where,
297 for( var j = 0; j < flist.length; j++ ) {
300 var frel = oilsRptPathRel(fil.path);
301 var fcol = oilsRptPathCol(fil.path);
303 var op = oilsRptObjectKeys(i.condition)[0];
305 if( frel == i.relation &&
306 fcol == col.colname &&
307 fil.operation == op &&
308 fil.tform == col.transform ) {
309 /* we have found a where clause with the same
310 relation, column, operation and transform */
312 /* we aren't setting params on template build.. */
313 //var param = (i.column.params) ? i.columns.params.match(/::P\d*/) : null;
314 //if( param ) delete oilsRpt.params[param];
315 //param = (i.condition[op]) ? i.condition[op].match(/::P\d*/) : null;
316 //if( param ) delete oilsRpt.params[param];
325 if(!oilsRpt.def.where)
326 oilsRpt.def.where = [];
329 for( var j = 0; j < flist.length; j++ ) {
330 var path = flist[j].path;
331 var rel = oilsRptPathRel(path);
332 /* if there are no items left in the "select", "where", or "having" clauses
333 for the given relation, trim this relation from the "from" clause */
335 var func = function(i){ return (i.relation == rel); };
337 if( !grep(oilsRpt.def.select, func) &&
338 !grep(oilsRpt.def.where, func) &&
339 !grep(oilsRpt.def.having, func) ) {
341 _debug("pruning item with path "+ path + ' and relation '+ rel);
343 oilsRptPruneFromClause(oilsRptPathRel(path));
350 /* adds an item to the display window */
351 function oilsAddRptAggFilterItem(val) {
352 oilsAddSelectorItem(oilsRptAggFilterSelector, val);
355 /* removes a specific item from the display window */
356 function oilsDelAggFilterItem(val) {
357 oilsDelSelectorItem(oilsRptAggFilterSelector, val);
360 /* removes selected items from the display window */
361 function oilsDelSelectedAggFilterItems() {
362 var list = oilsDelSelectedItems(oilsRptAggFilterSelector);
364 /* remove the de-selected columns from the report output */
365 oilsRpt.def.having = grep( oilsRpt.def.having,
367 for( var j = 0; j < list.length; j++ ) {
371 /* if this columsn has a transform,
372 it will be an object { tform => column } */
373 if( typeof col != 'string' )
374 for( var c in col ) col = col[c];
376 /* if this transform requires params, the column
377 will be the first item in the param set array */
378 if( typeof col != 'string' ) col = col[0];
380 if( oilsRptPathRel(d) == i.relation && oilsRptPathCol(d) == col ) {
381 var param = (i.alias) ? i.alias.match(/::P\d*/) : null;
382 if( param ) delete oilsRpt.params[param];
390 if(!oilsRpt.def.having) {
391 oilsRpt.def.having = [];
392 oilsReportBuilderReset();
395 for( var j = 0; j < list.length; j++ )
396 /* if there are no items left in the "select", "where", or "having" clauses
397 for the given relation, trim this relation from the "from" clause */
398 if( !grep(oilsRpt.def.select,
399 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
400 && !grep(oilsRpt.def.where,
401 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
402 && !grep(oilsRpt.def.having,
403 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
404 ) oilsRptPruneFromClause(oilsRptPathRel(list[j]));
411 /* adds an item to the display window */
412 function oilsAddSelectorItem(sel, val, name) {
413 name = (name) ? name : oilsRptMakeLabel(val);
414 _debug("adding selector item "+name+' = ' +val);
415 for( var i = 0; i < sel.options.length; i++ ) {
416 var opt = sel.options[i];
417 if( opt.value == val ) return false;
419 insertSelectorVal( sel, -1, name, val );
424 /* removes a specific item from the display window */
425 function oilsDelSelectorItem(sel, val) {
426 _debug("deleting selector item "+val);
427 var opts = sel.options;
428 for( var i = 0; i < opts.length; i++ ) {
430 if( opt.value == val ) {
431 if( i == opts.length - 1 )
433 else opts[i] = opts[i+1];
439 /* removes selected items from the display window */
440 function oilsDelSelectedItems(sel) {
441 var list = getSelectedList(sel);
442 for( var i = 0; i < list.length; i++ )
443 oilsDelSelectorItem(sel, list[i]);
448 /* hides the different field editor tabs */
449 function oilsRptHideEditorDivs() {
450 hideMe(DOM.oils_rpt_tform_div);
451 hideMe(DOM.oils_rpt_filter_div);
452 hideMe(DOM.oils_rpt_agg_filter_div);
457 This draws the 3-tabbed window containing the transform,
458 filter, and aggregate filter picker window
460 function oilsRptDrawDataWindow(path) {
461 var col = oilsRptPathCol(path);
462 var cls = oilsRptPathClass(path);
463 var field = oilsRptFindField(oilsIDL[cls], col);
465 appendClear(DOM.oils_rpt_editor_window_label, text(oilsRptMakeLabel(path)));
466 appendClear(DOM.oils_rpt_editor_window_datatype, text(field.datatype));
468 _debug("setting update data window for column "+col+' on class '+cls);
470 var div = DOM.oils_rpt_column_editor;
471 /* set a preliminary top position so the page won't bounce around */
472 div.setAttribute('style','top:'+oilsMouseX+'px');
474 /* unhide the div so we can determine the dimensions */
477 /* don't let them see the floating div until the position is fully determined */
478 div.style.visibility='hidden';
480 oilsRptDrawTransformWindow(path, col, cls, field);
481 oilsRptDrawFilterWindow(path, col, cls, field);
483 //oilsRptSetFilters(field.datatype);
485 //oilsRptDoFilterWidgets();
487 //DOM.oils_rpt_filter_tform_selector.onchange = oilsRptDoFilterWidgets;
489 buildFloatingDiv(div, 600);
491 /* now let them see it */
492 div.style.visibility='visible';
494 oilsRptSetDataWindowActions(div);
498 function oilsRptSetDataWindowActions(div) {
499 /* give the tab links behavior */
500 DOM.oils_rpt_tform_tab.onclick =
501 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_tform_div)};
502 DOM.oils_rpt_filter_tab.onclick =
503 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_filter_div)};
504 DOM.oils_rpt_agg_filter_tab.onclick =
505 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_agg_filter_div)};
507 DOM.oils_rpt_tform_tab.onclick();
508 DOM.oils_rpt_column_editor_close_button.onclick = function(){hideMe(div);};
512 function oilsRptDrawFilterWindow(path, col, cls, field) {
514 var fsel = $n(DOM.oils_rpt_filter_op_table,'selector');
515 for( var i = 0; i < fsel.options.length; i++ ){
516 var opt = fsel.options[i];
517 var dt = opt.getAttribute('datatype');
520 /* add a special case for boolean objects, since the only
521 operation that makes sense is "=" */
522 if( field.datatype == 'bool' ) {
524 if( opt.getAttribute('value') == '=' )
528 if( dt && dt != field.datatype )
535 DOM.oils_rpt_filter_submit.onclick = function() {
536 var tsel = $n(DOM.oils_rpt_filter_tform_table,'selector');
537 var tform = getSelectorVal(tsel);
538 var filter = getSelectorVal(fsel);
539 oilsAddRptFilterItem(path, tform, filter);
541 oilsRptShowFilters($n(DOM.oils_rpt_filter_tform_table,'selector'), field.datatype, false, true);
544 oilsRptCurrentFilterTform = new oilsRptTFormManager(DOM.oils_rpt_filter_tform_table);
545 oilsRptCurrentFilterTform.build(field.datatype, false, true);
546 oilsRptCurrentFilterOpManager = new oilsRptOpManager(DOM.oils_rpt_filter_op_table);
550 function oilsRptShowFilters( selector, dtype, show_agg, show_noagg ) {
551 for( var i = 0; i < selector.options.length; i++ ) {
552 var opt = selector.options[i];
553 var t = opt.getAttribute('datatype');
554 if( t && t != dtype ){
557 var ag = opt.getAttribute('aggregate');
560 else if( ag && ! show_agg )
562 else if( !ag && show_noagg )
570 /* draws the transform window */
571 function oilsRptDrawTransformWindow(path, col, cls, field) {
572 DOM.oils_rpt_tform_label_input.value = oilsRptMakeLabel(path);
573 var dtype = field.datatype;
575 DOM.oils_rpt_tform_submit.onclick =
577 var sel = $n(DOM.oils_rpt_tform_table,'selector');
578 var tform = getSelectorVal(sel);
579 oilsAddRptDisplayItem(path, DOM.oils_rpt_tform_label_input.value, tform )
583 DOM.oils_rpt_tform_label_input.focus();
584 DOM.oils_rpt_tform_label_input.select();
587 oilsRptCurrentTform = new oilsRptTFormManager(DOM.oils_rpt_tform_table);
588 oilsRptCurrentTform.build(dtype, true, true);
591 _debug($n(DOM.oils_rpt_tform_table,'selector'));
593 oilsRptShowFilters($n(DOM.oils_rpt_tform_table,'selector'), dtype, true, true);
596 oilsRptHideTformFields();
597 oilsRptUnHideTformFields(dtype);
600 _debug("Building transform window for datatype "+dtype);
603 unHideMe($('oils_rpt_tform_'+dtype+'_div'));
604 $('oils_rpt_tform_all_raw').checked = true;
609 function oilsRptHideTformFields() {
610 var rows = DOM.oils_rpt_tform_tbody.childNodes;
611 for( var i = 0; i < rows.length; i++ )
612 if( rows[i] && rows[i].nodeType == 1 )
616 function oilsRptUnHideTformFields(dtype) {
617 var rows = DOM.oils_rpt_tform_tbody.childNodes;
618 for( var i = 0; i < rows.length; i++ ) {
620 if( row && row.nodeType == 1 &&
621 (row.getAttribute('datatype')=='all'
622 || row.getAttribute('datatype') == dtype)) {
629 function oilsRptGetTform(datatype) {
630 for( var i in oilsRptTransforms[datatype] )
631 if( $('oils_rpt_tform_'+datatype+'_'+oilsRptTransforms[datatype][i]).checked )
632 return oilsRptTransforms[datatype][i];
633 for( var i in oilsRptTransforms.all )
634 if( $('oils_rpt_tform_all_'+oilsRptTransforms.all[i]).checked )
635 return oilsRptTransforms.all[i];
642 function getRptTformParams(type, tform) {
648 DOM.oils_rpt_tform_string_substring_offset.value,
649 DOM.oils_rpt_tform_string_substring_length.value];
656 /* given a transform selector, this displays the appropriate
657 transforms for the given datatype.
658 if aggregate is true, is displays the aggregate transforms */
660 function oilsRptSetTransforms(sel, dtype, show_agg, show_noagg) {
661 for( var i = 0; i < sel.options.length; i++ ) {
662 var opt = sel.options[i];
663 var t = opt.getAttribute('datatype');
664 if( t && t != dtype ){
667 var ag = opt.getAttribute('aggregate');
670 else if( ag && ! show_agg )
672 else if( !ag && show_noagg )
682 /* displays the correct filter-transforms for the given datatype */
684 function oilsRptSetFilters(dtype) {
686 DOM.oils_rpt_filter_submit.onclick = function() {
687 var data = oilsRptDoFilterWidgets();
688 alert(js2JSON(data));
691 var sel = DOM.oils_rpt_filter_tform_selector;
692 for( var i = 0; i < sel.options.length; i++ ) {
693 var opt = sel.options[i];
694 _debug(opt.getAttribute('op'));
695 var t = opt.getAttribute('datatype');
696 if( t && t != dtype ) hideMe(opt);
702 /* hides all of the filter widgets */
703 function oilsRptHideFilterWidgets(node) {
705 node = DOM.oils_rpt_filter_tform_widget_td;
706 if( node.nodeType != 1 ) return;
707 if( node.getAttribute('widget') ) {
710 var cs = node.childNodes;
711 for( var i = 0; cs && i < cs.length; i++ )
712 oilsRptHideFilterWidgets(cs[i]);
716 /* what does this need to do? */
717 function oilsRptSetFilterOpActions() {
722 /* hides/unhides the appropriate widgets and returns the parameter
723 array appropriate for the selected widget */
724 function oilsRptDoFilterWidgets() {
725 filter = getSelectorVal(DOM.oils_rpt_filter_tform_selector);
726 oilsRptHideFilterWidgets();
733 /* generic transforms */
735 if(!op) op = 'equals';
739 if(!op) op = 'ilike';
751 if(!op) op = 'not in';
753 if(!op) op = 'between';
755 if(!op) op = 'not between';
756 unHideMe(DOM.oils_rpt_filter_tform_input);
757 params = [DOM.oils_rpt_filter_tform_input.value];
760 /* timestamp transforms */
762 if(!op) op = 'between';
763 case 'date_not_between':
764 if(!op) op = 'not between';
767 unHideMe(DOM.oils_rpt_filter_tform_date_1);
768 unHideMe(DOM.oils_rpt_filter_tform_date_2);
769 unHideMe(DOM.oils_rpt_filter_tform_date_hint);
770 DOM.oils_rpt_filter_tform_date_1.value = mkYearMonDay();
771 DOM.oils_rpt_filter_tform_date_2.value = mkYearMonDay();
773 DOM.oils_rpt_filter_tform_date_1.value,
774 DOM.oils_rpt_filter_tform_date_2.value
780 if(!tform) tform = 'dow';
781 case 'dow_not_between':
782 if(!op) op = 'not between';
783 if(!tform) tform = 'dow';
788 if(!tform) tform = 'dom';
789 case 'dom_not_between':
790 if(!op) op = 'not between';
791 if(!tform) tform = 'dom';
794 case 'month_between':
796 if(!tform) tform = 'moy';
797 case 'month_not_between':
798 if(!op) op = 'not between';
799 if(!tform) tform = 'moy';
802 case 'quarter_between':
804 if(!tform) tform = 'qoy';
805 case 'quarter_not_between':
806 if(!op) op = 'not between';
807 if(!tform) tform = 'qoy';
811 if(!op) op = 'between';
812 if(!tform) tform = 'year_trunc';
813 case 'year_not_between':
814 if(!op) op = 'not between';
815 if(!tform) tform = 'year_trunc';
819 if(!op) op = 'between';
820 if(!tform) tform = 'age';
821 case 'age_not_between':
822 if(!op) op = 'not between';
823 if(!tform) tform = 'age';
826 /* string transforms */
828 if(!tform) tform = 'substring';
833 if(!tform) tform = 'dow';
837 if(!tform) tform = 'dow';
839 /* numeric transforms */
842 if(!tform) tform = 'dow';
846 if(!tform) tform = 'dow';
849 return { op : op, params : params, tform : tform };