manifold: fix in plugin.js
[myslice.git] / plugins / query_editor / query_editor.js
index 7514b4a..9f130f9 100644 (file)
  * License: GPLv3
  */
 
-/*
- * It's a best practice to pass jQuery to an IIFE (Immediately Invoked Function
- * Expression) that maps it to the dollar sign so it can't be overwritten by
- * another library in the scope of its execution.
- */
-
+// XXX TODO This plugin will be interested in changes in metadata
+// What if we remove a filter, is it removed in the right min/max field ???
+//  -> no on_filter_removed is not yet implemented
+// XXX if a plugin has not declared a handler, it might become inconsistent,
+// and the interface should either reset or disable it
 (function($){
 
-    var PLUGIN_NAME = 'QueryEditor';
-
-    // routing calls
-    jQuery.fn.QueryEditor = 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 QueryEditor(options);
-                $this.data('Manifold', plugin);
-
-                $this.set_query_handler(options.query_uuid, plugin.query_handler);
-                $this.set_record_handler(options.query_uuid, plugin.record_handler); 
-
-            }); // 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');
+    var QueryEditor = Plugin.extend({
+
+        event_filter_added: function(op, suffix) {
+            suffix = (typeof suffix === 'undefined') ? '' : manifold.separator + suffix;
+            var self = this;
+            return function(e) {
+                var array = self.array_from_id(e.target.id);
+                var key   = self.field_from_id(array); // No need to remove suffix...
+                var value = e.target.value;
+
+                if (value) {
+                    // XXX This should be handled by manifold
+                    //manifold.raise_event(object.options.query_uuid, FILTER_UPDATED, [key, op, value]);
+                    manifold.raise_event(self.options.query_uuid, FILTER_ADDED, [key, op, value]);
+                } else {
+                    // XXX This should be handled by manifold
+                    manifold.raise_event(self.options.query_uuid, FILTER_REMOVED, [key, op]);
+                }
+            }
+        },
 
-                // Unbind all events using namespacing
-                $(window).unbind(PLUGIN_NAME);
+        init: function(options, element) {
+            this._super(options, element);
 
-                // Remove associated data
-                hazelnut.remove();
-                $this.removeData('Manifold');
+            this.listen_query(options.query_uuid);
 
-                $this.set_query_handler(options.query_uuid, hazelnut.query_handler);
-                $this.set_record_handler(options.query_uuid, hazelnut.record_handler); 
+            this.els('queryeditor-auto-filter').change(this.event_filter_added('='));
+            this.els('queryeditor-filter').change(this.event_filter_added('='));
+            this.els('queryeditor-filter-min').change(this.event_filter_added('>'));
+            this.els('queryeditor-filter-max').change(this.event_filter_added('<'));
 
-                /* XXX Subscribe to query updates to maintain current state of query (multiple editors) */
-                jQuery.subscribe('/query/' + options.query_uuid + '/changed', {instance: $this}, query_changed);
-                jQuery.subscribe('/query/' + options.query_uuid + '/diff', {instance: $this}, query_changed_diff);
-                /* Subscribe to results in order to redraw the table when updates arrive */
-                jQuery.subscribe('/results/' + options.query_uuid + '/changed', {instance: $this}, update_autocomplete);
+            var self = this;
+            this.els('queryeditor-check').click(function() { 
+                manifold.raise_event(self.options.query_uuid, this.checked?FIELD_ADDED:FIELD_REMOVED, this.value);
+            });
 
+            /* The following code adds an expandable column for the table */
+            // XXX Why isn't it done statically ?
+            var nCloneTh = document.createElement( 'th' );
+            var nCloneTd = document.createElement( 'td' );
+            nCloneTd.innerHTML = "<span class='ui-icon ui-icon-triangle-1-e' style='cursor:pointer'></span>";
+            //nCloneTd.innerHTML = '<img src="/components/com_tophat/images/details_open.png">';
+            nCloneTh.innerHTML = '<b>Info</b>';
+            nCloneTd.className = "center";
+            nCloneTh.className = "center";
+            // XXX
+            jQuery('#'+this.options.plugin_uuid+'_fields thead tr').each( function () {
+                this.insertBefore( nCloneTh, this.childNodes[0] );
+            });
+            // XXX
+            jQuery('#'+this.options.plugin_uuid+'_fields tbody tr').each( function () {
+                this.insertBefore(  nCloneTd.cloneNode( true ), this.childNodes[0] );
+            });
+         
+            // We are currently using a DataTable display, but another browsing component could be better
+            //jQuery('#'+this.options.plugin_uuid+'-table').dataTable...
+            var  metaTable = this.el('table').dataTable({
+                bFilter     : false,
+                bPaginate   : false,
+                bInfo       : false,
+                sScrollX    : '100%',         // Horizontal scrolling
+                sScrollY    : '200px',
+                bJQueryUI   : true,           // Use jQuery UI
+                bProcessing : true,           // Loading
+                aaSorting   : [[ 1, "asc" ]], // sort by column fields on load
+                aoColumnDefs: [
+                    { 'bSortable': false, 'aTargets': [ 0 ]},
+                    { 'sWidth': '8px', 'aTargets': [ 0 ] },
+                    { 'sWidth': '8px', 'aTargets': [ 4 ] } // XXX NB OF COLS
+                ]
             });
-        }, // destroy
 
-    }; // var methods;
+            var self = this;
+            // Actions on the newly added fields
+            this.el('table tbody td span').on('click', function() {
+                var nTr = this.parentNode.parentNode;
+                // use jQuery UI instead of images to keep a common UI
+                // class="ui-icon treeclick ui-icon-triangle-1-s tree-minus"
+                // East oriented Triangle class="ui-icon-triangle-1-e"
+                // South oriented Triangle class="ui-icon-triangle-1-s"
+                
+                if (this.className=="ui-icon ui-icon-triangle-1-e") {
+                    this.removeClass("ui-icon-triangle-1-e").addClass("ui-icon-triangle-1-s");
+                    // XXX ??????
+                    metaTable.fnOpen(nTr, this.fnFormatDetails(metaTable, nTr, self.options.plugin_uuid+'_div'), 'details' );
+                } else {
+                    this.removeClass("ui-icon-triangle-1-s").addClass("ui-icon-triangle-1-e");
+                    metaTable.fnClose(nTr);
+                }
+            });
 
-    /***************************************************************************
-     * Plugin object
-     ***************************************************************************/
+            this.el('table_wrapper').css({
+                'padding-top'   : '0em',
+                'padding-bottom': '0em'
+            });
 
-    function QueryEditor(options)
-    {
+        }, // init
 
-        /* member variables */
-        this.options = options;
+        /* UI management */
 
-        var object = this;
+        check_field: function(field)
+        {
+            this.el('check', field).attr('checked', true);
+        },
 
-        this.initialize_table = function(data) 
+        uncheck_field: function(field)
         {
+            this.el('check', field).attr('checked', false);
+        },
 
-            var d = data;
-            
-            jQuery('.queryeditor-filter').change(function(event) { 
-                query = data.current_query;
-                var key=getKeySplitId(event.target.id,"-");
-                var op='=';
-                var value=event.target.value;
-                            
-                if(value){                
-                    query.update_filter(key, op, value);
-                    //add_ActiveFilter(event.target.id, '=',event.target.value,data);
-                }else{
-                    query.remove_filter(key,op,"");
-                    //remove_ActiveFilter(event, data, event.target.id,'=');
-                }
-                // Publish the query changed, the other plugins with subscribe will get the changes
-                jQuery.publish('/query/' + query.uuid + '/changed', query);
-            });
-            jQuery('.queryeditor-filter-min').change(function(event) {
-                query = data.current_query;
-                var key=getKeySplitId(event.target.id,"-");
-                var op='>';
-                var value=event.target.value;
-                
-                if(value){
-                    query.update_filter(key, op, value);
-                    //add_ActiveFilter(event.target.id,'>',event.target.value,data);
-                }else{
-                    query.remove_filter(key,op,"");
-                    //remove_ActiveFilter(event, data, event.target.id,'>');
-                }
-                // Publish the query changed, the other plugins with subscribe will get the changes
-                jQuery.publish('/query/' + query.uuid + '/changed', query);
-            });
-            jQuery('.queryeditor-filter-max').change(function(event) {
-                query = data.current_query;
-                var key=getKeySplitId(event.target.id,"-");
-                var op='<';
-                var value=event.target.value;
-                
-                if(value){
-                    query.update_filter(key, op, value);
-                    //add_ActiveFilter(event.target.id,'<',event.target.value,data);
-                }else{
-                    query.remove_filter(key,op,"");
-                    //remove_ActiveFilter(event, data, event.target.id,'<');
+        update_filter_value: function(filter, removed)
+        {
+            removed = !(typeof removed === 'undefined'); // default = False
+
+            var key   = filter[0];
+            var op    = filter[1];
+            var value = filter[2];
+
+            var id = this.id_from_field(key);
+
+            if (op == '=') {
+                var element = this.el(id);
+            } else {
+                var suffix;
+                if (op == '<') {
+                    this.el(id, 'max').val(value);
+                } else if (op == '>') {
+                    this.el(id, 'min').val(value);
+                } else {
+                    return;
                 }
-                // Publish the query changed, the other plugins with subscribe will get the changes
-                jQuery.publish('/query/' + query.uuid + '/changed', query);
-            });
+                var element = this.el(id, suffix);
+            }
 
-            jQuery('.queryeditor-check').click(function() { 
-                manifold.raise_event(object.options.query_uuid, this.checked?FIELD_ADDED:FIELD_REMOVED, this.value);
-                /*
-                    var column = this.id.substring(6);
-                    query = data.current_query;
-                    if (this.checked) {
-                        if (jQuery.inArray(column, query.fields) == -1) {
-                            query.fields.push(column);
-                            jQuery.publish('/query/' + query.uuid + '/changed', query);
-                        }
-                    } else {
-                        query.fields = jQuery.grep(query.fields, function(value) {return value != column;});
-                        jQuery.publish('/query/' + query.uuid + '/changed', query);
-                    }
-                */
-                });
+            element.val(removed?null:value);
 
-            //onFunctionAvailable('jQuery.fn.dataTable', function() {
+        },
 
-                var nCloneTh = document.createElement( 'th' );
-                var nCloneTd = document.createElement( 'td' );
-                nCloneTd.innerHTML = "<span class='ui-icon ui-icon-triangle-1-e' style='cursor:pointer'></span>";
-                //nCloneTd.innerHTML = '<img src="/components/com_tophat/images/details_open.png">';
-                nCloneTh.innerHTML = '<b>Info</b>';
-                nCloneTd.className = "center";
-                nCloneTh.className = "center";
-         
-                jQuery('#'+this.options.plugin_uuid+'_fields thead tr').each( function () {
-                    this.insertBefore( nCloneTh, this.childNodes[0] );
-                });
-         
-                jQuery('#'+this.options.plugin_uuid+'_fields tbody tr').each( function () {
-                    this.insertBefore(  nCloneTd.cloneNode( true ), this.childNodes[0] );
-                });
-         
-                var  metaTable = jQuery('#'+this.options.plugin_uuid+'-table').dataTable( {
-                    bFilter: false,
-                    bPaginate: false,
-                    bInfo: false,
-                    sScrollX: '100%',       /* Horizontal scrolling */
-                    sScrollY: "200px",
-                    bJQueryUI: true, // Use jQuery UI
-                    bProcessing: true, // Loading
-                    aaSorting: [[ 1, "asc" ]], // sort by column fields on load
-                    aoColumnDefs: [ {"bSortable": false, "aTargets": [ 0 ]},
-                                      { "sWidth": "8px", "aTargets": [ 0 ] },
-                                      { "sWidth": "8px", "aTargets": [ 4 ] }
-                    ]
-                });
+        /* Events */
 
-                jQuery('#'+this.options.plugin_uuid+'_fields tbody td span').live('click', function () {
-                    var nTr = this.parentNode.parentNode;
-                    // use jQuery UI instead of images to keep a common UI
-                    // class="ui-icon treeclick ui-icon-triangle-1-s tree-minus"
-                    //East oriented Triangle class="ui-icon-triangle-1-e"
-                    //South oriented Triangle class="ui-icon-triangle-1-s"
-                    
-                    if(this.className=="ui-icon ui-icon-triangle-1-e"){
-                        this.removeClass("ui-icon-triangle-1-e");
-                        this.addClass("ui-icon-triangle-1-s");
-                        metaTable.fnOpen( nTr, this.fnFormatDetails(metaTable, nTr, this.options.plugin_uuid+'_div'), 'details' );
-                    }else{
-                        this.removeClass("ui-icon-triangle-1-s");
-                        this.addClass("ui-icon-triangle-1-e");
-                        metaTable.fnClose( nTr );
-                    }
-                    /*
-                    if ( this.src.match('details_close') ) {
-                        this.src = "/components/com_tophat/images/details_open.png";
-                        metaTable.fnClose( nTr );
-                    }
-                    else {
-                        this.src = "/components/com_tophat/images/details_close.png";
-                        metaTable.fnOpen( nTr, this.fnFormatDetails(metaTable, nTr, this.options.plugin_uuid+'_div'), 'details' );
-                    }
-                    */
-                });
+        on_filter_added: function(filter)
+        {
+            this.update_filter_value(filter);
+        },
+
+        on_filter_removed: function(filter)
+        {
+            this.update_filter_value(filter, true);
+        },
 
-                jQuery('#'+this.options.plugin_uuid+'_fields_wrapper').css({'padding-top':'0em','padding-bottom':'0em'});
+        on_field_added: function(field)
+        {
+            this.check_field(field);
+        },
 
-            //}); // onfunctionAvailable
+        on_field_removed: function(field)
+        {
+            this.uncheck_field(field);
+        },
 
-        } // initialize_table
+        /* Former code */
 
-        this.print_field_description = function(field_header, div_id) { 
-            
+        print_field_description: function(field_header, div_id) 
+        { 
             //var selected = all_headers[field_header];
             var selected = getMetadata_field('resource',field_header);
 
             output += "</div>";
 
             return output;
-        }
+        },
 
-        this.update_autocomplete = function(e, rows, current_query)
+        update_autocomplete: function(e, rows, current_query)
         {
             var d = data;
             d.current_query = current_query;
                             }
                 });
             });                
