sequenceserver 2.0.0.rc8 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/bin/sequenceserver +22 -30
  3. data/lib/sequenceserver/api_errors.rb +5 -1
  4. data/lib/sequenceserver/blast/constants.rb +1 -1
  5. data/lib/sequenceserver/blast/hit.rb +5 -16
  6. data/lib/sequenceserver/blast/job.rb +9 -18
  7. data/lib/sequenceserver/blast/report.rb +5 -3
  8. data/lib/sequenceserver/config.rb +4 -1
  9. data/lib/sequenceserver/database.rb +69 -9
  10. data/lib/sequenceserver/job.rb +1 -1
  11. data/lib/sequenceserver/makeblastdb.rb +40 -45
  12. data/lib/sequenceserver/routes.rb +4 -0
  13. data/lib/sequenceserver/version.rb +1 -1
  14. data/lib/sequenceserver.rb +15 -11
  15. data/public/config.js +143 -142
  16. data/public/css/fonts.css +23 -22
  17. data/public/css/grapher.css +598 -594
  18. data/public/css/sequenceserver.css +86 -24
  19. data/public/css/sequenceserver.min.css +2 -2
  20. data/public/js/alignment_exporter.js +14 -14
  21. data/public/js/databases_tree.js +215 -0
  22. data/public/js/download_fasta.js +1 -1
  23. data/public/js/hit.js +6 -2
  24. data/public/js/hits_overview.js +1 -1
  25. data/public/js/length_distribution.js +5 -5
  26. data/public/js/query.js +4 -7
  27. data/public/js/report.js +12 -24
  28. data/public/js/search.js +21 -2
  29. data/public/js/sidebar.js +4 -4
  30. data/public/js/svgExporter.js +12 -12
  31. data/public/js/visualisation_helpers.js +4 -5
  32. data/public/sequenceserver-report.min.js +11 -11
  33. data/public/sequenceserver-search.min.js +15 -11
  34. data/public/vendor/github/vakata/jstree@3.3.8/LICENSE-MIT +22 -0
  35. data/public/vendor/github/vakata/jstree@3.3.8/README.md +663 -0
  36. data/public/vendor/github/vakata/jstree@3.3.8/bower.json +33 -0
  37. data/public/vendor/github/vakata/jstree@3.3.8/component.json +28 -0
  38. data/public/vendor/github/vakata/jstree@3.3.8/composer.json +46 -0
  39. data/public/vendor/github/vakata/jstree@3.3.8/demo/README.md +2 -0
  40. data/public/vendor/github/vakata/jstree@3.3.8/demo/basic/index.html +146 -0
  41. data/public/vendor/github/vakata/jstree@3.3.8/demo/basic/root.json +1 -0
  42. data/public/vendor/github/vakata/jstree@3.3.8/dist/jstree.js +8612 -0
  43. data/public/vendor/github/vakata/jstree@3.3.8/dist/jstree.min.js +6 -0
  44. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default/32px.png +0 -0
  45. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default/40px.png +0 -0
  46. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default/style.css +1102 -0
  47. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default/style.min.css +1 -0
  48. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default/throbber.gif +0 -0
  49. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default-dark/32px.png +0 -0
  50. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default-dark/40px.png +0 -0
  51. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default-dark/style.css +1146 -0
  52. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default-dark/style.min.css +1 -0
  53. data/public/vendor/github/vakata/jstree@3.3.8/dist/themes/default-dark/throbber.gif +0 -0
  54. data/public/vendor/github/vakata/jstree@3.3.8/gruntfile.js +242 -0
  55. data/public/vendor/github/vakata/jstree@3.3.8/jstree.jquery.json +28 -0
  56. data/public/vendor/github/vakata/jstree@3.3.8/package.json +58 -0
  57. data/public/vendor/github/vakata/jstree@3.3.8/src/intro.js +14 -0
  58. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.changed.js +69 -0
  59. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.checkbox.js +976 -0
  60. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.conditionalselect.js +38 -0
  61. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.contextmenu.js +661 -0
  62. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.dnd.js +669 -0
  63. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.js +4931 -0
  64. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.massload.js +137 -0
  65. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.search.js +421 -0
  66. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.sort.js +74 -0
  67. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.state.js +138 -0
  68. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.types.js +372 -0
  69. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.unique.js +164 -0
  70. data/public/vendor/github/vakata/jstree@3.3.8/src/jstree.wholerow.js +122 -0
  71. data/public/vendor/github/vakata/jstree@3.3.8/src/misc.js +656 -0
  72. data/public/vendor/github/vakata/jstree@3.3.8/src/outro.js +1 -0
  73. data/public/vendor/github/vakata/jstree@3.3.8/src/sample.js +93 -0
  74. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/base.less +93 -0
  75. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default/32px.png +0 -0
  76. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default/40px.png +0 -0
  77. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default/style.css +1102 -0
  78. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default/style.less +22 -0
  79. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default/throbber.gif +0 -0
  80. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default-dark/32px.png +0 -0
  81. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default-dark/40px.png +0 -0
  82. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default-dark/style.css +1146 -0
  83. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default-dark/style.less +50 -0
  84. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/default-dark/throbber.gif +0 -0
  85. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/main.less +77 -0
  86. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/mixins.less +104 -0
  87. data/public/vendor/github/vakata/jstree@3.3.8/src/themes/responsive.less +67 -0
  88. data/public/vendor/github/vakata/jstree@3.3.8/src/vakata-jstree.js +38 -0
  89. data/public/vendor/github/vakata/jstree@3.3.8/test/unit/index.html +16 -0
  90. data/public/vendor/github/vakata/jstree@3.3.8/test/unit/libs/qunit.css +244 -0
  91. data/public/vendor/github/vakata/jstree@3.3.8/test/unit/libs/qunit.js +2212 -0
  92. data/public/vendor/github/vakata/jstree@3.3.8/test/unit/test.js +11 -0
  93. data/public/vendor/github/vakata/jstree@3.3.8/test/visual/desktop/index.html +44 -0
  94. data/public/vendor/github/vakata/jstree@3.3.8/test/visual/mobile/index.html +42 -0
  95. data/public/vendor/github/vakata/jstree@3.3.8/test/visual/screenshots/desktop/desktop.png +0 -0
  96. data/public/vendor/github/vakata/jstree@3.3.8/test/visual/screenshots/desktop/home.png +0 -0
  97. data/public/vendor/github/vakata/jstree@3.3.8/test/visual/screenshots/mobile/home.png +0 -0
  98. data/public/vendor/github/vakata/jstree@3.3.8/test/visual/screenshots/mobile/mobile.png +0 -0
  99. data/public/vendor/github/vakata/jstree@3.3.8.js +3 -0
  100. data/public/vendor/system-csp-production.js +3 -3
  101. data/public/vendor/system-csp-production.js.map +1 -1
  102. data/public/vendor/system-csp-production.src.js +146 -140
  103. data/public/vendor/system-polyfills.js.map +1 -1
  104. data/public/vendor/system-polyfills.src.js +1 -0
  105. data/public/vendor/system.js +3 -3
  106. data/public/vendor/system.js.map +1 -1
  107. data/public/vendor/system.src.js +4771 -2383
  108. data/views/_options.erb +21 -0
  109. data/views/layout.erb +17 -18
  110. metadata +102 -43
  111. data/bin/chromedriver +0 -0
  112. data/bin/geckodriver +0 -0
  113. data/public/shims/form-core.js +0 -3
  114. data/public/shims/form-validation.js +0 -3
  115. data/public/shims/plugins/jquery.ui.position.js +0 -13
  116. data/public/shims/styles/shim.css +0 -1
