plugins: updated resource selected to receive proper updates from the query
[myslice.git] / plugins / resources_selected / static / js / resources_selected.js
1 /**
2  * MySlice ResourcesSelected plugin
3  * Version: 0.1.0
4  * URL: http://www.myslice.info
5  * Description: display of selected resources
6  * Requires: 
7  * Author: The MySlice Team
8  * Copyright: Copyright 2012 UPMC Sorbonne Universités
9  * License: GPLv3
10  */
11
12 (function( $ ){
13
14     // XXX record selected (multiple selection ?)
15     // XXX record disabled ?
16     // XXX out of sync plugin ?
17     // XXX out of date record ?
18     // record tags ???
19     //
20     // criticality of the absence of a handler in a plugin
21     // non-critical only can have switch case
22     // 
23     // Record state through the query cycle
24
25
26     var ResourcesSelected = Plugin.extend({
27
28         init: function(options, element)
29         {
30             this._super(options, element);
31
32             var self = this;
33             this.table = this.el('table').dataTable({
34                 //sPaginationType: 'full_numbers',  // Use pagination
35                 sPaginationType: 'bootstrap',
36                 //bJQueryUI      : true,
37                 //bRetrieve      : true,
38                 sScrollX       : '100%',                 // Horizontal scrolling 
39                 bSortClasses   : false,              // Disable style for the sorted column
40                 aaSorting      : [[ 0, 'asc' ]],        // Default sorting on URN
41                 fnDrawCallback: function() {      // Reassociate close click every time the table is redrawn
42                     /* Prevent to loop on click while redrawing table  */
43                     $('.ResourceSelectedClose').unbind('click');
44                     /* Handle clicks on close span */
45                     /* Reassociate close click every time the table is redrawn */
46                     $('.ResourceSelectedClose').bind('click', self, self._close_click);
47                 }
48              });
49             
50             this.listen_query(options.query_uuid);
51         },
52
53         /*************************** PLUGIN EVENTS ****************************/
54
55         /***************************** GUI EVENTS *****************************/
56         
57         // Move through the query cycle
58         // XXX 'update', 'refresh', 'reset' and 'remove annotation' button
59         // This is a query scheduler
60
61         /************************** GUI MANIPULATION **************************/
62
63         clear: function()
64         {
65
66         },
67
68         set_state: function(data)
69         {
70             var action;
71             var color;
72             var msg;
73             var button = '';
74
75             switch(data.request) {
76                 case FIELD_REQUEST_CHANGE:
77                     action = 'UPDATE';
78                     break;
79                 case FIELD_REQUEST_ADD:
80                     action = 'ADD';
81                     break;
82                 case FIELD_REQUEST_REMOVE:
83                     action = 'REMOVE';
84                     break;
85             }
86
87             switch(data.status) {
88                 case FIELD_REQUEST_PENDING:
89                     msg   = 'PENDING';
90                     color = 'white';
91                     button = "<span class='ui-icon ui-icon-close ResourceSelectedClose' id='" + data.key + "'/>";
92                     break;
93                 case FIELD_REQUEST_SUCCESS:
94                     msg   = 'SUCCESS';
95                     color = 'green';
96                     break;
97                 case FIELD_REQUEST_FAILURE:
98                     msg   = 'FAILURE';
99                     color = 'red';
100                     break;
101             }
102
103             var status = msg + color;
104
105             this.table.fnAddData([
106                 action,
107                 data.key,
108                 data.value,
109                 msg,
110                 button
111             ]);
112             // XXX change cell color according to status
113         },
114
115         /*************************** QUERY HANDLER ****************************/
116
117         // NONE
118
119         /*************************** RECORD HANDLER ***************************/
120
121         on_new_record: function(record)
122         {
123             // if (not and update) {
124
125                 // initial['resource'], initial['lease'] ?
126                 this.initial.push(record.urn);
127
128                 // We simply add to the table
129             // } else {
130                 //                 \ this.initial_resources
131                 //                  \
132                 // this.             \
133                 // current_resources  \    YES    |   NO
134                 // --------------------+----------+---------
135                 //       YES           | attached | added
136                 //       NO            | removed  |   /
137                 // 
138
139             // }
140         },
141
142         // QUERY STATUS
143         //                                      +-----------------+--------------+
144         //                                      v        R        |              |
145         // +-------+  ?G    +-------+        +-------+        +---+---+          |
146         // |       | -----> |       |  !G    |       |        |       |    DA    |
147         // |  ND   |        |  PG   | -----> |   D   | -----> |  PC   | <------+ |
148         // |       | <----- |       |  ~G    |       |   C    |       |        | | 
149         // +-------+   GE   +-------+        +-------+        +-------+      +------+
150         //                                       ^              ^  |         |      |
151         //                                       | DA        UE |  | ?U      | PCA  |
152         //                                       |              |  v         |      |
153         //                                   +-------+        +-------+      +------+
154         //                                   |       |   !U   |       |         ^
155         //                                   |  AD   | <----- |  PU   | --------+
156         //                                   |       |        |       |   ~U     
157         //                                   +-------+        +-------+          
158         //                                                                       
159         //
160         // LEGEND:
161         // 
162         // Plugins (i) receive state information, (ii) perform actions
163         //
164         // States:                                  Actions:
165         // ND : No data                             ?G : Get query
166         // PG : Pending Get                         !G : Get reply  
167         //  D : Data present                        ~G : Get partial reply
168         // PC : Pending changes                     GE : Get error                            
169         // PU : Pending update                       C : Change request
170         // PCA: Pending change with annotation       R : Reset request
171         // AD : Annotated data                      ?U : Update query
172         //                                          !U : Update reply
173         //                                          ~U : Update partial reply
174         //                                          UE : Update error            
175         //                                          DA : Delete annotation request
176         // NOTE:
177         // - D -> PU directly if the user chooses 'dynamic update'
178         // - Be careful for updates if partial Get success
179
180         // ND: No data == initialization state
181         
182         // PG : Pending get
183         // - on_query_in_progress
184         // NOTE: cannot distinguish get and update here. Is it important ?
185
186         on_query_in_progress: function()
187         {
188             this.spin();
189         },
190
191         // D : Data present
192         // - on_clear_records (Get)
193         // - on_new_record (shared with AD) XXX
194         // - on_query_done
195         // NOTE: cannot distinguish get and update here. Is it important ?
196         // NOTE: Would record key be sufficient for update ?
197
198         on_clear_records: function()
199         {
200             this.clear();
201         },
202
203         on_new_record: function(record)
204         {
205         },
206
207         on_query_done: function()
208         {
209             this.unspin();
210         },
211
212         // PC : Pending changes
213         // NOTE: record_key could be sufficient 
214         on_added_record: function(record)
215         {
216             this.set_record_state(record, RECORD_STATE_ADDED);
217         },
218
219         on_removed_record: function(record_key)
220         {
221             this.set_record_state(RECORD_STATE_REMOVED);
222         },
223
224         // PU : Pending update
225         // - on_query_in_progress (already done)
226         
227         // PCA : Pending change with annotation
228         // NOTE: Manifold will inform the plugin about updates, and thus won't
229         // call new record, even if the same channel UUID is used...
230         // - TODO on_updated_record
231         // - Key and confirmation could be sufficient, or key and record state
232         // XXX move record state to the manifold plugin API
233
234         on_field_state_changed: function(request, key, value, status)
235         {
236             this.set_state(request, key, value, status);
237         },
238
239         // XXX we will have the requests for change
240         // XXX + the requests to move into the query cycle = the buttons aforementioned
241
242         // XXX what happens in case of updates ? not implemented yet
243         // XXX we want resources and leases
244         // listen for SET_ADD and SET_REMOVE for slice query
245
246         /************************** PRIVATE METHODS ***************************/
247
248         _close_click: function(e)
249         {
250             var self = e.data;
251
252             //jQuery.publish('selected', 'add/'+key_value);
253             // this.parentNode is <td> this.parentNode.parentNode is <tr> 
254             // this.parentNode.parentNode.firstChild is the first cell <td> of this line <tr>
255             // this.parentNode.parentNode.firstChild.firstChild is the text in that cell
256             //var firstCellVal=this.parentNode.parentNode.firstChild.firstChild.data;
257             var remove_urn = this.id; 
258             var current_resources = event.data.instance.current_resources;
259             var list_resources = $.grep(current_resources, function(x) {return x.urn != remove_urn});
260             //jQuery.publish('selected', 'cancel/'+this.id+'/'+get_value(firstCellVal));
261             $.publish('/update-set/' + event.data.instance.options.resource_query_uuid, [list_resources, true]);
262         },
263
264         /******************************** TODO ********************************/
265
266         update_resources: function(resources, change)
267         {
268             console.log("update_resources");
269             var my_oTable = this.table.dataTable();
270             var prev_resources = this.current_resources; 
271
272             /*
273              * The first time the query is advertised, don't do anything.  The
274              * component will learn nodes in the slice through the manifest
275              * received through the other subscription 
276              */
277              if (!change)
278                 return;
279              // ioi: Refubrished
280              var initial = this.initial_resources;
281              //var r_removed  = []; //
282              /*-----------------------------------------------------------------------
283                 TODO: remove this dirty hack !!!
284              */
285              resources = jQuery.map(resources, function(x){
286                 if(!('timeslot' in x)){x.timeslot=0;}
287                 return x;
288              });
289              /*
290                 TODO: handle generic keys instead of specific stuff
291                       ex: urn
292                           urn-lease
293              */
294              var initial_urn = $.map(initial, function(x){return x.urn;});
295              var resources_urn = $.map(resources, function(x){return x.urn;});
296              var r_removed = $.grep(initial, function (x) { return $.inArray(x.urn, resources_urn) == -1 });
297              var r_attached = $.grep(initial, function (x) { return $.inArray(x.urn, resources_urn) > -1 });
298              var r_added = $.grep(resources, function (x) { return $.inArray(x.urn, initial_urn) == -1 });
299              exists = false; // ioi
300              /*-----------------------------------------------------------------------*/
301
302              my_oTable.fnClearTable();
303              /*
304                 TODO: factorization of this code !!!
305              */
306              $.each(r_added, function(i, r) { 
307                 //var type = (typeof initial == 'undefined' || r.node != initial.node) ? 'add' : 'attached';
308                 var type = 'add';  
309                 // Create the resource objects
310                 // ioi: refubrished
311                 var urn = r.urn;
312                 time = r.timeslot;
313                               
314                 var SPAN = "<span class='ui-icon ui-icon-close ResourceSelectedClose' id='"+urn+"'/>";
315                 var slot = "<span id='resource_"+urn+"'>" + time + "</span>"; //ioi
316                 // ioi
317                 var newline=Array();
318                 newline.push(type, urn, slot, SPAN); // ioi
319                 var line = my_oTable.fnAddData(newline);
320                 var nTr = my_oTable.fnSettings().aoData[ line[0] ].nTr;
321                 nTr.className = type;
322              });
323              $.each(r_attached, function(i, r) {  
324                 //var type = (typeof initial == 'undefined' || r.node != initial.node) ? 'add' : 'attached';
325                 var type = 'attached';
326                 // Create the resource objects
327                 // ioi: refubrished
328                 var node = r.urn;
329                 time = r.timeslot;
330
331                 var SPAN = "<span class='ui-icon ui-icon-close ResourceSelectedClose' id='"+node+"'/>";
332                 var slot = "<span id='resource_"+node+"'>" + time + "</span>"; //ioi
333                 // ioi
334                 var newline=Array();
335                 newline.push(type, node, slot, SPAN); // ioi
336                 var line = my_oTable.fnAddData(newline);
337                 var nTr = my_oTable.fnSettings().aoData[ line[0] ].nTr;
338                 nTr.className = type;
339              });
340              $.each(r_removed, function(i, r) { 
341                 // The list contains objects
342                 // ioi: refubrished
343                 var node = r.urn;
344                 var time = r.timeslot;
345                     
346                 var SPAN = "<span class='ui-icon ui-icon-close ResourceSelectedClose' id='"+node+"'/>";
347                 var slot = "<span id='resource_"+node+"'>" + time + "</span>";
348                 // ioi
349                 var newline=Array();
350                 newline.push('remove', node, slot, SPAN); // ioi
351                 var line = my_oTable.fnAddData(newline);
352                 var nTr = my_oTable.fnSettings().aoData[ line[0] ].nTr;
353                 nTr.className = 'remove';
354              });
355
356              this.current_resources = $.merge(r_attached,r_added);
357
358              /* Allow the user to update the slice */
359              //jQuery('#updateslice-' + data.ResourceSelected.plugin_uuid).prop('disabled', false);
360
361         }, // update_resources
362
363     });
364
365     $.plugin('ResourcesSelected', ResourcesSelected);
366
367 })(jQuery);