extremely rough sketch of querytable using slickgrid
[myslice.git] / plugins / querytable / static / js / querytable.js
index 9d7bced..45d12aa 100644 (file)
@@ -4,15 +4,14 @@
  * License: GPLv3
  */
 
-(function($){
+(function($) {
 
     var debug=false;
-//    debug=true
+    debug=true
 
     var QueryTable = Plugin.extend({
 
-        init: function(options, element) 
-        {
+        init: function(options, element) {
             this._super(options, element);
 
             /* Member variables */
             this.received_all_query = false;
             this.received_query = false;
 
-            // We need to remember the active filter for datatables filtering
-            this.filters = Array(); 
+//            // We need to remember the active filter for datatables filtering
+//            this.filters = Array(); 
 
             // an internal buffer for records that are 'in' and thus need to be checked 
             this.buffered_records_to_check = [];
-           // an internal buffer for keeping lines and display them in one call to fnAddData
-           this.buffered_lines = [];
 
             /* XXX Events XXX */
             // this.$element.on('show.Datatables', this.on_show);
@@ -52,7 +49,7 @@
            }
            if (! this.key) messages.warning("querytable.init could not kind valid key");
 
-           messages.debug("querytable: key="+this.key);
+           if (debug) messages.debug("querytable: key="+this.key);
 
             /* Setup query and record handlers */
             this.listen_query(options.query_uuid);
 
         /* PLUGIN EVENTS */
 
-        on_show: function(e)
-        {
+        on_show: function(e) {
             var self = e.data;
-
             self.table.fnAdjustColumnSizing()
-        
-            /* Refresh dataTabeles if click on the menu to display it : fix dataTables 1.9.x Bug */        
-            /* temp disabled... useful ? -- jordan
-            $(this).each(function(i,elt) {
-                if (jQuery(elt).hasClass('dataTables')) {
-                    var myDiv=jQuery('#querytable-' + this.id).parent();
-                    if(myDiv.height()==0) {
-                        var oTable=$('#querytable-' + this.id).dataTable();            
-                        oTable.fnDraw();
-                    }
-                }
-            });
-            */
         }, // on_show
 
         /* GUI EVENTS */
 
         /* GUI MANIPULATION */
 
-        initialize_table: function() 
-        {
-            /* Transforms the table into DataTable, and keep a pointer to it */
-            var self = this;
-            var actual_options = {
-                // Customize the position of Datatables elements (length,filter,button,...)
-                // we use a fluid row on top and another on the bottom, making sure we take 12 grid elt's each time
-                sDom: "<'row'<'col-xs-5'l><'col-xs-1'r><'col-xs-6'f>>t<'row'<'col-xs-5'i><'col-xs-7'p>>",
-               // XXX as of sept. 2013, I cannot locate a bootstrap3-friendly mode for now
-               // hopefully this would come with dataTables v1.10 ?
-               // in any case, search for 'sPaginationType' all over the code for more comments
-                sPaginationType: 'bootstrap',
-                // Handle the null values & the error : Datatables warning Requested unknown parameter
-                // http://datatables.net/forums/discussion/5331/datatables-warning-...-requested-unknown-parameter/p2
-                aoColumnDefs: [{sDefaultContent: '',aTargets: [ '_all' ]}],
-                // WARNING: this one causes tables in a 'tabs' that are not exposed at the time this is run to show up empty
-                // sScrollX: '100%',       /* Horizontal scrolling */
-                bProcessing: true,      /* Loading */
-                fnDrawCallback: function() { self._querytable_draw_callback.call(self); }
-                // XXX use $.proxy here !
-            };
-            // the intention here is that options.datatables_options as coming from the python object take precedence
-           // xxx DISABLED by jordan: was causing errors in datatables.js
-           // xxx turned back on by Thierry - this is the code that takes python-provided options into account
-           // check your datatables_options tag instead 
-           // however, we have to accumulate in aoColumnDefs from here (above) 
-           // and from the python wrapper (checkboxes management, plus any user-provided aoColumnDefs)
-           if ( 'aoColumnDefs' in this.options.datatables_options) {
-               actual_options['aoColumnDefs']=this.options.datatables_options['aoColumnDefs'].concat(actual_options['aoColumnDefs']);
-               delete this.options.datatables_options['aoColumnDefs'];
+        initialize_table: function() {
+           // compute columns based on columns and hidden_columns
+           this.slick_columns = [];
+           var all_columns = this.options.columns; // .concat(this.options.hidden_columns)
+           for (c in all_columns) {
+               var column=all_columns[c];
+               this.slick_columns.push ( {id:column, name:column, field:column });
            }
-           $.extend(actual_options, this.options.datatables_options );
-            this.table = this.elmt('table').dataTable(actual_options);
-
-            /* Setup the SelectAll button in the dataTable header */
-            /* xxx not sure this is still working */
-            var oSelectAll = $('#datatableSelectAll-'+ this.options.plugin_uuid);
-            oSelectAll.html("<span class='glyphicon glyphicon-ok' style='float:right;display:inline-block;'></span>Select All");
-            oSelectAll.button();
-            oSelectAll.css('font-size','11px');
-            oSelectAll.css('float','right');
-            oSelectAll.css('margin-right','15px');
-            oSelectAll.css('margin-bottom','5px');
-            oSelectAll.unbind('click');
-            oSelectAll.click(this._selectAll);
-
-            /* Add a filtering function to the current table 
-             * Note: we use closure to get access to the 'options'
-             */
-            $.fn.dataTableExt.afnFiltering.push(function( oSettings, aData, iDataIndex ) { 
-                /* No filtering if the table does not match */
-                if (oSettings.nTable.id != self.options.plugin_uuid + '__table')
-                    return true;
-                return self._querytable_filter.call(self, oSettings, aData, iDataIndex);
-            });
 
-            /* Processing hidden_columns */
-            $.each(this.options.hidden_columns, function(i, field) {
-                //manifold.raise_event(self.options.query_all_uuid, FIELD_REMOVED, field);
-                self.hide_column(field);
-            });
+           // xxx should be extensible from caller with this.options.slickgrid_options 
+           this.slick_options = {
+               enableCellNavigation: false,
+               enableColumnReorder: true,
+           };
+
+           this.slick_data=[];
+           
+           var selector="#grid-"+this.options.domid;
+           if (debug) {
+               messages.debug("slick grid selector is " + selector);
+               for (c in this.slick_columns) {
+                   var col=this.slick_columns[c];
+                   var msg="";
+                   for (k in col) msg = msg+" col["+k+"]="+col[k];
+                   messages.debug("slick_column["+c+"]:"+msg);
+               }
+           }
+           this.slick_grid = new Slick.Grid(selector, this.slick_data, this.slick_columns, this.slick_options);
+
         }, // initialize_table
 
-        /**
-         * @brief Determine index of key in the table columns 
-         * @param key
-         * @param cols
-         */
+       // Determine index of key in the table columns 
         getColIndex: function(key, cols) {
             var tabIndex = $.map(cols, function(x, i) { if (x.sTitle == key) return i; });
             return (tabIndex.length > 0) ? tabIndex[0] : -1;
         }, // getColIndex
 
-        checkbox_html : function (key, value)
-        {
+        checkbox_html : function (key, value) {
 //         if (debug) messages.debug("checkbox_html, value="+value);
             var result="";
             // Prefix id with plugin_uuid
             return result;
         }, 
 
-
-        new_record: function(record)
-        {
-            // this models a line in dataTables, each element in the line describes a cell
-            line = new Array();
-     
-            // go through table headers to get column names we want
-            // in order (we have temporarily hack some adjustments in names)
-            var cols = this.table.fnSettings().aoColumns;
-            var colnames = cols.map(function(x) {return x.sTitle})
-            var nb_col = cols.length;
-            /* if we've requested checkboxes, then forget about the checkbox column for now */
-            if (this.options.checkboxes) nb_col -= 1;
-
-            /* fill in stuff depending on the column name */
-            for (var j = 0; j < nb_col; j++) {
-                if (typeof colnames[j] == 'undefined') {
-                    line.push('...');
-                } else if (colnames[j] == 'hostname') {
-                    if (record['type'] == 'resource,link')
-                        //TODO: we need to add source/destination for links
-                        line.push('');
-                    else
-                        line.push(record['hostname']);
-
-                } else if (colnames[j] == 'hrn' && typeof(record) != 'undefined') {
-                    line.push('<a href="../resource/'+record['urn']+'"><span class="glyphicon glyphicon-search"></span></a> '+record['hrn']);
-                } else {
-                    if (record[colnames[j]])
-                        line.push(record[colnames[j]]);
-                    else
-                        line.push('');
-                }
-            }
-    
-            // catch up with the last column if checkboxes were requested 
-            if (this.options.checkboxes) {
-                // Use a key instead of hostname (hard coded...)
-                line.push(this.checkbox_html(this.key, record[this.key]));
-               }
-    
-           // adding an array in one call is *much* more efficient
-               // this.table.fnAddData(line);
-               this.buffered_lines.push(line);
+        new_record: function(record) {
+           this.slick_data.push(record);
         },
 
-        clear_table: function()
-        {
-            this.table.fnClearTable();
+        clear_table: function() {
+           console.log("clear_table not implemented");
         },
 
-        redraw_table: function()
-        {
+        redraw_table: function() {
             this.table.fnDraw();
         },
 
-        show_column: function(field)
-        {
+        show_column: function(field) {
             var oSettings = this.table.fnSettings();
             var cols = oSettings.aoColumns;
             var index = this.getColIndex(field,cols);
                 this.table.fnSetColumnVis(index, true);
         },
 
-        hide_column: function(field)
-        {
-            var oSettings = this.table.fnSettings();
-            var cols = oSettings.aoColumns;
-            var index = this.getColIndex(field,cols);
-            if (index != -1)
-                this.table.fnSetColumnVis(index, false);
+        hide_column: function(field) {
+           console.log("hide_column not implemented - field="+field);
         },
 
-        set_checkbox: function(record, checked)
-        {
+        set_checkbox: function(record, checked) {
+           console.log("set_checkbox not implemented");
+           return;
             /* Default: checked = true */
             if (checked === undefined) checked = true;
 
 
         /*************************** QUERY HANDLER ****************************/
 
-        on_filter_added: function(filter)
-        {
+        on_filter_added: function(filter) {
             this.filters.push(filter);
             this.redraw_table();
         },
 
-        on_filter_removed: function(filter)
-        {
+        on_filter_removed: function(filter) {
             // Remove corresponding filters
             this.filters = $.grep(this.filters, function(x) {
                 return x != filter;
             this.redraw_table();
         },
         
-        on_filter_clear: function()
-        {
-            // XXX
+        on_filter_clear: function() {
             this.redraw_table();
         },
 
-        on_field_added: function(field)
-        {
+        on_field_added: function(field) {
             this.show_column(field);
         },
 
-        on_field_removed: function(field)
-        {
+        on_field_removed: function(field) {
             this.hide_column(field);
         },
 
-        on_field_clear: function()
-        {
+        on_field_clear: function() {
             alert('QueryTable::clear_fields() not implemented');
         },
 
         /* XXX TODO: make this generic a plugin has to subscribe to a set of Queries to avoid duplicated code ! */
         /*************************** ALL QUERY HANDLER ****************************/
 
-        on_all_filter_added: function(filter)
-        {
+        on_all_filter_added: function(filter) {
             // XXX
             this.redraw_table();
         },
 
-        on_all_filter_removed: function(filter)
-        {
+        on_all_filter_removed: function(filter) {
             // XXX
             this.redraw_table();
         },
         
-        on_all_filter_clear: function()
-        {
+        on_all_filter_clear: function() {
             // XXX
             this.redraw_table();
         },
 
-        on_all_field_added: function(field)
-        {
+        on_all_field_added: function(field) {
             this.show_column(field);
         },
 
-        on_all_field_removed: function(field)
-        {
+        on_all_field_removed: function(field) {
             this.hide_column(field);
         },
 
-        on_all_field_clear: function()
-        {
+        on_all_field_clear: function() {
             alert('QueryTable::clear_fields() not implemented');
         },
 
 
         /*************************** RECORD HANDLER ***************************/
 
-        on_new_record: function(record)
-        {
+        on_new_record: function(record) {
             if (this.received_all_query) {
                // if the 'all' query has been dealt with already we may turn on the checkbox
                 this.set_checkbox(record, true);
             }
         },
 
-        on_clear_records: function()
-        {
+        on_clear_records: function() {
         },
 
         // Could be the default in parent
-        on_query_in_progress: function()
-        {
+        on_query_in_progress: function() {
             this.spin();
         },
 
-        on_query_done: function()
-        {
+        on_query_done: function() {
             this.received_query = true;
            // unspin once we have received both
             if (this.received_all_query && this.received_query) this.unspin();
         },
         
-        on_field_state_changed: function(data)
-        {
+        on_field_state_changed: function(data) {
             switch(data.request) {
                 case FIELD_REQUEST_ADD:
                 case FIELD_REQUEST_ADD_RESET:
 
         /* XXX TODO: make this generic a plugin has to subscribe to a set of Queries to avoid duplicated code ! */
         // all
-        on_all_field_state_changed: function(data)
-        {
+        on_all_field_state_changed: function(data) {
             switch(data.request) {
                 case FIELD_REQUEST_ADD:
                 case FIELD_REQUEST_ADD_RESET:
             }
         },
 
-        on_all_new_record: function(record)
-        {
+        on_all_new_record: function(record) {
             this.new_record(record);
         },
 
-        on_all_clear_records: function()
-        {
+        on_all_clear_records: function() {
             this.clear_table();
 
         },
 
-        on_all_query_in_progress: function()
-        {
+        on_all_query_in_progress: function() {
             // XXX parent
             this.spin();
         }, // on_all_query_in_progress
 
-        on_all_query_done: function()
-        {
-           if (debug) messages.debug("1-shot initializing dataTables content with " + this.buffered_lines.length + " lines");
-           this.table.fnAddData (this.buffered_lines);
-           this.buffered_lines=[];
+        on_all_query_done: function() {
+           if (debug) messages.debug("1-shot initializing dataTables content with " + this.slick_data.length + " lines");
+           this.slick_grid.setData (this.slick_data, true);
+           if (debug) 
+               for (k in this.slick_data[0]) messages.debug("slick_data[0]["+k+"]="+this.slick_data[0][k]);
+           this.slick_grid.render();
            
             var self = this;
            // if we've already received the slice query, we have not been able to set 
         /** 
          * @brief QueryTable filtering function
          */
-        _querytable_filter: function(oSettings, aData, iDataIndex)
-        {
+        _querytable_filter: function(oSettings, aData, iDataIndex) {
             var ret = true;
             $.each (this.filters, function(index, filter) { 
                 /* XXX How to manage checkbox ? */
             return ret;
         },
 
-        _querytable_draw_callback: function()
-        {
+        _querytable_draw_callback: function() {
             /* 
              * Handle clicks on checkboxes: reassociate checkbox click every time
              * the table is redrawn 
             }
         },
 
-        _check_click: function(e) 
-        {
+        _check_click: function(e) {
             e.stopPropagation();
 
             var self = e.data;
             
         },
 
-        _selectAll: function() 
-        {
+        _selectAll: function() {
             // requires jQuery id
             var uuid=this.id.split("-");
             var oTable=$("#querytable-"+uuid[1]).dataTable();
 
     $.plugin('QueryTable', QueryTable);
 
-  /* define the 'dom-checkbox' type for sorting in datatables 
-     http://datatables.net/examples/plug-ins/dom_sort.html
-     using trial and error I found that the actual column number
-     was in fact given as a third argument, and not second 
-     as the various online resources had it - go figure */
-    $.fn.dataTableExt.afnSortData['dom-checkbox'] = function  ( oSettings, _, iColumn ) {
-       return $.map( oSettings.oApi._fnGetTrNodes(oSettings), function (tr, i) {
-           return result=$('td:eq('+iColumn+') input', tr).prop('checked') ? '1' : '0';
-       } );
-    }
+//  /* define the 'dom-checkbox' type for sorting in datatables 
+//     http://datatables.net/examples/plug-ins/dom_sort.html
+//     using trial and error I found that the actual column number
+//     was in fact given as a third argument, and not second 
+//     as the various online resources had it - go figure */
+//    $.fn.dataTableExt.afnSortData['dom-checkbox'] = function  ( oSettings, _, iColumn ) {
+//     return $.map( oSettings.oApi._fnGetTrNodes(oSettings), function (tr, i) {
+//         return result=$('td:eq('+iColumn+') input', tr).prop('checked') ? '1' : '0';
+//     } );
+//    }
 
 })(jQuery);