@@ -7,28 +7,28 @@ export default class AlignmentExporter {
7
7
  var idx = 0;
8
8
  var wrapped = '';
9
9
  while(true) {
10
- wrapped += str.substring(idx, idx + width);
11
- idx += width;
12
- if(idx < str.length) {
13
- wrapped += '\n';
14
- } else {
15
- break;
16
- }
10
+ wrapped += str.substring(idx, idx + width);
11
+ idx += width;
12
+ if(idx < str.length) {
13
+ wrapped += '\n';
14
+ } else {
15
+ break;
16
+ }
17
17
  }
18
18
  return wrapped;
19
19
  }
20
20
 
21
21
  generate_fasta(hsps) {
22
22
 
23
- var fasta = "";
23
+ var fasta = '';
24
24
 
25
25
  _.each(hsps, _.bind(function (hsp) {
26
- fasta += ">"+hsp.query_id+":"+hsp.qstart+"-"+hsp.qend+"\n";
27
- fasta += hsp.qseq+"\n";
28
- fasta += ">"+hsp.query_id+":"+hsp.qstart+"-"+hsp.qend+"_alignment_"+hsp.hit_id+":"+hsp.sstart+"-"+hsp.send+"\n";
29
- fasta += hsp.midline+"\n";
30
- fasta += ">"+hsp.hit_id+":"+hsp.sstart+"-"+hsp.send+"\n";
31
- fasta += hsp.sseq+"\n";
26
+ fasta += '>'+hsp.query_id+':'+hsp.qstart+'-'+hsp.qend+'\n';
27
+ fasta += hsp.qseq+'\n';
28
+ fasta += '>'+hsp.query_id+':'+hsp.qstart+'-'+hsp.qend+'_alignment_'+hsp.hit_id+':'+hsp.sstart+'-'+hsp.send+'\n';
29
+ fasta += hsp.midline+'\n';
30
+ fasta += '>'+hsp.hit_id+':'+hsp.sstart+'-'+hsp.send+'\n';
31
+ fasta += hsp.sseq+'\n';
32
32
  }, this));
33
33
  return fasta;
34
34
  }
