plugins: migrated hazelnut and googlemaps to the new plugin class, updated plugin...
authorJordan Augé <jordan.auge@lip6.fr>
Fri, 9 Aug 2013 12:14:37 +0000 (14:14 +0200)
committerJordan Augé <jordan.auge@lip6.fr>
Fri, 9 Aug 2013 12:14:37 +0000 (14:14 +0200)
21 files changed:
auth/css/login.css
devel/server-loop.sh
manifold/js/manifold.js
manifold/js/plugin.js
myslice/settings.py
plugins/debug_platform/__init__.py
plugins/googlemap/__init__.py [deleted file]
plugins/googlemap/static/js/googlemap.js [deleted file]
plugins/googlemaps/__init__.py [moved from plugins/googlemap/googlemap.py with 89% similarity]
plugins/googlemaps/static/css/googlemaps.css [moved from plugins/googlemap/static/css/googlemap.css with 100% similarity]
plugins/googlemaps/static/googlemaps.html [moved from plugins/googlemap/static/googlemap.html with 100% similarity]
plugins/googlemaps/static/js/googlemaps.js [new file with mode: 0644]
plugins/googlemaps/static/js/markerclusterer.js [moved from plugins/googlemap/static/js/markerclusterer.js with 100% similarity]
plugins/googlemaps/static/js/markerclusterer_compiled.js [moved from plugins/googlemap/static/js/markerclusterer_compiled.js with 100% similarity]
plugins/googlemaps/static/js/markerclusterer_packed.js [moved from plugins/googlemap/static/js/markerclusterer_packed.js with 100% similarity]
plugins/hazelnut/DataTables.php [deleted file]
plugins/hazelnut/static/hazelnut.html
plugins/hazelnut/static/js/hazelnut.js
plugins/myplugin/static/js/myplugin.js
trash/pluginview.py
trash/sliceview.py

index 06528ee..11444f7 100644 (file)
@@ -6,7 +6,7 @@ input.login {
 }    
 input[type="password"] {
     border: solid 1px #444;
-    background-image: url( '/all-static/img/form_input_password.png' );
+    background-image: url( '../img/form_input_password.png' );
     background-repeat: repeat-x;
     background-position: top;
 }
index 94215e8..4ff84bf 100755 (executable)
@@ -9,4 +9,5 @@ hostname | grep -q '^z' && port=8080 || port=80
 while true; do 
     ./manage.py collectstatic --noinput
     ./manage.py runserver 0.0.0.0:$port
+       sleep 1
 done
