sequenceserver 0.6.8 → 0.6.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,10 +2,8 @@
2
2
  # copyright yannick . wurm at unil . ch
3
3
  # Finds files, reads first char. if its '>', read 500 lines. Guess sequence type, ask user for title to format as blast database.
4
4
 
5
- # ensure 'lib/' is in the load path
6
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
-
8
5
  require 'rubygems'
6
+ require 'bundler/setup'
9
7
  require 'ptools' # for File.binary?(file)
10
8
  require 'find'
11
9
  require 'logger'
data/bin/sequenceserver CHANGED
@@ -1,10 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- # application root
4
- root = File.dirname(File.dirname(__FILE__))
5
-
6
3
  require 'rubygems'
7
- require File.join(root, 'lib', 'sequenceserver')
4
+ require 'bundler/setup'
5
+ require 'sequenceserver'
8
6
 
9
7
  # display name for tools like `ps`
10
8
  $PROGRAM_NAME = 'sequenceserver'
@@ -1,9 +1,5 @@
1
1
  # sequenceserver.rb
2
2
 
3
- # ensure 'lib/' is in the load path
4
- $LOAD_PATH.unshift(File.dirname(__FILE__))
5
-
6
- require 'rubygems'
7
3
  require 'sinatra/base'
8
4
  require 'yaml'
9
5
  require 'logger'
@@ -233,8 +229,10 @@ module SequenceServer
233
229
  # evaluate empty sequence as nil, otherwise as fasta
234
230
  sequence = sequence.empty? ? nil : to_fasta(sequence)
235
231
 
232
+ # TODO: detect sequence type in the browser itself (no AJAX)
236
233
  if request.xhr?
237
- return (sequence && type_of_sequences(sequence)).to_s
234
+ # if the AJAX request didn't specify a blast method, it must be interested in sequence type only
235
+ return (sequence && type_of_sequences(sequence)).to_s unless method
238
236
  end
239
237
 
240
238
  # Raise ArgumentError if there is no database selected
@@ -293,6 +291,10 @@ module SequenceServer
293
291
 
294
292
  @blast = format_blast_results(blast.result, databases)
295
293
 
294
+ if request.xhr?
295
+ return @blast
296
+ end
297
+
296
298
  erb :search
297
299
  end
298
300
 
@@ -66,6 +66,7 @@ body {
66
66
  border-radius: 6px;
67
67
  -moz-border-radius: 6px;
68
68
  padding: 3%;
69
+ border: 1px solid transparent;
69
70
  }
70
71
 
