Merge pull request #5191 from solgenomics/topic/quality_control
[sgn.git] / js / source / legacy / SGN / Search / Feature.js
blob0fd4c8cde1413767f96e2fae1c3b2c6793633966
1 var SGN;
2 if( ! SGN ) SGN = {};
3 if( ! SGN.Search ) SGN.Search = {};
5 SGN.Search.Feature = {
7 set_up_feature_search: function( args ) {
8 var maximum_export_size = args.maximum_export_size || 10000;
10 Ext.Loader.setConfig({enabled: true});
12 Ext.require([
13 'Ext.grid.*',
14 'Ext.data.*',
15 'Ext.util.*',
16 'Ext.grid.PagingScroller'
17 ]);
19 // make the feature grid
20 Ext.onReady(function(){
22 var page_size = 100;
24 Ext.define('Feature', {
25 extend: 'Ext.data.Model',
26 fields: [
27 'feature_id',
28 'organism',
29 'name',
30 'type',
31 'seqlen',
32 'locations',
33 'description'
35 idProperty: 'feature_id'
36 });
38 function get_search_query( store ) {
39 // get the filtering data from the store
40 var post_vars = Ext.clone( store.proxy.extraParams );
42 // filter out any form fields that are empty or just whitespace
43 for( var name in post_vars ) {
44 var value = post_vars[name];
45 if( value == null || typeof value == 'string' && ! value.match(/[^\s]/) ) {
46 delete post_vars[name];
50 // get the sort settings from the store
51 var sorter = store.sorters.first();
52 post_vars.sort = sorter.property;
53 post_vars.dir = sorter.direction;
55 return post_vars;
58 // create the Data Store
59 var feature_store = Ext.create('Ext.data.Store', {
60 id: 'feature_store',
61 pageSize: page_size,
62 model: 'Feature',
63 remoteSort: true,
64 autoLoad: true,
66 listeners: {
67 // enable or disable the export and save
68 // toolbar based on how many features matched
69 datachanged: function( store ) {
70 var toolbar = Ext.getCmp('feature_export_toolbar');
71 var label = Ext.getCmp('feature_export_toolbar_disabled_label');
72 if( store.getTotalCount() <= maximum_export_size ) {
73 // enable the export toolbar
74 toolbar.enable();
75 label.hide();
76 } else {
77 // disable the export toolbar
78 toolbar.disable();
79 label.show();
84 proxy: {
85 type: 'ajax',
86 url: '/search/features/search_service',
87 timeout: 60000,
88 reader: {
89 root: 'data',
90 totalProperty: 'totalCount',
91 successProperty: 'success'
93 // sends single sort as multi parameter
94 simpleSortMode: true
96 sorters: [{
97 property: 'feature_id',
98 direction: 'ASC'
102 function hyphen_if_empty( value ) {
103 return value.length > 0 ? value : '-';
106 function export_to_bulk( bulk_url ) {
107 var search_query = get_search_query( feature_store );
108 search_query.fields = 'name';
109 Ext.Ajax.request({
110 url: '/search/features/search_service',
111 method: 'GET',
112 params: search_query,
113 success: function( response ) {
114 // make a bulk-download URL populated with these IDs
115 var features = Ext.JSON.decode( response.responseText ).data;
116 var names = [];
117 for( var i = 0; i < features.length; i++ ) {
118 names.push( features[i].name );
120 names = names.join("\n");
122 Ext.create( 'Ext.form.Panel', {
123 url: bulk_url,
124 standardSubmit: true,
125 defaultType: 'textfield',
126 hidden: true,
127 items: [{ name: 'ids', value: names }]
128 }).submit();
133 var feature_grid = Ext.create('Ext.grid.Panel', {
134 width: 700,
135 height: 400,
136 //title: 'Matching Features',
137 store: feature_store,
138 loadMask: true,
140 dockedItems: [
142 xtype: 'toolbar',
143 dock: 'top',
144 id: 'feature_export_toolbar',
145 items: [
146 '->',
147 { xtype: 'label',
148 id: 'feature_export_toolbar_disabled_label',
149 text: 'Exporting limited to '+ Ext.util.Format.number( maximum_export_size, '0,000' )+' features.',
150 hidden: true
152 xtype: 'button',
153 text: 'Save as',
154 icon: '/img/icons/oxygen/16x16/media-floppy.png',
155 menu: {
156 items: [
158 text: 'CSV',
159 icon: '/img/icons/oxygen/16x16/text-csv.png',
160 handler: function() {
161 var search_query_vars = get_search_query( feature_store );
162 var csv_url = '/search/features/export_csv?' + Ext.Object.toQueryString( search_query_vars );
163 location.href = csv_url;
169 xtype: 'button',
170 text: 'Send to',
171 icon: '/img/icons/oxygen/16x16/document-export.png',
172 menu: {
173 items: [
175 text: 'bulk feature download',
176 icon: '/img/icons/oxygen/16x16/document-export-table.png',
177 handler: function() {
178 export_to_bulk( '/bulk/feature' );
181 text: 'bulk gene download',
182 icon: '/img/icons/oxygen/16x16/document-export-table.png',
183 handler: function() {
184 export_to_bulk( '/bulk/gene' );
192 xtype: 'pagingtoolbar',
193 store: feature_store, // same store GridPanel is using
194 dock: 'bottom',
195 displayInfo: true,
196 emptyMsg: 'No matching features'
200 viewConfig: {
201 trackOver: false
203 // grid columns
204 columns:[
206 id: 'organism',
207 text: "Organism",
208 dataIndex: 'organism',
209 width: 150,
210 sortable: true,
211 flex: 1
213 text: "Type",
214 dataIndex: 'type',
215 width: 90,
216 hidden: false,
217 sortable: true
219 text: "Name",
220 dataIndex: 'name',
221 align: 'center',
222 width: 150,
223 sortable: true,
224 flex: 1,
225 renderer: function(value,p,record) {
226 return Ext.String.format(
227 '<a href="/feature/{0}/details" target="_blank">{1}</a>',
228 record.getId(),
229 value
233 text: "Description",
234 dataIndex: 'description',
235 align: 'left',
236 width: 200,
237 sortable: false,
238 flex: 1,
239 renderer: hyphen_if_empty
241 text: "Location(s)",
242 dataIndex: 'locations',
243 align: 'left',
244 width: 200,
245 sortable: false,
246 flex: 1,
247 renderer: hyphen_if_empty
250 renderTo: document.getElementById('search_grid')
253 // make the form for feature filtering
254 var feature_types_store =
255 Ext.create('Ext.data.Store', {
256 fields: ['type_id', 'name'],
257 proxy: {
258 type: 'ajax',
259 timeout: 60000,
260 url: '/search/features/feature_types_service',
261 reader: {
262 root: 'data',
263 totalProperty: 'totalCount',
264 successProperty: 'success'
269 var featureprop_types_store =
270 Ext.create('Ext.data.Store', {
271 fields: ['type_id', 'name'],
272 proxy: {
273 type: 'ajax',
274 timeout: 60000,
275 url: '/search/features/featureprop_types_service',
276 reader: {
277 root: 'data',
278 totalProperty: 'totalCount',
279 successProperty: 'success'
284 var srcfeatures_store =
285 Ext.create('Ext.data.Store', {
286 model: 'Feature',
287 proxy: {
288 type: 'ajax',
289 timeout: 60000,
290 url: '/search/features/srcfeatures_service',
291 reader: {
292 root: 'data',
293 totalProperty: 'totalCount',
294 successProperty: 'success'
299 function applyFeatureFilters( form ) {
300 var data = form.getFieldValues();
301 // filter out any form fields that are just whitespace
302 for( var name in data ) {
303 if( data[name] == null || typeof data[name] == 'string' && ! data[name].match(/[^\s]/) ) {
304 delete data[name];
307 feature_store.proxy.extraParams = data;
308 feature_store.load( function(records,operation,success) {
309 if( ! success ) {
310 feature_store.removeAll();
315 // default field settings for the text fields that make the
316 // enter key submit the form
318 var feature_search_field_defaults = {
319 maxLength: 100,
320 width: 425,
321 labelWidth: 130,
322 listeners: {
323 specialkey: function(field, e){
324 if (e.getKey() == e.ENTER) {
325 applyFeatureFilters( field.up('form').getForm() );
331 var feature_filter_form = Ext.create('Ext.form.Panel', {
332 width: 450,
333 bodyPadding: 10,
334 defaultType: 'textfield',
335 renderTo: document.getElementById('search_form'),
336 items: [
338 fieldLabel: 'Name contains',
339 name: 'name'
342 fieldLabel: 'Organism contains',
343 name: 'organism'
346 xtype: 'combobox',
347 fieldLabel: 'Type is',
348 id: 'feature_type_select',
349 name: 'type_id',
350 store: feature_types_store,
351 disabled: true, // enabled when feature_types_store finishes loading
352 queryMode: 'local',
353 displayField: 'name',
354 valueField: 'type_id',
355 typeAhead: true,
356 listeners: {} // don't override the combobox's enter key
359 fieldLabel: 'Description contains',
360 name: 'description'
363 xtype: 'fieldset',
364 title: 'Overlaps range',
365 width: 425,
366 layout: 'hbox',
367 defaults: feature_search_field_defaults,
368 items: [
370 xtype: 'combobox',
371 name: 'srcfeature_id',
372 store: srcfeatures_store,
373 disabled: true, // enabled when srcfeatures_store finishes load
374 id: 'srcfeature_select',
375 queryMode: 'local',
376 displayField: 'name',
377 valueField: 'feature_id',
378 width: 200,
379 listeners: {
380 // when the srcfeature is set, set the
381 // max values of the range numbers to
382 // the srcfeature's length
383 change: function( cbox, newValue, oldValue ) {
384 var feature = cbox.getStore().getById( newValue );
385 if( feature ) {
386 var len = feature.raw.seqlen;
387 var srcfeature_start = Ext.getCmp('srcfeature_start');
388 var srcfeature_end = Ext.getCmp('srcfeature_end');
389 srcfeature_start.setMaxValue( len );
390 srcfeature_end.setMaxValue( len );
391 if( ! srcfeature_start.getValue() )
392 srcfeature_start.setValue( 1 );
393 if( ! srcfeature_end.getValue() || srcfeature_end.getValue() > len )
394 srcfeature_end.setValue( len );
399 { xtype: 'numberfield',
400 id: 'srcfeature_start',
401 name: 'srcfeature_start',
402 step: 10000,
403 minValue: 1,
404 width: 100
406 { xtype: 'numberfield',
407 id: 'srcfeature_end',
408 name: 'srcfeature_end',
409 step: 10000,
410 minValue: 1,
411 width: 100
416 xtype: 'fieldset',
417 title: 'Has property',
418 width: 425,
419 layout: 'hbox',
420 defaultType: 'textfield',
421 defaults: feature_search_field_defaults,
422 items: [
424 xtype: 'combobox',
425 name: 'proptype_id',
426 id: 'featureprop_type_select',
427 width: 200,
428 store: featureprop_types_store,
429 disabled: true, // enabled when featureprop_types_store finishes loading
430 queryMode: 'local',
431 displayField: 'name',
432 valueField: 'type_id',
433 typeAhead: true,
434 listeners: {} // don't override the combobox's enter key
436 fieldLabel: 'containing',
437 labelWidth: 75,
438 labelAlign: 'right',
439 name: 'prop_value',
440 width: 200
445 // make the ENTER key submit the form by default for all form fields
446 defaults: feature_search_field_defaults,
447 buttons: [
449 text: 'Clear',
450 handler: function() {
451 var form = this.up('form').getForm();
452 form.reset();
455 text: 'Apply',
456 handler: function() {
457 applyFeatureFilters( this.up('form').getForm() );
464 // only enable the various comboboxes in the filtering
465 // form when their associated data stores finish
466 // loading.
467 feature_types_store.load(
468 function( recs, op, success ) {
469 if( success ) Ext.getCmp('feature_type_select').enable();
472 featureprop_types_store.load(
473 function( recs, op, success ) {
474 if( success ) Ext.getCmp('featureprop_type_select').enable();
477 srcfeatures_store.load(
478 function( recs, op, success ) {
479 if( success ) Ext.getCmp('srcfeature_select').enable();