index 667ad34..f7c098a 100644 (file)
@@ -370,14 +370,11 @@ var manifold = {
 
     raise_event_handler: function(type, query_uuid, event_type, value)
     {
-        if (type == 'query') {
-            var channels = [ manifold.get_query_channel(query_uuid), manifold.get_query_channel('*') ];
-        } else if (type == 'record') {
-            var channels = [ manifold.get_record_channel(query_uuid), manifold.get_record_channel('*') ];
-
-        } else {
+        if ((type != 'query') && (type != 'record'))
             throw 'Incorrect type for manifold.raise_event()';
-        }
+
+        var channels = [ manifold.get_channel(type, query_uuid), manifold.get_channel(type, '*') ];
+
         $.each(channels, function(i, channel) {
             if (value === undefined)
                 $('.plugin').trigger(channel, [event_type]);
@@ -468,35 +465,18 @@ var manifold = {
     },
 
     /* Publish/subscribe channels for internal use */
-    get_query_channel:  function(uuid) { return '/query/'  + uuid },
-    get_record_channel: function(uuid) { return '/record/' + uuid },
+    get_channel: function(type, query_uuid) 
+    {
+        if ((type !== 'query') && (type != 'record'))
+            return null;
+        return '/' + type + '/' + query_uuid;
+    },
 
 }; // manifold object
 /* ------------------------------------------------------------ */
 
 (function($) {
 
-    /* NEW PLUGIN API
-     * 
-     * NOTE: Since we don't have a plugin class, we are extending all jQuery
-     * plugins...
-     */
-
-    /*!
-     * \brief Associates a query handler to the current plugin
-     * \param uuid (string) query uuid
-     * \param handler (function) handler callback
-     */
-    $.fn.set_query_handler = function(uuid, handler)
-    {
-        this.on(manifold.get_query_channel(uuid), handler);
-    }
-
-    $.fn.set_record_handler = function(uuid, handler)
-    {
-        this.on(manifold.get_record_channel(uuid), handler);
-    }
-
     // OLD PLUGIN API: extend jQuery/$ with pubsub capabilities
     // https://gist.github.com/661855
     var o = $({});
index 84ebbc4..b72cc30 100644 (file)
@@ -40,7 +40,7 @@ var Plugin = Class.extend({
         return (typeof this.on_filter_added === 'function');
     },
 
-    _query_handler: function(e, event_type, data)
+    _query_handler: function(prefix, event_type, data)
     {
         // We suppose this.query_handler_prefix has been defined if this
         // callback is triggered    
@@ -68,7 +68,7 @@ var Plugin = Class.extend({
                 return;
         } // switch
         
-        fn = 'on_' + this.query_handler_prefix + fn;
+        fn = 'on_' + prefix + fn;
         if (typeof this[fn] === 'function') {
             // call with data as parameter
             // XXX implement anti loop
@@ -76,9 +76,51 @@ var Plugin = Class.extend({
         }
     },
 
-    listen_query: function(query_uuid, prefix) {
-        this.query_handler_prefix = (typeof prefix === 'undefined') ? '' : (prefix + manifold.separator);
-        this.$element.on(manifold.get_query_channel(query_uuid), $.proxy(this._query_handler, this));
+    _record_handler: function(prefix, event_type, record)
+    {
+        // We suppose this.query_handler_prefix has been defined if this
+        // callback is triggered    
+        var fn;
+        switch(event_type) {
+            case NEW_RECORD:
+                fn = 'new_record';
+                break;
+            case CLEAR_RECORDS:
+                fn = 'clear_records';
+                break;
+            case IN_PROGRESS:
+                fn = 'query_in_progress';
+                break;
+            case DONE:
+                fn = 'query_done';
+                break;
+            default:
+                return;
+        } // switch
+        
+        fn = 'on_' + prefix + fn;
+        if (typeof this[fn] === 'function') {
+            // call with data as parameter
+            // XXX implement anti loop
+            this[fn](record);
+        }
+    },
+
+    get_handler_function: function(type, prefix)
+    {
+        
+        return $.proxy(function(e, event_type, record) {
+            return this['_' + type + '_handler'](prefix, event_type, record);
+        }, this);
+    },
+
+    listen_query: function(query_uuid, prefix)
+    {
+        // default: prefix = ''
+        prefix = (typeof prefix === 'undefined') ? '' : (prefix + '_');
+
+        this.$element.on(manifold.get_channel('query', query_uuid),  this.get_handler_function('query',  prefix));
+        this.$element.on(manifold.get_channel('record', query_uuid),  this.get_handler_function('record', prefix));
     },
 
     default_options: {},
@@ -155,4 +197,14 @@ var Plugin = Class.extend({
         return array[1];
     },
 
+    spin: function()
+    {
+        manifold.spin(this.element);
+    },
+
+    unspin: function()
+    {
+        manifold.spin(this.element, false);
+    },
+
 });
index 269bde3..06e4eae 100644 (file)
@@ -98,10 +98,12 @@ STATICFILES_DIRS = (
     # Don't forget to use absolute paths, not relative paths.
     # thierry os.path.join(ROOT,'all-static'),
     ('js', os.path.join(ROOT,'manifold/js')),
-    ('js', os.path.join(ROOT,'unfold/js')),
-    ('js', os.path.join(ROOT,'auth/js')),
     ('css', os.path.join(ROOT,'manifold/css')),
+    ('js', os.path.join(ROOT,'unfold/js')),
     ('css', os.path.join(ROOT,'unfold/css')),
+    ('js', os.path.join(ROOT,'auth/js')),
+    ('css', os.path.join(ROOT,'auth/css')),
+    ('img', os.path.join(ROOT,'auth/img')),
     ('css', os.path.join(ROOT,'views/css')),
     ('img', os.path.join(ROOT,'views/img')),
 )
index 5dbb2b6..543fa5c 100644 (file)
@@ -1,7 +1,7 @@
 from unfold.plugin       import Plugin
 from unfold.page         import Page
 from plugins.code_editor import CodeEditor
-from plugins.hazelnut.hazelnut import Hazelnut
+from plugins.hazelnut    import Hazelnut
 
 class DebugPlatform(Plugin):
 
diff --git a/plugins/googlemap/__init__.py b/plugins/googlemap/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/plugins/googlemap/static/js/googlemap.js b/plugins/googlemap/static/js/googlemap.js
deleted file mode 100644 (file)
index c9d3923..0000000
+++ /dev/null
@@ -1,341 +0,0 @@
-/**
- * Description: display a query result in a googlemap
- * Copyright (c) 2012 UPMC Sorbonne Universite - INRIA
- * 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 = 'GoogleMap';
-
-    // routing calls
-    jQuery.fn.GoogleMap = 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 GoogleMaps(options);
-                $this.data('Manifold', plugin);
-
-                plugin.initialize();
-
-                /* Events */
-                $this.on('show.' + PLUGIN_NAME, methods.show);
-
-                $this.set_query_handler(options.query_uuid, plugin.query_handler);
-                $this.set_record_handler(options.query_uuid, plugin.record_handler); 
-                $this.set_record_handler(options.query_all_uuid, plugin.record_handler_all); 
-
-            }); // 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 hazelnut = $this.data('Manifold');
-
-                // Unbind all events using namespacing
-                $(window).unbind(PLUGIN_NAME);
-
-                // Remove associated data
-                hazelnut.remove();
-                $this.removeData('Manifold');
-            });
-
-        }, // destroy
-
-        show : function( ) {
-            google.maps.event.trigger(map, 'resize');
-        } // show
-
-    }; // var methods;
-
-    /***************************************************************************
-     * Plugin object
-     ***************************************************************************/
-
-    function GoogleMaps(options) 
-    {
-        /* member variables */
-        this.options = options;
-
-        // query status
-        this.received_all = false;
-        this.received_set = false;
-        this.in_set_buffer = Array();
-
-        var object = this;
-
-        /**
-         */
-        this.initialize = function() {
-            this.map = null;
-            this.markerCluster = null;
-            this.markers = [];
-            this.coords = new Array();
-
-            var myLatlng = new google.maps.LatLng(options.latitude, options.longitude);
-            var myOptions = {
-                zoom: options.zoom,
-                center: myLatlng,
-                mapTypeId: google.maps.MapTypeId.ROADMAP
-            }
-      
-            this.map = new google.maps.Map(document.getElementById("map"), myOptions);
-            this.infowindow = new google.maps.InfoWindow();
-        }
-
-        /**
-         */
-        this.new_record = function(record)
-        {
-
-            // get the coordinates
-            var latitude=get_value(record['latitude']);
-            var longitude=get_value(record['longitude']);
-            var hash = latitude + longitude;
-
-            // check to see if we've seen this hash before
-            if(this.coords[hash] == null) {
-                // get coordinate object
-                var myLatlng = new google.maps.LatLng(latitude, longitude);
-                // store an indicator that we've seen this point before
-                this.coords[hash] = 1;
-            } else {
-                // add some randomness to this point 1500 = 100 meters, 15000 = 10 meters
-                var lat = latitude + (Math.random() -.5) / 1500; 
-                var lng = longitude + (Math.random() -.5) / 1500; 
-
-                // get the coordinate object
-                var myLatlng = new google.maps.LatLng(lat, lng);
-            }
-            // If the node is attached to the slice, action will be Remove; else action will be add to slice
-            if (typeof(record['sliver']) != 'undefined') {
-                data.current_resources.push(record['urn']);
-                action="del";
-                action_class="ui-icon-circle-minus";
-                action_message="Remove from slice";
-            }else{
-                action="add";
-                action_class="ui-icon-circle-plus";
-                action_message="Add to slice";
-            }
-            // XXX not working
-            if (!(record['latitude'])) {
-                return true;
-            }
-
-            //jQuery(".map-button").click(button_click);
-            //if(jQuery.inArray(record, rows)>-1){
-                var marker = new google.maps.Marker({
-                    position: myLatlng,
-                    title: get_value(record['hostname']),
-                    // This should be done by the rendering
-                    content: '<p>Agent: ' + get_value(record['ip']) + ' (' + get_value(record['resource_hrn']) + ')<br/>Platform: ' + get_value(record['platform'])+'</p>' +
-                            '<div class="map-button" id="'+action+'/'+get_value(record['resource_hrn'])+'" style="cursor:pointer;">'+
-                            '<span class="ui-icon '+action_class+'" style="clear:both;float:left;"></span>'+action_message+
-                            '</div>'
-                }); 
-
-                this.addInfoWindow(marker, object.map);
-                object.markers.push(marker);
-            //}
-
-        };
-
-        this.addInfoWindow = function(marker, map) {
-            google.maps.event.addListener(marker, 'click', function () {     
-                if(object.infowindow){
-                    object.infowindow.close();
-                }
-                object.infowindow.setContent(marker.content);// = new google.maps.InfoWindow({ content: marker.content });
-                object.infowindow.open(map, marker);
-                // onload of the infowindow on the map, bind a click on a button
-                google.maps.event.addListener(object.infowindow, 'domready', function() {
-                    jQuery('.map-button').unbind('click');
-//                    jQuery(".map-button").click({instance: instance_, infoWindow: object.infowindow}, button_click);                     
-                });
-            });
-        }
-
-
-        this.set_checkbox = function(record)
-        {
-            // XXX urn should be replaced by the key
-            // XXX we should enforce that both queries have the same key !!
-            //checkbox_id = "#hazelnut-checkbox-" + object.options.plugin_uuid + "-" + unfold.escape_id(record[ELEMENT_KEY].replace(/\\/g, ''))
-            //$(checkbox_id, object.table.fnGetNodes()).attr('checked', true);
-        }
-
-        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:
-
-                    // MarkerClusterer
-                    object.markerCluster = new MarkerClusterer(object.map, object.markers, {zoomOnClick: false});
-                    google.maps.event.addListener(object.markerCluster, "clusterclick", function (cluster) {
-                        var markers = cluster.getMarkers();
-                        var bounds  = new google.maps.LatLngBounds();
-                      /* 
-                      * date: 24/05/2012
-                      * author: lbaron
-                      * Firefox JS Error - replaced $.each by JQuery.each
-                      */                  
-                      jQuery.each(markers, function(i, marker){
-                          bounds.extend(marker.getPosition()); 
-                      });
-
-                      //map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));
-                      object.map.fitBounds(bounds);
-                    });
-
-                    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, query)
-        {
-            // 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:
-                    break;
-
-                // Fields
-                /* Hide/unhide columns to match added/removed fields */
-                case FIELD_ADDED:
-                    break;
-                case FIELD_REMOVED:
-                    break;
-                case CLEAR_FIELDS:
-                    alert('GoogleMaps::clear_fields() not implemented');
-                    break;
-            } // switch
-
-
-        }
-
-        function button_click(e){
-            var op_value=this.id.split("/");
-            if(op_value.length>0){
-                var value = op_value[1];
-                manifold.raise_event(object.options.query_uuid, (op_value[0] == 'add')?SET_ADD:SET_REMOVED, value);
-            }
-        } // function button_click()
-    } 
-
-    // clear and replace
-//                jQuery.each(data.results, function(i, row){
-//                    jQuery.each(query.filter, function (idx, filter){
-//                        if(get_value(row[filter[0]])==filter[2]){
-//                            rows.push(row);
-//                        }
-//                    });
-//                });
-//                data.markerCluster=[];
-//                data.markers=[];
-//                var myLatlng = new google.maps.LatLng(34.397, 150.644);
-//                var myOptions = {
-//                    zoom: 2,
-//                    center: myLatlng,
-//                    mapTypeId: google.maps.MapTypeId.ROADMAP
-//                }
-//                map = new google.maps.Map(jQuery('#map')[0],myOptions);
-//                data.map=map;
-//                //map.clearMarkers();
-//                update_map(e, rows);
-//            }
-//        }
-
-})( jQuery );
similarity index 89%
rename from plugins/googlemap/googlemap.py
rename to plugins/googlemaps/__init__.py
index bce84f5..38c6564 100644 (file)
@@ -1,6 +1,6 @@
 from unfold.plugin import Plugin
 
-class GoogleMap (Plugin):
+class GoogleMaps (Plugin):
 
     # set checkboxes if a final column with checkboxes is desired
     # pass columns as the initial set of columns
@@ -16,7 +16,7 @@ class GoogleMap (Plugin):
         self.zoom=zoom
 
     def template_file (self):
-        return "googlemap.html"
+        return "googlemaps.html"
 
     def template_env (self, request):
         env={}
