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 var sel = $n(DOM.oils_rpt_tform_table,'selector');
111 for( var i = 0; i < sel.options.length; i++ ) {
112 var opt = sel.options[i];
113 if( opt.getAttribute('value') == tform )
114 return opt.getAttribute('aggregate');
118 /* takes a column path and builds a from-clause object for the path */
119 function oilsRptBuildFromClause(path) {
121 /* the path is the full path (relation) from the source
122 object to the column in question (e.g. au-home_ou-aou-name)*/
123 var parts = path.split(/-/);
125 /* the final from clause */
128 /* reference to the current position in the from clause */
133 /* walk the path, fleshing the from clause as we go */
134 for( var i = 0; i < parts.length; i += 2 ) {
136 var cls = parts[i]; /* class name (id) */
137 var col = parts[i+1]; /* column name */
139 /* a "node" is a class description from the IDL, it
140 contains relevant info, plus a list of "fields",
142 var node = oilsIDL[cls];
143 var pkey = oilsRptFindField(node, node.pkey);
145 /* a "field" is a parsed version of a column from the IDL,
146 contains datatype, column name, etc. */
147 var field = oilsRptFindField(node, col);
149 /* re-construct the path as we go so
150 we know what all we've seen thus far */
151 newpath = (newpath) ? newpath + '-'+ cls : cls;
153 /* extract relevant info */
154 tobj.table = node.table;
156 tobj.alias = hex_md5(newpath);
158 _debug('field type is ' + field.type);
159 if( i == (parts.length - 2) ) break;
161 /* we still have columns left in the path, keep adding join's */
163 if(field.reltype != 'has_a')
164 col = pkey.name + '-' + col;
171 if( field.type == 'link' )
172 tobj.key = field.key;
174 newpath = newpath + '-'+ path_col;
177 _debug("built 'from' clause: path="+path+"\n"+formatJSON(js2JSON(obj)));
182 /* removes a specific item from the display window */
183 function oilsDelDisplayItem(val) {
184 oilsDelSelectorItem(oilsRptDisplaySelector, val);
187 /* removes selected items from the display window */
188 function oilsDelSelectedDisplayItems() {
189 var list = oilsDelSelectedItems(oilsRptDisplaySelector);
191 _debug('deleting list: ' + list);
193 /* remove the de-selected columns from the report output */
194 oilsRpt.def.select = grep( oilsRpt.def.select,
196 for( var j = 0; j < list.length; j++ ) {
197 var d = list[j]; /* path */
200 _debug('in delete, looking at list = '+d+' : col = ' +
201 col.colname + ' : relation = ' + i.relation + ' : encoded = ' + hex_md5(oilsRptPathRel(d)) );
203 if( hex_md5(oilsRptPathRel(d)) == i.relation && oilsRptPathCol(d) == col.colname ) {
211 if(!oilsRpt.def.select) oilsRpt.def.select = [];
213 for( var j = 0; j < list.length; j++ ) {
214 /* if there are no items left in the "select", "where", or "having" clauses
215 for the given relation, trim this relation from the "from" clause */
216 debug('seeing if we can prune from clause with relation = ' + hex_md5(oilsRptPathRel(list[j])));
217 if( !grep(oilsRpt.def.select,
218 function(i){ return (i.relation == hex_md5(oilsRptPathRel(list[j]))); })
219 && !grep(oilsRpt.def.where,
220 function(i){ return (i.relation == hex_md5(oilsRptPathRel(list[j]))); })
221 && !grep(oilsRpt.def.having,
222 function(i){ return (i.relation == hex_md5(oilsRptPathRel(list[j]))); })
224 _debug('pruning from clause');
225 oilsRptPruneFromClause(oilsRptPathRel(list[j]));
233 /* for each item in the path list, remove the associated data
234 from the "from" clause */
236 function oilsRptPruneFromClause(relation, node) {
237 _debug("removing relation from 'from' clause " + relation);
238 if(!node) node = oilsRpt.def.from.join;
240 for( var i in node ) {
241 _debug("looking at node "+node[i].path);
242 // first, descend into the tree, and prune leaves first
244 oilsRptPruneFromClause(relation, node[i].join);
245 if(oilsRptObjectKeys(node[i].join).length == 0) delete node[i].join;
249 _debug(js2JSON(node));
251 // if we're at an unused empty leaf, remove it
254 var key = oilsRptObjectKeys(node)[0];
255 _debug("pruning from clause with "+node[key].alias);
257 if( !grep(oilsRpt.def.select,
258 function(n){ _debug(n.relation); return (n.relation == node[key].alias)})
259 && !grep(oilsRpt.def.where,
260 function(n){ _debug(n.relation); return (n.relation == node[key].alias)})
261 && !grep(oilsRpt.def.having,
262 function(n){ _debug(n.relation); return (n.relation == node[key].alias)})
272 function oilsRptMkFilterTags(path, tform, filter) {
273 var name = oilsRptMakeLabel(path);
274 if(tform) name += ' ('+tform+')';
275 name += ' "' + filter + '"';
276 var epath = path + ':'+filter+':';
277 if(tform) epath += tform;
279 return [ name, epath ];
283 /* adds an item to the display window */
284 function oilsAddRptFilterItem(path, tform, filter) {
285 _debug("Adding filter item for "+path+" tform="+tform+" filter="+filter);
287 var name = oilsRptMkFilterTags(path, tform, filter);
291 if( ! oilsAddSelectorItem(oilsRptFilterSelector, epath, name) )
295 relation: hex_md5(oilsRptPathRel(path)),
296 _relation: oilsRptPathRel(path),
298 column: { transform: tform, colname: oilsRptPathCol(path) },
301 where.condition[filter] = oilsRptNextParam();
304 case 'substring' : where.column.params = oilsRptNextParam();
307 oilsRpt.def.where.push(where);
308 mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
312 /* removes a specific item from the display window */
313 //function oilsDelFilterItem(path) {
314 //oilsDelSelectorItem(oilsRptFilterSelector, path);
317 /* removes selected items from the display window */
318 function oilsDelSelectedFilterItems() {
320 /* the values in this list are formed: <path>:<operation>:<transform> */
321 var list = oilsDelSelectedItems(oilsRptFilterSelector);
325 for( var i = 0; i < list.length; i++ ) {
328 path: item.replace(/:.*/,''),
329 operation: item.replace(/.*:(.*):.*/,'$1'),
330 tform: item.replace(/.*?:.*?:(.*)/,'$1')
335 /* XXX refactor the below to take operation and transform into account
336 since the same path can be used multiple times as long as a different
337 filter and/or transform is used */
339 /* remove the de-selected columns from the report output */
340 oilsRpt.def.where = grep( oilsRpt.def.where,
342 for( var j = 0; j < flist.length; j++ ) {
345 var frel = oilsRptPathRel(fil.path);
346 var fcol = oilsRptPathCol(fil.path);
348 var op = oilsRptObjectKeys(i.condition)[0];
350 if( frel == i.relation &&
351 fcol == col.colname &&
352 fil.operation == op &&
353 fil.tform == col.transform ) {
354 /* we have found a where clause with the same
355 relation, column, operation and transform */
357 /* we aren't setting params on template build.. */
358 //var param = (i.column.params) ? i.columns.params.match(/::P\d*/) : null;
359 //if( param ) delete oilsRpt.params[param];
360 //param = (i.condition[op]) ? i.condition[op].match(/::P\d*/) : null;
361 //if( param ) delete oilsRpt.params[param];
370 if(!oilsRpt.def.where)
371 oilsRpt.def.where = [];
374 for( var j = 0; j < flist.length; j++ ) {
375 var path = flist[j].path;
376 var rel = oilsRptPathRel(path);
377 /* if there are no items left in the "select", "where", or "having" clauses
378 for the given relation, trim this relation from the "from" clause */
380 var func = function(i){ return (i.relation == rel); };
382 if( !grep(oilsRpt.def.select, func) &&
383 !grep(oilsRpt.def.where, func) &&
384 !grep(oilsRpt.def.having, func) ) {
386 _debug("pruning item with path "+ path + ' and relation '+ rel);
388 oilsRptPruneFromClause(oilsRptPathRel(path));
395 /* adds an item to the display window */
396 function oilsAddRptAggFilterItem(val) {
397 oilsAddSelectorItem(oilsRptAggFilterSelector, val);
400 /* removes a specific item from the display window */
401 function oilsDelAggFilterItem(val) {
402 oilsDelSelectorItem(oilsRptAggFilterSelector, val);
405 /* removes selected items from the display window */
406 function oilsDelSelectedAggFilterItems() {
407 var list = oilsDelSelectedItems(oilsRptAggFilterSelector);
409 /* remove the de-selected columns from the report output */
410 oilsRpt.def.having = grep( oilsRpt.def.having,
412 for( var j = 0; j < list.length; j++ ) {
416 /* if this columsn has a transform,
417 it will be an object { tform => column } */
418 if( typeof col != 'string' )
419 for( var c in col ) col = col[c];
421 /* if this transform requires params, the column
422 will be the first item in the param set array */
423 if( typeof col != 'string' ) col = col[0];
425 if( oilsRptPathRel(d) == i.relation && oilsRptPathCol(d) == col ) {
426 var param = (i.alias) ? i.alias.match(/::P\d*/) : null;
427 if( param ) delete oilsRpt.params[param];
435 if(!oilsRpt.def.having) {
436 oilsRpt.def.having = [];
437 oilsReportBuilderReset();
440 for( var j = 0; j < list.length; j++ )
441 /* if there are no items left in the "select", "where", or "having" clauses
442 for the given relation, trim this relation from the "from" clause */
443 if( !grep(oilsRpt.def.select,
444 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
445 && !grep(oilsRpt.def.where,
446 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
447 && !grep(oilsRpt.def.having,
448 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
449 ) oilsRptPruneFromClause(oilsRptPathRel(list[j]));
456 /* adds an item to the display window */
457 function oilsAddSelectorItem(sel, val, name) {
458 name = (name) ? name : oilsRptMakeLabel(val);
459 _debug("adding selector item "+name+' = ' +val);
460 for( var i = 0; i < sel.options.length; i++ ) {
461 var opt = sel.options[i];
462 if( opt.value == val ) return false;
464 insertSelectorVal( sel, -1, name, val );
469 /* removes a specific item from the display window */
470 function oilsDelSelectorItem(sel, val) {
471 _debug("deleting selector item "+val);
472 var opts = sel.options;
473 for( var i = 0; i < opts.length; i++ ) {
475 if( opt.value == val ) {
476 if( i == opts.length - 1 )
478 else opts[i] = opts[i+1];
484 /* removes selected items from the display window */
485 function oilsDelSelectedItems(sel) {
486 var list = getSelectedList(sel);
487 for( var i = 0; i < list.length; i++ )
488 oilsDelSelectorItem(sel, list[i]);
493 /* hides the different field editor tabs */
494 function oilsRptHideEditorDivs() {
495 hideMe(DOM.oils_rpt_tform_div);
496 hideMe(DOM.oils_rpt_filter_div);
497 hideMe(DOM.oils_rpt_agg_filter_div);
502 This draws the 3-tabbed window containing the transform,
503 filter, and aggregate filter picker window
505 function oilsRptDrawDataWindow(path) {
506 var col = oilsRptPathCol(path);
507 var cls = oilsRptPathClass(path);
508 var field = oilsRptFindField(oilsIDL[cls], col);
510 appendClear(DOM.oils_rpt_editor_window_label, text(oilsRptMakeLabel(path)));
511 appendClear(DOM.oils_rpt_editor_window_datatype, text(field.datatype));
513 _debug("setting update data window for column "+col+' on class '+cls);
515 var div = DOM.oils_rpt_column_editor;
516 /* set a preliminary top position so the page won't bounce around */
517 div.setAttribute('style','top:'+oilsMouseX+'px');
519 /* unhide the div so we can determine the dimensions */
522 /* don't let them see the floating div until the position is fully determined */
523 div.style.visibility='hidden';
525 oilsRptDrawTransformWindow(path, col, cls, field);
526 oilsRptDrawFilterWindow(path, col, cls, field);
528 //oilsRptSetFilters(field.datatype);
530 //oilsRptDoFilterWidgets();
532 //DOM.oils_rpt_filter_tform_selector.onchange = oilsRptDoFilterWidgets;
534 buildFloatingDiv(div, 600);
536 /* now let them see it */
537 div.style.visibility='visible';
539 oilsRptSetDataWindowActions(div);
543 function oilsRptSetDataWindowActions(div) {
544 /* give the tab links behavior */
545 DOM.oils_rpt_tform_tab.onclick =
546 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_tform_div)};
547 DOM.oils_rpt_filter_tab.onclick =
548 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_filter_div)};
549 DOM.oils_rpt_agg_filter_tab.onclick =
550 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_agg_filter_div)};
552 DOM.oils_rpt_tform_tab.onclick();
553 DOM.oils_rpt_column_editor_close_button.onclick = function(){hideMe(div);};
557 function oilsRptDrawFilterWindow(path, col, cls, field) {
559 var fsel = $n(DOM.oils_rpt_filter_op_table,'selector');
560 for( var i = 0; i < fsel.options.length; i++ ){
561 var opt = fsel.options[i];
562 var dt = opt.getAttribute('datatype');
565 /* add a special case for boolean objects, since the only
566 operation that makes sense is "=" */
567 if( field.datatype == 'bool' ) {
569 if( opt.getAttribute('value') == '=' )
573 if( dt && dt != field.datatype )
580 DOM.oils_rpt_filter_submit.onclick = function() {
581 var tsel = $n(DOM.oils_rpt_filter_tform_table,'selector');
582 var tform = getSelectorVal(tsel);
583 var filter = getSelectorVal(fsel);
584 oilsAddRptFilterItem(path, tform, filter);
586 oilsRptShowFilters($n(DOM.oils_rpt_filter_tform_table,'selector'), field.datatype, false, true);
589 oilsRptCurrentFilterTform = new oilsRptTFormManager(DOM.oils_rpt_filter_tform_table);
590 oilsRptCurrentFilterTform.build(field.datatype, false, true);
591 oilsRptCurrentFilterOpManager = new oilsRptOpManager(DOM.oils_rpt_filter_op_table);
595 function oilsRptShowFilters( selector, dtype, show_agg, show_noagg ) {
596 for( var i = 0; i < selector.options.length; i++ ) {
597 var opt = selector.options[i];
598 var t = opt.getAttribute('datatype');
599 if( t && t != dtype ){
602 var ag = opt.getAttribute('aggregate');
605 else if( ag && ! show_agg )
607 else if( !ag && show_noagg )
615 /* draws the transform window */
616 function oilsRptDrawTransformWindow(path, col, cls, field) {
617 DOM.oils_rpt_tform_label_input.value = oilsRptMakeLabel(path);
618 var dtype = field.datatype;
620 DOM.oils_rpt_tform_submit.onclick =
622 var sel = $n(DOM.oils_rpt_tform_table,'selector');
623 var tform = getSelectorVal(sel);
624 oilsAddRptDisplayItem(path, DOM.oils_rpt_tform_label_input.value, tform )
628 DOM.oils_rpt_tform_label_input.focus();
629 DOM.oils_rpt_tform_label_input.select();
632 oilsRptCurrentTform = new oilsRptTFormManager(DOM.oils_rpt_tform_table);
633 oilsRptCurrentTform.build(dtype, true, true);
636 _debug($n(DOM.oils_rpt_tform_table,'selector'));
638 oilsRptShowFilters($n(DOM.oils_rpt_tform_table,'selector'), dtype, true, true);
641 oilsRptHideTformFields();
642 oilsRptUnHideTformFields(dtype);
645 _debug("Building transform window for datatype "+dtype);
648 unHideMe($('oils_rpt_tform_'+dtype+'_div'));
649 $('oils_rpt_tform_all_raw').checked = true;
654 function oilsRptHideTformFields() {
655 var rows = DOM.oils_rpt_tform_tbody.childNodes;
656 for( var i = 0; i < rows.length; i++ )
657 if( rows[i] && rows[i].nodeType == 1 )
661 function oilsRptUnHideTformFields(dtype) {
662 var rows = DOM.oils_rpt_tform_tbody.childNodes;
663 for( var i = 0; i < rows.length; i++ ) {
665 if( row && row.nodeType == 1 &&
666 (row.getAttribute('datatype')=='all'
667 || row.getAttribute('datatype') == dtype)) {
674 function oilsRptGetTform(datatype) {
675 for( var i in oilsRptTransforms[datatype] )
676 if( $('oils_rpt_tform_'+datatype+'_'+oilsRptTransforms[datatype][i]).checked )
677 return oilsRptTransforms[datatype][i];
678 for( var i in oilsRptTransforms.all )
679 if( $('oils_rpt_tform_all_'+oilsRptTransforms.all[i]).checked )
680 return oilsRptTransforms.all[i];
687 function getRptTformParams(type, tform) {
693 DOM.oils_rpt_tform_string_substring_offset.value,
694 DOM.oils_rpt_tform_string_substring_length.value];
701 /* given a transform selector, this displays the appropriate
702 transforms for the given datatype.
703 if aggregate is true, is displays the aggregate transforms */
705 function oilsRptSetTransforms(sel, dtype, show_agg, show_noagg) {
706 for( var i = 0; i < sel.options.length; i++ ) {
707 var opt = sel.options[i];
708 var t = opt.getAttribute('datatype');
709 if( t && t != dtype ){
712 var ag = opt.getAttribute('aggregate');
715 else if( ag && ! show_agg )
717 else if( !ag && show_noagg )
727 /* displays the correct filter-transforms for the given datatype */
729 function oilsRptSetFilters(dtype) {
731 DOM.oils_rpt_filter_submit.onclick = function() {
732 var data = oilsRptDoFilterWidgets();
733 alert(js2JSON(data));
736 var sel = DOM.oils_rpt_filter_tform_selector;
737 for( var i = 0; i < sel.options.length; i++ ) {
738 var opt = sel.options[i];
739 _debug(opt.getAttribute('op'));
740 var t = opt.getAttribute('datatype');
741 if( t && t != dtype ) hideMe(opt);
747 /* hides all of the filter widgets */
748 function oilsRptHideFilterWidgets(node) {
750 node = DOM.oils_rpt_filter_tform_widget_td;
751 if( node.nodeType != 1 ) return;
752 if( node.getAttribute('widget') ) {
755 var cs = node.childNodes;
756 for( var i = 0; cs && i < cs.length; i++ )
757 oilsRptHideFilterWidgets(cs[i]);
761 /* what does this need to do? */
762 function oilsRptSetFilterOpActions() {
767 /* hides/unhides the appropriate widgets and returns the parameter
768 array appropriate for the selected widget */
769 function oilsRptDoFilterWidgets() {
770 filter = getSelectorVal(DOM.oils_rpt_filter_tform_selector);
771 oilsRptHideFilterWidgets();
778 /* generic transforms */
780 if(!op) op = 'equals';
784 if(!op) op = 'ilike';
796 if(!op) op = 'not in';
798 if(!op) op = 'between';
800 if(!op) op = 'not between';
801 unHideMe(DOM.oils_rpt_filter_tform_input);
802 params = [DOM.oils_rpt_filter_tform_input.value];
805 /* timestamp transforms */
807 if(!op) op = 'between';
808 case 'date_not_between':
809 if(!op) op = 'not between';
812 unHideMe(DOM.oils_rpt_filter_tform_date_1);
813 unHideMe(DOM.oils_rpt_filter_tform_date_2);
814 unHideMe(DOM.oils_rpt_filter_tform_date_hint);
815 DOM.oils_rpt_filter_tform_date_1.value = mkYearMonDay();
816 DOM.oils_rpt_filter_tform_date_2.value = mkYearMonDay();
818 DOM.oils_rpt_filter_tform_date_1.value,
819 DOM.oils_rpt_filter_tform_date_2.value
825 if(!tform) tform = 'dow';
826 case 'dow_not_between':
827 if(!op) op = 'not between';
828 if(!tform) tform = 'dow';
833 if(!tform) tform = 'dom';
834 case 'dom_not_between':
835 if(!op) op = 'not between';
836 if(!tform) tform = 'dom';
839 case 'month_between':
841 if(!tform) tform = 'moy';
842 case 'month_not_between':
843 if(!op) op = 'not between';
844 if(!tform) tform = 'moy';
847 case 'quarter_between':
849 if(!tform) tform = 'qoy';
850 case 'quarter_not_between':
851 if(!op) op = 'not between';
852 if(!tform) tform = 'qoy';
856 if(!op) op = 'between';
857 if(!tform) tform = 'year_trunc';
858 case 'year_not_between':
859 if(!op) op = 'not between';
860 if(!tform) tform = 'year_trunc';
864 if(!op) op = 'between';
865 if(!tform) tform = 'age';
866 case 'age_not_between':
867 if(!op) op = 'not between';
868 if(!tform) tform = 'age';
871 /* string transforms */
873 if(!tform) tform = 'substring';
878 if(!tform) tform = 'dow';
882 if(!tform) tform = 'dow';
884 /* numeric transforms */
887 if(!tform) tform = 'dow';
891 if(!tform) tform = 'dow';
894 return { op : op, params : params, tform : tform };