-        } // update_autocomplete     
+        }, // update_autocomplete     
 
-        /**
-         * This function is used to update autocomplete
-         */
-        this.record_handler = function(e, event_type, record)
+        fnFormatDetails: function( metaTable, nTr, div_id ) 
         {
-            // elements in set
-            switch(event_type) {
-                case NEW_RECORD:
-                    break;
-                case CLEAR_RECORDS:
-                    break;
-                case IN_PROGRESS:
-                    break;
-                case DONE:
-                    break;
-            }
-        };
-
-        this.query_handler = function(e, event_type, data)
-        {
-            // This replaces the complex set_query function
-            // The plugin does not need to remember the query anymore
-            switch(event_type) {
-                // Filters
-                // When Query changed, Then we need to update the filters of
-                // QueryEditor plugin if the filter is active, set the value
-                // (the update can come from another plugin) else set the
-                // filter value to null PB if the filter is composed of MIN/MAX
-                // values
-                case FILTER_ADDED:
-                    filter = data;
-                    // Set the value of the filter = to query filter value
-                    // Necessary if the filter has been modified by another plugin (QuickFilter)
-                    if(filter[1]=="="){
-                        jQuery('#'+this.options.plugin_uuid+'-filter-'+filter[0]).val(filter[2]);
-                    }else if(filter[1]=="<"){
-                        jQuery('#'+this.options.plugin_uuid+'-filter-'+filter[0]+'-max').val(filter[2]);
-                    }else if(filter[1]==">"){
-                        jQuery('#'+this.options.plugin_uuid+'-filter-'+filter[0]+'-min').val(filter[2]);
-                    }
-                case FILTER_REMOVED:
-                    filter = data;
-                    if(filter[1]=="="){
-                        jQuery('#'+this.options.plugin_uuid+'-filter-'+filter[0]).val(null);
-                    }else if(filter[1]=="<"){
-                        //502124d5a5848-filter-asn-max
-                        jQuery('#'+this.options.plugin_uuid+'-filter-'+filter[0]+'-max').val(null);
-                    }else if(filter[1]==">"){
-                        //502124d5a5848-filter-asn-min
-                        jQuery('#'+this.options.plugin_uuid+'-filter-'+filter[0]+'-min').val(null);
-                    }
-                case CLEAR_FILTERS:
-                    break;
-
-                // Fields
-                /* Hide/unhide columns to match added/removed fields */
-                // XXX WRONG IDENTIFIERS
-                case FIELD_ADDED:
-                    object.check(data);
-                    break;
-                case FIELD_REMOVED:
-                    object.uncheck(data);
-                    break;
-                case CLEAR_FIELDS:
-                    alert(PLUGIN_NAME + '::clear_fields() not implemented');
-                    break;
-            } // switch
-
-
-        }
-        this.check = function(field)
-        {
-            $('#check_' + field).attr('checked', true);
-        }
-        this.uncheck = function(field)
-        {
-            $('#check_' + field).attr('checked', false);
-        }
-        this.fnFormatDetails  = function( metaTable, nTr, div_id ) {
             var aData = metaTable.fnGetData( nTr );
             var sOut = '<blockquote>';
             //sOut += prepare_tab_description(aData[1].substr(21, aData[1].length-21-7), div_id);
          
             return sOut;
         }
-       
-            
-        /**
-         *
-         */
-        this.initialize = function() {
-            //XXX
-            this.initialize_table(jQuery(this).data());
-        }
-        /* Constructor */
-
-        this.initialize();
+    });
 
-    } // function PresView
+    $.plugin('QueryEditor', QueryEditor);
 
-})( jQuery );
+})(jQuery);