@@ -25,13 +25,13 @@ class GoogleMap (Plugin):
     def requirements (self):
         reqs = {
             'js_files' : [ "https://maps.googleapis.com/maps/api/js?sensor=false", 
-                           "/js/googlemap.js",
+                           "/js/googlemaps.js",
                            "/js/markerclusterer.js",
                             "js/manifold.js", "js/manifold-query.js", 
                             "js/spin.presets.js", "js/spin.min.js", "js/jquery.spin.js", 
                             "js/unfold-helper.js",
                            ],
-            'css_files' : [ "css/googlemap.css",
+            'css_files' : [ "css/googlemaps.css",
                             ],
             }
         return reqs
diff --git a/plugins/googlemaps/static/js/googlemaps.js b/plugins/googlemaps/static/js/googlemaps.js
new file mode 100644 (file)
index 0000000..e97d1f5
--- /dev/null
@@ -0,0 +1,248 @@
+/**
+ * Description: display a query result in a Google map
+ * Copyright (c) 2012-2013 UPMC Sorbonne Universite - INRIA
+ * License: GPLv3
+ */
+
+(function($){
+
+   var GoogleMaps = Plugin.extend({
+
+        init: function(options, element)
+        {
+            this._super(options, element);
+
+            /* Member variables */
+            // query status
+            this.received_all = false;
+            this.received_set = false;
+            this.in_set_buffer = Array();
+
+            /* XXX Events XXX */
+            this.$element.on('show.Datatables', this.on_show);
+            // TODO in destructor
+            // $(window).unbind('Hazelnut');
+
+            /* Setup query and record handlers */
+            this.listen_query(options.query_uuid);
+            this.listen_query(options.query_all_uuid, 'all');
+
+            /* GUI setup and event binding */
+            this.initialize_map();
+        }, // init
+
+        /* PLUGIN EVENTS */
+
+        on_show: function()
+        {
+            google.maps.event.trigger(map, 'resize');
+        }, // on_show
+
+        /* GUI EVENTS */
+
+        /* GUI MANIPULATION */
+
+        /**
+         */
+        initialize_map: function()
+        {
+            this.map = null;
+            this.markerCluster = null;
+            this.markers = [];
+            this.coords = new Array();
+
+            var myLatlng = new google.maps.LatLng(this.options.latitude, this.options.longitude);
+            var myOptions = {
+                zoom: this.options.zoom,
+                center: myLatlng,
+                mapTypeId: google.maps.MapTypeId.ROADMAP
+            }
+      
+            this.map = new google.maps.Map(document.getElementById("map"), myOptions);
+            this.infowindow = new google.maps.InfoWindow();
+        }, // initialize_map
+
+        /**
+         */
+        new_record: function(record)
+        {
+            // get the coordinates
+            var latitude=get_value(record['latitude']);
+            var longitude=get_value(record['longitude']);
+            var hash = latitude + longitude;
+
+            // check to see if we've seen this hash before
+            if(this.coords[hash] == null) {
+                // get coordinate object
+                var myLatlng = new google.maps.LatLng(latitude, longitude);
+                // store an indicator that we've seen this point before
+                this.coords[hash] = 1;
+            } else {
+                // add some randomness to this point 1500 = 100 meters, 15000 = 10 meters
+                var lat = latitude + (Math.random() -.5) / 1500; 
+                var lng = longitude + (Math.random() -.5) / 1500; 
+
+                // get the coordinate object
+                var myLatlng = new google.maps.LatLng(lat, lng);
+            }
+            // If the node is attached to the slice, action will be Remove; else action will be add to slice
+            if (typeof(record['sliver']) != 'undefined') {
+                data.current_resources.push(record['urn']);
+                action="del";
+                action_class="ui-icon-circle-minus";
+                action_message="Remove from slice";
+            }else{
+                action="add";
+                action_class="ui-icon-circle-plus";
+                action_message="Add to slice";
+            }
+            // XXX not working
+            if (!(record['latitude'])) {
+                return true;
+            }
+
+            //jQuery(".map-button").click(button_click);
+            //if(jQuery.inArray(record, rows)>-1){
+                var marker = new google.maps.Marker({
+                    position: myLatlng,
+                    title: get_value(record['hostname']),
+                    // This should be done by the rendering
+                    content: '<p>Agent: ' + get_value(record['ip']) + ' (' + get_value(record['resource_hrn']) + ')<br/>Platform: ' + get_value(record['platform'])+'</p>' +
+                            '<div class="map-button" id="'+action+'/'+get_value(record['resource_hrn'])+'" style="cursor:pointer;">'+
+                            '<span class="ui-icon '+action_class+'" style="clear:both;float:left;"></span>'+action_message+
+                            '</div>'
+                }); 
+
+                this.addInfoWindow(marker, this.map);
+                this.markers.push(marker);
+            //}
+
+        }, // new_record
+
+        addInfoWindow: function(marker, map)
+        {
+            google.maps.event.addListener(marker, 'click', function () {     
+                if(object.infowindow){
+                    object.infowindow.close();
+                }
+                object.infowindow.setContent(marker.content);// = new google.maps.InfoWindow({ content: marker.content });
+                object.infowindow.open(map, marker);
+                // onload of the infowindow on the map, bind a click on a button
+                google.maps.event.addListener(object.infowindow, 'domready', function() {
+                    jQuery('.map-button').unbind('click');
+//                    jQuery(".map-button").click({instance: instance_, infoWindow: object.infowindow}, button_click);                     
+                });
+            });
+        }, // addInfoWindow
+
+        set_checkbox: function(record)
+        {
+            // XXX urn should be replaced by the key
+            // XXX we should enforce that both queries have the same key !!
+            //checkbox_id = "#hazelnut-checkbox-" + object.options.plugin_uuid + "-" + unfold.escape_id(record[ELEMENT_KEY].replace(/\\/g, ''))
+            //$(checkbox_id, object.table.fnGetNodes()).attr('checked', true);
+        }, // set_checkbox
+
+
+        /*************************** QUERY HANDLER ****************************/
+
+        /*************************** RECORD HANDLER ***************************/
+
+        on_new_record: function(record)
+        {
+            if (this.received_all)
+                // update checkbox for record
+                this.set_checkbox(record);
+            else
+                // store for later update of checkboxes
+                this.in_set_buffer.push(record);
+        },
+
+        on_clear_records: function(record)
+        {
+
+        },
+
+        // Could be the default in parent
+        on_query_in_progress: function()
+        {
+            this.spin();
+        },
+
+        on_query_done: function()
+        {
+            if (this.received_all)
+                this.unspin();
+            this.received_set = true;
+        },
+
+        // all
+
+        on_all_new_record: function(record)
+        {
+            this.new_record(record);
+        },
+
+        on_all_clear_records: function()
+        {
+        },
+
+        on_all_query_in_progress: function()
+        {
+            // XXX parent
+            this.spin();
+        },
+
+        on_all_query_done: function()
+        {
+
+            // MarkerClusterer
+            this.markerCluster = new MarkerClusterer(this.map, this.markers, {zoomOnClick: false});
+            google.maps.event.addListener(this.markerCluster, "clusterclick", function (cluster) {
+                var markers = cluster.getMarkers();
+                var bounds  = new google.maps.LatLngBounds();
+              /* 
+              * date: 24/05/2012
+              * author: lbaron
+              * Firefox JS Error - replaced $.each by JQuery.each
+              */                  
+              jQuery.each(markers, function(i, marker){
+                  bounds.extend(marker.getPosition()); 
+              });
+
+              //map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));
+              this.map.fitBounds(bounds);
+            });
+
+            var self = this;
+            if (this.received_set) {
+                /* XXX needed ? XXX We uncheck all checkboxes ... */
+                $("[id^='datatables-checkbox-" + this.options.plugin_uuid +"']").attr('checked', false);
+
+                /* ... and check the ones specified in the resource list */
+                $.each(this.in_set_buffer, function(i, record) {
+                    self.set_checkbox(record);
+                });
+
+                this.unspin();
+            }
+            this.received_all = true;
+
+        }, // on_all_query_done
+
+        /************************** PRIVATE METHODS ***************************/
+
+        _button_click: function(e)
+        {
+            var op_value=this.id.split("/");
+            if(op_value.length>0) {
+                var value = op_value[1];
+                manifold.raise_event(this.options.query_uuid, (op_value[0] == 'add')?SET_ADD:SET_REMOVED, value);
+            }
+        } // button_click
+
+    });
+
+    $.plugin('GoogleMaps', GoogleMaps);
+
+})(jQuery);
diff --git a/plugins/hazelnut/DataTables.php b/plugins/hazelnut/DataTables.php
deleted file mode 100644 (file)
index 67a8985..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-<?php
-
-
-class DataTables extends Plugin
-{
-
-       /* Knowing the uuid of a query, we could get the results with Plugins */
-       /* Same for async */
-    public function render_content()
-    //$plugin_uuid, $options)
-    {
-
-        //Plugins::add_js('/DataTables/jquery.dataTables.js');
-        Plugins::add_js('//ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.3/jquery.dataTables.js');
-        Plugins::add_js('/DataTables/DataTables.js');
-        //Plugins::add_css('/DataTables/DataTables.css');
-        //Plugins::add_css('/DataTables/demo_table.css');
-        Plugins::add_css('/DataTables/demo_table_jui.css');
-
-        $uuid = $this->uuid;
-
-               $results = Array();
-               $async = 1;
-
-
-        /* XXX required field in options : query_uuid */
-         
-        
-        $query = Plugins::get_query_by_uuid($this->params['query_uuid']);
-        $is_unique = Plugins::get_key_filter($query);
-           $method_keys = Plugins::get_default_fields($query->method, $is_unique);
-          //$method_keys = Plugins::query_get_default_keys($options['query_uuid']);
-          //$fields = Plugins::query_get_fields($options['query_uuid']);
-        //$all_headers = $_SESSION['metadata']['nodes']['columns'];        
-        //$fields = $all_headers;
-
-       $fields = Plugins::metadata_get_fields($query->method);
-
-       /*
-        * @author: lbaron
-        * date: 2012-05-29
-        * debug columns QueryEditor to DataTables
-        *
-        */
-        // Problem: field names are differents between 
-        // $_SESSION['metadata']['nodes']['columns'] 
-        // JSON values
-        //$fields[]="arch"; // architecture in Session metadata
-        //$fields[]="astype"; // as_type in Session metadata
-        $fields['platform'] = Array('column' => 'platform');
-        $fields['platform_longname'] = Array('column' => 'platform_longname');
-
-        //----------------------------------
-        
-        $out = Array();
-        $out[] = "<table class='display' id='table-$uuid'>";
-        $out[] = "<thead><tr>";
-
-        foreach ($method_keys as $f) {
-            $out[] = "<th>$f</th>";
-        }
-
-        /* We put defaults fields (should be keys) at the beginning, and don't repeat them afterwards */
-        foreach ($fields as $key=>$f) {
-            if((array_search($f['column'], $method_keys)) === false)
-                $out[] = "<th>".$f['column']."</th>";
-        }
-
-        if (array_key_exists('checkboxes', $this->params) && ($this->params['checkboxes'])) {
-            $out[] = "<th>+/-</th>";            
-        }
-        $out[] = "</tr></thead>";
-        $out[] = "<tbody>";        
-        
-        /* This might be done asynchronously */
-        if (!$async) {
-            $query = Plugins::get_query_by_uuid($this->params['query_uuid']);
-            foreach ($results as $r) {
-                $out[] = "<tr>";
-                foreach ($fields as $f) {
-                    $out[] = "<td>";
-                    $out[] = Plugins::render_element($query, $r[$f], $f); // XXX was query->method
-                    $out[] = "</td>";
-                }
-                if (array_key_exists('checkboxes', $this->params) && ($this->params['checkboxes'])) {
-                    $out[] = "<td>[X]</td>";
-                }
-                $out[] = "</tr>";
-            }
-        }
-
-
-        if ($async) {
-            /* setup datatables */
-            /* TODO:
-             * - fixed row for key columns
-             * - uniform row height
-             * - how to make some columns disappear
-             * - how to udpate some columns based on keys
-             */
-        }
-        $out[] = "</tbody>";
-        $out[] = "</table>";
-        return implode($out);
-    }
-}
-
-Plugins::register_plugin(
-    'DataTables',   /* plugin name */
-    'DataTables',   /* class name */
-    Array(
-        'method' => '*',
-        'fields' => Array()
-    )
-    /* XXX dependencies */
-);
index aae78e4..b49161b 100644 (file)
@@ -1,5 +1,5 @@
 <div id='main-{{ domid }}'>
-  <table class='table table-striped table-bordered dataTable' id='hazelnut-{{ domid }}'>
+  <table class='table table-striped table-bordered dataTable' id='{{domid}}__table'>
     <thead>
       <tr>
         {% for column in columns %}
index 8cbc537..d26f0ea 100644 (file)
 /**
  * Description: display a query result in a datatables-powered <table>
- * Copyright (c) 2012 UPMC Sorbonne Universite - INRIA
+ * Copyright (c) 2012-2013 UPMC Sorbonne Universite - INRIA
  * 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.
- */
-
-// TEMP
-var ELEMENT_KEY = 'resource_hrn';
-
 (function($){
 
+    // TEMP
+    var ELEMENT_KEY = 'resource_hrn';
     var debug=false;
     debug=true
 
-    // routing calls
-    $.fn.Hazelnut = 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 {
-            $.error( 'Method ' +  method + ' does not exist on jQuery.Hazelnut' );
-        }    
-    };
+    var Hazelnut = Plugin.extend({
 
-    /***************************************************************************
-     * Public methods
-     ***************************************************************************/
+        init: function(options, element) 
+        {
+            this._super(options, element);
 
-    var methods = {
+            /* Member variables */
+            // query status
+            this.received_all = false;
+            this.received_set = false;
+            this.in_set_buffer = Array();
 
-        /**
-         * @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 ) {
-
-            /* Default settings */
-            var options = $.extend( {
-                'checkboxes': false
-            }, options);
-
-            return this.each(function() {
-
-                var $this = $(this);
-
-                /* An object that will hold private variables and methods */
-                var plugin = new Hazelnut (options);
-                $this.data('Hazelnut', plugin);
-
-                /* Events */
-                $this.on('show.Datatables', methods.show);
-
-                // This is the new plugin API meant to replace the weird publish_subscribe mechanism
-                $this.set_query_handler(options.query_uuid, plugin.query_handler);
-                $this.set_record_handler(options.query_uuid, plugin.record_handler); 
-                $this.set_record_handler(options.query_all_uuid, plugin.record_handler_all); 
-
-//                /* Subscriptions */
-//                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
-//                $.subscribe(query_channel,  function(e, query) { hazelnut.set_query(query); });
-//                // xxx not tested yet
-//                $.subscribe(update_channel, function(e, resources, instance) { hazelnut.set_resources(resources, instance); });
-//                // expected to work
-//                $.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);
-
-            }); // this.each
-        }, // init
+            /* XXX Events XXX */
+            this.$element.on('show.Datatables', this.on_show);
+            // Unbind all events using namespacing
+            // TODO in destructor
+            // $(window).unbind('Hazelnut');
 
-        /**
-         * @brief Plugin destruction
-         * @return : a jQuery collection of objects on which the plugin is
-         *     applied, which allows to maintain chainability of calls
-         */
-        destroy : function( ) {
+            /* Setup query and record handlers */
+            this.listen_query(options.query_uuid);
+            this.listen_query(options.query_all_uuid, 'all');
 
-            return this.each(function() {
-                var $this = $(this);
-                var hazelnut = $this.data('Hazelnut');
+            /* GUI setup and event binding */
+            this.initialize_table();
+        },
 
-                // Unbind all events using namespacing
-                $(window).unbind('Hazelnut');
+        default_options: {
+            'checkboxes': false
+        },
 
-                // Remove associated data
-                hazelnut.remove();
-                $this.removeData('Hazelnut');
-            });
-        }, // destroy
+        /* PLUGIN EVENTS */
 
-        show : function( ) {
+        on_show: function()
+        {
+            // XXX
             var $this=$(this);
             // xxx wtf. why [1] ? would expect 0...
             if (debug)
@@ -119,35 +63,15 @@ var ELEMENT_KEY = 'resource_hrn';
                     }
                 }
             });
-        } // show
-
-    }; // var methods;
-
-    /***************************************************************************
-     * Plugin object
-     ***************************************************************************/
+        }, // on_show
 
