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