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