-    function Hazelnut(options) 
-    {
-        /* member variables */
-        this.options = options;
+        /* GUI EVENTS */
 
-        // xxx thierry : initialize this here - it was not, I expect this relied on set_query somehow..
-        //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_resources = Array();
+        /* GUI MANIPULATION */
 
-        // query status
-        this.received_all = false;
-        this.received_set = false;
-        this.in_set_buffer = Array();
-
-        var object = this;
-
-        this.initialize = function() {
+        initialize_table: function() {
             /* Transforms the table into DataTable, and keep a pointer to it */
+            var self = this;
             actual_options = {
                 // Customize the position of Datatables elements (length,filter,button,...)
                 // we use a fluid row on top and another on the bottom, making sure we take 12 grid elt's each time
@@ -159,15 +83,16 @@ var ELEMENT_KEY = 'resource_hrn';
                 // 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); }
+                fnDrawCallback: function() { self._hazelnut_draw_callback.call(self); }
+                // XXX use $.proxy here !
             };
             // the intention here is that options.datatables_options as coming from the python object take precedence
             //  XXX DISABLED by jordan: was causing errors in datatables.js     $.extend(actual_options, options.datatables_options );
-            this.table = $('#hazelnut-' + options.plugin_uuid).dataTable(actual_options);
+            this.table = this.el('table').dataTable(actual_options);
 
             /* Setup the SelectAll button in the dataTable header */
             /* xxx not sure this is still working */
-            var oSelectAll = $('#datatableSelectAll-'+ options.plugin_uuid);
+            var oSelectAll = $('#datatableSelectAll-'+ this.options.plugin_uuid);
             oSelectAll.html("<span class='ui-icon ui-icon-check' style='float:right;display:inline-block;'></span>Select All");
             oSelectAll.button();
             oSelectAll.css('font-size','11px');
@@ -175,228 +100,128 @@ var ELEMENT_KEY = 'resource_hrn';
             oSelectAll.css('margin-right','15px');
             oSelectAll.css('margin-bottom','5px');
             oSelectAll.unbind('click');
-            oSelectAll.click(selectAll);
+            oSelectAll.click(this._selectAll);
 
             /* Add a filtering function to the current table 
              * Note: we use closure to get access to the 'options'
              */
             $.fn.dataTableExt.afnFiltering.push(function( oSettings, aData, iDataIndex ) { 
                 /* No filtering if the table does not match */
-                if (oSettings.nTable.id != "hazelnut-" + options.plugin_uuid)
+                if (oSettings.nTable.id != "hazelnut-" + self.options.plugin_uuid)
                     return true;
-                return hazelnut_filter.call(object, oSettings, aData, iDataIndex);
+                return this._hazelnut_filter.call(self, oSettings, aData, iDataIndex);
             });
 
             /* Processing hidden_columns */
-            $.each(options.hidden_columns, function(i, field) {
-                object.hide_column(field);
+            $.each(this.options.hidden_columns, function(i, field) {
+                self.hide_column(field);
             });
-        }
-
-        /* methods */
-
-// DEPRECATED //        this.set_query = function(query) {
-// DEPRECATED //            messages.info('hazelnut.set_query');
-// DEPRECATED //            var options = this.options;
-// DEPRECATED //            /* Compare current and advertised query to get added and removed fields */
-// DEPRECATED //            previous_query = this.current_query;
-// DEPRECATED //            /* Save the query as the current query */
-// DEPRECATED //            this.current_query = query;
-// DEPRECATED //            if (debug)
-// DEPRECATED //                messages.debug("hazelnut.set_query, current_query is now -> " + this.current_query);
-// DEPRECATED //
-// DEPRECATED //            /* We check all necessary fields : in column editor I presume XXX */
-// DEPRECATED //            // XXX ID naming has no plugin_uuid
-// DEPRECATED //            if (typeof(query.fields) != 'undefined') {        
-// DEPRECATED //                $.each (query.fields, function(index, value) { 
-// DEPRECATED //                    if (!$('#hazelnut-checkbox-' + options.plugin_uuid + "-" + value).attr('checked'))
-// DEPRECATED //                        $('#hazelnut-checkbox-' + options.plugin_uuid + "-" + value).attr('checked', true);
-// DEPRECATED //                });
-// DEPRECATED //            }
-// DEPRECATED //
-// DEPRECATED //            /* Process updates in filters / current_query must be updated before this call for filtering ! */
-// DEPRECATED //            this.table.fnDraw();
-// DEPRECATED //
-// DEPRECATED //            /*
-// DEPRECATED //             * Process updates in fields
-// DEPRECATED //             */
-// DEPRECATED //            if (typeof(query.fields) != 'undefined') {     
-// DEPRECATED //                /* DataTable Settings */
-// DEPRECATED //                var oSettings = this.table.dataTable().fnSettings();
-// DEPRECATED //                var cols = oSettings.aoColumns;
-// DEPRECATED //                var colnames = cols.map(function(x) {return x.sTitle});
-// DEPRECATED //                colnames = $.grep(colnames, function(value) {return value != "+/-";});
-// DEPRECATED //
-// DEPRECATED //                if (previous_query == null) {
-// DEPRECATED //                    var added_fields = query.fields;
-// DEPRECATED //                    var removed_fields = colnames;            
-// DEPRECATED //                    removed_fields = $.grep(colnames, function(x) { return $.inArray(x, added_fields) == -1});
-// DEPRECATED //                } else {
-// DEPRECATED //                    var tmp = previous_query.diff_fields(query);
-// DEPRECATED //                    var added_fields = tmp.added;
-// DEPRECATED //                    var removed_fields = tmp.removed;
-// DEPRECATED //                }
-// DEPRECATED //
-// DEPRECATED //                /* Hide/unhide columns to match added/removed fields */
-// DEPRECATED //                var object = this;
-// DEPRECATED //                $.each(added_fields, function (index, field) {            
-// DEPRECATED //                    var index = object.getColIndex(field,cols);
-// DEPRECATED //                    if(index != -1)
-// DEPRECATED //                        object.table.fnSetColumnVis(index, true);
-// DEPRECATED //                });
-// DEPRECATED //                $.each(removed_fields, function (index, field) {
-// DEPRECATED //                    var index = object.getColIndex(field,cols);
-// DEPRECATED //                    if(index != -1)
-// DEPRECATED //                        object.table.fnSetColumnVis(index, false);
-// DEPRECATED //                });            
-// DEPRECATED //            }
-// DEPRECATED //        }
-
-// DEPRECATED //        this.set_resources = function(resources, instance) {
-// DEPRECATED //            if (debug)
-// DEPRECATED //                messages.debug("entering hazelnut.set_resources");
-// DEPRECATED //            var options = this.options;
-// DEPRECATED //            var previous_resources = this.current_resources;
-// DEPRECATED //            this.current_resources = resources;
-// DEPRECATED //    
-// DEPRECATED //            /* We uncheck all checkboxes ... */
-// DEPRECATED //            $('hazelnut-checkbox-' + options.plugin_uuid).attr('checked', false);
-// DEPRECATED //            /* ... and check the ones specified in the resource list */
-// DEPRECATED //            $.each(this.current_resources, function(index, urn) {
-// DEPRECATED //                $('#hazelnut-checkbox-' + options.plugin_uuid + "-" + urn).attr('checked', true)
-// DEPRECATED //            });
-// DEPRECATED //            
-// DEPRECATED //        }
+        }, // initialize_table
 
         /**
          * @brief Determine index of key in the table columns 
          * @param key
          * @param cols
          */
-        this.getColIndex = function(key, cols) {
+        getColIndex: function(key, cols) {
             var tabIndex = $.map(cols, function(x, i) { if (x.sTitle == key) return i; });
             return (tabIndex.length > 0) ? tabIndex[0] : -1;
-        };
-    
-// DEPRECATED //        /**
-// DEPRECATED //         * @brief
-// DEPRECATED //         * XXX will be removed/replaced
-// DEPRECATED //         */
-// DEPRECATED //        this.selected_changed = function(e, change) {
-// DEPRECATED //        if (debug) messages.debug("entering hazelnut.selected_changed");
-// DEPRECATED //            var actions = change.split("/");
-// DEPRECATED //            if (actions.length > 1) {
-// DEPRECATED //                var oNodes = this.table.fnGetNodes();
-// DEPRECATED //                var myNode = $.grep(oNodes, function(value) {
-// DEPRECATED //                    if (value.id == actions[1]) { return value; }
-// DEPRECATED //                });                
-// DEPRECATED //                if( myNode.length>0 ) {
-// DEPRECATED //                    if ((actions[2]=="add" && actions[0]=="cancel") || actions[0]=="del")
-// DEPRECATED //                        checked='';
-// DEPRECATED //                    else
-// DEPRECATED //                        checked="checked='checked' ";
-// DEPRECATED //                    var newValue = this.checkbox(actions[1], 'node', checked, false);
-// DEPRECATED //                    var columnPos = this.table.fnSettings().aoColumns.length - 1;
-// DEPRECATED //                    this.table.fnUpdate(newValue, myNode[0], columnPos);
-// DEPRECATED //                    this.table.fnDraw();
-// DEPRECATED //                }
-// DEPRECATED //            }
-// DEPRECATED //        }
-    
-        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);
-
-            var options = this.options;
-            var hazelnut = this;
-    
-            /* if we get no result, or an error, try to make that clear, and exit */
-            if (rows.length==0) {
-                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') {
-                // 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;
-            }
-
-            /* 
-             * 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) {
-                // 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
-                // in order (we have temporarily hack some adjustments in names)
-                var cols = object.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 (options.checkboxes) nb_col -= 1;
-
-                /* fill in stuff depending on the column name */
-                for (var j = 0; j < nb_col; j++) {
-                    if (typeof colnames[j] == 'undefined') {
-                        line.push('...');
-                    } else if (colnames[j] == 'hostname') {
-                        if (row['type'] == 'resource,link')
-                            //TODO: we need to add source/destination for links
-                            line.push('');
-                        else
-                            line.push(row['hostname']);
-                    } else {
-                        if (row[colnames[j]])
-                            line.push(row[colnames[j]]);
-                        else
-                            line.push('');
-                    }
-                }
-    
-                /* catch up with the last column if checkboxes were requested */
-                if (options.checkboxes) {
-                    var checked = '';
-                    // 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[ELEMENT_KEY]);
-                    }
-                    // Use a key instead of hostname (hard coded...)
-                    line.push(hazelnut.checkbox(options.plugin_uuid, row[ELEMENT_KEY], row['type'], checked, false));
-                }
-    
-                lines.push(line);
-    
-            });
-    
-            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)
+        }, // getColIndex
+
+ // UNUSED ? //         this.update_plugin = function(e, rows) {
+ // UNUSED ? //             // e.data is what we passed in second argument to subscribe
+ // UNUSED ? //             // so here it is the jquery object attached to the plugin <div>
+ // UNUSED ? //             var $plugindiv=e.data;
+ // UNUSED ? //             if (debug)
+ // UNUSED ? //                 messages.debug("entering hazelnut.update_plugin on id '" + $plugindiv.attr('id') + "'");
+ // UNUSED ? //             // clear the spinning wheel: look up an ancestor that has the need-spin class
+ // UNUSED ? //             // do this before we might return
+ // UNUSED ? //             $plugindiv.closest('.need-spin').spin(false);
+ // UNUSED ? // 
+ // UNUSED ? //             var options = this.options;
+ // UNUSED ? //             var hazelnut = this;
+ // UNUSED ? //     
+ // UNUSED ? //             /* if we get no result, or an error, try to make that clear, and exit */
+ // UNUSED ? //             if (rows.length==0) {
+ // UNUSED ? //                 if (debug) 
+ // UNUSED ? //                     messages.debug("Empty result on hazelnut " + this.options.domid);
+ // UNUSED ? //                 var placeholder=$(this.table).find("td.dataTables_empty");
+ // UNUSED ? //                 console.log("placeholder "+placeholder);
+ // UNUSED ? //                 if (placeholder.length==1) 
+ // UNUSED ? //                     placeholder.html(unfold.warning("Empty result"));
+ // UNUSED ? //                 else
+ // UNUSED ? //                     this.table.html(unfold.warning("Empty result"));
+ // UNUSED ? //                     return;
+ // UNUSED ? //             } else if (typeof(rows[0].error) != 'undefined') {
+ // UNUSED ? //                 // we now should have another means to report errors that this inline/embedded hack
+ // UNUSED ? //                 if (debug) 
+ // UNUSED ? //                     messages.error ("undefined result on " + this.options.domid + " - should not happen anymore");
+ // UNUSED ? //                 this.table.html(unfold.error(rows[0].error));
+ // UNUSED ? //                 return;
+ // UNUSED ? //             }
+ // UNUSED ? // 
+ // UNUSED ? //             /* 
+ // UNUSED ? //              * fill the dataTables object
+ // UNUSED ? //              * we cannot set html content directly here, need to use fnAddData
+ // UNUSED ? //              */
+ // UNUSED ? //             var lines = new Array();
+ // UNUSED ? //     
+ // UNUSED ? //             this.current_resources = Array();
+ // UNUSED ? //     
+ // UNUSED ? //             $.each(rows, function(index, row) {
+ // UNUSED ? //                 // this models a line in dataTables, each element in the line describes a cell
+ // UNUSED ? //                 line = new Array();
+ // UNUSED ? //      
+ // UNUSED ? //                 // go through table headers to get column names we want
+ // UNUSED ? //                 // in order (we have temporarily hack some adjustments in names)
+ // UNUSED ? //                 var cols = object.table.fnSettings().aoColumns;
+ // UNUSED ? //                 var colnames = cols.map(function(x) {return x.sTitle})
+ // UNUSED ? //                 var nb_col = cols.length;
+ // UNUSED ? //                 /* if we've requested checkboxes, then forget about the checkbox column for now */
+ // UNUSED ? //                 if (options.checkboxes) nb_col -= 1;
+ // UNUSED ? // 
+ // UNUSED ? //                 /* fill in stuff depending on the column name */
+ // UNUSED ? //                 for (var j = 0; j < nb_col; j++) {
+ // UNUSED ? //                     if (typeof colnames[j] == 'undefined') {
+ // UNUSED ? //                         line.push('...');
+ // UNUSED ? //                     } else if (colnames[j] == 'hostname') {
+ // UNUSED ? //                         if (row['type'] == 'resource,link')
+ // UNUSED ? //                             //TODO: we need to add source/destination for links
+ // UNUSED ? //                             line.push('');
+ // UNUSED ? //                         else
+ // UNUSED ? //                             line.push(row['hostname']);
+ // UNUSED ? //                     } else {
+ // UNUSED ? //                         if (row[colnames[j]])
+ // UNUSED ? //                             line.push(row[colnames[j]]);
+ // UNUSED ? //                         else
+ // UNUSED ? //                             line.push('');
+ // UNUSED ? //                     }
+ // UNUSED ? //                 }
+ // UNUSED ? //     
+ // UNUSED ? //                 /* catch up with the last column if checkboxes were requested */
+ // UNUSED ? //                 if (options.checkboxes) {
+ // UNUSED ? //                     var checked = '';
+ // UNUSED ? //                     // xxx problem is, we don't get this 'sliver' thing set apparently
+ // UNUSED ? //                     if (typeof(row['sliver']) != 'undefined') { /* It is equal to null when <sliver/> is present */
+ // UNUSED ? //                         checked = 'checked ';
+ // UNUSED ? //                         hazelnut.current_resources.push(row[ELEMENT_KEY]);
+ // UNUSED ? //                     }
+ // UNUSED ? //                     // Use a key instead of hostname (hard coded...)
+ // UNUSED ? //                     line.push(hazelnut.checkbox(options.plugin_uuid, row[ELEMENT_KEY], row['type'], checked, false));
+ // UNUSED ? //                 }
+ // UNUSED ? //     
+ // UNUSED ? //                 lines.push(line);
+ // UNUSED ? //     
+ // UNUSED ? //             });
+ // UNUSED ? //     
+ // UNUSED ? //             this.table.fnClearTable();
+ // UNUSED ? //             if (debug)
+ // UNUSED ? //                 messages.debug("hazelnut.update_plugin: total of " + lines.length + " rows");
+ // UNUSED ? //             this.table.fnAddData(lines);
+ // UNUSED ? //         
+ // UNUSED ? //         }, // update_plugin
+
+        checkbox: function (plugin_uuid, header, field, selected_str, disabled_str)
         {
             var result="";
             if (header === null)
@@ -413,25 +238,21 @@ var ELEMENT_KEY = 'resource_hrn';
             result += " value='" + unfold.get_value(header) + "'";
             result += "></input>";
             return result;
-        };
-
-        ////////////////////////////////////////////////////////////////////////
-        // New plugin API (in tests)
+        }, // checkbox
 
