X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=plugins%2Fresources_selected%2Fstatic%2Fjs%2Fresources_selected.js;h=9a064476fbe718c3ca25a0ba52498b3e8ff948e0;hb=a2069daeaa50cf7328f838d4c3f2ca2da0727bbc;hp=77d023c908962444cab7af11322ed8fb8005da98;hpb=d1e5d12b2b9519801f7b981a2177b3f36115714a;p=myslice.git diff --git a/plugins/resources_selected/static/js/resources_selected.js b/plugins/resources_selected/static/js/resources_selected.js index 77d023c9..9a064476 100644 --- a/plugins/resources_selected/static/js/resources_selected.js +++ b/plugins/resources_selected/static/js/resources_selected.js @@ -9,169 +9,350 @@ * 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.elmt('table').dataTable({ +// the original hazelnut layout was +// sDom: "<'row'<'col-xs-5'l><'col-xs-1'r><'col-xs-6'f>>t<'row'<'col-xs-5'i><'col-xs-7'p>>", +// however the bottom line with 'showing blabla...' and the navigation widget are not really helpful + sDom: "<'row'<'col-xs-5'l><'col-xs-1'r><'col-xs-6'f>>t>", +// so this does not matter anymore now that the pagination area is turned off +// sPaginationType: 'bootstrap', + bAutoWidth: true, +// 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); +// } + }); + + // XXX This should not be done at init... + this.elmt('update').click(this, this.do_update); + this.elmt('refresh').click(this, this.do_refresh); + this.elmt('reset').click(this, this.do_reset); + this.elmt('clear_annotations').click(this, this.do_clear_annotations); - if (typeof(resources[0].error) != 'undefined') { - this.table.html(errorDisplay(resources[0].error)); - return; - } + this.listen_query(options.query_uuid); + }, + + /*************************** PLUGIN EVENTS ****************************/ + + /***************************** GUI EVENTS *****************************/ + + do_update: function(e) + { + var self = e.data; + // XXX check that the query is not disabled + manifold.raise_event(self.options.query_uuid, RUN_UPDATE); + }, + + // related buttons are also disabled in the html template + do_refresh: function(e) + { + throw 'resource_selected.do_refresh Not implemented'; + }, + + do_reset: function(e) + { + throw 'resources_selected.do_reset Not implemented'; + }, + + do_clear_annotations: function(e) + { + throw 'resources_selected.do_clear_annotations Not implemented'; + }, + + /************************** GUI MANIPULATION **************************/ + + + set_button_state: function(name, state) + { + this.elmt(name).attr('disabled', state ? false : 'disabled'); + }, + + clear: function() + { - /* 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 + find_row: function(key) + { + // key in third position, column id = 2 + var KEY_POS = 2; + + var cols = $.grep(this.table.fnSettings().aoData, function(col) { + return (col._aData[KEY_POS] == key); + } ); + + if (cols.length == 0) + return null; + if (cols.length > 1) + throw "Too many same-key rows in ResourceSelected plugin"; + + return cols[0]; + }, + + set_state: function(data) + { + var action; + var msg; + var button = ''; + + var row; + + // make sure the change is visible : toggle on the whole plugin + // this might hae to be made an 'auto-toggle' option of this plugin.. + // also it might be needed to be a little finer-grained here + this.toggle_on(); - 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, "")); // ioi: added last element - }); - this.table.dataTable().fnAddData(newlines); + switch(data.request) { + case FIELD_REQUEST_ADD_RESET: + case FIELD_REQUEST_REMOVE_RESET: + // find line and delete it + row = this.find_row(data.value); + if (row) + this.table.fnDeleteRow(row.nTr); + return; + case FIELD_REQUEST_CHANGE: + action = 'UPDATE'; + break; + case FIELD_REQUEST_ADD: + action = 'ADD'; + break; + case FIELD_REQUEST_REMOVE: + action = 'REMOVE'; + break; + } + + switch(data.status) { + case FIELD_REQUEST_PENDING: + msg = 'PENDING'; + button = ""; + break; + case FIELD_REQUEST_SUCCESS: + msg = 'SUCCESS'; + break; + case FIELD_REQUEST_FAILURE: + msg = 'FAILURE'; + break; + } + + var status = msg + status; + + // find line + // if no, create it, else replace it + // XXX it's not just about adding lines, but sometimes removing some + // XXX how do we handle status reset ? + row = this.find_row(data.value); + newline = [ + action, + data.key, + data.value, + msg, + button + ]; + if (!row) { + // XXX second parameter refresh = false can improve performance. todo in hazelnut also + this.table.fnAddData(newline); + row = this.find_row(data.value); } else { - alert('Slice updated. Refresh not yet implemented!'); + // Update row text... + this.table.fnUpdate(newline, row.nTr); } - } - this.update_resources = function(resources, change) { + // Change cell color according to status + if (row) { + $(row.nTr).removeClass('add remove') + var cls = action.toLowerCase(); + if (cls) + $(row.nTr).addClass(cls); + } + }, + + /*************************** 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(result) + { + console.log(result) + /* this.set_state(result.request, result.key, result.value, result.status); */ + this.set_state(result); + }, + + // 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 this.parentNode.parentNode is + // this.parentNode.parentNode.firstChild is the first cell of this line + // 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+'/'+unfold.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 @@ -215,7 +396,7 @@ var urn = r.urn; time = r.timeslot; - var SPAN = ""; + var SPAN = ""; var slot = "" + time + ""; //ioi // ioi var newline=Array(); @@ -232,7 +413,7 @@ var node = r.urn; time = r.timeslot; - var SPAN = ""; + var SPAN = ""; var slot = "" + time + ""; //ioi // ioi var newline=Array(); @@ -247,7 +428,7 @@ var node = r.urn; var time = r.timeslot; - var SPAN = ""; + var SPAN = ""; var slot = "" + time + ""; // ioi var newline=Array(); @@ -262,123 +443,10 @@ /* Allow the user to update the slice */ //jQuery('#updateslice-' + data.ResourceSelected.plugin_uuid).prop('disabled', false); - } // update_resources + }, // 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; - } - }; - - 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 this.parentNode.parentNode is - // this.parentNode.parentNode.firstChild is the first cell of this line - // 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);