* init_key, expected to be provided by caller, specifies a key that can be used at init-time (shoud be present in both queries)
* canonical_key is rderived from metadata
this.in_set_backlog = [];
// we keep a couple of global hashes
- // lat_lon --> { marker, <ul> }
- // id --> { <li>, <input> }
- this.by_lat_lon = {};
- this.by_id = {};
+ // lat_lon --> { marker, <ul> }
+ // id --> { <li>, <input> }
+ this.by_lat_lon = {};
+ // locating checkboxes by DOM selectors might be abstruse, as we cannot safely assume
+ // all the items will belong under the toplevel <div>
+ this.by_id = {};
+ this.by_init_id = {};
/* XXX Events */
this.elmt().on('show', this, this.on_show);
var query = manifold.query_store.find_analyzed_query(this.options.query_uuid);
this.object = query.object;
- // var keys = manifold.metadata.get_key(this.object);
+ // see querytable.js for an explanation
+ var keys = manifold.metadata.get_key(this.object);
+ this.canonical_key = (keys && keys.length == 1) ? keys[0] : undefined;
//
- // this.key = (keys && keys.length == 1) ? keys[0] : null;
-
- // xxx temporary hack
- // as of nov. 28 2013 we have here this.key='urn', but in any place where
- // the code tries to access record[this.key] the records only have
- // keys=type,hrn,network_hrn,hostname
- // so for now we force using hrn instead
- // as soon as record have their primary key set this line can be removed
- // see also same hack in querytable
- //this.key= (this.key == 'urn') ? 'hrn' : this.key;
- this.key = (this.options.id_key);
- if (typeof(this.key)=='undefined' || (this.key).startsWith("unknown")) {
- // if not specified by caller, decide from metadata
- var keys = manifold.metadata.get_key(this.object);
- this.key = (keys && keys.length == 1) ? keys[0] : null;
- }
+ 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("googlemap: canonical_key="+this.canonical_key+" init_key="+this.init_key);
//// Setup query and record handlers
// this query is the one about the slice itself
this.infowindow = new google.maps.InfoWindow();
}, // initialize_map
- // The function accepts both records and their id
- // record.key points to the name of the primary key for this record
- // typically this is 'urn'
- record_id : function (input) {
- var id;
- switch (manifold.get_type(input)) {
- case TYPE_VALUE:
- id = input;
- break;
- case TYPE_RECORD:
- if ( ! this.key in input ) return;
- id = input[this.key];
- break;
- default:
- throw "googlemap.record_id: not implemented";
- break;
- }
- return id;
- },
-
// return { marker: gmap_marker, ul : <ul DOM> }
create_marker_struct: function (object,lat,lon) {
// the DOM fragment
// returns the created <input> element for further checkbox manipulation
create_record_checkbox: function (record,ul,checked) {
var checkbox = $("<input>", {type:'checkbox', checked:checked, class:'geo'});
- var id=this.record_id(record);
- // use hrn as far as possible for displaying
- // var label= ('hrn' in record) ? record.hrn : id;
- var label= (this.key in record) ? record[this.key] : id;
+ var id=record[this.canonical_key];
+ var init_id=record[this.init_key];
+ // xxx use init_key to find out label - or should we explicitly accept an incoming label_key ?
+ var label=init_id;
ul.append($("<li>").addClass("geo").append(checkbox).
append($("<span>").addClass("geo").append(label)));
- var googlemap=this;
+ // hash by id and by init_id
+ this.by_id[id]=checkbox;
+ this.by_init_id[init_id] = checkbox;
+ //
// the callback for when a user clicks
// NOTE: this will *not* be called for changes done by program
+ var self=this;
checkbox.change( function (e) {
- manifold.raise_event (googlemap.options.query_uuid, this.checked ? SET_ADD : SET_REMOVED, id);
+ manifold.raise_event (self.options.query_uuid, this.checked ? SET_ADD : SET_REMOVED, id);
});
return checkbox;
},
},
// retrieve DOM checkbox and make sure it is checked/unchecked
- set_checkbox: function(record, checked) {
- var id=this.record_id (record);
- if (! id) {
- this.warning (record, "googlemap.set_checkbox: record has no id");
- return;
- }
+ set_checkbox_from_record: function(record, checked) {
+ var init_id=record[this.init_key];
+ var checkbox = this.by_id [ init_id ];
+ checkbox.prop('checked',checked);
+ },
+
+ set_checkbox_from_data: function(id, checked) {
+ var id=record[this.canonical_key];
var checkbox = this.by_id [ id ];
- if (! checkbox ) {
- this.warning (record, "googlemap.set_checkbox: checkbox not found");
- return;
- }
checkbox.prop('checked',checked);
- }, // set_checkbox
+ },
// this record is *in* the slice
new_record: function(record) {
// this is where the checkbox will be appended
var ul=marker_s.ul;
var checkbox = this.create_record_checkbox (record, ul, false);
- var id=this.record_id(record);
- // used to keep a dict here, but only checkbox is required
- this.by_id[id] = checkbox;
}, // new_record
arm_marker: function(marker, map) {
if (debug_deep) messages.debug("on_new_record");
if (this.received_all)
// update checkbox for record
- this.set_checkbox(record, true);
+ this.set_checkbox_from_record(record, true);
else
// store for later update of checkboxes
this.in_set_backlog.push(record);
switch(data.request) {
case FIELD_REQUEST_ADD:
case FIELD_REQUEST_ADD_RESET:
- this.set_checkbox(data.value, true);
+ this.set_checkbox_from_data(data.value, true);
break;
case FIELD_REQUEST_REMOVE:
case FIELD_REQUEST_REMOVE_RESET:
- this.set_checkbox(data.value, false);
+ this.set_checkbox_from_data(data.value, false);
break;
default:
break;
if (this.received_set) {
/* ... and check the ones specified in the resource list */
$.each(this.in_set_backlog, function(i, record) {
- googlemap.set_checkbox(record, true);
+ googlemap.set_checkbox_from_record(record, true);
});
// reset
googlemap.in_set_backlog = [];
* License: GPLv3
*/
+/*
+ * WARNINGS
+ *
+ * This is very rough for now and not deemed working
+ *
+ * Also it still requires adaptation for the init_key / init_id / canonical_key / id business
+ * if the basic logic was to become usable
+ *
+ * WARNINGS
+ */
+
/* ongoing adaptation to slickgrid
still missing are
. checkboxes really running properly
with checkboxes is desired
* optionally pass columns as the initial set of columns
if None then this is taken from the query's fields
-* id_key is the name of a column used internally in the plugin
- for checkboxes management. Caller should specify a column that is present
- in the fields returned by 'query' and that has unique values.
+* init_key is the name of a column that should appear in both queries
+ and used internally in the plugin for checkboxes initialization.
If not specified, metadata will be used to find out a primary key.
However in the case of nodes & slice for example, the default key
- as returned by the metadata would be 'urn', but it is not necessarily
- a good idea to show urn's initially - if at all.
+ as returned by the metadata would be 'urn', but 'urn' could only
+ be used for this purpose if it gets displayed initially, which is
+ not necessarily a good idea.
This is why a slice view would use 'hrn' here instead.
* datatables_options are passed to dataTables as-is;
however please refrain from passing an 'aoColumns'
def __init__ (self, query=None, query_all=None,
checkboxes=False, columns=None,
- id_key=None,
+ init_key=None,
datatables_options={}, **settings):
Plugin.__init__ (self, **settings)
self.query = query
else:
self.columns = []
self.hidden_columns = []
- self.id_key=id_key
+ self.init_key=init_key
self.datatables_options=datatables_options
# if checkboxes were required, we tell datatables about this column's type
# so that sorting can take place on a selected-first basis (or -last of course)
return ['plugin_uuid', 'domid',
'query_uuid', 'query_all_uuid',
'checkboxes', 'datatables_options',
- 'hidden_columns', 'id_key',]
+ 'hidden_columns', 'init_key',]
(function($){
var debug=false;
-// debug=true
+ debug=true
var QueryTable = Plugin.extend({
var query = manifold.query_store.find_analyzed_query(this.options.query_uuid);
this.object = query.object;
- // xxx beware that this.key needs to contain a key that all records will have
- // in general query_all will return well populated records, but query
- // returns records with only the fields displayed on startup.
- this.key = (this.options.id_key);
- if (typeof(this.key)=='undefined' || (this.key).startsWith("unknown")) {
- // if not specified by caller, decide from metadata
- var keys = manifold.metadata.get_key(this.object);
- this.key = (keys && keys.length == 1) ? keys[0] : null;
- }
- if (! this.key) messages.warning("querytable.init could not kind valid key");
- messages.debug("querytable: key="+this.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);
return (tabIndex.length > 0) ? tabIndex[0] : -1;
}, // getColIndex
- checkbox_html : function (key, value)
- {
-// if (debug) messages.debug("checkbox_html, value="+value);
+ // create a checkbox <input> tag
+ // computes 'id' attribute from canonical_key (using flat_id)
+ // computes 'common_id' from init_key for initialization phase
+ checkbox_html : function (record) {
var result="";
// Prefix id with plugin_uuid
result += "<input";
result += " class='querytable-checkbox'";
- result += " id='" + this.flat_id(this.id('checkbox', value)) + "'";
- result += " name='" + key + "'";
+ // compute id from canonical_key
+ var id = record[this.canonical_key]
+ // normalize using flat_id - see plugin.js
+ id = this.flat_id(id)
+// if (debug) messages.debug("checkbox_html, id="+id);
+ result += " id='" + id + "'";
+ // compute common_id too
+ var common_id=record[this.init_key];
+ common_id=this.flat_id(common_id);
+ // wrap up
+ result += "common_id='" + common_id + "'";
+ // set value for posting events upon user's clicks
+ result += " value='"+record[this.canonical_key]+"'";
result += " type='checkbox'";
result += " autocomplete='off'";
- if (value === undefined) {
- messages.warning("querytable.checkbox_html - undefined value");
- } else {
- result += " value='" + value + "'";
- }
result += "></input>";
return result;
},
// catch up with the last column if checkboxes were requested
if (this.options.checkboxes) {
// Use a key instead of hostname (hard coded...)
- line.push(this.checkbox_html(this.key, record[this.key]));
+ line.push(this.checkbox_html(record));
}
// adding an array in one call is *much* more efficient
this.table.fnSetColumnVis(index, false);
},
- set_checkbox: function(record, checked)
- {
- /* Default: checked = true */
+ // 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 id;
- /* The function accepts both records and their key */
- switch (manifold.get_type(record)) {
- case TYPE_VALUE:
- id = record;
- break;
- case TYPE_RECORD:
- /* XXX Test the key before ? */
- id = record[this.key];
- break;
- default:
- throw "Not implemented";
- break;
- }
-
-
- if (id === undefined) {
- messages.warning("querytable.set_checkbox record has no id to figure which line to tick");
- return;
- }
- // PB TO CHECK THE RIGHT CHECKBOXES IS HERE... flat_id using \ in the key
- // need to use escape_id when creating the id of the checkboxes
- var checkbox_id = this.flat_id(this.id('checkbox', id));
- // function escape_id(myid) is defined in portal/static/js/common.functions.js
- checkbox_id = escape_id(checkbox_id);
- // As we are using [id="x"] syntax, we need to remove the # in the checkbox_id
- checkbox_id = checkbox_id.replace("#","");
- // using dataTables's $ to search also in nodes that are not currently displayed
- var element = this.table.$('[id="' + checkbox_id + '"]');
- if (debug)
- messages.debug("set_checkbox checked=" + checked
- + " id=" + checkbox_id + " matches=" + element.length);
- element.attr('checked', checked);
- },
+ var common_id = this.flat_id(record[this.init_key]);
+ if (debug) messages.debug("set_checkbox_from_record, common_id="+common_id);
+ var element = this.table.$('[common_id="'+common_id+'"]');
+ element.attr('checked',checked);
+ },
+
+ // id relates to canonical_key
+ set_checkbox_from_data: function (id, checked) {
+ if (checked === undefined) checked = true;
+ var id=this.flat_id(id);
+ if (debug) messages.debug("set_checkbox_from_data, id="+id);
+ var element = this.table.$('#'+id);
+ element.attr('checked',checked);
+ },
/*************************** QUERY HANDLER ****************************/
{
if (this.received_all_query) {
// if the 'all' query has been dealt with already we may turn on the checkbox
- this.set_checkbox(record, true);
+ this.set_checkbox_from_record(record, true);
} else {
// otherwise we need to remember that and do it later on
- if (debug) messages.debug("Remembering record to check " + record[this.key]);
+ if (debug) messages.debug("Remembering record to check " + record[this.init_key]);
this.buffered_records_to_check.push(record);
}
},
switch(data.request) {
case FIELD_REQUEST_ADD:
case FIELD_REQUEST_ADD_RESET:
- this.set_checkbox(data.value, true);
+ this.set_checkbox_from_data(data.value, true);
break;
case FIELD_REQUEST_REMOVE:
case FIELD_REQUEST_REMOVE_RESET:
- this.set_checkbox(data.value, false);
+ this.set_checkbox_from_data(data.value, false);
break;
default:
break;
switch(data.request) {
case FIELD_REQUEST_ADD:
case FIELD_REQUEST_ADD_RESET:
- this.set_checkbox(data.value, true);
+ this.set_checkboxfrom_data(data.value, true);
break;
case FIELD_REQUEST_REMOVE:
case FIELD_REQUEST_REMOVE_RESET:
- this.set_checkbox(data.value, false);
+ this.set_checkbox_from_data(data.value, false);
break;
default:
break;
// checkboxes on the fly at that time (dom not yet created)
$.each(this.buffered_records_to_check, function(i, record) {
if (debug) messages.debug ("delayed turning on checkbox " + i + " record= " + record);
- self.set_checkbox(record, true);
+ self.set_checkbox_from_record(record, true);
});
this.buffered_records_to_check = [];
var self = e.data;
// XXX this.value = key of object to be added... what about multiple keys ?
- if (debug) messages.debug("querytable click handler checked=" + this.checked + " "+this.key+"=" + this.value);
+ if (debug) messages.debug("querytable click handler checked=" + this.checked + " "+this.canonical_key+"=" + this.value);
manifold.raise_event(self.options.query_uuid, this.checked?SET_ADD:SET_REMOVED, this.value);
//return false; // prevent checkbox to be checked, waiting response from manifold plugin api
main_query = Query.get('slice').filter_by('slice_hrn', '=', slicename)
main_query.select(
'slice_hrn',
- 'resource.hrn', 'resource.urn', 'resource.hostname', 'resource.type',
+ #'resource.hrn', 'resource.urn',
+ 'resource.hostname', 'resource.type',
'resource.network_hrn',
'lease.urn',
'user.user_hrn',
)
# for internal use in the querytable plugin;
# needs to be a unique column present for each returned record
- #main_query_key = 'hrn'
+ main_query_init_key = 'hostname'
query_resource_all = Query.get('resource').select(resource_fields)
if do_query_users:
togglable = False,
query = sq_resource,
query_all = query_resource_all,
+ # this key is the one issued by google
googlemap_api_key = Config().googlemap_api_key(),
+ # the key to use at init-time
+ init_key = main_query_init_key,
checkboxes = True,
# center on Paris
latitude = 49.,
# this is the query at the core of the slice list
query = sq_resource,
query_all = query_resource_all,
- # safer to use 'hrn' as the internal unique key for this plugin
- #id_key = main_query_key,
+ # use 'hrn' as the internal unique key for this plugin
+ init_key = main_query_init_key,
checkboxes = True,
datatables_options = {
'iDisplayLength': 25,
# this is the query at the core of the slice list
query = sq_resource,
query_all = query_resource_all,
- # safer to use 'hrn' as the internal unique key for this plugin
- id_key = main_query_key,
+ # use 'hrn' as the internal unique key for this plugin
+ # xxx todo on querygrid as well
+ # init_key = main_query_init_key,
checkboxes = True,
)
if insert_grid:
resources_sons.append(resources_as_grid)
- print 40*'+-',"resources_sons has",len(resources_sons),"son"
-
resources_area = Tabs ( page=page,
domid="resources",
togglable=True,
main_query = Query.get('slice').filter_by('slice_hrn', '=', slicename)
main_query.select(
'slice_hrn',
- 'resource.hrn', 'resource.hostname', 'resource.type',
+ #'resource.hrn',
+ 'resource.hostname', 'resource.type',
'resource.network_hrn',
'lease.urn',
'user.user_hrn',
)
# for internal use in the querygrid plugin;
# needs to be a unique column present for each returned record
- main_query_key = 'hrn'
+ main_query_init_key = 'hostname'
query_resource_all = Query.get('resource').select(resource_fields)
query = sq_resource,
query_all = query_resource_all,
# safer to use 'hrn' as the internal unique key for this plugin
- id_key = main_query_key,
+ id_key = main_query_init_key,
checkboxes = True,
datatables_options = {
'iDisplayLength': 25,
main_query = Query.get('slice').filter_by('slice_hrn', '=', slicename)
main_query.select(
'slice_hrn',
- 'resource.hrn', 'resource.hostname', 'resource.type',
+ 'resource.hostname', 'resource.type',
'resource.network_hrn',
'lease.urn',
'user.user_hrn',
)
# for internal use in the querytable plugin;
# needs to be a unique column present for each returned record
- main_query_key = 'hrn'
+ main_query_init_key = 'hostname'
query_resource_all = Query.get('resource').select(resource_fields)
query = sq_resource,
query_all = query_resource_all,
# safer to use 'hrn' as the internal unique key for this plugin
- common_key = main_query_key,
+ init_key = main_query_init_key,
checkboxes = True,
datatables_options = {
'iDisplayLength': 25,