]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/reports/oils_rpt_builder.js
better support for removing items from the "from" clause
[Evergreen.git] / Open-ILS / web / reports / oils_rpt_builder.js
1 /** initializes reports, some basid display settings, 
2   * grabs and builds the IDL tree
3   */
4 function oilsInitReportBuilder() {
5         oilsInitReports();
6         oilsReportBuilderReset();
7         DOM.oils_rpt_table.onclick = 
8                 function(){hideMe(DOM.oils_rpt_column_editor)};
9         oilsDrawRptTree(
10                 function() { 
11                         hideMe(DOM.oils_rpt_tree_loading); 
12                         unHideMe(DOM.oils_rpt_table); 
13                 }
14         );
15 }
16
17 function oilsReportBuilderReset() {
18         var n = (oilsRpt) ? oilsRpt.name : "";
19         oilsRpt = new oilsReport();
20         oilsRpt.name = n;
21         oilsRptDisplaySelector  = DOM.oils_rpt_display_selector;
22         oilsRptFilterSelector   = DOM.oils_rpt_filter_selector;
23         removeChildren(oilsRptDisplaySelector);
24         removeChildren(oilsRptFilterSelector);
25         oilsRptDebug();
26         oilsRptResetParams();
27 }
28
29
30 /* returns just the column name */
31 function oilsRptPathCol(path) {
32         var parts = path.split(/-/);
33         return parts.pop();
34 }
35
36 /* returns the IDL class of the selected column */
37 function oilsRptPathClass(path) {
38         var parts = path.split(/-/);
39         parts.pop();
40         return parts.pop();
41 }
42
43 /* returns everything prior to the column name */
44 function oilsRptPathRel(path) {
45         var parts = path.split(/-/);
46         parts.pop();
47         return parts.join('-');
48 }
49
50 /* creates a label "path" based on the column path */
51 function oilsRptMakeLabel(path) {
52         var parts = path.split(/-/);
53         var str = '';
54         for( var i = 0; i < parts.length; i++ ) {
55                 if(i%2 == 0) {
56                         if( i == 0 )
57                                 str += oilsIDL[parts[i]].label;
58                 } else {
59                         var f = oilsRptFindField(oilsIDL[parts[i-1]], parts[i]);
60                         str += ":"+f.label;
61                 }
62         }
63         return str;
64 }
65
66
67 /* adds an item to the display window */
68 function oilsAddRptDisplayItem(path, name, tform, params) {
69         if( ! oilsAddSelectorItem(oilsRptDisplaySelector, path, name) ) 
70                 return;
71
72         /* add the selected columns to the report output */
73         name = (name) ? name : oilsRptPathCol(path);
74         var param = oilsRptNextParam();
75
76         /* add this item to the select blob */
77         var sel = {
78                 relation:oilsRptPathRel(path), 
79                 alias:param
80         };
81
82         if( tform ) {
83                 sel.column = {};
84                 if( params ) {
85                         params.unshift(oilsRptPathCol(path));
86                         sel.column[tform] = params;
87                 } else {
88                         sel.column[tform] = oilsRptPathCol(path); 
89                 }
90         } else { sel.column = oilsRptPathCol(path); }
91
92         oilsRpt.def.select.push(sel);
93
94         mergeObjects( oilsRpt.def.from, oilsRptBuildFromClause(path));
95         oilsRpt.params[param] = name;
96         oilsRptDebug();
97 }
98
99 /* takes a column path and builds a from-clause object for the path */
100 function oilsRptBuildFromClause(path) {
101         var parts = path.split(/-/);
102         var obj = {};
103         var tobj = obj;
104         var newpath = "";
105
106         for( var i = 0; i < parts.length; i += 2 ) {
107                 var cls = parts[i];
108                 var col = parts[i+1];
109                 var node = oilsIDL[parts[i]];
110                 var field = oilsRptFindField(node, col);
111                 newpath = (newpath) ? newpath + '-'+ cls : cls;
112
113                 tobj.table = node.table;
114                 tobj.alias = newpath;
115                 _debug('field type is ' + field.type);
116                 if( i == (parts.length - 2) ) break;
117
118                 tobj.join = {};
119                 tobj = tobj.join;
120                 tobj[col] = {};
121                 tobj = tobj[col];
122                 if( field.type == 'link' )
123                         tobj.key = field.key;
124
125                 newpath = newpath + '-'+ col;
126         }
127
128         _debug("built 'from' clause: path="+path+"\n"+formatJSON(js2JSON(obj)));
129         return obj;
130 }
131
132
133 /* removes a specific item from the display window */
134 function oilsDelDisplayItem(val) {
135         oilsDelSelectorItem(oilsRptDisplaySelector, val);
136 }
137
138 /* removes selected items from the display window */
139 function oilsDelSelectedDisplayItems() {
140         var list = oilsDelSelectedItems(oilsRptDisplaySelector);
141
142         /* remove the de-selected columns from the report output */
143         oilsRpt.def.select = grep( oilsRpt.def.select, 
144                 function(i) {
145                         for( var j = 0; j < list.length; j++ ) {
146                                 var d = list[j];
147                                 var col = i.column;
148
149                                 /* if this columsn has a transform, 
150                                         it will be an object { tform => column } */
151                                 if( typeof col != 'string' ) 
152                                         for( var c in col ) col = col[c];
153
154                                 /* if this transform requires params, the column 
155                                         will be the first item in the param set array */
156                                 if( typeof col != 'string' ) col = col[0];
157
158                                 if( oilsRptPathRel(d) == i.relation && oilsRptPathCol(d) == col ) {
159                                         var param = (i.alias) ? i.alias.match(/::PARAM\d*/) : null;
160                                         if( param ) delete oilsRpt.params[param];
161                                         return false;
162                                 }
163                         }
164                         return true;
165                 }
166         );
167
168         if(!oilsRpt.def.select) {
169                 oilsRpt.def.select = [];
170                 oilsReportBuilderReset();
171
172         } else {
173                 for( var j = 0; j < list.length; j++ ) 
174                         /* if there are no items left in the "select" clause for the given 
175                                 relation, trim this relation from the "from" clause */
176                         if(!grep(oilsRpt.def.select,
177                                         function(i){ return (i.relation == oilsRptPathRel(list[j])); })) 
178                                 oilsRptPruneFromClause(oilsRptPathRel(list[j]));
179         }
180
181         oilsRptDebug();
182 }
183
184 /* for each item in the path list, remove the associated data
185         from the "from" clause */
186
187 function oilsRptPruneFromClause(relation, node) {
188         _debug("removing relation from 'from' clause " + relation);
189         if(!node) node = oilsRpt.def.from.join;
190         for( var i in node ) {
191                 if( node[i].alias == relation ) {
192                         if( node[i].join ) {
193                                 /* if we have subtrees, don't delete our tree node */
194                                 return false;
195                         } else {
196                                 delete node[i];
197                                 return true;
198                         } 
199                 } else {
200                         if( node[i].join ) {
201                                 if( oilsRptPruneFromClause(relation, node[i].join ) ) {
202                                         if(oilsRptObjectKeys(node[i].join).length == 0) {
203                                                 delete node[i].join;
204                                                 /* if there are no items in the select clause with a relation matching
205                                                         this nodes alias, we can safely remove this node from the tree */
206                                                 if(!grep(oilsRpt.def.select,function(r){return (r.relation==node[i].alias)}))
207                                                         delete node[i];
208                                                 return true;
209                                         }
210                                 }
211                         }
212                 }
213         }
214         return false;
215 }
216
217 /* adds an item to the display window */
218 function oilsAddRptFilterItem(val) {
219         oilsAddSelectorItem(oilsRptFilterSelector, val);
220 }
221
222 /* removes a specific item from the display window */
223 function oilsDelFilterItem(val) {
224         oilsDelSelectorItem(oilsRptFilterSelector, val);
225 }
226
227 /* removes selected items from the display window */
228 function oilsDelSelectedFilterItems() {
229         oilsDelSelectedItems(oilsRptFilterSelector);
230 }
231
232
233 /* adds an item to the display window */
234 function oilsAddSelectorItem(sel, val, name) {
235         name = (name) ? name : oilsRptMakeLabel(val);
236         _debug("adding selector item "+name+' = ' +val);
237         for( var i = 0; i < sel.options.length; i++ ) {
238                 var opt = sel.options[i];
239                 if( opt.value == val ) return false;
240         }
241         insertSelectorVal( sel, -1, name, val );
242         return true;
243 }
244
245
246 /* removes a specific item from the display window */
247 function oilsDelSelectorItem(sel, val) {
248         _debug("deleting selector item "+val);
249         var opts = sel.options;
250         for( var i = 0; i < opts.length; i++ ) {
251                 var opt = opts[i];
252                 if( opt.value == val )  {
253                         if( i == opts.length - 1 ) 
254                                 opts[i] = null;
255                         else opts[i] = opts[i+1];
256                         return;
257                 }
258         }
259 }
260
261 /* removes selected items from the display window */
262 function oilsDelSelectedItems(sel) {
263         var list = getSelectedList(sel);
264         for( var i = 0; i < list.length; i++ ) 
265                 oilsDelSelectorItem(sel, list[i]);
266         return list;
267 }
268
269
270 /* hides the different field editor tabs */
271 function oilsRptHideEditorDivs() {
272         hideMe(DOM.oils_rpt_tform_div);
273         hideMe(DOM.oils_rpt_filter_div);
274         hideMe(DOM.oils_rpt_agg_filter_div);
275 }
276
277
278 /**
279   This draws the 3-tabbed window containing the transform,
280   filter, and aggregate filter picker window
281   */
282 function oilsRptDrawDataWindow(path) {
283         var col = oilsRptPathCol(path);
284         var cls = oilsRptPathClass(path);
285         var field = grep(oilsIDL[cls].fields, function(f){return (f.name==col);})[0];
286
287         _debug("setting update data window for column "+col+' on class '+cls);
288
289         var div = DOM.oils_rpt_column_editor;
290         /* set a preliminary top position so the page won't bounce around */
291         div.setAttribute('style','top:'+oilsMouseX+'px');
292
293         /* unhide the div so we can determine the dimensions */
294         unHideMe(div);
295
296         /* don't let them see the floating div until the position is fully determined */
297         div.style.visibility='hidden'; 
298
299         oilsRptDrawTransformWindow(path, col, cls, field);
300
301         DOM.oils_rpt_column_editor_close_button.onclick = function(){hideMe(div);};
302         buildFloatingDiv(div, 600);
303
304         /* now let them see it */
305         div.style.visibility='visible';
306
307         /* give the tab links behavior */
308         DOM.oils_rpt_tform_tab.onclick = 
309                 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_tform_div)};
310         DOM.oils_rpt_filter_tab.onclick = 
311                 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_filter_div)};
312         DOM.oils_rpt_agg_filter_tab.onclick = 
313                 function(){oilsRptHideEditorDivs();unHideMe(DOM.oils_rpt_agg_filter_div)};
314
315         DOM.oils_rpt_tform_tab.onclick();
316 }
317
318
319 /* draws the transform window */
320 function oilsRptDrawTransformWindow(path, col, cls, field) {
321         appendClear(DOM.oils_rpt_tform_label, text(oilsRptMakeLabel(path)));
322         DOM.oils_rpt_tform_label_input.value = oilsRptMakeLabel(path);
323         var dtype = field.datatype;
324
325         DOM.oils_rpt_tform_submit.onclick = 
326                 function(){ 
327                         var tform = oilsRptGetTform(dtype);
328                         _debug('found tform: ' + js2JSON(tform));
329                         var params = getRptTformParams(dtype, tform);
330                         _debug('found tform params: ' + js2JSON(params));
331                         tform = (tform == 'raw') ? null : tform;
332                         oilsAddRptDisplayItem(path, DOM.oils_rpt_tform_label_input.value, tform, params ) 
333                 };
334
335         DOM.oils_rpt_tform_label_input.focus();
336         DOM.oils_rpt_tform_label_input.select();
337         oilsRptHideTformFields();
338
339         _debug("Transforming item with datatype "+dtype);
340         unHideMe($('oils_rpt_tform_'+dtype+'_div'));
341         $('oils_rpt_tform_all_raw').checked = true;
342 }
343
344 function oilsRptHideTformFields() {
345         for( var t in oilsRptTransforms ) 
346                 hideMe($('oils_rpt_tform_'+t+'_div'));
347 }
348
349 function oilsRptGetTform(datatype) {
350         for( var i in oilsRptTransforms[datatype] ) 
351                 if( $('oils_rpt_tform_'+datatype+'_'+oilsRptTransforms[datatype][i]).checked )
352                         return oilsRptTransforms[datatype][i];
353         for( var i in oilsRptTransforms.all ) 
354                 if( $('oils_rpt_tform_all_'+oilsRptTransforms.all[i]).checked )
355                         return oilsRptTransforms.all[i];
356         return null;
357 }
358
359 function getRptTformParams(type, tform) {
360         switch(type) {
361                 case 'timestamp':
362                         switch(tform) {
363                                 case 'months_ago':
364                                         return [DOM.oils_rpt_tform_timestamp_months_ago_input.value];
365                                 case 'quarters_ago':
366                                         return [DOM.oils_rpt_tform_timestamp_quarters_ago_input.value];
367                         }
368                 case 'string' :
369                         switch(tform) {
370                                 case 'substring' :
371                                         return [];
372                         }
373         }
374 }
375
376