rbbt-views 1.0.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/rbbt/workflow/rest.rb +365 -95
- data/lib/rbbt/workflow/rest/client.rb +2 -0
- data/lib/rbbt/workflow/rest/entity.rb +82 -76
- data/lib/rbbt/workflow/rest/finder.rb +78 -0
- data/lib/rbbt/workflow/rest/helpers.rb +288 -47
- data/lib/rbbt/workflow/rest/notes.rb +125 -0
- data/lib/rbbt/workflow/rest/render.rb +280 -240
- data/lib/rbbt/workflow/rest/util.rb +47 -31
- data/share/views/compass/_base.sass +0 -8
- data/share/views/compass/colors.sass +10 -0
- data/share/views/compass/colors/ventana_azul.sass +5 -0
- data/share/views/compass/compass.config +2 -1
- data/share/views/compass/details.sass +50 -0
- data/share/views/compass/dom.sass +64 -0
- data/share/views/compass/embedded.sass +111 -0
- data/share/views/compass/entities.sass +8 -0
- data/share/views/compass/error.sass +13 -0
- data/share/views/compass/finder.sass +42 -0
- data/share/views/compass/fonts.sass +8 -0
- data/share/views/compass/form.sass +49 -1
- data/share/views/compass/header.sass +68 -0
- data/share/views/compass/{main.sass → helpers.sass} +53 -21
- data/share/views/compass/layout.sass +31 -199
- data/share/views/compass/lists.sass +128 -0
- data/share/views/compass/menu.sass +35 -0
- data/share/views/compass/notes.sass +52 -0
- data/share/views/compass/sizes.sass +8 -0
- data/share/views/compass/tables.sass +22 -0
- data/share/views/compass/wait.sass +9 -0
- data/share/views/edit_list.haml +41 -30
- data/share/views/entity/GOTerm.haml +4 -3
- data/share/views/entity/Gene.haml +8 -1
- data/share/views/entity/GenomicMutation.haml +4 -1
- data/share/views/entity/KeggPathway.haml +1 -1
- data/share/views/entity/MutatedIsoform.haml +68 -11
- data/share/views/entity/NCIBioCartaPathway.haml +2 -3
- data/share/views/entity/NCINaturePathway.haml +3 -3
- data/share/views/entity/NCIReactomePathway.haml +2 -3
- data/share/views/entity/PfamDomain.haml +2 -0
- data/share/views/entity/Transcript.haml +10 -0
- data/share/views/entity_list/Default.haml +4 -0
- data/share/views/entity_list/Default/compare_to_other_lists.haml +41 -0
- data/share/views/entity_list/Default/entity_links.haml +6 -0
- data/share/views/entity_list/Default/find_in_other_lists.haml +36 -0
- data/share/views/error.haml +6 -1
- data/share/views/find.haml +10 -0
- data/share/views/form.haml +1 -1
- data/share/views/info.haml +1 -1
- data/share/views/js/_action_setup.js +250 -0
- data/share/views/js/_basic.js +269 -0
- data/share/views/js/_cytoscape.js +44 -0
- data/share/views/js/_details.js +239 -0
- data/share/views/js/_dom_updates.js +384 -0
- data/share/views/js/_embedded.js +95 -0
- data/share/views/js/_images.js +20 -0
- data/share/views/js/_layout.js +21 -0
- data/share/views/js/_lists.js +224 -0
- data/share/views/js/_table.js +36 -0
- data/share/views/js/_workflow.js +42 -0
- data/share/views/js/app.js +0 -570
- data/share/views/js/fix_tablesorter_scientific.js +25 -0
- data/share/views/js/json2.js +487 -0
- data/share/views/layout.haml +8 -98
- data/share/views/notes.haml +15 -0
- data/share/views/partials/_form.haml +22 -7
- data/share/views/partials/_job_control.haml +8 -8
- data/share/views/partials/_list_control.haml +32 -0
- data/share/views/partials/_list_header.haml +6 -0
- data/share/views/partials/_note_list.haml +64 -0
- data/share/views/partials/_result_table.haml +12 -7
- data/share/views/partials/_result_table_controls.haml +11 -5
- data/share/views/partials/_table.haml +24 -6
- data/share/views/partials/layout/_coda.haml +10 -0
- data/share/views/partials/layout/_details.haml +25 -0
- data/share/views/partials/layout/_head.haml +22 -0
- data/share/views/partials/layout/_header.haml +29 -0
- data/share/views/partials/layout/_menu.haml +20 -0
- data/share/views/partials/layout/_resources.haml +41 -0
- data/share/views/public/background.png +0 -0
- data/share/views/public/plugins/cytoscape-web/LICENSE.txt +504 -0
- data/share/views/public/plugins/cytoscape-web/README.txt +213 -0
- data/share/views/public/plugins/cytoscape-web/js/AC_OETags.js +1 -0
- data/share/views/public/plugins/cytoscape-web/js/cytoscapeweb.js +1 -0
- data/share/views/public/plugins/cytoscape-web/js/json2.js +1 -0
- data/share/views/public/plugins/cytoscape-web/swf/CytoscapeWeb.swf +0 -0
- data/share/views/public/plugins/cytoscape-web/swf/playerProductInstall.swf +0 -0
- data/share/views/public/plugins/fancybox/CHANGELOG.md +68 -0
- data/share/views/public/plugins/fancybox/README.md +220 -0
- data/share/views/public/plugins/fancybox/css/blank.gif +0 -0
- data/share/views/public/plugins/fancybox/css/fancybox_loading.gif +0 -0
- data/share/views/public/plugins/fancybox/css/fancybox_sprite.png +0 -0
- data/share/views/public/plugins/fancybox/css/jquery.fancybox.css +234 -0
- data/share/views/public/plugins/fancybox/helpers/fancybox_buttons.png +0 -0
- data/share/views/public/plugins/fancybox/helpers/jquery.fancybox-buttons.css +85 -0
- data/share/views/public/plugins/fancybox/helpers/jquery.fancybox-buttons.js +115 -0
- data/share/views/public/plugins/fancybox/helpers/jquery.fancybox-media.js +85 -0
- data/share/views/public/plugins/fancybox/helpers/jquery.fancybox-thumbs.css +54 -0
- data/share/views/public/plugins/fancybox/helpers/jquery.fancybox-thumbs.js +157 -0
- data/share/views/public/plugins/fancybox/js/jquery.fancybox.js +1463 -0
- data/share/views/public/plugins/fancybox/js/jquery.mousewheel-3.0.6.pack.js +13 -0
- data/share/views/public/plugins/fancybox/lib/jquery-1.7.2.min.js +4 -0
- data/share/views/public/plugins/featuredimagezoomer/css/featuredimagezoomer.css +8 -0
- data/share/views/public/plugins/featuredimagezoomer/images/spinningred.gif +0 -0
- data/share/views/public/plugins/featuredimagezoomer/js/featuredimagezoomer.js +245 -0
- data/share/views/public/plugins/jquery-ui.hitarea.js +173 -0
- data/share/views/public/plugins/jquery/js/jquery-1.8.0.min.js +2 -0
- data/share/views/public/plugins/tablesorter/addons/pager/jquery.tablesorter.pager.css +25 -0
- data/share/views/public/plugins/tablesorter/addons/pager/jquery.tablesorter.pager.js +184 -0
- data/share/views/public/plugins/tablesorter/build.xml +26 -0
- data/share/views/public/plugins/tablesorter/build/ParseMaster.js +106 -0
- data/share/views/public/plugins/tablesorter/build/js.jar +0 -0
- data/share/views/public/plugins/tablesorter/build/jsmin.js +316 -0
- data/share/views/public/plugins/tablesorter/build/min.js +5 -0
- data/share/views/public/plugins/tablesorter/build/pack.js +5 -0
- data/share/views/public/plugins/tablesorter/build/packer.js +316 -0
- data/share/views/public/plugins/tablesorter/build/writeFile.js +19 -0
- data/share/views/public/plugins/tablesorter/changelog +41 -0
- data/share/views/public/plugins/tablesorter/docs/assets/ajax-content.html +43 -0
- data/share/views/public/plugins/tablesorter/docs/css/jq.css +29 -0
- data/share/views/public/plugins/tablesorter/docs/example-ajax.html +119 -0
- data/share/views/public/plugins/tablesorter/docs/example-empty-table.html +75 -0
- data/share/views/public/plugins/tablesorter/docs/example-extending-defaults.html +109 -0
- data/share/views/public/plugins/tablesorter/docs/example-meta-headers.html +108 -0
- data/share/views/public/plugins/tablesorter/docs/example-meta-parsers.html +105 -0
- data/share/views/public/plugins/tablesorter/docs/example-meta-sort-list.html +107 -0
- data/share/views/public/plugins/tablesorter/docs/example-option-debug.html +116 -0
- data/share/views/public/plugins/tablesorter/docs/example-option-digits.html +106 -0
- data/share/views/public/plugins/tablesorter/docs/example-option-sort-force.html +107 -0
- data/share/views/public/plugins/tablesorter/docs/example-option-sort-key.html +108 -0
- data/share/views/public/plugins/tablesorter/docs/example-option-sort-list.html +108 -0
- data/share/views/public/plugins/tablesorter/docs/example-option-sort-order.html +108 -0
- data/share/views/public/plugins/tablesorter/docs/example-option-text-extraction.html +85 -0
- data/share/views/public/plugins/tablesorter/docs/example-options-headers.html +118 -0
- data/share/views/public/plugins/tablesorter/docs/example-pager.html +329 -0
- data/share/views/public/plugins/tablesorter/docs/example-parsers.html +112 -0
- data/share/views/public/plugins/tablesorter/docs/example-trigger-sort.html +113 -0
- data/share/views/public/plugins/tablesorter/docs/example-triggers.html +336 -0
- data/share/views/public/plugins/tablesorter/docs/example-update-cell.html +118 -0
- data/share/views/public/plugins/tablesorter/docs/example-widgets.html +383 -0
- data/share/views/public/plugins/tablesorter/docs/img/external.png +0 -0
- data/share/views/public/plugins/tablesorter/docs/index.html +576 -0
- data/share/views/public/plugins/tablesorter/docs/js/docs.js +23 -0
- data/share/views/public/plugins/tablesorter/docs/js/examples.js +29 -0
- data/share/views/public/plugins/tablesorter/jquery-latest.js +154 -0
- data/share/views/public/plugins/tablesorter/jquery.metadata.js +122 -0
- data/share/views/public/plugins/tablesorter/jquery.tablesorter.js +1031 -0
- data/share/views/public/plugins/tablesorter/jquery.tablesorter.min.js +4 -0
- data/share/views/public/plugins/tablesorter/tests/assets/ajax-content.html +28 -0
- data/share/views/public/plugins/tablesorter/tests/cell.metadata.html +112 -0
- data/share/views/public/plugins/tablesorter/tests/checkbox.html +117 -0
- data/share/views/public/plugins/tablesorter/tests/colspan.html +149 -0
- data/share/views/public/plugins/tablesorter/tests/demo.html +353 -0
- data/share/views/public/plugins/tablesorter/tests/index.html +22 -0
- data/share/views/public/plugins/tablesorter/tests/large.html +30 -0
- data/share/views/public/plugins/tablesorter/tests/lockedOrder.html +355 -0
- data/share/views/public/plugins/tablesorter/tests/metadata.html +320 -0
- data/share/views/public/plugins/tablesorter/tests/multiple-headers.html +67 -0
- data/share/views/public/plugins/tablesorter/tests/pager.html +553 -0
- data/share/views/public/plugins/tablesorter/themes/blue/asc.gif +0 -0
- data/share/views/public/plugins/tablesorter/themes/blue/bg.gif +0 -0
- data/share/views/public/plugins/tablesorter/themes/blue/blue.zip +0 -0
- data/share/views/public/plugins/tablesorter/themes/blue/desc.gif +0 -0
- data/share/views/public/plugins/tablesorter/themes/blue/style.css +39 -0
- data/share/views/public/plugins/tablesorter/themes/green/asc.png +0 -0
- data/share/views/public/plugins/tablesorter/themes/green/bg.png +0 -0
- data/share/views/public/plugins/tablesorter/themes/green/desc.png +0 -0
- data/share/views/public/plugins/tablesorter/themes/green/green.zip +0 -0
- data/share/views/public/plugins/tablesorter/themes/green/style.css +39 -0
- data/share/views/public/plugins/wz_jsgraphics.js +1108 -0
- data/share/views/public/tmp/foo +0 -0
- data/share/views/result.haml +6 -1
- data/share/views/step_error.haml +5 -0
- data/share/views/user_lists.haml +8 -7
- data/share/views/wait.haml +40 -2
- metadata +302 -106
- data/share/views/compass/screen.sass +0 -8
- data/share/views/public/plugins/jquery/js/jquery-1.6.2.min.js +0 -18
@@ -52,6 +52,8 @@ class RbbtRestClient
|
|
52
52
|
RestClient.get(File.join(task.url, task.name.to_s, @remote_name) + "?_format=raw")
|
53
53
|
when :tsv
|
54
54
|
TSV.open(StringIO.new(RestClient.get(File.join(task.url, task.name.to_s, @remote_name) + "?_format=raw")))
|
55
|
+
when :annotations
|
56
|
+
Annotated.load_tsv(TSV.open(StringIO.new(RestClient.get(File.join(task.url, task.name.to_s, @remote_name) + "?_format=raw"))))
|
55
57
|
else
|
56
58
|
res = JSON.parse(RestClient.get(File.join(task.url, task.name.to_s, @remote_name) + "?_format=json"))
|
57
59
|
res = TSV.setup(res) if task.result_type.to_sym == :tsv
|
@@ -1,11 +1,14 @@
|
|
1
|
+
require 'rbbt/workflow/rest/render'
|
2
|
+
require 'rbbt/workflow/rest/helpers'
|
3
|
+
|
1
4
|
module Entity
|
2
5
|
|
3
6
|
module REST
|
4
7
|
include RbbtHTMLHelpers
|
5
8
|
|
6
9
|
def rbbt_id
|
7
|
-
return "" unless self.annotations.include? :format and String === self.format
|
8
|
-
([self.format.downcase, self] * "=").gsub(/[
|
10
|
+
return "entity_id='#{self.id}'" unless self.annotations.include? :format and String === self.format
|
11
|
+
([self.format.downcase, '"' + self + '"'] * "=").gsub(/[^"\w=]/,'_')
|
9
12
|
end
|
10
13
|
|
11
14
|
class << self
|
@@ -14,17 +17,19 @@ module Entity
|
|
14
17
|
|
15
18
|
def link(text = nil, url = nil, options = {})
|
16
19
|
return nil if self.nil?
|
20
|
+
|
17
21
|
if Array === self
|
18
22
|
text ||= self.name if self.respond_to? :name
|
19
23
|
if Array === text
|
20
24
|
translations = Misc.zip2hash(self, text)
|
21
|
-
self.collect{|e| e.link(translations[e], url, options)}
|
25
|
+
self.collect{|e| e.link(translations[e], url, options) unless e.nil?}.compact
|
22
26
|
else
|
23
|
-
self.collect{|e| e.link(text, url, options)}
|
27
|
+
self.collect{|e| e.link(text, url, options) unless e.nil?}.compact
|
24
28
|
end
|
25
29
|
else
|
30
|
+
text = nil if String === text and text.empty?
|
31
|
+
text ||= self.name if self.respond_to? :name
|
26
32
|
|
27
|
-
text ||= self.name if self.respond_to? :name
|
28
33
|
text = self if text.nil? or text == :literal or text.to_s.strip.empty?
|
29
34
|
|
30
35
|
klass = options[:class]
|
@@ -33,98 +38,90 @@ module Entity
|
|
33
38
|
klass += " " << options[:extra_classes] || "" if options.include? :extra_classes
|
34
39
|
klass += " " << html_class if self.respond_to? :html_class
|
35
40
|
|
36
|
-
|
41
|
+
main_annotation = options[:entity_type] || annotation_types.select{|a| Entity === a}.last.to_s
|
42
|
+
entity_type = self.respond_to?(:format)? main_annotation +
|
37
43
|
":" +
|
38
|
-
(self.format || "") :
|
44
|
+
CGI.escape(self.format || "") : main_annotation
|
39
45
|
|
40
|
-
params = options[:params] || self.info.reject{|k,v| [:annotation_types, :format].include?(k)}
|
46
|
+
params = options[:params] || self.info(true).reject{|k,v| [:annotation_types, :format].include?(k)}
|
41
47
|
params.merge! options[:extra_params] if options.include? :extra_params
|
48
|
+
params.merge! :entity_id => self.id if annotation_types.select{|annotation_type| annotation_type.respond_to?(:keep_id) and annotation_type.keep_id}.any?
|
42
49
|
|
43
50
|
url ||= if options.include? :action
|
44
|
-
File.join("/entity_action",
|
51
|
+
File.join("/entity_action", entity_type, options[:action].to_s, self)
|
45
52
|
else
|
46
|
-
File.join("/entity",
|
53
|
+
File.join("/entity", entity_type, self)
|
47
54
|
end
|
48
55
|
|
49
|
-
annotations_str = params.collect{|k,v| [k, CGI.escape(v.to_s)] * "="} * "&"
|
50
|
-
"<a class='#{klass}' #{rbbt_id} href
|
56
|
+
annotations_str = params.collect{|k,v| v = v * "|" if Array === v; [k, CGI.escape(v.to_s)] * "="} * "&"
|
57
|
+
"<a class='#{klass}' #{rbbt_id} href=\"#{annotations_str.empty? ? url : url + '?' + annotations_str}\" #{options.include?(:html_link_extra_attrs)? options[:html_link_extra_attrs] : "" } title='#{text}'>#{text}</a>"
|
51
58
|
end
|
52
59
|
end
|
53
60
|
|
54
|
-
def self.list_file(
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
61
|
+
def self.list_file(entity_type, id, user = nil)
|
62
|
+
entity_type = entity_type.split(":").first if not entity_type.nil? and entity_type.index ':'
|
63
|
+
|
64
|
+
id = CGI.unescape(id)
|
65
|
+
id = Misc.sanitize_filename(id)
|
66
|
+
raise "Ilegal list id: #{ id }" unless Misc.path_relative_to ".", File.join('.', id)
|
67
|
+
|
68
|
+
if user.nil?
|
69
|
+
File.join(Entity.entity_list_cache, entity_type.to_s, id)
|
62
70
|
else
|
63
|
-
|
71
|
+
File.join(Entity.entity_list_cache, user.to_s, entity_type.to_s, id)
|
64
72
|
end
|
65
73
|
end
|
66
74
|
|
67
75
|
def self.list_files(user)
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
76
|
+
lists = {}
|
77
|
+
Dir.glob(File.join(Entity.entity_list_cache, user, '*', '*')).each do |file|
|
78
|
+
next if File.directory? file
|
79
|
+
|
80
|
+
file = File.expand_path(file)
|
81
|
+
raise "Ilegal path: #{ file }. Not relative to #{File.expand_path('.')}" unless Misc.path_relative_to(File.expand_path('.'), file)
|
82
|
+
|
83
|
+
user, entity_type, list = file.split("/")[-3..-1]
|
84
|
+
lists[entity_type] ||= []
|
85
|
+
lists[entity_type] << list
|
78
86
|
end
|
87
|
+
lists
|
79
88
|
end
|
80
89
|
|
81
|
-
def self.load_list(
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
path = list_file(type, id) unless File.exists? path
|
90
|
+
def self.load_list(entity_type, id, user = nil)
|
91
|
+
path = list_file(entity_type, id, user)
|
92
|
+
path = list_file(entity_type, id, :public) unless path != nil and File.exists? path
|
93
|
+
path = list_file(entity_type, id) unless path != nil and File.exists? path
|
86
94
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
@@list_cache ||= {}
|
92
|
-
@@list_cache[id]
|
95
|
+
begin
|
96
|
+
Annotated.load_tsv TSV.open(path)
|
97
|
+
rescue
|
98
|
+
nil
|
93
99
|
end
|
94
100
|
end
|
95
101
|
|
96
|
-
def self.save_list(
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
raise $!
|
106
|
-
end
|
102
|
+
def self.save_list(entity_type, id, list, user = nil)
|
103
|
+
path = list_file(entity_type, id, user)
|
104
|
+
|
105
|
+
Misc.lock path do
|
106
|
+
begin
|
107
|
+
Open.write(path, Annotated.tsv(list, :all).to_s)
|
108
|
+
rescue
|
109
|
+
FileUtils.rm path if File.exists? path
|
110
|
+
raise $!
|
107
111
|
end
|
108
|
-
else
|
109
|
-
@@list_cache ||= {}
|
110
|
-
@@list_cache[id] = list
|
111
112
|
end
|
112
113
|
end
|
113
114
|
|
114
115
|
|
115
|
-
def self.delete_list(
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
raise $!
|
124
|
-
end
|
116
|
+
def self.delete_list(entity_type, id, user)
|
117
|
+
path = list_file(entity_type, id, user)
|
118
|
+
"This list does not belong to #{ user }: #{[entity_type, id] * ": "}" unless File.exists? path
|
119
|
+
Misc.lock path do
|
120
|
+
begin
|
121
|
+
FileUtils.rm path if File.exists? path
|
122
|
+
rescue
|
123
|
+
raise $!
|
125
124
|
end
|
126
|
-
else
|
127
|
-
@@list_cache.delete(id) if @@list_cache and @@list_cache.include? id
|
128
125
|
end
|
129
126
|
end
|
130
127
|
|
@@ -134,19 +131,24 @@ module Entity
|
|
134
131
|
|
135
132
|
id ||= options[:id] || Misc.digest((self * "|").inspect)
|
136
133
|
|
134
|
+
id = clean_list_id(id)
|
137
135
|
|
138
136
|
klass = (self.respond_to?(:format) and not self.format.nil?) ? self.format.gsub(/\s/,'_') : annotation_types.collect{|t| t.to_s.gsub(/\s/,'_')} * " "
|
139
137
|
|
140
138
|
klass += " " << options[:extra_classes] if options.include? :extra_classes
|
141
139
|
klass += " " << html_class if self.respond_to? :html_class
|
142
140
|
|
143
|
-
|
141
|
+
main_annotation = options[:entity_type] || annotation_types.select{|a| Entity === a}.last.to_s
|
142
|
+
entity_type = self.respond_to?(:format)? main_annotation +
|
143
|
+
":" +
|
144
|
+
CGI.escape(self.format || "") : main_annotation
|
145
|
+
|
144
146
|
|
145
147
|
Entity::REST.save_list(annotation_types.last.to_s, id, self) unless reuse
|
146
148
|
|
147
|
-
annotations_str = self.info.reject{|k,v| [:annotation_types, :format].include?(k)}.collect{|k,v| [k, CGI.escape(v.to_s)] * "="} * "&"
|
149
|
+
annotations_str = self.info(true).reject{|k,v| [:annotation_types, :format].include?(k)}.collect{|k,v| [k, CGI.escape(v.to_s)] * "="} * "&"
|
148
150
|
|
149
|
-
"<a class='entity_list #{klass}' href='#{File.join("/entity_list",
|
151
|
+
"<a class='entity_list #{klass}' href='#{File.join("/entity_list", entity_type, CGI.escape(id)) + (! annotations_str.empty? ? '?' + annotations_str : "")}' title='#{text}'>#{text}</a>"
|
150
152
|
end
|
151
153
|
|
152
154
|
def action_link(action, text = nil, inputs = {})
|
@@ -157,7 +159,7 @@ module Entity
|
|
157
159
|
clean_inputs[k] = Array === v ? v * "," : v
|
158
160
|
end
|
159
161
|
|
160
|
-
klass ||= "entity_action " + (self.respond_to?(:format)? self.format.gsub(/\s/,'_') : annotation_types.collect{|t| t.to_s.gsub(/\s/,'_')} * " ")
|
162
|
+
klass ||= "entity_action " + ((self.respond_to?(:format) and not self.format.nil?) ? self.format.gsub(/\s/,'_') : annotation_types.collect{|t| t.to_s.gsub(/\s/,'_')} * " ")
|
161
163
|
klass += " " << options[:extra_classes] if options.include? :extra_classes
|
162
164
|
klass += " " << html_class if self.respond_to? :html_class
|
163
165
|
|
@@ -172,19 +174,23 @@ module Entity
|
|
172
174
|
|
173
175
|
text = id if text == :id
|
174
176
|
|
177
|
+
id = clean_list_id(id)
|
175
178
|
|
176
179
|
klass = (self.respond_to?(:format) and not self.format.nil?) ? self.format.gsub(/\s/,'_') : annotation_types.collect{|t| t.to_s.gsub(/\s/,'_')} * " "
|
177
180
|
|
178
181
|
klass += " " << options.delete(:extra_classes) if options.include? :extra_classes
|
179
182
|
klass += " " << html_class if self.respond_to? :html_class
|
180
|
-
|
181
|
-
|
183
|
+
|
184
|
+
main_annotation = options[:entity_type] || annotation_types.select{|a| Entity === a}.last.to_s
|
185
|
+
entity_type = self.respond_to?(:format)? main_annotation +
|
186
|
+
":" +
|
187
|
+
CGI.escape(self.format || "") : main_annotation
|
182
188
|
|
183
189
|
Entity::REST.save_list(annotation_types.last.to_s, id, self) unless reuse
|
184
190
|
|
185
|
-
annotations_str = self.info.merge(options).reject{|k,v| [:annotation_types, :format].include?(k)}.collect{|k,v| [k, CGI.escape(v.to_s)] * "="} * "&"
|
191
|
+
annotations_str = self.info.merge(options).reject{|k,v| [:annotation_types, :format].include?(k)}.collect{|k,v| [k, CGI.escape(v.to_s)] * "="} * "&"
|
186
192
|
|
187
|
-
"<a class='entity_list_action #{klass}' href='#{File.join("/entity_list_action",
|
193
|
+
"<a class='entity_list_action #{klass}' href='#{File.join("/entity_list_action", entity_type, action, CGI.escape(id)) + (!annotations_str.empty? ? '?' + annotations_str : "")}' title='#{text}'>#{text}</a>"
|
188
194
|
end
|
189
195
|
|
190
196
|
def html_table(fields, workflow = nil, field_names = nil)
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'rbbt/ner/finder'
|
3
|
+
|
4
|
+
module Sinatra
|
5
|
+
module RbbtFinder
|
6
|
+
|
7
|
+
module Helpers
|
8
|
+
def finder_find(term)
|
9
|
+
results = settings.finder.find(term)
|
10
|
+
|
11
|
+
results.uniq.collect{|r|
|
12
|
+
info = r.info
|
13
|
+
format_string = [info[:namespace], info[:format]].compact * ":"
|
14
|
+
|
15
|
+
info[:code] = r
|
16
|
+
|
17
|
+
if not format_string.empty?
|
18
|
+
info[:value] = r + " [#{format_string}]"
|
19
|
+
else
|
20
|
+
info[:value] = r
|
21
|
+
end
|
22
|
+
|
23
|
+
score = info.delete :score
|
24
|
+
|
25
|
+
if Array === score
|
26
|
+
info[:score] = score[0]
|
27
|
+
info[:best] = score[1]
|
28
|
+
end
|
29
|
+
|
30
|
+
info
|
31
|
+
}.sort_by{|i| i[:score] || 0}.reverse
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.registered(app)
|
36
|
+
app.helpers RbbtFinder::Helpers
|
37
|
+
|
38
|
+
app.get '/find' do
|
39
|
+
return workflow_render('find.haml') if params[:term].nil?
|
40
|
+
|
41
|
+
Log.debug "find: #{params.inspect}"
|
42
|
+
term = params[:term]
|
43
|
+
sorted_results = finder_find(term)
|
44
|
+
|
45
|
+
raise "No finder defined" if app.finder.nil?
|
46
|
+
if request.xhr?
|
47
|
+
content_type "application/json"
|
48
|
+
sorted_results.to_json
|
49
|
+
else
|
50
|
+
i = sorted_results.first
|
51
|
+
raise "Term not recognized: #{ term }" if i.nil?
|
52
|
+
redirect_to_entity(i[:code], i[:format], i[:namespace])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
app.post '/find' do
|
57
|
+
term = params[:term]
|
58
|
+
if term =~ /(.*) \[(.*)\]$/
|
59
|
+
term = $1
|
60
|
+
namespace, format = $2.split(":")
|
61
|
+
format, namespace = namespace, nil if format.nil?
|
62
|
+
|
63
|
+
redirect_to_entity(term, format, namespace)
|
64
|
+
else
|
65
|
+
sorted_results = finder_find(term)
|
66
|
+
i = sorted_results.first
|
67
|
+
raise "Term not recognized: #{ term }" if i.nil?
|
68
|
+
redirect_to_entity(i[:code], i[:format], i[:namespace])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
register RbbtFinder
|
76
|
+
end
|
77
|
+
|
78
|
+
|
@@ -1,87 +1,328 @@
|
|
1
|
+
require 'rbbt/workflow/annotate'
|
2
|
+
require 'yui/compressor'
|
1
3
|
|
2
4
|
module RbbtHTMLHelpers
|
3
|
-
def
|
4
|
-
|
5
|
-
|
5
|
+
def clean_list_id(list_id)
|
6
|
+
list_id.gsub('/', '_')
|
7
|
+
end
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
9
|
+
def log(status, message)
|
10
|
+
if Step.log_relay_step
|
11
|
+
Step.log_relay_step.log status, message
|
12
|
+
else
|
13
|
+
Log.warn "[#{ status }] #{ message }"
|
10
14
|
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def included(base)
|
18
|
+
base.include AnnotatedModule
|
19
|
+
end
|
20
|
+
|
21
|
+
def format_float(float)
|
22
|
+
"%.3f" % float
|
23
|
+
end
|
24
|
+
|
25
|
+
def redirect_to_entity(entity, format, namespace)
|
26
|
+
entity_type = Entity.formats[format]
|
27
|
+
|
28
|
+
entity_options = []
|
29
|
+
|
30
|
+
if defined? Organism and
|
31
|
+
entity_type.annotations.include? :organism and
|
32
|
+
((String === namespace or Symbol === namespace) and
|
33
|
+
Organism.organisms.include? namespace.to_s or Organism.organisms.include? namespace.to_s.split("/").first)
|
34
|
+
entity_options << ["organism", namespace] * "="
|
35
|
+
end
|
36
|
+
|
37
|
+
entity_options = entity_options.empty? ? "" : "?" + entity_options * "&"
|
38
|
+
|
39
|
+
if format
|
40
|
+
redirect "/entity/#{ entity_type.to_s }:#{ format }/#{ entity }#{entity_options}"
|
41
|
+
else
|
42
|
+
redirect "/entity/#{ entity_type.to_s }/#{ entity }#{entity_options}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def user_action_defaults
|
47
|
+
@@user_action_defaults ||= Persist.open_tokyocabinet(settings.user_action_defaults, false, :marshal)
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_user_defaults(user, entity, action, params)
|
51
|
+
return params if params.delete :no_defaults
|
52
|
+
key = [user, entity, action] * ":"
|
53
|
+
|
54
|
+
user_action_defaults.read_and_close do
|
55
|
+
if user_action_defaults.include?(key) and not user_action_defaults[key] == :clear and not user_action_defaults[key].nil?
|
56
|
+
Log.debug("Loading user defaults for #{key}")
|
57
|
+
new = (user_action_defaults[key] || {} ).dup.merge(params)
|
58
|
+
new.each do |key, value|
|
59
|
+
next if params.include? key
|
60
|
+
params[key] = value
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
params
|
66
|
+
end
|
11
67
|
|
68
|
+
def save_user_defaults(user, entity, action, params)
|
69
|
+
key = [user, entity, action] * ":"
|
70
|
+
clear = user_action_defaults.read_and_close do user_action_defaults[key] == :clear end
|
71
|
+
|
72
|
+
if clear
|
73
|
+
Log.debug("Effectively clearing user defaults for #{key}")
|
74
|
+
user_action_defaults.write_and_close do
|
75
|
+
user_action_defaults.delete key
|
76
|
+
end
|
77
|
+
else
|
78
|
+
Log.debug("Saving user defaults for #{key}")
|
79
|
+
user_action_defaults.write_and_close do
|
80
|
+
user_action_defaults[key] = Hash[*(params.collect{|k,v| [k,v]}.flatten(1))]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def clear_user_defaults(user, entity, action)
|
86
|
+
key = [user, entity, action] * ":"
|
87
|
+
Log.debug("Clearing user defaults for #{key}")
|
88
|
+
user_action_defaults.write_and_close do
|
89
|
+
user_action_defaults[key] = :clear
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def parameter_controls(workflow = nil, values = {}, &block)
|
94
|
+
o = Object.new
|
95
|
+
o.extend AnnotatedModule
|
96
|
+
o.instance_eval &block
|
97
|
+
|
98
|
+
inputs = o.inputs
|
99
|
+
input_types = o.input_types
|
100
|
+
input_defaults = o.input_defaults
|
101
|
+
input_options = o.input_options
|
102
|
+
|
103
|
+
hidden_inputs = []
|
104
|
+
inputs.each do |input|
|
105
|
+
if values[input].nil? and input_defaults.include? input
|
106
|
+
values[input] = input_defaults[input]
|
107
|
+
end
|
108
|
+
hidden_inputs << input if input_options.include? input and input_options[input].delete :hide
|
109
|
+
end
|
110
|
+
|
111
|
+
workflow_partial('partials/_form', workflow, :hide_inputs => hidden_inputs, :inputs => inputs, :input_defaults => input_defaults, :input_options => input_options, :input_types => input_types, :values => values, :action => headers["AJAX-URL"], :klass => 'task', :method => 'get')
|
112
|
+
end
|
113
|
+
|
114
|
+
def link_to_resource(filename = nil, text = nil, type = nil, options = {})
|
115
|
+
case
|
116
|
+
when filename.nil?
|
117
|
+
filename = File.basename(TmpFile.tmp_file)
|
118
|
+
when filename[0] == "."[0]
|
119
|
+
extension = filename
|
120
|
+
filename = File.basename(TmpFile.tmp_file) + extension
|
121
|
+
end
|
122
|
+
|
123
|
+
text ||= filename
|
124
|
+
|
125
|
+
filename = Misc.sanitize_filename(filename)
|
126
|
+
f = File.join(settings.file_dir, filename)
|
127
|
+
FileUtils.mkdir_p(File.dirname(f))
|
128
|
+
yield(f)
|
129
|
+
|
130
|
+
type ||= :link
|
12
131
|
case type
|
13
|
-
when :
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
str << "<input type='file' #{"class='#{klass ? klass : "#{ name } #{ type }" }'"} #{"id='input_#{ id }_tsv_file'" if id} name='#{ name }_param_file' #{"value='#{ value }'" if value}/>" << "\n"
|
31
|
-
str << "<span class='tsv_textarea_note note'>(or use text area bellow)</span>"
|
32
|
-
str << "</p>"
|
33
|
-
str << "<textarea #{"class='#{klass ? klass : "#{ name } #{ type }" }'"} name='#{ name }' #{"id='input_#{ id }'" if id}></textarea>"
|
34
|
-
str << "</div>"
|
35
|
-
str
|
132
|
+
when :image
|
133
|
+
"<img src='/files/#{ filename }' class='file_resource'/>"
|
134
|
+
when :link
|
135
|
+
"<a href='/files/#{ filename }' class='file_resource'>#{ text }</a>"
|
136
|
+
when :linked_image
|
137
|
+
"<a href='/files/#{ filename }' class='file_resource' target='_blank'><img src='/files/#{ filename }' class='file_resource'/></a>"
|
138
|
+
when :zoomable_image
|
139
|
+
id = options[:id] || Misc.digest(filename)
|
140
|
+
width, height= [300, 300]
|
141
|
+
"<div class='zoomable_image'><img id='#{id}' style='width:#{width}px; height:#{height}px' rel='/files/#{ filename }' src='/files/#{ filename }' class='file_resource'/></div>"
|
142
|
+
when :mapped_image
|
143
|
+
mapid = options[:mapid] || options[:id] + '_map'
|
144
|
+
width, height= [300, 300]
|
145
|
+
mapfile = f.sub(/\.[^.]+$/, '.html')
|
146
|
+
"<div class='mapped_image'>#{Open.read(mapfile)}<img class='has_map' usemap='##{mapid}' rel='/files/#{ filename }' src='/files/#{ filename }' class='file_resource'/></div>"
|
147
|
+
else
|
148
|
+
raise "Type not understood: #{ type }"
|
36
149
|
end
|
37
150
|
end
|
38
151
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
152
|
+
def html_options_str(html_options = {})
|
153
|
+
return "" if html_options.nil? or html_options.empty?
|
154
|
+
html_options.collect{|k,v|
|
155
|
+
case
|
156
|
+
when (k.nil? or v.nil? or (String === v and v.empty?))
|
157
|
+
nil
|
158
|
+
when String === v
|
159
|
+
[k,"'" + v + "'"] * "="
|
160
|
+
when Symbol === v
|
161
|
+
[k,"'" + v.to_s + "'"] * "="
|
162
|
+
when TrueClass === v
|
163
|
+
[k,"'" + k.to_s + "'"] * "="
|
164
|
+
else
|
165
|
+
nil
|
166
|
+
end
|
167
|
+
}.compact * " "
|
168
|
+
end
|
169
|
+
|
170
|
+
def form_input(type, name, options = {})
|
171
|
+
id, label, hide, value, klass, default, description, input_options, array_separator = Misc.process_options options,
|
172
|
+
:id, :label, :hide, :value, :class, :default, :description, :input_options, :array_separator
|
173
|
+
|
174
|
+
html_options ||= (input_options.nil? ? nil : input_options[:html_options]) || {}
|
175
|
+
|
176
|
+
if id and not id.empty?
|
177
|
+
str = "<div class='form_input' id='#{ id }'>"
|
178
|
+
else
|
179
|
+
str = "<div class='form_input'>"
|
180
|
+
end
|
181
|
+
|
182
|
+
array_separator ||= '|'
|
183
|
+
label ||= name
|
184
|
+
|
185
|
+
hide ||= html_options.delete :hidden
|
42
186
|
|
43
187
|
if hide
|
44
|
-
|
188
|
+
value = value * array_separator if Array === value
|
189
|
+
|
190
|
+
html_options.merge! :id => id,
|
191
|
+
:type => 'hidden',
|
192
|
+
:name => name,
|
193
|
+
:value => value.to_s,
|
194
|
+
:class => [html_options[:class], klass].compact * " "
|
195
|
+
|
196
|
+
str = "<input #{html_options_str(html_options)}/>" << "\n"
|
45
197
|
return str
|
46
198
|
end
|
47
199
|
|
48
200
|
case type
|
49
201
|
when :select
|
50
|
-
str << "<label #{
|
51
|
-
str << "<
|
202
|
+
str << "<label #{html_options_str({:for => id})}>"
|
203
|
+
str << "<span class='input_name'>#{ label }</span>"
|
204
|
+
str << ": <span class='input_description'>#{ description }</span>" if description
|
205
|
+
str << "</label>" << "\n"
|
206
|
+
|
207
|
+
str << "<select #{html_options_str(html_options.merge :name => name, :id => ((id and not id.empty?) ? "input_#{id}_select" : nil ))}>" << "\n"
|
208
|
+
|
209
|
+
select_options = input_options.nil? ? nil : input_options[:select_options]
|
52
210
|
if not select_options.nil?
|
53
211
|
select_options.each do |option|
|
54
212
|
option, option_name = option if Array === option
|
55
213
|
option_name ||= option
|
56
|
-
str << "<option
|
214
|
+
str << "<option #{html_options_str(html_options.merge :value => option, :selected => option.to_s == value.to_s)}>" << option_name.to_s << "</option>" << "\n"
|
57
215
|
end
|
58
216
|
end
|
217
|
+
|
218
|
+
if html_options["attr-allow-empty"]
|
219
|
+
str << "<option #{html_options_str(html_options.merge :value => "none", :selected => "none" == value.to_s)}>none</option>" << "\n"
|
220
|
+
end
|
221
|
+
|
59
222
|
str << "</select>" << "\n"
|
60
223
|
str << "</div>"
|
61
224
|
str
|
62
225
|
when :boolean
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
226
|
+
value = false if value == "false"
|
227
|
+
default = value unless value.nil?
|
228
|
+
default = false if default == "false"
|
229
|
+
default = true if default == "true"
|
230
|
+
|
231
|
+
check_true = default and %w(true yes y).include? default.to_s.downcase
|
232
|
+
check_false = (default != nil and %w(false no n).include?(default.to_s.downcase))
|
233
|
+
|
234
|
+
str << "<label #{"for='#{ id }'" if id}>"
|
235
|
+
str << "<span class='input_name'>#{ label }</span>"
|
236
|
+
str << "#{": <span class='input_description'>#{ description }</span>" if description}</label>" << "\n"
|
237
|
+
|
238
|
+
str << "<input type='radio' #{check_true ? "checked=checked " : ""}#{html_options_str(html_options.merge :name => name, :value => 'true', :id => ((id and not id.empty?) ? "input_#{id}_true" : nil))}>" << "\n"
|
239
|
+
str << "<label #{html_options_str(html_options.merge :for => ((id and not id.empty?) ? "input_#{id}_true" : nil), :class => [html_options[:class], 'radio_option radio_true'].compact * " ")}>true</label>" << "\n"
|
240
|
+
|
241
|
+
str << "<input type='radio' #{check_false ? "checked=checked " : ""}#{html_options_str(html_options.merge :name => name, :value => 'false', :id => ((id and not id.empty?) ? "input_#{id}_false" : nil))}>" << "\n"
|
242
|
+
str << "<label #{html_options_str(html_options.merge :for => ((id and not id.empty?) ? "input_#{id}_false" : nil), :class => [html_options[:class], 'radio_option radio_false'].compact * " ")}>false</label>" << "\n"
|
69
243
|
str << "</div>"
|
70
244
|
str
|
71
245
|
when :string, :float, :integer
|
72
|
-
|
73
|
-
str << "<
|
246
|
+
value = value * array_separator if Array === value
|
247
|
+
str << "<label #{"for='#{ id }'" if id}><span class='input_name'>#{ label }</span>#{": <span class='input_description'>#{ description }</span>" if description}#{": <span class='input_default'>(Default: #{ default })</span>" if default}</label>" << "\n"
|
248
|
+
str << "<input #{html_options_str(html_options)} #{"class='#{klass ? klass : "#{ name } #{ type }" }'"} #{"id='#{ id }'" if id} name='#{ name }' #{"value='#{ value }'" if value}/>" << "\n"
|
74
249
|
str << "</div>"
|
75
250
|
str
|
76
251
|
when :tsv, :array, :text
|
77
|
-
str << "<label #{"for='#{ id }" if id}
|
252
|
+
str << "<label #{"for='#{ id }'" if id}><span class='input_name'>#{ label }</span>#{": <span class='input_description'>#{ description }</span>" if description}#{": <span class='input_default'>(Default: #{ default })</span>" if default}</label>" << "\n"
|
78
253
|
str << "<p>"
|
79
|
-
str << "<input type='file' #{"class='#{klass ? klass : "#{ name } #{ type }" }'"} #{"id='input_#{ id }_tsv_file'" if id} name='#{ name }_param_file' #{"value='#{ value }'" if value}/>" << "\n"
|
254
|
+
str << "<input #{html_options_str(html_options)} type='file' #{"class='#{klass ? klass : "#{ name } #{ type }" }'"} #{"id='input_#{ id }_tsv_file'" if id} name='#{ name }_param_file' #{"value='#{ value }'" if value}/>" << "\n"
|
80
255
|
str << "<span class='tsv_textarea_note note'>(or use text area bellow)</span>"
|
81
256
|
str << "</p>"
|
82
|
-
str << "<textarea #{"class='#{klass ? klass : "#{ name } #{ type }" }'"} name='#{ name }' #{"id='input_#{ id }'" if id}
|
257
|
+
str << "<textarea #{"class='#{klass ? klass : "#{ name } #{ type }" }'"} name='#{ name }' #{"id='input_#{ id }'" if id}>#{Array === value ? value * "\n" : value}</textarea>"
|
83
258
|
str << "</div>"
|
84
259
|
str
|
85
260
|
end
|
86
261
|
end
|
262
|
+
|
263
|
+
def table(rows, header = nil, options = {})
|
264
|
+
workflow_partial('partials/_table', StudyExplorer, nil, options.merge(:rows => rows, :header => header))
|
265
|
+
end
|
266
|
+
|
267
|
+
def followed_users(user)
|
268
|
+
settings.followed_users[user] || []
|
269
|
+
end
|
270
|
+
|
271
|
+
def record_js(file)
|
272
|
+
@js_files << file
|
273
|
+
end
|
274
|
+
|
275
|
+
def serve_js(compress = true)
|
276
|
+
res = if production? and compress
|
277
|
+
|
278
|
+
md5 = Misc.digest(@js_files * ",")
|
279
|
+
filename = File.join(settings.file_dir, "all_js-#{md5}.js")
|
280
|
+
|
281
|
+
if not File.exists?(filename)
|
282
|
+
text = @js_files.collect{|file|
|
283
|
+
file += '.js' unless file =~ /.js$/
|
284
|
+
if file =~ /^\/js\/entity\/(.*?)\/(.*?)\/(.*)/
|
285
|
+
entity_type, format = $1.split ":"
|
286
|
+
entity = setup_entity(entity_type, format, $2)
|
287
|
+
path = locate_file(WorkflowREST.workflows.last, nil, File.join("js", $3), entity)
|
288
|
+
else
|
289
|
+
path = begin
|
290
|
+
locate_file(WorkflowREST.workflows.last, nil, file.sub(/^\//,'')).find
|
291
|
+
rescue
|
292
|
+
locate_file(WorkflowREST.workflows.last, nil, File.join('public', file)).find
|
293
|
+
end
|
294
|
+
end
|
295
|
+
Open.read(path)
|
296
|
+
} * "\n"
|
297
|
+
|
298
|
+
|
299
|
+
FileUtils.mkdir_p File.dirname(filename) unless File.exists? File.dirname(filename)
|
300
|
+
Open.write(filename, YUI::JavaScriptCompressor.new(:munge => false).compress(text))
|
301
|
+
end
|
302
|
+
|
303
|
+
"<script src='/files/#{File.basename(filename)}' type='text/javascript'></script>"
|
304
|
+
else
|
305
|
+
@js_files.collect{|file|
|
306
|
+
file += '.js' unless file =~ /.js$/
|
307
|
+
"<script src='#{ file }' type='text/javascript'></script>"
|
308
|
+
} * "\n"
|
309
|
+
end
|
310
|
+
@js_files.clear
|
311
|
+
res
|
312
|
+
end
|
313
|
+
|
314
|
+
def record_css(file)
|
315
|
+
@css_files << file
|
316
|
+
end
|
317
|
+
|
318
|
+
def serve_css
|
319
|
+
res = @css_files.collect{|file|
|
320
|
+
file += '.css' unless file =~ /.css$/
|
321
|
+
"<link href='#{file}' rel='stylesheet' type='text/css' />"
|
322
|
+
} * "\n"
|
323
|
+
@css_files.clear
|
324
|
+
res
|
325
|
+
end
|
326
|
+
|
327
|
+
|
87
328
|
end
|