plugins: updated resource selected to receive proper updates from the query
[myslice.git] / plugins / resources_selected / static / js / resources_selected.js
index 77d023c..18b61fd 100644 (file)
  * License: GPLv3
  */
 
-/*
- * It's a best practice to pass jQuery to an IIFE (Immediately Invoked Function
- * Expression) that maps it to the dollar sign so it can't be overwritten by
- * another library in the scope of its execution.
- */
 (function( $ ){
 
-    var PLUGIN_NAME = 'ResourcesSelected';
-
-    // Routing calls
-    jQuery.fn.ResourcesSelected = function( method ) {
-        if ( methods[method] ) {
-            return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
-        } else if ( typeof method === 'object' || ! method ) {
-            return methods.init.apply( this, arguments );
-        } else {
-            jQuery.error( 'Method ' +  method + ' does not exist on jQuery.' + PLUGIN_NAME );
-        }    
-
-    };
-
-    /***************************************************************************
-     * Public methods
-     ***************************************************************************/
-
-    var methods = {
-
-        /**
-         * @brief Plugin initialization
-         * @param options : an associative array of setting values
-         * @return : a jQuery collection of objects on which the plugin is
-         *     applied, which allows to maintain chainability of calls
-         */
-        init : function( options ) {
-
-            return this.each(function(){
-
-                var $this = $(this);
-
-                /* An object that will hold private variables and methods */
-                var plugin = new ResourcesSelected(options);
-                $(this).data('Manifold', plugin);
-
-                //$this.set_query_handler(options.query_uuid, hazelnut.query_handler);
-                //$this.set_record_handler(options.query_uuid, hazelnut.record_handler); 
-
-                //var RESULTS_RESOURCES = '/results/' + options.resource_query_uuid + '/changed';
-                //var UPDATE_RESOURCES  = '/update-set/' + options.resource_query_uuid;
-                //$.subscribe(RESULTS_RESOURCES, function(e, resources) { s.set_resources(resources);    });
-                //$.subscribe(UPDATE_RESOURCES,  function(e, resources, change) { s.update_resources(resources, change); });
-                
-            }); // this.each
-        }, // init
-
-        /**
-         * @brief Plugin destruction
-         * @return : a jQuery collection of objects on which the plugin is
-         *     applied, which allows to maintain chainability of calls
-         */
-        destroy : function( ) {
-
-            return this.each(function() {
-                var $this = $(this);
-                var plugin = $this.data('Manifold');
-
-                // Remove associated data
-                plugin.remove();
-                $this.removeData('Manifold');
-            });
-        }, // destroy
-
-    }; // var methods
-
-    /***************************************************************************
-     * Plugin object
-     ***************************************************************************/
-
-    function ResourcesSelected(options)
-    {
-        /* member variables */
-        this.options = options;
-        var object = this;
-
-        /* The resources that are in the slice */
-        this.current_resources = null;
-
-        /* The resources that are in the slice before any edit */
-        this.initial_resources = null;
-
-        var rs = this;
-
-        /* constructor */
-           // ioi: resources table id
-        var TABLE_NAME = '#table-' + options.plugin_uuid;
-        this.table = $(TABLE_NAME).dataTable({
-            //sPaginationType: 'full_numbers',  // Use pagination
-            sPaginationType: 'bootstrap',
-            //bJQueryUI: true,
-            //bRetrieve: true,
-            sScrollX: '100%',                 // Horizontal scrolling 
-            bSortClasses: false,              // Disable style for the sorted column
-            aaSorting: [[ 1, "asc" ]],        // Default sorting on URN
-            fnDrawCallback: function() {      // Reassociate close click every time the table is redrawn
-                /* Prevent to loop on click while redrawing table  */
-                jQuery('.ResourceSelectedClose').unbind('click');
-                /* Handle clicks on close span */
-                /* Reassociate close click every time the table is redrawn */
-                $('.ResourceSelectedClose').bind('click',{instance: rs}, object.close_click);
-            }
-         });
+    // XXX record selected (multiple selection ?)
+    // XXX record disabled ?
+    // XXX out of sync plugin ?
+    // XXX out of date record ?
+    // record tags ???
+    //
+    // criticality of the absence of a handler in a plugin
+    // non-critical only can have switch case
+    // 
+    // Record state through the query cycle
+
 
-        /* methods */
+    var ResourcesSelected = Plugin.extend({
 
-        this.set_resources = function(resources)
+        init: function(options, element)
         {
-            console.log("set_resources");
-            /* Some sanity checks on the API results */
-            if(resources.length==0){
-                this.table.html(errorDisplay("No Result"));   
-                return;
-            }
+            this._super(options, element);
+
+            var self = this;
+            this.table = this.el('table').dataTable({
+                //sPaginationType: 'full_numbers',  // Use pagination
+                sPaginationType: 'bootstrap',
+                //bJQueryUI      : true,
+                //bRetrieve      : true,
+                sScrollX       : '100%',                 // Horizontal scrolling 
+                bSortClasses   : false,              // Disable style for the sorted column
+                aaSorting      : [[ 0, 'asc' ]],        // Default sorting on URN
+                fnDrawCallback: function() {      // Reassociate close click every time the table is redrawn
+                    /* Prevent to loop on click while redrawing table  */
+                    $('.ResourceSelectedClose').unbind('click');
+                    /* Handle clicks on close span */
+                    /* Reassociate close click every time the table is redrawn */
+                    $('.ResourceSelectedClose').bind('click', self, self._close_click);
+                }
+             });
+            
+            this.listen_query(options.query_uuid);
+        },
 
-            if (typeof(resources[0].error) != 'undefined') {
-                this.table.html(errorDisplay(resources[0].error));
-                return;
+        /*************************** PLUGIN EVENTS ****************************/
+
+        /***************************** GUI EVENTS *****************************/
+        
+        // Move through the query cycle
+        // XXX 'update', 'refresh', 'reset' and 'remove annotation' button
+        // This is a query scheduler
+
+        /************************** GUI MANIPULATION **************************/
+
+        clear: function()
+        {
+
+        },
+
+        set_state: function(data)
+        {
+            var action;
+            var color;
+            var msg;
+            var button = '';
+
+            switch(data.request) {
+                case FIELD_REQUEST_CHANGE:
+                    action = 'UPDATE';
+                    break;
+                case FIELD_REQUEST_ADD:
+                    action = 'ADD';
+                    break;
+                case FIELD_REQUEST_REMOVE:
+                    action = 'REMOVE';
+                    break;
             }
 
-            /* Update the table with resources in the slice */
-            //var slivers = $.grep(resources, function(i) {return typeof(i['sliver']) != 'undefined';})
-            var slivers = resources;
-            var sliver_urns = Array();
-            // ioi : refubrished
-               $.each(resources, function(i, x) { sliver_urns.push({urn:x.urn, timeslot:"0"}); }); // ioi
-
-            this.initial_resources = sliver_urns; // We make a copy of the object // ioi
-               // ioi
-           
-            if (this.current_resources == null) {
-                this.current_resources = sliver_urns;
-
-                /* We simply add to the ResourceSelected table */
-                var newlines=Array();
-                $.each(sliver_urns, function(index, elt) {
-                    newlines.push(Array('attached', elt.urn, elt.timeslot, "<span class='ui-icon ui-icon-close ResourceSelectedClose' id='"+elt.urn+"'/>")); // ioi: added last element
-                });
-                this.table.dataTable().fnAddData(newlines);
-            } else {
-                alert('Slice updated. Refresh not yet implemented!');
+            switch(data.status) {
+                case FIELD_REQUEST_PENDING:
+                    msg   = 'PENDING';
+                    color = 'white';
+                    button = "<span class='ui-icon ui-icon-close ResourceSelectedClose' id='" + data.key + "'/>";
+                    break;
+                case FIELD_REQUEST_SUCCESS:
+                    msg   = 'SUCCESS';
+                    color = 'green';
+                    break;
+                case FIELD_REQUEST_FAILURE:
+                    msg   = 'FAILURE';
+                    color = 'red';
+                    break;
             }
-        }
 
-        this.update_resources = function(resources, change) {
+            var status = msg + color;
+
+            this.table.fnAddData([
+                action,
+                data.key,
+                data.value,
+                msg,
+                button
+            ]);
+            // XXX change cell color according to status
+        },
+
+        /*************************** QUERY HANDLER ****************************/
+
+        // NONE
+
+        /*************************** RECORD HANDLER ***************************/
+
+        on_new_record: function(record)
+        {
+            // if (not and update) {
+
+                // initial['resource'], initial['lease'] ?
+                this.initial.push(record.urn);
+
+                // We simply add to the table
+            // } else {
+                //                 \ this.initial_resources
+                //                  \
+                // this.             \
+                // current_resources  \    YES    |   NO
+                // --------------------+----------+---------
+                //       YES           | attached | added
+                //       NO            | removed  |   /
+                // 
+
+            // }
+        },
+
+        // QUERY STATUS
+        //                                      +-----------------+--------------+
+        //                                      v        R        |              |
+        // +-------+  ?G    +-------+        +-------+        +---+---+          |
+        // |       | -----> |       |  !G    |       |        |       |    DA    |
+        // |  ND   |        |  PG   | -----> |   D   | -----> |  PC   | <------+ |
+        // |       | <----- |       |  ~G    |       |   C    |       |        | | 
+        // +-------+   GE   +-------+        +-------+        +-------+      +------+
+        //                                       ^              ^  |         |      |
+        //                                       | DA        UE |  | ?U      | PCA  |
+        //                                       |              |  v         |      |
+        //                                   +-------+        +-------+      +------+
+        //                                   |       |   !U   |       |         ^
+        //                                   |  AD   | <----- |  PU   | --------+
+        //                                   |       |        |       |   ~U     
+        //                                   +-------+        +-------+          
+        //                                                                       
+        //
+        // LEGEND:
+        // 
+        // Plugins (i) receive state information, (ii) perform actions
+        //
+        // States:                                  Actions:
+        // ND : No data                             ?G : Get query
+        // PG : Pending Get                         !G : Get reply  
+        //  D : Data present                        ~G : Get partial reply
+        // PC : Pending changes                     GE : Get error                            
+        // PU : Pending update                       C : Change request
+        // PCA: Pending change with annotation       R : Reset request
+        // AD : Annotated data                      ?U : Update query
+        //                                          !U : Update reply
+        //                                          ~U : Update partial reply
+        //                                          UE : Update error            
+        //                                          DA : Delete annotation request
+        // NOTE:
+        // - D -> PU directly if the user chooses 'dynamic update'
+        // - Be careful for updates if partial Get success
+
+        // ND: No data == initialization state
+        
+        // PG : Pending get
+        // - on_query_in_progress
+        // NOTE: cannot distinguish get and update here. Is it important ?
+
+        on_query_in_progress: function()
+        {
+            this.spin();
+        },
+
+        // D : Data present
+        // - on_clear_records (Get)
+        // - on_new_record (shared with AD) XXX
+        // - on_query_done
+        // NOTE: cannot distinguish get and update here. Is it important ?
+        // NOTE: Would record key be sufficient for update ?
+
+        on_clear_records: function()
+        {
+            this.clear();
+        },
+
+        on_new_record: function(record)
+        {
+        },
+
+        on_query_done: function()
+        {
+            this.unspin();
+        },
+
+        // PC : Pending changes
+        // NOTE: record_key could be sufficient 
+        on_added_record: function(record)
+        {
+            this.set_record_state(record, RECORD_STATE_ADDED);
+        },
+
+        on_removed_record: function(record_key)
+        {
+            this.set_record_state(RECORD_STATE_REMOVED);
+        },
+
+        // PU : Pending update
+        // - on_query_in_progress (already done)
+        
+        // PCA : Pending change with annotation
+        // NOTE: Manifold will inform the plugin about updates, and thus won't
+        // call new record, even if the same channel UUID is used...
+        // - TODO on_updated_record
+        // - Key and confirmation could be sufficient, or key and record state
+        // XXX move record state to the manifold plugin API
+
+        on_field_state_changed: function(request, key, value, status)
+        {
+            this.set_state(request, key, value, status);
+        },
+
+        // XXX we will have the requests for change
+        // XXX + the requests to move into the query cycle = the buttons aforementioned
+
+        // XXX what happens in case of updates ? not implemented yet
+        // XXX we want resources and leases
+        // listen for SET_ADD and SET_REMOVE for slice query
+
+        /************************** PRIVATE METHODS ***************************/
+
+        _close_click: function(e)
+        {
+            var self = e.data;
+
+            //jQuery.publish('selected', 'add/'+key_value);
+            // this.parentNode is <td> this.parentNode.parentNode is <tr> 
+            // this.parentNode.parentNode.firstChild is the first cell <td> of this line <tr>
+            // this.parentNode.parentNode.firstChild.firstChild is the text in that cell
+            //var firstCellVal=this.parentNode.parentNode.firstChild.firstChild.data;
+            var remove_urn = this.id; 
+            var current_resources = event.data.instance.current_resources;
+            var list_resources = $.grep(current_resources, function(x) {return x.urn != remove_urn});
+            //jQuery.publish('selected', 'cancel/'+this.id+'/'+get_value(firstCellVal));
+            $.publish('/update-set/' + event.data.instance.options.resource_query_uuid, [list_resources, true]);
+        },
+
+        /******************************** TODO ********************************/
+
+        update_resources: function(resources, change)
+        {
             console.log("update_resources");
             var my_oTable = this.table.dataTable();
             var prev_resources = this.current_resources; 
-            /*      \ this.initial_resources
-             *           \
-             * this.          \
-             * current_resources  \    YES    |   NO
-             * --------------------+----------+---------
-             *       YES           | attached | added
-             *       NO            | removed  |   /
-             */
 
             /*
              * The first time the query is advertised, don't do anything.  The
              /* Allow the user to update the slice */
              //jQuery('#updateslice-' + data.ResourceSelected.plugin_uuid).prop('disabled', false);
 
-        } // update_resources
-
-        this.record_handler = function(e, event_type, record)
-        {
-            // elements in set
-            switch(event_type) {
-                case NEW_RECORD:
-                    /* NOTE in fact we are doing a join here */
-                    if (object.received_all)
-                        // update checkbox for record
-                        object.set_checkbox(record);
-                    else
-                        // store for later update of checkboxes
-                        object.in_set_buffer.push(record);
-                    break;
-                case CLEAR_RECORDS:
-                    // nothing to do here
-                    break;
-                case IN_PROGRESS:
-                    manifold.spin($(this));
-                    break;
-                case DONE:
-                    if (object.received_all)
-                        manifold.spin($(this), false);
-                    object.received_set = true;
-                    break;
-            }
-        };
-
-        this.record_handler_all = function(e, event_type, record)
-        {
-            // all elements
-            switch(event_type) {
-                case NEW_RECORD:
-                    // Add the record to the table
-                    object.new_record(record);
-                    break;
-                case CLEAR_RECORDS:
-                    object.table.fnClearTable();
-                    break;
-                case IN_PROGRESS:
-                    manifold.spin($(this));
-                    break;
-                case DONE:
-                    if (object.received_set) {
-                        /* XXX needed ? XXX We uncheck all checkboxes ... */
-                        $("[id^='datatables-checkbox-" + object.options.plugin_uuid +"']").attr('checked', false);
-
-                        /* ... and check the ones specified in the resource list */
-                        $.each(object.in_set_buffer, function(i, record) {
-                            object.set_checkbox(record);
-                        });
-
-                        manifold.spin($(this), false);
-                    }
-                    object.received_all = true;
-                    break;
-            }
-        };
+        }, // update_resources
 
-        this.query_handler = function(e, event_type, data)
-        {
-            // This replaces the complex set_query function
-            // The plugin does not need to remember the query anymore
-            switch(event_type) {
-                // Filters
-                case FILTER_ADDED:
-                case FILTER_REMOVED:
-                case CLEAR_FILTERS:
-                    // XXX Here we might need to maintain the list of filters !
-                    /* Process updates in filters / current_query must be updated before this call for filtering ! */
-                    object.table.fnDraw();
-                    break;
+    });
 
-                // Fields
-                /* Hide/unhide columns to match added/removed fields */
-                case FIELD_ADDED:
-                    var field = data;
-                    var oSettings = object.table.fnSettings();
-                    var cols = oSettings.aoColumns;
-                    var index = object.getColIndex(field,cols);
-                    if(index != -1)
-                        object.table.fnSetColumnVis(index, true);
-                    break;
-                case FIELD_REMOVED:
-                    var field = data;
-                    var oSettings = object.table.fnSettings();
-                    var cols = oSettings.aoColumns;
-                    var index = object.getColIndex(field,cols);
-                    if(index != -1)
-                        object.table.fnSetColumnVis(index, false);
-                    break;
-                case CLEAR_FIELDS:
-                    alert('Hazelnut::clear_fields() not implemented');
-                    break;
-            } // switch
-        }
-
-    } // ResourcesSelected
-
-
-    /***************************************************************************
-     * Private methods
-     ***************************************************************************/
-
-    /* Callbacks */    
-    function close_click(event){
-        //jQuery.publish('selected', 'add/'+key_value);
-        // this.parentNode is <td> this.parentNode.parentNode is <tr> 
-        // this.parentNode.parentNode.firstChild is the first cell <td> of this line <tr>
-        // this.parentNode.parentNode.firstChild.firstChild is the text in that cell
-        //var firstCellVal=this.parentNode.parentNode.firstChild.firstChild.data;
-        var remove_urn = this.id; 
-        var current_resources = event.data.instance.current_resources;
-        var list_resources = $.grep(current_resources, function(x) {return x.urn != remove_urn});
-        //jQuery.publish('selected', 'cancel/'+this.id+'/'+get_value(firstCellVal));
-        $.publish('/update-set/' + event.data.instance.options.resource_query_uuid, [list_resources, true]);
-    }
+    $.plugin('ResourcesSelected', ResourcesSelected);
 
 })(jQuery);