sequenceserver 2.0.0.beta3 → 2.0.0.beta4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sequenceserver might be problematic. Click here for more details.

Files changed (87) hide show
  1. checksums.yaml +5 -5
  2. data/.eslintrc.json +36 -0
  3. data/.rubocop.yml +1 -1
  4. data/.travis.yml +53 -20
  5. data/AppImage/recipe.yml +15 -0
  6. data/AppImage/sequenceserver.desktop +8 -0
  7. data/AppImage/sequenceserver.png +0 -0
  8. data/AppImage/sequenceserver.sh +11 -0
  9. data/README.md +79 -46
  10. data/bin/sequenceserver +4 -4
  11. data/lib/sequenceserver/version.rb +1 -1
  12. data/package.json +2 -0
  13. data/public/css/grapher.css +3 -0
  14. data/public/css/sequenceserver.css +17 -6
  15. data/public/css/sequenceserver.min.css +3 -3
  16. data/public/js/circos.js +515 -491
  17. data/public/js/grapher.js +12 -6
  18. data/public/js/hits_overview.js +321 -308
  19. data/public/js/hsp.js +12 -7
  20. data/public/js/length_distribution.js +241 -234
  21. data/public/js/report.js +196 -174
  22. data/public/js/search.js +3 -3
  23. data/public/js/sequenceserver.js +9 -9
  24. data/public/js/utils.js +17 -10
  25. data/public/js/visualisation_helpers.js +77 -77
  26. data/public/sequenceserver-report.min.js +17 -17
  27. data/public/sequenceserver-search.min.js +1 -1
  28. data/public/vendor/github/nicgirault/circosJs@1.7.0/dist/circosJS.js +1 -5
  29. data/sequenceserver.gemspec +1 -2
  30. data/spec/blast_versions/blast_2.2.30/blast_2.2.30_spec.rb +13 -13
  31. data/spec/blast_versions/blast_2.2.30/import_spec_capybara_local_2.2.30.rb +555 -25
  32. data/spec/blast_versions/blast_2.2.31/blast_2.2.31_spec.rb +13 -13
  33. data/spec/blast_versions/blast_2.2.31/import_spec_capybara_local_2.2.31.rb +558 -24
  34. data/spec/blast_versions/blast_2.3.0/blast_2.3.0_spec.rb +13 -13
  35. data/spec/blast_versions/blast_2.3.0/import_spec_capybara_local_2.3.0.rb +561 -26
  36. data/spec/blast_versions/blast_2.4.0/blast_2.4.0_spec.rb +13 -13
  37. data/spec/blast_versions/blast_2.4.0/import_spec_capybara_local_2.4.0.rb +561 -25
  38. data/spec/blast_versions/blast_2.5.0/blast_2.5.0_spec.rb +13 -13
  39. data/spec/blast_versions/blast_2.5.0/import_spec_capybara_local_2.5.0.rb +558 -24
  40. data/spec/blast_versions/blast_2.6.0/blast_2.6.0_spec.rb +13 -13
  41. data/spec/blast_versions/blast_2.6.0/import_spec_capybara_local_2.6.0.rb +559 -24
  42. data/spec/blast_versions/blast_2.7.1/blast_2.7.1_spec.rb +13 -13
  43. data/spec/blast_versions/blast_2.7.1/import_spec_capybara_local_2.7.1.rb +559 -28
  44. data/spec/blast_versions/blast_2.8.1/blast_2.8.1_spec.rb +13 -13
  45. data/spec/blast_versions/blast_2.8.1/import_spec_capybara_local_2.8.1.rb +559 -27
  46. data/spec/blast_versions/blast_2.9.0/blast_2.9.0_spec.rb +13 -13
  47. data/spec/blast_versions/blast_2.9.0/import_spec_capybara_local_2.9.0.rb +557 -25
  48. data/spec/blast_versions/diamond_0.9.24/diamond_0.9.24_spec.rb +13 -13
  49. data/spec/blast_versions/diamond_0.9.24/import_spec_capybara_local_0.9.24.rb +219 -21
  50. data/spec/capybara_spec.rb +25 -28
  51. data/spec/download_helper.rb +6 -3
  52. data/spec/sequences/MH011443_1_gi_1486783306_gb_MH011443_1.txt +6 -0
  53. data/spec/sequences/MH011443_1_gi_1486783307_gb_AYF55702_1.txt +6 -0
  54. data/spec/sequences/MH011443_1_gi_1528997474_gb_MH447967_1.txt +30 -0
  55. data/spec/sequences/MH011443_1_sp_P04637_P53_HUMAN.txt +6 -0
  56. data/spec/sequences/alignment-35_hits_diamond_blastp.txt +210 -0
  57. data/spec/sequences/alignment-35_hits_diamond_blastx.txt +210 -0
  58. data/spec/sequences/alignment-3_hits.txt +18 -0
  59. data/spec/sequences/alignment-40_hits_blastn.txt +246 -0
  60. data/spec/sequences/alignment-40_hits_blastp.txt +240 -0
  61. data/spec/sequences/alignment-40_hits_blastp_2.2.30.txt +240 -0
  62. data/spec/sequences/alignment-40_hits_blastx.txt +240 -0
  63. data/spec/sequences/alignment-40_hits_tblastn.txt +240 -0
  64. data/spec/sequences/alignment-40_hits_tblastn_2.2.30.txt +240 -0
  65. data/spec/sequences/alignment-40_hits_tblastx.txt +2664 -0
  66. data/spec/sequences/alignment-4_hits.txt +24 -0
  67. data/spec/sequences/alignment-4_hits_blastn.txt +24 -0
  68. data/spec/sequences/alignment-4_hits_blastp.txt +24 -0
  69. data/spec/sequences/alignment-4_hits_blastp_2.2.30.txt +24 -0
  70. data/spec/sequences/alignment-4_hits_blastx.txt +24 -0
  71. data/spec/sequences/alignment-4_hits_diamond_blastp.txt +24 -0
  72. data/spec/sequences/alignment-4_hits_diamond_blastx.txt +24 -0
  73. data/spec/sequences/alignment-4_hits_tblastn.txt +24 -0
  74. data/spec/sequences/alignment-4_hits_tblastn_2.2.30.txt +24 -0
  75. data/spec/sequences/alignment-4_hits_tblastx.txt +318 -0
  76. data/spec/sequences/sp_P04637_P53_HUMAN_gi_1099170394_ref_XP_018868681_1.txt +6 -0
  77. data/spec/sequences/sp_P04637_P53_HUMAN_gi_120407068_ref_NP_000537_3.txt +6 -0
  78. data/spec/sequences/sp_P04637_P53_HUMAN_gi_1484127324_gb_MG595988_1.txt +6 -0
  79. data/spec/sequences/sp_P04637_P53_HUMAN_gi_395440626_gb_JQ694049_1.txt +6 -0
  80. data/spec/sequences/sp_P04637_P53_HUMAN_sp_P04637_P53_HUMAN.txt +6 -0
  81. data/spec/spec_helper.rb +3 -3
  82. metadata +67 -57
  83. data/.eslintrc +0 -213
  84. data/Rakefile +0 -8
  85. data/spec/dotdir/blast_2.4.0/blastn/TBLASTN_XML_2.4.0.xml +0 -1181
  86. data/spec/dotdir/blast_2.5.0/blastn/BLASTN_LONG_XML_2.5.0.xml +0 -18813
  87. data/spec/import_spec_capybara_local.rb +0 -61
