]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/reports/oils_rpt_builder.js
LP1889113 Staff catalog record holds sticky org select
[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 dojo.requireLocalization("openils.reports", "reports");
5
6 var rpt_strings = dojo.i18n.getLocalization("openils.reports", "reports");
7 var __dblclicks = {}; /* retain a cache of the selector value doubleclick event handlers */
8
9 function oilsInitReportBuilder() {
10         if(!oilsInitReports()) return false;
11         oilsReportBuilderReset();
12         DOM.oils_rpt_table.onclick = 
13                 function(){hideMe(DOM.oils_rpt_column_editor)};
14         oilsDrawRptTree(
15                 function() { 
16                         hideMe(DOM.oils_rpt_tree_loading); 
17                         unHideMe(DOM.oils_rpt_table); 
18                         oilsRptBuilderDrawClone(new CGI().param('ct'));
19                 }
20         );
21
22         DOM.oils_rpt_builder_save_template.onclick = oilsReportBuilderSave;
23 }
24
25 function oilsRptBuilderDrawClone(templateId) {
26         if(!templateId) return;
27         unHideMe(DOM.oils_rpt_builder_cloning);
28
29         oilsRptFetchTemplate(templateId,
30                 function(template) { oilsRptBuilderDrawClone2(template);}
31         );
32 }
33
34
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();
39
40         _debug(formatJSON(template.data()));
41
42         /* manually shove data into the display selectors */
43         var def = JSON2js(template.data());
44
45    /* --------------------------------------------------------------- */
46    /* hack to determine the higest existing param in the template */
47    matches = template.data().match(/::P\d/g);
48    var max = 0;
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;
52    }
53    oilsRptID2 = max + 1;
54    _debug("set next avail param to " + oilsRptID2);
55    //_debug('PARAM = ' + oilsRptNextParam());
56    //var x = null;
57    //x.blah();
58    /* --------------------------------------------------------------- */
59
60         var table = def.from.table;
61         var node;
62         for( var i in oilsIDL ) {
63                 node = oilsIDL[i];
64                 if( node.table == table ) {
65                         setSelector(DOM.oils_rpt_builder_type_selector, node.name);
66                         DOM.oils_rpt_builder_type_selector.onchange();
67                         break;
68                 }
69         }
70
71         iterate(def.select,
72                 function(item) {
73                         oilsAddRptDisplayItem(item.path, item.alias, item.column.transform)});
74
75         iterate(def.where,
76                 function(item) {
77                         oilsAddRptFilterItem(item.path, item.column.transform, oilsRptObjectKeys(item.condition)[0])});
78
79         iterate(def.having,
80                 function(item) {
81                         oilsAddRptHavingItem(item.path, item.column.transform, oilsRptObjectKeys(item.condition)[0])});
82
83         //oilsRpt.setTemplate(template); /* commented out with clone fix, *shouldn't* break anything */
84         oilsRpt.templateObject = null; /* simplify debugging */
85 }
86
87 function oilsReportBuilderReset() {
88         var n = (oilsRpt) ? oilsRpt.name : "";
89         oilsRpt = new oilsReport();
90         oilsRpt.name = n;
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();
99 }
100
101 function oilsReportBuilderSave() {
102
103         var tmpl = new rt();
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));
109
110         if(!confirm(dojo.string.substitute( rpt_strings.RPT_BUILDER_CONFIRM_SAVE, [tmpl.name(), tmpl.description()] )) )
111                 return;
112
113         debugFMObject(tmpl);
114         //return; /* XXX */
115
116         var req = new Request(OILS_RPT_CREATE_TEMPLATE, SESSION, tmpl);
117         req.request.alertEvent = false;
118         req.callback(
119                 function(r) {
120                         var res = r.getResultObject();
121                         if(checkILSEvent(res)) {
122                                 alertILSEvent(res);
123                         } else {
124                                 if( res && res != '0' ) {
125                                         oilsRptAlertSuccess();
126                                         _l('oils_rpt.xhtml');
127                                 } 
128                         }
129                 }
130         );
131         
132         req.send();
133 }
134
135
136
137 /* adds an item to the display window */
138 function oilsAddRptDisplayItem(path, name, tform, params) {
139
140         if( ! oilsAddSelectorItem( 
141                 {  selector : oilsRptDisplaySelector, 
142                         val : path, 
143                         label : name, 
144                         path : path, 
145                         type : 'display',
146                         transform : tform }) ) {
147                 return;
148         }
149
150         /* add the selected columns to the report output */
151         name = (name) ? name : oilsRptPathCol(path);
152         if( !tform ) tform = 'Bare';
153
154         var aggregate = oilsRptGetIsAgg(tform);
155
156         /* add this item to the select blob */
157         var sel = {
158                 relation: hex_md5(oilsRptPathRel(path)), 
159                 path : path,
160                 alias: name,
161                 column: { transform: tform, colname: oilsRptPathCol(path) }
162         };
163
164         if( params ) sel.column.params = params;
165         oilsRptAddSelectList(sel, tform);
166         mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
167         oilsRptDebug();
168 }
169
170 function oilsRptAddSelectList(obj, tform) {
171         if(!oilsRptGetIsAgg(tform)) {
172                 var select = [];
173                 var added = false;
174                 for( var i = 0; i < oilsRpt.def.select.length; i++ ) {
175                         var item = oilsRpt.def.select[i];
176
177                         /* shove the item in question in front of the first agg tform */
178                         if( !added && oilsRptGetIsAgg( item.column.transform ) ) {
179                                 select.push(obj);
180                                 added = true;
181                         }
182                         select.push(item);
183                 }
184
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);
188
189                 oilsRpt.def.select = select;
190
191                 if( added ) {
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,
196                                 function(item) {
197                                         _debug('re-inserting display item ' + item.path);
198                                         oilsAddSelectorItem(
199                                                 {  selector: oilsRptDisplaySelector, 
200                                                         val:item.path, 
201                                                         label:item.alias, 
202                                                         path:item.path,
203                                                         transform : item.column.transform,
204                                                         type : 'display'
205                                                 }
206                                         ) });
207                 }
208
209         } else {
210                 /* shove agg transforms onto the end */
211                 oilsRpt.def.select.push(obj);
212         }
213 }
214
215
216
217 function oilsRptGetIsAgg(tform) {
218         return OILS_RPT_TRANSFORMS[tform].aggregate;
219 }
220
221 /* takes a column path and builds a from-clause object for the path */
222 function oilsRptBuildFromClause(path) {
223
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(/-/);
227
228         /* the final from clause */
229         var obj = {}; 
230
231         /* reference to the current position in the from clause */
232         var tobj = obj; 
233
234         var newpath = "";
235
236    var last_is_left = false; /* true if our parent join is a 'left' join */
237
238         /* walk the path, fleshing the from clause as we go */
239         for( var i = 0; i < parts.length; i += 2 ) {
240
241                 var cls = parts[i]; /* class name (id) */
242                 var col = parts[i+1]; /* column name */
243
244                 /* a "node" is a class description from the IDL, it 
245                         contains relevant info, plus a list of "fields",
246                         or column objects */
247                 var node = oilsIDL[cls];
248                 var pkey = oilsRptFindField(node, node.pkey);
249
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);
253
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;
257
258                 /* extract relevant info */
259                 tobj.table = node.table;
260                 tobj.path = newpath;
261                 tobj.alias = hex_md5(newpath);
262
263                 _debug('field type is ' + field.type);
264                 if( i == (parts.length - 2) ) break;
265
266                 /* we still have columns left in the path, keep adding join's */
267                 var path_col = col;
268                 if(field.reltype != 'has_a')
269                         col = pkey.name + '-' + col;
270
271                 tobj.join = {};
272                 tobj = tobj.join;
273
274                 tobj[col] = {};
275                 tobj = tobj[col];
276                 if( field.type == 'link' ) {
277                         tobj.key = field.key;
278                         if( field.reltype == 'has_many' || field.reltype == 'might_have' || last_is_left ) {
279                                 tobj.type = 'left';
280             last_is_left = true;
281          } else {
282             last_is_left = false;
283          }
284                 }
285
286                 newpath = newpath + '-'+ path_col;
287         }
288
289         _debug("built 'from' clause: path="+path+"\n"+formatJSON(js2JSON(obj)));
290         return obj;
291 }
292
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;
299         idx--;
300
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');
305
306         opt = insertSelectorVal(sel, idx, label, val);
307
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);
313
314    /* re-attach the double-click event */
315         opt.addEventListener('dblclick', __dblclicks[evt_id], true );
316
317         sel.options[idx].selected = true;
318
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];
323                         arr[i-1] = arr[i];
324                         arr[i] = other;
325                         break;
326                 }
327         }
328         oilsRptDebug();
329 }
330
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;
337         idx++;
338
339         //var val = opt.getAttribute('value');
340         //insertSelectorVal(sel, idx, opt.innerHTML, val);
341         //insertSelectorVal(sel, idx, opt.getAttribute('label'), val);
342
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');
347
348         opt = insertSelectorVal(sel, idx, label, val);
349
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);
355
356    /* re-attach the double-click event */
357         opt.addEventListener('dblclick', __dblclicks[evt_id], true );
358
359         sel.options[idx].selected = true;
360
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];
365                         arr[i+1] = arr[i];
366                         arr[i] = other;
367                         break;
368                 }
369         }
370         oilsRptDebug();
371 }
372
373
374 /* removes a specific item from the display window */
375 /*
376 function oilsDelDisplayItem(val) {
377         oilsDelSelectorItem(oilsRptDisplaySelector, val);
378 }
379 */
380
381 /* removes selected items from the display window */
382 function oilsDelSelectedDisplayItems() {
383         var list = oilsDelSelectedItems(oilsRptDisplaySelector);
384
385         _debug('deleting list: ' + list);
386
387         /* remove the de-selected columns from the report output */
388         oilsRpt.def.select = grep( oilsRpt.def.select, 
389                 function(i) {
390                         for( var j = 0; j < list.length; j++ ) {
391                                 var d = list[j]; /* path */
392                                 var col = i.column;
393
394                                 _debug('in delete, looking at list = '+d+' : col = ' + 
395                                         col.colname + ' : relation = ' + i.relation + ' : encoded = ' + hex_md5(oilsRptPathRel(d)) );
396
397                                 if( hex_md5(oilsRptPathRel(d)) == i.relation && oilsRptPathCol(d) == col.colname ) {
398                                         return false;
399                                 }
400                         }
401                         return true;
402                 }
403         );
404
405         if(!oilsRpt.def.select) oilsRpt.def.select = [];
406         oilsRptPruneFromList(list);
407         oilsRptDebug();
408 }
409
410 function oilsRptPruneFromList(pathlist) {
411
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));
417
418                 debug('seeing if we can prune from clause with relation = ' + encrel +' : path = ' + path);
419
420                 var func = function(i){ return (i.relation == hex_md5(oilsRptPathRel(path))); };
421
422                 if(     !grep(oilsRpt.def.select, func) && 
423                                 !grep(oilsRpt.def.where, func) && 
424                                 !grep(oilsRpt.def.having, func) ) {
425
426                         debug('looks like we can prune ' + path);
427
428                         oilsRptPruneFromClause(oilsRptPathRel(pathlist[j]));
429                 }
430         }
431 }
432
433
434 /* for each item in the path list, remove the associated data
435         from the "from" clause */
436
437 function oilsRptPruneFromClause(relation, node) {
438
439         var keys = oilsRptObjectKeys(node);
440         _debug("trying to remove relation: " + relation+'\n\tthis object has keys: '+keys);
441
442         if(!node) node = oilsRpt.def.from.join;
443         if(!node) return false;
444
445         for( var i in node ) {
446                 var child_node = node[i];
447                 _debug("\tanalyzing child node: "+child_node.path);
448
449                 // first, descend into the tree, and prune leaves 
450                 if( child_node.join ) {
451
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+"]");
455
456                         if(join_keys.length == 0) {
457                                 _debug("\tdeleting join for object "+i);
458                                 delete child_node.join;
459                         }
460                 }
461
462                 if( !child_node.join ) {
463
464                         _debug("\tchild node has no sub-join, seeing if we should delete it");
465
466                         var from_alias = child_node.alias;
467                         var func = function(n){ return (n.relation == from_alias)};
468         
469                         if(     !grep(oilsRpt.def.select, func) &&
470                                         !grep(oilsRpt.def.where, func) &&
471                                         !grep(oilsRpt.def.having, func) ) {
472         
473                                 /* we are not used by any other clauses */
474                                 _debug("\tdeleting node with relation: "+ from_alias);
475                                 delete node[i];
476                                 return true;
477                         }
478                 }
479         }
480
481         return false;
482 }
483
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;
490
491         return [ name, epath ];
492 }
493
494
495 function oilsAddRptFilterItem(path, tform, filter) {
496         _debug("Adding filter item for "+path+" tform="+tform+" filter="+filter);
497
498         var name = oilsRptMkFilterTags(path, tform, filter);
499         var epath = name[1];
500         name = name[0];
501
502         if( ! oilsAddSelectorItem(
503                 {  selector : oilsRptFilterSelector, 
504                         val : epath, 
505                         label : name, 
506                         path : path,
507                         transform : tform,
508                         operation : filter,
509                         type : 'filter'
510                 }) )
511                 return;
512
513         var where = {
514                 relation: hex_md5(oilsRptPathRel(path)), 
515                 path : path,
516                 column:   { transform: tform, colname: oilsRptPathCol(path) },
517                 condition : {}
518         };
519
520    //_debug('NEXT PARAM = ' + oilsRptID2);
521    //_debug('NEXT PARAM = ' + oilsRptNextParam());
522
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();
526
527         switch(tform) {
528                 case 'substring' : where.column.params = oilsRptNextParam();
529         }
530
531         oilsRpt.def.where.push(where);
532         mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
533         oilsRptDebug();
534 }
535
536
537 function oilsAddRptHavingItem(path, tform, filter) {
538         _debug("Adding filter item for "+path+" tform="+tform+" filter="+filter);
539
540         var name = oilsRptMkFilterTags(path, tform, filter);
541         var epath = name[1];
542         name = name[0];
543
544         if( ! oilsAddSelectorItem(
545                 {  selector: oilsRptHavingSelector, 
546                         val:epath, 
547                         label:name, 
548                         path:path,
549                         transform : tform,
550                         operation : filter,
551                         type : 'agg_filter' /* XXX */
552                 }) )
553
554                 return;
555
556         var having = {
557                 relation: hex_md5(oilsRptPathRel(path)), 
558                 path : path,
559                 column:   { transform: tform, colname: oilsRptPathCol(path) },
560                 condition : {}
561         };
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();
565
566         switch(tform) {
567                 case 'substring' : having.column.params = oilsRptNextParam();
568         }
569
570         oilsRpt.def.having.push(having);
571         mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
572         oilsRptDebug();
573 }
574
575
576
577 function oilsDelSelectedFilterItems() {
578         _oilsDelSelectedFilterItems('where');
579 }
580 function oilsDelSelectedAggFilterItems() {
581         _oilsDelSelectedFilterItems('having');
582 }
583
584 function _oilsDelSelectedFilterItems(type) {
585
586         /* the values in this list are formed:  <path>:<operation>:<transform> */
587         var list;
588     if( type == 'where' )
589             list = oilsDelSelectedItems(oilsRptFilterSelector);
590     else if( type == 'having' )
591             list = oilsDelSelectedItems(oilsRptHavingSelector);
592
593         _debug("deleting filter items " + list);
594
595         for( var i = 0; i < list.length; i++ ) {
596                 var enc_path = list[i];
597                 var data = oilsRptParseFilterEncPath(enc_path);
598
599                 _debug("trimming filter items with enc_path = " + enc_path);
600                 _debug(data.path);
601                 _debug(data.operation);
602                 _debug(data.tform);
603                 _debug(data.tform);
604                 _debug(type);
605                 _debug('---------------------');
606
607                 oilsRpt.def[type] = grep( 
608                         oilsRpt.def[type],
609                         function(f) { 
610                                 return ! oilsRptFilterDataMatches( 
611                                         f, data.path, data.operation, data.tform );
612                         }
613                 );
614         }
615
616         if(!oilsRpt.def[type]) oilsRpt.def[type] = [];
617         oilsRptPruneFromList(list);
618         oilsRptDebug();
619 }
620
621 function oilsRptParseFilterEncPath(item) {
622         return {
623                 path:           item.replace(/:.*/,''),
624                 operation:      item.replace(/.*:(.*):.*/,'$1'),
625                 tform:  item.replace(/.*?:.*?:(.*)/,'$1')
626         };
627 }
628
629
630 function oilsRptFilterDataMatches(filter, path, operation, tform) {
631         var rel = hex_md5(oilsRptPathRel(path));
632         var col = oilsRptPathCol(path);
633
634         if(     col == filter.column.colname &&
635                         rel == filter.relation &&       
636                         tform == filter.column.transform &&
637                         operation == oilsRptObjectKeys(filter.condition)[0] ) return true;
638
639         return false;
640 }
641
642 /* adds an item to the display window */
643 /*
644 function oilsAddRptAggFilterItem(val) {
645         oilsAddSelectorItem({selector:oilsRptHavingFilterSelector, val:val, label:val, path:val});
646 }
647 */
648
649 /* removes a specific item from the display window */
650 /*
651 function oilsDelAggFilterItem(val) {
652         oilsDelSelectorItem(oilsRptHavingFilterSelector, val);
653 }
654 */
655
656
657 /* adds an item to the display window */
658 //function oilsAddSelectorItem(sel, val, name, path) {
659 function oilsAddSelectorItem(args) {
660
661         var sel = args.selector;
662         var label = args.label;
663         var path = args.path;
664         var val = args.val;
665
666         label = (label) ? label : oilsRptMakeLabel(val);
667
668         var i;
669         for( i = 0; i < sel.options.length; i++ ) {
670                 var opt = sel.options[i];
671                 if( opt.value == val ) return false;
672         }
673
674         var opt = insertSelectorVal( sel, -1, label, val );
675         opt.setAttribute('title', label);
676         opt.setAttribute('path', path);
677    opt.setAttribute('label', label);
678
679    var evt_id = oilsNextNumericId();
680    opt.setAttribute('listener', evt_id);
681
682         args.index = i;
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);
688
689         return true;
690 }
691
692
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++ ) {
697                 var opt = opts[i];
698                 if( opt.value == val )  {
699                         if( i == opts.length - 1 ) 
700                                 opts[i] = null;
701                         else opts[i] = opts[i+1];
702                         return;
703                 }
704         }
705 }
706
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]);
712         return list;
713 }
714
715
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);
722
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');
726 }
727
728
729 /**
730   This draws the 3-tabbed window containing the transform,
731   filter, and aggregate filter picker window
732   */
733 function oilsRptDrawDataWindow(path, args) {
734
735         args = (args) ? args : {};
736
737         for( var x in args ) 
738                 _debug("oilsRptDrawDataWindow(): args -> " + x + " = " + args[x]);
739
740         var col = oilsRptPathCol(path);
741         var cls = oilsRptPathClass(path);
742         var field = oilsRptFindField(oilsIDL[cls], col);
743
744         appendClear(DOM.oils_rpt_editor_window_label, text(oilsRptMakeLabel(path)));
745         appendClear(DOM.oils_rpt_editor_window_datatype, text(field.datatype));
746
747         _debug("setting update data window for column "+col+' on class '+cls);
748
749         var div = DOM.oils_rpt_column_editor;
750         /* set a preliminary top position so the page won't bounce around */
751
752
753         /* XXX */
754         //div.setAttribute('style','top:'+oilsMouseX+'px');
755
756         /* unhide the div so we can determine the dimensions */
757         unHideMe(div);
758
759         /* don't let them see the floating div until the position is fully determined */
760         div.style.visibility='hidden'; 
761
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);
766
767         //buildFloatingDiv(div, 600);
768
769         //window.scrollTo(0,0);
770         window.scrollTo(0, 60);
771
772         /* now let them see it */
773         div.style.visibility='visible';
774         //args.type = (args.type) ? args.type : 'display';
775         oilsRptSetDataWindowActions(div, args);
776 }
777
778
779 function oilsRptSetDataWindowActions(div, args) {
780         /* give the tab links behavior */
781
782         DOM.oils_rpt_tform_tab.onclick = 
783                 function(){
784                         oilsRptHideEditorDivs();
785                         unHideMe(DOM.oils_rpt_tform_div)
786                         addCSSClass(DOM.oils_rpt_tform_tab.parentNode, 'oils_rpt_tab_picker_selected');
787                 };
788
789         DOM.oils_rpt_filter_tab.onclick = 
790                 function(){
791                         oilsRptHideEditorDivs();
792                         unHideMe(DOM.oils_rpt_filter_div)
793                         addCSSClass(DOM.oils_rpt_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
794                 };
795
796         DOM.oils_rpt_agg_filter_tab.onclick = 
797                 function(){
798                         oilsRptHideEditorDivs();
799                         unHideMe(DOM.oils_rpt_agg_filter_div)
800                         addCSSClass(DOM.oils_rpt_agg_filter_tab.parentNode, 'oils_rpt_tab_picker_selected');
801                 };
802
803         /*
804         DOM.oils_rpt_order_by_tab.onclick = 
805                 function(){
806                         oilsRptHideEditorDivs();
807                         oilsRptDrawOrderByWindow();
808                         unHideMe(DOM.oils_rpt_order_by_div);
809                         };
810                         */
811
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;
815
816         if( !args.type ) {
817                 DOM.oils_rpt_tform_tab.onclick();
818         } else {
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;
823                 }
824                 if( args.type == 'filter' ) {
825                         DOM.oils_rpt_filter_tab.onclick();
826                         DOM.oils_rpt_filter_submit.disabled = true;
827                 }
828                 if( args.type == 'agg_filter' ) {
829                         DOM.oils_rpt_agg_filter_tab.onclick();
830                         DOM.oils_rpt_agg_filter_submit.disabled = true;
831                 }
832         }
833
834         DOM.oils_rpt_column_editor_close_button.onclick = function(){hideMe(div);};
835 }
836
837
838 function oilsRptDrawFilterWindow(path, col, cls, field, args) {
839
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
845                 }
846         );
847
848         var filterPicker = new oilsRptFilterPicker({
849                         node : DOM.oils_rpt_filter_op_table,
850                         datatype : field.datatype,
851                         select : args.operation
852                 }
853         );
854
855         DOM.oils_rpt_filter_submit.onclick = function() {
856                 oilsAddRptFilterItem(
857                         path, tformPicker.getSelected(), filterPicker.getSelected());
858         }
859 }
860
861
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,
866                         aggregate : true,
867                         select : args.transform
868                 }
869         );
870
871         var filterPicker = new oilsRptFilterPicker({
872                         node : DOM.oils_rpt_agg_filter_op_table,
873                         datatype : field.datatype,
874                         select : args.operation
875                 }
876         );
877
878         DOM.oils_rpt_agg_filter_submit.onclick = function() {
879                 oilsAddRptHavingItem(
880                         path, tformPicker.getSelected(), filterPicker.getSelected());
881         }
882 }
883
884 /* draws the transform window */
885 function oilsRptDrawTransformWindow(path, col, cls, field, args) {
886         args = (args) ? args : {};
887
888         DOM.oils_rpt_tform_label_input.value = 
889                 (args.label) ? args.label : oilsRptMakeLabel(path);
890
891         var dtype = field.datatype;
892
893         var tformPicker = new oilsRptTformPicker( {     
894                         node : DOM.oils_rpt_tform_table,
895                         datatype : field.datatype,
896                         non_aggregate : true,
897                         aggregate : true,
898                         select : args.transform
899                 }
900         );
901
902         DOM.oils_rpt_tform_submit.onclick = 
903                 function(){ 
904                         oilsAddRptDisplayItem(path, 
905                                 DOM.oils_rpt_tform_label_input.value, tformPicker.getSelected() );
906                 };
907
908         DOM.oils_rpt_tform_label_input.focus();
909         DOM.oils_rpt_tform_label_input.select();
910
911         _debug("Building transform window for datatype "+dtype);
912 }
913
914
915 //function oilsRptDrawOrderByWindow(path, col, cls, field) {
916 function oilsRptDrawOrderByWindow() {
917         var sel = DOM.oils_rpt_order_by_selector;
918         removeChildren(sel);
919         DOM.oils_rpt_order_by_submit.onclick = function() {
920                 oilsRptAddOrderBy(getSelectorVal(sel));
921         }
922
923         var cols = oilsRpt.def.select;
924         for( var i = 0; i < cols.length; i++ ) {
925                 var obj = cols[i];
926                 insertSelectorVal(sel, -1, obj.alias, obj.path);
927         }
928 }
929
930 function oilsRptAddOrderBy(path) {
931         var rel = hex_md5(oilsRptPathRel(path));
932         var order_by = oilsRpt.def.order_by;
933
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)});
937         
938         if(!order_by) order_by = [];
939
940         /* find the column definition in the select blob */
941         var obj = grep(oilsRpt.def.select,
942                 function(i) {return (i.path == path)});
943         
944         if(!obj) return;
945         obj = obj[0];
946         
947         order_by.push({ 
948                 relation : obj.relation, 
949                 column : obj.column,
950                 direction : getSelectorVal(DOM.oils_rpt_order_by_dir)
951         });
952
953         oilsRpt.def.order_by = order_by;
954         oilsRptDebug();
955 }
956
957
958