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 /* --------------------------------------------------------------- */
44 /* hack to determine the higest existing param in the template */
45 matches = template.data().match(/::P\d/g);
47 for( var i = 0; i < matches.length; i++ ) {
48 var num = parseInt(matches[i].replace(/::P(\d)/,'$1'));
49 if( num > max ) max = num;
52 _debug("set next avail param to " + oilsRptID2);
53 //_debug('PARAM = ' + oilsRptNextParam());
56 /* --------------------------------------------------------------- */
58 var table = def.from.table;
60 for( var i in oilsIDL ) {
62 if( node.table == table ) {
63 setSelector(DOM.oils_rpt_builder_type_selector, node.name);
64 DOM.oils_rpt_builder_type_selector.onchange();
71 oilsAddRptDisplayItem(item.path, item.alias, item.column.transform)});
75 oilsAddRptFilterItem(item.path, item.column.transform, oilsRptObjectKeys(item.condition)[0])});
79 oilsAddRptHavingItem(item.path, item.column.transform, oilsRptObjectKeys(item.condition)[0])});
81 //oilsRpt.setTemplate(template); /* commented out with clone fix, *shouldn't* break anything */
82 oilsRpt.templateObject = null; /* simplify debugging */
85 function oilsReportBuilderReset() {
86 var n = (oilsRpt) ? oilsRpt.name : "";
87 oilsRpt = new oilsReport();
89 oilsRptDisplaySelector = DOM.oils_rpt_display_selector;
90 oilsRptFilterSelector = DOM.oils_rpt_filter_selector;
91 oilsRptHavingSelector = DOM.oils_rpt_agg_filter_selector;
92 removeChildren(oilsRptDisplaySelector);
93 removeChildren(oilsRptFilterSelector);
94 removeChildren(oilsRptHavingSelector);
95 //removeChildren(oilsRptOrderBySelector);
96 //oilsRptResetParams();
99 function oilsReportBuilderSave() {
102 tmpl.name(DOM.oils_rpt_builder_new_name.value);
103 tmpl.description(DOM.oils_rpt_builder_new_desc.value);
104 tmpl.owner(USER.id());
105 tmpl.folder(new CGI().param('folder'));
106 tmpl.data(js2JSON(oilsRpt.def));
108 if(!confirm('Name : '+tmpl.name() + '\nDescription: ' + tmpl.description()+'\nSave Template?'))
114 var req = new Request(OILS_RPT_CREATE_TEMPLATE, SESSION, tmpl);
115 req.request.alertEvent = false;
118 var res = r.getResultObject();
119 if(checkILSEvent(res)) {
122 if( res && res != '0' ) {
123 oilsRptAlertSuccess();
124 _l('oils_rpt.xhtml');
135 /* adds an item to the display window */
136 function oilsAddRptDisplayItem(path, name, tform, params) {
138 if( ! oilsAddSelectorItem(
139 { selector : oilsRptDisplaySelector,
144 transform : tform }) ) {
148 /* add the selected columns to the report output */
149 name = (name) ? name : oilsRptPathCol(path);
150 if( !tform ) tform = 'Bare';
152 var aggregate = oilsRptGetIsAgg(tform);
154 /* add this item to the select blob */
156 relation: hex_md5(oilsRptPathRel(path)),
159 column: { transform: tform, colname: oilsRptPathCol(path) }
162 if( params ) sel.column.params = params;
163 oilsRptAddSelectList(sel, tform);
164 mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
168 function oilsRptAddSelectList(obj, tform) {
169 if(!oilsRptGetIsAgg(tform)) {
172 for( var i = 0; i < oilsRpt.def.select.length; i++ ) {
173 var item = oilsRpt.def.select[i];
175 /* shove the item in question in front of the first agg tform */
176 if( !added && oilsRptGetIsAgg( item.column.transform ) ) {
183 /* if there is no existing agg tfrom to
184 insert in front of, add me on the end */
185 if(!added) select.push(obj);
187 oilsRpt.def.select = select;
190 /* re-draw the select display to get the order correct */
191 var sel = oilsRptDisplaySelector;
192 while( sel.options.length > 0 ) sel.options[0] = null;
193 iterate(oilsRpt.def.select,
195 _debug('re-inserting display item ' + item.path);
197 { selector: oilsRptDisplaySelector,
201 transform : item.column.transform,
208 /* shove agg transforms onto the end */
209 oilsRpt.def.select.push(obj);
215 function oilsRptGetIsAgg(tform) {
216 return OILS_RPT_TRANSFORMS[tform].aggregate;
219 /* takes a column path and builds a from-clause object for the path */
220 function oilsRptBuildFromClause(path) {
222 /* the path is the full path (relation) from the source
223 object to the column in question (e.g. au-home_ou-aou-name)*/
224 var parts = path.split(/-/);
226 /* the final from clause */
229 /* reference to the current position in the from clause */
234 var last_is_left = false; /* true if our parent join is a 'left' join */
236 /* walk the path, fleshing the from clause as we go */
237 for( var i = 0; i < parts.length; i += 2 ) {
239 var cls = parts[i]; /* class name (id) */
240 var col = parts[i+1]; /* column name */
242 /* a "node" is a class description from the IDL, it
243 contains relevant info, plus a list of "fields",
245 var node = oilsIDL[cls];
246 var pkey = oilsRptFindField(node, node.pkey);
248 /* a "field" is a parsed version of a column from the IDL,
249 contains datatype, column name, etc. */
250 var field = oilsRptFindField(node, col);
252 /* re-construct the path as we go so
253 we know what all we've seen thus far */
254 newpath = (newpath) ? newpath + '-'+ cls : cls;
256 /* extract relevant info */
257 tobj.table = node.table;
259 tobj.alias = hex_md5(newpath);
261 _debug('field type is ' + field.type);
262 if( i == (parts.length - 2) ) break;
264 /* we still have columns left in the path, keep adding join's */
266 if(field.reltype != 'has_a')
267 col = pkey.name + '-' + col;
274 if( field.type == 'link' ) {
275 tobj.key = field.key;
276 if( field.reltype == 'has_many' || field.reltype == 'might_have' || last_is_left ) {
280 last_is_left = false;
284 newpath = newpath + '-'+ path_col;
287 _debug("built 'from' clause: path="+path+"\n"+formatJSON(js2JSON(obj)));
291 function oilsMoveUpDisplayItems() {
292 var sel = oilsRptDisplaySelector;
293 var idx = sel.selectedIndex;
294 if( idx == 0 ) return;
295 var opt = sel.options[idx];
296 sel.options[idx] = null;
299 var val = opt.getAttribute('value');
300 var label = opt.getAttribute('label');
301 var path = opt.getAttribute('path');
302 var evt_id = opt.getAttribute('listener');
304 opt = insertSelectorVal(sel, idx, label, val);
306 opt.setAttribute('path', path);
307 opt.setAttribute('title', label);
308 opt.setAttribute('label', label);
309 opt.setAttribute('value', val);
310 opt.setAttribute('listener', evt_id);
312 /* re-attach the double-click event */
313 opt.addEventListener('dblclick', __dblclicks[evt_id], true );
315 sel.options[idx].selected = true;
317 var arr = oilsRpt.def.select;
318 for( var i = 0; i < arr.length; i++ ) {
319 if( arr[i].path == val ) {
320 var other = arr[i-1];
329 function oilsMoveDownDisplayItems() {
330 var sel = oilsRptDisplaySelector;
331 var idx = sel.selectedIndex;
332 if( idx == sel.options.length - 1 ) return;
333 var opt = sel.options[idx];
334 sel.options[idx] = null;
337 //var val = opt.getAttribute('value');
338 //insertSelectorVal(sel, idx, opt.innerHTML, val);
339 //insertSelectorVal(sel, idx, opt.getAttribute('label'), val);
341 var val = opt.getAttribute('value');
342 var label = opt.getAttribute('label');
343 var path = opt.getAttribute('path');
344 var evt_id = opt.getAttribute('listener');
346 opt = insertSelectorVal(sel, idx, label, val);
348 opt.setAttribute('value', val);
349 opt.setAttribute('path', path);
350 opt.setAttribute('title', label);
351 opt.setAttribute('label', label);
352 opt.setAttribute('listener', evt_id);
354 /* re-attach the double-click event */
355 opt.addEventListener('dblclick', __dblclicks[evt_id], true );
357 sel.options[idx].selected = true;
359 var arr = oilsRpt.def.select;
360 for( var i = 0; i < arr.length; i++ ) {
361 if( arr[i].path == val ) {
362 var other = arr[i+1];
372 /* removes a specific item from the display window */
374 function oilsDelDisplayItem(val) {
375 oilsDelSelectorItem(oilsRptDisplaySelector, val);
379 /* removes selected items from the display window */
380 function oilsDelSelectedDisplayItems() {
381 var list = oilsDelSelectedItems(oilsRptDisplaySelector);
383 _debug('deleting list: ' + list);
385 /* remove the de-selected columns from the report output */
386 oilsRpt.def.select = grep( oilsRpt.def.select,
388 for( var j = 0; j < list.length; j++ ) {
389 var d = list[j]; /* path */
392 _debug('in delete, looking at list = '+d+' : col = ' +
393 col.colname + ' : relation = ' + i.relation + ' : encoded = ' + hex_md5(oilsRptPathRel(d)) );
395 if( hex_md5(oilsRptPathRel(d)) == i.relation && oilsRptPathCol(d) == col.colname ) {
403 if(!oilsRpt.def.select) oilsRpt.def.select = [];
404 oilsRptPruneFromList(list);
408 function oilsRptPruneFromList(pathlist) {
410 for( var j = 0; j < pathlist.length; j++ ) {
411 /* if there are no items left in the "select", "where", or "having" clauses
412 for the given relation, trim this relation from the "from" clause */
413 var path = pathlist[j];
414 var encrel = hex_md5(oilsRptPathRel(path));
416 debug('seeing if we can prune from clause with relation = ' + encrel +' : path = ' + path);
418 var func = function(i){ return (i.relation == hex_md5(oilsRptPathRel(path))); };
420 if( !grep(oilsRpt.def.select, func) &&
421 !grep(oilsRpt.def.where, func) &&
422 !grep(oilsRpt.def.having, func) ) {
424 debug('looks like we can prune ' + path);
426 oilsRptPruneFromClause(oilsRptPathRel(pathlist[j]));
432 /* for each item in the path list, remove the associated data
433 from the "from" clause */
435 function oilsRptPruneFromClause(relation, node) {
437 var keys = oilsRptObjectKeys(node);
438 _debug("trying to remove relation: " + relation+'\n\tthis object has keys: '+keys);
440 if(!node) node = oilsRpt.def.from.join;
441 if(!node) return false;
443 for( var i in node ) {
444 var child_node = node[i];
445 _debug("\tanalyzing child node: "+child_node.path);
447 // first, descend into the tree, and prune leaves
448 if( child_node.join ) {
450 oilsRptPruneFromClause(relation, child_node.join);
451 var join_keys = oilsRptObjectKeys(child_node.join);
452 _debug("\tchild has a sub-join for items : ["+ join_keys+"]");
454 if(join_keys.length == 0) {
455 _debug("\tdeleting join for object "+i);
456 delete child_node.join;
460 if( !child_node.join ) {
462 _debug("\tchild node has no sub-join, seeing if we should delete it");
464 var from_alias = child_node.alias;
465 var func = function(n){ return (n.relation == from_alias)};
467 if( !grep(oilsRpt.def.select, func) &&
468 !grep(oilsRpt.def.where, func) &&
469 !grep(oilsRpt.def.having, func) ) {
471 /* we are not used by any other clauses */
472 _debug("\tdeleting node with relation: "+ from_alias);
482 function oilsRptMkFilterTags(path, tform, filter) {
483 var name = oilsRptMakeLabel(path);
484 if(tform) name += ' ('+tform+')';
485 name += ' "' + filter + '"';
486 var epath = path + ':'+filter+':';
487 if(tform) epath += tform;
489 return [ name, epath ];
493 function oilsAddRptFilterItem(path, tform, filter) {
494 _debug("Adding filter item for "+path+" tform="+tform+" filter="+filter);
496 var name = oilsRptMkFilterTags(path, tform, filter);
500 if( ! oilsAddSelectorItem(
501 { selector : oilsRptFilterSelector,
512 relation: hex_md5(oilsRptPathRel(path)),
514 column: { transform: tform, colname: oilsRptPathCol(path) },
518 //_debug('NEXT PARAM = ' + oilsRptID2);
519 //_debug('NEXT PARAM = ' + oilsRptNextParam());
521 if( filter == 'is' || filter == 'is not' )
522 where.condition[filter] = null;
523 else where.condition[filter] = oilsRptNextParam();
526 case 'substring' : where.column.params = oilsRptNextParam();
529 oilsRpt.def.where.push(where);
530 mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
535 function oilsAddRptHavingItem(path, tform, filter) {
536 _debug("Adding filter item for "+path+" tform="+tform+" filter="+filter);
538 var name = oilsRptMkFilterTags(path, tform, filter);
542 if( ! oilsAddSelectorItem(
543 { selector: oilsRptHavingSelector,
549 type : 'agg_filter' /* XXX */
555 relation: hex_md5(oilsRptPathRel(path)),
557 column: { transform: tform, colname: oilsRptPathCol(path) },
560 if( filter == 'is' || filter == 'is not' )
561 having.condition[filter] = null;
562 else having.condition[filter] = oilsRptNextParam();
565 case 'substring' : having.column.params = oilsRptNextParam();
568 oilsRpt.def.having.push(having);
569 mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
575 function oilsDelSelectedFilterItems() {
576 _oilsDelSelectedFilterItems('where');
578 function oilsDelSelectedAggFilterItems() {
579 _oilsDelSelectedFilterItems('having');
582 function _oilsDelSelectedFilterItems(type) {
584 /* the values in this list are formed: <path>:<operation>:<transform> */
586 if( type == 'where' )
587 list = oilsDelSelectedItems(oilsRptFilterSelector);
588 else if( type == 'having' )
589 list = oilsDelSelectedItems(oilsRptHavingSelector);
591 _debug("deleting filter items " + list);
593 for( var i = 0; i < list.length; i++ ) {
594 var enc_path = list[i];
595 var data = oilsRptParseFilterEncPath(enc_path);
597 _debug("trimming filter items with enc_path = " + enc_path);
599 _debug(data.operation);
603 _debug('---------------------');
605 oilsRpt.def[type] = grep(
608 return ! oilsRptFilterDataMatches(
609 f, data.path, data.operation, data.tform );
614 if(!oilsRpt.def[type]) oilsRpt.def[type] = [];
615 oilsRptPruneFromList(list);
619 function oilsRptParseFilterEncPath(item) {
621 path: item.replace(/:.*/,''),
622 operation: item.replace(/.*:(.*):.*/,'$1'),
623 tform: item.replace(/.*?:.*?:(.*)/,'$1')
628 function oilsRptFilterDataMatches(filter, path, operation, tform) {
629 var rel = hex_md5(oilsRptPathRel(path));
630 var col = oilsRptPathCol(path);
632 if( col == filter.column.colname &&
633 rel == filter.relation &&
634 tform == filter.column.transform &&
635 operation == oilsRptObjectKeys(filter.condition)[0] ) return true;
640 /* adds an item to the display window */
642 function oilsAddRptAggFilterItem(val) {
643 oilsAddSelectorItem({selector:oilsRptHavingFilterSelector, val:val, label:val, path:val});
647 /* removes a specific item from the display window */
649 function oilsDelAggFilterItem(val) {
650 oilsDelSelectorItem(oilsRptHavingFilterSelector, val);
655 /* adds an item to the display window */
656 //function oilsAddSelectorItem(sel, val, name, path) {
657 function oilsAddSelectorItem(args) {
659 var sel = args.selector;
660 var label = args.label;
661 var path = args.path;
664 label = (label) ? label : oilsRptMakeLabel(val);
667 for( i = 0; i < sel.options.length; i++ ) {
668 var opt = sel.options[i];
669 if( opt.value == val ) return false;
672 var opt = insertSelectorVal( sel, -1, label, val );
673 opt.setAttribute('title', label);
674 opt.setAttribute('path', path);
675 opt.setAttribute('label', label);
677 var evt_id = oilsNextNumericId();
678 opt.setAttribute('listener', evt_id);
681 delete args.selector;
682 var listener = function(){ oilsRptDrawDataWindow(path, args);};
683 opt.addEventListener('dblclick', listener, true );
684 __dblclicks[evt_id] = listener;
685 //function(){ oilsRptDrawDataWindow(path, args);} , true);
691 /* removes a specific item from the display window */
692 function oilsDelSelectorItem(sel, val) {
693 var opts = sel.options;
694 for( var i = 0; i < opts.length; i++ ) {
696 if( opt.value == val ) {
697 if( i == opts.length - 1 )
699 else opts[i] = opts[i+1];
705 /* removes selected items from the display window */
706 function oilsDelSelectedItems(sel) {
707 var list = getSelectedList(sel);
708 for( var i = 0; i < list.length; i++ )
709 oilsDelSelectorItem(sel, list[i]);
714 /* hides the different field editor tabs */
715 function oilsRptHideEditorDivs() {
716 hideMe(DOM.oils_rpt_tform_div);
717 hideMe(DOM.oils_rpt_filter_div);
718 hideMe(DOM.oils_rpt_agg_filter_div);
719 hideMe(DOM.oils_rpt_order_by_div);
721 removeCSSClass(DOM.oils_rpt_tform_tab.parentNode, 'oils_rpt_tab_picker_selected');
722 removeCSSClass(DOM.oils_rpt_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
723 removeCSSClass(DOM.oils_rpt_agg_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
728 This draws the 3-tabbed window containing the transform,
729 filter, and aggregate filter picker window
731 function oilsRptDrawDataWindow(path, args) {
733 args = (args) ? args : {};
736 _debug("oilsRptDrawDataWindow(): args -> " + x + " = " + args[x]);
738 var col = oilsRptPathCol(path);
739 var cls = oilsRptPathClass(path);
740 var field = oilsRptFindField(oilsIDL[cls], col);
742 appendClear(DOM.oils_rpt_editor_window_label, text(oilsRptMakeLabel(path)));
743 appendClear(DOM.oils_rpt_editor_window_datatype, text(field.datatype));
745 _debug("setting update data window for column "+col+' on class '+cls);
747 var div = DOM.oils_rpt_column_editor;
748 /* set a preliminary top position so the page won't bounce around */
752 //div.setAttribute('style','top:'+oilsMouseX+'px');
754 /* unhide the div so we can determine the dimensions */
757 /* don't let them see the floating div until the position is fully determined */
758 div.style.visibility='hidden';
760 oilsRptDrawTransformWindow(path, col, cls, field, args);
761 oilsRptDrawFilterWindow(path, col, cls, field, args);
762 oilsRptDrawHavingWindow(path, col, cls, field, args);
763 //oilsRptDrawOrderByWindow(path, col, cls, field);
765 //buildFloatingDiv(div, 600);
767 //window.scrollTo(0,0);
768 window.scrollTo(0, 60);
770 /* now let them see it */
771 div.style.visibility='visible';
772 //args.type = (args.type) ? args.type : 'display';
773 oilsRptSetDataWindowActions(div, args);
777 function oilsRptSetDataWindowActions(div, args) {
778 /* give the tab links behavior */
780 DOM.oils_rpt_tform_tab.onclick =
782 oilsRptHideEditorDivs();
783 unHideMe(DOM.oils_rpt_tform_div)
784 addCSSClass(DOM.oils_rpt_tform_tab.parentNode, 'oils_rpt_tab_picker_selected');
787 DOM.oils_rpt_filter_tab.onclick =
789 oilsRptHideEditorDivs();
790 unHideMe(DOM.oils_rpt_filter_div)
791 addCSSClass(DOM.oils_rpt_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
794 DOM.oils_rpt_agg_filter_tab.onclick =
796 oilsRptHideEditorDivs();
797 unHideMe(DOM.oils_rpt_agg_filter_div)
798 addCSSClass(DOM.oils_rpt_agg_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
802 DOM.oils_rpt_order_by_tab.onclick =
804 oilsRptHideEditorDivs();
805 oilsRptDrawOrderByWindow();
806 unHideMe(DOM.oils_rpt_order_by_div);
810 DOM.oils_rpt_tform_submit.disabled = false;
811 DOM.oils_rpt_filter_submit.disabled = false;
812 DOM.oils_rpt_agg_filter_submit.disabled = false;
815 DOM.oils_rpt_tform_tab.onclick();
817 /* disable editing on existing items for now */
818 if( args.type == 'display' ) {
819 DOM.oils_rpt_tform_tab.onclick();
820 DOM.oils_rpt_tform_submit.disabled = true;
822 if( args.type == 'filter' ) {
823 DOM.oils_rpt_filter_tab.onclick();
824 DOM.oils_rpt_filter_submit.disabled = true;
826 if( args.type == 'agg_filter' ) {
827 DOM.oils_rpt_agg_filter_tab.onclick();
828 DOM.oils_rpt_agg_filter_submit.disabled = true;
832 DOM.oils_rpt_column_editor_close_button.onclick = function(){hideMe(div);};
836 function oilsRptDrawFilterWindow(path, col, cls, field, args) {
838 var tformPicker = new oilsRptTformPicker( {
839 node : DOM.oils_rpt_filter_tform_table,
840 datatype : field.datatype,
841 non_aggregate : true,
842 select : args.transform
846 var filterPicker = new oilsRptFilterPicker({
847 node : DOM.oils_rpt_filter_op_table,
848 datatype : field.datatype,
849 select : args.operation
853 DOM.oils_rpt_filter_submit.onclick = function() {
854 oilsAddRptFilterItem(
855 path, tformPicker.getSelected(), filterPicker.getSelected());
860 function oilsRptDrawHavingWindow(path, col, cls, field, args) {
861 var tformPicker = new oilsRptTformPicker( {
862 node : DOM.oils_rpt_agg_filter_tform_table,
863 datatype : field.datatype,
865 select : args.transform
869 var filterPicker = new oilsRptFilterPicker({
870 node : DOM.oils_rpt_agg_filter_op_table,
871 datatype : field.datatype,
872 select : args.operation
876 DOM.oils_rpt_agg_filter_submit.onclick = function() {
877 oilsAddRptHavingItem(
878 path, tformPicker.getSelected(), filterPicker.getSelected());
882 /* draws the transform window */
883 function oilsRptDrawTransformWindow(path, col, cls, field, args) {
884 args = (args) ? args : {};
886 DOM.oils_rpt_tform_label_input.value =
887 (args.label) ? args.label : oilsRptMakeLabel(path);
889 var dtype = field.datatype;
891 var tformPicker = new oilsRptTformPicker( {
892 node : DOM.oils_rpt_tform_table,
893 datatype : field.datatype,
894 non_aggregate : true,
896 select : args.transform
900 DOM.oils_rpt_tform_submit.onclick =
902 oilsAddRptDisplayItem(path,
903 DOM.oils_rpt_tform_label_input.value, tformPicker.getSelected() );
906 DOM.oils_rpt_tform_label_input.focus();
907 DOM.oils_rpt_tform_label_input.select();
909 _debug("Building transform window for datatype "+dtype);
913 //function oilsRptDrawOrderByWindow(path, col, cls, field) {
914 function oilsRptDrawOrderByWindow() {
915 var sel = DOM.oils_rpt_order_by_selector;
917 DOM.oils_rpt_order_by_submit.onclick = function() {
918 oilsRptAddOrderBy(getSelectorVal(sel));
921 var cols = oilsRpt.def.select;
922 for( var i = 0; i < cols.length; i++ ) {
924 insertSelectorVal(sel, -1, obj.alias, obj.path);
928 function oilsRptAddOrderBy(path) {
929 var rel = hex_md5(oilsRptPathRel(path));
930 var order_by = oilsRpt.def.order_by;
932 /* if this item is already in the order by remove it and overwrite it */
933 order_by = grep(oilsRpt.def.order_by,
934 function(i) {return (i.path != path)});
936 if(!order_by) order_by = [];
938 /* find the column definition in the select blob */
939 var obj = grep(oilsRpt.def.select,
940 function(i) {return (i.path == path)});
946 relation : obj.relation,
948 direction : getSelectorVal(DOM.oils_rpt_order_by_dir)
951 oilsRpt.def.order_by = order_by;