1 /** initializes reports, some basid display settings,
2 * grabs and builds the IDL tree
4 dojo.requireLocalization("openils.reports", "reports");
6 var rpt_strings = dojo.i18n.getLocalization("openils.reports", "reports");
7 var __dblclicks = {}; /* retain a cache of the selector value doubleclick event handlers */
9 function oilsInitReportBuilder() {
10 if(!oilsInitReports()) return false;
11 oilsReportBuilderReset();
12 DOM.oils_rpt_table.onclick =
13 function(){hideMe(DOM.oils_rpt_column_editor)};
16 hideMe(DOM.oils_rpt_tree_loading);
17 unHideMe(DOM.oils_rpt_table);
18 oilsRptBuilderDrawClone(new CGI().param('ct'));
22 DOM.oils_rpt_builder_save_template.onclick = oilsReportBuilderSave;
25 function oilsRptBuilderDrawClone(templateId) {
26 if(!templateId) return;
27 unHideMe(DOM.oils_rpt_builder_cloning);
29 oilsRptFetchTemplate(templateId,
30 function(template) { oilsRptBuilderDrawClone2(template);}
35 function oilsRptBuilderDrawClone2(template) {
36 appendClear( DOM.oils_rpt_build_cloning_name, template.name() );
37 DOM.oils_rpt_builder_new_name.value = template.name();
38 DOM.oils_rpt_builder_new_desc.value = template.description();
40 _debug(formatJSON(template.data()));
42 /* manually shove data into the display selectors */
43 var def = JSON2js(template.data());
45 /* --------------------------------------------------------------- */
46 /* hack to determine the higest existing param in the template */
47 matches = template.data().match(/::P\d/g);
49 for( var i = 0; i < matches.length; i++ ) {
50 var num = parseInt(matches[i].replace(/::P(\d)/,'$1'));
51 if( num > max ) max = num;
54 _debug("set next avail param to " + oilsRptID2);
55 //_debug('PARAM = ' + oilsRptNextParam());
58 /* --------------------------------------------------------------- */
60 var table = def.from.table;
62 for( var i in oilsIDL ) {
64 if( node.table == table ) {
65 setSelector(DOM.oils_rpt_builder_type_selector, node.name);
66 DOM.oils_rpt_builder_type_selector.onchange();
73 oilsAddRptDisplayItem(item.path, item.alias, item.column.transform)});
77 oilsAddRptFilterItem(item.path, item.column.transform, oilsRptObjectKeys(item.condition)[0])});
81 oilsAddRptHavingItem(item.path, item.column.transform, oilsRptObjectKeys(item.condition)[0])});
83 //oilsRpt.setTemplate(template); /* commented out with clone fix, *shouldn't* break anything */
84 oilsRpt.templateObject = null; /* simplify debugging */
87 function oilsReportBuilderReset() {
88 var n = (oilsRpt) ? oilsRpt.name : "";
89 oilsRpt = new oilsReport();
91 oilsRptDisplaySelector = DOM.oils_rpt_display_selector;
92 oilsRptFilterSelector = DOM.oils_rpt_filter_selector;
93 oilsRptHavingSelector = DOM.oils_rpt_agg_filter_selector;
94 removeChildren(oilsRptDisplaySelector);
95 removeChildren(oilsRptFilterSelector);
96 removeChildren(oilsRptHavingSelector);
97 //removeChildren(oilsRptOrderBySelector);
98 //oilsRptResetParams();
101 function oilsReportBuilderSave() {
104 tmpl.name(DOM.oils_rpt_builder_new_name.value);
105 tmpl.description(DOM.oils_rpt_builder_new_desc.value);
106 tmpl.owner(USER.id());
107 tmpl.folder(new CGI().param('folder'));
108 tmpl.data(js2JSON(oilsRpt.def));
110 if(!confirm(dojo.string.substitute( rpt_strings.RPT_BUILDER_CONFIRM_SAVE, [tmpl.name(), tmpl.description()] )) )
116 var req = new Request(OILS_RPT_CREATE_TEMPLATE, SESSION, tmpl);
117 req.request.alertEvent = false;
120 var res = r.getResultObject();
121 if(checkILSEvent(res)) {
124 if( res && res != '0' ) {
125 oilsRptAlertSuccess();
126 _l('oils_rpt.xhtml');
137 /* adds an item to the display window */
138 function oilsAddRptDisplayItem(path, name, tform, params) {
140 if( ! oilsAddSelectorItem(
141 { selector : oilsRptDisplaySelector,
146 transform : tform }) ) {
150 /* add the selected columns to the report output */
151 name = (name) ? name : oilsRptPathCol(path);
152 if( !tform ) tform = 'Bare';
154 var aggregate = oilsRptGetIsAgg(tform);
156 /* add this item to the select blob */
158 relation: hex_md5(oilsRptPathRel(path)),
161 column: { transform: tform, colname: oilsRptPathCol(path) }
164 if( params ) sel.column.params = params;
165 oilsRptAddSelectList(sel, tform);
166 mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
170 function oilsRptAddSelectList(obj, tform) {
171 if(!oilsRptGetIsAgg(tform)) {
174 for( var i = 0; i < oilsRpt.def.select.length; i++ ) {
175 var item = oilsRpt.def.select[i];
177 /* shove the item in question in front of the first agg tform */
178 if( !added && oilsRptGetIsAgg( item.column.transform ) ) {
185 /* if there is no existing agg tfrom to
186 insert in front of, add me on the end */
187 if(!added) select.push(obj);
189 oilsRpt.def.select = select;
192 /* re-draw the select display to get the order correct */
193 var sel = oilsRptDisplaySelector;
194 while( sel.options.length > 0 ) sel.options[0] = null;
195 iterate(oilsRpt.def.select,
197 _debug('re-inserting display item ' + item.path);
199 { selector: oilsRptDisplaySelector,
203 transform : item.column.transform,
210 /* shove agg transforms onto the end */
211 oilsRpt.def.select.push(obj);
217 function oilsRptGetIsAgg(tform) {
218 return OILS_RPT_TRANSFORMS[tform].aggregate;
221 /* takes a column path and builds a from-clause object for the path */
222 function oilsRptBuildFromClause(path) {
224 /* the path is the full path (relation) from the source
225 object to the column in question (e.g. au-home_ou-aou-name)*/
226 var parts = path.split(/-/);
228 /* the final from clause */
231 /* reference to the current position in the from clause */
236 var last_is_left = false; /* true if our parent join is a 'left' join */
238 /* walk the path, fleshing the from clause as we go */
239 for( var i = 0; i < parts.length; i += 2 ) {
241 var cls = parts[i]; /* class name (id) */
242 var col = parts[i+1]; /* column name */
244 /* a "node" is a class description from the IDL, it
245 contains relevant info, plus a list of "fields",
247 var node = oilsIDL[cls];
248 var pkey = oilsRptFindField(node, node.pkey);
250 /* a "field" is a parsed version of a column from the IDL,
251 contains datatype, column name, etc. */
252 var field = oilsRptFindField(node, col);
254 /* re-construct the path as we go so
255 we know what all we've seen thus far */
256 newpath = (newpath) ? newpath + '-'+ cls : cls;
258 /* extract relevant info */
259 tobj.table = node.table;
261 tobj.alias = hex_md5(newpath);
263 _debug('field type is ' + field.type);
264 if( i == (parts.length - 2) ) break;
266 /* we still have columns left in the path, keep adding join's */
268 if(field.reltype != 'has_a')
269 col = pkey.name + '-' + col;
276 if( field.type == 'link' ) {
277 tobj.key = field.key;
278 if( field.reltype == 'has_many' || field.reltype == 'might_have' || last_is_left ) {
282 last_is_left = false;
286 newpath = newpath + '-'+ path_col;
289 _debug("built 'from' clause: path="+path+"\n"+formatJSON(js2JSON(obj)));
293 function oilsMoveUpDisplayItems() {
294 var sel = oilsRptDisplaySelector;
295 var idx = sel.selectedIndex;
296 if( idx == 0 ) return;
297 var opt = sel.options[idx];
298 sel.options[idx] = null;
301 var val = opt.getAttribute('value');
302 var label = opt.getAttribute('label');
303 var path = opt.getAttribute('path');
304 var evt_id = opt.getAttribute('listener');
306 opt = insertSelectorVal(sel, idx, label, val);
308 opt.setAttribute('path', path);
309 opt.setAttribute('title', label);
310 opt.setAttribute('label', label);
311 opt.setAttribute('value', val);
312 opt.setAttribute('listener', evt_id);
314 /* re-attach the double-click event */
315 opt.addEventListener('dblclick', __dblclicks[evt_id], true );
317 sel.options[idx].selected = true;
319 var arr = oilsRpt.def.select;
320 for( var i = 0; i < arr.length; i++ ) {
321 if( arr[i].path == val ) {
322 var other = arr[i-1];
331 function oilsMoveDownDisplayItems() {
332 var sel = oilsRptDisplaySelector;
333 var idx = sel.selectedIndex;
334 if( idx == sel.options.length - 1 ) return;
335 var opt = sel.options[idx];
336 sel.options[idx] = null;
339 //var val = opt.getAttribute('value');
340 //insertSelectorVal(sel, idx, opt.innerHTML, val);
341 //insertSelectorVal(sel, idx, opt.getAttribute('label'), val);
343 var val = opt.getAttribute('value');
344 var label = opt.getAttribute('label');
345 var path = opt.getAttribute('path');
346 var evt_id = opt.getAttribute('listener');
348 opt = insertSelectorVal(sel, idx, label, val);
350 opt.setAttribute('value', val);
351 opt.setAttribute('path', path);
352 opt.setAttribute('title', label);
353 opt.setAttribute('label', label);
354 opt.setAttribute('listener', evt_id);
356 /* re-attach the double-click event */
357 opt.addEventListener('dblclick', __dblclicks[evt_id], true );
359 sel.options[idx].selected = true;
361 var arr = oilsRpt.def.select;
362 for( var i = 0; i < arr.length; i++ ) {
363 if( arr[i].path == val ) {
364 var other = arr[i+1];
374 /* removes a specific item from the display window */
376 function oilsDelDisplayItem(val) {
377 oilsDelSelectorItem(oilsRptDisplaySelector, val);
381 /* removes selected items from the display window */
382 function oilsDelSelectedDisplayItems() {
383 var list = oilsDelSelectedItems(oilsRptDisplaySelector);
385 _debug('deleting list: ' + list);
387 /* remove the de-selected columns from the report output */
388 oilsRpt.def.select = grep( oilsRpt.def.select,
390 for( var j = 0; j < list.length; j++ ) {
391 var d = list[j]; /* path */
394 _debug('in delete, looking at list = '+d+' : col = ' +
395 col.colname + ' : relation = ' + i.relation + ' : encoded = ' + hex_md5(oilsRptPathRel(d)) );
397 if( hex_md5(oilsRptPathRel(d)) == i.relation && oilsRptPathCol(d) == col.colname ) {
405 if(!oilsRpt.def.select) oilsRpt.def.select = [];
406 oilsRptPruneFromList(list);
410 function oilsRptPruneFromList(pathlist) {
412 for( var j = 0; j < pathlist.length; j++ ) {
413 /* if there are no items left in the "select", "where", or "having" clauses
414 for the given relation, trim this relation from the "from" clause */
415 var path = pathlist[j];
416 var encrel = hex_md5(oilsRptPathRel(path));
418 debug('seeing if we can prune from clause with relation = ' + encrel +' : path = ' + path);
420 var func = function(i){ return (i.relation == hex_md5(oilsRptPathRel(path))); };
422 if( !grep(oilsRpt.def.select, func) &&
423 !grep(oilsRpt.def.where, func) &&
424 !grep(oilsRpt.def.having, func) ) {
426 debug('looks like we can prune ' + path);
428 oilsRptPruneFromClause(oilsRptPathRel(pathlist[j]));
434 /* for each item in the path list, remove the associated data
435 from the "from" clause */
437 function oilsRptPruneFromClause(relation, node) {
439 var keys = oilsRptObjectKeys(node);
440 _debug("trying to remove relation: " + relation+'\n\tthis object has keys: '+keys);
442 if(!node) node = oilsRpt.def.from.join;
443 if(!node) return false;
445 for( var i in node ) {
446 var child_node = node[i];
447 _debug("\tanalyzing child node: "+child_node.path);
449 // first, descend into the tree, and prune leaves
450 if( child_node.join ) {
452 oilsRptPruneFromClause(relation, child_node.join);
453 var join_keys = oilsRptObjectKeys(child_node.join);
454 _debug("\tchild has a sub-join for items : ["+ join_keys+"]");
456 if(join_keys.length == 0) {
457 _debug("\tdeleting join for object "+i);
458 delete child_node.join;
462 if( !child_node.join ) {
464 _debug("\tchild node has no sub-join, seeing if we should delete it");
466 var from_alias = child_node.alias;
467 var func = function(n){ return (n.relation == from_alias)};
469 if( !grep(oilsRpt.def.select, func) &&
470 !grep(oilsRpt.def.where, func) &&
471 !grep(oilsRpt.def.having, func) ) {
473 /* we are not used by any other clauses */
474 _debug("\tdeleting node with relation: "+ from_alias);
484 function oilsRptMkFilterTags(path, tform, filter) {
485 var name = oilsRptMakeLabel(path);
486 if(tform) name += ' ('+tform+')';
487 name += ' "' + filter + '"';
488 var epath = path + ':'+filter+':';
489 if(tform) epath += tform;
491 return [ name, epath ];
495 function oilsAddRptFilterItem(path, tform, filter) {
496 _debug("Adding filter item for "+path+" tform="+tform+" filter="+filter);
498 var name = oilsRptMkFilterTags(path, tform, filter);
502 if( ! oilsAddSelectorItem(
503 { selector : oilsRptFilterSelector,
514 relation: hex_md5(oilsRptPathRel(path)),
516 column: { transform: tform, colname: oilsRptPathCol(path) },
520 //_debug('NEXT PARAM = ' + oilsRptID2);
521 //_debug('NEXT PARAM = ' + oilsRptNextParam());
523 if( filter == 'is' || filter == 'is not' || filter == 'is blank' || filter == 'is not blank' )
524 where.condition[filter] = null;
525 else where.condition[filter] = oilsRptNextParam();
528 case 'substring' : where.column.params = oilsRptNextParam();
531 oilsRpt.def.where.push(where);
532 mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
537 function oilsAddRptHavingItem(path, tform, filter) {
538 _debug("Adding filter item for "+path+" tform="+tform+" filter="+filter);
540 var name = oilsRptMkFilterTags(path, tform, filter);
544 if( ! oilsAddSelectorItem(
545 { selector: oilsRptHavingSelector,
551 type : 'agg_filter' /* XXX */
557 relation: hex_md5(oilsRptPathRel(path)),
559 column: { transform: tform, colname: oilsRptPathCol(path) },
562 if( filter == 'is' || filter == 'is not' || filter == 'is blank' || filter == 'is not blank' )
563 having.condition[filter] = null;
564 else having.condition[filter] = oilsRptNextParam();
567 case 'substring' : having.column.params = oilsRptNextParam();
570 oilsRpt.def.having.push(having);
571 mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
577 function oilsDelSelectedFilterItems() {
578 _oilsDelSelectedFilterItems('where');
580 function oilsDelSelectedAggFilterItems() {
581 _oilsDelSelectedFilterItems('having');
584 function _oilsDelSelectedFilterItems(type) {
586 /* the values in this list are formed: <path>:<operation>:<transform> */
588 if( type == 'where' )
589 list = oilsDelSelectedItems(oilsRptFilterSelector);
590 else if( type == 'having' )
591 list = oilsDelSelectedItems(oilsRptHavingSelector);
593 _debug("deleting filter items " + list);
595 for( var i = 0; i < list.length; i++ ) {
596 var enc_path = list[i];
597 var data = oilsRptParseFilterEncPath(enc_path);
599 _debug("trimming filter items with enc_path = " + enc_path);
601 _debug(data.operation);
605 _debug('---------------------');
607 oilsRpt.def[type] = grep(
610 return ! oilsRptFilterDataMatches(
611 f, data.path, data.operation, data.tform );
616 if(!oilsRpt.def[type]) oilsRpt.def[type] = [];
617 oilsRptPruneFromList(list);
621 function oilsRptParseFilterEncPath(item) {
623 path: item.replace(/:.*/,''),
624 operation: item.replace(/.*:(.*):.*/,'$1'),
625 tform: item.replace(/.*?:.*?:(.*)/,'$1')
630 function oilsRptFilterDataMatches(filter, path, operation, tform) {
631 var rel = hex_md5(oilsRptPathRel(path));
632 var col = oilsRptPathCol(path);
634 if( col == filter.column.colname &&
635 rel == filter.relation &&
636 tform == filter.column.transform &&
637 operation == oilsRptObjectKeys(filter.condition)[0] ) return true;
642 /* adds an item to the display window */
644 function oilsAddRptAggFilterItem(val) {
645 oilsAddSelectorItem({selector:oilsRptHavingFilterSelector, val:val, label:val, path:val});
649 /* removes a specific item from the display window */
651 function oilsDelAggFilterItem(val) {
652 oilsDelSelectorItem(oilsRptHavingFilterSelector, val);
657 /* adds an item to the display window */
658 //function oilsAddSelectorItem(sel, val, name, path) {
659 function oilsAddSelectorItem(args) {
661 var sel = args.selector;
662 var label = args.label;
663 var path = args.path;
666 label = (label) ? label : oilsRptMakeLabel(val);
669 for( i = 0; i < sel.options.length; i++ ) {
670 var opt = sel.options[i];
671 if( opt.value == val ) return false;
674 var opt = insertSelectorVal( sel, -1, label, val );
675 opt.setAttribute('title', label);
676 opt.setAttribute('path', path);
677 opt.setAttribute('label', label);
679 var evt_id = oilsNextNumericId();
680 opt.setAttribute('listener', evt_id);
683 delete args.selector;
684 var listener = function(){ oilsRptDrawDataWindow(path, args);};
685 opt.addEventListener('dblclick', listener, true );
686 __dblclicks[evt_id] = listener;
687 //function(){ oilsRptDrawDataWindow(path, args);} , true);
693 /* removes a specific item from the display window */
694 function oilsDelSelectorItem(sel, val) {
695 var opts = sel.options;
696 for( var i = 0; i < opts.length; i++ ) {
698 if( opt.value == val ) {
699 if( i == opts.length - 1 )
701 else opts[i] = opts[i+1];
707 /* removes selected items from the display window */
708 function oilsDelSelectedItems(sel) {
709 var list = getSelectedList(sel);
710 for( var i = 0; i < list.length; i++ )
711 oilsDelSelectorItem(sel, list[i]);
716 /* hides the different field editor tabs */
717 function oilsRptHideEditorDivs() {
718 hideMe(DOM.oils_rpt_tform_div);
719 hideMe(DOM.oils_rpt_filter_div);
720 hideMe(DOM.oils_rpt_agg_filter_div);
721 hideMe(DOM.oils_rpt_order_by_div);
723 removeCSSClass(DOM.oils_rpt_tform_tab.parentNode, 'oils_rpt_tab_picker_selected');
724 removeCSSClass(DOM.oils_rpt_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
725 removeCSSClass(DOM.oils_rpt_agg_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
730 This draws the 3-tabbed window containing the transform,
731 filter, and aggregate filter picker window
733 function oilsRptDrawDataWindow(path, args) {
735 args = (args) ? args : {};
738 _debug("oilsRptDrawDataWindow(): args -> " + x + " = " + args[x]);
740 var col = oilsRptPathCol(path);
741 var cls = oilsRptPathClass(path);
742 var field = oilsRptFindField(oilsIDL[cls], col);
744 appendClear(DOM.oils_rpt_editor_window_label, text(oilsRptMakeLabel(path)));
745 appendClear(DOM.oils_rpt_editor_window_datatype, text(field.datatype));
747 _debug("setting update data window for column "+col+' on class '+cls);
749 var div = DOM.oils_rpt_column_editor;
750 /* set a preliminary top position so the page won't bounce around */
754 //div.setAttribute('style','top:'+oilsMouseX+'px');
756 /* unhide the div so we can determine the dimensions */
759 /* don't let them see the floating div until the position is fully determined */
760 div.style.visibility='hidden';
762 oilsRptDrawTransformWindow(path, col, cls, field, args);
763 oilsRptDrawFilterWindow(path, col, cls, field, args);
764 oilsRptDrawHavingWindow(path, col, cls, field, args);
765 //oilsRptDrawOrderByWindow(path, col, cls, field);
767 //buildFloatingDiv(div, 600);
769 //window.scrollTo(0,0);
770 window.scrollTo(0, 60);
772 /* now let them see it */
773 div.style.visibility='visible';
774 //args.type = (args.type) ? args.type : 'display';
775 oilsRptSetDataWindowActions(div, args);
779 function oilsRptSetDataWindowActions(div, args) {
780 /* give the tab links behavior */
782 DOM.oils_rpt_tform_tab.onclick =
784 oilsRptHideEditorDivs();
785 unHideMe(DOM.oils_rpt_tform_div)
786 addCSSClass(DOM.oils_rpt_tform_tab.parentNode, 'oils_rpt_tab_picker_selected');
789 DOM.oils_rpt_filter_tab.onclick =
791 oilsRptHideEditorDivs();
792 unHideMe(DOM.oils_rpt_filter_div)
793 addCSSClass(DOM.oils_rpt_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
796 DOM.oils_rpt_agg_filter_tab.onclick =
798 oilsRptHideEditorDivs();
799 unHideMe(DOM.oils_rpt_agg_filter_div)
800 addCSSClass(DOM.oils_rpt_agg_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
804 DOM.oils_rpt_order_by_tab.onclick =
806 oilsRptHideEditorDivs();
807 oilsRptDrawOrderByWindow();
808 unHideMe(DOM.oils_rpt_order_by_div);
812 DOM.oils_rpt_tform_submit.disabled = false;
813 DOM.oils_rpt_filter_submit.disabled = false;
814 DOM.oils_rpt_agg_filter_submit.disabled = false;
817 DOM.oils_rpt_tform_tab.onclick();
819 /* disable editing on existing items for now */
820 if( args.type == 'display' ) {
821 DOM.oils_rpt_tform_tab.onclick();
822 DOM.oils_rpt_tform_submit.disabled = true;
824 if( args.type == 'filter' ) {
825 DOM.oils_rpt_filter_tab.onclick();
826 DOM.oils_rpt_filter_submit.disabled = true;
828 if( args.type == 'agg_filter' ) {
829 DOM.oils_rpt_agg_filter_tab.onclick();
830 DOM.oils_rpt_agg_filter_submit.disabled = true;
834 DOM.oils_rpt_column_editor_close_button.onclick = function(){hideMe(div);};
838 function oilsRptDrawFilterWindow(path, col, cls, field, args) {
840 var tformPicker = new oilsRptTformPicker( {
841 node : DOM.oils_rpt_filter_tform_table,
842 datatype : field.datatype,
843 non_aggregate : true,
844 select : args.transform
848 var filterPicker = new oilsRptFilterPicker({
849 node : DOM.oils_rpt_filter_op_table,
850 datatype : field.datatype,
851 select : args.operation
855 DOM.oils_rpt_filter_submit.onclick = function() {
856 oilsAddRptFilterItem(
857 path, tformPicker.getSelected(), filterPicker.getSelected());
862 function oilsRptDrawHavingWindow(path, col, cls, field, args) {
863 var tformPicker = new oilsRptTformPicker( {
864 node : DOM.oils_rpt_agg_filter_tform_table,
865 datatype : field.datatype,
867 select : args.transform
871 var filterPicker = new oilsRptFilterPicker({
872 node : DOM.oils_rpt_agg_filter_op_table,
873 datatype : field.datatype,
874 select : args.operation
878 DOM.oils_rpt_agg_filter_submit.onclick = function() {
879 oilsAddRptHavingItem(
880 path, tformPicker.getSelected(), filterPicker.getSelected());
884 /* draws the transform window */
885 function oilsRptDrawTransformWindow(path, col, cls, field, args) {
886 args = (args) ? args : {};
888 DOM.oils_rpt_tform_label_input.value =
889 (args.label) ? args.label : oilsRptMakeLabel(path);
891 var dtype = field.datatype;
893 var tformPicker = new oilsRptTformPicker( {
894 node : DOM.oils_rpt_tform_table,
895 datatype : field.datatype,
896 non_aggregate : true,
898 select : args.transform
902 DOM.oils_rpt_tform_submit.onclick =
904 oilsAddRptDisplayItem(path,
905 DOM.oils_rpt_tform_label_input.value, tformPicker.getSelected() );
908 DOM.oils_rpt_tform_label_input.focus();
909 DOM.oils_rpt_tform_label_input.select();
911 _debug("Building transform window for datatype "+dtype);
915 //function oilsRptDrawOrderByWindow(path, col, cls, field) {
916 function oilsRptDrawOrderByWindow() {
917 var sel = DOM.oils_rpt_order_by_selector;
919 DOM.oils_rpt_order_by_submit.onclick = function() {
920 oilsRptAddOrderBy(getSelectorVal(sel));
923 var cols = oilsRpt.def.select;
924 for( var i = 0; i < cols.length; i++ ) {
926 insertSelectorVal(sel, -1, obj.alias, obj.path);
930 function oilsRptAddOrderBy(path) {
931 var rel = hex_md5(oilsRptPathRel(path));
932 var order_by = oilsRpt.def.order_by;
934 /* if this item is already in the order by remove it and overwrite it */
935 order_by = grep(oilsRpt.def.order_by,
936 function(i) {return (i.path != path)});
938 if(!order_by) order_by = [];
940 /* find the column definition in the select blob */
941 var obj = grep(oilsRpt.def.select,
942 function(i) {return (i.path == path)});
948 relation : obj.relation,
950 direction : getSelectorVal(DOM.oils_rpt_order_by_dir)
953 oilsRpt.def.order_by = order_by;