reworked slice page, added ResourcesSelected plugin
authorJordan Augé <jordan.auge@lip6.fr>
Sun, 7 Jul 2013 12:51:02 +0000 (14:51 +0200)
committerJordan Augé <jordan.auge@lip6.fr>
Sun, 7 Jul 2013 12:51:02 +0000 (14:51 +0200)
manifold/js/manifold.js
plugins/hazelnut/hazelnut.js
plugins/hazelnut/hazelnut.py
plugins/resources_selected/__init__.py [new file with mode: 0644]
plugins/resources_selected/resources_selected.css [new file with mode: 0644]
plugins/resources_selected/resources_selected.js [new file with mode: 0644]
plugins/resources_selected/templates/resources_selected.html [new file with mode: 0644]
portal/views.py
trash/sliceview.py

index 927924f..bae00c7 100644 (file)
@@ -149,7 +149,10 @@ var manifold = {
     publish_result: function(query, result) {
         /* Publish an update announce */
         var channel="/results/" + query.query_uuid + "/changed";
     publish_result: function(query, result) {
         /* Publish an update announce */
         var channel="/results/" + query.query_uuid + "/changed";
-        if (manifold.asynchroneous_debug) messages.debug("publishing result on " + channel);
+        if (manifold.asynchroneous_debug)
+            messages.debug("publishing result on " + channel);
+        if (typeof result === 'undefined')
+            result = [];
         jQuery.publish(channel, [result, query]);
     },
 
         jQuery.publish(channel, [result, query]);
     },
 
index dbe29b5..5f1c27a 100644 (file)
 
     var 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 ) {
         init : function ( options ) {
+
             /* Default settings */
             var options = $.extend( {
                 'checkboxes': false
             }, options);
 
             return this.each(function() {
             /* Default settings */
             var options = $.extend( {
                 'checkboxes': false
             }, options);
 
             return this.each(function() {
+
                 var $this = $(this);
                 var $this = $(this);
+
                 /* Events */
                 $this.on('show.Datatables', methods.show);
 
                 /* An object that will hold private variables and methods */
                 /* Events */
                 $this.on('show.Datatables', methods.show);
 
                 /* An object that will hold private variables and methods */
-               var hazelnut = new Hazelnut (options);
+                var hazelnut = new Hazelnut (options);
                 $this.data('Hazelnut', hazelnut);
                 $this.data('Hazelnut', hazelnut);
-
                 var query_channel   = '/query/' + options.query_uuid + '/changed';
                 var update_channel  = '/update-set/' + options.query_uuid;
                 var results_channel = '/results/' + options.query_uuid + '/changed';
 
                 var query_channel   = '/query/' + options.query_uuid + '/changed';
                 var update_channel  = '/update-set/' + options.query_uuid;
                 var results_channel = '/results/' + options.query_uuid + '/changed';
 
-               // xxx not tested yet
+                // xxx not tested yet
                 $.subscribe(query_channel,  function(e, query) { hazelnut.set_query(query); });
                 $.subscribe(query_channel,  function(e, query) { hazelnut.set_query(query); });
-               // xxx not tested yet
+                // xxx not tested yet
                 $.subscribe(update_channel, function(e, resources, instance) { hazelnut.set_resources(resources, instance); });
                 $.subscribe(update_channel, function(e, resources, instance) { hazelnut.set_resources(resources, instance); });
-               // expected to work
+                // expected to work
                 $.subscribe(results_channel, $this, function(e, rows) { hazelnut.update_plugin(e,rows); });
                 $.subscribe(results_channel, $this, function(e, rows) { hazelnut.update_plugin(e,rows); });
-               if (debug) messages.debug("hazelnut '" + this.id + "' subscribed to e.g." + results_channel);
+                if (debug)
+                    messages.debug("hazelnut '" + this.id + "' subscribed to e.g." + results_channel);
 
             }); // this.each
         }, // init
 
 
             }); // 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( ) {
         destroy : function( ) {
+
             return this.each(function() {
                 var $this = $(this);
                 var hazelnut = $this.data('Hazelnut');
             return this.each(function() {
                 var $this = $(this);
                 var hazelnut = $this.data('Hazelnut');
         }, // destroy
 
         show : function( ) {
         }, // destroy
 
         show : function( ) {
-           var $this=$(this);
-           // xxx wtf. why [1] ? would expect 0...
-           if (debug) messages.debug("Hitting suspicious line in hazelnut.show");
+            var $this=$(this);
+            // xxx wtf. why [1] ? would expect 0...
+            if (debug)
+                messages.debug("Hitting suspicious line in hazelnut.show");
             var oTable = $($('.dataTable', $this)[1]).dataTable();
             oTable.fnAdjustColumnSizing()
             var oTable = $($('.dataTable', $this)[1]).dataTable();
             oTable.fnAdjustColumnSizing()
-    
+        
             /* Refresh dataTabeles if click on the menu to display it : fix dataTables 1.9.x Bug */        
             $(this).each(function(i,elt) {
                 if (jQuery(elt).hasClass('dataTables')) {
             /* Refresh dataTabeles if click on the menu to display it : fix dataTables 1.9.x Bug */        
             $(this).each(function(i,elt) {
                 if (jQuery(elt).hasClass('dataTables')) {
 
     }; // var methods;
 
 
     }; // var methods;
 
-
     /***************************************************************************
      * Hazelnut object
      ***************************************************************************/
     /***************************************************************************
      * Hazelnut object
      ***************************************************************************/
-    function Hazelnut(options) {
+
+    function Hazelnut(options) 
+    {
         /* member variables */
         this.options = options;
         /* member variables */
         this.options = options;
-       // xxx thierry : initialize this here - it was not, I expect this relied on set_query somehow..
+
+        // xxx thierry : initialize this here - it was not, I expect this relied on set_query somehow..
         //this.current_query = null;
         //this.current_query = null;
-       this.current_query=manifold.find_query(this.options.query_uuid);
-//     if (debug) messages.debug("Hazelnut constructor: have set current_query -> " + this.current_query.__repr());
-       this.query_update = null;
+        this.current_query=manifold.find_query(this.options.query_uuid);
+        //  if (debug) messages.debug("Hazelnut constructor: have set current_query -> " + this.current_query.__repr());
+        this.query_update = null;
         this.current_resources = Array();
 
         var object = this;
 
         /* Transforms the table into DataTable, and keep a pointer to it */
         this.current_resources = Array();
 
         var object = this;
 
         /* Transforms the table into DataTable, and keep a pointer to it */
-       actual_options = {
+        actual_options = {
             // Customize the position of Datatables elements (length,filter,button,...)
             // 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-fluid'<'span5'l><'span1'r><'span6'f>>t<'row-fluid'<'span5'i><'span7'p>>",
+            // we use a fluid row on top and another on the bottom, making sure we take 12 grid elt's each time
+            sDom: "<'row-fluid'<'span5'l><'span1'r><'span6'f>>t<'row-fluid'<'span5'i><'span7'p>>",
             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' ]}],
             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
+            // 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() { hazelnut_draw_callback.call(object, options); }
         };
             // sScrollX: '100%',       /* Horizontal scrolling */
             bProcessing: true,      /* Loading */
             fnDrawCallback: function() { hazelnut_draw_callback.call(object, options); }
         };
-       // 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 );
+        // 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 );
         this.table = $('#hazelnut-' + options.plugin_uuid).dataTable(actual_options);
 
         /* Setup the SelectAll button in the dataTable header */
         this.table = $('#hazelnut-' + options.plugin_uuid).dataTable(actual_options);
 
         /* Setup the SelectAll button in the dataTable header */
-       /* xxx not sure this is still working */
+        /* xxx not sure this is still working */
         var oSelectAll = $('#datatableSelectAll-'+ options.plugin_uuid);
         oSelectAll.html("<span class='ui-icon ui-icon-check' style='float:right;display:inline-block;'></span>Select All");
         oSelectAll.button();
         var oSelectAll = $('#datatableSelectAll-'+ options.plugin_uuid);
         oSelectAll.html("<span class='ui-icon ui-icon-check' style='float:right;display:inline-block;'></span>Select All");
         oSelectAll.button();
         /* methods */
 
         this.set_query = function(query) {
         /* methods */
 
         this.set_query = function(query) {
-           messages.info('hazelnut.set_query');
+            messages.info('hazelnut.set_query');
             var options = this.options;
             /* Compare current and advertised query to get added and removed fields */
             previous_query = this.current_query;
             /* Save the query as the current query */
             this.current_query = query;
             var options = this.options;
             /* Compare current and advertised query to get added and removed fields */
             previous_query = this.current_query;
             /* Save the query as the current query */
             this.current_query = query;
-           if (debug) messages.debug("hazelnut.set_query, current_query is now -> " + this.current_query);
+            if (debug)
+                messages.debug("hazelnut.set_query, current_query is now -> " + this.current_query);
+
             /* We check all necessary fields : in column editor I presume XXX */
             // XXX ID naming has no plugin_uuid
             if (typeof(query.fields) != 'undefined') {        
             /* We check all necessary fields : in column editor I presume XXX */
             // XXX ID naming has no plugin_uuid
             if (typeof(query.fields) != 'undefined') {        
                         $('#hazelnut-checkbox-' + options.plugin_uuid + "-" + value).attr('checked', true);
                 });
             }
                         $('#hazelnut-checkbox-' + options.plugin_uuid + "-" + value).attr('checked', true);
                 });
             }
-            /*Process updates in filters / current_query must be updated before this call for filtering ! */
+
+            /* Process updates in filters / current_query must be updated before this call for filtering ! */
             this.table.fnDraw();
 
             /*
             this.table.fnDraw();
 
             /*
         }
 
         this.set_resources = function(resources, instance) {
         }
 
         this.set_resources = function(resources, instance) {
-           if (debug) messages.debug("entering hazelnut.set_resources");
+            if (debug)
+                messages.debug("entering hazelnut.set_resources");
             var options = this.options;
             var previous_resources = this.current_resources;
             this.current_resources = resources;
             var options = this.options;
             var previous_resources = this.current_resources;
             this.current_resources = resources;
          * XXX will be removed/replaced
          */
         this.selected_changed = function(e, change) {
          * XXX will be removed/replaced
          */
         this.selected_changed = function(e, change) {
-           if (debug) messages.debug("entering hazelnut.selected_changed");
+        if (debug) messages.debug("entering hazelnut.selected_changed");
             var actions = change.split("/");
             if (actions.length > 1) {
                 var oNodes = this.table.fnGetNodes();
             var actions = change.split("/");
             if (actions.length > 1) {
                 var oNodes = this.table.fnGetNodes();
         }
     
         this.update_plugin = function(e, rows) {
         }
     
         this.update_plugin = function(e, rows) {
-           // e.data is what we passed in second argument to subscribe
-           // so here it is the jquery object attached to the plugin <div>
-           var $plugindiv=e.data;
-           if (debug) messages.debug("entering hazelnut.update_plugin on id '" + $plugindiv.attr('id') + "'");
-           // clear the spinning wheel: look up an ancestor that has the need-spin class
-           // do this before we might return
-           $plugindiv.closest('.need-spin').spin(false);
+        // e.data is what we passed in second argument to subscribe
+        // so here it is the jquery object attached to the plugin <div>
+        var $plugindiv=e.data;
+        if (debug) messages.debug("entering hazelnut.update_plugin on id '" + $plugindiv.attr('id') + "'");
+        // clear the spinning wheel: look up an ancestor that has the need-spin class
+        // do this before we might return
+        $plugindiv.closest('.need-spin').spin(false);
 
             var options = this.options;
             var hazelnut = this;
     
 
             var options = this.options;
             var hazelnut = this;
     
-           /* if we get no result, or an error, try to make that clear, and exit */
+        /* if we get no result, or an error, try to make that clear, and exit */
             if (rows.length==0) {
             if (rows.length==0) {
-               if (debug) messages.debug("Empty result on hazelnut " + domid);
-               var placeholder=$(this.table).find("td.dataTables_empty");
-               console.log("placeholder "+placeholder);
-               if (placeholder.length==1) placeholder.html(unfold.warning("Empty result"));
-               else                       this.table.html(unfold.warning("Empty result"));
+        if (debug) messages.debug("Empty result on hazelnut " + this.options.domid);
+        var placeholder=$(this.table).find("td.dataTables_empty");
+        console.log("placeholder "+placeholder);
+        if (placeholder.length==1) placeholder.html(unfold.warning("Empty result"));
+        else               this.table.html(unfold.warning("Empty result"));
                 return;
             } else if (typeof(rows[0].error) != 'undefined') {
                 return;
             } else if (typeof(rows[0].error) != 'undefined') {
-               // we now should have another means to report errors that this inline/embedded hack
-               if (debug) messages.error ("undefined result on " + domid + " - should not happen anymore");
+        // we now should have another means to report errors that this inline/embedded hack
+        if (debug) messages.error ("undefined result on " + this.options.domid + " - should not happen anymore");
                 this.table.html(unfold.error(rows[0].error));
                 return;
             }
 
                 this.table.html(unfold.error(rows[0].error));
                 return;
             }
 
-           /* 
-            * fill the dataTables object
-            * we cannot set html content directly here, need to use fnAddData
-            */
+        /* 
+         * fill the dataTables object
+         * we cannot set html content directly here, need to use fnAddData
+         */
             var lines = new Array();
     
             this.current_resources = Array();
     
             $.each(rows, function(index, row) {
             var lines = new Array();
     
             this.current_resources = Array();
     
             $.each(rows, function(index, row) {
-               // this models a line in dataTables, each element in the line describes a cell
+        // 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
                 line = new Array();
      
                 // go through table headers to get column names we want
                 var cols = hazelnut.table.fnSettings().aoColumns;
                 var colnames = cols.map(function(x) {return x.sTitle})
                 var nb_col = cols.length;
                 var cols = hazelnut.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 we've requested checkboxes, then forget about the checkbox column for now */
                 if (options.checkboxes) nb_col -= 1;
 
                 if (options.checkboxes) nb_col -= 1;
 
-               /* fill in stuff depending on the column name */
+        /* fill in stuff depending on the column name */
                 for (var j = 0; j < nb_col; j++) {
                     if (typeof colnames[j] == 'undefined') {
                         line.push('...');
                 for (var j = 0; j < nb_col; j++) {
                     if (typeof colnames[j] == 'undefined') {
                         line.push('...');
                     }
                 }
     
                     }
                 }
     
-               /* catch up with the last column if checkboxes were requested */
+        /* catch up with the last column if checkboxes were requested */
                 if (options.checkboxes) {
                     var checked = '';
                 if (options.checkboxes) {
                     var checked = '';
-                   // xxx problem is, we don't get this 'sliver' thing set apparently
+            // xxx problem is, we don't get this 'sliver' thing set apparently
                     if (typeof(row['sliver']) != 'undefined') { /* It is equal to null when <sliver/> is present */
                         checked = 'checked ';
                         hazelnut.current_resources.push(row['urn']);
                     if (typeof(row['sliver']) != 'undefined') { /* It is equal to null when <sliver/> is present */
                         checked = 'checked ';
                         hazelnut.current_resources.push(row['urn']);
     
             });
     
     
             });
     
-           this.table.fnClearTable();
-           if (debug) messages.debug("hazelnut.update_plugin: total of " + lines.length + " rows");
+        this.table.fnClearTable();
+        if (debug) messages.debug("hazelnut.update_plugin: total of " + lines.length + " rows");
             this.table.fnAddData(lines);
     
         };
 
         this.checkbox = function (plugin_uuid, header, field, selected_str, disabled_str) {
             this.table.fnAddData(lines);
     
         };
 
         this.checkbox = function (plugin_uuid, header, field, selected_str, disabled_str) {
-           var result="";
+        var result="";
             // Preafix id with plugin_uuid
             // Preafix id with plugin_uuid
-           result += "<input";
-           result += " class='hazelnut-checkbox-" + plugin_uuid + "'";
-           result += " id='hazelnut-checkbox-" + plugin_uuid + "-" + unfold.get_value(header) + "'";
-           result += " name='" + unfold.get_value(field) + "'";
-           result += " type='checkbox'";
-           result += selected_str;
-           result += disabled_str;
-           result += " autocomplete='off'";
-           result += " value='" + unfold.get_value(header) + "'";
-           result += "></input>";
-           return result;
+        result += "<input";
+        result += " class='hazelnut-checkbox-" + plugin_uuid + "'";
+        result += " id='hazelnut-checkbox-" + plugin_uuid + "-" + unfold.get_value(header) + "'";
+        result += " name='" + unfold.get_value(field) + "'";
+        result += " type='checkbox'";
+        result += selected_str;
+        result += disabled_str;
+        result += " autocomplete='off'";
+        result += " value='" + unfold.get_value(header) + "'";
+        result += "></input>";
+        return result;
         };
     } // constructor
 
         };
     } // constructor
 
index e2b3a7c..9dfebf1 100644 (file)
@@ -39,4 +39,4 @@ class Hazelnut (Plugin):
         return reqs
 
     # the list of things passed to the js plugin
         return reqs
 
     # the list of things passed to the js plugin
-    def json_settings_list (self): return ['plugin_uuid','query_uuid','checkboxes','datatables_options']
+    def json_settings_list (self): return ['plugin_uuid', 'domid', 'query_uuid','checkboxes','datatables_options']
diff --git a/plugins/resources_selected/__init__.py b/plugins/resources_selected/__init__.py
new file mode 100644 (file)
index 0000000..606a6d8
--- /dev/null
@@ -0,0 +1,19 @@
+from unfold.plugin import Plugin
+
+class ResourcesSelected(Plugin):
+
+    def template_file (self):
+        return "resources_selected.html"
+
+    def requirements (self):
+        reqs = {
+            'js_files' : [ "js/resources_selected.js" ] ,
+            'css_files': [ "css/resources_selected.css" ],
+            }
+        return reqs
+
+    def json_settings_list (self):
+        return ['plugin_uuid', 'domid', 'resource_query_uuid', 'lease_query_uuid']
+
+    def export_json_settings (self):
+        return True
diff --git a/plugins/resources_selected/resources_selected.css b/plugins/resources_selected/resources_selected.css
new file mode 100644 (file)
index 0000000..9431426
--- /dev/null
@@ -0,0 +1,27 @@
+/* 
+    Document   : ResourcesSelected
+    Created on : 9 août 2012, 11:54:41
+    Author     : loicbaron
+    Description:
+        Purpose of the stylesheet follows.
+*/
+
+tr.add td{ 
+    background-color: #E3F6CE;
+}
+tr.remove td{ 
+    background-color: #F6CECE;
+}
+.ResourceSelectedClose{
+    cursor: pointer;
+}
+
+input.myslice_action {
+   font-size:13px;
+   font-family:Arial,sans-serif;
+   font-weight:bold;
+   color:#0066CC;
+   width:100px;
+   height:30px;
+   background-color:#FF9933;
+}
diff --git a/plugins/resources_selected/resources_selected.js b/plugins/resources_selected/resources_selected.js
new file mode 100644 (file)
index 0000000..ad2e5fd
--- /dev/null
@@ -0,0 +1,282 @@
+/**
+ * MySlice ResourcesSelected plugin
+ * Version: 0.1.0
+ * URL: http://www.myslice.info
+ * Description: display of selected resources
+ * Requires: 
+ * Author: The MySlice Team
+ * Copyright: Copyright 2012 UPMC Sorbonne Universités
+ * 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( $ ){
+
+    // 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.ResourcesSelected' );
+        }    
+
+    };
+
+    /***************************************************************************
+     * 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 s = new ResourcesSelected(options);
+                $(this).data('ResourcesSelected', s);
+                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 = jQuery(this), data = $this.data('ResourcesSelected');
+                jQuery(window).unbind('ResourcesSelected');
+                data.ResourcesSelected.remove();
+                $this.removeData('ResourcesSelected');
+            })
+
+        }, // destroy
+
+    }; // var methods
+
+    /***************************************************************************
+     * ResourcesSelected object
+     ***************************************************************************/
+
+    function ResourcesSelected(options)
+    {
+        /* member variables */
+
+        this.options = options;
+
+        /* 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}, close_click);
+            }
+         });
+
+        /* methods */
+
+        this.set_resources = function(resources)
+        {
+            console.log("set_resources");
+            /* Some sanity checks on the API results */
+            if(resources.length==0){
+                this.table.html(errorDisplay("No Result"));   
+                return;
+            }
+
+            if (typeof(resources[0].error) != 'undefined') {
+                this.table.html(errorDisplay(resources[0].error));
+                return;
+            }
+
+            /* 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!');
+            }
+        }
+
+        this.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
+             * component will learn nodes in the slice through the manifest
+             * received through the other subscription 
+             */
+             if (!change)
+                return;
+             // ioi: Refubrished
+             var initial = this.initial_resources;
+             //var r_removed  = []; //
+             /*-----------------------------------------------------------------------
+                TODO: remove this dirty hack !!!
+             */
+             resources = jQuery.map(resources, function(x){
+                if(!('timeslot' in x)){x.timeslot=0;}
+                return x;
+             });
+             /*
+                TODO: handle generic keys instead of specific stuff
+                      ex: urn
+                          urn-lease
+             */
+             var initial_urn = $.map(initial, function(x){return x.urn;});
+             var resources_urn = $.map(resources, function(x){return x.urn;});
+             var r_removed = $.grep(initial, function (x) { return $.inArray(x.urn, resources_urn) == -1 });
+             var r_attached = $.grep(initial, function (x) { return $.inArray(x.urn, resources_urn) > -1 });
+             var r_added = $.grep(resources, function (x) { return $.inArray(x.urn, initial_urn) == -1 });
+             exists = false; // ioi
+             /*-----------------------------------------------------------------------*/
+
+             my_oTable.fnClearTable();
+             /*
+                TODO: factorization of this code !!!
+             */
+             $.each(r_added, function(i, r) { 
+                //var type = (typeof initial == 'undefined' || r.node != initial.node) ? 'add' : 'attached';
+                var type = 'add';  
+                // Create the resource objects
+                // ioi: refubrished
+                var urn = r.urn;
+                time = r.timeslot;
+                              
+                var SPAN = "<span class='ui-icon ui-icon-close ResourceSelectedClose' id='"+urn+"'/>";
+                var slot = "<span id='resource_"+urn+"'>" + time + "</span>"; //ioi
+                // ioi
+                var newline=Array();
+                newline.push(type, urn, slot, SPAN); // ioi
+                var line = my_oTable.fnAddData(newline);
+                var nTr = my_oTable.fnSettings().aoData[ line[0] ].nTr;
+                nTr.className = type;
+             });
+             $.each(r_attached, function(i, r) {  
+                //var type = (typeof initial == 'undefined' || r.node != initial.node) ? 'add' : 'attached';
+                var type = 'attached';
+                // Create the resource objects
+                // ioi: refubrished
+                var node = r.urn;
+                time = r.timeslot;
+
+                var SPAN = "<span class='ui-icon ui-icon-close ResourceSelectedClose' id='"+node+"'/>";
+                var slot = "<span id='resource_"+node+"'>" + time + "</span>"; //ioi
+                // ioi
+                var newline=Array();
+                newline.push(type, node, slot, SPAN); // ioi
+                var line = my_oTable.fnAddData(newline);
+                var nTr = my_oTable.fnSettings().aoData[ line[0] ].nTr;
+                nTr.className = type;
+             });
+             $.each(r_removed, function(i, r) { 
+                // The list contains objects
+                // ioi: refubrished
+                var node = r.urn;
+                var time = r.timeslot;
+                    
+                var SPAN = "<span class='ui-icon ui-icon-close ResourceSelectedClose' id='"+node+"'/>";
+                var slot = "<span id='resource_"+node+"'>" + time + "</span>";
+                // ioi
+                var newline=Array();
+                newline.push('remove', node, slot, SPAN); // ioi
+                var line = my_oTable.fnAddData(newline);
+                var nTr = my_oTable.fnSettings().aoData[ line[0] ].nTr;
+                nTr.className = 'remove';
+             });
+
+             this.current_resources = $.merge(r_attached,r_added);
+
+             /* Allow the user to update the slice */
+             //jQuery('#updateslice-' + data.ResourceSelected.plugin_uuid).prop('disabled', false);
+
+        } // update_resources
+
+    } // 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]);
+    }
+
+})(jQuery);
diff --git a/plugins/resources_selected/templates/resources_selected.html b/plugins/resources_selected/templates/resources_selected.html
new file mode 100644 (file)
index 0000000..00ac3ec
--- /dev/null
@@ -0,0 +1,10 @@
+<table class='display' id='table-{{ domid }}'>
+  <thead>
+    <tr>
+      <th>status</th>
+      <th>urn</th>
+      <th>slot</th>
+      <th>+/-</th>
+    </tr>
+  </thead>
+</table>
index f213986..f03befa 100644 (file)
@@ -32,6 +32,7 @@ from portal.util                 import RegistrationView, ActivationView
 from portal.models               import PendingUser, PendingSlice
 from manifold.core.query         import Query
 from unfold.page                 import Page
 from portal.models               import PendingUser, PendingSlice
 from manifold.core.query         import Query
 from unfold.page                 import Page
+from myslice.viewutils           import topmenu_items, the_user
 
 class DashboardView(TemplateView):
     template_name = "dashboard.html"
 
 class DashboardView(TemplateView):
     template_name = "dashboard.html"
@@ -69,6 +70,14 @@ class DashboardView(TemplateView):
         context['networks'] = authlist.render(self.request) 
         context['slices']   = slicelist.render(self.request)
 
         context['networks'] = authlist.render(self.request) 
         context['slices']   = slicelist.render(self.request)
 
+        # XXX This is repeated in all pages
+        # more general variables expected in the template
+        context['title'] = 'Test view that combines various plugins'
+        # the menu items on the top
+        context['topmenu_items'] = topmenu_items('dashboard', self.request) 
+        # so we can sho who is logged
+        context['username'] = the_user(self.request) 
+
         context.update(page.prelude_env())
 
         return context
         context.update(page.prelude_env())
 
         return context
index eea4e22..bf7aa2f 100644 (file)
@@ -1,33 +1,27 @@
 # Create your views here.
 
 # Create your views here.
 
-from django.template import RequestContext
-from django.shortcuts import render_to_response
-
-from django.contrib.auth.decorators import login_required
-from django.http import HttpResponseRedirect
-
-from unfold.page import Page
-#from manifold.manifoldquery import ManifoldQuery
-from manifold.core.query import Query, AnalyzedQuery
-
-from plugins.raw.raw import Raw
-from plugins.stack.stack import Stack
-from plugins.tabs.tabs import Tabs
-from plugins.lists.slicelist import SliceList
-from plugins.hazelnut.hazelnut import Hazelnut 
-from plugins.googlemap.googlemap import GoogleMap 
-from plugins.senslabmap.senslabmap import SensLabMap
-from plugins.querycode.querycode import QueryCode
+from django.template                 import RequestContext
+from django.shortcuts                import render_to_response
+from django.contrib.auth.decorators  import login_required
+from django.http                     import HttpResponseRedirect
+
+from unfold.page                     import Page
+from manifold.core.query             import Query, AnalyzedQuery
+from manifold.manifoldresult         import ManifoldException
+from manifold.metadata               import MetaData as Metadata
+from myslice.viewutils               import quickfilter_criterias, topmenu_items, the_user
+
+from plugins.raw.raw                 import Raw
+from plugins.stack.stack             import Stack
+from plugins.tabs.tabs               import Tabs
+from plugins.lists.slicelist         import SliceList
+from plugins.hazelnut.hazelnut       import Hazelnut 
+from plugins.resources_selected      import ResourcesSelected
+from plugins.googlemap.googlemap     import GoogleMap 
+from plugins.senslabmap.senslabmap   import SensLabMap
+from plugins.querycode.querycode     import QueryCode
 from plugins.quickfilter.quickfilter import QuickFilter
 from plugins.quickfilter.quickfilter import QuickFilter
-from plugins.messages.messages import Messages
-
-from manifold.manifoldresult import ManifoldException
-
-from myslice.viewutils import quickfilter_criterias
-from myslice.viewutils import topmenu_items, the_user
-
-# XXX JORDAN
-from manifold.metadata import MetaData as Metadata
+from plugins.messages.messages       import Messages
 
 tmp_default_slice='ple.inria.heartbeat'
 debug = True
 
 tmp_default_slice='ple.inria.heartbeat'
 debug = True
@@ -69,7 +63,8 @@ def _slice_view (request, slicename):
         # TODO Get default fields
         main_query.fields = [
                 'slice_hrn',
         # TODO Get default fields
         main_query.fields = [
                 'slice_hrn',
-                'resource.hrn', 'resource.hostname', 'resource.type', 'resource.authority',
+                'resource.resource_hrn', 'resource.hostname', 'resource.type', 'resource.authority',
+                'lease.urn',
                 'user.user_hrn',
 #                'application.measurement_point.counter'
         ]
                 'user.user_hrn',
 #                'application.measurement_point.counter'
         ]
@@ -85,9 +80,7 @@ def _slice_view (request, slicename):
     # Create the base layout (Stack)...
     main_plugin = Stack (
         page=page,
     # Create the base layout (Stack)...
     main_plugin = Stack (
         page=page,
-        title="Slice view for %s"%slicename,
-        domid='thestack',
-        togglable=False,
+        title="Slice !!view for %s"%slicename,
         sons=[],
     )
 
         sons=[],
     )
 
@@ -95,123 +88,153 @@ def _slice_view (request, slicename):
 
 
     main_plugin.insert (
 
 
     main_plugin.insert (
-        Raw (page=page,togglable=False, toggled=True,html="<h2> Slice page for %s</h2>"%slicename))
+        Raw (page=page,togglable=False, toggled=True,html="<h2> Slice page for %s</h2>"%slicename)
+    )
 
     main_plugin.insert(
         Raw (page=page,togglable=False, toggled=True,html='<b>Description:</b> TODO')
     )
 
 
     main_plugin.insert(
         Raw (page=page,togglable=False, toggled=True,html='<b>Description:</b> TODO')
     )
 
+    sq_plugin = Tabs (
+        page=page,
+        title="Slice view for %s"%slicename,
+        togglable=False,
+        sons=[],
+    )
+
 
     # ... and for the relations
     # XXX Let's hardcode resources for now
 
     # ... and for the relations
     # XXX Let's hardcode resources for now
-    sq = aq.subquery('resource')
+    sq_resource = aq.subquery('resource')
+    sq_user     = aq.subquery('user')
+    sq_lease    = aq.subquery('lease')
+    sq_measurement = aq.subquery('measurement')
     
     
-    tab_resources = Tabs (
-        page         = page,
+
+    ############################################################################
+    # RESOURCES
+    # 
+    # A stack inserted in the subquery tab that will hold all operations
+    # related to resources
+    # 
+    
+    stack_resources = Stack(
+        page = page,
         title        = 'Resources',
         title        = 'Resources',
-        domid        = 'thetabs',
-        # activeid   = 'checkboxes',
-        active_domid = 'gmap',
-    )
-    main_plugin.insert(tab_resources)
-
-    tab_resources.insert(
-        Hazelnut ( 
-            page        = page,
-            title       = 'List',
-            domid       = 'checkboxes',
-            # tab's sons preferably turn this off
-            togglable   = False,
-            # this is the query at the core of the slice list
-            query       = sq,
-            checkboxes  = True,
-            datatables_options = { 
-                # for now we turn off sorting on the checkboxes columns this way
-                # this of course should be automatic in hazelnut
-                'aoColumns'      : [None, None, None, None, {'bSortable': False}],
-                'iDisplayLength' : 25,
-                'bLengthChange'  : True,
-            },
-        )
+        sons=[],
     )
     )
-    tab_resources.insert(
-        GoogleMap (
-            page        = page,
-            title       = 'Geographic view',
-            domid       = 'gmap',
-            # tab's sons preferably turn this off
-            togglable   = False,
-            query       = sq,
-            # center on Paris
-            latitude    = 49.,
-            longitude   = 2.2,
-            zoom        = 3,
-        )
+
+    # --------------------------------------------------------------------------
+    # Different displays = DataTables + GoogleMaps
+    #
+    tab_resource_plugins = Tabs(
+        page    = page,
+        sons = []
     )
 
     )
 
-    # XXX Let's hardcode users also for now
-    sq = aq.subquery('user')
-    
-    tab_users = Tabs (
+    tab_resource_plugins.insert(Hazelnut( 
+        page        = page,
+        title       = 'List',
+        domid       = 'checkboxes',
+        # this is the query at the core of the slice list
+        query       = sq_resource,
+        checkboxes  = True,
+        datatables_options = { 
+            # for now we turn off sorting on the checkboxes columns this way
+            # this of course should be automatic in hazelnut
+            'aoColumns'      : [None, None, None, None, {'bSortable': False}],
+            'iDisplayLength' : 25,
+            'bLengthChange'  : True,
+        },
+    ))
+
+    tab_resource_plugins.insert(GoogleMap(
+        page        = page,
+        title       = 'Geographic view',
+        domid       = 'gmap',
+        # tab's sons preferably turn this off
+        togglable   = False,
+        query       = sq_resource,
+        # center on Paris
+        latitude    = 49.,
+        longitude   = 2.2,
+        zoom        = 3,
+    ))
+
+    stack_resources.insert(tab_resource_plugins)
+
+    # --------------------------------------------------------------------------
+    # ResourcesSelected
+    #
+    stack_resources.insert(ResourcesSelected(
+        page                = page,
+        title               = 'Pending operations',
+        resource_query_uuid = sq_resource,
+        lease_query_uuid    = sq_lease,
+        togglable           = True,
+    ))
+
+    sq_plugin.insert(stack_resources)
+
+    ############################################################################
+    # USERS
+    # 
+
+    tab_users = Tabs(
         page         = page,
         title        = 'Users',
         domid        = 'thetabs2',
         # activeid   = 'checkboxes',
         active_domid = 'checkboxes2',
     )
         page         = page,
         title        = 'Users',
         domid        = 'thetabs2',
         # activeid   = 'checkboxes',
         active_domid = 'checkboxes2',
     )
-    main_plugin.insert(tab_users)
-
-    tab_users.insert(
-        Hazelnut ( 
-            page        = page,
-            title       = 'List',
-            domid       = 'checkboxes2',
-            # tab's sons preferably turn this off
-            togglable   = False,
-            # this is the query at the core of the slice list
-            query       = sq,
-            checkboxes  = True,
-            datatables_options = { 
-                # for now we turn off sorting on the checkboxes columns this way
-                # this of course should be automatic in hazelnut
-                'aoColumns'      : [None, None, None, None, {'bSortable': False}],
-                'iDisplayLength' : 25,
-                'bLengthChange'  : True,
-            },
-        )
-    )
-
-    # XXX Let's hardcode measurements also for now
-    sq = aq.subquery('measurement')
-    
-    tab_users = Tabs (
+    sq_plugin.insert(tab_users)
+
+    tab_users.insert(Hazelnut( 
+        page        = page,
+        title       = 'List',
+        domid       = 'checkboxes2',
+        # tab's sons preferably turn this off
+        togglable   = False,
+        # this is the query at the core of the slice list
+        query       = sq_user,
+        checkboxes  = True,
+        datatables_options = { 
+            # for now we turn off sorting on the checkboxes columns this way
+            # this of course should be automatic in hazelnut
+            'aoColumns'      : [None, None, None, None, {'bSortable': False}],
+            'iDisplayLength' : 25,
+            'bLengthChange'  : True,
+        },
+    ))
+
+    tab_measurements = Tabs (
         page         = page,
         title        = 'Measurements',
         domid        = 'thetabs3',
         # activeid   = 'checkboxes',
         active_domid = 'checkboxes3',
     )
         page         = page,
         title        = 'Measurements',
         domid        = 'thetabs3',
         # activeid   = 'checkboxes',
         active_domid = 'checkboxes3',
     )
-    main_plugin.insert(tab_users)
-
-    tab_users.insert(
-        Hazelnut ( 
-            page        = page,
-            title       = 'List',
-            domid       = 'checkboxes3',
-            # tab's sons preferably turn this off
-            togglable   = False,
-            # this is the query at the core of the slice list
-            query       = sq,
-            checkboxes  = True,
-            datatables_options = { 
-                # for now we turn off sorting on the checkboxes columns this way
-                # this of course should be automatic in hazelnut
-                'aoColumns'      : [None, None, None, None, {'bSortable': False}],
-                'iDisplayLength' : 25,
-                'bLengthChange'  : True,
-            },
-        )
-    )
+    sq_plugin.insert(tab_measurements)
+
+    tab_measurements.insert(Hazelnut( 
+        page        = page,
+        title       = 'List',
+        domid       = 'checkboxes3',
+        # tab's sons preferably turn this off
+        togglable   = False,
+        # this is the query at the core of the slice list
+        query       = sq_measurement,
+        checkboxes  = True,
+        datatables_options = { 
+            # for now we turn off sorting on the checkboxes columns this way
+            # this of course should be automatic in hazelnut
+            'aoColumns'      : [None, None, None, None, {'bSortable': False}],
+            'iDisplayLength' : 25,
+            'bLengthChange'  : True,
+        },
+    ))
+
+    main_plugin.insert(sq_plugin)
 
     main_plugin.insert (
         Messages (
 
     main_plugin.insert (
         Messages (