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 var aggregate = oilsRptGetIsAgg(tform);
76 /* add this item to the select blob */
78 relation: hex_md5(oilsRptPathRel(path)),
79 _relation: oilsRptPathRel(path),
82 column: { transform: tform, colname: oilsRptPathCol(path) }
85 if( params ) sel.column.params = params;
87 if(!oilsRptGetIsAgg(tform)) {
90 for( var i = 0; i < oilsRpt.def.select.length; i++ ) {
91 var item = oilsRpt.def.select[i];
92 if( !added && oilsRptGetIsAgg( item.column.transform ) ) {
98 if(!added) select.push(sel);
99 oilsRpt.def.select = select;
101 oilsRpt.def.select.push(sel);
105 mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
109 function oilsRptGetIsAgg(tform) {
110 return OILS_RPT_TRANSFORMS[tform].aggregate;
113 var sel = $n(DOM.oils_rpt_tform_table,'selector');
114 for( var i = 0; i < sel.options.length; i++ ) {
115 var opt = sel.options[i];
116 if( opt.getAttribute('value') == tform )
117 return opt.getAttribute('aggregate');
121 /* takes a column path and builds a from-clause object for the path */
122 function oilsRptBuildFromClause(path) {
124 /* the path is the full path (relation) from the source
125 object to the column in question (e.g. au-home_ou-aou-name)*/
126 var parts = path.split(/-/);
128 /* the final from clause */
131 /* reference to the current position in the from clause */
136 /* walk the path, fleshing the from clause as we go */
137 for( var i = 0; i < parts.length; i += 2 ) {
139 var cls = parts[i]; /* class name (id) */
140 var col = parts[i+1]; /* column name */
142 /* a "node" is a class description from the IDL, it
143 contains relevant info, plus a list of "fields",
145 var node = oilsIDL[cls];
146 var pkey = oilsRptFindField(node, node.pkey);
148 /* a "field" is a parsed version of a column from the IDL,
149 contains datatype, column name, etc. */
150 var field = oilsRptFindField(node, col);
152 /* re-construct the path as we go so
153 we know what all we've seen thus far */
154 newpath = (newpath) ? newpath + '-'+ cls : cls;
156 /* extract relevant info */
157 tobj.table = node.table;
159 tobj.alias = hex_md5(newpath);
161 _debug('field type is ' + field.type);
162 if( i == (parts.length - 2) ) break;
164 /* we still have columns left in the path, keep adding join's */
166 if(field.reltype != 'has_a')
167 col = pkey.name + '-' + col;
174 if( field.type == 'link' )
175 tobj.key = field.key;
177 newpath = newpath + '-'+ path_col;
180 _debug("built 'from' clause: path="+path+"\n"+formatJSON(js2JSON(obj)));
185 /* removes a specific item from the display window */
186 function oilsDelDisplayItem(val) {
187 oilsDelSelectorItem(oilsRptDisplaySelector, val);
190 /* removes selected items from the display window */
191 function oilsDelSelectedDisplayItems() {
192 var list = oilsDelSelectedItems(oilsRptDisplaySelector);
194 _debug('deleting list: ' + list);
196 /* remove the de-selected columns from the report output */
197 oilsRpt.def.select = grep( oilsRpt.def.select,
199 for( var j = 0; j < list.length; j++ ) {
200 var d = list[j]; /* path */
203 _debug('in delete, looking at list = '+d+' : col = ' +
204 col.colname + ' : relation = ' + i.relation + ' : encoded = ' + hex_md5(oilsRptPathRel(d)) );
206 if( hex_md5(oilsRptPathRel(d)) == i.relation && oilsRptPathCol(d) == col.colname ) {
214 if(!oilsRpt.def.select) oilsRpt.def.select = [];
216 for( var j = 0; j < list.length; j++ ) {
217 /* if there are no items left in the "select", "where", or "having" clauses
218 for the given relation, trim this relation from the "from" clause */
219 debug('seeing if we can prune from clause with relation = ' + hex_md5(oilsRptPathRel(list[j])));
220 if( !grep(oilsRpt.def.select,
221 function(i){ return (i.relation == hex_md5(oilsRptPathRel(list[j]))); })
222 && !grep(oilsRpt.def.where,
223 function(i){ return (i.relation == hex_md5(oilsRptPathRel(list[j]))); })
224 && !grep(oilsRpt.def.having,
225 function(i){ return (i.relation == hex_md5(oilsRptPathRel(list[j]))); })
227 _debug('pruning from clause');
228 oilsRptPruneFromClause(oilsRptPathRel(list[j]));
236 /* for each item in the path list, remove the associated data
237 from the "from" clause */
239 function oilsRptPruneFromClause(relation, node) {
240 _debug("removing relation from 'from' clause " + relation);
241 if(!node) node = oilsRpt.def.from.join;
243 for( var i in node ) {
244 _debug("looking at node "+node[i].path);
245 // first, descend into the tree, and prune leaves first
247 oilsRptPruneFromClause(relation, node[i].join);
248 if(oilsRptObjectKeys(node[i].join).length == 0) delete node[i].join;
252 _debug(js2JSON(node));
254 // if we're at an unused empty leaf, remove it
257 var key = oilsRptObjectKeys(node)[0];
258 _debug("pruning from clause with "+node[key].alias);
260 if( !grep(oilsRpt.def.select,
261 function(n){ _debug(n.relation); return (n.relation == node[key].alias)})
262 && !grep(oilsRpt.def.where,
263 function(n){ _debug(n.relation); return (n.relation == node[key].alias)})
264 && !grep(oilsRpt.def.having,
265 function(n){ _debug(n.relation); return (n.relation == node[key].alias)})
275 function oilsRptMkFilterTags(path, tform, filter) {
276 var name = oilsRptMakeLabel(path);
277 if(tform) name += ' ('+tform+')';
278 name += ' "' + filter + '"';
279 var epath = path + ':'+filter+':';
280 if(tform) epath += tform;
282 return [ name, epath ];
286 /* adds an item to the display window */
287 function oilsAddRptFilterItem(path, tform, filter) {
288 _debug("Adding filter item for "+path+" tform="+tform+" filter="+filter);
290 var name = oilsRptMkFilterTags(path, tform, filter);
294 if( ! oilsAddSelectorItem(oilsRptFilterSelector, epath, name) )
298 relation: hex_md5(oilsRptPathRel(path)),
299 _relation: oilsRptPathRel(path),
301 column: { transform: tform, colname: oilsRptPathCol(path) },
304 if( filter == 'is' || filter == 'is not' )
305 where.condition[filter] = null;
306 else where.condition[filter] = oilsRptNextParam();
309 case 'substring' : where.column.params = oilsRptNextParam();
312 oilsRpt.def.where.push(where);
313 mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
317 /* removes a specific item from the display window */
318 //function oilsDelFilterItem(path) {
319 //oilsDelSelectorItem(oilsRptFilterSelector, path);
322 /* removes selected items from the display window */
323 function oilsDelSelectedFilterItems() {
325 /* the values in this list are formed: <path>:<operation>:<transform> */
326 var list = oilsDelSelectedItems(oilsRptFilterSelector);
330 for( var i = 0; i < list.length; i++ ) {
333 path: item.replace(/:.*/,''),
334 operation: item.replace(/.*:(.*):.*/,'$1'),
335 tform: item.replace(/.*?:.*?:(.*)/,'$1')
340 /* XXX refactor the below to take operation and transform into account
341 since the same path can be used multiple times as long as a different
342 filter and/or transform is used */
344 /* remove the de-selected columns from the report output */
345 oilsRpt.def.where = grep( oilsRpt.def.where,
347 for( var j = 0; j < flist.length; j++ ) {
350 var frel = oilsRptPathRel(fil.path);
351 var fcol = oilsRptPathCol(fil.path);
353 var op = oilsRptObjectKeys(i.condition)[0];
355 if( frel == i.relation &&
356 fcol == col.colname &&
357 fil.operation == op &&
358 fil.tform == col.transform ) {
359 /* we have found a where clause with the same
360 relation, column, operation and transform */
362 /* we aren't setting params on template build.. */
363 //var param = (i.column.params) ? i.columns.params.match(/::P\d*/) : null;
364 //if( param ) delete oilsRpt.params[param];
365 //param = (i.condition[op]) ? i.condition[op].match(/::P\d*/) : null;
366 //if( param ) delete oilsRpt.params[param];
375 if(!oilsRpt.def.where)
376 oilsRpt.def.where = [];
379 for( var j = 0; j < flist.length; j++ ) {
380 var path = flist[j].path;
381 var rel = oilsRptPathRel(path);
382 /* if there are no items left in the "select", "where", or "having" clauses
383 for the given relation, trim this relation from the "from" clause */
385 var func = function(i){ return (i.relation == rel); };
387 if( !grep(oilsRpt.def.select, func) &&
388 !grep(oilsRpt.def.where, func) &&
389 !grep(oilsRpt.def.having, func) ) {
391 _debug("pruning item with path "+ path + ' and relation '+ rel);
393 oilsRptPruneFromClause(oilsRptPathRel(path));
400 /* adds an item to the display window */
401 function oilsAddRptAggFilterItem(val) {
402 oilsAddSelectorItem(oilsRptAggFilterSelector, val);
405 /* removes a specific item from the display window */
406 function oilsDelAggFilterItem(val) {
407 oilsDelSelectorItem(oilsRptAggFilterSelector, val);
410 /* removes selected items from the display window */
411 function oilsDelSelectedAggFilterItems() {
412 var list = oilsDelSelectedItems(oilsRptAggFilterSelector);
414 /* remove the de-selected columns from the report output */
415 oilsRpt.def.having = grep( oilsRpt.def.having,
417 for( var j = 0; j < list.length; j++ ) {
421 /* if this columsn has a transform,
422 it will be an object { tform => column } */
423 if( typeof col != 'string' )
424 for( var c in col ) col = col[c];
426 /* if this transform requires params, the column
427 will be the first item in the param set array */
428 if( typeof col != 'string' ) col = col[0];
430 if( oilsRptPathRel(d) == i.relation && oilsRptPathCol(d) == col ) {
431 var param = (i.alias) ? i.alias.match(/::P\d*/) : null;
432 if( param ) delete oilsRpt.params[param];
440 if(!oilsRpt.def.having) {
441 oilsRpt.def.having = [];
442 oilsReportBuilderReset();
445 for( var j = 0; j < list.length; j++ )
446 /* if there are no items left in the "select", "where", or "having" clauses
447 for the given relation, trim this relation from the "from" clause */
448 if( !grep(oilsRpt.def.select,
449 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
450 && !grep(oilsRpt.def.where,
451 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
452 && !grep(oilsRpt.def.having,
453 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
454 ) oilsRptPruneFromClause(oilsRptPathRel(list[j]));
461 /* adds an item to the display window */
462 function oilsAddSelectorItem(sel, val, name) {
463 name = (name) ? name : oilsRptMakeLabel(val);
464 _debug("adding selector item "+name+' = ' +val);
465 for( var i = 0; i < sel.options.length; i++ ) {
466 var opt = sel.options[i];
467 if( opt.value == val ) return false;
469 insertSelectorVal( sel, -1, name, val );
474 /* removes a specific item from the display window */
475 function oilsDelSelectorItem(sel, val) {
476 _debug("deleting selector item "+val);
477 var opts = sel.options;
478 for( var i = 0; i < opts.length; i++ ) {
480 if( opt.value == val ) {
481 if( i == opts.length - 1 )
483 else opts[i] = opts[i+1];
489 /* removes selected items from the display window */
490 function oilsDelSelectedItems(sel) {
491 var list = getSelectedList(sel);
492 for( var i = 0; i < list.length; i++ )
493 oilsDelSelectorItem(sel, list[i]);
498 /* hides the different field editor tabs */
499 function oilsRptHideEditorDivs() {
500 hideMe(DOM.oils_rpt_tform_div);
501 hideMe(DOM.oils_rpt_filter_div);
502 hideMe(DOM.oils_rpt_agg_filter_div);
507 This draws the 3-tabbed window containing the transform,
508 filter, and aggregate filter picker window
510 function oilsRptDrawDataWindow(path) {
511 var col = oilsRptPathCol(path);
512 var cls = oilsRptPathClass(path);
513 var field = oilsRptFindField(oilsIDL[cls], col);
515 appendClear(DOM.oils_rpt_editor_window_label, text(oilsRptMakeLabel(path)));
516 appendClear(DOM.oils_rpt_editor_window_datatype, text(field.datatype));
518 _debug("setting update data window for column "+col+' on class '+cls);
520 var div = DOM.oils_rpt_column_editor;
521 /* set a preliminary top position so the page won't bounce around */
522 div.setAttribute('style','top:'+oilsMouseX+'px');
524 /* unhide the div so we can determine the dimensions */
527 /* don't let them see the floating div until the position is fully determined */
528 div.style.visibility='hidden';
530 oilsRptDrawTransformWindow(path, col, cls, field);
531 oilsRptDrawFilterWindow(path, col, cls, field);
533 //oilsRptSetFilters(field.datatype);
535 //oilsRptDoFilterWidgets();
537 //DOM.oils_rpt_filter_tform_selector.onchange = oilsRptDoFilterWidgets;
539 buildFloatingDiv(div, 600);
541 /* now let them see it */
542 div.style.visibility='visible';
544 oilsRptSetDataWindowActions(div);
548 function oilsRptSetDataWindowActions(div) {
549 /* give the tab links behavior */
550 DOM.oils_rpt_tform_tab.onclick =
551 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_tform_div)};
552 DOM.oils_rpt_filter_tab.onclick =
553 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_filter_div)};
554 DOM.oils_rpt_agg_filter_tab.onclick =
555 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_agg_filter_div)};
557 DOM.oils_rpt_tform_tab.onclick();
558 DOM.oils_rpt_column_editor_close_button.onclick = function(){hideMe(div);};
562 function oilsRptDrawFilterWindow(path, col, cls, field) {
564 var fsel = $n(DOM.oils_rpt_filter_op_table,'selector');
565 for( var i = 0; i < fsel.options.length; i++ ){
566 var opt = fsel.options[i];
567 var dt = opt.getAttribute('datatype');
570 /* add a special case for boolean objects, since the only
571 operation that makes sense is "=" */
572 if( field.datatype == 'bool' ) {
574 if( opt.getAttribute('value') == '=' )
578 if( dt && dt != field.datatype )
584 var tformPicker = new oilsRptTformPicker( {
585 node : DOM.oils_rpt_filter_tform_table,
586 datatype : field.datatype,
591 DOM.oils_rpt_filter_submit.onclick = function() {
592 oilsAddRptFilterItem(
593 path, tformPicker.getSelected(), getSelectorVal(fsel));
598 DOM.oils_rpt_filter_submit.onclick = function() {
599 var tsel = $n(DOM.oils_rpt_filter_tform_table,'selector');
600 var tform = getSelectorVal(tsel);
601 var filter = getSelectorVal(fsel);
602 oilsAddRptFilterItem(path, tform, filter);
604 oilsRptShowFilters($n(DOM.oils_rpt_filter_tform_table,'selector'), field.datatype, false, true);
608 oilsRptCurrentFilterTform = new oilsRptTFormManager(DOM.oils_rpt_filter_tform_table);
609 oilsRptCurrentFilterTform.build(field.datatype, false, true);
610 oilsRptCurrentFilterOpManager = new oilsRptOpManager(DOM.oils_rpt_filter_op_table);
614 function oilsRptShowFilters( selector, dtype, show_agg, show_noagg ) {
615 for( var i = 0; i < selector.options.length; i++ ) {
616 var opt = selector.options[i];
617 var t = opt.getAttribute('datatype');
618 if( t && t != dtype ){
621 var ag = opt.getAttribute('aggregate');
624 else if( ag && ! show_agg )
626 else if( !ag && show_noagg )
634 /* draws the transform window */
635 function oilsRptDrawTransformWindow(path, col, cls, field) {
636 DOM.oils_rpt_tform_label_input.value = oilsRptMakeLabel(path);
637 var dtype = field.datatype;
639 var tformPicker = new oilsRptTformPicker( {
640 node : DOM.oils_rpt_tform_table,
641 datatype : field.datatype,
642 non_aggregate : true,
647 DOM.oils_rpt_tform_submit.onclick =
649 oilsAddRptDisplayItem(path,
650 DOM.oils_rpt_tform_label_input.value, tformPicker.getSelected() );
654 DOM.oils_rpt_tform_label_input.focus();
655 DOM.oils_rpt_tform_label_input.select();
658 oilsRptCurrentTform = new oilsRptTFormManager(DOM.oils_rpt_tform_table);
659 oilsRptCurrentTform.build(dtype, true, true);
663 _debug($n(DOM.oils_rpt_tform_table,'selector'));
665 oilsRptShowFilters($n(DOM.oils_rpt_tform_table,'selector'), dtype, true, true);
669 oilsRptHideTformFields();
670 oilsRptUnHideTformFields(dtype);
673 _debug("Building transform window for datatype "+dtype);
676 unHideMe($('oils_rpt_tform_'+dtype+'_div'));
677 $('oils_rpt_tform_all_raw').checked = true;
682 function oilsRptHideTformFields() {
683 var rows = DOM.oils_rpt_tform_tbody.childNodes;
684 for( var i = 0; i < rows.length; i++ )
685 if( rows[i] && rows[i].nodeType == 1 )
689 function oilsRptUnHideTformFields(dtype) {
690 var rows = DOM.oils_rpt_tform_tbody.childNodes;
691 for( var i = 0; i < rows.length; i++ ) {
693 if( row && row.nodeType == 1 &&
694 (row.getAttribute('datatype')=='all'
695 || row.getAttribute('datatype') == dtype)) {
702 function oilsRptGetTform(datatype) {
703 for( var i in oilsRptTransforms[datatype] )
704 if( $('oils_rpt_tform_'+datatype+'_'+oilsRptTransforms[datatype][i]).checked )
705 return oilsRptTransforms[datatype][i];
706 for( var i in oilsRptTransforms.all )
707 if( $('oils_rpt_tform_all_'+oilsRptTransforms.all[i]).checked )
708 return oilsRptTransforms.all[i];
715 function getRptTformParams(type, tform) {
721 DOM.oils_rpt_tform_string_substring_offset.value,
722 DOM.oils_rpt_tform_string_substring_length.value];
729 /* given a transform selector, this displays the appropriate
730 transforms for the given datatype.
731 if aggregate is true, is displays the aggregate transforms */
733 function oilsRptSetTransforms(sel, dtype, show_agg, show_noagg) {
734 for( var i = 0; i < sel.options.length; i++ ) {
735 var opt = sel.options[i];
736 var t = opt.getAttribute('datatype');
737 if( t && t != dtype ){
740 var ag = opt.getAttribute('aggregate');
743 else if( ag && ! show_agg )
745 else if( !ag && show_noagg )
755 /* displays the correct filter-transforms for the given datatype */
757 function oilsRptSetFilters(dtype) {
759 DOM.oils_rpt_filter_submit.onclick = function() {
760 var data = oilsRptDoFilterWidgets();
761 alert(js2JSON(data));
764 var sel = DOM.oils_rpt_filter_tform_selector;
765 for( var i = 0; i < sel.options.length; i++ ) {
766 var opt = sel.options[i];
767 _debug(opt.getAttribute('op'));
768 var t = opt.getAttribute('datatype');
769 if( t && t != dtype ) hideMe(opt);
775 /* hides all of the filter widgets */
777 function oilsRptHideFilterWidgets(node) {
779 node = DOM.oils_rpt_filter_tform_widget_td;
780 if( node.nodeType != 1 ) return;
781 if( node.getAttribute('widget') ) {
784 var cs = node.childNodes;
785 for( var i = 0; cs && i < cs.length; i++ )
786 oilsRptHideFilterWidgets(cs[i]);
792 /* hides/unhides the appropriate widgets and returns the parameter
793 array appropriate for the selected widget */
795 function oilsRptDoFilterWidgets() {
796 filter = getSelectorVal(DOM.oils_rpt_filter_tform_selector);
797 oilsRptHideFilterWidgets();
805 if(!op) op = 'equals';
809 if(!op) op = 'ilike';
821 if(!op) op = 'not in';
823 if(!op) op = 'between';
825 if(!op) op = 'not between';
826 unHideMe(DOM.oils_rpt_filter_tform_input);
827 params = [DOM.oils_rpt_filter_tform_input.value];
831 if(!op) op = 'between';
832 case 'date_not_between':
833 if(!op) op = 'not between';
836 unHideMe(DOM.oils_rpt_filter_tform_date_1);
837 unHideMe(DOM.oils_rpt_filter_tform_date_2);
838 unHideMe(DOM.oils_rpt_filter_tform_date_hint);
839 DOM.oils_rpt_filter_tform_date_1.value = mkYearMonDay();
840 DOM.oils_rpt_filter_tform_date_2.value = mkYearMonDay();
842 DOM.oils_rpt_filter_tform_date_1.value,
843 DOM.oils_rpt_filter_tform_date_2.value
849 if(!tform) tform = 'dow';
850 case 'dow_not_between':
851 if(!op) op = 'not between';
852 if(!tform) tform = 'dow';
857 if(!tform) tform = 'dom';
858 case 'dom_not_between':
859 if(!op) op = 'not between';
860 if(!tform) tform = 'dom';
863 case 'month_between':
865 if(!tform) tform = 'moy';
866 case 'month_not_between':
867 if(!op) op = 'not between';
868 if(!tform) tform = 'moy';
871 case 'quarter_between':
873 if(!tform) tform = 'qoy';
874 case 'quarter_not_between':
875 if(!op) op = 'not between';
876 if(!tform) tform = 'qoy';
880 if(!op) op = 'between';
881 if(!tform) tform = 'year_trunc';
882 case 'year_not_between':
883 if(!op) op = 'not between';
884 if(!tform) tform = 'year_trunc';
888 if(!op) op = 'between';
889 if(!tform) tform = 'age';
890 case 'age_not_between':
891 if(!op) op = 'not between';
892 if(!tform) tform = 'age';
896 if(!tform) tform = 'substring';
901 if(!tform) tform = 'dow';
905 if(!tform) tform = 'dow';
909 if(!tform) tform = 'dow';
913 if(!tform) tform = 'dow';
916 return { op : op, params : params, tform : tform };