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