-        // TODO : signal empty/non empty table
 
-        this.new_record = function(record)
+        new_record: function(record)
         {
             // 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
             // in order (we have temporarily hack some adjustments in names)
-            var cols = object.table.fnSettings().aoColumns;
+            var cols = this.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 (options.checkboxes) nb_col -= 1;
+            if (this.options.checkboxes) nb_col -= 1;
 
             /* fill in stuff depending on the column name */
             for (var j = 0; j < nb_col; j++) {
@@ -452,7 +273,7 @@ var ELEMENT_KEY = 'resource_hrn';
             }
     
             /* catch up with the last column if checkboxes were requested */
-            if (options.checkboxes) {
+            if (this.options.checkboxes) {
                 var checked = '';
                 // xxx problem is, we don't get this 'sliver' thing set apparently
                 if (typeof(record['sliver']) != 'undefined') { /* It is equal to null when <sliver/> is present */
@@ -460,270 +281,277 @@ var ELEMENT_KEY = 'resource_hrn';
                     hazelnut.current_resources.push(record[ELEMENT_KEY]);
                 }
                 // Use a key instead of hostname (hard coded...)
-                line.push(object.checkbox(options.plugin_uuid, record[ELEMENT_KEY], record['type'], checked, false));
+                line.push(this.checkbox(this.options.plugin_uuid, record[ELEMENT_KEY], record['type'], checked, false));
             }
     
             // XXX Is adding an array of lines more efficient ?
             this.table.fnAddData(line);
 
-        };
-
-        this.set_checkbox = function(record)
-        {
-            // XXX urn should be replaced by the key
-            // XXX we should enforce that both queries have the same key !!
-            checkbox_id = "#hazelnut-checkbox-" + object.options.plugin_uuid + "-" + unfold.escape_id(record[ELEMENT_KEY].replace(/\\/g, ''))
-            $(checkbox_id, object.table.fnGetNodes()).attr('checked', true);
-        }
+        },
 
