VTAM & OCF almost integrated
[myslice.git] / plugins / univbrisvtam / static / js / univbrisvtam.js
1 /**
2  * Description: display a query result in a datatables-powered <table>
3  * Copyright (c) 2012-2013 UPMC Sorbonne Universite - INRIA
4  * License: GPLv3
5  */ 
6
7 (function($){
8
9     var debug=false;
10     debug=true
11
12     pk_flowspace_index=0;
13     opt_flowspace_index=0;
14     pk_mode=0;
15     fvf_add=1;
16     fvf_nrow=0;
17     
18
19     var UnivbrisVtam = Plugin.extend({
20
21         
22         init: function(options, element) {
23             this.classname="univbrisvtam";
24             this._super(options, element);
25                 
26                 this.elmt().on('show', this, this.on_show);
27             this.elmt().on('shown.bs.tab', this, this.on_show);
28             this.elmt().on('resize', this, this.on_resize);
29
30             // We need to remember the active filter for datatables filtering
31             this.filters = Array(); 
32
33             // an internal buffer for records that are 'in' and thus need to be checked 
34             this.buffered_records_to_check = [];
35             // an internal buffer for keeping lines and display them in one call to fnAddData
36             this.buffered_lines = [];
37
38             var keys = manifold.metadata.get_key(this.object);
39             this.canonical_key = (keys && keys.length == 1) ? keys[0] : undefined;
40             this.init_key = this.options.init_key;
41             // have init_key default to canonical_key
42             this.init_key = this.init_key || this.canonical_key;
43             // sanity check
44             if ( ! this.init_key ) messages.warning ("UnivbrisVtam : cannot find init_key");
45             if ( ! this.canonical_key ) messages.warning ("UnivbrisVtam : cannot find canonical_key");
46             if (debug) messages.debug("UnivbrisVtam: canonical_key="+this.canonical_key+" init_key="+this.init_key);
47
48             /* GUI setup and event binding */
49             this.initialize_table();
50             
51         },
52
53         /* PLUGIN EVENTS */
54
55         on_show: function(e) {
56             if (debug) messages.debug("UnivbrisVtam.on_show");
57             var self = e.data;
58             self.table.fnAdjustColumnSizing();
59         },        
60
61         on_resize: function(e) {
62             if (debug) messages.debug("UnivbrisVtam.on_resize");
63             var self = e.data;
64             self.table.fnAdjustColumnSizing();
65         },        
66
67         /* GUI EVENTS */
68
69         /* GUI MANIPULATION */
70
71         initialize_table: function() 
72         {
73
74             
75             /* Transforms the table into DataTable, and keep a pointer to it */
76             var self = this;
77             //alert(self.options);
78             var actual_options = {
79                 // Customize the position of Datatables elements (length,filter,button,...)
80                 // we use a fluid row on top and another on the bottom, making sure we take 12 grid elt's each time
81                 //sDom: "<'row'<'col-xs-5'l><'col-xs-1'r><'col-xs-6'f>>t<'row'<'col-xs-5'i><'col-xs-7'p>>",
82                 sDom: "<'row'<'col-xs-5'l><'col-xs-5'r><'col-xs-1'r><'col-xs-6'f>>t<'row'<'col-xs-5'i><'col-xs-7'p>><'buttons'>",
83                 //sDom: "<'row'<'col-xs-9'r>t<'buttons'>",
84                 // XXX as of sept. 2013, I cannot locate a bootstrap3-friendly mode for now
85                 // hopefully this would come with dataTables v1.10 ?
86                 // in any case, search for 'sPaginationType' all over the code for more comments
87                 sPaginationType: 'bootstrap',
88                 // Handle the null values & the error : Datatables warning Requested unknown parameter
89                 // http://datatables.net/forums/discussion/5331/datatables-warning-...-requested-unknown-parameter/p2
90                 aoColumnDefs: [{sDefaultContent: '',aTargets: [ '_all' ]}],
91                 // WARNING: this one causes tables in a 'tabs' that are not exposed at the time this is run to show up empty
92                 // sScrollX: '100%',       /* Horizontal scrolling */
93                 bProcessing: true,      /* Loading */
94                 fnDrawCallback: function() { self._querytable_draw_callback.call(self);}
95                 //fnFooterCallback: function() {self._UnivbrisVtam_footer_callback.call(self,nFoot, aData, iStart, iEnd, aiDisplay)};}
96                 // XXX use $.proxy here !
97             };
98             // the intention here is that options.datatables_options as coming from the python object take precedence
99             // xxx DISABLED by jordan: was causing errors in datatables.js
100             // xxx turned back on by Thierry - this is the code that takes python-provided options into account
101             // check your datatables_options tag instead 
102             // however, we have to accumulate in aoColumnDefs from here (above) 
103             // and from the python wrapper (checkboxes management, plus any user-provided aoColumnDefs)
104             if ( 'aoColumnDefs' in this.options.datatables_options) {
105                 actual_options['aoColumnDefs']=this.options.datatables_options['aoColumnDefs'].concat(actual_options['aoColumnDefs']);
106                 delete this.options.datatables_options['aoColumnDefs'];
107             }
108             $.extend(actual_options, this.options.datatables_options );
109
110             
111             this.table = $("#univbris_vtam__table").dataTable(actual_options);  
112             
113             
114             
115             //alert(this.table.$("name"));
116
117             /* Setup the SelectAll button in the dataTable header */
118             /* xxx not sure this is still working */
119             var oSelectAll = $('#datatableSelectAll-'+ this.options.plugin_uuid);
120             oSelectAll.html("<span class='glyphicon glyphicon-ok' style='float:right;display:inline-block;'></span>Select All");
121             oSelectAll.button();
122             oSelectAll.css('font-size','11px');
123             oSelectAll.css('float','right');
124             oSelectAll.css('margin-right','15px');
125             oSelectAll.css('margin-bottom','5px');
126             oSelectAll.unbind('click');
127             oSelectAll.click(this._selectAll);
128
129             /* Add a filtering function to the current table 
130              * Note: we use closure to get access to the 'options'
131              */
132             $.fn.dataTableExt.afnFiltering.push(function( oSettings, aData, iDataIndex ) { 
133                 /* No filtering if the table does not match */
134                 if (oSettings.nTable.id != self.options.plugin_uuid + '__table')
135                     return true;
136                 return self._querytable_filter.call(self, oSettings, aData, iDataIndex);
137             });
138
139             /* Processing hidden_columns */
140             $.each(this.options.hidden_columns, function(i, field) {
141                 //manifold.raise_event(self.options.query_all_uuid, FIELD_REMOVED, field);
142                 //alert (field);
143                 self.hide_column(field);
144                 //self.hide_column(field);
145             });
146
147
148             this._querytable_draw_callback();   
149
150         }, // initialize_table
151
152
153         fnCreateVms:function(e){
154                 console.log("building json to send to backend");
155
156                 var vms=[];
157
158                 try{
159                          var rows = $("#univbris_vtam__table").dataTable().fnGetNodes();
160                          if (rows.length<=0){
161                                 throw("no vm specified");
162                          }
163                          else{
164                                 for(var i=0;i<rows.length;i++){
165                     // get the id of the html element in the table
166                     var cell=rows[i].cells[2];
167                     element = cell.getElementsByTagName('p');
168                     server_vm = element.item(0).id;
169                     t_server_vm = JSON.parse(server_vm);
170                     current_server = Object.keys(t_server_vm);
171                     current_vm = t_server_vm[current_server[0]];
172                     if(vms.length>0){
173                         // add the current vm to vms
174                         $.each( vms, function( i, s_vm ) {
175                             // if the server is already listed in vms, add a new vm to the server
176                             s = Object.keys(s_vm);
177                             vm = s_vm[s[0]];
178                            
179                             if(s[0] == current_server[0]){
180                                 vm_exists = false;
181                                 // XXX We should also loop on the vm names
182                                 $.each( vm, function( i, vm_name ) {
183                                     if(vm_name == current_vm[0]){
184                                         vm_exists = true;
185                                         return;
186                                     }
187                                 });
188                                 if (vm_exists == false){
189                                     vm.push(current_vm[0]);
190                                 }
191                             // else add the server with the current vm
192                             }else{
193                                 vms.push(t_server_vm);
194                             }
195                         });
196                     }else{
197                         vms.push(t_server_vm);
198                     }
199
200                                 }
201
202                                 var rspecs = JSON.stringify(vms);
203                                 console.log(rspecs);
204                 // manifold.raise_event(self.options.query_uuid, ...);
205                         }
206
207                 }
208                 catch(err){
209                         alert(err)
210                 }               
211         },
212
213
214
215         fnAddVm:function(e){
216                 //this.hideFvfError(e);
217                 $('#uob_vm_name').removeClass('error');
218                 $("#uob_vm_name").val("");
219                 jQuery('#uob_vm_name_error').hide();
220                 jQuery("#univbris_vtam").hide();
221                 jQuery("#univbris_vtam_form").show();
222         },
223
224         
225
226
227
228
229         
230
231         fnDelete:function(e){
232                         e.preventDefault();
233                         var nRow = $(this).parents('tr')[0];
234                         this.table = $("#univbris_vtam__table").dataTable();
235                         this.table.fnDeleteRow( nRow );
236         },
237
238
239
240
241         
242
243         /**
244          * @brief Determine index of key in the table columns 
245          * @param key
246          * @param cols
247          */
248         getColIndex: function(key, cols) {
249             var tabIndex = $.map(cols, function(x, i) { if (x.sTitle == key) return i; });
250             return (tabIndex.length > 0) ? tabIndex[0] : -1;
251         }, // getColIndex
252
253
254         
255
256         new_record: function(record)
257         {
258            
259         },
260
261         clear_table: function()
262         {
263             this.table.fnClearTable();
264         },
265
266         redraw_table: function()
267         {
268             this.table.fnDraw();
269         },
270
271         show_column: function(field)
272         {
273             var oSettings = this.table.fnSettings();
274             var cols = oSettings.aoColumns;
275             var index = this.getColIndex(field,cols);
276             if (index != -1)
277                 this.table.fnSetColumnVis(index, true);
278         },
279
280         hide_column: function(field)
281         {
282             var oSettings = this.table.fnSettings();
283             var cols = oSettings.aoColumns;
284             var index = this.getColIndex(field,cols);
285             //index=-1;
286             //alert(field + ": index: " + index );
287             if (index != -1)
288                 //alert(field + ": hidden with index: " + index );
289                 this.table.fnSetColumnVis(index, false);
290         },
291
292         // this is used at init-time, at which point only init_key can make sense
293         // (because the argument record, if it comes from query, might not have canonical_key set
294         set_checkbox_from_record: function (record, checked) {
295             if (checked === undefined) checked = true;
296             var init_id = record[this.init_key];
297             if (debug) messages.debug("UnivbrisVtam.set_checkbox_from_record, init_id="+init_id);
298             // using table.$ to search inside elements that are not visible
299             var element = this.table.$('[init_id="'+init_id+'"]');
300             element.attr('checked',checked);
301         },
302
303         // id relates to canonical_key
304         set_checkbox_from_data: function (id, checked) {
305             if (checked === undefined) checked = true;
306             if (debug) messages.debug("UnivbrisVtam.set_checkbox_from_data, id="+id);
307             // using table.$ to search inside elements that are not visible
308             var element = this.table.$("[id='"+id+"']");
309             element.attr('checked',checked);
310         },
311
312         /*************************** QUERY HANDLER ****************************/
313
314         on_filter_added: function(filter)
315         {
316             this.filters.push(filter);
317             this.redraw_table();
318         },
319
320         on_filter_removed: function(filter)
321         {
322             // Remove corresponding filters
323             this.filters = $.grep(this.filters, function(x) {
324                 return x != filter;
325             });
326             this.redraw_table();
327         },
328         
329         on_filter_clear: function()
330         {
331             // XXX
332             this.redraw_table();
333         },
334
335         on_field_added: function(field)
336         {
337             this.show_column(field);
338         },
339
340         on_field_removed: function(field)
341         {
342             this.hide_column(field);
343         },
344
345         on_field_clear: function()
346         {
347             alert('UnivbrisVtam::clear_fields() not implemented');
348         },
349
350         /* XXX TODO: make this generic a plugin has to subscribe to a set of Queries to avoid duplicated code ! */
351         /*************************** ALL QUERY HANDLER ****************************/
352
353         on_all_filter_added: function(filter)
354         {
355             // XXX
356             this.redraw_table();
357         },
358
359         on_all_filter_removed: function(filter)
360         {
361             // XXX
362             this.redraw_table();
363         },
364         
365         on_all_filter_clear: function()
366         {
367             // XXX
368             this.redraw_table();
369         },
370
371         on_all_field_added: function(field)
372         {
373             this.show_column(field);
374         },
375
376         on_all_field_removed: function(field)
377         {
378             this.hide_column(field);
379         },
380
381         on_all_field_clear: function()
382         {
383             alert('UnivbrisVtam::clear_fields() not implemented');
384         },
385
386
387         /*************************** RECORD HANDLER ***************************/
388
389         on_new_record: function(record)
390         {
391         },
392
393         on_clear_records: function()
394         {
395         },
396
397         // Could be the default in parent
398         on_query_in_progress: function()
399         {
400             this.spin();
401         },
402
403         on_query_done: function()
404         {
405             this.received_query = true;
406             // unspin once we have received both
407             if (this.received_all_query && this.received_query) this.unspin();
408         },
409         
410         on_field_state_changed: function(data)
411         {
412             switch(data.request) {
413                 case FIELD_REQUEST_ADD:
414                 case FIELD_REQUEST_ADD_RESET:
415                     this.set_checkbox_from_data(data.value, true);
416                     break;
417                 case FIELD_REQUEST_REMOVE:
418                 case FIELD_REQUEST_REMOVE_RESET:
419                     this.set_checkbox_from_data(data.value, false);
420                     break;
421                 default:
422                     break;
423             }
424         },
425
426         /* XXX TODO: make this generic a plugin has to subscribe to a set of Queries to avoid duplicated code ! */
427         // all
428         on_all_field_state_changed: function(data)
429         {
430             switch(data.request) {
431                 case FIELD_REQUEST_ADD:
432                 case FIELD_REQUEST_ADD_RESET:
433                     this.set_checkboxfrom_data(data.value, true);
434                     break;
435                 case FIELD_REQUEST_REMOVE:
436                 case FIELD_REQUEST_REMOVE_RESET:
437                     this.set_checkbox_from_data(data.value, false);
438                     break;
439                 default:
440                     break;
441             }
442         },
443
444         on_all_new_record: function(record)
445         {
446             this.new_record(record);
447         },
448
449         on_all_clear_records: function()
450         {
451             this.clear_table();
452
453         },
454
455         on_all_query_in_progress: function()
456         {
457             // XXX parent
458             this.spin();
459         }, // on_all_query_in_progress
460
461         on_all_query_done: function()
462         {
463             if (debug) messages.debug("1-shot initializing dataTables content with " + this.buffered_lines.length + " lines");
464
465
466             //this.table.fnAddData (this.buffered_lines);
467             this.buffered_lines=[];
468             
469             var self = this;
470             // if we've already received the slice query, we have not been able to set 
471             // checkboxes on the fly at that time (dom not yet created)
472             $.each(this.buffered_records_to_check, function(i, record) {
473                 if (debug) messages.debug ("querytable delayed turning on checkbox " + i + " record= " + record);
474                 self.set_checkbox_from_record(record, true);
475             });
476             this.buffered_records_to_check = [];
477
478             this.received_all_query = true;
479             // unspin once we have received both
480             if (this.received_all_query && this.received_query) this.unspin();
481
482         }, // on_all_query_done
483
484         /************************** PRIVATE METHODS ***************************/
485
486         /** 
487          * @brief QueryTable filtering function
488          */
489         _querytable_filter: function(oSettings, aData, iDataIndex)
490         {
491             var ret = true;
492             $.each (this.filters, function(index, filter) { 
493                 /* XXX How to manage checkbox ? */
494                 var key = filter[0]; 
495                 var op = filter[1];
496                 var value = filter[2];
497
498                 /* Determine index of key in the table columns */
499                 var col = $.map(oSettings.aoColumns, function(x, i) {if (x.sTitle == key) return i;})[0];
500
501                 /* Unknown key: no filtering */
502                 if (typeof(col) == 'undefined')
503                     return;
504
505                 col_value=unfold.get_value(aData[col]);
506                 /* Test whether current filter is compatible with the column */
507                 if (op == '=' || op == '==') {
508                     if ( col_value != value || col_value==null || col_value=="" || col_value=="n/a")
509                         ret = false;
510                 }else if (op == '!=') {
511                     if ( col_value == value || col_value==null || col_value=="" || col_value=="n/a")
512                         ret = false;
513                 } else if(op=='<') {
514                     if ( parseFloat(col_value) >= value || col_value==null || col_value=="" || col_value=="n/a")
515                         ret = false;
516                 } else if(op=='>') {
517                     if ( parseFloat(col_value) <= value || col_value==null || col_value=="" || col_value=="n/a")
518                         ret = false;
519                 } else if(op=='<=' || op=='≤') {
520                     if ( parseFloat(col_value) > value || col_value==null || col_value=="" || col_value=="n/a")
521                         ret = false;
522                 } else if(op=='>=' || op=='≥') {
523                     if ( parseFloat(col_value) < value || col_value==null || col_value=="" || col_value=="n/a")
524                         ret = false;
525                 }else{
526                     // How to break out of a loop ?
527                     alert("filter not supported");
528                     return false;
529                 }
530
531             });
532             return ret;
533         },
534
535         _querytable_draw_callback: function()
536         {
537             /* 
538              * Handle clicks on checkboxes: reassociate checkbox click every time
539              * the table is redrawn    
540              */
541             this.elts('querytable-checkbox').unbind('click').click(this, this._check_click);
542             $("#add_vm").unbind('click').click(this, this.fnAddVm);
543             $("#submit_vms").unbind('click').click(this, this.fnCreateVms);
544             $('#univbris_vtam__table .delete').unbind('click').click(this, this.fnDelete);
545             /*var edits=this.elts.all.find('.edit');
546             edits.each(function(){
547                 this.unbind('click').click(this,this.fnEdit);
548              }
549             */
550             if (!this.table)
551                 return;
552
553             /* Remove pagination if we show only a few results */
554             var wrapper = this.table; //.parent().parent().parent();
555             var rowsPerPage = this.table.fnSettings()._iDisplayLength;
556             var rowsToShow = this.table.fnSettings().fnRecordsDisplay();
557             var minRowsPerPage = this.table.fnSettings().aLengthMenu[0];
558
559             if ( rowsToShow <= rowsPerPage || rowsPerPage == -1 ) {
560                 $('.querytable_paginate', wrapper).css('visibility', 'hidden');
561             } else {
562                 $('.querytable_paginate', wrapper).css('visibility', 'visible');
563             }
564
565             if ( rowsToShow <= minRowsPerPage ) {
566                 $('.querytable_length', wrapper).css('visibility', 'hidden');
567             } else {
568                 $('.querytable_length', wrapper).css('visibility', 'visible');
569             }
570
571             
572
573
574         },
575
576
577
578         _check_click: function(e) 
579         {
580             e.stopPropagation();
581
582             var self = e.data;
583             var id=this.id;
584
585             // this.id = key of object to be added... what about multiple keys ?
586             if (debug) messages.debug("querytable._check_click key="+this.canonical_key+"->"+id+" checked="+this.checked);
587             //manifold.raise_event(self.options.query_uuid, this.checked?SET_ADD:SET_REMOVED, id);
588             //return false; // prevent checkbox to be checked, waiting response from manifold plugin api
589             
590         },
591
592         _selectAll: function() 
593         {
594             // requires jQuery id
595             var uuid=this.id.split("-");
596             var oTable=$("#querytable-"+uuid[1]).dataTable();
597             // Function available in QueryTable 1.9.x
598             // Filter : displayed data only
599             var filterData = oTable._('tr', {"filter":"applied"});   
600             /* TODO: WARNING if too many nodes selected, use filters to reduce nuber of nodes */        
601             if(filterData.length<=100){
602                 $.each(filterData, function(index, obj) {
603                     var last=$(obj).last();
604                     var key_value=unfold.get_value(last[0]);
605                     if(typeof($(last[0]).attr('checked'))=="undefined"){
606                         $.publish('selected', 'add/'+key_value);
607                     }
608                 });
609             }
610         },
611
612     });
613
614    
615
616     $.plugin('UnivbrisVtam', UnivbrisVtam);
617
618   /* define the 'dom-checkbox' type for sorting in datatables 
619      http://datatables.net/examples/plug-ins/dom_sort.html
620      using trial and error I found that the actual column number
621      was in fact given as a third argument, and not second 
622      as the various online resources had it - go figure */
623     $.fn.dataTableExt.afnSortData['dom-checkbox'] = function  ( oSettings, _, iColumn ) {
624         return $.map( oSettings.oApi._fnGetTrNodes(oSettings), function (tr, i) {
625             return result=$('td:eq('+iColumn+') input', tr).prop('checked') ? '1' : '0';
626         } );
627     }
628
629    
630
631 })(jQuery);
632
633
634