1 /** initializes reports, some basid display settings,
2 * grabs and builds the IDL tree
4 function oilsInitReportBuilder() {
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;
17 oilsRpt.folder = new CGI().param('folder');
20 function oilsReportBuilderReset() {
21 var n = (oilsRpt) ? oilsRpt.name : "";
22 oilsRpt = new oilsReport();
24 oilsRptDisplaySelector = DOM.oils_rpt_display_selector;
25 oilsRptFilterSelector = DOM.oils_rpt_filter_selector;
26 oilsRptAggFilterSelector= DOM.oils_rpt_agg_filter_selector;
27 removeChildren(oilsRptDisplaySelector);
28 removeChildren(oilsRptFilterSelector);
29 removeChildren(oilsRptAggFilterSelector);
34 function oilsReportBuilderSave() {
35 if(!confirm('Name : '+oilsRpt.name + '\nDescription: '
36 + oilsRpt.description+'\nSave Template?'))
40 tmpl.name( oilsRpt.name );
41 tmpl.description( oilsRpt.desc );
43 tmpl.folder(oilsRpt.folder);
44 tmpl.data(js2JSON(oilsRpt.def));
46 var req = new Request(OILS_RPT_CREATE_TEMPLATE, SESSION, tmpl);
49 var res = r.getResultObject();
51 oilsRptAlertSuccess();
62 /* adds an item to the display window */
63 function oilsAddRptDisplayItem(path, name, tform, params) {
64 if( ! oilsAddSelectorItem(oilsRptDisplaySelector, path, name) )
67 /* add the selected columns to the report output */
68 name = (name) ? name : oilsRptPathCol(path);
69 if( !tform ) tform = 'Bare';
71 /* add this item to the select blob */
73 relation: oilsRptPathRel(path),
75 column: { transform: tform, colname: oilsRptPathCol(path) }
78 if( params ) sel.column.params = params;
79 oilsRpt.def.select.push(sel);
81 mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
85 /* takes a column path and builds a from-clause object for the path */
86 function oilsRptBuildFromClause(path) {
88 /* the path is the full path (relation) from the source
89 object to the column in question (e.g. au-home_ou-aou-name)*/
90 var parts = path.split(/-/);
92 /* the final from clause */
95 /* reference to the current position in the from clause */
100 /* walk the path, fleshing the from clause as we go */
101 for( var i = 0; i < parts.length; i += 2 ) {
103 var cls = parts[i]; /* class name (id) */
104 var col = parts[i+1]; /* column name */
106 /* a "node" is a class description from the IDL, it
107 contains relevant info, plus a list of "fields",
109 var node = oilsIDL[cls];
110 var pkey = oilsRptFindField(node, node.pkey);
112 /* a "field" is a parsed version of a column from the IDL,
113 contains datatype, column name, etc. */
114 var field = oilsRptFindField(node, col);
116 /* re-construct the path as we go so
117 we know what all we've seen thus far */
118 newpath = (newpath) ? newpath + '-'+ cls : cls;
120 /* extract relevant info */
121 tobj.table = node.table;
122 tobj.alias = newpath;
123 _debug('field type is ' + field.type);
124 if( i == (parts.length - 2) ) break;
126 /* we still have columns left in the path, keep adding join's */
128 if(field.reltype != 'has_a')
129 col = pkey.name + '-' + col;
136 if( field.type == 'link' )
137 tobj.key = field.key;
139 newpath = newpath + '-'+ path_col;
142 _debug("built 'from' clause: path="+path+"\n"+formatJSON(js2JSON(obj)));
147 /* removes a specific item from the display window */
148 function oilsDelDisplayItem(val) {
149 oilsDelSelectorItem(oilsRptDisplaySelector, val);
152 /* removes selected items from the display window */
153 function oilsDelSelectedDisplayItems() {
154 var list = oilsDelSelectedItems(oilsRptDisplaySelector);
156 /* remove the de-selected columns from the report output */
157 oilsRpt.def.select = grep( oilsRpt.def.select,
159 for( var j = 0; j < list.length; j++ ) {
163 if( oilsRptPathRel(d) == i.relation && oilsRptPathCol(d) == col.colname ) {
164 //var param = (i.alias) ? i.alias.match(/::PARAM\d*/) : null;
165 // if( param ) delete oilsRpt.params[param];
173 if(!oilsRpt.def.select) {
174 oilsRpt.def.select = [];
175 //oilsReportBuilderReset();
178 for( var j = 0; j < list.length; j++ )
179 /* if there are no items left in the "select", "where", or "having" clauses
180 for the given relation, trim this relation from the "from" clause */
181 if( !grep(oilsRpt.def.select,
182 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
183 && !grep(oilsRpt.def.where,
184 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
185 && !grep(oilsRpt.def.having,
186 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
187 ) oilsRptPruneFromClause(oilsRptPathRel(list[j]));
194 /* for each item in the path list, remove the associated data
195 from the "from" clause */
197 function oilsRptPruneFromClause(relation, node) {
198 _debug("removing relation from 'from' clause " + relation);
199 if(!node) node = oilsRpt.def.from.join;
200 for( var i in node ) {
201 _debug("looking at node "+node[i].alias);
202 // first, descend into the tree, and prune leaves first
204 oilsRptPruneFromClause(relation, node[i].join);
205 if(node[i].join && oilsRptObjectKeys(node[i].join).length == 0)
208 /* if there are no items in the select, where or having clauses with a relation
209 matching this nodes alias, we can safely remove this node from the tree */
210 if( node[i].alias == relation ) {
211 if( !grep(oilsRpt.def.select,
212 function(i){ return (i.relation == node[i].alias)})
213 && !grep(oilsRpt.def.where,
214 function(i){ return (i.relation == node[i].alias)})
215 && !grep(oilsRpt.def.having,
216 function(i){ return (i.relation == node[i].alias)})
224 // now, if we're at the leaf to remove, remove it
225 if( node[i].alias == relation ) {
227 /* if we have subtrees, don't delete our tree node */
238 function oilsRptMkFilterTags(path, tform, filter) {
239 var name = oilsRptMakeLabel(path);
240 if(tform) name += ' ('+tform+')';
241 name += ' "' + filter + '"';
242 var epath = path + ':'+filter+':';
243 if(tform) epath += tform;
245 return [ name, epath ];
249 /* adds an item to the display window */
250 function oilsAddRptFilterItem(path, tform, filter) {
251 _debug("Adding filter item for "+path+" tform="+tform+" filter="+filter);
253 var name = oilsRptMkFilterTags(path, tform, filter);
257 if( ! oilsAddSelectorItem(oilsRptFilterSelector, epath, name) )
261 relation: oilsRptPathRel(path),
262 column: { transform: tform, colname: oilsRptPathCol(path) },
265 where.condition[filter] = oilsRptNextParam();
268 case 'substring' : where.column.params = oilsRptNextParam();
271 oilsRpt.def.where.push(where);
272 mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
276 /* removes a specific item from the display window */
277 //function oilsDelFilterItem(path) {
278 //oilsDelSelectorItem(oilsRptFilterSelector, path);
281 /* removes selected items from the display window */
282 function oilsDelSelectedFilterItems() {
284 /* the values in this list are formed: <path>:<operation>:<transform> */
285 var list = oilsDelSelectedItems(oilsRptFilterSelector);
289 for( var i = 0; i < list.length; i++ ) {
292 path: item.replace(/:.*/,''),
293 operation: item.replace(/.*:(.*):.*/,'$1'),
294 tform: item.replace(/.*?:.*?:(.*)/,'$1')
299 /* XXX refactor the below to take operation and transform into account
300 since the same path can be used multiple times as long as a different
301 filter and/or transform is used */
303 /* remove the de-selected columns from the report output */
304 oilsRpt.def.where = grep( oilsRpt.def.where,
306 for( var j = 0; j < flist.length; j++ ) {
309 var frel = oilsRptPathRel(fil.path);
310 var fcol = oilsRptPathCol(fil.path);
312 var op = oilsRptObjectKeys(i.condition)[0];
314 if( frel == i.relation &&
315 fcol == col.colname &&
316 fil.operation == op &&
317 fil.tform == col.transform ) {
318 /* we have found a where clause with the same
319 relation, column, operation and transform */
321 /* we aren't setting params on template build.. */
322 //var param = (i.column.params) ? i.columns.params.match(/::P\d*/) : null;
323 //if( param ) delete oilsRpt.params[param];
324 //param = (i.condition[op]) ? i.condition[op].match(/::P\d*/) : null;
325 //if( param ) delete oilsRpt.params[param];
334 if(!oilsRpt.def.where)
335 oilsRpt.def.where = [];
338 for( var j = 0; j < flist.length; j++ ) {
339 var path = flist[j].path;
340 var rel = oilsRptPathRel(path);
341 /* if there are no items left in the "select", "where", or "having" clauses
342 for the given relation, trim this relation from the "from" clause */
344 var func = function(i){ return (i.relation == rel); };
346 if( !grep(oilsRpt.def.select, func) &&
347 !grep(oilsRpt.def.where, func) &&
348 !grep(oilsRpt.def.having, func) ) {
350 _debug("pruning item with path "+ path + ' and relation '+ rel);
352 oilsRptPruneFromClause(oilsRptPathRel(path));
359 /* adds an item to the display window */
360 function oilsAddRptAggFilterItem(val) {
361 oilsAddSelectorItem(oilsRptAggFilterSelector, val);
364 /* removes a specific item from the display window */
365 function oilsDelAggFilterItem(val) {
366 oilsDelSelectorItem(oilsRptAggFilterSelector, val);
369 /* removes selected items from the display window */
370 function oilsDelSelectedAggFilterItems() {
371 var list = oilsDelSelectedItems(oilsRptAggFilterSelector);
373 /* remove the de-selected columns from the report output */
374 oilsRpt.def.having = grep( oilsRpt.def.having,
376 for( var j = 0; j < list.length; j++ ) {
380 /* if this columsn has a transform,
381 it will be an object { tform => column } */
382 if( typeof col != 'string' )
383 for( var c in col ) col = col[c];
385 /* if this transform requires params, the column
386 will be the first item in the param set array */
387 if( typeof col != 'string' ) col = col[0];
389 if( oilsRptPathRel(d) == i.relation && oilsRptPathCol(d) == col ) {
390 var param = (i.alias) ? i.alias.match(/::P\d*/) : null;
391 if( param ) delete oilsRpt.params[param];
399 if(!oilsRpt.def.having) {
400 oilsRpt.def.having = [];
401 oilsReportBuilderReset();
404 for( var j = 0; j < list.length; j++ )
405 /* if there are no items left in the "select", "where", or "having" clauses
406 for the given relation, trim this relation from the "from" clause */
407 if( !grep(oilsRpt.def.select,
408 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
409 && !grep(oilsRpt.def.where,
410 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
411 && !grep(oilsRpt.def.having,
412 function(i){ return (i.relation == oilsRptPathRel(list[j])); })
413 ) oilsRptPruneFromClause(oilsRptPathRel(list[j]));
420 /* adds an item to the display window */
421 function oilsAddSelectorItem(sel, val, name) {
422 name = (name) ? name : oilsRptMakeLabel(val);
423 _debug("adding selector item "+name+' = ' +val);
424 for( var i = 0; i < sel.options.length; i++ ) {
425 var opt = sel.options[i];
426 if( opt.value == val ) return false;
428 insertSelectorVal( sel, -1, name, val );
433 /* removes a specific item from the display window */
434 function oilsDelSelectorItem(sel, val) {
435 _debug("deleting selector item "+val);
436 var opts = sel.options;
437 for( var i = 0; i < opts.length; i++ ) {
439 if( opt.value == val ) {
440 if( i == opts.length - 1 )
442 else opts[i] = opts[i+1];
448 /* removes selected items from the display window */
449 function oilsDelSelectedItems(sel) {
450 var list = getSelectedList(sel);
451 for( var i = 0; i < list.length; i++ )
452 oilsDelSelectorItem(sel, list[i]);
457 /* hides the different field editor tabs */
458 function oilsRptHideEditorDivs() {
459 hideMe(DOM.oils_rpt_tform_div);
460 hideMe(DOM.oils_rpt_filter_div);
461 hideMe(DOM.oils_rpt_agg_filter_div);
466 This draws the 3-tabbed window containing the transform,
467 filter, and aggregate filter picker window
469 function oilsRptDrawDataWindow(path) {
470 var col = oilsRptPathCol(path);
471 var cls = oilsRptPathClass(path);
472 var field = oilsRptFindField(oilsIDL[cls], col);
474 appendClear(DOM.oils_rpt_editor_window_label, text(oilsRptMakeLabel(path)));
475 appendClear(DOM.oils_rpt_editor_window_datatype, text(field.datatype));
477 _debug("setting update data window for column "+col+' on class '+cls);
479 var div = DOM.oils_rpt_column_editor;
480 /* set a preliminary top position so the page won't bounce around */
481 div.setAttribute('style','top:'+oilsMouseX+'px');
483 /* unhide the div so we can determine the dimensions */
486 /* don't let them see the floating div until the position is fully determined */
487 div.style.visibility='hidden';
489 oilsRptDrawTransformWindow(path, col, cls, field);
490 oilsRptDrawFilterWindow(path, col, cls, field);
492 //oilsRptSetFilters(field.datatype);
494 //oilsRptDoFilterWidgets();
496 //DOM.oils_rpt_filter_tform_selector.onchange = oilsRptDoFilterWidgets;
498 buildFloatingDiv(div, 600);
500 /* now let them see it */
501 div.style.visibility='visible';
503 oilsRptSetDataWindowActions(div);
507 function oilsRptSetDataWindowActions(div) {
508 /* give the tab links behavior */
509 DOM.oils_rpt_tform_tab.onclick =
510 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_tform_div)};
511 DOM.oils_rpt_filter_tab.onclick =
512 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_filter_div)};
513 DOM.oils_rpt_agg_filter_tab.onclick =
514 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_agg_filter_div)};
516 DOM.oils_rpt_tform_tab.onclick();
517 DOM.oils_rpt_column_editor_close_button.onclick = function(){hideMe(div);};
521 function oilsRptDrawFilterWindow(path, col, cls, field) {
523 var fsel = $n(DOM.oils_rpt_filter_op_table,'selector');
524 for( var i = 0; i < fsel.options.length; i++ ){
525 var opt = fsel.options[i];
526 var dt = opt.getAttribute('datatype');
529 /* add a special case for boolean objects, since the only
530 operation that makes sense is "=" */
531 if( field.datatype == 'bool' ) {
533 if( opt.getAttribute('value') == '=' )
537 if( dt && dt != field.datatype )
544 DOM.oils_rpt_filter_submit.onclick = function() {
545 var tsel = $n(DOM.oils_rpt_filter_tform_table,'selector');
546 var tform = getSelectorVal(tsel);
547 var filter = getSelectorVal(fsel);
548 oilsAddRptFilterItem(path, tform, filter);
550 oilsRptShowFilters($n(DOM.oils_rpt_filter_tform_table,'selector'), field.datatype, false, true);
553 oilsRptCurrentFilterTform = new oilsRptTFormManager(DOM.oils_rpt_filter_tform_table);
554 oilsRptCurrentFilterTform.build(field.datatype, false, true);
555 oilsRptCurrentFilterOpManager = new oilsRptOpManager(DOM.oils_rpt_filter_op_table);
559 function oilsRptShowFilters( selector, dtype, show_agg, show_noagg ) {
560 for( var i = 0; i < selector.options.length; i++ ) {
561 var opt = selector.options[i];
562 var t = opt.getAttribute('datatype');
563 if( t && t != dtype ){
566 var ag = opt.getAttribute('aggregate');
569 else if( ag && ! show_agg )
571 else if( !ag && show_noagg )
579 /* draws the transform window */
580 function oilsRptDrawTransformWindow(path, col, cls, field) {
581 DOM.oils_rpt_tform_label_input.value = oilsRptMakeLabel(path);
582 var dtype = field.datatype;
584 DOM.oils_rpt_tform_submit.onclick =
586 var sel = $n(DOM.oils_rpt_tform_table,'selector');
587 var tform = getSelectorVal(sel);
588 oilsAddRptDisplayItem(path, DOM.oils_rpt_tform_label_input.value, tform )
592 DOM.oils_rpt_tform_label_input.focus();
593 DOM.oils_rpt_tform_label_input.select();
596 oilsRptCurrentTform = new oilsRptTFormManager(DOM.oils_rpt_tform_table);
597 oilsRptCurrentTform.build(dtype, true, true);
600 _debug($n(DOM.oils_rpt_tform_table,'selector'));
602 oilsRptShowFilters($n(DOM.oils_rpt_tform_table,'selector'), dtype, true, true);
605 oilsRptHideTformFields();
606 oilsRptUnHideTformFields(dtype);
609 _debug("Building transform window for datatype "+dtype);
612 unHideMe($('oils_rpt_tform_'+dtype+'_div'));
613 $('oils_rpt_tform_all_raw').checked = true;
618 function oilsRptHideTformFields() {
619 var rows = DOM.oils_rpt_tform_tbody.childNodes;
620 for( var i = 0; i < rows.length; i++ )
621 if( rows[i] && rows[i].nodeType == 1 )
625 function oilsRptUnHideTformFields(dtype) {
626 var rows = DOM.oils_rpt_tform_tbody.childNodes;
627 for( var i = 0; i < rows.length; i++ ) {
629 if( row && row.nodeType == 1 &&
630 (row.getAttribute('datatype')=='all'
631 || row.getAttribute('datatype') == dtype)) {
638 function oilsRptGetTform(datatype) {
639 for( var i in oilsRptTransforms[datatype] )
640 if( $('oils_rpt_tform_'+datatype+'_'+oilsRptTransforms[datatype][i]).checked )
641 return oilsRptTransforms[datatype][i];
642 for( var i in oilsRptTransforms.all )
643 if( $('oils_rpt_tform_all_'+oilsRptTransforms.all[i]).checked )
644 return oilsRptTransforms.all[i];
651 function getRptTformParams(type, tform) {
657 DOM.oils_rpt_tform_string_substring_offset.value,
658 DOM.oils_rpt_tform_string_substring_length.value];
665 /* given a transform selector, this displays the appropriate
666 transforms for the given datatype.
667 if aggregate is true, is displays the aggregate transforms */
669 function oilsRptSetTransforms(sel, dtype, show_agg, show_noagg) {
670 for( var i = 0; i < sel.options.length; i++ ) {
671 var opt = sel.options[i];
672 var t = opt.getAttribute('datatype');
673 if( t && t != dtype ){
676 var ag = opt.getAttribute('aggregate');
679 else if( ag && ! show_agg )
681 else if( !ag && show_noagg )
691 /* displays the correct filter-transforms for the given datatype */
693 function oilsRptSetFilters(dtype) {
695 DOM.oils_rpt_filter_submit.onclick = function() {
696 var data = oilsRptDoFilterWidgets();
697 alert(js2JSON(data));
700 var sel = DOM.oils_rpt_filter_tform_selector;
701 for( var i = 0; i < sel.options.length; i++ ) {
702 var opt = sel.options[i];
703 _debug(opt.getAttribute('op'));
704 var t = opt.getAttribute('datatype');
705 if( t && t != dtype ) hideMe(opt);
711 /* hides all of the filter widgets */
712 function oilsRptHideFilterWidgets(node) {
714 node = DOM.oils_rpt_filter_tform_widget_td;
715 if( node.nodeType != 1 ) return;
716 if( node.getAttribute('widget') ) {
719 var cs = node.childNodes;
720 for( var i = 0; cs && i < cs.length; i++ )
721 oilsRptHideFilterWidgets(cs[i]);
725 /* what does this need to do? */
726 function oilsRptSetFilterOpActions() {
731 /* hides/unhides the appropriate widgets and returns the parameter
732 array appropriate for the selected widget */
733 function oilsRptDoFilterWidgets() {
734 filter = getSelectorVal(DOM.oils_rpt_filter_tform_selector);
735 oilsRptHideFilterWidgets();
742 /* generic transforms */
744 if(!op) op = 'equals';
748 if(!op) op = 'ilike';
760 if(!op) op = 'not in';
762 if(!op) op = 'between';
764 if(!op) op = 'not between';
765 unHideMe(DOM.oils_rpt_filter_tform_input);
766 params = [DOM.oils_rpt_filter_tform_input.value];
769 /* timestamp transforms */
771 if(!op) op = 'between';
772 case 'date_not_between':
773 if(!op) op = 'not between';
776 unHideMe(DOM.oils_rpt_filter_tform_date_1);
777 unHideMe(DOM.oils_rpt_filter_tform_date_2);
778 unHideMe(DOM.oils_rpt_filter_tform_date_hint);
779 DOM.oils_rpt_filter_tform_date_1.value = mkYearMonDay();
780 DOM.oils_rpt_filter_tform_date_2.value = mkYearMonDay();
782 DOM.oils_rpt_filter_tform_date_1.value,
783 DOM.oils_rpt_filter_tform_date_2.value
789 if(!tform) tform = 'dow';
790 case 'dow_not_between':
791 if(!op) op = 'not between';
792 if(!tform) tform = 'dow';
797 if(!tform) tform = 'dom';
798 case 'dom_not_between':
799 if(!op) op = 'not between';
800 if(!tform) tform = 'dom';
803 case 'month_between':
805 if(!tform) tform = 'moy';
806 case 'month_not_between':
807 if(!op) op = 'not between';
808 if(!tform) tform = 'moy';
811 case 'quarter_between':
813 if(!tform) tform = 'qoy';
814 case 'quarter_not_between':
815 if(!op) op = 'not between';
816 if(!tform) tform = 'qoy';
820 if(!op) op = 'between';
821 if(!tform) tform = 'year_trunc';
822 case 'year_not_between':
823 if(!op) op = 'not between';
824 if(!tform) tform = 'year_trunc';
828 if(!op) op = 'between';
829 if(!tform) tform = 'age';
830 case 'age_not_between':
831 if(!op) op = 'not between';
832 if(!tform) tform = 'age';
835 /* string transforms */
837 if(!tform) tform = 'substring';
842 if(!tform) tform = 'dow';
846 if(!tform) tform = 'dow';
848 /* numeric transforms */
851 if(!tform) tform = 'dow';
855 if(!tform) tform = 'dow';
858 return { op : op, params : params, tform : tform };