]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/reports/xul/template-config.js
introduce the saving logic
[Evergreen.git] / Open-ILS / web / reports / xul / template-config.js
1 function removeReportAtom (args) {
2         if (!args) args = {};
3
4         var active_tab = filterByAttribute(
5                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
6                 'selected',
7                 'true'
8         )[0];
9         var tabname = active_tab.getAttribute('id');
10
11         var tabpanel = $( tabname + 'panel' );
12         var tree = tabpanel.getElementsByTagName('tree')[0];
13         var fields = getSelectedItems(tree);
14
15
16         for (var i in fields) {
17                 var field = fields[i];
18                 var colname = field.firstChild.firstChild.nextSibling.getAttribute('label');
19                 var relation_alias = field.getAttribute('relation');
20
21                 delete rpt_rel_cache[relation_alias].fields[tabname][colname];
22                 if (tabname == 'dis_tab') {
23                         var _o_tmp = [];
24                         for each (var _o_col in rpt_rel_cache.order_by) {
25                                 if (_o_col.relation == relation_alias && _o_col.field == colname) continue;
26                                 _o_tmp.push( _o_col );
27                         }
28                         rpt_rel_cache.order_by = _o_tmp
29                 }
30
31                 with (rpt_rel_cache[relation_alias].fields) {
32                         if ( getKeys(dis_tab).length == 0 && getKeys(filter_tab).length == 0 && getKeys(aggfilter_tab).length == 0 )
33                                 delete rpt_rel_cache[relation_alias];
34                 }
35         }
36
37         renderSources();
38 }
39
40 function addReportAtoms () {
41         var nope = $( 'source-add' ).getAttribute('disabled');
42         if (nope == 'true') return false;
43
44         var class_tree = $('class-view');
45         var transform_tree = $('trans-view');
46
47         var active_tab = filterByAttribute(
48                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
49                 'selected',
50                 'true'
51         )[0];
52
53         var tabname = active_tab.getAttribute('id')
54
55         var items = getSelectedItems(class_tree);
56         var transform = getSelectedItems(transform_tree)[0];
57
58         var reltype = $('path-label').getAttribute('reltype');
59         var class_label = $('path-label').value;
60         var relation_alias = hex_md5(class_label);
61
62         for (var i in items) {
63                 var item = items[i];
64
65                 var class_path = item.getAttribute('fullpath');
66                 var field_class = item.getAttribute('idlclass');
67                 var datatype = item.getAttribute('datatype');
68                 var colname = item.getAttribute('idlfield');
69                 var field_label = item.firstChild.firstChild.getAttribute('label');
70
71                 var table_name = getIDLClass(field_class).getAttributeNS(persistNS,'tablename');
72
73                 if ( !rpt_rel_cache[relation_alias] ) {
74                         rpt_rel_cache[relation_alias] =
75                                 { label : class_label,
76                                   alias : relation_alias,
77                                   path  : class_path,
78                                   reltype  : reltype,
79                                   idlclass  : field_class,
80                                   table : table_name,
81                                   fields: { dis_tab : {}, filter_tab : {}, aggfilter_tab : {} }
82                                 };
83                 }
84
85                 if ( !rpt_rel_cache[relation_alias].fields[tabname][colname] ) {
86                         rpt_rel_cache[relation_alias].fields[tabname][colname] =
87                                 { colname   : colname,
88                                   transform : (transform && transform.getAttribute('name')) || 'Bare',
89                                   aggregate : transform && transform.getAttribute('aggregate'),
90                                   params    : transform && transform.getAttribute('params'),
91                                   transform_label: (transform && transform.getAttribute('alias')) || 'Raw Data',
92                                   alias     : field_label,
93                                   datatype  : datatype,
94                                   op        : '=',
95                                   op_label  : 'Equals',
96                                   op_value  : {},
97                                 };
98
99                         if (!rpt_rel_cache.order_by)
100                                 rpt_rel_cache.order_by = [];
101
102                         if (tabname == 'dis_tab')
103                                 rpt_rel_cache.order_by.push( { relation : relation_alias, field : colname } );
104
105                 } else if (
106                         confirm(
107                                 'You have already added the [' + field_label +
108                                 '] field\nfrom the [' + class_label + '] source. Click OK if you\nwould like ' +
109                                 'to reset this field.'
110                         )
111                 ) {
112                         rpt_rel_cache[relation_alias].fields[tabname][colname] =
113                                 { colname   : colname,
114                                   transform : (transform && transform.getAttribute('name')) || 'Bare',
115                                   aggregate : transform && transform.getAttribute('aggregate'),
116                                   params    : transform && transform.getAttribute('params'),
117                                   transform_label: (transform && transform.getAttribute('alias')) || 'Raw Data',
118                                   alias     : field_label,
119                                   datatype  : datatype,
120                                   op        : '=',
121                                   op_label  : 'Equals',
122                                   op_value  : {},
123                                 };
124                 }
125         }
126
127         renderSources();
128 }
129
130 function changeDisplayOrder (dir) {
131         var active_tab = filterByAttribute(
132                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
133                 'selected',
134                 'true'
135         )[0];
136
137         var tabname = active_tab.getAttribute('id');
138
139         var tabpanel = $( tabname + 'panel' );
140         var tree = tabpanel.getElementsByTagName('tree')[0];
141         var item = getSelectedItems(tree)[0];
142
143         var item_pos = tree.view.selection.currentIndex;
144
145         if (dir == 'u') {
146                 if ( item.previousSibling ) {
147                         item.parentNode.insertBefore( item, item.previousSibling );
148                         item_pos--;
149                 }
150         } else if (dir == 'd') {
151                 if ( item.nextSibling ) {
152                         if (item.nextSibling.nextSibling ) item.parentNode.insertBefore( item, item.nextSibling.nextSibling );
153                         else item.parentNode.appendChild( item );
154                         item_pos++;
155                 }
156         }
157         
158         rpt_rel_cache.order_by = [];
159         var ordered_list = tree.getElementsByTagName('treeitem');
160         for (var i = 0; i < ordered_list.length; i++) {
161                 rpt_rel_cache.order_by.push(
162                         { relation : ordered_list[i].getAttribute('relation'),
163                           field    : ordered_list[i].firstChild.firstChild.nextSibling.getAttribute('label')
164                         }
165                 );
166         }
167
168         tree.view.selection.select( item_pos );
169 }
170
171 function alterColumnLabel () {
172         var active_tab = filterByAttribute(
173                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
174                 'selected',
175                 'true'
176         )[0];
177
178         var tabname = active_tab.getAttribute('id');
179
180         var tabpanel = $( tabname + 'panel' );
181         var tree = tabpanel.getElementsByTagName('tree')[0];
182         var items = getSelectedItems(tree);
183
184         for (var i in items) {
185                 var item = items[i];
186                 var relation_alias = item.getAttribute('relation');
187
188                 var field = item.firstChild.firstChild;
189                 var colname = field.nextSibling.getAttribute('label');
190
191                 var new_label = prompt(
192                         "Change the column header to:",
193                         field.getAttribute("label")
194                 );
195
196                 if (new_label) {
197                         rpt_rel_cache[relation_alias].fields[tabname][colname].alias = new_label;
198                         renderSources(true);
199                 }
200         }
201 }
202
203 function alterColumnTransform (trans) {
204
205         var transform = OILS_RPT_TRANSFORMS[trans];
206
207         var active_tab = filterByAttribute(
208                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
209                 'selected',
210                 'true'
211         )[0];
212
213         var tabname = active_tab.getAttribute('id');
214
215         var tabpanel = $( tabname + 'panel' );
216         var tree = tabpanel.getElementsByTagName('tree')[0];
217         var items = getSelectedItems(tree);
218
219         for (var i in items) {
220                 var item = items[i];
221                 var relation_alias = item.getAttribute('relation');
222
223                 var field = item.firstChild.firstChild;
224                 var colname = field.nextSibling.getAttribute('label');
225
226                 rpt_rel_cache[relation_alias].fields[tabname][colname].transform = trans;
227                 rpt_rel_cache[relation_alias].fields[tabname][colname].aggregate = transform.aggregate;
228                 rpt_rel_cache[relation_alias].fields[tabname][colname].params = transform.params;
229                 rpt_rel_cache[relation_alias].fields[tabname][colname].transform_label = transform.label;
230
231         }
232
233         renderSources(true);
234         return true;
235 }
236
237 function changeOperator (args) {
238
239         var active_tab = filterByAttribute(
240                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
241                 'selected',
242                 'true'
243         )[0];
244
245         var tabname = active_tab.getAttribute('id');
246
247         var tabpanel = $( tabname + 'panel' );
248         var tree = tabpanel.getElementsByTagName('tree')[0];
249         var items = getSelectedItems(tree);
250
251         for (var i in items) {
252                 var item = items[i];
253                 var relation_alias = item.getAttribute('relation');
254
255                 var field = item.firstChild.firstChild;
256                 var colname = field.nextSibling.getAttribute('label');
257
258                 rpt_rel_cache[relation_alias].fields[tabname][colname].op = args.op;
259                 rpt_rel_cache[relation_alias].fields[tabname][colname].op_label = args.label;
260
261         }
262
263         renderSources(true);
264         return true;
265 }
266
267 function removeTemplateFilterValue () {
268
269         var active_tab = filterByAttribute(
270                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
271                 'selected',
272                 'true'
273         )[0];
274
275         var tabname = active_tab.getAttribute('id');
276
277         var tabpanel = $( tabname + 'panel' );
278         var tree = tabpanel.getElementsByTagName('tree')[0];
279         var items = getSelectedItems(tree);
280
281         for (var i in items) {
282                 var item = items[i];
283                 var relation_alias = item.getAttribute('relation');
284
285                 var field = item.firstChild.firstChild;
286                 var colname = field.nextSibling.getAttribute('label');
287
288                 rpt_rel_cache[relation_alias].fields[tabname][colname].op_value = {};
289         }
290
291         renderSources(true);
292 }
293
294 function timestampSetDate (obj, cal, date) {
295         obj.op_value.value = date;
296         obj.op_value.object = cal.date;
297         obj.op_value.label = '"' + date + '"';
298
299         renderSources(true);
300 }
301
302 var __handler_cache;
303
304 function changeTemplateFilterValue () {
305
306         var active_tab = filterByAttribute(
307                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
308                 'selected',
309                 'true'
310         )[0];
311
312         var tabname = active_tab.getAttribute('id');
313
314         var tabpanel = $( tabname + 'panel' );
315         var tree = tabpanel.getElementsByTagName('tree')[0];
316         var items = getSelectedItems(tree);
317
318         var targetCmd = $( tabname + '_value_action' );
319
320         targetCmd.menu = null;
321         targetCmd.command = null;
322         targetCmd.oncommand = null;
323         targetCmd.removeEventListener( 'command', __handler_cache, true );
324
325         for (var i in items) {
326                 var item = items[i];
327                 var relation_alias = item.getAttribute('relation');
328
329                 var field = item.firstChild.firstChild;
330                 var colname = field.nextSibling.getAttribute('label');
331
332                 var obj = rpt_rel_cache[relation_alias].fields[tabname][colname]
333                 var operation = OILS_RPT_FILTERS[obj.op];
334
335                 switch (obj.datatype) {
336                         case 'timestamp':
337                                 var cal_popup = $('calendar-widget');
338
339                                 while (cal_popup.firstChild) cal_popup.removeChild(cal_popup.lastChild);
340                                 var calendar = new Calendar(
341                                         0,
342                                         obj.op_value.object,
343                                         function (cal,date) { timestampSetDate(obj,cal,date) },
344                                         function (cal) { cal_popup.hidePopup(); cal.destroy(); }
345                                 );
346
347                                 var format = OILS_RPT_TRANSFORMS[obj.transform].cal_format || '%Y-%m-%d';
348
349                                 calendar.setDateFormat(format);
350                                 calendar.create(cal_popup);
351
352                                 targetCmd.menu = 'calendar-widget';
353
354                                 break;
355
356                         case 'bool':
357
358                                 function __bool_value_event_handler () {
359                                         var state, answer;
360
361                                         try {
362                                                 // get a reference to the prompt service component.
363                                                 var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
364                                                                     .getService(Components.interfaces.nsIPromptService);
365
366                                                 // set the buttons that will appear on the dialog. It should be
367                                                 // a set of constants multiplied by button position constants. In this case,
368                                                 // three buttons appear, Save, Cancel and a custom button.
369                                                 var flags=promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0 +
370                                                         promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_1 +
371                                                         promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_2;
372
373                                                 // display the dialog box. The flags set above are passed
374                                                 // as the fourth argument. The next three arguments are custom labels used for
375                                                 // the buttons, which are used if BUTTON_TITLE_IS_STRING is assigned to a
376                                                 // particular button. The last two arguments are for an optional check box.
377                                                 answer = promptService.select(
378                                                         window,
379                                                         "Boolean Value",
380                                                         "Select the value, or cancel:",
381                                                         2, ["True", "False"], state
382                                                 );
383                                         } catch (e) {
384                                                 answer = true;
385                                                 state = confirm("Click OK for TRUE and Cancel for FALSE.");
386                                                 state ? state = 0 : state = 1;
387                                         }
388
389                                         if (answer) {
390                                                 if (state) {
391                                                         obj.op_value.value = 'f';
392                                                         obj.op_value.label = 'False';
393                                                 } else {
394                                                         obj.op_value.value = 't';
395                                                         obj.op_value.label = 'True';
396                                                 }
397                                         }
398
399                                         targetCmd.removeEventListener( 'command', __bool_value_event_handler, true );
400                                         renderSources(true);
401                                 }
402
403                                 __handler_cache = __bool_value_event_handler;
404                                 targetCmd.addEventListener( 'command', __bool_value_event_handler, true );
405
406                                 break;
407
408                         default:
409
410
411                                 var promptstring = "Field does not match one of list (comma separated):";
412
413                                 switch (obj.op) {
414                                         case 'not between':
415                                                 promptstring = "Field value is not between (comma separated):";
416                                                 break;
417
418                                         case 'between':
419                                                 promptstring = "Field value is between (comma separated):";
420                                                 break;
421
422                                         case 'not in':
423                                                 promptstring = "Field does not match one of list (comma separated):";
424                                                 break;
425
426                                         case 'in':
427                                                 promptstring = "Field matches one of list (comma separated):";
428                                                 break;
429
430                                         default:
431                                                 promptstring = "Value " + obj.op_label + ":";
432                                                 break;
433                                 }
434
435                                 function __default_value_event_handler () {
436                                         var _v;
437                                         if (_v  = prompt( promptstring, obj.op_value.value || '' )) {
438                                                 switch (obj.op) {
439                                                         case 'between':
440                                                         case 'not between':
441                                                         case 'not in':
442                                                         case 'in':
443                                                                 obj.op_value.value = _v.split(/\s*,\s*/);
444                                                                 break;
445
446                                                         default:
447                                                                 obj.op_value.value = _v;
448                                                                 break;
449                                                 }
450
451                                                 obj.op_value.label = '"' + obj.op_value.value + '"';
452                                         }
453
454                                         targetCmd.removeEventListener( 'command', __default_value_event_handler, true );
455                                         renderSources(true);
456                                 }
457
458                                 __handler_cache = __default_value_event_handler;
459                                 targetCmd.addEventListener( 'command', __default_value_event_handler, true );
460
461                                 break;
462                 }
463         }
464
465         //renderSources(true);
466 }
467
468 function populateOperatorContext () {
469
470         var active_tab = filterByAttribute(
471                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
472                 'selected',
473                 'true'
474         )[0];
475
476         var tabname = active_tab.getAttribute('id');
477
478         var tabpanel = $( tabname + 'panel' );
479         var tree = tabpanel.getElementsByTagName('tree')[0];
480         var items = getSelectedItems(tree);
481
482         var dtypes = [];
483         for (var i in items) {
484                 var item = items[i];
485                 dtypes.push( item.getAttribute('datatype') );
486         }
487
488         var menu = $(tabname + '_op_menu');
489         while (menu.firstChild) menu.removeChild(menu.lastChild);
490
491         for (var i in OILS_RPT_FILTERS) {
492                 var o = OILS_RPT_FILTERS[i];
493                 menu.appendChild(
494                         createMenuItem(
495                                 { label : o.label,
496                                   oncommand : "changeOperator({op:'"+i+"',label:'"+o.label+"'})",
497                                 }
498                         )
499                 );
500                 if (o.labels) {
501                         var keys = getKeys(o.labels);
502                         for ( var k in keys ) {
503                                 var key = keys[k];
504                                 if ( grep(function(x){return key==x},dtypes).length ) {
505                                         menu.appendChild(
506                                                 createMenuItem(
507                                                         { label : o.labels[key],
508                                                           oncommand : "changeOperator({op:'"+i+"',label:'"+o.labels[key]+"'})",
509                                                         }
510                                                 )
511                                         );
512                                 }
513                         }
514                 }
515         }
516 }
517
518 function populateTransformContext () {
519
520         var active_tab = filterByAttribute(
521                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
522                 'selected',
523                 'true'
524         )[0];
525
526         var tabname = active_tab.getAttribute('id');
527
528         var tabpanel = $( tabname + 'panel' );
529         var tree = tabpanel.getElementsByTagName('tree')[0];
530         var items = getSelectedItems(tree);
531
532         var transforms = {};
533         for (var i in items) {
534                 var item = items[i];
535                 var dtype = item.getAttribute('datatype');
536                 var item_transforms = getTransforms({ datatype : dtype });
537
538                 for (var j in item_transforms) {
539                         transforms[item_transforms[j]] = OILS_RPT_TRANSFORMS[item_transforms[j]];
540                         transforms[item_transforms[j]].name = item_transforms[j];
541                 }
542         }
543
544         var transformList = [];
545         for (var i in transforms) {
546                 transformList.push( transforms[i] );
547         }
548
549         transformList.sort( sortHashLabels );
550
551         var menu = $(tabname + '_trans_menu');
552         while (menu.firstChild) menu.removeChild(menu.lastChild);
553
554         for (var i in transformList) {
555                 var t = transformList[i];
556
557                 if (tabname.match(/filter/)) {
558                         if (tabname.match(/^agg/)) {
559                                 if (!t.aggregate) continue;
560                         } else {
561                                 if (t.aggregate) continue;
562                         }
563                 }
564
565                 menu.appendChild(
566                         createMenuItem(
567                                 { aggregate : t.aggregate,
568                                   name : t.name,
569                                   alias : t.label,
570                                   label : t.label,
571                                   params : t.params,
572                                   oncommand : "alterColumnTransform('"+t.name+"')",
573                                 }
574                         )
575                 );
576         }
577
578         menu.parentNode.setAttribute('disabled','false');
579         if (menu.childNodes.length == 0) {
580                 menu.parentNode.setAttribute('disabled','true');
581         }
582 }
583
584
585 function renderSources (selected) {
586
587         var tree = $('used-sources');
588         var sources = $('used-sources-treetop');
589         var tabs = $('used-source-fields-tabbox').getElementsByTagName('tab');
590
591         if (!selected) {
592                 while (sources.firstChild) sources.removeChild(sources.lastChild);
593         } else {
594                 selected = getSelectedItems(tree);
595                 if (!selected.length) {
596                         selected = undefined;
597                         while (sources.firstChild) sources.removeChild(sources.lastChild);
598                 }
599         }
600
601         for (var j = 0; j < tabs.length; j++) {
602                 var tab = tabs[j];
603                 var tabname = tab.getAttribute('id')
604                 var tabpanel = $( tab.getAttribute('id') + 'panel' );
605                 var fieldtree = tabpanel.getElementsByTagName('treechildren')[0];
606
607                 while (fieldtree.firstChild) fieldtree.removeChild(fieldtree.lastChild);
608         }
609
610         for (var relation_alias in rpt_rel_cache) {
611                 if (!rpt_rel_cache[relation_alias].fields) continue;
612
613                 if (selected) {
614                         if (
615                                 !grep(
616                                         function (x) {
617                                                 return x.getAttribute('relation') == relation_alias;
618                                         },
619                                         selected
620                                 ).length
621                         ) continue;
622                 } else {
623
624                         $('used-sources-treetop').appendChild(
625                                 createTreeItem(
626                                         { relation : rpt_rel_cache[relation_alias].alias,
627                                           idlclass : rpt_rel_cache[relation_alias].idlclass,
628                                           reltype  : rpt_rel_cache[relation_alias].reltype,
629                                           path     : rpt_rel_cache[relation_alias].path,
630                                         },
631                                         createTreeRow(
632                                                 {},
633                                                 createTreeCell({ label : rpt_rel_cache[relation_alias].label }),
634                                                 createTreeCell({ label : rpt_rel_cache[relation_alias].table }),
635                                                 createTreeCell({ label : rpt_rel_cache[relation_alias].alias }),
636                                                 createTreeCell({ label : rpt_rel_cache[relation_alias].reltype })
637                                         )
638                                 )
639                         );
640                 }
641
642                 for each (var tabname in ['filter_tab','aggfilter_tab']) {
643                         tabpanel = $( tabname + 'panel' );
644                         fieldtree = tabpanel.getElementsByTagName('treechildren')[0];
645
646                         for (var colname in rpt_rel_cache[relation_alias].fields[tabname]) {
647                                 with (rpt_rel_cache[relation_alias].fields[tabname][colname]) {
648                                         fieldtree.appendChild(
649                                                 createTreeItem(
650                                                         { relation : relation_alias, datatype : datatype },
651                                                         createTreeRow(
652                                                                 {},
653                                                                 createTreeCell({ label : alias }),
654                                                                 createTreeCell({ label : colname }),
655                                                                 createTreeCell({ label : datatype }),
656                                                                 createTreeCell({ label : transform_label }),
657                                                                 createTreeCell({ label : transform })
658                                                         )
659                                                 )
660                                         );
661
662                                         fieldtree.lastChild.firstChild.appendChild(
663                                                 createTreeCell({ op : op, label : op_label })
664                                         );
665
666                                         if (op_value.value != undefined) {
667                                                 fieldtree.lastChild.firstChild.appendChild(
668                                                         createTreeCell({ label : op_value.label })
669                                                 );
670                                         }
671                                 }
672                         }
673                 }
674         }
675
676         tabpanel = $( 'dis_tabpanel' );
677         fieldtree = tabpanel.getElementsByTagName('treechildren')[0];
678         for each (var order in rpt_rel_cache.order_by) {
679
680                 if (selected) {
681                         if (
682                                 !grep(
683                                         function (x) {
684                                                 return x.getAttribute('relation') == order.relation;
685                                         },
686                                         selected
687                                 ).length
688                         ) continue;
689                 }
690
691                 with (rpt_rel_cache[order.relation].fields.dis_tab[order.field]) {
692                         fieldtree.appendChild(
693                                 createTreeItem(
694                                         { relation : order.relation, datatype : datatype },
695                                         createTreeRow(
696                                                 {},
697                                                 createTreeCell({ label : alias }),
698                                                 createTreeCell({ label : colname }),
699                                                 createTreeCell({ label : datatype }),
700                                                 createTreeCell({ label : transform_label }),
701                                                 createTreeCell({ label : transform })
702                                         )
703                                 )
704                         );
705
706                         fieldtree.lastChild.firstChild.appendChild(
707                                 createTreeCell({ op : op, label : op_label })
708                         );
709
710                         if (op_value.value != undefined) {
711                                 fieldtree.lastChild.firstChild.appendChild(
712                                         createTreeCell({ label : op_value.label })
713                                 );
714                         }
715                 }
716         }
717 }
718
719 var param_count;
720 var tab_use = {
721         dis_tab       : 'select',
722         filter_tab    : 'where',
723         aggfilter_tab : 'having',
724 };
725
726
727 function save_template () {
728         param_count = 0;
729
730         var template = {
731                 version    : 1,
732                 core_class : $('sources-treetop').getElementsByTagName('treeitem')[0].getAttribute('idlclass'),
733                 select     : [],
734                 from       : {},
735                 where      : [],
736                 having     : [],
737                 order_by   : []
738         };
739
740         for (var relname in rpt_rel_cache) {
741                 var relation = rpt_rel_cache[relname];
742                 if (!relation.fields) continue;
743
744                 // first, add the where and having clauses (easier)
745                 for each (var tab_name in [ 'filter_tab', 'aggfilter_tab' ]) {
746                         var tab = relation.fields[tab_name];
747                         for (var field in tab) {
748                                 fleshTemplateField( template, relation, tab_name, field );
749                         }
750                 }
751
752                 // now the from clause
753                 fleshFromPath( template, relation );
754         }
755
756         // and now for select (based on order_by)
757         for each (var order in rpt_rel_cache.order_by)
758                 fleshTemplateField( template, rpt_rel_cache[order.relation], 'dis_tab', order.field );
759
760
761         // and the saving throw ...
762         var cgi = new CGI();
763         var session = cgi.param('ses');
764         fetchUser( session );
765
766         var tmpl = new rt();
767         tmpl.name( $('template-name').value );
768         tmpl.description( $('template-description').value );
769         tmpl.owner(USER.id());
770         tmpl.folder(cgi.param('folder'));
771         tmpl.data(js2JSON(template));
772
773         prompt( 'template', js2JSON( tmpl ) );
774
775         if(!confirm('Name : '+tmpl.name() + '\nDescription: ' + tmpl.description()+'\nSave Template?'))
776                 return;
777
778         var req = new Request('open-ils.reporter:open-ils.reporter.template.create', session, tmpl);
779         req.request.alertEvent = false;
780         req.callback(
781                 function(r) {
782                         var res = r.getResultObject();
783                         if(checkILSEvent(res)) {
784                                 alertILSEvent(res);
785                         } else {
786                                 if( res && res != '0' ) {
787                                         confirm('Template ' + tmpl.name() + ' was successfully saved.');
788                                         _l('../oils_rpt.xhtml');
789                                 }
790                         }
791                 }
792         );
793
794         req.send();
795 }
796
797 function fleshFromPath ( template, rel ) {
798         var table_path = rel.path.split( /\./ );
799         if (table_path.length > 1 || rel.path.indexOf('-') > -1) table_path.push( rel.idlclass );
800
801         var prev_type = '';
802         var prev_link = '';
803         var current_path = '';
804         var current_obj = template.from;
805         var link;
806         while (link = table_path.shift()) {
807                 if (current_path) current_path += '-';
808                 current_path += link;
809
810                 var leaf = table_path.length == 0 ? true : false;
811
812                 current_obj.path = current_path;
813                 current_obj.table = getIDLClass( link.split(/-/)[0] ).getAttributeNS( persistNS, 'tablename' );
814
815                 if (prev_link != '') {
816                         var prev_class = getIDLClass( prev_link.split(/-/)[0] );
817                         var prev_field = prev_link.split(/-/)[1];
818
819                         var current_link = getIDLLink( prev_class, prev_field );
820                         current_obj.key = current_link.getAttribute('key');
821
822                         if (
823                                 current_link.getAttribute('reltype') != 'has_a' ||
824                                 prev_type == 'left' ||
825                                 rel.reltype != 'has_a'
826                         ) current_obj.type = 'left';
827
828                         prev_type = current_obj.type; 
829                 }
830
831                 if (leaf) {
832                         current_obj.label = rel.label;
833                         current_obj.alias = rel.alias;
834                         current_obj.idlclass = rel.idlclass;
835                         current_obj.template_path = rel.path;
836                 } else {
837                         var current_class = getIDLClass( link.split(/-/)[0] );
838                         var join_field = link.split(/-/)[1];
839                         var join_link = getIDLLink(current_class, join_field);
840
841                         if (join_link.getAttribute('reltype') != 'has_a') {
842                                 var fields_el = current_class.getElementsByTagName('fields')[0];
843                                 join_field = fields_el.getAttributeNS(persistNS, 'primary') + '-' + join_link.getAttribute('key');
844                         }
845
846                         current_obj.alias = hex_md5( current_path ) ;
847                         join_field += '-' + current_obj.alias;
848                         if (table_path.length == 1) join_field += '-' + rel.alias;
849
850                         if (!current_obj.join) current_obj.join = {};
851                         if (!current_obj.join[join_field]) current_obj.join[join_field] = {};
852
853                         if (current_obj.type == 'left') current_obj.join[join_field].type = 'left';
854
855                         current_obj = current_obj.join[join_field];
856                 }
857
858                 prev_link = link;
859         }
860
861
862 }
863
864 function fleshTemplateField ( template, rel, tab_name, field ) {
865
866         if (!rel.fields[tab_name] || !rel.fields[tab_name][field]) return;
867
868         var tab = rel.fields[tab_name];
869
870         var field_path = rel.path + '-' + field;
871         field_path = field_path.replace(/\./g, '-');
872
873         var element = {
874                 alias : tab[field].alias,
875                 column :
876                         { colname : field,
877                           transform : tab[field].transform,
878                           transform_label : tab[field].transform_label
879                         },
880                 path : field_path,
881                 relation : rel.alias
882         };
883
884         if (tab_name.match(/filter/)) {
885                 element.condition = {};
886                 element.condition[tab[field].op] =
887                         tab[field].op_value.value ?
888                                 tab[field].op_value.value :
889                                 '::P' + param_count++;
890         }
891
892         template[tab_use[tab_name]].push(element);
893 }
894