]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/reports/oils_rpt_builder.js
added left joins for has many / might_have links
[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                         if( field.reltype == 'has_many' || field.reltype == 'might_have' )
228                                 tobj.type = 'left';
229                 }
230
231                 newpath = newpath + '-'+ path_col;
232         }
233
234         _debug("built 'from' clause: path="+path+"\n"+formatJSON(js2JSON(obj)));
235         return obj;
236 }
237
238 function oilsMoveUpDisplayItems() {
239         var sel = oilsRptDisplaySelector;
240         var idx = sel.selectedIndex;
241         if( idx == 0 ) return;
242         var opt = sel.options[idx];
243         sel.options[idx] = null;
244         idx--;
245         var val = opt.getAttribute('value');
246         insertSelectorVal(sel, idx, opt.innerHTML, val);
247         sel.options[idx].selected = true;
248
249         var arr = oilsRpt.def.select;
250         for( var i = 0; i < arr.length; i++ ) {
251                 if( arr[i].path == val ) {
252                         var other = arr[i-1];
253                         arr[i-1] = arr[i];
254                         arr[i] = other;
255                         break;
256                 }
257         }
258         oilsRptDebug();
259 }
260
261 function oilsMoveDownDisplayItems() {
262         var sel = oilsRptDisplaySelector;
263         var idx = sel.selectedIndex;
264         if( idx == sel.options.length - 1 ) return;
265         var opt = sel.options[idx];
266         sel.options[idx] = null;
267         idx++;
268         var val = opt.getAttribute('value');
269         insertSelectorVal(sel, idx, opt.innerHTML, val);
270         sel.options[idx].selected = true;
271
272         var arr = oilsRpt.def.select;
273         for( var i = 0; i < arr.length; i++ ) {
274                 if( arr[i].path == val ) {
275                         var other = arr[i+1];
276                         arr[i+1] = arr[i];
277                         arr[i] = other;
278                         break;
279                 }
280         }
281         oilsRptDebug();
282 }
283
284
285 /* removes a specific item from the display window */
286 /*
287 function oilsDelDisplayItem(val) {
288         oilsDelSelectorItem(oilsRptDisplaySelector, val);
289 }
290 */
291
292 /* removes selected items from the display window */
293 function oilsDelSelectedDisplayItems() {
294         var list = oilsDelSelectedItems(oilsRptDisplaySelector);
295
296         _debug('deleting list: ' + list);
297
298         /* remove the de-selected columns from the report output */
299         oilsRpt.def.select = grep( oilsRpt.def.select, 
300                 function(i) {
301                         for( var j = 0; j < list.length; j++ ) {
302                                 var d = list[j]; /* path */
303                                 var col = i.column;
304
305                                 _debug('in delete, looking at list = '+d+' : col = ' + 
306                                         col.colname + ' : relation = ' + i.relation + ' : encoded = ' + hex_md5(oilsRptPathRel(d)) );
307
308                                 if( hex_md5(oilsRptPathRel(d)) == i.relation && oilsRptPathCol(d) == col.colname ) {
309                                         return false;
310                                 }
311                         }
312                         return true;
313                 }
314         );
315
316         if(!oilsRpt.def.select) oilsRpt.def.select = [];
317
318         oilsRptPruneFromList(list);
319
320         /*
321         for( var j = 0; j < list.length; j++ ) {
322                 debug('seeing if we can prune from clause with relation = ' + hex_md5(oilsRptPathRel(list[j])));
323                 if(     !grep(oilsRpt.def.select,
324                                 function(i){ return (i.relation == hex_md5(oilsRptPathRel(list[j]))); })
325                         && !grep(oilsRpt.def.where,
326                                 function(i){ return (i.relation == hex_md5(oilsRptPathRel(list[j]))); })
327                         && !grep(oilsRpt.def.having,
328                                 function(i){ return (i.relation == hex_md5(oilsRptPathRel(list[j]))); })
329                 ) {
330                         _debug('pruning from clause');
331                         oilsRptPruneFromClause(oilsRptPathRel(list[j]));
332                 }
333         }
334         */
335
336         oilsRptDebug();
337 }
338
339 function oilsRptPruneFromList(pathlist) {
340
341         for( var j = 0; j < pathlist.length; j++ ) {
342                 /* if there are no items left in the "select", "where", or "having" clauses 
343                         for the given relation, trim this relation from the "from" clause */
344                 var path = pathlist[j];
345                 var encrel = hex_md5(oilsRptPathRel(path));
346
347                 debug('seeing if we can prune from clause with relation = ' + encrel +' : path = ' + path);
348
349                 var func = function(i){ return (i.relation == hex_md5(oilsRptPathRel(path))); };
350
351                 if(     !grep(oilsRpt.def.select, func) && 
352                                 !grep(oilsRpt.def.where, func) && 
353                                 !grep(oilsRpt.def.having, func) ) {
354
355                         debug('looks like we can prune ' + path);
356
357                         oilsRptPruneFromClause(oilsRptPathRel(pathlist[j]));
358                 }
359         }
360 }
361
362
363 /* for each item in the path list, remove the associated data
364         from the "from" clause */
365
366 function oilsRptPruneFromClause(relation, node) {
367
368         var keys = oilsRptObjectKeys(node);
369         _debug("trying to remove relation: " + relation+'\n\tthis object has keys: '+keys);
370
371         if(!node) node = oilsRpt.def.from.join;
372         if(!node) return false;
373
374         for( var i in node ) {
375                 var child_node = node[i];
376                 _debug("\tanalyzing child node: "+child_node.path);
377
378                 // first, descend into the tree, and prune leaves 
379                 if( child_node.join ) {
380
381                         oilsRptPruneFromClause(relation, child_node.join); 
382                         var join_keys = oilsRptObjectKeys(child_node.join);
383                         _debug("\tchild has a sub-join for items : ["+ join_keys+"]");
384
385                         if(join_keys.length == 0) {
386                                 _debug("\tdeleting join for object "+i);
387                                 delete child_node.join;
388                         }
389                 }
390
391                 if( !child_node.join ) {
392
393                         _debug("\tchild node has no sub-join, seeing if we should delete it");
394
395                         var from_alias = child_node.alias;
396                         var func = function(n){ return (n.relation == from_alias)};
397         
398                         if(     !grep(oilsRpt.def.select, func) &&
399                                         !grep(oilsRpt.def.where, func) &&
400                                         !grep(oilsRpt.def.having, func) ) {
401         
402                                 /* we are not used by any other clauses */
403                                 _debug("\tdeleting node with relation: "+ from_alias);
404                                 delete node[i];
405                                 return true;
406                         }
407                 }
408         }
409
410         return false;
411 }
412
413 function oilsRptMkFilterTags(path, tform, filter) {
414         var name = oilsRptMakeLabel(path);
415         if(tform) name += ' ('+tform+')';
416         name += ' "' + filter + '"';
417         var epath = path + ':'+filter+':';
418         if(tform) epath += tform;
419
420         return [ name, epath ];
421 }
422
423
424 function oilsAddRptFilterItem(path, tform, filter) {
425         _debug("Adding filter item for "+path+" tform="+tform+" filter="+filter);
426
427         var name = oilsRptMkFilterTags(path, tform, filter);
428         var epath = name[1];
429         name = name[0];
430
431         if( ! oilsAddSelectorItem(oilsRptFilterSelector, epath, name) )
432                 return;
433
434         var where = {
435                 relation: hex_md5(oilsRptPathRel(path)), 
436                 path : path,
437                 column:   { transform: tform, colname: oilsRptPathCol(path) },
438                 condition : {}
439         };
440         if( filter == 'is' || filter == 'is not' )
441                 where.condition[filter] = null;
442         else where.condition[filter] = oilsRptNextParam();
443
444         switch(tform) {
445                 case 'substring' : where.column.params = oilsRptNextParam();
446         }
447
448         oilsRpt.def.where.push(where);
449         mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
450         oilsRptDebug();
451 }
452
453
454 function oilsAddRptHavingItem(path, tform, filter) {
455         _debug("Adding filter item for "+path+" tform="+tform+" filter="+filter);
456
457         var name = oilsRptMkFilterTags(path, tform, filter);
458         var epath = name[1];
459         name = name[0];
460
461         if( ! oilsAddSelectorItem(oilsRptHavingSelector, epath, name) )
462                 return;
463
464         var having = {
465                 relation: hex_md5(oilsRptPathRel(path)), 
466                 path : path,
467                 column:   { transform: tform, colname: oilsRptPathCol(path) },
468                 condition : {}
469         };
470         if( filter == 'is' || filter == 'is not' )
471                 having.condition[filter] = null;
472         else having.condition[filter] = oilsRptNextParam();
473
474         switch(tform) {
475                 case 'substring' : having.column.params = oilsRptNextParam();
476         }
477
478         oilsRpt.def.having.push(having);
479         mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
480         oilsRptDebug();
481 }
482
483
484
485 function oilsDelSelectedFilterItems() {
486         _oilsDelSelectedFilterItems('where');
487 }
488 function oilsDelSelectedAggFilterItems() {
489         _oilsDelSelectedFilterItems('having');
490 }
491
492 function _oilsDelSelectedFilterItems(type) {
493
494         /* the values in this list are formed:  <path>:<operation>:<transform> */
495         var list = oilsDelSelectedItems(oilsRptFilterSelector);
496
497         for( var i = 0; i < list.length; i++ ) {
498                 var enc_path = list[i];
499                 var data = oilsRptParseFilterEncPath(enc_path);
500                 oilsRpt.def[type] = grep( 
501                         oilsRpt.def[type],
502                         function(f) { 
503                                 return oilsRptFilterDataMatches( 
504                                         f, data.path, data.operation, data.tform );
505                         }
506                 );
507         }
508
509         if(!oilsRpt.def[type]) oilsRpt.def[type] = [];
510         oilsRptPruneFromList(list);
511         oilsRptDebug();
512 }
513
514 function oilsRptParseFilterEncPath(item) {
515         return {
516                 path:           item.replace(/:.*/,''),
517                 operation:      item.replace(/.*:(.*):.*/,'$1'),
518                 tform:  item.replace(/.*?:.*?:(.*)/,'$1')
519         };
520 }
521
522
523 function oilsRptFilterDataMatches(filter, path, operation, tform) {
524         var rel = hex_md5(oilsRptPathRel(path));
525         var col = oilsRptPathCol(path);
526
527         if(     col == filter.column.colname &&
528                         rel == filter.relation &&       
529                         tform == filter.column.transform &&
530                         operation == oilsRptObjectKeys(filter)[0] ) return true;
531
532         return false;
533 }
534
535 /*
536 function oilsRptFilterGrep(flist, filter) {
537
538         for( var j = 0; j < flist.length; j++ ) {
539
540                 var fil = flist[j];
541                 var col = filter.column;
542                 var frel = hex_md5(oilsRptPathRel(fil.path));
543                 var fcol = oilsRptPathCol(fil.path);
544
545                 var op = oilsRptObjectKeys(filter.condition)[0];
546
547                 if(     frel == filter.relation && 
548                                 fcol == col.colname && 
549                                 fil.operation == op &&
550                                 fil.tform == col.transform ) {
551                                 return false;
552                 }
553         }
554         return true;
555 }
556 */
557
558 /* adds an item to the display window */
559 function oilsAddRptAggFilterItem(val) {
560         oilsAddSelectorItem(oilsRptHavingFilterSelector, val);
561 }
562
563 /* removes a specific item from the display window */
564 function oilsDelAggFilterItem(val) {
565         oilsDelSelectorItem(oilsRptHavingFilterSelector, val);
566 }
567
568
569
570 /*
571 function ___oilsDelSelectedAggFilterItems() {
572         var list = oilsDelSelectedItems(oilsRptHavingFilterSelector);
573         oilsRpt.def.having = grep( oilsRpt.def.having, 
574                 function(i) {
575                         for( var j = 0; j < list.length; j++ ) {
576                                 var d = list[j];
577                                 var col = i.column;
578
579                                 if( typeof col != 'string' ) 
580                                         for( var c in col ) col = col[c];
581
582                                 if( typeof col != 'string' ) col = col[0];
583
584                                 if( oilsRptPathRel(d) == i.relation && oilsRptPathCol(d) == col ) {
585                                 */
586                                 //      var param = (i.alias) ? i.alias.match(/::P\d*/) : null;
587                                         /*
588                                         if( param ) delete oilsRpt.params[param];
589                                         return false;
590                                 }
591                         }
592                         return true;
593                 }
594         );
595
596         if(!oilsRpt.def.having) oilsRpt.def.having = [];
597         oilsRptPruneFromList(list);
598         oilsRptDebug();
599 }
600 */
601
602
603 /* adds an item to the display window */
604 function oilsAddSelectorItem(sel, val, name) {
605         name = (name) ? name : oilsRptMakeLabel(val);
606         for( var i = 0; i < sel.options.length; i++ ) {
607                 var opt = sel.options[i];
608                 if( opt.value == val ) return false;
609         }
610         var opt = insertSelectorVal( sel, -1, name, val );
611         opt.setAttribute('title', name);
612         return true;
613 }
614
615
616 /* removes a specific item from the display window */
617 function oilsDelSelectorItem(sel, val) {
618         var opts = sel.options;
619         for( var i = 0; i < opts.length; i++ ) {
620                 var opt = opts[i];
621                 if( opt.value == val )  {
622                         if( i == opts.length - 1 ) 
623                                 opts[i] = null;
624                         else opts[i] = opts[i+1];
625                         return;
626                 }
627         }
628 }
629
630 /* removes selected items from the display window */
631 function oilsDelSelectedItems(sel) {
632         var list = getSelectedList(sel);
633         for( var i = 0; i < list.length; i++ ) 
634                 oilsDelSelectorItem(sel, list[i]);
635         return list;
636 }
637
638
639 /* hides the different field editor tabs */
640 function oilsRptHideEditorDivs() {
641         hideMe(DOM.oils_rpt_tform_div);
642         hideMe(DOM.oils_rpt_filter_div);
643         hideMe(DOM.oils_rpt_agg_filter_div);
644         hideMe(DOM.oils_rpt_order_by_div);
645
646         removeCSSClass(DOM.oils_rpt_tform_tab.parentNode, 'oils_rpt_tab_picker_selected');
647         removeCSSClass(DOM.oils_rpt_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
648         removeCSSClass(DOM.oils_rpt_agg_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
649 }
650
651
652 /**
653   This draws the 3-tabbed window containing the transform,
654   filter, and aggregate filter picker window
655   */
656 function oilsRptDrawDataWindow(path) {
657         var col = oilsRptPathCol(path);
658         var cls = oilsRptPathClass(path);
659         var field = oilsRptFindField(oilsIDL[cls], col);
660
661         appendClear(DOM.oils_rpt_editor_window_label, text(oilsRptMakeLabel(path)));
662         appendClear(DOM.oils_rpt_editor_window_datatype, text(field.datatype));
663
664         _debug("setting update data window for column "+col+' on class '+cls);
665
666         var div = DOM.oils_rpt_column_editor;
667         /* set a preliminary top position so the page won't bounce around */
668
669
670         /* XXX */
671         //div.setAttribute('style','top:'+oilsMouseX+'px');
672
673         /* unhide the div so we can determine the dimensions */
674         unHideMe(div);
675
676         /* don't let them see the floating div until the position is fully determined */
677         div.style.visibility='hidden'; 
678
679         oilsRptDrawTransformWindow(path, col, cls, field);
680         oilsRptDrawFilterWindow(path, col, cls, field);
681         oilsRptDrawHavingWindow(path, col, cls, field);
682         oilsRptDrawOrderByWindow(path, col, cls, field);
683
684         //buildFloatingDiv(div, 600);
685
686         //window.scrollTo(0,0);
687         window.scrollTo(0, 60);
688
689         /* now let them see it */
690         div.style.visibility='visible';
691         oilsRptSetDataWindowActions(div);
692 }
693
694
695 function oilsRptSetDataWindowActions(div) {
696         /* give the tab links behavior */
697
698
699         DOM.oils_rpt_tform_tab.onclick = 
700                 function(){
701                         oilsRptHideEditorDivs();
702                         unHideMe(DOM.oils_rpt_tform_div)
703                         addCSSClass(DOM.oils_rpt_tform_tab.parentNode, 'oils_rpt_tab_picker_selected');
704                 };
705
706         DOM.oils_rpt_filter_tab.onclick = 
707                 function(){
708                         oilsRptHideEditorDivs();
709                         unHideMe(DOM.oils_rpt_filter_div)
710                         addCSSClass(DOM.oils_rpt_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
711                 };
712         DOM.oils_rpt_agg_filter_tab.onclick = 
713                 function(){
714                         oilsRptHideEditorDivs();
715                         unHideMe(DOM.oils_rpt_agg_filter_div)
716                         addCSSClass(DOM.oils_rpt_agg_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
717                 };
718
719         /*
720         DOM.oils_rpt_order_by_tab.onclick = 
721                 function(){
722                         oilsRptHideEditorDivs();
723                         oilsRptDrawOrderByWindow();
724                         unHideMe(DOM.oils_rpt_order_by_div);
725                         };
726                         */
727
728         DOM.oils_rpt_tform_tab.onclick();
729         DOM.oils_rpt_column_editor_close_button.onclick = function(){hideMe(div);};
730 }
731
732
733 function oilsRptDrawFilterWindow(path, col, cls, field) {
734
735         var tformPicker = new oilsRptTformPicker( {     
736                         node : DOM.oils_rpt_filter_tform_table,
737                         datatype : field.datatype,
738                         non_aggregate : true
739                 }
740         );
741
742         var filterPicker = new oilsRptFilterPicker({
743                         node : DOM.oils_rpt_filter_op_table,
744                         datatype : field.datatype
745                 }
746         );
747
748         DOM.oils_rpt_filter_submit.onclick = function() {
749                 oilsAddRptFilterItem(
750                         path, tformPicker.getSelected(), filterPicker.getSelected());
751         }
752 }
753
754
755 function oilsRptDrawHavingWindow(path, col, cls, field) {
756         var tformPicker = new oilsRptTformPicker( {     
757                         node : DOM.oils_rpt_agg_filter_tform_table,
758                         datatype : field.datatype,
759                         aggregate : true
760                 }
761         );
762
763         var filterPicker = new oilsRptFilterPicker({
764                         node : DOM.oils_rpt_agg_filter_op_table,
765                         datatype : field.datatype
766                 }
767         );
768
769         DOM.oils_rpt_agg_filter_submit.onclick = function() {
770                 oilsAddRptHavingItem(
771                         path, tformPicker.getSelected(), filterPicker.getSelected());
772         }
773 }
774
775 /* draws the transform window */
776 function oilsRptDrawTransformWindow(path, col, cls, field) {
777         DOM.oils_rpt_tform_label_input.value = oilsRptMakeLabel(path);
778         var dtype = field.datatype;
779
780         var tformPicker = new oilsRptTformPicker( {     
781                         node : DOM.oils_rpt_tform_table,
782                         datatype : field.datatype,
783                         non_aggregate : true,
784                         aggregate : true
785                 }
786         );
787
788         DOM.oils_rpt_tform_submit.onclick = 
789                 function(){ 
790                         oilsAddRptDisplayItem(path, 
791                                 DOM.oils_rpt_tform_label_input.value, tformPicker.getSelected() );
792                 };
793
794         DOM.oils_rpt_tform_label_input.focus();
795         DOM.oils_rpt_tform_label_input.select();
796
797         _debug("Building transform window for datatype "+dtype);
798 }
799
800
801 //function oilsRptDrawOrderByWindow(path, col, cls, field) {
802 function oilsRptDrawOrderByWindow() {
803         var sel = DOM.oils_rpt_order_by_selector;
804         removeChildren(sel);
805         DOM.oils_rpt_order_by_submit.onclick = function() {
806                 oilsRptAddOrderBy(getSelectorVal(sel));
807         }
808
809         var cols = oilsRpt.def.select;
810         for( var i = 0; i < cols.length; i++ ) {
811                 var obj = cols[i];
812                 insertSelectorVal(sel, -1, obj.alias, obj.path);
813         }
814 }
815
816 function oilsRptAddOrderBy(path) {
817         var rel = hex_md5(oilsRptPathRel(path));
818         var order_by = oilsRpt.def.order_by;
819
820         /* if this item is already in the order by remove it and overwrite it */
821         order_by = grep(oilsRpt.def.order_by, 
822                 function(i) {return (i.path != path)});
823         
824         if(!order_by) order_by = [];
825
826         /* find the column definition in the select blob */
827         var obj = grep(oilsRpt.def.select,
828                 function(i) {return (i.path == path)});
829         
830         if(!obj) return;
831         obj = obj[0];
832         
833         order_by.push({ 
834                 relation : obj.relation, 
835                 column : obj.column,
836                 direction : getSelectorVal(DOM.oils_rpt_order_by_dir)
837         });
838
839         oilsRpt.def.order_by = order_by;
840         oilsRptDebug();
841 }
842
843
844