Merge branch 'fed4fire' into onelab
[myslice.git] / plugins / univbrisfvfo / static / js / univbrisfvfo.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
13     var UnivbrisFvfo = Plugin.extend({
14
15         init: function(options, element) {
16             //alert("foam init called");
17             this.classname="univbrisfvfo";
18             this._super(options, element);
19                 
20             //alert(this.options.hidden_columns);
21             /* Member variables */
22             // in general we expect 2 queries here
23             // query_uuid refers to a single object (typically a slice)
24             // query_all_uuid refers to a list (typically resources or users)
25             // these can return in any order so we keep track of which has been received yet
26             //this.received_all_query = false;
27             //this.received_query = false;
28
29             // We need to remember the active filter for datatables filtering
30             this.filters = Array(); 
31
32             // an internal buffer for records that are 'in' and thus need to be checked 
33             this.buffered_records_to_check = [];
34             // an internal buffer for keeping lines and display them in one call to fnAddData
35             this.buffered_lines = [];
36
37             /* Events */
38             // xx somehow non of these triggers at all for now
39             //this.elmt().on('show', this, this.on_show);
40             //this.elmt().on('shown.bs.tab', this, this.on_show);
41             //this.elmt().on('resize', this, this.on_resize);
42
43             //var query = manifold.query_store.find_analyzed_query(this.options.query_uuid);
44             //this.object = query.object;
45
46             //// we need 2 different keys
47             // * canonical_key is the primary key as derived from metadata (typically: urn)
48             //   and is used to communicate about a given record with the other plugins
49             // * init_key is a key that both kinds of records 
50             //   (i.e. records returned by both queries) must have (typically: hrn or hostname)
51             //   in general query_all will return well populated records, but query
52             //   returns records with only the fields displayed on startup
53             var keys = manifold.metadata.get_key(this.object);
54             this.canonical_key = (keys && keys.length == 1) ? keys[0] : undefined;
55             // 
56             this.init_key = this.options.init_key;
57             // have init_key default to canonical_key
58             this.init_key = this.init_key || this.canonical_key;
59             // sanity check
60             if ( ! this.init_key ) messages.warning ("UnivbrisFvfo : cannot find init_key");
61             if ( ! this.canonical_key ) messages.warning ("UnivbrisFvfo : cannot find canonical_key");
62             if (debug) messages.debug("UnivbrisFvfo: canonical_key="+this.canonical_key+" init_key="+this.init_key);
63
64             /* Setup query and record handlers */
65             //this.listen_query(options.query_uuid);
66             //this.listen_query(options.query_all_uuid, 'all');
67
68             /* GUI setup and event binding */
69             //this.initialize_table();
70             //alert("init fvf");
71             jQuery("#uob_ofv_table_form").hide();
72         
73             //$('<button id="cancel_addflowspaceform" type="button" style="height: 25px; width: 200px" onclick="fnCancel()">Cancel</button>').appendTo('#fvf_table_button');
74
75             //$('<button id="addflowspaceform" type="button" style="height: 25px; width: 200px" onclick="fnAddflowspace()">Add flowspace</button>').appendTo('#fvf_table_button');
76                 
77             this._querytable_draw_callback();
78         },
79
80         /* PLUGIN EVENTS */
81
82         on_show: function(e) {
83             if (debug) messages.debug("univbrisfvfo.on_show");
84             var self = e.data;
85             self.table.fnAdjustColumnSizing();
86         },        
87
88         on_resize: function(e) {
89             if (debug) messages.debug("univbrisfvfo.on_resize");
90             var self = e.data;
91             self.table.fnAdjustColumnSizing();
92         },        
93
94         /* GUI EVENTS */
95
96         /* GUI MANIPULATION */
97
98         initialize_table: function() 
99         {
100             /* Transforms the table into DataTable, and keep a pointer to it */
101             var self = this;
102             var actual_options = {
103                 // Customize the position of Datatables elements (length,filter,button,...)
104                 // we use a fluid row on top and another on the bottom, making sure we take 12 grid elt's each time
105                 //sDom: "<'row'<'col-xs-5'l><'col-xs-1'r><'col-xs-6'f>>t<'row'<'col-xs-5'i><'col-xs-7'p>>",
106                 //sDom: "<'row'<'col-xs-2'l><'col-xs-9'r><'col-xs-2'f>>t<'row'<'col-xs-5'i><'col-xs-5'p>><'next'>",
107                 sDom: "<'row'<'col-xs-9'r>t<'buttons'>",
108                 // XXX as of sept. 2013, I cannot locate a bootstrap3-friendly mode for now
109                 // hopefully this would come with dataTables v1.10 ?
110                 // in any case, search for 'sPaginationType' all over the code for more comments
111                 sPaginationType: 'bootstrap',
112                 // Handle the null values & the error : Datatables warning Requested unknown parameter
113                 // http://datatables.net/forums/discussion/5331/datatables-warning-...-requested-unknown-parameter/p2
114                 aoColumnDefs: [{sDefaultContent: '',aTargets: [ '_all' ]}],
115                 // WARNING: this one causes tables in a 'tabs' that are not exposed at the time this is run to show up empty
116                 // sScrollX: '100%',       /* Horizontal scrolling */
117                 bProcessing: false,      /* Loading */
118                 fnDrawCallback: function() { self._querytable_draw_callback.call(self);}
119                 //fnFooterCallback: function() {self._univbrisfvf_footer_callback.call(self,nFoot, aData, iStart, iEnd, aiDisplay)};}
120                 // XXX use $.proxy here !
121             };
122             // the intention here is that options.datatables_options as coming from the python object take precedence
123             // xxx DISABLED by jordan: was causing errors in datatables.js
124             // xxx turned back on by Thierry - this is the code that takes python-provided options into account
125             // check your datatables_options tag instead 
126             // however, we have to accumulate in aoColumnDefs from here (above) 
127             // and from the python wrapper (checkboxes management, plus any user-provided aoColumnDefs)
128             if ( 'aoColumnDefs' in this.options.datatables_options) {
129                 actual_options['aoColumnDefs']=this.options.datatables_options['aoColumnDefs'].concat(actual_options['aoColumnDefs']);
130                 delete this.options.datatables_options['aoColumnDefs'];
131             }
132             $.extend(actual_options, this.options.datatables_options );
133             this.table = $("#univbris_flowspace_form__table").dataTable(actual_options);
134
135             //alert(this.table);
136
137             /* Setup the SelectAll button in the dataTable header */
138             /* xxx not sure this is still working */
139             var oSelectAll = $('#datatableSelectAll-'+ this.options.plugin_uuid);
140             oSelectAll.html("<span class='glyphicon glyphicon-ok' style='float:right;display:inline-block;'></span>Select All");
141             oSelectAll.button();
142             oSelectAll.css('font-size','11px');
143             oSelectAll.css('float','right');
144             oSelectAll.css('margin-right','15px');
145             oSelectAll.css('margin-bottom','5px');
146             oSelectAll.unbind('click');
147             oSelectAll.click(this._selectAll);
148
149             /* Add a filtering function to the current table 
150              * Note: we use closure to get access to the 'options'
151              */
152             $.fn.dataTableExt.afnFiltering.push(function( oSettings, aData, iDataIndex ) { 
153                 /* No filtering if the table does not match */
154                 if (oSettings.nTable.id != self.options.plugin_uuid + '__table')
155                     return true;
156                 return self._querytable_filter.call(self, oSettings, aData, iDataIndex);
157             });
158
159            //alert(this.options.hidden_columns);
160
161             /* Processing hidden_columns */
162             $.each(this.options.hidden_columns, function(i, field) {
163                 //manifold.raise_event(self.options.query_all_uuid, FIELD_REMOVED, field);
164                 //alert (field);
165                 self.hide_column(field);
166                 //self.hide_column(field);
167             });
168
169         }, // initialize_table
170
171
172         fnCancel:function(e){
173                 //var sData=$("#uob_fv_table_form").find("input").serialize();
174                 //alert("add flowspace:" + sData);
175                 //alert("cancel"); 
176                 
177                 jQuery("#uob_ofv_table_form").hide();
178                 jQuery( "#univbris_foam_ports_selection" ).hide();
179                 jQuery( "#univbris_flowspace_selection" ).show();
180                 jQuery('#topo_plugin').hide();
181                 /*var port_table=$("#univbris_foam_ports_selection__table").dataTable();
182                 var nodes = $('input',port_table.fnGetNodes());
183                 for(var i=0;i<nodes.length;i++){
184                         nodes[i].checked=false;
185                         console.log(nodes[i].id);
186                 }*/
187
188         },
189
190
191         fnAddflowspace:function(e){
192                 e.stopPropagation();
193                 if(fvf_add==1){         
194                         pk_flowspace_index=1+pk_flowspace_index;
195                         jQuery("#uob_fv_table_form").hide();
196                         var sData=$("#uob_fv_table_form").find("input").serialize();
197                         var form =serializeAnything("#uob_fv_table_form");
198                         //alert(form);
199                         //var form2=serializeAnything("#uob_form");
200                         //alert(form2);
201                         var port_table=$("#univbris_foam_ports_selection__table").dataTable();
202                         var form2=$('input',port_table.fnGetNodes()).serialize();
203                         //console.log(form2);
204                         //alert($('input',port_table.fnGetNodes()).serialize());
205                         var nodes = $('input',port_table.fnGetNodes());
206                         //console.log(nodes[1]);
207                         //console.log(nodes);
208                         //alert($("#uob_form").serialize());
209                         //var pos = form.search("&urn");
210                         //form2=form2.substring(pos+1);
211                         //alert(form2[1]);
212                         //console.log(form2);
213                         this.table = $("#univbris_flowspace_selection__table").dataTable();
214                         
215                         var val_status=validateFvfForm();
216                         //val_status=true;
217                         if (val_status == true){
218                                 flowspace=sData;
219                                 var m_form=form+","+form2;
220                                 var string = "<p id='"+m_form+"'> <a onclick=\'fnPopTable(\""+form+"\",\""+form2+"\");'>"+$("#flowspace_name").val()+"</a></p>";        
221                                 this.table.fnAddData([string, '<a class="edit">Edit</a>', '<a class="delete" href="">Delete</a>']);
222                                 jQuery( "#univbris_foam_ports_selection" ).hide();
223                                 jQuery( "#univbris_flowspace_selection" ).show();
224                                 jQuery('#topo_plugin').hide();
225                         }
226                         else{
227                                 alert("validation failed");
228                                 jQuery("#uob_ofv_table_form").show();
229                                 jQuery( "#univbris_foam_ports_selection" ).show();
230                         }
231                 }
232                 else{
233                         jQuery("#uob_fv_table_form").hide();
234                         var sData=$("#uob_fv_table_form").find("input").serialize();
235                         var form =serializeAnything("#uob_fv_table_form");
236                         //var form2=serializeAnything("#uob_form");
237
238                         var port_table=$("#univbris_foam_ports_selection__table").dataTable();
239                         var form2=$('input',port_table.fnGetNodes()).serialize();
240                         this.table = $("#univbris_flowspace_selection__table").dataTable();
241                         flowspace=sData;
242                         var m_form=form+","+form2;
243                         var string = "<p id='"+m_form+"'> <a onclick=\'fnPopTable(\""+form+"\",\""+form2+"\");'>"+$("#flowspace_name").val()+"</a></p>";
244                         this.table.fnDeleteRow(fvf_nrow);       
245                         this.table.fnAddData([string, '<a class="edit">Edit</a>', '<a class="delete" href="">Delete</a>']);
246                         
247                         jQuery( "#univbris_foam_ports_selection" ).hide();
248                         jQuery( "#univbris_flowspace_selection" ).show();
249                         jQuery('#topo_plugin').hide();
250                 
251                 }
252         },
253
254
255         /**
256          * @brief Determine index of key in the table columns 
257          * @param key
258          * @param cols
259          */
260         getColIndex: function(key, cols) {
261             var tabIndex = $.map(cols, function(x, i) { if (x.sTitle == key) return i; });
262             return (tabIndex.length > 0) ? tabIndex[0] : -1;
263         }, // getColIndex
264
265         // create a checkbox <input> tag
266         // computes 'id' attribute from canonical_key
267         // computes 'init_id' from init_key for initialization phase
268         // no need to used convoluted ids with plugin-uuid or others, since
269         // we search using table.$ which looks only in this table
270         checkbox_html : function (record) {
271             var result="";
272             // Prefix id with plugin_uuid
273             result += "<input";
274             result += " class='univbrisfvfo-checkbox'";
275          // compute id from canonical_key
276             var id = record[this.canonical_key]
277          // compute init_id form init_key
278             var init_id=record[this.init_key];
279          // set id - for retrieving from an id, or for posting events upon user's clicks
280             result += " id='"+record[this.canonical_key]+"'";
281          // set init_id
282             result += "init_id='" + init_id + "'";
283          // wrap up
284             result += " type='checkbox'";
285             result += " autocomplete='off'";
286             result += "></input>";
287             return result;
288         }, 
289
290          fake_checkbox_html : function (record) {
291             //alert("fake fun called");
292             var result="";
293             // Prefix id with plugin_uuid
294             result += "<input";
295             //result += " class='univbrisfvfo-checkbox'";
296          // set id - for retrieving from an id, or for posting events upon user's clicks
297             result += " id='"+ record +"'";
298             result += " name='"+ record +"'";
299          // set init_id
300             result += " init_id='" + record + "'";
301          // wrap up
302             result += " type='checkbox'";
303             result += " autocomplete='off'";
304             result += "></input>";
305             ///alert(result);
306             return result;
307         }, 
308
309
310         new_record: function(record)
311         {
312            
313          // this models a line in dataTables, each element in the line describes a cell
314             line = new Array();
315      
316             // go through table headers to get column names we want
317             // in order (we have temporarily hack some adjustments in names)
318             var cols = this.table.fnSettings().aoColumns;
319             var colnames = cols.map(function(x) {return x.sTitle})
320             var nb_col = cols.length;
321             /* if we've requested checkboxes, then forget about the checkbox column for now */
322             if (this.options.checkboxes) nb_col -= 1;
323             
324             //alert(colnames);
325             /*replace production*/
326             /* fill in stuff depending on the column name */
327              var cols = this.table.fnSettings().aoColumns;
328             //alert("col "+cols);
329             var colnames = cols.map(function(x) {return x.sTitle})
330             var nb_col = cols.length;
331                         //alert("nb_col: "+ nb_col);
332             /* if we've requested checkboxes, then forget about the checkbox column for now */
333             if (this.options.checkboxes) nb_col -= 1;
334                         //alert("nb_col: "+ nb_col);
335             //alert(colnames);
336             /*replace production*/
337             /* fill in stuff depending on the column name */
338             for (var j = 0; j < nb_col; j++) {
339                 if (typeof colnames[j] == 'undefined') {
340                     line.push('...');
341                 } else if (colnames[j] == 'Flowspace Selector') {
342                     //alert("added");
343                     line.push("first");
344                 }
345                 
346             }
347     
348             // catch up with the last column if checkboxes were requested 
349             if (this.options.checkboxes) {
350                 // Use a key instead of hostname (hard coded...)
351                 line.push(this.checkbox_html(record));
352                 }
353     
354             // adding an array in one call is *much* more efficient
355                 // this.table.fnAddData(line);
356                 this.buffered_lines.push(line);
357                 this.table.fnAddData(this.buffered_lines);
358                 //this.table.redraw();
359                 //this._querytable_draw_callback();
360         },
361
362         clear_table: function()
363         {
364             this.table.fnClearTable();
365         },
366
367         redraw_table: function()
368         {
369             this.table.fnDraw();
370         },
371
372         show_column: function(field)
373         {
374             var oSettings = this.table.fnSettings();
375             var cols = oSettings.aoColumns;
376             var index = this.getColIndex(field,cols);
377             if (index != -1)
378                 this.table.fnSetColumnVis(index, true);
379         },
380
381         hide_column: function(field)
382         {
383             var oSettings = this.table.fnSettings();
384             var cols = oSettings.aoColumns;
385             var index = this.getColIndex(field,cols);
386             //index=-1;
387             //alert(field + ": index: " + index );
388             if (index != -1)
389                 //alert(field + ": hidden with index: " + index );
390                 this.table.fnSetColumnVis(index, false);
391         },
392
393         // this is used at init-time, at which point only init_key can make sense
394         // (because the argument record, if it comes from query, might not have canonical_key set
395         set_checkbox_from_record: function (record, checked) {
396             if (checked === undefined) checked = true;
397             var init_id = record[this.init_key];
398             if (debug) messages.debug("univbrisfvfo.set_checkbox_from_record, init_id="+init_id);
399             // using table.$ to search inside elements that are not visible
400             var element = this.table.$('[init_id="'+init_id+'"]');
401             element.attr('checked',checked);
402         },
403
404         // id relates to canonical_key
405         set_checkbox_from_data: function (id, checked) {
406             if (checked === undefined) checked = true;
407             if (debug) messages.debug("univbrisfvfo.set_checkbox_from_data, id="+id);
408             // using table.$ to search inside elements that are not visible
409             var element = this.table.$("[id='"+id+"']");
410             element.attr('checked',checked);
411         },
412
413         /*************************** QUERY HANDLER ****************************/
414
415         on_filter_added: function(filter)
416         {
417             this.filters.push(filter);
418             this.redraw_table();
419         },
420
421         on_filter_removed: function(filter)
422         {
423             // Remove corresponding filters
424             this.filters = $.grep(this.filters, function(x) {
425                 return x != filter;
426             });
427             this.redraw_table();
428         },
429         
430         on_filter_clear: function()
431         {
432             // XXX
433             this.redraw_table();
434         },
435
436         on_field_added: function(field)
437         {
438             this.show_column(field);
439         },
440
441         on_field_removed: function(field)
442         {
443             this.hide_column(field);
444         },
445
446         on_field_clear: function()
447         {
448             alert('UnivbrisFvfo::clear_fields() not implemented');
449         },
450
451         /* XXX TODO: make this generic a plugin has to subscribe to a set of Queries to avoid duplicated code ! */
452         /*************************** ALL QUERY HANDLER ****************************/
453
454         on_all_filter_added: function(filter)
455         {
456             // XXX
457             this.redraw_table();
458         },
459
460         on_all_filter_removed: function(filter)
461         {
462             // XXX
463             this.redraw_table();
464         },
465         
466         on_all_filter_clear: function()
467         {
468             // XXX
469             this.redraw_table();
470         },
471
472         on_all_field_added: function(field)
473         {
474             this.show_column(field);
475         },
476
477         on_all_field_removed: function(field)
478         {
479             this.hide_column(field);
480         },
481
482         on_all_field_clear: function()
483         {
484             alert('UnivbrisFvfo::clear_fields() not implemented');
485         },
486
487
488         /*************************** RECORD HANDLER ***************************/
489
490         on_new_record: function(record)
491         {
492             if (this.received_all_query) {
493                 // if the 'all' query has been dealt with already we may turn on the checkbox
494                 this.set_checkbox_from_record(record, true);
495             } else {
496                 this.buffered_records_to_check.push(record);
497             }
498         },
499
500         on_clear_records: function()
501         {
502         },
503
504         // Could be the default in parent
505         on_query_in_progress: function()
506         {
507             this.spin();
508         },
509
510         on_query_done: function()
511         {
512             this.received_query = true;
513             // unspin once we have received both
514             if (this.received_all_query && this.received_query) this.unspin();
515         },
516         
517         on_field_state_changed: function(data)
518         {
519             switch(data.request) {
520                 case FIELD_REQUEST_ADD:
521                 case FIELD_REQUEST_ADD_RESET:
522                     this.set_checkbox_from_data(data.value, true);
523                     break;
524                 case FIELD_REQUEST_REMOVE:
525                 case FIELD_REQUEST_REMOVE_RESET:
526                     this.set_checkbox_from_data(data.value, false);
527                     break;
528                 default:
529                     break;
530             }
531         },
532
533         /* XXX TODO: make this generic a plugin has to subscribe to a set of Queries to avoid duplicated code ! */
534         // all
535         on_all_field_state_changed: function(data)
536         {
537             switch(data.request) {
538                 case FIELD_REQUEST_ADD:
539                 case FIELD_REQUEST_ADD_RESET:
540                     this.set_checkboxfrom_data(data.value, true);
541                     break;
542                 case FIELD_REQUEST_REMOVE:
543                 case FIELD_REQUEST_REMOVE_RESET:
544                     this.set_checkbox_from_data(data.value, false);
545                     break;
546                 default:
547                     break;
548             }
549         },
550
551         on_all_new_record: function(record)
552         {
553             this.new_record(record);
554         },
555
556         on_all_clear_records: function()
557         {
558             this.clear_table();
559
560         },
561
562         on_all_query_in_progress: function()
563         {
564             // XXX parent
565             this.spin();
566         }, // on_all_query_in_progress
567
568         on_all_query_done: function()
569         {
570             if (debug) messages.debug("1-shot initializing dataTables content with " + this.buffered_lines.length + " lines");
571             this.table.fnAddData (this.buffered_lines);
572             this.buffered_lines=[];
573             
574             var self = this;
575             // if we've already received the slice query, we have not been able to set 
576             // checkboxes on the fly at that time (dom not yet created)
577             $.each(this.buffered_records_to_check, function(i, record) {
578                 if (debug) messages.debug ("querytable delayed turning on checkbox " + i + " record= " + record);
579                 self.set_checkbox_from_record(record, true);
580             });
581             this.buffered_records_to_check = [];
582
583             this.received_all_query = true;
584             // unspin once we have received both
585             if (this.received_all_query && this.received_query) this.unspin();
586
587         }, // on_all_query_done
588
589         /************************** PRIVATE METHODS ***************************/
590
591         /** 
592          * @brief QueryTable filtering function
593          */
594         _querytable_filter: function(oSettings, aData, iDataIndex)
595         {
596             var ret = true;
597             $.each (this.filters, function(index, filter) { 
598                 /* XXX How to manage checkbox ? */
599                 var key = filter[0]; 
600                 var op = filter[1];
601                 var value = filter[2];
602
603                 /* Determine index of key in the table columns */
604                 var col = $.map(oSettings.aoColumns, function(x, i) {if (x.sTitle == key) return i;})[0];
605
606                 /* Unknown key: no filtering */
607                 if (typeof(col) == 'undefined')
608                     return;
609
610                 col_value=unfold.get_value(aData[col]);
611                 /* Test whether current filter is compatible with the column */
612                 if (op == '=' || op == '==') {
613                     if ( col_value != value || col_value==null || col_value=="" || col_value=="n/a")
614                         ret = false;
615                 }else if (op == '!=') {
616                     if ( col_value == value || col_value==null || col_value=="" || col_value=="n/a")
617                         ret = false;
618                 } else if(op=='<') {
619                     if ( parseFloat(col_value) >= value || col_value==null || col_value=="" || col_value=="n/a")
620                         ret = false;
621                 } else if(op=='>') {
622                     if ( parseFloat(col_value) <= value || col_value==null || col_value=="" || col_value=="n/a")
623                         ret = false;
624                 } else if(op=='<=' || op=='≤') {
625                     if ( parseFloat(col_value) > value || col_value==null || col_value=="" || col_value=="n/a")
626                         ret = false;
627                 } else if(op=='>=' || op=='≥') {
628                     if ( parseFloat(col_value) < value || col_value==null || col_value=="" || col_value=="n/a")
629                         ret = false;
630                 }else{
631                     // How to break out of a loop ?
632                     alert("filter not supported");
633                     return false;
634                 }
635
636             });
637             return ret;
638         },
639
640         _querytable_draw_callback: function()
641         {
642             /* 
643              * Handle clicks on checkboxes: reassociate checkbox click every time
644              * the table is redrawn    
645              */
646             this.elts('querytable-checkbox').unbind('click').click(this, this._check_click);
647             //alert("fvf_add: "+fvf_add);
648             if(fvf_add==1){
649                 $("#addflowspaceform").unbind('click').click(this, this.fnAddflowspace);
650             }
651             else{
652                 $("[id='addflowspaceform']").unbind('click').click(this, this.fnModflowspace);
653             }
654             $("#cancel_addflowspaceform").unbind('click').click(this,this.fnCancel); 
655
656             if (!this.table)
657                 return;
658
659             /* Remove pagination if we show only a few results */
660             var wrapper = this.table; //.parent().parent().parent();
661             var rowsPerPage = this.table.fnSettings()._iDisplayLength;
662             var rowsToShow = this.table.fnSettings().fnRecordsDisplay();
663             var minRowsPerPage = this.table.fnSettings().aLengthMenu[0];
664
665             if ( rowsToShow <= rowsPerPage || rowsPerPage == -1 ) {
666                 $('.querytable_paginate', wrapper).css('visibility', 'hidden');
667             } else {
668                 $('.querytable_paginate', wrapper).css('visibility', 'visible');
669             }
670
671             if ( rowsToShow <= minRowsPerPage ) {
672                 $('.querytable_length', wrapper).css('visibility', 'hidden');
673             } else {
674                 $('.querytable_length', wrapper).css('visibility', 'visible');
675             }
676
677         },
678
679
680
681         _check_click: function(e) 
682         {
683             e.stopPropagation();
684
685             var self = e.data;
686             var id=this.id;
687
688             // this.id = key of object to be added... what about multiple keys ?
689             if (debug) messages.debug("querytable._check_click key="+this.canonical_key+"->"+id+" checked="+this.checked);
690             //manifold.raise_event(self.options.query_uuid, this.checked?SET_ADD:SET_REMOVED, id);
691             //return false; // prevent checkbox to be checked, waiting response from manifold plugin api
692             
693         },
694
695         _selectAll: function() 
696         {
697             // requires jQuery id
698             var uuid=this.id.split("-");
699             var oTable=$("#querytable-"+uuid[1]).dataTable();
700             // Function available in QueryTable 1.9.x
701             // Filter : displayed data only
702             var filterData = oTable._('tr', {"filter":"applied"});   
703             /* TODO: WARNING if too many nodes selected, use filters to reduce nuber of nodes */        
704             if(filterData.length<=100){
705                 $.each(filterData, function(index, obj) {
706                     var last=$(obj).last();
707                     var key_value=unfold.get_value(last[0]);
708                     if(typeof($(last[0]).attr('checked'))=="undefined"){
709                         $.publish('selected', 'add/'+key_value);
710                     }
711                 });
712             }
713         },
714
715     });
716
717     $.plugin('UnivbrisFvfo', UnivbrisFvfo);
718
719   /* define the 'dom-checkbox' type for sorting in datatables 
720      http://datatables.net/examples/plug-ins/dom_sort.html
721      using trial and error I found that the actual column number
722      was in fact given as a third argument, and not second 
723      as the various online resources had it - go figure */
724     $.fn.dataTableExt.afnSortData['dom-checkbox'] = function  ( oSettings, _, iColumn ) {
725         return $.map( oSettings.oApi._fnGetTrNodes(oSettings), function (tr, i) {
726             return result=$('td:eq('+iColumn+') input', tr).prop('checked') ? '1' : '0';
727         } );
728
729 };
730
731 })(jQuery);
732
733
734 function deserializeDT(d){
735
736         try{
737             var data = d,
738                 currentDom,
739                 $current = null,
740                 $currentSavedValue = null,
741                 $self = this,
742                 i = 0,
743                 keyValPairString = [],
744                 keyValPairObject = {},
745                 tmp = null,
746                 defaults = null;
747
748             if (data.constructor === String) {
749
750
751                 data = decodeURIComponent(data.replace(/\+/g, " "));
752
753                 keyValPairString = data.split('&');
754
755                 for (i = 0; i < keyValPairString.length; i++) {
756                     tmp = keyValPairString[i].split('=');
757                     keyValPairObject[tmp[0]] = tmp[1];
758
759                 }
760             }
761
762           var port_table=$("#univbris_foam_ports_selection__table").dataTable();
763           var nodes = $('input',port_table.fnGetNodes());
764
765
766           for(i=0;i<nodes.length;i++){
767                         $currentSavedValue = keyValPairObject[nodes[i].id];
768                         if ($currentSavedValue === undefined){
769                                 nodes[i].checked=false;
770                         }
771                         else{
772                                 nodes[i].checked=true;
773                         }
774           };
775
776         }
777         catch(err){
778                 alert(err);
779         }
780
781            
782 };
783
784
785 function fnPopTable(form1,form2){
786                 hideFvfError();
787                 $("[id='addflowspaceform']").hide();
788                 $("#uob_fv_table_form :input").prop("disabled", false);
789                 $("#uob_fv_table_form").deserialize(form1);
790                 deserializeDT(form2);
791
792
793                 $("[name='flowspace_name']").prop("disabled", true);
794                 $("#uob_fv_table_form :input").prop("disabled", true);
795                 $("[id='cancel_addflowspaceform']").prop("disabled", false);
796                 $("[id='cancel_addflowspaceform']").text('close');
797
798                 var port_table=$("#univbris_foam_ports_selection__table").dataTable();
799                 var nodes = $('input',port_table.fnGetNodes());
800                 for(var i=0;i<nodes.length;i++){
801                         nodes[i].disabled=true;
802                 }
803
804                 jQuery("#univbris_flowspace_selection").hide();
805                 jQuery("#uob_fv_table_form").show();
806                 jQuery( "#univbris_foam_ports_selection" ).show();
807
808                 if  ($("#flowspace_name").val().search("pk")==0){
809                         topoviewer_state={mode:"read",link_type:"non-optical"};
810                 }
811                 else{
812                         topoviewer_state={mode:"read",link_type:"optical"};
813                 }
814                 
815                 jQuery('#topo_plugin').show();
816 };
817
818 function macValidator (mac_str){
819         if (mac_str != ""){
820                 var mac_validator=/(^(([0-9a-fA-F]{2}[:-]){5}([0-9a-fA-F]{2}))$)|(^(([0-9a-fA-F]{2}[:-]){5}([0-9a-fA-F]{2})))$/;
821                 var result =mac_str.match(mac_validator);
822                 if (result==null){
823                         return false;
824                 }
825                 else{
826                         return true;
827                 }
828         }
829         else{
830                 return true;
831         }
832 };
833
834 function ethertypeValidator (eth_str){
835         if (eth_str != ""){
836                 var ethertype_validator=/^0x[0-9a-fA-F]{4}$/;
837                 var result = eth_str.match(ethertype_validator);
838                 if (result==null){
839                         return false;
840                 }
841                 else{
842                         return true;
843                 }
844         }
845         else{
846                 return true;
847         }
848 };
849
850
851 function vlanValidator (vlan_str){
852         if (vlan_str != ""){
853                 var vlan_validator=/(^[1-9][0-9]{0,2}|[1-3][0-9]{3}|40[0-8][0-9]|409[0-5]$)/;
854                 var result = vlan_str.match(vlan_validator);
855                 if (result==null){
856                         return false;
857                 }
858                 else{
859                         return true;
860                 }
861         }
862         else {
863                 return true;
864         }
865 };
866
867 function ipValidator(ip_str){
868         if (ip_str != ""){
869                 var ip_validator=/(^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)/;
870                 var result = ip_str.match(ip_validator);
871                 if (result==null){
872                         return false;
873                 }
874                 else{
875                         return true;
876                 }
877         }
878         else {
879                 return true;
880         }
881 };
882
883
884 function portValidator (port_str){
885         if (port_str != ""){
886                 var port_validator=/^([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$/;
887                 var result = port_str.match(port_validator);
888                 if (result==null){
889                         return false;
890                 }
891                 else{
892                         return true;
893                 }
894         }
895         else {
896                 return true;
897         }       
898 }
899
900 function ipProtoValidator (ipproto_str){
901         if (ipproto_str != ""){
902                 var ipproto_validator=/(^[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5]$)/;
903                 var result = ipproto_str.match(ipproto_validator);
904                 if (result==null){
905                         return false;
906                 }
907                 else{
908                         return true;
909                 }
910         }
911         else {
912                 return true;
913         }       
914 }
915
916
917
918
919
920
921
922 function validateFvfForm(){
923         var status = false;
924         var checked =0;
925
926         //row 1 validation
927         if (macValidator ($("#uob_fv_table_dl_src_start").val())==false){
928                 $("#uob_fv_table_dl_src_start").addClass('error');
929                 $("#uob_fv_table_dl_src_error").show();
930         }
931         else {
932                 checked++;
933         }
934
935         if (macValidator ($("#uob_fv_table_dl_src_end").val())==false){
936                 $("#uob_fv_table_dl_src_end").addClass('error');
937                 $("#uob_fv_table_dl_src_error").show();
938         }
939         else {
940                 checked++;
941         }
942
943         //row 2 validation
944
945         if (macValidator ($("#uob_fv_table_dl_dst_start").val())==false){
946                 $("#uob_fv_table_dl_dst_start").addClass('error');
947                 $("#uob_fv_table_dl_dst_error").show();
948         }
949         else {
950                 checked++;
951         }
952
953         if (macValidator ($("#uob_fv_table_dl_dst_end").val())==false){
954                 $("#uob_fv_table_dl_dst_end").addClass('error');
955                 $("#uob_fv_table_dl_dst_error").show();
956         }
957         else {
958                 checked++;
959         }
960
961         //row 3 validation
962         
963         if (ethertypeValidator ($("#uob_fv_table_dl_type_start").val())==false){
964                 $("#uob_fv_table_dl_type_start").addClass('error');
965                 $("#uob_fv_table_dl_type_error").show();
966         }
967         else {
968                 checked++;
969         }
970
971         if (ethertypeValidator ($("#uob_fv_table_dl_type_end").val())==false){
972                 $("#uob_fv_table_dl_type_end").addClass('error');
973                 $("#uob_fv_table_dl_type_error").show();
974         }
975         else {
976                 checked++;
977         }
978
979
980         //row 4 validation
981         if (vlanValidator ($("#uob_fv_table_vlan_id_start").val())==false){
982                 $("#uob_fv_table_vlan_id_start").addClass('error');
983                 $("#uob_fv_table_vlan_id_error").show();
984         }
985         else {
986                 checked++;
987         }
988
989         if (vlanValidator ($("#uob_fv_table_vlan_id_end").val())==false){
990                 $("#uob_fv_table_vlan_id_end").addClass('error');
991                 $("#uob_fv_table_vlan_id_error").show();
992         }
993         else {
994                 checked++;
995         }
996  
997         //row 5 validation
998         if (ipValidator ($("#uob_fv_table_nw_src_start").val())==false){
999                 $("#uob_fv_table_nw_src_start").addClass('error');
1000                 $("#uob_fv_table_nw_src_error").show();
1001         }
1002         else {
1003                 checked++;
1004         }
1005
1006         if (ipValidator ($("#uob_fv_table_nw_src_end").val())==false){
1007                 $("#uob_fv_table_nw_src_end").addClass('error');
1008                 $("#uob_fv_table_nw_src_error").show();
1009         }
1010         else {
1011                 checked++;
1012         }
1013
1014         //row 6 validation
1015         if (ipValidator ($("#uob_fv_table_nw_dst_start").val())==false){
1016                 $("#uob_fv_table_nw_dst_start").addClass('error');
1017                 $("#uob_fv_table_nw_dst_error").show();
1018         }
1019         else {
1020                 checked++;
1021         }
1022
1023         if (ipValidator ($("#uob_fv_table_nw_dst_end").val())==false){
1024                 $("#uob_fv_table_nw_dst_end").addClass('error');
1025                 $("#uob_fv_table_nw_dst_error").show();
1026         }
1027         else {
1028                 checked++;
1029         }
1030
1031
1032
1033         //row 7 validation
1034
1035         if (ipProtoValidator ($("#uob_fv_table_nw_proto_start").val())==false){
1036                 $("#uob_fv_table_nw_proto_start").addClass('error');
1037                 $("#uob_fv_table_nw_proto_error").show();
1038         }
1039         else {
1040                 checked++;
1041         }
1042
1043         if (ipProtoValidator ($("#uob_fv_table_nw_proto_end").val())==false){
1044                 $("#uob_fv_table_nw_proto_end").addClass('error');
1045                 $("#uob_fv_table_nw_proto_error").show();
1046         }
1047         else {
1048                 checked++;
1049         }
1050
1051         //row 8 validation
1052         if (portValidator ($("#uob_fv_table_tp_src_start").val())==false){
1053                 $("#uob_fv_table_tp_src_start").addClass('error');
1054                 $("#uob_fv_table_tp_src_error").show();
1055         }
1056         else {
1057                 checked++;
1058         }
1059
1060         if (portValidator ($("#uob_fv_table_tp_src_end").val())==false){
1061                 $("#uob_fv_table_tp_src_end").addClass('error');
1062                 $("#uob_fv_table_tp_src_error").show();
1063         }
1064         else {
1065                 checked++;
1066         }
1067
1068         //row 9 validation
1069         if (portValidator ($("#uob_fv_table_tp_dst_start").val())==false){
1070                 $("#uob_fv_table_tp_dst_start").addClass('error');
1071                 $("#uob_fv_table_tp_dst_error").show();
1072         }
1073         else {
1074                 checked++;
1075         }
1076
1077         if (portValidator ($("#uob_fv_table_tp_dst_end").val())==false){
1078                 $("#uob_fv_table_tp_dst_end").addClass('error');
1079                 $("#uob_fv_table_tp_dst_error").show();
1080         }
1081         else {
1082                 checked++;
1083         }/**/
1084
1085         //validate that at least one port is selected
1086         var port_table=$("#univbris_foam_ports_selection__table").dataTable();
1087         var nodes = $('input',port_table.fnGetNodes());
1088
1089         var port_selected=false;
1090         for(var i=0;i<nodes.length;i++){
1091                 if(nodes[i].checked==true){
1092                         checked++;
1093                         port_selected=true;
1094                         break;
1095                 }                       
1096         }
1097
1098         if (checked >= 19) {
1099                 status=true;
1100         }
1101
1102         if (port_selected==false & checked == 18){
1103                 alert("you need to select at least one port");
1104         }
1105         else if (port_selected==false & checked <= 18){
1106                 alert("you need to select at least one port and correct other flowspace parameter errors");
1107         }
1108         else if (port_selected==true & checked <= 18){
1109                 alert("you need to correct other flowspace parameter errors");
1110         }
1111         
1112         //alert("validator status:"+status+" checked:"+checked);
1113         return status;
1114 }
1115
1116
1117
1118 function fnGetSelected( oTableLocal )
1119 {
1120         var aReturn = new Array();
1121         var aTrs = oTableLocal.fnGetNodes();
1122         
1123         for ( var i=0 ; i<aTrs.length ; i++ )
1124         {
1125                 if ( $(aTrs[i]).hasClass('row_selected') )
1126                 {
1127                         aReturn.push( aTrs[i] );
1128                 }
1129         }
1130         return aReturn;
1131 }
1132
1133 function serializeAnything (form){
1134         var toReturn    = [];
1135         var els         = $(form).find(':input').get();
1136
1137         $.each(els, function() {                        
1138                 if (this.name && (this.checked || /select|textarea/i.test(this.nodeName) || /text|hidden|password/i.test(this.type))) {
1139                                 var val = $(this).val();
1140                                 toReturn.push( encodeURIComponent(this.name) + "=" + encodeURIComponent( val ) );
1141                         }
1142                 });
1143
1144                 return toReturn.join("&").replace(/%20/g, "+");
1145 }
1146
1147 function hideFvfError(){
1148         $("[id*=_error]").hide();
1149         console
1150         $("#uob_fv_table_form :input").each(function(){
1151                 try{
1152                         $(this).removeClass('error');
1153                 }
1154                 catch (err){
1155                 }
1156
1157         });
1158 }
1159
1160
1161 (function ($) {
1162     $.fn.extend({
1163         deserialize : function (d, config) {
1164             var data = d,
1165                 currentDom,
1166                 $current = null,
1167                 $currentSavedValue = null,
1168                 $self = this,
1169                 i = 0,
1170                 keyValPairString = [],
1171                 keyValPairObject = {},
1172                 tmp = null,
1173                 defaults = null;
1174
1175             if (d === undefined || !$self.is('form')) {
1176                 return $self;
1177             }
1178
1179             defaults = {
1180                 overwrite : true
1181             };
1182
1183             config = $.extend(defaults, config);
1184
1185             if (d.constructor === String) {
1186
1187
1188                 d = decodeURIComponent(d.replace(/\+/g, " "));
1189
1190                 keyValPairString = d.split('&');
1191
1192                 for (i = 0; i < keyValPairString.length; i++) {
1193                     tmp = keyValPairString[i].split('=');
1194                     keyValPairObject[tmp[0]] = tmp[1];
1195
1196                 }
1197             }
1198
1199             $('input, select, textarea', $self).each(function (i) {
1200
1201                 $current = $(this);
1202                 currentDom = $current.get(0);
1203                 $currentSavedValue = keyValPairObject[$current.attr('name')];
1204
1205                 if (currentDom.disabled === true) {
1206                     //current.val($currentSavedValue);
1207                     return true;
1208                 }
1209
1210                 if ($current.is('textarea')) {
1211                     if ($currentSavedValue === undefined) {
1212                         $current.val('');
1213                     } else {
1214                         $current.val($currentSavedValue);
1215                     }
1216                     return true;
1217                 }
1218
1219                 if ($current.is('select')) {
1220                     if ($currentSavedValue === undefined) {
1221                         return true;
1222                     } else {
1223                         currentDom.selectedIndex = $currentSavedValue;
1224                     }
1225                     return true;
1226                 }
1227
1228                 if ($current.is('input:radio')) {
1229                     if ($currentSavedValue !== undefined) {
1230
1231                         $current.each(function () {
1232                             if ($(this).val() === $currentSavedValue) {
1233                                 $(this).get(0).checked = true;
1234                             }
1235                         });
1236                     }
1237
1238                     return true;
1239                 }
1240
1241                 if ($current.is('input:checkbox')) {
1242                     currentDom.checked = ($current.val() === $currentSavedValue);
1243                     return true;
1244                 }
1245
1246                 if ($current.is('input:text, input:hidden')) {
1247                     if ($currentSavedValue === undefined) {
1248                         $current.val('');
1249                     } else {
1250                         $current.val($currentSavedValue);
1251                         return true;
1252                     }
1253
1254                 }
1255
1256             });
1257
1258             return $self;
1259         }
1260
1261     });
1262
1263
1264 }(jQuery));
1265
1266