-        this.record_handler = function(e, event_type, record)
+        clear_table: function()
         {
-            // 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.table.fnClearTable();
+        },
 
-        this.record_handler_all = function(e, event_type, record)
+        redraw_table: function()
         {
-            // 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.table.fnDraw();
+        },
 
-        this.show_column = function(field)
+        show_column: function(field)
         {
-            var oSettings = object.table.fnSettings();
+            var oSettings = this.table.fnSettings();
             var cols = oSettings.aoColumns;
-            var index = object.getColIndex(field,cols);
+            var index = this.getColIndex(field,cols);
             if (index != -1)
-                object.table.fnSetColumnVis(index, true);
-        }
+                this.table.fnSetColumnVis(index, true);
+        },
 
-        this.hide_column = function(field)
+        hide_column: function(field)
         {
-            var oSettings = object.table.fnSettings();
+            var oSettings = this.table.fnSettings();
             var cols = oSettings.aoColumns;
-            var index = object.getColIndex(field,cols);
+            var index = this.getColIndex(field,cols);
             if (index != -1)
-                object.table.fnSetColumnVis(index, false);
-        }
+                this.table.fnSetColumnVis(index, false);
+        },
 
-        this.query_handler = function(e, event_type, data)
+        set_checkbox: function(record)
         {
-            // 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:
-                    object.show_column(data);
-                    break;
-                case FIELD_REMOVED:
-                    object.hide_column(data);
-                    break;
-                case CLEAR_FIELDS:
-                    alert('Hazelnut::clear_fields() not implemented');
-                    break;
-            } // switch
-
-
-        }
-
-        // Constructor
-        object.initialize();
-
-    } // constructor
-
-    /***************************************************************************
-     * Private methods
-     * xxx I'm not sure why this should not be methods in the Hazelnut class above
-     ***************************************************************************/
-
-    /** 
-     * @brief Hazelnut filtering function
-     */
-    function hazelnut_filter (oSettings, aData, iDataIndex) {
-        var cur_query = this.current_query;
-        if (!cur_query) return true;
-        var ret = true;
-
-        /* We have an array of filters : a filter is an array (key op val) 
-         * field names (unless shortcut)    : oSettings.aoColumns  = [ sTitle ]
-         *     can we exploit the data property somewhere ?
-         * field values (unless formatting) : aData
-         *     formatting should leave original data available in a hidden field
-         *
-         * The current line should validate all filters
-         */
-        $.each (cur_query.filters, function(index, filter) { 
-            /* XXX How to manage checkbox ? */
-            var key = filter[0]; 
-            var op = filter[1];
-            var value = filter[2];
+            // XXX urn should be replaced by the key
+            // XXX we should enforce that both queries have the same key !!
+            checkbox_id = "#hazelnut-checkbox-" + this.options.plugin_uuid + "-" + unfold.escape_id(record[ELEMENT_KEY].replace(/\\/g, ''))
+            $(checkbox_id, this.table.fnGetNodes()).attr('checked', true);
+        },
 
-            /* Determine index of key in the table columns */
-            var col = $.map(oSettings.aoColumns, function(x, i) {if (x.sTitle == key) return i;})[0];
+        /*************************** QUERY HANDLER ****************************/
 
-            /* Unknown key: no filtering */
-            if (typeof(col) == 'undefined')
-                return;
+        on_filter_added: function(filter)
+        {
+            // XXX
+            this.redraw_table();
+        },
 
-            col_value=unfold.get_value(aData[col]);
-            /* Test whether current filter is compatible with the column */
-            if (op == '=' || op == '==') {
-                if ( col_value != value || col_value==null || col_value=="" || col_value=="n/a")
-                    ret = false;
-            }else if (op == '!=') {
-                if ( col_value == value || col_value==null || col_value=="" || col_value=="n/a")
-                    ret = false;
-            } else if(op=='<') {
-                if ( parseFloat(col_value) >= value || col_value==null || col_value=="" || col_value=="n/a")
-                    ret = false;
-            } else if(op=='>') {
-                if ( parseFloat(col_value) <= value || col_value==null || col_value=="" || col_value=="n/a")
-                    ret = false;
-            } else if(op=='<=' || op=='≤') {
-                if ( parseFloat(col_value) > value || col_value==null || col_value=="" || col_value=="n/a")
-                    ret = false;
-            } else if(op=='>=' || op=='≥') {
-                if ( parseFloat(col_value) < value || col_value==null || col_value=="" || col_value=="n/a")
-                    ret = false;
-            }else{
-                // How to break out of a loop ?
-                alert("filter not supported");
-                return false;
-            }
+        on_filter_removed: function(filter)
+        {
+            // XXX
+            this.redraw_table();
+        },
+        
+        on_filter_clear: function()
+        {
+            // XXX
+            this.redraw_table();
+        },
 
-        });
-        return ret;
-    }
+        on_field_added: function(field)
+        {
+            this.show_column(field);
+        },
 
