2 * Description: QueryEditor plugin
3 * Copyright (c) 2012-2013 UPMC Sorbonne Universite
7 // XXX TODO This plugin will be interested in changes in metadata
8 // What if we remove a filter, is it removed in the right min/max field ???
9 // -> no on_filter_removed is not yet implemented
10 // XXX if a plugin has not declared a handler, it might become inconsistent,
11 // and the interface should either reset or disable it
14 var QueryEditor = Plugin.extend({
16 event_filter_added: function(op, suffix) {
17 suffix = (typeof suffix === 'undefined') ? '' : manifold.separator + suffix;
19 return function(e, ui) {
20 var array = self.array_from_id(e.target.id);
21 var key = self.field_from_id(array); // No need to remove suffix...
23 // using autocomplete ui
24 if(typeof(ui) != "undefined"){
25 var value = ui.item.value;
27 var value = e.target.value;
31 // XXX This should be handled by manifold
32 //manifold.raise_event(object.options.query_uuid, FILTER_UPDATED, [key, op, value]);
33 manifold.raise_event(self.options.query_uuid, FILTER_ADDED, [key, op, value]);
35 // XXX This should be handled by manifold
36 manifold.raise_event(self.options.query_uuid, FILTER_REMOVED, [key, op]);
41 init: function(options, element) {
42 this._super(options, element);
43 console.log("init Query_Editor");
44 this.listen_query(options.query_uuid);
46 this.elts('queryeditor-auto-filter').change(this.event_filter_added('='));
47 this.elts('queryeditor-filter').change(this.event_filter_added('='));
48 this.elts('queryeditor-filter-min').change(this.event_filter_added('>'));
49 this.elts('queryeditor-filter-max').change(this.event_filter_added('<'));
52 this.elts('queryeditor-check').click(function() {
53 manifold.raise_event(self.options.query_uuid, this.checked?FIELD_ADDED:FIELD_REMOVED, this.value);
56 /* The following code adds an expandable column for the table
57 // XXX Why isn't it done statically ?
58 var nCloneTh = document.createElement( 'th' );
59 var nCloneTd = document.createElement( 'td' );
60 nCloneTd.innerHTML = "<span class='ui-icon ui-icon-triangle-1-e' style='cursor:pointer'></span>";
61 //nCloneTd.innerHTML = '<img src="/components/com_tophat/images/details_open.png">';
62 nCloneTh.innerHTML = '<b>Info</b>';
63 nCloneTd.className = "center";
64 nCloneTh.className = "center";
65 this.elmt('table thead tr').each(function() {
66 this.insertBefore(nCloneTh, this.childNodes[0]);
68 this.elmt('table tbody tr').each(function() {
69 this.insertBefore(nCloneTd.cloneNode( true ), this.childNodes[0]);
73 // We are currently using a DataTable display, but another browsing component could be better
74 //jQuery('#'+this.options.plugin_uuid+'-table').dataTable...
75 var metaTable = this.elmt('table').dataTable({
79 sScrollX : '100%', // Horizontal scrolling
81 //bJQueryUI : true, // Use jQuery UI
82 bProcessing : true, // Loading
83 aaSorting : [[ 1, "asc" ]], // sort by column fields on load
85 { 'bSortable': false, 'aTargets': [ 0 ]},
86 { 'sWidth': '8px', 'aTargets': [ 0 ] },
87 { 'sWidth': '8px', 'aTargets': [ 4 ] } // XXX NB OF COLS
91 // Actions on the newly added fields
92 this.elmt('table tbody td span').on('click', function() {
93 var nTr = this.parentNode.parentNode;
94 // use jQuery UI instead of images to keep a common UI
95 // class="ui-icon treeclick ui-icon-triangle-1-s tree-minus"
96 // East oriented Triangle class="ui-icon-triangle-1-e"
97 // South oriented Triangle class="ui-icon-triangle-1-s"
99 if (this.className=="ui-icon ui-icon-triangle-1-e") {
100 this.removeClass("ui-icon-triangle-1-e").addClass("ui-icon-triangle-1-s");
102 metaTable.fnOpen(nTr, this.fnFormatDetails(metaTable, nTr, self.options.plugin_uuid+'_div'), 'details' );
104 this.removeClass("ui-icon-triangle-1-s").addClass("ui-icon-triangle-1-e");
105 metaTable.fnClose(nTr);
109 this.elmt('table_wrapper').css({
110 'padding-top' : '0em',
111 'padding-bottom': '0em'
114 // autocomplete list of tags
115 this.availableTags = {};
121 check_field: function(field)
123 this.elmt('check', field).attr('checked', true);
126 uncheck_field: function(field)
128 this.elmt('check', field).attr('checked', false);
131 update_filter_value: function(filter, removed)
133 removed = !(typeof removed === 'undefined'); // default = False
137 var value = filter[2];
139 var id = this.id_from_field(key);
142 var element = this.elmt(id);
146 this.elmt(id, 'max').val(value);
147 } else if (op == '>') {
148 this.elmt(id, 'min').val(value);
152 var element = this.elmt(id, suffix);
155 element.val(removed?null:value);
161 on_filter_added: function(filter)
163 this.update_filter_value(filter);
166 on_filter_removed: function(filter)
168 this.update_filter_value(filter, true);
171 on_field_added: function(field)
173 console.log("on_field_added : "+field);
174 this.check_field(field);
177 on_field_removed: function(field)
179 this.uncheck_field(field);
182 /* RECORD HANDLERS */
183 on_query_done: function()
185 //console.log("Query_Editor: query_done!");
186 //console.log(this.availableTags);
188 on_new_record: function(record)
190 //console.log("Query_Editor: new_record!");
191 //console.log(record);
192 availableTags = this.availableTags;
193 jQuery.each(record,function(key,value){
194 value = get_value(value);
195 if(!availableTags.hasOwnProperty(key)){availableTags[key]=new Array();}
196 //availableTags[key].push(value);
197 var currentArray = availableTags[key];
199 if(jQuery.inArray(value,currentArray)==-1){availableTags[key].push(value);}
202 this.availableTags = availableTags;
203 this.update_autocomplete(availableTags);
206 /* Former code not used at the moment */
208 print_field_description: function(field_header, div_id)
210 //var selected = all_headers[field_header];
211 var selected = getMetadata_field('resource',field_header);
213 field_header = div_id+"_"+field_header;
215 var output = "<div id='desc"+field_header+"'>";
217 output += "<div id='divinfo"+field_header+"'>";
218 output += '<p><span class="column-title">'+selected['title']+'</span></p></span>';
219 output += '<p><span class="column-detail">'+selected['description']+'</span></p></span>';
221 var period_select = "<select id='selectperiod"+field_header+"'><option value='Now'> Now </option><option value='latest'> Latest </option><option value=w> Week </option><option value=m> Month </option><option value=y> Year </option></select>";
223 if (selected['value_type'] == 'string') {
225 var values_select = "<p><select id='selectvalues"+field_header+"' MULTIPLE size=3>";
227 output += '<p>Values: ';
229 var values_list = selected['allowed_values'].split(",");
231 for (var value_index = 0; value_index < values_list.length ; value_index++) {
232 var value_desc = values_list[value_index].split("-");
235 output += '<span class="bold">'+value_desc[0]+'</span>';
236 values_select += "<option value ='"+value_desc[0]+"'> "+value_desc[0];
237 if (value_desc[1]!='')
238 output += ' ('+value_desc[1]+')';
240 values_select += " </option>";
242 values_select += "</select>";
245 output+='<p>Unit: '+selected['unit'];
249 output += '<p>Source: <a class="source-url" target="source_window" href="'+selected['platform_url']+'">'+selected['platform']+'</a>';
251 //if (selected['via'] != '')
252 //output += ' via <a class="source-url" target="source_window" href="http://'+selected['via_url']+'">'+selected['via']+'</a>';
258 output += "<div id='divgroup"+field_header+"'>";
259 output += "<p>Group resources with the same value <input type=checkbox></input>";
260 output += "<p>Select aggregator : <select><option>Count</option><option selected=true>Average</option><option>Maximum</option><option>Minimum</option></select>";
262 output += "<div id='divtime"+field_header+"'>";
263 output += "<p>Select timestamp : ";
264 output += period_select;
272 update_autocomplete: function(availableTags)
275 var domid = this.options.plugin_uuid;
277 jQuery.each(availableTags, function(key, value){
279 jQuery("#"+domid+"__field__"+key).autocomplete({
282 minLength: 0, // allows to browse items with no value typed in
283 select: self.event_filter_added('=')
286 }, // update_autocomplete
289 update_autocomplete: function(e, rows, current_query)
292 d.current_query = current_query;
293 var availableTags={};
294 jQuery.each (rows, function(index, obj) {
295 jQuery.each(obj,function(key,value){
296 value = get_value(value);
297 if(!availableTags.hasOwnProperty(key)){availableTags[key]=new Array();}
298 //availableTags[key].push(value);
299 var currentArray=availableTags[key];
301 if(jQuery.inArray(value,currentArray)==-1){availableTags[key].push(value);}
305 jQuery.each(availableTags, function(key, value){
307 jQuery("#"+options.plugin_uuid+"-filter-"+key).autocomplete({
310 minLength: 0, // allows to browse items with no value typed in
311 select: function(event, ui) {
312 var key=getKeySplitId(this.id,"-");
314 var val=ui.item.value;
316 query=d.current_query;
317 query.update_filter(key,op,val);
318 // Publish the query changed, the other plugins with subscribe will get the changes
319 jQuery.publish('/query/' + query.uuid + '/changed', query);
320 //add_ActiveFilter(this.id,'=',ui.item.value,d);
324 }, // update_autocomplete
326 fnFormatDetails: function( metaTable, nTr, div_id )
328 var aData = metaTable.fnGetData( nTr );
329 var sOut = '<blockquote>';
330 //sOut += prepare_tab_description(aData[1].substr(21, aData[1].length-21-7), div_id);
331 sOut += this.print_field_description(aData[1].substring(3, aData[1].length-4), div_id);
332 sOut += '</blockquote>';
338 $.plugin('QueryEditor', QueryEditor);