data/public/js/report.js CHANGED
@@ -1,4 +1,4 @@
1
- import './sequenceserver' // for custom $.tooltip function
1
+ import './sequenceserver'; // for custom $.tooltip function
2
2
  import React from 'react';
3
3
  import _ from 'underscore';
4
4
 
@@ -19,8 +19,8 @@ import showErrorModal from './error_modal';
19
19
  */
20
20
  var downloadFASTA = function (sequence_ids, database_ids) {
21
21
  var form = $('<form/>').attr('method', 'post').attr('action', 'get_sequence');
22
- addField("sequence_ids", sequence_ids);
23
- addField("database_ids", database_ids);
22
+ addField('sequence_ids', sequence_ids);
23
+ addField('database_ids', database_ids);
24
24
  form.appendTo('body').submit().remove();
25
25
 
26
26
  function addField(name, val) {
@@ -28,7 +28,7 @@ var downloadFASTA = function (sequence_ids, database_ids) {
28
28
  $('<input>').attr('type', 'hidden').attr('name', name).val(val)
29
29
  );
30
30
  }
31
- }
31
+ };
32
32
 
33
33
  /**
34
34
  * Base component of report page. This component is later rendered into page's
@@ -86,24 +86,24 @@ var Report = React.createClass({
86
86
  $.getJSON(location.pathname + '.json')
87
87
  .complete(function (jqXHR) {
88
88
  switch (jqXHR.status) {
89
- case 202:
90
- var interval;
91
- if (intervals.length === 1) {
92
- interval = intervals[0];
93
- }
94
- else {
95
- interval = intervals.shift();
96
- }
97
- setTimeout(poll, interval);
98
- break;
99
- case 200:
100
- component.updateState(jqXHR.responseJSON);
101
- break;
102
- case 404:
103
- case 400:
104
- case 500:
105
- showErrorModal(jqXHR.responseJSON);
106
- break;
89
+ case 202:
90
+ var interval;
91
+ if (intervals.length === 1) {
92
+ interval = intervals[0];
93
+ }
94
+ else {
95
+ interval = intervals.shift();
96
+ }
97
+ setTimeout(poll, interval);
98
+ break;
99
+ case 200:
100
+ component.updateState(jqXHR.responseJSON);
101
+ break;
102
+ case 404:
103
+ case 400:
104
+ case 500:
105
+ showErrorModal(jqXHR.responseJSON);
106
+ break;
107
107
  }
108
108
  });
109
109
  }
@@ -188,19 +188,14 @@ var Report = React.createClass({
188
188
  <div className={this.shouldShowSidebar() ?
189
189
  'col-md-9' : 'col-md-12'}>
190
190
  { this.overviewJSX() }
191
- { this.isHitsAvailable()
192
- ? <Circos queries={this.state.queries}
193
- program={this.state.program} collapsed="true"/>
194
- : <span></span> }
191
+ { this.circosJSX() }
195
192
  {
196
193
  _.map(this.state.queries, _.bind(function (query) {
197
194
  return (
198
- <Query key={"Query_"+query.id}
199
- program={this.state.program} querydb={this.state.querydb}
200
- query={query} num_queries={this.state.num_queries}
201
- veryBig={this.state.veryBig} selectHit={this.selectHit}
202
- imported_xml={this.state.imported_xml} />
203
- );
195
+ <Query key={'Query_'+query.id} query={query} showQueryCrumbs={this.state.num_queries > 1}
196
+ selectHit={this.selectHit} program={this.state.program} querydb={this.state.querydb}
197
+ veryBig={this.state.veryBig} imported_xml={this.state.imported_xml} />
198
+ );
204
199
  }, this))
205
200
  }
206
201
  </div>
@@ -214,25 +209,36 @@ var Report = React.createClass({
214
209
  overviewJSX: function () {
215
210
  return (
216
211
  <div className="overview">
217
- <pre className="pre-reset">
212
+ <p className="text-monospace">
218
213
  {this.state.program_version}{this.state.submitted_at
219
- && `; query submitted on ${this.state.submitted_at}`}
220
- <br/>
221
- Databases ({this.state.stats.nsequences} sequences,&nbsp;
222
- {this.state.stats.ncharacters} characters): {
223
- this.state.querydb.map((db) => { return db.title }).join(", ")
224
- }
225
- <br/>
214
+ && `, query submitted on ${this.state.submitted_at}`}
215
+ </p>
216
+ <p className="text-monospace">
217
+ Databases: {
218
+ this.state.querydb.map((db) => { return db.title; }).join(', ')
219
+ } ({this.state.stats.nsequences} sequences,&nbsp;
220
+ {this.state.stats.ncharacters} characters)
221
+ </p>
222
+ <p className="text-monospace">
226
223
  Parameters: {
227
224
  _.map(this.state.params, function (val, key) {
228
- return key + " " + val;
229
- }).join(", ")
225
+ return key + ' ' + val;
226
+ }).join(', ')
230
227
  }
231
- </pre>
228
+ </p>
232
229
  </div>
233
230
  );
234
- },
231
+ },
235
232
 
233
+ /**
234
+ * Return JSX for circos if we have at least one hit.
235
+ */
236
+ circosJSX: function () {
237
+ return this.atLeastTwoHits()
238
+ ? <Circos queries={this.state.queries}
239
+ program={this.state.program} collapsed="true"/>
240
+ : <span></span>;
241
+ },
236
242
 