@@ -0,0 +1,215 @@
1
+ import React from 'react';
2
+ import _ from 'underscore';
3
+ import Jstree from 'vakata/jstree';
4
+
5
+ export default React.createClass({
6
+ getInitialState: function () {
7
+ return { type: '' };
8
+ },
9
+
10
+ databases: function (category) {
11
+ var databases = this.props.databases;
12
+ if (category) {
13
+ databases = _.select(databases, database => database.type === category);
14
+ }
15
+
16
+ return _.sortBy(databases, 'title');
17
+ },
18
+
19
+ nselected: function () {
20
+ return $('input[name="databases[]"]:checked').length;
21
+ },
22
+
23
+ categories: function () {
24
+ return _.uniq(_.map(this.props.databases,
25
+ _.iteratee('type'))).sort();
26
+ },
27
+
28
+ handleClick: function (database) {
29
+ var type = this.nselected() ? database.type : '';
30
+ if (type != this.state.type) this.setState({type: type});
31
+ },
32
+
33
+ handleLoadTree: function (category) {
34
+ var tree_id = '#' + category + '_database_tree';
35
+ // hack that is needed to sync the selected tree db with the hidden main db
36
+ window.jstree_node_change_timeout = null;
37
+
38
+ // when a tree database gets selected
39
+ $(tree_id).on('select_node.jstree deselect_node.jstree', function (e, data) {
40
+ if (window.jstree_node_change_timeout) {
41
+ clearTimeout(window.jstree_node_change_timeout);
42
+ window.jstree_node_change_timeout = null;
43
+ }
44
+
45
+ window.jstree_node_change_timeout = setTimeout(function(){
46
+ // uncheck all input
47
+ $('div#database_list input[type="checkbox"]:checked').click();
48
+ setTimeout(function(){
49
+ // get all selected tree dbs. Also includes folders. Therefore, the id must have a length of 32
50
+ // this id is used to find the corresponding element from the hidden main form
51
+ var selected = $(tree_id).jstree('get_selected').filter(selected => selected.length == 32);
52
+ $.each(selected, function( index, value ) {
53
+ // select hidden element to trigger original sequenceserver behavior, like blast algorithm, ...
54
+ $('input[value="'+ value + '"]').click();
55
+ });
56
+ }, 100);
57
+ }, 100);
58
+ });
59
+
60
+ $(tree_id).jstree({
61
+ 'core' : {
62
+ 'data': this.props.tree[category]
63
+ },
64
+ 'plugins' : [ 'checkbox', 'search', 'sort' ],
65
+ 'checkbox' : {
66
+ 'keep_selected_style' : false
67
+ }
68
+ });
69
+ },
70
+
71
+ handleTreeSearch: function(category, tree_id, search_id) {
72
+ var search_for = $('#' + search_id).val();
73
+ $('#' + tree_id).jstree(true).search(search_for);
74
+ },
75
+
76
+ handleToggle: function (toggleState, type) {
77
+ switch (toggleState) {
78
+ case '[Select all]':
79
+ $(`.${type} .database input:not(:checked)`).click();
80
+ break;
81
+ case '[Deselect all]':
82
+ $(`.${type} .database input:checked`).click();
83
+ break;
84
+ }
85
+ },
86
+
87
+ render: function () {
88
+ return (
89
+ <div className='form-group databases-container'>
90
+ { _.map(this.categories(), this.renderDatabases) }
91
+ </div>
92
+ );
93
+ },
94
+
95
+ renderDatabases: function (category) {
96
+ // Panel name and column width.
97
+ var panelTitle = category[0].toUpperCase() +
98
+ category.substring(1).toLowerCase() + ' databases';
99
+ var columnClass = this.categories().length === 1 ? 'col-md-12' :
100
+ 'col-md-6';
101
+
102
+ // Toggle button.
103
+ var toggleState = '[Select all]';
104
+ var toggleClass = 'btn-link';
105
+ var toggleShown = this.databases(category).length > 1 ;
106
+ var toggleDisabled = this.state.type && this.state.type !== category;
107
+ if (toggleShown && toggleDisabled) toggleClass += ' disabled';
108
+ if (!toggleShown) toggleClass += ' hidden';
109
+ if (this.nselected() === this.databases(category).length) {
110
+ toggleState = '[Deselect all]';
111
+ }
112
+
113
+ // JSX.
114
+ return (
115
+ <div className={columnClass} key={'DB_'+category}>
116
+ <div className='panel panel-default' id='database_list'>
117
+ <div className='panel-heading'>
118
+ <h4 style={{display: 'inline'}}>{panelTitle}</h4> &nbsp;&nbsp;
119
+ {
120
+ this.renderDatabaseSearch(category)
121
+ }
122
+ <button type='button' className={toggleClass} disabled={toggleDisabled} style={{display: 'none'}}
123
+ onClick={ function () { this.handleToggle(toggleState, category); }.bind(this) }>
124
+ {toggleState}
125
+ </button>
126
+ </div>
127
+ <ul className={'list-group databases ' + category} style={{display: 'none'}}>
128
+ {
129
+ _.map(this.databases(category), _.bind(function (database,index) {
130
+ return (
131
+ <li className='list-group-item' key={'DB_'+category+index}>
132
+ { this.renderDatabase(database) }
133
+ </li>
134
+ );
135
+ }, this))
136
+ }
137
+ </ul>
138
+ </div>
139
+ {
140
+ this.renderDatabaseTree(category)
141
+ }
142
+ </div>
143
+ );
144
+ },
145
+
146
+ renderDatabaseSearch: function (category) {
147
+ var tree_id = category + '_database_tree';
148
+ var search_id = tree_id + '_search';
149
+
150
+ return (
151
+ <input type='text' id={search_id} class='input'
152
+ onKeyUp=
153
+ {
154
+ _.bind(function () {
155
+ this.handleTreeSearch(category, tree_id, search_id);
156
+ }, this)
157
+ }
158
+ ></input>
159
+ );
160
+ },
161
+
162
+ renderDatabaseTree: function (category) {
163
+ var tree_id = category + '_database_tree';
164
+ var data = this.props.tree[category];
165
+
166
+ return (
167
+ <div
168
+ id={tree_id}
169
+ className={'jstree_div'}
170
+ onClick=
171
+ {
172
+ _.bind(function () {
173
+ this.handleLoadTree(category);
174
+ }, this)
175
+ }
176
+ >
177
+ </div>
178
+ );
179
+ },
180
+
181
+ renderDatabase: function (database) {
182
+ var disabled = this.state.type && this.state.type !== database.type;
183
+
184
+ return (
185
+ <label
186
+ className={disabled && 'disabled database' || 'database'}>
187
+ <input
188
+ type='checkbox' name='databases[]' value={database.id}
189
+ data-type={database.type} disabled={disabled}
190
+ onChange=
191
+ {
192
+ _.bind(function () {
193
+ this.handleClick(database);
194
+ }, this)
195
+ }/>
196
+ {' ' + (database.title || database.name)}
197
+ </label>
198
+ );
199
+ },
200
+
201
+ componentDidUpdate: function () {
202
+ if (this.databases() && this.databases().length === 1) {
203
+ $('.databases').find('input').prop('checked',true);
204
+ this.handleClick(this.databases()[0]);
205
+ }
206
+
207
+ if (this.props.preSelectedDbs) {
208
+ var selectors = this.props.preSelectedDbs.map(db => `input[value=${db.id}]`);
209
+ $(...selectors).prop('checked',true);
210
+ this.handleClick(this.props.preSelectedDbs[0]);
211
+ this.props.preSelectedDbs = null;
212
+ }
213
+ this.props.onDatabaseTypeChanged(this.state.type);
214
+ }
215
+ });
@@ -14,4 +14,4 @@ export default function downloadFASTA(sequence_ids, database_ids) {
14
14
  $('<input>').attr('type', 'hidden').attr('name', name).val(val)
15
15
  );
