sequenceserver 2.0.0.rc8 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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]) {