237
243
  // Controller //
238
244
 
@@ -245,12 +251,19 @@ var Report = React.createClass({
245
251
  return this.state.queries.length >= 1;
246
252
  },
247
253
 
248
- isHitsAvailable: function () {
249
- var cnt = 0;
250
- _.each(this.state.queries, function (query) {
251
- if(query.hits.length == 0) cnt++;
254
+ /**
255
+ * Returns true if we have at least one hit.
256
+ */
257
+ atLeastOneHit: function () {
258
+ return this.state.queries.some(query => query.hits.length > 0);
259
+ },
260
+
261
+ atLeastTwoHits: function () {
262
+ var hit_num = 0;
263
+ return this.state.queries.some(query => {
264
+ hit_num += query.hits.length;
265
+ return hit_num > 1;
252
266
  });
253
- return !(cnt == this.state.queries.length);
254
267
  },
255
268
 
256
269
  /**
@@ -265,13 +278,12 @@ var Report = React.createClass({
265
278
  },
266
279
 
267
280
  /**
268
- * Returns true if index should be shown in the sidebar.
269
- *
270
- * Index is not shown in the sidebar if there are more than eight queries
271
- * in total.
281
+ * Returns true if index should be shown in the sidebar. Index is shown
282
+ * only for 2 and 8 queries.
272
283
  */
273
284
  shouldShowIndex: function () {
274
- return this.state.queries.length <= 8;
285
+ var num_queries = this.state.queries.length;
286
+ return num_queries >= 2 && num_queries <= 8;
275
287
  },
276
288
 
277
289
  /**
@@ -309,7 +321,7 @@ var Report = React.createClass({
309
321
  * Prevents folding of hits during text-selection.
310
322
  */
311
323
  preventCollapseOnSelection: function () {
312
- $('body').on('mousedown', ".hit > .section-header > h4", function (event) {
324
+ $('body').on('mousedown', '.hit > .section-header > h4', function (event) {
313
325
  var $this = $(this);
314
326
  $this.on('mouseup mousemove', function handler(event) {
315
327
  if (event.type === 'mouseup') {
@@ -355,7 +367,7 @@ var Report = React.createClass({
355
367
  */
356
368
  selectHit: function (id) {
357
369
 
358
- var checkbox = $("#" + id);
370
+ var checkbox = $('#' + id);
359
371
  var num_checked = $('.hit-links :checkbox:checked').length;
360
372
 
361
373
  if (!checkbox || !checkbox.val()) {
@@ -366,7 +378,7 @@ var Report = React.createClass({
366
378
 
367
379
  // Highlight selected hit and enable 'Download FASTA/Alignment of
368
380
  // selected' links.
369
- if (checkbox.is(":checked")) {
381
+ if (checkbox.is(':checked')) {
370
382
  $hit.find('.section-content').addClass('glow');
371
383
  $('.download-alignment-of-selected').enable();
372
384
  $('.download-fasta-of-selected').enable();
@@ -406,7 +418,11 @@ var Query = React.createClass({
406
418
  * Returns the id of query.
407
419
  */
408
420
  domID: function () {
409
- return "Query_" + this.props.query.number;
421
+ return 'Query_' + this.props.query.number;
422
+ },
423
+
424
+ queryLength: function () {
425
+ return this.props.query.length;
410
426
  },
411
427
 
412
428
  /**
@@ -423,59 +439,57 @@ var Query = React.createClass({
423
439
  <div className="resultn" id={this.domID()}
424
440
  data-query-len={this.props.query.length}
425
441
  data-algorithm={this.props.program}>
426
- <div className="section-header">
427
- <h3>
428
- Query= {this.props.query.id}
429
- &nbsp;
430
- <small>
431
- {this.props.query.title}
432
- </small>
433
- </h3>
434
- <span
435
- className="label label-reset pos-label"
436
- title={"Query" + this.props.query.number + "."}
437
- data-toggle="tooltip">
438
- {this.props.query.number + "/" + this.props.num_queries}
439
- </span>
440
- </div>
441
- {this.numhits() &&
442
- (
443
- <div className="section-content">
444
- <HitsOverview key={"GO_"+this.props.query.number} query={this.props.query} program={this.props.program} collapsed={this.props.veryBig}/>
445
- <LengthDistribution key={"LD_"+this.props.query.id} query={this.props.query} algorithm={this.props.program} collapsed="true"/>
446
- <HitsTable key={"HT_"+this.props.query.number} query={this.props.query} imported_xml={this.props.imported_xml} />
447
- <div id="hits">
448
- {
449
- _.map(this.props.query.hits, _.bind(function (hit) {
450
- return (
451
- <Hit hit={hit}
452
- key={"HIT_"+hit.number}
453
- algorithm={this.props.program}
454
- querydb={this.props.querydb}
455
- query={this.props.query}
456
- imported_xml={this.props.imported_xml}
457
- selectHit={this.props.selectHit}/>
458
- );
459
- }, this))
460
- }
461
- </div>
462
- </div>
463
- ) || (
464
- <div
465
- className="section-content">
466
- <p>
467
- Query length: {this.props.query.length}
468
- </p>
469
- <br/>
470
- <br/>
471
- <p>
472
- <strong> ****** No hits found ****** </strong>
473
- </p>
474
- </div>
475
- )
442
+ { this.headerJSX() }
443
+ { this.numhits() && this.hitsListJSX() || this.noHitsJSX() }
444
+ </div>
445
+ );
446
+ },
447
+
448
+ headerJSX: function () {
449
+ var meta = `length: ${this.queryLength().toLocaleString()}`;
450
+ if (this.props.showQueryCrumbs) {
451
+ meta = `query ${this.props.query.number}, ` + meta;
452
+ }
453
+ return <div className="section-header">
454
+ <h3>
455
+ Query= {this.props.query.id}&nbsp;
456
+ <small>{this.props.query.title}</small>
457
+ </h3>
458
+ <span className="label label-reset pos-label">{ meta }</span>
459
+ </div>;
460
+ },
461
+
462
+ hitsListJSX: function () {
463
+ return <div className="section-content">
464
+ <HitsOverview key={'GO_' + this.props.query.number} query={this.props.query} program={this.props.program} collapsed={this.props.veryBig} />
465
+ <LengthDistribution key={'LD_' + this.props.query.id} query={this.props.query} algorithm={this.props.program} collapsed="true" />
466
+ <HitsTable key={'HT_' + this.props.query.number} query={this.props.query} imported_xml={this.props.imported_xml} />
467
+ <div id="hits">
468
+ {
469
+ _.map(this.props.query.hits, _.bind(function (hit) {
470
+ return (
471
+ <Hit key={'HIT_' + hit.number} hit={hit}
472
+ algorithm={this.props.program}
473
+ querydb={this.props.querydb}
474
+ query={this.props.query}
475
+ imported_xml={this.props.imported_xml}
476
+ selectHit={this.props.selectHit}
477
+ showHitCrumbs={this.numhits() > 1}
478
+ showQueryCrumbs={this.props.showQueryCrumbs} />
479
+ );
480
+ }, this))
476
481
  }
477
482
  </div>
478
- )
483
+ </div>;
484
+ },
485
+
486
+ noHitsJSX: function () {
487
+ return <div className="section-content">
488
+ <br />
489
+ <p>
490
+ <strong> ****** No hits found ****** </strong>
491
+ </p>
492
+ </div>;
479
493
  },
480
494
 
481
495
  shouldComponentUpdate: function (nextProps, nextState) {
@@ -490,9 +504,9 @@ var HitsTable = React.createClass({
490
504
  mixins: [Utils],
491
505
  render: function () {
492
506
  var count = 0,
493
- hasName = _.every(this.props.query.hits, function(hit) {
494
- return hit.sciname !== '';
495
- });
507
+ hasName = _.every(this.props.query.hits, function(hit) {
508
+ return hit.sciname !== '';
509
+ });
496
510
 
497
511
  return (
498
512
  <table
@@ -514,9 +528,9 @@ var HitsTable = React.createClass({
514
528
  _.map(this.props.query.hits, _.bind(function (hit) {
515
529
  return (
516
530
  <tr key={hit.number}>
517
- <td className="text-left">{hit.number + "."}</td>
531
+ <td className="text-left">{hit.number + '.'}</td>
518
532
  <td>
519
- <a href={"#Query_" + this.props.query.number + "_hit_" + hit.number}>
533
+ <a href={'#Query_' + this.props.query.number + '_hit_' + hit.number}>
520
534
  {hit.id}
521
535
  </a>
522
536
  </td>
@@ -526,7 +540,7 @@ var HitsTable = React.createClass({
526
540
  <td className="text-right">{this.inExponential(hit.hsps[0].evalue)}</td>
527
541
  <td className="text-right">{hit.identity}</td>
528
542
  </tr>
529
- )
543
+ );
530
544
  }, this))
531
545
  }
532
546
  </tbody>
@@ -551,7 +565,7 @@ var Hit = React.createClass({
551
565
  /**
552
566
  * Returns length of the hit sequence.
553
567
  */
554
- length: function () {
568
+ hitLength: function () {
555
569
  return this.props.hit.length;
556
570
  },
557
571
 
@@ -561,7 +575,7 @@ var Hit = React.createClass({
561
575
  * Returns id that will be used for the DOM node corresponding to the hit.
562
576
  */
563
577
  domID: function () {
564
- return "Query_" + this.props.query.number + "_hit_" + this.props.hit.number;
578
+ return 'Query_' + this.props.query.number + '_hit_' + this.props.hit.number;
565
579
  },
566
580
 
567
581
  databaseIDs: function () {
@@ -593,10 +607,10 @@ var Hit = React.createClass({
593
607
  hsp.query_id = this.props.query.id;
594
608
  hsp.hit_id = this.props.hit.id;
595
609
  return hsp;
596
- }, this))
610
+ }, this));
597
611
 
598
612
  var aln_exporter = new AlignmentExporter();
599
- aln_exporter.export_alignments(hsps, this.props.query.id+"_"+this.props.hit.id);
613
+ aln_exporter.export_alignments(hsps, this.props.query.id+'_'+this.props.hit.id);
600
614
  },
601
615
 
602
616
 
@@ -608,7 +622,7 @@ var Hit = React.createClass({
608
622
 
609
623
  // Return JSX for view sequence button.
610
624
  viewSequenceButton: function () {
611
- if (this.length() > 10000) {
625
+ if (this.hitLength() > 10000) {
612
626
  return (
613
627
  <button
614
628
  className="btn btn-link view-sequence disabled"
@@ -630,49 +644,57 @@ var Hit = React.createClass({
630
644
 
631
645
  render: function () {
632
646
  return (
633
- <div className="hit" id={this.domID()}
634
- data-hit-def={this.props.hit.id} data-hit-evalue={this.props.hit.evalue}
635
- data-hit-len={this.props.hit.length}>
636
- <div className="section-header">
637
- <h4 data-toggle="collapse"
638
- data-target={this.domID() + "_content"}>
639
- <i className="fa fa-chevron-down"></i>
640
- &nbsp;
641
- <span>
642
- {this.props.hit.id}
643
- &nbsp;
644
- <small>
645
- {this.props.hit.title}
646
- </small>
647
- </span>
648
- </h4>
649
- <span className="label label-reset pos-label"
650
- title={"Query " + this.props.query.number + ". Hit "
651
- + this.props.hit.number + " of "
652
- + this.props.query.hits.length + "."}
653
- data-toggle="tooltip">
654
- {this.props.hit.number + "/" + this.props.query.hits.length}
655
- </span>
656
- </div>
657
- <div id={this.domID() + "_content"}
658
- className="section-content collapse in">
659
- { this.hitLinks() }
660
- <HSPOverview key={"kablammo"+this.props.query.id}
661
- query={this.props.query} hit={this.props.hit}
662
- algorithm={this.props.algorithm}/>
663
- { this.hspListJSX() }
664
- </div>
647
+ <div className="hit" id={this.domID()} data-hit-def={this.props.hit.id}
648
+ data-hit-len={this.props.hit.length} data-hit-evalue={this.props.hit.evalue}>
649
+ { this.headerJSX() } { this.contentJSX() }
665
650
  </div>
666
651
  );
667
652
  },
668
653
 
654
+ headerJSX: function () {
655
+ var meta = `length: ${this.hitLength().toLocaleString()}`;
656
+
657
+ if (this.props.showQueryCrumbs && this.props.showHitCrumbs) {
658
+ // Multiper queries, multiple hits
659
+ meta = `hit ${this.props.hit.number} of query ${this.props.query.number}, ` + meta;
660
+ }
661
+ else if (this.props.showQueryCrumbs && !this.props.showHitCrumbs) {
662
+ // Multiple queries, single hit
663
+ meta = `the only hit of query ${this.props.query.number}, ` + meta;
664
+ }
665
+ else if (!this.props.showQueryCrumbs && this.props.showHitCrumbs) {
666
+ // Single query, multiple hits
667
+ meta = `hit ${this.props.hit.number}, ` + meta;
668
+ }
669
+
670
+ return <div className="section-header">
671
+ <h4 data-toggle="collapse" data-target={this.domID() + '_content'}>
672
+ <i className="fa fa-chevron-down"></i>&nbsp;
673
+ <span>
674
+ {this.props.hit.id}&nbsp;
675
+ <small>{this.props.hit.title}</small>
676
+ </span>
677
+ </h4>
678
+ <span className="label label-reset pos-label">{ meta }</span>
679
+ </div>;
680
+ },
681
+
682
+ contentJSX: function () {
683
+ return <div id={this.domID() + '_content'} className="section-content collapse in">
684
+ { this.hitLinks() }
685
+ <HSPOverview key={'kablammo' + this.props.query.id} query={this.props.query}
686
+ hit={this.props.hit} algorithm={this.props.algorithm} />
687
+ { this.hspListJSX() }
688
+ </div>;
689
+ },
690
+
669
691
  hitLinks: function () {
670
692
  return (
671
693
  <div className="hit-links">
672
694
  <label>
673
- <input type="checkbox" id={this.domID() + "_checkbox"}
695
+ <input type="checkbox" id={this.domID() + '_checkbox'}
674
696
  value={this.accession()} onChange={function () {
675
- this.props.selectHit(this.domID() + "_checkbox");
697
+ this.props.selectHit(this.domID() + '_checkbox');
676
698
  }.bind(this)} data-target={'#' + this.domID()}
677
699
  /> Select
678
700
  </label>
@@ -714,10 +736,10 @@ var Hit = React.createClass({
714
736
  return <HSP key={hsp.number}
715
737
  algorithm={this.props.algorithm}
716
738
  queryNumber={this.props.query.number}
717
- hitNumber={this.props.hit.number} hsp={hsp}/>
739
+ hitNumber={this.props.hit.number} hsp={hsp}/>;
718
740
  }, this)
719
741
  }
720
- </div>
742
+ </div>;
721
743
  }
722
744
  });
723
745
 
@@ -886,7 +908,7 @@ var SequenceViewer = (function () {
886
908
  sequences: response.sequences,
887
909
  error_msgs: response.error_msgs,
888
910
  requestCompleted: true
889
- })
911
+ });
890
912
  }, this))
891
913
  .fail(function (jqXHR, status, error) {
892
914
  showErrorModal(jqXHR, function () {
@@ -941,11 +963,11 @@ var SideBar = React.createClass({
941
963
  hsp.hit_id = hit.id;
942
964
  hsp.query_id = query.id;
943
965
  hsps_arr.push(hsp);
944
- })
945
- })
966
+ });
967
+ });
946
968
  }, this));
947
969
  console.log('len '+hsps_arr.length);
948
- aln_exporter.export_alignments(hsps_arr, "alignment-"+sequence_ids.length+"_hits");
970
+ aln_exporter.export_alignments(hsps_arr, 'alignment-'+sequence_ids.length+'_hits');
949
971
  return false;
950
972
  },
951
973
 
@@ -967,7 +989,7 @@ var SideBar = React.createClass({
967
989
  }
968
990
  });
969
991
  }, this));
970
- aln_exporter.export_alignments(hsps_arr, "alignment-"+sequence_ids.length+"_hits");
992
+ aln_exporter.export_alignments(hsps_arr, 'alignment-'+sequence_ids.length+'_hits');
971
993
  return false;
972
994
  },
973
995
 
@@ -979,29 +1001,29 @@ var SideBar = React.createClass({
979
1001
  { this.props.shouldShowIndex && this.index() }
980
1002
  { this.downloads() }
981
1003
  </div>
982
- )
1004
+ );
983
1005
  },
984
1006
 
985
1007
  index: function () {
986
1008
  return (
987
1009
  <div className="index">
988
1010
  <div
989
- className="section-header">
990
- <h4>
991
- { this.summary() }
992
- </h4>
1011
+ className="section-header">
1012
+ <h4>
1013
+ { this.summary() }
1014
+ </h4>
993
1015
  </div>
994
1016
  <ul
995
1017
  className="nav hover-reset active-bold">
996
1018
  {
997
1019
  _.map(this.props.data.queries, _.bind(function (query) {
998
1020
  return (
999
- <li key={"Side_bar_"+query.id}>
1021
+ <li key={'Side_bar_'+query.id}>
1000
1022
  <a
1001
1023
  className="nowrap-ellipsis hover-bold"
1002
- href={"#Query_" + query.number}
1003
- title={"Query= " + query.id + ' ' + query.title}>
1004
- {"Query= " + query.id}
1024
+ href={'#Query_' + query.number}
1025
+ title={'Query= ' + query.id + ' ' + query.title}>
1026
+ {'Query= ' + query.id}
1005
1027
  </a>
1006
1028
  </li>
1007
1029
  );
@@ -1019,7 +1041,7 @@ var SideBar = React.createClass({
1019
1041
 
1020
1042
  return (
1021
1043
  program.toUpperCase() + ': ' +
1022
- numqueries + ' ' + (numqueries > 1 ? 'queries' : 'query') + ", " +
1044
+ numqueries + ' ' + (numqueries > 1 ? 'queries' : 'query') + ', ' +
1023
1045
  numquerydb + ' ' + (numquerydb > 1 ? 'databases' : 'database')
1024
1046
  );
1025
1047
  },
@@ -1068,7 +1090,7 @@ var SideBar = React.createClass({
1068
1090
  name, alignment length, mismatches, gaps, identity,
1069
1091
  start and end coordinates, e value, bitscore, query
1070
1092
  coverage per subject and per HSP."
1071
- href={"download/" + this.props.data.search_id + ".std_tsv"}>
1093
+ href={'download/' + this.props.data.search_id + '.std_tsv'}>
1072
1094
  Standard tabular report
1073
1095
  </a>
1074
1096
  </li>
@@ -1080,7 +1102,7 @@ var SideBar = React.createClass({
1080
1102
  accessions, and length; alignment details;
1081
1103
  taxonomy details of subject sequence(s) and
1082
1104
  query coverage per subject and per HSP."
1083
- href={"download/" + this.props.data.search_id + ".full_tsv"}>
1105
+ href={'download/' + this.props.data.search_id + '.full_tsv'}>
1084
1106
  Full tabular report
1085
1107
  </a>
1086
1108
  </li>
@@ -1089,7 +1111,7 @@ var SideBar = React.createClass({
1089
1111
  !this.props.data.imported_xml && <li>
1090
1112
  <a className="download" data-toggle="tooltip"
1091
1113
  title="Results in XML format."
1092
- href={"download/" + this.props.data.search_id + ".xml"}>
1114
+ href={'download/' + this.props.data.search_id + '.xml'}>
1093
1115
  Full XML report
1094
1116
  </a>
1095
1117
  </li>