1 /** initializes reports, some basid display settings,
2 * grabs and builds the IDL tree
5 var __dblclicks = {}; /* retain a cache of the selector value doubleclick event handlers */
7 function oilsInitReportBuilder() {
8 if(!oilsInitReports()) return false;
9 oilsReportBuilderReset();
10 DOM.oils_rpt_table.onclick =
11 function(){hideMe(DOM.oils_rpt_column_editor)};
14 hideMe(DOM.oils_rpt_tree_loading);
15 unHideMe(DOM.oils_rpt_table);
16 oilsRptBuilderDrawClone(new CGI().param('ct'));
20 DOM.oils_rpt_builder_save_template.onclick = oilsReportBuilderSave;
23 function oilsRptBuilderDrawClone(templateId) {
24 if(!templateId) return;
25 unHideMe(DOM.oils_rpt_builder_cloning);
27 oilsRptFetchTemplate(templateId,
28 function(template) { oilsRptBuilderDrawClone2(template);}
33 function oilsRptBuilderDrawClone2(template) {
34 appendClear( DOM.oils_rpt_build_cloning_name, template.name() );
35 DOM.oils_rpt_builder_new_name.value = template.name();
36 DOM.oils_rpt_builder_new_desc.value = template.description();
38 _debug(formatJSON(template.data()));
40 /* manually shove data into the display selectors */
41 var def = JSON2js(template.data());
43 var table = def.from.table;
45 for( var i in oilsIDL ) {
47 if( node.table == table ) {
48 setSelector(DOM.oils_rpt_builder_type_selector, node.name);
49 DOM.oils_rpt_builder_type_selector.onchange();
56 oilsAddRptDisplayItem(item.path, item.alias, item.column.transform)});
60 oilsAddRptFilterItem(item.path, item.column.transform, oilsRptObjectKeys(item.condition)[0])});
64 oilsAddRptHavingItem(item.path, item.column.transform, oilsRptObjectKeys(item.condition)[0])});
66 oilsRpt.setTemplate(template);
67 oilsRpt.templateObject = null; /* simplify debugging */
70 function oilsReportBuilderReset() {
71 var n = (oilsRpt) ? oilsRpt.name : "";
72 oilsRpt = new oilsReport();
74 oilsRptDisplaySelector = DOM.oils_rpt_display_selector;
75 oilsRptFilterSelector = DOM.oils_rpt_filter_selector;
76 oilsRptHavingSelector = DOM.oils_rpt_agg_filter_selector;
77 removeChildren(oilsRptDisplaySelector);
78 removeChildren(oilsRptFilterSelector);
79 removeChildren(oilsRptHavingSelector);
80 //removeChildren(oilsRptOrderBySelector);
84 function oilsReportBuilderSave() {
87 tmpl.name(DOM.oils_rpt_builder_new_name.value);
88 tmpl.description(DOM.oils_rpt_builder_new_desc.value);
89 tmpl.owner(USER.id());
90 tmpl.folder(new CGI().param('folder'));
91 tmpl.data(js2JSON(oilsRpt.def));
93 if(!confirm('Name : '+tmpl.name() + '\nDescription: ' + tmpl.description()+'\nSave Template?'))
99 var req = new Request(OILS_RPT_CREATE_TEMPLATE, SESSION, tmpl);
100 req.request.alertEvent = false;
103 var res = r.getResultObject();
104 if(checkILSEvent(res)) {
107 if( res && res != '0' ) {
108 oilsRptAlertSuccess();
109 _l('oils_rpt.xhtml');
120 /* adds an item to the display window */
121 function oilsAddRptDisplayItem(path, name, tform, params) {
123 if( ! oilsAddSelectorItem(
124 { selector : oilsRptDisplaySelector,
129 transform : tform }) ) {
133 /* add the selected columns to the report output */
134 name = (name) ? name : oilsRptPathCol(path);
135 if( !tform ) tform = 'Bare';
137 var aggregate = oilsRptGetIsAgg(tform);
139 /* add this item to the select blob */
141 relation: hex_md5(oilsRptPathRel(path)),
144 column: { transform: tform, colname: oilsRptPathCol(path) }
147 if( params ) sel.column.params = params;
148 oilsRptAddSelectList(sel, tform);
149 mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
153 function oilsRptAddSelectList(obj, tform) {
154 if(!oilsRptGetIsAgg(tform)) {
157 for( var i = 0; i < oilsRpt.def.select.length; i++ ) {
158 var item = oilsRpt.def.select[i];
160 /* shove the item in question in front of the first agg tform */
161 if( !added && oilsRptGetIsAgg( item.column.transform ) ) {
168 /* if there is no existing agg tfrom to
169 insert in front of, add me on the end */
170 if(!added) select.push(obj);
172 oilsRpt.def.select = select;
175 /* re-draw the select display to get the order correct */
176 var sel = oilsRptDisplaySelector;
177 while( sel.options.length > 0 ) sel.options[0] = null;
178 iterate(oilsRpt.def.select,
180 _debug('re-inserting display item ' + item.path);
182 { selector: oilsRptDisplaySelector,
186 transform : item.column.transform,
193 /* shove agg transforms onto the end */
194 oilsRpt.def.select.push(obj);
200 function oilsRptGetIsAgg(tform) {
201 return OILS_RPT_TRANSFORMS[tform].aggregate;
204 /* takes a column path and builds a from-clause object for the path */
205 function oilsRptBuildFromClause(path) {
207 /* the path is the full path (relation) from the source
208 object to the column in question (e.g. au-home_ou-aou-name)*/
209 var parts = path.split(/-/);
211 /* the final from clause */
214 /* reference to the current position in the from clause */
219 /* walk the path, fleshing the from clause as we go */
220 for( var i = 0; i < parts.length; i += 2 ) {
222 var cls = parts[i]; /* class name (id) */
223 var col = parts[i+1]; /* column name */
225 /* a "node" is a class description from the IDL, it
226 contains relevant info, plus a list of "fields",
228 var node = oilsIDL[cls];
229 var pkey = oilsRptFindField(node, node.pkey);
231 /* a "field" is a parsed version of a column from the IDL,
232 contains datatype, column name, etc. */
233 var field = oilsRptFindField(node, col);
235 /* re-construct the path as we go so
236 we know what all we've seen thus far */
237 newpath = (newpath) ? newpath + '-'+ cls : cls;
239 /* extract relevant info */
240 tobj.table = node.table;
242 tobj.alias = hex_md5(newpath);
244 _debug('field type is ' + field.type);
245 if( i == (parts.length - 2) ) break;
247 /* we still have columns left in the path, keep adding join's */
249 if(field.reltype != 'has_a')
250 col = pkey.name + '-' + col;
257 if( field.type == 'link' ) {
258 tobj.key = field.key;
259 if( field.reltype == 'has_many' || field.reltype == 'might_have' )
263 newpath = newpath + '-'+ path_col;
266 _debug("built 'from' clause: path="+path+"\n"+formatJSON(js2JSON(obj)));
270 function oilsMoveUpDisplayItems() {
271 var sel = oilsRptDisplaySelector;
272 var idx = sel.selectedIndex;
273 if( idx == 0 ) return;
274 var opt = sel.options[idx];
275 sel.options[idx] = null;
278 var val = opt.getAttribute('value');
279 var label = opt.getAttribute('label');
280 var path = opt.getAttribute('path');
281 var evt_id = opt.getAttribute('listener');
283 opt = insertSelectorVal(sel, idx, label, val);
285 opt.setAttribute('path', path);
286 opt.setAttribute('title', label);
287 opt.setAttribute('label', label);
288 opt.setAttribute('value', val);
289 opt.setAttribute('listener', evt_id);
291 /* re-attach the double-click event */
292 opt.addEventListener('dblclick', __dblclicks[evt_id], true );
294 sel.options[idx].selected = true;
296 var arr = oilsRpt.def.select;
297 for( var i = 0; i < arr.length; i++ ) {
298 if( arr[i].path == val ) {
299 var other = arr[i-1];
308 function oilsMoveDownDisplayItems() {
309 var sel = oilsRptDisplaySelector;
310 var idx = sel.selectedIndex;
311 if( idx == sel.options.length - 1 ) return;
312 var opt = sel.options[idx];
313 sel.options[idx] = null;
316 //var val = opt.getAttribute('value');
317 //insertSelectorVal(sel, idx, opt.innerHTML, val);
318 //insertSelectorVal(sel, idx, opt.getAttribute('label'), val);
320 var val = opt.getAttribute('value');
321 var label = opt.getAttribute('label');
322 var path = opt.getAttribute('path');
323 var evt_id = opt.getAttribute('listener');
325 opt = insertSelectorVal(sel, idx, label, val);
327 opt.setAttribute('value', val);
328 opt.setAttribute('path', path);
329 opt.setAttribute('title', label);
330 opt.setAttribute('label', label);
331 opt.setAttribute('listener', evt_id);
333 /* re-attach the double-click event */
334 opt.addEventListener('dblclick', __dblclicks[evt_id], true );
336 sel.options[idx].selected = true;
338 var arr = oilsRpt.def.select;
339 for( var i = 0; i < arr.length; i++ ) {
340 if( arr[i].path == val ) {
341 var other = arr[i+1];
351 /* removes a specific item from the display window */
353 function oilsDelDisplayItem(val) {
354 oilsDelSelectorItem(oilsRptDisplaySelector, val);
358 /* removes selected items from the display window */
359 function oilsDelSelectedDisplayItems() {
360 var list = oilsDelSelectedItems(oilsRptDisplaySelector);
362 _debug('deleting list: ' + list);
364 /* remove the de-selected columns from the report output */
365 oilsRpt.def.select = grep( oilsRpt.def.select,
367 for( var j = 0; j < list.length; j++ ) {
368 var d = list[j]; /* path */
371 _debug('in delete, looking at list = '+d+' : col = ' +
372 col.colname + ' : relation = ' + i.relation + ' : encoded = ' + hex_md5(oilsRptPathRel(d)) );
374 if( hex_md5(oilsRptPathRel(d)) == i.relation && oilsRptPathCol(d) == col.colname ) {
382 if(!oilsRpt.def.select) oilsRpt.def.select = [];
383 oilsRptPruneFromList(list);
387 function oilsRptPruneFromList(pathlist) {
389 for( var j = 0; j < pathlist.length; j++ ) {
390 /* if there are no items left in the "select", "where", or "having" clauses
391 for the given relation, trim this relation from the "from" clause */
392 var path = pathlist[j];
393 var encrel = hex_md5(oilsRptPathRel(path));
395 debug('seeing if we can prune from clause with relation = ' + encrel +' : path = ' + path);
397 var func = function(i){ return (i.relation == hex_md5(oilsRptPathRel(path))); };
399 if( !grep(oilsRpt.def.select, func) &&
400 !grep(oilsRpt.def.where, func) &&
401 !grep(oilsRpt.def.having, func) ) {
403 debug('looks like we can prune ' + path);
405 oilsRptPruneFromClause(oilsRptPathRel(pathlist[j]));
411 /* for each item in the path list, remove the associated data
412 from the "from" clause */
414 function oilsRptPruneFromClause(relation, node) {
416 var keys = oilsRptObjectKeys(node);
417 _debug("trying to remove relation: " + relation+'\n\tthis object has keys: '+keys);
419 if(!node) node = oilsRpt.def.from.join;
420 if(!node) return false;
422 for( var i in node ) {
423 var child_node = node[i];
424 _debug("\tanalyzing child node: "+child_node.path);
426 // first, descend into the tree, and prune leaves
427 if( child_node.join ) {
429 oilsRptPruneFromClause(relation, child_node.join);
430 var join_keys = oilsRptObjectKeys(child_node.join);
431 _debug("\tchild has a sub-join for items : ["+ join_keys+"]");
433 if(join_keys.length == 0) {
434 _debug("\tdeleting join for object "+i);
435 delete child_node.join;
439 if( !child_node.join ) {
441 _debug("\tchild node has no sub-join, seeing if we should delete it");
443 var from_alias = child_node.alias;
444 var func = function(n){ return (n.relation == from_alias)};
446 if( !grep(oilsRpt.def.select, func) &&
447 !grep(oilsRpt.def.where, func) &&
448 !grep(oilsRpt.def.having, func) ) {
450 /* we are not used by any other clauses */
451 _debug("\tdeleting node with relation: "+ from_alias);
461 function oilsRptMkFilterTags(path, tform, filter) {
462 var name = oilsRptMakeLabel(path);
463 if(tform) name += ' ('+tform+')';
464 name += ' "' + filter + '"';
465 var epath = path + ':'+filter+':';
466 if(tform) epath += tform;
468 return [ name, epath ];
472 function oilsAddRptFilterItem(path, tform, filter) {
473 _debug("Adding filter item for "+path+" tform="+tform+" filter="+filter);
475 var name = oilsRptMkFilterTags(path, tform, filter);
479 if( ! oilsAddSelectorItem(
480 { selector : oilsRptFilterSelector,
491 relation: hex_md5(oilsRptPathRel(path)),
493 column: { transform: tform, colname: oilsRptPathCol(path) },
496 if( filter == 'is' || filter == 'is not' )
497 where.condition[filter] = null;
498 else where.condition[filter] = oilsRptNextParam();
501 case 'substring' : where.column.params = oilsRptNextParam();
504 oilsRpt.def.where.push(where);
505 mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
510 function oilsAddRptHavingItem(path, tform, filter) {
511 _debug("Adding filter item for "+path+" tform="+tform+" filter="+filter);
513 var name = oilsRptMkFilterTags(path, tform, filter);
517 if( ! oilsAddSelectorItem(
518 { selector: oilsRptHavingSelector,
524 type : 'agg_filter' /* XXX */
530 relation: hex_md5(oilsRptPathRel(path)),
532 column: { transform: tform, colname: oilsRptPathCol(path) },
535 if( filter == 'is' || filter == 'is not' )
536 having.condition[filter] = null;
537 else having.condition[filter] = oilsRptNextParam();
540 case 'substring' : having.column.params = oilsRptNextParam();
543 oilsRpt.def.having.push(having);
544 mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
550 function oilsDelSelectedFilterItems() {
551 _oilsDelSelectedFilterItems('where');
553 function oilsDelSelectedAggFilterItems() {
554 _oilsDelSelectedFilterItems('having');
557 function _oilsDelSelectedFilterItems(type) {
559 /* the values in this list are formed: <path>:<operation>:<transform> */
560 var list = oilsDelSelectedItems(oilsRptFilterSelector);
562 _debug("deleting filter items " + list);
564 for( var i = 0; i < list.length; i++ ) {
565 var enc_path = list[i];
566 var data = oilsRptParseFilterEncPath(enc_path);
568 _debug("trimming filter items with enc_path = " + enc_path);
570 _debug(data.operation);
574 _debug('---------------------');
576 oilsRpt.def[type] = grep(
579 return ! oilsRptFilterDataMatches(
580 f, data.path, data.operation, data.tform );
585 if(!oilsRpt.def[type]) oilsRpt.def[type] = [];
586 oilsRptPruneFromList(list);
590 function oilsRptParseFilterEncPath(item) {
592 path: item.replace(/:.*/,''),
593 operation: item.replace(/.*:(.*):.*/,'$1'),
594 tform: item.replace(/.*?:.*?:(.*)/,'$1')
599 function oilsRptFilterDataMatches(filter, path, operation, tform) {
600 var rel = hex_md5(oilsRptPathRel(path));
601 var col = oilsRptPathCol(path);
603 if( col == filter.column.colname &&
604 rel == filter.relation &&
605 tform == filter.column.transform &&
606 operation == oilsRptObjectKeys(filter.condition)[0] ) return true;
611 /* adds an item to the display window */
613 function oilsAddRptAggFilterItem(val) {
614 oilsAddSelectorItem({selector:oilsRptHavingFilterSelector, val:val, label:val, path:val});
618 /* removes a specific item from the display window */
620 function oilsDelAggFilterItem(val) {
621 oilsDelSelectorItem(oilsRptHavingFilterSelector, val);
626 /* adds an item to the display window */
627 //function oilsAddSelectorItem(sel, val, name, path) {
628 function oilsAddSelectorItem(args) {
630 var sel = args.selector;
631 var label = args.label;
632 var path = args.path;
635 label = (label) ? label : oilsRptMakeLabel(val);
638 for( i = 0; i < sel.options.length; i++ ) {
639 var opt = sel.options[i];
640 if( opt.value == val ) return false;
643 var opt = insertSelectorVal( sel, -1, label, val );
644 opt.setAttribute('title', label);
645 opt.setAttribute('path', path);
646 opt.setAttribute('label', label);
648 var evt_id = oilsNextNumericId();
649 opt.setAttribute('listener', evt_id);
652 delete args.selector;
653 var listener = function(){ oilsRptDrawDataWindow(path, args);};
654 opt.addEventListener('dblclick', listener, true );
655 __dblclicks[evt_id] = listener;
656 //function(){ oilsRptDrawDataWindow(path, args);} , true);
662 /* removes a specific item from the display window */
663 function oilsDelSelectorItem(sel, val) {
664 var opts = sel.options;
665 for( var i = 0; i < opts.length; i++ ) {
667 if( opt.value == val ) {
668 if( i == opts.length - 1 )
670 else opts[i] = opts[i+1];
676 /* removes selected items from the display window */
677 function oilsDelSelectedItems(sel) {
678 var list = getSelectedList(sel);
679 for( var i = 0; i < list.length; i++ )
680 oilsDelSelectorItem(sel, list[i]);
685 /* hides the different field editor tabs */
686 function oilsRptHideEditorDivs() {
687 hideMe(DOM.oils_rpt_tform_div);
688 hideMe(DOM.oils_rpt_filter_div);
689 hideMe(DOM.oils_rpt_agg_filter_div);
690 hideMe(DOM.oils_rpt_order_by_div);
692 removeCSSClass(DOM.oils_rpt_tform_tab.parentNode, 'oils_rpt_tab_picker_selected');
693 removeCSSClass(DOM.oils_rpt_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
694 removeCSSClass(DOM.oils_rpt_agg_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
699 This draws the 3-tabbed window containing the transform,
700 filter, and aggregate filter picker window
702 function oilsRptDrawDataWindow(path, args) {
704 args = (args) ? args : {};
707 _debug("oilsRptDrawDataWindow(): args -> " + x + " = " + args[x]);
709 var col = oilsRptPathCol(path);
710 var cls = oilsRptPathClass(path);
711 var field = oilsRptFindField(oilsIDL[cls], col);
713 appendClear(DOM.oils_rpt_editor_window_label, text(oilsRptMakeLabel(path)));
714 appendClear(DOM.oils_rpt_editor_window_datatype, text(field.datatype));
716 _debug("setting update data window for column "+col+' on class '+cls);
718 var div = DOM.oils_rpt_column_editor;
719 /* set a preliminary top position so the page won't bounce around */
723 //div.setAttribute('style','top:'+oilsMouseX+'px');
725 /* unhide the div so we can determine the dimensions */
728 /* don't let them see the floating div until the position is fully determined */
729 div.style.visibility='hidden';
731 oilsRptDrawTransformWindow(path, col, cls, field, args);
732 oilsRptDrawFilterWindow(path, col, cls, field, args);
733 oilsRptDrawHavingWindow(path, col, cls, field, args);
734 //oilsRptDrawOrderByWindow(path, col, cls, field);
736 //buildFloatingDiv(div, 600);
738 //window.scrollTo(0,0);
739 window.scrollTo(0, 60);
741 /* now let them see it */
742 div.style.visibility='visible';
743 //args.type = (args.type) ? args.type : 'display';
744 oilsRptSetDataWindowActions(div, args);
748 function oilsRptSetDataWindowActions(div, args) {
749 /* give the tab links behavior */
751 DOM.oils_rpt_tform_tab.onclick =
753 oilsRptHideEditorDivs();
754 unHideMe(DOM.oils_rpt_tform_div)
755 addCSSClass(DOM.oils_rpt_tform_tab.parentNode, 'oils_rpt_tab_picker_selected');
758 DOM.oils_rpt_filter_tab.onclick =
760 oilsRptHideEditorDivs();
761 unHideMe(DOM.oils_rpt_filter_div)
762 addCSSClass(DOM.oils_rpt_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
765 DOM.oils_rpt_agg_filter_tab.onclick =
767 oilsRptHideEditorDivs();
768 unHideMe(DOM.oils_rpt_agg_filter_div)
769 addCSSClass(DOM.oils_rpt_agg_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
773 DOM.oils_rpt_order_by_tab.onclick =
775 oilsRptHideEditorDivs();
776 oilsRptDrawOrderByWindow();
777 unHideMe(DOM.oils_rpt_order_by_div);
781 DOM.oils_rpt_tform_submit.disabled = false;
782 DOM.oils_rpt_filter_submit.disabled = false;
783 DOM.oils_rpt_agg_filter_submit.disabled = false;
786 DOM.oils_rpt_tform_tab.onclick();
788 /* disable editing on existing items for now */
789 if( args.type == 'display' ) {
790 DOM.oils_rpt_tform_tab.onclick();
791 DOM.oils_rpt_tform_submit.disabled = true;
793 if( args.type == 'filter' ) {
794 DOM.oils_rpt_filter_tab.onclick();
795 DOM.oils_rpt_filter_submit.disabled = true;
797 if( args.type == 'agg_filter' ) {
798 DOM.oils_rpt_agg_filter_tab.onclick();
799 DOM.oils_rpt_agg_filter_submit.disabled = true;
803 DOM.oils_rpt_column_editor_close_button.onclick = function(){hideMe(div);};
807 function oilsRptDrawFilterWindow(path, col, cls, field, args) {
809 var tformPicker = new oilsRptTformPicker( {
810 node : DOM.oils_rpt_filter_tform_table,
811 datatype : field.datatype,
812 non_aggregate : true,
813 select : args.transform
817 var filterPicker = new oilsRptFilterPicker({
818 node : DOM.oils_rpt_filter_op_table,
819 datatype : field.datatype,
820 select : args.operation
824 DOM.oils_rpt_filter_submit.onclick = function() {
825 oilsAddRptFilterItem(
826 path, tformPicker.getSelected(), filterPicker.getSelected());
831 function oilsRptDrawHavingWindow(path, col, cls, field, args) {
832 var tformPicker = new oilsRptTformPicker( {
833 node : DOM.oils_rpt_agg_filter_tform_table,
834 datatype : field.datatype,
836 select : args.transform
840 var filterPicker = new oilsRptFilterPicker({
841 node : DOM.oils_rpt_agg_filter_op_table,
842 datatype : field.datatype,
843 select : args.operation
847 DOM.oils_rpt_agg_filter_submit.onclick = function() {
848 oilsAddRptHavingItem(
849 path, tformPicker.getSelected(), filterPicker.getSelected());
853 /* draws the transform window */
854 function oilsRptDrawTransformWindow(path, col, cls, field, args) {
855 args = (args) ? args : {};
857 DOM.oils_rpt_tform_label_input.value =
858 (args.label) ? args.label : oilsRptMakeLabel(path);
860 var dtype = field.datatype;
862 var tformPicker = new oilsRptTformPicker( {
863 node : DOM.oils_rpt_tform_table,
864 datatype : field.datatype,
865 non_aggregate : true,
867 select : args.transform
871 DOM.oils_rpt_tform_submit.onclick =
873 oilsAddRptDisplayItem(path,
874 DOM.oils_rpt_tform_label_input.value, tformPicker.getSelected() );
877 DOM.oils_rpt_tform_label_input.focus();
878 DOM.oils_rpt_tform_label_input.select();
880 _debug("Building transform window for datatype "+dtype);
884 //function oilsRptDrawOrderByWindow(path, col, cls, field) {
885 function oilsRptDrawOrderByWindow() {
886 var sel = DOM.oils_rpt_order_by_selector;
888 DOM.oils_rpt_order_by_submit.onclick = function() {
889 oilsRptAddOrderBy(getSelectorVal(sel));
892 var cols = oilsRpt.def.select;
893 for( var i = 0; i < cols.length; i++ ) {
895 insertSelectorVal(sel, -1, obj.alias, obj.path);
899 function oilsRptAddOrderBy(path) {
900 var rel = hex_md5(oilsRptPathRel(path));
901 var order_by = oilsRpt.def.order_by;
903 /* if this item is already in the order by remove it and overwrite it */
904 order_by = grep(oilsRpt.def.order_by,
905 function(i) {return (i.path != path)});
907 if(!order_by) order_by = [];
909 /* find the column definition in the select blob */
910 var obj = grep(oilsRpt.def.select,
911 function(i) {return (i.path == path)});
917 relation : obj.relation,
919 direction : getSelectorVal(DOM.oils_rpt_order_by_dir)
922 oilsRpt.def.order_by = order_by;