]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/reports/oils_rpt_builder.js
fixed a bug that caused from-clause pruning to fail in some cases...
[Evergreen.git] / Open-ILS / web / reports / oils_rpt_builder.js
1 /** initializes reports, some basid display settings, 
2   * grabs and builds the IDL tree
3   */
4 function oilsInitReportBuilder() {
5         if(!oilsInitReports()) return false;
6         oilsReportBuilderReset();
7         DOM.oils_rpt_table.onclick = 
8                 function(){hideMe(DOM.oils_rpt_column_editor)};
9         oilsDrawRptTree(
10                 function() { 
11                         hideMe(DOM.oils_rpt_tree_loading); 
12                         unHideMe(DOM.oils_rpt_table); 
13                         oilsRptBuilderDrawClone(new CGI().param('ct'));
14                 }
15         );
16
17         DOM.oils_rpt_builder_save_template.onclick = oilsReportBuilderSave;
18 }
19
20 function oilsRptBuilderDrawClone(templateId) {
21         if(!templateId) return;
22         unHideMe(DOM.oils_rpt_builder_cloning);
23
24         oilsRptFetchTemplate(templateId,
25                 function(template) { oilsRptBuilderDrawClone2(template);}
26         );
27 }
28
29
30 function oilsRptBuilderDrawClone2(template) {
31         //oilsRpt.
32         appendClear( DOM.oils_rpt_build_cloning_name, template.name() );
33         DOM.oils_rpt_builder_new_name.value = template.name();
34         DOM.oils_rpt_builder_new_desc.value = template.description();
35
36         _debug(formatJSON(template.data()));
37
38         /* manually shove data into the display selectors */
39         var def = JSON2js(template.data());
40
41         var table = def.from.table;
42         var node;
43         for( var i in oilsIDL ) {
44                 node = oilsIDL[i];
45                 if( node.table == table ) {
46                         setSelector(DOM.oils_rpt_builder_type_selector, node.name);
47                         DOM.oils_rpt_builder_type_selector.onchange();
48                         break;
49                 }
50         }
51
52         iterate(def.select,
53                 function(item) {
54                         oilsAddRptDisplayItem(item.path, item.alias, item.column.transform)});
55
56         iterate(def.where,
57                 function(item) {
58                         oilsAddRptFilterItem(item.path, item.column.transform, oilsRptObjectKeys(item.condition)[0])});
59
60         iterate(def.having,
61                 function(item) {
62                         oilsAddRptHavingItem(item.path, item.column.transform, oilsRptObjectKeys(item.condition)[0])});
63
64         oilsRpt.setTemplate(template);
65 }
66
67 function oilsReportBuilderReset() {
68         var n = (oilsRpt) ? oilsRpt.name : "";
69         oilsRpt = new oilsReport();
70         oilsRpt.name = n;
71         oilsRptDisplaySelector  = DOM.oils_rpt_display_selector;
72         oilsRptFilterSelector   = DOM.oils_rpt_filter_selector;
73         oilsRptHavingSelector   = DOM.oils_rpt_agg_filter_selector;
74         removeChildren(oilsRptDisplaySelector);
75         removeChildren(oilsRptFilterSelector);
76         removeChildren(oilsRptHavingSelector);
77         //removeChildren(oilsRptOrderBySelector);
78         oilsRptResetParams();
79 }
80
81 function oilsReportBuilderSave() {
82
83         var tmpl = new rt();
84         tmpl.name(DOM.oils_rpt_builder_new_name.value);
85         tmpl.description(DOM.oils_rpt_builder_new_desc.value);
86         tmpl.owner(USER.id());
87         tmpl.folder(new CGI().param('folder'));
88         tmpl.data(js2JSON(oilsRpt.def));
89
90         if(!confirm('Name : '+tmpl.name() + '\nDescription: ' + tmpl.description()+'\nSave Template?'))
91                 return;
92
93         debugFMObject(tmpl);
94         //return; /* XXX */
95
96         var req = new Request(OILS_RPT_CREATE_TEMPLATE, SESSION, tmpl);
97         req.request.alertEvent = false;
98         req.callback(
99                 function(r) {
100                         var res = r.getResultObject();
101                         if(checkILSEvent(res)) {
102                                 alertILSEvent(res);
103                         } else {
104                                 if( res && res != '0' ) {
105                                         oilsRptAlertSuccess();
106                                         _l('oils_rpt.xhtml');
107                                 } 
108                         }
109                 }
110         );
111         
112         req.send();
113 }
114
115
116
117 /* adds an item to the display window */
118 function oilsAddRptDisplayItem(path, name, tform, params) {
119         if( ! oilsAddSelectorItem(oilsRptDisplaySelector, path, name) ) 
120                 return;
121
122         /* add the selected columns to the report output */
123         name = (name) ? name : oilsRptPathCol(path);
124         if( !tform ) tform = 'Bare';
125
126         var aggregate = oilsRptGetIsAgg(tform);
127
128         /* add this item to the select blob */
129         var sel = {
130                 relation: hex_md5(oilsRptPathRel(path)), 
131                 path : path,
132                 alias:    name,
133                 column:   { transform: tform, colname: oilsRptPathCol(path) }
134         };
135
136         if( params ) sel.column.params = params;
137
138         if(!oilsRptGetIsAgg(tform)) {
139                 var select = [];
140                 var added = false;
141                 for( var i = 0; i < oilsRpt.def.select.length; i++ ) {
142                         var item = oilsRpt.def.select[i];
143                         if( !added && oilsRptGetIsAgg( item.column.transform ) ) {
144                                 select.push(sel);
145                                 added = true;
146                         }
147                         select.push(item);
148                 }
149                 if(!added) select.push(sel);
150                 oilsRpt.def.select = select;
151         } else {
152                 oilsRpt.def.select.push(sel);
153         }
154
155
156         mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
157         oilsRptDebug();
158 }
159
160 function oilsRptGetIsAgg(tform) {
161         return OILS_RPT_TRANSFORMS[tform].aggregate;
162         
163         /* DEPRECATED */
164         var sel = $n(DOM.oils_rpt_tform_table,'selector');
165         for( var i = 0; i < sel.options.length; i++ ) {
166                 var opt = sel.options[i];
167                 if( opt.getAttribute('value') == tform )
168                         return opt.getAttribute('aggregate');
169         }
170 }
171
172 /* takes a column path and builds a from-clause object for the path */
173 function oilsRptBuildFromClause(path) {
174
175         /* the path is the full path (relation) from the source 
176                 object to the column in question (e.g. au-home_ou-aou-name)*/
177         var parts = path.split(/-/);
178
179         /* the final from clause */
180         var obj = {}; 
181
182         /* reference to the current position in the from clause */
183         var tobj = obj; 
184
185         var newpath = "";
186
187         /* walk the path, fleshing the from clause as we go */
188         for( var i = 0; i < parts.length; i += 2 ) {
189
190                 var cls = parts[i]; /* class name (id) */
191                 var col = parts[i+1]; /* column name */
192
193                 /* a "node" is a class description from the IDL, it 
194                         contains relevant info, plus a list of "fields",
195                         or column objects */
196                 var node = oilsIDL[cls];
197                 var pkey = oilsRptFindField(node, node.pkey);
198
199                 /* a "field" is a parsed version of a column from the IDL,
200                         contains datatype, column name, etc. */
201                 var field = oilsRptFindField(node, col);
202
203                 /* re-construct the path as we go so 
204                         we know what all we've seen thus far */
205                 newpath = (newpath) ? newpath + '-'+ cls : cls;
206
207                 /* extract relevant info */
208                 tobj.table = node.table;
209                 tobj.path = newpath;
210                 tobj.alias = hex_md5(newpath);
211
212                 _debug('field type is ' + field.type);
213                 if( i == (parts.length - 2) ) break;
214
215                 /* we still have columns left in the path, keep adding join's */
216                 var path_col = col;
217                 if(field.reltype != 'has_a')
218                         col = pkey.name + '-' + col;
219
220                 tobj.join = {};
221                 tobj = tobj.join;
222
223                 tobj[col] = {};
224                 tobj = tobj[col];
225                 if( field.type == 'link' )
226                         tobj.key = field.key;
227
228                 newpath = newpath + '-'+ path_col;
229         }
230
231         _debug("built 'from' clause: path="+path+"\n"+formatJSON(js2JSON(obj)));
232         return obj;
233 }
234
235 function oilsMoveUpDisplayItems() {
236         var sel = oilsRptDisplaySelector;
237         var idx = sel.selectedIndex;
238         if( idx == 0 ) return;
239         var opt = sel.options[idx];
240         sel.options[idx] = null;
241         idx--;
242         var val = opt.getAttribute('value');
243         insertSelectorVal(sel, idx, opt.innerHTML, val);
244         sel.options[idx].selected = true;
245
246         var arr = oilsRpt.def.select;
247         for( var i = 0; i < arr.length; i++ ) {
248                 if( arr[i].path == val ) {
249                         var other = arr[i-1];
250                         arr[i-1] = arr[i];
251                         arr[i] = other;
252                         break;
253                 }
254         }
255         oilsRptDebug();
256 }
257
258 function oilsMoveDownDisplayItems() {
259         var sel = oilsRptDisplaySelector;
260         var idx = sel.selectedIndex;
261         if( idx == sel.options.length - 1 ) return;
262         var opt = sel.options[idx];
263         sel.options[idx] = null;
264         idx++;
265         var val = opt.getAttribute('value');
266         insertSelectorVal(sel, idx, opt.innerHTML, val);
267         sel.options[idx].selected = true;
268
269         var arr = oilsRpt.def.select;
270         for( var i = 0; i < arr.length; i++ ) {
271                 if( arr[i].path == val ) {
272                         var other = arr[i+1];
273                         arr[i+1] = arr[i];
274                         arr[i] = other;
275                         break;
276                 }
277         }
278         oilsRptDebug();
279 }
280
281
282 /* removes a specific item from the display window */
283 /*
284 function oilsDelDisplayItem(val) {
285         oilsDelSelectorItem(oilsRptDisplaySelector, val);
286 }
287 */
288
289 /* removes selected items from the display window */
290 function oilsDelSelectedDisplayItems() {
291         var list = oilsDelSelectedItems(oilsRptDisplaySelector);
292
293         _debug('deleting list: ' + list);
294
295         /* remove the de-selected columns from the report output */
296         oilsRpt.def.select = grep( oilsRpt.def.select, 
297                 function(i) {
298                         for( var j = 0; j < list.length; j++ ) {
299                                 var d = list[j]; /* path */
300                                 var col = i.column;
301
302                                 _debug('in delete, looking at list = '+d+' : col = ' + 
303                                         col.colname + ' : relation = ' + i.relation + ' : encoded = ' + hex_md5(oilsRptPathRel(d)) );
304
305                                 if( hex_md5(oilsRptPathRel(d)) == i.relation && oilsRptPathCol(d) == col.colname ) {
306                                         return false;
307                                 }
308                         }
309                         return true;
310                 }
311         );
312
313         if(!oilsRpt.def.select) oilsRpt.def.select = [];
314
315         oilsRptPruneFromList(list);
316
317         /*
318         for( var j = 0; j < list.length; j++ ) {
319                 debug('seeing if we can prune from clause with relation = ' + hex_md5(oilsRptPathRel(list[j])));
320                 if(     !grep(oilsRpt.def.select,
321                                 function(i){ return (i.relation == hex_md5(oilsRptPathRel(list[j]))); })
322                         && !grep(oilsRpt.def.where,
323                                 function(i){ return (i.relation == hex_md5(oilsRptPathRel(list[j]))); })
324                         && !grep(oilsRpt.def.having,
325                                 function(i){ return (i.relation == hex_md5(oilsRptPathRel(list[j]))); })
326                 ) {
327                         _debug('pruning from clause');
328                         oilsRptPruneFromClause(oilsRptPathRel(list[j]));
329                 }
330         }
331         */
332
333         oilsRptDebug();
334 }
335
336 function oilsRptPruneFromList(pathlist) {
337
338         for( var j = 0; j < pathlist.length; j++ ) {
339                 /* if there are no items left in the "select", "where", or "having" clauses 
340                         for the given relation, trim this relation from the "from" clause */
341                 var path = pathlist[j];
342                 var encrel = hex_md5(oilsRptPathRel(path));
343
344                 debug('seeing if we can prune from clause with relation = ' + encrel +' : path = ' + path);
345
346                 var func = function(i){ return (i.relation == hex_md5(oilsRptPathRel(path))); };
347
348                 if(     !grep(oilsRpt.def.select, func) && 
349                                 !grep(oilsRpt.def.where, func) && 
350                                 !grep(oilsRpt.def.having, func) ) {
351
352                         debug('looks like we can prune ' + path);
353
354                         oilsRptPruneFromClause(oilsRptPathRel(pathlist[j]));
355                 }
356         }
357 }
358
359
360 /* for each item in the path list, remove the associated data
361         from the "from" clause */
362
363 function oilsRptPruneFromClause(relation, node) {
364
365         var keys = oilsRptObjectKeys(node);
366         _debug("trying to remove relation: " + relation+'\n\tthis object has keys: '+keys);
367
368         if(!node) node = oilsRpt.def.from.join;
369         if(!node) return false;
370
371         for( var i in node ) {
372                 var child_node = node[i];
373                 _debug("\tanalyzing child node: "+child_node.path);
374
375                 // first, descend into the tree, and prune leaves 
376                 if( child_node.join ) {
377
378                         oilsRptPruneFromClause(relation, child_node.join); 
379                         var join_keys = oilsRptObjectKeys(child_node.join);
380                         _debug("\tchild has a sub-join for items : ["+ join_keys+"]");
381
382                         if(join_keys.length == 0) {
383                                 _debug("\tdeleting join for object "+i);
384                                 delete child_node.join;
385                         }
386                 }
387
388                 if( !child_node.join ) {
389
390                         _debug("\tchild node has no sub-join, seeing if we should delete it");
391
392                         var from_alias = child_node.alias;
393                         var func = function(n){ return (n.relation == from_alias)};
394         
395                         if(     !grep(oilsRpt.def.select, func) &&
396                                         !grep(oilsRpt.def.where, func) &&
397                                         !grep(oilsRpt.def.having, func) ) {
398         
399                                 /* we are not used by any other clauses */
400                                 _debug("\tdeleting node with relation: "+ from_alias);
401                                 delete node[i];
402                                 return true;
403                         }
404                 }
405         }
406
407         return false;
408 }
409
410 function oilsRptMkFilterTags(path, tform, filter) {
411         var name = oilsRptMakeLabel(path);
412         if(tform) name += ' ('+tform+')';
413         name += ' "' + filter + '"';
414         var epath = path + ':'+filter+':';
415         if(tform) epath += tform;
416
417         return [ name, epath ];
418 }
419
420
421 function oilsAddRptFilterItem(path, tform, filter) {
422         _debug("Adding filter item for "+path+" tform="+tform+" filter="+filter);
423
424         var name = oilsRptMkFilterTags(path, tform, filter);
425         var epath = name[1];
426         name = name[0];
427
428         if( ! oilsAddSelectorItem(oilsRptFilterSelector, epath, name) )
429                 return;
430
431         var where = {
432                 relation: hex_md5(oilsRptPathRel(path)), 
433                 path : path,
434                 column:   { transform: tform, colname: oilsRptPathCol(path) },
435                 condition : {}
436         };
437         if( filter == 'is' || filter == 'is not' )
438                 where.condition[filter] = null;
439         else where.condition[filter] = oilsRptNextParam();
440
441         switch(tform) {
442                 case 'substring' : where.column.params = oilsRptNextParam();
443         }
444
445         oilsRpt.def.where.push(where);
446         mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
447         oilsRptDebug();
448 }
449
450
451 function oilsAddRptHavingItem(path, tform, filter) {
452         _debug("Adding filter item for "+path+" tform="+tform+" filter="+filter);
453
454         var name = oilsRptMkFilterTags(path, tform, filter);
455         var epath = name[1];
456         name = name[0];
457
458         if( ! oilsAddSelectorItem(oilsRptHavingSelector, epath, name) )
459                 return;
460
461         var having = {
462                 relation: hex_md5(oilsRptPathRel(path)), 
463                 path : path,
464                 column:   { transform: tform, colname: oilsRptPathCol(path) },
465                 condition : {}
466         };
467         if( filter == 'is' || filter == 'is not' )
468                 having.condition[filter] = null;
469         else having.condition[filter] = oilsRptNextParam();
470
471         switch(tform) {
472                 case 'substring' : having.column.params = oilsRptNextParam();
473         }
474
475         oilsRpt.def.having.push(having);
476         mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
477         oilsRptDebug();
478 }
479
480
481
482 function oilsDelSelectedFilterItems() {
483         _oilsDelSelectedFilterItems('where');
484 }
485 function oilsDelSelectedAggFilterItems() {
486         _oilsDelSelectedFilterItems('having');
487 }
488
489 function _oilsDelSelectedFilterItems(type) {
490
491         /* the values in this list are formed:  <path>:<operation>:<transform> */
492         var list = oilsDelSelectedItems(oilsRptFilterSelector);
493
494         for( var i = 0; i < list.length; i++ ) {
495                 var enc_path = list[i];
496                 var data = oilsRptParseFilterEncPath(enc_path);
497                 oilsRpt.def[type] = grep( 
498                         oilsRpt.def[type],
499                         function(f) { 
500                                 return oilsRptFilterDataMatches( 
501                                         f, data.path, data.operation, data.tform );
502                         }
503                 );
504         }
505
506         if(!oilsRpt.def[type]) oilsRpt.def[type] = [];
507         oilsRptPruneFromList(list);
508         oilsRptDebug();
509 }
510
511 function oilsRptParseFilterEncPath(item) {
512         return {
513                 path:           item.replace(/:.*/,''),
514                 operation:      item.replace(/.*:(.*):.*/,'$1'),
515                 tform:  item.replace(/.*?:.*?:(.*)/,'$1')
516         };
517 }
518
519
520 function oilsRptFilterDataMatches(filter, path, operation, tform) {
521         var rel = hex_md5(oilsRptPathRel(path));
522         var col = oilsRptPathCol(path);
523
524         if(     col == filter.column.colname &&
525                         rel == filter.relation &&       
526                         tform == filter.column.transform &&
527                         operation == oilsRptObjectKeys(filter)[0] ) return true;
528
529         return false;
530 }
531
532 /*
533 function oilsRptFilterGrep(flist, filter) {
534
535         for( var j = 0; j < flist.length; j++ ) {
536
537                 var fil = flist[j];
538                 var col = filter.column;
539                 var frel = hex_md5(oilsRptPathRel(fil.path));
540                 var fcol = oilsRptPathCol(fil.path);
541
542                 var op = oilsRptObjectKeys(filter.condition)[0];
543
544                 if(     frel == filter.relation && 
545                                 fcol == col.colname && 
546                                 fil.operation == op &&
547                                 fil.tform == col.transform ) {
548                                 return false;
549                 }
550         }
551         return true;
552 }
553 */
554
555 /* adds an item to the display window */
556 function oilsAddRptAggFilterItem(val) {
557         oilsAddSelectorItem(oilsRptHavingFilterSelector, val);
558 }
559
560 /* removes a specific item from the display window */
561 function oilsDelAggFilterItem(val) {
562         oilsDelSelectorItem(oilsRptHavingFilterSelector, val);
563 }
564
565
566
567 /*
568 function ___oilsDelSelectedAggFilterItems() {
569         var list = oilsDelSelectedItems(oilsRptHavingFilterSelector);
570         oilsRpt.def.having = grep( oilsRpt.def.having, 
571                 function(i) {
572                         for( var j = 0; j < list.length; j++ ) {
573                                 var d = list[j];
574                                 var col = i.column;
575
576                                 if( typeof col != 'string' ) 
577                                         for( var c in col ) col = col[c];
578
579                                 if( typeof col != 'string' ) col = col[0];
580
581                                 if( oilsRptPathRel(d) == i.relation && oilsRptPathCol(d) == col ) {
582                                 */
583                                 //      var param = (i.alias) ? i.alias.match(/::P\d*/) : null;
584                                         /*
585                                         if( param ) delete oilsRpt.params[param];
586                                         return false;
587                                 }
588                         }
589                         return true;
590                 }
591         );
592
593         if(!oilsRpt.def.having) oilsRpt.def.having = [];
594         oilsRptPruneFromList(list);
595         oilsRptDebug();
596 }
597 */
598
599
600 /* adds an item to the display window */
601 function oilsAddSelectorItem(sel, val, name) {
602         name = (name) ? name : oilsRptMakeLabel(val);
603         for( var i = 0; i < sel.options.length; i++ ) {
604                 var opt = sel.options[i];
605                 if( opt.value == val ) return false;
606         }
607         var opt = insertSelectorVal( sel, -1, name, val );
608         opt.setAttribute('title', name);
609         return true;
610 }
611
612
613 /* removes a specific item from the display window */
614 function oilsDelSelectorItem(sel, val) {
615         var opts = sel.options;
616         for( var i = 0; i < opts.length; i++ ) {
617                 var opt = opts[i];
618                 if( opt.value == val )  {
619                         if( i == opts.length - 1 ) 
620                                 opts[i] = null;
621                         else opts[i] = opts[i+1];
622                         return;
623                 }
624         }
625 }
626
627 /* removes selected items from the display window */
628 function oilsDelSelectedItems(sel) {
629         var list = getSelectedList(sel);
630         for( var i = 0; i < list.length; i++ ) 
631                 oilsDelSelectorItem(sel, list[i]);
632         return list;
633 }
634
635
636 /* hides the different field editor tabs */
637 function oilsRptHideEditorDivs() {
638         hideMe(DOM.oils_rpt_tform_div);
639         hideMe(DOM.oils_rpt_filter_div);
640         hideMe(DOM.oils_rpt_agg_filter_div);
641         hideMe(DOM.oils_rpt_order_by_div);
642
643         removeCSSClass(DOM.oils_rpt_tform_tab.parentNode, 'oils_rpt_tab_picker_selected');
644         removeCSSClass(DOM.oils_rpt_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
645         removeCSSClass(DOM.oils_rpt_agg_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
646 }
647
648
649 /**
650   This draws the 3-tabbed window containing the transform,
651   filter, and aggregate filter picker window
652   */
653 function oilsRptDrawDataWindow(path) {
654         var col = oilsRptPathCol(path);
655         var cls = oilsRptPathClass(path);
656         var field = oilsRptFindField(oilsIDL[cls], col);
657
658         appendClear(DOM.oils_rpt_editor_window_label, text(oilsRptMakeLabel(path)));
659         appendClear(DOM.oils_rpt_editor_window_datatype, text(field.datatype));
660
661         _debug("setting update data window for column "+col+' on class '+cls);
662
663         var div = DOM.oils_rpt_column_editor;
664         /* set a preliminary top position so the page won't bounce around */
665
666
667         /* XXX */
668         //div.setAttribute('style','top:'+oilsMouseX+'px');
669
670         /* unhide the div so we can determine the dimensions */
671         unHideMe(div);
672
673         /* don't let them see the floating div until the position is fully determined */
674         div.style.visibility='hidden'; 
675
676         oilsRptDrawTransformWindow(path, col, cls, field);
677         oilsRptDrawFilterWindow(path, col, cls, field);
678         oilsRptDrawHavingWindow(path, col, cls, field);
679         oilsRptDrawOrderByWindow(path, col, cls, field);
680
681         //buildFloatingDiv(div, 600);
682
683         //window.scrollTo(0,0);
684         window.scrollTo(0, 60);
685
686         /* now let them see it */
687         div.style.visibility='visible';
688         oilsRptSetDataWindowActions(div);
689 }
690
691
692 function oilsRptSetDataWindowActions(div) {
693         /* give the tab links behavior */
694
695
696         DOM.oils_rpt_tform_tab.onclick = 
697                 function(){
698                         oilsRptHideEditorDivs();
699                         unHideMe(DOM.oils_rpt_tform_div)
700                         addCSSClass(DOM.oils_rpt_tform_tab.parentNode, 'oils_rpt_tab_picker_selected');
701                 };
702
703         DOM.oils_rpt_filter_tab.onclick = 
704                 function(){
705                         oilsRptHideEditorDivs();
706                         unHideMe(DOM.oils_rpt_filter_div)
707                         addCSSClass(DOM.oils_rpt_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
708                 };
709         DOM.oils_rpt_agg_filter_tab.onclick = 
710                 function(){
711                         oilsRptHideEditorDivs();
712                         unHideMe(DOM.oils_rpt_agg_filter_div)
713                         addCSSClass(DOM.oils_rpt_agg_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
714                 };
715
716         /*
717         DOM.oils_rpt_order_by_tab.onclick = 
718                 function(){
719                         oilsRptHideEditorDivs();
720                         oilsRptDrawOrderByWindow();
721                         unHideMe(DOM.oils_rpt_order_by_div);
722                         };
723                         */
724
725         DOM.oils_rpt_tform_tab.onclick();
726         DOM.oils_rpt_column_editor_close_button.onclick = function(){hideMe(div);};
727 }
728
729
730 function oilsRptDrawFilterWindow(path, col, cls, field) {
731
732         var tformPicker = new oilsRptTformPicker( {     
733                         node : DOM.oils_rpt_filter_tform_table,
734                         datatype : field.datatype,
735                         non_aggregate : true
736                 }
737         );
738
739         var filterPicker = new oilsRptFilterPicker({
740                         node : DOM.oils_rpt_filter_op_table,
741                         datatype : field.datatype
742                 }
743         );
744
745         DOM.oils_rpt_filter_submit.onclick = function() {
746                 oilsAddRptFilterItem(
747                         path, tformPicker.getSelected(), filterPicker.getSelected());
748         }
749 }
750
751
752 function oilsRptDrawHavingWindow(path, col, cls, field) {
753         var tformPicker = new oilsRptTformPicker( {     
754                         node : DOM.oils_rpt_agg_filter_tform_table,
755                         datatype : field.datatype,
756                         aggregate : true
757                 }
758         );
759
760         var filterPicker = new oilsRptFilterPicker({
761                         node : DOM.oils_rpt_agg_filter_op_table,
762                         datatype : field.datatype
763                 }
764         );
765
766         DOM.oils_rpt_agg_filter_submit.onclick = function() {
767                 oilsAddRptHavingItem(
768                         path, tformPicker.getSelected(), filterPicker.getSelected());
769         }
770 }
771
772 /* draws the transform window */
773 function oilsRptDrawTransformWindow(path, col, cls, field) {
774         DOM.oils_rpt_tform_label_input.value = oilsRptMakeLabel(path);
775         var dtype = field.datatype;
776
777         var tformPicker = new oilsRptTformPicker( {     
778                         node : DOM.oils_rpt_tform_table,
779                         datatype : field.datatype,
780                         non_aggregate : true,
781                         aggregate : true
782                 }
783         );
784
785         DOM.oils_rpt_tform_submit.onclick = 
786                 function(){ 
787                         oilsAddRptDisplayItem(path, 
788                                 DOM.oils_rpt_tform_label_input.value, tformPicker.getSelected() );
789                 };
790
791         DOM.oils_rpt_tform_label_input.focus();
792         DOM.oils_rpt_tform_label_input.select();
793
794         _debug("Building transform window for datatype "+dtype);
795 }
796
797
798 //function oilsRptDrawOrderByWindow(path, col, cls, field) {
799 function oilsRptDrawOrderByWindow() {
800         var sel = DOM.oils_rpt_order_by_selector;
801         removeChildren(sel);
802         DOM.oils_rpt_order_by_submit.onclick = function() {
803                 oilsRptAddOrderBy(getSelectorVal(sel));
804         }
805
806         var cols = oilsRpt.def.select;
807         for( var i = 0; i < cols.length; i++ ) {
808                 var obj = cols[i];
809                 insertSelectorVal(sel, -1, obj.alias, obj.path);
810         }
811 }
812
813 function oilsRptAddOrderBy(path) {
814         var rel = hex_md5(oilsRptPathRel(path));
815         var order_by = oilsRpt.def.order_by;
816
817         /* if this item is already in the order by remove it and overwrite it */
818         order_by = grep(oilsRpt.def.order_by, 
819                 function(i) {return (i.path != path)});
820         
821         if(!order_by) order_by = [];
822
823         /* find the column definition in the select blob */
824         var obj = grep(oilsRpt.def.select,
825                 function(i) {return (i.path == path)});
826         
827         if(!obj) return;
828         obj = obj[0];
829         
830         order_by.push({ 
831                 relation : obj.relation, 
832                 column : obj.column,
833                 direction : getSelectorVal(DOM.oils_rpt_order_by_dir)
834         });
835
836         oilsRpt.def.order_by = order_by;
837         oilsRptDebug();
838 }
839
840
841