-    function hazelnut_draw_callback() {
-        var options = this.options;
-        /* 
-         * Handle clicks on checkboxes: reassociate checkbox click every time
-         * the table is redrawn 
-         */
-        $('.hazelnut-checkbox-' + options.plugin_uuid).unbind('click');
-        $('.hazelnut-checkbox-' + options.plugin_uuid).click({instance: this}, check_click);
+        on_field_removed: function(field)
+        {
+            this.hide_column(field);
+        },
 
-        if (!this.table)
-            return;
+        on_field_clear: function()
+        {
+            alert('Hazelnut::clear_fields() not implemented');
+        },
 
-        /* Remove pagination if we show only a few results */
-        var wrapper = this.table; //.parent().parent().parent();
-        var rowsPerPage = this.table.fnSettings()._iDisplayLength;
-        var rowsToShow = this.table.fnSettings().fnRecordsDisplay();
-        var minRowsPerPage = this.table.fnSettings().aLengthMenu[0];
+        /* RECORD HANDLERS */
 
-        if ( rowsToShow <= rowsPerPage || rowsPerPage == -1 ) {
-            $('.hazelnut_paginate', wrapper).css('visibility', 'hidden');
-        } else {
-            $('.hazelnut_paginate', wrapper).css('visibility', 'visible');
-        }
+        on_new_record: function(record)
+        {
+            /* NOTE in fact we are doing a join here */
+            if (this.received_all)
+                // update checkbox for record
+                this.set_checkbox(record);
+            else
+                // store for later update of checkboxes
+                this.in_set_buffer.push(record);
+        },
+
+        on_clear_records: function()
+        {
+        },
 
-        if ( rowsToShow <= minRowsPerPage ) {
-            $('.hazelnut_length', wrapper).css('visibility', 'hidden');
-        } else {
-            $('.hazelnut_length', wrapper).css('visibility', 'visible');
-        }
-    }
+        // Could be the default in parent
+        on_query_in_progress: function()
+        {
+            this.spin();
+        },
 