71
72
  .focussed {
@@ -0,0 +1,224 @@
1
+ /*!
2
+ * NETEYE Activity Indicator jQuery Plugin
3
+ *
4
+ * Copyright (c) 2010 NETEYE GmbH
5
+ * Licensed under the MIT license
6
+ *
7
+ * Author: Felix Gnass [fgnass at neteye dot de]
8
+ * Version: @{VERSION}
9
+ */
10
+
11
+ /**
12
+ * Plugin that renders a customisable activity indicator (spinner) using SVG or VML.
13
+ */
14
+ (function($) {
15
+
16
+ $.fn.activity = function(opts) {
17
+ this.each(function() {
18
+ var $this = $(this);
19
+ var el = $this.data('activity');
20
+ if (el) {
21
+ clearInterval(el.data('interval'));
22
+ el.remove();
23
+ $this.removeData('activity');
24
+ }
25
+ if (opts !== false) {
26
+ opts = $.extend({color: $this.css('color')}, $.fn.activity.defaults, opts);
27
+
28
+ el = render($this, opts).css('position', 'absolute').prependTo(opts.outside ? 'body' : $this);
29
+ var h = $this.outerHeight() - el.height();
30
+ var w = $this.outerWidth() - el.width();
31
+ var margin = {
32
+ top: opts.valign == 'top' ? opts.padding : opts.valign == 'bottom' ? h - opts.padding : Math.floor(h / 2),
33
+ left: opts.align == 'left' ? opts.padding : opts.align == 'right' ? w - opts.padding : Math.floor(w / 2)
34
+ };
35
+ var offset = $this.offset();
36
+ if (opts.outside) {
37
+ el.css({top: offset.top + 'px', left: offset.left + 'px'});
38
+ }
39
+ else {
40
+ margin.top -= el.offset().top - offset.top;
41
+ margin.left -= el.offset().left - offset.left;
42
+ }
43
+ el.css({marginTop: margin.top + 'px', marginLeft: margin.left + 'px'});
44
+ animate(el, opts.segments, Math.round(10 / opts.speed) / 10);
45
+ $this.data('activity', el);
46
+ }
47
+ });
48
+ return this;
49
+ };
50
+
51
+ $.fn.activity.defaults = {
52
+ segments: 12,
53
+ space: 3,
54
+ length: 7,
55
+ width: 4,
56
+ speed: 1.2,
57
+ align: 'center',
58
+ valign: 'center',
59
+ padding: 4
60
+ };
61
+
62
+ $.fn.activity.getOpacity = function(opts, i) {
63
+ var steps = opts.steps || opts.segments-1;
64
+ var end = opts.opacity !== undefined ? opts.opacity : 1/steps;
65
+ return 1 - Math.min(i, steps) * (1 - end) / steps;
66
+ };
67
+
68
+ /**
69
+ * Default rendering strategy. If neither SVG nor VML is available, a div with class-name 'busy'
70
+ * is inserted, that can be styled with CSS to display an animated gif as fallback.
71
+ */
72
+ var render = function() {
73
+ return $('<div>').addClass('busy');
74
+ };
75
+
76
+ /**
77
+ * The default animation strategy does nothing as we expect an animated gif as fallback.
78
+ */
79
+ var animate = function() {
80
+ };
81
+
82
+ /**
83
+ * Utility function to create elements in the SVG namespace.
84
+ */
85
+ function svg(tag, attr) {
86
+ var el = document.createElementNS("http://www.w3.org/2000/svg", tag || 'svg');
87
+ if (attr) {
88
+ $.each(attr, function(k, v) {
89
+ el.setAttributeNS(null, k, v);
90
+ });
91
+ }
92
+ return $(el);
93
+ }
94
+
95
+ if (document.createElementNS && document.createElementNS( "http://www.w3.org/2000/svg", "svg").createSVGRect) {
96
+
97
+ // =======================================================================================
98
+ // SVG Rendering
99
+ // =======================================================================================
100
+
101
+ /**
102
+ * Rendering strategy that creates a SVG tree.
103
+ */
104
+ render = function(target, d) {
105
+ var innerRadius = d.width*2 + d.space;
106
+ var r = (innerRadius + d.length + Math.ceil(d.width / 2) + 1);
107
+
108
+ var el = svg().width(r*2).height(r*2);
109
+
110
+ var g = svg('g', {
111
+ 'stroke-width': d.width,
112
+ 'stroke-linecap': 'round',
113
+ stroke: d.color
114
+ }).appendTo(svg('g', {transform: 'translate('+ r +','+ r +')'}).appendTo(el));
115
+
116
+ for (var i = 0; i < d.segments; i++) {
117
+ g.append(svg('line', {
118
+ x1: 0,
119
+ y1: innerRadius,
120
+ x2: 0,
121
+ y2: innerRadius + d.length,
122
+ transform: 'rotate(' + (360 / d.segments * i) + ', 0, 0)',
123
+ opacity: $.fn.activity.getOpacity(d, i)
124
+ }));
125
+ }
126
+ return $('<div>').append(el).width(2*r).height(2*r);
127
+ };
128
+
129
+ // Check if Webkit CSS animations are available, as they work much better on the iPad
130
+ // than setTimeout() based animations.
131
+
132
+ if (document.createElement('div').style.WebkitAnimationName !== undefined) {
133
+
134
+ var animations = {};
135
+
136
+ /**
137
+ * Animation strategy that uses dynamically created CSS animation rules.
138
+ */
139
+ animate = function(el, steps, duration) {
140
+ if (!animations[steps]) {
141
+ var name = 'spin' + steps;
142
+ var rule = '@-webkit-keyframes '+ name +' {';
143
+ for (var i=0; i < steps; i++) {
144
+ var p1 = Math.round(100000 / steps * i) / 1000;
145
+ var p2 = Math.round(100000 / steps * (i+1) - 1) / 1000;
146
+ var value = '% { -webkit-transform:rotate(' + Math.round(360 / steps * i) + 'deg); }\n';
147
+ rule += p1 + value + p2 + value;
148
+ }
149
+ rule += '100% { -webkit-transform:rotate(100deg); }\n}';
150
+ document.styleSheets[0].insertRule(rule);
151
+ animations[steps] = name;
152
+ }
153
+ el.css('-webkit-animation', animations[steps] + ' ' + duration +'s linear infinite');
154
+ };
155
+ }
156
+ else {
157
+
158
+ /**
159
+ * Animation strategy that transforms a SVG element using setInterval().
160
+ */
161
+ animate = function(el, steps, duration) {
162
+ var rotation = 0;
163
+ var g = el.find('g g').get(0);
164
+ el.data('interval', setInterval(function() {
165
+ g.setAttributeNS(null, 'transform', 'rotate(' + (++rotation % steps * (360 / steps)) + ')');
166
+ }, duration * 1000 / steps));
167
+ };
168
+ }
169
+
170
+ }
171
+ else {
172
+
173
+ // =======================================================================================
174
+ // VML Rendering
175
+ // =======================================================================================
176
+
177
+ var s = $('<shape>').css('behavior', 'url(#default#VML)');
178
+
179
+ $('body').append(s);
180
+
181
+ if (s.get(0).adj) {
182
+
183
+ // VML support detected. Insert CSS rules for group, shape and stroke.
184
+ var sheet = document.createStyleSheet();
185
+ $.each(['group', 'shape', 'stroke'], function() {
186
+ sheet.addRule(this, "behavior:url(#default#VML);");
187
+ });
188
+
189
+ /**
190
+ * Rendering strategy that creates a VML tree.
191
+ */
192
+ render = function(target, d) {
193
+
194
+ var innerRadius = d.width*2 + d.space;
195
+ var r = (innerRadius + d.length + Math.ceil(d.width / 2) + 1);
196
+ var s = r*2;
197
+ var o = -Math.ceil(s/2);
198
+
199
+ var el = $('<group>', {coordsize: s + ' ' + s, coordorigin: o + ' ' + o}).css({top: o, left: o, width: s, height: s});
200
+ for (var i = 0; i < d.segments; i++) {
201
+ el.append($('<shape>', {path: 'm ' + innerRadius + ',0 l ' + (innerRadius + d.length) + ',0'}).css({
202
+ width: s,
203
+ height: s,
204
+ rotation: (360 / d.segments * i) + 'deg'
205
+ }).append($('<stroke>', {color: d.color, weight: d.width + 'px', endcap: 'round', opacity: $.fn.activity.getOpacity(d, i)})));
206
+ }
207
+ return $('<group>', {coordsize: s + ' ' + s}).css({width: s, height: s, overflow: 'hidden'}).append(el);
208
+ };
209
+
210
+ /**
211
+ * Animation strategy that modifies the VML rotation property using setInterval().
212
+ */
213
+ animate = function(el, steps, duration) {
214
+ var rotation = 0;
215
+ var g = el.get(0);
216
+ el.data('interval', setInterval(function() {
217
+ g.style.rotation = ++rotation % steps * (360 / steps);
218
+ }, duration * 1000 / steps));
219
+ };
220
+ }
221
+ $(s).remove();
222
+ }
223
+
224
+ })(jQuery);
data/public/js/search.js CHANGED
@@ -129,6 +129,23 @@ $(document).ready(function(){
129
129
  $.onedb();
130
130
  });
131
131
 
132
+ $('input:submit').click(function(){
133
+ var button = $(this);
134
+
135
+ //prevent submitting another query while this one is being processed
136
+ button.disable();
137
+
138
+ //fetch results now
139
+ $.post('', $('form').serialize(), function(data){
140
+ $('#result').html(data);
141
+ location.hash = '#result';
142
+
143
+ //result of previous query loaded; allow submitting a new query now
144
+ button.enable();
145
+ });
146
+ return false;
147
+ });
148
+
132
149
  $(window).scroll(function() {
133
150
  var areaHeight = $(this).height();
134
151
 
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  # meta
3
3
  s.name = 'sequenceserver'
4
- s.version = '0.6.8'
4
+ s.version = '0.6.9'
5
5
  s.authors = ['Anurag Priyam', 'Ben J Woodcroft', 'Yannick Wurm']
6
6
  s.email = 'anurag08priyam@gmail.com'
7
7
  s.homepage = 'http://sequenceserver.com'
@@ -13,6 +13,7 @@ SequenceServer lets you rapidly set up a BLAST+ server with an intuitive user in
13
13
  DESC
14
14
 
15
15
  # dependencies
16
+ s.add_dependency('bundler')
16
17
  s.add_dependency('sinatra', '>= 1.2.0')
17
18
  s.add_dependency('ptools')
18
19
 
data/views/search.erb CHANGED
@@ -1,11 +1,12 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
- <title>SequenceServer</title>
4
+ <title>SequenceServer: Custom BLAST Server</title>
5
5
  <meta name="author" content="Anurag Priyam" />
6
6
  <meta name="author" content="Ben J. Woodcroft" />
7
7
  <meta name="author" content="Yannick Wurm" />
8
8
  <meta name="author" content="Cedric Wurm" />
9
+ <meta name="description" content="Custom BLAST server provided by SequenceServer (http://www.sequenceserver.com)"/>
9
10
  <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
10
11
  <script type="text/javascript" src="<%= uri('/js/jquery.js') %>"></script>
11
12
  <script type="text/javascript" src="<%= uri('/js/jquery.enablePlaceholder.min.js') %>"></script>
@@ -213,7 +214,7 @@
213
214
  </div>
214
215
 
215
216
  <div id="underbar">
216
- <p>&copy; <a href='http://www.sequenceserver.com'>sequenceserver.com</a></p>
217
+ <p>&copy; <a href='http://www.sequenceserver.com'>SequenceServer: BLAST search made easy!</a></p>
217
218
  </div>
218
219
  </div> <!-- /page -->
219
220
  </div> <!-- /container -->
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequenceserver
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 6
9
- - 8
10
- version: 0.6.8
9
+ - 9
10
+ version: 0.6.9
11
11
  platform: ruby
12
12
  authors:
13
13
  - Anurag Priyam
@@ -17,12 +17,26 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2011-12-15 00:00:00 Z
20
+ date: 2011-12-16 00:00:00 Z
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
23
- name: sinatra
23
+ name: bundler
24
24
  prerelease: false
25
25
  requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 0
33
+ version: "0"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: sinatra
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
26
40
  none: false
27
41
  requirements:
28
42
  - - ">="
@@ -34,11 +48,11 @@ dependencies:
34
48
  - 0
35
49
  version: 1.2.0
36
50
  type: :runtime
37
- version_requirements: *id001
51
+ version_requirements: *id002
38
52
  - !ruby/object:Gem::Dependency
39
53
  name: ptools
40
54
  prerelease: false
41
- requirement: &id002 !ruby/object:Gem::Requirement
55
+ requirement: &id003 !ruby/object:Gem::Requirement
42
56
  none: false
43
57
  requirements:
44
58
  - - ">="
@@ -48,7 +62,7 @@ dependencies:
48
62
  - 0
49
63
  version: "0"
50
64
  type: :runtime
51
- version_requirements: *id002
65
+ version_requirements: *id003
52
66
  description: |
53
67
  SequenceServer lets you rapidly set up a BLAST+ server with an intuitive user interface for use locally or over the web.
54
68
 
@@ -76,6 +90,7 @@ files:
76
90
  - public/js/jquery.js
77
91
  - public/js/jquery.enablePlaceholder.min.js
78
92
  - public/js/search.js
93
+ - public/js/jquery.activity.js
79
94
  - tests/test_sequencehelpers.rb
80
95
  - tests/database/protein/Sinvicta2-2-3.prot.subset.fasta.pin
81
96
  - tests/database/protein/Sinvicta2-2-3.prot.subset.fasta
@@ -140,3 +155,4 @@ specification_version: 3
140
155
  summary: iPod of BLAST searching
141
156
  test_files: []
142
157
 
158
+ has_rdoc: