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