-    function check_click (e) {
+        on_query_done: function()
+        {
+            if (this.received_all)
+                this.unspin();
+            this.received_set = true;
+        },
 
-        var object = e.data.instance;
+        // all
 
-        /* The key of the object to be added */
-        // XXX What about multiple keys ?
-        var value = this.value; 
+        on_all_new_record: function(record)
+        {
+            this.new_record(record);
+        },
 
-        // NEW PLUGIN API
-        manifold.raise_event(object.options.query_uuid, this.checked?SET_ADD:SET_REMOVED, value);
-        
-        // OLD PLUGIN API BELOW
-
-        if (this.checked) {
-            object.current_resources.push(value);
-        } else {
-            tmp = $.grep(object.current_resources, function(x) { return x != value; });
-            object.current_resources = tmp;
-        }
-
-        /* inform slice that our selected resources have changed */
-        $.publish('/update-set/' + object.options.query_uuid, [object.current_resources, true]);
-
-    }
-
-    function selectAll() {
-        // requires jQuery id
-        var uuid=this.id.split("-");
-        var oTable=$("#hazelnut-"+uuid[1]).dataTable();
-        // Function available in Hazelnut 1.9.x
-        // Filter : displayed data only
-        var filterData = oTable._('tr', {"filter":"applied"});   
-        /* TODO: WARNING if too many nodes selected, use filters to reduce nuber of nodes */        
-        if(filterData.length<=100){
-            $.each(filterData, function(index, obj) {
-                var last=$(obj).last();
-                var key_value=unfold.get_value(last[0]);
-                if(typeof($(last[0]).attr('checked'))=="undefined"){
-                    $.publish('selected', 'add/'+key_value);
+        on_all_clear_records: function()
+        {
+            this.clear_table();
+
+        },
+
+        on_all_query_in_progress: function()
+        {
+            // XXX parent
+            this.spin();
+        }, // on_all_query_in_progress
+
+        on_all_query_done: function()
+        {
+            var self = this;
+            if (this.received_set) {
+                /* XXX needed ? XXX We uncheck all checkboxes ... */
+                $("[id^='datatables-checkbox-" + this.options.plugin_uuid +"']").attr('checked', false);
+
+                /* ... and check the ones specified in the resource list */
+                $.each(this.in_set_buffer, function(i, record) {
+                    self.set_checkbox(record);
+                });
+
+                this.unspin();
+            }
+            this.received_all = true;
+
+        }, // on_all_query_done
+
+        /************************** PRIVATE METHODS ***************************/
+
+        /** 
+         * @brief Hazelnut filtering function
+         */
+        _hazelnut_filter: function(oSettings, aData, iDataIndex)
+        {
+            var cur_query = this.current_query;
+            if (!cur_query) return true;
+            var ret = true;
+
+            /* We have an array of filters : a filter is an array (key op val) 
+             * field names (unless shortcut)    : oSettings.aoColumns  = [ sTitle ]
+             *     can we exploit the data property somewhere ?
+             * field values (unless formatting) : aData
+             *     formatting should leave original data available in a hidden field
+             *
+             * The current line should validate all filters
+             */
+            $.each (cur_query.filters, function(index, filter) { 
+                /* XXX How to manage checkbox ? */
+                var key = filter[0]; 
+                var op = filter[1];
+                var value = filter[2];
+
+                /* Determine index of key in the table columns */
+                var col = $.map(oSettings.aoColumns, function(x, i) {if (x.sTitle == key) return i;})[0];
+
+                /* Unknown key: no filtering */
+                if (typeof(col) == 'undefined')
+                    return;
+
+                col_value=unfold.get_value(aData[col]);
+                /* Test whether current filter is compatible with the column */
+                if (op == '=' || op == '==') {
+                    if ( col_value != value || col_value==null || col_value=="" || col_value=="n/a")
+                        ret = false;
+                }else if (op == '!=') {
+                    if ( col_value == value || col_value==null || col_value=="" || col_value=="n/a")
+                        ret = false;
+                } else if(op=='<') {
+                    if ( parseFloat(col_value) >= value || col_value==null || col_value=="" || col_value=="n/a")
+                        ret = false;
+                } else if(op=='>') {
+                    if ( parseFloat(col_value) <= value || col_value==null || col_value=="" || col_value=="n/a")
+                        ret = false;
+                } else if(op=='<=' || op=='≤') {
+                    if ( parseFloat(col_value) > value || col_value==null || col_value=="" || col_value=="n/a")
+                        ret = false;
+                } else if(op=='>=' || op=='≥') {
+                    if ( parseFloat(col_value) < value || col_value==null || col_value=="" || col_value=="n/a")
+                        ret = false;
+                }else{
+                    // How to break out of a loop ?
+                    alert("filter not supported");
+                    return false;
                 }
+
             });
-        }
-    }
-    
-})( jQuery );
+            return ret;
+        },
+
+        _hazelnut_draw_callback: function()
+        {
+            /* 
+             * Handle clicks on checkboxes: reassociate checkbox click every time
+             * the table is redrawn 
+             */
+            $('.hazelnut-checkbox-' + this.options.plugin_uuid).unbind('click');
+            $('.hazelnut-checkbox-' + this.options.plugin_uuid).click({instance: this}, this._check_click);
+
+            if (!this.table)
+                return;
+
+            /* Remove pagination if we show only a few results */
+            var wrapper = this.table; //.parent().parent().parent();
+            var rowsPerPage = this.table.fnSettings()._iDisplayLength;
+            var rowsToShow = this.table.fnSettings().fnRecordsDisplay();
+            var minRowsPerPage = this.table.fnSettings().aLengthMenu[0];
+
+            if ( rowsToShow <= rowsPerPage || rowsPerPage == -1 ) {
+                $('.hazelnut_paginate', wrapper).css('visibility', 'hidden');
+            } else {
+                $('.hazelnut_paginate', wrapper).css('visibility', 'visible');
+            }
+
+            if ( rowsToShow <= minRowsPerPage ) {
+                $('.hazelnut_length', wrapper).css('visibility', 'hidden');
+            } else {
+                $('.hazelnut_length', wrapper).css('visibility', 'visible');
+            }
+        },
+
+        _check_click: function(e) 
+        {
+
+            var self = e.data.instance;
+
+            // XXX this.value = key of object to be added... what about multiple keys ?
+            manifold.raise_event(self.options.query_uuid, this.checked?SET_ADD:SET_REMOVED, this.value);
+            
+        },
+
+        _selectAll: function() 
+        {
+            // requires jQuery id
+            var uuid=this.id.split("-");
+            var oTable=$("#hazelnut-"+uuid[1]).dataTable();
+            // Function available in Hazelnut 1.9.x
+            // Filter : displayed data only
+            var filterData = oTable._('tr', {"filter":"applied"});   
+            /* TODO: WARNING if too many nodes selected, use filters to reduce nuber of nodes */        
+            if(filterData.length<=100){
+                $.each(filterData, function(index, obj) {
+                    var last=$(obj).last();
+                    var key_value=unfold.get_value(last[0]);
+                    if(typeof($(last[0]).attr('checked'))=="undefined"){
+                        $.publish('selected', 'add/'+key_value);
+                    }
+                });
+            }
+        },
+
+    });
+
+    $.plugin('Hazelnut', Hazelnut);
+
+})(jQuery);
index fee1e4b..1801115 100644 (file)
 
     var MyPlugin = Plugin.extend({
 
-        // Constructor
+        /** XXX to check
+         * @brief Plugin constructor
+         * @param options : an associative array of setting values
+         * @param element : 
+         * @return : a jQuery collection of objects on which the plugin is
+         *     applied, which allows to maintain chainability of calls
+         */
         init: function(options, element) {
             // Call the parent constructor, see FAQ when forgotten
             this._super(options, element);
 
+            /* Member variables */
+
+            /* Plugin events */
+
+            /* Setup query and record handlers */
+
             // Explain this will allow query events to be handled
             // What happens when we don't define some events ?
             // Some can be less efficient
             this.listen_query(options.query_uuid);
             this.listen_query(options.query_uuid, 'all');
 
-            // GUI Event binding
+            /* GUI setup and event binding */
             // call function
 
         },
 
+        /* PLUGIN EVENTS */
+        // on_show like in hazelnut
+
+
         /* GUI EVENTS */
 
-        // a function to bind events here
+        // a function to bind events here: click change
         // how to raise manifold events
 
+
         /* GUI MANIPULATION */
 
         // We advise you to write function to change behaviour of the GUI
             //
         },
 
+        /* INTERNAL FUNCTIONS */
+        _dummy: function() {
+            // only convention, not strictly enforced at the moment
+        },
+
     });
 
+    /* Plugin registration */
+    $.plugin('MyPlugin', MyPlugin);
+
     // TODO Here use cases for instanciating plugins in different ways like in the pastie.
 
 })(jQuery);
index 6d60220..b165d6a 100644 (file)
@@ -1,28 +1,27 @@
 # Create your views here.
 
-from django.core.context_processors import csrf
-from django.template import RequestContext
-from django.template.loader import render_to_string
-from django.shortcuts import render_to_response
+from django.core.context_processors     import csrf
+from django.template                    import RequestContext
+from django.template.loader             import render_to_string
+from django.shortcuts                   import render_to_response
 
-from django.contrib.auth.decorators import login_required
+from django.contrib.auth.decorators     import login_required
 
-from unfold.page import Page
-#from manifold.manifoldquery import ManifoldQuery
-from manifold.core.query import Query
+from unfold.page                        import Page
+from manifold.core.query                import Query
 
-from plugins.stack.stack import Stack
-from plugins.tabs.tabs import Tabs
-from plugins.lists.staticlist import StaticList
-from plugins.quickfilter.quickfilter import QuickFilter
-from plugins.querycode.querycode import QueryCode
-from plugins.raw.raw import Raw
-from plugins.messages.messages import Messages
-from plugins.hazelnut.hazelnut import Hazelnut
-from plugins.updater.updater import Updater
+from plugins.stack.stack                import Stack
+from plugins.tabs.tabs                  import Tabs
+from plugins.lists.staticlist           import StaticList
+from plugins.quickfilter.quickfilter    import QuickFilter
+from plugins.querycode.querycode        import QueryCode
+from plugins.raw.raw                    import Raw
+from plugins.messages.messages          import Messages
+from plugins.hazelnut                   import Hazelnut
+from plugins.updater.updater            import Updater
 
-from myslice.viewutils import topmenu_items, the_user
-from myslice.viewutils import hard_wired_slice_names, hard_wired_list, lorem_p, lorem, quickfilter_criterias
+from myslice.viewutils                  import topmenu_items, the_user
+from myslice.viewutils                  import hard_wired_slice_names, hard_wired_list, lorem_p, lorem, quickfilter_criterias
 
 @login_required
 def test_plugin_view (request):
index a0790c0..f1591c8 100644 (file)
@@ -15,9 +15,9 @@ 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.hazelnut                import Hazelnut 
 from plugins.resources_selected      import ResourcesSelected
-from plugins.googlemap.googlemap     import GoogleMap 
+from plugins.googlemaps              import GoogleMaps
 from plugins.senslabmap.senslabmap   import SensLabMap
 from plugins.querycode.querycode     import QueryCode
 from plugins.query_editor            import QueryEditor
@@ -163,7 +163,7 @@ def _slice_view (request, slicename):
         },
     ))
 
-    tab_resource_plugins.insert(GoogleMap(
+    tab_resource_plugins.insert(GoogleMaps(
         page       = page,
         title      = 'Geographic view',
         domid      = 'gmap',