cosmetic - on_show message displayed only if debug selected
[myslice.git] / plugins / hazelnut / static / js / hazelnut.js
index 316c3f8..dbff4ce 100644 (file)
@@ -6,9 +6,8 @@
 
 (function($){
 
-    // TEMP
     var debug=false;
-    debug=true
+//    debug=true
 
     var Hazelnut = Plugin.extend({
 
             this._super(options, element);
 
             /* Member variables */
-            // query status
-            this.received_all = false;
-            this.received_set = false;
-            this.in_set_buffer = Array();
+           // in general we expect 2 queries here
+           // query_uuid refers to a single object (typically a slice)
+           // query_all_uuid refers to a list (typically resources or users)
+           // these can return in any order so we keep track of which has been received yet
+            this.received_all_query = false;
+            this.received_query = false;
+
+            // 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);
             this.listen_query(options.query_uuid);
             this.listen_query(options.query_all_uuid, 'all');
 
-           /* an internal buffer for keeping lines and display them in one call to fnAddData */
-           this.buffered_lines = [];
-
             /* GUI setup and event binding */
             this.initialize_table();
         },
 
-        default_options: {
-            'checkboxes': false
-        },
-
         /* PLUGIN EVENTS */
 
         on_show: function(e)
@@ -80,7 +79,7 @@
         {
             /* Transforms the table into DataTable, and keep a pointer to it */
             var self = this;
-            actual_options = {
+            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-md-5'l><'col-md-1'r><'col-md-6'f>>t<'row'<'col-md-5'i><'col-md-7'p>>",
                 // 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     $.extend(actual_options, options.datatables_options );
+           // 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'];
+           }
+           $.extend(actual_options, this.options.datatables_options );
             this.table = this.elmt('table').dataTable(actual_options);
 
             /* Setup the SelectAll button in the dataTable header */
             return (tabIndex.length > 0) ? tabIndex[0] : -1;
         }, // getColIndex
 
-        checkbox: function (key, value)
+        checkbox_html : function (key, value)
         {
             var result="";
             // Prefix id with plugin_uuid
             result += "<input";
             result += " class='hazelnut-checkbox'";
-            result += " id='" + this.id('checkbox', this.id_from_key(key, value)) + "'";
+            result += " id='" + this.flat_id(this.id('checkbox', value)) + "'";
             result += " name='" + key + "'";
             result += " type='checkbox'";
             result += " autocomplete='off'";
                 }
             }
     
-            /* catch up with the last column if checkboxes were requested */
-            if (this.options.checkboxes)
+            // catch up with the last column if checkboxes were requested 
+            if (this.options.checkboxes) {
                 // Use a key instead of hostname (hard coded...)
-                // XXX remove the empty checked attribute
-                line.push(this.checkbox(this.key, record[this.key]));
+                line.push(this.checkbox_html(this.key, record[this.key]));
+           }
     
-            // XXX Is adding an array of lines more efficient ?
-//            this.table.fnAddData(line);
-           this.buffered_lines.push(line)
+           // adding an array in one call is *much* more efficient
+           // this.table.fnAddData(line);
+           this.buffered_lines.push(line);
 
         },
 
         set_checkbox: function(record, checked)
         {
             /* Default: checked = true */
-            if (typeof checked === 'undefined')
-                checked = true;
+            if (checked === undefined) checked = true;
 
             var key_value;
             /* The function accepts both records and their key */
             }
 
 
-            var checkbox_id = this.id('checkbox', this.id_from_key(this.key, key_value));
-            checkbox_id = '#' + checkbox_id.replace(/\./g, '\\.');
-
-            var element = $(checkbox_id, this.table.fnGetNodes());
-
+            var checkbox_id = this.flat_id(this.id('checkbox', key_value));
+            checkbox_id = '#' + checkbox_id;
+           // using dataTables's $ to search also in nodes that are not currently displayed
+            var element = this.table.$(checkbox_id);
+           if (debug) messages.debug("set_checkbox checked=" + checked + " id=" + checkbox_id + " matches=" + element.length);
             element.attr('checked', checked);
         },
 
 
         on_new_record: function(record)
         {
-            /* NOTE in fact we are doing a join here */
-            if (this.received_all)
-                // update checkbox for record
+            if (this.received_all_query) {
+               // if the 'all' query has been dealt with already we may turn on the checkbox
+               if (debug) messages.debug("turning on checkbox for record "+record[this.key]);
                 this.set_checkbox(record, true);
-            else
-                // store for later update of checkboxes
-                this.in_set_buffer.push(record);
+           } else {
+               // otherwise we need to remember that and do it later on
+               if (debug) messages.debug ("Remembering record to check " + record[this.key]);
+                this.buffered_records_to_check.push(record);
+           }
         },
 
         on_clear_records: function()
 
         on_query_done: function()
         {
-            if (this.received_all)
-                this.unspin();
-            this.received_set = true;
+            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_all_query_done: function()
         {
-            var self = this;
-            if (this.received_set) {
-                /* XXX needed ? XXX We uncheck all checkboxes ... */
-                $("[id^='datatables-checkbox-" + this.options.plugin_uuid +"']").attr('checked', false);
-
-                /* ... and check the ones specified in the resource list */
-                $.each(this.in_set_buffer, function(i, record) {
-                    self.set_checkbox(record, true);
-                });
-
-                this.unspin();
-            }
+           if (debug) messages.debug("1-shot initializing dataTables content with " + this.buffered_lines.length + " lines");
            this.table.fnAddData (this.buffered_lines);
            this.buffered_lines=[];
-            this.received_all = true;
+           
+            var self = this;
+           // if we've already received the slice query, we have not been able to set 
+           // checkboxes on the fly at that time (dom not yet created)
+            $.each(this.buffered_records_to_check, function(i, record) {
+               if (debug) messages.debug ("delayed turning on checkbox " + i + " record= " + record);
+                self.set_checkbox(record, true);
+            });
+           this.buffered_records_to_check = [];
+
+            this.received_all_query = true;
+           // unspin once we have received both
+            if (this.received_all_query && this.received_query) this.unspin();
 
         }, // on_all_query_done
 
             var self = e.data;
 
             // XXX this.value = key of object to be added... what about multiple keys ?
+           if (debug) messages.debug("hazelnut click handler checked=" + this.checked + " hrn=" + this.value);
             manifold.raise_event(self.options.query_uuid, this.checked?SET_ADD:SET_REMOVED, this.value);
             //return false; // prevent checkbox to be checked, waiting response from manifold plugin api
             
 
     $.plugin('Hazelnut', Hazelnut);
 
+  /* 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);
+