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