16
16
  }
17
- };
17
+ }
data/public/js/hit.js CHANGED
@@ -30,6 +30,10 @@ export default React.createClass({
30
30
  return this.props.hit.length;
31
31
  },
32
32
 
33
+ numHSPs: function () {
34
+ return this.props.hit.hsps.length;
35
+ },
36
+
33
37
  // Internal helpers. //
34
38
 
35
39
  /**
@@ -119,14 +123,14 @@ export default React.createClass({
119
123
  { this.hitLinks() }
120
124
  <HSPOverview key={'kablammo' + this.props.query.id} query={this.props.query}
121
125
  hit={this.props.hit} algorithm={this.props.algorithm}
122
- showHSPCrumbs={this.props.hit.hsps.length > 1}
126
+ showHSPCrumbs={this.numHSPs() > 1 && this.numHSPs() < 27}
123
127
  collapsed={this.props.veryBig} />
124
128
  </div>;
125
129
  },
126
130
 
127
131
  hitLinks: function () {
128
132
  var btns = [];
129
- if (!this.props.imported_xml) {
133
+ if (!(this.props.imported_xml || this.props.non_parse_seqids)) {
130
134
  btns = btns.concat([
131
135
  this.viewSequenceButton(),
132
136
  this.downloadFASTAButton()
@@ -49,7 +49,7 @@ class Graph {
49
49
  });
50
50
  _hsps.hitId = hit.id;
51
51
  _hsps.hitDef = 'Query_'+number+'_hit_'+hit.number;
52
- _hsps.hitEvalue = hit.evalue;
52
+ _hsps.hitEvalue = hit.hsps[0].evalue;
53
53
  hits.push(_hsps);
54
54
  });
55
55
  return hits;
@@ -9,7 +9,7 @@ import * as Helpers from './visualisation_helpers';
9
9
 
10
10
  class Graph {
11
11
  static name() {
12
- return 'Length distribution of hits';
12
+ return 'Length distribution of matching sequences';
13
13
  }
14
14
 
15
15
  static className() {
@@ -69,8 +69,7 @@ class Graph {
69
69
  .range([0, this._width]);
70
70
  this._bins = d3.layout.histogram()
71
71
  .range(this._scale_x.domain())
72
- .bins(this._scale_x.ticks(50))
73
- (this._data);
72
+ .bins(this._scale_x.ticks(50))(this._data);
74
73
  this._scale_y = d3.scale.linear()
75
74
  .domain([0, d3.max(this._bins, function(d) { return d.length; })])
76
75
  .range([this._height, 0]).nice();
@@ -129,14 +128,15 @@ class Graph {
129
128
  bin.map(function (d,i) {
130
129
  var y1 = bin.length - (i+1);
131
130
  var len_index = _.findIndex(self.query.hits, {length: d});
131
+ var evalue = self.query.hits[len_index].hsps[0].evalue;
132
132
  var item = {
133
133
  value: d,
134
134
  id: self.query.hits[len_index].id,
135
- evalue: self.query.hits[len_index].evalue,
135
+ evalue: evalue,
136
136
  url: '#Query_'+self.query.number+'_hit_'+self.query.hits[len_index].number,
137
137
  y0: y0,
138
138
  y1: y0 += (y1 - y0),
139
- color: Helpers.get_colors_for_evalue(self.query.hits[len_index].evalue,self.query.hits)
139
+ color: Helpers.get_colors_for_evalue(evalue,self.query.hits)
140
140
  };
141
141
  inner_data.push(item);
142
142
  });
data/public/js/query.js CHANGED
@@ -111,7 +111,7 @@ var HitsTable = React.createClass({
111
111
  <div className="table-hit-overview">
112
112
  <h4 className="caption" data-toggle="collapse" data-target={'#Query_'+this.props.query.number+'HT_'+this.props.query.number}>
113
113
  <i className="fa fa-minus-square-o"></i>&nbsp;
114
- <span>Summary table of hits</span>
114
+ <span>Sequences producing significant alignments</span>
115
115
  </h4>
116
116
  <div className="collapsed in"id={'Query_'+ this.props.query.number + 'HT_'+ this.props.query.number}>
117
117
  <table
@@ -123,10 +123,7 @@ var HitsTable = React.createClass({
123
123
  {!this.props.imported_xml && <th width="15%" className="text-right">Query coverage (%)</th>}
124
124
  <th width="10%" className="text-right">Total score</th>
125
125
  <th width="10%" className="text-right">E value</th>
126
- <th width="10%" className="text-right" data-toggle="tooltip"
127
- data-placement="left" title="Total identity of all hsps / total length of all hsps">
128
- Identity (%)
129
- </th>
126
+ <th width="10%" className="text-right">Identity (%)</th>
130
127
  </thead>
131
128
  <tbody>
132
129
  {
@@ -147,9 +144,9 @@ var HitsTable = React.createClass({
147
144
  </td>
148
145
  }
149
146
  {!this.props.imported_xml && <td className="text-right">{hit.qcovs}</td>}
150
- <td className="text-right">{hit.score}</td>
147
+ <td className="text-right">{hit.total_score}</td>
151
148
  <td className="text-right">{this.inExponential(hit.hsps[0].evalue)}</td>
152
- <td className="text-right">{hit.identity}</td>
149
+ <td className="text-right">{this.inPercentage(hit.hsps[0].identity, hit.hsps[0].length)}</td>
153
150
  </tr>
154
151
  );
155
152
  }, this))
data/public/js/report.js CHANGED
@@ -203,6 +203,7 @@ var Report = React.createClass({
203
203
  results.push(<Query key={'Query_'+query.number} query={query}
204
204
  program={this.state.program} querydb={this.state.querydb}
205
205
  showQueryCrumbs={this.state.queries.length > 1}
206
+ non_parse_seqids={this.state.non_parse_seqids}
206
207
  imported_xml={this.state.imported_xml}
207
208
  veryBig={this.state.veryBig} />);
208
209
  }
@@ -216,6 +217,7 @@ var Report = React.createClass({
216
217
  results.push(<Hit key={'Query_'+query.number+'_Hit_'+hit.number} query={query}
217
218
  hit={hit} algorithm={this.state.program} querydb={this.state.querydb}
218
219
  selectHit={this.selectHit} imported_xml={this.state.imported_xml}
220
+ non_parse_seqids={this.state.non_parse_seqids}
219
221
  showQueryCrumbs={this.state.queries.length > 1}
220
222
  showHitCrumbs={query.hits.length > 1}
221
223
  veryBig={this.state.veryBig}
@@ -301,14 +303,12 @@ var Report = React.createClass({
301
303
  resultsJSX: function () {
302
304
  return (
303
305
  <div className="row">
304
- { this.shouldShowSidebar() &&
305
- (
306
- <div className="col-md-3 hidden-sm hidden-xs">
307
- <Sidebar data={this.state} shouldShowIndex={this.shouldShowIndex()}/>
308
- </div>
309
- )
310
- }
311
- <div className={this.shouldShowSidebar() ? 'col-md-9' : 'col-md-12'}>
306
+ <div className="col-md-3 hidden-sm hidden-xs">
307
+ <Sidebar data={this.state}
308
+ atLeastOneHit={this.atLeastOneHit()}
309
+ shouldShowIndex={this.shouldShowIndex()} />
310
+ </div>
311
+ <div className="col-md-9">
312
312
  { this.overviewJSX() }
313
313
  { this.circosJSX() }
314
314
  { this.state.results }
@@ -387,17 +387,6 @@ var Report = React.createClass({
387
387
  });
388
388
  },
389
389
 
390
- /**
391
- * Returns true if sidebar should be shown.
392
- *
393
- * Sidebar is not shown if there is only one query and there are no hits
394
- * corresponding to the query.
395
- */
396
- shouldShowSidebar: function () {
397
- return !(this.state.queries.length == 1 &&
398
- this.state.queries[0].hits.length == 0);
399
- },
400
-
401
390
  /**
402
391
  * Returns true if index should be shown in the sidebar. Index is shown
403
392
  * only for 2 and 8 queries.
@@ -446,7 +435,7 @@ var Report = React.createClass({
446
435
  */
447
436
  affixSidebar: function () {
448
437
  var $sidebar = $('.sidebar');
449
- var sidebarOffset = $sidebar.offset()
438
+ var sidebarOffset = $sidebar.offset();
450
439
  if (sidebarOffset) {
451
440
  $sidebar.affix({
452
441
  offset: {
@@ -492,17 +481,16 @@ var Report = React.createClass({
492
481
  $hit.next('.hsp').removeClass('glow');
493
482
  }
494
483
 
484
+ var $a = $('.download-fasta-of-selected');
485
+ var $b = $('.download-alignment-of-selected');
486
+
495
487
  if (num_checked >= 1)
496
488
  {
497
- var $a = $('.download-fasta-of-selected');
498
- var $b = $('.download-alignment-of-selected');
499
489
  $a.find('.text-bold').html(num_checked);
500
490
  $b.find('.text-bold').html(num_checked);
501
491
  }
502
492
 
503
493
  if (num_checked == 0) {
504
- var $a = $('.download-fasta-of-selected');
505
- var $b = $('.download-alignment-of-selected');
506
494
  $a.addClass('disabled').find('.text-bold').html('');
507
495
  $b.addClass('disabled').find('.text-bold').html('');
508
496
  }
data/public/js/search.js CHANGED
@@ -1,10 +1,12 @@
1
1
  import './jquery_world';
2
2
  import React from 'react';
3
3
  import _ from 'underscore';
4
+ import DatabasesTree from './databases_tree';
4
5
 
5
6
  /**
6
7
  * Load necessary polyfills.
7
8
  */
9
+ $.webshims.setOptions('basePath', '/vendor/npm/webshim@1.15.8/js-webshim/minified/shims/');
8
10
  $.webshims.polyfill('forms');
9
11
 
10
12
  /**
@@ -206,7 +208,7 @@ var DnD = React.createClass({
206
208
  var Form = React.createClass({
207
209
 
208
210
  getInitialState: function () {
209
- return { databases: {}, preDefinedOpts: {} };
211
+ return { databases: [], preDefinedOpts: {}, tree: {} };
210
212
  },
211
213
 
212
214
  componentDidMount: function () {
@@ -225,6 +227,7 @@ var Form = React.createClass({
225
227
  * advanced options.
226
228
  */
227
229
  this.setState({
230
+ tree: data['tree'],
228
231
  databases: data['database'],
229
232
  preSelectedDbs: data['preSelectedDbs'],
230
233
  preDefinedOpts: data['options']
@@ -236,6 +239,10 @@ var Form = React.createClass({
236
239
  if (data['query']) {
237
240
  this.refs.query.value(data['query']);
238
241
  }
242
+
243
+ setTimeout(function(){
244
+ $('.jstree_div').click();
245
+ }, 1000);
239
246
  }.bind(this));
240
247
 
241
248
  /* Enable submitting form on Cmd+Enter */
@@ -248,6 +255,10 @@ var Form = React.createClass({
248
255
  });
249
256
  },
250
257
 
258
+ useTreeWidget: function () {
259
+ return !_.isEmpty(this.state.tree);
260
+ },
261
+
251
262
  determineBlastMethod: function () {
252
263
  var database_type = this.databaseType;
253
264
  var sequence_type = this.sequenceType;
@@ -335,9 +346,16 @@ var Form = React.createClass({
335
346
  <ProteinNotification/>
336
347
  <MixedNotification/>
337
348
  </div>
349
+ {this.useTreeWidget() ?
350
+ <DatabasesTree ref="databases"
351
+ databases={this.state.databases} tree={this.state.tree}
352
+ preSelectedDbs={this.state.preSelectedDbs}
353
+ onDatabaseTypeChanged={this.handleDatabaseTypeChanaged} />
354
+ :
338
355
  <Databases ref="databases" databases={this.state.databases}
339
356
  preSelectedDbs={this.state.preSelectedDbs}
340
357
  onDatabaseTypeChanged={this.handleDatabaseTypeChanaged} />
358
+ }
341
359
  <div className="form-group">
342
360
  <Options ref="opts"/>
343
361
  <div className="col-md-2">
@@ -687,6 +705,7 @@ var Databases = React.createClass({
687
705
  $(`.${type} .database input:checked`).click();
688
706
  break;
689
707
  }
708
+ this.forceUpdate();
690
709
  },
691
710
 
692
711
  render: function () {
@@ -770,7 +789,7 @@ var Databases = React.createClass({
770
789
 
771
790
  if (this.props.preSelectedDbs) {
772
791
  var selectors = this.props.preSelectedDbs.map(db => `input[value=${db.id}]`);
773
- $(...selectors).prop('checked',true);
792
+ $(selectors.join(',')).prop('checked',true);
774
793
  this.handleClick(this.props.preSelectedDbs[0]);
775
794
  this.props.preSelectedDbs = null;
776
795
  }
data/public/js/sidebar.js CHANGED
@@ -166,15 +166,15 @@ export default React.createClass({
166
166
  </div>
167
167
  <ul className="nav">
168
168
  {
169
- !this.props.data.imported_xml && <li>
170
- <a href="#" className="btn-link download-fasta-of-all"
169
+ !(this.props.data.imported_xml || this.props.data.non_parse_seqids) && <li>
170
+ <a href="#" className={`btn-link download-fasta-of-all ${!this.props.atLeastOneHit && 'disabled'}`}
171
171
  onClick={this.downloadFastaOfAll}>
172
172
  FASTA of all hits
173
173
  </a>
174
174
  </li>
175
175
  }
176
176
  {
177
- !this.props.data.imported_xml && <li>
177
+ !(this.props.data.imported_xml || this.props.data.non_parse_seqids) && <li>
178
178
  <a href="#" className="btn-link download-fasta-of-selected disabled"
179
179
  onClick={this.downloadFastaOfSelected}>
180
180
  FASTA of <span className="text-bold"></span> selected hit(s)
@@ -182,7 +182,7 @@ export default React.createClass({
182
182
  </li>
183
183
  }
184
184
  <li>
185
- <a href="#" className="btn-link download-alignment-of-all"
185
+ <a href="#" className={`btn-link download-alignment-of-all ${!this.props.atLeastOneHit && 'disabled'}`}
186
186
  onClick={this.downloadAlignmentOfAll}>
187
187
  Alignment of all hits
188
188
  </a>
@@ -16,7 +16,7 @@ var export_as_svg = function (svg, filename) {
16
16
  var blob = new Blob([serialize_svg(svg)], { type: 'text/xml' });
17
17
  filename = Exporter.sanitize_filename(filename) + '.svg';
18
18
  Exporter.download_blob(blob, filename);
19
- }
19
+ };
20
20
 
21
21
  /**
22
22
  * Exports the given <svg> DOM node as a .png file.
@@ -45,19 +45,19 @@ var export_as_png = function (svg, filename) {
45
45
  };
46
46
 
47
47
  img.src = 'data:image/svg+xml;base64,' + window.btoa(serialize_svg(svg));
48
- }
48
+ };
49
49
 
50
50
  var serialize_svg = function(svg) {
51
51
  // Clone svg first so that none of our changes to affect the actual SVG.
52
52
  svg = svg.cloneNode(true);
53
53
 
54
54
  d3.select(svg).attr('version', '1.1')
55
- .insert('defs', ':first-child')
56
- .append('style')
57
- .attr('class', 'exported-css')
58
- .attr('type', 'text/css')
59
- .node()
60
- .textContent = get_styles();
55
+ .insert('defs', ':first-child')
56
+ .append('style')
57
+ .attr('class', 'exported-css')
58
+ .attr('type', 'text/css')
59
+ .node()
60
+ .textContent = get_styles();
61
61
 
62
62
  svg.removeAttribute('xmlns');
63
63
  svg.removeAttribute('xlink');
@@ -67,8 +67,8 @@ var serialize_svg = function(svg) {
67
67
  var source = (new XMLSerializer()).serializeToString(svg);
68
68
  var doctype = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC ' +
69
69
  '"-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';
70
- return doctype + source;
71
- }
70
+ return doctype + source;
71
+ };
72
72
 
73
73
  var get_styles = function () {
74
74
  var styles = '';
@@ -113,14 +113,14 @@ var get_styles = function () {
113
113
  }
114
114
 
115
115
  return styles;
116
- }
116
+ };
117
117
 
118
118
  var handle_click = function (export_callback) {
119
119
  return function () {
120
120
  var $svg = $(this).parents('.grapher').find('svg');
121
121
  export_callback($svg[0], $svg.attr('data-name'));
122
122
  return false;
123
- }
123
+ };
124
124
  };
125
125
 
126
126
  var $body = $('body');
@@ -39,16 +39,15 @@ export function tick_formatter(scale, seq_type) {
39
39
  var digits = 0;
40
40
  var format;
41
41
  var _ticks;
42
- while (true) {
42
+
43
+ do {
43
44
  format = d3.format('.' + digits + 'f');
44
45
  _ticks = scale.ticks().map(function (d) {
45
46
  return format(prefix.scale(d));
46
47
  });
47
- if (_ticks.length === _.uniq(_ticks).length) {
48
- break;
49
- }
50
48
  digits++;
51
- }
49
+
50
+ } while (_ticks.length !== _.uniq(_ticks).length);
52
51
 
53
52
  return function (d) {
54
53
  if (!prefix.symbol || d === scale.domain()[0]) {