X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=plugins%2Fquerytable%2Fstatic%2Fjs%2Fquerytable.js;h=7ddf300d75e3fe8e0e839b7c9ef1e925c00e4f90;hb=261afa50a6fade31685a23b104ab919bebaf25ef;hp=3731f7a9a761cca13cd08b587ee03e11d72b8bdf;hpb=6eb1d8c9d03d2b10b514c317b6fff11172097346;p=unfold.git diff --git a/plugins/querytable/static/js/querytable.js b/plugins/querytable/static/js/querytable.js index 3731f7a9..7ddf300d 100644 --- a/plugins/querytable/static/js/querytable.js +++ b/plugins/querytable/static/js/querytable.js @@ -4,67 +4,62 @@ * License: GPLv3 */ -BGCOLOR_RESET = 0; -BGCOLOR_ADDED = 1; -BGCOLOR_REMOVED = 2; +QUERYTABLE_BGCOLOR_RESET = 0; +QUERYTABLE_BGCOLOR_ADDED = 1; +QUERYTABLE_BGCOLOR_REMOVED = 2; (function($){ + + var QUERYTABLE_MAP = { + 'Facility': 'facility_name', + 'Testbed': 'testbed_name', + 'Resource name': 'hostname', + 'Type': 'type', + }; + var debug=false; // debug=true var QueryTable = Plugin.extend({ init: function(options, element) { - this.classname="querytable"; + this.classname="querytable"; this._super(options, element); /* Member variables */ - // in general we expect 2 queries here - // query_uuid refers to a single object (typically a slice) - // query_all_uuid refers to a list (typically resources or users) - // these can return in any order so we keep track of which has been received yet - this.received_all_query = false; - this.received_query = false; - - // We need to remember the active filter for datatables filtering - this.filters = Array(); - - // an internal buffer for records that are 'in' and thus need to be checked - this.buffered_records_to_check = []; - // an internal buffer for keeping lines and display them in one call to fnAddData - this.buffered_lines = []; + var query = manifold.query_store.find_analyzed_query(this.options.query_uuid); + this.object = query.object; // XXX /* Events */ - // xx somehow non of these triggers at all for now this.elmt().on('show', this, this.on_show); this.elmt().on('shown.bs.tab', this, this.on_show); this.elmt().on('resize', this, this.on_resize); - var query = manifold.query_store.find_analyzed_query(this.options.query_uuid); - this.object = query.object; - - //// we need 2 different keys - // * canonical_key is the primary key as derived from metadata (typically: urn) - // and is used to communicate about a given record with the other plugins - // * init_key is a key that both kinds of records - // (i.e. records returned by both queries) must have (typically: hrn or hostname) - // in general query_all will return well populated records, but query - // returns records with only the fields displayed on startup - var keys = manifold.metadata.get_key(this.object); - this.canonical_key = (keys && keys.length == 1) ? keys[0] : undefined; - // - this.init_key = this.options.init_key; - // have init_key default to canonical_key - this.init_key = this.init_key || this.canonical_key; - // sanity check - if ( ! this.init_key ) messages.warning ("QueryTable : cannot find init_key"); - if ( ! this.canonical_key ) messages.warning ("QueryTable : cannot find canonical_key"); - if (debug) messages.debug("querytable: canonical_key="+this.canonical_key+" init_key="+this.init_key); + //// we need 2 different keys + // * canonical_key is the primary key as derived from metadata (typically: urn) + // and is used to communicate about a given record with the other plugins + // * init_key is a key that both kinds of records + // (i.e. records returned by both queries) must have (typically: hrn or hostname) + // in general query_all will return well populated records, but query + // returns records with only the fields displayed on startup + var keys = manifold.metadata.get_key(this.object); + this.canonical_key = (keys && keys.length == 1) ? keys[0] : undefined; + // + this.init_key = this.options.init_key; + // have init_key default to canonical_key + this.init_key = this.init_key || this.canonical_key; + + /* sanity check */ + if ( ! this.init_key ) + messages.warning ("QueryTable : cannot find init_key"); + if ( ! this.canonical_key ) + messages.warning ("QueryTable : cannot find canonical_key"); + if (debug) + messages.debug("querytable: canonical_key="+this.canonical_key+" init_key="+this.init_key); /* 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_table(); @@ -73,16 +68,16 @@ BGCOLOR_REMOVED = 2; /* PLUGIN EVENTS */ on_show: function(e) { - if (debug) messages.debug("querytable.on_show"); + if (debug) messages.debug("querytable.on_show"); var self = e.data; self.table.fnAdjustColumnSizing(); - }, + }, on_resize: function(e) { - if (debug) messages.debug("querytable.on_resize"); + if (debug) messages.debug("querytable.on_resize"); var self = e.data; self.table.fnAdjustColumnSizing(); - }, + }, /* GUI EVENTS */ @@ -97,13 +92,13 @@ BGCOLOR_REMOVED = 2; // we use a fluid row on top and another on the bottom, making sure we take 12 grid elt's each time //sDom: "<'row'<'col-xs-5'l><'col-xs-1'r><'col-xs-6'f>>t<'row'<'col-xs-5'i><'col-xs-7'p>>", sDom: "<'row'<'col-xs-5'f><'col-xs-1'r><'col-xs-6 columns_selector'>>t<'row'<'col-xs-5'l><'col-xs-7'p>>", - // XXX as of sept. 2013, I cannot locate a bootstrap3-friendly mode for now - // hopefully this would come with dataTables v1.10 ? - // in any case, search for 'sPaginationType' all over the code for more comments + // XXX as of sept. 2013, I cannot locate a bootstrap3-friendly mode for now + // hopefully this would come with dataTables v1.10 ? + // in any case, search for 'sPaginationType' all over the code for more comments sPaginationType: 'bootstrap', // Handle the null values & the error : Datatables warning Requested unknown parameter // http://datatables.net/forums/discussion/5331/datatables-warning-...-requested-unknown-parameter/p2 - aoColumnDefs: [{sDefaultContent: '',aTargets: [ '_all' ]}], + aoColumnDefs: [{sDefaultContent: '', aTargets: [ '_all' ]}], // WARNING: this one causes tables in a 'tabs' that are not exposed at the time this is run to show up empty // sScrollX: '100%', /* Horizontal scrolling */ bProcessing: true, /* Loading */ @@ -115,7 +110,7 @@ BGCOLOR_REMOVED = 2; var key = self.canonical_key; // Get the index of the key in the columns - var cols = self.table.fnSettings().aoColumns; + var cols = self._get_columns(); var index = self.getColIndex(key, cols); if (index != -1) { // The key is found in the table, set the TR id after the data @@ -128,16 +123,16 @@ BGCOLOR_REMOVED = 2; // 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 - // xxx turned back on by Thierry - this is the code that takes python-provided options into account - // check your datatables_options tag instead - // however, we have to accumulate in aoColumnDefs from here (above) - // and from the python wrapper (checkboxes management, plus any user-provided aoColumnDefs) - if ( 'aoColumnDefs' in this.options.datatables_options) { - actual_options['aoColumnDefs']=this.options.datatables_options['aoColumnDefs'].concat(actual_options['aoColumnDefs']); - delete this.options.datatables_options['aoColumnDefs']; - } - $.extend(actual_options, this.options.datatables_options ); + // xxx DISABLED by jordan: was causing errors in datatables.js + // xxx turned back on by Thierry - this is the code that takes python-provided options into account + // check your datatables_options tag instead + // however, we have to accumulate in aoColumnDefs from here (above) + // and from the python wrapper (checkboxes management, plus any user-provided aoColumnDefs) + if ( 'aoColumnDefs' in this.options.datatables_options) { + actual_options['aoColumnDefs']=this.options.datatables_options['aoColumnDefs'].concat(actual_options['aoColumnDefs']); + delete this.options.datatables_options['aoColumnDefs']; + } + $.extend(actual_options, this.options.datatables_options ); this.table = this.elmt('table').dataTable(actual_options); /* Setup the SelectAll button in the dataTable header */ @@ -164,7 +159,6 @@ BGCOLOR_REMOVED = 2; /* Processing hidden_columns */ $.each(this.options.hidden_columns, function(i, field) { - //manifold.raise_event(self.options.query_all_uuid, FIELD_REMOVED, field); self.hide_column(field); }); $(".dataTables_filter").append("
"); @@ -177,29 +171,30 @@ BGCOLOR_REMOVED = 2; * @param cols */ getColIndex: function(key, cols) { - var tabIndex = $.map(cols, function(x, i) { if (x.sTitle == key) return i; }); + var self = this; + var tabIndex = $.map(cols, function(x, i) { if (self._get_map(x.sTitle) == key) return i; }); return (tabIndex.length > 0) ? tabIndex[0] : -1; }, // getColIndex - // create a checkbox tag - // computes 'id' attribute from canonical_key - // computes 'init_id' from init_key for initialization phase - // no need to used convoluted ids with plugin-uuid or others, since - // we search using table.$ which looks only in this table + // create a checkbox tag + // computes 'id' attribute from canonical_key + // computes 'init_id' from init_key for initialization phase + // no need to used convoluted ids with plugin-uuid or others, since + // we search using table.$ which looks only in this table checkbox_html : function (record) { var result=""; // Prefix id with plugin_uuid result += "'); // STATUS + /* fill in stuff depending on the column name */ - for (var j = 1; j < nb_col - 1; j++) { // nb_col includes status + for (var j = 2; j < nb_col - 1; j++) { // nb_col includes status if (typeof colnames[j] == 'undefined') { line.push('...'); } else if (colnames[j] == 'hostname') { @@ -258,11 +256,10 @@ BGCOLOR_REMOVED = 2; line.push(''); } } - line.push(''); // STATUS - // adding an array in one call is *much* more efficient - // this.table.fnAddData(line); - return line; + // adding an array in one call is *much* more efficient + // this.table.fnAddData(line); + return line; }, clear_table: function() @@ -293,30 +290,24 @@ BGCOLOR_REMOVED = 2; this.table.fnSetColumnVis(index, false); }, - // this is used at init-time, at which point only init_key can make sense - // (because the argument record, if it comes from query, might not have canonical_key set - set_checkbox_from_record: function (record, checked) { - if (checked === undefined) checked = true; - var init_id = record[this.init_key]; - this.set_checkbox_from_record_key(init_id, checked); - }, - - set_checkbox_from_record_key: function (record_key, checked) { - if (checked === undefined) checked = true; - if (debug) messages.debug("querytable.set_checkbox_from_record, record_key="+record_key); - // using table.$ to search inside elements that are not visible - var element = this.table.$('[init_id="'+record_key+'"]'); - element.attr('checked',checked); - }, - - // id relates to canonical_key - set_checkbox_from_data: function (id, checked) { + set_checkbox_from_record_key: function (record_key, checked) + { + if (checked === undefined) checked = true; + + // using table.$ to search inside elements that are not visible + var element = this.table.$('[init_id="'+record_key+'"]'); + element.attr('checked',checked); + }, + + // id relates to canonical_key + set_checkbox_from_data: function (id, checked) + { if (checked === undefined) checked = true; - if (debug) messages.debug("querytable.set_checkbox_from_data, id="+id); - // using table.$ to search inside elements that are not visible - var element = this.table.$("[id='"+id+"']"); - element.attr('checked',checked); - }, + + // using table.$ to search inside elements that are not visible + var element = this.table.$("[id='"+id+"']"); + element.attr('checked',checked); + }, /** * Arguments @@ -365,29 +356,25 @@ BGCOLOR_REMOVED = 2; set_bgcolor: function(key_value, class_name) { var elt = $(document.getElementById(this.id_from_key(this.canonical_key, key_value))) - if (class_name == BGCOLOR_RESET) + if (class_name == QUERYTABLE_BGCOLOR_RESET) elt.removeClass('added removed'); else - elt.addClass((class_name == BGCOLOR_ADDED ? 'added' : 'removed')); + elt.addClass((class_name == QUERYTABLE_BGCOLOR_ADDED ? 'added' : 'removed')); }, - do_filter: function() + populate_table: function() { // Let's clear the table and only add lines that are visible var self = this; this.clear_table(); - // XXX Here we have lost checkboxes - // set checkbox from record. - // only the current plugin known that we have an element in a set - lines = Array(); var record_keys = []; - manifold.query_store.iter_visible_records(this.options.query_uuid, function (record_key, record) { + manifold.query_store.iter_records(this.options.query_uuid, function (record_key, record) { lines.push(self.new_record(record)); record_keys.push(record_key); }); - this.table.fnAddData(lines); + this.table.fnAddData(lines); $.each(record_keys, function(i, record_key) { var state = manifold.query_store.get_record_state(self.options.query_uuid, record_key, STATE_SET); var warnings = manifold.query_store.get_record_state(self.options.query_uuid, record_key, STATE_WARNINGS); @@ -405,11 +392,11 @@ BGCOLOR_REMOVED = 2; break; case STATE_SET_IN_PENDING: self.set_checkbox_from_record_key(record_key, true); - self.set_bgcolor(record_key, BGCOLOR_ADDED); + self.set_bgcolor(record_key, QUERYTABLE_BGCOLOR_ADDED); break; case STATE_SET_OUT_PENDING: //self.set_checkbox_from_record_key(record_key, false); - self.set_bgcolor(record_key, BGCOLOR_REMOVED); + self.set_bgcolor(record_key, QUERYTABLE_BGCOLOR_REMOVED); break; } self.change_status(record_key, warnings); // XXX will retrieve status again @@ -420,29 +407,17 @@ BGCOLOR_REMOVED = 2; on_filter_added: function(filter) { - this.do_filter(); - - /* - this.filters.push(filter); this.redraw_table(); - */ }, on_filter_removed: function(filter) { - this.do_filter(); - /* - // Remove corresponding filters - this.filters = $.grep(this.filters, function(x) { - return x == filter; - }); this.redraw_table(); - */ }, on_filter_clear: function() { - this.do_filter(); + this.redraw_table(); }, on_field_added: function(field) @@ -460,56 +435,8 @@ BGCOLOR_REMOVED = 2; alert('QueryTable::clear_fields() not implemented'); }, - /* XXX TODO: make this generic a plugin has to subscribe to a set of Queries to avoid duplicated code ! */ - /*************************** ALL QUERY HANDLER ****************************/ - - on_all_filter_added: function(filter) - { - this.do_filter(); - }, - - on_all_filter_removed: function(filter) - { - this.do_filter(); - }, - - on_all_filter_clear: function() - { - this.do_filter(); - }, - - on_all_field_added: function(field) - { - this.show_column(field); - }, - - on_all_field_removed: function(field) - { - this.hide_column(field); - }, - - on_all_field_clear: function() - { - alert('QueryTable::clear_fields() not implemented'); - }, - - /*************************** RECORD HANDLER ***************************/ - on_new_record: function(record) - { - if (this.received_all_query) { - // if the 'all' query has been dealt with already we may turn on the checkbox - this.set_checkbox_from_record(record, true); - } else { - this.buffered_records_to_check.push(record); - } - }, - - on_clear_records: function() - { - }, - // Could be the default in parent on_query_in_progress: function() { @@ -518,107 +445,81 @@ BGCOLOR_REMOVED = 2; on_query_done: function() { - this.do_filter(); -/* - this.received_query = true; - // unspin once we have received both - if (this.received_all_query && this.received_query) this.unspin(); -*/ + this.populate_table(); + this.unspin(); }, on_field_state_changed: function(data) { - var state = manifold.query_store.get_record_state(this.options.query_uuid, data.value, data.status); - switch(data.status) { + // XXX We could get this from data.value + // var state = manifold.query_store.get_record_state(this.options.query_uuid, data.value, data.state); + + switch(data.state) { case STATE_SET: - switch(state) { + switch(data.op) { case STATE_SET_IN: case STATE_SET_IN_SUCCESS: case STATE_SET_OUT_FAILURE: this.set_checkbox_from_data(data.value, true); - this.set_bgcolor(data.value, BGCOLOR_RESET); + this.set_bgcolor(data.value, QUERYTABLE_BGCOLOR_RESET); break; case STATE_SET_OUT: case STATE_SET_OUT_SUCCESS: case STATE_SET_IN_FAILURE: this.set_checkbox_from_data(data.value, false); - this.set_bgcolor(data.value, BGCOLOR_RESET); + this.set_bgcolor(data.value, QUERYTABLE_BGCOLOR_RESET); break; case STATE_SET_IN_PENDING: - this.set_checkbox_from_data(data.value, true); - this.set_bgcolor(data.value, BGCOLOR_ADDED); + this.set_checkbox_from_data(data.key, true); + this.set_bgcolor(data.value, QUERYTABLE_BGCOLOR_ADDED); break; case STATE_SET_OUT_PENDING: - this.set_checkbox_from_data(data.value, false); - this.set_bgcolor(data.value, BGCOLOR_REMOVED); + this.set_checkbox_from_data(data.key, false); + this.set_bgcolor(data.value, QUERYTABLE_BGCOLOR_REMOVED); break; } break; case STATE_WARNINGS: - this.change_status(data.value, state); + this.change_status(data.key, data.value); break; } }, /************************** PRIVATE METHODS ***************************/ + _get_columns: function() + { + return this.table.fnSettings().aoColumns; + // XXX return $.map(table.fnSettings().aoColumns, function(x, i) { return QUERYTABLE_MAP[x]; }); + }, + + _get_map: function(column_title) { + return (column_title in QUERYTABLE_MAP) ? QUERYTABLE_MAP[column_title] : column_title; + }, /** - * @brief QueryTable filtering function + * @brief QueryTable filtering function, called for every line in the datatable. + * + * Return value: + * boolean determining whether the column is visible or not. */ _querytable_filter: function(oSettings, aData, iDataIndex) { - var ret = true; - $.each (this.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 == 'included') { - $.each(value, function(i,x) { - if(x == col_value){ - ret = true; - return false; - }else{ - 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; - } + var self = this; + var key_col, record_key_value; - }); - return ret; + /* Determine index of key in the table columns */ + key_col = $.map(oSettings.aoColumns, function(x, i) {if (self._get_map(x.sTitle) == self.canonical_key) return i;})[0]; + + /* Unknown key: no filtering */ + if (typeof(key_col) == 'undefined') { + console.log("Unknown key"); + return true; + } + + record_key_value = unfold.get_value(aData[key_col]); + + return manifold.query_store.get_record_state(this.options.query_uuid, record_key_value, STATE_VISIBLE); }, _querytable_draw_callback: function() @@ -653,14 +554,18 @@ BGCOLOR_REMOVED = 2; _check_click: function(e) { - e.stopPropagation(); - + var data; var self = e.data; - var id=this.id; - // this.id = key of object to be added... what about multiple keys ? - if (debug) messages.debug("querytable._check_click key="+this.canonical_key+"->"+id+" checked="+this.checked); - manifold.raise_event(self.options.query_uuid, this.checked?SET_ADD:SET_REMOVED, id); + e.stopPropagation(); + + data = { + state: STATE_SET, + key : null, + op : this.checked ? STATE_SET_ADD : STATE_SET_REMOVE, + value: this.id + } + manifold.raise_event(self.options.query_uuid, FIELD_STATE_CHANGED, data); //return false; // prevent checkbox to be checked, waiting response from manifold plugin api }, @@ -695,9 +600,9 @@ BGCOLOR_REMOVED = 2; was in fact given as a third argument, and not second as the various online resources had it - go figure */ $.fn.dataTableExt.afnSortData['dom-checkbox'] = function ( oSettings, _, iColumn ) { - return $.map( oSettings.oApi._fnGetTrNodes(oSettings), function (tr, i) { - return result=$('td:eq('+iColumn+') input', tr).prop('checked') ? '1' : '0'; - }); + return $.map( oSettings.oApi._fnGetTrNodes(oSettings), function (tr, i) { + return result=$('td:eq('+iColumn+') input', tr).prop('checked') ? '1' : '0'; + }); }; })(jQuery);