galaxy-commits
Threads by month
- ----- 2026 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions
commit/galaxy-central: Jeremy Goecks: Trackster: (a) default read track block colors to gray in order to show variants; (b) do not set default height of variant track.
by commits-noreply@bitbucket.org 27 Mar '14
by commits-noreply@bitbucket.org 27 Mar '14
27 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/6301e0c62a03/
Changeset: 6301e0c62a03
User: Jeremy Goecks
Date: 2014-03-27 03:14:10
Summary: Trackster: (a) default read track block colors to gray in order to show variants; (b) do not set default height of variant track.
Affected #: 2 files
diff -r 8bb0825fe57b1592331ca685c1e3f74ffdb83ca9 -r 6301e0c62a03b508f2a6fd218dd71ef5d6163511 static/scripts/viz/trackster/tracks.js
--- a/static/scripts/viz/trackster/tracks.js
+++ b/static/scripts/viz/trackster/tracks.js
@@ -4031,7 +4031,7 @@
{ key: 'show_labels', label: 'Show summary and sample labels', type: 'bool', default_value: true },
{ key: 'summary_height', label: 'Locus summary height', type: 'float', default_value: 20 },
{ key: 'mode', type: 'string', default_value: this.mode, hidden: true },
- { key: 'height', type: 'int', default_value: 32, hidden: true }
+ { key: 'height', type: 'int', default_value: 0, hidden: true }
] ),
config_onchange: function() {
@@ -4169,8 +4169,8 @@
extend(ReadTrack.prototype, Drawable.prototype, TiledTrack.prototype, FeatureTrack.prototype, {
config_params: _.union( Drawable.prototype.config_params, [
- { key: 'block_color', label: 'Block and sense strand color', type: 'color' },
- { key: 'reverse_strand_color', label: 'Antisense strand color', type: 'color' },
+ { key: 'block_color', label: 'Block and sense strand color', type: 'color', 'default_value': '#DDDDDD' },
+ { key: 'reverse_strand_color', label: 'Antisense strand color', type: 'color', 'default_value': '#AAAAAA' },
{ key: 'label_color', label: 'Label color', type: 'color', default_value: 'black' },
{ key: 'show_insertions', label: 'Show insertions', type: 'bool', default_value: false },
{ key: 'show_differences', label: 'Show differences only', type: 'bool', default_value: true },
diff -r 8bb0825fe57b1592331ca685c1e3f74ffdb83ca9 -r 6301e0c62a03b508f2a6fd218dd71ef5d6163511 static/scripts/viz/trackster_ui.js
--- a/static/scripts/viz/trackster_ui.js
+++ b/static/scripts/viz/trackster_ui.js
@@ -43,7 +43,7 @@
{ icon_class: 'plus-button', title: 'Add tracks', on_click: function() {
visualization.select_datasets(galaxy_config.root + "visualization/list_current_history_datasets", galaxy_config.root + "api/datasets", { 'f-dbkey': view.dbkey }, function(tracks) {
_.each(tracks, function(track) {
- view.add_drawable( object_from_template(track, view, view) );
+ view.add_drawable( object_from_template(track, view, view) );
});
});
} },
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: Jeremy Goecks: Visualization JS: fix incorrect method call. Pack script.
by commits-noreply@bitbucket.org 26 Mar '14
by commits-noreply@bitbucket.org 26 Mar '14
26 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/8bb0825fe57b/
Changeset: 8bb0825fe57b
User: Jeremy Goecks
Date: 2014-03-26 22:53:07
Summary: Visualization JS: fix incorrect method call. Pack script.
Affected #: 3 files
diff -r 231a61e88777bbf7e2db9ef1fdaa9d7fb757523f -r 8bb0825fe57b1592331ca685c1e3f74ffdb83ca9 static/scripts/packed/viz/visualization.js
--- a/static/scripts/packed/viz/visualization.js
+++ b/static/scripts/packed/viz/visualization.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","mvc/data","viz/trackster/util","utils/config"],function(t,k,m,p){var f={toJSON:function(){var v=this,w={};t.each(v.constructor.to_json_keys,function(x){var y=v.get(x);if(x in v.constructor.to_json_mappers){y=v.constructor.to_json_mappers[x](y,v)}w[x]=y});return w}};var a=function(v,y,x,w){$.ajax({url:v,data:x,error:function(){alert("Grid failed")},success:function(z){Galaxy.modal.show({title:"Select datasets for new tracks",body:z,buttons:{Cancel:function(){Galaxy.modal.hide()},Add:function(){var A=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var B={data_type:"track_config",hda_ldda:"hda"},C=$(this).val();if($(this).attr("name")!=="id"){B.hda_ldda="ldda"}A[A.length]=$.ajax({url:y+"/"+C,data:B,dataType:"json"})});$.when.apply($,A).then(function(){var B=(arguments[0] instanceof Array?$.map(arguments,function(C){return C[0]}):[arguments[0]]);w(B)});Galaxy.modal.hide()}}})}})};var g=function(v){this.default_font=v!==undefined?v:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};t.extend(g.prototype,{load_pattern:function(v,z){var w=this.patterns,x=this.dummy_context,y=new Image();y.src=galaxy_config.root+"static/images"+z;y.onload=function(){w[v]=x.createPattern(y,"repeat")}},get_pattern:function(v){return this.patterns[v]},new_canvas:function(){var v=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(v)}v.manager=this;return v}});var r=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(v){this.clear()},get_elt:function(x){var y=this.attributes.obj_cache,z=this.attributes.key_ary,w=x.toString(),v=t.indexOf(z,function(A){return A.toString()===w});if(v!==-1){if(y[w].stale){z.splice(v,1);delete y[w]}else{this.move_key_to_end(x,v)}}return y[w]},set_elt:function(x,z){var A=this.attributes.obj_cache,B=this.attributes.key_ary,w=x.toString(),y=this.attributes.num_elements;if(!A[w]){if(B.length>=y){var v=B.shift();delete A[v.toString()]}B.push(x)}A[w]=z;return z},move_key_to_end:function(w,v){this.attributes.key_ary.splice(v,1);this.attributes.key_ary.push(w)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length},most_recently_added:function(){return this.size()===0?null:this.attributes.key_ary[this.attributes.key_ary.length-1]}});var d=r.extend({defaults:t.extend({},r.prototype.defaults,{dataset:null,genome:null,init_data:null,min_region_size:200,filters_manager:null,data_type:"data",data_mode_compatible:function(v,w){return true},can_subset:function(v){return false}}),initialize:function(v){r.prototype.initialize.call(this);var w=this.get("init_data");if(w){this.add_data(w)}},add_data:function(v){if(this.get("num_elements")<v.length){this.set("num_elements",v.length)}var w=this;t.each(v,function(x){w.set_data(x.region,x)})},data_is_ready:function(){var y=this.get("dataset"),x=$.Deferred(),v=(this.get("data_type")==="raw_data"?"state":this.get("data_type")==="data"?"converted_datasets_state":"error"),w=new m.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:y.get("hda_ldda"),data_type:v},dataType:"json"},interval:5000,success_fn:function(z){return z!=="pending"}});$.when(w.go()).then(function(z){x.resolve(z==="ok"||z==="data")});return x},search_features:function(v){var w=this.get("dataset"),x={query:v,hda_ldda:w.get("hda_ldda"),data_type:"features"};return $.getJSON(w.url(),x)},load_data:function(D,C,w,B){var z=this.get("dataset"),y={data_type:this.get("data_type"),chrom:D.get("chrom"),low:D.get("start"),high:D.get("end"),mode:C,resolution:w,hda_ldda:z.get("hda_ldda")};$.extend(y,B);var F=this.get("filters_manager");if(F){var G=[];var v=F.filters;for(var A=0;A<v.length;A++){G.push(v[A].name)}y.filter_cols=JSON.stringify(G)}var x=this,E=$.getJSON(z.url(),y,function(H){H.region=D;x.set_data(D,H)});this.set_data(D,E);return E},get_data:function(C,B,x,z){var D=this.get_elt(C);if(D&&(m.is_deferred(D)||this.get("data_mode_compatible")(D,B))){return D}var E=this.get("key_ary"),v=this.get("obj_cache"),w,A;for(var y=0;y<E.length;y++){w=E[y];if(w.contains(C)){A=true;D=v[w.toString()];if(m.is_deferred(D)||(this.get("data_mode_compatible")(D,B)&&this.get("can_subset")(D))){this.move_key_to_end(w,y);if(!m.is_deferred(D)){var G=this.subset_entry(D,C);this.set(C,G);D=G}return D}}}if(!A&&C.length()<this.attributes.min_region_size){C=C.copy();var F=this.most_recently_added();if(!F||(C.get("start")>F.get("start"))){C.set("end",C.get("start")+this.attributes.min_region_size)}else{C.set("start",C.get("end")-this.attributes.min_region_size)}C.set("genome",this.attributes.genome);C.trim()}return this.load_data(C,B,x,z)},set_data:function(w,v){this.set_elt(w,v)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(D,C,y,B,z){var F=this._mark_stale(D);if(!(F&&this.get("data_mode_compatible")(F,C))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var x=D.get("start");if(z===this.DEEP_DATA_REQ){$.extend(B,{start_val:F.data.length+1})}else{if(z===this.BROAD_DATA_REQ){x=(F.max_high?F.max_high:F.data[F.data.length-1][2])+1}}var E=D.copy().set("start",x);var w=this,A=this.load_data(E,C,y,B),v=$.Deferred();this.set_data(D,v);$.when(A).then(function(G){if(G.data){G.data=F.data.concat(G.data);if(G.max_low){G.max_low=F.max_low}if(G.message){G.message=G.message.replace(/[0-9]+/,G.data.length)}}w.set_data(D,G);v.resolve(G)});return v},can_get_more_detailed_data:function(w){var v=this.get_elt(w);return(v.dataset_type==="bigwig"&&v.data.length<8000)},get_more_detailed_data:function(y,A,w,z,x){var v=this._mark_stale(y);if(!v){console.log("ERROR getting more detailed data: no current data");return}if(!x){x={}}if(v.dataset_type==="bigwig"){x.num_samples=1000*z}return this.load_data(y,A,w,x)},_mark_stale:function(w){var v=this.get_elt(w);if(!v){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),w.toString())}v.stale=true;return v},get_genome_wide_data:function(v){var x=this,z=true,y=t.map(v.get("chroms_info").chrom_info,function(B){var A=x.get_elt(new h({chrom:B.chrom,start:0,end:B.len}));if(!A){z=false}return A});if(z){return y}var w=$.Deferred();$.getJSON(this.get("dataset").url(),{data_type:"genome_data"},function(A){x.add_data(A.data);w.resolve(A.data)});return w},subset_entry:function(x,y){var v={bigwig:function(z,A){return t.filter(z,function(B){return B[0]>=A.get("start")&&B[0]<=A.get("end")})},refseq:function(A,B){var C=B.get("start")-x.region.get("start"),z=x.data.length-(x.region.get("end")-B.get("end"));return x.data.slice(C,z)}};var w=x.data;if(!x.region.same(y)&&x.dataset_type in v){w=v[x.dataset_type](x.data,y)}return{region:y,data:w,dataset_type:x.dataset_type}}});var q=d.extend({initialize:function(v){var w=new Backbone.Model();w.urlRoot=v.data_url;this.set("dataset",w)},load_data:function(x,y,v,w){return(x.length()<=100000?d.prototype.load_data.call(this,x,y,v,w):{data:null,region:x})}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(v){this.id=v.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(v){var w=t.find(this.get_chroms_info(),function(x){return x.chrom===v});return new h({chrom:w.chrom,end:w.len})},get_chrom_len:function(v){return t.find(this.get_chroms_info(),function(w){return w.chrom===v}).len}});var h=Backbone.Model.extend({defaults:{chrom:null,start:0,end:0,str_val:null,genome:null},same:function(v){return this.attributes.chrom===v.get("chrom")&&this.attributes.start===v.get("start")&&this.attributes.end===v.get("end")},initialize:function(w){if(w.from_str){var y=w.from_str.split(":"),x=y[0],v=y[1].split("-");this.set({chrom:x,start:parseInt(v[0],10),end:parseInt(v[1],10)})}this.attributes.str_val=this.get("chrom")+":"+this.get("start")+"-"+this.get("end");this.on("change",function(){this.attributes.str_val=this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},this)},copy:function(){return new h({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.attributes.str_val},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(C){var w=this.get("chrom"),B=C.get("chrom"),A=this.get("start"),y=C.get("start"),z=this.get("end"),x=C.get("end"),v;if(w&&B&&w!==B){return h.overlap_results.DIF_CHROMS}if(A<y){if(z<y){v=h.overlap_results.BEFORE}else{if(z<x){v=h.overlap_results.OVERLAP_START}else{v=h.overlap_results.CONTAINS}}}else{if(A>y){if(A>x){v=h.overlap_results.AFTER}else{if(z<=x){v=h.overlap_results.CONTAINED_BY}else{v=h.overlap_results.OVERLAP_END}}}else{v=(z>=x?h.overlap_results.CONTAINS:h.overlap_results.CONTAINED_BY)}}return v},trim:function(v){if(this.attributes.start<0){this.attributes.start=0}if(this.attributes.genome){var w=this.attributes.genome.get_chrom_len(this.attributes.chrom);if(this.attributes.end>w){this.attributes.end=w-1}}return this},contains:function(v){return this.compute_overlap(v)===h.overlap_results.CONTAINS},overlaps:function(v){return t.intersection([this.compute_overlap(v)],[h.overlap_results.DIF_CHROMS,h.overlap_results.BEFORE,h.overlap_results.AFTER]).length===0}},{overlap_results:{DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006}});var n=Backbone.Collection.extend({model:h});var e=Backbone.Model.extend({defaults:{region:null,note:""},initialize:function(v){this.set("region",new h(v.region))}});var s=Backbone.Collection.extend({model:e});var u=Backbone.Model.extend(f).extend({defaults:{mode:"Auto"},initialize:function(v){this.set("dataset",new k.Dataset(v.dataset));this.set("config",p.ConfigSettingCollection.from_config_dict(v.prefs));this.get("config").add([{key:"name",value:this.get("dataset").get("name")},{key:"color"}]);var w=this.get("preloaded_data");if(w){w=w.data}else{w=[]}this.set("data_manager",new d({dataset:this.get("dataset"),init_data:w}))}},{to_json_keys:["track_type","dataset","prefs","mode","filters","tool_state"],to_json_mappers:{prefs:function(w,v){if(t.size(w)===0){w={name:v.get("config").get("name").get("value"),color:v.get("config").get("color").get("value")}}return w},dataset:function(v){return{id:v.id,hda_ldda:v.get("hda_ldda")}}}});var j=Backbone.Collection.extend({model:u});var o=Backbone.Model.extend({defaults:{title:"",type:""},url:galaxy_config.root+"visualization/save",save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var l=o.extend(f).extend({defaults:t.extend({},o.prototype.defaults,{dbkey:"",drawables:null,bookmarks:null,viewport:null}),initialize:function(v){this.set("drawables",new j(v.tracks));this.set("config",p.ConfigSettingCollection.from_config_dict(v.prefs||{}));this.unset("tracks");this.get("drawables").each(function(w){w.unset("preloaded_data")})},add_tracks:function(v){this.get("drawables").add(v)}},{to_json_keys:["view","viewport","bookmarks"],to_json_mappers:{view:function(w,v){return{obj_type:"View",prefs:{name:v.get("title"),content_visible:true},drawables:v.get("drawables")}}}});var b=Backbone.Model.extend({});var i=Backbone.Router.extend({initialize:function(w){this.view=w.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var v=this;v.view.on("navigate",function(x){v.navigate(x)})},change_location:function(v){this.view.go_to(v)}});return{BackboneTrack:u,BrowserBookmark:e,BrowserBookmarkCollection:s,Cache:r,CanvasManager:g,Genome:c,GenomeDataManager:d,GenomeRegion:h,GenomeRegionCollection:n,GenomeVisualization:l,GenomeReferenceDataManager:q,TrackBrowserRouter:i,TrackConfig:b,Visualization:o,select_datasets:a}});
\ No newline at end of file
+define(["libs/underscore","mvc/data","viz/trackster/util","utils/config"],function(t,k,m,p){var f={toJSON:function(){var v=this,w={};t.each(v.constructor.to_json_keys,function(x){var y=v.get(x);if(x in v.constructor.to_json_mappers){y=v.constructor.to_json_mappers[x](y,v)}w[x]=y});return w}};var a=function(v,y,x,w){$.ajax({url:v,data:x,error:function(){alert("Grid failed")},success:function(z){Galaxy.modal.show({title:"Select datasets for new tracks",body:z,buttons:{Cancel:function(){Galaxy.modal.hide()},Add:function(){var A=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var B={data_type:"track_config",hda_ldda:"hda"},C=$(this).val();if($(this).attr("name")!=="id"){B.hda_ldda="ldda"}A[A.length]=$.ajax({url:y+"/"+C,data:B,dataType:"json"})});$.when.apply($,A).then(function(){var B=(arguments[0] instanceof Array?$.map(arguments,function(C){return C[0]}):[arguments[0]]);w(B)});Galaxy.modal.hide()}}})}})};var g=function(v){this.default_font=v!==undefined?v:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};t.extend(g.prototype,{load_pattern:function(v,z){var w=this.patterns,x=this.dummy_context,y=new Image();y.src=galaxy_config.root+"static/images"+z;y.onload=function(){w[v]=x.createPattern(y,"repeat")}},get_pattern:function(v){return this.patterns[v]},new_canvas:function(){var v=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(v)}v.manager=this;return v}});var r=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(v){this.clear()},get_elt:function(x){var y=this.attributes.obj_cache,z=this.attributes.key_ary,w=x.toString(),v=t.indexOf(z,function(A){return A.toString()===w});if(v!==-1){if(y[w].stale){z.splice(v,1);delete y[w]}else{this.move_key_to_end(x,v)}}return y[w]},set_elt:function(x,z){var A=this.attributes.obj_cache,B=this.attributes.key_ary,w=x.toString(),y=this.attributes.num_elements;if(!A[w]){if(B.length>=y){var v=B.shift();delete A[v.toString()]}B.push(x)}A[w]=z;return z},move_key_to_end:function(w,v){this.attributes.key_ary.splice(v,1);this.attributes.key_ary.push(w)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length},most_recently_added:function(){return this.size()===0?null:this.attributes.key_ary[this.attributes.key_ary.length-1]}});var d=r.extend({defaults:t.extend({},r.prototype.defaults,{dataset:null,genome:null,init_data:null,min_region_size:200,filters_manager:null,data_type:"data",data_mode_compatible:function(v,w){return true},can_subset:function(v){return false}}),initialize:function(v){r.prototype.initialize.call(this);var w=this.get("init_data");if(w){this.add_data(w)}},add_data:function(v){if(this.get("num_elements")<v.length){this.set("num_elements",v.length)}var w=this;t.each(v,function(x){w.set_data(x.region,x)})},data_is_ready:function(){var y=this.get("dataset"),x=$.Deferred(),v=(this.get("data_type")==="raw_data"?"state":this.get("data_type")==="data"?"converted_datasets_state":"error"),w=new m.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:y.get("hda_ldda"),data_type:v},dataType:"json"},interval:5000,success_fn:function(z){return z!=="pending"}});$.when(w.go()).then(function(z){x.resolve(z==="ok"||z==="data")});return x},search_features:function(v){var w=this.get("dataset"),x={query:v,hda_ldda:w.get("hda_ldda"),data_type:"features"};return $.getJSON(w.url(),x)},load_data:function(D,C,w,B){var z=this.get("dataset"),y={data_type:this.get("data_type"),chrom:D.get("chrom"),low:D.get("start"),high:D.get("end"),mode:C,resolution:w,hda_ldda:z.get("hda_ldda")};$.extend(y,B);var F=this.get("filters_manager");if(F){var G=[];var v=F.filters;for(var A=0;A<v.length;A++){G.push(v[A].name)}y.filter_cols=JSON.stringify(G)}var x=this,E=$.getJSON(z.url(),y,function(H){H.region=D;x.set_data(D,H)});this.set_data(D,E);return E},get_data:function(C,B,x,z){var D=this.get_elt(C);if(D&&(m.is_deferred(D)||this.get("data_mode_compatible")(D,B))){return D}var E=this.get("key_ary"),v=this.get("obj_cache"),w,A;for(var y=0;y<E.length;y++){w=E[y];if(w.contains(C)){A=true;D=v[w.toString()];if(m.is_deferred(D)||(this.get("data_mode_compatible")(D,B)&&this.get("can_subset")(D))){this.move_key_to_end(w,y);if(!m.is_deferred(D)){var G=this.subset_entry(D,C);this.set_data(C,G);D=G}return D}}}if(!A&&C.length()<this.attributes.min_region_size){C=C.copy();var F=this.most_recently_added();if(!F||(C.get("start")>F.get("start"))){C.set("end",C.get("start")+this.attributes.min_region_size)}else{C.set("start",C.get("end")-this.attributes.min_region_size)}C.set("genome",this.attributes.genome);C.trim()}return this.load_data(C,B,x,z)},set_data:function(w,v){this.set_elt(w,v)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(D,C,y,B,z){var F=this._mark_stale(D);if(!(F&&this.get("data_mode_compatible")(F,C))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var x=D.get("start");if(z===this.DEEP_DATA_REQ){$.extend(B,{start_val:F.data.length+1})}else{if(z===this.BROAD_DATA_REQ){x=(F.max_high?F.max_high:F.data[F.data.length-1][2])+1}}var E=D.copy().set("start",x);var w=this,A=this.load_data(E,C,y,B),v=$.Deferred();this.set_data(D,v);$.when(A).then(function(G){if(G.data){G.data=F.data.concat(G.data);if(G.max_low){G.max_low=F.max_low}if(G.message){G.message=G.message.replace(/[0-9]+/,G.data.length)}}w.set_data(D,G);v.resolve(G)});return v},can_get_more_detailed_data:function(w){var v=this.get_elt(w);return(v.dataset_type==="bigwig"&&v.data.length<8000)},get_more_detailed_data:function(y,A,w,z,x){var v=this._mark_stale(y);if(!v){console.log("ERROR getting more detailed data: no current data");return}if(!x){x={}}if(v.dataset_type==="bigwig"){x.num_samples=1000*z}return this.load_data(y,A,w,x)},_mark_stale:function(w){var v=this.get_elt(w);if(!v){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),w.toString())}v.stale=true;return v},get_genome_wide_data:function(v){var x=this,z=true,y=t.map(v.get("chroms_info").chrom_info,function(B){var A=x.get_elt(new h({chrom:B.chrom,start:0,end:B.len}));if(!A){z=false}return A});if(z){return y}var w=$.Deferred();$.getJSON(this.get("dataset").url(),{data_type:"genome_data"},function(A){x.add_data(A.data);w.resolve(A.data)});return w},subset_entry:function(x,y){var v={bigwig:function(z,A){return t.filter(z,function(B){return B[0]>=A.get("start")&&B[0]<=A.get("end")})},refseq:function(A,B){var C=B.get("start")-x.region.get("start"),z=x.data.length-(x.region.get("end")-B.get("end"));return x.data.slice(C,z)}};var w=x.data;if(!x.region.same(y)&&x.dataset_type in v){w=v[x.dataset_type](x.data,y)}return{region:y,data:w,dataset_type:x.dataset_type}}});var q=d.extend({initialize:function(v){var w=new Backbone.Model();w.urlRoot=v.data_url;this.set("dataset",w)},load_data:function(x,y,v,w){return(x.length()<=100000?d.prototype.load_data.call(this,x,y,v,w):{data:null,region:x})}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(v){this.id=v.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(v){var w=t.find(this.get_chroms_info(),function(x){return x.chrom===v});return new h({chrom:w.chrom,end:w.len})},get_chrom_len:function(v){return t.find(this.get_chroms_info(),function(w){return w.chrom===v}).len}});var h=Backbone.Model.extend({defaults:{chrom:null,start:0,end:0,str_val:null,genome:null},same:function(v){return this.attributes.chrom===v.get("chrom")&&this.attributes.start===v.get("start")&&this.attributes.end===v.get("end")},initialize:function(w){if(w.from_str){var y=w.from_str.split(":"),x=y[0],v=y[1].split("-");this.set({chrom:x,start:parseInt(v[0],10),end:parseInt(v[1],10)})}this.attributes.str_val=this.get("chrom")+":"+this.get("start")+"-"+this.get("end");this.on("change",function(){this.attributes.str_val=this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},this)},copy:function(){return new h({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.attributes.str_val},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(C){var w=this.get("chrom"),B=C.get("chrom"),A=this.get("start"),y=C.get("start"),z=this.get("end"),x=C.get("end"),v;if(w&&B&&w!==B){return h.overlap_results.DIF_CHROMS}if(A<y){if(z<y){v=h.overlap_results.BEFORE}else{if(z<x){v=h.overlap_results.OVERLAP_START}else{v=h.overlap_results.CONTAINS}}}else{if(A>y){if(A>x){v=h.overlap_results.AFTER}else{if(z<=x){v=h.overlap_results.CONTAINED_BY}else{v=h.overlap_results.OVERLAP_END}}}else{v=(z>=x?h.overlap_results.CONTAINS:h.overlap_results.CONTAINED_BY)}}return v},trim:function(v){if(this.attributes.start<0){this.attributes.start=0}if(this.attributes.genome){var w=this.attributes.genome.get_chrom_len(this.attributes.chrom);if(this.attributes.end>w){this.attributes.end=w-1}}return this},contains:function(v){return this.compute_overlap(v)===h.overlap_results.CONTAINS},overlaps:function(v){return t.intersection([this.compute_overlap(v)],[h.overlap_results.DIF_CHROMS,h.overlap_results.BEFORE,h.overlap_results.AFTER]).length===0}},{overlap_results:{DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006}});var n=Backbone.Collection.extend({model:h});var e=Backbone.Model.extend({defaults:{region:null,note:""},initialize:function(v){this.set("region",new h(v.region))}});var s=Backbone.Collection.extend({model:e});var u=Backbone.Model.extend(f).extend({defaults:{mode:"Auto"},initialize:function(v){this.set("dataset",new k.Dataset(v.dataset));this.set("config",p.ConfigSettingCollection.from_config_dict(v.prefs));this.get("config").add([{key:"name",value:this.get("dataset").get("name")},{key:"color"}]);var w=this.get("preloaded_data");if(w){w=w.data}else{w=[]}this.set("data_manager",new d({dataset:this.get("dataset"),init_data:w}))}},{to_json_keys:["track_type","dataset","prefs","mode","filters","tool_state"],to_json_mappers:{prefs:function(w,v){if(t.size(w)===0){w={name:v.get("config").get("name").get("value"),color:v.get("config").get("color").get("value")}}return w},dataset:function(v){return{id:v.id,hda_ldda:v.get("hda_ldda")}}}});var j=Backbone.Collection.extend({model:u});var o=Backbone.Model.extend({defaults:{title:"",type:""},url:galaxy_config.root+"visualization/save",save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var l=o.extend(f).extend({defaults:t.extend({},o.prototype.defaults,{dbkey:"",drawables:null,bookmarks:null,viewport:null}),initialize:function(v){this.set("drawables",new j(v.tracks));this.set("config",p.ConfigSettingCollection.from_config_dict(v.prefs||{}));this.unset("tracks");this.get("drawables").each(function(w){w.unset("preloaded_data")})},add_tracks:function(v){this.get("drawables").add(v)}},{to_json_keys:["view","viewport","bookmarks"],to_json_mappers:{view:function(w,v){return{obj_type:"View",prefs:{name:v.get("title"),content_visible:true},drawables:v.get("drawables")}}}});var b=Backbone.Model.extend({});var i=Backbone.Router.extend({initialize:function(w){this.view=w.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var v=this;v.view.on("navigate",function(x){v.navigate(x)})},change_location:function(v){this.view.go_to(v)}});return{BackboneTrack:u,BrowserBookmark:e,BrowserBookmarkCollection:s,Cache:r,CanvasManager:g,Genome:c,GenomeDataManager:d,GenomeRegion:h,GenomeRegionCollection:n,GenomeVisualization:l,GenomeReferenceDataManager:q,TrackBrowserRouter:i,TrackConfig:b,Visualization:o,select_datasets:a}});
\ No newline at end of file
diff -r 231a61e88777bbf7e2db9ef1fdaa9d7fb757523f -r 8bb0825fe57b1592331ca685c1e3f74ffdb83ca9 static/scripts/viz/trackster/painters.js
--- a/static/scripts/viz/trackster/painters.js
+++ b/static/scripts/viz/trackster/painters.js
@@ -120,7 +120,7 @@
this.view_start = view_start;
this.view_end = view_end;
// Drawing prefs
- this.prefs = extend( {}, this.default_prefs, prefs );
+ this.prefs = extend({}, this.default_prefs, prefs);
this.mode = mode;
};
diff -r 231a61e88777bbf7e2db9ef1fdaa9d7fb757523f -r 8bb0825fe57b1592331ca685c1e3f74ffdb83ca9 static/scripts/viz/visualization.js
--- a/static/scripts/viz/visualization.js
+++ b/static/scripts/viz/visualization.js
@@ -403,7 +403,7 @@
// If there's data, subset it.
if ( !util_mod.is_deferred(entry) ) {
var subset_entry = this.subset_entry(entry, region);
- this.set(region, subset_entry);
+ this.set_data(region, subset_entry);
entry = subset_entry;
}
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
26 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/231a61e88777/
Changeset: 231a61e88777
User: Jeremy Goecks
Date: 2014-03-26 22:39:58
Summary: Pack scripts.
Affected #: 5 files
diff -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 -r 231a61e88777bbf7e2db9ef1fdaa9d7fb757523f static/scripts/packed/utils/config.js
--- a/static/scripts/packed/utils/config.js
+++ b/static/scripts/packed/utils/config.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","viz/trackster/util","utils/config"],function(c,f,b){var d=Backbone.Model.extend({initialize:function(g){var h=this.get("key");this.set("id",h);var i=c.find(d.known_settings_defaults,function(j){return j.key===h});if(i){this.set(c.extend({},i,g))}if(!this.get("value")){this.set_value(this.get("default_value"));if(!this.get("value")&&this.get("type")==="color"){this.set("value",f.get_random_color())}}},set_value:function(h){var g=this.get("type");if(g==="float"){h=parseFloat(h)}else{if(g==="int"){h=parseInt(h,10)}}this.set("value",h)}},{known_settings_defaults:[{key:"name",label:"Name",type:"text",default_value:""},{key:"color",label:"Color",type:"color",default_value:null},{key:"min_value",label:"Min Value",type:"float",default_value:null},{key:"max_value",label:"Max Value",type:"float",default_value:null},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:32,hidden:true},{key:"pos_color",label:"Positive Color",type:"color",default_value:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"block_color",label:"Block color",type:"color",default_value:null},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:null},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true}]});var e=Backbone.Collection.extend({model:d,to_key_value_dict:function(){var g={};this.each(function(h){g[h.get("key")]=h.get("value")});return g},get_value:function(g){var h=this.get(g);if(h){return h.get("value")}return undefined},set_value:function(g,i){var h=this.get(g);if(h){return h.set_value(i)}return undefined},set_default_value:function(h,g){var i=this.get(h);if(i){return i.set("default_value",g)}return undefined}},{from_models_and_saved_values:function(h,g){if(g){h=c.map(h,function(i){return c.extend({},i,{value:g[i.key]})})}return new e(h)}});var a=Backbone.View.extend({className:"config-settings-view",render:function(){var g=this.$el;this.collection.each(function(j,n){if(j.get("hidden")){return}var i="param_"+n,o=j.get("type"),s=j.get("value");var t=$("<div class='form-row' />").appendTo(g);t.append($("<label />").attr("for",i).text(j.get("label")+":"));if(o==="bool"){t.append($('<input type="checkbox" />').attr("id",i).attr("name",i).attr("checked",s))}else{if(o==="text"){t.append($('<input type="text"/>').attr("id",i).val(s).click(function(){$(this).select()}))}else{if(o==="select"){var q=$("<select />").attr("id",i);c.each(j.get("options"),function(v){$("<option/>").text(v.label).attr("value",v.value).appendTo(q)});q.val(s);t.append(q)}else{if(o==="color"){var u=$("<div/>").appendTo(t),p=$("<input />").attr("id",i).attr("name",i).val(s).css("float","left").appendTo(u).click(function(w){$(".tooltip").removeClass("in");var v=$(this).siblings(".tooltip").addClass("in");v.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(v).height()/2)+($(this).height()/2)}).show();v.click(function(x){x.stopPropagation()});$(document).bind("click.color-picker",function(){v.hide();$(document).unbind("click.color-picker")});w.stopPropagation()}),m=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(u).attr("title","Set new random color").tooltip(),r=$("<div class='tooltip right' style='position: absolute;' />").appendTo(u).hide(),k=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(r),h=$("<div class='tooltip-arrow'></div>").appendTo(r),l=$.farbtastic(k,{width:100,height:100,callback:p,color:s});u.append($("<div/>").css("clear","both"));(function(v){m.click(function(){v.setColor(f.get_random_color())})})(l)}else{t.append($("<input />").attr("id",i).attr("name",i).val(s))}}}}if(j.help){t.append($("<div class='help'/>").text(j.help))}});return this},render_in_modal:function(k){var g=this,j=function(){Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc")},h=function(){Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc");g.update_from_form()},i=function(l){if((l.keyCode||l.which)===27){j()}else{if((l.keyCode||l.which)===13){h()}}};$(window).bind("keypress.check_enter_esc",i);if(this.$el.children().length===0){this.render()}Galaxy.modal.show({title:k||"Configure",body:this.$el,buttons:{Cancel:j,OK:h}})},update_from_form:function(){var g=this;this.collection.each(function(i,h){if(!i.get("hidden")){var k="param_"+h;var j=g.$el.find("#"+k).val();if(i.get("type")==="bool"){j=g.$el.find("#"+k).is(":checked")}i.set_value(j)}})}});return{ConfigSettingCollection:e,ConfigSettingCollectionView:a}});
\ No newline at end of file
+define(["libs/underscore","viz/trackster/util","utils/config"],function(c,f,b){var d=Backbone.Model.extend({initialize:function(g){var h=this.get("key");this.set("id",h);var i=c.find(d.known_settings_defaults,function(j){return j.key===h});if(i){this.set(c.extend({},i,g))}if(this.get("value")===undefined){this.set_value(this.get("default_value"));if(!this.get("value")&&this.get("type")==="color"){this.set("value",f.get_random_color())}}},set_value:function(h){var g=this.get("type");if(g==="float"){h=parseFloat(h)}else{if(g==="int"){h=parseInt(h,10)}}this.set("value",h)}},{known_settings_defaults:[{key:"name",label:"Name",type:"text",default_value:""},{key:"color",label:"Color",type:"color",default_value:null},{key:"min_value",label:"Min Value",type:"float",default_value:null},{key:"max_value",label:"Max Value",type:"float",default_value:null},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:32,hidden:true},{key:"pos_color",label:"Positive Color",type:"color",default_value:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"block_color",label:"Block color",type:"color",default_value:null},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:null},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true}]});var e=Backbone.Collection.extend({model:d,to_key_value_dict:function(){var g={};this.each(function(h){g[h.get("key")]=h.get("value")});return g},get_value:function(g){var h=this.get(g);if(h){return h.get("value")}return undefined},set_value:function(g,i){var h=this.get(g);if(h){return h.set_value(i)}return undefined},set_default_value:function(h,g){var i=this.get(h);if(i){return i.set("default_value",g)}return undefined}},{from_models_and_saved_values:function(h,g){if(g){h=c.map(h,function(i){return c.extend({},i,{value:g[i.key]})})}return new e(h)}});var a=Backbone.View.extend({className:"config-settings-view",render:function(){var g=this.$el;this.collection.each(function(j,n){if(j.get("hidden")){return}var i="param_"+n,o=j.get("type"),s=j.get("value");var t=$("<div class='form-row' />").appendTo(g);t.append($("<label />").attr("for",i).text(j.get("label")+":"));if(o==="bool"){t.append($('<input type="checkbox" />').attr("id",i).attr("name",i).attr("checked",s))}else{if(o==="text"){t.append($('<input type="text"/>').attr("id",i).val(s).click(function(){$(this).select()}))}else{if(o==="select"){var q=$("<select />").attr("id",i);c.each(j.get("options"),function(v){$("<option/>").text(v.label).attr("value",v.value).appendTo(q)});q.val(s);t.append(q)}else{if(o==="color"){var u=$("<div/>").appendTo(t),p=$("<input />").attr("id",i).attr("name",i).val(s).css("float","left").appendTo(u).click(function(w){$(".tooltip").removeClass("in");var v=$(this).siblings(".tooltip").addClass("in");v.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(v).height()/2)+($(this).height()/2)}).show();v.click(function(x){x.stopPropagation()});$(document).bind("click.color-picker",function(){v.hide();$(document).unbind("click.color-picker")});w.stopPropagation()}),m=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(u).attr("title","Set new random color").tooltip(),r=$("<div class='tooltip right' style='position: absolute;' />").appendTo(u).hide(),k=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(r),h=$("<div class='tooltip-arrow'></div>").appendTo(r),l=$.farbtastic(k,{width:100,height:100,callback:p,color:s});u.append($("<div/>").css("clear","both"));(function(v){m.click(function(){v.setColor(f.get_random_color())})})(l)}else{t.append($("<input />").attr("id",i).attr("name",i).val(s))}}}}if(j.help){t.append($("<div class='help'/>").text(j.help))}});return this},render_in_modal:function(k){var g=this,j=function(){Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc")},h=function(){Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc");g.update_from_form()},i=function(l){if((l.keyCode||l.which)===27){j()}else{if((l.keyCode||l.which)===13){h()}}};$(window).bind("keypress.check_enter_esc",i);if(this.$el.children().length===0){this.render()}Galaxy.modal.show({title:k||"Configure",body:this.$el,buttons:{Cancel:j,OK:h}})},update_from_form:function(){var g=this;this.collection.each(function(i,h){if(!i.get("hidden")){var k="param_"+h;var j=g.$el.find("#"+k).val();if(i.get("type")==="bool"){j=g.$el.find("#"+k).is(":checked")}i.set_value(j)}})}});return{ConfigSettingCollection:e,ConfigSettingCollectionView:a}});
\ No newline at end of file
diff -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 -r 231a61e88777bbf7e2db9ef1fdaa9d7fb757523f static/scripts/packed/viz/trackster/painters.js
--- a/static/scripts/packed/viz/trackster/painters.js
+++ b/static/scripts/packed/viz/trackster/painters.js
@@ -1,1 +1,1 @@
-define(["libs/underscore"],function(_){var extend=_.extend;var BEFORE=1001,CONTAINS=1002,OVERLAP_START=1003,OVERLAP_END=1004,CONTAINED_BY=1005,AFTER=1006;var compute_overlap=function(first_region,second_region){var first_start=first_region[0],first_end=first_region[1],second_start=second_region[0],second_end=second_region[1],overlap;if(first_start<second_start){if(first_end<=second_start){overlap=BEFORE}else{if(first_end<=second_end){overlap=OVERLAP_START}else{overlap=CONTAINS}}}else{if(first_start>second_end){overlap=AFTER}else{if(first_end<=second_end){overlap=CONTAINED_BY}else{overlap=OVERLAP_END}}}return overlap};var is_overlap=function(first_region,second_region){var overlap=compute_overlap(first_region,second_region);return(overlap!==BEFORE&&overlap!==AFTER)};var dashedLine=function(ctx,x1,y1,x2,y2,dashLen){if(dashLen===undefined){dashLen=4}var dX=x2-x1;var dY=y2-y1;var dashes=Math.floor(Math.sqrt(dX*dX+dY*dY)/dashLen);var dashX=dX/dashes;var dashY=dY/dashes;var q;for(q=0;q<dashes;q++,x1+=dashX,y1+=dashY){if(q%2!==0){continue}ctx.fillRect(x1,y1,dashLen,1)}};var drawDownwardEquilateralTriangle=function(ctx,down_vertex_x,down_vertex_y,side_len){var x1=down_vertex_x-side_len/2,x2=down_vertex_x+side_len/2,y=down_vertex_y-Math.sqrt(side_len*3/2);ctx.beginPath();ctx.moveTo(x1,y);ctx.lineTo(x2,y);ctx.lineTo(down_vertex_x,down_vertex_y);ctx.lineTo(x1,y);ctx.strokeStyle=this.fillStyle;ctx.fill();ctx.stroke();ctx.closePath()};var Scaler=function(default_val){this.default_val=(default_val?default_val:1)};Scaler.prototype.gen_val=function(input){return this.default_val};var Painter=function(data,view_start,view_end,prefs,mode){this.data=data;this.view_start=view_start;this.view_end=view_end;this.prefs=extend({},this.default_prefs,prefs);this.mode=mode};Painter.prototype.default_prefs={};Painter.prototype.draw=function(ctx,width,height,w_scale){};var LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);if(this.prefs.min_value===undefined){this.prefs.min_value=_.min(_.map(this.data,function(d){return d[1]}))||0}if(this.prefs.max_value===undefined){this.prefs.max_value=_.max(_.map(this.data,function(d){return d[1]}))||0}};LinePainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Histogram",color:"#000",overflow_color:"#F66"};LinePainter.prototype.draw=function(ctx,width,height,w_scale){var in_path=false,min_value=this.prefs.min_value,max_value=this.prefs.max_value,vertical_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data;ctx.save();var y_zero=Math.round(height+min_value/vertical_range*height);if(mode!=="Intensity"){ctx.fillStyle="#aaa";ctx.fillRect(0,y_zero,width,1)}ctx.beginPath();var x_scaled,y,delta_x_px;if(data.length>1){delta_x_px=Math.ceil((data[1][0]-data[0][0])*w_scale)}else{delta_x_px=10}var painter_color=this.prefs.block_color||this.prefs.color,pref_color=parseInt(painter_color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255,top_overflow=false,bot_overflow=false;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=painter_color;top_overflow=bot_overflow=false;x_scaled=Math.round((data[i][0]-view_start)*w_scale);y=data[i][1];if(y===null){if(in_path&&mode==="Filled"){ctx.lineTo(x_scaled,height_px)}in_path=false;continue}if(y<min_value){bot_overflow=true;y=min_value}else{if(y>max_value){top_overflow=true;y=max_value}}if(mode==="Histogram"){y=Math.round(y/vertical_range*height_px);ctx.fillRect(x_scaled,y_zero,delta_x_px,-y)}else{if(mode==="Intensity"){var saturation=(y-min_value)/vertical_range,new_r=Math.round(pref_r+(255-pref_r)*(1-saturation)),new_g=Math.round(pref_g+(255-pref_g)*(1-saturation)),new_b=Math.round(pref_b+(255-pref_b)*(1-saturation));ctx.fillStyle="rgb("+new_r+","+new_g+","+new_b+")";ctx.fillRect(x_scaled,0,delta_x_px,height_px)}else{y=Math.round(height_px-(y-min_value)/vertical_range*height_px);if(in_path){ctx.lineTo(x_scaled,y)}else{in_path=true;if(mode==="Filled"){ctx.moveTo(x_scaled,height_px);ctx.lineTo(x_scaled,y)}else{ctx.moveTo(x_scaled,y)}}}}ctx.fillStyle=this.prefs.overflow_color;if(top_overflow||bot_overflow){var overflow_x;if(mode==="Histogram"||mode==="Intensity"){overflow_x=delta_x_px}else{x_scaled-=2;overflow_x=4}if(top_overflow){ctx.fillRect(x_scaled,0,overflow_x,3)}if(bot_overflow){ctx.fillRect(x_scaled,height_px-3,overflow_x,3)}}ctx.fillStyle=painter_color}if(mode==="Filled"){if(in_path){ctx.lineTo(x_scaled,y_zero);ctx.lineTo(0,y_zero)}ctx.fill()}else{ctx.stroke()}ctx.restore()};var FeaturePositionMapper=function(slot_height){this.feature_positions={};this.slot_height=slot_height;this.translation=0;this.y_translation=0};FeaturePositionMapper.prototype.map_feature_data=function(feature_data,slot,x_start,x_end){if(!this.feature_positions[slot]){this.feature_positions[slot]=[]}this.feature_positions[slot].push({data:feature_data,x_start:x_start,x_end:x_end})};FeaturePositionMapper.prototype.get_feature_data=function(x,y){var slot=Math.floor((y-this.y_translation)/this.slot_height),feature_dict;if(!this.feature_positions[slot]){return null}x+=this.translation;for(var i=0;i<this.feature_positions[slot].length;i++){feature_dict=this.feature_positions[slot][i];if(x>=feature_dict.x_start&&x<=feature_dict.x_end){return feature_dict.data}}};var FeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){Painter.call(this,data,view_start,view_end,prefs,mode);this.alpha_scaler=(alpha_scaler?alpha_scaler:new Scaler());this.height_scaler=(height_scaler?height_scaler:new Scaler())};FeaturePainter.prototype.default_prefs={block_color:"#FFF",connector_color:"#FFF"};extend(FeaturePainter.prototype,{get_required_height:function(rows_required,width){var required_height=this.get_row_height(),y_scale=required_height,mode=this.mode;if(mode==="no_detail"||mode==="Squish"||mode==="Pack"){required_height=rows_required*y_scale}return required_height+this.get_top_padding(width)},get_top_padding:function(width){return 0},draw:function(ctx,width,height,w_scale,slots){var data=this.data,view_start=this.view_start,view_end=this.view_end;ctx.save();ctx.fillStyle=this.prefs.block_color;ctx.textAlign="right";var y_scale=this.get_row_height(),feature_mapper=new FeaturePositionMapper(y_scale),x_draw_coords;for(var i=0,len=data.length;i<len;i++){var feature=data[i],feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],slot=(slots&&slots[feature_uid]!==undefined?slots[feature_uid]:null);if((feature_start<view_end&&feature_end>view_start)&&(this.mode==="Dense"||slot!==null)){x_draw_coords=this.draw_element(ctx,this.mode,feature,slot,view_start,view_end,w_scale,y_scale,width);feature_mapper.map_feature_data(feature,slot,x_draw_coords[0],x_draw_coords[1])}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return feature_mapper},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){return[0,0]}});var DENSE_TRACK_HEIGHT=10,NO_DETAIL_TRACK_HEIGHT=3,SQUISH_TRACK_HEIGHT=5,PACK_TRACK_HEIGHT=10,NO_DETAIL_FEATURE_HEIGHT=1,DENSE_FEATURE_HEIGHT=9,SQUISH_FEATURE_HEIGHT=3,PACK_FEATURE_HEIGHT=9,LABEL_SPACING=2,CONNECTOR_COLOR="#ccc";var LinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.draw_background_connector=true;this.draw_individual_connectors=false};extend(LinkedFeaturePainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="no_detail"){height=NO_DETAIL_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}}return height},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),draw_start=f_start,draw_end=f_end,y_start=(mode==="Dense"?0:(0+slot))*y_scale+this.get_top_padding(width),thickness,y_start,thick_start=null,thick_end=null,block_color=(!feature_strand||feature_strand==="+"||feature_strand==="."?this.prefs.block_color:this.prefs.reverse_strand_color);label_color=this.prefs.label_color;ctx.globalAlpha=this.alpha_scaler.gen_val(feature);if(mode==="Dense"){slot=1}if(mode==="no_detail"){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+5,f_end-f_start,NO_DETAIL_FEATURE_HEIGHT)}else{var feature_ts=feature[5],feature_te=feature[6],feature_blocks=feature[7],full_height=true;if(feature_ts&&feature_te){thick_start=Math.floor(Math.max(0,(feature_ts-tile_low)*w_scale));thick_end=Math.ceil(Math.min(width,Math.max(0,(feature_te-tile_low)*w_scale)))}var thin_height,thick_height;if(mode==="Squish"){thin_height=1;thick_height=SQUISH_FEATURE_HEIGHT;full_height=false}else{if(mode==="Dense"){thin_height=5;thick_height=DENSE_FEATURE_HEIGHT}else{thin_height=5;thick_height=PACK_FEATURE_HEIGHT}}if(!feature_blocks){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height);if(feature_strand&&full_height){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height)}}else{var cur_y_start,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_start=y_start+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_start=y_start;cur_height=thick_height}else{cur_y_start+=(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}}if(this.draw_background_connector){if(mode==="Squish"||mode==="Dense"){ctx.fillStyle=CONNECTOR_COLOR}else{if(feature_strand){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand")}}}else{ctx.fillStyle=CONNECTOR_COLOR}}ctx.fillRect(f_start,cur_y_start,f_end-f_start,cur_height)}var start_and_height;for(var k=0,k_len=feature_blocks.length;k<k_len;k++){var block=feature_blocks[k],block_start=Math.floor(Math.max(0,(block[0]-tile_low-0.5)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-tile_low-0.5)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_start+(thick_height-thin_height)/2+1,block_end-block_start,thin_height);if(thick_start!==undefined&&feature_te>feature_ts&&!(block_start>thick_end||block_end<thick_start)){var block_thick_start=Math.max(block_start,thick_start),block_thick_end=Math.min(block_end,thick_end);ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height);if(feature_blocks.length===1&&mode==="Pack"){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}if(block_thick_start+14<block_thick_end){block_thick_start+=2;block_thick_end-=2}ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height)}}if(this.draw_individual_connectors&&last_block_start){this.draw_connector(ctx,last_block_start,last_block_end,block_start,block_end,y_start)}last_block_start=block_start;last_block_end=block_end}if(mode==="Pack"){ctx.globalAlpha=1;ctx.fillStyle="white";var hscale_factor=this.height_scaler.gen_val(feature),new_height=Math.ceil(thick_height*hscale_factor),ws_height=Math.round((thick_height-new_height)/2);if(hscale_factor!==1){ctx.fillRect(f_start,cur_y_start+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_start+thick_height-ws_height+1,f_end-f_start,ws_height)}}}ctx.globalAlpha=1;if(feature_name&&mode==="Pack"&&feature_start>tile_low){ctx.fillStyle=label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+8);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+8);draw_start-=ctx.measureText(feature_name).width+LABEL_SPACING}}}ctx.globalAlpha=1;return[draw_start,draw_end]}});var ReadPainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler,ref_seq,base_color_fn){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null);this.base_color_fn=base_color_fn};extend(ReadPainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var height,mode=this.mode;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT;if(this.prefs.show_insertions){height*=2}}}return height},_parse_cigar:function(cigar_str){var cigar_ops="MIDNSHP=X";var blocks=[[0,0]],cur_block=blocks[0],base_pos=0,parsed_cigar=_.map(cigar_str.match(/[0-9]+[MIDNSHP=X]/g),function(op){var op_len=parseInt(op.slice(0,-1),10),op_char=op.slice(-1);if(op_char==="N"){if(cur_block[1]!==0){cur_block=[base_pos+op_len,base_pos+op_len];blocks.push(cur_block)}}else{if("ISHP".indexOf(op_char)===-1){cur_block[1]+=op_len;base_pos+=op_len}}return[cigar_ops.indexOf(op_char),op_len]});return{blocks:blocks,cigar:parsed_cigar}},draw_read:function(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,cigar,strand,read_seq){ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=Math.round(w_scale/2),char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.block_color:this.prefs.reverse_strand_color),pack_mode=(mode==="Pack"),paint_utils=new ReadPainterUtils(ctx,(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),w_scale,mode);var draw_last=[];if(!cigar){cigar=[[0,read_seq.length]]}for(var cig_id=0,len=cigar.length;cig_id<len;cig_id++){var cig=cigar[cig_id],cig_op="MIDNSHP=X"[cig[0]],cig_len=cig[1];var seq_start=feature_start+base_offset,s_start=Math.floor(Math.max(-0.5*w_scale,(seq_start-tile_low-0.5)*w_scale)),s_end=Math.floor(Math.max(0,(seq_start+cig_len-tile_low-0.5)*w_scale));if(!is_overlap([seq_start,seq_start+cig_len],tile_region)){if("MDN=X".indexOf(cig_op)!==-1){base_offset+=cig_len}continue}if(s_start===s_end){s_end+=1}switch(cig_op){case"H":break;case"S":seq_offset+=cig_len;break;case"M":case"=":case"X":ctx.fillStyle=block_color;ctx.fillRect(s_start,y_start+(pack_mode?1:4),s_end-s_start,(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT));var seq=read_seq.slice(seq_offset,seq_offset+cig_len),ref_char,read_char;for(var c=0,str_len=seq.length;c<str_len;c++){if(seq_start+c>=tile_low&&seq_start+c<=tile_high){ref_char=(this.ref_seq?this.ref_seq[seq_start-tile_low+c]:null);read_char=seq[c];if((ref_char&&(!this.prefs.show_differences||(read_char.toLowerCase!=="n"&&(ref_char.toLowerCase()!==read_char.toLowerCase()))))||(!ref_char&&!this.prefs.show_differences)){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillStyle=this.base_color_fn(seq[c]);if(pack_mode&&w_scale>char_width_px){ctx.fillText(seq[c],c_start,y_start+9)}else{if(w_scale>0.05){ctx.fillRect(c_start-gap,y_start+(pack_mode?1:4),Math.max(1,Math.round(w_scale)),(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT))}}}}}seq_offset+=cig_len;base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start,y_start+5,s_end-s_start,1);base_offset+=cig_len;break;case"D":paint_utils.draw_deletion(s_start,y_start,1);base_offset+=cig_len;break;case"P":break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=read_seq.slice(seq_offset,seq_offset+cig_len);if(this.prefs.show_insertions){var x_center=s_start-(s_end-s_start)/2;if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_start-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_start+4,5]};ctx.fillStyle=CONNECTOR_COLOR;switch(compute_overlap([seq_start,seq_start+cig_len],tile_region)){case (OVERLAP_START):seq=seq.slice(tile_low-seq_start);break;case (OVERLAP_END):seq=seq.slice(0,seq_start-tile_high);break;case (CONTAINED_BY):break;case (CONTAINS):seq=seq.slice(tile_low-seq_start,seq_start-tile_high);break}for(var c=0,str_len=seq.length;c<str_len;c++){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start-(s_end-s_start)/2,y_start)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_start+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_start+9]})}else{}}}seq_offset+=cig_len;break}}ctx.fillStyle="yellow";var item,type,data;for(var i=0;i<draw_last.length;i++){item=draw_last[i];type=item.type;data=item.data;if(type==="text"){ctx.save();ctx.font="bold "+ctx.font;ctx.fillText(data[0],data[1],data[2]);ctx.restore()}else{if(type==="triangle"){drawDownwardEquilateralTriangle(ctx,data[0],data[1],data[2])}}}},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],f_start=Math.floor(Math.max(-0.5*w_scale,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),y_start=(mode==="Dense"?0:(0+slot))*y_scale,label_color=this.prefs.label_color;if(feature[5] instanceof Array){var connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[4][0],feature[4][2],feature[4][3],feature[4][4])}else{connector=false}if(feature[5][1]>=tile_low&&feature[5][0]<=tile_high&&feature[5][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}var b1_end=Math.ceil(Math.min(width,Math.max(-0.5*w_scale,(feature[4][1]-tile_low-0.5)*w_scale))),b2_start=Math.floor(Math.max(-0.5*w_scale,(feature[5][0]-tile_low-0.5)*w_scale));if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;dashedLine(ctx,b1_end,y_start+5,b2_start,y_start+5)}}else{this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,feature[4],feature[5],feature[6])}if(mode==="Pack"&&feature_start>=tile_low&&feature_name!=="."){ctx.fillStyle=this.prefs.label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+8)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+8)}}return[0,0]}});var RefBasedReadPainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler,ref_seq,base_color_fn){ReadPainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler,ref_seq,base_color_fn)};extend(RefBasedReadPainter.prototype,ReadPainter.prototype,FeaturePainter,{draw_read:function(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,cigar,strand,read_seq){ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=Math.round(w_scale/2),char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.block_color:this.prefs.reverse_strand_color),pack_mode=(mode==="Pack"),paint_utils=new ReadPainterUtils(ctx,(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),w_scale,mode),drawing_blocks=[];var draw_last=[];var t=this._parse_cigar(cigar);cigar=t.cigar;drawing_blocks=t.blocks;for(var i=0;i<drawing_blocks.length;i++){var block=drawing_blocks[i];if(is_overlap([feature_start+block[0],feature_start+block[1]],tile_region)){var s_start=Math.floor(Math.max(-0.5*w_scale,(feature_start+block[0]-tile_low-0.5)*w_scale)),s_end=Math.floor(Math.max(0,(feature_start+block[1]-tile_low-0.5)*w_scale));if(s_start===s_end){s_end+=1}ctx.fillStyle=block_color;ctx.fillRect(s_start,y_start+(pack_mode?1:4),s_end-s_start,(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT))}}for(var cig_id=0,len=cigar.length;cig_id<len;cig_id++){var cig=cigar[cig_id],cig_op="MIDNSHP=X"[cig[0]],cig_len=cig[1];var seq_start=feature_start+base_offset,s_start=Math.floor(Math.max(0,-0.5*w_scale,(seq_start-tile_low-0.5)*w_scale)),s_end=Math.floor(Math.max(0,(seq_start+cig_len-tile_low-0.5)*w_scale));if(!is_overlap([seq_start,seq_start+cig_len],tile_region)){continue}if(s_start===s_end){s_end+=1}switch(cig_op){case"H":case"S":case"P":break;case"M":base_offset+=cig_len;break;case"=":case"X":var cur_seq="";if(cig_op==="X"){cur_seq=read_seq.slice(seq_offset,seq_offset+cig_len)}else{if(this.ref_seq){cur_seq=this.ref_seq.slice(Math.max(0,seq_start-tile_low),Math.min(seq_start-tile_low+cig_len,tile_high-tile_low))}}var start_pos=Math.max(seq_start,tile_low);for(var c=0;c<cur_seq.length;c++){if(cur_seq&&!this.prefs.show_differences||cig_op==="X"){var c_start=Math.floor(Math.max(0,(start_pos+c-tile_low)*w_scale));ctx.fillStyle=this.base_color_fn(cur_seq[c]);if(pack_mode&&w_scale>char_width_px){ctx.fillText(cur_seq[c],c_start,y_start+9)}else{if(w_scale>0.05){ctx.fillRect(c_start-gap,y_start+(pack_mode?1:4),Math.max(1,Math.round(w_scale)),(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT))}}}}if(cig_op==="X"){seq_offset+=cig_len}base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start,y_start+5,s_end-s_start,1);base_offset+=cig_len;break;case"D":paint_utils.draw_deletion(s_start,y_start+(pack_mode?1:4),cig_len);base_offset+=cig_len;break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=read_seq.slice(seq_offset,seq_offset+cig_len);if(this.prefs.show_insertions){var x_center=s_start-(s_end-s_start)/2;if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_start-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_start+4,5]};ctx.fillStyle=CONNECTOR_COLOR;switch(compute_overlap([seq_start,seq_start+cig_len],tile_region)){case (OVERLAP_START):seq=seq.slice(tile_low-seq_start);break;case (OVERLAP_END):seq=seq.slice(0,seq_start-tile_high);break;case (CONTAINED_BY):break;case (CONTAINS):seq=seq.slice(tile_low-seq_start,seq_start-tile_high);break}for(var c=0,str_len=seq.length;c<str_len;c++){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start-(s_end-s_start)/2,y_start)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_start+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_start+9]})}else{}}}seq_offset+=cig_len;break}}ctx.fillStyle="yellow";var item,type,data;for(var i=0;i<draw_last.length;i++){item=draw_last[i];type=item.type;data=item.data;if(type==="text"){ctx.save();ctx.font="bold "+ctx.font;ctx.fillText(data[0],data[1],data[2]);ctx.restore()}else{if(type==="triangle"){drawDownwardEquilateralTriangle(ctx,data[0],data[1],data[2])}}}}});var ArcLinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){LinkedFeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.longest_feature_length=this.calculate_longest_feature_length();this.draw_background_connector=false;this.draw_individual_connectors=true};extend(ArcLinkedFeaturePainter.prototype,FeaturePainter.prototype,LinkedFeaturePainter.prototype,{calculate_longest_feature_length:function(){var longest_feature_length=0;for(var i=0,len=this.data.length;i<len;i++){var feature=this.data[i],feature_start=feature[1],feature_end=feature[2];longest_feature_length=Math.max(longest_feature_length,feature_end-feature_start)}return longest_feature_length},get_top_padding:function(width){var view_range=this.view_end-this.view_start,w_scale=width/view_range;return Math.min(128,Math.ceil((this.longest_feature_length/2)*w_scale))},draw_connector:function(ctx,block1_start,block1_end,block2_start,block2_end,y_start){var x_center=(block1_end+block2_start)/2,radius=block2_start-x_center;var angle1=Math.PI,angle2=0;if(radius>0){ctx.beginPath();ctx.arc(x_center,y_start,block2_start-x_center,Math.PI,0);ctx.stroke()}}});var Color=function(rgb,a){if(Array.isArray(rgb)){this.rgb=rgb}else{if(rgb.length==6){this.rgb=rgb.match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{if(rgb.length==7){this.rgb=rgb.substring(1,7).match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{this.rgb=rgb.split("").map(function(c){return parseInt(c+c,16)})}}}this.alpha=typeof(a)==="number"?a:1};Color.prototype={eval:function(){return this},toCSS:function(){if(this.alpha<1){return"rgba("+this.rgb.map(function(c){return Math.round(c)}).concat(this.alpha).join(", ")+")"}else{return"#"+this.rgb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")}},toHSL:function(){var r=this.rgb[0]/255,g=this.rgb[1]/255,b=this.rgb[2]/255,a=this.alpha;var max=Math.max(r,g,b),min=Math.min(r,g,b);var h,s,l=(max+min)/2,d=max-min;if(max===min){h=s=0}else{s=l>0.5?d/(2-max-min):d/(max+min);switch(max){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4;break}h/=6}return{h:h*360,s:s,l:l,a:a}},toARGB:function(){var argb=[Math.round(this.alpha*255)].concat(this.rgb);return"#"+argb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")},mix:function(color2,weight){color1=this;var p=weight;var w=p*2-1;var a=color1.toHSL().a-color2.toHSL().a;var w1=(((w*a==-1)?w:(w+a)/(1+w*a))+1)/2;var w2=1-w1;var rgb=[color1.rgb[0]*w1+color2.rgb[0]*w2,color1.rgb[1]*w1+color2.rgb[1]*w2,color1.rgb[2]*w1+color2.rgb[2]*w2];var alpha=color1.alpha*p+color2.alpha*(1-p);return new Color(rgb,alpha)}};var LinearRamp=function(start_color,end_color,start_value,end_value){this.start_color=new Color(start_color);this.end_color=new Color(end_color);this.start_value=start_value;this.end_value=end_value;this.value_range=end_value-start_value};LinearRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);value=(value-this.start_value)/this.value_range;return this.start_color.mix(this.end_color,1-value).toCSS()};var SplitRamp=function(start_color,middle_color,end_color,start_value,end_value){this.positive_ramp=new LinearRamp(middle_color,end_color,0,end_value);this.negative_ramp=new LinearRamp(middle_color,start_color,0,-start_value);this.start_value=start_value;this.end_value=end_value};SplitRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);if(value>=0){return this.positive_ramp.map_value(value)}else{return this.negative_ramp.map_value(-value)}};var DiagonalHeatmapPainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][5])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][5])}this.prefs.max_value=max_value}};DiagonalHeatmapPainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Heatmap",pos_color:"#FF8C00",neg_color:"#4169E1"};DiagonalHeatmapPainter.prototype.draw=function(ctx,width,height,w_scale){var min_value=this.prefs.min_value,max_value=this.prefs.max_value,value_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data,invsqrt2=1/Math.sqrt(2);var ramp=(new SplitRamp(this.prefs.neg_color,"#FFFFFF",this.prefs.pos_color,min_value,max_value));var d,s1,e1,s2,e2,value;var scale=function(p){return(p-view_start)*w_scale};ctx.save();ctx.rotate(-45*Math.PI/180);ctx.scale(invsqrt2,invsqrt2);for(var i=0,len=data.length;i<len;i++){d=data[i];s1=scale(d[1]);e1=scale(d[2]);s2=scale(d[4]);e2=scale(d[5]);value=d[6];ctx.fillStyle=(ramp.map_value(value));ctx.fillRect(s1,s2,(e1-s1),(e2-s2))}ctx.restore()};var ReadPainterUtils=function(ctx,row_height,px_per_base,mode){this.ctx=ctx;this.row_height=row_height;this.px_per_base=px_per_base;this.draw_details=(mode==="Pack"||mode==="Auto")&&(px_per_base>=ctx.canvas.manager.char_width_px);this.delete_details_thickness=0.2};extend(ReadPainterUtils.prototype,{draw_deletion:function(x,y,len){this.ctx.fillStyle="black";var thickness=(this.draw_details?this.delete_details_thickness:1)*this.row_height;y+=0.5*(this.row_height-thickness);this.ctx.fillRect(x,y,len*this.px_per_base,thickness)}});var VariantPainter=function(data,view_start,view_end,prefs,mode,base_color_fn){Painter.call(this,data,view_start,view_end,prefs,mode);this.base_color_fn=base_color_fn;this.divider_height=1};extend(VariantPainter.prototype,Painter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}return height},get_required_height:function(num_samples){var height=this.prefs.summary_height;if(num_samples>1&&this.prefs.show_sample_data){height+=this.divider_height+num_samples*this.get_row_height()}return height},draw:function(ctx,width,height,w_scale){ctx.save();var get_deletion_info=function(ref,alt){var ref_len=ref.length,alt_len=alt.length,start=0,len=1,is_delete=false;if(alt==="-"){is_delete=true;len=ref.length}else{if(ref.indexOf(alt)===0&&ref_len>alt_len){is_delete=true;len=ref_len=alt_len;start+=alt_len}}return(is_delete?{start:start,len:len}:null)};var locus_data,pos,id,ref,alt,qual,filter,sample_gts,allele_counts,variant,draw_x_start,char_x_start,draw_y_start,genotype,base_px=Math.max(1,Math.floor(w_scale)),num_samples=(this.data.length?this.data[0][7].split(",").length:0),row_height=(this.mode==="Squish"?SQUISH_TRACK_HEIGHT:PACK_TRACK_HEIGHT),feature_height=(w_scale<0.1?row_height:(this.mode==="Squish"?SQUISH_FEATURE_HEIGHT:PACK_FEATURE_HEIGHT)),draw_summary=true,paint_utils=new ReadPainterUtils(ctx,row_height,w_scale,this.mode),j;if(num_samples===1){row_height=feature_height=(w_scale<ctx.canvas.manager.char_width_px?this.prefs.summary_height:row_height);draw_summary=false}if(this.prefs.show_sample_data&&draw_summary){ctx.fillStyle="#F3F3F3";ctx.globalAlpha=1;ctx.fillRect(0,this.prefs.summary_height-this.divider_height,width,this.divider_height)}ctx.textAlign="center";for(var i=0;i<this.data.length;i++){locus_data=this.data[i];pos=locus_data[1];ref=locus_data[3];alt=[locus_data[4].split(",")];sample_gts=locus_data[7].split(",");allele_counts=locus_data.slice(8);alt=_.map(_.flatten(alt),function(a){var type,alt_info={},delete_info=get_deletion_info(ref,a);if(delete_info){type="deletion";_.extend(alt_info,delete_info)}else{type="snp"}return _.extend(alt_info,{type:type,value:a,})});if(pos<this.view_start||pos>this.view_end){continue}draw_x_start=Math.floor(Math.max(-0.5*w_scale,(pos-this.view_start-0.5)*w_scale));char_x_start=Math.floor(Math.max(0,(pos-this.view_start)*w_scale));if(draw_summary){ctx.fillStyle="#999999";ctx.globalAlpha=1;ctx.fillRect(draw_x_start,0,base_px,this.prefs.summary_height);draw_y_start=this.prefs.summary_height;for(j=0;j<alt.length;j++){ctx.fillStyle=(alt[j].type==="deletion"?"black":this.base_color_fn(alt[j].value));allele_frac=allele_counts/sample_gts.length;draw_height=Math.ceil(this.prefs.summary_height*allele_frac);ctx.fillRect(draw_x_start,draw_y_start-draw_height,base_px,draw_height);draw_y_start-=draw_height}}if(!this.prefs.show_sample_data){continue}draw_y_start=(draw_summary?this.prefs.summary_height+this.divider_height:0);for(j=0;j<sample_gts.length;j++,draw_y_start+=row_height){genotype=(sample_gts[j]?sample_gts[j].split(/\/|\|/):["0","0"]);variant=null;if(genotype[0]===genotype[1]){if(genotype[0]==="."){}else{if(genotype[0]!=="0"){variant=alt[parseInt(genotype[0],10)-1];ctx.globalAlpha=1}}}else{variant=(genotype[0]!=="0"?genotype[0]:genotype[1]);variant=alt[parseInt(variant,10)-1];ctx.globalAlpha=0.5}if(variant){if(variant.type==="snp"){var snp=variant.value;ctx.fillStyle=this.base_color_fn(snp);if(paint_utils.draw_details){ctx.fillText(snp,char_x_start,draw_y_start+row_height)}else{ctx.fillRect(draw_x_start,draw_y_start+1,base_px,feature_height)}}else{if(variant.type==="deletion"){paint_utils.draw_deletion(draw_x_start+base_px*variant.start,draw_y_start+1,variant.len)}else{}}}}}ctx.restore()}});return{Scaler:Scaler,LinePainter:LinePainter,LinkedFeaturePainter:LinkedFeaturePainter,ReadPainter:ReadPainter,RefBasedReadPainter:RefBasedReadPainter,ArcLinkedFeaturePainter:ArcLinkedFeaturePainter,DiagonalHeatmapPainter:DiagonalHeatmapPainter,VariantPainter:VariantPainter}});
\ No newline at end of file
+define(["libs/underscore"],function(_){var extend=_.extend;var BEFORE=1001,CONTAINS=1002,OVERLAP_START=1003,OVERLAP_END=1004,CONTAINED_BY=1005,AFTER=1006;var compute_overlap=function(first_region,second_region){var first_start=first_region[0],first_end=first_region[1],second_start=second_region[0],second_end=second_region[1],overlap;if(first_start<second_start){if(first_end<=second_start){overlap=BEFORE}else{if(first_end<=second_end){overlap=OVERLAP_START}else{overlap=CONTAINS}}}else{if(first_start>second_end){overlap=AFTER}else{if(first_end<=second_end){overlap=CONTAINED_BY}else{overlap=OVERLAP_END}}}return overlap};var is_overlap=function(first_region,second_region){var overlap=compute_overlap(first_region,second_region);return(overlap!==BEFORE&&overlap!==AFTER)};var dashedLine=function(ctx,x1,y1,x2,y2,dashLen){if(dashLen===undefined){dashLen=4}var dX=x2-x1;var dY=y2-y1;var dashes=Math.floor(Math.sqrt(dX*dX+dY*dY)/dashLen);var dashX=dX/dashes;var dashY=dY/dashes;var q;for(q=0;q<dashes;q++,x1+=dashX,y1+=dashY){if(q%2!==0){continue}ctx.fillRect(x1,y1,dashLen,1)}};var drawDownwardEquilateralTriangle=function(ctx,down_vertex_x,down_vertex_y,side_len){var x1=down_vertex_x-side_len/2,x2=down_vertex_x+side_len/2,y=down_vertex_y-Math.sqrt(side_len*3/2);ctx.beginPath();ctx.moveTo(x1,y);ctx.lineTo(x2,y);ctx.lineTo(down_vertex_x,down_vertex_y);ctx.lineTo(x1,y);ctx.strokeStyle=this.fillStyle;ctx.fill();ctx.stroke();ctx.closePath()};var Scaler=function(default_val){this.default_val=(default_val?default_val:1)};Scaler.prototype.gen_val=function(input){return this.default_val};var Painter=function(data,view_start,view_end,prefs,mode){this.data=data;this.view_start=view_start;this.view_end=view_end;this.prefs=extend({},this.default_prefs,prefs);this.mode=mode};Painter.prototype.default_prefs={};Painter.prototype.draw=function(ctx,width,height,w_scale){};var LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);if(this.prefs.min_value===undefined){this.prefs.min_value=_.min(_.map(this.data,function(d){return d[1]}))||0}if(this.prefs.max_value===undefined){this.prefs.max_value=_.max(_.map(this.data,function(d){return d[1]}))||0}};LinePainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Histogram",color:"#000",overflow_color:"#F66"};LinePainter.prototype.draw=function(ctx,width,height,w_scale){var in_path=false,min_value=this.prefs.min_value,max_value=this.prefs.max_value,vertical_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data;ctx.save();var y_zero=Math.round(height+min_value/vertical_range*height);if(mode!=="Intensity"){ctx.fillStyle="#aaa";ctx.fillRect(0,y_zero,width,1)}ctx.beginPath();var x_scaled,y,delta_x_px;if(data.length>1){delta_x_px=Math.ceil((data[1][0]-data[0][0])*w_scale)}else{delta_x_px=10}var painter_color=this.prefs.block_color||this.prefs.color,pref_color=parseInt(painter_color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255,top_overflow=false,bot_overflow=false;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=painter_color;top_overflow=bot_overflow=false;x_scaled=Math.round((data[i][0]-view_start)*w_scale);y=data[i][1];if(y===null){if(in_path&&mode==="Filled"){ctx.lineTo(x_scaled,height_px)}in_path=false;continue}if(y<min_value){bot_overflow=true;y=min_value}else{if(y>max_value){top_overflow=true;y=max_value}}if(mode==="Histogram"){y=Math.round(y/vertical_range*height_px);ctx.fillRect(x_scaled,y_zero,delta_x_px,-y)}else{if(mode==="Intensity"){var saturation=(y-min_value)/vertical_range,new_r=Math.round(pref_r+(255-pref_r)*(1-saturation)),new_g=Math.round(pref_g+(255-pref_g)*(1-saturation)),new_b=Math.round(pref_b+(255-pref_b)*(1-saturation));ctx.fillStyle="rgb("+new_r+","+new_g+","+new_b+")";ctx.fillRect(x_scaled,0,delta_x_px,height_px)}else{y=Math.round(height_px-(y-min_value)/vertical_range*height_px);if(in_path){ctx.lineTo(x_scaled,y)}else{in_path=true;if(mode==="Filled"){ctx.moveTo(x_scaled,height_px);ctx.lineTo(x_scaled,y)}else{ctx.moveTo(x_scaled,y)}}}}ctx.fillStyle=this.prefs.overflow_color;if(top_overflow||bot_overflow){var overflow_x;if(mode==="Histogram"||mode==="Intensity"){overflow_x=delta_x_px}else{x_scaled-=2;overflow_x=4}if(top_overflow){ctx.fillRect(x_scaled,0,overflow_x,3)}if(bot_overflow){ctx.fillRect(x_scaled,height_px-3,overflow_x,3)}}ctx.fillStyle=painter_color}if(mode==="Filled"){if(in_path){ctx.lineTo(x_scaled,y_zero);ctx.lineTo(0,y_zero)}ctx.fill()}else{ctx.stroke()}ctx.restore()};var FeaturePositionMapper=function(slot_height){this.feature_positions={};this.slot_height=slot_height;this.translation=0;this.y_translation=0};FeaturePositionMapper.prototype.map_feature_data=function(feature_data,slot,x_start,x_end){if(!this.feature_positions[slot]){this.feature_positions[slot]=[]}this.feature_positions[slot].push({data:feature_data,x_start:x_start,x_end:x_end})};FeaturePositionMapper.prototype.get_feature_data=function(x,y){var slot=Math.floor((y-this.y_translation)/this.slot_height),feature_dict;if(!this.feature_positions[slot]){return null}x+=this.translation;for(var i=0;i<this.feature_positions[slot].length;i++){feature_dict=this.feature_positions[slot][i];if(x>=feature_dict.x_start&&x<=feature_dict.x_end){return feature_dict.data}}};var FeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){Painter.call(this,data,view_start,view_end,prefs,mode);this.alpha_scaler=(alpha_scaler?alpha_scaler:new Scaler());this.height_scaler=(height_scaler?height_scaler:new Scaler());this.max_label_length=200};FeaturePainter.prototype.default_prefs={block_color:"#FFF",connector_color:"#FFF"};extend(FeaturePainter.prototype,{get_required_height:function(rows_required,width){var required_height=this.get_row_height(),y_scale=required_height,mode=this.mode;if(mode==="no_detail"||mode==="Squish"||mode==="Pack"){required_height=rows_required*y_scale}return required_height+this.get_top_padding(width)},get_top_padding:function(width){return 0},draw:function(ctx,width,height,w_scale,slots){var data=this.data,view_start=this.view_start,view_end=this.view_end;ctx.save();ctx.fillStyle=this.prefs.block_color;ctx.textAlign="right";var y_scale=this.get_row_height(),feature_mapper=new FeaturePositionMapper(y_scale),x_draw_coords;for(var i=0,len=data.length;i<len;i++){var feature=data[i],feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],slot=(slots&&slots[feature_uid]!==undefined?slots[feature_uid]:null);if((feature_start<view_end&&feature_end>view_start)&&(this.mode==="Dense"||slot!==null)){x_draw_coords=this.draw_element(ctx,this.mode,feature,slot,view_start,view_end,w_scale,y_scale,width);feature_mapper.map_feature_data(feature,slot,x_draw_coords[0],x_draw_coords[1])}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return feature_mapper},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){return[0,0]}});var DENSE_TRACK_HEIGHT=10,NO_DETAIL_TRACK_HEIGHT=3,SQUISH_TRACK_HEIGHT=5,PACK_TRACK_HEIGHT=10,NO_DETAIL_FEATURE_HEIGHT=1,DENSE_FEATURE_HEIGHT=9,SQUISH_FEATURE_HEIGHT=3,PACK_FEATURE_HEIGHT=9,LABEL_SPACING=2,CONNECTOR_COLOR="#ccc";var LinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.draw_background_connector=true;this.draw_individual_connectors=false};extend(LinkedFeaturePainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="no_detail"){height=NO_DETAIL_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}}return height},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),draw_start=f_start,draw_end=f_end,y_start=(mode==="Dense"?0:(0+slot))*y_scale+this.get_top_padding(width),thickness,y_start,thick_start=null,thick_end=null,block_color=(!feature_strand||feature_strand==="+"||feature_strand==="."?this.prefs.block_color:this.prefs.reverse_strand_color);label_color=this.prefs.label_color;ctx.globalAlpha=this.alpha_scaler.gen_val(feature);if(mode==="Dense"){slot=1}if(mode==="no_detail"){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+5,f_end-f_start,NO_DETAIL_FEATURE_HEIGHT)}else{var feature_ts=feature[5],feature_te=feature[6],feature_blocks=feature[7],full_height=true;if(feature_ts&&feature_te){thick_start=Math.floor(Math.max(0,(feature_ts-tile_low)*w_scale));thick_end=Math.ceil(Math.min(width,Math.max(0,(feature_te-tile_low)*w_scale)))}var thin_height,thick_height;if(mode==="Squish"){thin_height=1;thick_height=SQUISH_FEATURE_HEIGHT;full_height=false}else{if(mode==="Dense"){thin_height=5;thick_height=DENSE_FEATURE_HEIGHT}else{thin_height=5;thick_height=PACK_FEATURE_HEIGHT}}if(!feature_blocks){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height);if(feature_strand&&full_height){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height)}}else{var cur_y_start,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_start=y_start+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_start=y_start;cur_height=thick_height}else{cur_y_start+=(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}}if(this.draw_background_connector){if(mode==="Squish"||mode==="Dense"){ctx.fillStyle=CONNECTOR_COLOR}else{if(feature_strand){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand")}}}else{ctx.fillStyle=CONNECTOR_COLOR}}ctx.fillRect(f_start,cur_y_start,f_end-f_start,cur_height)}var start_and_height;for(var k=0,k_len=feature_blocks.length;k<k_len;k++){var block=feature_blocks[k],block_start=Math.floor(Math.max(0,(block[0]-tile_low-0.5)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-tile_low-0.5)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_start+(thick_height-thin_height)/2+1,block_end-block_start,thin_height);if(thick_start!==undefined&&feature_te>feature_ts&&!(block_start>thick_end||block_end<thick_start)){var block_thick_start=Math.max(block_start,thick_start),block_thick_end=Math.min(block_end,thick_end);ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height);if(feature_blocks.length===1&&mode==="Pack"){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}if(block_thick_start+14<block_thick_end){block_thick_start+=2;block_thick_end-=2}ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height)}}if(this.draw_individual_connectors&&last_block_start){this.draw_connector(ctx,last_block_start,last_block_end,block_start,block_end,y_start)}last_block_start=block_start;last_block_end=block_end}if(mode==="Pack"){ctx.globalAlpha=1;ctx.fillStyle="white";var hscale_factor=this.height_scaler.gen_val(feature),new_height=Math.ceil(thick_height*hscale_factor),ws_height=Math.round((thick_height-new_height)/2);if(hscale_factor!==1){ctx.fillRect(f_start,cur_y_start+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_start+thick_height-ws_height+1,f_end-f_start,ws_height)}}}ctx.globalAlpha=1;if(feature_name&&mode==="Pack"&&feature_start>tile_low){ctx.fillStyle=label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+8,this.max_label_length);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+8,this.max_label_length);draw_start-=ctx.measureText(feature_name).width+LABEL_SPACING}}}ctx.globalAlpha=1;return[draw_start,draw_end]}});var ReadPainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler,ref_seq,base_color_fn){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null);this.base_color_fn=base_color_fn};extend(ReadPainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var height,mode=this.mode;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT;if(this.prefs.show_insertions){height*=2}}}return height},_parse_cigar:function(cigar_str){var cigar_ops="MIDNSHP=X";var blocks=[[0,0]],cur_block=blocks[0],base_pos=0,parsed_cigar=_.map(cigar_str.match(/[0-9]+[MIDNSHP=X]/g),function(op){var op_len=parseInt(op.slice(0,-1),10),op_char=op.slice(-1);if(op_char==="N"){if(cur_block[1]!==0){cur_block=[base_pos+op_len,base_pos+op_len];blocks.push(cur_block)}}else{if("ISHP".indexOf(op_char)===-1){cur_block[1]+=op_len;base_pos+=op_len}}return[cigar_ops.indexOf(op_char),op_len]});return{blocks:blocks,cigar:parsed_cigar}},draw_read:function(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,cigar,strand,read_seq){var update_base_offset=function(offset,cig_op,cig_len){if("M=NXD".indexOf(cig_op)!==-1){offset+=cig_len}return offset},update_seq_offset=function(offset,cig_op,cig_len){if("IX".indexOf(cig_op)!==-1){offset+=cig_len}return offset};ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=Math.round(w_scale/2),char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.block_color:this.prefs.reverse_strand_color),pack_mode=(mode==="Pack"),paint_utils=new ReadPainterUtils(ctx,(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),w_scale,mode),drawing_blocks=[];var draw_last=[];var t=this._parse_cigar(cigar);cigar=t.cigar;drawing_blocks=t.blocks;for(var i=0;i<drawing_blocks.length;i++){var block=drawing_blocks[i];if(is_overlap([feature_start+block[0],feature_start+block[1]],tile_region)){var s_start=Math.floor(Math.max(-0.5*w_scale,(feature_start+block[0]-tile_low-0.5)*w_scale)),s_end=Math.floor(Math.max(0,(feature_start+block[1]-tile_low-0.5)*w_scale));if(s_start===s_end){s_end+=1}ctx.fillStyle=block_color;ctx.fillRect(s_start,y_start+(pack_mode?1:4),s_end-s_start,(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT))}}for(var cig_id=0,len=cigar.length;cig_id<len;cig_id++){var cig=cigar[cig_id],cig_op="MIDNSHP=X"[cig[0]],cig_len=cig[1];var seq_start=feature_start+base_offset,s_start=Math.floor(Math.max(-0.5*w_scale,(seq_start-tile_low-0.5)*w_scale)),s_end=Math.floor(Math.max(0,(seq_start+cig_len-tile_low-0.5)*w_scale));if(!is_overlap([seq_start,seq_start+cig_len],tile_region)){base_offset=update_base_offset(base_offset,cig_op,cig_len);seq_offset=update_seq_offset(seq_offset,cig_op,cig_len);continue}if(s_start===s_end){s_end+=1}switch(cig_op){case"H":case"S":case"P":break;case"M":base_offset+=cig_len;break;case"=":case"X":var cur_seq="";if(cig_op==="X"){cur_seq=read_seq.slice(seq_offset,seq_offset+cig_len)}else{if(this.ref_seq){cur_seq=this.ref_seq.slice(Math.max(0,seq_start-tile_low),Math.min(seq_start-tile_low+cig_len,tile_high-tile_low))}}var start_pos=Math.max(seq_start,tile_low);for(var c=0;c<cur_seq.length;c++){if(cur_seq&&!this.prefs.show_differences||cig_op==="X"){var c_start=Math.floor(Math.max(0,(start_pos+c-tile_low)*w_scale));ctx.fillStyle=this.base_color_fn(cur_seq[c]);if(pack_mode&&w_scale>char_width_px){ctx.fillText(cur_seq[c],c_start,y_start+9)}else{if(w_scale>0.05){ctx.fillRect(c_start-gap,y_start+(pack_mode?1:4),Math.max(1,Math.round(w_scale)),(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT))}}}}if(cig_op==="X"){seq_offset+=cig_len}base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start,y_start+5,s_end-s_start,1);base_offset+=cig_len;break;case"D":paint_utils.draw_deletion(s_start,y_start+(pack_mode?1:4),cig_len);base_offset+=cig_len;break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=read_seq.slice(seq_offset,seq_offset+cig_len);if(this.prefs.show_insertions){var x_center=s_start-(s_end-s_start)/2;if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_start-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_start+4,5]};ctx.fillStyle=CONNECTOR_COLOR;switch(compute_overlap([seq_start,seq_start+cig_len],tile_region)){case (OVERLAP_START):seq=seq.slice(tile_low-seq_start);break;case (OVERLAP_END):seq=seq.slice(0,seq_start-tile_high);break;case (CONTAINED_BY):break;case (CONTAINS):seq=seq.slice(tile_low-seq_start,seq_start-tile_high);break}for(var c=0,str_len=seq.length;c<str_len;c++){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start-(s_end-s_start)/2,y_start)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_start+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_start+9]})}else{}}}seq_offset+=cig_len;break}}ctx.fillStyle="yellow";var item,type,data;for(var i=0;i<draw_last.length;i++){item=draw_last[i];type=item.type;data=item.data;if(type==="text"){ctx.save();ctx.font="bold "+ctx.font;ctx.fillText(data[0],data[1],data[2]);ctx.restore()}else{if(type==="triangle"){drawDownwardEquilateralTriangle(ctx,data[0],data[1],data[2])}}}},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],f_start=Math.floor(Math.max(-0.5*w_scale,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),y_start=(mode==="Dense"?0:(0+slot))*y_scale,label_color=this.prefs.label_color;if(feature[5] instanceof Array){var connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[4][0],feature[4][2],feature[4][3],feature[4][4])}else{connector=false}if(feature[5][1]>=tile_low&&feature[5][0]<=tile_high&&feature[5][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}var b1_end=Math.ceil(Math.min(width,Math.max(-0.5*w_scale,(feature[4][1]-tile_low-0.5)*w_scale))),b2_start=Math.floor(Math.max(-0.5*w_scale,(feature[5][0]-tile_low-0.5)*w_scale));if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;dashedLine(ctx,b1_end,y_start+5,b2_start,y_start+5)}}else{this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,feature[4],feature[5],feature[6])}if(mode==="Pack"&&feature_start>=tile_low&&feature_name!=="."){ctx.fillStyle=this.prefs.label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+8,this.max_label_length)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+8,this.max_label_length)}}return[0,0]}});var ArcLinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){LinkedFeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.longest_feature_length=this.calculate_longest_feature_length();this.draw_background_connector=false;this.draw_individual_connectors=true};extend(ArcLinkedFeaturePainter.prototype,FeaturePainter.prototype,LinkedFeaturePainter.prototype,{calculate_longest_feature_length:function(){var longest_feature_length=0;for(var i=0,len=this.data.length;i<len;i++){var feature=this.data[i],feature_start=feature[1],feature_end=feature[2];longest_feature_length=Math.max(longest_feature_length,feature_end-feature_start)}return longest_feature_length},get_top_padding:function(width){var view_range=this.view_end-this.view_start,w_scale=width/view_range;return Math.min(128,Math.ceil((this.longest_feature_length/2)*w_scale))},draw_connector:function(ctx,block1_start,block1_end,block2_start,block2_end,y_start){var x_center=(block1_end+block2_start)/2,radius=block2_start-x_center;var angle1=Math.PI,angle2=0;if(radius>0){ctx.beginPath();ctx.arc(x_center,y_start,block2_start-x_center,Math.PI,0);ctx.stroke()}}});var Color=function(rgb,a){if(Array.isArray(rgb)){this.rgb=rgb}else{if(rgb.length==6){this.rgb=rgb.match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{if(rgb.length==7){this.rgb=rgb.substring(1,7).match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{this.rgb=rgb.split("").map(function(c){return parseInt(c+c,16)})}}}this.alpha=typeof(a)==="number"?a:1};Color.prototype={eval:function(){return this},toCSS:function(){if(this.alpha<1){return"rgba("+this.rgb.map(function(c){return Math.round(c)}).concat(this.alpha).join(", ")+")"}else{return"#"+this.rgb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")}},toHSL:function(){var r=this.rgb[0]/255,g=this.rgb[1]/255,b=this.rgb[2]/255,a=this.alpha;var max=Math.max(r,g,b),min=Math.min(r,g,b);var h,s,l=(max+min)/2,d=max-min;if(max===min){h=s=0}else{s=l>0.5?d/(2-max-min):d/(max+min);switch(max){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4;break}h/=6}return{h:h*360,s:s,l:l,a:a}},toARGB:function(){var argb=[Math.round(this.alpha*255)].concat(this.rgb);return"#"+argb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")},mix:function(color2,weight){color1=this;var p=weight;var w=p*2-1;var a=color1.toHSL().a-color2.toHSL().a;var w1=(((w*a==-1)?w:(w+a)/(1+w*a))+1)/2;var w2=1-w1;var rgb=[color1.rgb[0]*w1+color2.rgb[0]*w2,color1.rgb[1]*w1+color2.rgb[1]*w2,color1.rgb[2]*w1+color2.rgb[2]*w2];var alpha=color1.alpha*p+color2.alpha*(1-p);return new Color(rgb,alpha)}};var LinearRamp=function(start_color,end_color,start_value,end_value){this.start_color=new Color(start_color);this.end_color=new Color(end_color);this.start_value=start_value;this.end_value=end_value;this.value_range=end_value-start_value};LinearRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);value=(value-this.start_value)/this.value_range;return this.start_color.mix(this.end_color,1-value).toCSS()};var SplitRamp=function(start_color,middle_color,end_color,start_value,end_value){this.positive_ramp=new LinearRamp(middle_color,end_color,0,end_value);this.negative_ramp=new LinearRamp(middle_color,start_color,0,-start_value);this.start_value=start_value;this.end_value=end_value};SplitRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);if(value>=0){return this.positive_ramp.map_value(value)}else{return this.negative_ramp.map_value(-value)}};var DiagonalHeatmapPainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][5])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][5])}this.prefs.max_value=max_value}};DiagonalHeatmapPainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Heatmap",pos_color:"#FF8C00",neg_color:"#4169E1"};DiagonalHeatmapPainter.prototype.draw=function(ctx,width,height,w_scale){var min_value=this.prefs.min_value,max_value=this.prefs.max_value,value_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data,invsqrt2=1/Math.sqrt(2);var ramp=(new SplitRamp(this.prefs.neg_color,"#FFFFFF",this.prefs.pos_color,min_value,max_value));var d,s1,e1,s2,e2,value;var scale=function(p){return(p-view_start)*w_scale};ctx.save();ctx.rotate(-45*Math.PI/180);ctx.scale(invsqrt2,invsqrt2);for(var i=0,len=data.length;i<len;i++){d=data[i];s1=scale(d[1]);e1=scale(d[2]);s2=scale(d[4]);e2=scale(d[5]);value=d[6];ctx.fillStyle=(ramp.map_value(value));ctx.fillRect(s1,s2,(e1-s1),(e2-s2))}ctx.restore()};var ReadPainterUtils=function(ctx,row_height,px_per_base,mode){this.ctx=ctx;this.row_height=row_height;this.px_per_base=px_per_base;this.draw_details=(mode==="Pack"||mode==="Auto")&&(px_per_base>=ctx.canvas.manager.char_width_px);this.delete_details_thickness=0.2};extend(ReadPainterUtils.prototype,{draw_deletion:function(x,y,len){this.ctx.fillStyle="black";var thickness=(this.draw_details?this.delete_details_thickness:1)*this.row_height;y+=0.5*(this.row_height-thickness);this.ctx.fillRect(x,y,len*this.px_per_base,thickness)}});var VariantPainter=function(data,view_start,view_end,prefs,mode,base_color_fn){Painter.call(this,data,view_start,view_end,prefs,mode);this.base_color_fn=base_color_fn;this.divider_height=1};extend(VariantPainter.prototype,Painter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}return height},get_required_height:function(num_samples){var height=this.prefs.summary_height;if(num_samples>1&&this.prefs.show_sample_data){height+=this.divider_height+num_samples*this.get_row_height()}return height},draw:function(ctx,width,height,w_scale){ctx.save();var get_deletion_info=function(ref,alt){var ref_len=ref.length,alt_len=alt.length,start=0,len=1,is_delete=false;if(alt==="-"){is_delete=true;len=ref.length}else{if(ref.indexOf(alt)===0&&ref_len>alt_len){is_delete=true;len=ref_len=alt_len;start+=alt_len}}return(is_delete?{start:start,len:len}:null)};var locus_data,pos,id,ref,alt,qual,filter,sample_gts,allele_counts,variant,draw_x_start,char_x_start,draw_y_start,genotype,base_px=Math.max(1,Math.floor(w_scale)),num_samples=(this.data.length?this.data[0][7].split(",").length:0),row_height=(this.mode==="Squish"?SQUISH_TRACK_HEIGHT:PACK_TRACK_HEIGHT),feature_height=(w_scale<0.1?row_height:(this.mode==="Squish"?SQUISH_FEATURE_HEIGHT:PACK_FEATURE_HEIGHT)),draw_summary=true,paint_utils=new ReadPainterUtils(ctx,row_height,w_scale,this.mode),j;if(num_samples===1){row_height=feature_height=(w_scale<ctx.canvas.manager.char_width_px?this.prefs.summary_height:row_height);draw_summary=false}if(this.prefs.show_sample_data&&draw_summary){ctx.fillStyle="#F3F3F3";ctx.globalAlpha=1;ctx.fillRect(0,this.prefs.summary_height-this.divider_height,width,this.divider_height)}ctx.textAlign="center";for(var i=0;i<this.data.length;i++){locus_data=this.data[i];pos=locus_data[1];ref=locus_data[3];alt=[locus_data[4].split(",")];sample_gts=locus_data[7].split(",");allele_counts=locus_data.slice(8);alt=_.map(_.flatten(alt),function(a){var type,alt_info={},delete_info=get_deletion_info(ref,a);if(delete_info){type="deletion";_.extend(alt_info,delete_info)}else{type="snp"}return _.extend(alt_info,{type:type,value:a,})});if(pos<this.view_start||pos>this.view_end){continue}draw_x_start=Math.floor(Math.max(-0.5*w_scale,(pos-this.view_start-0.5)*w_scale));char_x_start=Math.floor(Math.max(0,(pos-this.view_start)*w_scale));if(draw_summary){ctx.fillStyle="#999999";ctx.globalAlpha=1;ctx.fillRect(draw_x_start,0,base_px,this.prefs.summary_height);draw_y_start=this.prefs.summary_height;for(j=0;j<alt.length;j++){ctx.fillStyle=(alt[j].type==="deletion"?"black":this.base_color_fn(alt[j].value));allele_frac=allele_counts/sample_gts.length;draw_height=Math.ceil(this.prefs.summary_height*allele_frac);ctx.fillRect(draw_x_start,draw_y_start-draw_height,base_px,draw_height);draw_y_start-=draw_height}}if(!this.prefs.show_sample_data){continue}draw_y_start=(draw_summary?this.prefs.summary_height+this.divider_height:0);for(j=0;j<sample_gts.length;j++,draw_y_start+=row_height){genotype=(sample_gts[j]?sample_gts[j].split(/\/|\|/):["0","0"]);variant=null;if(genotype[0]===genotype[1]){if(genotype[0]==="."){}else{if(genotype[0]!=="0"){variant=alt[parseInt(genotype[0],10)-1];ctx.globalAlpha=1}}}else{variant=(genotype[0]!=="0"?genotype[0]:genotype[1]);variant=alt[parseInt(variant,10)-1];ctx.globalAlpha=0.5}if(variant){if(variant.type==="snp"){var snp=variant.value;ctx.fillStyle=this.base_color_fn(snp);if(paint_utils.draw_details){ctx.fillText(snp,char_x_start,draw_y_start+row_height)}else{ctx.fillRect(draw_x_start,draw_y_start+1,base_px,feature_height)}}else{if(variant.type==="deletion"){paint_utils.draw_deletion(draw_x_start+base_px*variant.start,draw_y_start+1,variant.len)}else{}}}}}ctx.restore()}});return{Scaler:Scaler,LinePainter:LinePainter,LinkedFeaturePainter:LinkedFeaturePainter,ReadPainter:ReadPainter,ArcLinkedFeaturePainter:ArcLinkedFeaturePainter,DiagonalHeatmapPainter:DiagonalHeatmapPainter,VariantPainter:VariantPainter}});
\ No newline at end of file
diff -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 -r 231a61e88777bbf7e2db9ef1fdaa9d7fb757523f static/scripts/packed/viz/trackster/tracks.js
--- a/static/scripts/packed/viz/trackster/tracks.js
+++ b/static/scripts/packed/viz/trackster/tracks.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","viz/visualization","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters","viz/trackster/filters","mvc/data","mvc/tools","utils/config"],function(aa,w,j,s,J,h,W,P,R){var o=aa.extend;var l={};var i=function(ab,ac){l[ab.attr("id")]=ac};var k=function(ab,ac,ae,ad){ae=".group";l[ab.attr("id")]=ad;ab.bind("drag",{handle:"."+ac,relative:true},function(am,an){var al=$(this),aq=$(this).parent(),ai=aq.children(".track,.group"),ak=l[$(this).attr("id")],ah,ag,ao,af,aj;ag=$(this).parents(ae);if(ag.length!==0){ao=ag.position().top;af=ao+ag.outerHeight();var ap=l[ag.attr("id")];if(an.offsetY<ao){$(this).insertBefore(ag);ap.remove_drawable(ak);ap.container.add_drawable_before(ak,ap);return}else{if(an.offsetY>af){$(this).insertAfter(ag);ap.remove_drawable(ak);ap.container.add_drawable(ak);return}}}ag=null;for(aj=0;aj<ai.length;aj++){ah=$(ai.get(aj));ao=ah.position().top;af=ao+ah.outerHeight();if(ah.is(ae)&&this!==ah.get(0)&&an.offsetY>=ao&&an.offsetY<=af){if(an.offsetY-ao<af-an.offsetY){ah.find(".content-div").prepend(this)}else{ah.find(".content-div").append(this)}if(ak.container){ak.container.remove_drawable(ak)}l[ah.attr("id")].add_drawable(ak);return}}for(aj=0;aj<ai.length;aj++){ah=$(ai.get(aj));if(an.offsetY<ah.position().top&&!(ah.hasClass("reference-track")||ah.hasClass("intro"))){break}}if(aj===ai.length){if(this!==ai.get(aj-1)){aq.append(this);l[aq.attr("id")].move_drawable(ak,aj)}}else{if(this!==ai.get(aj)){$(this).insertBefore(ai.get(aj));l[aq.attr("id")].move_drawable(ak,(an.deltaY>0?aj-1:aj))}}}).bind("dragstart",function(){$(this).addClass("dragging")}).bind("dragend",function(){$(this).removeClass("dragging")})};var D=20,z=100,G=12000,Q=400,I=5000,v=100,m="Cannot display dataset due to an error. ",H="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",u="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",x="Tool cannot be rerun: ",a="Loading data...",T="Ready for display",O=10,F=20,A=["Histogram","Line","Filled","Intensity"];function U(ac,ab){if(!ab){ab=0}var ad=Math.pow(10,ab);return Math.round(ac*ad)/ad}var p=function(ac,ab,ae){if(!p.id_counter){p.id_counter=0}this.id=p.id_counter++;this.view=ac;this.container=ab;this.drag_handle_class=ae.drag_handle_class;this.is_overview=false;this.action_icons={};this.config=R.ConfigSettingCollection.from_models_and_saved_values(this.config_params,ae.prefs);if(!this.config.get_value("name")){this.config.set_value("name",ae.name)}if(this.config_onchange){this.config.on("change",this.config_onchange,this)}this.container_div=this.build_container_div();this.header_div=this.build_header_div();if(this.header_div){this.container_div.append(this.header_div);this.icons_div=$("<div/>").addClass("track-icons").hide().appendTo(this.header_div);this.build_action_icons(this.action_icons_def);this.header_div.append($("<div style='clear: both'/>"));this.header_div.dblclick(function(af){af.stopPropagation()});var ad=this;this.container_div.hover(function(){ad.icons_div.show()},function(){ad.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};p.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ab){if(ab.config.get_value("content_visible")){ab.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ab.hide_contents();ab.config.set_value("content_visible",false)}else{ab.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ab.config.set_value("content_visible",true);ab.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"gear",on_click_fn:function(ac){var ab=new R.ConfigSettingCollectionView({collection:ac.config});ab.render_in_modal("Configure Track")}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ab){$(".tooltip").remove();ab.remove()}}];o(p.prototype,{config_params:[{key:"name",label:"Name",type:"text",default_value:""},{key:"content_visible",type:"bool",default_value:true,hidden:true}],config_onchange:function(){this.track.set_name(this.track.config.get("values").name)},init:function(){},changed:function(){this.view.changed()},can_draw:function(){if(this.enabled&&this.config.get_value("content_visible")){return true}return false},request_draw:function(){},_draw:function(ab){},to_dict:function(){},set_name:function(ab){this.old_name=this.config.get_value("name");this.config.set_value("name",ab);this.name_div.text(ab)},revert_name:function(){if(this.old_name){this.config.set_value("name",this.old_name);this.name_div.text(this.old_name)}},remove:function(){this.changed();this.container.remove_drawable(this);var ab=this.view;this.container_div.hide(0,function(){$(this).remove();ab.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ac,ah,ag,af,ab,ae){var ad=this;this.action_icons[ac]=$("<a/>").attr("title",ah).addClass("icon-button").addClass(ag).tooltip().click(function(){af(ad)}).appendTo(this.icons_div);if(ae){this.action_icons[ac].hide()}},build_action_icons:function(ab){var ad;for(var ac=0;ac<ab.length;ac++){ad=ab[ac];this.add_action_icon(ad.name,ad.title,ad.css_class,ad.on_click_fn,ad.prepend,ad.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var y=function(ac,ab,ad){p.call(this,ac,ab,ad);this.obj_type=ad.obj_type;this.drawables=[]};o(y.prototype,p.prototype,{unpack_drawables:function(ad){this.drawables=[];var ac;for(var ab=0;ab<ad.length;ab++){ac=n(ad[ab],this.view,this);this.add_drawable(ac)}},init:function(){for(var ab=0;ab<this.drawables.length;ab++){this.drawables[ab].init()}},_draw:function(ab){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac]._draw(ab)}},to_dict:function(){var ac=[];for(var ab=0;ab<this.drawables.length;ab++){ac.push(this.drawables[ab].to_dict())}return{prefs:this.config.to_key_value_dict(),obj_type:this.obj_type,drawables:ac}},add_drawable:function(ab){this.drawables.push(ab);ab.container=this;this.changed()},add_drawable_before:function(ad,ab){this.changed();var ac=this.drawables.indexOf(ab);if(ac!==-1){this.drawables.splice(ac,0,ad);return true}return false},replace_drawable:function(ad,ab,ac){var ae=this.drawables.indexOf(ad);if(ae!==-1){this.drawables[ae]=ab;if(ac){ad.container_div.replaceWith(ab.container_div)}this.changed()}return ae},remove_drawable:function(ac){var ab=this.drawables.indexOf(ac);if(ab!==-1){this.drawables.splice(ab,1);ac.container=null;this.changed();return true}return false},move_drawable:function(ac,ad){var ab=this.drawables.indexOf(ac);if(ab!==-1){this.drawables.splice(ab,1);this.drawables.splice(ad,0,ac);this.changed();return true}return false},get_drawables:function(){return this.drawables},get_tracks:function(ae){var ab=this.drawables.slice(0),ac=[],ad;while(ab.length!==0){ad=ab.shift();if(ad instanceof ae){ac.push(ad)}else{if(ad.drawables){ab=ab.concat(ad.drawables)}}}return ac}});var N=function(ac,ab,ae){o(ae,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});y.call(this,ac,ab,ae);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);i(this.container_div,this);i(this.content_div,this);k(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new h.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in ae){this.unpack_drawables(ae.drawables)}if("filters" in ae){var ad=this.filters_manager;this.filters_manager=new h.FiltersManager(this,ae.filters);ad.parent_div.replaceWith(this.filters_manager.parent_div);if(ae.filters.visible){this.setup_multitrack_filtering()}}};o(N.prototype,p.prototype,y.prototype,{action_icons_def:[p.prototype.action_icons_def[0],p.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ab){$(".tooltip").remove();ab.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ab){if(ab.filters_manager.visible()){ab.filters_manager.clear_filters();ab._restore_filter_managers()}else{ab.setup_multitrack_filtering();ab.request_draw({clear_tile_cache:true})}ab.filters_manager.toggle()}},p.prototype.action_icons_def[2]],build_container_div:function(){var ab=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ab)}return ab},build_header_div:function(){var ab=$("<div/>").addClass("track-header");ab.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.config.get_value("name")).appendTo(ab);return ab},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ad=this.drawables.length;if(ad===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ad===1){if(this.drawables[0] instanceof e){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var ak,aj,ah,an=true,af=this.drawables[0].get_type(),ab=0;for(ak=0;ak<ad;ak++){ah=this.drawables[ak];if(ah.get_type()!==af){can_composite=false;break}if(ah instanceof c){ab++}}if(an||ab===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".tooltip").remove()}if(ab>1&&ab===this.drawables.length){var ao={},ac;ah=this.drawables[0];for(aj=0;aj<ah.filters_manager.filters.length;aj++){ac=ah.filters_manager.filters[aj];ao[ac.name]=[ac]}for(ak=1;ak<this.drawables.length;ak++){ah=this.drawables[ak];for(aj=0;aj<ah.filters_manager.filters.length;aj++){ac=ah.filters_manager.filters[aj];if(ac.name in ao){ao[ac.name].push(ac)}}}this.filters_manager.remove_all();var ae,ag,ai,al;for(var am in ao){ae=ao[am];if(ae.length===ab){ag=new h.NumberFilter({name:ae[0].name,index:ae[0].index});this.filters_manager.add_filter(ag)}}if(this.filters_manager.filters.length>0){this.action_icons.filters_icon.show()}else{this.action_icons.filters_icon.hide()}}else{this.action_icons.filters_icon.hide()}}}},_restore_filter_managers:function(){for(var ab=0;ab<this.drawables.length;ab++){this.drawables[ab].filters_manager=this.saved_filters_managers[ab]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ab=0;ab<this.drawables.length;ab++){drawable=this.drawables[ab];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ac=new e(this.view,this.view,{name:this.config.get_value("name"),drawables:this.drawables});var ab=this.container.replace_drawable(this,ac,true);ac.request_draw()},add_drawable:function(ab){y.prototype.add_drawable.call(this,ab);this.update_icons()},remove_drawable:function(ab){y.prototype.remove_drawable.call(this,ab);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ab=o(y.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ab},request_draw:function(ab){aa.each(this.drawables,function(ac){ac.request_draw(ab)})}});var X=Backbone.View.extend({initialize:function(ab){o(ab,{obj_type:"View"});y.call(this,"View",ab.container,ab);this.chrom=null;this.vis_id=ab.vis_id;this.dbkey=ab.dbkey;this.label_tracks=[];this.tracks_to_be_redrawn=[];this.max_low=0;this.max_high=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.load_chroms_deferred=null;this.render();this.canvas_manager=new w.CanvasManager(this.container.get(0).ownerDocument);this.reset();this.config=R.ConfigSettingCollection.from_models_and_saved_values([{key:"name",label:"Name",type:"text",default_value:""},{key:"a_color",label:"A Color",type:"color",default_value:"#FF0000"},{key:"c_color",label:"C Color",type:"color",default_value:"#00FF00"},{key:"g_color",label:"G Color",type:"color",default_value:"#0000FF"},{key:"t_color",label:"T Color",type:"color",default_value:"#FF00FF"},{key:"n_color",label:"N Color",type:"color",default_value:"#AAAAAA"}],{name:ab.name})},render:function(){this.requested_redraw=false;var ad=this.container,ab=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ad);this.browser_content_div=$("<div/>").addClass("content").appendTo(ad);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ad);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").attr("id","viewport-container").appendTo(this.browser_content_div);this.content_div=this.viewport_container;i(this.viewport_container,ab);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var af=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){w.select_datasets(galaxy_config.root+"visualization/list_current_history_datasets",galaxy_config.root+"api/datasets",{"f-dbkey":ab.dbkey},function(ag){aa.each(ag,function(ah){ab.add_drawable(n(ah,ab,ab))})})});this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("trackster-nav-container").prependTo(this.top_container);this.nav=$("<div/>").addClass("trackster-nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a/>").attr("title","Close overview").addClass("icon-button overview-close tooltip").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div/>").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_select=$("<select/>").attr({name:"chrom"}).addClass("chrom-nav").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var ac=function(ag){if(ag.type==="focusout"||(ag.keyCode||ag.which)===13||(ag.keyCode||ag.which)===27){if((ag.keyCode||ag.which)!==27){ab.go_to($(this).val())}$(this).hide();$(this).val("");ab.location_span.show();ab.chrom_select.show()}ag.stopPropagation()};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ac).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").attr("title","Click to change location").tooltip({placement:"bottom"}).appendTo(this.nav_controls);this.location_span.click(function(){ab.location_span.hide();ab.chrom_select.hide();ab.nav_input.val(ab.chrom+":"+ab.low+"-"+ab.high);ab.nav_input.css("display","inline-block");ab.nav_input.select();ab.nav_input.focus();ab.nav_input.autocomplete({source:function(ai,ag){var aj=[],ah=$.map(ab.get_tracks(c),function(ak){return ak.data_manager.search_features(ai.term).success(function(al){aj=aj.concat(al)})});$.when.apply($,ah).done(function(){ag($.map(aj,function(ak){return{label:ak[0],value:ak[1]}}))})}})});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a/>").attr("id","zoom-out").attr("title","Zoom out").tooltip({placement:"bottom"}).click(function(){ab.zoom_out()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ab.zoom_in()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ab.change_chrom(ab.chrom_select.val())});this.browser_content_div.click(function(ag){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ag){ab.zoom_in(ag.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ag,ah){this.current_x=ah.offsetX}).bind("drag",function(ag,ai){var aj=ai.offsetX-this.current_x;this.current_x=ai.offsetX;var ah=Math.round(aj/ab.viewport_container.width()*(ab.max_high-ab.max_low));ab.move_delta(-ah)});this.overview_close.click(function(){ab.reset_overview()});this.viewport_container.bind("draginit",function(ag,ah){if(ag.clientX>ab.viewport_container.width()-16){return false}}).bind("dragstart",function(ag,ah){ah.original_low=ab.low;ah.current_height=ag.clientY;ah.current_x=ah.offsetX}).bind("drag",function(ai,ak){var ag=$(this);var al=ak.offsetX-ak.current_x;var ah=ag.scrollTop()-(ai.clientY-ak.current_height);ag.scrollTop(ah);ak.current_height=ai.clientY;ak.current_x=ak.offsetX;var aj=Math.round(al/ab.viewport_container.width()*(ab.high-ab.low));ab.move_delta(aj)}).bind("mousewheel",function(ai,ak,ah,ag){if(ah){ah*=50;var aj=Math.round(-ah/ab.viewport_container.width()*(ab.high-ab.low));ab.move_delta(aj)}});this.top_labeltrack.bind("dragstart",function(ag,ah){return $("<div/>").addClass("zoom-area").css("height",ab.browser_content_div.height()+ab.top_labeltrack.height()+ab.nav_labeltrack.height()+1).appendTo($(this))}).bind("drag",function(ak,al){$(al.proxy).css({left:Math.min(ak.pageX,al.startX)-ab.container.offset().left,width:Math.abs(ak.pageX-al.startX)});var ah=Math.min(ak.pageX,al.startX)-ab.container.offset().left,ag=Math.max(ak.pageX,al.startX)-ab.container.offset().left,aj=(ab.high-ab.low),ai=ab.viewport_container.width();ab.update_location(Math.round(ah/ai*aj)+ab.low,Math.round(ag/ai*aj)+ab.low)}).bind("dragend",function(al,am){var ah=Math.min(al.pageX,am.startX),ag=Math.max(al.pageX,am.startX),aj=(ab.high-ab.low),ai=ab.viewport_container.width(),ak=ab.low;ab.low=Math.round(ah/ai*aj)+ak;ab.high=Math.round(ag/ai*aj)+ak;$(am.proxy).remove();ab.request_redraw()});var ae=$("<div/>").addClass("mouse-pos").appendTo(ad);ad.hover(function(){ae.show();ad.mousemove(function(ag){ae.css({left:ag.pageX-1})})},function(){ad.off("mousemove");ae.hide()});this.add_label_track(new V(this,{content_div:this.top_labeltrack}));this.add_label_track(new V(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ab.resize_window()},500)});$(document).bind("redraw",function(){ab.redraw()});this.reset();$(window).trigger("resize")},get_base_color:function(ab){return this.config.get_value(ab.toLowerCase()+"_color")||this.config.get_value("n_color")}});o(X.prototype,y.prototype,{changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(ac,ae,ab,af){if(this.timer){clearTimeout(this.timer)}if(af){var ad=this;this.timer=setTimeout(function(){ad.trigger("navigate",ac+":"+ae+"-"+ab)},500)}else{view.trigger("navigate",ac+":"+ae+"-"+ab)}},update_location:function(ab,ad){this.location_span.text(commatize(ab)+" - "+commatize(ad));this.nav_input.val(this.chrom+":"+commatize(ab)+"-"+commatize(ad));var ac=view.chrom_select.val();if(ac!==""){this.trigger_navigate(ac,view.low,view.high,true)}},load_chroms:function(ad){ad.num=v;var ab=this,ac=$.Deferred();$.ajax({url:galaxy_config.root+"api/genomes/"+this.dbkey,data:ad,dataType:"json",success:function(af){if(af.chrom_info.length===0){return}if(af.reference){var ag=new B(ab);ab.add_label_track(ag);ab.reference_track=ag}ab.chrom_data=af.chrom_info;var aj='<option value="">Select Chrom/Contig</option>';for(var ai=0,ae=ab.chrom_data.length;ai<ae;ai++){var ah=ab.chrom_data[ai].chrom;aj+='<option value="'+ah+'">'+ah+"</option>"}if(af.prev_chroms){aj+='<option value="previous">Previous '+v+"</option>"}if(af.next_chroms){aj+='<option value="next">Next '+v+"</option>"}ab.chrom_select.html(aj);ab.chrom_start_index=af.start_index;ac.resolve(af.chrom_info)},error:function(){alert("Could not load chroms for this dbkey: "+ab.dbkey)}});return ac},change_chrom:function(ag,ac,ai){var ad=this;if(!ad.chrom_data){ad.load_chroms_deferred.then(function(){ad.change_chrom(ag,ac,ai)});return}if(!ag||ag==="None"){return}if(ag==="previous"){ad.load_chroms({low:this.chrom_start_index-v});return}if(ag==="next"){ad.load_chroms({low:this.chrom_start_index+v});return}var ah=$.grep(ad.chrom_data,function(aj,ak){return aj.chrom===ag})[0];if(ah===undefined){ad.load_chroms({chrom:ag},function(){ad.change_chrom(ag,ac,ai)});return}else{if(ag!==ad.chrom){ad.chrom=ag;ad.chrom_select.val(ad.chrom);ad.max_high=ah.len-1;ad.reset();for(var af=0,ab=ad.drawables.length;af<ab;af++){var ae=ad.drawables[af];if(ae.init){ae.init()}}if(ad.reference_track){ad.reference_track.init()}}if(ac===undefined&&ai===undefined){ad.low=0;ad.high=ad.max_high}else{ad.low=(ac!==undefined?Math.max(ac,0):0);if(ai===undefined){ad.low=Math.max(ad.low-15,0);ad.high=ad.low+30}else{ad.high=Math.min(ai,ad.max_high)}}ad.reset_overview();ad.request_redraw()}},go_to:function(af){af=af.replace(/,/g,"");af=af.replace(/:|\-/g," ");var ac=af.split(/\s+/),ae=ac[0],ad=(ac[1]?parseInt(ac[1],10):undefined),ab=(ac[2]?parseInt(ac[2],10):undefined);this.change_chrom(ae,ad,ab)},move_fraction:function(ad){var ab=this;var ac=ab.high-ab.low;this.move_delta(ad*ac)},move_delta:function(ae){var ab=this;var ad=ab.high-ab.low;if(ab.low-ae<ab.max_low){ab.low=ab.max_low;ab.high=ab.max_low+ad}else{if(ab.high-ae>ab.max_high){ab.high=ab.max_high;ab.low=ab.max_high-ad}else{ab.high-=ae;ab.low-=ae}}ab.request_redraw({data_fetch:false});if(this.redraw_on_move_fn){clearTimeout(this.redraw_on_move_fn)}this.redraw_on_move_fn=setTimeout(function(){ab.request_redraw()},200);var ac=ab.chrom_select.val();this.trigger_navigate(ac,ab.low,ab.high,true)},add_drawable:function(ab){y.prototype.add_drawable.call(this,ab);ab.init();this.changed();this.update_intro_div()},add_label_track:function(ab){ab.view=this;ab.init();this.label_tracks.push(ab)},remove_drawable:function(ad,ac){y.prototype.remove_drawable.call(this,ad);if(ac){var ab=this;ad.container_div.hide(0,function(){$(this).remove();ab.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ac,ad){var ab=this,ae=(ad?[ad]:ab.drawables);aa.each(ae,function(af){var ag=aa.find(ab.tracks_to_be_redrawn,function(ah){return ah[0]===af});if(ag){ag[1]=ac}else{ab.tracks_to_be_redrawn.push([af,ac])}});if(!this.requested_redraw){requestAnimationFrame(function(){ab._redraw()});this.requested_redraw=true}},_redraw:function(){this.requested_redraw=false;var ab=this.low,af=this.high;if(ab<this.max_low){ab=this.max_low}if(af>this.max_high){af=this.max_high}var ac=this.high-this.low;if(this.high!==0&&ac<this.min_separation){af=ab+this.min_separation}this.low=Math.floor(ab);this.high=Math.ceil(af);this.update_location(this.low,this.high);this.resolution_px_b=this.viewport_container.width()/(this.high-this.low);var ae=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ag=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ad=13;this.overview_box.css({left:ae,width:Math.max(ad,ag)}).show();if(ag<ad){this.overview_box.css("left",ae-(ad-ag)/2)}if(this.overview_highlight){this.overview_highlight.css({left:ae,width:ag})}aa.each(this.tracks_to_be_redrawn,function(aj){var ah=aj[0],ai=aj[1];if(ah){ah._draw(ai)}});this.tracks_to_be_redrawn=[];aa.each(this.label_tracks,function(ah){ah._draw()})},zoom_in:function(ac,ad){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var ae=this.high-this.low,af=ae/2+this.low,ab=(ae/this.zoom_factor)/2;if(ac){af=ac/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(af-ab);this.high=Math.round(af+ab);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ac=this.high-this.low,ad=ac/2+this.low,ab=(ac*this.zoom_factor)/2;this.low=Math.round(ad-ab);this.high=Math.round(ad+ab);this.changed();this.request_redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.request_redraw()},set_overview:function(ad){if(this.overview_drawable){if(this.overview_drawable.dataset.id===ad.dataset.id){return}this.overview_viewport.find(".track").remove()}var ac=ad.copy({content_div:this.overview_viewport}),ab=this;ac.header_div.hide();ac.is_overview=true;ab.overview_drawable=ac;this.overview_drawable.postdraw_actions=function(){ab.overview_highlight.show().height(ab.overview_drawable.content_div.height());ab.overview_viewport.height(ab.overview_drawable.content_div.height()+ab.overview_box.outerHeight());ab.overview_close.show();ab.resize_window()};ab.overview_drawable.request_draw();this.changed()},reset_overview:function(){$(".tooltip").remove();this.overview_viewport.find(".track-tile").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide();view.resize_window();view.overview_drawable=null}});var q=P.Tool.extend({defaults:{track:null},initialize:function(ab){P.Tool.prototype.initialize.call(this,ab);var ac=true;if(ab.tool_state!==undefined&&ab.tool_state.hidden!==undefined){ac=ab.tool_state.hidden}this.set("hidden",ac);this.remove_inputs(["data","hidden_data","conditional"])},state_dict:function(ab){return aa.extend(this.get_inputs_dict(),{hidden:!this.is_visible()})}});var t=Backbone.View.extend({events:{"change input":"update_value"},render:function(){var ad=this.$el.addClass("param-row"),ae=this.model;var ab=$("<div>").addClass("param-label").text(ae.get("label")).appendTo(ad);var ac=$("<div/>").addClass("param-input").html(ae.get("html")).appendTo(ad);ac.find(":input").val(ae.get("value"));$("<div style='clear: both;'/>").appendTo(ad)},update_value:function(ab){this.model.set_value($(ab.target).val())}});var Z=Backbone.View.extend({initialize:function(ab){this.model.on("change:hidden",this.set_visible,this)},render:function(){var ac=this;tool=this.model,parent_div=this.$el.addClass("dynamic-tool").hide();parent_div.bind("drag",function(ag){ag.stopPropagation()}).click(function(ag){ag.stopPropagation()}).bind("dblclick",function(ag){ag.stopPropagation()}).keydown(function(ag){ag.stopPropagation()});var ad=$("<div class='tool-name'>").appendTo(parent_div).text(tool.get("name"));tool.get("inputs").each(function(ah){var ag=new t({model:ah});ag.render();parent_div.append(ag.$el)});parent_div.find("input").click(function(){$(this).select()});var ae=$("<div>").addClass("param-row").appendTo(parent_div);var af=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(ae);var ab=$("<input type='submit'>").attr("value","Run on visible region").appendTo(ae);ab.click(function(){ac.run_on_region()});af.click(function(){ac.run_on_dataset()});if(tool.is_visible()){this.$el.show()}},set_visible:function(){if(this.model.is_visible()){this.$el.show()}else{this.$el.hide()}},update_params:function(){for(var ab=0;ab<this.params.length;ab++){this.params[ab].update_value()}},run_on_dataset:function(){var ab=this.model;this.run({target_dataset_id:this.model.get("track").dataset.id,action:"rerun",tool_id:ab.id},null,function(ac){Galaxy.modal.show({title:ab.get("name")+" is Running",body:ab.get("name")+" is running on the complete dataset. Tool outputs are in dataset's history.",buttons:{Close:function(){Galaxy.modal.hide()}}})})},run_on_region:function(){var ac=this.model.get("track"),af=this.model,ah=new w.GenomeRegion({chrom:ac.view.chrom,start:ac.view.low,end:ac.view.high}),ai={target_dataset_id:ac.dataset.id,action:"rerun",tool_id:af.id,regions:[ah.toJSON()]},ag=ac,ak=af.get("name")+ag.tool_region_and_parameters_str(ah),ab;if(ag.container===view){var aj=new N(view,view,{name:ac.config.get_value("name")});var ae=ag.container.replace_drawable(ag,aj,false);aj.container_div.insertBefore(ag.view.content_div.children()[ae]);aj.add_drawable(ag);ag.container_div.appendTo(aj.content_div);ab=aj}else{ab=ag.container}var ad=new ag.constructor(view,ab,{name:ak,hda_ldda:"hda"});ad.init_for_tool_data();ad.change_mode(ag.mode);ad.set_filters_manager(ag.filters_manager.copy(ad));ad.update_icons();ab.add_drawable(ad);ad.tiles_div.text("Starting job.");this.run(ai,ad,function(al){ad.set_dataset(new W.Dataset(al));ad.tiles_div.text("Running job.");ad.init()})},run:function(ab,ad,ae){ab.inputs=this.model.get_inputs_dict();var ac=new j.ServerStateDeferred({ajax_settings:{url:galaxy_config.root+"api/tools",data:JSON.stringify(ab),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(af){return af!=="pending"}});$.when(ac.go()).then(function(af){if(af==="no converter"){ad.container_div.addClass("error");ad.content_div.text(H)}else{if(af.error){ad.container_div.addClass("error");ad.content_div.text(x+af.message)}else{ae(af)}}})}});var C=function(ab,ac){J.Scaler.call(this,ac);this.filter=ab};C.prototype.gen_val=function(ab){if(this.filter.high===Number.MAX_VALUE||this.filter.low===-Number.MAX_VALUE||this.filter.low===this.filter.high){return this.default_val}return((parseFloat(ab[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var b=function(ab,ae,af,ac,ad){this.track=ab;this.region=ae;this.low=ae.get("start");this.high=ae.get("end");this.w_scale=af;this.canvas=ac;this.html_elt=$("<div class='track-tile'/>").append(ac);this.data=ad;this.stale=false};b.prototype.predisplay_actions=function(){};var K=function(ab,ae,af,ac,ad){b.call(this,ab,ae,af,ac,ad)};K.prototype.predisplay_actions=function(){};var M=function(ae,al,an,ad,ag,ah,ao,ac,ak){b.call(this,ae,al,an,ad,ag);this.mode=ah;this.all_slotted=ac;this.feature_mapper=ak;this.has_icons=false;if(ao){this.has_icons=true;var ai=this;ad=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:D,width:ad.width}).prependTo(this.html_elt);var aj=new w.GenomeRegion({chrom:ae.view.chrom,start:this.low,end:this.high}),am=ag.length,af=$("<a/>").addClass("icon more-down").attr("title","For speed, only the first "+am+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ab=$("<a/>").addClass("icon more-across").attr("title","For speed, only the first "+am+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);af.click(function(){ai.stale=true;ae.data_manager.get_more_data(aj,ae.mode,1/ai.w_scale,{},ae.data_manager.DEEP_DATA_REQ);$(".tooltip").hide();ae.request_draw()}).dblclick(function(ap){ap.stopPropagation()});ab.click(function(){ai.stale=true;ae.data_manager.get_more_data(aj,ae.mode,1/ai.w_scale,{},ae.data_manager.BROAD_DATA_REQ);$(".tooltip").hide();ae.request_draw()}).dblclick(function(ap){ap.stopPropagation()})}};o(M.prototype,b.prototype);M.prototype.predisplay_actions=function(){var ac=this,ab={};if(ac.mode!=="Pack"){return}$(this.html_elt).hover(function(){this.hovered=true;$(this).mousemove()},function(){this.hovered=false;$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()}).mousemove(function(an){if(!this.hovered){return}var ai=$(this).offset(),am=an.pageX-ai.left,al=an.pageY-ai.top,ar=ac.feature_mapper.get_feature_data(am,al),aj=(ar?ar[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!aj||$(this).attr("id")!==aj.toString()){$(this).remove()}});if(ar){var ae=ab[aj];if(!ae){var ao={name:ar[3],start:ar[1],end:ar[2],strand:ar[4]},ah=ac.track.filters_manager.filters,ag;for(var ak=0;ak<ah.length;ak++){ag=ah[ak];ao[ag.name]=ar[ag.index]}ae=$("<div/>").attr("id",aj).addClass("feature-popup");var at=$("<table/>"),aq,ap,au;for(aq in ao){ap=ao[aq];au=$("<tr/>").appendTo(at);$("<th/>").appendTo(au).text(aq);$("<td/>").attr("align","left").appendTo(au).text(typeof(ap)==="number"?U(ap,2):ap)}ae.append($("<div class='feature-popup-inner'>").append(at));ab[aj]=ae}ae.appendTo($(this).parents(".track-content").children(".overlay"));var af=am+parseInt(ac.html_elt.css("left"),10)-ae.width()/2,ad=al+parseInt(ac.html_elt.css("top"),10)+7;ae.css("left",af+"px").css("top",ad+"px")}else{if(!an.isPropagationStopped()){an.stopPropagation();$(this).siblings().each(function(){$(this).trigger(an)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var f=function(ac,ab,ad){o(ad,{drag_handle_class:"draghandle"});p.call(this,ac,ab,ad);this.dataset=null;if(ad.dataset){this.dataset=(ad.dataset instanceof Backbone.Model?ad.dataset:new W.Dataset(ad.dataset))}this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ad?ad.data_query_wait:I);this.data_manager=("data_manager" in ad?ad.data_manager:new w.GenomeDataManager({dataset:this.dataset,genome:new w.Genome({key:ac.dbkey,chroms_info:{chrom_info:ac.chrom_data}}),data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=this.config.get_value("height");this.content_div=$("<div class='track-content'>").appendTo(this.container_div);if(this.container){this.container.content_div.append(this.container_div);if(!("resize" in ad)||ad.resize){this.add_resize_handle()}}};o(f.prototype,p.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},p.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"application-dock-270",on_click_fn:function(ab){ab.view.set_overview(ab)}},p.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"ui-slider-050",on_click_fn:function(ab){if(ab.filters_manager.visible()){ab.filters_manager.clear_filters()}else{ab.filters_manager.init_filters()}ab.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ab){ab.tool.toggle();if(ab.tool.is_visible()){ab.set_name(ab.config.get_value("name")+ab.tool_region_and_parameters_str())}else{ab.revert_name()}$(".tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ab){var ae='<strong>Tool</strong>: <%= track.tool.get("name") %><br/><strong>Dataset</strong>: <%= track.config.get("name") %><br/><strong>Region(s)</strong>: <select name="regions"><option value="cur">current viewing area</option><option value="bookmarks">bookmarks</option><option value="both">current viewing area and bookmarks</option></select>',ad=aa.template(ae,{track:ab});var ag=function(){Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc")},ac=function(){var ai=$('select[name="regions"] option:selected').val(),ak,ah=new w.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),aj=aa.map($(".bookmark"),function(al){return new w.GenomeRegion({from_str:$(al).children(".position").text()})});if(ai==="cur"){ak=[ah]}else{if(ai==="bookmarks"){ak=aj}else{ak=[ah].concat(aj)}}Galaxy.modal.hide();window.location.href=galaxy_config.root+"visualization/sweepster?"+$.param({dataset_id:ab.dataset.id,hda_ldda:ab.dataset.get("hda_ldda"),regions:JSON.stringify(new Backbone.Collection(ak).toJSON())})},af=function(ah){if((ah.keyCode||ah.which)===27){ag()}else{if((ah.keyCode||ah.which)===13){ac()}}};Galaxy.modal.show({title:"Visualize tool parameter space and output from different parameter settings?",body:ad,buttons:{No:ag,Yes:ac}})}},p.prototype.action_icons_def[2]],can_draw:function(){return this.dataset&&p.prototype.can_draw.call(this)},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id)},build_header_div:function(){var ab=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ab)}this.name_div=$("<div/>").addClass("track-name").appendTo(ab).text(this.config.get_value("name")).attr("id",this.config.get_value("name").replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ab},set_dataset:function(ab){this.dataset=ab;this.data_manager.set("dataset",ab)},on_resize:function(){this.request_draw({clear_tile_cache:true})},add_resize_handle:function(){var ab=this;var ae=false;var ad=false;var ac=$("<div class='track-resize'>");$(ab.container_div).hover(function(){if(ab.config.get_value("content_visible")){ae=true;ac.show()}},function(){ae=false;if(!ad){ac.hide()}});ac.hide().bind("dragstart",function(af,ag){ad=true;ag.original_height=$(ab.content_div).height()}).bind("drag",function(ag,ah){var af=Math.min(Math.max(ah.original_height+ah.deltaY,ab.min_height_px),ab.max_height_px);$(ab.tiles_div).css("height",af);ab.visible_height_px=(ab.max_height_px===af?0:af);ab.on_resize()}).bind("dragend",function(af,ag){ab.tile_cache.clear();ad=false;if(!ae){ac.hide()}ab.config.set("height",ab.visible_height_px);ab.changed()}).appendTo(ab.container_div)},set_display_modes:function(ae,ah){this.display_modes=ae;this.mode=(ah?ah:(this.config&&this.config.get_value("mode")?this.config.get_value("mode"):this.display_modes[0]));this.action_icons.mode_icon.attr("title","Set display mode (now: "+this.mode+")");var ac=this,af={};for(var ad=0,ab=ac.display_modes.length;ad<ab;ad++){var ag=ac.display_modes[ad];af[ag]=function(ai){return function(){ac.change_mode(ai);ac.icons_div.show();ac.container_div.mouseleave(function(){ac.icons_div.hide()})}}(ag)}make_popupmenu(this.action_icons.mode_icon,af)},build_action_icons:function(){p.prototype.build_action_icons.call(this,this.action_icons_def);if(this.display_modes!==undefined){this.set_display_modes(this.display_modes)}},hide_contents:function(){this.tiles_div.hide();this.container_div.find(".yaxislabel, .track-resize").hide()},show_contents:function(){this.tiles_div.show();this.container_div.find(".yaxislabel, .track-resize").show();this.request_draw()},get_type:function(){if(this instanceof V){return"LabelTrack"}else{if(this instanceof B){return"ReferenceTrack"}else{if(this instanceof g){return"LineTrack"}else{if(this instanceof S){return"ReadTrack"}else{if(this instanceof Y){return"VariantTrack"}else{if(this instanceof e){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},show_message:function(ab){this.tiles_div.remove();return $("<span/>").addClass("message").html(ab).appendTo(this.content_div)},init:function(ad){var ac=this;ac.enabled=false;ac.tile_cache.clear();ac.data_manager.clear();ac.content_div.children().remove();ac.container_div.removeClass("nodata error pending");ac.tiles_div=$("<div/>").addClass("tiles").appendTo(ac.content_div);if(!ac.dataset.id){return}var ab=$.Deferred(),ae={hda_ldda:ac.dataset.get("hda_ldda"),data_type:this.dataset_check_type,chrom:ac.view.chrom,retry:ad};$.getJSON(this.dataset.url(),ae,function(af){if(!af||af==="error"||af.kind==="error"){ac.container_div.addClass("error");var ag=ac.show_message(m);if(af.message){ag.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){Galaxy.modal.show({title:"Trackster Error",body:"<pre>"+af.message+"</pre>",buttons:{Close:function(){Galaxy.modal.hide()}}})}));ag.append($("<span/>").text(" "));ag.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ac.init(true)}))}}else{if(af==="no converter"){ac.container_div.addClass("error");ac.show_message(H)}else{if(af==="no data"||(af.data!==undefined&&(af.data===null||af.data.length===0))){ac.container_div.addClass("nodata");ac.show_message(E)}else{if(af==="pending"){ac.container_div.addClass("pending");ac.show_message(u);setTimeout(function(){ac.init()},ac.data_query_wait)}else{if(af==="data"||af.status==="data"){if(af.valid_chroms){ac.valid_chroms=af.valid_chroms;ac.update_icons()}ac.tiles_div.text(T);if(ac.view.chrom){ac.tiles_div.text("");ac.tiles_div.css("height",ac.visible_height_px+"px");ac.enabled=true;$.when.apply($,ac.predraw_init()).done(function(){ab.resolve();ac.container_div.removeClass("nodata error pending");ac.request_draw()})}else{ab.resolve()}}}}}}});this.update_icons();return ab},predraw_init:function(){var ab=this;return $.getJSON(ab.dataset.url(),{data_type:"data",stats:true,chrom:ab.view.chrom,low:0,high:ab.view.max_high,hda_ldda:ab.dataset.get("hda_ldda")},function(ac){var ae=ac.data;if(ae&&ae.min&&ae.max){var ad=ae.min,af=ae.max;ad=Math.floor(Math.min(0,Math.max(ad,ae.mean-2*ae.sd)));af=Math.ceil(Math.max(0,Math.min(af,ae.mean+2*ae.sd)));ab.config.set_default_value("min_value",ad);ab.config.set_default_value("max_value",af);ab.config.set_value("min_value",ad);ab.config.set_value("max_value",af)}})},get_drawables:function(){return this}});var L=function(ad,ac,af){f.call(this,ad,ac,af);var ab=this;k(ab.container_div,ab.drag_handle_class,".group",ab);this.filters_manager=new h.FiltersManager(this,("filters" in af?af.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=(af.tool?new q(aa.extend(af.tool,{track:this,tool_state:af.tool_state})):null);this.tile_cache=new w.Cache(O);this.left_offset=0;if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){var ae=new Z({model:this.tool});ae.render();this.dynamic_tool_div=ae.$el;this.header_div.after(this.dynamic_tool_div)}}this.tiles_div=$("<div/>").addClass("tiles").appendTo(this.content_div);if(!this.config.get_value("content_visible")){this.tiles_div.hide()}this.overlay_div=$("<div/>").addClass("overlay").appendTo(this.content_div);if(af.mode){this.change_mode(af.mode)}};o(L.prototype,p.prototype,f.prototype,{action_icons_def:f.prototype.action_icons_def.concat([{name:"show_more_rows_icon",title:"To minimize track height, not all feature rows are displayed. Click to display more rows.",css_class:"exclamation",on_click_fn:function(ab){$(".tooltip").remove();ab.slotters[ab.view.resolution_px_b].max_rows*=2;ab.request_draw({clear_tile_cache:true})},hide:true}]),copy:function(ab){var ac=this.to_dict();o(ac,{data_manager:this.data_manager});var ad=new this.constructor(this.view,ab,ac);ad.change_mode(this.mode);ad.enabled=this.enabled;return ad},set_filters_manager:function(ab){this.filters_manager=ab;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),dataset:{id:this.dataset.id,hda_ldda:this.dataset.get("hda_ldda")},prefs:this.config.to_key_value_dict(),mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},set_min_max:function(){var ab=this;return $.getJSON(ab.dataset.url(),{data_type:"data",stats:true,chrom:ab.view.chrom,low:0,high:ab.view.max_high,hda_ldda:ab.dataset.get("hda_ldda")},function(ac){var ae=ac.data;if(isNaN(parseFloat(ab.config.get_value("min_value")))||isNaN(parseFloat(ab.config.get_value("max_value")))){var ad=ae.min,af=ae.max;ad=Math.floor(Math.min(0,Math.max(ad,ae.mean-2*ae.sd)));af=Math.ceil(Math.max(0,Math.min(af,ae.mean+2*ae.sd)));ab.config.set_value("min_value",ad);ab.config.set_value("max_value",af)}})},change_mode:function(ac){var ab=this;ab.mode=ac;ab.config.set_value("mode",ac);if(ac==="Auto"){this.data_manager.clear()}ab.request_draw({clear_tile_cache:true});this.action_icons.mode_icon.attr("title","Set display mode (now: "+ab.mode+")");return ab},update_icons:function(){var ab=this;if(ab.filters_available){ab.action_icons.filters_icon.show()}else{ab.action_icons.filters_icon.hide()}if(ab.tool){ab.action_icons.tools_icon.show();ab.action_icons.param_space_viz_icon.show()}else{ab.action_icons.tools_icon.hide();ab.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ac,ab){return ac+"_"+ab},request_draw:function(ab){if(ab&&ab.clear_tile_cache){this.tile_cache.clear()}this.view.request_redraw(ab,this)},before_draw:function(){this.max_height_px=0},_draw:function(ap){if(!this.can_draw()){return}var am=ap&&ap.clear_after,ak=this.view.low,af=this.view.high,ai=af-ak,ac=this.view.container.width(),ao=this.view.resolution_px_b,ae=1/ao;if(this.is_overview){ak=this.view.max_low;af=this.view.max_high;ao=ac/(view.max_high-view.max_low);ae=1/ao}this.before_draw();this.tiles_div.children().addClass("remove");var ab=Math.floor(ak/(ae*Q)),aj,al,ag,ah=[],an=[];while((ab*Q*ae)<af){aj=Math.floor(ab*Q*ae);al=new w.GenomeRegion({chrom:this.view.chrom,start:aj,end:Math.min(aj+Math.ceil(Q*ae),this.view.max_high)});ag=this.draw_helper(al,ao,ap);ah.push(ag);$.when(ag).then(function(aq){an.push(aq)});ab+=1}if(!am){this.tiles_div.children(".remove").removeClass("remove").remove()}var ad=this;$.when.apply($,ah).then(function(){ad.tiles_div.children(".remove").remove();an=aa.filter(an,function(aq){return aq!==null});if(an.length!==0){ad.postdraw_actions(an,ac,ao,am)}})},_add_yaxis_label:function(ae,ag){var ac=this,af=(ae==="max"?"top":"bottom"),ah=(ae==="max"?"max":"min"),ab=(ae==="max"?"max_value":"min_value"),ad=this.container_div.find(".yaxislabel."+af);ag=ag||function(){ac.request_draw({clear_tile_cache:true})};if(ad.length!==0){ad.text(ac.config.get_value(ab))}else{ad=$("<div/>").text(ac.config.get_value(ab)).make_text_editable({num_cols:12,on_finish:function(ai){$(".tooltip").remove();ac.config.set_param_value(ab,ai);ag()},help_text:"Set "+ah+" value"}).addClass("yaxislabel "+af).css("color",this.config.get_value("label_color"));this.container_div.prepend(ad)}},postdraw_actions:function(ae,af,ah,ab){var ad=aa.filter(ae,function(ai){return(ai instanceof K)});if(ad.length>0){this.max_height_px=0;var ac=this;aa.each(ae,function(ai){if(!(ai instanceof K)){ai.html_elt.remove();ac.draw_helper(ai.region,ah,{force:true,mode:"Coverage"})}});ac._add_yaxis_label("max")}else{this.container_div.find(".yaxislabel").remove();var ag=aa.find(ae,function(ai){return ai.has_icons});if(ag){aa.each(ae,function(ai){if(!ai.has_icons){ai.html_elt.css("padding-top",D)}})}}},get_mode:function(ab){return this.mode},update_auto_mode:function(ab){},_get_drawables:function(){return[this]},draw_helper:function(ak,am,an){if(!an){an={}}var ac=an.force,ah=an.mode||this.mode,ae=1/am,ad=this,af=this._get_drawables(),al=this._gen_tile_cache_key(am,ak),ag=function(ao){return(ao&&"track" in ao)};var ai=(ac?undefined:ad.tile_cache.get_elt(al));if(ai){if(ag(ai)){ad.show_tile(ai,am)}return ai}if(an.data_fetch===false){return null}var aj=function(){var ao=(aa.find(A,function(aq){return aq===ah})?"Coverage":ah);var ap=aa.map(af,function(aq){return aq.data_manager.get_data(ak,ao,ae,ad.data_url_extra_params)});if(view.reference_track){ap.push(view.reference_track.data_manager.get_data(ak,ah,ae,view.reference_track.data_url_extra_params))}return ap};var ab=$.Deferred();ad.tile_cache.set_elt(al,ab);$.when.apply($,aj()).then(function(){var ao=aj(),au=ao,aA;if(view.reference_track){aA=view.reference_track.data_manager.subset_entry(ao.pop(),ak)}var av=[],ar=[];aa.each(af,function(aF,aC){var aE=aF.mode,aD=au[aC];if(aE==="Auto"){aE=aF.get_mode(aD);aF.update_auto_mode(aE)}av.push(aE);ar.push(aF.get_canvas_height(aD,aE,am,ap))});var at=ad.view.canvas_manager.new_canvas(),aw=ak.get("start"),aB=ak.get("end"),aq=0,ap=Math.ceil((aB-aw)*am)+ad.left_offset,ay=aa.max(ar),ax;at.width=ap;at.height=(an.height||ay);var az=at.getContext("2d");az.translate(ad.left_offset,0);if(af.length>1){az.globalAlpha=0.5;az.globalCompositeOperation="source-over"}aa.each(af,function(aD,aC){ax=aD.draw_tile(au[aC],az,av[aC],ak,am,aA)});if(ax!==undefined){ad.tile_cache.set_elt(al,ax);ad.show_tile(ax,am)}ab.resolve(ax)});return ab},get_canvas_height:function(ab,ad,ae,ac){return this.visible_height_px},_draw_line_track_tile:function(ab,ad,ag,af,ah){var ae=ad.canvas,ac=new J.LinePainter(ab.data,af.get("start"),af.get("end"),this.config.to_key_value_dict(),ag);ac.draw(ad,ae.width,ae.height,ah);return new K(this,af,ah,ae,ab.data)},draw_tile:function(ab,ac,af,ae,ag,ad){},show_tile:function(ad,ag){var ac=this,ab=ad.html_elt;ad.predisplay_actions();var af=(ad.low-(this.is_overview?this.view.max_low:this.view.low))*ag;if(this.left_offset){af-=this.left_offset}ab.css("left",af);if(ab.hasClass("remove")){ab.removeClass("remove")}else{this.tiles_div.append(ab)}ab.css("height","auto");this.max_height_px=Math.max(this.max_height_px,ab.height()-2);ab.parent().children().css("height",this.max_height_px+"px");var ae=this.max_height_px;if(this.visible_height_px!==0){ae=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",ae+"px")},tool_region_and_parameters_str:function(ae){var ab=this,ad=(ae!==undefined?ae.toString():"all"),ac=aa.values(ab.tool.get_inputs_dict()).join(", ");return" - region=["+ad+"], parameters=["+ac+"]"},data_and_mode_compatible:function(ab,ac){if(ac==="Auto"){return true}else{if(ac==="Coverage"){return ab.dataset_type==="bigwig"}else{if(ab.dataset_type==="bigwig"||ab.extra_info==="no_detail"){return false}else{return true}}}},can_subset:function(ab){if(ab.message||ab.extra_info==="no_detail"){return false}else{if(ab.dataset_type==="bigwig"){return(ab.data[1][0]-ab.data[0][0]===1)}}return true},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state"}});var V=function(ac,ab){var ad={resize:false};f.call(this,ac,ab,ad);this.container_div.addClass("label-track")};o(V.prototype,f.prototype,{build_header_div:function(){},init:function(){this.enabled=true},predraw_init:function(){},_draw:function(af){var ad=this.view,ae=ad.high-ad.low,ai=Math.floor(Math.pow(10,Math.floor(Math.log(ae)/Math.log(10)))),ab=Math.floor(ad.low/ai)*ai,ag=this.view.container.width(),ac=$("<div/>").addClass("label-container");while(ab<ad.high){var ah=(ab-ad.low)/ae*ag;ac.append($("<div/>").addClass("label").text(commatize(ab)).css({left:ah}));ab+=ai}this.content_div.children(":first").remove();this.content_div.append(ac)}});var e=function(ac,ab,af){L.call(this,ac,ab,af);this.drawables=[];if("drawables" in af){var ae;for(var ad=0;ad<af.drawables.length;ad++){ae=af.drawables[ad];this.drawables[ad]=n(ae,ac,null);if(ae.left_offset>this.left_offset){this.left_offset=ae.left_offset}}this.enabled=true}aa.each(this.drawables,function(ag){if(ag instanceof c||ag instanceof S){ag.change_mode("Coverage")}});this.update_icons();this.obj_type="CompositeTrack"};o(e.prototype,L.prototype,{display_modes:A,action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ab){$(".tooltip").remove();ab.show_group()}}].concat(L.prototype.action_icons_def),to_dict:y.prototype.to_dict,add_drawable:y.prototype.add_drawable,unpack_drawables:y.prototype.unpack_drawables,change_mode:function(ab){L.prototype.change_mode.call(this,ab);for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].change_mode(ab)}},init:function(){var ad=[];for(var ac=0;ac<this.drawables.length;ac++){ad.push(this.drawables[ac].init())}var ab=this;$.when.apply($,ad).then(function(){ab.enabled=true;ab.request_draw()})},update_icons:function(){this.action_icons.filters_icon.hide();this.action_icons.tools_icon.hide();this.action_icons.param_space_viz_icon.hide()},can_draw:p.prototype.can_draw,_get_drawables:function(){return this.drawables},show_group:function(){var ae=new N(this.view,this.container,{name:this.config.get_value("name")}),ab;for(var ad=0;ad<this.drawables.length;ad++){ab=this.drawables[ad];ab.update_icons();ae.add_drawable(ab);ab.container=ae;ae.content_div.append(ab.container_div)}var ac=this.container.replace_drawable(this,ae,true);ae.request_draw({clear_tile_cache:true})},before_draw:function(){L.prototype.before_draw.call(this);var ac=aa.min(aa.map(this.drawables,function(ad){return ad.config.get_value("min_value")})),ab=aa.max(aa.map(this.drawables,function(ad){return ad.config.get_value("max_value")}));this.config.set_value("min_value",ac);this.config.set_value("max_value",ab);aa.each(this.drawables,function(ad){ad.config.set_value("min_value",ac);ad.config.set_value("max_value",ab)})},update_all_min_max:function(){var ac=this,ab=this.config.get_value("min_value"),ad=this.config.get_value("max_value");aa.each(this.drawables,function(ae){ae.config.set_value("min_value",ab);ae.config.set_value("max_value",ad)});this.request_draw({clear_tile_cache:true})},postdraw_actions:function(ah,ab,ak,ag){L.prototype.postdraw_actions.call(this,ah,ab,ak,ag);var af=-1,ad;for(ad=0;ad<ah.length;ad++){var ai=ah[ad].html_elt.find("canvas").height();if(ai>af){af=ai}}for(ad=0;ad<ah.length;ad++){var ae=ah[ad];if(ae.html_elt.find("canvas").height()!==af){this.draw_helper(ae.region,ak,{force:true,height:af});ae.html_elt.remove()}}var ac=this,aj=function(){ac.update_all_min_max()};this._add_yaxis_label("min",aj);this._add_yaxis_label("max",aj)}});var B=function(ab){L.call(this,ab,{content_div:ab.top_labeltrack},{resize:false});this.left_offset=ab.canvas_manager.char_width_px;this.container_div.addClass("reference-track");this.data_url=galaxy_config.root+"api/genomes/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new w.GenomeReferenceDataManager({data_url:this.data_url,can_subset:this.can_subset});this.hide_contents()};o(B.prototype,p.prototype,L.prototype,{config_params:aa.union(p.prototype.config_params,[{key:"height",type:"int",default_value:13,hidden:true}]),build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},predraw_init:function(){},can_draw:p.prototype.can_draw,draw_helper:function(ac,ad,ab){if(ad>this.view.canvas_manager.char_width_px){this.tiles_div.show();return L.prototype.draw_helper.call(this,ac,ad,ab)}else{this.tiles_div.hide();return null}},can_subset:function(ab){return true},draw_tile:function(ad,aj,ae,ag,ak){var ac=this.data_manager.subset_entry(ad,ag),ai=ac.data;var ab=aj.canvas;aj.font=aj.canvas.manager.default_font;aj.textAlign="center";for(var af=0,ah=ai.length;af<ah;af++){aj.fillStyle=this.view.get_base_color(ai[af]);aj.fillText(ai[af],Math.floor(af*ak),10)}return new b(this,ag,ak,ab,ac)}});var g=function(ac,ab,ad){this.mode="Histogram";L.call(this,ac,ab,ad)};o(g.prototype,p.prototype,L.prototype,{display_modes:A,config_params:aa.union(p.prototype.config_params,[{key:"color",label:"Color",type:"color"},{key:"min_value",label:"Min Value",type:"float",default_value:undefined},{key:"max_value",label:"Max Value",type:"float",default_value:undefined},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:30,hidden:true}]),config_onchange:function(){this.set_name(this.config.get_value("name"));this.request_draw({clear_tile_cache:true})},before_draw:function(){},draw_tile:function(ab,ac,ae,ad,af){return this._draw_line_track_tile(ab,ac,ae,ad,af)},can_subset:function(ab){return(ab.data[1][0]-ab.data[0][0]===1)},postdraw_actions:function(ac,ad,ae,ab){this._add_yaxis_label("max");this._add_yaxis_label("min")}});var r=function(ac,ab,ad){this.mode="Heatmap";L.call(this,ac,ab,ad)};o(r.prototype,p.prototype,L.prototype,{display_modes:["Heatmap"],config_params:aa.union(p.prototype.config_params,[{key:"pos_color",label:"Positive Color",type:"color",default_value:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"min_value",label:"Min Value",type:"float",default_value:-1},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}]),config_onchange:function(){this.set_name(this.config.get_value("name"));this.request_draw({clear_tile_cache:true})},draw_tile:function(ab,ad,ag,af,ah){var ae=ad.canvas,ac=new J.DiagonalHeatmapPainter(ab.data,af.get("start"),af.get("end"),this.config.to_key_value_dict(),ag);ac.draw(ad,ae.width,ae.height,ah);return new b(this,af,ah,ae,ab.data)}});var c=function(ac,ab,ad){L.call(this,ac,ab,ad);this.container_div.addClass("feature-track");this.summary_draw_height=30;this.slotters={};this.start_end_dct={};this.left_offset=200;this.set_painter_from_config()};o(c.prototype,p.prototype,L.prototype,{display_modes:["Auto","Coverage","Dense","Squish","Pack"],config_params:aa.union(p.prototype.config_params,[{key:"block_color",label:"Block color",type:"color"},{key:"reverse_strand_color",label:"Antisense strand color",type:"color"},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true,help:"Show the number of items in each bin when drawing summary histogram"},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:0,hidden:true}]),config_onchange:function(){this.set_name(this.config.get_value("name"));this.set_painter_from_config();this.request_draw({clear_tile_cache:true})},set_painter_from_config:function(){if(this.config.get_value("connector_style")==="arcs"){this.painter=J.ArcLinkedFeaturePainter}else{this.painter=J.LinkedFeaturePainter}},postdraw_actions:function(al,ad,am,ak){L.prototype.postdraw_actions.call(this,al,ad,am,ak);var af=this,ag;if(af.filters_manager){var ae=af.filters_manager.filters,ai;for(ai=0;ai<ae.length;ai++){ae[ai].update_ui_elt()}var ah=false,aj,ac;for(ag=0;ag<al.length;ag++){if(al[ag].data.length){aj=al[ag].data[0];for(ai=0;ai<ae.length;ai++){ac=ae[ai];if(ac.applies_to(aj)&&ac.min!==ac.max){ah=true;break}}}}if(af.filters_available!==ah){af.filters_available=ah;if(!af.filters_available){af.filters_manager.hide()}af.update_icons()}}if(al[0] instanceof M){var ab=true;for(ag=0;ag<al.length;ag++){if(!al[ag].all_slotted){ab=false;break}}if(!ab){this.action_icons.show_more_rows_icon.show()}else{this.action_icons.show_more_rows_icon.hide()}}else{this.action_icons.show_more_rows_icon.hide()}},update_auto_mode:function(ab){if(this.mode==="Auto"){if(ab==="no_detail"){ab="feature spans"}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ab+")")}},incremental_slots:function(af,ab,ae){var ac=this.view.canvas_manager.dummy_context,ad=this.slotters[af];if(!ad||(ad.mode!==ae)){ad=new (s.FeatureSlotter)(af,ae,z,function(ag){return ac.measureText(ag)});this.slotters[af]=ad}return ad.slot_features(ab)},get_mode:function(ab){if(ab.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>G){mode="Squish"}else{mode="Pack"}}return mode},get_canvas_height:function(ab,af,ag,ac){if(af==="Coverage"||ab.dataset_type==="bigwig"){return this.summary_draw_height}else{var ae=this.incremental_slots(ag,ab.data,af);var ad=new (this.painter)(null,null,null,this.config.to_key_value_dict(),af);return Math.max(this.min_height_px,ad.get_required_height(ae,ac))}},draw_tile:function(al,ap,an,ae,ai,ad){var ao=this,ac=ap.canvas,aw=ae.get("start"),ab=ae.get("end"),af=this.left_offset;if(al.dataset_type==="bigwig"){return this._draw_line_track_tile(al,ap,an,ae,ai)}var ah=[],am=this.slotters[ai].slots;all_slotted=true;if(al.data){var aj=this.filters_manager.filters;for(var aq=0,at=al.data.length;aq<at;aq++){var ag=al.data[aq];var ar=false;var ak;for(var av=0,aA=aj.length;av<aA;av++){ak=aj[av];ak.update_attrs(ag);if(!ak.keep(ag)){ar=true;break}}if(!ar){ah.push(ag);if(!(ag[0] in am)){all_slotted=false}}}}var az=(this.filters_manager.alpha_filter?new C(this.filters_manager.alpha_filter):null),ax=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null),ay=new (this.painter)(ah,aw,ab,this.config.to_key_value_dict(),an,az,ax,ad,function(aB){return ao.view.get_base_color(aB)});var au=null;ap.fillStyle=this.config.get_value("block_color");ap.font=ap.canvas.manager.default_font;ap.textAlign="right";if(al.data){au=ay.draw(ap,ac.width,ac.height,ai,am);au.translation=-af}return new M(ao,ae,ai,ac,al.data,an,al.message,all_slotted,au)}});var Y=function(ac,ab,ad){L.call(this,ac,ab,ad);this.painter=J.VariantPainter;this.summary_draw_height=30;this.left_offset=30};o(Y.prototype,p.prototype,L.prototype,{display_modes:["Auto","Coverage","Dense","Squish","Pack"],config_params:aa.union(p.prototype.config_params,[{key:"color",label:"Histogram color",type:"color"},{key:"show_sample_data",label:"Show sample data",type:"bool",default_value:true},{key:"show_labels",label:"Show summary and sample labels",type:"bool",default_value:true},{key:"summary_height",label:"Locus summary height",type:"float",default_value:20},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:32,hidden:true}]),config_onchange:function(){this.set_name(this.config.get_value("name"));this.request_draw({clear_tile_cache:true})},draw_tile:function(ab,ae,ag,af,ah){if(ab.dataset_type==="bigwig"){return this._draw_line_track_tile(ab,ae,"Histogram",af,ah)}else{var ad=this.view,ac=new (this.painter)(ab.data,af.get("start"),af.get("end"),this.config.to_key_value_dict(),ag,function(ai){return ad.get_base_color(ai)});ac.draw(ae,ae.canvas.width,ae.canvas.height,ah);return new b(this,af,ah,ae.canvas,ab.data)}},get_canvas_height:function(ab,af,ag,ad){if(ab.dataset_type==="bigwig"){return this.summary_draw_height}else{var ac=(this.dataset.get_metadata("sample_names")?this.dataset.get_metadata("sample_names").length:0);if(ac===0&&ab.data.length!==0){ac=ab.data[0][7].match(/,/g);if(ac===null){ac=1}else{ac=ac.length+1}}var ae=new (this.painter)(null,null,null,this.config.to_key_value_dict(),af);return ae.get_required_height(ac)}},predraw_init:function(){var ab=[f.prototype.predraw_init.call(this)];if(!this.dataset.get_metadata("sample_names")){ab.push(this.dataset.fetch())}return ab},postdraw_actions:function(af,ag,ai,ac){L.prototype.postdraw_actions.call(this,af,ag,ai,ac);var ae=aa.filter(af,function(aj){return(aj instanceof K)});var ad=this.dataset.get_metadata("sample_names");if(ae.length===0&&this.config.get_value("show_labels")&&ad&&ad.length>1){var ab;if(this.container_div.find(".yaxislabel.variant").length===0){ab=this.config.get_value("summary_height")/2;this.tiles_div.prepend($("<div/>").text("Summary").addClass("yaxislabel variant top").css({"font-size":ab+"px",top:(this.config.get_value("summary_height")-ab)/2+"px"}));if(this.config.get_value("show_sample_data")){var ah=ad.join("<br/>");this.tiles_div.prepend($("<div/>").html(ah).addClass("yaxislabel variant top sample").css({top:this.config.get_value("summary_height")}))}}ab=(this.mode==="Squish"?5:10)+"px";$(this.tiles_div).find(".sample").css({"font-size":ab,"line-height":ab});$(this.tiles_div).find(".yaxislabel").css("color",this.config.get_value("label_color"))}else{this.container_div.find(".yaxislabel.variant").remove()}}});var S=function(ac,ab,ad){c.call(this,ac,ab,ad);this.painter=(ac.reference_track?J.RefBasedReadPainter:J.ReadPainter);this.update_icons()};o(S.prototype,p.prototype,L.prototype,c.prototype,{config_params:aa.union(p.prototype.config_params,[{key:"block_color",label:"Block and sense strand color",type:"color"},{key:"reverse_strand_color",label:"Antisense strand color",type:"color"},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"height",type:"int",default_value:0,hidden:true}]),config_onchange:function(){this.set_name(this.config.get_value("name"));this.request_draw({clear_tile_cache:true})}});var d={CompositeTrack:e,DrawableGroup:N,DiagonalHeatmapTrack:r,FeatureTrack:c,LineTrack:g,ReadTrack:S,VariantTrack:Y,VcfTrack:Y};var n=function(ad,ac,ab){if("copy" in ad){return ad.copy(ab)}else{var ae=ad.obj_type;if(!ae){ae=ad.track_type}return new d[ae](ac,ab,ad)}};return{TracksterView:X,DrawableGroup:N,LineTrack:g,FeatureTrack:c,DiagonalHeatmapTrack:r,ReadTrack:S,VariantTrack:Y,CompositeTrack:e,object_from_template:n}});
\ No newline at end of file
+define(["libs/underscore","viz/visualization","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters","viz/trackster/filters","mvc/data","mvc/tools","utils/config"],function(aa,w,j,s,J,h,W,P,R){var o=aa.extend;var l={};var i=function(ab,ac){l[ab.attr("id")]=ac};var k=function(ab,ac,ae,ad){ae=".group";l[ab.attr("id")]=ad;ab.bind("drag",{handle:"."+ac,relative:true},function(am,an){var al=$(this),aq=$(this).parent(),ai=aq.children(".track,.group"),ak=l[$(this).attr("id")],ah,ag,ao,af,aj;ag=$(this).parents(ae);if(ag.length!==0){ao=ag.position().top;af=ao+ag.outerHeight();var ap=l[ag.attr("id")];if(an.offsetY<ao){$(this).insertBefore(ag);ap.remove_drawable(ak);ap.container.add_drawable_before(ak,ap);return}else{if(an.offsetY>af){$(this).insertAfter(ag);ap.remove_drawable(ak);ap.container.add_drawable(ak);return}}}ag=null;for(aj=0;aj<ai.length;aj++){ah=$(ai.get(aj));ao=ah.position().top;af=ao+ah.outerHeight();if(ah.is(ae)&&this!==ah.get(0)&&an.offsetY>=ao&&an.offsetY<=af){if(an.offsetY-ao<af-an.offsetY){ah.find(".content-div").prepend(this)}else{ah.find(".content-div").append(this)}if(ak.container){ak.container.remove_drawable(ak)}l[ah.attr("id")].add_drawable(ak);return}}for(aj=0;aj<ai.length;aj++){ah=$(ai.get(aj));if(an.offsetY<ah.position().top&&!(ah.hasClass("reference-track")||ah.hasClass("intro"))){break}}if(aj===ai.length){if(this!==ai.get(aj-1)){aq.append(this);l[aq.attr("id")].move_drawable(ak,aj)}}else{if(this!==ai.get(aj)){$(this).insertBefore(ai.get(aj));l[aq.attr("id")].move_drawable(ak,(an.deltaY>0?aj-1:aj))}}}).bind("dragstart",function(){$(this).addClass("dragging")}).bind("dragend",function(){$(this).removeClass("dragging")})};var D=20,z=100,G=12000,Q=400,I=5000,v=100,m="Cannot display dataset due to an error. ",H="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",u="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",x="Tool cannot be rerun: ",a="Loading data...",T="Ready for display",O=10,F=20,A=["Histogram","Line","Filled","Intensity"];function U(ac,ab){if(!ab){ab=0}var ad=Math.pow(10,ab);return Math.round(ac*ad)/ad}var p=function(ac,ab,ae){if(!p.id_counter){p.id_counter=0}this.id=p.id_counter++;this.view=ac;this.container=ab;this.drag_handle_class=ae.drag_handle_class;this.is_overview=false;this.action_icons={};this.config=R.ConfigSettingCollection.from_models_and_saved_values(this.config_params,ae.prefs);if(!this.config.get_value("name")){this.config.set_value("name",ae.name)}if(this.config_onchange){this.config.on("change",this.config_onchange,this)}this.container_div=this.build_container_div();this.header_div=this.build_header_div();if(this.header_div){this.container_div.append(this.header_div);this.icons_div=$("<div/>").addClass("track-icons").hide().appendTo(this.header_div);this.build_action_icons(this.action_icons_def);this.header_div.append($("<div style='clear: both'/>"));this.header_div.dblclick(function(af){af.stopPropagation()});var ad=this;this.container_div.hover(function(){ad.icons_div.show()},function(){ad.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};p.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ab){if(ab.config.get_value("content_visible")){ab.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ab.hide_contents();ab.config.set_value("content_visible",false)}else{ab.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ab.config.set_value("content_visible",true);ab.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"gear",on_click_fn:function(ac){var ab=new R.ConfigSettingCollectionView({collection:ac.config});ab.render_in_modal("Configure Track")}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ab){$(".tooltip").remove();ab.remove()}}];o(p.prototype,{config_params:[{key:"name",label:"Name",type:"text",default_value:""},{key:"content_visible",type:"bool",default_value:true,hidden:true}],config_onchange:function(){this.track.set_name(this.track.config.get("values").name)},init:function(){},changed:function(){this.view.changed()},can_draw:function(){if(this.enabled&&this.config.get_value("content_visible")){return true}return false},request_draw:function(){},_draw:function(ab){},to_dict:function(){},set_name:function(ab){this.old_name=this.config.get_value("name");this.config.set_value("name",ab);this.name_div.text(ab)},revert_name:function(){if(this.old_name){this.config.set_value("name",this.old_name);this.name_div.text(this.old_name)}},remove:function(){this.changed();this.container.remove_drawable(this);var ab=this.view;this.container_div.hide(0,function(){$(this).remove();ab.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ac,ah,ag,af,ab,ae){var ad=this;this.action_icons[ac]=$("<a/>").attr("title",ah).addClass("icon-button").addClass(ag).tooltip().click(function(){af(ad)}).appendTo(this.icons_div);if(ae){this.action_icons[ac].hide()}},build_action_icons:function(ab){var ad;for(var ac=0;ac<ab.length;ac++){ad=ab[ac];this.add_action_icon(ad.name,ad.title,ad.css_class,ad.on_click_fn,ad.prepend,ad.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var y=function(ac,ab,ad){p.call(this,ac,ab,ad);this.obj_type=ad.obj_type;this.drawables=[]};o(y.prototype,p.prototype,{unpack_drawables:function(ad){this.drawables=[];var ac;for(var ab=0;ab<ad.length;ab++){ac=n(ad[ab],this.view,this);this.add_drawable(ac)}},init:function(){for(var ab=0;ab<this.drawables.length;ab++){this.drawables[ab].init()}},_draw:function(ab){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac]._draw(ab)}},to_dict:function(){var ac=[];for(var ab=0;ab<this.drawables.length;ab++){ac.push(this.drawables[ab].to_dict())}return{prefs:this.config.to_key_value_dict(),obj_type:this.obj_type,drawables:ac}},add_drawable:function(ab){this.drawables.push(ab);ab.container=this;this.changed()},add_drawable_before:function(ad,ab){this.changed();var ac=this.drawables.indexOf(ab);if(ac!==-1){this.drawables.splice(ac,0,ad);return true}return false},replace_drawable:function(ad,ab,ac){var ae=this.drawables.indexOf(ad);if(ae!==-1){this.drawables[ae]=ab;if(ac){ad.container_div.replaceWith(ab.container_div)}this.changed()}return ae},remove_drawable:function(ac){var ab=this.drawables.indexOf(ac);if(ab!==-1){this.drawables.splice(ab,1);ac.container=null;this.changed();return true}return false},move_drawable:function(ac,ad){var ab=this.drawables.indexOf(ac);if(ab!==-1){this.drawables.splice(ab,1);this.drawables.splice(ad,0,ac);this.changed();return true}return false},get_drawables:function(){return this.drawables},get_tracks:function(ae){var ab=this.drawables.slice(0),ac=[],ad;while(ab.length!==0){ad=ab.shift();if(ad instanceof ae){ac.push(ad)}else{if(ad.drawables){ab=ab.concat(ad.drawables)}}}return ac}});var N=function(ac,ab,ae){o(ae,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});y.call(this,ac,ab,ae);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);i(this.container_div,this);i(this.content_div,this);k(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new h.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in ae){this.unpack_drawables(ae.drawables)}if("filters" in ae){var ad=this.filters_manager;this.filters_manager=new h.FiltersManager(this,ae.filters);ad.parent_div.replaceWith(this.filters_manager.parent_div);if(ae.filters.visible){this.setup_multitrack_filtering()}}};o(N.prototype,p.prototype,y.prototype,{action_icons_def:[p.prototype.action_icons_def[0],p.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ab){$(".tooltip").remove();ab.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ab){if(ab.filters_manager.visible()){ab.filters_manager.clear_filters();ab._restore_filter_managers()}else{ab.setup_multitrack_filtering();ab.request_draw({clear_tile_cache:true})}ab.filters_manager.toggle()}},p.prototype.action_icons_def[2]],build_container_div:function(){var ab=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ab)}return ab},build_header_div:function(){var ab=$("<div/>").addClass("track-header");ab.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.config.get_value("name")).appendTo(ab);return ab},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ad=this.drawables.length;if(ad===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ad===1){if(this.drawables[0] instanceof e){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var ak,aj,ah,an=true,af=this.drawables[0].get_type(),ab=0;for(ak=0;ak<ad;ak++){ah=this.drawables[ak];if(ah.get_type()!==af){can_composite=false;break}if(ah instanceof c){ab++}}if(an||ab===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".tooltip").remove()}if(ab>1&&ab===this.drawables.length){var ao={},ac;ah=this.drawables[0];for(aj=0;aj<ah.filters_manager.filters.length;aj++){ac=ah.filters_manager.filters[aj];ao[ac.name]=[ac]}for(ak=1;ak<this.drawables.length;ak++){ah=this.drawables[ak];for(aj=0;aj<ah.filters_manager.filters.length;aj++){ac=ah.filters_manager.filters[aj];if(ac.name in ao){ao[ac.name].push(ac)}}}this.filters_manager.remove_all();var ae,ag,ai,al;for(var am in ao){ae=ao[am];if(ae.length===ab){ag=new h.NumberFilter({name:ae[0].name,index:ae[0].index});this.filters_manager.add_filter(ag)}}if(this.filters_manager.filters.length>0){this.action_icons.filters_icon.show()}else{this.action_icons.filters_icon.hide()}}else{this.action_icons.filters_icon.hide()}}}},_restore_filter_managers:function(){for(var ab=0;ab<this.drawables.length;ab++){this.drawables[ab].filters_manager=this.saved_filters_managers[ab]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ab=0;ab<this.drawables.length;ab++){drawable=this.drawables[ab];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ac=new e(this.view,this.view,{name:this.config.get_value("name"),drawables:this.drawables});var ab=this.container.replace_drawable(this,ac,true);ac.request_draw()},add_drawable:function(ab){y.prototype.add_drawable.call(this,ab);this.update_icons()},remove_drawable:function(ab){y.prototype.remove_drawable.call(this,ab);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ab=o(y.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ab},request_draw:function(ab){aa.each(this.drawables,function(ac){ac.request_draw(ab)})}});var X=Backbone.View.extend({initialize:function(ab){o(ab,{obj_type:"View"});y.call(this,"View",ab.container,ab);this.chrom=null;this.vis_id=ab.vis_id;this.dbkey=ab.dbkey;this.label_tracks=[];this.tracks_to_be_redrawn=[];this.max_low=0;this.max_high=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.load_chroms_deferred=null;this.render();this.canvas_manager=new w.CanvasManager(this.container.get(0).ownerDocument);this.reset();this.config=R.ConfigSettingCollection.from_models_and_saved_values([{key:"name",label:"Name",type:"text",default_value:""},{key:"a_color",label:"A Color",type:"color",default_value:"#FF0000"},{key:"c_color",label:"C Color",type:"color",default_value:"#00FF00"},{key:"g_color",label:"G Color",type:"color",default_value:"#0000FF"},{key:"t_color",label:"T Color",type:"color",default_value:"#FF00FF"},{key:"n_color",label:"N Color",type:"color",default_value:"#AAAAAA"}],{name:ab.name})},render:function(){this.requested_redraw=false;var ad=this.container,ab=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ad);this.browser_content_div=$("<div/>").addClass("content").appendTo(ad);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ad);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").attr("id","viewport-container").appendTo(this.browser_content_div);this.content_div=this.viewport_container;i(this.viewport_container,ab);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var ae=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){w.select_datasets(galaxy_config.root+"visualization/list_current_history_datasets",galaxy_config.root+"api/datasets",{"f-dbkey":ab.dbkey},function(af){aa.each(af,function(ag){ab.add_drawable(n(ag,ab,ab))})})});this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("trackster-nav-container").prependTo(this.top_container);this.nav=$("<div/>").addClass("trackster-nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a/>").attr("title","Close overview").addClass("icon-button overview-close tooltip").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div/>").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_select=$("<select/>").attr({name:"chrom"}).addClass("chrom-nav").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var ac=function(af){if(af.type==="focusout"||(af.keyCode||af.which)===13||(af.keyCode||af.which)===27){if((af.keyCode||af.which)!==27){ab.go_to($(this).val())}$(this).hide();$(this).val("");ab.location_span.show();ab.chrom_select.show()}af.stopPropagation()};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ac).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").attr("title","Click to change location").tooltip({placement:"bottom"}).appendTo(this.nav_controls);this.location_span.click(function(){ab.location_span.hide();ab.chrom_select.hide();ab.nav_input.val(ab.chrom+":"+ab.low+"-"+ab.high);ab.nav_input.css("display","inline-block");ab.nav_input.select();ab.nav_input.focus();ab.nav_input.autocomplete({source:function(ah,af){var ai=[],ag=$.map(ab.get_tracks(c),function(aj){return aj.data_manager.search_features(ah.term).success(function(ak){ai=ai.concat(ak)})});$.when.apply($,ag).done(function(){af($.map(ai,function(aj){return{label:aj[0],value:aj[1]}}))})}})});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a/>").attr("id","zoom-out").attr("title","Zoom out").tooltip({placement:"bottom"}).click(function(){ab.zoom_out()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ab.zoom_in()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ab.change_chrom(ab.chrom_select.val())});this.browser_content_div.click(function(af){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(af){ab.zoom_in(af.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(af,ag){this.current_x=ag.offsetX}).bind("drag",function(af,ah){var ai=ah.offsetX-this.current_x;this.current_x=ah.offsetX;var ag=Math.round(ai/ab.viewport_container.width()*(ab.max_high-ab.max_low));ab.move_delta(-ag)});this.overview_close.click(function(){ab.reset_overview()});this.viewport_container.bind("draginit",function(af,ag){if(af.clientX>ab.viewport_container.width()-16){return false}}).bind("dragstart",function(af,ag){ag.original_low=ab.low;ag.current_height=af.clientY;ag.current_x=ag.offsetX}).bind("drag",function(ah,aj){var af=$(this);var ak=aj.offsetX-aj.current_x;var ag=af.scrollTop()-(ah.clientY-aj.current_height);af.scrollTop(ag);aj.current_height=ah.clientY;aj.current_x=aj.offsetX;var ai=Math.round(ak/ab.viewport_container.width()*(ab.high-ab.low));ab.move_delta(ai)}).bind("mousewheel",function(ah,aj,ag,af){if(ag){ag*=50;var ai=Math.round(-ag/ab.viewport_container.width()*(ab.high-ab.low));ab.move_delta(ai)}});this.top_labeltrack.bind("dragstart",function(af,ag){return $("<div/>").addClass("zoom-area").css("height",ab.browser_content_div.height()+ab.top_labeltrack.height()+ab.nav_labeltrack.height()+1).appendTo($(this))}).bind("drag",function(aj,ak){$(ak.proxy).css({left:Math.min(aj.pageX,ak.startX)-ab.container.offset().left,width:Math.abs(aj.pageX-ak.startX)});var ag=Math.min(aj.pageX,ak.startX)-ab.container.offset().left,af=Math.max(aj.pageX,ak.startX)-ab.container.offset().left,ai=(ab.high-ab.low),ah=ab.viewport_container.width();ab.update_location(Math.round(ag/ah*ai)+ab.low,Math.round(af/ah*ai)+ab.low)}).bind("dragend",function(ak,al){var ag=Math.min(ak.pageX,al.startX),af=Math.max(ak.pageX,al.startX),ai=(ab.high-ab.low),ah=ab.viewport_container.width(),aj=ab.low;ab.low=Math.round(ag/ah*ai)+aj;ab.high=Math.round(af/ah*ai)+aj;$(al.proxy).remove();ab.request_redraw()});this.add_label_track(new V(this,{content_div:this.top_labeltrack}));this.add_label_track(new V(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ab.resize_window()},500)});$(document).bind("redraw",function(){ab.redraw()});this.reset();$(window).trigger("resize")},get_base_color:function(ab){return this.config.get_value(ab.toLowerCase()+"_color")||this.config.get_value("n_color")}});o(X.prototype,y.prototype,{changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(ac,ae,ab,af){if(this.timer){clearTimeout(this.timer)}if(af){var ad=this;this.timer=setTimeout(function(){ad.trigger("navigate",ac+":"+ae+"-"+ab)},500)}else{view.trigger("navigate",ac+":"+ae+"-"+ab)}},update_location:function(ab,ad){this.location_span.text(commatize(ab)+" - "+commatize(ad));this.nav_input.val(this.chrom+":"+commatize(ab)+"-"+commatize(ad));var ac=view.chrom_select.val();if(ac!==""){this.trigger_navigate(ac,view.low,view.high,true)}},load_chroms:function(ad){ad.num=v;var ab=this,ac=$.Deferred();$.ajax({url:galaxy_config.root+"api/genomes/"+this.dbkey,data:ad,dataType:"json",success:function(af){if(af.chrom_info.length===0){return}if(af.reference){var ag=new B(ab);ab.add_label_track(ag);ab.reference_track=ag}ab.chrom_data=af.chrom_info;var aj='<option value="">Select Chrom/Contig</option>';for(var ai=0,ae=ab.chrom_data.length;ai<ae;ai++){var ah=ab.chrom_data[ai].chrom;aj+='<option value="'+ah+'">'+ah+"</option>"}if(af.prev_chroms){aj+='<option value="previous">Previous '+v+"</option>"}if(af.next_chroms){aj+='<option value="next">Next '+v+"</option>"}ab.chrom_select.html(aj);ab.chrom_start_index=af.start_index;ac.resolve(af.chrom_info)},error:function(){alert("Could not load chroms for this dbkey: "+ab.dbkey)}});return ac},change_chrom:function(ag,ac,ai){var ad=this;if(!ad.chrom_data){ad.load_chroms_deferred.then(function(){ad.change_chrom(ag,ac,ai)});return}if(!ag||ag==="None"){return}if(ag==="previous"){ad.load_chroms({low:this.chrom_start_index-v});return}if(ag==="next"){ad.load_chroms({low:this.chrom_start_index+v});return}var ah=$.grep(ad.chrom_data,function(aj,ak){return aj.chrom===ag})[0];if(ah===undefined){ad.load_chroms({chrom:ag},function(){ad.change_chrom(ag,ac,ai)});return}else{if(ag!==ad.chrom){ad.chrom=ag;ad.chrom_select.val(ad.chrom);ad.max_high=ah.len-1;ad.reset();for(var af=0,ab=ad.drawables.length;af<ab;af++){var ae=ad.drawables[af];if(ae.init){ae.init()}}if(ad.reference_track){ad.reference_track.init()}}if(ac===undefined&&ai===undefined){ad.low=0;ad.high=ad.max_high}else{ad.low=(ac!==undefined?Math.max(ac,0):0);if(ai===undefined){ad.low=Math.max(ad.low-15,0);ad.high=ad.low+30}else{ad.high=Math.min(ai,ad.max_high)}}ad.reset_overview();ad.request_redraw()}},go_to:function(af){af=af.replace(/,/g,"");af=af.replace(/:|\-/g," ");var ac=af.split(/\s+/),ae=ac[0],ad=(ac[1]?parseInt(ac[1],10):undefined),ab=(ac[2]?parseInt(ac[2],10):undefined);this.change_chrom(ae,ad,ab)},move_fraction:function(ad){var ab=this;var ac=ab.high-ab.low;this.move_delta(ad*ac)},move_delta:function(ae){var ab=this;var ad=ab.high-ab.low;if(ab.low-ae<ab.max_low){ab.low=ab.max_low;ab.high=ab.max_low+ad}else{if(ab.high-ae>ab.max_high){ab.high=ab.max_high;ab.low=ab.max_high-ad}else{ab.high-=ae;ab.low-=ae}}ab.request_redraw({data_fetch:false});if(this.redraw_on_move_fn){clearTimeout(this.redraw_on_move_fn)}this.redraw_on_move_fn=setTimeout(function(){ab.request_redraw()},200);var ac=ab.chrom_select.val();this.trigger_navigate(ac,ab.low,ab.high,true)},add_drawable:function(ab){y.prototype.add_drawable.call(this,ab);ab.init();this.changed();this.update_intro_div()},add_label_track:function(ab){ab.view=this;ab.init();this.label_tracks.push(ab)},remove_drawable:function(ad,ac){y.prototype.remove_drawable.call(this,ad);if(ac){var ab=this;ad.container_div.hide(0,function(){$(this).remove();ab.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ac,ad){var ab=this,ae=(ad?[ad]:ab.drawables);aa.each(ae,function(af){var ag=aa.find(ab.tracks_to_be_redrawn,function(ah){return ah[0]===af});if(ag){ag[1]=ac}else{ab.tracks_to_be_redrawn.push([af,ac])}});if(!this.requested_redraw){requestAnimationFrame(function(){ab._redraw()});this.requested_redraw=true}},_redraw:function(){this.requested_redraw=false;var ab=this.low,af=this.high;if(ab<this.max_low){ab=this.max_low}if(af>this.max_high){af=this.max_high}var ac=this.high-this.low;if(this.high!==0&&ac<this.min_separation){af=ab+this.min_separation}this.low=Math.floor(ab);this.high=Math.ceil(af);this.update_location(this.low,this.high);this.resolution_px_b=this.viewport_container.width()/(this.high-this.low);var ae=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ag=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ad=13;this.overview_box.css({left:ae,width:Math.max(ad,ag)}).show();if(ag<ad){this.overview_box.css("left",ae-(ad-ag)/2)}if(this.overview_highlight){this.overview_highlight.css({left:ae,width:ag})}aa.each(this.tracks_to_be_redrawn,function(aj){var ah=aj[0],ai=aj[1];if(ah){ah._draw(ai)}});this.tracks_to_be_redrawn=[];aa.each(this.label_tracks,function(ah){ah._draw()})},zoom_in:function(ac,ad){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var ae=this.high-this.low,af=ae/2+this.low,ab=(ae/this.zoom_factor)/2;if(ac){af=ac/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(af-ab);this.high=Math.round(af+ab);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ac=this.high-this.low,ad=ac/2+this.low,ab=(ac*this.zoom_factor)/2;this.low=Math.round(ad-ab);this.high=Math.round(ad+ab);this.changed();this.request_redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.request_redraw()},set_overview:function(ad){if(this.overview_drawable){if(this.overview_drawable.dataset.id===ad.dataset.id){return}this.overview_viewport.find(".track").remove()}var ac=ad.copy({content_div:this.overview_viewport}),ab=this;ac.header_div.hide();ac.is_overview=true;ab.overview_drawable=ac;this.overview_drawable.postdraw_actions=function(){ab.overview_highlight.show().height(ab.overview_drawable.content_div.height());ab.overview_viewport.height(ab.overview_drawable.content_div.height()+ab.overview_box.outerHeight());ab.overview_close.show();ab.resize_window()};ab.overview_drawable.request_draw();this.changed()},reset_overview:function(){$(".tooltip").remove();this.overview_viewport.find(".track-tile").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide();view.resize_window();view.overview_drawable=null}});var q=P.Tool.extend({defaults:{track:null},initialize:function(ab){P.Tool.prototype.initialize.call(this,ab);var ac=true;if(ab.tool_state!==undefined&&ab.tool_state.hidden!==undefined){ac=ab.tool_state.hidden}this.set("hidden",ac);this.remove_inputs(["data","hidden_data","conditional"])},state_dict:function(ab){return aa.extend(this.get_inputs_dict(),{hidden:!this.is_visible()})}});var t=Backbone.View.extend({events:{"change input":"update_value"},render:function(){var ad=this.$el.addClass("param-row"),ae=this.model;var ab=$("<div>").addClass("param-label").text(ae.get("label")).appendTo(ad);var ac=$("<div/>").addClass("param-input").html(ae.get("html")).appendTo(ad);ac.find(":input").val(ae.get("value"));$("<div style='clear: both;'/>").appendTo(ad)},update_value:function(ab){this.model.set_value($(ab.target).val())}});var Z=Backbone.View.extend({initialize:function(ab){this.model.on("change:hidden",this.set_visible,this)},render:function(){var ac=this;tool=this.model,parent_div=this.$el.addClass("dynamic-tool").hide();parent_div.bind("drag",function(ag){ag.stopPropagation()}).click(function(ag){ag.stopPropagation()}).bind("dblclick",function(ag){ag.stopPropagation()}).keydown(function(ag){ag.stopPropagation()});var ad=$("<div class='tool-name'>").appendTo(parent_div).text(tool.get("name"));tool.get("inputs").each(function(ah){var ag=new t({model:ah});ag.render();parent_div.append(ag.$el)});parent_div.find("input").click(function(){$(this).select()});var ae=$("<div>").addClass("param-row").appendTo(parent_div);var af=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(ae);var ab=$("<input type='submit'>").attr("value","Run on visible region").appendTo(ae);ab.click(function(){ac.run_on_region()});af.click(function(){ac.run_on_dataset()});if(tool.is_visible()){this.$el.show()}},set_visible:function(){if(this.model.is_visible()){this.$el.show()}else{this.$el.hide()}},update_params:function(){for(var ab=0;ab<this.params.length;ab++){this.params[ab].update_value()}},run_on_dataset:function(){var ab=this.model;this.run({target_dataset_id:this.model.get("track").dataset.id,action:"rerun",tool_id:ab.id},null,function(ac){Galaxy.modal.show({title:ab.get("name")+" is Running",body:ab.get("name")+" is running on the complete dataset. Tool outputs are in dataset's history.",buttons:{Close:function(){Galaxy.modal.hide()}}})})},run_on_region:function(){var ac=this.model.get("track"),af=this.model,ah=new w.GenomeRegion({chrom:ac.view.chrom,start:ac.view.low,end:ac.view.high}),ai={target_dataset_id:ac.dataset.id,action:"rerun",tool_id:af.id,regions:[ah.toJSON()]},ag=ac,ak=af.get("name")+ag.tool_region_and_parameters_str(ah),ab;if(ag.container===view){var aj=new N(view,view,{name:ac.config.get_value("name")});var ae=ag.container.replace_drawable(ag,aj,false);aj.container_div.insertBefore(ag.view.content_div.children()[ae]);aj.add_drawable(ag);ag.container_div.appendTo(aj.content_div);ab=aj}else{ab=ag.container}var ad=new ag.constructor(view,ab,{name:ak,hda_ldda:"hda"});ad.init_for_tool_data();ad.change_mode(ag.mode);ad.set_filters_manager(ag.filters_manager.copy(ad));ad.update_icons();ab.add_drawable(ad);ad.tiles_div.text("Starting job.");this.run(ai,ad,function(al){ad.set_dataset(new W.Dataset(al));ad.tiles_div.text("Running job.");ad.init()})},run:function(ab,ad,ae){ab.inputs=this.model.get_inputs_dict();var ac=new j.ServerStateDeferred({ajax_settings:{url:galaxy_config.root+"api/tools",data:JSON.stringify(ab),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(af){return af!=="pending"}});$.when(ac.go()).then(function(af){if(af==="no converter"){ad.container_div.addClass("error");ad.content_div.text(H)}else{if(af.error){ad.container_div.addClass("error");ad.content_div.text(x+af.message)}else{ae(af)}}})}});var C=function(ab,ac){J.Scaler.call(this,ac);this.filter=ab};C.prototype.gen_val=function(ab){if(this.filter.high===Number.MAX_VALUE||this.filter.low===-Number.MAX_VALUE||this.filter.low===this.filter.high){return this.default_val}return((parseFloat(ab[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var b=function(ab,ae,af,ac,ad){this.track=ab;this.region=ae;this.low=ae.get("start");this.high=ae.get("end");this.w_scale=af;this.canvas=ac;this.html_elt=$("<div class='track-tile'/>").append(ac);this.data=ad;this.stale=false};b.prototype.predisplay_actions=function(){};var K=function(ab,ae,af,ac,ad){b.call(this,ab,ae,af,ac,ad)};K.prototype.predisplay_actions=function(){};var M=function(ae,al,an,ad,ag,ah,ao,ac,ak){b.call(this,ae,al,an,ad,ag);this.mode=ah;this.all_slotted=ac;this.feature_mapper=ak;this.has_icons=false;if(ao){this.has_icons=true;var ai=this;ad=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:D,width:ad.width}).prependTo(this.html_elt);var aj=new w.GenomeRegion({chrom:ae.view.chrom,start:this.low,end:this.high}),am=ag.length,af=$("<a/>").addClass("icon more-down").attr("title","For speed, only the first "+am+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ab=$("<a/>").addClass("icon more-across").attr("title","For speed, only the first "+am+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);af.click(function(){ai.stale=true;ae.data_manager.get_more_data(aj,ae.mode,1/ai.w_scale,{},ae.data_manager.DEEP_DATA_REQ);$(".tooltip").hide();ae.request_draw()}).dblclick(function(ap){ap.stopPropagation()});ab.click(function(){ai.stale=true;ae.data_manager.get_more_data(aj,ae.mode,1/ai.w_scale,{},ae.data_manager.BROAD_DATA_REQ);$(".tooltip").hide();ae.request_draw()}).dblclick(function(ap){ap.stopPropagation()})}};o(M.prototype,b.prototype);M.prototype.predisplay_actions=function(){var ac=this,ab={};if(ac.mode!=="Pack"){return}$(this.html_elt).hover(function(){this.hovered=true;$(this).mousemove()},function(){this.hovered=false;$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()}).mousemove(function(an){if(!this.hovered){return}var ai=$(this).offset(),am=an.pageX-ai.left,al=an.pageY-ai.top,ar=ac.feature_mapper.get_feature_data(am,al),aj=(ar?ar[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!aj||$(this).attr("id")!==aj.toString()){$(this).remove()}});if(ar){var ae=ab[aj];if(!ae){var ao={name:ar[3],start:ar[1],end:ar[2],strand:ar[4]},ah=ac.track.filters_manager.filters,ag;for(var ak=0;ak<ah.length;ak++){ag=ah[ak];ao[ag.name]=ar[ag.index]}ae=$("<div/>").attr("id",aj).addClass("feature-popup");var at=$("<table/>"),aq,ap,au;for(aq in ao){ap=ao[aq];au=$("<tr/>").appendTo(at);$("<th/>").appendTo(au).text(aq);$("<td/>").attr("align","left").appendTo(au).text(typeof(ap)==="number"?U(ap,2):ap)}ae.append($("<div class='feature-popup-inner'>").append(at));ab[aj]=ae}ae.appendTo($(this).parents(".track-content").children(".overlay"));var af=am+parseInt(ac.html_elt.css("left"),10)-ae.width()/2,ad=al+parseInt(ac.html_elt.css("top"),10)+7;ae.css("left",af+"px").css("top",ad+"px")}else{if(!an.isPropagationStopped()){an.stopPropagation();$(this).siblings().each(function(){$(this).trigger(an)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var f=function(ac,ab,ad){o(ad,{drag_handle_class:"draghandle"});p.call(this,ac,ab,ad);this.dataset=null;if(ad.dataset){this.dataset=(ad.dataset instanceof Backbone.Model?ad.dataset:new W.Dataset(ad.dataset))}this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ad?ad.data_query_wait:I);this.data_manager=("data_manager" in ad?ad.data_manager:new w.GenomeDataManager({dataset:this.dataset,genome:new w.Genome({key:ac.dbkey,chroms_info:{chrom_info:ac.chrom_data}}),data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=this.config.get_value("height");this.content_div=$("<div class='track-content'>").appendTo(this.container_div);if(this.container){this.container.content_div.append(this.container_div);if(!("resize" in ad)||ad.resize){this.add_resize_handle()}}};o(f.prototype,p.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},p.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"application-dock-270",on_click_fn:function(ab){ab.view.set_overview(ab)}},p.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"ui-slider-050",on_click_fn:function(ab){if(ab.filters_manager.visible()){ab.filters_manager.clear_filters()}else{ab.filters_manager.init_filters()}ab.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ab){ab.tool.toggle();if(ab.tool.is_visible()){ab.set_name(ab.config.get_value("name")+ab.tool_region_and_parameters_str())}else{ab.revert_name()}$(".tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ab){var ae='<strong>Tool</strong>: <%= track.tool.get("name") %><br/><strong>Dataset</strong>: <%= track.config.get("name") %><br/><strong>Region(s)</strong>: <select name="regions"><option value="cur">current viewing area</option><option value="bookmarks">bookmarks</option><option value="both">current viewing area and bookmarks</option></select>',ad=aa.template(ae,{track:ab});var ag=function(){Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc")},ac=function(){var ai=$('select[name="regions"] option:selected').val(),ak,ah=new w.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),aj=aa.map($(".bookmark"),function(al){return new w.GenomeRegion({from_str:$(al).children(".position").text()})});if(ai==="cur"){ak=[ah]}else{if(ai==="bookmarks"){ak=aj}else{ak=[ah].concat(aj)}}Galaxy.modal.hide();window.location.href=galaxy_config.root+"visualization/sweepster?"+$.param({dataset_id:ab.dataset.id,hda_ldda:ab.dataset.get("hda_ldda"),regions:JSON.stringify(new Backbone.Collection(ak).toJSON())})},af=function(ah){if((ah.keyCode||ah.which)===27){ag()}else{if((ah.keyCode||ah.which)===13){ac()}}};Galaxy.modal.show({title:"Visualize tool parameter space and output from different parameter settings?",body:ad,buttons:{No:ag,Yes:ac}})}},p.prototype.action_icons_def[2]],can_draw:function(){return this.dataset&&p.prototype.can_draw.call(this)},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id)},build_header_div:function(){var ab=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ab)}this.name_div=$("<div/>").addClass("track-name").appendTo(ab).text(this.config.get_value("name")).attr("id",this.config.get_value("name").replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ab},set_dataset:function(ab){this.dataset=ab;this.data_manager.set("dataset",ab)},on_resize:function(){this.request_draw({clear_tile_cache:true})},add_resize_handle:function(){var ab=this;var ae=false;var ad=false;var ac=$("<div class='track-resize'>");$(ab.container_div).hover(function(){if(ab.config.get_value("content_visible")){ae=true;ac.show()}},function(){ae=false;if(!ad){ac.hide()}});ac.hide().bind("dragstart",function(af,ag){ad=true;ag.original_height=$(ab.content_div).height()}).bind("drag",function(ag,ah){var af=Math.min(Math.max(ah.original_height+ah.deltaY,ab.min_height_px),ab.max_height_px);$(ab.tiles_div).css("height",af);ab.visible_height_px=(ab.max_height_px===af?0:af);ab.on_resize()}).bind("dragend",function(af,ag){ab.tile_cache.clear();ad=false;if(!ae){ac.hide()}ab.config.set("height",ab.visible_height_px);ab.changed()}).appendTo(ab.container_div)},set_display_modes:function(ae,ah){this.display_modes=ae;this.mode=(ah?ah:(this.config&&this.config.get_value("mode")?this.config.get_value("mode"):this.display_modes[0]));this.action_icons.mode_icon.attr("title","Set display mode (now: "+this.mode+")");var ac=this,af={};for(var ad=0,ab=ac.display_modes.length;ad<ab;ad++){var ag=ac.display_modes[ad];af[ag]=function(ai){return function(){ac.change_mode(ai);ac.icons_div.show();ac.container_div.mouseleave(function(){ac.icons_div.hide()})}}(ag)}make_popupmenu(this.action_icons.mode_icon,af)},build_action_icons:function(){p.prototype.build_action_icons.call(this,this.action_icons_def);if(this.display_modes!==undefined){this.set_display_modes(this.display_modes)}},hide_contents:function(){this.tiles_div.hide();this.container_div.find(".yaxislabel, .track-resize").hide()},show_contents:function(){this.tiles_div.show();this.container_div.find(".yaxislabel, .track-resize").show();this.request_draw()},get_type:function(){if(this instanceof V){return"LabelTrack"}else{if(this instanceof B){return"ReferenceTrack"}else{if(this instanceof g){return"LineTrack"}else{if(this instanceof S){return"ReadTrack"}else{if(this instanceof Y){return"VariantTrack"}else{if(this instanceof e){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},show_message:function(ab){this.tiles_div.remove();return $("<span/>").addClass("message").html(ab).appendTo(this.content_div)},init:function(ad){var ac=this;ac.enabled=false;ac.tile_cache.clear();ac.data_manager.clear();ac.content_div.children().remove();ac.container_div.removeClass("nodata error pending");ac.tiles_div=$("<div/>").addClass("tiles").appendTo(ac.content_div);if(!ac.dataset.id){return}var ab=$.Deferred(),ae={hda_ldda:ac.dataset.get("hda_ldda"),data_type:this.dataset_check_type,chrom:ac.view.chrom,retry:ad};$.getJSON(this.dataset.url(),ae,function(af){if(!af||af==="error"||af.kind==="error"){ac.container_div.addClass("error");var ag=ac.show_message(m);if(af.message){ag.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){Galaxy.modal.show({title:"Trackster Error",body:"<pre>"+af.message+"</pre>",buttons:{Close:function(){Galaxy.modal.hide()}}})}));ag.append($("<span/>").text(" "));ag.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ac.init(true)}))}}else{if(af==="no converter"){ac.container_div.addClass("error");ac.show_message(H)}else{if(af==="no data"||(af.data!==undefined&&(af.data===null||af.data.length===0))){ac.container_div.addClass("nodata");ac.show_message(E)}else{if(af==="pending"){ac.container_div.addClass("pending");ac.show_message(u);setTimeout(function(){ac.init()},ac.data_query_wait)}else{if(af==="data"||af.status==="data"){if(af.valid_chroms){ac.valid_chroms=af.valid_chroms;ac.update_icons()}ac.tiles_div.text(T);if(ac.view.chrom){ac.tiles_div.text("");ac.tiles_div.css("height",ac.visible_height_px+"px");ac.enabled=true;$.when.apply($,ac.predraw_init()).done(function(){ab.resolve();ac.container_div.removeClass("nodata error pending");ac.request_draw()})}else{ab.resolve()}}}}}}});this.update_icons();return ab},predraw_init:function(){var ab=this;return $.getJSON(ab.dataset.url(),{data_type:"data",stats:true,chrom:ab.view.chrom,low:0,high:ab.view.max_high,hda_ldda:ab.dataset.get("hda_ldda")},function(ac){var ae=ac.data;if(ae&&ae.min&&ae.max){var ad=ae.min,af=ae.max;ad=Math.floor(Math.min(0,Math.max(ad,ae.mean-2*ae.sd)));af=Math.ceil(Math.max(0,Math.min(af,ae.mean+2*ae.sd)));ab.config.set_default_value("min_value",ad);ab.config.set_default_value("max_value",af);ab.config.set_value("min_value",ad);ab.config.set_value("max_value",af)}})},get_drawables:function(){return this}});var L=function(ad,ac,af){f.call(this,ad,ac,af);var ab=this;k(ab.container_div,ab.drag_handle_class,".group",ab);this.filters_manager=new h.FiltersManager(this,("filters" in af?af.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=(af.tool?new q(aa.extend(af.tool,{track:this,tool_state:af.tool_state})):null);this.tile_cache=new w.Cache(O);this.left_offset=0;if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){var ae=new Z({model:this.tool});ae.render();this.dynamic_tool_div=ae.$el;this.header_div.after(this.dynamic_tool_div)}}this.tiles_div=$("<div/>").addClass("tiles").appendTo(this.content_div);if(!this.config.get_value("content_visible")){this.tiles_div.hide()}this.overlay_div=$("<div/>").addClass("overlay").appendTo(this.content_div);if(af.mode){this.change_mode(af.mode)}};o(L.prototype,p.prototype,f.prototype,{action_icons_def:f.prototype.action_icons_def.concat([{name:"show_more_rows_icon",title:"To minimize track height, not all feature rows are displayed. Click to display more rows.",css_class:"exclamation",on_click_fn:function(ab){$(".tooltip").remove();ab.slotters[ab.view.resolution_px_b].max_rows*=2;ab.request_draw({clear_tile_cache:true})},hide:true}]),copy:function(ab){var ac=this.to_dict();o(ac,{data_manager:this.data_manager});var ad=new this.constructor(this.view,ab,ac);ad.change_mode(this.mode);ad.enabled=this.enabled;return ad},set_filters_manager:function(ab){this.filters_manager=ab;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),dataset:{id:this.dataset.id,hda_ldda:this.dataset.get("hda_ldda")},prefs:this.config.to_key_value_dict(),mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},set_min_max:function(){var ab=this;return $.getJSON(ab.dataset.url(),{data_type:"data",stats:true,chrom:ab.view.chrom,low:0,high:ab.view.max_high,hda_ldda:ab.dataset.get("hda_ldda")},function(ac){var ae=ac.data;if(isNaN(parseFloat(ab.config.get_value("min_value")))||isNaN(parseFloat(ab.config.get_value("max_value")))){var ad=ae.min,af=ae.max;ad=Math.floor(Math.min(0,Math.max(ad,ae.mean-2*ae.sd)));af=Math.ceil(Math.max(0,Math.min(af,ae.mean+2*ae.sd)));ab.config.set_value("min_value",ad);ab.config.set_value("max_value",af)}})},change_mode:function(ac){var ab=this;ab.mode=ac;ab.config.set_value("mode",ac);if(ac==="Auto"){this.data_manager.clear()}ab.request_draw({clear_tile_cache:true});this.action_icons.mode_icon.attr("title","Set display mode (now: "+ab.mode+")");return ab},update_icons:function(){var ab=this;if(ab.filters_available){ab.action_icons.filters_icon.show()}else{ab.action_icons.filters_icon.hide()}if(ab.tool){ab.action_icons.tools_icon.show();ab.action_icons.param_space_viz_icon.show()}else{ab.action_icons.tools_icon.hide();ab.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ac,ab){return ac+"_"+ab},request_draw:function(ab){if(ab&&ab.clear_tile_cache){this.tile_cache.clear()}this.view.request_redraw(ab,this)},before_draw:function(){this.max_height_px=0},_draw:function(ap){if(!this.can_draw()){return}var am=ap&&ap.clear_after,ak=this.view.low,af=this.view.high,ai=af-ak,ac=this.view.container.width(),ao=this.view.resolution_px_b,ae=1/ao;if(this.is_overview){ak=this.view.max_low;af=this.view.max_high;ao=ac/(view.max_high-view.max_low);ae=1/ao}this.before_draw();this.tiles_div.children().addClass("remove");var ab=Math.floor(ak/(ae*Q)),aj,al,ag,ah=[],an=[];while((ab*Q*ae)<af){aj=Math.floor(ab*Q*ae);al=new w.GenomeRegion({chrom:this.view.chrom,start:aj,end:Math.min(aj+Math.ceil(Q*ae),this.view.max_high)});ag=this.draw_helper(al,ao,ap);ah.push(ag);$.when(ag).then(function(aq){an.push(aq)});ab+=1}if(!am){this.tiles_div.children(".remove").removeClass("remove").remove()}var ad=this;$.when.apply($,ah).then(function(){ad.tiles_div.children(".remove").remove();an=aa.filter(an,function(aq){return aq!==null});if(an.length!==0){ad.postdraw_actions(an,ac,ao,am)}})},_add_yaxis_label:function(ae,ag){var ac=this,af=(ae==="max"?"top":"bottom"),ah=(ae==="max"?"max":"min"),ab=(ae==="max"?"max_value":"min_value"),ad=this.container_div.find(".yaxislabel."+af);ag=ag||function(){ac.request_draw({clear_tile_cache:true})};if(ad.length!==0){ad.text(ac.config.get_value(ab))}else{ad=$("<div/>").text(ac.config.get_value(ab)).make_text_editable({num_cols:12,on_finish:function(ai){$(".tooltip").remove();ac.config.set_param_value(ab,ai);ag()},help_text:"Set "+ah+" value"}).addClass("yaxislabel "+af).css("color",this.config.get_value("label_color"));this.container_div.prepend(ad)}},postdraw_actions:function(ae,af,ah,ab){var ad=aa.filter(ae,function(ai){return(ai instanceof K)});if(ad.length>0){this.max_height_px=0;var ac=this;aa.each(ae,function(ai){if(!(ai instanceof K)){ai.html_elt.remove();ac.draw_helper(ai.region,ah,{force:true,mode:"Coverage"})}});ac._add_yaxis_label("max")}else{this.container_div.find(".yaxislabel").remove();var ag=aa.find(ae,function(ai){return ai.has_icons});if(ag){aa.each(ae,function(ai){if(!ai.has_icons){ai.html_elt.css("padding-top",D)}})}}},get_mode:function(ab){return this.mode},update_auto_mode:function(ab){},_get_drawables:function(){return[this]},draw_helper:function(ak,am,an){if(!an){an={}}var ac=an.force,ah=an.mode||this.mode,ae=1/am,ad=this,af=this._get_drawables(),al=this._gen_tile_cache_key(am,ak),ag=function(ao){return(ao&&"track" in ao)};var ai=(ac?undefined:ad.tile_cache.get_elt(al));if(ai){if(ag(ai)){ad.show_tile(ai,am)}return ai}if(an.data_fetch===false){return null}var aj=function(){var ao=(aa.find(A,function(aq){return aq===ah})?"Coverage":ah);var ap=aa.map(af,function(aq){return aq.data_manager.get_data(ak,ao,ae,ad.data_url_extra_params)});if(view.reference_track){ap.push(view.reference_track.data_manager.get_data(ak,ah,ae,view.reference_track.data_url_extra_params))}return ap};var ab=$.Deferred();ad.tile_cache.set_elt(al,ab);$.when.apply($,aj()).then(function(){var ao=aj(),au=ao,aA;if(aa.find(ao,function(aC){return j.is_deferred(aC)})){ad.tile_cache.set_elt(al,undefined);$.when(ad.draw_helper(ak,am,an)).then(function(aC){ab.resolve(aC)});return}if(view.reference_track){aA=view.reference_track.data_manager.subset_entry(ao.pop(),ak)}var av=[],ar=[];aa.each(af,function(aF,aC){var aE=aF.mode,aD=au[aC];if(aE==="Auto"){aE=aF.get_mode(aD);aF.update_auto_mode(aE)}av.push(aE);ar.push(aF.get_canvas_height(aD,aE,am,ap))});var at=ad.view.canvas_manager.new_canvas(),aw=ak.get("start"),aB=ak.get("end"),aq=0,ap=Math.ceil((aB-aw)*am)+ad.left_offset,ay=aa.max(ar),ax;at.width=ap;at.height=(an.height||ay);var az=at.getContext("2d");az.translate(ad.left_offset,0);if(af.length>1){az.globalAlpha=0.5;az.globalCompositeOperation="source-over"}aa.each(af,function(aD,aC){ax=aD.draw_tile(au[aC],az,av[aC],ak,am,aA)});if(ax!==undefined){ad.tile_cache.set_elt(al,ax);ad.show_tile(ax,am)}ab.resolve(ax)});return ab},get_canvas_height:function(ab,ad,ae,ac){return this.visible_height_px},_draw_line_track_tile:function(ab,ad,ag,af,ah){var ae=ad.canvas,ac=new J.LinePainter(ab.data,af.get("start"),af.get("end"),this.config.to_key_value_dict(),ag);ac.draw(ad,ae.width,ae.height,ah);return new K(this,af,ah,ae,ab.data)},draw_tile:function(ab,ac,af,ae,ag,ad){},show_tile:function(ad,ag){var ac=this,ab=ad.html_elt;ad.predisplay_actions();var af=(ad.low-(this.is_overview?this.view.max_low:this.view.low))*ag;if(this.left_offset){af-=this.left_offset}ab.css("left",af);if(ab.hasClass("remove")){ab.removeClass("remove")}else{this.tiles_div.append(ab)}ab.css("height","auto");this.max_height_px=Math.max(this.max_height_px,ab.height()-2);ab.parent().children().css("height",this.max_height_px+"px");var ae=this.max_height_px;if(this.visible_height_px!==0){ae=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",ae+"px")},tool_region_and_parameters_str:function(ae){var ab=this,ad=(ae!==undefined?ae.toString():"all"),ac=aa.values(ab.tool.get_inputs_dict()).join(", ");return" - region=["+ad+"], parameters=["+ac+"]"},data_and_mode_compatible:function(ab,ac){if(ac==="Auto"){return true}else{if(ac==="Coverage"){return ab.dataset_type==="bigwig"}else{if(ab.dataset_type==="bigwig"||ab.extra_info==="no_detail"){return false}else{return true}}}},can_subset:function(ab){if(ab.message||ab.extra_info==="no_detail"){return false}else{if(ab.dataset_type==="bigwig"){return(ab.data[1][0]-ab.data[0][0]===1)}}return true},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state"}});var V=function(ac,ab){var ad={resize:false};f.call(this,ac,ab,ad);this.container_div.addClass("label-track")};o(V.prototype,f.prototype,{build_header_div:function(){},init:function(){this.enabled=true},predraw_init:function(){},_draw:function(af){var ad=this.view,ae=ad.high-ad.low,ai=Math.floor(Math.pow(10,Math.floor(Math.log(ae)/Math.log(10)))),ab=Math.floor(ad.low/ai)*ai,ag=this.view.container.width(),ac=$("<div/>").addClass("label-container");while(ab<ad.high){var ah=(ab-ad.low)/ae*ag;ac.append($("<div/>").addClass("label").text(commatize(ab)).css({left:ah}));ab+=ai}this.content_div.children(":first").remove();this.content_div.append(ac)}});var e=function(ac,ab,af){L.call(this,ac,ab,af);this.drawables=[];if("drawables" in af){var ae;for(var ad=0;ad<af.drawables.length;ad++){ae=af.drawables[ad];this.drawables[ad]=n(ae,ac,null);if(ae.left_offset>this.left_offset){this.left_offset=ae.left_offset}}this.enabled=true}aa.each(this.drawables,function(ag){if(ag instanceof c||ag instanceof S){ag.change_mode("Coverage")}});this.update_icons();this.obj_type="CompositeTrack"};o(e.prototype,L.prototype,{display_modes:A,action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ab){$(".tooltip").remove();ab.show_group()}}].concat(L.prototype.action_icons_def),to_dict:y.prototype.to_dict,add_drawable:y.prototype.add_drawable,unpack_drawables:y.prototype.unpack_drawables,change_mode:function(ab){L.prototype.change_mode.call(this,ab);for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].change_mode(ab)}},init:function(){var ad=[];for(var ac=0;ac<this.drawables.length;ac++){ad.push(this.drawables[ac].init())}var ab=this;$.when.apply($,ad).then(function(){ab.enabled=true;ab.request_draw()})},update_icons:function(){this.action_icons.filters_icon.hide();this.action_icons.tools_icon.hide();this.action_icons.param_space_viz_icon.hide()},can_draw:p.prototype.can_draw,_get_drawables:function(){return this.drawables},show_group:function(){var ae=new N(this.view,this.container,{name:this.config.get_value("name")}),ab;for(var ad=0;ad<this.drawables.length;ad++){ab=this.drawables[ad];ab.update_icons();ae.add_drawable(ab);ab.container=ae;ae.content_div.append(ab.container_div)}var ac=this.container.replace_drawable(this,ae,true);ae.request_draw({clear_tile_cache:true})},before_draw:function(){L.prototype.before_draw.call(this);var ac=aa.min(aa.map(this.drawables,function(ad){return ad.config.get_value("min_value")})),ab=aa.max(aa.map(this.drawables,function(ad){return ad.config.get_value("max_value")}));this.config.set_value("min_value",ac);this.config.set_value("max_value",ab);aa.each(this.drawables,function(ad){ad.config.set_value("min_value",ac);ad.config.set_value("max_value",ab)})},update_all_min_max:function(){var ac=this,ab=this.config.get_value("min_value"),ad=this.config.get_value("max_value");aa.each(this.drawables,function(ae){ae.config.set_value("min_value",ab);ae.config.set_value("max_value",ad)});this.request_draw({clear_tile_cache:true})},postdraw_actions:function(ah,ab,ak,ag){L.prototype.postdraw_actions.call(this,ah,ab,ak,ag);var af=-1,ad;for(ad=0;ad<ah.length;ad++){var ai=ah[ad].html_elt.find("canvas").height();if(ai>af){af=ai}}for(ad=0;ad<ah.length;ad++){var ae=ah[ad];if(ae.html_elt.find("canvas").height()!==af){this.draw_helper(ae.region,ak,{force:true,height:af});ae.html_elt.remove()}}var ac=this,aj=function(){ac.update_all_min_max()};this._add_yaxis_label("min",aj);this._add_yaxis_label("max",aj)}});var B=function(ab){L.call(this,ab,{content_div:ab.top_labeltrack},{resize:false});this.left_offset=ab.canvas_manager.char_width_px;this.container_div.addClass("reference-track");this.data_url=galaxy_config.root+"api/genomes/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new w.GenomeReferenceDataManager({data_url:this.data_url,can_subset:this.can_subset});this.hide_contents()};o(B.prototype,p.prototype,L.prototype,{config_params:aa.union(p.prototype.config_params,[{key:"height",type:"int",default_value:13,hidden:true}]),build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},predraw_init:function(){},can_draw:p.prototype.can_draw,draw_helper:function(ac,ad,ab){if(ad>this.view.canvas_manager.char_width_px){this.tiles_div.show();return L.prototype.draw_helper.call(this,ac,ad,ab)}else{this.tiles_div.hide();return null}},can_subset:function(ab){return true},draw_tile:function(ad,aj,ae,ag,ak){var ac=this.data_manager.subset_entry(ad,ag),ai=ac.data;var ab=aj.canvas;aj.font=aj.canvas.manager.default_font;aj.textAlign="center";for(var af=0,ah=ai.length;af<ah;af++){aj.fillStyle=this.view.get_base_color(ai[af]);aj.fillText(ai[af],Math.floor(af*ak),10)}return new b(this,ag,ak,ab,ac)}});var g=function(ac,ab,ad){this.mode="Histogram";L.call(this,ac,ab,ad)};o(g.prototype,p.prototype,L.prototype,{display_modes:A,config_params:aa.union(p.prototype.config_params,[{key:"color",label:"Color",type:"color"},{key:"min_value",label:"Min Value",type:"float",default_value:undefined},{key:"max_value",label:"Max Value",type:"float",default_value:undefined},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:30,hidden:true}]),config_onchange:function(){this.set_name(this.config.get_value("name"));this.request_draw({clear_tile_cache:true})},before_draw:function(){},draw_tile:function(ab,ac,ae,ad,af){return this._draw_line_track_tile(ab,ac,ae,ad,af)},can_subset:function(ab){return(ab.data[1][0]-ab.data[0][0]===1)},postdraw_actions:function(ac,ad,ae,ab){this._add_yaxis_label("max");this._add_yaxis_label("min")}});var r=function(ac,ab,ad){this.mode="Heatmap";L.call(this,ac,ab,ad)};o(r.prototype,p.prototype,L.prototype,{display_modes:["Heatmap"],config_params:aa.union(p.prototype.config_params,[{key:"pos_color",label:"Positive Color",type:"color",default_value:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"min_value",label:"Min Value",type:"float",default_value:-1},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}]),config_onchange:function(){this.set_name(this.config.get_value("name"));this.request_draw({clear_tile_cache:true})},draw_tile:function(ab,ad,ag,af,ah){var ae=ad.canvas,ac=new J.DiagonalHeatmapPainter(ab.data,af.get("start"),af.get("end"),this.config.to_key_value_dict(),ag);ac.draw(ad,ae.width,ae.height,ah);return new b(this,af,ah,ae,ab.data)}});var c=function(ac,ab,ad){L.call(this,ac,ab,ad);this.container_div.addClass("feature-track");this.summary_draw_height=30;this.slotters={};this.start_end_dct={};this.left_offset=200;this.set_painter_from_config()};o(c.prototype,p.prototype,L.prototype,{display_modes:["Auto","Coverage","Dense","Squish","Pack"],config_params:aa.union(p.prototype.config_params,[{key:"block_color",label:"Block color",type:"color"},{key:"reverse_strand_color",label:"Antisense strand color",type:"color"},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true,help:"Show the number of items in each bin when drawing summary histogram"},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:0,hidden:true}]),config_onchange:function(){this.set_name(this.config.get_value("name"));this.set_painter_from_config();this.request_draw({clear_tile_cache:true})},set_painter_from_config:function(){if(this.config.get_value("connector_style")==="arcs"){this.painter=J.ArcLinkedFeaturePainter}else{this.painter=J.LinkedFeaturePainter}},postdraw_actions:function(al,ad,am,ak){L.prototype.postdraw_actions.call(this,al,ad,am,ak);var af=this,ag;if(af.filters_manager){var ae=af.filters_manager.filters,ai;for(ai=0;ai<ae.length;ai++){ae[ai].update_ui_elt()}var ah=false,aj,ac;for(ag=0;ag<al.length;ag++){if(al[ag].data.length){aj=al[ag].data[0];for(ai=0;ai<ae.length;ai++){ac=ae[ai];if(ac.applies_to(aj)&&ac.min!==ac.max){ah=true;break}}}}if(af.filters_available!==ah){af.filters_available=ah;if(!af.filters_available){af.filters_manager.hide()}af.update_icons()}}if(al[0] instanceof M){var ab=true;for(ag=0;ag<al.length;ag++){if(!al[ag].all_slotted){ab=false;break}}if(!ab){this.action_icons.show_more_rows_icon.show()}else{this.action_icons.show_more_rows_icon.hide()}}else{this.action_icons.show_more_rows_icon.hide()}},update_auto_mode:function(ab){if(this.mode==="Auto"){if(ab==="no_detail"){ab="feature spans"}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ab+")")}},incremental_slots:function(af,ab,ae){var ac=this.view.canvas_manager.dummy_context,ad=this.slotters[af];if(!ad||(ad.mode!==ae)){ad=new (s.FeatureSlotter)(af,ae,z,function(ag){return ac.measureText(ag)});this.slotters[af]=ad}return ad.slot_features(ab)},get_mode:function(ab){if(ab.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>G){mode="Squish"}else{mode="Pack"}}return mode},get_canvas_height:function(ab,af,ag,ac){if(af==="Coverage"||ab.dataset_type==="bigwig"){return this.summary_draw_height}else{var ae=this.incremental_slots(ag,ab.data,af);var ad=new (this.painter)(null,null,null,this.config.to_key_value_dict(),af);return Math.max(this.min_height_px,ad.get_required_height(ae,ac))}},draw_tile:function(al,ap,an,ae,ai,ad){var ao=this,ac=ap.canvas,aw=ae.get("start"),ab=ae.get("end"),af=this.left_offset;if(al.dataset_type==="bigwig"){return this._draw_line_track_tile(al,ap,an,ae,ai)}var ah=[],am=this.slotters[ai].slots;all_slotted=true;if(al.data){var aj=this.filters_manager.filters;for(var aq=0,at=al.data.length;aq<at;aq++){var ag=al.data[aq];var ar=false;var ak;for(var av=0,aA=aj.length;av<aA;av++){ak=aj[av];ak.update_attrs(ag);if(!ak.keep(ag)){ar=true;break}}if(!ar){ah.push(ag);if(!(ag[0] in am)){all_slotted=false}}}}var az=(this.filters_manager.alpha_filter?new C(this.filters_manager.alpha_filter):null),ax=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null),ay=new (this.painter)(ah,aw,ab,this.config.to_key_value_dict(),an,az,ax,ad,function(aB){return ao.view.get_base_color(aB)});var au=null;ap.fillStyle=this.config.get_value("block_color");ap.font=ap.canvas.manager.default_font;ap.textAlign="right";if(al.data){au=ay.draw(ap,ac.width,ac.height,ai,am);au.translation=-af}return new M(ao,ae,ai,ac,al.data,an,al.message,all_slotted,au)}});var Y=function(ac,ab,ad){L.call(this,ac,ab,ad);this.painter=J.VariantPainter;this.summary_draw_height=30;this.left_offset=30};o(Y.prototype,p.prototype,L.prototype,{display_modes:["Auto","Coverage","Dense","Squish","Pack"],config_params:aa.union(p.prototype.config_params,[{key:"color",label:"Histogram color",type:"color"},{key:"show_sample_data",label:"Show sample data",type:"bool",default_value:true},{key:"show_labels",label:"Show summary and sample labels",type:"bool",default_value:true},{key:"summary_height",label:"Locus summary height",type:"float",default_value:20},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:32,hidden:true}]),config_onchange:function(){this.set_name(this.config.get_value("name"));this.request_draw({clear_tile_cache:true})},draw_tile:function(ab,ae,ag,af,ah){if(ab.dataset_type==="bigwig"){return this._draw_line_track_tile(ab,ae,"Histogram",af,ah)}else{var ad=this.view,ac=new (this.painter)(ab.data,af.get("start"),af.get("end"),this.config.to_key_value_dict(),ag,function(ai){return ad.get_base_color(ai)});ac.draw(ae,ae.canvas.width,ae.canvas.height,ah);return new b(this,af,ah,ae.canvas,ab.data)}},get_canvas_height:function(ab,af,ag,ad){if(ab.dataset_type==="bigwig"){return this.summary_draw_height}else{var ac=(this.dataset.get_metadata("sample_names")?this.dataset.get_metadata("sample_names").length:0);if(ac===0&&ab.data.length!==0){ac=ab.data[0][7].match(/,/g);if(ac===null){ac=1}else{ac=ac.length+1}}var ae=new (this.painter)(null,null,null,this.config.to_key_value_dict(),af);return ae.get_required_height(ac)}},predraw_init:function(){var ab=[f.prototype.predraw_init.call(this)];if(!this.dataset.get_metadata("sample_names")){ab.push(this.dataset.fetch())}return ab},postdraw_actions:function(af,ag,ai,ac){L.prototype.postdraw_actions.call(this,af,ag,ai,ac);var ae=aa.filter(af,function(aj){return(aj instanceof K)});var ad=this.dataset.get_metadata("sample_names");if(ae.length===0&&this.config.get_value("show_labels")&&ad&&ad.length>1){var ab;if(this.container_div.find(".yaxislabel.variant").length===0){ab=this.config.get_value("summary_height")/2;this.tiles_div.prepend($("<div/>").text("Summary").addClass("yaxislabel variant top").css({"font-size":ab+"px",top:(this.config.get_value("summary_height")-ab)/2+"px"}));if(this.config.get_value("show_sample_data")){var ah=ad.join("<br/>");this.tiles_div.prepend($("<div/>").html(ah).addClass("yaxislabel variant top sample").css({top:this.config.get_value("summary_height")}))}}ab=(this.mode==="Squish"?5:10)+"px";$(this.tiles_div).find(".sample").css({"font-size":ab,"line-height":ab});$(this.tiles_div).find(".yaxislabel").css("color",this.config.get_value("label_color"))}else{this.container_div.find(".yaxislabel.variant").remove()}}});var S=function(ac,ab,ad){c.call(this,ac,ab,ad);this.painter=J.ReadPainter;this.update_icons()};o(S.prototype,p.prototype,L.prototype,c.prototype,{config_params:aa.union(p.prototype.config_params,[{key:"block_color",label:"Block and sense strand color",type:"color"},{key:"reverse_strand_color",label:"Antisense strand color",type:"color"},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"height",type:"int",default_value:0,hidden:true}]),config_onchange:function(){this.set_name(this.config.get_value("name"));this.request_draw({clear_tile_cache:true})}});var d={CompositeTrack:e,DrawableGroup:N,DiagonalHeatmapTrack:r,FeatureTrack:c,LineTrack:g,ReadTrack:S,VariantTrack:Y,VcfTrack:Y};var n=function(ad,ac,ab){if("copy" in ad){return ad.copy(ab)}else{var ae=ad.obj_type;if(!ae){ae=ad.track_type}return new d[ae](ac,ab,ad)}};return{TracksterView:X,DrawableGroup:N,LineTrack:g,FeatureTrack:c,DiagonalHeatmapTrack:r,ReadTrack:S,VariantTrack:Y,CompositeTrack:e,object_from_template:n}});
\ No newline at end of file
diff -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 -r 231a61e88777bbf7e2db9ef1fdaa9d7fb757523f static/scripts/packed/viz/trackster/util.js
--- a/static/scripts/packed/viz/trackster/util.js
+++ b/static/scripts/packed/viz/trackster/util.js
@@ -1,1 +1,1 @@
-define(function(){var b=Backbone.Model.extend({defaults:{ajax_settings:{},interval:1000,success_fn:function(c){return true}},go:function(){var f=$.Deferred(),e=this,h=e.get("ajax_settings"),g=e.get("success_fn"),d=e.get("interval"),c=function(){$.ajax(h).success(function(i){if(g(i)){f.resolve(i)}else{setTimeout(c,d)}})};c();return f}});var a=function(c){if(!c){c="#ffffff"}if(typeof(c)==="string"){c=[c]}for(var l=0;l<c.length;l++){c[l]=parseInt(c[l].slice(1),16)}var p=function(v,u,i){return((v*299)+(u*587)+(i*114))/1000};var g=function(x,w,y,u,i,v){return(Math.max(x,u)-Math.min(x,u))+(Math.max(w,i)-Math.min(w,i))+(Math.max(y,v)-Math.min(y,v))};var j,q,h,m,s,k,t,e,f,d,r,o=false,n=0;do{j=Math.round(Math.random()*16777215);q=(j&16711680)>>16;h=(j&65280)>>8;m=j&255;f=p(q,h,m);o=true;for(l=0;l<c.length;l++){s=c[l];k=(s&16711680)>>16;t=(s&65280)>>8;e=s&255;d=p(k,t,e);r=g(q,h,m,k,t,e);if((Math.abs(f-d)<40)||(r<200)){o=false;break}}n++}while(!o&&n<=10);return"#"+(16777216+j).toString(16).substr(1,6)};return{ServerStateDeferred:b,get_random_color:a}});
\ No newline at end of file
+define(function(){var b=function(e){return("promise" in e)};var c=Backbone.Model.extend({defaults:{ajax_settings:{},interval:1000,success_fn:function(d){return true}},go:function(){var g=$.Deferred(),f=this,i=f.get("ajax_settings"),h=f.get("success_fn"),e=f.get("interval"),d=function(){$.ajax(i).success(function(j){if(h(j)){g.resolve(j)}else{setTimeout(d,e)}})};d();return g}});var a=function(d){if(!d){d="#ffffff"}if(typeof(d)==="string"){d=[d]}for(var m=0;m<d.length;m++){d[m]=parseInt(d[m].slice(1),16)}var q=function(w,v,i){return((w*299)+(v*587)+(i*114))/1000};var h=function(y,x,z,v,i,w){return(Math.max(y,v)-Math.min(y,v))+(Math.max(x,i)-Math.min(x,i))+(Math.max(z,w)-Math.min(z,w))};var k,r,j,n,t,l,u,f,g,e,s,p=false,o=0;do{k=Math.round(Math.random()*16777215);r=(k&16711680)>>16;j=(k&65280)>>8;n=k&255;g=q(r,j,n);p=true;for(m=0;m<d.length;m++){t=d[m];l=(t&16711680)>>16;u=(t&65280)>>8;f=t&255;e=q(l,u,f);s=h(r,j,n,l,u,f);if((Math.abs(g-e)<40)||(s<200)){p=false;break}}o++}while(!p&&o<=10);return"#"+(16777216+k).toString(16).substr(1,6)};return{is_deferred:b,ServerStateDeferred:c,get_random_color:a}});
\ No newline at end of file
diff -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 -r 231a61e88777bbf7e2db9ef1fdaa9d7fb757523f static/scripts/packed/viz/visualization.js
--- a/static/scripts/packed/viz/visualization.js
+++ b/static/scripts/packed/viz/visualization.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","mvc/data","viz/trackster/util","utils/config"],function(u,k,n,q){var f={toJSON:function(){var w=this,x={};u.each(w.constructor.to_json_keys,function(y){var z=w.get(y);if(y in w.constructor.to_json_mappers){z=w.constructor.to_json_mappers[y](z,w)}x[y]=z});return x}};var a=function(w,z,y,x){$.ajax({url:w,data:y,error:function(){alert("Grid failed")},success:function(A){Galaxy.modal.show({title:"Select datasets for new tracks",body:A,buttons:{Cancel:function(){Galaxy.modal.hide()},Add:function(){var B=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var C={data_type:"track_config",hda_ldda:"hda"},D=$(this).val();if($(this).attr("name")!=="id"){C.hda_ldda="ldda"}B[B.length]=$.ajax({url:z+"/"+D,data:C,dataType:"json"})});$.when.apply($,B).then(function(){var C=(arguments[0] instanceof Array?$.map(arguments,function(D){return D[0]}):[arguments[0]]);x(C)});Galaxy.modal.hide()}}})}})};var l=function(w){return("promise" in w)};var g=function(w){this.default_font=w!==undefined?w:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};u.extend(g.prototype,{load_pattern:function(w,A){var x=this.patterns,y=this.dummy_context,z=new Image();z.src=galaxy_config.root+"static/images"+A;z.onload=function(){x[w]=y.createPattern(z,"repeat")}},get_pattern:function(w){return this.patterns[w]},new_canvas:function(){var w=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(w)}w.manager=this;return w}});var s=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(w){this.clear()},get_elt:function(y){var z=this.attributes.obj_cache,A=this.attributes.key_ary,x=y.toString(),w=u.indexOf(A,function(B){return B.toString()===x});if(w!==-1){if(z[x].stale){A.splice(w,1);delete z[x]}else{this.move_key_to_end(y,w)}}return z[x]},set_elt:function(y,A){var B=this.attributes.obj_cache,C=this.attributes.key_ary,x=y.toString(),z=this.attributes.num_elements;if(!B[x]){if(C.length>=z){var w=C.shift();delete B[w.toString()]}C.push(y)}B[x]=A;return A},move_key_to_end:function(x,w){this.attributes.key_ary.splice(w,1);this.attributes.key_ary.push(x)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length},most_recently_added:function(){return this.size()===0?null:this.attributes.key_ary[this.attributes.key_ary.length-1]}});var d=s.extend({defaults:u.extend({},s.prototype.defaults,{dataset:null,genome:null,init_data:null,min_region_size:200,filters_manager:null,data_type:"data",data_mode_compatible:function(w,x){return true},can_subset:function(w){return false}}),initialize:function(w){s.prototype.initialize.call(this);var x=this.get("init_data");if(x){this.add_data(x)}},add_data:function(w){if(this.get("num_elements")<w.length){this.set("num_elements",w.length)}var x=this;u.each(w,function(y){x.set_data(y.region,y)})},data_is_ready:function(){var z=this.get("dataset"),y=$.Deferred(),w=(this.get("data_type")==="raw_data"?"state":this.get("data_type")==="data"?"converted_datasets_state":"error"),x=new n.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:z.get("hda_ldda"),data_type:w},dataType:"json"},interval:5000,success_fn:function(A){return A!=="pending"}});$.when(x.go()).then(function(A){y.resolve(A==="ok"||A==="data")});return y},search_features:function(w){var x=this.get("dataset"),y={query:w,hda_ldda:x.get("hda_ldda"),data_type:"features"};return $.getJSON(x.url(),y)},load_data:function(E,D,x,C){var A=this.get("dataset"),z={data_type:this.get("data_type"),chrom:E.get("chrom"),low:E.get("start"),high:E.get("end"),mode:D,resolution:x,hda_ldda:A.get("hda_ldda")};$.extend(z,C);var G=this.get("filters_manager");if(G){var H=[];var w=G.filters;for(var B=0;B<w.length;B++){H.push(w[B].name)}z.filter_cols=JSON.stringify(H)}var y=this,F=$.getJSON(A.url(),z,function(I){I.region=E;y.set_data(E,I)});this.set_data(E,F);return F},get_data:function(D,C,y,A){var E=this.get_elt(D);if(E&&(l(E)||this.get("data_mode_compatible")(E,C))){return E}var F=this.get("key_ary"),w=this.get("obj_cache"),x,B;for(var z=0;z<F.length;z++){x=F[z];if(x.contains(D)){B=true;E=w[x.toString()];if(l(E)||(this.get("data_mode_compatible")(E,C)&&this.get("can_subset")(E))){this.move_key_to_end(x,z);if(!l(E)){var H=this.subset_entry(E,D);this.set(D,H);E=H}return E}}}if(!B&&D.length()<this.attributes.min_region_size){D=D.copy();var G=this.most_recently_added();if(!G||(D.get("start")>G.get("start"))){D.set("end",D.get("start")+this.attributes.min_region_size)}else{D.set("start",D.get("end")-this.attributes.min_region_size)}D.set("genome",this.attributes.genome);D.trim()}return this.load_data(D,C,y,A)},set_data:function(x,w){this.set_elt(x,w)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(E,D,z,C,A){var G=this._mark_stale(E);if(!(G&&this.get("data_mode_compatible")(G,D))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var y=E.get("start");if(A===this.DEEP_DATA_REQ){$.extend(C,{start_val:G.data.length+1})}else{if(A===this.BROAD_DATA_REQ){y=(G.max_high?G.max_high:G.data[G.data.length-1][2])+1}}var F=E.copy().set("start",y);var x=this,B=this.load_data(F,D,z,C),w=$.Deferred();this.set_data(E,w);$.when(B).then(function(H){if(H.data){H.data=G.data.concat(H.data);if(H.max_low){H.max_low=G.max_low}if(H.message){H.message=H.message.replace(/[0-9]+/,H.data.length)}}x.set_data(E,H);w.resolve(H)});return w},can_get_more_detailed_data:function(x){var w=this.get_elt(x);return(w.dataset_type==="bigwig"&&w.data.length<8000)},get_more_detailed_data:function(z,B,x,A,y){var w=this._mark_stale(z);if(!w){console.log("ERROR getting more detailed data: no current data");return}if(!y){y={}}if(w.dataset_type==="bigwig"){y.num_samples=1000*A}return this.load_data(z,B,x,y)},_mark_stale:function(x){var w=this.get_elt(x);if(!w){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),x.toString())}w.stale=true;return w},get_genome_wide_data:function(w){var y=this,A=true,z=u.map(w.get("chroms_info").chrom_info,function(C){var B=y.get_elt(new h({chrom:C.chrom,start:0,end:C.len}));if(!B){A=false}return B});if(A){return z}var x=$.Deferred();$.getJSON(this.get("dataset").url(),{data_type:"genome_data"},function(B){y.add_data(B.data);x.resolve(B.data)});return x},subset_entry:function(y,z){var w={bigwig:function(A,B){return u.filter(A,function(C){return C[0]>=B.get("start")&&C[0]<=B.get("end")})},refseq:function(B,C){var D=C.get("start")-y.region.get("start"),A=y.data.length-(y.region.get("end")-C.get("end"));return y.data.slice(D,A)}};var x=y.data;if(!y.region.same(z)&&y.dataset_type in w){x=w[y.dataset_type](y.data,z)}return{region:z,data:x,dataset_type:y.dataset_type}}});var r=d.extend({initialize:function(w){var x=new Backbone.Model();x.urlRoot=w.data_url;this.set("dataset",x)},load_data:function(y,z,w,x){return(y.length()<=100000?d.prototype.load_data.call(this,y,z,w,x):{data:null,region:y})}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(w){this.id=w.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(w){var x=u.find(this.get_chroms_info(),function(y){return y.chrom===w});return new h({chrom:x.chrom,end:x.len})},get_chrom_len:function(w){return u.find(this.get_chroms_info(),function(x){return x.chrom===w}).len}});var h=Backbone.Model.extend({defaults:{chrom:null,start:0,end:0,str_val:null,genome:null},same:function(w){return this.attributes.chrom===w.get("chrom")&&this.attributes.start===w.get("start")&&this.attributes.end===w.get("end")},initialize:function(x){if(x.from_str){var z=x.from_str.split(":"),y=z[0],w=z[1].split("-");this.set({chrom:y,start:parseInt(w[0],10),end:parseInt(w[1],10)})}this.attributes.str_val=this.get("chrom")+":"+this.get("start")+"-"+this.get("end");this.on("change",function(){this.attributes.str_val=this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},this)},copy:function(){return new h({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.attributes.str_val},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(D){var x=this.get("chrom"),C=D.get("chrom"),B=this.get("start"),z=D.get("start"),A=this.get("end"),y=D.get("end"),w;if(x&&C&&x!==C){return h.overlap_results.DIF_CHROMS}if(B<z){if(A<z){w=h.overlap_results.BEFORE}else{if(A<y){w=h.overlap_results.OVERLAP_START}else{w=h.overlap_results.CONTAINS}}}else{if(B>z){if(B>y){w=h.overlap_results.AFTER}else{if(A<=y){w=h.overlap_results.CONTAINED_BY}else{w=h.overlap_results.OVERLAP_END}}}else{w=(A>=y?h.overlap_results.CONTAINS:h.overlap_results.CONTAINED_BY)}}return w},trim:function(w){if(this.attributes.start<0){this.attributes.start=0}if(this.attributes.genome){var x=this.attributes.genome.get_chrom_len(this.attributes.chrom);if(this.attributes.end>x){this.attributes.end=x-1}}return this},contains:function(w){return this.compute_overlap(w)===h.overlap_results.CONTAINS},overlaps:function(w){return u.intersection([this.compute_overlap(w)],[h.overlap_results.DIF_CHROMS,h.overlap_results.BEFORE,h.overlap_results.AFTER]).length===0}},{overlap_results:{DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006}});var o=Backbone.Collection.extend({model:h});var e=Backbone.Model.extend({defaults:{region:null,note:""},initialize:function(w){this.set("region",new h(w.region))}});var t=Backbone.Collection.extend({model:e});var v=Backbone.Model.extend(f).extend({defaults:{mode:"Auto"},initialize:function(w){this.set("dataset",new k.Dataset(w.dataset));this.set("config",q.ConfigSettingCollection.from_config_dict(w.prefs));this.get("config").add([{key:"name",value:this.get("dataset").get("name")},{key:"color"}]);var x=this.get("preloaded_data");if(x){x=x.data}else{x=[]}this.set("data_manager",new d({dataset:this.get("dataset"),init_data:x}))}},{to_json_keys:["track_type","dataset","prefs","mode","filters","tool_state"],to_json_mappers:{prefs:function(x,w){if(u.size(x)===0){x={name:w.get("config").get("name").get("value"),color:w.get("config").get("color").get("value")}}return x},dataset:function(w){return{id:w.id,hda_ldda:w.get("hda_ldda")}}}});var j=Backbone.Collection.extend({model:v});var p=Backbone.Model.extend({defaults:{title:"",type:""},url:galaxy_config.root+"visualization/save",save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var m=p.extend(f).extend({defaults:u.extend({},p.prototype.defaults,{dbkey:"",drawables:null,bookmarks:null,viewport:null}),initialize:function(w){this.set("drawables",new j(w.tracks));this.set("config",q.ConfigSettingCollection.from_config_dict(w.prefs||{}));this.unset("tracks");this.get("drawables").each(function(x){x.unset("preloaded_data")})},add_tracks:function(w){this.get("drawables").add(w)}},{to_json_keys:["view","viewport","bookmarks"],to_json_mappers:{view:function(x,w){return{obj_type:"View",prefs:{name:w.get("title"),content_visible:true},drawables:w.get("drawables")}}}});var b=Backbone.Model.extend({});var i=Backbone.Router.extend({initialize:function(x){this.view=x.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var w=this;w.view.on("navigate",function(y){w.navigate(y)})},change_location:function(w){this.view.go_to(w)}});return{BackboneTrack:v,BrowserBookmark:e,BrowserBookmarkCollection:t,Cache:s,CanvasManager:g,Genome:c,GenomeDataManager:d,GenomeRegion:h,GenomeRegionCollection:o,GenomeVisualization:m,GenomeReferenceDataManager:r,TrackBrowserRouter:i,TrackConfig:b,Visualization:p,select_datasets:a}});
\ No newline at end of file
+define(["libs/underscore","mvc/data","viz/trackster/util","utils/config"],function(t,k,m,p){var f={toJSON:function(){var v=this,w={};t.each(v.constructor.to_json_keys,function(x){var y=v.get(x);if(x in v.constructor.to_json_mappers){y=v.constructor.to_json_mappers[x](y,v)}w[x]=y});return w}};var a=function(v,y,x,w){$.ajax({url:v,data:x,error:function(){alert("Grid failed")},success:function(z){Galaxy.modal.show({title:"Select datasets for new tracks",body:z,buttons:{Cancel:function(){Galaxy.modal.hide()},Add:function(){var A=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var B={data_type:"track_config",hda_ldda:"hda"},C=$(this).val();if($(this).attr("name")!=="id"){B.hda_ldda="ldda"}A[A.length]=$.ajax({url:y+"/"+C,data:B,dataType:"json"})});$.when.apply($,A).then(function(){var B=(arguments[0] instanceof Array?$.map(arguments,function(C){return C[0]}):[arguments[0]]);w(B)});Galaxy.modal.hide()}}})}})};var g=function(v){this.default_font=v!==undefined?v:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};t.extend(g.prototype,{load_pattern:function(v,z){var w=this.patterns,x=this.dummy_context,y=new Image();y.src=galaxy_config.root+"static/images"+z;y.onload=function(){w[v]=x.createPattern(y,"repeat")}},get_pattern:function(v){return this.patterns[v]},new_canvas:function(){var v=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(v)}v.manager=this;return v}});var r=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(v){this.clear()},get_elt:function(x){var y=this.attributes.obj_cache,z=this.attributes.key_ary,w=x.toString(),v=t.indexOf(z,function(A){return A.toString()===w});if(v!==-1){if(y[w].stale){z.splice(v,1);delete y[w]}else{this.move_key_to_end(x,v)}}return y[w]},set_elt:function(x,z){var A=this.attributes.obj_cache,B=this.attributes.key_ary,w=x.toString(),y=this.attributes.num_elements;if(!A[w]){if(B.length>=y){var v=B.shift();delete A[v.toString()]}B.push(x)}A[w]=z;return z},move_key_to_end:function(w,v){this.attributes.key_ary.splice(v,1);this.attributes.key_ary.push(w)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length},most_recently_added:function(){return this.size()===0?null:this.attributes.key_ary[this.attributes.key_ary.length-1]}});var d=r.extend({defaults:t.extend({},r.prototype.defaults,{dataset:null,genome:null,init_data:null,min_region_size:200,filters_manager:null,data_type:"data",data_mode_compatible:function(v,w){return true},can_subset:function(v){return false}}),initialize:function(v){r.prototype.initialize.call(this);var w=this.get("init_data");if(w){this.add_data(w)}},add_data:function(v){if(this.get("num_elements")<v.length){this.set("num_elements",v.length)}var w=this;t.each(v,function(x){w.set_data(x.region,x)})},data_is_ready:function(){var y=this.get("dataset"),x=$.Deferred(),v=(this.get("data_type")==="raw_data"?"state":this.get("data_type")==="data"?"converted_datasets_state":"error"),w=new m.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:y.get("hda_ldda"),data_type:v},dataType:"json"},interval:5000,success_fn:function(z){return z!=="pending"}});$.when(w.go()).then(function(z){x.resolve(z==="ok"||z==="data")});return x},search_features:function(v){var w=this.get("dataset"),x={query:v,hda_ldda:w.get("hda_ldda"),data_type:"features"};return $.getJSON(w.url(),x)},load_data:function(D,C,w,B){var z=this.get("dataset"),y={data_type:this.get("data_type"),chrom:D.get("chrom"),low:D.get("start"),high:D.get("end"),mode:C,resolution:w,hda_ldda:z.get("hda_ldda")};$.extend(y,B);var F=this.get("filters_manager");if(F){var G=[];var v=F.filters;for(var A=0;A<v.length;A++){G.push(v[A].name)}y.filter_cols=JSON.stringify(G)}var x=this,E=$.getJSON(z.url(),y,function(H){H.region=D;x.set_data(D,H)});this.set_data(D,E);return E},get_data:function(C,B,x,z){var D=this.get_elt(C);if(D&&(m.is_deferred(D)||this.get("data_mode_compatible")(D,B))){return D}var E=this.get("key_ary"),v=this.get("obj_cache"),w,A;for(var y=0;y<E.length;y++){w=E[y];if(w.contains(C)){A=true;D=v[w.toString()];if(m.is_deferred(D)||(this.get("data_mode_compatible")(D,B)&&this.get("can_subset")(D))){this.move_key_to_end(w,y);if(!m.is_deferred(D)){var G=this.subset_entry(D,C);this.set(C,G);D=G}return D}}}if(!A&&C.length()<this.attributes.min_region_size){C=C.copy();var F=this.most_recently_added();if(!F||(C.get("start")>F.get("start"))){C.set("end",C.get("start")+this.attributes.min_region_size)}else{C.set("start",C.get("end")-this.attributes.min_region_size)}C.set("genome",this.attributes.genome);C.trim()}return this.load_data(C,B,x,z)},set_data:function(w,v){this.set_elt(w,v)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(D,C,y,B,z){var F=this._mark_stale(D);if(!(F&&this.get("data_mode_compatible")(F,C))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var x=D.get("start");if(z===this.DEEP_DATA_REQ){$.extend(B,{start_val:F.data.length+1})}else{if(z===this.BROAD_DATA_REQ){x=(F.max_high?F.max_high:F.data[F.data.length-1][2])+1}}var E=D.copy().set("start",x);var w=this,A=this.load_data(E,C,y,B),v=$.Deferred();this.set_data(D,v);$.when(A).then(function(G){if(G.data){G.data=F.data.concat(G.data);if(G.max_low){G.max_low=F.max_low}if(G.message){G.message=G.message.replace(/[0-9]+/,G.data.length)}}w.set_data(D,G);v.resolve(G)});return v},can_get_more_detailed_data:function(w){var v=this.get_elt(w);return(v.dataset_type==="bigwig"&&v.data.length<8000)},get_more_detailed_data:function(y,A,w,z,x){var v=this._mark_stale(y);if(!v){console.log("ERROR getting more detailed data: no current data");return}if(!x){x={}}if(v.dataset_type==="bigwig"){x.num_samples=1000*z}return this.load_data(y,A,w,x)},_mark_stale:function(w){var v=this.get_elt(w);if(!v){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),w.toString())}v.stale=true;return v},get_genome_wide_data:function(v){var x=this,z=true,y=t.map(v.get("chroms_info").chrom_info,function(B){var A=x.get_elt(new h({chrom:B.chrom,start:0,end:B.len}));if(!A){z=false}return A});if(z){return y}var w=$.Deferred();$.getJSON(this.get("dataset").url(),{data_type:"genome_data"},function(A){x.add_data(A.data);w.resolve(A.data)});return w},subset_entry:function(x,y){var v={bigwig:function(z,A){return t.filter(z,function(B){return B[0]>=A.get("start")&&B[0]<=A.get("end")})},refseq:function(A,B){var C=B.get("start")-x.region.get("start"),z=x.data.length-(x.region.get("end")-B.get("end"));return x.data.slice(C,z)}};var w=x.data;if(!x.region.same(y)&&x.dataset_type in v){w=v[x.dataset_type](x.data,y)}return{region:y,data:w,dataset_type:x.dataset_type}}});var q=d.extend({initialize:function(v){var w=new Backbone.Model();w.urlRoot=v.data_url;this.set("dataset",w)},load_data:function(x,y,v,w){return(x.length()<=100000?d.prototype.load_data.call(this,x,y,v,w):{data:null,region:x})}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(v){this.id=v.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(v){var w=t.find(this.get_chroms_info(),function(x){return x.chrom===v});return new h({chrom:w.chrom,end:w.len})},get_chrom_len:function(v){return t.find(this.get_chroms_info(),function(w){return w.chrom===v}).len}});var h=Backbone.Model.extend({defaults:{chrom:null,start:0,end:0,str_val:null,genome:null},same:function(v){return this.attributes.chrom===v.get("chrom")&&this.attributes.start===v.get("start")&&this.attributes.end===v.get("end")},initialize:function(w){if(w.from_str){var y=w.from_str.split(":"),x=y[0],v=y[1].split("-");this.set({chrom:x,start:parseInt(v[0],10),end:parseInt(v[1],10)})}this.attributes.str_val=this.get("chrom")+":"+this.get("start")+"-"+this.get("end");this.on("change",function(){this.attributes.str_val=this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},this)},copy:function(){return new h({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.attributes.str_val},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(C){var w=this.get("chrom"),B=C.get("chrom"),A=this.get("start"),y=C.get("start"),z=this.get("end"),x=C.get("end"),v;if(w&&B&&w!==B){return h.overlap_results.DIF_CHROMS}if(A<y){if(z<y){v=h.overlap_results.BEFORE}else{if(z<x){v=h.overlap_results.OVERLAP_START}else{v=h.overlap_results.CONTAINS}}}else{if(A>y){if(A>x){v=h.overlap_results.AFTER}else{if(z<=x){v=h.overlap_results.CONTAINED_BY}else{v=h.overlap_results.OVERLAP_END}}}else{v=(z>=x?h.overlap_results.CONTAINS:h.overlap_results.CONTAINED_BY)}}return v},trim:function(v){if(this.attributes.start<0){this.attributes.start=0}if(this.attributes.genome){var w=this.attributes.genome.get_chrom_len(this.attributes.chrom);if(this.attributes.end>w){this.attributes.end=w-1}}return this},contains:function(v){return this.compute_overlap(v)===h.overlap_results.CONTAINS},overlaps:function(v){return t.intersection([this.compute_overlap(v)],[h.overlap_results.DIF_CHROMS,h.overlap_results.BEFORE,h.overlap_results.AFTER]).length===0}},{overlap_results:{DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006}});var n=Backbone.Collection.extend({model:h});var e=Backbone.Model.extend({defaults:{region:null,note:""},initialize:function(v){this.set("region",new h(v.region))}});var s=Backbone.Collection.extend({model:e});var u=Backbone.Model.extend(f).extend({defaults:{mode:"Auto"},initialize:function(v){this.set("dataset",new k.Dataset(v.dataset));this.set("config",p.ConfigSettingCollection.from_config_dict(v.prefs));this.get("config").add([{key:"name",value:this.get("dataset").get("name")},{key:"color"}]);var w=this.get("preloaded_data");if(w){w=w.data}else{w=[]}this.set("data_manager",new d({dataset:this.get("dataset"),init_data:w}))}},{to_json_keys:["track_type","dataset","prefs","mode","filters","tool_state"],to_json_mappers:{prefs:function(w,v){if(t.size(w)===0){w={name:v.get("config").get("name").get("value"),color:v.get("config").get("color").get("value")}}return w},dataset:function(v){return{id:v.id,hda_ldda:v.get("hda_ldda")}}}});var j=Backbone.Collection.extend({model:u});var o=Backbone.Model.extend({defaults:{title:"",type:""},url:galaxy_config.root+"visualization/save",save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var l=o.extend(f).extend({defaults:t.extend({},o.prototype.defaults,{dbkey:"",drawables:null,bookmarks:null,viewport:null}),initialize:function(v){this.set("drawables",new j(v.tracks));this.set("config",p.ConfigSettingCollection.from_config_dict(v.prefs||{}));this.unset("tracks");this.get("drawables").each(function(w){w.unset("preloaded_data")})},add_tracks:function(v){this.get("drawables").add(v)}},{to_json_keys:["view","viewport","bookmarks"],to_json_mappers:{view:function(w,v){return{obj_type:"View",prefs:{name:v.get("title"),content_visible:true},drawables:v.get("drawables")}}}});var b=Backbone.Model.extend({});var i=Backbone.Router.extend({initialize:function(w){this.view=w.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var v=this;v.view.on("navigate",function(x){v.navigate(x)})},change_location:function(v){this.view.go_to(v)}});return{BackboneTrack:u,BrowserBookmark:e,BrowserBookmarkCollection:s,Cache:r,CanvasManager:g,Genome:c,GenomeDataManager:d,GenomeRegion:h,GenomeRegionCollection:n,GenomeVisualization:l,GenomeReferenceDataManager:q,TrackBrowserRouter:i,TrackConfig:b,Visualization:o,select_datasets:a}});
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
6 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9e7f9282deba/
Changeset: 9e7f9282deba
User: Jeremy Goecks
Date: 2014-03-26 18:42:54
Summary: Trackster: consolidate read painters.
Affected #: 2 files
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 9e7f9282deba9d383e708e210acea5dea8eb7673 static/scripts/viz/trackster/painters.js
--- a/static/scripts/viz/trackster/painters.js
+++ b/static/scripts/viz/trackster/painters.js
@@ -736,297 +736,6 @@
};
},
- // FIXME: extract common functionality from draw_read functions for ReadPainters.
-
- /**
- * Draw a single read.
- */
- draw_read: function(ctx, mode, w_scale, y_start, tile_low, tile_high, feature_start, cigar, strand, read_seq) {
- ctx.textAlign = "center";
- var tile_region = [tile_low, tile_high],
- base_offset = 0,
- seq_offset = 0,
- gap = Math.round(w_scale/2),
- char_width_px = ctx.canvas.manager.char_width_px,
- block_color = (strand === "+" ? this.prefs.block_color : this.prefs.reverse_strand_color),
- pack_mode = (mode === 'Pack'),
- paint_utils = new ReadPainterUtils(ctx, (pack_mode ? PACK_FEATURE_HEIGHT : SQUISH_FEATURE_HEIGHT), w_scale, mode);
-
- // Keep list of items that need to be drawn on top of initial drawing layer.
- var draw_last = [];
-
- // If no cigar string, then assume all matches.
- if (!cigar) {
- cigar = [ [0, read_seq.length] ];
- }
-
- // Draw read by processing cigar.
- for (var cig_id = 0, len = cigar.length; cig_id < len; cig_id++) {
- var cig = cigar[cig_id],
- cig_op = "MIDNSHP=X"[ cig[0] ],
- cig_len = cig[1];
-
- var seq_start = feature_start + base_offset,
- // -0.5 to offset sequence between bases.
- s_start = Math.floor( Math.max(-0.5 * w_scale, (seq_start - tile_low - 0.5) * w_scale) ),
- s_end = Math.floor( Math.max(0, (seq_start + cig_len - tile_low - 0.5) * w_scale) );
-
- if (!is_overlap([seq_start, seq_start + cig_len], tile_region)) {
- // Increment base offset only for certain operations.
- if ("MDN=X".indexOf(cig_op) !== -1) {
- base_offset += cig_len;
- }
- continue;
- }
-
- // Make sure that read is drawn even if it too small to be rendered officially; in this case,
- // read is drawn at 1px.
- // TODO: need to ensure that s_start, s_end are calcuated the same for both slotting
- // and drawing.
- if (s_start === s_end) {
- s_end += 1;
- }
-
- switch (cig_op) {
- case "H": // Hard clipping.
- // Sequence not present, so do not increment seq_offset.
- break;
- case "S": // Soft clipping.
- seq_offset += cig_len;
- break;
- case "M": // Loose match with reference; can be match or mismatch.
- case "=": // Strict match with reference.
- case "X": // Strict mismatch with reference.
- // Draw read base as rectangle.
- ctx.fillStyle = block_color;
- ctx.fillRect(s_start,
- y_start + (pack_mode ? 1 : 4 ),
- s_end - s_start,
- (pack_mode ? PACK_FEATURE_HEIGHT : SQUISH_FEATURE_HEIGHT));
-
- // Draw sequence and/or variants.
- var seq = read_seq.slice(seq_offset, seq_offset + cig_len),
- ref_char,
- read_char;
- for (var c = 0, str_len = seq.length; c < str_len; c++) {
- // Draw base if it's on tile:
- if (seq_start + c >= tile_low && seq_start + c <= tile_high) {
- // Get reference and read character.
- ref_char = (this.ref_seq ? this.ref_seq[seq_start - tile_low + c] : null);
- read_char = seq[c];
-
- // Draw base depending on (a) available reference data and (b) config options.
- if (
- // If there's reference data and (a) showing all (i.e. not showing
- // differences) or (b) if there is a variant.
- (ref_char &&
- (!this.prefs.show_differences ||
- (read_char.toLowerCase !== 'n' && (ref_char.toLowerCase() !== read_char.toLowerCase())))
- ) ||
- // If there's no reference data and showing all.
- (!ref_char && !this.prefs.show_differences)
- ) {
-
- // Draw base.
- var c_start = Math.floor( Math.max(0, (seq_start + c - tile_low) * w_scale) );
- ctx.fillStyle = this.base_color_fn(seq[c]);
- if (pack_mode && w_scale > char_width_px) {
- ctx.fillText(seq[c], c_start, y_start + 9);
- }
- // Require a minimum w_scale so that variants are only drawn when somewhat zoomed in.
- else if (w_scale > 0.05) {
- ctx.fillRect(c_start - gap,
- y_start + (pack_mode ? 1 : 4),
- Math.max( 1, Math.round(w_scale) ),
- (pack_mode ? PACK_FEATURE_HEIGHT : SQUISH_FEATURE_HEIGHT));
- }
- }
-
- }
- }
-
- seq_offset += cig_len;
- base_offset += cig_len;
- break;
- case "N": // Skipped bases.
- ctx.fillStyle = CONNECTOR_COLOR;
- ctx.fillRect(s_start, y_start + 5, s_end - s_start, 1);
- //ctx.dashedLine(s_start + this.left_offset, y_start + 5, this.left_offset + s_end, y_start + 5);
- base_offset += cig_len;
- break;
- case "D": // Deletion.
- paint_utils.draw_deletion(s_start, y_start, 1);
- base_offset += cig_len;
- break;
- case "P": // TODO: No good way to draw insertions/padding right now, so ignore
- // Sequences not present, so do not increment seq_offset.
- break;
- case "I": // Insertion.
- // Check to see if sequence should be drawn at all by looking at the overlap between
- // the sequence region and the tile region.
- var insert_x_coord = s_start - gap;
-
- if (is_overlap([seq_start, seq_start + cig_len], tile_region)) {
- var seq = read_seq.slice(seq_offset, seq_offset + cig_len);
- // Insertion point is between the sequence start and the previous base: (-gap) moves
- // back from sequence start to insertion point.
- if (this.prefs.show_insertions) {
- //
- // Show inserted sequence above, centered on insertion point.
- //
-
- // Draw sequence.
- // X center is offset + start - <half_sequence_length>
- var x_center = s_start - (s_end - s_start)/2;
- if ( (mode === "Pack" || this.mode === "Auto") && read_seq !== undefined && w_scale > char_width_px) {
- // Draw sequence container.
- ctx.fillStyle = "yellow";
- ctx.fillRect(x_center - gap, y_start - 9, s_end - s_start, 9);
- draw_last[draw_last.length] = {type: "triangle", data: [insert_x_coord, y_start + 4, 5]};
- ctx.fillStyle = CONNECTOR_COLOR;
- // Based on overlap b/t sequence and tile, get sequence to be drawn.
- switch( compute_overlap( [seq_start, seq_start + cig_len], tile_region ) ) {
- case(OVERLAP_START):
- seq = seq.slice(tile_low-seq_start);
- break;
- case(OVERLAP_END):
- seq = seq.slice(0, seq_start-tile_high);
- break;
- case(CONTAINED_BY):
- // All of sequence drawn.
- break;
- case(CONTAINS):
- seq = seq.slice(tile_low-seq_start, seq_start-tile_high);
- break;
- }
- // Draw sequence.
- for (var c = 0, str_len = seq.length; c < str_len; c++) {
- var c_start = Math.floor( Math.max(0, (seq_start + c - tile_low) * w_scale) );
- ctx.fillText(seq[c], c_start - (s_end - s_start)/2, y_start);
- }
- }
- else {
- // Draw block.
- ctx.fillStyle = "yellow";
- // TODO: This is a pretty hack-ish way to fill rectangle based on mode.
- ctx.fillRect(x_center, y_start + (this.mode !== "Dense" ? 2 : 5),
- s_end - s_start, (mode !== "Dense" ? SQUISH_FEATURE_HEIGHT : DENSE_FEATURE_HEIGHT));
- }
- }
- else {
- if ( (mode === "Pack" || this.mode === "Auto") && read_seq !== undefined && w_scale > char_width_px) {
- // Show insertions with a single number at the insertion point.
- draw_last.push( { type: "text", data: [seq.length, insert_x_coord, y_start + 9] } );
- }
- else {
- // TODO: probably can merge this case with code above.
- }
- }
- }
- seq_offset += cig_len;
- // No change to base offset because insertions are drawn above sequence/read.
- break;
- }
- }
-
- //
- // Draw last items.
- //
- ctx.fillStyle = "yellow";
- var item, type, data;
- for (var i = 0; i < draw_last.length; i++) {
- item = draw_last[i];
- type = item.type;
- data = item.data;
- if (type === "text") {
- ctx.save();
- ctx.font = "bold " + ctx.font;
- ctx.fillText(data[0], data[1], data[2]);
- ctx.restore();
- }
- else if (type === "triangle") {
- drawDownwardEquilateralTriangle(ctx, data[0], data[1], data[2]);
- }
- }
- },
-
- /**
- * Draw a complete read pair
- */
- draw_element: function(ctx, mode, feature, slot, tile_low, tile_high, w_scale, y_scale, width ) {
- // All features need a start, end, and vertical center.
- var feature_uid = feature[0],
- feature_start = feature[1],
- feature_end = feature[2],
- feature_name = feature[3],
- // -0.5 to put element between bases.
- f_start = Math.floor( Math.max(-0.5 * w_scale, (feature_start - tile_low - 0.5) * w_scale) ),
- f_end = Math.ceil( Math.min(width, Math.max(0, (feature_end - tile_low - 0.5) * w_scale)) ),
- y_start = (mode === "Dense" ? 0 : (0 + slot)) * y_scale,
- label_color = this.prefs.label_color;
-
- // Draw read.
- if (feature[5] instanceof Array) {
- // Read is paired.
- var connector = true;
-
- // Draw left/forward read.
- if (feature[4][1] >= tile_low && feature[4][0] <= tile_high && feature[4][2]) {
- this.draw_read(ctx, mode, w_scale, y_start, tile_low, tile_high, feature[4][0], feature[4][2], feature[4][3], feature[4][4]);
- }
- else {
- connector = false;
- }
-
- // Draw right/reverse read.
- if (feature[5][1] >= tile_low && feature[5][0] <= tile_high && feature[5][2]) {
- this.draw_read(ctx, mode, w_scale, y_start, tile_low, tile_high, feature[5][0], feature[5][2], feature[5][3], feature[5][4]);
- }
- else {
- connector = false;
- }
-
- // Draw connector if both reads were drawn.
- // TODO: currently, there is no way to connect reads drawn on different tiles; to connect reads on different tiles, data manager
- // code is needed to join mate pairs from different regions. Alternatively, requesting multiple regions of data at once would
- // make it possible to put together more easily.
- // -0.5 to position connector correctly between reads.
- var b1_end = Math.ceil( Math.min(width, Math.max(-0.5 * w_scale, (feature[4][1] - tile_low - 0.5) * w_scale)) ),
- b2_start = Math.floor( Math.max(-0.5 * w_scale, (feature[5][0] - tile_low - 0.5) * w_scale) );
- if (connector && b2_start > b1_end) {
- ctx.fillStyle = CONNECTOR_COLOR;
- dashedLine(ctx, b1_end, y_start + 5, b2_start, y_start + 5);
- }
- } else {
- // Read is single.
- this.draw_read(ctx, mode, w_scale, y_start, tile_low, tile_high, feature_start, feature[4], feature[5], feature[6]);
- }
- if (mode === "Pack" && feature_start >= tile_low && feature_name !== ".") {
- // Draw label.
- ctx.fillStyle = this.prefs.label_color;
- if (tile_low === 0 && f_start - ctx.measureText(feature_name).width < 0) {
- ctx.textAlign = "left";
- ctx.fillText(feature_name, f_end + LABEL_SPACING, y_start + 8);
- } else {
- ctx.textAlign = "right";
- ctx.fillText(feature_name, f_start - LABEL_SPACING, y_start + 8);
- }
- }
-
- // FIXME: provide actual coordinates for drawn read.
- return [0,0];
- }
-});
-
-/**
- * Painter for reads encoded using reference-based compression.
- */
-var RefBasedReadPainter = function(data, view_start, view_end, prefs, mode, alpha_scaler, height_scaler, ref_seq, base_color_fn) {
- ReadPainter.call(this, data, view_start, view_end, prefs, mode, alpha_scaler, height_scaler, ref_seq, base_color_fn);
-};
-
-extend(RefBasedReadPainter.prototype, ReadPainter.prototype, FeaturePainter, {
-
/**
* Draw a single read from reference-based read sequence and cigar.
*/
@@ -1255,6 +964,73 @@
drawDownwardEquilateralTriangle(ctx, data[0], data[1], data[2]);
}
}
+ },
+
+ /**
+ * Draw a complete read pair
+ */
+ draw_element: function(ctx, mode, feature, slot, tile_low, tile_high, w_scale, y_scale, width ) {
+ // All features need a start, end, and vertical center.
+ var feature_uid = feature[0],
+ feature_start = feature[1],
+ feature_end = feature[2],
+ feature_name = feature[3],
+ // -0.5 to put element between bases.
+ f_start = Math.floor( Math.max(-0.5 * w_scale, (feature_start - tile_low - 0.5) * w_scale) ),
+ f_end = Math.ceil( Math.min(width, Math.max(0, (feature_end - tile_low - 0.5) * w_scale)) ),
+ y_start = (mode === "Dense" ? 0 : (0 + slot)) * y_scale,
+ label_color = this.prefs.label_color;
+
+ // Draw read.
+ if (feature[5] instanceof Array) {
+ // Read is paired.
+ var connector = true;
+
+ // Draw left/forward read.
+ if (feature[4][1] >= tile_low && feature[4][0] <= tile_high && feature[4][2]) {
+ this.draw_read(ctx, mode, w_scale, y_start, tile_low, tile_high, feature[4][0], feature[4][2], feature[4][3], feature[4][4]);
+ }
+ else {
+ connector = false;
+ }
+
+ // Draw right/reverse read.
+ if (feature[5][1] >= tile_low && feature[5][0] <= tile_high && feature[5][2]) {
+ this.draw_read(ctx, mode, w_scale, y_start, tile_low, tile_high, feature[5][0], feature[5][2], feature[5][3], feature[5][4]);
+ }
+ else {
+ connector = false;
+ }
+
+ // Draw connector if both reads were drawn.
+ // TODO: currently, there is no way to connect reads drawn on different tiles; to connect reads on different tiles, data manager
+ // code is needed to join mate pairs from different regions. Alternatively, requesting multiple regions of data at once would
+ // make it possible to put together more easily.
+ // -0.5 to position connector correctly between reads.
+ var b1_end = Math.ceil( Math.min(width, Math.max(-0.5 * w_scale, (feature[4][1] - tile_low - 0.5) * w_scale)) ),
+ b2_start = Math.floor( Math.max(-0.5 * w_scale, (feature[5][0] - tile_low - 0.5) * w_scale) );
+ if (connector && b2_start > b1_end) {
+ ctx.fillStyle = CONNECTOR_COLOR;
+ dashedLine(ctx, b1_end, y_start + 5, b2_start, y_start + 5);
+ }
+ } else {
+ // Read is single.
+ this.draw_read(ctx, mode, w_scale, y_start, tile_low, tile_high, feature_start, feature[4], feature[5], feature[6]);
+ }
+ if (mode === "Pack" && feature_start >= tile_low && feature_name !== ".") {
+ // Draw label.
+ ctx.fillStyle = this.prefs.label_color;
+ if (tile_low === 0 && f_start - ctx.measureText(feature_name).width < 0) {
+ ctx.textAlign = "left";
+ ctx.fillText(feature_name, f_end + LABEL_SPACING, y_start + 8);
+ } else {
+ ctx.textAlign = "right";
+ ctx.fillText(feature_name, f_start - LABEL_SPACING, y_start + 8);
+ }
+ }
+
+ // FIXME: provide actual coordinates for drawn read.
+ return [0,0];
}
});
@@ -1775,7 +1551,6 @@
LinePainter: LinePainter,
LinkedFeaturePainter: LinkedFeaturePainter,
ReadPainter: ReadPainter,
- RefBasedReadPainter: RefBasedReadPainter,
ArcLinkedFeaturePainter: ArcLinkedFeaturePainter,
DiagonalHeatmapPainter: DiagonalHeatmapPainter,
VariantPainter: VariantPainter
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 9e7f9282deba9d383e708e210acea5dea8eb7673 static/scripts/viz/trackster/tracks.js
--- a/static/scripts/viz/trackster/tracks.js
+++ b/static/scripts/viz/trackster/tracks.js
@@ -4163,8 +4163,7 @@
*/
var ReadTrack = function (view, container, obj_dict) {
FeatureTrack.call(this, view, container, obj_dict);
- // Choose painter based on whether there is reference data.
- this.painter = (view.reference_track ? painters.RefBasedReadPainter : painters.ReadPainter);
+ this.painter = painters.ReadPainter;
this.update_icons();
};
https://bitbucket.org/galaxy/galaxy-central/commits/09676399640d/
Changeset: 09676399640d
User: Jeremy Goecks
Date: 2014-03-26 19:46:29
Summary: Trackster: remove reference to left_offset in painters because it is not needed.
Affected #: 1 file
diff -r 9e7f9282deba9d383e708e210acea5dea8eb7673 -r 09676399640d304d45dfeb81a32ed30d7314d855 static/scripts/viz/trackster/painters.js
--- a/static/scripts/viz/trackster/painters.js
+++ b/static/scripts/viz/trackster/painters.js
@@ -127,9 +127,7 @@
Painter.prototype.default_prefs = {};
/**
- * Draw on the context using a rectangle of width x height. w_scale is
- * needed because it cannot be computed from width and view size alone
- * as a left_offset may be present.
+ * Draw on the context using a rectangle of width x height using scale w_scale.
*/
Painter.prototype.draw = function(ctx, width, height, w_scale) {};
@@ -869,7 +867,6 @@
case "N": // Skipped bases.
ctx.fillStyle = CONNECTOR_COLOR;
ctx.fillRect(s_start, y_start + 5, s_end - s_start, 1);
- //ctx.dashedLine(s_start + this.left_offset, y_start + 5, this.left_offset + s_end, y_start + 5);
// No change in seq_offset because sequence not used when skipping.
base_offset += cig_len;
break;
@@ -1357,9 +1354,7 @@
},
/**
- * Draw on the context using a rectangle of width x height. w_scale is
- * needed because it cannot be computed from width and view size alone
- * as a left_offset may be present.
+ * Draw on the context using a rectangle of width x height with scale w_scale.
*/
draw: function(ctx, width, height, w_scale) {
ctx.save();
https://bitbucket.org/galaxy/galaxy-central/commits/ff91d665fb8e/
Changeset: ff91d665fb8e
User: Jeremy Goecks
Date: 2014-03-26 20:12:39
Summary: Trackster: set maximum label length.
Affected #: 1 file
diff -r 09676399640d304d45dfeb81a32ed30d7314d855 -r ff91d665fb8e211c0bea4c02d9c046f32be7005c static/scripts/viz/trackster/painters.js
--- a/static/scripts/viz/trackster/painters.js
+++ b/static/scripts/viz/trackster/painters.js
@@ -341,6 +341,7 @@
Painter.call(this, data, view_start, view_end, prefs, mode);
this.alpha_scaler = (alpha_scaler ? alpha_scaler : new Scaler());
this.height_scaler = (height_scaler ? height_scaler : new Scaler());
+ this.max_label_length = 200;
};
FeaturePainter.prototype.default_prefs = { block_color: "#FFF", connector_color: "#FFF" };
@@ -399,6 +400,7 @@
feature_mapper.y_translation = this.get_top_padding(width);
return feature_mapper;
},
+
/**
* Abstract function for drawing an individual feature.
*/
@@ -645,11 +647,11 @@
// FIXME: assumption here that the entire view starts at 0
if (tile_low === 0 && f_start - ctx.measureText(feature_name).width < 0) {
ctx.textAlign = "left";
- ctx.fillText(feature_name, f_end + LABEL_SPACING, y_start + 8);
+ ctx.fillText(feature_name, f_end + LABEL_SPACING, y_start + 8, this.max_label_length);
draw_end += ctx.measureText(feature_name).width + LABEL_SPACING;
} else {
ctx.textAlign = "right";
- ctx.fillText(feature_name, f_start - LABEL_SPACING, y_start + 8);
+ ctx.fillText(feature_name, f_start - LABEL_SPACING, y_start + 8, this.max_label_length);
draw_start -= ctx.measureText(feature_name).width + LABEL_SPACING;
}
//ctx.fillStyle = block_color;
@@ -1019,10 +1021,10 @@
ctx.fillStyle = this.prefs.label_color;
if (tile_low === 0 && f_start - ctx.measureText(feature_name).width < 0) {
ctx.textAlign = "left";
- ctx.fillText(feature_name, f_end + LABEL_SPACING, y_start + 8);
+ ctx.fillText(feature_name, f_end + LABEL_SPACING, y_start + 8, this.max_label_length);
} else {
ctx.textAlign = "right";
- ctx.fillText(feature_name, f_start - LABEL_SPACING, y_start + 8);
+ ctx.fillText(feature_name, f_start - LABEL_SPACING, y_start + 8, this.max_label_length);
}
}
https://bitbucket.org/galaxy/galaxy-central/commits/cc7b0f0be551/
Changeset: cc7b0f0be551
User: Jeremy Goecks
Date: 2014-03-26 20:39:14
Summary: Fix initialization of boolean values in client-side config object.
Affected #: 1 file
diff -r ff91d665fb8e211c0bea4c02d9c046f32be7005c -r cc7b0f0be551dd1c0564c1fd7b95b6a2aaa7ee39 static/scripts/utils/config.js
--- a/static/scripts/utils/config.js
+++ b/static/scripts/utils/config.js
@@ -16,7 +16,7 @@
this.set(_.extend({}, defaults, options));
}
- if (!this.get('value')) {
+ if (this.get('value') === undefined) {
// Use default to set value.
this.set_value(this.get('default_value'));
https://bitbucket.org/galaxy/galaxy-central/commits/e298d0294721/
Changeset: e298d0294721
User: Jeremy Goecks
Date: 2014-03-26 22:37:03
Summary: Trackster: fix offset bug that was rendering bases incorrectly.
Affected #: 1 file
diff -r cc7b0f0be551dd1c0564c1fd7b95b6a2aaa7ee39 -r e298d029472150df08bfae9b6ec311c78cb63dfd static/scripts/viz/trackster/painters.js
--- a/static/scripts/viz/trackster/painters.js
+++ b/static/scripts/viz/trackster/painters.js
@@ -740,6 +740,20 @@
* Draw a single read from reference-based read sequence and cigar.
*/
draw_read: function(ctx, mode, w_scale, y_start, tile_low, tile_high, feature_start, cigar, strand, read_seq) {
+ // Helper function to update base and sequnence offsets.
+ var update_base_offset = function(offset, cig_op, cig_len) {
+ if ('M=NXD'.indexOf(cig_op) !== -1) {
+ offset += cig_len;
+ }
+ return offset;
+ },
+ update_seq_offset = function(offset, cig_op, cig_len) {
+ if ('IX'.indexOf(cig_op) !== -1) {
+ offset += cig_len;
+ }
+ return offset;
+ };
+
ctx.textAlign = "center";
var tile_region = [tile_low, tile_high],
base_offset = 0,
@@ -770,7 +784,7 @@
// Make sure that block is drawn even if it too small to be rendered officially; in this case,
// read is drawn at 1px.
- // TODO: need to ensure that s_start, s_end are calcuated the same for both slotting
+ // TODO: need to ensure that s_start, s_end are calculated the same for both slotting
// and drawing.
if (s_start === s_end) {
s_end += 1;
@@ -793,21 +807,26 @@
var seq_start = feature_start + base_offset,
// -0.5 to offset sequence between bases.
- s_start = Math.floor( Math.max(0, -0.5 * w_scale, (seq_start - tile_low - 0.5) * w_scale) ),
+ s_start = Math.floor( Math.max(-0.5 * w_scale, (seq_start - tile_low - 0.5) * w_scale) ),
s_end = Math.floor( Math.max(0, (seq_start + cig_len - tile_low - 0.5) * w_scale) );
+ // Skip feature if it's not in tile.
if (!is_overlap([seq_start, seq_start + cig_len], tile_region)) {
+ // Update offsets.
+ base_offset = update_base_offset(base_offset, cig_op, cig_len);
+ seq_offset = update_seq_offset(seq_offset, cig_op, cig_len);
continue;
}
// Make sure that read is drawn even if it too small to be rendered officially; in this case,
// read is drawn at 1px.
- // TODO: need to ensure that s_start, s_end are calcuated the same for both slotting
+ // TODO: need to ensure that s_start, s_end are calculated the same for both slotting
// and drawing.
if (s_start === s_end) {
s_end += 1;
}
-
+
+ // Draw read feature.
switch (cig_op) {
case "H": // Hard clipping.
case "S": // Soft clipping.
https://bitbucket.org/galaxy/galaxy-central/commits/bc739e4b5bdf/
Changeset: bc739e4b5bdf
User: Jeremy Goecks
Date: 2014-03-26 22:38:22
Summary: Automated merge of local changesets with -default
Affected #: 24 files
diff -r e298d029472150df08bfae9b6ec311c78cb63dfd -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 eggs.ini
--- a/eggs.ini
+++ b/eggs.ini
@@ -56,6 +56,7 @@
python_openid = 2.2.5
python_daemon = 1.5.5
pytz = 2013.9
+requests = 2.2.1
Routes = 1.12.3
sqlalchemy_migrate = 0.7.2
ssh = 1.7.14
diff -r e298d029472150df08bfae9b6ec311c78cb63dfd -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -41,6 +41,7 @@
from galaxy.tools.parameters.basic import DataToolParameter
from galaxy.util.json import to_json_string
from galaxy.workflow.modules import ToolModule
+from galaxy.workflow.steps import attach_ordered_steps
log = logging.getLogger( __name__ )
@@ -1676,7 +1677,6 @@
"""
Creates a workflow from a dict. Created workflow is stored in the database and returned.
"""
- from galaxy.webapps.galaxy.controllers.workflow import attach_ordered_steps
# Put parameters in workflow mode
trans.workflow_building_mode = True
diff -r e298d029472150df08bfae9b6ec311c78cb63dfd -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 lib/galaxy/webapps/galaxy/api/workflows.py
--- a/lib/galaxy/webapps/galaxy/api/workflows.py
+++ b/lib/galaxy/webapps/galaxy/api/workflows.py
@@ -11,8 +11,10 @@
from galaxy import web
from galaxy.web import _future_expose_api as expose_api
from galaxy.web.base.controller import BaseAPIController, url_for, UsesStoredWorkflowMixin
+from galaxy.web.base.controller import UsesHistoryMixin
from galaxy.workflow.modules import module_factory
from galaxy.workflow.run import invoke
+from galaxy.workflow.extract import extract_workflow
log = logging.getLogger(__name__)
@@ -51,7 +53,7 @@
step.state.inputs.update(param_dict)
-class WorkflowsAPIController(BaseAPIController, UsesStoredWorkflowMixin):
+class WorkflowsAPIController(BaseAPIController, UsesStoredWorkflowMixin, UsesHistoryMixin):
@web.expose_api
def index(self, trans, **kwd):
@@ -141,9 +143,11 @@
"""
POST /api/workflows
- We're not creating workflows from the api. Just execute for now.
+ Run or create workflows from the api.
- However, we will import them if installed_repository_file is specified.
+ If installed_repository_file or from_history_id is specified a new
+ workflow will be created for this user. Otherwise, workflow_id must be
+ specified and this API method will cause a workflow to execute.
:param installed_repository_file The path of a workflow to import. Either workflow_id or installed_repository_file must be specified
:type installed_repository_file str
@@ -165,6 +169,15 @@
:param replacement_params: A dictionary used when renaming datasets
:type replacement_params: dict
+
+ :param from_history_id: Id of history to extract a workflow from. Should not be used with worfklow_id or installed_repository_file.
+ :type from_history_id: str
+
+ :param job_ids: If from_history_id is set - this should be a list of jobs to include when extracting workflow from history.
+ :type job_ids: str
+
+ :param dataset_ids: If from_history_id is set - this should be a list of HDA ids corresponding to workflow inputs when extracting workflow from history.
+ :type dataset_ids: str
"""
# Pull parameters out of payload.
@@ -183,6 +196,24 @@
cntrller='api',
**payload)
return result
+ if 'from_history_id' in payload:
+ from_history_id = payload.get( 'from_history_id' )
+ history = self.get_history( trans, from_history_id, check_ownership=False, check_accessible=True )
+ job_ids = map( trans.security.decode_id, payload.get( "job_ids", [] ) )
+ dataset_ids = map( trans.security.decode_id, payload.get( "dataset_ids", [] ) )
+ workflow_name = payload[ "workflow_name" ]
+ stored_workflow = extract_workflow(
+ trans=trans,
+ user=trans.get_user(),
+ history=history,
+ job_ids=job_ids,
+ dataset_ids=dataset_ids,
+ workflow_name=workflow_name,
+ )
+ item = stored_workflow.to_dict( value_mapper={ "id": trans.security.encode_id } )
+ item[ 'url' ] = url_for( 'workflow', id=item[ "id" ] )
+ return item
+
trans.response.status = 403
return "Either workflow_id or installed_repository_file must be specified"
if 'installed_repository_file' in payload:
diff -r e298d029472150df08bfae9b6ec311c78cb63dfd -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
@@ -201,9 +201,13 @@
repository_id = kwd.get( 'id', None )
repository = suc.get_installed_tool_shed_repository( trans, repository_id )
tool_shed_url = suc.get_url_from_tool_shed( trans.app, repository.tool_shed )
+ params = '?galaxy_url=%s&name=%s&owner=%s&changeset_revision=%s' % \
+ ( web.url_for( '/', qualified=True ),
+ str( repository.name ),
+ str( repository.owner ),
+ str( repository.changeset_revision ) )
url = suc.url_join( tool_shed_url,
- 'repository/check_for_updates?galaxy_url=%s&name=%s&owner=%s&changeset_revision=%s' % \
- ( web.url_for( '/', qualified=True ), repository.name, repository.owner, repository.changeset_revision ) )
+ 'repository/check_for_updates%s' % params )
return trans.response.send_redirect( url )
@web.expose
@@ -367,9 +371,10 @@
@web.require_admin
def get_tool_dependencies( self, trans, repository_id, repository_name, repository_owner, changeset_revision ):
"""
- Send a request to the appropriate tool shed to retrieve the dictionary of tool dependencies defined for the received repository name,
- owner and changeset revision. The received repository_id is the encoded id of the installed tool shed repository in Galaxy. We need
- it so that we can derive the tool shed from which it was installed.
+ Send a request to the appropriate tool shed to retrieve the dictionary of tool dependencies defined for
+ the received repository name, owner and changeset revision. The received repository_id is the encoded id
+ of the installed tool shed repository in Galaxy. We need it so that we can derive the tool shed from which
+ it was installed.
"""
repository = suc.get_installed_tool_shed_repository( trans, repository_id )
tool_shed_url = suc.get_url_from_tool_shed( trans.app, repository.tool_shed )
@@ -388,8 +393,8 @@
@web.require_admin
def get_updated_repository_information( self, trans, repository_id, repository_name, repository_owner, changeset_revision ):
"""
- Send a request to the appropriate tool shed to retrieve the dictionary of information required to reinstall an updated revision of an
- uninstalled tool shed repository.
+ Send a request to the appropriate tool shed to retrieve the dictionary of information required to reinstall
+ an updated revision of an uninstalled tool shed repository.
"""
repository = suc.get_installed_tool_shed_repository( trans, repository_id )
tool_shed_url = suc.get_url_from_tool_shed( trans.app, repository.tool_shed )
@@ -436,13 +441,16 @@
@web.expose
@web.require_admin
- def initiate_tool_dependency_installation( self, trans, tool_dependencies ):
+ def initiate_tool_dependency_installation( self, trans, tool_dependencies, **kwd ):
"""Install specified dependencies for repository tools."""
# Get the tool_shed_repository from one of the tool_dependencies.
- message = ''
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ err_msg = ''
tool_shed_repository = tool_dependencies[ 0 ].tool_shed_repository
# Get the tool_dependencies.xml file from the repository.
- tool_dependencies_config = suc.get_config_from_disk( suc.TOOL_DEPENDENCY_DEFINITION_FILENAME, tool_shed_repository.repo_path( trans.app ) )
+ tool_dependencies_config = suc.get_config_from_disk( suc.TOOL_DEPENDENCY_DEFINITION_FILENAME,
+ tool_shed_repository.repo_path( trans.app ) )
installed_tool_dependencies = common_install_util.handle_tool_dependencies( app=trans.app,
tool_shed_repository=tool_shed_repository,
tool_dependencies_config=tool_dependencies_config,
@@ -452,13 +460,12 @@
if installed_tool_dependency.status == trans.app.install_model.ToolDependency.installation_status.ERROR:
text = util.unicodify( installed_tool_dependency.error_message )
if text is not None:
- message += ' %s' % text
+ err_msg += ' %s' % text
tool_dependency_ids = [ trans.security.encode_id( td.id ) for td in tool_dependencies ]
- if message:
+ if err_msg:
+ message += err_msg
status = 'error'
- else:
- message = "Installed tool dependencies: %s" % ','.join( td.name for td in installed_tool_dependencies )
- status = 'done'
+ message += "Installed tool dependencies: %s" % ','.join( td.name for td in installed_tool_dependencies )
td_ids = [ trans.security.encode_id( td.id ) for td in tool_shed_repository.tool_dependencies ]
return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
action='manage_tool_dependencies',
@@ -506,9 +513,10 @@
status = 'error'
else:
# Install the latest downloadable revision of the repository.
+ params = '?name=%s&owner=%s&changeset_revisions=%s&galaxy_url=%s' % \
+ ( name, owner, str( latest_downloadable_revision ), web.url_for( '/', qualified=True ) )
url = suc.url_join( tool_shed_url,
- 'repository/install_repositories_by_revision?name=%s&owner=%s&changeset_revisions=%s&galaxy_url=%s' % \
- ( name, owner, latest_downloadable_revision, web.url_for( '/', qualified=True ) ) )
+ 'repository/install_repositories_by_revision%s' % params )
return trans.response.send_redirect( url )
else:
message = 'Cannot locate installed tool shed repository with encoded id <b>%s</b>.' % str( repository_id )
@@ -521,43 +529,74 @@
message=message,
status=status ) )
-
@web.expose
@web.require_admin
- def install_tool_dependencies( self, trans, **kwd ):
+ def install_tool_dependencies_with_update( self, trans, **kwd ):
+ """
+ Updating an installed tool shed repository where new tool dependencies but no new repository
+ dependencies are included in the updated revision.
+ """
+ updating_repository_id = kwd.get( 'updating_repository_id', None )
+ repository = suc.get_installed_tool_shed_repository( trans, updating_repository_id )
+ # All received dependencies need to be installed - confirmed by the caller.
+ encoded_tool_dependencies_dict = kwd.get( 'encoded_tool_dependencies_dict', None )
+ if encoded_tool_dependencies_dict is not None:
+ tool_dependencies_dict = encoding_util.tool_shed_decode( encoded_tool_dependencies_dict )
+ else:
+ tool_dependencies_dict = {}
+ encoded_relative_install_dir = kwd.get( 'encoded_relative_install_dir', None )
+ if encoded_relative_install_dir is not None:
+ relative_install_dir = encoding_util.tool_shed_decode( encoded_relative_install_dir )
+ else:
+ relative_install_dir = ''
+ updating_to_changeset_revision = kwd.get( 'updating_to_changeset_revision', None )
+ updating_to_ctx_rev = kwd.get( 'updating_to_ctx_rev', None )
+ encoded_updated_metadata = kwd.get( 'encoded_updated_metadata', None )
message = kwd.get( 'message', '' )
status = kwd.get( 'status', 'done' )
- tool_dependency_ids = tool_dependency_util.get_tool_dependency_ids( as_string=False, **kwd )
- tool_dependencies = []
- for tool_dependency_id in tool_dependency_ids:
- tool_dependency = tool_dependency_util.get_tool_dependency( trans, tool_dependency_id )
- tool_dependencies.append( tool_dependency )
- if kwd.get( 'install_tool_dependencies_button', False ):
- # Filter tool dependencies to only those that are installed.
- tool_dependencies_for_installation = []
- for tool_dependency in tool_dependencies:
- if tool_dependency.status in [ trans.install_model.ToolDependency.installation_status.UNINSTALLED,
- trans.install_model.ToolDependency.installation_status.ERROR ]:
- tool_dependencies_for_installation.append( tool_dependency )
- if tool_dependencies_for_installation:
- # Redirect back to the ToolDependencyGrid before initiating installation.
- encoded_tool_dependency_for_installation_ids = [ trans.security.encode_id( td.id ) for td in tool_dependencies_for_installation ]
- new_kwd = dict( action='manage_tool_dependencies',
- operation='initiate_tool_dependency_installation',
- tool_dependency_ids=encoded_tool_dependency_for_installation_ids,
- message=message,
- status=status )
- return self.tool_dependency_grid( trans, **new_kwd )
+ install_tool_dependencies = CheckboxField.is_checked( kwd.get( 'install_tool_dependencies', '' ) )
+ if 'install_tool_dependencies_with_update_button' in kwd:
+ # Now that the user has chosen whether to install tool dependencies or not, we can
+ # update the repository record with the changes in the updated revision.
+ if encoded_updated_metadata:
+ updated_metadata = encoding_util.tool_shed_decode( encoded_updated_metadata )
else:
- message = 'All of the selected tool dependencies are already installed.'
- status = 'error'
- return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
- action='manage_repository_tool_dependencies',
- tool_dependency_ids=tool_dependency_ids,
- status=status,
- message=message ) )
- return trans.fill_template( '/admin/tool_shed_repository/install_tool_dependencies.mako',
- tool_dependencies=tool_dependencies,
+ updated_metadata = None
+ repository = repository_util.update_repository_record( trans,
+ repository=repository,
+ updated_metadata_dict=updated_metadata,
+ updated_changeset_revision=updating_to_changeset_revision,
+ updated_ctx_rev=updating_to_ctx_rev )
+ if install_tool_dependencies:
+ tool_dependencies = tool_dependency_util.create_tool_dependency_objects( trans.app,
+ repository,
+ relative_install_dir,
+ set_status=False )
+ message = "The installed repository named '%s' has been updated to change set revision '%s'. " % \
+ ( str( repository.name ), updating_to_changeset_revision )
+ self.initiate_tool_dependency_installation( trans, tool_dependencies, message=message, status=status )
+ # Handle tool dependencies check box.
+ if trans.app.config.tool_dependency_dir is None:
+ if includes_tool_dependencies:
+ message = "Tool dependencies defined in this repository can be automatically installed if you set "
+ message += "the value of your <b>tool_dependency_dir</b> setting in your Galaxy config file "
+ message += "(universe_wsgi.ini) and restart your Galaxy server."
+ status = "warning"
+ install_tool_dependencies_check_box_checked = False
+ else:
+ install_tool_dependencies_check_box_checked = True
+ install_tool_dependencies_check_box = CheckboxField( 'install_tool_dependencies',
+ checked=install_tool_dependencies_check_box_checked )
+ return trans.fill_template( '/admin/tool_shed_repository/install_tool_dependencies_with_update.mako',
+ repository=repository,
+ updating_repository_id=updating_repository_id,
+ updating_to_ctx_rev=updating_to_ctx_rev,
+ updating_to_changeset_revision=updating_to_changeset_revision,
+ encoded_updated_metadata=encoded_updated_metadata,
+ encoded_relative_install_dir=encoded_relative_install_dir,
+ encoded_tool_dependencies_dict=encoded_tool_dependencies_dict,
+ install_tool_dependencies_check_box=install_tool_dependencies_check_box,
+ tool_dependencies_dict=tool_dependencies_dict,
message=message,
status=status )
@@ -611,7 +650,8 @@
# TODO: I believe this block should be removed, but make sure..
repositories_for_uninstallation = []
for repository_id in tsridslist:
- repository = trans.install_model.context.query( trans.install_model.ToolShedRepository ).get( trans.security.decode_id( repository_id ) )
+ repository = trans.install_model.context.query( trans.install_model.ToolShedRepository ) \
+ .get( trans.security.decode_id( repository_id ) )
if repository.status in [ trans.install_model.ToolShedRepository.installation_status.INSTALLED,
trans.install_model.ToolShedRepository.installation_status.ERROR ]:
repositories_for_uninstallation.append( repository )
@@ -632,28 +672,34 @@
filtered_repo_info_dicts = []
filtered_tool_panel_section_keys = []
repositories_for_installation = []
- # Some repositories may have repository dependencies that are required to be installed before the dependent repository, so we'll
- # order the list of tsr_ids to ensure all repositories install in the required order.
+ # Some repositories may have repository dependencies that are required to be installed before the
+ # dependent repository, so we'll order the list of tsr_ids to ensure all repositories install in the
+ # required order.
ordered_tsr_ids, ordered_repo_info_dicts, ordered_tool_panel_section_keys = \
repository_util.order_components_for_installation( trans,
tsr_ids,
repo_info_dicts,
tool_panel_section_keys=tool_panel_section_keys )
for tsr_id in ordered_tsr_ids:
- repository = trans.install_model.context.query( trans.install_model.ToolShedRepository ).get( trans.security.decode_id( tsr_id ) )
+ repository = trans.install_model.context.query( trans.install_model.ToolShedRepository ) \
+ .get( trans.security.decode_id( tsr_id ) )
if repository.status in [ trans.install_model.ToolShedRepository.installation_status.NEW,
trans.install_model.ToolShedRepository.installation_status.UNINSTALLED ]:
repositories_for_installation.append( repository )
- repo_info_dict, tool_panel_section_key = repository_util.get_repository_components_for_installation( tsr_id,
- ordered_tsr_ids,
- ordered_repo_info_dicts,
- ordered_tool_panel_section_keys )
+ repo_info_dict, tool_panel_section_key = \
+ repository_util.get_repository_components_for_installation( tsr_id,
+ ordered_tsr_ids,
+ ordered_repo_info_dicts,
+ ordered_tool_panel_section_keys )
filtered_repo_info_dicts.append( repo_info_dict )
filtered_tool_panel_section_keys.append( tool_panel_section_key )
if repositories_for_installation:
decoded_kwd[ 'repo_info_dicts' ] = filtered_repo_info_dicts
decoded_kwd[ 'tool_panel_section_keys' ] = filtered_tool_panel_section_keys
- self.install_tool_shed_repositories( trans, repositories_for_installation, reinstalling=reinstalling, **decoded_kwd )
+ self.install_tool_shed_repositories( trans,
+ repositories_for_installation,
+ reinstalling=reinstalling,
+ **decoded_kwd )
else:
kwd[ 'message' ] = 'All selected tool shed repositories are already installed.'
kwd[ 'status' ] = 'error'
@@ -772,7 +818,10 @@
trans.install_model.ToolDependency.installation_status.UNINSTALLED ]:
tool_dependencies_for_installation.append( tool_dependency )
if tool_dependencies_for_installation:
- self.initiate_tool_dependency_installation( trans, tool_dependencies_for_installation )
+ self.initiate_tool_dependency_installation( trans,
+ tool_dependencies_for_installation,
+ message=message,
+ status=status )
else:
message = 'All selected tool dependencies are already installed.'
status = 'error'
@@ -780,14 +829,16 @@
message = 'Set the value of your <b>tool_dependency_dir</b> setting in your Galaxy config file (universe_wsgi.ini) '
message += ' and restart your Galaxy server to install tool dependencies.'
status = 'error'
- installed_tool_dependencies_select_field = suc.build_tool_dependencies_select_field( trans,
- tool_shed_repository=tool_shed_repository,
- name='inst_td_ids',
- uninstalled_only=False )
- uninstalled_tool_dependencies_select_field = suc.build_tool_dependencies_select_field( trans,
- tool_shed_repository=tool_shed_repository,
- name='uninstalled_tool_dependency_ids',
- uninstalled_only=True )
+ installed_tool_dependencies_select_field = \
+ suc.build_tool_dependencies_select_field( trans,
+ tool_shed_repository=tool_shed_repository,
+ name='inst_td_ids',
+ uninstalled_only=False )
+ uninstalled_tool_dependencies_select_field = \
+ suc.build_tool_dependencies_select_field( trans,
+ tool_shed_repository=tool_shed_repository,
+ name='uninstalled_tool_dependency_ids',
+ uninstalled_only=True )
return trans.fill_template( '/admin/tool_shed_repository/manage_repository_tool_dependencies.mako',
repository=tool_shed_repository,
installed_tool_dependencies_select_field=installed_tool_dependencies_select_field,
@@ -836,7 +887,10 @@
trans.install_model.ToolDependency.installation_status.UNINSTALLED ]:
tool_dependencies_for_installation.append( tool_dependency )
if tool_dependencies_for_installation:
- self.initiate_tool_dependency_installation( trans, tool_dependencies_for_installation )
+ self.initiate_tool_dependency_installation( trans,
+ tool_dependencies_for_installation,
+ message=message,
+ status=status )
else:
kwd[ 'message' ] = 'All selected tool dependencies are already installed.'
kwd[ 'status' ] = 'error'
@@ -876,18 +930,21 @@
@web.require_admin
def prepare_for_install( self, trans, **kwd ):
if not suc.have_shed_tool_conf_for_install( trans ):
- message = 'The <b>tool_config_file</b> setting in <b>universe_wsgi.ini</b> must include at least one shed tool configuration file name with a '
- message += '<b><toolbox></b> tag that includes a <b>tool_path</b> attribute value which is a directory relative to the Galaxy installation '
- message += 'directory in order to automatically install tools from a Galaxy tool shed (e.g., the file name <b>shed_tool_conf.xml</b> whose '
- message += '<b><toolbox></b> tag is <b><toolbox tool_path="../shed_tools"></b>).<p/>See the '
- message += '<a href="http://wiki.g2.bx.psu.edu/InstallingRepositoriesToGalaxy" target="_blank">Installation of Galaxy tool shed repository tools '
- message += 'into a local Galaxy instance</a> section of the Galaxy tool shed wiki for all of the details.'
+ message = 'The <b>tool_config_file</b> setting in <b>universe_wsgi.ini</b> must include at least one '
+ message += 'shed tool configuration file name with a <b><toolbox></b> tag that includes a <b>tool_path</b> '
+ message += 'attribute value which is a directory relative to the Galaxy installation directory in order '
+ message += 'to automatically install tools from a Galaxy Tool Shed (e.g., the file name <b>shed_tool_conf.xml</b> '
+ message += 'whose <b><toolbox></b> tag is <b><toolbox tool_path="../shed_tools"></b>).<p/>See the '
+ message += '<a href="http://wiki.g2.bx.psu.edu/InstallingRepositoriesToGalaxy" target="_blank">Installation '
+ message += 'of Galaxy Tool Shed repository tools into a local Galaxy instance</a> section of the Galaxy Tool '
+ message += 'Shed wiki for all of the details.'
return trans.show_error_message( message )
message = kwd.get( 'message', '' )
status = kwd.get( 'status', 'done' )
shed_tool_conf = kwd.get( 'shed_tool_conf', None )
tool_shed_url = kwd.get( 'tool_shed_url', None )
- # Handle repository dependencies, which do not include those that are required only for compiling a dependent repository's tool dependencies.
+ # Handle repository dependencies, which do not include those that are required only for compiling a dependent
+ # repository's tool dependencies.
has_repository_dependencies = util.string_as_bool( kwd.get( 'has_repository_dependencies', False ) )
install_repository_dependencies = kwd.get( 'install_repository_dependencies', '' )
# Every repository will be installed into the same tool panel section or all will be installed outside of any sections.
@@ -900,13 +957,36 @@
includes_tools_for_display_in_tool_panel = util.string_as_bool( kwd.get( 'includes_tools_for_display_in_tool_panel', False ) )
includes_tool_dependencies = util.string_as_bool( kwd.get( 'includes_tool_dependencies', False ) )
install_tool_dependencies = kwd.get( 'install_tool_dependencies', '' )
+ # In addition to installing new repositories, this method is called when updating an installed repository
+ # to a new changeset_revision where the update includes newly defined repository dependencies.
+ updating = util.asbool( kwd.get( 'updating', False ) )
+ updating_repository_id = kwd.get( 'updating_repository_id', None )
+ updating_to_changeset_revision = kwd.get( 'updating_to_changeset_revision', None )
+ updating_to_ctx_rev = kwd.get( 'updating_to_ctx_rev', None )
+ encoded_updated_metadata = kwd.get( 'encoded_updated_metadata', None )
encoded_repo_info_dicts = kwd.get( 'encoded_repo_info_dicts', '' )
if encoded_repo_info_dicts:
encoded_repo_info_dicts = encoded_repo_info_dicts.split( encoding_util.encoding_sep )
if not encoded_repo_info_dicts:
- # The request originated in the tool shed via a tool search.
+ # The request originated in the tool shed via a tool search or from this controller's
+ # update_to_changeset_revision() method.
repository_ids = kwd.get( 'repository_ids', None )
- changeset_revisions = kwd.get( 'changeset_revisions', None )
+ if updating:
+ # We have updated an installed repository where the updates included newly defined repository
+ # and possibly tool dependencies. We will have arrived here only if the updates include newly
+ # defined repository dependencies. We're preparing to allow the user to elect to install these
+ # dependencies. At this point, the repository has been updated to the latest changeset revision,
+ # but the received repository id is from the Galaxy side (the caller is this controller's
+ # update_to_changeset_revision() method. We need to get the id of the same repository from the
+ # Tool Shed side.
+ repository = suc.get_tool_shed_repository_by_id( trans, updating_repository_id )
+ url = suc.url_join( tool_shed_url,
+ 'repository/get_repository_id?name=%s&owner=%s' % \
+ ( str( repository.name ), str( repository.owner ) ) )
+ repository_ids = common_util.tool_shed_get( trans.app, tool_shed_url, url )
+ changeset_revisions = updating_to_changeset_revision
+ else:
+ changeset_revisions = kwd.get( 'changeset_revisions', None )
# Get the information necessary to install each repository.
url = suc.url_join( tool_shed_url,
'repository/get_repository_information?repository_ids=%s&changeset_revisions=%s' % \
@@ -918,7 +998,8 @@
if not includes_tools:
includes_tools = util.string_as_bool( decoded_repo_info_dict.get( 'includes_tools', False ) )
if not includes_tools_for_display_in_tool_panel:
- includes_tools_for_display_in_tool_panel = util.string_as_bool( decoded_repo_info_dict.get( 'includes_tools_for_display_in_tool_panel', False ) )
+ includes_tools_for_display_in_tool_panel = \
+ util.string_as_bool( decoded_repo_info_dict.get( 'includes_tools_for_display_in_tool_panel', False ) )
if not has_repository_dependencies:
has_repository_dependencies = util.string_as_bool( repo_information_dict.get( 'has_repository_dependencies', False ) )
if not includes_tool_dependencies:
@@ -927,6 +1008,19 @@
repo_info_dicts = [ encoding_util.tool_shed_decode( encoded_repo_info_dict ) for encoded_repo_info_dict in encoded_repo_info_dicts ]
if ( not includes_tools_for_display_in_tool_panel and kwd.get( 'select_shed_tool_panel_config_button', False ) ) or \
( includes_tools_for_display_in_tool_panel and kwd.get( 'select_tool_panel_section_button', False ) ):
+ if updating:
+ encoded_updated_metadata_dict = kwd.get( 'encoded_updated_metadata_dict', None )
+ updated_changeset_revision = kwd.get( 'updated_changeset_revision', None )
+ updated_ctx_rev = kwd.get( 'updated_ctx_rev', None )
+ repository = suc.get_tool_shed_repository_by_id( trans, updating_repository_id )
+ decoded_updated_metadata = encoding_util.tool_shed_decode( encoded_updated_metadata )
+ # Now that the user has decided whether they will handle dependencies, we can update
+ # the repository to the latest revision.
+ repository = repository_util.update_repository_record( trans,
+ repository=repository,
+ updated_metadata_dict=decoded_updated_metadata,
+ updated_changeset_revision=updating_to_changeset_revision,
+ updated_ctx_rev=updating_to_ctx_rev )
install_repository_dependencies = CheckboxField.is_checked( install_repository_dependencies )
if includes_tool_dependencies:
install_tool_dependencies = CheckboxField.is_checked( install_tool_dependencies )
@@ -959,7 +1053,8 @@
tool_panel_section_keys=tool_panel_section_keys,
tool_path=tool_path,
tool_shed_url=tool_shed_url )
- encoded_kwd, query, tool_shed_repositories, encoded_repository_ids = repository_util.initiate_repository_installation( trans, installation_dict )
+ encoded_kwd, query, tool_shed_repositories, encoded_repository_ids = \
+ repository_util.initiate_repository_installation( trans, installation_dict )
return trans.fill_template( 'admin/tool_shed_repository/initiate_repository_installation.mako',
encoded_kwd=encoded_kwd,
query=query,
@@ -976,12 +1071,14 @@
tool_path = suc.get_tool_path_by_shed_tool_conf_filename( trans, shed_tool_conf )
tool_panel_section_select_field = tool_util.build_tool_panel_section_select_field( trans )
if len( repo_info_dicts ) == 1:
- # If we're installing a single repository, see if it contains a readme or dependencies that we can display.
+ # If we're installing or updating a single repository, see if it contains a readme or
+ # dependencies that we can display.
repo_info_dict = repo_info_dicts[ 0 ]
dependencies_for_repository_dict = common_install_util.get_dependencies_for_repository( trans,
tool_shed_url,
repo_info_dict,
- includes_tool_dependencies )
+ includes_tool_dependencies,
+ updating=updating )
changeset_revision = dependencies_for_repository_dict.get( 'changeset_revision', None )
if not has_repository_dependencies:
has_repository_dependencies = dependencies_for_repository_dict.get( 'has_repository_dependencies', False )
@@ -990,7 +1087,8 @@
if not includes_tools:
includes_tools = dependencies_for_repository_dict.get( 'includes_tools', False )
if not includes_tools_for_display_in_tool_panel:
- includes_tools_for_display_in_tool_panel = dependencies_for_repository_dict.get( 'includes_tools_for_display_in_tool_panel', False )
+ includes_tools_for_display_in_tool_panel = \
+ dependencies_for_repository_dict.get( 'includes_tools_for_display_in_tool_panel', False )
installed_repository_dependencies = dependencies_for_repository_dict.get( 'installed_repository_dependencies', None )
installed_tool_dependencies = dependencies_for_repository_dict.get( 'installed_tool_dependencies', None )
missing_repository_dependencies = dependencies_for_repository_dict.get( 'missing_repository_dependencies', None )
@@ -998,19 +1096,25 @@
name = dependencies_for_repository_dict.get( 'name', None )
repository_owner = dependencies_for_repository_dict.get( 'repository_owner', None )
readme_files_dict = readme_util.get_readme_files_dict_for_display( trans, tool_shed_url, repo_info_dict )
- # We're handling 1 of 2 scenarios here: (1) we're installing a tool shed repository for the first time, so we've retrieved the list of installed
- # and missing repository dependencies from the database (2) we're handling the scenario where an error occurred during the installation process,
- # so we have a tool_shed_repository record in the database with associated repository dependency records. Since we have the repository
- # dependencies in either case, we'll merge the list of missing repository dependencies into the list of installed repository dependencies since
- # each displayed repository dependency will display a status, whether installed or missing.
- containers_dict = repository_util.populate_containers_dict_for_new_install( trans=trans,
- tool_shed_url=tool_shed_url,
- tool_path=tool_path,
- readme_files_dict=readme_files_dict,
- installed_repository_dependencies=installed_repository_dependencies,
- missing_repository_dependencies=missing_repository_dependencies,
- installed_tool_dependencies=installed_tool_dependencies,
- missing_tool_dependencies=missing_tool_dependencies )
+ # We're handling 1 of 3 scenarios here: (1) we're installing a tool shed repository for the first time, so we've
+ # retrieved the list of installed and missing repository dependencies from the database (2) we're handling the
+ # scenario where an error occurred during the installation process, so we have a tool_shed_repository record in
+ # the database with associated repository dependency records. Since we have the repository dependencies in both
+ # of the above 2 cases, we'll merge the list of missing repository dependencies into the list of installed
+ # repository dependencies since each displayed repository dependency will display a status, whether installed or
+ # missing. The 3rd scenario is where we're updating an installed repository and the updates include newly
+ # defined repository (and possibly tool) dependencies. In this case, merging will result in newly defined
+ # dependencies to be lost. We pass the updating parameter to make sure merging occurs only when appropriate.
+ containers_dict = \
+ repository_util.populate_containers_dict_for_new_install( trans=trans,
+ tool_shed_url=tool_shed_url,
+ tool_path=tool_path,
+ readme_files_dict=readme_files_dict,
+ installed_repository_dependencies=installed_repository_dependencies,
+ missing_repository_dependencies=missing_repository_dependencies,
+ installed_tool_dependencies=installed_tool_dependencies,
+ missing_tool_dependencies=missing_tool_dependencies,
+ updating=updating )
else:
# We're installing a list of repositories, each of which may have tool dependencies or repository dependencies.
containers_dicts = []
@@ -1018,7 +1122,8 @@
dependencies_for_repository_dict = common_install_util.get_dependencies_for_repository( trans,
tool_shed_url,
repo_info_dict,
- includes_tool_dependencies )
+ includes_tool_dependencies,
+ updating=updating )
changeset_revision = dependencies_for_repository_dict.get( 'changeset_revision', None )
if not has_repository_dependencies:
has_repository_dependencies = dependencies_for_repository_dict.get( 'has_repository_dependencies', False )
@@ -1027,34 +1132,39 @@
if not includes_tools:
includes_tools = dependencies_for_repository_dict.get( 'includes_tools', False )
if not includes_tools_for_display_in_tool_panel:
- includes_tools_for_display_in_tool_panel = dependencies_for_repository_dict.get( 'includes_tools_for_display_in_tool_panel', False )
+ includes_tools_for_display_in_tool_panel = \
+ dependencies_for_repository_dict.get( 'includes_tools_for_display_in_tool_panel', False )
installed_repository_dependencies = dependencies_for_repository_dict.get( 'installed_repository_dependencies', None )
installed_tool_dependencies = dependencies_for_repository_dict.get( 'installed_tool_dependencies', None )
missing_repository_dependencies = dependencies_for_repository_dict.get( 'missing_repository_dependencies', None )
missing_tool_dependencies = dependencies_for_repository_dict.get( 'missing_tool_dependencies', None )
name = dependencies_for_repository_dict.get( 'name', None )
repository_owner = dependencies_for_repository_dict.get( 'repository_owner', None )
- containers_dict = repository_util.populate_containers_dict_for_new_install( trans=trans,
- tool_shed_url=tool_shed_url,
- tool_path=tool_path,
- readme_files_dict=None,
- installed_repository_dependencies=installed_repository_dependencies,
- missing_repository_dependencies=missing_repository_dependencies,
- installed_tool_dependencies=installed_tool_dependencies,
- missing_tool_dependencies=missing_tool_dependencies )
+ containers_dict = \
+ repository_util.populate_containers_dict_for_new_install( trans=trans,
+ tool_shed_url=tool_shed_url,
+ tool_path=tool_path,
+ readme_files_dict=None,
+ installed_repository_dependencies=installed_repository_dependencies,
+ missing_repository_dependencies=missing_repository_dependencies,
+ installed_tool_dependencies=installed_tool_dependencies,
+ missing_tool_dependencies=missing_tool_dependencies,
+ updating=updating )
containers_dicts.append( containers_dict )
# Merge all containers into a single container.
containers_dict = repository_util.merge_containers_dicts_for_new_install( containers_dicts )
# Handle tool dependencies check box.
if trans.app.config.tool_dependency_dir is None:
if includes_tool_dependencies:
- message = "Tool dependencies defined in this repository can be automatically installed if you set the value of your <b>tool_dependency_dir</b> "
- message += "setting in your Galaxy config file (universe_wsgi.ini) and restart your Galaxy server before installing the repository."
+ message = "Tool dependencies defined in this repository can be automatically installed if you set "
+ message += "the value of your <b>tool_dependency_dir</b> setting in your Galaxy config file "
+ message += "(universe_wsgi.ini) and restart your Galaxy server before installing the repository."
status = "warning"
install_tool_dependencies_check_box_checked = False
else:
install_tool_dependencies_check_box_checked = True
- install_tool_dependencies_check_box = CheckboxField( 'install_tool_dependencies', checked=install_tool_dependencies_check_box_checked )
+ install_tool_dependencies_check_box = CheckboxField( 'install_tool_dependencies',
+ checked=install_tool_dependencies_check_box_checked )
# Handle repository dependencies check box.
install_repository_dependencies_check_box = CheckboxField( 'install_repository_dependencies', checked=True )
encoded_repo_info_dicts = encoding_util.encoding_sep.join( encoded_repo_info_dicts )
@@ -1062,6 +1172,11 @@
if includes_tools_for_display_in_tool_panel:
return trans.fill_template( '/admin/tool_shed_repository/select_tool_panel_section.mako',
encoded_repo_info_dicts=encoded_repo_info_dicts,
+ updating=updating,
+ updating_repository_id=updating_repository_id,
+ updating_to_ctx_rev=updating_to_ctx_rev,
+ updating_to_changeset_revision=updating_to_changeset_revision,
+ encoded_updated_metadata=encoded_updated_metadata,
includes_tools=includes_tools,
includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel,
includes_tool_dependencies=includes_tool_dependencies,
@@ -1077,10 +1192,16 @@
message=message,
status=status )
else:
- # If installing repositories that includes no tools and has no repository dependencies, display a page allowing the Galaxy administrator to
- # select a shed-related tool panel configuration file whose tool_path setting will be the location the repositories will be installed.
+ # If installing repositories that includes no tools and has no repository dependencies, display a page
+ # allowing the Galaxy administrator to select a shed-related tool panel configuration file whose tool_path
+ # setting will be the location the repositories will be installed.
return trans.fill_template( '/admin/tool_shed_repository/select_shed_tool_panel_config.mako',
encoded_repo_info_dicts=encoded_repo_info_dicts,
+ updating=updating,
+ updating_repository_id=updating_repository_id,
+ updating_to_ctx_rev=updating_to_ctx_rev,
+ updating_to_changeset_revision=updating_to_changeset_revision,
+ encoded_updated_metadata=encoded_updated_metadata,
includes_tools=includes_tools,
includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel,
includes_tool_dependencies=includes_tool_dependencies,
@@ -1400,7 +1521,8 @@
dependencies_for_repository_dict = common_install_util.get_dependencies_for_repository( trans,
tool_shed_url,
repo_info_dict,
- includes_tool_dependencies )
+ includes_tool_dependencies,
+ updating=False )
changeset_revision = dependencies_for_repository_dict.get( 'changeset_revision', None )
has_repository_dependencies = dependencies_for_repository_dict.get( 'has_repository_dependencies', False )
includes_tool_dependencies = dependencies_for_repository_dict.get( 'includes_tool_dependencies', False )
@@ -1449,14 +1571,16 @@
original_section_name = ''
tool_panel_section_select_field = None
shed_tool_conf_select_field = tool_util.build_shed_tool_conf_select_field( trans )
- containers_dict = repository_util.populate_containers_dict_for_new_install( trans=trans,
- tool_shed_url=tool_shed_url,
- tool_path=tool_path,
- readme_files_dict=readme_files_dict,
- installed_repository_dependencies=installed_repository_dependencies,
- missing_repository_dependencies=missing_repository_dependencies,
- installed_tool_dependencies=installed_tool_dependencies,
- missing_tool_dependencies=missing_tool_dependencies )
+ containers_dict = \
+ repository_util.populate_containers_dict_for_new_install( trans=trans,
+ tool_shed_url=tool_shed_url,
+ tool_path=tool_path,
+ readme_files_dict=readme_files_dict,
+ installed_repository_dependencies=installed_repository_dependencies,
+ missing_repository_dependencies=missing_repository_dependencies,
+ installed_tool_dependencies=installed_tool_dependencies,
+ missing_tool_dependencies=missing_tool_dependencies,
+ updating=False )
# Since we're reinstalling we'll merge the list of missing repository dependencies into the list of installed repository dependencies since each displayed
# repository dependency will display a status, whether installed or missing.
containers_dict = repository_dependency_util.merge_missing_repository_dependencies_to_installed_container( containers_dict )
@@ -1574,8 +1698,8 @@
@web.require_admin
def set_tool_versions( self, trans, **kwd ):
"""
- Get the tool_versions from the tool shed for each tool in the installed revision of a selected tool shed repository and update the
- metadata for the repository's revision in the Galaxy database.
+ Get the tool_versions from the tool shed for each tool in the installed revision of a selected tool shed
+ repository and update the metadata for the repository's revision in the Galaxy database.
"""
repository = suc.get_installed_tool_shed_repository( trans, kwd[ 'id' ] )
tool_shed_url = suc.get_url_from_tool_shed( trans.app, repository.tool_shed )
@@ -1720,29 +1844,17 @@
resetting_all_metadata_on_repository=False,
updating_installed_repository=True,
persist=True )
- repository.metadata = metadata_dict
- # Update the repository.changeset_revision column in the database.
- repository.changeset_revision = latest_changeset_revision
- repository.ctx_rev = latest_ctx_rev
- # Update the repository.tool_shed_status column in the database.
- tool_shed_status_dict = suc.get_tool_shed_status_for_installed_repository( trans.app, repository )
- if tool_shed_status_dict:
- repository.tool_shed_status = tool_shed_status_dict
- else:
- repository.tool_shed_status = None
- trans.install_model.context.add( repository )
- trans.install_model.context.flush()
if 'tools' in metadata_dict:
tool_panel_dict = metadata_dict.get( 'tool_panel_section', None )
if tool_panel_dict is None:
tool_panel_dict = suc.generate_tool_panel_dict_from_shed_tool_conf_entries( trans.app, repository )
repository_tools_tups = suc.get_repository_tools_tups( trans.app, metadata_dict )
tool_util.add_to_tool_panel( app=trans.app,
- repository_name=repository.name,
+ repository_name=str( repository.name ),
repository_clone_url=repository_clone_url,
- changeset_revision=repository.installed_changeset_revision,
+ changeset_revision=str( repository.installed_changeset_revision ),
repository_tools_tups=repository_tools_tups,
- owner=repository.owner,
+ owner=str( repository.owner ),
shed_tool_conf=shed_tool_conf,
tool_panel_dict=tool_panel_dict,
new_install=False )
@@ -1755,19 +1867,40 @@
os.path.join( relative_install_dir, name ),
repository,
repository_tools_tups )
- # Create tool_dependency records if necessary.
- if 'tool_dependencies' in metadata_dict:
- tool_dependencies = tool_dependency_util.create_tool_dependency_objects( trans.app,
- repository,
- relative_install_dir,
- set_status=False )
+ if 'repository_dependencies' in metadata_dict or 'tool_dependencies' in metadata_dict:
+ if 'repository_dependencies' in metadata_dict:
+ # Updates received include newly defined repository dependencies, so allow the user
+ # the option of installting them. We cannot update the repository with the changes
+ # until that happens, so we have to send them along.
+ new_kwd = dict( tool_shed_url=tool_shed_url,
+ updating_repository_id=trans.security.encode_id( repository.id ),
+ updating_to_ctx_rev=latest_ctx_rev,
+ updating_to_changeset_revision=latest_changeset_revision,
+ encoded_updated_metadata=encoding_util.tool_shed_encode( metadata_dict ),
+ updating=True )
+ return self.prepare_for_install( trans, **new_kwd )
+ # Updates received did not include any newly defined repository dependencies but did include
+ # newly defined tool dependencies.
+ encoded_tool_dependencies_dict = encoding_util.tool_shed_encode( metadata_dict.get( 'tool_dependencies', {} ) )
+ encoded_relative_install_dir = encoding_util.tool_shed_encode( relative_install_dir )
+ new_kwd = dict( updating_repository_id=trans.security.encode_id( repository.id ),
+ updating_to_ctx_rev=latest_ctx_rev,
+ updating_to_changeset_revision=latest_changeset_revision,
+ encoded_updated_metadata=encoding_util.tool_shed_encode( metadata_dict ),
+ encoded_relative_install_dir=encoded_relative_install_dir,
+ encoded_tool_dependencies_dict=encoded_tool_dependencies_dict,
+ message=message,
+ status = status )
+ return self.install_tool_dependencies_with_update( trans, **new_kwd )
+ # Updates received did not include any newly defined repository dependencies or newly defined
+ # tool dependencies.
+ repository = repository_util.update_repository_record( trans,
+ repository=repository,
+ updated_metadata_dict=metadata_dict,
+ updated_changeset_revision=latest_changeset_revision,
+ updated_ctx_rev=latest_ctx_rev )
message = "The installed repository named '%s' has been updated to change set revision '%s'. " % \
( name, latest_changeset_revision )
- # See if any tool dependencies can be installed.
- shed_tool_conf, tool_path, relative_install_dir = \
- suc.get_tool_panel_config_tool_path_install_dir( trans.app, repository )
- if repository.missing_tool_dependencies:
- message += "Click the name of one of the missing tool dependencies listed below to install tool dependencies."
else:
message = "The directory containing the installed repository named '%s' cannot be found. " % name
status = 'error'
diff -r e298d029472150df08bfae9b6ec311c78cb63dfd -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -4,7 +4,6 @@
import base64
import httplib
import json
-import math
import os
import sgmllib
import svgfig
@@ -20,12 +19,9 @@
from galaxy.datatypes.data import Data
from galaxy.model.item_attrs import UsesItemRatings
from galaxy.model.mapping import desc
+from galaxy.tools.parameters.basic import DataToolParameter
from galaxy.tools.parameters import visit_input_values
-from galaxy.tools.parameters.basic import DataToolParameter, DrillDownSelectToolParameter, SelectToolParameter, UnvalidatedValue
-from galaxy.tools.parameters.grouping import Conditional, Repeat
-from galaxy.util.odict import odict
from galaxy.util.sanitize_html import sanitize_html
-from galaxy.util.topsort import CycleError, topsort, topsort_levels
from galaxy.web import error, url_for
from galaxy.web.base.controller import BaseUIController, SharableMixin, UsesStoredWorkflowMixin
from galaxy.web.framework import form
@@ -33,6 +29,14 @@
from galaxy.web.framework.helpers import to_unicode
from galaxy.workflow.modules import module_factory
from galaxy.workflow.run import invoke
+from galaxy.workflow.extract import summarize
+from galaxy.workflow.extract import extract_workflow
+from galaxy.workflow.steps import (
+ attach_ordered_steps,
+ order_workflow_steps,
+ edgelist_for_workflow_steps,
+ order_workflow_steps_with_levels,
+)
class StoredWorkflowListGrid( grids.Grid ):
@@ -1188,7 +1192,7 @@
if not user:
return trans.show_error_message( "Must be logged in to create workflows" )
if ( job_ids is None and dataset_ids is None ) or workflow_name is None:
- jobs, warnings = get_job_dict( trans )
+ jobs, warnings = summarize( trans )
# Render
return trans.fill_template(
"workflow/build_from_current_history.mako",
@@ -1197,82 +1201,13 @@
history=history
)
else:
- # Ensure job_ids and dataset_ids are lists (possibly empty)
- if job_ids is None:
- job_ids = []
- elif type( job_ids ) is not list:
- job_ids = [ job_ids ]
- if dataset_ids is None:
- dataset_ids = []
- elif type( dataset_ids ) is not list:
- dataset_ids = [ dataset_ids ]
- # Convert both sets of ids to integers
- job_ids = [ int( id ) for id in job_ids ]
- dataset_ids = [ int( id ) for id in dataset_ids ]
- # Find each job, for security we (implicately) check that they are
- # associated witha job in the current history.
- jobs, warnings = get_job_dict( trans )
- jobs_by_id = dict( ( job.id, job ) for job in jobs.keys() )
- steps = []
- steps_by_job_id = {}
- hid_to_output_pair = {}
- # Input dataset steps
- for hid in dataset_ids:
- step = model.WorkflowStep()
- step.type = 'data_input'
- step.tool_inputs = dict( name="Input Dataset" )
- hid_to_output_pair[ hid ] = ( step, 'output' )
- steps.append( step )
- # Tool steps
- for job_id in job_ids:
- assert job_id in jobs_by_id, "Attempt to create workflow with job not connected to current history"
- job = jobs_by_id[ job_id ]
- tool = trans.app.toolbox.get_tool( job.tool_id )
- param_values = job.get_param_values( trans.app, ignore_errors=True ) # If a tool was updated and e.g. had a text value changed to an integer, we don't want a traceback here
- associations = cleanup_param_values( tool.inputs, param_values )
- step = model.WorkflowStep()
- step.type = 'tool'
- step.tool_id = job.tool_id
- step.tool_inputs = tool.params_to_strings( param_values, trans.app )
- # NOTE: We shouldn't need to do two passes here since only
- # an earlier job can be used as an input to a later
- # job.
- for other_hid, input_name in associations:
- if other_hid in hid_to_output_pair:
- other_step, other_name = hid_to_output_pair[ other_hid ]
- conn = model.WorkflowStepConnection()
- conn.input_step = step
- conn.input_name = input_name
- # Should always be connected to an earlier step
- conn.output_step = other_step
- conn.output_name = other_name
- steps.append( step )
- steps_by_job_id[ job_id ] = step
- # Store created dataset hids
- for assoc in job.output_datasets:
- hid_to_output_pair[ assoc.dataset.hid ] = ( step, assoc.name )
- # Workflow to populate
- workflow = model.Workflow()
- workflow.name = workflow_name
- # Order the steps if possible
- attach_ordered_steps( workflow, steps )
- # And let's try to set up some reasonable locations on the canvas
- # (these are pretty arbitrary values)
- levorder = order_workflow_steps_with_levels( steps )
- base_pos = 10
- for i, steps_at_level in enumerate( levorder ):
- for j, index in enumerate( steps_at_level ):
- step = steps[ index ]
- step.position = dict( top=( base_pos + 120 * j ),
- left=( base_pos + 220 * i ) )
- # Store it
- stored = model.StoredWorkflow()
- stored.user = user
- stored.name = workflow_name
- workflow.stored_workflow = stored
- stored.latest_workflow = workflow
- trans.sa_session.add( stored )
- trans.sa_session.flush()
+ extract_workflow(
+ trans,
+ user=user,
+ job_ids=job_ids,
+ dataset_ids=dataset_ids,
+ workflow_name=workflow_name
+ )
# Index page with message
return trans.show_message( "Workflow '%s' created from current history." % workflow_name )
## return trans.show_ok_message( "<p>Workflow '%s' created.</p><p><a target='_top' href='%s'>Click to load in workflow editor</a></p>"
@@ -1692,148 +1627,6 @@
## ---- Utility methods -------------------------------------------------------
-def attach_ordered_steps( workflow, steps ):
- ordered_steps = order_workflow_steps( steps )
- if ordered_steps:
- workflow.has_cycles = False
- for i, step in enumerate( ordered_steps ):
- step.order_index = i
- workflow.steps.append( step )
- else:
- workflow.has_cycles = True
- workflow.steps = steps
-
-
-def edgelist_for_workflow_steps( steps ):
- """
- Create a list of tuples representing edges between ``WorkflowSteps`` based
- on associated ``WorkflowStepConnection``s
- """
- edges = []
- steps_to_index = dict( ( step, i ) for i, step in enumerate( steps ) )
- for step in steps:
- edges.append( ( steps_to_index[step], steps_to_index[step] ) )
- for conn in step.input_connections:
- edges.append( ( steps_to_index[conn.output_step], steps_to_index[conn.input_step] ) )
- return edges
-
-
-def order_workflow_steps( steps ):
- """
- Perform topological sort of the steps, return ordered or None
- """
- position_data_available = True
- for step in steps:
- if not step.position or not 'left' in step.position or not 'top' in step.position:
- position_data_available = False
- if position_data_available:
- steps.sort(cmp=lambda s1, s2: cmp( math.sqrt(s1.position['left'] ** 2 + s1.position['top'] ** 2), math.sqrt(s2.position['left'] ** 2 + s2.position['top'] ** 2)))
- try:
- edges = edgelist_for_workflow_steps( steps )
- node_order = topsort( edges )
- return [ steps[i] for i in node_order ]
- except CycleError:
- return None
-
-
-def order_workflow_steps_with_levels( steps ):
- try:
- return topsort_levels( edgelist_for_workflow_steps( steps ) )
- except CycleError:
- return None
-
-
-class FakeJob( object ):
- """
- Fake job object for datasets that have no creating_job_associations,
- they will be treated as "input" datasets.
- """
- def __init__( self, dataset ):
- self.is_fake = True
- self.id = "fake_%s" % dataset.id
-
-
-def get_job_dict( trans ):
- """
- Return a dictionary of Job -> [ Dataset ] mappings, for all finished
- active Datasets in the current history and the jobs that created them.
- """
- history = trans.get_history()
- # Get the jobs that created the datasets
- warnings = set()
- jobs = odict()
- for dataset in history.active_datasets:
- # FIXME: Create "Dataset.is_finished"
- if dataset.state in ( 'new', 'running', 'queued' ):
- warnings.add( "Some datasets still queued or running were ignored" )
- continue
-
- #if this hda was copied from another, we need to find the job that created the origial hda
- job_hda = dataset
- while job_hda.copied_from_history_dataset_association:
- job_hda = job_hda.copied_from_history_dataset_association
-
- if not job_hda.creating_job_associations:
- jobs[ FakeJob( dataset ) ] = [ ( None, dataset ) ]
-
- for assoc in job_hda.creating_job_associations:
- job = assoc.job
- if job in jobs:
- jobs[ job ].append( ( assoc.name, dataset ) )
- else:
- jobs[ job ] = [ ( assoc.name, dataset ) ]
- return jobs, warnings
-
-
-def cleanup_param_values( inputs, values ):
- """
- Remove 'Data' values from `param_values`, along with metadata cruft,
- but track the associations.
- """
- associations = []
- # dbkey is pushed in by the framework
- if 'dbkey' in values:
- del values['dbkey']
- root_values = values
-
- # Recursively clean data inputs and dynamic selects
- def cleanup( prefix, inputs, values ):
- for key, input in inputs.items():
- if isinstance( input, ( SelectToolParameter, DrillDownSelectToolParameter ) ):
- if input.is_dynamic and not isinstance( values[key], UnvalidatedValue ):
- values[key] = UnvalidatedValue( values[key] )
- if isinstance( input, DataToolParameter ):
- tmp = values[key]
- values[key] = None
- # HACK: Nested associations are not yet working, but we
- # still need to clean them up so we can serialize
- # if not( prefix ):
- if tmp: # this is false for a non-set optional dataset
- if not isinstance(tmp, list):
- associations.append( ( tmp.hid, prefix + key ) )
- else:
- associations.extend( [ (t.hid, prefix + key) for t in tmp] )
-
- # Cleanup the other deprecated crap associated with datasets
- # as well. Worse, for nested datasets all the metadata is
- # being pushed into the root. FIXME: MUST REMOVE SOON
- key = prefix + key + "_"
- for k in root_values.keys():
- if k.startswith( key ):
- del root_values[k]
- elif isinstance( input, Repeat ):
- group_values = values[key]
- for i, rep_values in enumerate( group_values ):
- rep_index = rep_values['__index__']
- cleanup( "%s%s_%d|" % (prefix, key, rep_index ), input.inputs, group_values[i] )
- elif isinstance( input, Conditional ):
- group_values = values[input.name]
- current_case = group_values['__current_case__']
- cleanup( "%s%s|" % ( prefix, key ), input.cases[current_case].inputs, group_values )
- cleanup( "", inputs, values )
- return associations
-
-
def _build_workflow_on_str(instance_ds_names):
# Returns suffix for new histories based on multi input iteration
num_multi_inputs = len(instance_ds_names)
diff -r e298d029472150df08bfae9b6ec311c78cb63dfd -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 lib/galaxy/webapps/tool_shed/controllers/repository.py
--- a/lib/galaxy/webapps/tool_shed/controllers/repository.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py
@@ -866,11 +866,13 @@
no_update = 'false'
elif galaxy_url:
# Start building up the url to redirect back to the calling Galaxy instance.
+ params = '?tool_shed_url=%s&name=%s&owner=%s&changeset_revision=%s&latest_changeset_revision=' % \
+ ( web.url_for( '/', qualified=True ), repository.name, repository.user.username, changeset_revision )
url = suc.url_join( galaxy_url,
- 'admin_toolshed/update_to_changeset_revision?tool_shed_url=%s&name=%s&owner=%s&changeset_revision=%s&latest_changeset_revision=' % \
- ( web.url_for( '/', qualified=True ), repository.name, repository.user.username, changeset_revision ) )
+ 'admin_toolshed/update_to_changeset_revision%s' % params )
else:
- message = 'Unable to check for updates due to an invalid Galaxy URL: <b>%s</b>. You may need to enable third-party cookies in your browser. ' % galaxy_url
+ message = 'Unable to check for updates due to an invalid Galaxy URL: <b>%s</b>. ' % galaxy_url
+ message += 'You may need to enable third-party cookies in your browser. '
return trans.show_error_message( message )
if changeset_revision == repository.tip( trans.app ):
# If changeset_revision is the repository tip, there are no additional updates.
@@ -883,15 +885,17 @@
trans.security.encode_id( repository.id ),
changeset_revision )
if repository_metadata:
- # If changeset_revision is in the repository_metadata table for this repository, there are no additional updates.
+ # If changeset_revision is in the repository_metadata table for this repository, there are no
+ # additional updates.
if from_update_manager:
return no_update
else:
# Return the same value for changeset_revision and latest_changeset_revision.
url += latest_changeset_revision
else:
- # The changeset_revision column in the repository_metadata table has been updated with a new changeset_revision value since the
- # repository was installed. We need to find the changeset_revision to which we need to update.
+ # The changeset_revision column in the repository_metadata table has been updated with a new
+ # changeset_revision value since the repository was installed. We need to find the changeset_revision
+ # to which we need to update.
update_to_changeset_hash = None
for changeset in repo.changelog:
changeset_hash = str( repo.changectx( changeset ) )
@@ -1680,6 +1684,16 @@
return encoding_util.tool_shed_encode( repository_dependencies )
return ''
+ @web.expose
+ def get_repository_id( self, trans, **kwd ):
+ """Given a repository name and owner, return the encoded repository id."""
+ repository_name = kwd[ 'name' ]
+ repository_owner = kwd[ 'owner' ]
+ repository = suc.get_repository_by_name_and_owner( trans.app, repository_name, repository_owner )
+ if repository:
+ return trans.security.encode_id( repository.id )
+ return ''
+
@web.json
def get_repository_information( self, trans, repository_ids, changeset_revisions, **kwd ):
"""
@@ -1824,7 +1838,9 @@
if not repository_metadata:
# The received changeset_revision is no longer associated with metadata, so get the next changeset_revision in the repository
# changelog that is associated with metadata.
- changeset_revision = suc.get_next_downloadable_changeset_revision( repository, repo, after_changeset_revision=changeset_revision )
+ changeset_revision = suc.get_next_downloadable_changeset_revision( repository,
+ repo,
+ after_changeset_revision=changeset_revision )
repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, repository_id, changeset_revision )
ctx = suc.get_changectx_for_changeset( repo, changeset_revision )
repo_info_dict = repository_util.create_repo_info_dict( trans=trans,
@@ -2039,11 +2055,12 @@
galaxy_url = suc.handle_galaxy_url( trans, **kwd )
if galaxy_url:
# Redirect back to local Galaxy to perform install.
+ params = '?tool_shed_url=%s&repository_ids=%s&changeset_revisions=%s' % \
+ ( web.url_for( '/', qualified=True ),
+ ','.join( util.listify( repository_ids ) ),
+ ','.join( util.listify( changeset_revisions ) ) )
url = suc.url_join( galaxy_url,
- 'admin_toolshed/prepare_for_install?tool_shed_url=%s&repository_ids=%s&changeset_revisions=%s' % \
- ( web.url_for( '/', qualified=True ),
- ','.join( util.listify( repository_ids ) ),
- ','.join( util.listify( changeset_revisions ) ) ) )
+ 'admin_toolshed/prepare_for_install%s' % params )
return trans.response.send_redirect( url )
else:
message = 'Repository installation is not possible due to an invalid Galaxy URL: <b>%s</b>. ' % galaxy_url
@@ -2477,9 +2494,10 @@
@web.expose
def next_installable_changeset_revision( self, trans, **kwd ):
"""
- Handle a request from a Galaxy instance where the changeset_revision defined for a repository in a dependency definition file is older
- than the changeset_revision associated with the installed repository. This will occur with repository's of type tool_dependency_definition,
- and this scenario will occur while repository dependency hierarchies are bing installed.
+ Handle a request from a Galaxy instance where the changeset_revision defined for a repository
+ in a dependency definition file is older than the changeset_revision associated with the installed
+ repository. This will occur with repository's of type tool_dependency_definition, and this scenario
+ will occur while repository dependency hierarchies are bing installed.
"""
name = kwd.get( 'name', None )
owner = kwd.get( 'owner', None )
@@ -2981,12 +2999,13 @@
@web.expose
def updated_changeset_revisions( self, trans, **kwd ):
"""
- Handle a request from a local Galaxy instance to retrieve the list of changeset revisions to which an installed repository can be updated. This
- method will return a string of comma-separated changeset revision hashes for all available updates to the received changeset revision. Among
- other things , this method handles the scenario where an installed tool shed repository's tool_dependency definition file defines a changeset
- revision for a complex repository dependency that is outdated. In other words, a defined changeset revision is older than the current changeset
- revision for the required repository, making it impossible to discover the repository without knowledge of revisions to which it could have been
- updated.
+ Handle a request from a local Galaxy instance to retrieve the list of changeset revisions to which an
+ installed repository can be updated. This method will return a string of comma-separated changeset revision
+ hashes for all available updates to the received changeset revision. Among other things , this method
+ handles the scenario where an installed tool shed repository's tool_dependency definition file defines a
+ changeset revision for a complex repository dependency that is outdated. In other words, a defined changeset
+ revision is older than the current changeset revision for the required repository, making it impossible to
+ discover the repository without knowledge of revisions to which it could have been updated.
"""
name = kwd.get( 'name', None )
owner = kwd.get( 'owner', None )
diff -r e298d029472150df08bfae9b6ec311c78cb63dfd -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 lib/galaxy/workflow/extract.py
--- /dev/null
+++ b/lib/galaxy/workflow/extract.py
@@ -0,0 +1,209 @@
+""" This module contains functionality to aid in extracting workflows from
+histories.
+"""
+from galaxy.util.odict import odict
+from galaxy import model
+from galaxy.tools.parameters.basic import (
+ DataToolParameter,
+ DrillDownSelectToolParameter,
+ SelectToolParameter,
+ UnvalidatedValue
+)
+from galaxy.tools.parameters.grouping import (
+ Conditional,
+ Repeat
+)
+from .steps import (
+ attach_ordered_steps,
+ order_workflow_steps_with_levels
+)
+
+WARNING_SOME_DATASETS_NOT_READY = "Some datasets still queued or running were ignored"
+
+
+def extract_workflow( trans, user, history=None, job_ids=None, dataset_ids=None, workflow_name=None ):
+ steps = extract_steps( trans, history=history, job_ids=job_ids, dataset_ids=dataset_ids )
+ # Workflow to populate
+ workflow = model.Workflow()
+ workflow.name = workflow_name
+ # Order the steps if possible
+ attach_ordered_steps( workflow, steps )
+ # And let's try to set up some reasonable locations on the canvas
+ # (these are pretty arbitrary values)
+ levorder = order_workflow_steps_with_levels( steps )
+ base_pos = 10
+ for i, steps_at_level in enumerate( levorder ):
+ for j, index in enumerate( steps_at_level ):
+ step = steps[ index ]
+ step.position = dict( top=( base_pos + 120 * j ),
+ left=( base_pos + 220 * i ) )
+ # Store it
+ stored = model.StoredWorkflow()
+ stored.user = user
+ stored.name = workflow_name
+ workflow.stored_workflow = stored
+ stored.latest_workflow = workflow
+ trans.sa_session.add( stored )
+ trans.sa_session.flush()
+ return stored
+
+
+def extract_steps( trans, history=None, job_ids=None, dataset_ids=None ):
+ # Ensure job_ids and dataset_ids are lists (possibly empty)
+ if job_ids is None:
+ job_ids = []
+ elif type( job_ids ) is not list:
+ job_ids = [ job_ids ]
+ if dataset_ids is None:
+ dataset_ids = []
+ elif type( dataset_ids ) is not list:
+ dataset_ids = [ dataset_ids ]
+ # Convert both sets of ids to integers
+ job_ids = [ int( id ) for id in job_ids ]
+ dataset_ids = [ int( id ) for id in dataset_ids ]
+ # Find each job, for security we (implicately) check that they are
+ # associated witha job in the current history.
+ jobs, warnings = summarize( trans, history=history )
+ jobs_by_id = dict( ( job.id, job ) for job in jobs.keys() )
+ steps = []
+ steps_by_job_id = {}
+ hid_to_output_pair = {}
+ # Input dataset steps
+ for hid in dataset_ids:
+ step = model.WorkflowStep()
+ step.type = 'data_input'
+ step.tool_inputs = dict( name="Input Dataset" )
+ hid_to_output_pair[ hid ] = ( step, 'output' )
+ steps.append( step )
+ # Tool steps
+ for job_id in job_ids:
+ assert job_id in jobs_by_id, "Attempt to create workflow with job not connected to current history"
+ job = jobs_by_id[ job_id ]
+ tool_inputs, associations = step_inputs( trans, job )
+ step = model.WorkflowStep()
+ step.type = 'tool'
+ step.tool_id = job.tool_id
+ step.tool_inputs = tool_inputs
+ # NOTE: We shouldn't need to do two passes here since only
+ # an earlier job can be used as an input to a later
+ # job.
+ for other_hid, input_name in associations:
+ if other_hid in hid_to_output_pair:
+ other_step, other_name = hid_to_output_pair[ other_hid ]
+ conn = model.WorkflowStepConnection()
+ conn.input_step = step
+ conn.input_name = input_name
+ # Should always be connected to an earlier step
+ conn.output_step = other_step
+ conn.output_name = other_name
+ steps.append( step )
+ steps_by_job_id[ job_id ] = step
+ # Store created dataset hids
+ for assoc in job.output_datasets:
+ hid_to_output_pair[ assoc.dataset.hid ] = ( step, assoc.name )
+ return steps
+
+
+class FakeJob( object ):
+ """
+ Fake job object for datasets that have no creating_job_associations,
+ they will be treated as "input" datasets.
+ """
+ def __init__( self, dataset ):
+ self.is_fake = True
+ self.id = "fake_%s" % dataset.id
+
+
+def summarize( trans, history=None ):
+ """ Return mapping of job description to datasets for active items in
+ supplied history - needed for building workflow from a history.
+
+ Formerly call get_job_dict in workflow web controller.
+ """
+ if not history:
+ history = trans.get_history()
+
+ # Get the jobs that created the datasets
+ warnings = set()
+ jobs = odict()
+ for dataset in history.active_datasets:
+ # FIXME: Create "Dataset.is_finished"
+ if dataset.state in ( 'new', 'running', 'queued' ):
+ warnings.add( WARNING_SOME_DATASETS_NOT_READY )
+ continue
+
+ #if this hda was copied from another, we need to find the job that created the origial hda
+ job_hda = dataset
+ while job_hda.copied_from_history_dataset_association:
+ job_hda = job_hda.copied_from_history_dataset_association
+
+ if not job_hda.creating_job_associations:
+ jobs[ FakeJob( dataset ) ] = [ ( None, dataset ) ]
+
+ for assoc in job_hda.creating_job_associations:
+ job = assoc.job
+ if job in jobs:
+ jobs[ job ].append( ( assoc.name, dataset ) )
+ else:
+ jobs[ job ] = [ ( assoc.name, dataset ) ]
+
+ return jobs, warnings
+
+
+def step_inputs( trans, job ):
+ tool = trans.app.toolbox.get_tool( job.tool_id )
+ param_values = job.get_param_values( trans.app, ignore_errors=True ) # If a tool was updated and e.g. had a text value changed to an integer, we don't want a traceback here
+ associations = __cleanup_param_values( tool.inputs, param_values )
+ tool_inputs = tool.params_to_strings( param_values, trans.app )
+ return tool_inputs, associations
+
+
+def __cleanup_param_values( inputs, values ):
+ """
+ Remove 'Data' values from `param_values`, along with metadata cruft,
+ but track the associations.
+ """
+ associations = []
+ # dbkey is pushed in by the framework
+ if 'dbkey' in values:
+ del values['dbkey']
+ root_values = values
+
+ # Recursively clean data inputs and dynamic selects
+ def cleanup( prefix, inputs, values ):
+ for key, input in inputs.items():
+ if isinstance( input, ( SelectToolParameter, DrillDownSelectToolParameter ) ):
+ if input.is_dynamic and not isinstance( values[key], UnvalidatedValue ):
+ values[key] = UnvalidatedValue( values[key] )
+ if isinstance( input, DataToolParameter ):
+ tmp = values[key]
+ values[key] = None
+ # HACK: Nested associations are not yet working, but we
+ # still need to clean them up so we can serialize
+ # if not( prefix ):
+ if tmp: # this is false for a non-set optional dataset
+ if not isinstance(tmp, list):
+ associations.append( ( tmp.hid, prefix + key ) )
+ else:
+ associations.extend( [ (t.hid, prefix + key) for t in tmp] )
+
+ # Cleanup the other deprecated crap associated with datasets
+ # as well. Worse, for nested datasets all the metadata is
+ # being pushed into the root. FIXME: MUST REMOVE SOON
+ key = prefix + key + "_"
+ for k in root_values.keys():
+ if k.startswith( key ):
+ del root_values[k]
+ elif isinstance( input, Repeat ):
+ group_values = values[key]
+ for i, rep_values in enumerate( group_values ):
+ rep_index = rep_values['__index__']
+ cleanup( "%s%s_%d|" % (prefix, key, rep_index ), input.inputs, group_values[i] )
+ elif isinstance( input, Conditional ):
+ group_values = values[input.name]
+ current_case = group_values['__current_case__']
+ cleanup( "%s%s|" % ( prefix, key ), input.cases[current_case].inputs, group_values )
+ cleanup( "", inputs, values )
+ return associations
+
+__all__ = [ summarize, extract_workflow ]
diff -r e298d029472150df08bfae9b6ec311c78cb63dfd -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 lib/galaxy/workflow/steps.py
--- /dev/null
+++ b/lib/galaxy/workflow/steps.py
@@ -0,0 +1,63 @@
+""" This module contains utility methods for reasoning about and ordering
+workflow steps.
+"""
+import math
+from galaxy.util.topsort import (
+ CycleError,
+ topsort,
+ topsort_levels
+)
+
+
+def attach_ordered_steps( workflow, steps ):
+ """ Attempt to topologically order steps and attach to workflow. If this
+ fails - the workflow contains cycles so it mark it as such.
+ """
+ ordered_steps = order_workflow_steps( steps )
+ if ordered_steps:
+ workflow.has_cycles = False
+ for i, step in enumerate( ordered_steps ):
+ step.order_index = i
+ workflow.steps.append( step )
+ else:
+ workflow.has_cycles = True
+ workflow.steps = steps
+
+
+def order_workflow_steps( steps ):
+ """
+ Perform topological sort of the steps, return ordered or None
+ """
+ position_data_available = True
+ for step in steps:
+ if not step.position or not 'left' in step.position or not 'top' in step.position:
+ position_data_available = False
+ if position_data_available:
+ steps.sort(cmp=lambda s1, s2: cmp( math.sqrt(s1.position['left'] ** 2 + s1.position['top'] ** 2), math.sqrt(s2.position['left'] ** 2 + s2.position['top'] ** 2)))
+ try:
+ edges = edgelist_for_workflow_steps( steps )
+ node_order = topsort( edges )
+ return [ steps[i] for i in node_order ]
+ except CycleError:
+ return None
+
+
+def edgelist_for_workflow_steps( steps ):
+ """
+ Create a list of tuples representing edges between ``WorkflowSteps`` based
+ on associated ``WorkflowStepConnection``s
+ """
+ edges = []
+ steps_to_index = dict( ( step, i ) for i, step in enumerate( steps ) )
+ for step in steps:
+ edges.append( ( steps_to_index[step], steps_to_index[step] ) )
+ for conn in step.input_connections:
+ edges.append( ( steps_to_index[conn.output_step], steps_to_index[conn.input_step] ) )
+ return edges
+
+
+def order_workflow_steps_with_levels( steps ):
+ try:
+ return topsort_levels( edgelist_for_workflow_steps( steps ) )
+ except CycleError:
+ return None
diff -r e298d029472150df08bfae9b6ec311c78cb63dfd -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 lib/tool_shed/galaxy_install/repository_util.py
--- a/lib/tool_shed/galaxy_install/repository_util.py
+++ b/lib/tool_shed/galaxy_install/repository_util.py
@@ -37,15 +37,19 @@
Galaxy instance. The dictionary will also contain the recursive list of repository dependencies defined
for the repository, as well as the defined tool dependencies.
- This method is called from Galaxy under three scenarios:
+ This method is called from Galaxy under four scenarios:
1. During the tool shed repository installation process via the tool shed's get_repository_information()
- method. In this case both the received repository and repository_metadata will be objects., but
+ method. In this case both the received repository and repository_metadata will be objects, but
tool_dependencies and repository_dependencies will be None.
- 2. When a tool shed repository that was uninstalled from a Galaxy instance is being reinstalled with no
+ 2. When getting updates for an install repository where the updates include newly defined repository
+ dependency definitions. This scenario is similar to 1. above. The tool shed's get_repository_information()
+ method is the caller, and both the received repository and repository_metadata will be objects, but
+ tool_dependencies and repository_dependencies will be None.
+ 3. When a tool shed repository that was uninstalled from a Galaxy instance is being reinstalled with no
updates available. In this case, both repository and repository_metadata will be None, but tool_dependencies
and repository_dependencies will be objects previously retrieved from the tool shed if the repository includes
definitions for them.
- 3. When a tool shed repository that was uninstalled from a Galaxy instance is being reinstalled with updates
+ 4. When a tool shed repository that was uninstalled from a Galaxy instance is being reinstalled with updates
available. In this case, this method is reached via the tool shed's get_updated_repository_information()
method, and both repository and repository_metadata will be objects but tool_dependencies and
repository_dependencies will be None.
@@ -184,16 +188,22 @@
repo_dir = repository.repo_path( trans.app )
repo = hg.repository( suc.get_configured_ui(), repo_dir )
repository_clone_url = suc.generate_clone_url_for_repository_in_tool_shed( trans, repository )
- repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, repository_id, changeset_revision )
+ repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans,
+ repository_id,
+ changeset_revision )
if not repository_metadata:
- # The received changeset_revision is no longer installable, so get the next changeset_revision in the repository's changelog.
- # This generally occurs only with repositories of type tool_dependency_definition.
- next_downloadable_changeset_revision = suc.get_next_downloadable_changeset_revision( repository, repo, changeset_revision )
+ # The received changeset_revision is no longer installable, so get the next changeset_revision
+ # in the repository's changelog. This generally occurs only with repositories of type
+ # tool_dependency_definition.
+ next_downloadable_changeset_revision = \
+ suc.get_next_downloadable_changeset_revision( repository,repo, changeset_revision )
if next_downloadable_changeset_revision:
- repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, repository_id, next_downloadable_changeset_revision )
+ repository_metadata = \
+ suc.get_repository_metadata_by_changeset_revision( trans, repository_id, next_downloadable_changeset_revision )
if repository_metadata:
- # For now, we'll always assume that we'll get repository_metadata, but if we discover our assumption is not valid we'll have to
- # enhance the callers to handle repository_metadata values of None in the returned repo_info_dict.
+ # For now, we'll always assume that we'll get repository_metadata, but if we discover our assumption
+ # is not valid we'll have to enhance the callers to handle repository_metadata values of None in the
+ # returned repo_info_dict.
metadata = repository_metadata.metadata
if 'tools' in metadata:
includes_tools = True
@@ -743,9 +753,13 @@
ordered_tool_panel_section_keys.append( tool_panel_section_key )
return ordered_tsr_ids, ordered_repo_info_dicts, ordered_tool_panel_section_keys
-def populate_containers_dict_for_new_install( trans, tool_shed_url, tool_path, readme_files_dict, installed_repository_dependencies, missing_repository_dependencies,
- installed_tool_dependencies, missing_tool_dependencies ):
- """Return the populated containers for a repository being installed for the first time."""
+def populate_containers_dict_for_new_install( trans, tool_shed_url, tool_path, readme_files_dict, installed_repository_dependencies,
+ missing_repository_dependencies, installed_tool_dependencies, missing_tool_dependencies,
+ updating=False ):
+ """
+ Return the populated containers for a repository being installed for the first time or for an installed repository
+ that is being updated and the updates include newly defined repository (and possibly tool) dependencies.
+ """
installed_tool_dependencies, missing_tool_dependencies = \
tool_dependency_util.populate_tool_dependencies_dicts( trans=trans,
tool_shed_url=tool_shed_url,
@@ -753,27 +767,32 @@
repository_installed_tool_dependencies=installed_tool_dependencies,
repository_missing_tool_dependencies=missing_tool_dependencies,
required_repo_info_dicts=None )
- # Since we are installing a new repository, most of the repository contents are set to None since we don't yet know what they are.
- containers_dict = container_util.build_repository_containers_for_galaxy( trans=trans,
- repository=None,
- datatypes=None,
- invalid_tools=None,
- missing_repository_dependencies=missing_repository_dependencies,
- missing_tool_dependencies=missing_tool_dependencies,
- readme_files_dict=readme_files_dict,
- repository_dependencies=installed_repository_dependencies,
- tool_dependencies=installed_tool_dependencies,
- valid_tools=None,
- workflows=None,
- valid_data_managers=None,
- invalid_data_managers=None,
- data_managers_errors=None,
- new_install=True,
- reinstalling=False )
- # Merge the missing_repository_dependencies container contents to the installed_repository_dependencies container.
- containers_dict = repository_dependency_util.merge_missing_repository_dependencies_to_installed_container( containers_dict )
- # Merge the missing_tool_dependencies container contents to the installed_tool_dependencies container.
- containers_dict = tool_dependency_util.merge_missing_tool_dependencies_to_installed_container( containers_dict )
+ # Most of the repository contents are set to None since we don't yet know what they are.
+ containers_dict = \
+ container_util.build_repository_containers_for_galaxy( trans=trans,
+ repository=None,
+ datatypes=None,
+ invalid_tools=None,
+ missing_repository_dependencies=missing_repository_dependencies,
+ missing_tool_dependencies=missing_tool_dependencies,
+ readme_files_dict=readme_files_dict,
+ repository_dependencies=installed_repository_dependencies,
+ tool_dependencies=installed_tool_dependencies,
+ valid_tools=None,
+ workflows=None,
+ valid_data_managers=None,
+ invalid_data_managers=None,
+ data_managers_errors=None,
+ new_install=True,
+ reinstalling=False )
+ if not updating:
+ # If we installing a new repository and not updaing an installed repository, we can merge
+ # the missing_repository_dependencies container contents to the installed_repository_dependencies
+ # container. When updating an installed repository, merging will result in losing newly defined
+ # dependencies included in the updates.
+ containers_dict = repository_dependency_util.merge_missing_repository_dependencies_to_installed_container( containers_dict )
+ # Merge the missing_tool_dependencies container contents to the installed_tool_dependencies container.
+ containers_dict = tool_dependency_util.merge_missing_tool_dependencies_to_installed_container( containers_dict )
return containers_dict
def pull_repository( repo, repository_clone_url, ctx_rev ):
@@ -875,3 +894,23 @@
repository.uninstalled = uninstalled
trans.install_model.context.add( repository )
trans.install_model.context.flush()
+
+def update_repository_record( trans, repository, updated_metadata_dict, updated_changeset_revision, updated_ctx_rev ):
+ """
+ Update a tool_shed_repository database record with new information retrieved from the
+ Tool Shed. This happens when updating an installed repository to a new changeset revision.
+ """
+ repository.metadata = updated_metadata_dict
+ # Update the repository.changeset_revision column in the database.
+ repository.changeset_revision = updated_changeset_revision
+ repository.ctx_rev = updated_ctx_rev
+ # Update the repository.tool_shed_status column in the database.
+ tool_shed_status_dict = suc.get_tool_shed_status_for_installed_repository( trans.app, repository )
+ if tool_shed_status_dict:
+ repository.tool_shed_status = tool_shed_status_dict
+ else:
+ repository.tool_shed_status = None
+ trans.install_model.context.add( repository )
+ trans.install_model.context.flush()
+ trans.install_model.context.refresh( repository )
+ return repository
diff -r e298d029472150df08bfae9b6ec311c78cb63dfd -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
@@ -359,13 +359,14 @@
can_install_tool_dependency = True
if can_install_tool_dependency:
package_install_version = package_elem.get( 'version', '1.0' )
- tool_dependency = tool_dependency_util.create_or_update_tool_dependency( app=app,
- tool_shed_repository=tool_shed_repository,
- name=package_name,
- version=package_version,
- type='package',
- status=app.install_model.ToolDependency.installation_status.INSTALLING,
- set_status=True )
+ tool_dependency = \
+ tool_dependency_util.create_or_update_tool_dependency( app=app,
+ tool_shed_repository=tool_shed_repository,
+ name=package_name,
+ version=package_version,
+ type='package',
+ status=app.install_model.ToolDependency.installation_status.INSTALLING,
+ set_status=True )
# Get the information about the current platform in case the tool dependency definition includes tag sets
# for installing compiled binaries.
platform_info_dict = tool_dependency_util.get_platform_info_dict()
@@ -879,25 +880,28 @@
# Tool dependencies of type "set_environmnet" always have the version attribute set to None.
attr_tup = ( env_var_name, None, 'set_environment' )
if attr_tup in attr_tups_of_dependencies_for_install:
- install_dir = tool_dependency_util.get_tool_dependency_install_dir( app=app,
- repository_name=tool_shed_repository.name,
- repository_owner=tool_shed_repository.owner,
- repository_changeset_revision=tool_shed_repository.installed_changeset_revision,
- tool_dependency_type='set_environment',
- tool_dependency_name=env_var_name,
- tool_dependency_version=None )
+ install_dir = \
+ tool_dependency_util.get_tool_dependency_install_dir( app=app,
+ repository_name=tool_shed_repository.name,
+ repository_owner=tool_shed_repository.owner,
+ repository_changeset_revision=tool_shed_repository.installed_changeset_revision,
+ tool_dependency_type='set_environment',
+ tool_dependency_name=env_var_name,
+ tool_dependency_version=None )
tool_shed_repository_install_dir = get_tool_shed_repository_install_dir( app, tool_shed_repository )
env_var_dict = td_common_util.create_env_var_dict( env_var_elem, tool_shed_repository_install_dir=tool_shed_repository_install_dir )
if env_var_dict:
if not os.path.exists( install_dir ):
os.makedirs( install_dir )
- tool_dependency = tool_dependency_util.create_or_update_tool_dependency( app=app,
- tool_shed_repository=tool_shed_repository,
- name=env_var_name,
- version=None,
- type='set_environment',
- status=app.install_model.ToolDependency.installation_status.INSTALLING,
- set_status=True )
+ status = app.install_model.ToolDependency.installation_status.INSTALLING
+ tool_dependency = \
+ tool_dependency_util.create_or_update_tool_dependency( app=app,
+ tool_shed_repository=tool_shed_repository,
+ name=env_var_name,
+ version=None,
+ type='set_environment',
+ status=status,
+ set_status=True )
if env_var_version == '1.0':
# Create this tool dependency's env.sh file.
env_file_builder = fabric_util.EnvFileBuilder( install_dir )
@@ -906,28 +910,34 @@
error_message = 'Error creating env.sh file for tool dependency %s, return_code: %s' % \
( str( tool_dependency.name ), str( return_code ) )
log.debug( error_message )
- tool_dependency = tool_dependency_util.set_tool_dependency_attributes( app,
- tool_dependency=tool_dependency,
- status=app.install_model.ToolDependency.installation_status.ERROR,
- error_message=error_message,
- remove_from_disk=False )
+ status = app.install_model.ToolDependency.installation_status.ERROR
+ tool_dependency = \
+ tool_dependency_util.set_tool_dependency_attributes( app,
+ tool_dependency=tool_dependency,
+ status=status,
+ error_message=error_message,
+ remove_from_disk=False )
else:
if tool_dependency.status not in [ app.install_model.ToolDependency.installation_status.ERROR,
app.install_model.ToolDependency.installation_status.INSTALLED ]:
- tool_dependency = tool_dependency_util.set_tool_dependency_attributes( app,
- tool_dependency=tool_dependency,
- status=app.install_model.ToolDependency.installation_status.INSTALLED,
- error_message=None,
- remove_from_disk=False )
+ status = app.install_model.ToolDependency.installation_status.INSTALLED
+ tool_dependency = \
+ tool_dependency_util.set_tool_dependency_attributes( app,
+ tool_dependency=tool_dependency,
+ status=status,
+ error_message=None,
+ remove_from_disk=False )
log.debug( 'Environment variable %s set in %s for tool dependency %s.' % \
( str( env_var_name ), str( install_dir ), str( tool_dependency.name ) ) )
else:
error_message = 'Only set_environment version 1.0 is currently supported (i.e., change your tag to be <set_environment version="1.0">).'
- tool_dependency = tool_dependency_util.set_tool_dependency_attributes( app,
- tool_dependency=tool_dependency,
- status=app.install_model.ToolDependency.installation_status.ERROR,
- error_message=error_message,
- remove_from_disk=False )
+ status = app.install_model.ToolDependency.installation_status.ERROR
+ tool_dependency = \
+ tool_dependency_util.set_tool_dependency_attributes( app,
+ tool_dependency=tool_dependency,
+ status=status,
+ error_message=error_message,
+ remove_from_disk=False )
return tool_dependency
def strip_path( fpath ):
diff -r e298d029472150df08bfae9b6ec311c78cb63dfd -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 lib/tool_shed/util/common_install_util.py
--- a/lib/tool_shed/util/common_install_util.py
+++ b/lib/tool_shed/util/common_install_util.py
@@ -70,7 +70,7 @@
if display_path is not None:
datatype_util.load_installed_display_applications( trans.app, installed_repository_dict, deactivate=False )
-def get_dependencies_for_repository( trans, tool_shed_url, repo_info_dict, includes_tool_dependencies ):
+def get_dependencies_for_repository( trans, tool_shed_url, repo_info_dict, includes_tool_dependencies, updating=False ):
"""
Return dictionaries containing the sets of installed and missing tool dependencies and repository
dependencies associated with the repository defined by the received repo_info_dict.
@@ -90,7 +90,7 @@
# Inspect the tool_dependencies dictionary to separate the installed and missing tool dependencies.
# We don't add to installed_td and missing_td here because at this point they are empty.
installed_td, missing_td = \
- get_installed_and_missing_tool_dependencies_for_installing_repository( trans, tool_shed_url, tool_dependencies )
+ get_installed_and_missing_tool_dependencies_for_repository( trans, tool_shed_url, tool_dependencies )
# In cases where a repository dependency is required only for compiling a dependent repository's
# tool dependency, the value of repository_dependencies will be an empty dictionary here.
if repository_dependencies:
@@ -101,10 +101,11 @@
name,
repository_owner,
changeset_revision )
- if repository and repository.metadata:
+ if not updating and repository and repository.metadata:
installed_rd, missing_rd = get_installed_and_missing_repository_dependencies( trans, repository )
else:
- installed_rd, missing_rd = get_installed_and_missing_repository_dependencies_for_new_install( trans, repo_info_tuple )
+ installed_rd, missing_rd = \
+ get_installed_and_missing_repository_dependencies_for_new_or_updated_install( trans, repo_info_tuple )
# Discover all repository dependencies and retrieve information for installing them.
all_repo_info_dict = get_required_repo_info_dicts( trans, tool_shed_url, util.listify( repo_info_dict ) )
has_repository_dependencies = all_repo_info_dict.get( 'has_repository_dependencies', False )
@@ -119,7 +120,8 @@
required_tool_dependencies = {}
for rid in required_repo_info_dicts:
for name, repo_info_tuple in rid.items():
- description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, rid_repository_dependencies, rid_tool_dependencies = \
+ description, repository_clone_url, changeset_revision, ctx_rev, \
+ repository_owner, rid_repository_dependencies, rid_tool_dependencies = \
suc.get_repo_info_tuple_contents( repo_info_tuple )
if rid_tool_dependencies:
for td_key, td_dict in rid_tool_dependencies.items():
@@ -128,7 +130,9 @@
if required_tool_dependencies:
# Discover and categorize all tool dependencies defined for this repository's repository dependencies.
required_installed_td, required_missing_td = \
- get_installed_and_missing_tool_dependencies_for_installing_repository( trans, tool_shed_url, required_tool_dependencies )
+ get_installed_and_missing_tool_dependencies_for_repository( trans,
+ tool_shed_url,
+ required_tool_dependencies )
if required_installed_td:
if not includes_tool_dependencies:
includes_tool_dependencies = True
@@ -168,11 +172,12 @@
def get_installed_and_missing_repository_dependencies( trans, repository ):
"""
- Return the installed and missing repository dependencies for a tool shed repository that has a record in the Galaxy database, but
- may or may not be installed. In this case, the repository dependencies are associated with the repository in the database. Do not
- include a repository dependency if it is required only to compile a tool dependency defined for the dependent repository since these
- special kinds of repository dependencies are really a dependency of the dependent repository's contained tool dependency, and only if
- that tool dependency requires compilation.
+ Return the installed and missing repository dependencies for a tool shed repository that has a record
+ in the Galaxy database, but may or may not be installed. In this case, the repository dependencies are
+ associated with the repository in the database. Do not include a repository dependency if it is required
+ only to compile a tool dependency defined for the dependent repository since these special kinds of repository
+ dependencies are really a dependency of the dependent repository's contained tool dependency, and only
+ if that tool dependency requires compilation.
"""
missing_repository_dependencies = {}
installed_repository_dependencies = {}
@@ -228,7 +233,7 @@
missing_repository_dependencies[ 'description' ] = description
return installed_repository_dependencies, missing_repository_dependencies
-def get_installed_and_missing_repository_dependencies_for_new_install( trans, repo_info_tuple ):
+def get_installed_and_missing_repository_dependencies_for_new_or_updated_install( trans, repo_info_tuple ):
"""
Parse the received repository_dependencies dictionary that is associated with a repository being
installed into Galaxy for the first time and attempt to determine repository dependencies that are
@@ -264,13 +269,13 @@
tmp_repo_info_tuple )
if repository:
new_rd_tup = [ tool_shed,
- name,
- owner,
- changeset_revision,
- prior_installation_required,
- only_if_compiling_contained_td,
- repository.id,
- repository.status ]
+ name,
+ owner,
+ changeset_revision,
+ prior_installation_required,
+ only_if_compiling_contained_td,
+ repository.id,
+ repository.status ]
if repository.status == trans.install_model.ToolShedRepository.installation_status.INSTALLED:
if new_rd_tup not in installed_rd_tups:
installed_rd_tups.append( new_rd_tup )
@@ -285,12 +290,12 @@
missing_rd_tups.append( new_rd_tup )
else:
new_rd_tup = [ tool_shed,
- name,
- owner,
- changeset_revision,
- prior_installation_required,
- only_if_compiling_contained_td,
- None,
+ name,
+ owner,
+ changeset_revision,
+ prior_installation_required,
+ only_if_compiling_contained_td,
+ None,
'Never installed' ]
if not util.asbool( only_if_compiling_contained_td ):
# A repository dependency that is not installed will not be considered missing if it's value for
@@ -307,11 +312,17 @@
missing_repository_dependencies[ 'description' ] = description
return installed_repository_dependencies, missing_repository_dependencies
-def get_installed_and_missing_tool_dependencies_for_installing_repository( trans, tool_shed_url, tool_dependencies_dict ):
+def get_installed_and_missing_tool_dependencies_for_repository( trans, tool_shed_url, tool_dependencies_dict ):
"""
Return the lists of installed tool dependencies and missing tool dependencies for a set of repositories
being installed into Galaxy.
"""
+ # FIXME: This implementation breaks when updates to a repository contain dependencies that result in
+ # multiple entries for a specific tool dependency. A scenario where this can happen is where 2 repositories
+ # define the same dependency internally (not using the complex repository dependency definition to a separate
+ # package repository approach). If 2 repositories contain the same tool_dependencies.xml file, one dependency
+ # will be lost since the values in these returned dictionaries are not lists. All tool dependency dictionaries
+ # should have lists as values. These scenarios are probably extreme corner cases, but still should be handled.
installed_tool_dependencies = {}
missing_tool_dependencies = {}
if tool_dependencies_dict:
diff -r e298d029472150df08bfae9b6ec311c78cb63dfd -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 lib/tool_shed/util/container_util.py
--- a/lib/tool_shed/util/container_util.py
+++ b/lib/tool_shed/util/container_util.py
@@ -821,8 +821,8 @@
tool_dependencies = metadata[ 'tool_dependencies' ]
if trans.webapp.name == 'tool_shed':
if 'orphan_tool_dependencies' in metadata:
- # The use of the orphan_tool_dependencies category in metadata has been deprecated, but we still need to check in case
- # the metadata is out of date.
+ # The use of the orphan_tool_dependencies category in metadata has been deprecated,
+ # but we still need to check in case the metadata is out of date.
orphan_tool_dependencies = metadata[ 'orphan_tool_dependencies' ]
tool_dependencies.update( orphan_tool_dependencies )
# Tool dependencies can be categorized as orphans only if the repository contains tools.
diff -r e298d029472150df08bfae9b6ec311c78cb63dfd -r bc739e4b5bdf2a49a7c1a365b1e779df26d0f813 lib/tool_shed/util/encoding_util.py
--- a/lib/tool_shed/util/encoding_util.py
+++ b/lib/tool_shed/util/encoding_util.py
@@ -21,7 +21,6 @@
try:
values = json.loads( value )
except Exception, e:
- #log.debug( "Decoding json value from tool shed for value '%s' threw exception: %s" % ( str( value ), str( e ) ) )
pass
if values is not None:
try:
@@ -34,7 +33,7 @@
return values
def tool_shed_encode( val ):
- if isinstance( val, dict ):
+ if isinstance( val, dict ) or isinstance( val, list ):
value = json.dumps( val )
else:
value = val
This diff is so big that we needed to truncate the remainder.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Fix broken import with workflow PR.
by commits-noreply@bitbucket.org 26 Mar '14
by commits-noreply@bitbucket.org 26 Mar '14
26 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/8af539a3006b/
Changeset: 8af539a3006b
User: jmchilton
Date: 2014-03-26 22:28:31
Summary: Fix broken import with workflow PR.
Affected #: 1 file
diff -r 46d4a48fcb7b6dd736f081f5d8b650b0a33a296c -r 8af539a3006b24e027215af4f270b5db0d07c5e6 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -41,7 +41,7 @@
from galaxy.tools.parameters.basic import DataToolParameter
from galaxy.util.json import to_json_string
from galaxy.workflow.modules import ToolModule
-from galaxy.workflow.build_util import attach_ordered_steps
+from galaxy.workflow.steps import attach_ordered_steps
log = logging.getLogger( __name__ )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d5d2a3a7e244/
Changeset: d5d2a3a7e244
User: jmchilton
Date: 2014-03-20 16:43:24
Summary: Add dependency on requests 2.2.1.
Will improve and fix bugs in API testing and API driven tests of tools.
Affected #: 1 file
diff -r 215f23b27be962047909c7676fb8a42fa44ea053 -r d5d2a3a7e244a2ff91ca3392729ae7d58c4bb08b eggs.ini
--- a/eggs.ini
+++ b/eggs.ini
@@ -56,6 +56,7 @@
python_openid = 2.2.5
python_daemon = 1.5.5
pytz = 2013.9
+requests = 2.2.1
Routes = 1.12.3
sqlalchemy_migrate = 0.7.2
ssh = 1.7.14
https://bitbucket.org/galaxy/galaxy-central/commits/1996ad824139/
Changeset: 1996ad824139
User: jmchilton
Date: 2014-03-20 16:43:57
Summary: Force use of requests in API tests, eliminate hacked together compatibility layer.
Affected #: 1 file
diff -r d5d2a3a7e244a2ff91ca3392729ae7d58c4bb08b -r 1996ad824139dc5540a2844d90f0cd5cae0b0650 test/base/interactor.py
--- a/test/base/interactor.py
+++ b/test/base/interactor.py
@@ -1,6 +1,8 @@
import os
from StringIO import StringIO
from galaxy.tools.parameters import grouping
+from galaxy import eggs
+eggs.require( "requests" )
from galaxy.util import listify
from galaxy.util.odict import odict
import galaxy.model
@@ -424,104 +426,7 @@
}
-# Lets just try to use requests if it is available, but if not provide fallback
-# on custom implementations of limited requests get, put, etc... functionality.
-try:
- from requests import get as get_request
- from requests import post as post_request
- from requests import put as put_request
- from requests import delete as delete_request
-except ImportError:
- import urllib2
- import httplib
-
- class RequestsLikeResponse( object ):
-
- def __init__( self, content, status_code ):
- self.content = content
- self.status_code = status_code
-
- def json( self ):
- return loads( self.content )
-
- def get_request( url, params={} ):
- argsep = '&'
- if '?' not in url:
- argsep = '?'
- param_pairs = []
- for key, value in params.iteritems():
- # Handle single parameters or lists and tuples of them.
- if isinstance( value, tuple ):
- value = list( value )
- elif not isinstance( value, list ):
- value = [ value ]
- for val in value:
- param_pairs.append( "%s=%s" % ( key, val ) )
- url = url + argsep + '&'.join( param_pairs )
- #req = urllib2.Request( url, headers = { 'Content-Type': 'application/json' } )
- try:
- response = urllib2.urlopen( url )
- return RequestsLikeResponse( response.read(), status_code=response.getcode() )
- except urllib2.HTTPError as e:
- return RequestsLikeResponse( e.read(), status_code=e.code )
-
- def post_request( url, data, files={} ):
- return __multipart_request( url, data, files, verb="POST" )
-
- def put_request( url, data=None ):
- if isinstance( data, dict ):
- assert False, "This test will fail, Galaxy's webob dependency does not parse out urlencoded PUT/PATCH entity data, API will receive empty payload."
- return __urllib_request( url, 'PUT', json_str=data )
-
- def delete_request( url ):
- return __urllib_request( url, 'DELETE' )
-
- def __urllib_request( url, verb, json_str=None ):
- opener = urllib2.build_opener(urllib2.HTTPHandler)
- request = urllib2.Request(url)
- request.get_method = lambda: verb
- if json_str:
- request.add_header( "content-type", "application/json" )
- request.add_data(json_str)
- try:
- response = opener.open(request)
- return RequestsLikeResponse( response.read(), status_code=response.getcode() )
- except urllib2.HTTPError as e:
- return RequestsLikeResponse( e.read(), status_code=e.code )
-
- def __multipart_request( url, data, files={}, verb="POST" ):
- parsed_url = urllib2.urlparse.urlparse( url )
- return __multipart( host=parsed_url.netloc, selector=parsed_url.path, fields=data.iteritems(), files=(files or {}).iteritems(), verb=verb )
-
- # http://stackoverflow.com/a/681182
- def __multipart(host, selector, fields, files, verb="POST"):
- h = httplib.HTTP(host)
- h.putrequest(verb, selector)
- content_type, body = __encode_multipart_formdata(fields, files)
- h.putheader('content-type', content_type)
- h.putheader('content-length', str(len(body)))
- h.endheaders()
- h.send(body)
- errcode, errmsg, headers = h.getreply()
- return RequestsLikeResponse(h.file.read(), status_code=errcode)
-
- def __encode_multipart_formdata(fields, files):
- LIMIT = '----------lImIt_of_THE_fIle_eW_$'
- CRLF = '\r\n'
- L = []
- for (key, value) in fields:
- L.append('--' + LIMIT)
- L.append('Content-Disposition: form-data; name="%s"' % key)
- L.append('')
- L.append(value)
- for (key, value) in files:
- L.append('--' + LIMIT)
- L.append('Content-Disposition: form-data; name="%s"; filename="%s";' % (key, key))
- L.append('Content-Type: application/octet-stream')
- L.append('')
- L.append(value.read())
- L.append('--' + LIMIT + '--')
- L.append('')
- body = CRLF.join(L)
- content_type = 'multipart/form-data; boundary=%s' % LIMIT
- return content_type, body
+from requests import get as get_request
+from requests import post as post_request
+from requests import put as put_request
+from requests import delete as delete_request
https://bitbucket.org/galaxy/galaxy-central/commits/46d4a48fcb7b/
Changeset: 46d4a48fcb7b
User: jmchilton
Date: 2014-03-26 22:22:34
Summary: Merged in jmchilton/galaxy-central-fork-1 (pull request #350)
Make requests dependency mandatory for testing
Affected #: 2 files
diff -r 6d0c89fc3558d7185daaa1dbda05e6d15879ff00 -r 46d4a48fcb7b6dd736f081f5d8b650b0a33a296c eggs.ini
--- a/eggs.ini
+++ b/eggs.ini
@@ -56,6 +56,7 @@
python_openid = 2.2.5
python_daemon = 1.5.5
pytz = 2013.9
+requests = 2.2.1
Routes = 1.12.3
sqlalchemy_migrate = 0.7.2
ssh = 1.7.14
diff -r 6d0c89fc3558d7185daaa1dbda05e6d15879ff00 -r 46d4a48fcb7b6dd736f081f5d8b650b0a33a296c test/base/interactor.py
--- a/test/base/interactor.py
+++ b/test/base/interactor.py
@@ -1,6 +1,8 @@
import os
from StringIO import StringIO
from galaxy.tools.parameters import grouping
+from galaxy import eggs
+eggs.require( "requests" )
from galaxy.util import listify
from galaxy.util.odict import odict
import galaxy.model
@@ -424,104 +426,7 @@
}
-# Lets just try to use requests if it is available, but if not provide fallback
-# on custom implementations of limited requests get, put, etc... functionality.
-try:
- from requests import get as get_request
- from requests import post as post_request
- from requests import put as put_request
- from requests import delete as delete_request
-except ImportError:
- import urllib2
- import httplib
-
- class RequestsLikeResponse( object ):
-
- def __init__( self, content, status_code ):
- self.content = content
- self.status_code = status_code
-
- def json( self ):
- return loads( self.content )
-
- def get_request( url, params={} ):
- argsep = '&'
- if '?' not in url:
- argsep = '?'
- param_pairs = []
- for key, value in params.iteritems():
- # Handle single parameters or lists and tuples of them.
- if isinstance( value, tuple ):
- value = list( value )
- elif not isinstance( value, list ):
- value = [ value ]
- for val in value:
- param_pairs.append( "%s=%s" % ( key, val ) )
- url = url + argsep + '&'.join( param_pairs )
- #req = urllib2.Request( url, headers = { 'Content-Type': 'application/json' } )
- try:
- response = urllib2.urlopen( url )
- return RequestsLikeResponse( response.read(), status_code=response.getcode() )
- except urllib2.HTTPError as e:
- return RequestsLikeResponse( e.read(), status_code=e.code )
-
- def post_request( url, data, files={} ):
- return __multipart_request( url, data, files, verb="POST" )
-
- def put_request( url, data=None ):
- if isinstance( data, dict ):
- assert False, "This test will fail, Galaxy's webob dependency does not parse out urlencoded PUT/PATCH entity data, API will receive empty payload."
- return __urllib_request( url, 'PUT', json_str=data )
-
- def delete_request( url ):
- return __urllib_request( url, 'DELETE' )
-
- def __urllib_request( url, verb, json_str=None ):
- opener = urllib2.build_opener(urllib2.HTTPHandler)
- request = urllib2.Request(url)
- request.get_method = lambda: verb
- if json_str:
- request.add_header( "content-type", "application/json" )
- request.add_data(json_str)
- try:
- response = opener.open(request)
- return RequestsLikeResponse( response.read(), status_code=response.getcode() )
- except urllib2.HTTPError as e:
- return RequestsLikeResponse( e.read(), status_code=e.code )
-
- def __multipart_request( url, data, files={}, verb="POST" ):
- parsed_url = urllib2.urlparse.urlparse( url )
- return __multipart( host=parsed_url.netloc, selector=parsed_url.path, fields=data.iteritems(), files=(files or {}).iteritems(), verb=verb )
-
- # http://stackoverflow.com/a/681182
- def __multipart(host, selector, fields, files, verb="POST"):
- h = httplib.HTTP(host)
- h.putrequest(verb, selector)
- content_type, body = __encode_multipart_formdata(fields, files)
- h.putheader('content-type', content_type)
- h.putheader('content-length', str(len(body)))
- h.endheaders()
- h.send(body)
- errcode, errmsg, headers = h.getreply()
- return RequestsLikeResponse(h.file.read(), status_code=errcode)
-
- def __encode_multipart_formdata(fields, files):
- LIMIT = '----------lImIt_of_THE_fIle_eW_$'
- CRLF = '\r\n'
- L = []
- for (key, value) in fields:
- L.append('--' + LIMIT)
- L.append('Content-Disposition: form-data; name="%s"' % key)
- L.append('')
- L.append(value)
- for (key, value) in files:
- L.append('--' + LIMIT)
- L.append('Content-Disposition: form-data; name="%s"; filename="%s";' % (key, key))
- L.append('Content-Type: application/octet-stream')
- L.append('')
- L.append(value.read())
- L.append('--' + LIMIT + '--')
- L.append('')
- body = CRLF.join(L)
- content_type = 'multipart/form-data; boundary=%s' % LIMIT
- return content_type, body
+from requests import get as get_request
+from requests import post as post_request
+from requests import put as put_request
+from requests import delete as delete_request
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
5 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/6c786abce7e2/
Changeset: 6c786abce7e2
User: jmchilton
Date: 2014-03-17 16:44:09
Summary: Start work on stand-alone module for extracting workflows from histories.
In particular, this moves get_job_dict out of workflow controller. I am making big changes to this downstream in dataset collection work so I want unit tests - additionally get_job_dict isn't really a great name for what this becomes - so I am renaming it to summarize.
Affected #: 3 files
diff -r c53fbb2655e2756c8977782df2381d883c5aa8af -r 6c786abce7e2735e80f5f57482f72b57a98a74e7 lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -23,7 +23,6 @@
from galaxy.tools.parameters import visit_input_values
from galaxy.tools.parameters.basic import DataToolParameter, DrillDownSelectToolParameter, SelectToolParameter, UnvalidatedValue
from galaxy.tools.parameters.grouping import Conditional, Repeat
-from galaxy.util.odict import odict
from galaxy.util.sanitize_html import sanitize_html
from galaxy.util.topsort import CycleError, topsort, topsort_levels
from galaxy.web import error, url_for
@@ -33,6 +32,7 @@
from galaxy.web.framework.helpers import to_unicode
from galaxy.workflow.modules import module_factory
from galaxy.workflow.run import invoke
+from galaxy.workflow.extract import summarize
class StoredWorkflowListGrid( grids.Grid ):
@@ -1188,7 +1188,7 @@
if not user:
return trans.show_error_message( "Must be logged in to create workflows" )
if ( job_ids is None and dataset_ids is None ) or workflow_name is None:
- jobs, warnings = get_job_dict( trans )
+ jobs, warnings = summarize( trans )
# Render
return trans.fill_template(
"workflow/build_from_current_history.mako",
@@ -1211,7 +1211,7 @@
dataset_ids = [ int( id ) for id in dataset_ids ]
# Find each job, for security we (implicately) check that they are
# associated witha job in the current history.
- jobs, warnings = get_job_dict( trans )
+ jobs, warnings = summarize( trans )
jobs_by_id = dict( ( job.id, job ) for job in jobs.keys() )
steps = []
steps_by_job_id = {}
@@ -1743,48 +1743,6 @@
return None
-class FakeJob( object ):
- """
- Fake job object for datasets that have no creating_job_associations,
- they will be treated as "input" datasets.
- """
- def __init__( self, dataset ):
- self.is_fake = True
- self.id = "fake_%s" % dataset.id
-
-
-def get_job_dict( trans ):
- """
- Return a dictionary of Job -> [ Dataset ] mappings, for all finished
- active Datasets in the current history and the jobs that created them.
- """
- history = trans.get_history()
- # Get the jobs that created the datasets
- warnings = set()
- jobs = odict()
- for dataset in history.active_datasets:
- # FIXME: Create "Dataset.is_finished"
- if dataset.state in ( 'new', 'running', 'queued' ):
- warnings.add( "Some datasets still queued or running were ignored" )
- continue
-
- #if this hda was copied from another, we need to find the job that created the origial hda
- job_hda = dataset
- while job_hda.copied_from_history_dataset_association:
- job_hda = job_hda.copied_from_history_dataset_association
-
- if not job_hda.creating_job_associations:
- jobs[ FakeJob( dataset ) ] = [ ( None, dataset ) ]
-
- for assoc in job_hda.creating_job_associations:
- job = assoc.job
- if job in jobs:
- jobs[ job ].append( ( assoc.name, dataset ) )
- else:
- jobs[ job ] = [ ( assoc.name, dataset ) ]
- return jobs, warnings
-
-
def cleanup_param_values( inputs, values ):
"""
Remove 'Data' values from `param_values`, along with metadata cruft,
diff -r c53fbb2655e2756c8977782df2381d883c5aa8af -r 6c786abce7e2735e80f5f57482f72b57a98a74e7 lib/galaxy/workflow/extract.py
--- /dev/null
+++ b/lib/galaxy/workflow/extract.py
@@ -0,0 +1,54 @@
+""" This module contains functionality to aid in extracting workflows from
+histories.
+"""
+from galaxy.util.odict import odict
+
+WARNING_SOME_DATASETS_NOT_READY = "Some datasets still queued or running were ignored"
+
+
+class FakeJob( object ):
+ """
+ Fake job object for datasets that have no creating_job_associations,
+ they will be treated as "input" datasets.
+ """
+ def __init__( self, dataset ):
+ self.is_fake = True
+ self.id = "fake_%s" % dataset.id
+
+
+def summarize( trans, history=None ):
+ """ Return mapping of job description to datasets for active items in
+ supplied history - needed for building workflow from a history.
+
+ Formerly call get_job_dict in workflow web controller.
+ """
+ if not history:
+ history = trans.get_history()
+
+ # Get the jobs that created the datasets
+ warnings = set()
+ jobs = odict()
+ for dataset in history.active_datasets:
+ # FIXME: Create "Dataset.is_finished"
+ if dataset.state in ( 'new', 'running', 'queued' ):
+ warnings.add( WARNING_SOME_DATASETS_NOT_READY )
+ continue
+
+ #if this hda was copied from another, we need to find the job that created the origial hda
+ job_hda = dataset
+ while job_hda.copied_from_history_dataset_association:
+ job_hda = job_hda.copied_from_history_dataset_association
+
+ if not job_hda.creating_job_associations:
+ jobs[ FakeJob( dataset ) ] = [ ( None, dataset ) ]
+
+ for assoc in job_hda.creating_job_associations:
+ job = assoc.job
+ if job in jobs:
+ jobs[ job ].append( ( assoc.name, dataset ) )
+ else:
+ jobs[ job ] = [ ( assoc.name, dataset ) ]
+
+ return jobs, warnings
+
+__all__ = [ summarize ]
diff -r c53fbb2655e2756c8977782df2381d883c5aa8af -r 6c786abce7e2735e80f5f57482f72b57a98a74e7 test/unit/workflows/test_extract_summary.py
--- /dev/null
+++ b/test/unit/workflows/test_extract_summary.py
@@ -0,0 +1,98 @@
+import unittest
+
+from galaxy import model
+from galaxy.workflow import extract
+
+UNDEFINED_JOB = object()
+
+
+class TestWorkflowExtractSummary( unittest.TestCase ):
+
+ def setUp( self ):
+ self.history = MockHistory()
+ self.trans = MockTrans( self.history )
+
+ def test_empty_history( self ):
+ job_dict, warnings = extract.summarize( trans=self.trans )
+ assert not warnings
+ assert not job_dict
+
+ def test_summarize_returns_name_and_dataset_list( self ):
+ # Create two jobs and three datasets, test they are groupped
+ # by job correctly with correct output names.
+ hda1 = MockHda()
+ self.history.active_datasets.append( hda1 )
+ hda2 = MockHda( job=hda1.job, output_name="out2" )
+ self.history.active_datasets.append( hda2 )
+ hda3 = MockHda( output_name="out3" )
+ self.history.active_datasets.append( hda3 )
+
+ job_dict, warnings = extract.summarize( trans=self.trans )
+ assert len( job_dict ) == 2
+ assert not warnings
+ self.assertEquals( job_dict[ hda1.job ], [ ( 'out1', hda1 ), ( 'out2', hda2 ) ] )
+ self.assertEquals( job_dict[ hda3.job ], [ ( 'out3', hda3 ) ] )
+
+ def test_finds_original_job_if_copied( self ):
+ hda = MockHda()
+ derived_hda_1 = MockHda()
+ derived_hda_1.copied_from_history_dataset_association = hda
+ derived_hda_2 = MockHda()
+ derived_hda_2.copied_from_history_dataset_association = derived_hda_1
+ self.history.active_datasets.append( derived_hda_2 )
+ job_dict, warnings = extract.summarize( trans=self.trans )
+ assert not warnings
+ assert len( job_dict ) == 1
+ self.assertEquals( job_dict[ hda.job ], [ ('out1', derived_hda_2 ) ] )
+
+ def test_fake_job( self ):
+ """ Fakes job if creating_job_associations is empty.
+ """
+ hda = MockHda( job=UNDEFINED_JOB )
+ self.history.active_datasets.append( hda )
+ job_dict, warnings = extract.summarize( trans=self.trans )
+ assert not warnings
+ assert len( job_dict ) == 1
+ fake_job = job_dict.keys()[ 0 ]
+ assert fake_job.id.startswith( "fake_" )
+ datasets = job_dict.values()[ 0 ]
+ assert datasets == [ ( None, hda ) ]
+
+ def test_warns_and_skips_datasets_if_not_finished( self ):
+ hda = MockHda( state='queued' )
+ self.history.active_datasets.append( hda )
+ job_dict, warnings = extract.summarize( trans=self.trans )
+ assert warnings
+ assert len( job_dict ) == 0
+
+
+class MockHistory( object ):
+
+ def __init__( self ):
+ self.active_datasets = []
+
+
+class MockTrans( object ):
+
+ def __init__( self, history ):
+ self.history = history
+
+ def get_history( self ):
+ return self.history
+
+
+class MockHda( object ):
+
+ def __init__( self, state='ok', output_name='out1', job=None ):
+ self.id = 123
+ self.state = state
+ self.copied_from_history_dataset_association = None
+ if job is not UNDEFINED_JOB:
+ if not job:
+ job = model.Job()
+ self.job = job
+ assoc = model.JobToOutputDatasetAssociation( output_name, self )
+ assoc.job = job
+ self.creating_job_associations = [ assoc ]
+ else:
+ self.creating_job_associations = []
https://bitbucket.org/galaxy/galaxy-central/commits/69e29134e64c/
Changeset: 69e29134e64c
User: jmchilton
Date: 2014-03-17 16:44:09
Summary: Refactor workflow controller step utilities into new module.
This will allow for cleaner reuse outside of web controller, clean up API import of attach_steps accordingly.
Affected #: 3 files
diff -r 6c786abce7e2735e80f5f57482f72b57a98a74e7 -r 69e29134e64c08c09e94a9f69d59329eb2f52107 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -41,6 +41,7 @@
from galaxy.tools.parameters.basic import DataToolParameter
from galaxy.util.json import to_json_string
from galaxy.workflow.modules import ToolModule
+from galaxy.workflow.build_util import attach_ordered_steps
log = logging.getLogger( __name__ )
@@ -1626,7 +1627,6 @@
"""
Creates a workflow from a dict. Created workflow is stored in the database and returned.
"""
- from galaxy.webapps.galaxy.controllers.workflow import attach_ordered_steps
# Put parameters in workflow mode
trans.workflow_building_mode = True
diff -r 6c786abce7e2735e80f5f57482f72b57a98a74e7 -r 69e29134e64c08c09e94a9f69d59329eb2f52107 lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -4,7 +4,6 @@
import base64
import httplib
import json
-import math
import os
import sgmllib
import svgfig
@@ -24,7 +23,6 @@
from galaxy.tools.parameters.basic import DataToolParameter, DrillDownSelectToolParameter, SelectToolParameter, UnvalidatedValue
from galaxy.tools.parameters.grouping import Conditional, Repeat
from galaxy.util.sanitize_html import sanitize_html
-from galaxy.util.topsort import CycleError, topsort, topsort_levels
from galaxy.web import error, url_for
from galaxy.web.base.controller import BaseUIController, SharableMixin, UsesStoredWorkflowMixin
from galaxy.web.framework import form
@@ -33,6 +31,12 @@
from galaxy.workflow.modules import module_factory
from galaxy.workflow.run import invoke
from galaxy.workflow.extract import summarize
+from galaxy.workflow.steps import (
+ attach_ordered_steps,
+ order_workflow_steps,
+ edgelist_for_workflow_steps,
+ order_workflow_steps_with_levels,
+)
class StoredWorkflowListGrid( grids.Grid ):
@@ -1692,57 +1696,6 @@
## ---- Utility methods -------------------------------------------------------
-def attach_ordered_steps( workflow, steps ):
- ordered_steps = order_workflow_steps( steps )
- if ordered_steps:
- workflow.has_cycles = False
- for i, step in enumerate( ordered_steps ):
- step.order_index = i
- workflow.steps.append( step )
- else:
- workflow.has_cycles = True
- workflow.steps = steps
-
-
-def edgelist_for_workflow_steps( steps ):
- """
- Create a list of tuples representing edges between ``WorkflowSteps`` based
- on associated ``WorkflowStepConnection``s
- """
- edges = []
- steps_to_index = dict( ( step, i ) for i, step in enumerate( steps ) )
- for step in steps:
- edges.append( ( steps_to_index[step], steps_to_index[step] ) )
- for conn in step.input_connections:
- edges.append( ( steps_to_index[conn.output_step], steps_to_index[conn.input_step] ) )
- return edges
-
-
-def order_workflow_steps( steps ):
- """
- Perform topological sort of the steps, return ordered or None
- """
- position_data_available = True
- for step in steps:
- if not step.position or not 'left' in step.position or not 'top' in step.position:
- position_data_available = False
- if position_data_available:
- steps.sort(cmp=lambda s1, s2: cmp( math.sqrt(s1.position['left'] ** 2 + s1.position['top'] ** 2), math.sqrt(s2.position['left'] ** 2 + s2.position['top'] ** 2)))
- try:
- edges = edgelist_for_workflow_steps( steps )
- node_order = topsort( edges )
- return [ steps[i] for i in node_order ]
- except CycleError:
- return None
-
-
-def order_workflow_steps_with_levels( steps ):
- try:
- return topsort_levels( edgelist_for_workflow_steps( steps ) )
- except CycleError:
- return None
-
-
def cleanup_param_values( inputs, values ):
"""
Remove 'Data' values from `param_values`, along with metadata cruft,
diff -r 6c786abce7e2735e80f5f57482f72b57a98a74e7 -r 69e29134e64c08c09e94a9f69d59329eb2f52107 lib/galaxy/workflow/steps.py
--- /dev/null
+++ b/lib/galaxy/workflow/steps.py
@@ -0,0 +1,63 @@
+""" This module contains utility methods for reasoning about and ordering
+workflow steps.
+"""
+import math
+from galaxy.util.topsort import (
+ CycleError,
+ topsort,
+ topsort_levels
+)
+
+
+def attach_ordered_steps( workflow, steps ):
+ """ Attempt to topologically order steps and attach to workflow. If this
+ fails - the workflow contains cycles so it mark it as such.
+ """
+ ordered_steps = order_workflow_steps( steps )
+ if ordered_steps:
+ workflow.has_cycles = False
+ for i, step in enumerate( ordered_steps ):
+ step.order_index = i
+ workflow.steps.append( step )
+ else:
+ workflow.has_cycles = True
+ workflow.steps = steps
+
+
+def order_workflow_steps( steps ):
+ """
+ Perform topological sort of the steps, return ordered or None
+ """
+ position_data_available = True
+ for step in steps:
+ if not step.position or not 'left' in step.position or not 'top' in step.position:
+ position_data_available = False
+ if position_data_available:
+ steps.sort(cmp=lambda s1, s2: cmp( math.sqrt(s1.position['left'] ** 2 + s1.position['top'] ** 2), math.sqrt(s2.position['left'] ** 2 + s2.position['top'] ** 2)))
+ try:
+ edges = edgelist_for_workflow_steps( steps )
+ node_order = topsort( edges )
+ return [ steps[i] for i in node_order ]
+ except CycleError:
+ return None
+
+
+def edgelist_for_workflow_steps( steps ):
+ """
+ Create a list of tuples representing edges between ``WorkflowSteps`` based
+ on associated ``WorkflowStepConnection``s
+ """
+ edges = []
+ steps_to_index = dict( ( step, i ) for i, step in enumerate( steps ) )
+ for step in steps:
+ edges.append( ( steps_to_index[step], steps_to_index[step] ) )
+ for conn in step.input_connections:
+ edges.append( ( steps_to_index[conn.output_step], steps_to_index[conn.input_step] ) )
+ return edges
+
+
+def order_workflow_steps_with_levels( steps ):
+ try:
+ return topsort_levels( edgelist_for_workflow_steps( steps ) )
+ except CycleError:
+ return None
https://bitbucket.org/galaxy/galaxy-central/commits/0eb7631a6d67/
Changeset: 0eb7631a6d67
User: jmchilton
Date: 2014-03-17 16:44:09
Summary: Refactor code for extracting workflow from history into workflow extract module.
Will allow reuse with API controller.
Affected #: 2 files
diff -r 69e29134e64c08c09e94a9f69d59329eb2f52107 -r 0eb7631a6d67317a93b480794d9c4a33a3ceceda lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -19,9 +19,8 @@
from galaxy.datatypes.data import Data
from galaxy.model.item_attrs import UsesItemRatings
from galaxy.model.mapping import desc
+from galaxy.tools.parameters.basic import DataToolParameter
from galaxy.tools.parameters import visit_input_values
-from galaxy.tools.parameters.basic import DataToolParameter, DrillDownSelectToolParameter, SelectToolParameter, UnvalidatedValue
-from galaxy.tools.parameters.grouping import Conditional, Repeat
from galaxy.util.sanitize_html import sanitize_html
from galaxy.web import error, url_for
from galaxy.web.base.controller import BaseUIController, SharableMixin, UsesStoredWorkflowMixin
@@ -31,6 +30,7 @@
from galaxy.workflow.modules import module_factory
from galaxy.workflow.run import invoke
from galaxy.workflow.extract import summarize
+from galaxy.workflow.extract import extract_workflow
from galaxy.workflow.steps import (
attach_ordered_steps,
order_workflow_steps,
@@ -1201,82 +1201,13 @@
history=history
)
else:
- # Ensure job_ids and dataset_ids are lists (possibly empty)
- if job_ids is None:
- job_ids = []
- elif type( job_ids ) is not list:
- job_ids = [ job_ids ]
- if dataset_ids is None:
- dataset_ids = []
- elif type( dataset_ids ) is not list:
- dataset_ids = [ dataset_ids ]
- # Convert both sets of ids to integers
- job_ids = [ int( id ) for id in job_ids ]
- dataset_ids = [ int( id ) for id in dataset_ids ]
- # Find each job, for security we (implicately) check that they are
- # associated witha job in the current history.
- jobs, warnings = summarize( trans )
- jobs_by_id = dict( ( job.id, job ) for job in jobs.keys() )
- steps = []
- steps_by_job_id = {}
- hid_to_output_pair = {}
- # Input dataset steps
- for hid in dataset_ids:
- step = model.WorkflowStep()
- step.type = 'data_input'
- step.tool_inputs = dict( name="Input Dataset" )
- hid_to_output_pair[ hid ] = ( step, 'output' )
- steps.append( step )
- # Tool steps
- for job_id in job_ids:
- assert job_id in jobs_by_id, "Attempt to create workflow with job not connected to current history"
- job = jobs_by_id[ job_id ]
- tool = trans.app.toolbox.get_tool( job.tool_id )
- param_values = job.get_param_values( trans.app, ignore_errors=True ) # If a tool was updated and e.g. had a text value changed to an integer, we don't want a traceback here
- associations = cleanup_param_values( tool.inputs, param_values )
- step = model.WorkflowStep()
- step.type = 'tool'
- step.tool_id = job.tool_id
- step.tool_inputs = tool.params_to_strings( param_values, trans.app )
- # NOTE: We shouldn't need to do two passes here since only
- # an earlier job can be used as an input to a later
- # job.
- for other_hid, input_name in associations:
- if other_hid in hid_to_output_pair:
- other_step, other_name = hid_to_output_pair[ other_hid ]
- conn = model.WorkflowStepConnection()
- conn.input_step = step
- conn.input_name = input_name
- # Should always be connected to an earlier step
- conn.output_step = other_step
- conn.output_name = other_name
- steps.append( step )
- steps_by_job_id[ job_id ] = step
- # Store created dataset hids
- for assoc in job.output_datasets:
- hid_to_output_pair[ assoc.dataset.hid ] = ( step, assoc.name )
- # Workflow to populate
- workflow = model.Workflow()
- workflow.name = workflow_name
- # Order the steps if possible
- attach_ordered_steps( workflow, steps )
- # And let's try to set up some reasonable locations on the canvas
- # (these are pretty arbitrary values)
- levorder = order_workflow_steps_with_levels( steps )
- base_pos = 10
- for i, steps_at_level in enumerate( levorder ):
- for j, index in enumerate( steps_at_level ):
- step = steps[ index ]
- step.position = dict( top=( base_pos + 120 * j ),
- left=( base_pos + 220 * i ) )
- # Store it
- stored = model.StoredWorkflow()
- stored.user = user
- stored.name = workflow_name
- workflow.stored_workflow = stored
- stored.latest_workflow = workflow
- trans.sa_session.add( stored )
- trans.sa_session.flush()
+ extract_workflow(
+ trans,
+ user=user,
+ job_ids=job_ids,
+ dataset_ids=dataset_ids,
+ workflow_name=workflow_name
+ )
# Index page with message
return trans.show_message( "Workflow '%s' created from current history." % workflow_name )
## return trans.show_ok_message( "<p>Workflow '%s' created.</p><p><a target='_top' href='%s'>Click to load in workflow editor</a></p>"
@@ -1696,55 +1627,6 @@
## ---- Utility methods -------------------------------------------------------
-def cleanup_param_values( inputs, values ):
- """
- Remove 'Data' values from `param_values`, along with metadata cruft,
- but track the associations.
- """
- associations = []
- # dbkey is pushed in by the framework
- if 'dbkey' in values:
- del values['dbkey']
- root_values = values
-
- # Recursively clean data inputs and dynamic selects
- def cleanup( prefix, inputs, values ):
- for key, input in inputs.items():
- if isinstance( input, ( SelectToolParameter, DrillDownSelectToolParameter ) ):
- if input.is_dynamic and not isinstance( values[key], UnvalidatedValue ):
- values[key] = UnvalidatedValue( values[key] )
- if isinstance( input, DataToolParameter ):
- tmp = values[key]
- values[key] = None
- # HACK: Nested associations are not yet working, but we
- # still need to clean them up so we can serialize
- # if not( prefix ):
- if tmp: # this is false for a non-set optional dataset
- if not isinstance(tmp, list):
- associations.append( ( tmp.hid, prefix + key ) )
- else:
- associations.extend( [ (t.hid, prefix + key) for t in tmp] )
-
- # Cleanup the other deprecated crap associated with datasets
- # as well. Worse, for nested datasets all the metadata is
- # being pushed into the root. FIXME: MUST REMOVE SOON
- key = prefix + key + "_"
- for k in root_values.keys():
- if k.startswith( key ):
- del root_values[k]
- elif isinstance( input, Repeat ):
- group_values = values[key]
- for i, rep_values in enumerate( group_values ):
- rep_index = rep_values['__index__']
- cleanup( "%s%s_%d|" % (prefix, key, rep_index ), input.inputs, group_values[i] )
- elif isinstance( input, Conditional ):
- group_values = values[input.name]
- current_case = group_values['__current_case__']
- cleanup( "%s%s|" % ( prefix, key ), input.cases[current_case].inputs, group_values )
- cleanup( "", inputs, values )
- return associations
-
-
def _build_workflow_on_str(instance_ds_names):
# Returns suffix for new histories based on multi input iteration
num_multi_inputs = len(instance_ds_names)
diff -r 69e29134e64c08c09e94a9f69d59329eb2f52107 -r 0eb7631a6d67317a93b480794d9c4a33a3ceceda lib/galaxy/workflow/extract.py
--- a/lib/galaxy/workflow/extract.py
+++ b/lib/galaxy/workflow/extract.py
@@ -2,10 +2,108 @@
histories.
"""
from galaxy.util.odict import odict
+from galaxy import model
+from galaxy.tools.parameters.basic import (
+ DataToolParameter,
+ DrillDownSelectToolParameter,
+ SelectToolParameter,
+ UnvalidatedValue
+)
+from galaxy.tools.parameters.grouping import (
+ Conditional,
+ Repeat
+)
+from .steps import (
+ attach_ordered_steps,
+ order_workflow_steps_with_levels
+)
WARNING_SOME_DATASETS_NOT_READY = "Some datasets still queued or running were ignored"
+def extract_workflow( trans, user, history=None, job_ids=None, dataset_ids=None, workflow_name=None ):
+ steps = extract_steps( trans, history=history, job_ids=job_ids, dataset_ids=dataset_ids )
+ # Workflow to populate
+ workflow = model.Workflow()
+ workflow.name = workflow_name
+ # Order the steps if possible
+ attach_ordered_steps( workflow, steps )
+ # And let's try to set up some reasonable locations on the canvas
+ # (these are pretty arbitrary values)
+ levorder = order_workflow_steps_with_levels( steps )
+ base_pos = 10
+ for i, steps_at_level in enumerate( levorder ):
+ for j, index in enumerate( steps_at_level ):
+ step = steps[ index ]
+ step.position = dict( top=( base_pos + 120 * j ),
+ left=( base_pos + 220 * i ) )
+ # Store it
+ stored = model.StoredWorkflow()
+ stored.user = user
+ stored.name = workflow_name
+ workflow.stored_workflow = stored
+ stored.latest_workflow = workflow
+ trans.sa_session.add( stored )
+ trans.sa_session.flush()
+ return stored
+
+
+def extract_steps( trans, history=None, job_ids=None, dataset_ids=None ):
+ # Ensure job_ids and dataset_ids are lists (possibly empty)
+ if job_ids is None:
+ job_ids = []
+ elif type( job_ids ) is not list:
+ job_ids = [ job_ids ]
+ if dataset_ids is None:
+ dataset_ids = []
+ elif type( dataset_ids ) is not list:
+ dataset_ids = [ dataset_ids ]
+ # Convert both sets of ids to integers
+ job_ids = [ int( id ) for id in job_ids ]
+ dataset_ids = [ int( id ) for id in dataset_ids ]
+ # Find each job, for security we (implicately) check that they are
+ # associated witha job in the current history.
+ jobs, warnings = summarize( trans, history=history )
+ jobs_by_id = dict( ( job.id, job ) for job in jobs.keys() )
+ steps = []
+ steps_by_job_id = {}
+ hid_to_output_pair = {}
+ # Input dataset steps
+ for hid in dataset_ids:
+ step = model.WorkflowStep()
+ step.type = 'data_input'
+ step.tool_inputs = dict( name="Input Dataset" )
+ hid_to_output_pair[ hid ] = ( step, 'output' )
+ steps.append( step )
+ # Tool steps
+ for job_id in job_ids:
+ assert job_id in jobs_by_id, "Attempt to create workflow with job not connected to current history"
+ job = jobs_by_id[ job_id ]
+ tool_inputs, associations = step_inputs( trans, job )
+ step = model.WorkflowStep()
+ step.type = 'tool'
+ step.tool_id = job.tool_id
+ step.tool_inputs = tool_inputs
+ # NOTE: We shouldn't need to do two passes here since only
+ # an earlier job can be used as an input to a later
+ # job.
+ for other_hid, input_name in associations:
+ if other_hid in hid_to_output_pair:
+ other_step, other_name = hid_to_output_pair[ other_hid ]
+ conn = model.WorkflowStepConnection()
+ conn.input_step = step
+ conn.input_name = input_name
+ # Should always be connected to an earlier step
+ conn.output_step = other_step
+ conn.output_name = other_name
+ steps.append( step )
+ steps_by_job_id[ job_id ] = step
+ # Store created dataset hids
+ for assoc in job.output_datasets:
+ hid_to_output_pair[ assoc.dataset.hid ] = ( step, assoc.name )
+ return steps
+
+
class FakeJob( object ):
"""
Fake job object for datasets that have no creating_job_associations,
@@ -51,4 +149,61 @@
return jobs, warnings
-__all__ = [ summarize ]
+
+def step_inputs( trans, job ):
+ tool = trans.app.toolbox.get_tool( job.tool_id )
+ param_values = job.get_param_values( trans.app, ignore_errors=True ) # If a tool was updated and e.g. had a text value changed to an integer, we don't want a traceback here
+ associations = __cleanup_param_values( tool.inputs, param_values )
+ tool_inputs = tool.params_to_strings( param_values, trans.app )
+ return tool_inputs, associations
+
+
+def __cleanup_param_values( inputs, values ):
+ """
+ Remove 'Data' values from `param_values`, along with metadata cruft,
+ but track the associations.
+ """
+ associations = []
+ # dbkey is pushed in by the framework
+ if 'dbkey' in values:
+ del values['dbkey']
+ root_values = values
+
+ # Recursively clean data inputs and dynamic selects
+ def cleanup( prefix, inputs, values ):
+ for key, input in inputs.items():
+ if isinstance( input, ( SelectToolParameter, DrillDownSelectToolParameter ) ):
+ if input.is_dynamic and not isinstance( values[key], UnvalidatedValue ):
+ values[key] = UnvalidatedValue( values[key] )
+ if isinstance( input, DataToolParameter ):
+ tmp = values[key]
+ values[key] = None
+ # HACK: Nested associations are not yet working, but we
+ # still need to clean them up so we can serialize
+ # if not( prefix ):
+ if tmp: # this is false for a non-set optional dataset
+ if not isinstance(tmp, list):
+ associations.append( ( tmp.hid, prefix + key ) )
+ else:
+ associations.extend( [ (t.hid, prefix + key) for t in tmp] )
+
+ # Cleanup the other deprecated crap associated with datasets
+ # as well. Worse, for nested datasets all the metadata is
+ # being pushed into the root. FIXME: MUST REMOVE SOON
+ key = prefix + key + "_"
+ for k in root_values.keys():
+ if k.startswith( key ):
+ del root_values[k]
+ elif isinstance( input, Repeat ):
+ group_values = values[key]
+ for i, rep_values in enumerate( group_values ):
+ rep_index = rep_values['__index__']
+ cleanup( "%s%s_%d|" % (prefix, key, rep_index ), input.inputs, group_values[i] )
+ elif isinstance( input, Conditional ):
+ group_values = values[input.name]
+ current_case = group_values['__current_case__']
+ cleanup( "%s%s|" % ( prefix, key ), input.cases[current_case].inputs, group_values )
+ cleanup( "", inputs, values )
+ return associations
+
+__all__ = [ summarize, extract_workflow ]
https://bitbucket.org/galaxy/galaxy-central/commits/17a2dc7d3902/
Changeset: 17a2dc7d3902
User: jmchilton
Date: 2014-03-17 16:44:09
Summary: Add ability to extract workflow from a history to workflows API.
Affected #: 2 files
diff -r 0eb7631a6d67317a93b480794d9c4a33a3ceceda -r 17a2dc7d39027d97a4185adbd03944b4bb1642cf lib/galaxy/webapps/galaxy/api/workflows.py
--- a/lib/galaxy/webapps/galaxy/api/workflows.py
+++ b/lib/galaxy/webapps/galaxy/api/workflows.py
@@ -11,8 +11,10 @@
from galaxy import web
from galaxy.web import _future_expose_api as expose_api
from galaxy.web.base.controller import BaseAPIController, url_for, UsesStoredWorkflowMixin
+from galaxy.web.base.controller import UsesHistoryMixin
from galaxy.workflow.modules import module_factory
from galaxy.workflow.run import invoke
+from galaxy.workflow.extract import extract_workflow
log = logging.getLogger(__name__)
@@ -51,7 +53,7 @@
step.state.inputs.update(param_dict)
-class WorkflowsAPIController(BaseAPIController, UsesStoredWorkflowMixin):
+class WorkflowsAPIController(BaseAPIController, UsesStoredWorkflowMixin, UsesHistoryMixin):
@web.expose_api
def index(self, trans, **kwd):
@@ -141,9 +143,11 @@
"""
POST /api/workflows
- We're not creating workflows from the api. Just execute for now.
+ Run or create workflows from the api.
- However, we will import them if installed_repository_file is specified.
+ If installed_repository_file or from_history_id is specified a new
+ workflow will be created for this user. Otherwise, workflow_id must be
+ specified and this API method will cause a workflow to execute.
:param installed_repository_file The path of a workflow to import. Either workflow_id or installed_repository_file must be specified
:type installed_repository_file str
@@ -165,6 +169,15 @@
:param replacement_params: A dictionary used when renaming datasets
:type replacement_params: dict
+
+ :param from_history_id: Id of history to extract a workflow from. Should not be used with worfklow_id or installed_repository_file.
+ :type from_history_id: str
+
+ :param job_ids: If from_history_id is set - this should be a list of jobs to include when extracting workflow from history.
+ :type job_ids: str
+
+ :param dataset_ids: If from_history_id is set - this should be a list of HDA ids corresponding to workflow inputs when extracting workflow from history.
+ :type dataset_ids: str
"""
# Pull parameters out of payload.
@@ -183,6 +196,24 @@
cntrller='api',
**payload)
return result
+ if 'from_history_id' in payload:
+ from_history_id = payload.get( 'from_history_id' )
+ history = self.get_history( trans, from_history_id, check_ownership=False, check_accessible=True )
+ job_ids = map( trans.security.decode_id, payload.get( "job_ids", [] ) )
+ dataset_ids = map( trans.security.decode_id, payload.get( "dataset_ids", [] ) )
+ workflow_name = payload[ "workflow_name" ]
+ stored_workflow = extract_workflow(
+ trans=trans,
+ user=trans.get_user(),
+ history=history,
+ job_ids=job_ids,
+ dataset_ids=dataset_ids,
+ workflow_name=workflow_name,
+ )
+ item = stored_workflow.to_dict( value_mapper={ "id": trans.security.encode_id } )
+ item[ 'url' ] = url_for( 'workflow', id=item[ "id" ] )
+ return item
+
trans.response.status = 403
return "Either workflow_id or installed_repository_file must be specified"
if 'installed_repository_file' in payload:
diff -r 0eb7631a6d67317a93b480794d9c4a33a3ceceda -r 17a2dc7d39027d97a4185adbd03944b4bb1642cf test/functional/api/test_workflows.py
--- a/test/functional/api/test_workflows.py
+++ b/test/functional/api/test_workflows.py
@@ -67,6 +67,39 @@
self._assert_status_code_is( run_workflow_response, 200 )
self._wait_for_history( history_id, assert_ok=True )
+ def test_extract_from_history( self ):
+ workflow = self.workflow_populator.load_workflow( name="test_for_extract" )
+ workflow_request, history_id = self._setup_workflow_run( workflow )
+ contents_response = self._get( "histories/%s/contents" % history_id )
+ self._assert_status_code_is( contents_response, 200 )
+ hda_ids = map( lambda c: c[ "id" ], contents_response.json() )
+
+ run_workflow_response = self._post( "workflows", data=workflow_request )
+ self._assert_status_code_is( run_workflow_response, 200 )
+
+ self._wait_for_history( history_id, assert_ok=True )
+ data = dict( history_id=history_id, tool_id="cat1" )
+ jobs_response = self._get( "jobs", data=data )
+ self._assert_status_code_is( jobs_response, 200 )
+ cat1_job_id = jobs_response.json()[ 0 ][ "id" ]
+
+ contents_response = self._get( "history/%s/contents", data=data )
+ create_from_data = dict(
+ from_history_id=history_id,
+ dataset_ids=dumps( hda_ids ),
+ job_ids=dumps( [ cat1_job_id ] ),
+ workflow_name="test import from history",
+ )
+ run_workflow_response = self._post( "workflows", data=create_from_data )
+ self._assert_status_code_is( run_workflow_response, 200 )
+
+ new_workflow_id = run_workflow_response.json()[ "id" ]
+ download_response = self._get( "workflows/%s/download" % new_workflow_id )
+ self._assert_status_code_is( download_response, 200 )
+ downloaded_workflow = download_response.json()
+ self.assertEquals( downloaded_workflow[ "name" ], "test import from history" )
+ assert len( downloaded_workflow[ "steps" ] ) == 3
+
def test_run_replace_params_by_tool( self ):
workflow_request, history_id = self._setup_random_x2_workflow( "test_for_replace_tool_params" )
workflow_request[ "parameters" ] = dumps( dict( random_lines1=dict( num_lines=5 ) ) )
https://bitbucket.org/galaxy/galaxy-central/commits/6d0c89fc3558/
Changeset: 6d0c89fc3558
User: jmchilton
Date: 2014-03-26 22:21:15
Summary: Merged in jmchilton/galaxy-central-fork-1 (pull request #348)
Enhance workflows API to allow extracting workflow from history.
Affected #: 7 files
diff -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 -r 6d0c89fc3558d7185daaa1dbda05e6d15879ff00 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -41,6 +41,7 @@
from galaxy.tools.parameters.basic import DataToolParameter
from galaxy.util.json import to_json_string
from galaxy.workflow.modules import ToolModule
+from galaxy.workflow.build_util import attach_ordered_steps
log = logging.getLogger( __name__ )
@@ -1676,7 +1677,6 @@
"""
Creates a workflow from a dict. Created workflow is stored in the database and returned.
"""
- from galaxy.webapps.galaxy.controllers.workflow import attach_ordered_steps
# Put parameters in workflow mode
trans.workflow_building_mode = True
diff -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 -r 6d0c89fc3558d7185daaa1dbda05e6d15879ff00 lib/galaxy/webapps/galaxy/api/workflows.py
--- a/lib/galaxy/webapps/galaxy/api/workflows.py
+++ b/lib/galaxy/webapps/galaxy/api/workflows.py
@@ -11,8 +11,10 @@
from galaxy import web
from galaxy.web import _future_expose_api as expose_api
from galaxy.web.base.controller import BaseAPIController, url_for, UsesStoredWorkflowMixin
+from galaxy.web.base.controller import UsesHistoryMixin
from galaxy.workflow.modules import module_factory
from galaxy.workflow.run import invoke
+from galaxy.workflow.extract import extract_workflow
log = logging.getLogger(__name__)
@@ -51,7 +53,7 @@
step.state.inputs.update(param_dict)
-class WorkflowsAPIController(BaseAPIController, UsesStoredWorkflowMixin):
+class WorkflowsAPIController(BaseAPIController, UsesStoredWorkflowMixin, UsesHistoryMixin):
@web.expose_api
def index(self, trans, **kwd):
@@ -141,9 +143,11 @@
"""
POST /api/workflows
- We're not creating workflows from the api. Just execute for now.
+ Run or create workflows from the api.
- However, we will import them if installed_repository_file is specified.
+ If installed_repository_file or from_history_id is specified a new
+ workflow will be created for this user. Otherwise, workflow_id must be
+ specified and this API method will cause a workflow to execute.
:param installed_repository_file The path of a workflow to import. Either workflow_id or installed_repository_file must be specified
:type installed_repository_file str
@@ -165,6 +169,15 @@
:param replacement_params: A dictionary used when renaming datasets
:type replacement_params: dict
+
+ :param from_history_id: Id of history to extract a workflow from. Should not be used with worfklow_id or installed_repository_file.
+ :type from_history_id: str
+
+ :param job_ids: If from_history_id is set - this should be a list of jobs to include when extracting workflow from history.
+ :type job_ids: str
+
+ :param dataset_ids: If from_history_id is set - this should be a list of HDA ids corresponding to workflow inputs when extracting workflow from history.
+ :type dataset_ids: str
"""
# Pull parameters out of payload.
@@ -183,6 +196,24 @@
cntrller='api',
**payload)
return result
+ if 'from_history_id' in payload:
+ from_history_id = payload.get( 'from_history_id' )
+ history = self.get_history( trans, from_history_id, check_ownership=False, check_accessible=True )
+ job_ids = map( trans.security.decode_id, payload.get( "job_ids", [] ) )
+ dataset_ids = map( trans.security.decode_id, payload.get( "dataset_ids", [] ) )
+ workflow_name = payload[ "workflow_name" ]
+ stored_workflow = extract_workflow(
+ trans=trans,
+ user=trans.get_user(),
+ history=history,
+ job_ids=job_ids,
+ dataset_ids=dataset_ids,
+ workflow_name=workflow_name,
+ )
+ item = stored_workflow.to_dict( value_mapper={ "id": trans.security.encode_id } )
+ item[ 'url' ] = url_for( 'workflow', id=item[ "id" ] )
+ return item
+
trans.response.status = 403
return "Either workflow_id or installed_repository_file must be specified"
if 'installed_repository_file' in payload:
diff -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 -r 6d0c89fc3558d7185daaa1dbda05e6d15879ff00 lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -4,7 +4,6 @@
import base64
import httplib
import json
-import math
import os
import sgmllib
import svgfig
@@ -20,12 +19,9 @@
from galaxy.datatypes.data import Data
from galaxy.model.item_attrs import UsesItemRatings
from galaxy.model.mapping import desc
+from galaxy.tools.parameters.basic import DataToolParameter
from galaxy.tools.parameters import visit_input_values
-from galaxy.tools.parameters.basic import DataToolParameter, DrillDownSelectToolParameter, SelectToolParameter, UnvalidatedValue
-from galaxy.tools.parameters.grouping import Conditional, Repeat
-from galaxy.util.odict import odict
from galaxy.util.sanitize_html import sanitize_html
-from galaxy.util.topsort import CycleError, topsort, topsort_levels
from galaxy.web import error, url_for
from galaxy.web.base.controller import BaseUIController, SharableMixin, UsesStoredWorkflowMixin
from galaxy.web.framework import form
@@ -33,6 +29,14 @@
from galaxy.web.framework.helpers import to_unicode
from galaxy.workflow.modules import module_factory
from galaxy.workflow.run import invoke
+from galaxy.workflow.extract import summarize
+from galaxy.workflow.extract import extract_workflow
+from galaxy.workflow.steps import (
+ attach_ordered_steps,
+ order_workflow_steps,
+ edgelist_for_workflow_steps,
+ order_workflow_steps_with_levels,
+)
class StoredWorkflowListGrid( grids.Grid ):
@@ -1188,7 +1192,7 @@
if not user:
return trans.show_error_message( "Must be logged in to create workflows" )
if ( job_ids is None and dataset_ids is None ) or workflow_name is None:
- jobs, warnings = get_job_dict( trans )
+ jobs, warnings = summarize( trans )
# Render
return trans.fill_template(
"workflow/build_from_current_history.mako",
@@ -1197,82 +1201,13 @@
history=history
)
else:
- # Ensure job_ids and dataset_ids are lists (possibly empty)
- if job_ids is None:
- job_ids = []
- elif type( job_ids ) is not list:
- job_ids = [ job_ids ]
- if dataset_ids is None:
- dataset_ids = []
- elif type( dataset_ids ) is not list:
- dataset_ids = [ dataset_ids ]
- # Convert both sets of ids to integers
- job_ids = [ int( id ) for id in job_ids ]
- dataset_ids = [ int( id ) for id in dataset_ids ]
- # Find each job, for security we (implicately) check that they are
- # associated witha job in the current history.
- jobs, warnings = get_job_dict( trans )
- jobs_by_id = dict( ( job.id, job ) for job in jobs.keys() )
- steps = []
- steps_by_job_id = {}
- hid_to_output_pair = {}
- # Input dataset steps
- for hid in dataset_ids:
- step = model.WorkflowStep()
- step.type = 'data_input'
- step.tool_inputs = dict( name="Input Dataset" )
- hid_to_output_pair[ hid ] = ( step, 'output' )
- steps.append( step )
- # Tool steps
- for job_id in job_ids:
- assert job_id in jobs_by_id, "Attempt to create workflow with job not connected to current history"
- job = jobs_by_id[ job_id ]
- tool = trans.app.toolbox.get_tool( job.tool_id )
- param_values = job.get_param_values( trans.app, ignore_errors=True ) # If a tool was updated and e.g. had a text value changed to an integer, we don't want a traceback here
- associations = cleanup_param_values( tool.inputs, param_values )
- step = model.WorkflowStep()
- step.type = 'tool'
- step.tool_id = job.tool_id
- step.tool_inputs = tool.params_to_strings( param_values, trans.app )
- # NOTE: We shouldn't need to do two passes here since only
- # an earlier job can be used as an input to a later
- # job.
- for other_hid, input_name in associations:
- if other_hid in hid_to_output_pair:
- other_step, other_name = hid_to_output_pair[ other_hid ]
- conn = model.WorkflowStepConnection()
- conn.input_step = step
- conn.input_name = input_name
- # Should always be connected to an earlier step
- conn.output_step = other_step
- conn.output_name = other_name
- steps.append( step )
- steps_by_job_id[ job_id ] = step
- # Store created dataset hids
- for assoc in job.output_datasets:
- hid_to_output_pair[ assoc.dataset.hid ] = ( step, assoc.name )
- # Workflow to populate
- workflow = model.Workflow()
- workflow.name = workflow_name
- # Order the steps if possible
- attach_ordered_steps( workflow, steps )
- # And let's try to set up some reasonable locations on the canvas
- # (these are pretty arbitrary values)
- levorder = order_workflow_steps_with_levels( steps )
- base_pos = 10
- for i, steps_at_level in enumerate( levorder ):
- for j, index in enumerate( steps_at_level ):
- step = steps[ index ]
- step.position = dict( top=( base_pos + 120 * j ),
- left=( base_pos + 220 * i ) )
- # Store it
- stored = model.StoredWorkflow()
- stored.user = user
- stored.name = workflow_name
- workflow.stored_workflow = stored
- stored.latest_workflow = workflow
- trans.sa_session.add( stored )
- trans.sa_session.flush()
+ extract_workflow(
+ trans,
+ user=user,
+ job_ids=job_ids,
+ dataset_ids=dataset_ids,
+ workflow_name=workflow_name
+ )
# Index page with message
return trans.show_message( "Workflow '%s' created from current history." % workflow_name )
## return trans.show_ok_message( "<p>Workflow '%s' created.</p><p><a target='_top' href='%s'>Click to load in workflow editor</a></p>"
@@ -1692,148 +1627,6 @@
## ---- Utility methods -------------------------------------------------------
-def attach_ordered_steps( workflow, steps ):
- ordered_steps = order_workflow_steps( steps )
- if ordered_steps:
- workflow.has_cycles = False
- for i, step in enumerate( ordered_steps ):
- step.order_index = i
- workflow.steps.append( step )
- else:
- workflow.has_cycles = True
- workflow.steps = steps
-
-
-def edgelist_for_workflow_steps( steps ):
- """
- Create a list of tuples representing edges between ``WorkflowSteps`` based
- on associated ``WorkflowStepConnection``s
- """
- edges = []
- steps_to_index = dict( ( step, i ) for i, step in enumerate( steps ) )
- for step in steps:
- edges.append( ( steps_to_index[step], steps_to_index[step] ) )
- for conn in step.input_connections:
- edges.append( ( steps_to_index[conn.output_step], steps_to_index[conn.input_step] ) )
- return edges
-
-
-def order_workflow_steps( steps ):
- """
- Perform topological sort of the steps, return ordered or None
- """
- position_data_available = True
- for step in steps:
- if not step.position or not 'left' in step.position or not 'top' in step.position:
- position_data_available = False
- if position_data_available:
- steps.sort(cmp=lambda s1, s2: cmp( math.sqrt(s1.position['left'] ** 2 + s1.position['top'] ** 2), math.sqrt(s2.position['left'] ** 2 + s2.position['top'] ** 2)))
- try:
- edges = edgelist_for_workflow_steps( steps )
- node_order = topsort( edges )
- return [ steps[i] for i in node_order ]
- except CycleError:
- return None
-
-
-def order_workflow_steps_with_levels( steps ):
- try:
- return topsort_levels( edgelist_for_workflow_steps( steps ) )
- except CycleError:
- return None
-
-
-class FakeJob( object ):
- """
- Fake job object for datasets that have no creating_job_associations,
- they will be treated as "input" datasets.
- """
- def __init__( self, dataset ):
- self.is_fake = True
- self.id = "fake_%s" % dataset.id
-
-
-def get_job_dict( trans ):
- """
- Return a dictionary of Job -> [ Dataset ] mappings, for all finished
- active Datasets in the current history and the jobs that created them.
- """
- history = trans.get_history()
- # Get the jobs that created the datasets
- warnings = set()
- jobs = odict()
- for dataset in history.active_datasets:
- # FIXME: Create "Dataset.is_finished"
- if dataset.state in ( 'new', 'running', 'queued' ):
- warnings.add( "Some datasets still queued or running were ignored" )
- continue
-
- #if this hda was copied from another, we need to find the job that created the origial hda
- job_hda = dataset
- while job_hda.copied_from_history_dataset_association:
- job_hda = job_hda.copied_from_history_dataset_association
-
- if not job_hda.creating_job_associations:
- jobs[ FakeJob( dataset ) ] = [ ( None, dataset ) ]
-
- for assoc in job_hda.creating_job_associations:
- job = assoc.job
- if job in jobs:
- jobs[ job ].append( ( assoc.name, dataset ) )
- else:
- jobs[ job ] = [ ( assoc.name, dataset ) ]
- return jobs, warnings
-
-
-def cleanup_param_values( inputs, values ):
- """
- Remove 'Data' values from `param_values`, along with metadata cruft,
- but track the associations.
- """
- associations = []
- # dbkey is pushed in by the framework
- if 'dbkey' in values:
- del values['dbkey']
- root_values = values
-
- # Recursively clean data inputs and dynamic selects
- def cleanup( prefix, inputs, values ):
- for key, input in inputs.items():
- if isinstance( input, ( SelectToolParameter, DrillDownSelectToolParameter ) ):
- if input.is_dynamic and not isinstance( values[key], UnvalidatedValue ):
- values[key] = UnvalidatedValue( values[key] )
- if isinstance( input, DataToolParameter ):
- tmp = values[key]
- values[key] = None
- # HACK: Nested associations are not yet working, but we
- # still need to clean them up so we can serialize
- # if not( prefix ):
- if tmp: # this is false for a non-set optional dataset
- if not isinstance(tmp, list):
- associations.append( ( tmp.hid, prefix + key ) )
- else:
- associations.extend( [ (t.hid, prefix + key) for t in tmp] )
-
- # Cleanup the other deprecated crap associated with datasets
- # as well. Worse, for nested datasets all the metadata is
- # being pushed into the root. FIXME: MUST REMOVE SOON
- key = prefix + key + "_"
- for k in root_values.keys():
- if k.startswith( key ):
- del root_values[k]
- elif isinstance( input, Repeat ):
- group_values = values[key]
- for i, rep_values in enumerate( group_values ):
- rep_index = rep_values['__index__']
- cleanup( "%s%s_%d|" % (prefix, key, rep_index ), input.inputs, group_values[i] )
- elif isinstance( input, Conditional ):
- group_values = values[input.name]
- current_case = group_values['__current_case__']
- cleanup( "%s%s|" % ( prefix, key ), input.cases[current_case].inputs, group_values )
- cleanup( "", inputs, values )
- return associations
-
-
def _build_workflow_on_str(instance_ds_names):
# Returns suffix for new histories based on multi input iteration
num_multi_inputs = len(instance_ds_names)
diff -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 -r 6d0c89fc3558d7185daaa1dbda05e6d15879ff00 lib/galaxy/workflow/extract.py
--- /dev/null
+++ b/lib/galaxy/workflow/extract.py
@@ -0,0 +1,209 @@
+""" This module contains functionality to aid in extracting workflows from
+histories.
+"""
+from galaxy.util.odict import odict
+from galaxy import model
+from galaxy.tools.parameters.basic import (
+ DataToolParameter,
+ DrillDownSelectToolParameter,
+ SelectToolParameter,
+ UnvalidatedValue
+)
+from galaxy.tools.parameters.grouping import (
+ Conditional,
+ Repeat
+)
+from .steps import (
+ attach_ordered_steps,
+ order_workflow_steps_with_levels
+)
+
+WARNING_SOME_DATASETS_NOT_READY = "Some datasets still queued or running were ignored"
+
+
+def extract_workflow( trans, user, history=None, job_ids=None, dataset_ids=None, workflow_name=None ):
+ steps = extract_steps( trans, history=history, job_ids=job_ids, dataset_ids=dataset_ids )
+ # Workflow to populate
+ workflow = model.Workflow()
+ workflow.name = workflow_name
+ # Order the steps if possible
+ attach_ordered_steps( workflow, steps )
+ # And let's try to set up some reasonable locations on the canvas
+ # (these are pretty arbitrary values)
+ levorder = order_workflow_steps_with_levels( steps )
+ base_pos = 10
+ for i, steps_at_level in enumerate( levorder ):
+ for j, index in enumerate( steps_at_level ):
+ step = steps[ index ]
+ step.position = dict( top=( base_pos + 120 * j ),
+ left=( base_pos + 220 * i ) )
+ # Store it
+ stored = model.StoredWorkflow()
+ stored.user = user
+ stored.name = workflow_name
+ workflow.stored_workflow = stored
+ stored.latest_workflow = workflow
+ trans.sa_session.add( stored )
+ trans.sa_session.flush()
+ return stored
+
+
+def extract_steps( trans, history=None, job_ids=None, dataset_ids=None ):
+ # Ensure job_ids and dataset_ids are lists (possibly empty)
+ if job_ids is None:
+ job_ids = []
+ elif type( job_ids ) is not list:
+ job_ids = [ job_ids ]
+ if dataset_ids is None:
+ dataset_ids = []
+ elif type( dataset_ids ) is not list:
+ dataset_ids = [ dataset_ids ]
+ # Convert both sets of ids to integers
+ job_ids = [ int( id ) for id in job_ids ]
+ dataset_ids = [ int( id ) for id in dataset_ids ]
+ # Find each job, for security we (implicately) check that they are
+ # associated witha job in the current history.
+ jobs, warnings = summarize( trans, history=history )
+ jobs_by_id = dict( ( job.id, job ) for job in jobs.keys() )
+ steps = []
+ steps_by_job_id = {}
+ hid_to_output_pair = {}
+ # Input dataset steps
+ for hid in dataset_ids:
+ step = model.WorkflowStep()
+ step.type = 'data_input'
+ step.tool_inputs = dict( name="Input Dataset" )
+ hid_to_output_pair[ hid ] = ( step, 'output' )
+ steps.append( step )
+ # Tool steps
+ for job_id in job_ids:
+ assert job_id in jobs_by_id, "Attempt to create workflow with job not connected to current history"
+ job = jobs_by_id[ job_id ]
+ tool_inputs, associations = step_inputs( trans, job )
+ step = model.WorkflowStep()
+ step.type = 'tool'
+ step.tool_id = job.tool_id
+ step.tool_inputs = tool_inputs
+ # NOTE: We shouldn't need to do two passes here since only
+ # an earlier job can be used as an input to a later
+ # job.
+ for other_hid, input_name in associations:
+ if other_hid in hid_to_output_pair:
+ other_step, other_name = hid_to_output_pair[ other_hid ]
+ conn = model.WorkflowStepConnection()
+ conn.input_step = step
+ conn.input_name = input_name
+ # Should always be connected to an earlier step
+ conn.output_step = other_step
+ conn.output_name = other_name
+ steps.append( step )
+ steps_by_job_id[ job_id ] = step
+ # Store created dataset hids
+ for assoc in job.output_datasets:
+ hid_to_output_pair[ assoc.dataset.hid ] = ( step, assoc.name )
+ return steps
+
+
+class FakeJob( object ):
+ """
+ Fake job object for datasets that have no creating_job_associations,
+ they will be treated as "input" datasets.
+ """
+ def __init__( self, dataset ):
+ self.is_fake = True
+ self.id = "fake_%s" % dataset.id
+
+
+def summarize( trans, history=None ):
+ """ Return mapping of job description to datasets for active items in
+ supplied history - needed for building workflow from a history.
+
+ Formerly call get_job_dict in workflow web controller.
+ """
+ if not history:
+ history = trans.get_history()
+
+ # Get the jobs that created the datasets
+ warnings = set()
+ jobs = odict()
+ for dataset in history.active_datasets:
+ # FIXME: Create "Dataset.is_finished"
+ if dataset.state in ( 'new', 'running', 'queued' ):
+ warnings.add( WARNING_SOME_DATASETS_NOT_READY )
+ continue
+
+ #if this hda was copied from another, we need to find the job that created the origial hda
+ job_hda = dataset
+ while job_hda.copied_from_history_dataset_association:
+ job_hda = job_hda.copied_from_history_dataset_association
+
+ if not job_hda.creating_job_associations:
+ jobs[ FakeJob( dataset ) ] = [ ( None, dataset ) ]
+
+ for assoc in job_hda.creating_job_associations:
+ job = assoc.job
+ if job in jobs:
+ jobs[ job ].append( ( assoc.name, dataset ) )
+ else:
+ jobs[ job ] = [ ( assoc.name, dataset ) ]
+
+ return jobs, warnings
+
+
+def step_inputs( trans, job ):
+ tool = trans.app.toolbox.get_tool( job.tool_id )
+ param_values = job.get_param_values( trans.app, ignore_errors=True ) # If a tool was updated and e.g. had a text value changed to an integer, we don't want a traceback here
+ associations = __cleanup_param_values( tool.inputs, param_values )
+ tool_inputs = tool.params_to_strings( param_values, trans.app )
+ return tool_inputs, associations
+
+
+def __cleanup_param_values( inputs, values ):
+ """
+ Remove 'Data' values from `param_values`, along with metadata cruft,
+ but track the associations.
+ """
+ associations = []
+ # dbkey is pushed in by the framework
+ if 'dbkey' in values:
+ del values['dbkey']
+ root_values = values
+
+ # Recursively clean data inputs and dynamic selects
+ def cleanup( prefix, inputs, values ):
+ for key, input in inputs.items():
+ if isinstance( input, ( SelectToolParameter, DrillDownSelectToolParameter ) ):
+ if input.is_dynamic and not isinstance( values[key], UnvalidatedValue ):
+ values[key] = UnvalidatedValue( values[key] )
+ if isinstance( input, DataToolParameter ):
+ tmp = values[key]
+ values[key] = None
+ # HACK: Nested associations are not yet working, but we
+ # still need to clean them up so we can serialize
+ # if not( prefix ):
+ if tmp: # this is false for a non-set optional dataset
+ if not isinstance(tmp, list):
+ associations.append( ( tmp.hid, prefix + key ) )
+ else:
+ associations.extend( [ (t.hid, prefix + key) for t in tmp] )
+
+ # Cleanup the other deprecated crap associated with datasets
+ # as well. Worse, for nested datasets all the metadata is
+ # being pushed into the root. FIXME: MUST REMOVE SOON
+ key = prefix + key + "_"
+ for k in root_values.keys():
+ if k.startswith( key ):
+ del root_values[k]
+ elif isinstance( input, Repeat ):
+ group_values = values[key]
+ for i, rep_values in enumerate( group_values ):
+ rep_index = rep_values['__index__']
+ cleanup( "%s%s_%d|" % (prefix, key, rep_index ), input.inputs, group_values[i] )
+ elif isinstance( input, Conditional ):
+ group_values = values[input.name]
+ current_case = group_values['__current_case__']
+ cleanup( "%s%s|" % ( prefix, key ), input.cases[current_case].inputs, group_values )
+ cleanup( "", inputs, values )
+ return associations
+
+__all__ = [ summarize, extract_workflow ]
diff -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 -r 6d0c89fc3558d7185daaa1dbda05e6d15879ff00 lib/galaxy/workflow/steps.py
--- /dev/null
+++ b/lib/galaxy/workflow/steps.py
@@ -0,0 +1,63 @@
+""" This module contains utility methods for reasoning about and ordering
+workflow steps.
+"""
+import math
+from galaxy.util.topsort import (
+ CycleError,
+ topsort,
+ topsort_levels
+)
+
+
+def attach_ordered_steps( workflow, steps ):
+ """ Attempt to topologically order steps and attach to workflow. If this
+ fails - the workflow contains cycles so it mark it as such.
+ """
+ ordered_steps = order_workflow_steps( steps )
+ if ordered_steps:
+ workflow.has_cycles = False
+ for i, step in enumerate( ordered_steps ):
+ step.order_index = i
+ workflow.steps.append( step )
+ else:
+ workflow.has_cycles = True
+ workflow.steps = steps
+
+
+def order_workflow_steps( steps ):
+ """
+ Perform topological sort of the steps, return ordered or None
+ """
+ position_data_available = True
+ for step in steps:
+ if not step.position or not 'left' in step.position or not 'top' in step.position:
+ position_data_available = False
+ if position_data_available:
+ steps.sort(cmp=lambda s1, s2: cmp( math.sqrt(s1.position['left'] ** 2 + s1.position['top'] ** 2), math.sqrt(s2.position['left'] ** 2 + s2.position['top'] ** 2)))
+ try:
+ edges = edgelist_for_workflow_steps( steps )
+ node_order = topsort( edges )
+ return [ steps[i] for i in node_order ]
+ except CycleError:
+ return None
+
+
+def edgelist_for_workflow_steps( steps ):
+ """
+ Create a list of tuples representing edges between ``WorkflowSteps`` based
+ on associated ``WorkflowStepConnection``s
+ """
+ edges = []
+ steps_to_index = dict( ( step, i ) for i, step in enumerate( steps ) )
+ for step in steps:
+ edges.append( ( steps_to_index[step], steps_to_index[step] ) )
+ for conn in step.input_connections:
+ edges.append( ( steps_to_index[conn.output_step], steps_to_index[conn.input_step] ) )
+ return edges
+
+
+def order_workflow_steps_with_levels( steps ):
+ try:
+ return topsort_levels( edgelist_for_workflow_steps( steps ) )
+ except CycleError:
+ return None
diff -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 -r 6d0c89fc3558d7185daaa1dbda05e6d15879ff00 test/functional/api/test_workflows.py
--- a/test/functional/api/test_workflows.py
+++ b/test/functional/api/test_workflows.py
@@ -67,6 +67,39 @@
self._assert_status_code_is( run_workflow_response, 200 )
self._wait_for_history( history_id, assert_ok=True )
+ def test_extract_from_history( self ):
+ workflow = self.workflow_populator.load_workflow( name="test_for_extract" )
+ workflow_request, history_id = self._setup_workflow_run( workflow )
+ contents_response = self._get( "histories/%s/contents" % history_id )
+ self._assert_status_code_is( contents_response, 200 )
+ hda_ids = map( lambda c: c[ "id" ], contents_response.json() )
+
+ run_workflow_response = self._post( "workflows", data=workflow_request )
+ self._assert_status_code_is( run_workflow_response, 200 )
+
+ self._wait_for_history( history_id, assert_ok=True )
+ data = dict( history_id=history_id, tool_id="cat1" )
+ jobs_response = self._get( "jobs", data=data )
+ self._assert_status_code_is( jobs_response, 200 )
+ cat1_job_id = jobs_response.json()[ 0 ][ "id" ]
+
+ contents_response = self._get( "history/%s/contents", data=data )
+ create_from_data = dict(
+ from_history_id=history_id,
+ dataset_ids=dumps( hda_ids ),
+ job_ids=dumps( [ cat1_job_id ] ),
+ workflow_name="test import from history",
+ )
+ run_workflow_response = self._post( "workflows", data=create_from_data )
+ self._assert_status_code_is( run_workflow_response, 200 )
+
+ new_workflow_id = run_workflow_response.json()[ "id" ]
+ download_response = self._get( "workflows/%s/download" % new_workflow_id )
+ self._assert_status_code_is( download_response, 200 )
+ downloaded_workflow = download_response.json()
+ self.assertEquals( downloaded_workflow[ "name" ], "test import from history" )
+ assert len( downloaded_workflow[ "steps" ] ) == 3
+
def test_run_replace_params_by_tool( self ):
workflow_request, history_id = self._setup_random_x2_workflow( "test_for_replace_tool_params" )
workflow_request[ "parameters" ] = dumps( dict( random_lines1=dict( num_lines=5 ) ) )
diff -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 -r 6d0c89fc3558d7185daaa1dbda05e6d15879ff00 test/unit/workflows/test_extract_summary.py
--- /dev/null
+++ b/test/unit/workflows/test_extract_summary.py
@@ -0,0 +1,98 @@
+import unittest
+
+from galaxy import model
+from galaxy.workflow import extract
+
+UNDEFINED_JOB = object()
+
+
+class TestWorkflowExtractSummary( unittest.TestCase ):
+
+ def setUp( self ):
+ self.history = MockHistory()
+ self.trans = MockTrans( self.history )
+
+ def test_empty_history( self ):
+ job_dict, warnings = extract.summarize( trans=self.trans )
+ assert not warnings
+ assert not job_dict
+
+ def test_summarize_returns_name_and_dataset_list( self ):
+ # Create two jobs and three datasets, test they are groupped
+ # by job correctly with correct output names.
+ hda1 = MockHda()
+ self.history.active_datasets.append( hda1 )
+ hda2 = MockHda( job=hda1.job, output_name="out2" )
+ self.history.active_datasets.append( hda2 )
+ hda3 = MockHda( output_name="out3" )
+ self.history.active_datasets.append( hda3 )
+
+ job_dict, warnings = extract.summarize( trans=self.trans )
+ assert len( job_dict ) == 2
+ assert not warnings
+ self.assertEquals( job_dict[ hda1.job ], [ ( 'out1', hda1 ), ( 'out2', hda2 ) ] )
+ self.assertEquals( job_dict[ hda3.job ], [ ( 'out3', hda3 ) ] )
+
+ def test_finds_original_job_if_copied( self ):
+ hda = MockHda()
+ derived_hda_1 = MockHda()
+ derived_hda_1.copied_from_history_dataset_association = hda
+ derived_hda_2 = MockHda()
+ derived_hda_2.copied_from_history_dataset_association = derived_hda_1
+ self.history.active_datasets.append( derived_hda_2 )
+ job_dict, warnings = extract.summarize( trans=self.trans )
+ assert not warnings
+ assert len( job_dict ) == 1
+ self.assertEquals( job_dict[ hda.job ], [ ('out1', derived_hda_2 ) ] )
+
+ def test_fake_job( self ):
+ """ Fakes job if creating_job_associations is empty.
+ """
+ hda = MockHda( job=UNDEFINED_JOB )
+ self.history.active_datasets.append( hda )
+ job_dict, warnings = extract.summarize( trans=self.trans )
+ assert not warnings
+ assert len( job_dict ) == 1
+ fake_job = job_dict.keys()[ 0 ]
+ assert fake_job.id.startswith( "fake_" )
+ datasets = job_dict.values()[ 0 ]
+ assert datasets == [ ( None, hda ) ]
+
+ def test_warns_and_skips_datasets_if_not_finished( self ):
+ hda = MockHda( state='queued' )
+ self.history.active_datasets.append( hda )
+ job_dict, warnings = extract.summarize( trans=self.trans )
+ assert warnings
+ assert len( job_dict ) == 0
+
+
+class MockHistory( object ):
+
+ def __init__( self ):
+ self.active_datasets = []
+
+
+class MockTrans( object ):
+
+ def __init__( self, history ):
+ self.history = history
+
+ def get_history( self ):
+ return self.history
+
+
+class MockHda( object ):
+
+ def __init__( self, state='ok', output_name='out1', job=None ):
+ self.id = 123
+ self.state = state
+ self.copied_from_history_dataset_association = None
+ if job is not UNDEFINED_JOB:
+ if not job:
+ job = model.Job()
+ self.job = job
+ assoc = model.JobToOutputDatasetAssociation( output_name, self )
+ assoc.job = job
+ self.creating_job_associations = [ assoc ]
+ else:
+ self.creating_job_associations = []
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Handle combinations of newly defined tool dependencies and repository dependencies that are included in updates being pulled to tool shed repositories installed into Galaxy.
by commits-noreply@bitbucket.org 26 Mar '14
by commits-noreply@bitbucket.org 26 Mar '14
26 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/90b4baa5c2b1/
Changeset: 90b4baa5c2b1
User: greg
Date: 2014-03-26 19:58:08
Summary: Handle combinations of newly defined tool dependencies and repository dependencies that are included in updates being pulled to tool shed repositories installed into Galaxy.
Affected #: 15 files
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
@@ -201,9 +201,13 @@
repository_id = kwd.get( 'id', None )
repository = suc.get_installed_tool_shed_repository( trans, repository_id )
tool_shed_url = suc.get_url_from_tool_shed( trans.app, repository.tool_shed )
+ params = '?galaxy_url=%s&name=%s&owner=%s&changeset_revision=%s' % \
+ ( web.url_for( '/', qualified=True ),
+ str( repository.name ),
+ str( repository.owner ),
+ str( repository.changeset_revision ) )
url = suc.url_join( tool_shed_url,
- 'repository/check_for_updates?galaxy_url=%s&name=%s&owner=%s&changeset_revision=%s' % \
- ( web.url_for( '/', qualified=True ), repository.name, repository.owner, repository.changeset_revision ) )
+ 'repository/check_for_updates%s' % params )
return trans.response.send_redirect( url )
@web.expose
@@ -367,9 +371,10 @@
@web.require_admin
def get_tool_dependencies( self, trans, repository_id, repository_name, repository_owner, changeset_revision ):
"""
- Send a request to the appropriate tool shed to retrieve the dictionary of tool dependencies defined for the received repository name,
- owner and changeset revision. The received repository_id is the encoded id of the installed tool shed repository in Galaxy. We need
- it so that we can derive the tool shed from which it was installed.
+ Send a request to the appropriate tool shed to retrieve the dictionary of tool dependencies defined for
+ the received repository name, owner and changeset revision. The received repository_id is the encoded id
+ of the installed tool shed repository in Galaxy. We need it so that we can derive the tool shed from which
+ it was installed.
"""
repository = suc.get_installed_tool_shed_repository( trans, repository_id )
tool_shed_url = suc.get_url_from_tool_shed( trans.app, repository.tool_shed )
@@ -388,8 +393,8 @@
@web.require_admin
def get_updated_repository_information( self, trans, repository_id, repository_name, repository_owner, changeset_revision ):
"""
- Send a request to the appropriate tool shed to retrieve the dictionary of information required to reinstall an updated revision of an
- uninstalled tool shed repository.
+ Send a request to the appropriate tool shed to retrieve the dictionary of information required to reinstall
+ an updated revision of an uninstalled tool shed repository.
"""
repository = suc.get_installed_tool_shed_repository( trans, repository_id )
tool_shed_url = suc.get_url_from_tool_shed( trans.app, repository.tool_shed )
@@ -436,13 +441,16 @@
@web.expose
@web.require_admin
- def initiate_tool_dependency_installation( self, trans, tool_dependencies ):
+ def initiate_tool_dependency_installation( self, trans, tool_dependencies, **kwd ):
"""Install specified dependencies for repository tools."""
# Get the tool_shed_repository from one of the tool_dependencies.
- message = ''
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ err_msg = ''
tool_shed_repository = tool_dependencies[ 0 ].tool_shed_repository
# Get the tool_dependencies.xml file from the repository.
- tool_dependencies_config = suc.get_config_from_disk( suc.TOOL_DEPENDENCY_DEFINITION_FILENAME, tool_shed_repository.repo_path( trans.app ) )
+ tool_dependencies_config = suc.get_config_from_disk( suc.TOOL_DEPENDENCY_DEFINITION_FILENAME,
+ tool_shed_repository.repo_path( trans.app ) )
installed_tool_dependencies = common_install_util.handle_tool_dependencies( app=trans.app,
tool_shed_repository=tool_shed_repository,
tool_dependencies_config=tool_dependencies_config,
@@ -452,13 +460,12 @@
if installed_tool_dependency.status == trans.app.install_model.ToolDependency.installation_status.ERROR:
text = util.unicodify( installed_tool_dependency.error_message )
if text is not None:
- message += ' %s' % text
+ err_msg += ' %s' % text
tool_dependency_ids = [ trans.security.encode_id( td.id ) for td in tool_dependencies ]
- if message:
+ if err_msg:
+ message += err_msg
status = 'error'
- else:
- message = "Installed tool dependencies: %s" % ','.join( td.name for td in installed_tool_dependencies )
- status = 'done'
+ message += "Installed tool dependencies: %s" % ','.join( td.name for td in installed_tool_dependencies )
td_ids = [ trans.security.encode_id( td.id ) for td in tool_shed_repository.tool_dependencies ]
return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
action='manage_tool_dependencies',
@@ -506,9 +513,10 @@
status = 'error'
else:
# Install the latest downloadable revision of the repository.
+ params = '?name=%s&owner=%s&changeset_revisions=%s&galaxy_url=%s' % \
+ ( name, owner, str( latest_downloadable_revision ), web.url_for( '/', qualified=True ) )
url = suc.url_join( tool_shed_url,
- 'repository/install_repositories_by_revision?name=%s&owner=%s&changeset_revisions=%s&galaxy_url=%s' % \
- ( name, owner, latest_downloadable_revision, web.url_for( '/', qualified=True ) ) )
+ 'repository/install_repositories_by_revision%s' % params )
return trans.response.send_redirect( url )
else:
message = 'Cannot locate installed tool shed repository with encoded id <b>%s</b>.' % str( repository_id )
@@ -521,43 +529,74 @@
message=message,
status=status ) )
-
@web.expose
@web.require_admin
- def install_tool_dependencies( self, trans, **kwd ):
+ def install_tool_dependencies_with_update( self, trans, **kwd ):
+ """
+ Updating an installed tool shed repository where new tool dependencies but no new repository
+ dependencies are included in the updated revision.
+ """
+ updating_repository_id = kwd.get( 'updating_repository_id', None )
+ repository = suc.get_installed_tool_shed_repository( trans, updating_repository_id )
+ # All received dependencies need to be installed - confirmed by the caller.
+ encoded_tool_dependencies_dict = kwd.get( 'encoded_tool_dependencies_dict', None )
+ if encoded_tool_dependencies_dict is not None:
+ tool_dependencies_dict = encoding_util.tool_shed_decode( encoded_tool_dependencies_dict )
+ else:
+ tool_dependencies_dict = {}
+ encoded_relative_install_dir = kwd.get( 'encoded_relative_install_dir', None )
+ if encoded_relative_install_dir is not None:
+ relative_install_dir = encoding_util.tool_shed_decode( encoded_relative_install_dir )
+ else:
+ relative_install_dir = ''
+ updating_to_changeset_revision = kwd.get( 'updating_to_changeset_revision', None )
+ updating_to_ctx_rev = kwd.get( 'updating_to_ctx_rev', None )
+ encoded_updated_metadata = kwd.get( 'encoded_updated_metadata', None )
message = kwd.get( 'message', '' )
status = kwd.get( 'status', 'done' )
- tool_dependency_ids = tool_dependency_util.get_tool_dependency_ids( as_string=False, **kwd )
- tool_dependencies = []
- for tool_dependency_id in tool_dependency_ids:
- tool_dependency = tool_dependency_util.get_tool_dependency( trans, tool_dependency_id )
- tool_dependencies.append( tool_dependency )
- if kwd.get( 'install_tool_dependencies_button', False ):
- # Filter tool dependencies to only those that are installed.
- tool_dependencies_for_installation = []
- for tool_dependency in tool_dependencies:
- if tool_dependency.status in [ trans.install_model.ToolDependency.installation_status.UNINSTALLED,
- trans.install_model.ToolDependency.installation_status.ERROR ]:
- tool_dependencies_for_installation.append( tool_dependency )
- if tool_dependencies_for_installation:
- # Redirect back to the ToolDependencyGrid before initiating installation.
- encoded_tool_dependency_for_installation_ids = [ trans.security.encode_id( td.id ) for td in tool_dependencies_for_installation ]
- new_kwd = dict( action='manage_tool_dependencies',
- operation='initiate_tool_dependency_installation',
- tool_dependency_ids=encoded_tool_dependency_for_installation_ids,
- message=message,
- status=status )
- return self.tool_dependency_grid( trans, **new_kwd )
+ install_tool_dependencies = CheckboxField.is_checked( kwd.get( 'install_tool_dependencies', '' ) )
+ if 'install_tool_dependencies_with_update_button' in kwd:
+ # Now that the user has chosen whether to install tool dependencies or not, we can
+ # update the repository record with the changes in the updated revision.
+ if encoded_updated_metadata:
+ updated_metadata = encoding_util.tool_shed_decode( encoded_updated_metadata )
else:
- message = 'All of the selected tool dependencies are already installed.'
- status = 'error'
- return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
- action='manage_repository_tool_dependencies',
- tool_dependency_ids=tool_dependency_ids,
- status=status,
- message=message ) )
- return trans.fill_template( '/admin/tool_shed_repository/install_tool_dependencies.mako',
- tool_dependencies=tool_dependencies,
+ updated_metadata = None
+ repository = repository_util.update_repository_record( trans,
+ repository=repository,
+ updated_metadata_dict=updated_metadata,
+ updated_changeset_revision=updating_to_changeset_revision,
+ updated_ctx_rev=updating_to_ctx_rev )
+ if install_tool_dependencies:
+ tool_dependencies = tool_dependency_util.create_tool_dependency_objects( trans.app,
+ repository,
+ relative_install_dir,
+ set_status=False )
+ message = "The installed repository named '%s' has been updated to change set revision '%s'. " % \
+ ( str( repository.name ), updating_to_changeset_revision )
+ self.initiate_tool_dependency_installation( trans, tool_dependencies, message=message, status=status )
+ # Handle tool dependencies check box.
+ if trans.app.config.tool_dependency_dir is None:
+ if includes_tool_dependencies:
+ message = "Tool dependencies defined in this repository can be automatically installed if you set "
+ message += "the value of your <b>tool_dependency_dir</b> setting in your Galaxy config file "
+ message += "(universe_wsgi.ini) and restart your Galaxy server."
+ status = "warning"
+ install_tool_dependencies_check_box_checked = False
+ else:
+ install_tool_dependencies_check_box_checked = True
+ install_tool_dependencies_check_box = CheckboxField( 'install_tool_dependencies',
+ checked=install_tool_dependencies_check_box_checked )
+ return trans.fill_template( '/admin/tool_shed_repository/install_tool_dependencies_with_update.mako',
+ repository=repository,
+ updating_repository_id=updating_repository_id,
+ updating_to_ctx_rev=updating_to_ctx_rev,
+ updating_to_changeset_revision=updating_to_changeset_revision,
+ encoded_updated_metadata=encoded_updated_metadata,
+ encoded_relative_install_dir=encoded_relative_install_dir,
+ encoded_tool_dependencies_dict=encoded_tool_dependencies_dict,
+ install_tool_dependencies_check_box=install_tool_dependencies_check_box,
+ tool_dependencies_dict=tool_dependencies_dict,
message=message,
status=status )
@@ -611,7 +650,8 @@
# TODO: I believe this block should be removed, but make sure..
repositories_for_uninstallation = []
for repository_id in tsridslist:
- repository = trans.install_model.context.query( trans.install_model.ToolShedRepository ).get( trans.security.decode_id( repository_id ) )
+ repository = trans.install_model.context.query( trans.install_model.ToolShedRepository ) \
+ .get( trans.security.decode_id( repository_id ) )
if repository.status in [ trans.install_model.ToolShedRepository.installation_status.INSTALLED,
trans.install_model.ToolShedRepository.installation_status.ERROR ]:
repositories_for_uninstallation.append( repository )
@@ -632,28 +672,34 @@
filtered_repo_info_dicts = []
filtered_tool_panel_section_keys = []
repositories_for_installation = []
- # Some repositories may have repository dependencies that are required to be installed before the dependent repository, so we'll
- # order the list of tsr_ids to ensure all repositories install in the required order.
+ # Some repositories may have repository dependencies that are required to be installed before the
+ # dependent repository, so we'll order the list of tsr_ids to ensure all repositories install in the
+ # required order.
ordered_tsr_ids, ordered_repo_info_dicts, ordered_tool_panel_section_keys = \
repository_util.order_components_for_installation( trans,
tsr_ids,
repo_info_dicts,
tool_panel_section_keys=tool_panel_section_keys )
for tsr_id in ordered_tsr_ids:
- repository = trans.install_model.context.query( trans.install_model.ToolShedRepository ).get( trans.security.decode_id( tsr_id ) )
+ repository = trans.install_model.context.query( trans.install_model.ToolShedRepository ) \
+ .get( trans.security.decode_id( tsr_id ) )
if repository.status in [ trans.install_model.ToolShedRepository.installation_status.NEW,
trans.install_model.ToolShedRepository.installation_status.UNINSTALLED ]:
repositories_for_installation.append( repository )
- repo_info_dict, tool_panel_section_key = repository_util.get_repository_components_for_installation( tsr_id,
- ordered_tsr_ids,
- ordered_repo_info_dicts,
- ordered_tool_panel_section_keys )
+ repo_info_dict, tool_panel_section_key = \
+ repository_util.get_repository_components_for_installation( tsr_id,
+ ordered_tsr_ids,
+ ordered_repo_info_dicts,
+ ordered_tool_panel_section_keys )
filtered_repo_info_dicts.append( repo_info_dict )
filtered_tool_panel_section_keys.append( tool_panel_section_key )
if repositories_for_installation:
decoded_kwd[ 'repo_info_dicts' ] = filtered_repo_info_dicts
decoded_kwd[ 'tool_panel_section_keys' ] = filtered_tool_panel_section_keys
- self.install_tool_shed_repositories( trans, repositories_for_installation, reinstalling=reinstalling, **decoded_kwd )
+ self.install_tool_shed_repositories( trans,
+ repositories_for_installation,
+ reinstalling=reinstalling,
+ **decoded_kwd )
else:
kwd[ 'message' ] = 'All selected tool shed repositories are already installed.'
kwd[ 'status' ] = 'error'
@@ -772,7 +818,10 @@
trans.install_model.ToolDependency.installation_status.UNINSTALLED ]:
tool_dependencies_for_installation.append( tool_dependency )
if tool_dependencies_for_installation:
- self.initiate_tool_dependency_installation( trans, tool_dependencies_for_installation )
+ self.initiate_tool_dependency_installation( trans,
+ tool_dependencies_for_installation,
+ message=message,
+ status=status )
else:
message = 'All selected tool dependencies are already installed.'
status = 'error'
@@ -780,14 +829,16 @@
message = 'Set the value of your <b>tool_dependency_dir</b> setting in your Galaxy config file (universe_wsgi.ini) '
message += ' and restart your Galaxy server to install tool dependencies.'
status = 'error'
- installed_tool_dependencies_select_field = suc.build_tool_dependencies_select_field( trans,
- tool_shed_repository=tool_shed_repository,
- name='inst_td_ids',
- uninstalled_only=False )
- uninstalled_tool_dependencies_select_field = suc.build_tool_dependencies_select_field( trans,
- tool_shed_repository=tool_shed_repository,
- name='uninstalled_tool_dependency_ids',
- uninstalled_only=True )
+ installed_tool_dependencies_select_field = \
+ suc.build_tool_dependencies_select_field( trans,
+ tool_shed_repository=tool_shed_repository,
+ name='inst_td_ids',
+ uninstalled_only=False )
+ uninstalled_tool_dependencies_select_field = \
+ suc.build_tool_dependencies_select_field( trans,
+ tool_shed_repository=tool_shed_repository,
+ name='uninstalled_tool_dependency_ids',
+ uninstalled_only=True )
return trans.fill_template( '/admin/tool_shed_repository/manage_repository_tool_dependencies.mako',
repository=tool_shed_repository,
installed_tool_dependencies_select_field=installed_tool_dependencies_select_field,
@@ -836,7 +887,10 @@
trans.install_model.ToolDependency.installation_status.UNINSTALLED ]:
tool_dependencies_for_installation.append( tool_dependency )
if tool_dependencies_for_installation:
- self.initiate_tool_dependency_installation( trans, tool_dependencies_for_installation )
+ self.initiate_tool_dependency_installation( trans,
+ tool_dependencies_for_installation,
+ message=message,
+ status=status )
else:
kwd[ 'message' ] = 'All selected tool dependencies are already installed.'
kwd[ 'status' ] = 'error'
@@ -876,18 +930,21 @@
@web.require_admin
def prepare_for_install( self, trans, **kwd ):
if not suc.have_shed_tool_conf_for_install( trans ):
- message = 'The <b>tool_config_file</b> setting in <b>universe_wsgi.ini</b> must include at least one shed tool configuration file name with a '
- message += '<b><toolbox></b> tag that includes a <b>tool_path</b> attribute value which is a directory relative to the Galaxy installation '
- message += 'directory in order to automatically install tools from a Galaxy tool shed (e.g., the file name <b>shed_tool_conf.xml</b> whose '
- message += '<b><toolbox></b> tag is <b><toolbox tool_path="../shed_tools"></b>).<p/>See the '
- message += '<a href="http://wiki.g2.bx.psu.edu/InstallingRepositoriesToGalaxy" target="_blank">Installation of Galaxy tool shed repository tools '
- message += 'into a local Galaxy instance</a> section of the Galaxy tool shed wiki for all of the details.'
+ message = 'The <b>tool_config_file</b> setting in <b>universe_wsgi.ini</b> must include at least one '
+ message += 'shed tool configuration file name with a <b><toolbox></b> tag that includes a <b>tool_path</b> '
+ message += 'attribute value which is a directory relative to the Galaxy installation directory in order '
+ message += 'to automatically install tools from a Galaxy Tool Shed (e.g., the file name <b>shed_tool_conf.xml</b> '
+ message += 'whose <b><toolbox></b> tag is <b><toolbox tool_path="../shed_tools"></b>).<p/>See the '
+ message += '<a href="http://wiki.g2.bx.psu.edu/InstallingRepositoriesToGalaxy" target="_blank">Installation '
+ message += 'of Galaxy Tool Shed repository tools into a local Galaxy instance</a> section of the Galaxy Tool '
+ message += 'Shed wiki for all of the details.'
return trans.show_error_message( message )
message = kwd.get( 'message', '' )
status = kwd.get( 'status', 'done' )
shed_tool_conf = kwd.get( 'shed_tool_conf', None )
tool_shed_url = kwd.get( 'tool_shed_url', None )
- # Handle repository dependencies, which do not include those that are required only for compiling a dependent repository's tool dependencies.
+ # Handle repository dependencies, which do not include those that are required only for compiling a dependent
+ # repository's tool dependencies.
has_repository_dependencies = util.string_as_bool( kwd.get( 'has_repository_dependencies', False ) )
install_repository_dependencies = kwd.get( 'install_repository_dependencies', '' )
# Every repository will be installed into the same tool panel section or all will be installed outside of any sections.
@@ -900,13 +957,36 @@
includes_tools_for_display_in_tool_panel = util.string_as_bool( kwd.get( 'includes_tools_for_display_in_tool_panel', False ) )
includes_tool_dependencies = util.string_as_bool( kwd.get( 'includes_tool_dependencies', False ) )
install_tool_dependencies = kwd.get( 'install_tool_dependencies', '' )
+ # In addition to installing new repositories, this method is called when updating an installed repository
+ # to a new changeset_revision where the update includes newly defined repository dependencies.
+ updating = util.asbool( kwd.get( 'updating', False ) )
+ updating_repository_id = kwd.get( 'updating_repository_id', None )
+ updating_to_changeset_revision = kwd.get( 'updating_to_changeset_revision', None )
+ updating_to_ctx_rev = kwd.get( 'updating_to_ctx_rev', None )
+ encoded_updated_metadata = kwd.get( 'encoded_updated_metadata', None )
encoded_repo_info_dicts = kwd.get( 'encoded_repo_info_dicts', '' )
if encoded_repo_info_dicts:
encoded_repo_info_dicts = encoded_repo_info_dicts.split( encoding_util.encoding_sep )
if not encoded_repo_info_dicts:
- # The request originated in the tool shed via a tool search.
+ # The request originated in the tool shed via a tool search or from this controller's
+ # update_to_changeset_revision() method.
repository_ids = kwd.get( 'repository_ids', None )
- changeset_revisions = kwd.get( 'changeset_revisions', None )
+ if updating:
+ # We have updated an installed repository where the updates included newly defined repository
+ # and possibly tool dependencies. We will have arrived here only if the updates include newly
+ # defined repository dependencies. We're preparing to allow the user to elect to install these
+ # dependencies. At this point, the repository has been updated to the latest changeset revision,
+ # but the received repository id is from the Galaxy side (the caller is this controller's
+ # update_to_changeset_revision() method. We need to get the id of the same repository from the
+ # Tool Shed side.
+ repository = suc.get_tool_shed_repository_by_id( trans, updating_repository_id )
+ url = suc.url_join( tool_shed_url,
+ 'repository/get_repository_id?name=%s&owner=%s' % \
+ ( str( repository.name ), str( repository.owner ) ) )
+ repository_ids = common_util.tool_shed_get( trans.app, tool_shed_url, url )
+ changeset_revisions = updating_to_changeset_revision
+ else:
+ changeset_revisions = kwd.get( 'changeset_revisions', None )
# Get the information necessary to install each repository.
url = suc.url_join( tool_shed_url,
'repository/get_repository_information?repository_ids=%s&changeset_revisions=%s' % \
@@ -918,7 +998,8 @@
if not includes_tools:
includes_tools = util.string_as_bool( decoded_repo_info_dict.get( 'includes_tools', False ) )
if not includes_tools_for_display_in_tool_panel:
- includes_tools_for_display_in_tool_panel = util.string_as_bool( decoded_repo_info_dict.get( 'includes_tools_for_display_in_tool_panel', False ) )
+ includes_tools_for_display_in_tool_panel = \
+ util.string_as_bool( decoded_repo_info_dict.get( 'includes_tools_for_display_in_tool_panel', False ) )
if not has_repository_dependencies:
has_repository_dependencies = util.string_as_bool( repo_information_dict.get( 'has_repository_dependencies', False ) )
if not includes_tool_dependencies:
@@ -927,6 +1008,19 @@
repo_info_dicts = [ encoding_util.tool_shed_decode( encoded_repo_info_dict ) for encoded_repo_info_dict in encoded_repo_info_dicts ]
if ( not includes_tools_for_display_in_tool_panel and kwd.get( 'select_shed_tool_panel_config_button', False ) ) or \
( includes_tools_for_display_in_tool_panel and kwd.get( 'select_tool_panel_section_button', False ) ):
+ if updating:
+ encoded_updated_metadata_dict = kwd.get( 'encoded_updated_metadata_dict', None )
+ updated_changeset_revision = kwd.get( 'updated_changeset_revision', None )
+ updated_ctx_rev = kwd.get( 'updated_ctx_rev', None )
+ repository = suc.get_tool_shed_repository_by_id( trans, updating_repository_id )
+ decoded_updated_metadata = encoding_util.tool_shed_decode( encoded_updated_metadata )
+ # Now that the user has decided whether they will handle dependencies, we can update
+ # the repository to the latest revision.
+ repository = repository_util.update_repository_record( trans,
+ repository=repository,
+ updated_metadata_dict=decoded_updated_metadata,
+ updated_changeset_revision=updating_to_changeset_revision,
+ updated_ctx_rev=updating_to_ctx_rev )
install_repository_dependencies = CheckboxField.is_checked( install_repository_dependencies )
if includes_tool_dependencies:
install_tool_dependencies = CheckboxField.is_checked( install_tool_dependencies )
@@ -959,7 +1053,8 @@
tool_panel_section_keys=tool_panel_section_keys,
tool_path=tool_path,
tool_shed_url=tool_shed_url )
- encoded_kwd, query, tool_shed_repositories, encoded_repository_ids = repository_util.initiate_repository_installation( trans, installation_dict )
+ encoded_kwd, query, tool_shed_repositories, encoded_repository_ids = \
+ repository_util.initiate_repository_installation( trans, installation_dict )
return trans.fill_template( 'admin/tool_shed_repository/initiate_repository_installation.mako',
encoded_kwd=encoded_kwd,
query=query,
@@ -976,12 +1071,14 @@
tool_path = suc.get_tool_path_by_shed_tool_conf_filename( trans, shed_tool_conf )
tool_panel_section_select_field = tool_util.build_tool_panel_section_select_field( trans )
if len( repo_info_dicts ) == 1:
- # If we're installing a single repository, see if it contains a readme or dependencies that we can display.
+ # If we're installing or updating a single repository, see if it contains a readme or
+ # dependencies that we can display.
repo_info_dict = repo_info_dicts[ 0 ]
dependencies_for_repository_dict = common_install_util.get_dependencies_for_repository( trans,
tool_shed_url,
repo_info_dict,
- includes_tool_dependencies )
+ includes_tool_dependencies,
+ updating=updating )
changeset_revision = dependencies_for_repository_dict.get( 'changeset_revision', None )
if not has_repository_dependencies:
has_repository_dependencies = dependencies_for_repository_dict.get( 'has_repository_dependencies', False )
@@ -990,7 +1087,8 @@
if not includes_tools:
includes_tools = dependencies_for_repository_dict.get( 'includes_tools', False )
if not includes_tools_for_display_in_tool_panel:
- includes_tools_for_display_in_tool_panel = dependencies_for_repository_dict.get( 'includes_tools_for_display_in_tool_panel', False )
+ includes_tools_for_display_in_tool_panel = \
+ dependencies_for_repository_dict.get( 'includes_tools_for_display_in_tool_panel', False )
installed_repository_dependencies = dependencies_for_repository_dict.get( 'installed_repository_dependencies', None )
installed_tool_dependencies = dependencies_for_repository_dict.get( 'installed_tool_dependencies', None )
missing_repository_dependencies = dependencies_for_repository_dict.get( 'missing_repository_dependencies', None )
@@ -998,19 +1096,25 @@
name = dependencies_for_repository_dict.get( 'name', None )
repository_owner = dependencies_for_repository_dict.get( 'repository_owner', None )
readme_files_dict = readme_util.get_readme_files_dict_for_display( trans, tool_shed_url, repo_info_dict )
- # We're handling 1 of 2 scenarios here: (1) we're installing a tool shed repository for the first time, so we've retrieved the list of installed
- # and missing repository dependencies from the database (2) we're handling the scenario where an error occurred during the installation process,
- # so we have a tool_shed_repository record in the database with associated repository dependency records. Since we have the repository
- # dependencies in either case, we'll merge the list of missing repository dependencies into the list of installed repository dependencies since
- # each displayed repository dependency will display a status, whether installed or missing.
- containers_dict = repository_util.populate_containers_dict_for_new_install( trans=trans,
- tool_shed_url=tool_shed_url,
- tool_path=tool_path,
- readme_files_dict=readme_files_dict,
- installed_repository_dependencies=installed_repository_dependencies,
- missing_repository_dependencies=missing_repository_dependencies,
- installed_tool_dependencies=installed_tool_dependencies,
- missing_tool_dependencies=missing_tool_dependencies )
+ # We're handling 1 of 3 scenarios here: (1) we're installing a tool shed repository for the first time, so we've
+ # retrieved the list of installed and missing repository dependencies from the database (2) we're handling the
+ # scenario where an error occurred during the installation process, so we have a tool_shed_repository record in
+ # the database with associated repository dependency records. Since we have the repository dependencies in both
+ # of the above 2 cases, we'll merge the list of missing repository dependencies into the list of installed
+ # repository dependencies since each displayed repository dependency will display a status, whether installed or
+ # missing. The 3rd scenario is where we're updating an installed repository and the updates include newly
+ # defined repository (and possibly tool) dependencies. In this case, merging will result in newly defined
+ # dependencies to be lost. We pass the updating parameter to make sure merging occurs only when appropriate.
+ containers_dict = \
+ repository_util.populate_containers_dict_for_new_install( trans=trans,
+ tool_shed_url=tool_shed_url,
+ tool_path=tool_path,
+ readme_files_dict=readme_files_dict,
+ installed_repository_dependencies=installed_repository_dependencies,
+ missing_repository_dependencies=missing_repository_dependencies,
+ installed_tool_dependencies=installed_tool_dependencies,
+ missing_tool_dependencies=missing_tool_dependencies,
+ updating=updating )
else:
# We're installing a list of repositories, each of which may have tool dependencies or repository dependencies.
containers_dicts = []
@@ -1018,7 +1122,8 @@
dependencies_for_repository_dict = common_install_util.get_dependencies_for_repository( trans,
tool_shed_url,
repo_info_dict,
- includes_tool_dependencies )
+ includes_tool_dependencies,
+ updating=updating )
changeset_revision = dependencies_for_repository_dict.get( 'changeset_revision', None )
if not has_repository_dependencies:
has_repository_dependencies = dependencies_for_repository_dict.get( 'has_repository_dependencies', False )
@@ -1027,34 +1132,39 @@
if not includes_tools:
includes_tools = dependencies_for_repository_dict.get( 'includes_tools', False )
if not includes_tools_for_display_in_tool_panel:
- includes_tools_for_display_in_tool_panel = dependencies_for_repository_dict.get( 'includes_tools_for_display_in_tool_panel', False )
+ includes_tools_for_display_in_tool_panel = \
+ dependencies_for_repository_dict.get( 'includes_tools_for_display_in_tool_panel', False )
installed_repository_dependencies = dependencies_for_repository_dict.get( 'installed_repository_dependencies', None )
installed_tool_dependencies = dependencies_for_repository_dict.get( 'installed_tool_dependencies', None )
missing_repository_dependencies = dependencies_for_repository_dict.get( 'missing_repository_dependencies', None )
missing_tool_dependencies = dependencies_for_repository_dict.get( 'missing_tool_dependencies', None )
name = dependencies_for_repository_dict.get( 'name', None )
repository_owner = dependencies_for_repository_dict.get( 'repository_owner', None )
- containers_dict = repository_util.populate_containers_dict_for_new_install( trans=trans,
- tool_shed_url=tool_shed_url,
- tool_path=tool_path,
- readme_files_dict=None,
- installed_repository_dependencies=installed_repository_dependencies,
- missing_repository_dependencies=missing_repository_dependencies,
- installed_tool_dependencies=installed_tool_dependencies,
- missing_tool_dependencies=missing_tool_dependencies )
+ containers_dict = \
+ repository_util.populate_containers_dict_for_new_install( trans=trans,
+ tool_shed_url=tool_shed_url,
+ tool_path=tool_path,
+ readme_files_dict=None,
+ installed_repository_dependencies=installed_repository_dependencies,
+ missing_repository_dependencies=missing_repository_dependencies,
+ installed_tool_dependencies=installed_tool_dependencies,
+ missing_tool_dependencies=missing_tool_dependencies,
+ updating=updating )
containers_dicts.append( containers_dict )
# Merge all containers into a single container.
containers_dict = repository_util.merge_containers_dicts_for_new_install( containers_dicts )
# Handle tool dependencies check box.
if trans.app.config.tool_dependency_dir is None:
if includes_tool_dependencies:
- message = "Tool dependencies defined in this repository can be automatically installed if you set the value of your <b>tool_dependency_dir</b> "
- message += "setting in your Galaxy config file (universe_wsgi.ini) and restart your Galaxy server before installing the repository."
+ message = "Tool dependencies defined in this repository can be automatically installed if you set "
+ message += "the value of your <b>tool_dependency_dir</b> setting in your Galaxy config file "
+ message += "(universe_wsgi.ini) and restart your Galaxy server before installing the repository."
status = "warning"
install_tool_dependencies_check_box_checked = False
else:
install_tool_dependencies_check_box_checked = True
- install_tool_dependencies_check_box = CheckboxField( 'install_tool_dependencies', checked=install_tool_dependencies_check_box_checked )
+ install_tool_dependencies_check_box = CheckboxField( 'install_tool_dependencies',
+ checked=install_tool_dependencies_check_box_checked )
# Handle repository dependencies check box.
install_repository_dependencies_check_box = CheckboxField( 'install_repository_dependencies', checked=True )
encoded_repo_info_dicts = encoding_util.encoding_sep.join( encoded_repo_info_dicts )
@@ -1062,6 +1172,11 @@
if includes_tools_for_display_in_tool_panel:
return trans.fill_template( '/admin/tool_shed_repository/select_tool_panel_section.mako',
encoded_repo_info_dicts=encoded_repo_info_dicts,
+ updating=updating,
+ updating_repository_id=updating_repository_id,
+ updating_to_ctx_rev=updating_to_ctx_rev,
+ updating_to_changeset_revision=updating_to_changeset_revision,
+ encoded_updated_metadata=encoded_updated_metadata,
includes_tools=includes_tools,
includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel,
includes_tool_dependencies=includes_tool_dependencies,
@@ -1077,10 +1192,16 @@
message=message,
status=status )
else:
- # If installing repositories that includes no tools and has no repository dependencies, display a page allowing the Galaxy administrator to
- # select a shed-related tool panel configuration file whose tool_path setting will be the location the repositories will be installed.
+ # If installing repositories that includes no tools and has no repository dependencies, display a page
+ # allowing the Galaxy administrator to select a shed-related tool panel configuration file whose tool_path
+ # setting will be the location the repositories will be installed.
return trans.fill_template( '/admin/tool_shed_repository/select_shed_tool_panel_config.mako',
encoded_repo_info_dicts=encoded_repo_info_dicts,
+ updating=updating,
+ updating_repository_id=updating_repository_id,
+ updating_to_ctx_rev=updating_to_ctx_rev,
+ updating_to_changeset_revision=updating_to_changeset_revision,
+ encoded_updated_metadata=encoded_updated_metadata,
includes_tools=includes_tools,
includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel,
includes_tool_dependencies=includes_tool_dependencies,
@@ -1400,7 +1521,8 @@
dependencies_for_repository_dict = common_install_util.get_dependencies_for_repository( trans,
tool_shed_url,
repo_info_dict,
- includes_tool_dependencies )
+ includes_tool_dependencies,
+ updating=False )
changeset_revision = dependencies_for_repository_dict.get( 'changeset_revision', None )
has_repository_dependencies = dependencies_for_repository_dict.get( 'has_repository_dependencies', False )
includes_tool_dependencies = dependencies_for_repository_dict.get( 'includes_tool_dependencies', False )
@@ -1449,14 +1571,16 @@
original_section_name = ''
tool_panel_section_select_field = None
shed_tool_conf_select_field = tool_util.build_shed_tool_conf_select_field( trans )
- containers_dict = repository_util.populate_containers_dict_for_new_install( trans=trans,
- tool_shed_url=tool_shed_url,
- tool_path=tool_path,
- readme_files_dict=readme_files_dict,
- installed_repository_dependencies=installed_repository_dependencies,
- missing_repository_dependencies=missing_repository_dependencies,
- installed_tool_dependencies=installed_tool_dependencies,
- missing_tool_dependencies=missing_tool_dependencies )
+ containers_dict = \
+ repository_util.populate_containers_dict_for_new_install( trans=trans,
+ tool_shed_url=tool_shed_url,
+ tool_path=tool_path,
+ readme_files_dict=readme_files_dict,
+ installed_repository_dependencies=installed_repository_dependencies,
+ missing_repository_dependencies=missing_repository_dependencies,
+ installed_tool_dependencies=installed_tool_dependencies,
+ missing_tool_dependencies=missing_tool_dependencies,
+ updating=False )
# Since we're reinstalling we'll merge the list of missing repository dependencies into the list of installed repository dependencies since each displayed
# repository dependency will display a status, whether installed or missing.
containers_dict = repository_dependency_util.merge_missing_repository_dependencies_to_installed_container( containers_dict )
@@ -1574,8 +1698,8 @@
@web.require_admin
def set_tool_versions( self, trans, **kwd ):
"""
- Get the tool_versions from the tool shed for each tool in the installed revision of a selected tool shed repository and update the
- metadata for the repository's revision in the Galaxy database.
+ Get the tool_versions from the tool shed for each tool in the installed revision of a selected tool shed
+ repository and update the metadata for the repository's revision in the Galaxy database.
"""
repository = suc.get_installed_tool_shed_repository( trans, kwd[ 'id' ] )
tool_shed_url = suc.get_url_from_tool_shed( trans.app, repository.tool_shed )
@@ -1720,29 +1844,17 @@
resetting_all_metadata_on_repository=False,
updating_installed_repository=True,
persist=True )
- repository.metadata = metadata_dict
- # Update the repository.changeset_revision column in the database.
- repository.changeset_revision = latest_changeset_revision
- repository.ctx_rev = latest_ctx_rev
- # Update the repository.tool_shed_status column in the database.
- tool_shed_status_dict = suc.get_tool_shed_status_for_installed_repository( trans.app, repository )
- if tool_shed_status_dict:
- repository.tool_shed_status = tool_shed_status_dict
- else:
- repository.tool_shed_status = None
- trans.install_model.context.add( repository )
- trans.install_model.context.flush()
if 'tools' in metadata_dict:
tool_panel_dict = metadata_dict.get( 'tool_panel_section', None )
if tool_panel_dict is None:
tool_panel_dict = suc.generate_tool_panel_dict_from_shed_tool_conf_entries( trans.app, repository )
repository_tools_tups = suc.get_repository_tools_tups( trans.app, metadata_dict )
tool_util.add_to_tool_panel( app=trans.app,
- repository_name=repository.name,
+ repository_name=str( repository.name ),
repository_clone_url=repository_clone_url,
- changeset_revision=repository.installed_changeset_revision,
+ changeset_revision=str( repository.installed_changeset_revision ),
repository_tools_tups=repository_tools_tups,
- owner=repository.owner,
+ owner=str( repository.owner ),
shed_tool_conf=shed_tool_conf,
tool_panel_dict=tool_panel_dict,
new_install=False )
@@ -1755,19 +1867,40 @@
os.path.join( relative_install_dir, name ),
repository,
repository_tools_tups )
- # Create tool_dependency records if necessary.
- if 'tool_dependencies' in metadata_dict:
- tool_dependencies = tool_dependency_util.create_tool_dependency_objects( trans.app,
- repository,
- relative_install_dir,
- set_status=False )
+ if 'repository_dependencies' in metadata_dict or 'tool_dependencies' in metadata_dict:
+ if 'repository_dependencies' in metadata_dict:
+ # Updates received include newly defined repository dependencies, so allow the user
+ # the option of installting them. We cannot update the repository with the changes
+ # until that happens, so we have to send them along.
+ new_kwd = dict( tool_shed_url=tool_shed_url,
+ updating_repository_id=trans.security.encode_id( repository.id ),
+ updating_to_ctx_rev=latest_ctx_rev,
+ updating_to_changeset_revision=latest_changeset_revision,
+ encoded_updated_metadata=encoding_util.tool_shed_encode( metadata_dict ),
+ updating=True )
+ return self.prepare_for_install( trans, **new_kwd )
+ # Updates received did not include any newly defined repository dependencies but did include
+ # newly defined tool dependencies.
+ encoded_tool_dependencies_dict = encoding_util.tool_shed_encode( metadata_dict.get( 'tool_dependencies', {} ) )
+ encoded_relative_install_dir = encoding_util.tool_shed_encode( relative_install_dir )
+ new_kwd = dict( updating_repository_id=trans.security.encode_id( repository.id ),
+ updating_to_ctx_rev=latest_ctx_rev,
+ updating_to_changeset_revision=latest_changeset_revision,
+ encoded_updated_metadata=encoding_util.tool_shed_encode( metadata_dict ),
+ encoded_relative_install_dir=encoded_relative_install_dir,
+ encoded_tool_dependencies_dict=encoded_tool_dependencies_dict,
+ message=message,
+ status = status )
+ return self.install_tool_dependencies_with_update( trans, **new_kwd )
+ # Updates received did not include any newly defined repository dependencies or newly defined
+ # tool dependencies.
+ repository = repository_util.update_repository_record( trans,
+ repository=repository,
+ updated_metadata_dict=metadata_dict,
+ updated_changeset_revision=latest_changeset_revision,
+ updated_ctx_rev=latest_ctx_rev )
message = "The installed repository named '%s' has been updated to change set revision '%s'. " % \
( name, latest_changeset_revision )
- # See if any tool dependencies can be installed.
- shed_tool_conf, tool_path, relative_install_dir = \
- suc.get_tool_panel_config_tool_path_install_dir( trans.app, repository )
- if repository.missing_tool_dependencies:
- message += "Click the name of one of the missing tool dependencies listed below to install tool dependencies."
else:
message = "The directory containing the installed repository named '%s' cannot be found. " % name
status = 'error'
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 lib/galaxy/webapps/tool_shed/controllers/repository.py
--- a/lib/galaxy/webapps/tool_shed/controllers/repository.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py
@@ -866,11 +866,13 @@
no_update = 'false'
elif galaxy_url:
# Start building up the url to redirect back to the calling Galaxy instance.
+ params = '?tool_shed_url=%s&name=%s&owner=%s&changeset_revision=%s&latest_changeset_revision=' % \
+ ( web.url_for( '/', qualified=True ), repository.name, repository.user.username, changeset_revision )
url = suc.url_join( galaxy_url,
- 'admin_toolshed/update_to_changeset_revision?tool_shed_url=%s&name=%s&owner=%s&changeset_revision=%s&latest_changeset_revision=' % \
- ( web.url_for( '/', qualified=True ), repository.name, repository.user.username, changeset_revision ) )
+ 'admin_toolshed/update_to_changeset_revision%s' % params )
else:
- message = 'Unable to check for updates due to an invalid Galaxy URL: <b>%s</b>. You may need to enable third-party cookies in your browser. ' % galaxy_url
+ message = 'Unable to check for updates due to an invalid Galaxy URL: <b>%s</b>. ' % galaxy_url
+ message += 'You may need to enable third-party cookies in your browser. '
return trans.show_error_message( message )
if changeset_revision == repository.tip( trans.app ):
# If changeset_revision is the repository tip, there are no additional updates.
@@ -883,15 +885,17 @@
trans.security.encode_id( repository.id ),
changeset_revision )
if repository_metadata:
- # If changeset_revision is in the repository_metadata table for this repository, there are no additional updates.
+ # If changeset_revision is in the repository_metadata table for this repository, there are no
+ # additional updates.
if from_update_manager:
return no_update
else:
# Return the same value for changeset_revision and latest_changeset_revision.
url += latest_changeset_revision
else:
- # The changeset_revision column in the repository_metadata table has been updated with a new changeset_revision value since the
- # repository was installed. We need to find the changeset_revision to which we need to update.
+ # The changeset_revision column in the repository_metadata table has been updated with a new
+ # changeset_revision value since the repository was installed. We need to find the changeset_revision
+ # to which we need to update.
update_to_changeset_hash = None
for changeset in repo.changelog:
changeset_hash = str( repo.changectx( changeset ) )
@@ -1680,6 +1684,16 @@
return encoding_util.tool_shed_encode( repository_dependencies )
return ''
+ @web.expose
+ def get_repository_id( self, trans, **kwd ):
+ """Given a repository name and owner, return the encoded repository id."""
+ repository_name = kwd[ 'name' ]
+ repository_owner = kwd[ 'owner' ]
+ repository = suc.get_repository_by_name_and_owner( trans.app, repository_name, repository_owner )
+ if repository:
+ return trans.security.encode_id( repository.id )
+ return ''
+
@web.json
def get_repository_information( self, trans, repository_ids, changeset_revisions, **kwd ):
"""
@@ -1824,7 +1838,9 @@
if not repository_metadata:
# The received changeset_revision is no longer associated with metadata, so get the next changeset_revision in the repository
# changelog that is associated with metadata.
- changeset_revision = suc.get_next_downloadable_changeset_revision( repository, repo, after_changeset_revision=changeset_revision )
+ changeset_revision = suc.get_next_downloadable_changeset_revision( repository,
+ repo,
+ after_changeset_revision=changeset_revision )
repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, repository_id, changeset_revision )
ctx = suc.get_changectx_for_changeset( repo, changeset_revision )
repo_info_dict = repository_util.create_repo_info_dict( trans=trans,
@@ -2039,11 +2055,12 @@
galaxy_url = suc.handle_galaxy_url( trans, **kwd )
if galaxy_url:
# Redirect back to local Galaxy to perform install.
+ params = '?tool_shed_url=%s&repository_ids=%s&changeset_revisions=%s' % \
+ ( web.url_for( '/', qualified=True ),
+ ','.join( util.listify( repository_ids ) ),
+ ','.join( util.listify( changeset_revisions ) ) )
url = suc.url_join( galaxy_url,
- 'admin_toolshed/prepare_for_install?tool_shed_url=%s&repository_ids=%s&changeset_revisions=%s' % \
- ( web.url_for( '/', qualified=True ),
- ','.join( util.listify( repository_ids ) ),
- ','.join( util.listify( changeset_revisions ) ) ) )
+ 'admin_toolshed/prepare_for_install%s' % params )
return trans.response.send_redirect( url )
else:
message = 'Repository installation is not possible due to an invalid Galaxy URL: <b>%s</b>. ' % galaxy_url
@@ -2477,9 +2494,10 @@
@web.expose
def next_installable_changeset_revision( self, trans, **kwd ):
"""
- Handle a request from a Galaxy instance where the changeset_revision defined for a repository in a dependency definition file is older
- than the changeset_revision associated with the installed repository. This will occur with repository's of type tool_dependency_definition,
- and this scenario will occur while repository dependency hierarchies are bing installed.
+ Handle a request from a Galaxy instance where the changeset_revision defined for a repository
+ in a dependency definition file is older than the changeset_revision associated with the installed
+ repository. This will occur with repository's of type tool_dependency_definition, and this scenario
+ will occur while repository dependency hierarchies are bing installed.
"""
name = kwd.get( 'name', None )
owner = kwd.get( 'owner', None )
@@ -2981,12 +2999,13 @@
@web.expose
def updated_changeset_revisions( self, trans, **kwd ):
"""
- Handle a request from a local Galaxy instance to retrieve the list of changeset revisions to which an installed repository can be updated. This
- method will return a string of comma-separated changeset revision hashes for all available updates to the received changeset revision. Among
- other things , this method handles the scenario where an installed tool shed repository's tool_dependency definition file defines a changeset
- revision for a complex repository dependency that is outdated. In other words, a defined changeset revision is older than the current changeset
- revision for the required repository, making it impossible to discover the repository without knowledge of revisions to which it could have been
- updated.
+ Handle a request from a local Galaxy instance to retrieve the list of changeset revisions to which an
+ installed repository can be updated. This method will return a string of comma-separated changeset revision
+ hashes for all available updates to the received changeset revision. Among other things , this method
+ handles the scenario where an installed tool shed repository's tool_dependency definition file defines a
+ changeset revision for a complex repository dependency that is outdated. In other words, a defined changeset
+ revision is older than the current changeset revision for the required repository, making it impossible to
+ discover the repository without knowledge of revisions to which it could have been updated.
"""
name = kwd.get( 'name', None )
owner = kwd.get( 'owner', None )
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 lib/tool_shed/galaxy_install/repository_util.py
--- a/lib/tool_shed/galaxy_install/repository_util.py
+++ b/lib/tool_shed/galaxy_install/repository_util.py
@@ -37,15 +37,19 @@
Galaxy instance. The dictionary will also contain the recursive list of repository dependencies defined
for the repository, as well as the defined tool dependencies.
- This method is called from Galaxy under three scenarios:
+ This method is called from Galaxy under four scenarios:
1. During the tool shed repository installation process via the tool shed's get_repository_information()
- method. In this case both the received repository and repository_metadata will be objects., but
+ method. In this case both the received repository and repository_metadata will be objects, but
tool_dependencies and repository_dependencies will be None.
- 2. When a tool shed repository that was uninstalled from a Galaxy instance is being reinstalled with no
+ 2. When getting updates for an install repository where the updates include newly defined repository
+ dependency definitions. This scenario is similar to 1. above. The tool shed's get_repository_information()
+ method is the caller, and both the received repository and repository_metadata will be objects, but
+ tool_dependencies and repository_dependencies will be None.
+ 3. When a tool shed repository that was uninstalled from a Galaxy instance is being reinstalled with no
updates available. In this case, both repository and repository_metadata will be None, but tool_dependencies
and repository_dependencies will be objects previously retrieved from the tool shed if the repository includes
definitions for them.
- 3. When a tool shed repository that was uninstalled from a Galaxy instance is being reinstalled with updates
+ 4. When a tool shed repository that was uninstalled from a Galaxy instance is being reinstalled with updates
available. In this case, this method is reached via the tool shed's get_updated_repository_information()
method, and both repository and repository_metadata will be objects but tool_dependencies and
repository_dependencies will be None.
@@ -184,16 +188,22 @@
repo_dir = repository.repo_path( trans.app )
repo = hg.repository( suc.get_configured_ui(), repo_dir )
repository_clone_url = suc.generate_clone_url_for_repository_in_tool_shed( trans, repository )
- repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, repository_id, changeset_revision )
+ repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans,
+ repository_id,
+ changeset_revision )
if not repository_metadata:
- # The received changeset_revision is no longer installable, so get the next changeset_revision in the repository's changelog.
- # This generally occurs only with repositories of type tool_dependency_definition.
- next_downloadable_changeset_revision = suc.get_next_downloadable_changeset_revision( repository, repo, changeset_revision )
+ # The received changeset_revision is no longer installable, so get the next changeset_revision
+ # in the repository's changelog. This generally occurs only with repositories of type
+ # tool_dependency_definition.
+ next_downloadable_changeset_revision = \
+ suc.get_next_downloadable_changeset_revision( repository,repo, changeset_revision )
if next_downloadable_changeset_revision:
- repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, repository_id, next_downloadable_changeset_revision )
+ repository_metadata = \
+ suc.get_repository_metadata_by_changeset_revision( trans, repository_id, next_downloadable_changeset_revision )
if repository_metadata:
- # For now, we'll always assume that we'll get repository_metadata, but if we discover our assumption is not valid we'll have to
- # enhance the callers to handle repository_metadata values of None in the returned repo_info_dict.
+ # For now, we'll always assume that we'll get repository_metadata, but if we discover our assumption
+ # is not valid we'll have to enhance the callers to handle repository_metadata values of None in the
+ # returned repo_info_dict.
metadata = repository_metadata.metadata
if 'tools' in metadata:
includes_tools = True
@@ -743,9 +753,13 @@
ordered_tool_panel_section_keys.append( tool_panel_section_key )
return ordered_tsr_ids, ordered_repo_info_dicts, ordered_tool_panel_section_keys
-def populate_containers_dict_for_new_install( trans, tool_shed_url, tool_path, readme_files_dict, installed_repository_dependencies, missing_repository_dependencies,
- installed_tool_dependencies, missing_tool_dependencies ):
- """Return the populated containers for a repository being installed for the first time."""
+def populate_containers_dict_for_new_install( trans, tool_shed_url, tool_path, readme_files_dict, installed_repository_dependencies,
+ missing_repository_dependencies, installed_tool_dependencies, missing_tool_dependencies,
+ updating=False ):
+ """
+ Return the populated containers for a repository being installed for the first time or for an installed repository
+ that is being updated and the updates include newly defined repository (and possibly tool) dependencies.
+ """
installed_tool_dependencies, missing_tool_dependencies = \
tool_dependency_util.populate_tool_dependencies_dicts( trans=trans,
tool_shed_url=tool_shed_url,
@@ -753,27 +767,32 @@
repository_installed_tool_dependencies=installed_tool_dependencies,
repository_missing_tool_dependencies=missing_tool_dependencies,
required_repo_info_dicts=None )
- # Since we are installing a new repository, most of the repository contents are set to None since we don't yet know what they are.
- containers_dict = container_util.build_repository_containers_for_galaxy( trans=trans,
- repository=None,
- datatypes=None,
- invalid_tools=None,
- missing_repository_dependencies=missing_repository_dependencies,
- missing_tool_dependencies=missing_tool_dependencies,
- readme_files_dict=readme_files_dict,
- repository_dependencies=installed_repository_dependencies,
- tool_dependencies=installed_tool_dependencies,
- valid_tools=None,
- workflows=None,
- valid_data_managers=None,
- invalid_data_managers=None,
- data_managers_errors=None,
- new_install=True,
- reinstalling=False )
- # Merge the missing_repository_dependencies container contents to the installed_repository_dependencies container.
- containers_dict = repository_dependency_util.merge_missing_repository_dependencies_to_installed_container( containers_dict )
- # Merge the missing_tool_dependencies container contents to the installed_tool_dependencies container.
- containers_dict = tool_dependency_util.merge_missing_tool_dependencies_to_installed_container( containers_dict )
+ # Most of the repository contents are set to None since we don't yet know what they are.
+ containers_dict = \
+ container_util.build_repository_containers_for_galaxy( trans=trans,
+ repository=None,
+ datatypes=None,
+ invalid_tools=None,
+ missing_repository_dependencies=missing_repository_dependencies,
+ missing_tool_dependencies=missing_tool_dependencies,
+ readme_files_dict=readme_files_dict,
+ repository_dependencies=installed_repository_dependencies,
+ tool_dependencies=installed_tool_dependencies,
+ valid_tools=None,
+ workflows=None,
+ valid_data_managers=None,
+ invalid_data_managers=None,
+ data_managers_errors=None,
+ new_install=True,
+ reinstalling=False )
+ if not updating:
+ # If we installing a new repository and not updaing an installed repository, we can merge
+ # the missing_repository_dependencies container contents to the installed_repository_dependencies
+ # container. When updating an installed repository, merging will result in losing newly defined
+ # dependencies included in the updates.
+ containers_dict = repository_dependency_util.merge_missing_repository_dependencies_to_installed_container( containers_dict )
+ # Merge the missing_tool_dependencies container contents to the installed_tool_dependencies container.
+ containers_dict = tool_dependency_util.merge_missing_tool_dependencies_to_installed_container( containers_dict )
return containers_dict
def pull_repository( repo, repository_clone_url, ctx_rev ):
@@ -875,3 +894,23 @@
repository.uninstalled = uninstalled
trans.install_model.context.add( repository )
trans.install_model.context.flush()
+
+def update_repository_record( trans, repository, updated_metadata_dict, updated_changeset_revision, updated_ctx_rev ):
+ """
+ Update a tool_shed_repository database record with new information retrieved from the
+ Tool Shed. This happens when updating an installed repository to a new changeset revision.
+ """
+ repository.metadata = updated_metadata_dict
+ # Update the repository.changeset_revision column in the database.
+ repository.changeset_revision = updated_changeset_revision
+ repository.ctx_rev = updated_ctx_rev
+ # Update the repository.tool_shed_status column in the database.
+ tool_shed_status_dict = suc.get_tool_shed_status_for_installed_repository( trans.app, repository )
+ if tool_shed_status_dict:
+ repository.tool_shed_status = tool_shed_status_dict
+ else:
+ repository.tool_shed_status = None
+ trans.install_model.context.add( repository )
+ trans.install_model.context.flush()
+ trans.install_model.context.refresh( repository )
+ return repository
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
@@ -359,13 +359,14 @@
can_install_tool_dependency = True
if can_install_tool_dependency:
package_install_version = package_elem.get( 'version', '1.0' )
- tool_dependency = tool_dependency_util.create_or_update_tool_dependency( app=app,
- tool_shed_repository=tool_shed_repository,
- name=package_name,
- version=package_version,
- type='package',
- status=app.install_model.ToolDependency.installation_status.INSTALLING,
- set_status=True )
+ tool_dependency = \
+ tool_dependency_util.create_or_update_tool_dependency( app=app,
+ tool_shed_repository=tool_shed_repository,
+ name=package_name,
+ version=package_version,
+ type='package',
+ status=app.install_model.ToolDependency.installation_status.INSTALLING,
+ set_status=True )
# Get the information about the current platform in case the tool dependency definition includes tag sets
# for installing compiled binaries.
platform_info_dict = tool_dependency_util.get_platform_info_dict()
@@ -879,25 +880,28 @@
# Tool dependencies of type "set_environmnet" always have the version attribute set to None.
attr_tup = ( env_var_name, None, 'set_environment' )
if attr_tup in attr_tups_of_dependencies_for_install:
- install_dir = tool_dependency_util.get_tool_dependency_install_dir( app=app,
- repository_name=tool_shed_repository.name,
- repository_owner=tool_shed_repository.owner,
- repository_changeset_revision=tool_shed_repository.installed_changeset_revision,
- tool_dependency_type='set_environment',
- tool_dependency_name=env_var_name,
- tool_dependency_version=None )
+ install_dir = \
+ tool_dependency_util.get_tool_dependency_install_dir( app=app,
+ repository_name=tool_shed_repository.name,
+ repository_owner=tool_shed_repository.owner,
+ repository_changeset_revision=tool_shed_repository.installed_changeset_revision,
+ tool_dependency_type='set_environment',
+ tool_dependency_name=env_var_name,
+ tool_dependency_version=None )
tool_shed_repository_install_dir = get_tool_shed_repository_install_dir( app, tool_shed_repository )
env_var_dict = td_common_util.create_env_var_dict( env_var_elem, tool_shed_repository_install_dir=tool_shed_repository_install_dir )
if env_var_dict:
if not os.path.exists( install_dir ):
os.makedirs( install_dir )
- tool_dependency = tool_dependency_util.create_or_update_tool_dependency( app=app,
- tool_shed_repository=tool_shed_repository,
- name=env_var_name,
- version=None,
- type='set_environment',
- status=app.install_model.ToolDependency.installation_status.INSTALLING,
- set_status=True )
+ status = app.install_model.ToolDependency.installation_status.INSTALLING
+ tool_dependency = \
+ tool_dependency_util.create_or_update_tool_dependency( app=app,
+ tool_shed_repository=tool_shed_repository,
+ name=env_var_name,
+ version=None,
+ type='set_environment',
+ status=status,
+ set_status=True )
if env_var_version == '1.0':
# Create this tool dependency's env.sh file.
env_file_builder = fabric_util.EnvFileBuilder( install_dir )
@@ -906,28 +910,34 @@
error_message = 'Error creating env.sh file for tool dependency %s, return_code: %s' % \
( str( tool_dependency.name ), str( return_code ) )
log.debug( error_message )
- tool_dependency = tool_dependency_util.set_tool_dependency_attributes( app,
- tool_dependency=tool_dependency,
- status=app.install_model.ToolDependency.installation_status.ERROR,
- error_message=error_message,
- remove_from_disk=False )
+ status = app.install_model.ToolDependency.installation_status.ERROR
+ tool_dependency = \
+ tool_dependency_util.set_tool_dependency_attributes( app,
+ tool_dependency=tool_dependency,
+ status=status,
+ error_message=error_message,
+ remove_from_disk=False )
else:
if tool_dependency.status not in [ app.install_model.ToolDependency.installation_status.ERROR,
app.install_model.ToolDependency.installation_status.INSTALLED ]:
- tool_dependency = tool_dependency_util.set_tool_dependency_attributes( app,
- tool_dependency=tool_dependency,
- status=app.install_model.ToolDependency.installation_status.INSTALLED,
- error_message=None,
- remove_from_disk=False )
+ status = app.install_model.ToolDependency.installation_status.INSTALLED
+ tool_dependency = \
+ tool_dependency_util.set_tool_dependency_attributes( app,
+ tool_dependency=tool_dependency,
+ status=status,
+ error_message=None,
+ remove_from_disk=False )
log.debug( 'Environment variable %s set in %s for tool dependency %s.' % \
( str( env_var_name ), str( install_dir ), str( tool_dependency.name ) ) )
else:
error_message = 'Only set_environment version 1.0 is currently supported (i.e., change your tag to be <set_environment version="1.0">).'
- tool_dependency = tool_dependency_util.set_tool_dependency_attributes( app,
- tool_dependency=tool_dependency,
- status=app.install_model.ToolDependency.installation_status.ERROR,
- error_message=error_message,
- remove_from_disk=False )
+ status = app.install_model.ToolDependency.installation_status.ERROR
+ tool_dependency = \
+ tool_dependency_util.set_tool_dependency_attributes( app,
+ tool_dependency=tool_dependency,
+ status=status,
+ error_message=error_message,
+ remove_from_disk=False )
return tool_dependency
def strip_path( fpath ):
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 lib/tool_shed/util/common_install_util.py
--- a/lib/tool_shed/util/common_install_util.py
+++ b/lib/tool_shed/util/common_install_util.py
@@ -70,7 +70,7 @@
if display_path is not None:
datatype_util.load_installed_display_applications( trans.app, installed_repository_dict, deactivate=False )
-def get_dependencies_for_repository( trans, tool_shed_url, repo_info_dict, includes_tool_dependencies ):
+def get_dependencies_for_repository( trans, tool_shed_url, repo_info_dict, includes_tool_dependencies, updating=False ):
"""
Return dictionaries containing the sets of installed and missing tool dependencies and repository
dependencies associated with the repository defined by the received repo_info_dict.
@@ -90,7 +90,7 @@
# Inspect the tool_dependencies dictionary to separate the installed and missing tool dependencies.
# We don't add to installed_td and missing_td here because at this point they are empty.
installed_td, missing_td = \
- get_installed_and_missing_tool_dependencies_for_installing_repository( trans, tool_shed_url, tool_dependencies )
+ get_installed_and_missing_tool_dependencies_for_repository( trans, tool_shed_url, tool_dependencies )
# In cases where a repository dependency is required only for compiling a dependent repository's
# tool dependency, the value of repository_dependencies will be an empty dictionary here.
if repository_dependencies:
@@ -101,10 +101,11 @@
name,
repository_owner,
changeset_revision )
- if repository and repository.metadata:
+ if not updating and repository and repository.metadata:
installed_rd, missing_rd = get_installed_and_missing_repository_dependencies( trans, repository )
else:
- installed_rd, missing_rd = get_installed_and_missing_repository_dependencies_for_new_install( trans, repo_info_tuple )
+ installed_rd, missing_rd = \
+ get_installed_and_missing_repository_dependencies_for_new_or_updated_install( trans, repo_info_tuple )
# Discover all repository dependencies and retrieve information for installing them.
all_repo_info_dict = get_required_repo_info_dicts( trans, tool_shed_url, util.listify( repo_info_dict ) )
has_repository_dependencies = all_repo_info_dict.get( 'has_repository_dependencies', False )
@@ -119,7 +120,8 @@
required_tool_dependencies = {}
for rid in required_repo_info_dicts:
for name, repo_info_tuple in rid.items():
- description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, rid_repository_dependencies, rid_tool_dependencies = \
+ description, repository_clone_url, changeset_revision, ctx_rev, \
+ repository_owner, rid_repository_dependencies, rid_tool_dependencies = \
suc.get_repo_info_tuple_contents( repo_info_tuple )
if rid_tool_dependencies:
for td_key, td_dict in rid_tool_dependencies.items():
@@ -128,7 +130,9 @@
if required_tool_dependencies:
# Discover and categorize all tool dependencies defined for this repository's repository dependencies.
required_installed_td, required_missing_td = \
- get_installed_and_missing_tool_dependencies_for_installing_repository( trans, tool_shed_url, required_tool_dependencies )
+ get_installed_and_missing_tool_dependencies_for_repository( trans,
+ tool_shed_url,
+ required_tool_dependencies )
if required_installed_td:
if not includes_tool_dependencies:
includes_tool_dependencies = True
@@ -168,11 +172,12 @@
def get_installed_and_missing_repository_dependencies( trans, repository ):
"""
- Return the installed and missing repository dependencies for a tool shed repository that has a record in the Galaxy database, but
- may or may not be installed. In this case, the repository dependencies are associated with the repository in the database. Do not
- include a repository dependency if it is required only to compile a tool dependency defined for the dependent repository since these
- special kinds of repository dependencies are really a dependency of the dependent repository's contained tool dependency, and only if
- that tool dependency requires compilation.
+ Return the installed and missing repository dependencies for a tool shed repository that has a record
+ in the Galaxy database, but may or may not be installed. In this case, the repository dependencies are
+ associated with the repository in the database. Do not include a repository dependency if it is required
+ only to compile a tool dependency defined for the dependent repository since these special kinds of repository
+ dependencies are really a dependency of the dependent repository's contained tool dependency, and only
+ if that tool dependency requires compilation.
"""
missing_repository_dependencies = {}
installed_repository_dependencies = {}
@@ -228,7 +233,7 @@
missing_repository_dependencies[ 'description' ] = description
return installed_repository_dependencies, missing_repository_dependencies
-def get_installed_and_missing_repository_dependencies_for_new_install( trans, repo_info_tuple ):
+def get_installed_and_missing_repository_dependencies_for_new_or_updated_install( trans, repo_info_tuple ):
"""
Parse the received repository_dependencies dictionary that is associated with a repository being
installed into Galaxy for the first time and attempt to determine repository dependencies that are
@@ -264,13 +269,13 @@
tmp_repo_info_tuple )
if repository:
new_rd_tup = [ tool_shed,
- name,
- owner,
- changeset_revision,
- prior_installation_required,
- only_if_compiling_contained_td,
- repository.id,
- repository.status ]
+ name,
+ owner,
+ changeset_revision,
+ prior_installation_required,
+ only_if_compiling_contained_td,
+ repository.id,
+ repository.status ]
if repository.status == trans.install_model.ToolShedRepository.installation_status.INSTALLED:
if new_rd_tup not in installed_rd_tups:
installed_rd_tups.append( new_rd_tup )
@@ -285,12 +290,12 @@
missing_rd_tups.append( new_rd_tup )
else:
new_rd_tup = [ tool_shed,
- name,
- owner,
- changeset_revision,
- prior_installation_required,
- only_if_compiling_contained_td,
- None,
+ name,
+ owner,
+ changeset_revision,
+ prior_installation_required,
+ only_if_compiling_contained_td,
+ None,
'Never installed' ]
if not util.asbool( only_if_compiling_contained_td ):
# A repository dependency that is not installed will not be considered missing if it's value for
@@ -307,11 +312,17 @@
missing_repository_dependencies[ 'description' ] = description
return installed_repository_dependencies, missing_repository_dependencies
-def get_installed_and_missing_tool_dependencies_for_installing_repository( trans, tool_shed_url, tool_dependencies_dict ):
+def get_installed_and_missing_tool_dependencies_for_repository( trans, tool_shed_url, tool_dependencies_dict ):
"""
Return the lists of installed tool dependencies and missing tool dependencies for a set of repositories
being installed into Galaxy.
"""
+ # FIXME: This implementation breaks when updates to a repository contain dependencies that result in
+ # multiple entries for a specific tool dependency. A scenario where this can happen is where 2 repositories
+ # define the same dependency internally (not using the complex repository dependency definition to a separate
+ # package repository approach). If 2 repositories contain the same tool_dependencies.xml file, one dependency
+ # will be lost since the values in these returned dictionaries are not lists. All tool dependency dictionaries
+ # should have lists as values. These scenarios are probably extreme corner cases, but still should be handled.
installed_tool_dependencies = {}
missing_tool_dependencies = {}
if tool_dependencies_dict:
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 lib/tool_shed/util/container_util.py
--- a/lib/tool_shed/util/container_util.py
+++ b/lib/tool_shed/util/container_util.py
@@ -821,8 +821,8 @@
tool_dependencies = metadata[ 'tool_dependencies' ]
if trans.webapp.name == 'tool_shed':
if 'orphan_tool_dependencies' in metadata:
- # The use of the orphan_tool_dependencies category in metadata has been deprecated, but we still need to check in case
- # the metadata is out of date.
+ # The use of the orphan_tool_dependencies category in metadata has been deprecated,
+ # but we still need to check in case the metadata is out of date.
orphan_tool_dependencies = metadata[ 'orphan_tool_dependencies' ]
tool_dependencies.update( orphan_tool_dependencies )
# Tool dependencies can be categorized as orphans only if the repository contains tools.
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 lib/tool_shed/util/encoding_util.py
--- a/lib/tool_shed/util/encoding_util.py
+++ b/lib/tool_shed/util/encoding_util.py
@@ -21,7 +21,6 @@
try:
values = json.loads( value )
except Exception, e:
- #log.debug( "Decoding json value from tool shed for value '%s' threw exception: %s" % ( str( value ), str( e ) ) )
pass
if values is not None:
try:
@@ -34,7 +33,7 @@
return values
def tool_shed_encode( val ):
- if isinstance( val, dict ):
+ if isinstance( val, dict ) or isinstance( val, list ):
value = json.dumps( val )
else:
value = val
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 lib/tool_shed/util/metadata_util.py
--- a/lib/tool_shed/util/metadata_util.py
+++ b/lib/tool_shed/util/metadata_util.py
@@ -662,9 +662,11 @@
# See if we have a repository dependencies defined.
if name == suc.REPOSITORY_DEPENDENCY_DEFINITION_FILENAME:
path_to_repository_dependencies_config = os.path.join( root, name )
- metadata_dict, error_message = generate_repository_dependency_metadata( app,
- path_to_repository_dependencies_config,
- metadata_dict )
+ metadata_dict, error_message = \
+ generate_repository_dependency_metadata( app,
+ path_to_repository_dependencies_config,
+ metadata_dict,
+ updating_installed_repository=updating_installed_repository )
if error_message:
invalid_file_tups.append( ( name, error_message ) )
# See if we have one or more READ_ME files.
@@ -795,7 +797,10 @@
# is True, the tool dependency definition will be set as invalid. This is currently the only case
# where a tool dependency definition is considered invalid.
repository_dependency_tup, repository_dependency_is_valid, error_message = \
- handle_repository_elem( app=app, repository_elem=sub_elem, only_if_compiling_contained_td=False )
+ handle_repository_elem( app=app,
+ repository_elem=sub_elem,
+ only_if_compiling_contained_td=False,
+ updating_installed_repository=False )
elif sub_elem.tag == 'install':
package_install_version = sub_elem.get( 'version', '1.0' )
if package_install_version == '1.0':
@@ -829,7 +834,8 @@
repository_dependency_tup, repository_dependency_is_valid, error_message = \
handle_repository_elem( app=app,
repository_elem=sub_action_elem,
- only_if_compiling_contained_td=True )
+ only_if_compiling_contained_td=True,
+ updating_installed_repository=False )
if requirements_dict:
dependency_key = '%s/%s' % ( package_name, package_version )
if repository_dependency_is_valid:
@@ -841,10 +847,10 @@
return valid_tool_dependencies_dict, invalid_tool_dependencies_dict, repository_dependency_tup, \
repository_dependency_is_valid, error_message
-def generate_repository_dependency_metadata( app, repository_dependencies_config, metadata_dict ):
+def generate_repository_dependency_metadata( app, repository_dependencies_config, metadata_dict, updating_installed_repository=False ):
"""
- Generate a repository dependencies dictionary based on valid information defined in the received repository_dependencies_config. This method
- is called from the tool shed as well as from Galaxy.
+ Generate a repository dependencies dictionary based on valid information defined in the received
+ repository_dependencies_config. This method is called from the tool shed as well as from Galaxy.
"""
error_message = ''
# Make sure we're looking at a valid repository_dependencies.xml file.
@@ -861,7 +867,10 @@
valid_repository_dependency_tups = []
for repository_elem in root.findall( 'repository' ):
repository_dependency_tup, repository_dependency_is_valid, err_msg = \
- handle_repository_elem( app, repository_elem, only_if_compiling_contained_td=False )
+ handle_repository_elem( app,
+ repository_elem,
+ only_if_compiling_contained_td=False,
+ updating_installed_repository=updating_installed_repository )
if repository_dependency_is_valid:
valid_repository_dependency_tups.append( repository_dependency_tup )
else:
@@ -885,11 +894,12 @@
metadata_dict[ 'repository_dependencies' ] = valid_repository_dependencies_dict
return metadata_dict, error_message
-def generate_tool_dependency_metadata( app, repository, changeset_revision, repository_clone_url, tool_dependencies_config, metadata_dict,
- original_repository_metadata=None ):
+def generate_tool_dependency_metadata( app, repository, changeset_revision, repository_clone_url, tool_dependencies_config,
+ metadata_dict, original_repository_metadata=None ):
"""
- If the combination of name, version and type of each element is defined in the <requirement> tag for at least one tool in the repository,
- then update the received metadata_dict with information from the parsed tool_dependencies_config.
+ If the combination of name, version and type of each element is defined in the <requirement> tag for
+ at least one tool in the repository, then update the received metadata_dict with information from the
+ parsed tool_dependencies_config.
"""
error_message = ''
if original_repository_metadata:
@@ -1171,7 +1181,7 @@
deleted_tool_dependency_names.append( original_dependency_val_dict[ 'name' ] )
return updated_tool_dependency_names, deleted_tool_dependency_names
-def handle_repository_elem( app, repository_elem, only_if_compiling_contained_td=False ):
+def handle_repository_elem( app, repository_elem, only_if_compiling_contained_td=False, updating_installed_repository=False ):
"""
Process the received repository_elem which is a <repository> tag either from a repository_dependencies.xml
file or a tool_dependencies.xml file. If the former, we're generating repository dependencies metadata for
@@ -1187,14 +1197,17 @@
changeset_revision = repository_elem.get( 'changeset_revision', None )
prior_installation_required = str( repository_elem.get( 'prior_installation_required', False ) )
if app.name == 'galaxy':
- # We're installing a repository into Galaxy, so make sure its contained repository dependency definition
- # is valid.
- if toolshed is None or name is None or owner is None or changeset_revision is None:
- # Raise an exception here instead of returning an error_message to keep the installation from
- # proceeding. Reaching here implies a bug in the Tool Shed framework.
- error_message = 'Installation halted because the following repository dependency definition is invalid:\n'
- error_message += xml_util.xml_to_string( repository_elem, use_indent=True )
- raise Exception( error_message )
+ if updating_installed_repository:
+ pass
+ else:
+ # We're installing a repository into Galaxy, so make sure its contained repository dependency definition
+ # is valid.
+ if toolshed is None or name is None or owner is None or changeset_revision is None:
+ # Raise an exception here instead of returning an error_message to keep the installation from
+ # proceeding. Reaching here implies a bug in the Tool Shed framework.
+ error_message = 'Installation halted because the following repository dependency definition is invalid:\n'
+ error_message += xml_util.xml_to_string( repository_elem, use_indent=True )
+ raise Exception( error_message )
if not toolshed:
# Default to the current tool shed.
toolshed = str( url_for( '/', qualified=True ) ).rstrip( '/' )
@@ -1230,6 +1243,14 @@
updated_changeset_revision )
if repository:
return repository_dependency_tup, is_valid, error_message
+ if updating_installed_repository:
+ # The repository dependency was included in an update to the installed repository, so it will
+ # not yet be installed. Return the tuple for later installation.
+ return repository_dependency_tup, is_valid, error_message
+ if updating_installed_repository:
+ # The repository dependency was included in an update to the installed repository, so it will not yet
+ # be installed. Return the tuple for later installation.
+ return repository_dependency_tup, is_valid, error_message
# Don't generate an error message for missing repository dependencies that are required only if compiling the
# dependent repository's tool dependency.
if not only_if_compiling_contained_td:
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 lib/tool_shed/util/tool_dependency_util.py
--- a/lib/tool_shed/util/tool_dependency_util.py
+++ b/lib/tool_shed/util/tool_dependency_util.py
@@ -90,7 +90,6 @@
if tree is None:
return tool_dependency_objects
root = tree.getroot()
- fabric_version_checked = False
for elem in root:
tool_dependency_type = elem.tag
if tool_dependency_type == 'package':
@@ -574,8 +573,8 @@
sa_session.flush()
return tool_dependency
-def sync_database_with_file_system( app, tool_shed_repository, tool_dependency_name, tool_dependency_version, tool_dependency_install_dir,
- tool_dependency_type='package' ):
+def sync_database_with_file_system( app, tool_shed_repository, tool_dependency_name, tool_dependency_version,
+ tool_dependency_install_dir, tool_dependency_type='package' ):
"""
The installation directory defined by the received tool_dependency_install_dir exists, so check for the presence
of fabric_util.INSTALLATION_LOG. If the files exists, we'll assume the tool dependency is installed, but not
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 templates/admin/tool_shed_repository/common.mako
--- a/templates/admin/tool_shed_repository/common.mako
+++ b/templates/admin/tool_shed_repository/common.mako
@@ -90,6 +90,7 @@
return str( self.count )
repository_dependencies_root_folder = containers_dict.get( 'repository_dependencies', None )
+ missing_repository_dependencies_root_folder = containers_dict.get( 'missing_repository_dependencies', None )
tool_dependencies_root_folder = containers_dict.get( 'tool_dependencies', None )
missing_tool_dependencies_root_folder = containers_dict.get( 'missing_tool_dependencies', None )
env_settings_heaader_row_displayed = False
@@ -112,7 +113,7 @@
</p></div></div>
- %if repository_dependencies_root_folder:
+ %if repository_dependencies_root_folder or missing_repository_dependencies_root_folder:
%if repository_dependencies_check_box is not None:
<div class="form-row">
%if export:
@@ -131,14 +132,26 @@
</div><div style="clear: both"></div>
%endif
- <div class="form-row">
- <p/>
- <% row_counter = RowCounter() %>
- <table cellspacing="2" cellpadding="2" border="0" width="100%" class="tables container-table">
- ${render_folder( repository_dependencies_root_folder, 0, parent=None, row_counter=row_counter, is_root_folder=True )}
- </table>
- <div style="clear: both"></div>
- </div>
+ %if repository_dependencies_root_folder:
+ <div class="form-row">
+ <p/>
+ <% row_counter = RowCounter() %>
+ <table cellspacing="2" cellpadding="2" border="0" width="100%" class="tables container-table">
+ ${render_folder( repository_dependencies_root_folder, 0, parent=None, row_counter=row_counter, is_root_folder=True )}
+ </table>
+ <div style="clear: both"></div>
+ </div>
+ %endif
+ %if missing_repository_dependencies_root_folder:
+ <div class="form-row">
+ <p/>
+ <% row_counter = RowCounter() %>
+ <table cellspacing="2" cellpadding="2" border="0" width="100%" class="tables container-table">
+ ${render_folder( missing_repository_dependencies_root_folder, 0, parent=None, row_counter=row_counter, is_root_folder=True )}
+ </table>
+ <div style="clear: both"></div>
+ </div>
+ %endif
%endif
%if tool_dependencies_root_folder or missing_tool_dependencies_root_folder:
%if install_tool_dependencies_check_box is not None:
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 templates/admin/tool_shed_repository/install_tool_dependencies.mako
--- a/templates/admin/tool_shed_repository/install_tool_dependencies.mako
+++ /dev/null
@@ -1,81 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-
-<% import os %>
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-<div class="warningmessage">
- <p>
- The tool dependencies listed below can be automatically installed with the repository. Installing them provides significant
- benefits and Galaxy includes various features to manage them.
- </p>
- <p>
- Each of these dependencies may require their own build requirements (e.g., CMake, g++, etc). Galaxy will not attempt to install
- these build requirements, so if any are missing from your environment tool dependency installation may partially fail. The
- repository and all of it's contents will be installed in any case.
- </p>
- <p>
- If tool dependency installation fails in any way, you can install the missing build requirements and have Galaxy attempt to install
- the tool dependencies again using the <b>Install tool dependencies</b> pop-up menu option on the <b>Manage repository</b> page.
- </p>
-</div>
-
-<div class="toolForm">
- <div class="toolFormBody">
- <form name="install_tool_dependenceies" id="install_tool_dependenceies" action="${h.url_for( controller='admin_toolshed', action='install_tool_dependencies' )}" method="post" >
- <div class="form-row">
- <table class="grid">
- <tr><td colspan="4" bgcolor="#D8D8D8"><b>Tool dependencies</b></td></tr>
- <tr>
- <th>Name</th>
- <th>Version</th>
- <th>Type</th>
- <th>Install directory</th>
- </tr>
- <% tool_shed_repository = None %>
- %for tool_dependency in tool_dependencies:
- <input type="hidden" name="tool_dependency_ids" value="${trans.security.encode_id( tool_dependency.id )}"/>
- <%
- readme_text = None
- if tool_shed_repository is None:
- tool_shed_repository = tool_dependency.tool_shed_repository
- metadata = tool_shed_repository.metadata
- tool_dependencies_dict = metadata[ 'tool_dependencies' ]
- for key, requirements_dict in tool_dependencies_dict.items():
- key_items = key.split( '/' )
- key_name = key_items[ 0 ]
- key_version = key_items[ 1 ]
- if key_name == tool_dependency.name and key_version == tool_dependency.version:
- readme_text = requirements_dict.get( 'readme', None )
- install_dir = os.path.join( trans.app.config.tool_dependency_dir,
- tool_dependency.name,
- tool_dependency.version,
- tool_shed_repository.owner,
- tool_shed_repository.name,
- tool_shed_repository.installed_changeset_revision )
- %>
- %if not os.path.exists( install_dir ):
- <tr>
- <td>${tool_dependency.name}</td>
- <td>${tool_dependency.version}</td>
- <td>${tool_dependency.type}</td>
- <td>${install_dir}</td>
- </tr>
- %if readme_text:
- <tr><td colspan="4" bgcolor="#FFFFCC">${tool_dependency.name} ${tool_dependency.version} requirements and installation information</td></tr>
- <tr><td colspan="4"><pre>${readme_text}</pre></td></tr>
- %endif
- %endif
- %endfor
- </table>
- <div style="clear: both"></div>
- </div>
- <div class="form-row">
- <input type="submit" name="install_tool_dependencies_button" value="Install"/>
- </div>
- </form>
- </div>
-</div>
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 templates/admin/tool_shed_repository/install_tool_dependencies_with_update.mako
--- /dev/null
+++ b/templates/admin/tool_shed_repository/install_tool_dependencies_with_update.mako
@@ -0,0 +1,91 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/admin/tool_shed_repository/repository_actions_menu.mako" import="*" />
+<%namespace file="/message.mako" import="render_msg" />
+
+<%
+ import os
+ from tool_shed.util.common_util import parse_repository_dependency_tuple
+%>
+
+${render_galaxy_repository_actions( repository )}
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<div class="warningmessage">
+ <p>
+ The updates to the <b>${repository.name}</b> repository require the following packages. Click the <b>Install</b> button to install them.
+ Installing some packages may take a while, but you can continue to use Galaxy during installation.
+ </p>
+</div>
+
+<div class="toolForm">
+ <div class="toolFormBody">
+ <form name="install_tool_dependencies_with_update" id="install_tool_dependencies_with_update" action="${h.url_for( controller='admin_toolshed', action='install_tool_dependencies_with_update' )}" method="post" >
+ <input type="hidden" name="updating_repository_id" value="${updating_repository_id}"/>
+ <input type="hidden" name="updating_to_ctx_rev" value="${updating_to_ctx_rev}"/>
+ <input type="hidden" name="updating_to_changeset_revision" value="${updating_to_changeset_revision}"/>
+ <input type="hidden" name="encoded_updated_metadata" value="${encoded_updated_metadata}"/>
+ <input type="hidden" name="encoded_relative_install_dir" value="${encoded_relative_install_dir}"/>
+ <input type="hidden" name="encoded_tool_dependencies_dict" value="${encoded_tool_dependencies_dict}"/>
+ %if tool_dependencies_dict:
+ %if install_tool_dependencies_check_box is not None:
+ <div class="form-row">
+ <label>Handle tool dependencies?</label>
+ <% disabled = trans.app.config.tool_dependency_dir is None %>
+ ${install_tool_dependencies_check_box.get_html( disabled=disabled )}
+ <div class="toolParamHelp" style="clear: both;">
+ %if disabled:
+ Set the tool_dependency_dir configuration value in your Galaxy config to automatically handle tool dependencies.
+ %else:
+ Un-check to skip automatic handling of these tool dependencies.
+ %endif
+ </div>
+ </div>
+ <div style="clear: both"></div>
+ %endif
+ <div class="form-row">
+ <table class="grid">
+ <tr><td colspan="4" bgcolor="#D8D8D8"><b>New tool dependencies included in update</b></td></tr>
+ <tr>
+ <th>Name</th>
+ <th>Version</th>
+ <th>Install directory</th>
+ </tr>
+ %for key, requirements_dict in tool_dependencies_dict.items():
+ <%
+ readme_text = None
+ key_items = key.split( '/' )
+ key_name = key_items[ 0 ]
+ key_version = key_items[ 1 ]
+ readme_text = requirements_dict.get( 'readme', None )
+ install_dir = os.path.join( trans.app.config.tool_dependency_dir,
+ key_name,
+ key_version,
+ repository.owner,
+ repository.name,
+ repository.installed_changeset_revision )
+ %>
+ %if not os.path.exists( install_dir ):
+ <tr>
+ <td>${key_name}</td>
+ <td>${key_version}</td>
+ <td>${install_dir}</td>
+ </tr>
+ %if readme_text:
+ <tr><td colspan="4" bgcolor="#FFFFCC">${key_name} ${key_version} requirements and installation information</td></tr>
+ <tr><td colspan="4"><pre>${readme_text}</pre></td></tr>
+ %endif
+ %endif
+ %endfor
+ </table>
+ <div style="clear: both"></div>
+ </div>
+ %endif
+ <div class="form-row">
+ <input type="submit" name="install_tool_dependencies_with_update_button" value="Install"/>
+ </div>
+ </form>
+ </div>
+</div>
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 templates/admin/tool_shed_repository/manage_repository_tool_dependencies.mako
--- a/templates/admin/tool_shed_repository/manage_repository_tool_dependencies.mako
+++ b/templates/admin/tool_shed_repository/manage_repository_tool_dependencies.mako
@@ -30,8 +30,6 @@
<tr><th bgcolor="#D8D8D8">Name</th><th bgcolor="#D8D8D8">Version</th><th bgcolor="#D8D8D8">Type</th><th bgcolor="#D8D8D8">Status</th><th bgcolor="#D8D8D8">Error</th></tr>
%for tool_dependency in repository.tool_dependencies:
<%
- # Tool dependencies cannot be uninstalled if they have a status of 'Installed'. Only the containing repository
- # can be uninstalled (only if it has no dependent repositories) if a tool dependency has been successfully installed.
if tool_dependency.error_message:
error_message = tool_dependency.error_message
else:
@@ -41,8 +39,7 @@
trans.install_model.ToolDependency.installation_status.UNINSTALLED ]:
can_install = True
if not can_uninstall:
- if tool_dependency.status not in [ trans.install_model.ToolDependency.installation_status.INSTALLED,
- trans.install_model.ToolDependency.installation_status.NEVER_INSTALLED,
+ if tool_dependency.status not in [ trans.install_model.ToolDependency.installation_status.NEVER_INSTALLED,
trans.install_model.ToolDependency.installation_status.UNINSTALLED ]:
can_uninstall = True
%>
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 templates/admin/tool_shed_repository/select_shed_tool_panel_config.mako
--- a/templates/admin/tool_shed_repository/select_shed_tool_panel_config.mako
+++ b/templates/admin/tool_shed_repository/select_shed_tool_panel_config.mako
@@ -46,8 +46,8 @@
<div class="warningmessage"><p>
- The core Galaxy development team does not maintain the contents of many Galaxy tool shed repositories. Some repository tools
- may include code that produces malicious behavior, so be aware of what you are installing.
+ The Galaxy development team does not maintain the contents of many Galaxy Tool Shed repositories. Some
+ repository tools may include code that produces malicious behavior, so be aware of what you are installing.
</p><p>
If you discover a repository that causes problems after installation, contact <a href="http://wiki.g2.bx.psu.edu/Support" target="_blank">Galaxy support</a>,
@@ -63,6 +63,11 @@
<form name="select_shed_tool_panel_config" id="select_shed_tool_panel_config" action="${h.url_for( controller='admin_toolshed', action='prepare_for_install' )}" method="post" ><div class="form-row"><input type="hidden" name="encoded_repo_info_dicts" value="${encoded_repo_info_dicts}" />
+ <input type="hidden" name="updating" value="${updating}" />
+ <input type="hidden" name="updating_repository_id" value="${updating_repository_id}" />
+ <input type="hidden" name="updating_to_ctx_rev" value="${updating_to_ctx_rev}" />
+ <input type="hidden" name="updating_to_changeset_revision" value="${updating_to_changeset_revision}" />
+ <input type="hidden" name="encoded_updated_metadata" value="${encoded_updated_metadata}" /><input type="hidden" name="includes_tools" value="${includes_tools}" /><input type="hidden" name="includes_tool_dependencies" value="${includes_tool_dependencies}" /><input type="hidden" name="includes_tools_for_display_in_tool_panel" value="${includes_tools_for_display_in_tool_panel}" />
diff -r 09985439d17f9bef026554938b05d0d6eedd06cb -r 90b4baa5c2b18d49bcea5a0807f0df8924abebb1 templates/admin/tool_shed_repository/select_tool_panel_section.mako
--- a/templates/admin/tool_shed_repository/select_tool_panel_section.mako
+++ b/templates/admin/tool_shed_repository/select_tool_panel_section.mako
@@ -46,8 +46,8 @@
<div class="warningmessage"><p>
- The core Galaxy development team does not maintain the contents of many Galaxy tool shed repositories. Some repository tools
- may include code that produces malicious behavior, so be aware of what you are installing.
+ The Galaxy development team does not maintain the contents of many Galaxy Tool Shed repositories. Some
+ repository tools may include code that produces malicious behavior, so be aware of what you are installing.
</p><p>
If you discover a repository that causes problems after installation, contact <a href="http://wiki.g2.bx.psu.edu/Support" target="_blank">Galaxy support</a>,
@@ -67,6 +67,11 @@
<input type="hidden" name="includes_tools_for_display_in_tool_panel" value="${includes_tools_for_display_in_tool_panel}" /><input type="hidden" name="tool_shed_url" value="${tool_shed_url}" /><input type="hidden" name="encoded_repo_info_dicts" value="${encoded_repo_info_dicts}" />
+ <input type="hidden" name="updating" value="${updating}" />
+ <input type="hidden" name="updating_repository_id" value="${updating_repository_id}" />
+ <input type="hidden" name="updating_to_ctx_rev" value="${updating_to_ctx_rev}" />
+ <input type="hidden" name="updating_to_changeset_revision" value="${updating_to_changeset_revision}" />
+ <input type="hidden" name="encoded_updated_metadata" value="${encoded_updated_metadata}" /></div><div style="clear: both"></div><% readme_files_dict = containers_dict.get( 'readme_files', None ) %>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Update LWR client through LWR commit 2fec198.
by commits-noreply@bitbucket.org 26 Mar '14
by commits-noreply@bitbucket.org 26 Mar '14
26 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/dc67550cf28a/
Changeset: dc67550cf28a
User: jmchilton
Date: 2014-03-26 16:00:22
Summary: Update LWR client through LWR commit 2fec198.
Makes parsing LWR host more robust - auto-adding http to beginning and trailing / if needed. Also makes LWR runn compatible with forthcoming job metrics pull request and pulls in Python 3 fix for job_script module.
Affected #: 3 files
diff -r 62146f92190c00c621a3ce2ed7860f3f0c2c7ec4 -r dc67550cf28a3e32f8cc867ce82cb8a7b1495335 lib/galaxy/jobs/runners/lwr_client/interface.py
--- a/lib/galaxy/jobs/runners/lwr_client/interface.py
+++ b/lib/galaxy/jobs/runners/lwr_client/interface.py
@@ -36,8 +36,13 @@
def __init__(self, destination_params, transport):
self.transport = transport
- self.remote_host = destination_params.get("url")
- assert self.remote_host is not None, "Failed to determine url for LWR client."
+ remote_host = destination_params.get("url")
+ assert remote_host is not None, "Failed to determine url for LWR client."
+ if not remote_host.endswith("/"):
+ remote_host = "%s/" % remote_host
+ if not remote_host.startswith("http"):
+ remote_host = "http://%s" % remote_host
+ self.remote_host = remote_host
self.private_key = destination_params.get("private_token", None)
def execute(self, command, args={}, data=None, input_path=None, output_path=None):
diff -r 62146f92190c00c621a3ce2ed7860f3f0c2c7ec4 -r dc67550cf28a3e32f8cc867ce82cb8a7b1495335 lib/galaxy/jobs/runners/lwr_client/staging/down.py
--- a/lib/galaxy/jobs/runners/lwr_client/staging/down.py
+++ b/lib/galaxy/jobs/runners/lwr_client/staging/down.py
@@ -14,7 +14,7 @@
# this pattern picks up attiditional files to copy back - such as those
# associated with multiple outputs and metadata configuration. Set to .* to just
# copy everything
-COPY_FROM_WORKING_DIRECTORY_PATTERN = compile(r"primary_.*|galaxy.json|metadata_.*|dataset_\d+\.dat|dataset_\d+_files.+")
+COPY_FROM_WORKING_DIRECTORY_PATTERN = compile(r"primary_.*|galaxy.json|metadata_.*|dataset_\d+\.dat|__instrument_.*|dataset_\d+_files.+")
def finish_job(client, cleanup_job, job_completed_normally, client_outputs, lwr_outputs):
diff -r 62146f92190c00c621a3ce2ed7860f3f0c2c7ec4 -r dc67550cf28a3e32f8cc867ce82cb8a7b1495335 lib/galaxy/jobs/runners/util/job_script/__init__.py
--- a/lib/galaxy/jobs/runners/util/job_script/__init__.py
+++ b/lib/galaxy/jobs/runners/util/job_script/__init__.py
@@ -2,11 +2,11 @@
from pkg_resources import resource_string
DEFAULT_JOB_FILE_TEMPLATE = Template(
- resource_string(__name__, 'DEFAULT_JOB_FILE_TEMPLATE.sh')
+ resource_string(__name__, 'DEFAULT_JOB_FILE_TEMPLATE.sh').decode('UTF-8')
)
SLOTS_STATEMENT_CLUSTER_DEFAULT = \
- resource_string(__name__, 'CLUSTER_SLOTS_STATEMENT.sh')
+ resource_string(__name__, 'CLUSTER_SLOTS_STATEMENT.sh').decode('UTF-8')
SLOTS_STATEMENT_SINGLE = """
GALAXY_SLOTS="1"
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/56be13c43a4e/
Changeset: 56be13c43a4e
Branch: stable
User: jmchilton
Date: 2014-03-26 15:24:08
Summary: Fix NoneType exception when using LWR with old-style tool runner URLs.
Affected #: 1 file
diff -r 6007992cbcd3626cbed38b0e883f516b016f98be -r 56be13c43a4e8c1ad391eab212982659e4845d94 lib/galaxy/jobs/runners/lwr.py
--- a/lib/galaxy/jobs/runners/lwr.py
+++ b/lib/galaxy/jobs/runners/lwr.py
@@ -156,7 +156,8 @@
job_id = "%s_%s" % (job_id, job_wrapper.task_id)
params = job_wrapper.job_destination.params.copy()
for key, value in params.iteritems():
- params[key] = model.User.expand_user_properties( job_wrapper.get_job().user, value )
+ if value:
+ params[key] = model.User.expand_user_properties( job_wrapper.get_job().user, value )
return self.get_client( params, job_id )
def get_client_from_state(self, job_state):
https://bitbucket.org/galaxy/galaxy-central/commits/62146f92190c/
Changeset: 62146f92190c
User: jmchilton
Date: 2014-03-26 15:27:44
Summary: Merge latest stable.
Affected #: 1 file
diff -r 66c7385957303447c8f5bb96731945bba179c83a -r 62146f92190c00c621a3ce2ed7860f3f0c2c7ec4 lib/galaxy/jobs/runners/lwr.py
--- a/lib/galaxy/jobs/runners/lwr.py
+++ b/lib/galaxy/jobs/runners/lwr.py
@@ -220,7 +220,8 @@
job_id = "%s_%s" % (job_id, job_wrapper.task_id)
params = job_wrapper.job_destination.params.copy()
for key, value in params.iteritems():
- params[key] = model.User.expand_user_properties( job_wrapper.get_job().user, value )
+ if value:
+ params[key] = model.User.expand_user_properties( job_wrapper.get_job().user, value )
return self.get_client( params, job_id )
def get_client_from_state(self, job_state):
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: davebgx: Add check to ensure that repositories cannot be created unless at least one category has been defined.
by commits-noreply@bitbucket.org 26 Mar '14
by commits-noreply@bitbucket.org 26 Mar '14
26 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/66c738595730/
Changeset: 66c738595730
User: davebgx
Date: 2014-03-26 15:11:54
Summary: Add check to ensure that repositories cannot be created unless at least one category has been defined.
Affected #: 1 file
diff -r 561929fb2d7e827f20ea078904aeebe35173f3f9 -r 66c7385957303447c8f5bb96731945bba179c83a test/tool_shed/functional/test_0000_basic_repository_features.py
--- a/test/tool_shed/functional/test_0000_basic_repository_features.py
+++ b/test/tool_shed/functional/test_0000_basic_repository_features.py
@@ -2,6 +2,8 @@
repository_name = 'filtering_0000'
repository_description = "Galaxy's filtering tool for test 0000"
repository_long_description = "Long description of Galaxy's filtering tool for test 0000"
+import logging
+log = logging.getLogger( __name__ )
class TestBasicRepositoryFeatures( ShedTwillTestCase ):
'''Test core repository features.'''
@@ -24,12 +26,18 @@
assert admin_user is not None, 'Problem retrieving user with email %s from the database' % common.admin_email
admin_user_private_role = self.test_db_util.get_private_role( admin_user )
- def test_0005_create_categories( self ):
+ def test_0005_create_repository_without_categories( self ):
+ '''Verify that a repository cannot be created unless at least one category has been defined.'''
+ strings_displayed = [ 'No categories have been configured in this instance of the Galaxy Tool Shed' ]
+ self.visit_url( '/repository/create_repository' )
+ self.check_for_strings( strings_displayed=strings_displayed, strings_not_displayed=[] )
+
+ def test_0010_create_categories( self ):
"""Create categories for this test suite"""
self.create_category( name='Test 0000 Basic Repository Features 1', description='Test 0000 Basic Repository Features 1' )
self.create_category( name='Test 0000 Basic Repository Features 2', description='Test 0000 Basic Repository Features 2' )
- def test_0010_create_repository( self ):
+ def test_0015_create_repository( self ):
"""Create the filtering repository"""
self.logout()
self.login( email=common.test_user_1_email, username=common.test_user_1_name )
@@ -43,7 +51,7 @@
category_id=self.security.encode_id( category.id ),
strings_displayed=strings_displayed )
- def test_0015_edit_repository( self ):
+ def test_0020_edit_repository( self ):
"""Edit the repository name, description, and long description"""
repository = self.test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
new_name = "renamed_filtering"
@@ -51,20 +59,20 @@
new_long_description = "Edited long description"
self.edit_repository_information( repository, repo_name=new_name, description=new_description, long_description=new_long_description )
- def test_0020_change_repository_category( self ):
+ def test_0025_change_repository_category( self ):
"""Change the categories associated with the filtering repository"""
repository = self.test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
self.edit_repository_categories( repository,
categories_to_add=[ "Test 0000 Basic Repository Features 2" ],
categories_to_remove=[ "Test 0000 Basic Repository Features 1" ] )
- def test_0025_grant_write_access( self ):
+ def test_0030_grant_write_access( self ):
'''Grant write access to another user'''
repository = self.test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
self.grant_write_access( repository, usernames=[ common.test_user_2_name ] )
self.revoke_write_access( repository, common.test_user_2_name )
- def test_0030_upload_filtering_1_1_0( self ):
+ def test_0035_upload_filtering_1_1_0( self ):
"""Upload filtering_1.1.0.tar to the repository"""
repository = self.test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
self.upload_file( repository,
@@ -77,7 +85,7 @@
strings_displayed=[],
strings_not_displayed=[] )
- def test_0035_verify_repository( self ):
+ def test_0040_verify_repository( self ):
'''Display basic repository pages'''
repository = self.test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
latest_changeset_revision = self.get_repository_tip( repository )
@@ -101,7 +109,7 @@
repository_name,
strings_displayed=[ 'Uploaded filtering 1.1.0', latest_changeset_revision ] )
- def test_0040_alter_repository_states( self ):
+ def test_0045_alter_repository_states( self ):
'''Test toggling the malicious and deprecated repository flags.'''
repository = self.test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
self.logout()
@@ -127,7 +135,7 @@
strings_displayed = [ 'Mark repository as deprecated', 'Upload files', 'Reset all repository metadata' ]
self.display_manage_repository_page( repository, strings_displayed=strings_displayed )
- def test_0045_display_repository_tip_file( self ):
+ def test_0050_display_repository_tip_file( self ):
'''Display the contents of filtering.xml in the repository tip revision'''
repository = self.test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
self.display_repository_file_contents( repository=repository,
@@ -136,7 +144,7 @@
strings_displayed=[ '1.1.0' ],
strings_not_displayed=[] )
- def test_0050_upload_filtering_txt_file( self ):
+ def test_0055_upload_filtering_txt_file( self ):
'''Upload filtering.txt file associated with tool version 1.1.0.'''
repository = self.test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
self.upload_file( repository,
@@ -150,7 +158,7 @@
strings_not_displayed=[] )
self.display_manage_repository_page( repository, strings_displayed=[ 'Readme file for filtering 1.1.0' ] )
- def test_0055_upload_filtering_test_data( self ):
+ def test_0060_upload_filtering_test_data( self ):
'''Upload filtering test data.'''
repository = self.test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
self.upload_file( repository,
@@ -169,7 +177,7 @@
strings_not_displayed=[] )
self.check_repository_metadata( repository, tip_only=True )
- def test_0060_upload_filtering_2_2_0( self ):
+ def test_0065_upload_filtering_2_2_0( self ):
'''Upload filtering version 2.2.0'''
repository = self.test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
self.upload_file( repository,
@@ -182,7 +190,7 @@
strings_displayed=[],
strings_not_displayed=[] )
- def test_0065_verify_filtering_repository( self ):
+ def test_0070_verify_filtering_repository( self ):
'''Verify the new tool versions and repository metadata.'''
repository = self.test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
category = self.test_db_util.get_category_by_name( 'Test 0000 Basic Repository Features 1' )
@@ -204,7 +212,7 @@
tool_page_strings_displayed=tool_page_strings_displayed )
self.check_repository_metadata( repository, tip_only=False )
- def test_0070_upload_readme_txt_file( self ):
+ def test_0075_upload_readme_txt_file( self ):
'''Upload readme.txt file associated with tool version 2.2.0.'''
repository = self.test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
self.upload_file( repository,
@@ -223,26 +231,26 @@
strings_displayed=[ 'Readme file for filtering 1.1.0',
'This is a readme file.' ] )
- def test_0075_delete_readme_txt_file( self ):
+ def test_0080_delete_readme_txt_file( self ):
'''Delete the readme.txt file.'''
repository = self.test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
self.delete_files_from_repository( repository, filenames=[ 'readme.txt' ] )
self.check_count_of_metadata_revisions_associated_with_repository( repository, metadata_count=2 )
self.display_manage_repository_page( repository, strings_displayed=[ 'Readme file for filtering 1.1.0' ] )
- def test_0080_search_for_valid_filter_tool( self ):
+ def test_0085_search_for_valid_filter_tool( self ):
'''Search for the filtering tool by tool ID, name, and version.'''
repository = self.test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
tip_changeset = self.get_repository_tip( repository )
search_fields = dict( tool_id='Filter1', tool_name='filter', tool_version='2.2.0' )
self.search_for_valid_tools( search_fields=search_fields, strings_displayed=[ tip_changeset ], strings_not_displayed=[] )
- def test_0085_verify_repository_metadata( self ):
+ def test_0090_verify_repository_metadata( self ):
'''Verify that resetting the metadata does not change it.'''
repository = self.test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
self.verify_unchanged_repository_metadata( repository )
- def test_0090_verify_reserved_repository_name_handling( self ):
+ def test_0095_verify_reserved_repository_name_handling( self ):
'''Check that reserved repository names are handled correctly.'''
category = self.test_db_util.get_category_by_name( 'Test 0000 Basic Repository Features 1' )
error_message = 'The term <b>repos</b> is a reserved word in the tool shed, so it cannot be used as a repository name.'
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/c4950bc66225/
Changeset: c4950bc66225
User: carlfeberhard
Date: 2014-03-25 20:30:51
Summary: History API: show: add importable, username_and_slug to returned attributes, update: 1) allow setting importable and published, 2) published automatically makes a history importable, 3) in both cases slug is automatically set set_as_current: now correctly uses the HTTP method PUT (not POST), HDA API: all: histories that are importable and/or published now allow GET'ing the contents properly, create: you can now copy HDAs into your histories if the HDA and it's history are accessible
Affected #: 7 files
diff -r 4d2f3398ad6d6eebfe084a184bf860dd7c6f9071 -r c4950bc662256f013916b0aaabb73a47508213c5 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -773,7 +773,7 @@
class History( object, Dictifiable, UsesAnnotations, HasName ):
dict_collection_visible_keys = ( 'id', 'name', 'published', 'deleted' )
- dict_element_visible_keys = ( 'id', 'name', 'published', 'deleted', 'genome_build', 'purged' )
+ dict_element_visible_keys = ( 'id', 'name', 'published', 'deleted', 'genome_build', 'purged', 'importable', 'slug' )
default_name = 'Unnamed history'
def __init__( self, id=None, name=None, user=None ):
diff -r 4d2f3398ad6d6eebfe084a184bf860dd7c6f9071 -r c4950bc662256f013916b0aaabb73a47508213c5 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -187,8 +187,11 @@
def validate_and_sanitize_basestring_list( self, key, val ):
if not isinstance( val, list ):
- raise ValueError( '%s must be a list: %s' %( key, str( type( val ) ) ) )
- return [ unicode( sanitize_html( t, 'utf-8', 'text/html' ), 'utf-8' ) for t in val ]
+ raise ValueError( '%s must be a list of strings: %s' %( key, str( type( val ) ) ) )
+ try:
+ return [ unicode( sanitize_html( t, 'utf-8', 'text/html' ), 'utf-8' ) for t in val ]
+ except TypeError, type_err:
+ raise ValueError( '%s must be a list of strings: %s' %( key, str( type_err ) ) )
def validate_boolean( self, key, val ):
if not isinstance( val, bool ):
@@ -527,6 +530,10 @@
if not history_dict[ 'annotation' ]:
history_dict[ 'annotation' ] = ''
#TODO: item_slug url
+ if history_dict[ 'importable' ] and history_dict[ 'slug' ]:
+ #TODO: this should be in History (or a superclass of)
+ username_and_slug = ( '/' ).join(( 'u', history.user.username, 'h', history_dict[ 'slug' ] ))
+ history_dict[ 'username_and_slug' ] = username_and_slug
hda_summaries = hda_dictionaries if hda_dictionaries else self.get_hda_summary_dicts( trans, history )
#TODO remove the following in v2
@@ -541,26 +548,69 @@
"""
Changes history data using the given dictionary new_data.
"""
- # precondition: access of the history has already been checked
+ #precondition: ownership of the history has already been checked
+ #precondition: user is not None (many of these attributes require a user to set properly)
+ user = trans.get_user()
+ # published histories should always be importable
+ if 'published' in new_data and new_data[ 'published' ] and not history.importable:
+ new_data[ 'importable' ] = True
# send what we can down into the model
changed = history.set_from_dict( new_data )
+
# the rest (often involving the trans) - do here
- if 'annotation' in new_data.keys() and trans.get_user():
- history.add_item_annotation( trans.sa_session, trans.get_user(), history, new_data[ 'annotation' ] )
+ #TODO: the next two could be an aspect/mixin
+ #TODO: also need a way to check whether they've changed - assume they have for now
+ if 'annotation' in new_data:
+ history.add_item_annotation( trans.sa_session, user, history, new_data[ 'annotation' ] )
changed[ 'annotation' ] = new_data[ 'annotation' ]
- if 'tags' in new_data.keys() and trans.get_user():
- self.set_tags_from_list( trans, history, new_data[ 'tags' ], user=trans.user )
- # importable (ctrl.history.set_accessible_async)
- # sharing/permissions?
- # slugs?
- # purged - duh duh duhhhhhhnnnnnnnnnn
+
+ if 'tags' in new_data:
+ self.set_tags_from_list( trans, history, new_data[ 'tags' ], user=user )
+ changed[ 'tags' ] = new_data[ 'tags' ]
+
+ #TODO: sharing with user/permissions?
if changed.keys():
trans.sa_session.flush()
+ # create a slug if none exists (setting importable to false should not remove the slug)
+ if 'importable' in changed and changed[ 'importable' ] and not history.slug:
+ self._create_history_slug( trans, history )
+
return changed
+ def _create_history_slug( self, trans, history ):
+ #TODO: mixins need to die a quick, horrible death
+ # (this is duplicate from SharableMixin which can't be added to UsesHistory without exposing various urls)
+ cur_slug = history.slug
+
+ # Setup slug base.
+ if cur_slug is None or cur_slug == "":
+ # Item can have either a name or a title.
+ item_name = history.name
+ slug_base = util.ready_name_for_url( item_name.lower() )
+ else:
+ slug_base = cur_slug
+
+ # Using slug base, find a slug that is not taken. If slug is taken,
+ # add integer to end.
+ new_slug = slug_base
+ count = 1
+ while ( trans.sa_session.query( trans.app.model.History )
+ .filter_by( user=history.user, slug=new_slug, importable=True )
+ .count() != 0 ):
+ # Slug taken; choose a new slug based on count. This approach can
+ # handle numerous items with the same name gracefully.
+ new_slug = '%s-%i' % ( slug_base, count )
+ count += 1
+
+ # Set slug and return.
+ trans.sa_session.add( history )
+ history.slug = new_slug
+ trans.sa_session.flush()
+ return history.slug == cur_slug
+
class ExportsHistoryMixin:
@@ -685,9 +735,9 @@
else:
#TODO: do we really need the history?
history = self.get_history( trans, history_id,
- check_ownership=True, check_accessible=True, deleted=False )
+ check_ownership=False, check_accessible=True, deleted=False )
hda = self.get_history_dataset_association( trans, history, id,
- check_ownership=True, check_accessible=True )
+ check_ownership=False, check_accessible=True )
return hda
def get_hda_list( self, trans, hda_ids, check_ownership=True, check_accessible=False, check_state=True ):
diff -r 4d2f3398ad6d6eebfe084a184bf860dd7c6f9071 -r c4950bc662256f013916b0aaabb73a47508213c5 lib/galaxy/webapps/galaxy/api/histories.py
--- a/lib/galaxy/webapps/galaxy/api/histories.py
+++ b/lib/galaxy/webapps/galaxy/api/histories.py
@@ -6,20 +6,26 @@
import pkg_resources
pkg_resources.require( "Paste" )
-from paste.httpexceptions import HTTPBadRequest, HTTPForbidden, HTTPInternalServerError, HTTPException
+
+from paste.httpexceptions import HTTPBadRequest
+from paste.httpexceptions import HTTPForbidden
+from paste.httpexceptions import HTTPInternalServerError
+from paste.httpexceptions import HTTPException
from galaxy import exceptions
from galaxy import web
from galaxy.web import _future_expose_api as expose_api
from galaxy.web import _future_expose_api_anonymous as expose_api_anonymous
from galaxy.web import _future_expose_api_raw as expose_api_raw
-from galaxy.util import string_as_bool
-from galaxy.util import restore_text
+
from galaxy.web.base.controller import BaseAPIController
from galaxy.web.base.controller import UsesHistoryMixin
from galaxy.web.base.controller import UsesTagsMixin
from galaxy.web.base.controller import ExportsHistoryMixin
from galaxy.web.base.controller import ImportsHistoryMixin
+
+from galaxy.util import string_as_bool
+from galaxy.util import restore_text
from galaxy.web import url_for
import logging
@@ -48,27 +54,22 @@
#TODO: query (by name, date, etc.)
rval = []
deleted = string_as_bool( deleted )
- try:
- if trans.user:
- histories = self.get_user_histories( trans, user=trans.user, only_deleted=deleted )
- #for history in query:
- for history in histories:
- item = history.to_dict(value_mapper={'id': trans.security.encode_id})
- item['url'] = url_for( 'history', id=trans.security.encode_id( history.id ) )
- rval.append( item )
- elif trans.galaxy_session.current_history:
- #No user, this must be session authentication with an anonymous user.
- history = trans.galaxy_session.current_history
+ if trans.user:
+ histories = self.get_user_histories( trans, user=trans.user, only_deleted=deleted )
+
+ for history in histories:
item = history.to_dict(value_mapper={'id': trans.security.encode_id})
item['url'] = url_for( 'history', id=trans.security.encode_id( history.id ) )
- rval.append(item)
+ rval.append( item )
- except Exception, e:
- raise
- rval = "Error in history API"
- log.error( rval + ": %s" % str(e) )
- trans.response.status = 500
+ elif trans.galaxy_session.current_history:
+ #No user, this must be session authentication with an anonymous user.
+ history = trans.galaxy_session.current_history
+ item = history.to_dict(value_mapper={'id': trans.security.encode_id})
+ item['url'] = url_for( 'history', id=trans.security.encode_id( history.id ) )
+ rval.append(item)
+
return rval
@web.expose_api_anonymous
@@ -92,7 +93,6 @@
:returns: detailed history information from
:func:`galaxy.web.base.controller.UsesHistoryDatasetAssociationMixin.get_history_dict`
"""
- #TODO: GET /api/histories/{encoded_history_id}?as_archive=True
#TODO: GET /api/histories/s/{username}/{slug}
history_id = id
deleted = string_as_bool( deleted )
@@ -116,7 +116,7 @@
except HTTPBadRequest, bad_req:
trans.response.status = 400
- return str( bad_req )
+ raise exceptions.MessageException( bad_req.detail )
except Exception, e:
msg = "Error in history API at showing history detail: %s" % ( str( e ) )
@@ -444,7 +444,7 @@
continue
if key in ( 'name', 'genome_build', 'annotation' ):
validated_payload[ key ] = self.validate_and_sanitize_basestring( key, val )
- if key in ( 'deleted', 'published' ):
+ if key in ( 'deleted', 'published', 'importable' ):
validated_payload[ key ] = self.validate_boolean( key, val )
elif key == 'tags':
validated_payload[ key ] = self.validate_and_sanitize_basestring_list( key, val )
diff -r 4d2f3398ad6d6eebfe084a184bf860dd7c6f9071 -r c4950bc662256f013916b0aaabb73a47508213c5 lib/galaxy/webapps/galaxy/api/history_contents.py
--- a/lib/galaxy/webapps/galaxy/api/history_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/history_contents.py
@@ -2,20 +2,32 @@
API operations on the contents of a history.
"""
-import logging
-from galaxy import exceptions, util, web
-from galaxy.web.base.controller import ( BaseAPIController, url_for,
- UsesHistoryDatasetAssociationMixin, UsesHistoryMixin, UsesLibraryMixin,
- UsesLibraryMixinItems, UsesTagsMixin )
+from galaxy import exceptions
+from galaxy import util
+from galaxy import web
+
+from galaxy.web import _future_expose_api as expose_api
+from galaxy.web import _future_expose_api_anonymous as expose_api_anonymous
+from galaxy.web import _future_expose_api_raw as expose_api_raw
+
+from galaxy.web.base.controller import BaseAPIController
+from galaxy.web.base.controller import UsesHistoryDatasetAssociationMixin
+from galaxy.web.base.controller import UsesHistoryMixin
+from galaxy.web.base.controller import UsesLibraryMixin
+from galaxy.web.base.controller import UsesLibraryMixinItems
+from galaxy.web.base.controller import UsesTagsMixin
+
+from galaxy.web.base.controller import url_for
from galaxy.util.sanitize_html import sanitize_html
+import logging
log = logging.getLogger( __name__ )
class HistoryContentsController( BaseAPIController, UsesHistoryDatasetAssociationMixin, UsesHistoryMixin,
UsesLibraryMixin, UsesLibraryMixinItems, UsesTagsMixin ):
- @web.expose_api_anonymous
+ @expose_api_anonymous
def index( self, trans, history_id, ids=None, **kwd ):
"""
index( self, trans, history_id, ids=None, **kwd )
@@ -52,7 +64,7 @@
history = trans.history
# otherwise, check permissions for the history first
else:
- history = self.get_history( trans, history_id, check_ownership=True, check_accessible=True )
+ history = self.get_history( trans, history_id, check_ownership=False, check_accessible=True )
# Allow passing in type or types - for continuity rest of methods
# take in type - but this one can be passed multiple types and
@@ -134,7 +146,7 @@
hda.history_id, hda.id, type( exc ), str( exc ) )
return self.get_hda_dict_with_error( trans, hda=hda, error_msg=str( exc ) )
- @web.expose_api_anonymous
+ @expose_api_anonymous
def show( self, trans, id, history_id, **kwd ):
"""
show( self, trans, id, history_id, **kwd )
@@ -170,7 +182,7 @@
trans.response.status = 500
return msg
- @web.expose_api
+ @expose_api
def create( self, trans, history_id, payload, **kwd ):
"""
create( self, trans, history_id, payload, **kwd )
@@ -201,6 +213,8 @@
# retrieve history
try:
history = self.get_history( trans, history_id, check_ownership=True, check_accessible=False )
+ except exceptions.httpexceptions.HTTPException:
+ raise
except Exception, e:
# no way to tell if it failed bc of perms or other (all MessageExceptions)
trans.response.status = 500
@@ -236,7 +250,8 @@
elif source == 'hda':
try:
#NOTE: user currently only capable of copying one of their own datasets
- hda = self.get_dataset( trans, content )
+ hda = self.get_dataset( trans, content, check_ownership=False, check_accessible=True )
+ self.security_check( trans, hda.history, check_ownership=False, check_accessible=True )
except ( exceptions.httpexceptions.HTTPRequestRangeNotSatisfiable,
exceptions.httpexceptions.HTTPBadRequest ), id_exc:
# wot...
@@ -259,7 +274,7 @@
trans.response.status = 501
return
- @web.expose_api_anonymous
+ @expose_api_anonymous
def update( self, trans, history_id, id, payload, **kwd ):
"""
update( self, trans, history_id, id, payload, **kwd )
@@ -306,6 +321,7 @@
if hda.history != trans.history:
trans.response.status = 401
return { 'error': 'Anonymous users cannot edit datasets outside their current history' }
+
else:
payload = self._validate_and_parse_update_payload( payload )
# only check_state if not deleting, otherwise cannot delete uploading files
@@ -316,6 +332,7 @@
changed = self.set_hda_from_dict( trans, hda, payload )
if payload.get( 'deleted', False ):
self.stop_hda_creating_job( hda )
+
except Exception, exception:
log.error( 'Update of history (%s), HDA (%s) failed: %s',
history_id, id, str( exception ), exc_info=True )
@@ -330,7 +347,7 @@
return changed
#TODO: allow anonymous del/purge and test security on this
- @web.expose_api
+ @expose_api
def delete( self, trans, history_id, id, purge=False, **kwd ):
"""
delete( self, trans, history_id, id, **kwd )
diff -r 4d2f3398ad6d6eebfe084a184bf860dd7c6f9071 -r c4950bc662256f013916b0aaabb73a47508213c5 lib/galaxy/webapps/galaxy/buildapp.py
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -165,8 +165,9 @@
parent_resources=dict( member_name='page', collection_name='pages' ) )
# add as a non-ATOM API call to support the notion of a 'current/working' history unique to the history resource
+ #webapp.mapper.connect( "set_as_current", "/api/histories/set_as_current/{id}",
webapp.mapper.connect( "set_as_current", "/api/histories/{id}/set_as_current",
- controller="histories", action="set_as_current", conditions=dict( method=["POST"] ) )
+ controller="histories", action="set_as_current", conditions=dict( method=["PUT"] ) )
webapp.mapper.connect( "history_archive_export", "/api/histories/{id}/exports",
controller="histories", action="archive_export", conditions=dict( method=[ "PUT" ] ) )
diff -r 4d2f3398ad6d6eebfe084a184bf860dd7c6f9071 -r c4950bc662256f013916b0aaabb73a47508213c5 static/scripts/mvc/history/current-history-panel.js
--- a/static/scripts/mvc/history/current-history-panel.js
+++ b/static/scripts/mvc/history/current-history-panel.js
@@ -84,7 +84,10 @@
var panel = this,
historyFn = function(){
// make this current and get history data with one call
- return jQuery.post( galaxy_config.root + 'api/histories/' + historyId + '/set_as_current' );
+ return jQuery.ajax({
+ url : galaxy_config.root + 'api/histories/' + historyId + '/set_as_current',
+ method : 'PUT'
+ });
};
return this.loadHistoryWithHDADetails( historyId, attributes, historyFn )
.then(function( historyData, hdaData ){
diff -r 4d2f3398ad6d6eebfe084a184bf860dd7c6f9071 -r c4950bc662256f013916b0aaabb73a47508213c5 static/scripts/packed/mvc/history/current-history-panel.js
--- a/static/scripts/packed/mvc/history/current-history-panel.js
+++ b/static/scripts/packed/mvc/history/current-history-panel.js
@@ -1,1 +1,1 @@
-define(["mvc/dataset/hda-edit","mvc/history/history-panel","mvc/base-mvc"],function(b,f,c){var d=c.SessionStorageModel.extend({defaults:{searching:false,tagsEditorShown:false,annotationEditorShown:false},toString:function(){return"HistoryPanelPrefs("+JSON.stringify(this.toJSON())+")"}});d.storageKey=function e(){return("history-panel")};var a=f.HistoryPanel.extend({HDAViewClass:b.HDAEditView,emptyMsg:_l("This history is empty. Click 'Get Data' on the left tool menu to start"),noneFoundMsg:_l("No matching datasets found"),initialize:function(g){g=g||{};this.preferences=new d(_.extend({id:d.storageKey()},_.pick(g,_.keys(d.prototype.defaults))));f.HistoryPanel.prototype.initialize.call(this,g)},loadCurrentHistory:function(h){var g=this;return this.loadHistoryWithHDADetails("current",h).then(function(j,i){g.trigger("current-history",g)})},switchToHistory:function(j,i){var g=this,h=function(){return jQuery.post(galaxy_config.root+"api/histories/"+j+"/set_as_current")};return this.loadHistoryWithHDADetails(j,i,h).then(function(l,k){g.trigger("switched-history",g)})},createNewHistory:function(i){if(!Galaxy||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){this.displayMessage("error",_l("You must be logged in to create histories"));return $.when()}var g=this,h=function(){return jQuery.post(galaxy_config.root+"api/histories",{current:true})};return this.loadHistory(undefined,i,h).then(function(k,j){g.trigger("new-history",g)})},setModel:function(h,g,i){f.HistoryPanel.prototype.setModel.call(this,h,g,i);if(this.model){this.log("checking for updates");this.model.checkForUpdates()}return this},_setUpModelEventHandlers:function(){f.HistoryPanel.prototype._setUpModelEventHandlers.call(this);if(Galaxy&&Galaxy.quotaMeter){this.listenTo(this.model,"change:nice_size",function(){Galaxy.quotaMeter.update()})}this.model.hdas.on("state:ready",function(h,i,g){if((!h.get("visible"))&&(!this.storage.get("show_hidden"))){this.removeHdaView(this.hdaViews[h.id])}},this)},render:function(i,j){i=(i===undefined)?(this.fxSpeed):(i);var g=this,h;if(this.model){h=this.renderModel()}else{h=this.renderWithoutModel()}$(g).queue("fx",[function(k){if(i&&g.$el.is(":visible")){g.$el.fadeOut(i,k)}else{k()}},function(k){g.$el.empty();if(h){g.$el.append(h.children());g.renderBasedOnPrefs()}k()},function(k){if(i&&!g.$el.is(":visible")){g.$el.fadeIn(i,k)}else{k()}},function(k){if(j){j.call(this)}g.trigger("rendered",this);k()}]);return this},renderBasedOnPrefs:function(){if(this.preferences.get("searching")){this.toggleSearchControls(0,true)}},_renderEmptyMsg:function(i){var h=this,g=h.$emptyMessage(i),j=$(".toolMenuContainer");if((_.isEmpty(h.hdaViews)&&!h.searchFor)&&(Galaxy&&Galaxy.upload&&j.size())){g.empty();g.html([_l("This history is empty. "),_l("You can "),'<a class="uploader-link" href="javascript:void(0)">',_l("load your own data"),"</a>",_l(" or "),'<a class="get-data-link" href="javascript:void(0)">',_l("get data from an external source"),"</a>"].join(""));g.find(".uploader-link").click(function(k){Galaxy.upload._eventShow(k)});g.find(".get-data-link").click(function(k){j.parent().scrollTop(0);j.find('span:contains("Get Data")').click()});g.show()}else{f.HistoryPanel.prototype._renderEmptyMsg.call(this,i)}return this},toggleSearchControls:function(h,g){var i=f.HistoryPanel.prototype.toggleSearchControls.call(this,h,g);this.preferences.set("searching",i)},_renderTags:function(g){var h=this;f.HistoryPanel.prototype._renderTags.call(this,g);if(this.preferences.get("tagsEditorShown")){this.tagsEditor.toggle(true)}this.tagsEditor.on("hiddenUntilActivated:shown hiddenUntilActivated:hidden",function(i){h.preferences.set("tagsEditorShown",i.hidden)})},_renderAnnotation:function(g){var h=this;f.HistoryPanel.prototype._renderAnnotation.call(this,g);if(this.preferences.get("annotationEditorShown")){this.annotationEditor.toggle(true)}this.annotationEditor.on("hiddenUntilActivated:shown hiddenUntilActivated:hidden",function(i){h.preferences.set("annotationEditorShown",i.hidden)})},connectToQuotaMeter:function(g){if(!g){return this}this.listenTo(g,"quota:over",this.showQuotaMessage);this.listenTo(g,"quota:under",this.hideQuotaMessage);this.on("rendered rendered:initial",function(){if(g&&g.isOverQuota()){this.showQuotaMessage()}});return this},showQuotaMessage:function(){var g=this.$el.find(".quota-message");if(g.is(":hidden")){g.slideDown(this.fxSpeed)}},hideQuotaMessage:function(){var g=this.$el.find(".quota-message");if(!g.is(":hidden")){g.slideUp(this.fxSpeed)}},connectToOptionsMenu:function(g){if(!g){return this}this.on("new-storage",function(i,h){if(g&&i){g.findItemByHtml(_l("Include Deleted Datasets")).checked=i.get("show_deleted");g.findItemByHtml(_l("Include Hidden Datasets")).checked=i.get("show_hidden")}});return this},toString:function(){return"CurrentHistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{CurrentHistoryPanel:a}});
\ No newline at end of file
+define(["mvc/dataset/hda-edit","mvc/history/history-panel","mvc/base-mvc"],function(b,f,c){var d=c.SessionStorageModel.extend({defaults:{searching:false,tagsEditorShown:false,annotationEditorShown:false},toString:function(){return"HistoryPanelPrefs("+JSON.stringify(this.toJSON())+")"}});d.storageKey=function e(){return("history-panel")};var a=f.HistoryPanel.extend({HDAViewClass:b.HDAEditView,emptyMsg:_l("This history is empty. Click 'Get Data' on the left tool menu to start"),noneFoundMsg:_l("No matching datasets found"),initialize:function(g){g=g||{};this.preferences=new d(_.extend({id:d.storageKey()},_.pick(g,_.keys(d.prototype.defaults))));f.HistoryPanel.prototype.initialize.call(this,g)},loadCurrentHistory:function(h){var g=this;return this.loadHistoryWithHDADetails("current",h).then(function(j,i){g.trigger("current-history",g)})},switchToHistory:function(j,i){var g=this,h=function(){return jQuery.ajax({url:galaxy_config.root+"api/histories/"+j+"/set_as_current",method:"PUT"})};return this.loadHistoryWithHDADetails(j,i,h).then(function(l,k){g.trigger("switched-history",g)})},createNewHistory:function(i){if(!Galaxy||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){this.displayMessage("error",_l("You must be logged in to create histories"));return $.when()}var g=this,h=function(){return jQuery.post(galaxy_config.root+"api/histories",{current:true})};return this.loadHistory(undefined,i,h).then(function(k,j){g.trigger("new-history",g)})},setModel:function(h,g,i){f.HistoryPanel.prototype.setModel.call(this,h,g,i);if(this.model){this.log("checking for updates");this.model.checkForUpdates()}return this},_setUpModelEventHandlers:function(){f.HistoryPanel.prototype._setUpModelEventHandlers.call(this);if(Galaxy&&Galaxy.quotaMeter){this.listenTo(this.model,"change:nice_size",function(){Galaxy.quotaMeter.update()})}this.model.hdas.on("state:ready",function(h,i,g){if((!h.get("visible"))&&(!this.storage.get("show_hidden"))){this.removeHdaView(this.hdaViews[h.id])}},this)},render:function(i,j){i=(i===undefined)?(this.fxSpeed):(i);var g=this,h;if(this.model){h=this.renderModel()}else{h=this.renderWithoutModel()}$(g).queue("fx",[function(k){if(i&&g.$el.is(":visible")){g.$el.fadeOut(i,k)}else{k()}},function(k){g.$el.empty();if(h){g.$el.append(h.children());g.renderBasedOnPrefs()}k()},function(k){if(i&&!g.$el.is(":visible")){g.$el.fadeIn(i,k)}else{k()}},function(k){if(j){j.call(this)}g.trigger("rendered",this);k()}]);return this},renderBasedOnPrefs:function(){if(this.preferences.get("searching")){this.toggleSearchControls(0,true)}},_renderEmptyMsg:function(i){var h=this,g=h.$emptyMessage(i),j=$(".toolMenuContainer");if((_.isEmpty(h.hdaViews)&&!h.searchFor)&&(Galaxy&&Galaxy.upload&&j.size())){g.empty();g.html([_l("This history is empty. "),_l("You can "),'<a class="uploader-link" href="javascript:void(0)">',_l("load your own data"),"</a>",_l(" or "),'<a class="get-data-link" href="javascript:void(0)">',_l("get data from an external source"),"</a>"].join(""));g.find(".uploader-link").click(function(k){Galaxy.upload._eventShow(k)});g.find(".get-data-link").click(function(k){j.parent().scrollTop(0);j.find('span:contains("Get Data")').click()});g.show()}else{f.HistoryPanel.prototype._renderEmptyMsg.call(this,i)}return this},toggleSearchControls:function(h,g){var i=f.HistoryPanel.prototype.toggleSearchControls.call(this,h,g);this.preferences.set("searching",i)},_renderTags:function(g){var h=this;f.HistoryPanel.prototype._renderTags.call(this,g);if(this.preferences.get("tagsEditorShown")){this.tagsEditor.toggle(true)}this.tagsEditor.on("hiddenUntilActivated:shown hiddenUntilActivated:hidden",function(i){h.preferences.set("tagsEditorShown",i.hidden)})},_renderAnnotation:function(g){var h=this;f.HistoryPanel.prototype._renderAnnotation.call(this,g);if(this.preferences.get("annotationEditorShown")){this.annotationEditor.toggle(true)}this.annotationEditor.on("hiddenUntilActivated:shown hiddenUntilActivated:hidden",function(i){h.preferences.set("annotationEditorShown",i.hidden)})},connectToQuotaMeter:function(g){if(!g){return this}this.listenTo(g,"quota:over",this.showQuotaMessage);this.listenTo(g,"quota:under",this.hideQuotaMessage);this.on("rendered rendered:initial",function(){if(g&&g.isOverQuota()){this.showQuotaMessage()}});return this},showQuotaMessage:function(){var g=this.$el.find(".quota-message");if(g.is(":hidden")){g.slideDown(this.fxSpeed)}},hideQuotaMessage:function(){var g=this.$el.find(".quota-message");if(!g.is(":hidden")){g.slideUp(this.fxSpeed)}},connectToOptionsMenu:function(g){if(!g){return this}this.on("new-storage",function(i,h){if(g&&i){g.findItemByHtml(_l("Include Deleted Datasets")).checked=i.get("show_deleted");g.findItemByHtml(_l("Include Hidden Datasets")).checked=i.get("show_hidden")}});return this},toString:function(){return"CurrentHistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{CurrentHistoryPanel:a}});
\ No newline at end of file
https://bitbucket.org/galaxy/galaxy-central/commits/79ab14af25e4/
Changeset: 79ab14af25e4
User: carlfeberhard
Date: 2014-03-25 21:59:27
Summary: History/HDA API: begin normalizing exceptions and return codes; Browser testing: update and expand history/hda testing, add importable/published permissions testing, transfer upload functions to api module
Affected #: 8 files
diff -r c4950bc662256f013916b0aaabb73a47508213c5 -r 79ab14af25e4182dac99ecad3918ed653c50f272 lib/galaxy/webapps/galaxy/api/histories.py
--- a/lib/galaxy/webapps/galaxy/api/histories.py
+++ b/lib/galaxy/webapps/galaxy/api/histories.py
@@ -97,32 +97,32 @@
history_id = id
deleted = string_as_bool( deleted )
- try:
- if history_id == "most_recently_used":
- if not trans.user or len( trans.user.galaxy_sessions ) <= 0:
- return None
- # Most recent active history for user sessions, not deleted
- history = trans.user.galaxy_sessions[0].histories[-1].history
+ #try:
+ if history_id == "most_recently_used":
+ if not trans.user or len( trans.user.galaxy_sessions ) <= 0:
+ return None
+ # Most recent active history for user sessions, not deleted
+ history = trans.user.galaxy_sessions[0].histories[-1].history
- elif history_id == "current":
- history = trans.get_history( create=True )
+ elif history_id == "current":
+ history = trans.get_history( create=True )
- else:
- history = self.get_history( trans, history_id, check_ownership=False,
- check_accessible=True, deleted=deleted )
+ else:
+ history = self.get_history( trans, history_id, check_ownership=False,
+ check_accessible=True, deleted=deleted )
- history_data = self.get_history_dict( trans, history )
- history_data[ 'contents_url' ] = url_for( 'history_contents', history_id=history_id )
+ history_data = self.get_history_dict( trans, history )
+ history_data[ 'contents_url' ] = url_for( 'history_contents', history_id=history_id )
- except HTTPBadRequest, bad_req:
- trans.response.status = 400
- raise exceptions.MessageException( bad_req.detail )
-
- except Exception, e:
- msg = "Error in history API at showing history detail: %s" % ( str( e ) )
- log.exception( msg )
- trans.response.status = 500
- return msg
+ #except HTTPBadRequest, bad_req:
+ # trans.response.status = 400
+ # raise exceptions.MessageException( bad_req.detail )
+ #
+ #except Exception, e:
+ # msg = "Error in history API at showing history detail: %s" % ( str( e ) )
+ # log.exception( msg )
+ # trans.response.status = 500
+ # return msg
return history_data
diff -r c4950bc662256f013916b0aaabb73a47508213c5 -r 79ab14af25e4182dac99ecad3918ed653c50f272 test/casperjs/api-hda-tests.js
--- a/test/casperjs/api-hda-tests.js
+++ b/test/casperjs/api-hda-tests.js
@@ -32,33 +32,12 @@
}
spaceghost.user.loginOrRegisterUser( email, password );
-var uploadFilename = '1.sam',
- uploadFilepath = '../../test-data/' + uploadFilename,
- upload = {};
-spaceghost.thenOpen( spaceghost.baseUrl ).tools.uploadFile( uploadFilepath, function( uploadInfo ){
- upload = uploadInfo;
+spaceghost.thenOpen( spaceghost.baseUrl, function(){
+ this.api.tools.thenUpload( spaceghost.api.histories.show( 'current' ).id, {
+ filepath: this.options.scriptDir + '/../../test-data/1.sam'
+ });
});
-function hasKeys( object, keysArray ){
- if( !utils.isObject( object ) ){ return false; }
- for( var i=0; i<keysArray.length; i += 1 ){
- if( !object.hasOwnProperty( keysArray[i] ) ){
- spaceghost.debug( 'object missing key: ' + keysArray[i] );
- return false;
- }
- }
- return true;
-}
-
-function countKeys( object ){
- if( !utils.isObject( object ) ){ return 0; }
- var count = 0;
- for( var key in object ){
- if( object.hasOwnProperty( key ) ){ count += 1; }
- }
- return count;
-}
-
// =================================================================== TESTS
var summaryKeys = [ 'id', 'name', 'type', 'url' ],
detailKeys = [
@@ -76,11 +55,8 @@
'metadata_comment_lines', 'metadata_data_lines'
];
-spaceghost.historypanel.waitForHdas().then( function(){
+spaceghost.then( function(){
- var uploaded = this.historypanel.hdaElementInfoByTitle( uploadFilename );
- this.info( 'found uploaded hda: ' + uploaded.attributes.id );
- this.debug( 'uploaded hda: ' + this.jsonStr( uploaded ) );
// ------------------------------------------------------------------------------------------- INDEX
this.test.comment( 'index should return a list of summary data for each hda' );
var histories = this.api.histories.index(),
@@ -92,18 +68,17 @@
this.test.assert( hdaIndex.length >= 1, 'Has at least one hda' );
var firstHda = hdaIndex[0];
- this.test.assert( hasKeys( firstHda, summaryKeys ), 'Has the proper keys' );
+ this.test.assert( this.hasKeys( firstHda, summaryKeys ), 'Has the proper keys' );
this.test.assert( this.api.isEncodedId( firstHda.id ), 'Id appears well-formed: ' + firstHda.id );
- this.test.assert( uploaded.text.indexOf( firstHda.name ) !== -1, 'Title matches: ' + firstHda.name );
- // not caring about type or url here
+ this.test.assert( firstHda.name === '1.sam', 'Title matches: ' + firstHda.name );
// ------------------------------------------------------------------------------------------- SHOW
this.test.comment( 'show should get an HDA details object' );
var hdaShow = this.api.hdas.show( lastHistory.id, firstHda.id );
//this.debug( this.jsonStr( hdaShow ) );
- this.test.assert( hasKeys( hdaShow, detailKeys ), 'Has the proper keys' );
+ this.test.assert( this.hasKeys( hdaShow, detailKeys ), 'Has the proper keys' );
//TODO: validate data in each hdaShow attribute...
@@ -117,7 +92,7 @@
this.test.assert( hdaIndex.length >= 1, 'Has at least one hda' );
firstHda = hdaIndex[0];
- this.test.assert( hasKeys( firstHda, detailKeys ), 'Has the proper keys' );
+ this.test.assert( this.hasKeys( firstHda, detailKeys ), 'Has the proper keys' );
//TODO??: validate data in firstHda attribute? we ASSUME it's from a common method as show...
@@ -133,29 +108,21 @@
var returned = this.api.hdas.update( lastHistory.id, firstHda.id, {
name : hdaShow.name
});
- this.test.assert( countKeys( returned ) === 0, "No changed returned: " + this.jsonStr( returned ) );
+ this.test.assert( this.countKeys( returned ) === 0, "No changed returned: " + this.jsonStr( returned ) );
this.test.comment( 'updating using a nonsense key should NOT fail with an error' );
returned = this.api.hdas.update( lastHistory.id, firstHda.id, {
konamiCode : 'uuddlrlrba'
});
- this.test.assert( countKeys( returned ) === 0, "No changed returned: " + this.jsonStr( returned ) );
+ this.test.assert( this.countKeys( returned ) === 0, "No changed returned: " + this.jsonStr( returned ) );
this.test.comment( 'updating by attempting to change type should cause an error' );
- err = {};
- try {
+ this.api.assertRaises( function(){
returned = this.api.hdas.update( lastHistory.id, firstHda.id, {
//name : false
deleted : 'sure why not'
});
- } catch( error ){
- err = error;
- //this.debug( this.jsonStr( err ) );
- }
- this.test.assert( !!err.message, "Error occurred: " + err.message );
- this.test.assert( err.status === 400, "Error status is 400: " + err.status );
- //TODO??: other type checks?
-
+ }, 400, 'deleted must be a boolean', 'changing deleted type failed' );
// ........................................................................................... name
this.test.comment( 'update should allow changing the name' );
@@ -330,25 +297,68 @@
// ------------------------------------------------------------------------------------------- ERRORS
this.test.comment( 'create should error with "Please define the source" when the param "from_ld_id" is not used' );
- var errored = false;
- try {
- // sending an empty object won't work
- var created = this.api.hdas.create( lastHistory.id, { bler: 'bler' } );
+ this.api.assertRaises( function(){
+ this.api.hdas.create( lastHistory.id, { bler: 'bler' } );
+ }, 400, 'Please define the source', 'create with no source failed' );
- } catch( err ){
- errored = true;
- this.test.assert( err.message.indexOf( 'Please define the source' ) !== -1,
- 'Error has the proper message: ' + err.message );
- this.test.assert( err.status === 400, 'Error has the proper status code: ' + err.status );
- }
- if( !errored ){
- this.test.fail( 'create without "from_ld_id" did not cause error' );
- }
+ this.test.comment( 'updating using a nonsense key should fail silently' );
+ returned = this.api.hdas.update( lastHistory.id, hdaShow.id, {
+ konamiCode : 'uuddlrlrba'
+ });
+ this.test.assert( returned.konamiCode === undefined, 'key was not set: ' + returned.konamiCode );
- //var returned = this.api.hdas.update( lastHistory.id, hdaIndex[0].id, { deleted: true, blerp: 'blerp' });
- //var returned = this.api.hdas.update( lastHistory.id, { deleted: true, blerp: 'blerp' });
- //this.debug( 'returned:' + this.jsonStr( returned ) );
- //this.debug( 'page:' + this.jsonStr( this.page ) );
+ spaceghost.test.comment( 'A bad id should throw an error when using show' );
+ this.api.assertRaises( function(){
+ this.api.hdas.show( lastHistory.id, '1234123412341234' );
+ }, 500, 'unable to decode', 'Bad Request with invalid id: show' );
+ spaceghost.test.comment( 'A bad id should throw an error when using update' );
+ this.api.assertRaises( function(){
+ this.api.hdas.update( lastHistory.id, '1234123412341234', {} );
+ }, 400, 'invalid literal for int', 'Bad Request with invalid id: update' );
+ spaceghost.test.comment( 'A bad id should throw an error when using delete' );
+ this.api.assertRaises( function(){
+ this.api.hdas.delete_( lastHistory.id, '1234123412341234' );
+ }, 500, 'invalid literal for int', 'Bad Request with invalid id: delete' );
+ spaceghost.test.comment( 'A bad id should throw an error when using undelete' );
+
+ this.test.comment( 'updating by attempting to change type should cause an error' );
+ [ 'name', 'annotation', 'genome_build', 'misc_info' ].forEach( function( key ){
+ var updatedAttrs = {};
+ updatedAttrs[ key ] = false;
+ spaceghost.api.assertRaises( function(){
+ returned = spaceghost.api.hdas.update( hdaShow.history_id, hdaShow.id, updatedAttrs );
+ }, 400, key + ' must be a string or unicode', 'type validation error' );
+ });
+ [ 'deleted', 'visible' ].forEach( function( key ){
+ var updatedAttrs = {};
+ updatedAttrs[ key ] = 'straaang';
+ spaceghost.api.assertRaises( function(){
+ returned = spaceghost.api.hdas.update( hdaShow.history_id, hdaShow.id, updatedAttrs );
+ }, 400, key + ' must be a boolean', 'type validation error' );
+ });
+ [ 'you\'re it', [ true ] ].forEach( function( badVal ){
+ spaceghost.api.assertRaises( function(){
+ returned = spaceghost.api.hdas.update( hdaShow.history_id, hdaShow.id, { tags: badVal });
+ }, 400, 'tags must be a list', 'type validation error' );
+ });
+
+ // ------------------------------------------------------------------------------------------- DELETE
+ this.test.comment( 'calling delete on an hda should mark it as deleted but not change the history size' );
+ lastHistory = this.api.histories.show( lastHistory.id );
+ var sizeBeforeDelete = lastHistory.nice_size;
+
+ returned = this.api.hdas.delete_( lastHistory.id, firstHda.id );
+ //this.debug( this.jsonStr( returned ) );
+
+ hdaShow = this.api.hdas.show( lastHistory.id, firstHda.id );
+ this.test.assert( hdaShow.deleted, 'hda is marked deleted' );
+ lastHistory = this.api.histories.show( lastHistory.id );
+ this.test.assert( lastHistory.nice_size === sizeBeforeDelete, 'history size has not changed' );
+
+ // by default, purging fails bc uni.ini:allow_user_dataset_purge=False
+ this.api.assertRaises( function(){
+ returned = this.api.hdas.delete_( lastHistory.id, firstHda.id, { purge : true });
+ }, 403, 'This instance does not allow user dataset purging', 'Purge failed' );
/*
*/
});
diff -r c4950bc662256f013916b0aaabb73a47508213c5 -r 79ab14af25e4182dac99ecad3918ed653c50f272 test/casperjs/api-history-permission-tests.js
--- /dev/null
+++ b/test/casperjs/api-history-permission-tests.js
@@ -0,0 +1,303 @@
+/* Utility to load a specific page and output html, page text, or a screenshot
+ * Optionally wait for some time, text, or dom selector
+ */
+try {
+ //...if there's a better way - please let me know, universe
+ var scriptDir = require( 'system' ).args[3]
+ // remove the script filename
+ .replace( /[\w|\.|\-|_]*$/, '' )
+ // if given rel. path, prepend the curr dir
+ .replace( /^(?!\/)/, './' ),
+ spaceghost = require( scriptDir + 'spaceghost' ).create({
+ // script options here (can be overridden by CLI)
+ //verbose: true,
+ //logLevel: debug,
+ scriptDir: scriptDir
+ });
+
+} catch( error ){
+ console.debug( error );
+ phantom.exit( 1 );
+}
+spaceghost.start();
+
+
+// =================================================================== SET UP
+var utils = require( 'utils' );
+
+var email = spaceghost.user.getRandomEmail(),
+ password = '123456';
+if( spaceghost.fixtureData.testUser ){
+ email = spaceghost.fixtureData.testUser.email;
+ password = spaceghost.fixtureData.testUser.password;
+}
+var email2 = spaceghost.user.getRandomEmail(),
+ password2 = '123456';
+if( spaceghost.fixtureData.testUser2 ){
+ email2 = spaceghost.fixtureData.testUser2.email;
+ password2 = spaceghost.fixtureData.testUser2.password;
+}
+
+var inaccessibleHistory, accessibleHistory, publishedHistory,
+ inaccessibleHdas, accessibleHdas, publishedHdas,
+ accessibleLink;
+
+// =================================================================== TESTS
+//// ------------------------------------------------------------------------------------------- create 3 histories
+spaceghost.user.loginOrRegisterUser( email, password );
+spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
+ // create three histories: make the 2nd importable (via the API), and the third published
+
+ this.test.comment( 'importable, slug, and published should all be returned by show and initially off' );
+ // make the current the inaccessible one
+ inaccessibleHistory = this.api.histories.show( 'current' );
+ this.test.assert( this.hasKeys( inaccessibleHistory, [ 'id', 'name', 'slug', 'importable', 'published' ] ),
+ 'Has the proper keys' );
+ this.test.assert( inaccessibleHistory.slug === null,
+ 'initial slug is null: ' + inaccessibleHistory.slug );
+ this.test.assert( inaccessibleHistory.importable === false,
+ 'initial importable is false: ' + inaccessibleHistory.importable );
+ this.test.assert( inaccessibleHistory.published === false,
+ 'initial published is false: ' + inaccessibleHistory.published );
+ this.api.histories.update( inaccessibleHistory.id, { name: 'inaccessible' });
+
+ this.test.comment( 'Setting importable to true should create a slug, username_and_slug, and importable === true' );
+ accessibleHistory = this.api.histories.create({ name: 'accessible' });
+ var returned = this.api.histories.update( accessibleHistory.id, {
+ importable : true
+ });
+ this.debug( this.jsonStr( returned ) );
+ accessibleHistory = this.api.histories.show( accessibleHistory.id );
+ this.test.assert( this.hasKeys( accessibleHistory, [ 'username_and_slug' ] ),
+ 'Has the proper keys' );
+ this.test.assert( accessibleHistory.slug === 'accessible',
+ 'slug is not null: ' + accessibleHistory.slug );
+ this.test.assert( accessibleHistory.importable,
+ 'importable is true: ' + accessibleHistory.importable );
+ accessibleLink = 'u/' + email.replace( '@test.test', '' ) + '/h/accessible';
+ this.test.assert( accessibleHistory.username_and_slug === accessibleLink,
+ 'username_and_slug is proper: ' + accessibleHistory.username_and_slug );
+
+ this.test.comment( 'Setting published to true should create make accessible and published === true' );
+ publishedHistory = this.api.histories.create({ name: 'published' });
+ returned = this.api.histories.update( publishedHistory.id, {
+ published : true
+ });
+ this.debug( this.jsonStr( returned ) );
+ publishedHistory = this.api.histories.show( publishedHistory.id );
+ this.test.assert( this.hasKeys( publishedHistory, [ 'username_and_slug' ] ),
+ 'Has the proper keys' );
+ this.test.assert( publishedHistory.published,
+ 'published is true: ' + publishedHistory.published );
+ this.test.assert( publishedHistory.importable,
+ 'importable is true: ' + publishedHistory.importable );
+ this.test.assert( publishedHistory.slug === 'published',
+ 'slug is not null: ' + publishedHistory.slug );
+ accessibleLink = 'u/' + email.replace( '@test.test', '' ) + '/h/published';
+ this.test.assert( publishedHistory.username_and_slug === accessibleLink,
+ 'username_and_slug is proper: ' + publishedHistory.username_and_slug );
+
+});
+
+//// ------------------------------------------------------------------------------------------- upload some files
+spaceghost.then( function(){
+ this.api.tools.thenUpload( inaccessibleHistory.id, { filepath: this.options.scriptDir + '/../../test-data/1.bed' });
+ this.api.tools.thenUpload( accessibleHistory.id, { filepath: this.options.scriptDir + '/../../test-data/1.bed' });
+ this.api.tools.thenUpload( publishedHistory.id, { filepath: this.options.scriptDir + '/../../test-data/1.bed' });
+});
+spaceghost.then( function(){
+ // check that they're there
+ inaccessibleHdas = this.api.hdas.index( inaccessibleHistory.id ),
+ accessibleHdas = this.api.hdas.index( accessibleHistory.id ),
+ publishedHdas = this.api.hdas.index( publishedHistory.id );
+ this.test.assert( inaccessibleHdas.length === 1,
+ 'uploaded file to inaccessible: ' + inaccessibleHdas.length );
+ this.test.assert( accessibleHdas.length === 1,
+ 'uploaded file to accessible: ' + accessibleHdas.length );
+ this.test.assert( publishedHdas.length === 1,
+ 'uploaded file to published: ' + publishedHdas.length );
+});
+spaceghost.user.logout();
+
+//// ------------------------------------------------------------------------------------------- log in user2
+function ensureInaccessibility( history, hdas ){
+
+ this.test.comment( 'all four CRUD API calls should fail for user2 with history: ' + history.name );
+ this.api.assertRaises( function(){
+ this.api.histories.show( history.id );
+ }, 400, 'History is not accessible to the current user', 'show failed with error' );
+ this.api.assertRaises( function(){
+ this.api.histories.create({ history_id : history.id });
+ }, 403, 'History is not accessible to the current user', 'copy failed with error' );
+ this.api.assertRaises( function(){
+ this.api.histories.update( history.id, { deleted: true });
+ }, 500, 'History is not owned by the current user', 'update failed with error' );
+ this.api.assertRaises( function(){
+ this.api.histories.delete_( history.id );
+ }, 400, 'History is not owned by the current user', 'delete failed with error' );
+
+ this.test.comment( 'all four HDA CRUD API calls should fail for user2 with history: ' + history.name );
+ this.api.assertRaises( function(){
+ this.api.hdas.index( history.id );
+ }, 500, 'History is not accessible to the current user', 'index failed with error' );
+ this.api.assertRaises( function(){
+ this.api.hdas.show( history.id, hdas[0].id );
+ }, 500, 'History is not accessible to the current user', 'show failed with error' );
+ this.api.assertRaises( function(){
+ this.api.hdas.update( history.id, hdas[0].id, { deleted: true });
+ }, 500, 'HistoryDatasetAssociation is not owned by current user', 'update failed with error' );
+ this.api.assertRaises( function(){
+ this.api.hdas.delete_( history.id, hdas[0].id );
+ }, 500, 'HistoryDatasetAssociation is not owned by current user', 'delete failed with error' );
+
+ this.test.comment( 'Attempting to copy an accessible hda (default is accessible)'
+ + 'from an inaccessible history should fail' );
+ this.api.assertRaises( function(){
+ var returned = this.api.hdas.create( this.api.histories.show( 'current' ).id, {
+ source : 'hda',
+ content : hdas[0].id
+ });
+ this.debug( this.jsonStr( returned ) );
+ }, 403, 'History is not accessible to the current user', 'copy failed with error' );
+
+}
+spaceghost.user.loginOrRegisterUser( email2, password2 );
+spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
+
+ // ----------------------------------------------------------------------------------------- user2 + inaccessible
+ ensureInaccessibility.call( spaceghost, inaccessibleHistory, inaccessibleHdas );
+
+ // ----------------------------------------------------------------------------------------- user2 + accessible
+ this.test.comment( 'show should work for the importable history' );
+ this.test.assert( this.api.histories.show( accessibleHistory.id ).id === accessibleHistory.id,
+ 'show worked' );
+
+ this.test.comment( 'create/copy should work for the importable history' );
+ var returned = this.api.histories.create({ history_id : accessibleHistory.id });
+ this.test.assert( returned.name === "Copy of '" + accessibleHistory.name + "'",
+ 'copied name matches: ' + returned.name );
+
+ this.test.comment( 'update should fail for the importable history' );
+ this.api.assertRaises( function(){
+ this.api.histories.update( accessibleHistory.id, { deleted: true });
+ }, 500, 'History is not owned by the current user', 'update failed with error' );
+ this.test.comment( 'delete should fail for the importable history' );
+ this.api.assertRaises( function(){
+ this.api.histories.delete_( accessibleHistory.id );
+ }, 400, 'History is not owned by the current user', 'delete failed with error' );
+
+ this.test.comment( 'indexing should work for the contents of the importable history' );
+ this.test.assert( this.api.hdas.index( accessibleHistory.id ).length === 1,
+ 'index worked' );
+ this.test.comment( 'showing should work for the contents of the importable history' );
+ this.test.assert( this.api.hdas.show( accessibleHistory.id, accessibleHdas[0].id ).id === accessibleHdas[0].id,
+ 'show worked' );
+ this.test.comment( 'updating should fail for the contents of the importable history' );
+ this.api.assertRaises( function(){
+ this.api.hdas.update( accessibleHistory.id, accessibleHdas[0].id, { deleted: true });
+ }, 500, 'HistoryDatasetAssociation is not owned by current user', 'update failed with error' );
+ this.test.comment( 'deleting should fail for the contents of the importable history' );
+ this.api.assertRaises( function(){
+ this.api.hdas.delete_( accessibleHistory.id, accessibleHdas[0].id );
+ }, 500, 'HistoryDatasetAssociation is not owned by current user', 'delete failed with error' );
+ this.test.comment( 'copying a dataset from the importable history should work' );
+ returned = this.api.hdas.create( this.api.histories.show( 'current' ).id, {
+ source : 'hda',
+ content : accessibleHdas[0].id
+ });
+ this.test.assert( returned.name === accessibleHdas[0].name, 'successful copy from: ' + returned.name );
+
+ this.test.comment( 'copying a dataset into the importable history should fail' );
+ this.api.assertRaises( function(){
+ this.api.hdas.create( accessibleHistory.id, {
+ source : 'hda',
+ // should error before it checks the id
+ content : 'bler'
+ });
+ }, 400, 'History is not owned by the current user', 'copy to failed' );
+
+ //// ----------------------------------------------------------------------------------------- user2 + published
+ this.test.comment( 'show should work for the published history' );
+ this.test.assert( this.api.histories.show( publishedHistory.id ).id === publishedHistory.id,
+ 'show worked' );
+ this.test.comment( 'create/copy should work for the published history' );
+ returned = this.api.histories.create({ history_id : publishedHistory.id });
+ this.test.assert( returned.name === "Copy of '" + publishedHistory.name + "'",
+ 'copied name matches: ' + returned.name );
+ this.test.comment( 'update should fail for the published history' );
+ this.api.assertRaises( function(){
+ this.api.histories.update( publishedHistory.id, { deleted: true });
+ }, 500, 'History is not owned by the current user', 'update failed with error' );
+ this.test.comment( 'delete should fail for the published history' );
+ this.api.assertRaises( function(){
+ this.api.histories.delete_( publishedHistory.id );
+ }, 400, 'History is not owned by the current user', 'delete failed with error' );
+
+ this.test.comment( 'indexing should work for the contents of the published history' );
+ this.test.assert( this.api.hdas.index( publishedHistory.id ).length === 1,
+ 'index worked' );
+ this.test.comment( 'showing should work for the contents of the published history' );
+ this.test.assert( this.api.hdas.show( publishedHistory.id, publishedHdas[0].id ).id === publishedHdas[0].id,
+ 'show worked' );
+ this.test.comment( 'updating should fail for the contents of the published history' );
+ this.api.assertRaises( function(){
+ this.api.hdas.update( publishedHistory.id, publishedHdas[0].id, { deleted: true });
+ }, 500, 'HistoryDatasetAssociation is not owned by current user', 'update failed with error' );
+ this.test.comment( 'deleting should fail for the contents of the published history' );
+ this.api.assertRaises( function(){
+ this.api.hdas.delete_( publishedHistory.id, publishedHdas[0].id );
+ }, 500, 'HistoryDatasetAssociation is not owned by current user', 'delete failed with error' );
+
+ this.test.comment( 'copying a dataset from the published history should work' );
+ returned = this.api.hdas.create( this.api.histories.show( 'current' ).id, {
+ source : 'hda',
+ content : publishedHdas[0].id
+ });
+ this.test.assert( returned.name === publishedHdas[0].name, 'successful copy from: ' + returned.name );
+
+ this.test.comment( 'copying a dataset into the published history should fail' );
+ this.api.assertRaises( function(){
+ this.api.hdas.create( publishedHistory.id, {
+ source : 'hda',
+ // should error before it checks the id
+ content : 'bler'
+ });
+ }, 400, 'History is not owned by the current user', 'copy to failed' );
+});
+spaceghost.user.logout();
+
+
+//// ------------------------------------------------------------------------------------------- user1 revoke perms
+spaceghost.user.loginOrRegisterUser( email, password );
+spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
+ this.test.comment( 'revoking perms should prevent access' );
+ this.api.histories.update( accessibleHistory.id, {
+ importable : false
+ });
+ var returned = this.api.histories.show( accessibleHistory.id );
+ this.test.assert( !returned.importable, 'now not importable' );
+ this.test.assert( !returned.published, '(still not published)' );
+ this.test.assert( !!returned.slug, '(slug still set) ' + returned.slug );
+
+ this.api.histories.update( publishedHistory.id, {
+ importable : false,
+ published : false
+ });
+ returned = this.api.histories.show( publishedHistory.id );
+ this.test.assert( !returned.importable, 'now not importable' );
+ this.test.assert( !returned.published, 'now not published' );
+ this.test.assert( !!returned.slug, '(slug still set) ' + returned.slug );
+});
+spaceghost.user.logout();
+
+
+//// ------------------------------------------------------------------------------------------- user2 retry perms
+spaceghost.user.loginOrRegisterUser( email2, password2 );
+spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
+ ensureInaccessibility.call( spaceghost, accessibleHistory, accessibleHdas );
+ ensureInaccessibility.call( spaceghost, publishedHistory, publishedHdas );
+});
+
+// ===================================================================
+spaceghost.run( function(){
+});
diff -r c4950bc662256f013916b0aaabb73a47508213c5 -r 79ab14af25e4182dac99ecad3918ed653c50f272 test/casperjs/api-history-tests.js
--- a/test/casperjs/api-history-tests.js
+++ b/test/casperjs/api-history-tests.js
@@ -33,25 +33,6 @@
}
spaceghost.user.loginOrRegisterUser( email, password );
-function hasKeys( object, keysArray ){
- if( !utils.isObject( object ) ){ return false; }
- for( var i=0; i<keysArray.length; i += 1 ){
- if( !object.hasOwnProperty( keysArray[i] ) ){
- spaceghost.debug( 'object missing key: ' + keysArray[i] );
- return false;
- }
- }
- return true;
-}
-
-function countKeys( object ){
- if( !utils.isObject( object ) ){ return 0; }
- var count = 0;
- for( var key in object ){
- if( object.hasOwnProperty( key ) ){ count += 1; }
- }
- return count;
-}
// =================================================================== TESTS
spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
@@ -64,7 +45,7 @@
this.test.assert( historyIndex.length >= 1, 'Has at least one history' );
var firstHistory = historyIndex[0];
- this.test.assert( hasKeys( firstHistory, [ 'id', 'name', 'url' ] ), 'Has the proper keys' );
+ this.test.assert( this.hasKeys( firstHistory, [ 'id', 'name', 'url' ] ), 'Has the proper keys' );
this.test.assert( this.api.isEncodedId( firstHistory.id ), 'Id appears well-formed' );
@@ -72,7 +53,7 @@
this.test.comment( 'show should get a history details object' );
var historyShow = this.api.histories.show( firstHistory.id );
//this.debug( this.jsonStr( historyShow ) );
- this.test.assert( hasKeys( historyShow, [
+ this.test.assert( this.hasKeys( historyShow, [
'id', 'name', 'annotation', 'nice_size', 'contents_url',
'state', 'state_details', 'state_ids' ]),
'Has the proper keys' );
@@ -83,8 +64,8 @@
'ok', 'paused', 'queued', 'running', 'setting_metadata', 'upload' ],
state_details = historyShow.state_details,
state_ids = historyShow.state_ids;
- this.test.assert( hasKeys( state_details, states ), 'state_details has the proper keys' );
- this.test.assert( hasKeys( state_ids, states ), 'state_ids has the proper keys' );
+ this.test.assert( this.hasKeys( state_details, states ), 'state_details has the proper keys' );
+ this.test.assert( this.hasKeys( state_ids, states ), 'state_ids has the proper keys' );
var state_detailsAreNumbers = true;
state_idsAreArrays = true;
states.forEach( function( state ){
@@ -103,20 +84,19 @@
this.test.assert( this.api.histories.show( this.api.histories.index()[0].id ).id === firstHistory.id,
'combining function calls works' );
- // test server bad id protection
- this.test.comment( 'A bad id to show should throw an error' );
- this.assertRaises( function(){
- this.api.histories.show( '1234123412341234' );
- }, '400 Bad Request', 'Raises an exception' );
+ this.test.comment( 'Calling show with "current" should return the current history' );
+ this.test.assert( this.api.histories.show( 'current' ).id === historyShow.id, 'current returned same id' );
// ------------------------------------------------------------------------------------------- CREATE
- this.test.comment( 'Calling create should create a new history and allow setting the name' );
+ this.test.comment( 'Calling create should create a new history and allow setting the name and making it current' );
var newHistoryName = 'Created History',
- createdHistory = this.api.histories.create({ name: newHistoryName });
+ createdHistory = this.api.histories.create({ name: newHistoryName, current: true });
//this.debug( 'returned from create:\n' + this.jsonStr( createdHistory ) );
this.test.assert( createdHistory.name === newHistoryName,
"Name of created history (from create) is correct: " + createdHistory.name );
+ this.test.assert( this.api.histories.show( 'current' ).id === createdHistory.id,
+ "was made current" );
// check the index
var newFirstHistory = this.api.histories.index()[0];
@@ -156,50 +136,25 @@
"Undeletion returned 'OK' - even though that's not a great, informative response: " + undeletedHistory );
newFirstHistory = this.api.histories.index()[0];
- this.debug( 'newFirstHistory:\n' + this.jsonStr( newFirstHistory ) );
+ //this.debug( 'newFirstHistory:\n' + this.jsonStr( newFirstHistory ) );
this.test.assert( newFirstHistory.id === createdHistory.id,
"Id of last history (from index) DOES appear after undeletion: " + newFirstHistory.id );
//TODO: show, deleted flag
//TODO: delete, purge flag
+
+
+ // ------------------------------------------------------------------------------------------- set_as_current
+ this.test.comment( 'calling set_as_current on a non-current history will make it current' );
+ this.test.assert( this.api.histories.show( 'current' ).id !== historyShow.id, historyShow.id + ' is not current' );
+ var returned = this.api.histories.set_as_current( historyShow.id );
+ this.debug( this.jsonStr( returned ) );
+ this.test.assert( this.api.histories.show( 'current' ).id === historyShow.id, 'made current' );
+ this.api.histories.set_as_current( newFirstHistory.id );
+
+
// ------------------------------------------------------------------------------------------- UPDATE
- // ........................................................................................... idiot proofing
- this.test.comment( 'updating to the current value should return no value (no change)' );
- historyShow = this.api.histories.show( newFirstHistory.id );
- var returned = this.api.histories.update( newFirstHistory.id, {
- name : historyShow.name
- });
- this.test.assert( countKeys( returned ) === 0, "No changed returned: " + this.jsonStr( returned ) );
-
- this.test.comment( 'updating using a nonsense key should fail silently' );
- var err = null;
- try {
- returned = this.api.histories.update( newFirstHistory.id, {
- konamiCode : 'uuddlrlrba'
- });
- } catch( error ){
- err = error;
- //this.debug( this.jsonStr( err ) );
- }
- this.test.assert( err === null, "No error occurred: " + this.jsonStr( err ) );
-
- this.test.comment( 'updating by attempting to change type should cause an error' );
- err = {};
- try {
- returned = this.api.histories.update( newFirstHistory.id, {
- //name : false
- deleted : 'sure why not'
- });
- } catch( error ){
- err = error;
- //this.debug( this.jsonStr( err ) );
- }
- this.test.assert( !!err.message, "Error occurred: " + err.message );
- this.test.assert( err.status === 400, "Error status is 400: " + err.status );
- //TODO??: other type checks?
-
-
// ........................................................................................... name
this.test.comment( 'update should allow changing the name' );
returned = this.api.histories.update( newFirstHistory.id, {
@@ -339,8 +294,58 @@
// ------------------------------------------------------------------------------------------- ERRORS
- //TODO: make sure expected errors are being passed back (but no permissions checks here - different suite)
- // bad ids: index, show, update, delete, undelete
+ // ........................................................................................... idiot proofing
+ this.test.comment( 'updating to the current value should return no value (no change)' );
+ historyShow = this.api.histories.show( newFirstHistory.id );
+ returned = this.api.histories.update( newFirstHistory.id, {
+ name : historyShow.name
+ });
+ this.test.assert( this.countKeys( returned ) === 0, "No changed returned: " + this.jsonStr( returned ) );
+
+ this.test.comment( 'updating using a nonsense key should fail silently' );
+ returned = this.api.histories.update( newFirstHistory.id, {
+ konamiCode : 'uuddlrlrba'
+ });
+ this.test.assert( returned.konamiCode === undefined, 'key was not set: ' + returned.konamiCode );
+
+ // test server bad id protection
+ spaceghost.test.comment( 'A bad id should throw an error' );
+ this.api.assertRaises( function(){
+ this.api.histories.show( '1234123412341234' );
+ }, 400, 'unable to decode', 'Bad Request with invalid id: show' );
+ spaceghost.test.comment( 'A bad id should throw an error when using update' );
+ this.api.assertRaises( function(){
+ this.api.histories.update( '1234123412341234', {} );
+ }, 500, 'unable to decode', 'Bad Request with invalid id: update' );
+ spaceghost.test.comment( 'A bad id should throw an error when using delete' );
+ this.api.assertRaises( function(){
+ this.api.histories.delete_( '1234123412341234' );
+ }, 400, 'unable to decode', 'Bad Request with invalid id: delete' );
+ spaceghost.test.comment( 'A bad id should throw an error when using undelete' );
+ this.api.assertRaises( function(){
+ this.api.histories.undelete( '1234123412341234' );
+ }, 400, 'unable to decode', 'Bad Request with invalid id: undelete' );
+
+ this.test.comment( 'updating by attempting to change type should cause an error' );
+ [ 'name', 'annotation' ].forEach( function( key ){
+ var updatedAttrs = {};
+ updatedAttrs[ key ] = false;
+ spaceghost.api.assertRaises( function(){
+ returned = spaceghost.api.histories.update( newFirstHistory.id, updatedAttrs );
+ }, 400, key + ' must be a string or unicode', 'type validation error' );
+ });
+ [ 'deleted', 'importable', 'published' ].forEach( function( key ){
+ var updatedAttrs = {};
+ updatedAttrs[ key ] = 'straaang';
+ spaceghost.api.assertRaises( function(){
+ returned = spaceghost.api.histories.update( newFirstHistory.id, updatedAttrs );
+ }, 400, key + ' must be a boolean', 'type validation error' );
+ });
+ [ 'you\'re it', [ true ] ].forEach( function( badVal ){
+ spaceghost.api.assertRaises( function(){
+ returned = spaceghost.api.histories.update( newFirstHistory.id, { tags: badVal });
+ }, 400, 'tags must be a list', 'type validation error' );
+ });
/*
*/
//this.debug( this.jsonStr( historyShow ) );
diff -r c4950bc662256f013916b0aaabb73a47508213c5 -r 79ab14af25e4182dac99ecad3918ed653c50f272 test/casperjs/casperjs_runner.py
--- a/test/casperjs/casperjs_runner.py
+++ b/test/casperjs/casperjs_runner.py
@@ -81,6 +81,7 @@
"""
# debugging flag - set to true to have casperjs tests output with --verbose=true and --logLevel=debug
+ #debug = True
debug = False
# bit of a hack - this is the beginning of the last string when capserjs --verbose=true --logLevel=debug
# use this to get subprocess to stop waiting for output
@@ -191,6 +192,7 @@
except ValueError, val_err:
if str( val_err ) == 'No JSON object could be decoded':
log.debug( '(error parsing returned JSON from casperjs, dumping stdout...)\n:%s', stdout_output )
+ return HeadlessJSJavascriptError( 'see log for details' )
else:
raise
@@ -375,19 +377,29 @@
class Test_04_HDAs( CasperJSTestCase ):
"""Tests for HistoryDatasetAssociation fetching, rendering, and modeling.
"""
- def test_00_HDA_states( self ):
- """Test structure rendering of HDAs in all the possible HDA states
- """
- self.run_js_script( 'hda-state-tests.js' )
+ #def test_00_HDA_states( self ):
+ # """Test structure rendering of HDAs in all the possible HDA states
+ # """
+ # self.run_js_script( 'hda-state-tests.js' )
class Test_05_API( CasperJSTestCase ):
"""Tests for API functionality and security.
"""
- def test_00_history_api( self ):
- """Test history API.
+ #def test_00_history_api( self ):
+ # """Test history API.
+ # """
+ # self.run_js_script( 'api-history-tests.js' )
+
+ def test_01_hda_api( self ):
+ """Test HDA API.
"""
- self.run_js_script( 'api-history-tests.js' )
+ self.run_js_script( 'api-hda-tests.js' )
+
+ def test_02_history_permissions_api( self ):
+ """Test API permissions for importable, published histories.
+ """
+ self.run_js_script( 'api-history-permission-tests.js' )
# ==================================================================== MAIN
diff -r c4950bc662256f013916b0aaabb73a47508213c5 -r 79ab14af25e4182dac99ecad3918ed653c50f272 test/casperjs/modules/api.js
--- a/test/casperjs/modules/api.js
+++ b/test/casperjs/modules/api.js
@@ -75,12 +75,63 @@
if( resp.status !== 200 ){
// grrr... this doesn't lose the \n\r\t
//throw new APIError( resp.responseText.replace( /[\s\n\r\t]+/gm, ' ' ).replace( /"/, '' ) );
- this.spaceghost.debug( 'api error response status code: ' + resp.status );
+ this.spaceghost.debug( 'API error: code: ' + resp.status + ', responseText: ' + resp.responseText );
+ this.spaceghost.debug( '\t responseJSON: ' + this.spaceghost.jsonStr( resp.responseJSON ) );
throw new APIError( resp.responseText, resp.status );
}
return JSON.parse( resp.responseText );
};
+// =================================================================== TESTING
+/** Checks whether fn raises an error with a message that contains a status and given string.
+ * NOTE: DOES NOT work with steps. @see SpaceGhost#assertStepsRaise
+ * @param {Function} testFn a function that may throw an error
+ * @param {Integer} statusExpected the HTTP status code expected
+ * @param {String} errMsgContains some portion of the correct error msg
+ * @private
+ */
+API.prototype._APIRaises = function _APIRaises( testFn, statusExpected, errMsgContains ){
+ var failed = false;
+ try {
+ testFn.call( this.spaceghost );
+ } catch( err ){
+ this.spaceghost.debug( err.name + ': ' + err.status );
+ this.spaceghost.debug( err.message );
+ if( ( err.name === 'APIError' )
+ && ( err.status && err.status === statusExpected )
+ && ( err.message.indexOf( errMsgContains ) !== -1 ) ){
+ failed = true;
+
+ // re-raise other, non-searched-for errors
+ } else {
+ throw err;
+ }
+ }
+ return failed;
+};
+
+/** Simple assert raises.
+ * NOTE: DOES NOT work with steps. @see SpaceGhost#assertStepsRaise
+ * @param {Function} testFn a function that may throw an error
+ * @param {Integer} statusExpected the HTTP status code expected
+ * @param {String} errMsgContains some portion of the correct error msg
+ * @param {String} msg assertion message to display
+ */
+API.prototype.assertRaises = function assertRaises( testFn, statusExpected, errMsgContains, msg ){
+ return this.spaceghost.test.assert( this._APIRaises( testFn, statusExpected, errMsgContains ), msg );
+};
+
+/** Simple assert does not raise.
+ * NOTE: DOES NOT work with steps. @see SpaceGhost#assertStepsRaise
+ * @param {Function} testFn a function that may throw an error
+ * @param {Integer} statusExpected the HTTP status code expected
+ * @param {String} errMsgContains some portion of the correct error msg
+ * @param {String} msg assertion message to display
+ */
+API.prototype.assertDoesntRaise = function assertDoesntRaise( testFn, statusExpected, errMsgContains, msg ){
+ return this.spaceghost.test.assert( !this._APIRaises( testFn, statusExpected, errMsgContains ), msg );
+};
+
// =================================================================== MISC
API.prototype.isEncodedId = function isEncodedId( id ){
if( typeof id !== 'string' ){ return false; }
@@ -164,7 +215,8 @@
create : 'api/histories',
delete_ : 'api/histories/%s',
undelete: 'api/histories/deleted/%s/undelete',
- update : 'api/histories/%s'
+ update : 'api/histories/%s',
+ set_as_current : 'api/histories/%s/set_as_current'
};
HistoriesAPI.prototype.index = function index( deleted ){
@@ -179,7 +231,7 @@
HistoriesAPI.prototype.show = function show( id, deleted ){
this.api.spaceghost.info( 'histories.show: ' + [ id, (( deleted )?( 'w deleted' ):( '' )) ] );
- id = ( id === 'most_recently_used' )?( id ):( this.api.ensureId( id ) );
+ id = ( id === 'most_recently_used' || id === 'current' )?( id ):( this.api.ensureId( id ) );
deleted = deleted || false;
return this.api._ajax( utils.format( this.urlTpls.show, id ), {
data : { deleted: deleted }
@@ -217,7 +269,7 @@
});
};
-HistoriesAPI.prototype.update = function create( id, payload ){
+HistoriesAPI.prototype.update = function update( id, payload ){
this.api.spaceghost.info( 'histories.update: ' + id + ',' + this.api.spaceghost.jsonStr( payload ) );
// py.payload <-> ajax.data
@@ -231,6 +283,15 @@
});
};
+HistoriesAPI.prototype.set_as_current = function set_as_current( id ){
+ this.api.spaceghost.info( 'histories.set_as_current: ' + id );
+ id = this.api.ensureId( id );
+
+ return this.api._ajax( utils.format( this.urlTpls.set_as_current, id ), {
+ type : 'PUT'
+ });
+};
+
// =================================================================== HDAS
var HDAAPI = function HDAAPI( api ){
@@ -297,6 +358,23 @@
});
};
+HDAAPI.prototype.delete_ = function create( historyId, id, purge ){
+ this.api.spaceghost.info( 'hdas.delete_: ' + [ historyId, id ] );
+ historyId = this.api.ensureId( historyId );
+ id = this.api.ensureId( id );
+
+ // have to attach like GET param - due to body loss in jq
+ url = utils.format( this.urlTpls.update, historyId, id );
+ if( purge ){
+ url += '?purge=True';
+ }
+ return this.api._ajax( url, {
+ type : 'DELETE'
+ });
+};
+
+//TODO: delete_
+
// =================================================================== TOOLS
var ToolsAPI = function HDAAPI( api ){
@@ -350,6 +428,218 @@
});
};
+//ToolsAPI.prototype.uploadByForm = function upload( historyId, options ){
+// this.api.spaceghost.debug( '-------------------------------------------------' );
+// this.api.spaceghost.info( 'tools.upload: ' + [ historyId, '(contents)', this.api.spaceghost.jsonStr( options ) ] );
+// this.api.ensureId( historyId );
+// options = options || {};
+//
+// this.api.spaceghost.evaluate( function( url ){
+// var html = [
+// '<form action="', url, '" method="post" enctype="multipart/form-data">',
+// '<input type="file" name="files_0|file_data">',
+// '<input type="hidden" name="tool_id" />',
+// '<input type="hidden" name="history_id" />',
+// '<input type="hidden" name="inputs" />',
+// '<button type="submit">Submit</button>',
+// '</form>'
+// ];
+// document.write( html.join('') );
+// //document.getElementsByTagName( 'body' )[0].innerHTML = html.join('');
+// }, utils.format( this.urlTpls.create ) );
+//
+// this.api.spaceghost.fill( 'form', {
+// 'files_0|file_data' : '1.txt',
+// 'tool_id' : 'upload1',
+// 'history_id' : historyId,
+// 'inputs' : JSON.stringify({
+// 'file_type' : 'auto',
+// 'files_0|type' : 'upload_dataset',
+// 'to_posix_lines' : true,
+// 'space_to_tabs' : false,
+// 'dbkey' : '?'
+// })
+// }, true );
+// // this causes the page to switch...I think
+//};
+
+/** paste a file - either from a string (options.paste) or from a filesystem file (options.filepath) */
+ToolsAPI.prototype.uploadByPaste = function upload( historyId, options ){
+ this.api.spaceghost.info( 'tools.upload: ' + [ historyId, this.api.spaceghost.jsonStr( options ) ] );
+ this.api.ensureId( historyId );
+ options = options || {};
+
+ var inputs = {
+ 'files_0|NAME' : options.name || 'Test Dataset',
+ 'dbkey' : options.dbkey || '?',
+ 'file_type' : options.ext || 'auto'
+ };
+ if( options.filepath ){
+ var fs = require( 'fs' );
+ inputs[ 'files_0|url_paste' ] = fs.read( options.filepath );
+
+ } else if( options.paste ){
+ inputs[ 'files_0|url_paste' ] = options.paste;
+ }
+ if( options.posix ){
+ inputs[ 'files_0|to_posix_lines' ] = 'Yes';
+ }
+ if( options.tabs ){
+ inputs[ 'files_0|space_to_tab' ] = 'Yes';
+ }
+ return this.api._ajax( utils.format( this.urlTpls.create ), {
+ type : 'POST',
+ data : {
+ tool_id : 'upload1',
+ upload_type : 'upload_dataset',
+ history_id : historyId,
+ inputs : inputs
+ }
+ });
+};
+
+/** post a file to the upload1 tool over ajax */
+ToolsAPI.prototype.upload = function upload( historyId, options ){
+ this.api.spaceghost.info( 'tools.upload: ' + [ historyId, this.api.spaceghost.jsonStr( options ) ] );
+ this.api.ensureId( historyId );
+ options = options || {};
+
+ // We can post an upload using jquery and formdata (see below), the more
+ // difficult part is attaching the file without user intervention.
+ // To do this we need to (unfortunately) create a form phantom can attach the file to first.
+ this.api.spaceghost.evaluate( function(){
+ $( 'body' ).append( '<input type="file" name="casperjs-upload-file" />' );
+ });
+ this.api.spaceghost.page.uploadFile( 'input[name="casperjs-upload-file"]', options.filepath );
+
+ var inputs = {
+ 'file_type' : options.ext || 'auto',
+ 'files_0|type' : 'upload_dataset',
+ 'dbkey' : options.dbkey || '?'
+ };
+ if( options.posix ){
+ inputs[ 'files_0|to_posix_lines' ] = 'Yes';
+ }
+ if( options.tabs ){
+ inputs[ 'files_0|space_to_tab' ] = 'Yes';
+ }
+ var response = this.api.spaceghost.evaluate( function( url, historyId, inputs ){
+ var file = $( 'input[name="casperjs-upload-file"]' )[0].files[0],
+ formData = new FormData(),
+ response;
+
+ formData.append( 'files_0|file_data', file );
+ formData.append( 'history_id', historyId );
+ formData.append( 'tool_id', 'upload1' );
+ formData.append( 'inputs', JSON.stringify( inputs ) );
+ $.ajax({
+ url : url,
+ async : false,
+ type : 'POST',
+ data : formData,
+ // when sending FormData don't have jq process or cache the data
+ cache : false,
+ contentType : false,
+ processData : false,
+ // if we don't add this, payload isn't processed as JSON
+ headers : { 'Accept': 'application/json' }
+ }).done(function( resp ){
+ response = resp;
+ });
+ // this works only bc jq is async
+ return response;
+ }, utils.format( this.urlTpls.create ), historyId, inputs );
+
+ if( !response ){
+ throw new APIError( 'Failed to upload: ' + options.filepath, 0 );
+ }
+
+ return response;
+};
+
+/** amount of time allowed to upload a file (before erroring) */
+ToolsAPI.prototype.DEFAULT_UPLOAD_TIMEOUT = 12000;
+
+/** add two casperjs steps - upload a file, wait for the job to complete, and run 'then' when they are */
+ToolsAPI.prototype.thenUpload = function thenUpload( historyId, options, then ){
+ var spaceghost = this.api.spaceghost,
+ uploadedId;
+
+ spaceghost.then( function(){
+ var returned = this.api.tools.upload( historyId, options );
+ this.debug( 'returned: ' + this.jsonStr( returned ) );
+ uploadedId = returned.outputs[0].id;
+ this.debug( 'uploadedId: ' + uploadedId );
+ });
+
+ spaceghost.then( function(){
+ this.waitFor(
+ function testHdaState(){
+ var hda = spaceghost.api.hdas.show( historyId, uploadedId );
+ spaceghost.debug( spaceghost.jsonStr( hda.state ) );
+ return !( hda.state === 'upload' || hda.state === 'queued' || hda.state === 'running' );
+ },
+ function _then(){
+ spaceghost.info( 'upload finished: ' + uploadedId );
+ if( then ){
+ then.call( spaceghost, uploadedId );
+ }
+ //var hda = spaceghost.api.hdas.show( historyId, uploadedId );
+ //spaceghost.debug( spaceghost.jsonStr( hda ) );
+ },
+ function timeout(){
+ throw new APIError( 'timeout uploading file', 408 );
+ },
+ options.timeout || spaceghost.api.tools.DEFAULT_UPLOAD_TIMEOUT
+ );
+ });
+ return spaceghost;
+};
+
+/** add two casperjs steps - upload multiple files (described in optionsArray) and wait for all jobs to complete */
+ToolsAPI.prototype.thenUploadMultiple = function thenUploadMultiple( historyId, optionsArray, then ){
+ var spaceghost = this.api.spaceghost,
+ uploadedIds = [];
+
+ this.api.spaceghost.then( function(){
+ var spaceghost = this;
+ optionsArray.forEach( function( options ){
+ var returned = spaceghost.api.tools.upload( historyId, options );
+ spaceghost.debug( 'uploaded:' + spaceghost.jsonStr( returned ) );
+ uploadedIds.push( returned.outputs[0].id );
+ });
+ });
+
+ // wait for every hda to finish running - IOW, don't use uploadedIds
+ this.api.spaceghost.then( function(){
+ this.debug( this.jsonStr( uploadedIds ) );
+ this.waitFor(
+ function testHdaStates(){
+ var hdas = spaceghost.api.hdas.index( historyId ),
+ running = hdas.filter( function( hda ){
+ return ( hda.state === 'upload' || hda.state === 'queued' || hda.state === 'running' );
+ }).map( function( hda ){
+ return hda.id;
+ });
+ //spaceghost.debug( 'still uploading: ' + spaceghost.jsonStr( running ) );
+ return running.length === 0;
+ },
+ function _then(){
+ var hdas = spaceghost.api.hdas.index( historyId );
+ spaceghost.debug( spaceghost.jsonStr( hdas ) );
+ if( then ){
+ then.call( spaceghost, uploadedIds );
+ }
+ },
+ function timeout(){
+ throw new APIError( 'timeout uploading files', 408 );
+ },
+ ( options.timeout || spaceghost.api.tools.DEFAULT_UPLOAD_TIMEOUT ) * optionsArray.length
+ );
+ });
+ return spaceghost;
+};
+
// =================================================================== WORKFLOWS
var WorkflowsAPI = function WorkflowsAPI( api ){
@@ -495,7 +785,7 @@
};
-// =================================================================== HISTORIES
+// =================================================================== VISUALIZATIONS
var VisualizationsAPI = function VisualizationsAPI( api ){
this.api = api;
};
diff -r c4950bc662256f013916b0aaabb73a47508213c5 -r 79ab14af25e4182dac99ecad3918ed653c50f272 test/casperjs/modules/user.js
--- a/test/casperjs/modules/user.js
+++ b/test/casperjs/modules/user.js
@@ -280,6 +280,9 @@
User.prototype.getRandomEmail = function getRandomEmail( username, domain ){
username = username || 'test';
domain = domain || 'test.test';
- return username + Date.now() + '@' + domain;
+ var number = Math.ceil( Math.random() * 10000000000000 );
+ // doesn't work so well when creating two users at once
+ //var number = Date.now();
+ return username + number + '@' + domain;
};
diff -r c4950bc662256f013916b0aaabb73a47508213c5 -r 79ab14af25e4182dac99ecad3918ed653c50f272 test/casperjs/spaceghost.js
--- a/test/casperjs/spaceghost.js
+++ b/test/casperjs/spaceghost.js
@@ -886,6 +886,30 @@
this.test.assert( classes.indexOf( className ) === -1, msg );
};
+/** Return true if object has all keys in keysArray (useful in API testing of return values).
+ * @param {Object} object the object to test
+ * @param {String[]} keysArray an array of expected keys
+ */
+SpaceGhost.prototype.hasKeys = function hasKeys( object, keysArray ){
+ if( !utils.isObject( object ) ){ return false; }
+ for( var i=0; i<keysArray.length; i += 1 ){
+ if( !object.hasOwnProperty( keysArray[i] ) ){
+ return false;
+ }
+ }
+ return true;
+};
+
+/** Returns count of keys in object. */
+SpaceGhost.prototype.countKeys = function countKeys( object ){
+ if( !utils.isObject( object ) ){ return 0; }
+ var count = 0;
+ for( var key in object ){
+ if( object.hasOwnProperty( key ) ){ count += 1; }
+ }
+ return count;
+};
+
// =================================================================== CONVENIENCE
/** Wraps casper.getElementInfo in try, returning null if element not found instead of erroring.
https://bitbucket.org/galaxy/galaxy-central/commits/561929fb2d7e/
Changeset: 561929fb2d7e
User: carlfeberhard
Date: 2014-03-25 22:00:03
Summary: merge
Affected #: 3 files
diff -r 79ab14af25e4182dac99ecad3918ed653c50f272 -r 561929fb2d7e827f20ea078904aeebe35173f3f9 static/scripts/viz/trackster/tracks.js
--- a/static/scripts/viz/trackster/tracks.js
+++ b/static/scripts/viz/trackster/tracks.js
@@ -1106,6 +1106,10 @@
});
// For vertical alignment, track mouse with simple line.
+ // Fixes needed for this to work:
+ // (a) make work with embedded visualizations;
+ // (b) seems to get stuck on tile overlaps.
+ /*
var mouse_tracker_div = $('<div/>').addClass('mouse-pos').appendTo(parent_element);
// Show tracker only when hovering over view.
@@ -1125,6 +1129,7 @@
mouse_tracker_div.hide();
}
);
+ */
this.add_label_track( new LabelTrack( this, { content_div: this.top_labeltrack } ) );
this.add_label_track( new LabelTrack( this, { content_div: this.nav_labeltrack } ) );
@@ -3053,14 +3058,21 @@
var tile_drawn = $.Deferred();
track.tile_cache.set_elt(key, tile_drawn);
$.when.apply($, get_tile_data()).then( function() {
- // If deferred objects ever show up in tile data, that is likely because a
- // Deferred-subsetting interaction failed. Specifically, a Deferred for a superset
- // was returned but then couldn't be used). It's not clear whether this will happen
- // in practice, and currently the code doesn't handle it. It could probably handle it
- // by recursively calling draw_helper.
var tile_data = get_tile_data(),
tracks_data = tile_data,
seq_data;
+
+ // Deferreds may show up here if trying to fetch a subset of data from a superset data chunk
+ // that cannot be subsetted. This may occur if the superset has a message. If there is a
+ // Deferred, try again from the top. NOTE: this condition could (should?) be handled by the
+ // GenomeDataManager in visualization module.
+ if (_.find(tile_data, function(d) { return util.is_deferred(d); })) {
+ track.tile_cache.set_elt(key, undefined);
+ $.when(track.draw_helper(region, w_scale, options)).then(function(tile) {
+ tile_drawn.resolve(tile);
+ });
+ return;
+ }
// If sequence data is available, subset to get only data in region.
if (view.reference_track) {
diff -r 79ab14af25e4182dac99ecad3918ed653c50f272 -r 561929fb2d7e827f20ea078904aeebe35173f3f9 static/scripts/viz/trackster/util.js
--- a/static/scripts/viz/trackster/util.js
+++ b/static/scripts/viz/trackster/util.js
@@ -1,6 +1,13 @@
define(function(){
/**
+ * Helper to determine if object is jQuery deferred.
+ */
+var is_deferred = function ( d ) {
+ return ('promise' in d);
+};
+
+/**
* Implementation of a server-state based deferred. Server is repeatedly polled, and when
* condition is met, deferred is resolved.
*/
@@ -109,6 +116,7 @@
};
return {
+ is_deferred: is_deferred,
ServerStateDeferred : ServerStateDeferred,
get_random_color : get_random_color
};
diff -r 79ab14af25e4182dac99ecad3918ed653c50f272 -r 561929fb2d7e827f20ea078904aeebe35173f3f9 static/scripts/viz/visualization.js
--- a/static/scripts/viz/visualization.js
+++ b/static/scripts/viz/visualization.js
@@ -86,14 +86,6 @@
});
};
-
-/**
- * Helper to determine if object is jQuery deferred.
- */
-var is_deferred = function ( d ) {
- return ('promise' in d);
-};
-
// --------- Models ---------
/**
@@ -380,11 +372,10 @@
* Get data from dataset.
*/
get_data: function(region, mode, resolution, extra_params) {
-
// Look for entry and return if it's a deferred or if data available is compatible with mode.
var entry = this.get_elt(region);
if ( entry &&
- ( is_deferred(entry) || this.get('data_mode_compatible')(entry, mode) ) ) {
+ ( util_mod.is_deferred(entry) || this.get('data_mode_compatible')(entry, mode) ) ) {
return entry;
}
@@ -405,12 +396,12 @@
// This entry has data in the requested range. Return if data
// is compatible and can be subsetted.
entry = obj_cache[entry_region.toString()];
- if ( is_deferred(entry) ||
+ if ( util_mod.is_deferred(entry) ||
( this.get('data_mode_compatible')(entry, mode) && this.get('can_subset')(entry) ) ) {
this.move_key_to_end(entry_region, i);
// If there's data, subset it.
- if ( !is_deferred(entry) ) {
+ if ( !util_mod.is_deferred(entry) ) {
var subset_entry = this.subset_entry(entry, region);
this.set(region, subset_entry);
entry = subset_entry;
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: Jeremy Goecks: Trackster: (a) fix bug when trying to subset from supersets with messages; (b) display vertical placeholder until bugs are resolved.
by commits-noreply@bitbucket.org 25 Mar '14
by commits-noreply@bitbucket.org 25 Mar '14
25 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/47211cedc8d0/
Changeset: 47211cedc8d0
User: Jeremy Goecks
Date: 2014-03-25 20:41:40
Summary: Trackster: (a) fix bug when trying to subset from supersets with messages; (b) display vertical placeholder until bugs are resolved.
Affected #: 3 files
diff -r 4d2f3398ad6d6eebfe084a184bf860dd7c6f9071 -r 47211cedc8d0db9a3d9189bc2d3bfa7e3fe11b86 static/scripts/viz/trackster/tracks.js
--- a/static/scripts/viz/trackster/tracks.js
+++ b/static/scripts/viz/trackster/tracks.js
@@ -1106,6 +1106,10 @@
});
// For vertical alignment, track mouse with simple line.
+ // Fixes needed for this to work:
+ // (a) make work with embedded visualizations;
+ // (b) seems to get stuck on tile overlaps.
+ /*
var mouse_tracker_div = $('<div/>').addClass('mouse-pos').appendTo(parent_element);
// Show tracker only when hovering over view.
@@ -1125,6 +1129,7 @@
mouse_tracker_div.hide();
}
);
+ */
this.add_label_track( new LabelTrack( this, { content_div: this.top_labeltrack } ) );
this.add_label_track( new LabelTrack( this, { content_div: this.nav_labeltrack } ) );
@@ -3053,14 +3058,21 @@
var tile_drawn = $.Deferred();
track.tile_cache.set_elt(key, tile_drawn);
$.when.apply($, get_tile_data()).then( function() {
- // If deferred objects ever show up in tile data, that is likely because a
- // Deferred-subsetting interaction failed. Specifically, a Deferred for a superset
- // was returned but then couldn't be used). It's not clear whether this will happen
- // in practice, and currently the code doesn't handle it. It could probably handle it
- // by recursively calling draw_helper.
var tile_data = get_tile_data(),
tracks_data = tile_data,
seq_data;
+
+ // Deferreds may show up here if trying to fetch a subset of data from a superset data chunk
+ // that cannot be subsetted. This may occur if the superset has a message. If there is a
+ // Deferred, try again from the top. NOTE: this condition could (should?) be handled by the
+ // GenomeDataManager in visualization module.
+ if (_.find(tile_data, function(d) { return util.is_deferred(d); })) {
+ track.tile_cache.set_elt(key, undefined);
+ $.when(track.draw_helper(region, w_scale, options)).then(function(tile) {
+ tile_drawn.resolve(tile);
+ });
+ return;
+ }
// If sequence data is available, subset to get only data in region.
if (view.reference_track) {
diff -r 4d2f3398ad6d6eebfe084a184bf860dd7c6f9071 -r 47211cedc8d0db9a3d9189bc2d3bfa7e3fe11b86 static/scripts/viz/trackster/util.js
--- a/static/scripts/viz/trackster/util.js
+++ b/static/scripts/viz/trackster/util.js
@@ -1,6 +1,13 @@
define(function(){
/**
+ * Helper to determine if object is jQuery deferred.
+ */
+var is_deferred = function ( d ) {
+ return ('promise' in d);
+};
+
+/**
* Implementation of a server-state based deferred. Server is repeatedly polled, and when
* condition is met, deferred is resolved.
*/
@@ -109,6 +116,7 @@
};
return {
+ is_deferred: is_deferred,
ServerStateDeferred : ServerStateDeferred,
get_random_color : get_random_color
};
diff -r 4d2f3398ad6d6eebfe084a184bf860dd7c6f9071 -r 47211cedc8d0db9a3d9189bc2d3bfa7e3fe11b86 static/scripts/viz/visualization.js
--- a/static/scripts/viz/visualization.js
+++ b/static/scripts/viz/visualization.js
@@ -86,14 +86,6 @@
});
};
-
-/**
- * Helper to determine if object is jQuery deferred.
- */
-var is_deferred = function ( d ) {
- return ('promise' in d);
-};
-
// --------- Models ---------
/**
@@ -380,11 +372,10 @@
* Get data from dataset.
*/
get_data: function(region, mode, resolution, extra_params) {
-
// Look for entry and return if it's a deferred or if data available is compatible with mode.
var entry = this.get_elt(region);
if ( entry &&
- ( is_deferred(entry) || this.get('data_mode_compatible')(entry, mode) ) ) {
+ ( util_mod.is_deferred(entry) || this.get('data_mode_compatible')(entry, mode) ) ) {
return entry;
}
@@ -405,12 +396,12 @@
// This entry has data in the requested range. Return if data
// is compatible and can be subsetted.
entry = obj_cache[entry_region.toString()];
- if ( is_deferred(entry) ||
+ if ( util_mod.is_deferred(entry) ||
( this.get('data_mode_compatible')(entry, mode) && this.get('can_subset')(entry) ) ) {
this.move_key_to_end(entry_region, i);
// If there's data, subset it.
- if ( !is_deferred(entry) ) {
+ if ( !util_mod.is_deferred(entry) ) {
var subset_entry = this.subset_entry(entry, region);
this.set(region, subset_entry);
entry = subset_entry;
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: Ui/Upload: Close modal on escape
by commits-noreply@bitbucket.org 25 Mar '14
by commits-noreply@bitbucket.org 25 Mar '14
25 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/4d2f3398ad6d/
Changeset: 4d2f3398ad6d
User: guerler
Date: 2014-03-25 19:01:26
Summary: Ui/Upload: Close modal on escape
Affected #: 2 files
diff -r 208533b58c7e135e99a74e7cf5183a63020b3341 -r 4d2f3398ad6d6eebfe084a184bf860dd7c6f9071 static/scripts/mvc/ui/ui-modal.js
--- a/static/scripts/mvc/ui/ui-modal.js
+++ b/static/scripts/mvc/ui/ui-modal.js
@@ -115,7 +115,7 @@
this.$el.remove();
// remove escape event
- $(document).off('keyup');
+ $(document).off('keyup.ui-modal');
}
// create new element
@@ -157,13 +157,11 @@
// bind additional closing events
if (this.options.closing_events) {
// bind the ESC key to hide() function
- if (!this.options.buttons.Pause){ // don't bind for the upload modal because of the side effects with system modal for file choosing
- $(document).on('keyup', function(e) {
- if (e.keyCode == 27) {
- self.hide();
- }
- });
- }
+ $(document).on('keyup.ui-modal', function(e) {
+ if (e.keyCode == 27) {
+ self.hide();
+ }
+ });
// hide modal if background is clicked
this.$el.find('.modal-backdrop').on('click', function() { self.hide(); });
diff -r 208533b58c7e135e99a74e7cf5183a63020b3341 -r 4d2f3398ad6d6eebfe084a184bf860dd7c6f9071 static/scripts/packed/mvc/ui/ui-modal.js
--- a/static/scripts/packed/mvc/ui/ui-modal.js
+++ b/static/scripts/packed/mvc/ui/ui-modal.js
@@ -1,1 +1,1 @@
-define(["utils/utils"],function(a){var b=Backbone.View.extend({elMain:"body",optionsDefault:{title:"ui-modal",body:"",backdrop:true,height:null,width:null,closing_events:false},buttonList:{},initialize:function(c){if(c){this._create(c)}},show:function(c){this.initialize(c);if(this.options.height){this.$body.css("height",this.options.height);this.$body.css("overflow","hidden")}else{this.$body.css("max-height",$(window).height()/2)}if(this.options.width){this.$dialog.css("width",this.options.width)}if(this.visible){this.$el.show()}else{this.$el.fadeIn("fast")}this.visible=true},hide:function(){this.visible=false;this.$el.fadeOut("fast")},enableButton:function(c){var d=this.buttonList[c];this.$buttons.find("#"+d).prop("disabled",false)},disableButton:function(c){var d=this.buttonList[c];this.$buttons.find("#"+d).prop("disabled",true)},showButton:function(c){var d=this.buttonList[c];this.$buttons.find("#"+d).show()},hideButton:function(c){var d=this.buttonList[c];this.$buttons.find("#"+d).hide()},getButton:function(c){var d=this.buttonList[c];return this.$buttons.find("#"+d)},scrollTop:function(){return this.$body.scrollTop()},_create:function(e){var d=this;this.options=_.defaults(e,this.optionsDefault);if(this.options.body=="progress"){this.options.body=$('<div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width:100%"></div></div>')}if(this.$el){this.$el.remove();$(document).off("keyup")}this.setElement(this._template(this.options.title));this.$dialog=(this.$el).find(".modal-dialog");this.$body=(this.$el).find(".modal-body");this.$footer=(this.$el).find(".modal-footer");this.$buttons=(this.$el).find(".buttons");this.$backdrop=(this.$el).find(".modal-backdrop");this.$body.html(this.options.body);if(!this.options.backdrop){this.$backdrop.removeClass("in")}if(this.options.buttons){this.buttonList={};var c=0;$.each(this.options.buttons,function(f,h){var g="button-"+c++;d.$buttons.append($('<button id="'+g+'"></button>').text(f).click(h)).append(" ");d.buttonList[f]=g})}else{this.$footer.hide()}$(this.elMain).append($(this.el));if(this.options.closing_events){if(!this.options.buttons.Pause){$(document).on("keyup",function(f){if(f.keyCode==27){d.hide()}})}this.$el.find(".modal-backdrop").on("click",function(){d.hide()})}},_template:function(c){return'<div class="modal"><div class="modal-backdrop fade in" style="z-index: -1;"></div><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" style="display: none;">×</button><h4 class="title">'+c+'</h4></div><div class="modal-body" style="position: static;"></div><div class="modal-footer"><div class="buttons" style="float: right;"></div></div></div</div></div>'}});return{View:b}});
\ No newline at end of file
+define(["utils/utils"],function(a){var b=Backbone.View.extend({elMain:"body",optionsDefault:{title:"ui-modal",body:"",backdrop:true,height:null,width:null,closing_events:false},buttonList:{},initialize:function(c){if(c){this._create(c)}},show:function(c){this.initialize(c);if(this.options.height){this.$body.css("height",this.options.height);this.$body.css("overflow","hidden")}else{this.$body.css("max-height",$(window).height()/2)}if(this.options.width){this.$dialog.css("width",this.options.width)}if(this.visible){this.$el.show()}else{this.$el.fadeIn("fast")}this.visible=true},hide:function(){this.visible=false;this.$el.fadeOut("fast")},enableButton:function(c){var d=this.buttonList[c];this.$buttons.find("#"+d).prop("disabled",false)},disableButton:function(c){var d=this.buttonList[c];this.$buttons.find("#"+d).prop("disabled",true)},showButton:function(c){var d=this.buttonList[c];this.$buttons.find("#"+d).show()},hideButton:function(c){var d=this.buttonList[c];this.$buttons.find("#"+d).hide()},getButton:function(c){var d=this.buttonList[c];return this.$buttons.find("#"+d)},scrollTop:function(){return this.$body.scrollTop()},_create:function(e){var d=this;this.options=_.defaults(e,this.optionsDefault);if(this.options.body=="progress"){this.options.body=$('<div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width:100%"></div></div>')}if(this.$el){this.$el.remove();$(document).off("keyup.ui-modal")}this.setElement(this._template(this.options.title));this.$dialog=(this.$el).find(".modal-dialog");this.$body=(this.$el).find(".modal-body");this.$footer=(this.$el).find(".modal-footer");this.$buttons=(this.$el).find(".buttons");this.$backdrop=(this.$el).find(".modal-backdrop");this.$body.html(this.options.body);if(!this.options.backdrop){this.$backdrop.removeClass("in")}if(this.options.buttons){this.buttonList={};var c=0;$.each(this.options.buttons,function(f,h){var g="button-"+c++;d.$buttons.append($('<button id="'+g+'"></button>').text(f).click(h)).append(" ");d.buttonList[f]=g})}else{this.$footer.hide()}$(this.elMain).append($(this.el));if(this.options.closing_events){$(document).on("keyup.ui-modal",function(f){if(f.keyCode==27){d.hide()}});this.$el.find(".modal-backdrop").on("click",function(){d.hide()})}},_template:function(c){return'<div class="modal"><div class="modal-backdrop fade in" style="z-index: -1;"></div><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" style="display: none;">×</button><h4 class="title">'+c+'</h4></div><div class="modal-body" style="position: static;"></div><div class="modal-footer"><div class="buttons" style="float: right;"></div></div></div</div></div>'}});return{View:b}});
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: davebgx: Fix server error when attempting to create a repository before any categories have been created.
by commits-noreply@bitbucket.org 25 Mar '14
by commits-noreply@bitbucket.org 25 Mar '14
25 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/208533b58c7e/
Changeset: 208533b58c7e
User: davebgx
Date: 2014-03-25 18:25:19
Summary: Fix server error when attempting to create a repository before any categories have been created.
Affected #: 1 file
diff -r cab5878ce755b1736d09a9a74e419eddb12c0f2d -r 208533b58c7e135e99a74e7cf5183a63020b3341 lib/galaxy/webapps/tool_shed/controllers/repository.py
--- a/lib/galaxy/webapps/tool_shed/controllers/repository.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py
@@ -950,7 +950,7 @@
categories = suc.get_categories( trans )
if not categories:
message = 'No categories have been configured in this instance of the Galaxy Tool Shed. '
- message += 'An administrator needs to create some via the Administrator control panel before creating repositories.',
+ message += 'An administrator needs to create some via the Administrator control panel before creating repositories.'
status = 'error'
return trans.response.send_redirect( web.url_for( controller='repository',
action='browse_repositories',
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: Charts: Improve fit and chart state handling, recalculate chart only if neccessary
by commits-noreply@bitbucket.org 25 Mar '14
by commits-noreply@bitbucket.org 25 Mar '14
25 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/cab5878ce755/
Changeset: cab5878ce755
User: guerler
Date: 2014-03-25 13:35:20
Summary: Charts: Improve fit and chart state handling, recalculate chart only if neccessary
Affected #: 9 files
diff -r ec715604b476c47703b90385062a6ec482cfd302 -r cab5878ce755b1736d09a9a74e419eddb12c0f2d config/plugins/visualizations/charts/static/build-app.js
--- a/config/plugins/visualizations/charts/static/build-app.js
+++ b/config/plugins/visualizations/charts/static/build-app.js
@@ -3,4 +3,4 @@
// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore may be freely distributed under the MIT license.
-(function(){var e=this,t=e._,n={},r=Array.prototype,i=Object.prototype,s=Function.prototype,o=r.push,u=r.slice,a=r.concat,f=i.toString,l=i.hasOwnProperty,c=r.forEach,h=r.map,p=r.reduce,d=r.reduceRight,v=r.filter,m=r.every,g=r.some,y=r.indexOf,b=r.lastIndexOf,w=Array.isArray,E=Object.keys,S=s.bind,x=function(e){if(e instanceof x)return e;if(!(this instanceof x))return new x(e);this._wrapped=e};typeof exports!="undefined"?(typeof module!="undefined"&&module.exports&&(exports=module.exports=x),exports._=x):e._=x,x.VERSION="1.4.4";var T=x.each=x.forEach=function(e,t,r){if(e==null)return;if(c&&e.forEach===c)e.forEach(t,r);else if(e.length===+e.length){for(var i=0,s=e.length;i<s;i++)if(t.call(r,e[i],i,e)===n)return}else for(var o in e)if(x.has(e,o)&&t.call(r,e[o],o,e)===n)return};x.map=x.collect=function(e,t,n){var r=[];return e==null?r:h&&e.map===h?e.map(t,n):(T(e,function(e,i,s){r.push(t.call(n,e,i,s))}),r)};var N="Reduce of empty array with no initial value";x.reduce=x.foldl=x.inject=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(p&&e.reduce===p)return r&&(t=x.bind(t,r)),i?e.reduce(t,n):e.reduce(t);T(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError(N);return n},x.reduceRight=x.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(d&&e.reduceRight===d)return r&&(t=x.bind(t,r)),i?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=x.keys(e);s=o.length}T(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError(N);return n},x.find=x.detect=function(e,t,n){var r;return C(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},x.filter=x.select=function(e,t,n){var r=[];return e==null?r:v&&e.filter===v?e.filter(t,n):(T(e,function(e,i,s){t.call(n,e,i,s)&&r.push(e)}),r)},x.reject=function(e,t,n){return x.filter(e,function(e,r,i){return!t.call(n,e,r,i)},n)},x.every=x.all=function(e,t,r){t||(t=x.identity);var i=!0;return e==null?i:m&&e.every===m?e.every(t,r):(T(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var C=x.some=x.any=function(e,t,r){t||(t=x.identity);var i=!1;return e==null?i:g&&e.some===g?e.some(t,r):(T(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};x.contains=x.include=function(e,t){return e==null?!1:y&&e.indexOf===y?e.indexOf(t)!=-1:C(e,function(e){return e===t})},x.invoke=function(e,t){var n=u.call(arguments,2),r=x.isFunction(t);return x.map(e,function(e){return(r?t:e[t]).apply(e,n)})},x.pluck=function(e,t){return x.map(e,function(e){return e[t]})},x.where=function(e,t,n){return x.isEmpty(t)?n?void 0:[]:x[n?"find":"filter"](e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},x.findWhere=function(e,t){return x.where(e,t,!0)},x.max=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&x.isEmpty(e))return-Infinity;var r={computed:-Infinity,value:-Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},x.min=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&x.isEmpty(e))return Infinity;var r={computed:Infinity,value:Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o<r.computed&&(r={value:e,computed:o})}),r.value},x.shuffle=function(e){var t,n=0,r=[];return T(e,function(e){t=x.random(n++),r[n-1]=r[t],r[t]=e}),r};var k=function(e){return x.isFunction(e)?e:function(t){return t[e]}};x.sortBy=function(e,t,n){var r=k(t);return x.pluck(x.map(e,function(e,t,i){return{value:e,index:t,criteria:r.call(n,e,t,i)}}).sort(function(e,t){var n=e.criteria,r=t.criteria;if(n!==r){if(n>r||n===void 0)return 1;if(n<r||r===void 0)return-1}return e.index<t.index?-1:1}),"value")};var L=function(e,t,n,r){var i={},s=k(t==null?x.identity:t);return T(e,function(t,o){var u=s.call(n,t,o,e);r(i,u,t)}),i};x.groupBy=function(e,t,n){return L(e,t,n,function(e,t,n){(x.has(e,t)?e[t]:e[t]=[]).push(n)})},x.countBy=function(e,t,n){return L(e,t,n,function(e,t){x.has(e,t)||(e[t]=0),e[t]++})},x.sortedIndex=function(e,t,n,r){n=n==null?x.identity:k(n);var i=n.call(r,t),s=0,o=e.length;while(s<o){var u=s+o>>>1;n.call(r,e[u])<i?s=u+1:o=u}return s},x.toArray=function(e){return e?x.isArray(e)?u.call(e):e.length===+e.length?x.map(e,x.identity):x.values(e):[]},x.size=function(e){return e==null?0:e.length===+e.length?e.length:x.keys(e).length},x.first=x.head=x.take=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,0,t):e[0]},x.initial=function(e,t,n){return u.call(e,0,e.length-(t==null||n?1:t))},x.last=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,Math.max(e.length-t,0)):e[e.length-1]},x.rest=x.tail=x.drop=function(e,t,n){return u.call(e,t==null||n?1:t)},x.compact=function(e){return x.filter(e,x.identity)};var A=function(e,t,n){return T(e,function(e){x.isArray(e)?t?o.apply(n,e):A(e,t,n):n.push(e)}),n};x.flatten=function(e,t){return A(e,t,[])},x.without=function(e){return x.difference(e,u.call(arguments,1))},x.uniq=x.unique=function(e,t,n,r){x.isFunction(t)&&(r=n,n=t,t=!1);var i=n?x.map(e,n,r):e,s=[],o=[];return T(i,function(n,r){if(t?!r||o[o.length-1]!==n:!x.contains(o,n))o.push(n),s.push(e[r])}),s},x.union=function(){return x.uniq(a.apply(r,arguments))},x.intersection=function(e){var t=u.call(arguments,1);return x.filter(x.uniq(e),function(e){return x.every(t,function(t){return x.indexOf(t,e)>=0})})},x.difference=function(e){var t=a.apply(r,u.call(arguments,1));return x.filter(e,function(e){return!x.contains(t,e)})},x.zip=function(){var e=u.call(arguments),t=x.max(x.pluck(e,"length")),n=new Array(t);for(var r=0;r<t;r++)n[r]=x.pluck(e,""+r);return n},x.unzip=function(e){var t=[];return x.each(e,function(e,n){x.each(e,function(e,r){t.length<=r&&(t[r]=[]),t[r][n]=e})}),t},x.object=function(e,t){if(e==null)return{};var n={};for(var r=0,i=e.length;r<i;r++)t?n[e[r]]=t[r]:n[e[r][0]]=e[r][1];return n},x.indexOf=function(e,t,n){if(e==null)return-1;var r=0,i=e.length;if(n){if(typeof n!="number")return r=x.sortedIndex(e,t),e[r]===t?r:-1;r=n<0?Math.max(0,i+n):n}if(y&&e.indexOf===y)return e.indexOf(t,n);for(;r<i;r++)if(e[r]===t)return r;return-1},x.lastIndexOf=function(e,t,n){if(e==null)return-1;var r=n!=null;if(b&&e.lastIndexOf===b)return r?e.lastIndexOf(t,n):e.lastIndexOf(t);var i=r?n:e.length;while(i--)if(e[i]===t)return i;return-1},x.range=function(e,t,n){arguments.length<=1&&(t=e||0,e=0),n=arguments[2]||1;var r=Math.max(Math.ceil((t-e)/n),0),i=0,s=new Array(r);while(i<r)s[i++]=e,e+=n;return s};var O=function(){};x.bind=function(e,t){var n,r;if(e.bind===S&&S)return S.apply(e,u.call(arguments,1));if(!x.isFunction(e))throw new TypeError;return n=u.call(arguments,2),r=function(){if(this instanceof r){O.prototype=e.prototype;var i=new O;O.prototype=null;var s=e.apply(i,n.concat(u.call(arguments)));return Object(s)===s?s:i}return e.apply(t,n.concat(u.call(arguments)))}},x.partial=function(e){var t=u.call(arguments,1);return function(){return e.apply(this,t.concat(u.call(arguments)))}},x.bindAll=function(e){var t=u.call(arguments,1);if(t.length===0)throw new Error("bindAll must be passed function names");return T(t,function(t){e[t]=x.bind(e[t],e)}),e},x.memoize=function(e,t){var n={};return t||(t=x.identity),function(){var r=t.apply(this,arguments);return x.has(n,r)?n[r]:n[r]=e.apply(this,arguments)}},x.delay=function(e,t){var n=u.call(arguments,2);return setTimeout(function(){return e.apply(null,n)},t)},x.defer=function(e){return x.delay.apply(x,[e,1].concat(u.call(arguments,1)))},x.throttle=function(e,t,n){var r,i,s,o,u=0,a=function(){u=new Date,s=null,o=e.apply(r,i)};return function(){var f=new Date;!u&&n===!1&&(u=f);var l=t-(f-u);return r=this,i=arguments,l<=0?(clearTimeout(s),s=null,u=f,o=e.apply(r,i)):s||(s=setTimeout(a,l)),o}},x.debounce=function(e,t,n){var r,i;return function(){var s=this,o=arguments,u=function(){r=null,n||(i=e.apply(s,o))},a=n&&!r;return clearTimeout(r),r=setTimeout(u,t),a&&(i=e.apply(s,o)),i}},x.once=function(e){var t=!1,n;return function(){return t?n:(t=!0,n=e.apply(this,arguments),e=null,n)}},x.wrap=function(e,t){return function(){var n=[e];return o.apply(n,arguments),t.apply(this,n)}},x.compose=function(){var e=arguments;return function(){var t=arguments;for(var n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},x.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},x.keys=E||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)x.has(e,n)&&t.push(n);return t},x.values=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push(e[n]);return t},x.pairs=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push([n,e[n]]);return t},x.invert=function(e){var t={};for(var n in e)x.has(e,n)&&(t[e[n]]=n);return t},x.functions=x.methods=function(e){var t=[];for(var n in e)x.isFunction(e[n])&&t.push(n);return t.sort()},x.extend=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]=t[n]}),e},x.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return T(n,function(n){n in e&&(t[n]=e[n])}),t},x.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)x.contains(n,i)||(t[i]=e[i]);return t},x.defaults=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]===void 0&&(e[n]=t[n])}),e},x.clone=function(e){return x.isObject(e)?x.isArray(e)?e.slice():x.extend({},e):e},x.tap=function(e,t){return t(e),e};var M=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof x&&(e=e._wrapped),t instanceof x&&(t=t._wrapped);var i=f.call(e);if(i!=f.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=M(e[o],t[o],n,r)))break}else{var a=e.constructor,l=t.constructor;if(a!==l&&!(x.isFunction(a)&&a instanceof a&&x.isFunction(l)&&l instanceof l))return!1;for(var c in e)if(x.has(e,c)){o++;if(!(u=x.has(t,c)&&M(e[c],t[c],n,r)))break}if(u){for(c in t)if(x.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};x.isEqual=function(e,t){return M(e,t,[],[])},x.isEmpty=function(e){if(e==null)return!0;if(x.isArray(e)||x.isString(e))return e.length===0;for(var t in e)if(x.has(e,t))return!1;return!0},x.isElement=function(e){return!!e&&e.nodeType===1},x.isArray=w||function(e){return f.call(e)=="[object Array]"},x.isObject=function(e){return e===Object(e)},T(["Arguments","Function","String","Number","Date","RegExp"],function(e){x["is"+e]=function(t){return f.call(t)=="[object "+e+"]"}}),x.isArguments(arguments)||(x.isArguments=function(e){return!!e&&!!x.has(e,"callee")}),typeof /./!="function"&&(x.isFunction=function(e){return typeof e=="function"}),x.isFinite=function(e){return isFinite(e)&&!isNaN(parseFloat(e))},x.isNaN=function(e){return x.isNumber(e)&&e!=+e},x.isBoolean=function(e){return e===!0||e===!1||f.call(e)=="[object Boolean]"},x.isNull=function(e){return e===null},x.isUndefined=function(e){return e===void 0},x.has=function(e,t){return l.call(e,t)},x.noConflict=function(){return e._=t,this},x.identity=function(e){return e},x.times=function(e,t,n){var r=Array(e);for(var i=0;i<e;i++)r[i]=t.call(n,i);return r},x.random=function(e,t){return t==null&&(t=e,e=0),e+Math.floor(Math.random()*(t-e+1))};var _={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};_.unescape=x.invert(_.escape);var D={escape:new RegExp("["+x.keys(_.escape).join("")+"]","g"),unescape:new RegExp("("+x.keys(_.unescape).join("|")+")","g")};x.each(["escape","unescape"],function(e){x[e]=function(t){return t==null?"":(""+t).replace(D[e],function(t){return _[e][t]})}}),x.result=function(e,t){if(e==null)return void 0;var n=e[t];return x.isFunction(n)?n.call(e):n},x.mixin=function(e){T(x.functions(e),function(t){var n=x[t]=e[t];x.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),F.call(this,n.apply(x,e))}})};var P=0;x.uniqueId=function(e){var t=++P+"";return e?e+t:t},x.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var H=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},j=/\\|'|\r|\n|\t|\u2028|\u2029/g;x.template=function(e,t,n){var r;n=x.defaults({},n,x.templateSettings);var i=new RegExp([(n.escape||H).source,(n.interpolate||H).source,(n.evaluate||H).source].join("|")+"|$","g"),s=0,o="__p+='";e.replace(i,function(t,n,r,i,u){return o+=e.slice(s,u).replace(j,function(e){return"\\"+B[e]}),n&&(o+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'"),r&&(o+="'+\n((__t=("+r+"))==null?'':__t)+\n'"),i&&(o+="';\n"+i+"\n__p+='"),s=u+t.length,t}),o+="';\n",n.variable||(o="with(obj||{}){\n"+o+"}\n"),o="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+o+"return __p;\n";try{r=new Function(n.variable||"obj","_",o)}catch(u){throw u.source=o,u}if(t)return r(t,x);var a=function(e){return r.call(this,e,x)};return a.source="function("+(n.variable||"obj")+"){\n"+o+"}",a},x.chain=function(e){return x(e).chain()};var F=function(e){return this._chain?x(e).chain():e};x.mixin(x),T(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];x.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],F.call(this,n)}}),T(["concat","join","slice"],function(e){var t=r[e];x.prototype[e]=function(){return F.call(this,t.apply(this._wrapped,arguments))}}),x.extend(x.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this),define("libs/underscore",function(e){return function(){var t,n;return t||e._}}(this)),define("utils/utils",["libs/underscore"],function(e){function t(e,t,r){n("GET",e,{},t,r)}function n(e,t,n,r,i){if(e=="GET"||e=="DELETE")t.indexOf("?")==-1?t+="?":t+="&",t+=$.param(n);var s=new XMLHttpRequest;s.open(e,t,!0),s.setRequestHeader("Accept","application/json"),s.setRequestHeader("Cache-Control","no-cache"),s.setRequestHeader("X-Requested-With","XMLHttpRequest"),s.setRequestHeader("Content-Type","application/json"),s.onloadend=function(){var e=s.status;try{response=jQuery.parseJSON(s.responseText)}catch(t){response=s.responseText}e==200?r&&r(response):i&&i(response)},e=="GET"||e=="DELETE"?s.send():s.send(JSON.stringify(n))}function r(e,t){var n=$('<div class="'+e+'"></div>');n.appendTo(":eq(0)");var r=n.css(t);return n.remove(),r}function i(e){$('link[href^="'+e+'"]').length||$('<link href="'+galaxy_config.root+e+'" rel="stylesheet">').appendTo("head")}function s(t,n){return t?e.defaults(t,n):n}function o(e,t){var n="";if(e>=1e11)e/=1e11,n="TB";else if(e>=1e8)e/=1e8,n="GB";else if(e>=1e5)e/=1e5,n="MB";else if(e>=100)e/=100,n="KB";else{if(!(e>0))return"<strong>-</strong>";e*=10,n="b"}var r=Math.round(e)/10;return t?r+" "+n:"<strong>"+r+"</strong> "+n}function u(){return(new Date).getTime().toString(36)}function a(e){var t=$("<p></p>");return t.append(e),t}function f(){var e=new Date,t=(e.getHours()<10?"0":"")+e.getHours(),n=(e.getMinutes()<10?"0":"")+e.getMinutes(),r=e.getDate()+"/"+(e.getMonth()+1)+"/"+e.getFullYear()+", "+t+":"+n;return r}return{cssLoadFile:i,cssGetAttribute:r,get:t,merge:s,bytesToString:o,uuid:u,time:f,wrap:a,request:n}}),define("mvc/ui/ui-modal",["utils/utils"],function(e){var t=Backbone.View.extend({elMain:"body",optionsDefault:{title:"ui-modal",body:"",backdrop:!0,height:null,width:null,closing_events:!1},buttonList:{},initialize:function(e){e&&this._create(e)},show:function(e){this.initialize(e),this.options.height?(this.$body.css("height",this.options.height),this.$body.css("overflow","hidden")):this.$body.css("max-height",$(window).height()/2),this.options.width&&this.$dialog.css("width",this.options.width),this.visible?this.$el.show():this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.visible=!1,this.$el.fadeOut("fast")},enableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!1)},disableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!0)},showButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).show()},hideButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).hide()},getButton:function(e){var t=this.buttonList[e];return this.$buttons.find("#"+t)},scrollTop:function(){return this.$body.scrollTop()},_create:function(e){var t=this;this.options=_.defaults(e,this.optionsDefault),this.options.body=="progress"&&(this.options.body=$('<div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width:100%"></div></div>')),this.$el&&(this.$el.remove(),$(document).off("keyup")),this.setElement(this._template(this.options.title)),this.$dialog=this.$el.find(".modal-dialog"),this.$body=this.$el.find(".modal-body"),this.$footer=this.$el.find(".modal-footer"),this.$buttons=this.$el.find(".buttons"),this.$backdrop=this.$el.find(".modal-backdrop"),this.$body.html(this.options.body),this.options.backdrop||this.$backdrop.removeClass("in");if(this.options.buttons){this.buttonList={};var n=0;$.each(this.options.buttons,function(e,r){var i="button-"+n++;t.$buttons.append($('<button id="'+i+'"></button>').text(e).click(r)).append(" "),t.buttonList[e]=i})}else this.$footer.hide();$(this.elMain).append($(this.el)),this.options.closing_events&&(this.options.buttons.Pause||$(document).on("keyup",function(e){e.keyCode==27&&t.hide()}),this.$el.find(".modal-backdrop").on("click",function(){t.hide()}))},_template:function(e){return'<div class="modal"><div class="modal-backdrop fade in" style="z-index: -1;"></div><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" style="display: none;">×</button><h4 class="title">'+e+"</h4>"+"</div>"+'<div class="modal-body" style="position: static;"></div>'+'<div class="modal-footer">'+'<div class="buttons" style="float: right;"></div>'+"</div>"+"</div"+"</div>"+"</div>"}});return{View:t}}),define("mvc/ui/ui-portlet",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,optionsDefault:{title:"",icon:"",buttons:null,body:null,height:null,operations:null,placement:"bottom",overflow:"auto"},$title:null,$content:null,$buttons:null,$operations:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$content=this.$el.find("#content"),this.$title=this.$el.find("#title-text"),this.options.height&&(this.$el.find("#body").css("height",this.options.height),this.$el.find("#content").css("overflow",this.options.overflow)),this.$buttons=$(this.el).find("#buttons");if(this.options.buttons){var n=this;$.each(this.options.buttons,function(e,t){t.$el.prop("id",e),n.$buttons.append(t.$el)})}else this.$buttons.remove();this.$operations=$(this.el).find("#operations");if(this.options.operations){var n=this;$.each(this.options.operations,function(e,t){t.$el.prop("id",e),n.$operations.append(t.$el)})}this.options.body&&this.append(this.options.body)},append:function(t){this.$content.append(e.wrap(t))},content:function(){return this.$content},show:function(){this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},enableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!1)},disableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!0)},hideOperation:function(e){this.$operations.find("#"+e).hide()},showOperation:function(e){this.$operations.find("#"+e).show()},setOperation:function(e,t){var n=this.$operations.find("#"+e);n.off("click"),n.on("click",t)},title:function(e){var t=this.$title;return e&&t.html(e),t.html()},_template:function(e){var t='<div class="toolForm portlet-view no-highlight">';if(e.title||e.icon)t+='<div id="title" class="toolFormTitle portlet-title"><div id="operations" class="portlet-operations"/><div style="overflow: hidden;">',e.icon&&(t+='<div class="portlet-title-icon fa '+e.icon+'"> </div>'),t+='<div id="title-text" class="portlet-title-text">'+e.title+"</div>",t+="</div></div>";return t+='<div id="body" class="toolFormBody portlet-body">',e.placement=="top"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+='<div id="content" class="portlet-content"/>',e.placement=="bottom"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+="</div></div>",t}});return{View:t}}),define("plugin/library/ui-select",["utils/utils"],function(e){var t=Backbone.View.extend({optionsDefault:{id:"",cls:"",empty:"No data available",visible:!0,wait:!1},selected:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$select=this.$el.find("#select"),this.$icon=this.$el.find("#icon"),this.selected=this.options.value;var n=this;this.options.onchange&&this.$select.on("change",function(){n.value(n.$select.val())}),this._refresh(),this.options.visible||this.hide(),this.options.wait?this.wait():this.show()},value:function(e){var t=this.selected;e!==undefined&&(this.selected=e,this.$select.val(e));var n=this.selected;return n&&n!=t&&this.options.onchange&&this.options.onchange(n),n},text:function(){return this.$select.find("option:selected").text()},show:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-caret-down"),this.$select.show(),this.$el.show()},hide:function(){this.$el.hide()},wait:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-spinner fa-spin"),this.$select.hide()},disabled:function(){return this.$select.is(":disabled")},enable:function(){this.$select.prop("disabled",!1)},disable:function(){this.$select.prop("disabled",!0)},add:function(e){this.$select.append(this._templateOption(e)),this._refresh()},del:function(e){this.$select.find("option[value="+e+"]").remove(),this.$select.trigger("change"),this._refresh()},update:function(e){this.$select.find("option").remove();for(var t in e)this.$select.append(this._templateOption(e[t]));!this.selected&&e.length>0&&this.value(e[0].value),this._refresh()},_refresh:function(){this.$select.find("option[value=null]").remove();var e=this.$select.find("option").length;e==0?(this.$select.append(this._templateOption({value:"null",label:this.options.empty})),this.disable()):(this.enable(),this.selected&&this.$select.val(this.selected))},_exists:function(e){return 0!=this.$select.find("option[value="+e+"]").length},_templateOption:function(e){return'<option value="'+e.value+'">'+e.label+"</option>"},_template:function(e){var t='<div id="'+e.id+'" class="styled-select">'+'<div class="button">'+'<i id="icon"/>'+"</div>"+'<select id="select" class="select '+e.cls+" "+e.id+'">';for(key in e.data){var n=e.data[key],r="";if(n.value==e.value||n.value=="")r="selected";t+='<option value="'+n.value+'" '+r+">"+n.label+"</option>"}return t+="</select></div>",t}});return{View:t}}),define("plugin/library/ui",["utils/utils","plugin/library/ui-select"],function(e,t){var n=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options))},title:function(e){this.$el.find("b").html(e)},_template:function(e){return"<label><b>"+e.title+"</b></label>"},value:function(){return options.title}}),r=Backbone.View.extend({optionsDefault:{id:null,title:"","float":"right",cls:"btn-default",icon:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t='<button id="'+e.id+'" type="submit" style="margin-right: 5px; float: '+e.float+';" type="button" class="btn '+e.cls+'">';return e.icon&&(t+='<i class="icon fa '+e.icon+'"></i> '),t+=e.title+"</button>",t}}),i=Backbone.View.extend({optionsDefault:{"float":"right",icon:"",tooltip:"",placement:"bottom",title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){return'<div><span class="fa '+e.icon+'" style="font-size: 1.2em;"/> '+e.title+"</div>"}}),s=Backbone.View.extend({optionsDefault:{title:"",id:null,"float":"right",cls:"icon-btn",icon:"",tooltip:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t="";e.title&&(t="width: auto;");var n='<div id="'+e.id+'" style="margin-right: 5px; float: '+e.float+"; "+t+'" class="'+e.cls+'">';return e.title?n+='<div style="margin-right: 5px; margin-left: 5px;"><i class="icon fa '+e.icon+'"/> '+'<span style="position: relative; font-size: 0.8em; font-weight: normal; top: -1px;">'+e.title+"</span>"+"</div>":n+='<i class="icon fa '+e.icon+'"/>',n+="</div>",n}}),o=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick)},_template:function(e){return'<div><a href="javascript:void(0)">'+e.title+"</a></div>"}}),u=Backbone.View.extend({optionsDefault:{message:"",status:"info",persistent:!1},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement("<div></div>")},update:function(t){this.options=e.merge(t,this.optionsDefault);if(t.message!=""){this.$el.html(this._template(this.options)),this.$el.fadeIn();if(!t.persistent){var n=this;window.setTimeout(function(){n.$el.is(":visible")?n.$el.fadeOut():n.$el.hide()},3e3)}}else this.$el.fadeOut()},_template:function(e){return'<div class="alert alert-'+e.status+'" style="padding: 2px 2px 2px 10px;">'+e.message+"</div>"}}),a=Backbone.View.extend({optionsDefault:{onclick:null,searchword:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options));var n=this;this.options.onclick&&this.$el.on("submit",function(e){var t=n.$el.find("#search");n.options.onclick(t.val())})},_template:function(e){return'<div class="search"><form onsubmit="return false;"><input id="search" class="form-control input-sm" type="text" name="search" placeholder="Search..." value="'+e.searchword+'">'+'<button type="submit" class="btn search-btn">'+'<i class="fa fa-search"></i>'+"</button>"+"</form>"+"</div>"}}),f=Backbone.View.extend({optionsDefault:{title:"Unlabeled",body:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.body&&this.$el.find(".body").append(this.options.body)},_template:function(e){return'<div id="title" class="title">'+e.title+":"+"</div>"}}),l=Backbone.View.extend({optionsDefault:{id:"",title:"",target:"",href:"",onunload:null,onclick:null,visible:!0,icon:null,tag:""},$menu:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement($(this._template(this.options)));var n=$(this.el).find(".root"),r=this;n.on("click",function(e){e.preventDefault(),r.options.onclick&&r.options.onclick()}),this.options.visible||this.hide()},show:function(){$(this.el).show()},hide:function(){$(this.el).hide()},addMenu:function(t){var n={title:"",target:"",href:"",onclick:null,divider:!1,icon:null};n=e.merge(t,n),this.$menu||($(this.el).append(this._templateMenu()),this.$menu=$(this.el).find(".menu"));var r=$(this._templateMenuItem(n));r.on("click",function(e){e.preventDefault(),n.onclick&&n.onclick()}),this.$menu.append(r),n.divider&&this.$menu.append($(this._templateDivider()))},_templateMenuItem:function(e){var t='<li><a href="'+e.href+'" target="'+e.target+'">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),t+=" "+e.title+"</a>"+"</li>",t},_templateMenu:function(){return'<ul class="menu dropdown-menu pull-right" role="menu"></ul>'},_templateDivider:function(){return'<li class="divider"></li>'},_template:function(e){var t='<div id="'+e.id+'" class="button-menu btn-group">'+'<button type="button" class="root btn btn-default dropdown-toggle" data-toggle="dropdown">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),"</button></div>",t}}),c=Backbone.View.extend({optionsDefault:{value:"",type:"text",placeholder:"",disabled:!1,visible:!0},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.disabled&&this.$el.prop("disabled",!0),this.options.visible||this.$el.hide();var n=this;this.options.onchange&&this.$el.on("input",function(){n.options.onchange()})},value:function(e){return e!==undefined&&this.$el.val(e),this.$el.val()},_template:function(e){return'<input id="'+e.id+'" type="'+e.type+'" value="'+e.value+'" placeholder="'+e.placeholder+'" class="form-control">'}});return{Label:n,Button:r,Icon:i,ButtonIcon:s,Input:c,Anchor:o,Message:u,Searchbox:a,Title:f,Select:t,ButtonMenu:l}}),define("plugin/library/jobs",["utils/utils"],function(e){return Backbone.Model.extend({initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},cleanup:function(t){var n=t.get("dataset_id_job");if(n){var r=this;e.request("PUT",config.root+"api/histories/none/contents/"+n,{deleted:!0},function(){r._refreshHdas()})}},submit:function(t,n,r,i){var s=this,o=t.id,u=t.get("type"),a=this.app.types.get(u);data={tool_id:"rkit",inputs:{input:{id:t.get("dataset_id"),src:"hda"},module:u,columns:r,settings:n}},s.cleanup(t),t.state("submit","Sending job request..."),e.request("POST",config.root+"api/tools",data,function(e){if(!e.outputs||e.outputs.length==0)t.state("failed","Job submission failed. No response.");else{s._refreshHdas();var n=e.outputs[0];t.state("queued","Job has been queued..."),t.set("dataset_id_job",n.id),s._loop(n.id,function(e){switch(e.state){case"ok":return t.state("success","Job completed successfully..."),i(e),!0;case"error":return t.state("failed","Job has failed. Please check the history for details."),!0;case"running":return t.state("running","Job is running..."),!1}})}},function(e){var n="";e&&e.message&&e.message.data&&e.message.data.input&&(n=e.message.data.input+"."),t.state("failed","This visualization requires the R-kit. Please make sure it is installed. "+n)})},_loop:function(t,n){var r=this;e.request("GET",config.root+"api/jobs/"+t,{},function(e){n(e)||setTimeout(function(){r._loop(t,n)},r.app.config.get("query_timeout"))})},_refreshHdas:function(){Galaxy&&Galaxy.currHistoryPanel&&Galaxy.currHistoryPanel.refreshHdas()}})}),define("plugin/library/datasets",["utils/utils"],function(e){return Backbone.Collection.extend({list:{},initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},request:function(t,n,r){var i=this;if(t.groups)this._fetch(t,n);else{var s=this.list[t.id];if(s){n(s);return}e.request("GET",config.root+"api/datasets/"+t.id,{},function(e){switch(e.state){case"error":r&&r(e);break;default:i.list[t.id]=e,n(e)}})}},_fetch:function(t,n){var r=t.start?t.start:0,i=Math.abs(t.end-t.start),s=this.app.config.get("query_limit");if(!i||i>s)i=s;var o="",u={},a=0;for(var f in t.groups){var l=t.groups[f];for(var c in l.columns){var h=l.columns[c];o+=h+",",u[h]=a,a++}}if(a==0){n({});return}o=o.substring(0,o.length-1);var p=t.groups.slice(0);for(var f in p)p[f].values=[];var d=this;e.request("GET",config.root+"api/datasets/"+t.id,{data_type:"raw_data",provider:"dataset-column",limit:i,offset:r,indeces:o},function(e){for(var i in e.data){var s=e.data[i];for(var o in t.groups){var a=t.groups[o],f={x:parseInt(i)+r};for(var l in a.columns){var c=a.columns[l],h=u[c],d=s[h];if(isNaN(d)||!d)d=0;f[l]=d}p[o].values.push(f)}}n(p)})}})}),define("plugin/models/group",[],function(){return Backbone.Model.extend({defaults:{key:"Data label",date:""},reset:function(){this.clear({silent:!0}).set(this.defaults),this.trigger("reset",this)}})}),define("plugin/models/groups",["plugin/models/group"],function(e){return Backbone.Collection.extend({model:e})});var Visualization=Backbone.Model.extend({defaults:{config:{}},urlRoot:function(){var e="/api/visualizations";return window.galaxy_config&&galaxy_config.root?galaxy_config.root+e:e},initialize:function(e){_.isObject(e.config)&&_.isObject(this.defaults.config)&&_.defaults(e.config,this.defaults.config),this._setUpListeners()},_setUpListeners:function(){},set:function(e,t){if(e==="config"){var n=this.get("config");_.isObject(n)&&(t=_.extend(_.clone(n),t))}return Backbone.Model.prototype.set.call(this,e,t),this},toString:function(){var e=this.get("id")||"";return this.get("title")&&(e+=":"+this.get("title")),"Visualization("+e+")"}}),VisualizationCollection=Backbone.Collection.extend({model:Visualization,url:function(){return galaxy_config.root+"api/visualizations"},initialize:function(e,t){t=t||{}},set:function(e,t){var n=this;e=_.map(e,function(e){var t=n.get(e.id);if(!t)return e;var r=t.toJSON();return _.extend(r,e),r}),Backbone.Collection.prototype.set.call(this,e,t)},toString:function(){return["VisualizationCollection(",[this.historyId,this.length].join(),")"].join("")}});define("mvc/visualization/visualization-model",function(){}),define("plugin/models/chart",["plugin/models/groups","mvc/visualization/visualization-model"],function(e){return Backbone.Model.extend({defaults:{id:null,title:"",type:"",date:null,state:"ok",state_info:""},initialize:function(t){this.groups=new e,this.settings=new Backbone.Model},reset:function(){this.clear({silent:!0}).set(this.defaults),this.groups.reset(),this.settings.clear(),this.trigger("reset",this)},copy:function(e){var t=this;t.clear({silent:!0}).set(this.defaults),t.set(e.attributes),t.settings=e.settings.clone(),t.groups.reset(),e.groups.each(function(e){t.groups.add(e.clone())}),t.trigger("change",t)},state:function(e,t){this.set("state_info",t),this.set("state",e)},ready:function(){return this.get("state")=="ok"||this.get("state")=="failed"}})}),define("plugin/library/storage",["utils/utils","plugin/models/chart","plugin/models/group"],function(e,t,n){return Backbone.Model.extend({vis:null,initialize:function(e){this.app=e,this.chart=this.app.chart,this.options=this.app.options,this.id=this.options.id,this.vis=new Visualization({type:"charts",config:{dataset_id:this.options.config.dataset_id,chart_dict:{}}}),this.id&&(this.vis.id=this.id);var t=this.options.config.chart_dict;t&&(this.vis.get("config").chart_dict=t)},save:function(){var e=this.app.chart;this.vis.get("config").chart_dict={};var t=e.get("title");t!=""&&this.vis.set("title",t);var n={attributes:e.attributes,settings:e.settings.attributes,groups:[]};e.groups.each(function(e){n.groups.push(e.attributes)}),this.vis.get("config").chart_dict=n;var r=this;this.vis.save().fail(function(e,t,n){console.error(e,t,n),alert("Error loading data:\n"+e.responseText)}).then(function(e){e&&e.id&&(r.id=e.id)})},load:function(){var e=this.vis.get("config").chart_dict;if(!e.attributes)return!1;this.chart.set(e.attributes),this.chart.settings.set(e.settings);for(var t in e.groups)this.chart.groups.add(new n(e.groups[t]));return this.chart.state("ok","Loaded previously saved visualization."),!0}})}),define("plugin/views/viewport",["mvc/ui/ui-portlet","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({height:300,initialize:function(e,t){this.app=e,this.chart=this.app.chart,this.options=n.merge(t,this.optionsDefault),this.setElement($(this._template()));var r=this;this.chart.on("redraw",function(){r._draw(r.chart)})},show:function(){this.$el.show()},hide:function(){this.$el.hide()},_draw:function(e){var t=this;if(!e.ready()){this.app.log("viewport:_drawChart()","Invalid attempt to draw chart before completion.");return}this.svg&&this.svg.remove(),this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.setAttribute("height",this.height),this.$el.append(this.svg),this.svg=d3.select(this.$el.find("svg")[0]),e.off("change:state"),e.on("change:state",function(){var n=t.$el.find("#info"),r=n.find("#icon");r.removeClass(),n.show(),n.find("#text").html(e.get("state_info"));var i=e.get("state");switch(i){case"ok":n.hide();break;case"failed":r.addClass("fa fa-warning");break;default:r.addClass("fa fa-spinner fa-spin")}}),e.state("wait","Please wait...");var n=e.get("type"),r=this.app.types.get(n),t=this;require(["plugin/charts/"+n+"/"+n],function(n){var i=new n(t.app,{svg:t.svg});r.execute?t.app.jobs.submit(e,t._defaultSettingsString(e),t._defaultRequestString(e),function(){i.draw(e,t._defaultRequestDictionary(e))}):i.draw(e,t._defaultRequestDictionary(e))})},_template:function(){return'<div><div id="info" style="text-align: center; margin-top: 20px;"><span id="icon" style="font-size: 1.2em; display: inline-block;"/><span id="text" style="position: relative; margin-left: 5px; top: -1px; font-size: 1.0em;"/></div></div>'},_defaultRequestString:function(e){var t=this.app.types.get(e.get("type")),n="",r=0;return e.groups.each(function(e){for(var i in t.columns)n+=i+"_"+ ++r+":"+(parseInt(e.get(i))+1)+", "}),n.substring(0,n.length-2)},_defaultSettingsString:function(e){var t="";for(key in e.settings.attributes)t+=key+":"+e.settings.get(key)+", ";return t.substring(0,t.length-2)},_defaultRequestDictionary:function(e){var t=this.app.types.get(e.get("type")),n={id:e.get("dataset_id"),groups:[]},r=0;return e.groups.each(function(e){var i={};for(var s in t.columns)i[s]=e.get(s);n.groups.push({key:++r+":"+e.get("key"),columns:i})}),n}})}),define("plugin/views/viewer",["utils/utils","plugin/library/ui","mvc/ui/ui-portlet","plugin/models/group","plugin/views/viewport"],function(e,t,n,r,i){return Backbone.View.extend({initialize:function(e,r){this.app=e,this.chart=this.app.chart,this.viewport_view=new i(e);var s=this;this.portlet=new n.View({icon:"fa-bar-chart-o",title:"Viewport",operations:{edit_button:new t.ButtonIcon({icon:"fa-gear",tooltip:"Customize Chart",title:"Customize",onclick:function(){s._wait(s.app.chart,function(){s.app.go("editor")})}})}}),this.portlet.append(this.viewport_view.$el),this.setElement(this.portlet.$el);var s=this;this.chart.on("change:title",function(){s._refreshTitle()})},show:function(){this.$el.show(),$(window).trigger("resize")},hide:function(){this.$el.hide()},_refreshTitle:function(){var e=this.chart.get("title");e&&(e=" - "+e),this.portlet.title("Charts"+e)},_wait:function(e,t){if(e.ready())t();else{var n=this;this.app.modal.show({title:"Please wait!",body:"Your chart is currently being processed. Please wait...",buttons:{Close:function(){n.app.modal.hide()},Retry:function(){n.app.modal.hide(),setTimeout(function(){n._wait(e,t)},n.app.config.get("query_timeout"))}}})}}})}),define("mvc/ui/ui-tabs",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,list:{},$nav:null,$content:null,first_tab:null,optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(this.options));this.$nav=n.find(".tab-navigation"),this.$content=n.find(".tab-content"),this.setElement(n),this.list={};var r=this;this.options.operations&&$.each(this.options.operations,function(e,t){t.$el.prop("id",e),r.$nav.find(".operations").append(t.$el)});if(this.options.onnew){var i=$(this._template_tab_new(this.options));this.$nav.append(i),i.tooltip({title:"Add a new tab",placement:"bottom",container:r.$el}),i.on("click",function(e){i.tooltip("hide"),r.options.onnew()})}},add:function(e){var t=e.id,n={$title:$(this._template_tab(e)),$content:$(this._template_tab_content(e)),removable:e.ondel?!0:!1};this.list[t]=n,this.options.onnew?this.$nav.find("#new-tab").before(n.$title):this.$nav.append(n.$title),n.$content.append(e.$el),this.$content.append(n.$content),_.size(this.list)==1&&(n.$title.addClass("active"),n.$content.addClass("active"),this.first_tab=t);if(e.ondel){var r=this,i=n.$title.find("#delete");i.tooltip({title:"Delete this tab",placement:"bottom",container:r.$el}),i.on("click",function(){return i.tooltip("destroy"),r.$el.find(".tooltip").remove(),e.ondel(),!1})}e.onclick&&n.$title.on("click",function(){e.onclick()})},del:function(e){var t=this.list[e];t.$title.remove(),t.$content.remove(),delete t,this.first_tab==e&&(this.first_tab=null),this.first_tab!=null&&this.show(this.first_tab)},delRemovable:function(){for(var e in this.list){var t=this.list[e];t.removable&&this.del(e)}},show:function(e){this.$el.fadeIn("fast"),this.visible=!0,e&&this.list[e].$title.find("a").tab("show")},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},hideOperation:function(e){this.$nav.find("#"+e).hide()},showOperation:function(e){this.$nav.find("#"+e).show()},setOperation:function(e,t){var n=this.$nav.find("#"+e);n.off("click"),n.on("click",t)},title:function(e,t){var n=this.list[e].$title.find("#text");return t&&n.html(t),n.html()},_template:function(e){return'<div class="tabbable tabs-left"><ul class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div class="tab-content"/></div>'},_template_tab_new:function(e){return'<li id="new-tab"><a href="javascript:void(0);"><i style="font-size: 0.8em; margin-right: 5px;" class="fa fa-plus-circle"/>'+e.title_new+"</a>"+"</li>"},_template_tab:function(e){var t='<li id="title-'+e.id+'">'+'<a title="" href="#tab-'+e.id+'" data-toggle="tab" data-original-title="">'+'<span id="text">'+e.title+"</span>";return e.ondel&&(t+='<i id="delete" style="font-size: 0.8em; margin-left: 5px; cursor: pointer;" class="fa fa-minus-circle"/>'),t+="</a></li>",t},_template_tab_content:function(e){return'<div id="tab-'+e.id+'" class="tab-pane"/>'}});return{View:t}}),define("plugin/library/ui-table",["utils/utils"],function(e){var t=Backbone.View.extend({row:null,row_count:0,optionsDefault:{content:"No content available.",onchange:null,ondblclick:null,onconfirm:null},events:{click:"_onclick",dblclick:"_ondblclick"},first:!0,initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(t));this.$thead=n.find("thead"),this.$tbody=n.find("tbody"),this.$tmessage=n.find("tmessage"),this.setElement(n),this.row=$("<tr></tr>")},addHeader:function(e){var t=$("<th></th>");t.append(e),this.row.append(t)},appendHeader:function(){this.$thead.append(this.row),this.row=$("<tr></tr>")},add:function(e,t){var n=$("<td></td>");t&&n.css("width",t),n.append(e),this.row.append(n)},append:function(e){this._commit(e)},prepend:function(e){this._commit(e,!0)},remove:function(e){var t=this.$tbody.find("#"+e);t.length>0&&(t.remove(),this.row_count--,this._refresh())},removeAll:function(){this.$tbody.html(""),this.row_count=0,this._refresh()},value:function(e){this.before=this.$tbody.find(".current").attr("id"),e!==undefined&&(this.$tbody.find("tr").removeClass("current"),e&&this.$tbody.find("#"+e).addClass("current"));var t=this.$tbody.find(".current").attr("id");return t===undefined?null:(t!=this.before&&this.options.onchange&&this.options.onchange(e),t)},size:function(){return this.$tbody.find("tr").length},_commit:function(e,t){this.remove(e),this.row.attr("id",e),t?this.$tbody.prepend(this.row):this.$tbody.append(this.row),this.row=$("<tr></tr>"),this.row_count++,this._refresh()},_onclick:function(e){var t=this.value(),n=$(e.target).closest("tr").attr("id");n&&t!=n&&(this.options.onconfirm?this.options.onconfirm(n):this.value(n))},_ondblclick:function(e){var t=this.value();t&&this.options.ondblclick&&this.options.ondblclick(t)},_refresh:function(){this.row_count==0?this.$tmessage.show():this.$tmessage.hide()},_template:function(e){return'<div><table class="grid"><thead></thead><tbody style="cursor: pointer;"></tbody></table><tmessage>'+e.content+"</tmessage>"+"<div>"}});return{View:t}}),define("plugin/views/group",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({columns:[],initialize:function(r,i){this.app=r;var s=this;this.chart=this.app.chart,this.group=i.group,this.group_key=new t.Input({placeholder:"Data label",onchange:function(){s.group.set("key",s.group_key.value())}}),this.table=new e.View({content:"No data column."});var o=$("<div/>");o.append(n.wrap((new t.Label({title:"Provide a label:"})).$el)),o.append(n.wrap(this.group_key.$el)),o.append(n.wrap((new t.Label({title:"Select columns:"})).$el)),o.append(n.wrap(this.table.$el)),this.setElement(o);var s=this;this.chart.on("change:dataset_id",function(){s._refreshTable()}),this.chart.on("change:type",function(){s._refreshTable()}),this.group.on("change:key",function(){s._refreshGroupKey()}),this.group.on("change",function(){s._refreshGroup()}),this._refreshTable(),this._refreshGroupKey(),this._refreshGroup()},_refreshTable:function(){var e=this.chart.get("dataset_id"),n=this.chart.get("type");if(!e||!n)return;var r=this,i=this.app.types.get(n);this.table.removeAll();var s={};for(var o in i.columns){var u=this.group.get(o);u||this.group.set(o,0);var a=i.columns[o],f=new t.Select.View({id:"select_"+o,gid:o,onchange:function(e){r.group.set(this.gid,e)},value:u,wait:!0});this.table.add(a.title,"25%"),this.table.add(f.$el),this.table.append(o),s[o]=f}this.app.datasets.request({id:e},function(e){r.columns=[];var t=e.metadata_column_types;for(var n in t)(t[n]=="int"||t[n]=="float")&&r.columns.push({label:"Column: "+(parseInt(n)+1)+" ["+t[n]+"]",value:n});for(var n in s)s[n].update(r.columns),s[n].show()})},_refreshGroup:function(){this.group.set("date",n.time())},_refreshGroupKey:function(){var e=this.group.get("key");e===undefined&&(e=""),this.group_key.value(e)}})}),define("plugin/library/ui-table-form",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){var r=Backbone.View.extend({initialize:function(r){this.table_title=new t.Label({title:r.title}),this.table=new e.View({content:r.content});var i=$("<div/>");i.append(n.wrap(this.table_title.$el)),i.append(n.wrap(this.table.$el)),this.setElement(i)},title:function(e){this.table_title.title(e)},update:function(e,t){this.table.removeAll();for(var n in e)this._add(n,e[n],t)},_add:function(e,n,r){var i=null,s=n.type;switch(s){case"text":i=new t.Input({placeholder:n.placeholder,onchange:function(){r.set(e,i.value())}});break;case"select":i=new t.Select.View({data:n.data,onchange:function(){r.set(e,i.value())}});break;case"slider":i=new t.Input({placeholder:n.placeholder,onchange:function(){r.set(e,i.value())}});break;case"separator":i=$("<div/>");break;default:console.log("ui-table-form:_add","Unknown setting type ("+n.type+")");return}if(s!="separator"){r.get(e)||r.set(e,n.init),i.value(r.get(e));var o=$("<div/>");o.append(i.$el),o.append('<div class="toolParamHelp" style="font-size: 0.9em;">'+n.info+"</div>"),this.table.add('<span style="white-space: nowrap;">'+n.title+"</span>","25%"),this.table.add(o)}else this.table.add('<h6 style="white-space: nowrap;">'+n.title+":<h6/>"),this.table.add($("<div/>"));this.table.append(e)}});return{View:r}}),define("plugin/views/settings",["plugin/library/ui","plugin/library/ui-table-form","utils/utils"],function(e,t,n){return Backbone.View.extend({initialize:function(e,n){this.app=e;var r=this;this.chart=this.app.chart,this.form=new t.View({title:"Chart options:",content:"This chart type does not provide any options."}),this.setElement(this.form.$el);var r=this;this.chart.on("change",function(){r._refreshTable()})},_refreshTable:function(){var e=this.chart.get("type");if(!e)return;var t=this.app.types.get(e);this.form.title(t.title+":"),this.form.update(t.settings,this.chart.settings)}})}),define("plugin/views/editor",["mvc/ui/ui-tabs","plugin/library/ui-table","plugin/library/ui","mvc/ui/ui-portlet","utils/utils","plugin/models/chart","plugin/models/group","plugin/views/group","plugin/views/settings"],function(e,t,n,r,i,s,o,u,a){return Backbone.View.extend({optionsDefault:{header:!0,content:"No content available."},initialize:function(s,o){this.app=s,this.chart=this.app.chart,this.options=i.merge(o,this.optionsDefault),this.portlet=new r.View({icon:"fa-bar-chart-o",title:"Editor",operations:{save:new n.ButtonIcon({icon:"fa-save",tooltip:"Draw Chart",title:"Draw",onclick:function(){u.app.go("viewer"),u._saveChart()}}),back:new n.ButtonIcon({icon:"fa-caret-left",tooltip:"Return to Viewer",title:"Return",onclick:function(){u.app.go("viewer"),u.app.storage.load()}})}});var u=this;this.table=new t.View({header:!1,onconfirm:function(e){u.chart.groups.length>0?u.app.modal.show({title:"Switching to another chart type?",body:"If you continue your settings and selections will be cleared.",buttons:{Cancel:function(){u.app.modal.hide()},Continue:function(){u.app.modal.hide(),u.table.value(e)}}}):u.table.value(e)},onchange:function(e){u.chart.groups.reset(),u.chart.settings.clear(),u.chart.set({type:e})},ondblclick:function(e){u.tabs.show("settings")},content:"No chart types available"});var f=0,l=s.types.attributes;for(var c in l){var h=l[c];this.table.add(++f+"."),h.execute?this.table.add(h.title+" (requires processing)"):this.table.add(h.title),this.table.append(c)}this.tabs=new e.View({title_new:"Add Data",onnew:function(){var e=u._addGroupModel();u.tabs.show(e.id)}}),this.title=new n.Input({placeholder:"Chart title",onchange:function(){u.app.config.set("title",u.title.value())}});var p=$("<div/>");p.append(i.wrap((new n.Label({title:"Provide a chart title:"})).$el)),p.append(i.wrap(this.title.$el)),p.append(i.wrap((new n.Label({title:"Select a chart type:"})).$el)),p.append(i.wrap(this.table.$el)),this.tabs.add({id:"main",title:"Start",$el:p}),this.settings=new a(this.app),this.tabs.add({id:"settings",title:"Configuration",$el:this.settings.$el}),this.portlet.append(this.tabs.$el),this.setElement(this.portlet.$el),this.tabs.hideOperation("back");var u=this;this.chart.on("change:title",function(e){u._refreshTitle()}),this.chart.on("change:type",function(e){u.table.value(e.get("type"))}),this.chart.on("reset",function(e){u._resetChart()}),this.app.chart.on("redraw",function(e){u.portlet.showOperation("back")}),this.app.chart.groups.on("add",function(e){u._addGroup(e)}),this.app.chart.groups.on("remove",function(e){u._removeGroup(e)}),this.app.chart.groups.on("reset",function(e){u._removeAllGroups()}),this.app.chart.groups.on("change:key",function(e){u._refreshGroupKey()}),this._resetChart()},show:function(){this.$el.show()},hide:function(){this.$el.hide()},_refreshTitle:function(){var e=this.chart.get("title");e&&(e=" - "+e),this.portlet.title("Charts"+e)},_refreshGroupKey:function(){var e=this,t=0;this.chart.groups.each(function(n){var r=n.get("key","");r==""&&(r="Chart data"),e.tabs.title(n.id,++t+": "+r)})},_addGroupModel:function(){var e=new o({id:i.uuid()});return this.chart.groups.add(e),e},_addGroup:function(e){var t=this,n=new u(this.app,{group:e}),r=t.chart.groups.length;this.tabs.add({id:e.id,$el:n.$el,ondel:function(){t.chart.groups.remove(e.id)}}),this._refreshGroupKey()},_removeGroup:function(e){this.tabs.del(e.id),this._refreshGroupKey()},_removeAllGroups:function(e){this.tabs.delRemovable()},_resetChart:function(){this.chart.set("id",i.uuid()),this.chart.set("type","bardiagram"),this.chart.set("dataset_id",this.app.options.config.dataset_id),this.chart.set("title","New Chart"),this.portlet.hideOperation("back")},_saveChart:function(){this.chart.set({type:this.table.value(),title:this.title.value(),date:i.time()}),this.chart.groups.length==0&&this._addGroupModel(),this.chart.trigger("redraw"),this.app.storage.save()}})}),define("plugin/models/config",[],function(){return Backbone.Model.extend({defaults:{query_limit:1e3,query_timeout:500}})}),define("plugin/charts/_nvd3/config",[],function(){return{title:"",columns:{y:{title:"Values for y-axis"}},settings:{separator_label:{title:"X axis",type:"separator"},x_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"X-axis",placeholder:"Axis label"},x_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"f",data:[{label:"-- Do not show values --",value:"hide"},{label:"Float",value:"f"},{label:"Exponent",value:"e"},{label:"Integer",value:"d"},{label:"Percentage",value:"p"},{label:"Rounded",value:"r"},{label:"SI-prefix",value:"s"}]},x_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_tick:{title:"Y axis",type:"separator"},y_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"Y-axis",placeholder:"Axis label"},y_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"f",data:[{label:"-- Do not show values --",value:"hide"},{label:"Float",value:"f"},{label:"Exponent",value:"e"},{label:"Integer",value:"d"},{label:"Percentage",value:"p"},{label:"Rounded",value:"r"},{label:"SI-prefix",value:"s"}]},y_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_legend:{title:"Others",type:"separator"},show_legend:{title:"Show legend",info:"Would you like to add a legend?",type:"select",init:"true",data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]}}}}),define("plugin/charts/bardiagram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram"})}),define("plugin/charts/histogram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Histogram",execute:!0,columns:{y:{title:"Observations"}},settings:{x_axis_label:{init:"Breaks"},y_axis_label:{init:"Density"},y_axis_tick:{init:".3"}}})}),define("plugin/charts/horizontal/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram (horizontal)",settings:{x_axis_type:{init:"hide"}}})}),define("plugin/charts/line/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line chart"})}),define("plugin/charts/linewithfocus/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line with focus"})}),define("plugin/charts/piechart/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Pie chart"})}),define("plugin/charts/scatterplot/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Scatter plot",columns:{x:{title:"Values for x-axis"}}})}),define("plugin/charts/stackedarea/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Stacked area"})}),define("plugin/charts/types",["plugin/charts/bardiagram/config","plugin/charts/histogram/config","plugin/charts/horizontal/config","plugin/charts/line/config","plugin/charts/linewithfocus/config","plugin/charts/piechart/config","plugin/charts/scatterplot/config","plugin/charts/stackedarea/config"],function(e,t,n,r,i,s,o,u){return Backbone.Model.extend({defaults:{bardiagram:e,horizontal:n,histogram:t,line:r,linewithfocus:i,piechart:s,scatterplot:o,stackedarea:u}})}),define("plugin/app",["mvc/ui/ui-modal","mvc/ui/ui-portlet","plugin/library/ui","utils/utils","plugin/library/jobs","plugin/library/datasets","plugin/library/storage","plugin/views/viewer","plugin/views/editor","plugin/models/config","plugin/models/chart","plugin/charts/types"],function(e,t,n,r,i,s,o,u,a,f,l,c){return Backbone.View.extend({initialize:function(t){this.options=t,Galaxy&&Galaxy.modal?this.modal=Galaxy.modal:this.modal=new e.View,this.config=new f,this.types=new c,this.chart=new l,this.jobs=new i(this),this.datasets=new s(this),this.storage=new o(this),this.viewer_view=new u(this),this.editor_view=new a(this),this.$el.append(this.viewer_view.$el),this.$el.append(this.editor_view.$el),this.storage.load()?(this.go("viewer"),this.chart.trigger("redraw")):this.go("editor")},go:function(e){$(".tooltip").hide();switch(e){case"editor":this.editor_view.show(),this.viewer_view.hide();break;case"viewer":this.editor_view.hide(),this.viewer_view.show()}},execute:function(e){},onunload:function(){},log:function(e,t){console.log(e+" "+t)}})});
\ No newline at end of file
+(function(){var e=this,t=e._,n={},r=Array.prototype,i=Object.prototype,s=Function.prototype,o=r.push,u=r.slice,a=r.concat,f=i.toString,l=i.hasOwnProperty,c=r.forEach,h=r.map,p=r.reduce,d=r.reduceRight,v=r.filter,m=r.every,g=r.some,y=r.indexOf,b=r.lastIndexOf,w=Array.isArray,E=Object.keys,S=s.bind,x=function(e){if(e instanceof x)return e;if(!(this instanceof x))return new x(e);this._wrapped=e};typeof exports!="undefined"?(typeof module!="undefined"&&module.exports&&(exports=module.exports=x),exports._=x):e._=x,x.VERSION="1.4.4";var T=x.each=x.forEach=function(e,t,r){if(e==null)return;if(c&&e.forEach===c)e.forEach(t,r);else if(e.length===+e.length){for(var i=0,s=e.length;i<s;i++)if(t.call(r,e[i],i,e)===n)return}else for(var o in e)if(x.has(e,o)&&t.call(r,e[o],o,e)===n)return};x.map=x.collect=function(e,t,n){var r=[];return e==null?r:h&&e.map===h?e.map(t,n):(T(e,function(e,i,s){r.push(t.call(n,e,i,s))}),r)};var N="Reduce of empty array with no initial value";x.reduce=x.foldl=x.inject=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(p&&e.reduce===p)return r&&(t=x.bind(t,r)),i?e.reduce(t,n):e.reduce(t);T(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError(N);return n},x.reduceRight=x.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(d&&e.reduceRight===d)return r&&(t=x.bind(t,r)),i?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=x.keys(e);s=o.length}T(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError(N);return n},x.find=x.detect=function(e,t,n){var r;return C(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},x.filter=x.select=function(e,t,n){var r=[];return e==null?r:v&&e.filter===v?e.filter(t,n):(T(e,function(e,i,s){t.call(n,e,i,s)&&r.push(e)}),r)},x.reject=function(e,t,n){return x.filter(e,function(e,r,i){return!t.call(n,e,r,i)},n)},x.every=x.all=function(e,t,r){t||(t=x.identity);var i=!0;return e==null?i:m&&e.every===m?e.every(t,r):(T(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var C=x.some=x.any=function(e,t,r){t||(t=x.identity);var i=!1;return e==null?i:g&&e.some===g?e.some(t,r):(T(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};x.contains=x.include=function(e,t){return e==null?!1:y&&e.indexOf===y?e.indexOf(t)!=-1:C(e,function(e){return e===t})},x.invoke=function(e,t){var n=u.call(arguments,2),r=x.isFunction(t);return x.map(e,function(e){return(r?t:e[t]).apply(e,n)})},x.pluck=function(e,t){return x.map(e,function(e){return e[t]})},x.where=function(e,t,n){return x.isEmpty(t)?n?void 0:[]:x[n?"find":"filter"](e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},x.findWhere=function(e,t){return x.where(e,t,!0)},x.max=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&x.isEmpty(e))return-Infinity;var r={computed:-Infinity,value:-Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},x.min=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&x.isEmpty(e))return Infinity;var r={computed:Infinity,value:Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o<r.computed&&(r={value:e,computed:o})}),r.value},x.shuffle=function(e){var t,n=0,r=[];return T(e,function(e){t=x.random(n++),r[n-1]=r[t],r[t]=e}),r};var k=function(e){return x.isFunction(e)?e:function(t){return t[e]}};x.sortBy=function(e,t,n){var r=k(t);return x.pluck(x.map(e,function(e,t,i){return{value:e,index:t,criteria:r.call(n,e,t,i)}}).sort(function(e,t){var n=e.criteria,r=t.criteria;if(n!==r){if(n>r||n===void 0)return 1;if(n<r||r===void 0)return-1}return e.index<t.index?-1:1}),"value")};var L=function(e,t,n,r){var i={},s=k(t==null?x.identity:t);return T(e,function(t,o){var u=s.call(n,t,o,e);r(i,u,t)}),i};x.groupBy=function(e,t,n){return L(e,t,n,function(e,t,n){(x.has(e,t)?e[t]:e[t]=[]).push(n)})},x.countBy=function(e,t,n){return L(e,t,n,function(e,t){x.has(e,t)||(e[t]=0),e[t]++})},x.sortedIndex=function(e,t,n,r){n=n==null?x.identity:k(n);var i=n.call(r,t),s=0,o=e.length;while(s<o){var u=s+o>>>1;n.call(r,e[u])<i?s=u+1:o=u}return s},x.toArray=function(e){return e?x.isArray(e)?u.call(e):e.length===+e.length?x.map(e,x.identity):x.values(e):[]},x.size=function(e){return e==null?0:e.length===+e.length?e.length:x.keys(e).length},x.first=x.head=x.take=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,0,t):e[0]},x.initial=function(e,t,n){return u.call(e,0,e.length-(t==null||n?1:t))},x.last=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,Math.max(e.length-t,0)):e[e.length-1]},x.rest=x.tail=x.drop=function(e,t,n){return u.call(e,t==null||n?1:t)},x.compact=function(e){return x.filter(e,x.identity)};var A=function(e,t,n){return T(e,function(e){x.isArray(e)?t?o.apply(n,e):A(e,t,n):n.push(e)}),n};x.flatten=function(e,t){return A(e,t,[])},x.without=function(e){return x.difference(e,u.call(arguments,1))},x.uniq=x.unique=function(e,t,n,r){x.isFunction(t)&&(r=n,n=t,t=!1);var i=n?x.map(e,n,r):e,s=[],o=[];return T(i,function(n,r){if(t?!r||o[o.length-1]!==n:!x.contains(o,n))o.push(n),s.push(e[r])}),s},x.union=function(){return x.uniq(a.apply(r,arguments))},x.intersection=function(e){var t=u.call(arguments,1);return x.filter(x.uniq(e),function(e){return x.every(t,function(t){return x.indexOf(t,e)>=0})})},x.difference=function(e){var t=a.apply(r,u.call(arguments,1));return x.filter(e,function(e){return!x.contains(t,e)})},x.zip=function(){var e=u.call(arguments),t=x.max(x.pluck(e,"length")),n=new Array(t);for(var r=0;r<t;r++)n[r]=x.pluck(e,""+r);return n},x.unzip=function(e){var t=[];return x.each(e,function(e,n){x.each(e,function(e,r){t.length<=r&&(t[r]=[]),t[r][n]=e})}),t},x.object=function(e,t){if(e==null)return{};var n={};for(var r=0,i=e.length;r<i;r++)t?n[e[r]]=t[r]:n[e[r][0]]=e[r][1];return n},x.indexOf=function(e,t,n){if(e==null)return-1;var r=0,i=e.length;if(n){if(typeof n!="number")return r=x.sortedIndex(e,t),e[r]===t?r:-1;r=n<0?Math.max(0,i+n):n}if(y&&e.indexOf===y)return e.indexOf(t,n);for(;r<i;r++)if(e[r]===t)return r;return-1},x.lastIndexOf=function(e,t,n){if(e==null)return-1;var r=n!=null;if(b&&e.lastIndexOf===b)return r?e.lastIndexOf(t,n):e.lastIndexOf(t);var i=r?n:e.length;while(i--)if(e[i]===t)return i;return-1},x.range=function(e,t,n){arguments.length<=1&&(t=e||0,e=0),n=arguments[2]||1;var r=Math.max(Math.ceil((t-e)/n),0),i=0,s=new Array(r);while(i<r)s[i++]=e,e+=n;return s};var O=function(){};x.bind=function(e,t){var n,r;if(e.bind===S&&S)return S.apply(e,u.call(arguments,1));if(!x.isFunction(e))throw new TypeError;return n=u.call(arguments,2),r=function(){if(this instanceof r){O.prototype=e.prototype;var i=new O;O.prototype=null;var s=e.apply(i,n.concat(u.call(arguments)));return Object(s)===s?s:i}return e.apply(t,n.concat(u.call(arguments)))}},x.partial=function(e){var t=u.call(arguments,1);return function(){return e.apply(this,t.concat(u.call(arguments)))}},x.bindAll=function(e){var t=u.call(arguments,1);if(t.length===0)throw new Error("bindAll must be passed function names");return T(t,function(t){e[t]=x.bind(e[t],e)}),e},x.memoize=function(e,t){var n={};return t||(t=x.identity),function(){var r=t.apply(this,arguments);return x.has(n,r)?n[r]:n[r]=e.apply(this,arguments)}},x.delay=function(e,t){var n=u.call(arguments,2);return setTimeout(function(){return e.apply(null,n)},t)},x.defer=function(e){return x.delay.apply(x,[e,1].concat(u.call(arguments,1)))},x.throttle=function(e,t,n){var r,i,s,o,u=0,a=function(){u=new Date,s=null,o=e.apply(r,i)};return function(){var f=new Date;!u&&n===!1&&(u=f);var l=t-(f-u);return r=this,i=arguments,l<=0?(clearTimeout(s),s=null,u=f,o=e.apply(r,i)):s||(s=setTimeout(a,l)),o}},x.debounce=function(e,t,n){var r,i;return function(){var s=this,o=arguments,u=function(){r=null,n||(i=e.apply(s,o))},a=n&&!r;return clearTimeout(r),r=setTimeout(u,t),a&&(i=e.apply(s,o)),i}},x.once=function(e){var t=!1,n;return function(){return t?n:(t=!0,n=e.apply(this,arguments),e=null,n)}},x.wrap=function(e,t){return function(){var n=[e];return o.apply(n,arguments),t.apply(this,n)}},x.compose=function(){var e=arguments;return function(){var t=arguments;for(var n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},x.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},x.keys=E||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)x.has(e,n)&&t.push(n);return t},x.values=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push(e[n]);return t},x.pairs=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push([n,e[n]]);return t},x.invert=function(e){var t={};for(var n in e)x.has(e,n)&&(t[e[n]]=n);return t},x.functions=x.methods=function(e){var t=[];for(var n in e)x.isFunction(e[n])&&t.push(n);return t.sort()},x.extend=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]=t[n]}),e},x.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return T(n,function(n){n in e&&(t[n]=e[n])}),t},x.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)x.contains(n,i)||(t[i]=e[i]);return t},x.defaults=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]===void 0&&(e[n]=t[n])}),e},x.clone=function(e){return x.isObject(e)?x.isArray(e)?e.slice():x.extend({},e):e},x.tap=function(e,t){return t(e),e};var M=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof x&&(e=e._wrapped),t instanceof x&&(t=t._wrapped);var i=f.call(e);if(i!=f.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=M(e[o],t[o],n,r)))break}else{var a=e.constructor,l=t.constructor;if(a!==l&&!(x.isFunction(a)&&a instanceof a&&x.isFunction(l)&&l instanceof l))return!1;for(var c in e)if(x.has(e,c)){o++;if(!(u=x.has(t,c)&&M(e[c],t[c],n,r)))break}if(u){for(c in t)if(x.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};x.isEqual=function(e,t){return M(e,t,[],[])},x.isEmpty=function(e){if(e==null)return!0;if(x.isArray(e)||x.isString(e))return e.length===0;for(var t in e)if(x.has(e,t))return!1;return!0},x.isElement=function(e){return!!e&&e.nodeType===1},x.isArray=w||function(e){return f.call(e)=="[object Array]"},x.isObject=function(e){return e===Object(e)},T(["Arguments","Function","String","Number","Date","RegExp"],function(e){x["is"+e]=function(t){return f.call(t)=="[object "+e+"]"}}),x.isArguments(arguments)||(x.isArguments=function(e){return!!e&&!!x.has(e,"callee")}),typeof /./!="function"&&(x.isFunction=function(e){return typeof e=="function"}),x.isFinite=function(e){return isFinite(e)&&!isNaN(parseFloat(e))},x.isNaN=function(e){return x.isNumber(e)&&e!=+e},x.isBoolean=function(e){return e===!0||e===!1||f.call(e)=="[object Boolean]"},x.isNull=function(e){return e===null},x.isUndefined=function(e){return e===void 0},x.has=function(e,t){return l.call(e,t)},x.noConflict=function(){return e._=t,this},x.identity=function(e){return e},x.times=function(e,t,n){var r=Array(e);for(var i=0;i<e;i++)r[i]=t.call(n,i);return r},x.random=function(e,t){return t==null&&(t=e,e=0),e+Math.floor(Math.random()*(t-e+1))};var _={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};_.unescape=x.invert(_.escape);var D={escape:new RegExp("["+x.keys(_.escape).join("")+"]","g"),unescape:new RegExp("("+x.keys(_.unescape).join("|")+")","g")};x.each(["escape","unescape"],function(e){x[e]=function(t){return t==null?"":(""+t).replace(D[e],function(t){return _[e][t]})}}),x.result=function(e,t){if(e==null)return void 0;var n=e[t];return x.isFunction(n)?n.call(e):n},x.mixin=function(e){T(x.functions(e),function(t){var n=x[t]=e[t];x.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),F.call(this,n.apply(x,e))}})};var P=0;x.uniqueId=function(e){var t=++P+"";return e?e+t:t},x.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var H=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},j=/\\|'|\r|\n|\t|\u2028|\u2029/g;x.template=function(e,t,n){var r;n=x.defaults({},n,x.templateSettings);var i=new RegExp([(n.escape||H).source,(n.interpolate||H).source,(n.evaluate||H).source].join("|")+"|$","g"),s=0,o="__p+='";e.replace(i,function(t,n,r,i,u){return o+=e.slice(s,u).replace(j,function(e){return"\\"+B[e]}),n&&(o+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'"),r&&(o+="'+\n((__t=("+r+"))==null?'':__t)+\n'"),i&&(o+="';\n"+i+"\n__p+='"),s=u+t.length,t}),o+="';\n",n.variable||(o="with(obj||{}){\n"+o+"}\n"),o="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+o+"return __p;\n";try{r=new Function(n.variable||"obj","_",o)}catch(u){throw u.source=o,u}if(t)return r(t,x);var a=function(e){return r.call(this,e,x)};return a.source="function("+(n.variable||"obj")+"){\n"+o+"}",a},x.chain=function(e){return x(e).chain()};var F=function(e){return this._chain?x(e).chain():e};x.mixin(x),T(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];x.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],F.call(this,n)}}),T(["concat","join","slice"],function(e){var t=r[e];x.prototype[e]=function(){return F.call(this,t.apply(this._wrapped,arguments))}}),x.extend(x.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this),define("libs/underscore",function(e){return function(){var t,n;return t||e._}}(this)),define("utils/utils",["libs/underscore"],function(e){function t(e,t,r){n("GET",e,{},t,r)}function n(e,t,n,r,i){if(e=="GET"||e=="DELETE")t.indexOf("?")==-1?t+="?":t+="&",t+=$.param(n);var s=new XMLHttpRequest;s.open(e,t,!0),s.setRequestHeader("Accept","application/json"),s.setRequestHeader("Cache-Control","no-cache"),s.setRequestHeader("X-Requested-With","XMLHttpRequest"),s.setRequestHeader("Content-Type","application/json"),s.onloadend=function(){var e=s.status;try{response=jQuery.parseJSON(s.responseText)}catch(t){response=s.responseText}e==200?r&&r(response):i&&i(response)},e=="GET"||e=="DELETE"?s.send():s.send(JSON.stringify(n))}function r(e,t){var n=$('<div class="'+e+'"></div>');n.appendTo(":eq(0)");var r=n.css(t);return n.remove(),r}function i(e){$('link[href^="'+e+'"]').length||$('<link href="'+galaxy_config.root+e+'" rel="stylesheet">').appendTo("head")}function s(t,n){return t?e.defaults(t,n):n}function o(e,t){var n="";if(e>=1e11)e/=1e11,n="TB";else if(e>=1e8)e/=1e8,n="GB";else if(e>=1e5)e/=1e5,n="MB";else if(e>=100)e/=100,n="KB";else{if(!(e>0))return"<strong>-</strong>";e*=10,n="b"}var r=Math.round(e)/10;return t?r+" "+n:"<strong>"+r+"</strong> "+n}function u(){return(new Date).getTime().toString(36)}function a(e){var t=$("<p></p>");return t.append(e),t}function f(){var e=new Date,t=(e.getHours()<10?"0":"")+e.getHours(),n=(e.getMinutes()<10?"0":"")+e.getMinutes(),r=e.getDate()+"/"+(e.getMonth()+1)+"/"+e.getFullYear()+", "+t+":"+n;return r}return{cssLoadFile:i,cssGetAttribute:r,get:t,merge:s,bytesToString:o,uuid:u,time:f,wrap:a,request:n}}),define("mvc/ui/ui-modal",["utils/utils"],function(e){var t=Backbone.View.extend({elMain:"body",optionsDefault:{title:"ui-modal",body:"",backdrop:!0,height:null,width:null,closing_events:!1},buttonList:{},initialize:function(e){e&&this._create(e)},show:function(e){this.initialize(e),this.options.height?(this.$body.css("height",this.options.height),this.$body.css("overflow","hidden")):this.$body.css("max-height",$(window).height()/2),this.options.width&&this.$dialog.css("width",this.options.width),this.visible?this.$el.show():this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.visible=!1,this.$el.fadeOut("fast")},enableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!1)},disableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!0)},showButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).show()},hideButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).hide()},getButton:function(e){var t=this.buttonList[e];return this.$buttons.find("#"+t)},scrollTop:function(){return this.$body.scrollTop()},_create:function(e){var t=this;this.options=_.defaults(e,this.optionsDefault),this.options.body=="progress"&&(this.options.body=$('<div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width:100%"></div></div>')),this.$el&&(this.$el.remove(),$(document).off("keyup")),this.setElement(this._template(this.options.title)),this.$dialog=this.$el.find(".modal-dialog"),this.$body=this.$el.find(".modal-body"),this.$footer=this.$el.find(".modal-footer"),this.$buttons=this.$el.find(".buttons"),this.$backdrop=this.$el.find(".modal-backdrop"),this.$body.html(this.options.body),this.options.backdrop||this.$backdrop.removeClass("in");if(this.options.buttons){this.buttonList={};var n=0;$.each(this.options.buttons,function(e,r){var i="button-"+n++;t.$buttons.append($('<button id="'+i+'"></button>').text(e).click(r)).append(" "),t.buttonList[e]=i})}else this.$footer.hide();$(this.elMain).append($(this.el)),this.options.closing_events&&(this.options.buttons.Pause||$(document).on("keyup",function(e){e.keyCode==27&&t.hide()}),this.$el.find(".modal-backdrop").on("click",function(){t.hide()}))},_template:function(e){return'<div class="modal"><div class="modal-backdrop fade in" style="z-index: -1;"></div><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" style="display: none;">×</button><h4 class="title">'+e+"</h4>"+"</div>"+'<div class="modal-body" style="position: static;"></div>'+'<div class="modal-footer">'+'<div class="buttons" style="float: right;"></div>'+"</div>"+"</div"+"</div>"+"</div>"}});return{View:t}}),define("mvc/ui/ui-portlet",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,optionsDefault:{title:"",icon:"",buttons:null,body:null,height:null,operations:null,placement:"bottom",overflow:"auto"},$title:null,$content:null,$buttons:null,$operations:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$content=this.$el.find("#content"),this.$title=this.$el.find("#title-text"),this.options.height&&(this.$el.find("#body").css("height",this.options.height),this.$el.find("#content").css("overflow",this.options.overflow)),this.$buttons=$(this.el).find("#buttons");if(this.options.buttons){var n=this;$.each(this.options.buttons,function(e,t){t.$el.prop("id",e),n.$buttons.append(t.$el)})}else this.$buttons.remove();this.$operations=$(this.el).find("#operations");if(this.options.operations){var n=this;$.each(this.options.operations,function(e,t){t.$el.prop("id",e),n.$operations.append(t.$el)})}this.options.body&&this.append(this.options.body)},append:function(t){this.$content.append(e.wrap(t))},content:function(){return this.$content},show:function(){this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},enableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!1)},disableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!0)},hideOperation:function(e){this.$operations.find("#"+e).hide()},showOperation:function(e){this.$operations.find("#"+e).show()},setOperation:function(e,t){var n=this.$operations.find("#"+e);n.off("click"),n.on("click",t)},title:function(e){var t=this.$title;return e&&t.html(e),t.html()},_template:function(e){var t='<div class="toolForm portlet-view no-highlight">';if(e.title||e.icon)t+='<div id="title" class="toolFormTitle portlet-title"><div id="operations" class="portlet-operations"/><div style="overflow: hidden;">',e.icon&&(t+='<div class="portlet-title-icon fa '+e.icon+'"> </div>'),t+='<div id="title-text" class="portlet-title-text">'+e.title+"</div>",t+="</div></div>";return t+='<div id="body" class="toolFormBody portlet-body">',e.placement=="top"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+='<div id="content" class="portlet-content"/>',e.placement=="bottom"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+="</div></div>",t}});return{View:t}}),define("plugin/library/ui-select",["utils/utils"],function(e){var t=Backbone.View.extend({optionsDefault:{id:"",cls:"",empty:"No data available",visible:!0,wait:!1},selected:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$select=this.$el.find("#select"),this.$icon=this.$el.find("#icon"),this.selected=this.options.value;var n=this;this.options.onchange&&this.$select.on("change",function(){n.value(n.$select.val())}),this._refresh(),this.options.visible||this.hide(),this.options.wait?this.wait():this.show()},value:function(e){var t=this.selected;e!==undefined&&(this.selected=e,this.$select.val(e));var n=this.selected;return n&&n!=t&&this.options.onchange&&this.options.onchange(n),n},text:function(){return this.$select.find("option:selected").text()},show:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-caret-down"),this.$select.show(),this.$el.show()},hide:function(){this.$el.hide()},wait:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-spinner fa-spin"),this.$select.hide()},disabled:function(){return this.$select.is(":disabled")},enable:function(){this.$select.prop("disabled",!1)},disable:function(){this.$select.prop("disabled",!0)},add:function(e){this.$select.append(this._templateOption(e)),this._refresh()},del:function(e){this.$select.find("option[value="+e+"]").remove(),this.$select.trigger("change"),this._refresh()},update:function(e){this.$select.find("option").remove();for(var t in e)this.$select.append(this._templateOption(e[t]));!this.selected&&e.length>0&&this.value(e[0].value),this._refresh()},_refresh:function(){this.$select.find("option[value=null]").remove();var e=this.$select.find("option").length;e==0?(this.$select.append(this._templateOption({value:"null",label:this.options.empty})),this.disable()):(this.enable(),this.selected&&this.$select.val(this.selected))},_exists:function(e){return 0!=this.$select.find("option[value="+e+"]").length},_templateOption:function(e){return'<option value="'+e.value+'">'+e.label+"</option>"},_template:function(e){var t='<div id="'+e.id+'" class="styled-select">'+'<div class="button">'+'<i id="icon"/>'+"</div>"+'<select id="select" class="select '+e.cls+" "+e.id+'">';for(key in e.data){var n=e.data[key],r="";if(n.value==e.value||n.value=="")r="selected";t+='<option value="'+n.value+'" '+r+">"+n.label+"</option>"}return t+="</select></div>",t}});return{View:t}}),define("plugin/library/ui",["utils/utils","plugin/library/ui-select"],function(e,t){var n=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options))},title:function(e){this.$el.find("b").html(e)},_template:function(e){return"<label><b>"+e.title+"</b></label>"},value:function(){return options.title}}),r=Backbone.View.extend({optionsDefault:{id:null,title:"","float":"right",cls:"btn-default",icon:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t='<button id="'+e.id+'" type="submit" style="margin-right: 5px; float: '+e.float+';" type="button" class="btn '+e.cls+'">';return e.icon&&(t+='<i class="icon fa '+e.icon+'"></i> '),t+=e.title+"</button>",t}}),i=Backbone.View.extend({optionsDefault:{"float":"right",icon:"",tooltip:"",placement:"bottom",title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){return'<div><span class="fa '+e.icon+'" style="font-size: 1.2em;"/> '+e.title+"</div>"}}),s=Backbone.View.extend({optionsDefault:{title:"",id:null,"float":"right",cls:"icon-btn",icon:"",tooltip:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t="";e.title&&(t="width: auto;");var n='<div id="'+e.id+'" style="margin-right: 5px; float: '+e.float+"; "+t+'" class="'+e.cls+'">';return e.title?n+='<div style="margin-right: 5px; margin-left: 5px;"><i class="icon fa '+e.icon+'"/> '+'<span style="position: relative; font-size: 0.8em; font-weight: normal; top: -1px;">'+e.title+"</span>"+"</div>":n+='<i class="icon fa '+e.icon+'"/>',n+="</div>",n}}),o=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick)},_template:function(e){return'<div><a href="javascript:void(0)">'+e.title+"</a></div>"}}),u=Backbone.View.extend({optionsDefault:{message:"",status:"info",persistent:!1},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement("<div></div>")},update:function(t){this.options=e.merge(t,this.optionsDefault);if(t.message!=""){this.$el.html(this._template(this.options)),this.$el.fadeIn();if(!t.persistent){var n=this;window.setTimeout(function(){n.$el.is(":visible")?n.$el.fadeOut():n.$el.hide()},3e3)}}else this.$el.fadeOut()},_template:function(e){return'<div class="alert alert-'+e.status+'" style="padding: 2px 2px 2px 10px;">'+e.message+"</div>"}}),a=Backbone.View.extend({optionsDefault:{onclick:null,searchword:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options));var n=this;this.options.onclick&&this.$el.on("submit",function(e){var t=n.$el.find("#search");n.options.onclick(t.val())})},_template:function(e){return'<div class="search"><form onsubmit="return false;"><input id="search" class="form-control input-sm" type="text" name="search" placeholder="Search..." value="'+e.searchword+'">'+'<button type="submit" class="btn search-btn">'+'<i class="fa fa-search"></i>'+"</button>"+"</form>"+"</div>"}}),f=Backbone.View.extend({optionsDefault:{title:"Unlabeled",body:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.body&&this.$el.find(".body").append(this.options.body)},_template:function(e){return'<div id="title" class="title">'+e.title+":"+"</div>"}}),l=Backbone.View.extend({optionsDefault:{id:"",title:"",target:"",href:"",onunload:null,onclick:null,visible:!0,icon:null,tag:""},$menu:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement($(this._template(this.options)));var n=$(this.el).find(".root"),r=this;n.on("click",function(e){e.preventDefault(),r.options.onclick&&r.options.onclick()}),this.options.visible||this.hide()},show:function(){$(this.el).show()},hide:function(){$(this.el).hide()},addMenu:function(t){var n={title:"",target:"",href:"",onclick:null,divider:!1,icon:null};n=e.merge(t,n),this.$menu||($(this.el).append(this._templateMenu()),this.$menu=$(this.el).find(".menu"));var r=$(this._templateMenuItem(n));r.on("click",function(e){e.preventDefault(),n.onclick&&n.onclick()}),this.$menu.append(r),n.divider&&this.$menu.append($(this._templateDivider()))},_templateMenuItem:function(e){var t='<li><a href="'+e.href+'" target="'+e.target+'">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),t+=" "+e.title+"</a>"+"</li>",t},_templateMenu:function(){return'<ul class="menu dropdown-menu pull-right" role="menu"></ul>'},_templateDivider:function(){return'<li class="divider"></li>'},_template:function(e){var t='<div id="'+e.id+'" class="button-menu btn-group">'+'<button type="button" class="root btn btn-default dropdown-toggle" data-toggle="dropdown">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),"</button></div>",t}}),c=Backbone.View.extend({optionsDefault:{value:"",type:"text",placeholder:"",disabled:!1,visible:!0},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.disabled&&this.$el.prop("disabled",!0),this.options.visible||this.$el.hide();var n=this;this.options.onchange&&this.$el.on("input",function(){n.options.onchange()})},value:function(e){return e!==undefined&&this.$el.val(e),this.$el.val()},_template:function(e){return'<input id="'+e.id+'" type="'+e.type+'" value="'+e.value+'" placeholder="'+e.placeholder+'" class="form-control">'}});return{Label:n,Button:r,Icon:i,ButtonIcon:s,Input:c,Anchor:o,Message:u,Searchbox:a,Title:f,Select:t,ButtonMenu:l}}),define("plugin/library/jobs",["utils/utils"],function(e){return Backbone.Model.extend({initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},cleanup:function(t){var n=t.get("dataset_id_job");if(n!=""){var r=this;e.request("PUT",config.root+"api/histories/none/contents/"+n,{deleted:!0},function(){r._refreshHdas()}),t.set("dataset_id_job","")}},submit:function(t,n,r,i){var s=this,o=t.id,u=t.get("type"),a=this.app.types.get(u);data={tool_id:"rkit",inputs:{input:{id:t.get("dataset_id"),src:"hda"},module:u,columns:r,settings:n}},t.state("submit","Sending job request..."),e.request("POST",config.root+"api/tools",data,function(e){if(!e.outputs||e.outputs.length==0)t.state("failed","Job submission failed. No response.");else{s._refreshHdas();var n=e.outputs[0];t.state("queued","Job has been queued..."),t.set("dataset_id_job",n.id),s._loop(n.id,function(e){switch(e.state){case"ok":return t.state("success","Job completed successfully..."),i(e),!0;case"error":return t.state("failed","Job has failed. Please check the history for details."),!0;case"running":return t.state("running","Job is running..."),!1}})}},function(e){var n="";e&&e.message&&e.message.data&&e.message.data.input&&(n=e.message.data.input+"."),t.state("failed","This visualization requires the R-kit. Please make sure it is installed. "+n)})},_loop:function(t,n){var r=this;e.request("GET",config.root+"api/jobs/"+t,{},function(e){n(e)||setTimeout(function(){r._loop(t,n)},r.app.config.get("query_timeout"))})},_refreshHdas:function(){Galaxy&&Galaxy.currHistoryPanel&&Galaxy.currHistoryPanel.refreshHdas()}})}),define("plugin/library/datasets",["utils/utils"],function(e){return Backbone.Collection.extend({list:{},initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},request:function(t,n,r){var i=this;if(t.groups)this._fetch(t,n);else{var s=this.list[t.id];if(s){n(s);return}e.request("GET",config.root+"api/datasets/"+t.id,{},function(e){switch(e.state){case"error":r&&r(e);break;default:i.list[t.id]=e,n(e)}})}},_fetch:function(t,n){var r=t.start?t.start:0,i=Math.abs(t.end-t.start),s=this.app.config.get("query_limit");if(!i||i>s)i=s;var o="",u={},a=0;for(var f in t.groups){var l=t.groups[f];for(var c in l.columns){var h=l.columns[c];o+=h+",",u[h]=a,a++}}if(a==0){n({});return}o=o.substring(0,o.length-1);var p=t.groups.slice(0);for(var f in p)p[f].values=[];var d=this;e.request("GET",config.root+"api/datasets/"+t.id,{data_type:"raw_data",provider:"dataset-column",limit:i,offset:r,indeces:o},function(e){for(var i in e.data){var s=e.data[i];for(var o in t.groups){var a=t.groups[o],f={x:parseInt(i)+r};for(var l in a.columns){var c=a.columns[l],h=u[c],d=s[h];if(isNaN(d)||!d)d=0;f[l]=d}p[o].values.push(f)}}n(p)})}})}),define("plugin/models/group",[],function(){return Backbone.Model.extend({defaults:{key:"Data label",date:""},reset:function(){this.clear({silent:!0}).set(this.defaults),this.trigger("reset",this)}})}),define("plugin/models/groups",["plugin/models/group"],function(e){return Backbone.Collection.extend({model:e})});var Visualization=Backbone.Model.extend({defaults:{config:{}},urlRoot:function(){var e="/api/visualizations";return window.galaxy_config&&galaxy_config.root?galaxy_config.root+e:e},initialize:function(e){_.isObject(e.config)&&_.isObject(this.defaults.config)&&_.defaults(e.config,this.defaults.config),this._setUpListeners()},_setUpListeners:function(){},set:function(e,t){if(e==="config"){var n=this.get("config");_.isObject(n)&&(t=_.extend(_.clone(n),t))}return Backbone.Model.prototype.set.call(this,e,t),this},toString:function(){var e=this.get("id")||"";return this.get("title")&&(e+=":"+this.get("title")),"Visualization("+e+")"}}),VisualizationCollection=Backbone.Collection.extend({model:Visualization,url:function(){return galaxy_config.root+"api/visualizations"},initialize:function(e,t){t=t||{}},set:function(e,t){var n=this;e=_.map(e,function(e){var t=n.get(e.id);if(!t)return e;var r=t.toJSON();return _.extend(r,e),r}),Backbone.Collection.prototype.set.call(this,e,t)},toString:function(){return["VisualizationCollection(",[this.historyId,this.length].join(),")"].join("")}});define("mvc/visualization/visualization-model",function(){}),define("plugin/models/chart",["plugin/models/groups","mvc/visualization/visualization-model"],function(e){return Backbone.Model.extend({defaults:{id:null,title:"",type:"",date:null,state:"",state_info:"",modified:!1,dataset_id:"",dataset_id_job:""},initialize:function(t){this.groups=new e,this.settings=new Backbone.Model},reset:function(){this.clear({silent:!0}).set(this.defaults),this.groups.reset(),this.settings.clear(),this.trigger("reset",this)},copy:function(e){var t=this;t.clear({silent:!0}).set(this.defaults),t.set(e.attributes),t.settings=e.settings.clone(),t.groups.reset(),e.groups.each(function(e){t.groups.add(e.clone())}),t.trigger("change",t)},state:function(e,t){this.set("state_info",t),this.set("state",e)},drawable:function(){return this.get("state")=="ok"||this.get("state")=="failed"||this.get("state")=="initialized"},editable:function(){return this.get("state")=="ok"||this.get("state")=="failed"}})}),define("plugin/library/storage",["utils/utils","plugin/models/chart","plugin/models/group"],function(e,t,n){return Backbone.Model.extend({vis:null,initialize:function(e){this.app=e,this.chart=this.app.chart,this.options=this.app.options,this.id=this.options.id,this.vis=new Visualization({type:"charts",config:{dataset_id:this.options.config.dataset_id,chart_dict:{}}}),this.id&&(this.vis.id=this.id);var t=this.options.config.chart_dict;t&&(this.vis.get("config").chart_dict=t)},save:function(){var e=this.app.chart;this.vis.get("config").chart_dict={};var t=e.get("title");t!=""&&this.vis.set("title",t);var n={attributes:e.attributes,settings:e.settings.attributes,groups:[]};e.groups.each(function(e){n.groups.push(e.attributes)}),this.vis.get("config").chart_dict=n;var r=this;this.vis.save().fail(function(e,t,n){console.error(e,t,n)}).then(function(e){e&&e.id&&(r.id=e.id)})},load:function(){var e=this.vis.get("config").chart_dict;if(!e.attributes)return!1;this.chart.set(e.attributes),this.chart.settings.set(e.settings);for(var t in e.groups)this.chart.groups.add(new n(e.groups[t]));return this.chart.state("ok","Loaded previously saved visualization."),this.chart.set("modified",!1),!0}})}),define("plugin/views/viewport",["mvc/ui/ui-portlet","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({initialize:function(e,t){this.app=e,this.chart=this.app.chart,this.options=n.merge(t,this.optionsDefault),this.setElement($(this._template()));var r=this;this.chart.on("redraw",function(){r._create_svg(),r._draw(r.chart)}),this.chart.on("change:state",function(){var e=r.$el.find("#info"),t=e.find("#icon");t.removeClass(),e.show(),e.find("#text").html(r.chart.get("state_info"));var n=r.chart.get("state");switch(n){case"ok":r.chart.trigger("drawable"),e.hide();break;case"failed":r.chart.trigger("drawable"),t.addClass("fa fa-warning");break;case"initialized":r.chart.trigger("drawable"),t.addClass("fa fa-warning");break;default:t.addClass("fa fa-spinner fa-spin")}})},show:function(){this.$el.show()},hide:function(){this.$el.hide()},_create_svg:function(){this.svg&&this.svg.remove(),this.$el.append($(this._template_svg())),this.svg=d3.select(this.$el.find("svg")[0])},_draw:function(e){var t=this;if(!e.drawable()){e.off("drawable"),e.on("drawable",function(){t.chart.off("drawable"),e.drawable()&&t._draw(e)});return}e.state("wait","Please wait...");var n=e.get("type"),r=this.app.types.get(n);if(!r.execute||r.execute&&e.get("modified"))this.app.jobs.cleanup(e),e.set("modified",!1);var t=this;require(["plugin/charts/"+n+"/"+n],function(n){var i=new n(t.app,{svg:t.svg});r.execute?e.get("dataset_id_job")==""?t.app.jobs.submit(e,t._defaultSettingsString(e),t._defaultRequestString(e),function(){this.app.storage.save(),i.draw(e,t._defaultRequestDictionary(e))}):i.draw(e,t._defaultRequestDictionary(e)):i.draw(e,t._defaultRequestDictionary(e))})},_defaultRequestString:function(e){var t=this.app.types.get(e.get("type")),n="",r=0;return e.groups.each(function(e){for(var i in t.columns)n+=i+"_"+ ++r+":"+(parseInt(e.get(i))+1)+", "}),n.substring(0,n.length-2)},_defaultSettingsString:function(e){var t="";for(key in e.settings.attributes)t+=key+":"+e.settings.get(key)+", ";return t.substring(0,t.length-2)},_defaultRequestDictionary:function(e){var t=this.app.types.get(e.get("type")),n={groups:[]};t.execute?n.id=e.get("dataset_id_job"):n.id=e.get("dataset_id");var r=0;return e.groups.each(function(e){var i={};for(var s in t.columns)i[s]=e.get(s);n.groups.push({key:++r+":"+e.get("key"),columns:i})}),n},_template:function(){return'<div style="height: 100%; min-height: 50px;"><div id="info" style="position: absolute; margin-left: 10px; margin-top: 10px; margin-bottom: 50px;"><span id="icon" style="font-size: 1.2em; display: inline-block;"/><span id="text" style="position: relative; margin-left: 5px; top: -1px; font-size: 1.0em;"/></div></div>'},_template_svg:function(){return'<svg style="height: calc(100% - 80px)"/>'}})}),define("plugin/views/viewer",["utils/utils","plugin/library/ui","mvc/ui/ui-portlet","plugin/models/group","plugin/views/viewport"],function(e,t,n,r,i){return Backbone.View.extend({initialize:function(e,r){this.app=e,this.chart=this.app.chart,this.viewport_view=new i(e);var s=this;this.portlet=new n.View({icon:"fa-bar-chart-o",title:"Viewport",operations:{edit_button:new t.ButtonIcon({icon:"fa-gear",tooltip:"Customize Chart",title:"Customize",onclick:function(){s._wait(s.chart,function(){s.app.go("editor")})}})}}),this.portlet.append(this.viewport_view.$el),this.setElement(this.portlet.$el);var s=this;this.chart.on("change:title",function(){s._refreshTitle()})},show:function(){this.$el.show(),$(window).trigger("resize")},hide:function(){this.$el.hide()},_refreshTitle:function(){var e=this.chart.get("title");this.portlet.title(e)},_wait:function(e,t){if(e.editable())t();else{var n=this;this.app.modal.show({title:"Please wait!",body:"Your chart is currently being processed. Please wait and try again.",buttons:{Close:function(){n.app.modal.hide()},Retry:function(){n.app.modal.hide(),setTimeout(function(){n._wait(e,t)},n.app.config.get("query_timeout"))}}})}}})}),define("mvc/ui/ui-tabs",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,list:{},$nav:null,$content:null,first_tab:null,optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(this.options));this.$nav=n.find(".tab-navigation"),this.$content=n.find(".tab-content"),this.setElement(n),this.list={};var r=this;this.options.operations&&$.each(this.options.operations,function(e,t){t.$el.prop("id",e),r.$nav.find(".operations").append(t.$el)});if(this.options.onnew){var i=$(this._template_tab_new(this.options));this.$nav.append(i),i.tooltip({title:"Add a new tab",placement:"bottom",container:r.$el}),i.on("click",function(e){i.tooltip("hide"),r.options.onnew()})}},add:function(e){var t=e.id,n={$title:$(this._template_tab(e)),$content:$(this._template_tab_content(e)),removable:e.ondel?!0:!1};this.list[t]=n,this.options.onnew?this.$nav.find("#new-tab").before(n.$title):this.$nav.append(n.$title),n.$content.append(e.$el),this.$content.append(n.$content),_.size(this.list)==1&&(n.$title.addClass("active"),n.$content.addClass("active"),this.first_tab=t);if(e.ondel){var r=this,i=n.$title.find("#delete");i.tooltip({title:"Delete this tab",placement:"bottom",container:r.$el}),i.on("click",function(){return i.tooltip("destroy"),r.$el.find(".tooltip").remove(),e.ondel(),!1})}e.onclick&&n.$title.on("click",function(){e.onclick()})},del:function(e){var t=this.list[e];t.$title.remove(),t.$content.remove(),delete t,this.first_tab==e&&(this.first_tab=null),this.first_tab!=null&&this.show(this.first_tab)},delRemovable:function(){for(var e in this.list){var t=this.list[e];t.removable&&this.del(e)}},show:function(e){this.$el.fadeIn("fast"),this.visible=!0,e&&this.list[e].$title.find("a").tab("show")},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},hideOperation:function(e){this.$nav.find("#"+e).hide()},showOperation:function(e){this.$nav.find("#"+e).show()},setOperation:function(e,t){var n=this.$nav.find("#"+e);n.off("click"),n.on("click",t)},title:function(e,t){var n=this.list[e].$title.find("#text");return t&&n.html(t),n.html()},_template:function(e){return'<div class="tabbable tabs-left"><ul class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div class="tab-content"/></div>'},_template_tab_new:function(e){return'<li id="new-tab"><a href="javascript:void(0);"><i style="font-size: 0.8em; margin-right: 5px;" class="fa fa-plus-circle"/>'+e.title_new+"</a>"+"</li>"},_template_tab:function(e){var t='<li id="title-'+e.id+'">'+'<a title="" href="#tab-'+e.id+'" data-toggle="tab" data-original-title="">'+'<span id="text">'+e.title+"</span>";return e.ondel&&(t+='<i id="delete" style="font-size: 0.8em; margin-left: 5px; cursor: pointer;" class="fa fa-minus-circle"/>'),t+="</a></li>",t},_template_tab_content:function(e){return'<div id="tab-'+e.id+'" class="tab-pane"/>'}});return{View:t}}),define("plugin/library/ui-table",["utils/utils"],function(e){var t=Backbone.View.extend({row:null,row_count:0,optionsDefault:{content:"No content available.",onchange:null,ondblclick:null,onconfirm:null},events:{click:"_onclick",dblclick:"_ondblclick"},first:!0,initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(t));this.$thead=n.find("thead"),this.$tbody=n.find("tbody"),this.$tmessage=n.find("tmessage"),this.setElement(n),this.row=$("<tr></tr>")},addHeader:function(e){var t=$("<th></th>");t.append(e),this.row.append(t)},appendHeader:function(){this.$thead.append(this.row),this.row=$("<tr></tr>")},add:function(e,t){var n=$("<td></td>");t&&n.css("width",t),n.append(e),this.row.append(n)},append:function(e){this._commit(e)},prepend:function(e){this._commit(e,!0)},remove:function(e){var t=this.$tbody.find("#"+e);t.length>0&&(t.remove(),this.row_count--,this._refresh())},removeAll:function(){this.$tbody.html(""),this.row_count=0,this._refresh()},value:function(e){this.before=this.$tbody.find(".current").attr("id"),e!==undefined&&(this.$tbody.find("tr").removeClass("current"),e&&this.$tbody.find("#"+e).addClass("current"));var t=this.$tbody.find(".current").attr("id");return t===undefined?null:(t!=this.before&&this.options.onchange&&this.options.onchange(e),t)},size:function(){return this.$tbody.find("tr").length},_commit:function(e,t){this.remove(e),this.row.attr("id",e),t?this.$tbody.prepend(this.row):this.$tbody.append(this.row),this.row=$("<tr></tr>"),this.row_count++,this._refresh()},_onclick:function(e){var t=this.value(),n=$(e.target).closest("tr").attr("id");n&&t!=n&&(this.options.onconfirm?this.options.onconfirm(n):this.value(n))},_ondblclick:function(e){var t=this.value();t&&this.options.ondblclick&&this.options.ondblclick(t)},_refresh:function(){this.row_count==0?this.$tmessage.show():this.$tmessage.hide()},_template:function(e){return'<div><table class="grid"><thead></thead><tbody style="cursor: pointer;"></tbody></table><tmessage>'+e.content+"</tmessage>"+"<div>"}});return{View:t}}),define("plugin/views/group",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({columns:[],initialize:function(r,i){this.app=r;var s=this;this.chart=this.app.chart,this.group=i.group,this.group_key=new t.Input({placeholder:"Data label",onchange:function(){s.group.set("key",s.group_key.value())}}),this.table=new e.View({content:"No data column."});var o=$("<div/>");o.append(n.wrap((new t.Label({title:"Provide a label:"})).$el)),o.append(n.wrap(this.group_key.$el)),o.append(n.wrap((new t.Label({title:"Select columns:"})).$el)),o.append(n.wrap(this.table.$el)),this.setElement(o);var s=this;this.chart.on("change:dataset_id",function(){s._refreshTable()}),this.chart.on("change:type",function(){s._refreshTable()}),this.group.on("change:key",function(){s._refreshGroupKey()}),this.group.on("change",function(){s._refreshGroup()}),this._refreshTable(),this._refreshGroupKey(),this._refreshGroup()},_refreshTable:function(){var e=this.chart.get("dataset_id"),n=this.chart.get("type");if(!e||!n)return;var r=this,i=this.app.types.get(n);this.table.removeAll();var s={};for(var o in i.columns){var u=this.group.get(o);u||this.group.set(o,0);var a=i.columns[o],f=new t.Select.View({id:"select_"+o,gid:o,onchange:function(e){r.group.set(this.gid,e),r.chart.set("modified",!0)},value:u,wait:!0});this.table.add(a.title,"25%"),this.table.add(f.$el),this.table.append(o),s[o]=f}this.chart.state("wait","Loading metadata..."),this.app.datasets.request({id:e},function(e){r.columns=[];var t=e.metadata_column_types;for(var n in t)(t[n]=="int"||t[n]=="float")&&r.columns.push({label:"Column: "+(parseInt(n)+1)+" ["+t[n]+"]",value:n});for(var n in s)s[n].update(r.columns),s[n].show();r.chart.state("initialized","Metadata initialized...")})},_refreshGroup:function(){this.group.set("date",n.time())},_refreshGroupKey:function(){var e=this.group.get("key");e===undefined&&(e=""),this.group_key.value(e)}})}),define("plugin/library/ui-table-form",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){var r=Backbone.View.extend({initialize:function(r){this.table_title=new t.Label({title:r.title}),this.table=new e.View({content:r.content});var i=$("<div/>");i.append(n.wrap(this.table_title.$el)),i.append(n.wrap(this.table.$el)),this.setElement(i)},title:function(e){this.table_title.title(e)},update:function(e,t){this.table.removeAll();for(var n in e)this._add(n,e[n],t)},_add:function(e,n,r){var i=null,s=n.type;switch(s){case"text":i=new t.Input({placeholder:n.placeholder,onchange:function(){r.set(e,i.value())}});break;case"select":i=new t.Select.View({data:n.data,onchange:function(){r.set(e,i.value())}});break;case"slider":i=new t.Input({placeholder:n.placeholder,onchange:function(){r.set(e,i.value())}});break;case"separator":i=$("<div/>");break;default:console.log("ui-table-form:_add","Unknown setting type ("+n.type+")");return}if(s!="separator"){r.get(e)||r.set(e,n.init),i.value(r.get(e));var o=$("<div/>");o.append(i.$el),o.append('<div class="toolParamHelp" style="font-size: 0.9em;">'+n.info+"</div>"),this.table.add('<span style="white-space: nowrap;">'+n.title+"</span>","25%"),this.table.add(o)}else this.table.add('<h6 style="white-space: nowrap;">'+n.title+":<h6/>"),this.table.add($("<div/>"));this.table.append(e)}});return{View:r}}),define("plugin/views/settings",["plugin/library/ui","plugin/library/ui-table-form","utils/utils"],function(e,t,n){return Backbone.View.extend({initialize:function(e,n){this.app=e;var r=this;this.chart=this.app.chart,this.form=new t.View({title:"Chart options:",content:"This chart type does not provide any options."}),this.setElement(this.form.$el);var r=this;this.chart.on("change",function(){r._refreshTable()})},_refreshTable:function(){var e=this.chart.get("type");if(!e)return;var t=this.app.types.get(e);this.form.title(t.title+":"),this.form.update(t.settings,this.chart.settings)}})}),define("plugin/views/editor",["mvc/ui/ui-tabs","plugin/library/ui-table","plugin/library/ui","mvc/ui/ui-portlet","utils/utils","plugin/models/chart","plugin/models/group","plugin/views/group","plugin/views/settings"],function(e,t,n,r,i,s,o,u,a){return Backbone.View.extend({optionsDefault:{header:!0,content:"No content available."},initialize:function(s,o){this.app=s,this.chart=this.app.chart,this.options=i.merge(o,this.optionsDefault),this.portlet=new r.View({icon:"fa-bar-chart-o",title:"Editor",operations:{save:new n.ButtonIcon({icon:"fa-save",tooltip:"Draw Chart",title:"Draw",onclick:function(){u.app.go("viewer"),u._saveChart()}}),back:new n.ButtonIcon({icon:"fa-caret-left",tooltip:"Return to Viewer",title:"Return",onclick:function(){u.app.go("viewer"),u.app.storage.load()}})}});var u=this;this.table=new t.View({header:!1,onconfirm:function(e){u.chart.groups.length>0?u.app.modal.show({title:"Switching to another chart type?",body:"If you continue your settings and selections will be cleared.",buttons:{Cancel:function(){u.app.modal.hide()},Continue:function(){u.app.modal.hide(),u.table.value(e)}}}):u.table.value(e)},onchange:function(e){u.chart.groups.reset(),u.chart.settings.clear(),u.chart.set({type:e})},ondblclick:function(e){u.tabs.show("settings")},content:"No chart types available"});var f=0,l=s.types.attributes;for(var c in l){var h=l[c];this.table.add(++f+"."),h.execute?this.table.add(h.title+" (requires processing)"):this.table.add(h.title),this.table.append(c)}this.tabs=new e.View({title_new:"Add Data",onnew:function(){var e=u._addGroupModel();u.tabs.show(e.id)}}),this.title=new n.Input({placeholder:"Chart title",onchange:function(){u.app.config.set("title",u.title.value())}});var p=$("<div/>");p.append(i.wrap((new n.Label({title:"Provide a chart title:"})).$el)),p.append(i.wrap(this.title.$el)),p.append(i.wrap((new n.Label({title:"Select a chart type:"})).$el)),p.append(i.wrap(this.table.$el)),this.tabs.add({id:"main",title:"Start",$el:p}),this.settings=new a(this.app),this.tabs.add({id:"settings",title:"Configuration",$el:this.settings.$el}),this.portlet.append(this.tabs.$el),this.setElement(this.portlet.$el),this.tabs.hideOperation("back");var u=this;this.chart.on("change:title",function(e){u._refreshTitle()}),this.chart.on("change:type",function(e){u.table.value(e.get("type"))}),this.chart.on("reset",function(e){u._resetChart()}),this.app.chart.on("redraw",function(e){u.portlet.showOperation("back")}),this.app.chart.groups.on("add",function(e){u._addGroup(e)}),this.app.chart.groups.on("remove",function(e){u._removeGroup(e)}),this.app.chart.groups.on("reset",function(e){u._removeAllGroups()}),this.app.chart.groups.on("change:key",function(e){u._refreshGroupKey()}),this._resetChart()},show:function(){this.$el.show()},hide:function(){this.$el.hide()},_refreshTitle:function(){var e=this.chart.get("title");this.portlet.title(e)},_refreshGroupKey:function(){var e=this,t=0;this.chart.groups.each(function(n){var r=n.get("key","");r==""&&(r="Chart data"),e.tabs.title(n.id,++t+": "+r)})},_addGroupModel:function(){var e=new o({id:i.uuid()});return this.chart.groups.add(e),e},_addGroup:function(e){var t=this,n=new u(this.app,{group:e}),r=t.chart.groups.length;this.tabs.add({id:e.id,$el:n.$el,ondel:function(){t.chart.groups.remove(e.id)}}),this._refreshGroupKey()},_removeGroup:function(e){this.tabs.del(e.id),this._refreshGroupKey(),this.chart.set("modified",!0)},_removeAllGroups:function(e){this.tabs.delRemovable()},_resetChart:function(){this.chart.set("id",i.uuid()),this.chart.set("type","bardiagram"),this.chart.set("dataset_id",this.app.options.config.dataset_id),this.chart.set("title","New Chart"),this.portlet.hideOperation("back")},_saveChart:function(){this.chart.set({type:this.table.value(),title:this.title.value(),date:i.time()}),this.chart.groups.length==0&&this._addGroupModel(),this.chart.trigger("redraw"),this.app.storage.save()}})}),define("plugin/models/config",[],function(){return Backbone.Model.extend({defaults:{query_limit:1e3,query_timeout:500}})}),define("plugin/charts/_nvd3/config",[],function(){return{title:"",columns:{y:{title:"Values for y-axis"}},settings:{separator_label:{title:"X axis",type:"separator"},x_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"X-axis",placeholder:"Axis label"},x_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"f",data:[{label:"-- Do not show values --",value:"hide"},{label:"Float",value:"f"},{label:"Exponent",value:"e"},{label:"Integer",value:"d"},{label:"Percentage",value:"p"},{label:"Rounded",value:"r"},{label:"SI-prefix",value:"s"}]},x_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_tick:{title:"Y axis",type:"separator"},y_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"Y-axis",placeholder:"Axis label"},y_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"f",data:[{label:"-- Do not show values --",value:"hide"},{label:"Float",value:"f"},{label:"Exponent",value:"e"},{label:"Integer",value:"d"},{label:"Percentage",value:"p"},{label:"Rounded",value:"r"},{label:"SI-prefix",value:"s"}]},y_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_legend:{title:"Others",type:"separator"},show_legend:{title:"Show legend",info:"Would you like to add a legend?",type:"select",init:"true",data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]}}}}),define("plugin/charts/bardiagram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram"})}),define("plugin/charts/histogram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Histogram",execute:!0,columns:{y:{title:"Observations"}},settings:{x_axis_label:{init:"Breaks"},y_axis_label:{init:"Density"},y_axis_tick:{init:".3"}}})}),define("plugin/charts/horizontal/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram (horizontal)",settings:{x_axis_type:{init:"hide"}}})}),define("plugin/charts/line/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line chart"})}),define("plugin/charts/linewithfocus/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line with focus"})}),define("plugin/charts/piechart/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Pie chart"})}),define("plugin/charts/scatterplot/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Scatter plot",columns:{x:{title:"Values for x-axis"}}})}),define("plugin/charts/stackedarea/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Stacked area"})}),define("plugin/charts/types",["plugin/charts/bardiagram/config","plugin/charts/histogram/config","plugin/charts/horizontal/config","plugin/charts/line/config","plugin/charts/linewithfocus/config","plugin/charts/piechart/config","plugin/charts/scatterplot/config","plugin/charts/stackedarea/config"],function(e,t,n,r,i,s,o,u){return Backbone.Model.extend({defaults:{bardiagram:e,horizontal:n,histogram:t,line:r,linewithfocus:i,piechart:s,scatterplot:o,stackedarea:u}})}),define("plugin/app",["mvc/ui/ui-modal","mvc/ui/ui-portlet","plugin/library/ui","utils/utils","plugin/library/jobs","plugin/library/datasets","plugin/library/storage","plugin/views/viewer","plugin/views/editor","plugin/models/config","plugin/models/chart","plugin/charts/types"],function(e,t,n,r,i,s,o,u,a,f,l,c){return Backbone.View.extend({initialize:function(t){this.options=t,Galaxy&&Galaxy.modal?this.modal=Galaxy.modal:this.modal=new e.View,this.config=new f,this.types=new c,this.chart=new l,this.jobs=new i(this),this.datasets=new s(this),this.storage=new o(this),this.viewer_view=new u(this),this.editor_view=new a(this),this.$el.append(this.viewer_view.$el),this.$el.append(this.editor_view.$el),this.storage.load()?(this.go("viewer"),this.chart.trigger("redraw")):this.go("editor")},go:function(e){$(".tooltip").hide();switch(e){case"editor":this.editor_view.show(),this.viewer_view.hide();break;case"viewer":this.editor_view.hide(),this.viewer_view.show()}},execute:function(e){},onunload:function(){},log:function(e,t){console.log(e+" "+t)}})});
\ No newline at end of file
diff -r ec715604b476c47703b90385062a6ec482cfd302 -r cab5878ce755b1736d09a9a74e419eddb12c0f2d config/plugins/visualizations/charts/static/charts/histogram/histogram.js
--- a/config/plugins/visualizations/charts/static/charts/histogram/histogram.js
+++ b/config/plugins/visualizations/charts/static/charts/histogram/histogram.js
@@ -13,9 +13,6 @@
// render
draw : function(chart, request_dictionary)
{
- // update request dataset id
- request_dictionary.id = chart.get('dataset_id_job');
-
// configure request
var index = 0;
for (var i in request_dictionary.groups) {
diff -r ec715604b476c47703b90385062a6ec482cfd302 -r cab5878ce755b1736d09a9a74e419eddb12c0f2d config/plugins/visualizations/charts/static/library/jobs.js
--- a/config/plugins/visualizations/charts/static/library/jobs.js
+++ b/config/plugins/visualizations/charts/static/library/jobs.js
@@ -17,12 +17,15 @@
cleanup: function(chart) {
// cleanup previous dataset file
var previous = chart.get('dataset_id_job');
- if (previous) {
+ if (previous != '') {
var self = this;
Utils.request('PUT', config.root + 'api/histories/none/contents/' + previous, { deleted: true }, function() {
// update galaxy history
self._refreshHdas();
});
+
+ // reset id
+ chart.set('dataset_id_job', '');
}
},
@@ -53,9 +56,6 @@
}
}
- // cleanup
- self.cleanup(chart);
-
// set chart state
chart.state('submit', 'Sending job request...');
diff -r ec715604b476c47703b90385062a6ec482cfd302 -r cab5878ce755b1736d09a9a74e419eddb12c0f2d config/plugins/visualizations/charts/static/library/storage.js
--- a/config/plugins/visualizations/charts/static/library/storage.js
+++ b/config/plugins/visualizations/charts/static/library/storage.js
@@ -77,7 +77,6 @@
this.vis.save()
.fail(function(xhr, status, message) {
console.error(xhr, status, message);
- alert( 'Error loading data:\n' + xhr.responseText );
})
.then(function(response) {
if (response && response.id) {
@@ -110,6 +109,9 @@
// reset status
this.chart.state('ok', 'Loaded previously saved visualization.');
+ // reset modified flag
+ this.chart.set('modified', false);
+
// return
return true;
}
diff -r ec715604b476c47703b90385062a6ec482cfd302 -r cab5878ce755b1736d09a9a74e419eddb12c0f2d config/plugins/visualizations/charts/static/models/chart.js
--- a/config/plugins/visualizations/charts/static/models/chart.js
+++ b/config/plugins/visualizations/charts/static/models/chart.js
@@ -7,12 +7,15 @@
{
// defaults
defaults : {
- id : null,
- title : '',
- type : '',
- date : null,
- state : 'ok',
- state_info : ''
+ id : null,
+ title : '',
+ type : '',
+ date : null,
+ state : '',
+ state_info : '',
+ modified : false,
+ dataset_id : '',
+ dataset_id_job : ''
},
// initialize
@@ -56,7 +59,11 @@
this.set('state', value);
},
- ready: function() {
+ drawable: function() {
+ return (this.get('state') == 'ok') || (this.get('state') == 'failed') || (this.get('state') == 'initialized');
+ },
+
+ editable: function() {
return (this.get('state') == 'ok') || (this.get('state') == 'failed');
}
});
diff -r ec715604b476c47703b90385062a6ec482cfd302 -r cab5878ce755b1736d09a9a74e419eddb12c0f2d config/plugins/visualizations/charts/static/views/editor.js
--- a/config/plugins/visualizations/charts/static/views/editor.js
+++ b/config/plugins/visualizations/charts/static/views/editor.js
@@ -222,10 +222,7 @@
// refresh title
_refreshTitle: function() {
var title = this.chart.get('title');
- if (title) {
- title = ' - ' + title;
- }
- this.portlet.title('Charts' + title);
+ this.portlet.title(title);
},
// update
@@ -280,6 +277,9 @@
// update titles
this._refreshGroupKey();
+
+ // reset
+ this.chart.set('modified', true);
},
// remove group
diff -r ec715604b476c47703b90385062a6ec482cfd302 -r cab5878ce755b1736d09a9a74e419eddb12c0f2d config/plugins/visualizations/charts/static/views/group.js
--- a/config/plugins/visualizations/charts/static/views/group.js
+++ b/config/plugins/visualizations/charts/static/views/group.js
@@ -98,6 +98,7 @@
gid : id,
onchange : function(value) {
self.group.set(this.gid, value);
+ self.chart.set('modified', true);
},
value : value,
wait : true
@@ -112,6 +113,9 @@
list[id] = select;
}
+ // loading
+ this.chart.state('wait', 'Loading metadata...');
+
// get dataset
this.app.datasets.request({id : dataset_id}, function(dataset) {
// configure columns
@@ -133,6 +137,9 @@
list[key].update(self.columns);
list[key].show();
}
+
+ // loading
+ self.chart.state('initialized', 'Metadata initialized...');
});
},
diff -r ec715604b476c47703b90385062a6ec482cfd302 -r cab5878ce755b1736d09a9a74e419eddb12c0f2d config/plugins/visualizations/charts/static/views/viewer.js
--- a/config/plugins/visualizations/charts/static/views/viewer.js
+++ b/config/plugins/visualizations/charts/static/views/viewer.js
@@ -32,7 +32,7 @@
title : 'Customize',
onclick : function() {
// attempt to load chart editor
- self._wait (self.app.chart, function() {
+ self._wait (self.chart, function() {
self.app.go('editor');
});
}
@@ -41,7 +41,7 @@
}
});
- // append view port
+ // append portlet
this.portlet.append(this.viewport_view.$el);
// set element
@@ -71,23 +71,20 @@
// refresh title
_refreshTitle: function() {
var title = this.chart.get('title');
- if (title) {
- title = ' - ' + title;
- }
- this.portlet.title('Charts' + title);
+ this.portlet.title(title);
},
// wait for chart to be ready
_wait: function(chart, callback) {
// get chart
- if (chart.ready()) {
+ if (chart.editable()) {
callback();
} else {
// show modal
var self = this;
this.app.modal.show({
title : 'Please wait!',
- body : 'Your chart is currently being processed. Please wait...',
+ body : 'Your chart is currently being processed. Please wait and try again.',
buttons : {
'Close' : function() {self.app.modal.hide();},
'Retry' : function() {
diff -r ec715604b476c47703b90385062a6ec482cfd302 -r cab5878ce755b1736d09a9a74e419eddb12c0f2d config/plugins/visualizations/charts/static/views/viewport.js
--- a/config/plugins/visualizations/charts/static/views/viewport.js
+++ b/config/plugins/visualizations/charts/static/views/viewport.js
@@ -5,9 +5,6 @@
// widget
return Backbone.View.extend(
{
- // height
- height : 300,
-
// initialize
initialize: function(app, options)
{
@@ -26,8 +23,48 @@
// events
var self = this;
this.chart.on('redraw', function() {
+ // create svg element
+ self._create_svg();
+
+ // initialize
self._draw(self.chart);
});
+
+ // link status handler
+ this.chart.on('change:state', function() {
+ // get info element
+ var $info = self.$el.find('#info');
+
+ // get icon
+ var $icon = $info.find('#icon');
+
+ // remove icon
+ $icon.removeClass();
+
+ // show info
+ $info.show();
+ $info.find('#text').html(self.chart.get('state_info'));
+
+ // check status
+ var state = self.chart.get('state');
+ switch (state) {
+ case 'ok':
+ self.chart.trigger('drawable');
+ $info.hide();
+ break;
+ case 'failed':
+ self.chart.trigger('drawable');
+ $icon.addClass('fa fa-warning');
+ break;
+ case 'initialized':
+ self.chart.trigger('drawable');
+ $icon.addClass('fa fa-warning');
+ break;
+ default:
+ $icon.addClass('fa fa-spinner fa-spin');
+ break;
+ }
+ });
},
// show
@@ -40,62 +77,36 @@
this.$el.hide();
},
- // add
- _draw: function(chart) {
- // link this
- var self = this;
-
- // check
- if (!chart.ready()) {
- this.app.log('viewport:_drawChart()', 'Invalid attempt to draw chart before completion.');
- return;
- }
-
+ // create
+ _create_svg: function() {
// clear svg
if (this.svg) {
this.svg.remove();
}
// create
- this.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
- this.svg.setAttribute('height', this.height);
- this.$el.append(this.svg);
+ this.$el.append($(this._template_svg()));
// find svg element
this.svg = d3.select(this.$el.find('svg')[0]);
-
- // clear all previous handlers (including redraw listeners)
- chart.off('change:state');
+ },
+
+ // add
+ _draw: function(chart) {
+ // link this
+ var self = this;
- // link status handler
- chart.on('change:state', function() {
- // get info element
- var $info = self.$el.find('#info');
-
- // get icon
- var $icon = $info.find('#icon');
-
- // remove icon
- $icon.removeClass();
-
- // show info
- $info.show();
- $info.find('#text').html(chart.get('state_info'));
-
- // check status
- var state = chart.get('state');
- switch (state) {
- case 'ok':
- $info.hide();
- break;
- case 'failed':
- $icon.addClass('fa fa-warning');
- break;
- default:
- $icon.addClass('fa fa-spinner fa-spin');
- break;
- }
- });
+ // proceed once chart is drawable
+ if (!chart.drawable()) {
+ chart.off('drawable');
+ chart.on('drawable', function() {
+ self.chart.off('drawable');
+ if (chart.drawable()) {
+ self._draw(chart);
+ }
+ });
+ return;
+ }
// set chart state
chart.state('wait', 'Please wait...');
@@ -104,6 +115,16 @@
var chart_type = chart.get('type');
var chart_settings = this.app.types.get(chart_type);
+ // clean up data if there is any from previous jobs
+ if (!chart_settings.execute ||
+ (chart_settings.execute && chart.get('modified'))) {
+ // reset jobs
+ this.app.jobs.cleanup(chart);
+
+ // reset modified flag
+ chart.set('modified', false);
+ }
+
// create chart view
var self = this;
require(['plugin/charts/' + chart_type + '/' + chart_type], function(ChartView) {
@@ -112,25 +133,26 @@
// request data
if (chart_settings.execute) {
- self.app.jobs.submit(chart, self._defaultSettingsString(chart), self._defaultRequestString(chart), function() {
+ if (chart.get('dataset_id_job') == '') {
+ // submit job
+ self.app.jobs.submit(chart, self._defaultSettingsString(chart), self._defaultRequestString(chart), function() {
+ // save
+ this.app.storage.save();
+
+ // draw
+ view.draw(chart, self._defaultRequestDictionary(chart));
+ });
+ } else {
+ // load data into view
view.draw(chart, self._defaultRequestDictionary(chart));
- });
+ }
} else {
+ // load data into view
view.draw(chart, self._defaultRequestDictionary(chart));
}
});
},
- // template
- _template: function() {
- return '<div>' +
- '<div id="info" style="text-align: center; margin-top: 20px;">' +
- '<span id="icon" style="font-size: 1.2em; display: inline-block;"/>' +
- '<span id="text" style="position: relative; margin-left: 5px; top: -1px; font-size: 1.0em;"/>' +
- '</div>' +
- '</div>';
- },
-
// create default chart request
_defaultRequestString: function(chart) {
@@ -175,10 +197,16 @@
// configure request
var request_dictionary = {
- id : chart.get('dataset_id'),
- groups : []
+ groups : []
};
+ // update request dataset id
+ if (chart_settings.execute) {
+ request_dictionary.id = chart.get('dataset_id_job');
+ } else {
+ request_dictionary.id = chart.get('dataset_id');
+ }
+
// add groups to data request
var group_index = 0;
chart.groups.each(function(group) {
@@ -198,7 +226,23 @@
// return
return request_dictionary;
- }
+ },
+
+ // template
+ _template: function() {
+ return '<div style="height: 100%; min-height: 50px;">' +
+ '<div id="info" style="position: absolute; margin-left: 10px; margin-top: 10px; margin-bottom: 50px;">' +
+ '<span id="icon" style="font-size: 1.2em; display: inline-block;"/>' +
+ '<span id="text" style="position: relative; margin-left: 5px; top: -1px; font-size: 1.0em;"/>' +
+ '</div>' +
+ '</div>';
+ },
+
+ // template svg element
+ _template_svg: function() {
+ return '<svg style="height: calc(100% - 80px)"/>';
+ },
+
});
});
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: Refactor tool error / bug reporting. Allow reporting errors via biostar in addition to existing email functionality.
by commits-noreply@bitbucket.org 24 Mar '14
by commits-noreply@bitbucket.org 24 Mar '14
24 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ec715604b476/
Changeset: ec715604b476
User: dan
Date: 2014-03-24 21:19:35
Summary: Refactor tool error / bug reporting. Allow reporting errors via biostar in addition to existing email functionality.
Affected #: 5 files
diff -r 6e9354d1fbdfd92ff316c52302945c02bbf13a0c -r ec715604b476c47703b90385062a6ec482cfd302 lib/galaxy/tools/errors.py
--- /dev/null
+++ b/lib/galaxy/tools/errors.py
@@ -0,0 +1,121 @@
+"""
+Functionality for dealing with tool errors.
+"""
+import string
+from galaxy import model, util, web
+
+error_report_template = """
+GALAXY TOOL ERROR REPORT
+------------------------
+
+This error report was sent from the Galaxy instance hosted on the server
+"${host}"
+-----------------------------------------------------------------------------
+This is in reference to dataset id ${dataset_id} from history id ${history_id}
+-----------------------------------------------------------------------------
+You should be able to view the history containing the related history item
+
+${hid}: ${history_item_name}
+
+by logging in as a Galaxy admin user to the Galaxy instance referenced above
+and pointing your browser to the following link.
+
+${history_view_link}
+-----------------------------------------------------------------------------
+The user '${email}' provided the following information:
+
+${message}
+-----------------------------------------------------------------------------
+job id: ${job_id}
+tool id: ${job_tool_id}
+job pid or drm id: ${job_runner_external_id}
+-----------------------------------------------------------------------------
+job command line:
+${job_command_line}
+-----------------------------------------------------------------------------
+job stderr:
+${job_stderr}
+-----------------------------------------------------------------------------
+job stdout:
+${job_stdout}
+-----------------------------------------------------------------------------
+job info:
+${job_info}
+-----------------------------------------------------------------------------
+job traceback:
+${job_traceback}
+-----------------------------------------------------------------------------
+(This is an automated message).
+"""
+
+class ErrorReporter( object ):
+ def __init__( self, hda, app ):
+ # Get the dataset
+ sa_session = app.model.context
+ if not isinstance( hda, model.HistoryDatasetAssociation ):
+ try:
+ hda = sa_session.query( model.HistoryDatasetAssociation ).get( hda )
+ except:
+ hda = sa_session.query( model.HistoryDatasetAssociation ).get( app.security.decode_id( hda ) )
+ assert isinstance( hda, model.HistoryDatasetAssociation ), ValueError( "Bad value provided for HDA (%s)." % ( hda ) )
+ self.hda = hda
+ # Get the associated job
+ self.job = hda.creating_job
+ self.app = app
+ self.tool_id = self.job.tool_id
+ self.report = None
+ def _can_access_dataset( self, user ):
+ if user:
+ roles = user.all_roles()
+ else:
+ roles = []
+ return self.app.security_agent.can_access_dataset( roles, self.hda.dataset )
+ def create_report( self, email='', message='', **kwd ):
+ hda = self.hda
+ job = self.job
+ host = web.url_for( '/', qualified=True )
+ history_view_link = web.url_for( controller="history", action="view", id=self.app.security.encode_id( hda.history_id ), qualified=True )
+ # Build the email message
+ self.report = string.Template( error_report_template ) \
+ .safe_substitute( host=host,
+ dataset_id=hda.dataset_id,
+ history_id=hda.history_id,
+ hid=hda.hid,
+ history_item_name=hda.get_display_name(),
+ history_view_link=history_view_link,
+ job_id=job.id,
+ job_tool_id=job.tool_id,
+ job_runner_external_id=job.job_runner_external_id,
+ job_command_line=job.command_line,
+ job_stderr=util.unicodify( job.stderr ),
+ job_stdout=util.unicodify( job.stdout ),
+ job_info=util.unicodify( job.info ),
+ job_traceback=util.unicodify( job.traceback ),
+ email=email,
+ message=util.unicodify( message ) )
+ def _send_report( self, user, email=None, message=None, **kwd ):
+ return self.report
+ def send_report( self, user, email=None, message=None, **kwd ):
+ if self.report is None:
+ self.create_report( email=email, message=message, **kwd )
+ return self._send_report( user, email=email, message=message, **kwd )
+
+class EmailErrorReporter( ErrorReporter ):
+ def _send_report( self, user, email=None, message=None, **kwd ):
+ smtp_server = self.app.config.smtp_server
+ assert smtp_server, ValueError( "Mail is not configured for this galaxy instance" )
+ to_address = self.app.config.error_email_to
+ assert to_address, ValueError( "Error reporting has been disabled for this galaxy instance" )
+
+ frm = to_address
+ # Check email a bit
+ email = email or ''
+ email = email.strip()
+ parts = email.split()
+ if len( parts ) == 1 and len( email ) > 0 and self._can_access_dataset( user ):
+ to = to_address + ", " + email
+ else:
+ to = to_address
+ subject = "Galaxy tool error report from %s" % email
+ # Send it
+ return util.send_mail( frm, to, subject, self.report, self.app.config )
diff -r 6e9354d1fbdfd92ff316c52302945c02bbf13a0c -r ec715604b476c47703b90385062a6ec482cfd302 lib/galaxy/util/biostar.py
--- a/lib/galaxy/util/biostar.py
+++ b/lib/galaxy/util/biostar.py
@@ -7,6 +7,7 @@
import re
from unicodedata import normalize
from galaxy.web.base.controller import url_for
+from galaxy.tools.errors import ErrorReporter
_punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?(a)\[\\\]^_`{|},.]+')
@@ -27,6 +28,8 @@
# Slugifying from Armin Ronacher (http://flask.pocoo.org/snippets/5/)
def slugify(text, delim=u'-'):
"""Generates an slightly worse ASCII-only slug."""
+ if not isinstance( text, unicode ):
+ text = unicode( text )
result = []
for word in _punct_re.split(text.lower()):
word = normalize('NFKD', word).encode('ascii', 'ignore')
@@ -63,7 +66,7 @@
Generate a reasonable biostar tag for a tool.
"""
#Biostar can now handle tags with spaces, do we want to generate tags differently now?
- return slugify( unicode( tool.name ), delim='-' )
+ return slugify( tool.name, delim='-' )
def populate_tag_payload( payload=None, tool=None ):
if payload is None:
@@ -119,3 +122,18 @@
delete_cookie( trans, trans.app.config.biostar_key_name )
return get_biostar_url( trans.app, biostar_action='log_out' )
return None
+
+class BiostarErrorReporter( ErrorReporter ):
+ def _send_report( self, user, email=None, message=None, **kwd ):
+ assert biostar_enabled( self.app ), ValueError( "Biostar is not configured for this galaxy instance" )
+ assert self._can_access_dataset( user ), Exception( "You are not allowed to access this dataset." )
+ tool_version_select_field, tools, tool = \
+ self.app.toolbox.get_tool_components( self.tool_id, tool_version=None, get_loaded_tools_by_lineage=False, set_selected=True )
+ payload = { 'title': 'Bug report on "%s" tool' % ( tool.name ), 'content': self.report.replace( '\n', '<br />' ), 'tag_val':slugify( 'bug report' ) }
+ #Get footer for email from here
+ payload2 = populate_tool_payload( tool=tool )
+ if 'content' in payload2:
+ payload[ 'content' ] = "%s<br />%s" % ( payload['content'], payload2['content'] )
+ if 'tag_val' in payload2:
+ payload[ 'tag_val' ] = ','.join( [ payload2[ 'tag_val' ], payload[ 'tag_val' ] ] )
+ return payload
diff -r 6e9354d1fbdfd92ff316c52302945c02bbf13a0c -r ec715604b476c47703b90385062a6ec482cfd302 lib/galaxy/webapps/galaxy/controllers/biostar.py
--- a/lib/galaxy/webapps/galaxy/controllers/biostar.py
+++ b/lib/galaxy/webapps/galaxy/controllers/biostar.py
@@ -75,6 +75,19 @@
return self.biostar_question_redirect( trans, payload )
@web.expose
+ def biostar_tool_bug_report( self, trans, hda=None, email=None, message=None ):
+ """
+ Generate a redirect to a Biostar site using external authentication to
+ pass Galaxy user information and information about a specific tool error.
+ """
+ try:
+ error_reporter = biostar.BiostarErrorReporter( hda, trans.app )
+ payload = error_reporter.send_report( trans.user, email=email, message=message )
+ except Exception, e:
+ return error( str( e ) )
+ return self.biostar_question_redirect( trans, payload=payload )
+
+ @web.expose
def biostar_logout( self, trans ):
"""
Log out of biostar
diff -r 6e9354d1fbdfd92ff316c52302945c02bbf13a0c -r ec715604b476c47703b90385062a6ec482cfd302 lib/galaxy/webapps/galaxy/controllers/dataset.py
--- a/lib/galaxy/webapps/galaxy/controllers/dataset.py
+++ b/lib/galaxy/webapps/galaxy/controllers/dataset.py
@@ -1,6 +1,5 @@
import logging
import os
-import string
import tempfile
import urllib
import zipfile
@@ -14,6 +13,7 @@
from galaxy.web.base.controller import BaseUIController, ERROR, SUCCESS, url_for, UsesHistoryDatasetAssociationMixin, UsesHistoryMixin, UsesExtendedMetadataMixin
from galaxy.web.framework.helpers import grids, iff, time_ago
from galaxy.web.framework.helpers import to_unicode
+from galaxy.tools.errors import EmailErrorReporter
eggs.require( "Paste" )
import paste.httpexceptions
@@ -27,51 +27,6 @@
except ImportError:
pass
-
-error_report_template = """
-GALAXY TOOL ERROR REPORT
-------------------------
-
-This error report was sent from the Galaxy instance hosted on the server
-"${host}"
------------------------------------------------------------------------------
-This is in reference to dataset id ${dataset_id} from history id ${history_id}
------------------------------------------------------------------------------
-You should be able to view the history containing the related history item
-
-${hid}: ${history_item_name}
-
-by logging in as a Galaxy admin user to the Galaxy instance referenced above
-and pointing your browser to the following link.
-
-${history_view_link}
------------------------------------------------------------------------------
-The user '${email}' provided the following information:
-
-${message}
------------------------------------------------------------------------------
-job id: ${job_id}
-tool id: ${job_tool_id}
-job pid or drm id: ${job_runner_external_id}
------------------------------------------------------------------------------
-job command line:
-${job_command_line}
------------------------------------------------------------------------------
-job stderr:
-${job_stderr}
------------------------------------------------------------------------------
-job stdout:
-${job_stdout}
------------------------------------------------------------------------------
-job info:
-${job_info}
------------------------------------------------------------------------------
-job traceback:
-${job_traceback}
------------------------------------------------------------------------------
-(This is an automated message).
-"""
-
class HistoryDatasetAssociationListGrid( grids.Grid ):
# Custom columns for grid.
class HistoryColumn( grids.GridColumn ):
@@ -197,50 +152,15 @@
except:
exit_code = "Invalid dataset ID or you are not allowed to access this dataset"
return exit_code
+
@web.expose
def report_error( self, trans, id, email='', message="", **kwd ):
- smtp_server = trans.app.config.smtp_server
- if smtp_server is None:
- return trans.show_error_message( "Mail is not configured for this galaxy instance" )
- to_address = trans.app.config.error_email_to
- if to_address is None:
- return trans.show_error_message( "Error reporting has been disabled for this galaxy instance" )
- # Get the dataset and associated job
- hda = trans.sa_session.query( model.HistoryDatasetAssociation ).get( id )
- job = hda.creating_job
- # Get the name of the server hosting the Galaxy instance from which this report originated
- host = trans.request.host
- history_view_link = "%s/history/view?id=%s" % ( str( host ), trans.security.encode_id( hda.history_id ) )
- # Build the email message
- body = string.Template( error_report_template ) \
- .safe_substitute( host=host,
- dataset_id=hda.dataset_id,
- history_id=hda.history_id,
- hid=hda.hid,
- history_item_name=hda.get_display_name(),
- history_view_link=history_view_link,
- job_id=job.id,
- job_tool_id=job.tool_id,
- job_runner_external_id=job.job_runner_external_id,
- job_command_line=job.command_line,
- job_stderr=util.unicodify( job.stderr ),
- job_stdout=util.unicodify( job.stdout ),
- job_info=util.unicodify( job.info ),
- job_traceback=util.unicodify( job.traceback ),
- email=email,
- message=util.unicodify( message ) )
- frm = to_address
- # Check email a bit
- email = email.strip()
- parts = email.split()
- if len( parts ) == 1 and len( email ) > 0 and self._can_access_dataset( trans, hda ):
- to = to_address + ", " + email
- else:
- to = to_address
- subject = "Galaxy tool error report from %s" % email
- # Send it
+ biostar_report = 'biostar' in str( kwd.get( 'submit_error_report') ).lower()
+ if biostar_report:
+ return trans.response.send_redirect( url_for( controller='biostar', action='biostar_tool_bug_report', hda=id, email=email, message=message ) )
try:
- util.send_mail( frm, to, subject, body, trans.app.config )
+ error_reporter = EmailErrorReporter( id, trans.app )
+ error_reporter.send_report( user=trans.user, email=email, message=message )
return trans.show_ok_message( "Your error report has been sent" )
except Exception, e:
return trans.show_error_message( "An error occurred sending the report by email: %s" % str( e ) )
diff -r 6e9354d1fbdfd92ff316c52302945c02bbf13a0c -r ec715604b476c47703b90385062a6ec482cfd302 templates/webapps/galaxy/dataset/errors.mako
--- a/templates/webapps/galaxy/dataset/errors.mako
+++ b/templates/webapps/galaxy/dataset/errors.mako
@@ -71,7 +71,10 @@
<textarea name="message" rows="10" cols="40"></textarea></div><div class="form-row">
- <input type="submit" name="submit_error_report" value="Report"/>
+ <input type="submit" name="submit_error_report" value="Report" onclick="form.setAttribute('target', '_self');"/>
+ %if trans.app.config.biostar_url:
+ <input type="submit" name="submit_error_report" value="Post on Biostar" onclick="form.setAttribute('target', '_blank');"/>
+ %endif
</div></form></div>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: martenson: correct for random error that happens during grunt build (this css modification is just randomly modified for some builds)
by commits-noreply@bitbucket.org 24 Mar '14
by commits-noreply@bitbucket.org 24 Mar '14
24 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/6e9354d1fbdf/
Changeset: 6e9354d1fbdf
User: martenson
Date: 2014-03-24 20:15:10
Summary: correct for random error that happens during grunt build (this css modification is just randomly modified for some builds)
Affected #: 1 file
diff -r 68d35caf407f367c3447a1a6675d6705c8daacf4 -r 6e9354d1fbdfd92ff316c52302945c02bbf13a0c static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -41,7 +41,7 @@
body{font-family:"Lucida Grande",verdana,arial,helvetica,sans-serif;font-size:12px;line-height:1.428571429;color:#333;background-color:#fff}
input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}
button,input,select[multiple],textarea{background-image:none}
-a{color:#5f6990;text-decoration:none}a:hover,a:focus{color:#404862;text-decoration:underline}
+a{color:#303030;text-decoration:none}a:hover,a:focus{color:#0a0a0a;text-decoration:underline}
a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
img{vertical-align:middle}
.img-responsive{display:block;max-width:100%;height:auto}
@@ -114,13 +114,13 @@
.col-xs-12{width:100%}
@media (min-width:768px){.container{max-width:750px} .col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11{float:left} .col-sm-1{width:8.333333333333332%} .col-sm-2{width:16.666666666666664%} .col-sm-3{width:25%} .col-sm-4{width:33.33333333333333%} .col-sm-5{width:41.66666666666667%} .col-sm-6{width:50%} .col-sm-7{width:58.333333333333336%} .col-sm-8{width:66.66666666666666%} .col-sm-9{width:75%} .col-sm-10{width:83.33333333333334%} .col-sm-11{width:91.66666666666666%} .col-sm-12{width:100%} .col-sm-push-1{left:8.333333333333332%} .col-sm-push-2{left:16.666666666666664%} .col-sm-push-3{left:25%} .col-sm-push-4{left:33.33333333333333%} .col-sm-push-5{left:41.66666666666667%} .col-sm-push-6{left:50%} .col-sm-push-7{left:58.333333333333336%} .col-sm-push-8{left:66.66666666666666%} .col-sm-push-9{left:75%} .col-sm-push-10{left:83.33333333333334%} .col-sm-push-11{left:91.66666666666666%} .col-sm-pull-1{right:8.333333333333332%} .col-sm-pull-2{right:16.666666666666664%} .col-sm-pull-3{right:25%} .col-sm-pull-4{right:33.33333333333333%} .col-sm-pull-5{right:41.66666666666667%} .col-sm-pull-6{right:50%} .col-sm-pull-7{right:58.333333333333336%} .col-sm-pull-8{right:66.66666666666666%} .col-sm-pull-9{right:75%} .col-sm-pull-10{right:83.33333333333334%} .col-sm-pull-11{right:91.66666666666666%} .col-sm-offset-1{margin-left:8.333333333333332%} .col-sm-offset-2{margin-left:16.666666666666664%} .col-sm-offset-3{margin-left:25%} .col-sm-offset-4{margin-left:33.33333333333333%} .col-sm-offset-5{margin-left:41.66666666666667%} .col-sm-offset-6{margin-left:50%} .col-sm-offset-7{margin-left:58.333333333333336%} .col-sm-offset-8{margin-left:66.66666666666666%} .col-sm-offset-9{margin-left:75%} .col-sm-offset-10{margin-left:83.33333333333334%} .col-sm-offset-11{margin-left:91.66666666666666%}}@media (min-width:992px){.container{max-width:970px} .col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11{float:left} .col-md-1{width:8.333333333333332%} .col-md-2{width:16.666666666666664%} .col-md-3{width:25%} .col-md-4{width:33.33333333333333%} .col-md-5{width:41.66666666666667%} .col-md-6{width:50%} .col-md-7{width:58.333333333333336%} .col-md-8{width:66.66666666666666%} .col-md-9{width:75%} .col-md-10{width:83.33333333333334%} .col-md-11{width:91.66666666666666%} .col-md-12{width:100%} .col-md-push-0{left:auto} .col-md-push-1{left:8.333333333333332%} .col-md-push-2{left:16.666666666666664%} .col-md-push-3{left:25%} .col-md-push-4{left:33.33333333333333%} .col-md-push-5{left:41.66666666666667%} .col-md-push-6{left:50%} .col-md-push-7{left:58.333333333333336%} .col-md-push-8{left:66.66666666666666%} .col-md-push-9{left:75%} .col-md-push-10{left:83.33333333333334%} .col-md-push-11{left:91.66666666666666%} .col-md-pull-0{right:auto} .col-md-pull-1{right:8.333333333333332%} .col-md-pull-2{right:16.666666666666664%} .col-md-pull-3{right:25%} .col-md-pull-4{right:33.33333333333333%} .col-md-pull-5{right:41.66666666666667%} .col-md-pull-6{right:50%} .col-md-pull-7{right:58.333333333333336%} .col-md-pull-8{right:66.66666666666666%} .col-md-pull-9{right:75%} .col-md-pull-10{right:83.33333333333334%} .col-md-pull-11{right:91.66666666666666%} .col-md-offset-0{margin-left:0} .col-md-offset-1{margin-left:8.333333333333332%} .col-md-offset-2{margin-left:16.666666666666664%} .col-md-offset-3{margin-left:25%} .col-md-offset-4{margin-left:33.33333333333333%} .col-md-offset-5{margin-left:41.66666666666667%} .col-md-offset-6{margin-left:50%} .col-md-offset-7{margin-left:58.333333333333336%} .col-md-offset-8{margin-left:66.66666666666666%} .col-md-offset-9{margin-left:75%} .col-md-offset-10{margin-left:83.33333333333334%} .col-md-offset-11{margin-left:91.66666666666666%}}@media (min-width:1200px){.container{max-width:1170px} .col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11{float:left} .col-lg-1{width:8.333333333333332%} .col-lg-2{width:16.666666666666664%} .col-lg-3{width:25%} .col-lg-4{width:33.33333333333333%} .col-lg-5{width:41.66666666666667%} .col-lg-6{width:50%} .col-lg-7{width:58.333333333333336%} .col-lg-8{width:66.66666666666666%} .col-lg-9{width:75%} .col-lg-10{width:83.33333333333334%} .col-lg-11{width:91.66666666666666%} .col-lg-12{width:100%} .col-lg-push-0{left:auto} .col-lg-push-1{left:8.333333333333332%} .col-lg-push-2{left:16.666666666666664%} .col-lg-push-3{left:25%} .col-lg-push-4{left:33.33333333333333%} .col-lg-push-5{left:41.66666666666667%} .col-lg-push-6{left:50%} .col-lg-push-7{left:58.333333333333336%} .col-lg-push-8{left:66.66666666666666%} .col-lg-push-9{left:75%} .col-lg-push-10{left:83.33333333333334%} .col-lg-push-11{left:91.66666666666666%} .col-lg-pull-0{right:auto} .col-lg-pull-1{right:8.333333333333332%} .col-lg-pull-2{right:16.666666666666664%} .col-lg-pull-3{right:25%} .col-lg-pull-4{right:33.33333333333333%} .col-lg-pull-5{right:41.66666666666667%} .col-lg-pull-6{right:50%} .col-lg-pull-7{right:58.333333333333336%} .col-lg-pull-8{right:66.66666666666666%} .col-lg-pull-9{right:75%} .col-lg-pull-10{right:83.33333333333334%} .col-lg-pull-11{right:91.66666666666666%} .col-lg-offset-0{margin-left:0} .col-lg-offset-1{margin-left:8.333333333333332%} .col-lg-offset-2{margin-left:16.666666666666664%} .col-lg-offset-3{margin-left:25%} .col-lg-offset-4{margin-left:33.33333333333333%} .col-lg-offset-5{margin-left:41.66666666666667%} .col-lg-offset-6{margin-left:50%} .col-lg-offset-7{margin-left:58.333333333333336%} .col-lg-offset-8{margin-left:66.66666666666666%} .col-lg-offset-9{margin-left:75%} .col-lg-offset-10{margin-left:83.33333333333334%} .col-lg-offset-11{margin-left:91.66666666666666%}}table{max-width:100%;background-color:transparent}
th{text-align:left}
-.table{width:100%;margin-bottom:17px}.table thead>tr>th,.table tbody>tr>th,.table tfoot>tr>th,.table thead>tr>td,.table tbody>tr>td,.table tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #bfbfbf}
-.table thead>tr>th{vertical-align:bottom;border-bottom:2px solid #bfbfbf}
+.table{width:100%;margin-bottom:17px}.table thead>tr>th,.table tbody>tr>th,.table tfoot>tr>th,.table thead>tr>td,.table tbody>tr>td,.table tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #d6b161}
+.table thead>tr>th{vertical-align:bottom;border-bottom:2px solid #d6b161}
.table caption+thead tr:first-child th,.table colgroup+thead tr:first-child th,.table thead:first-child tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child td{border-top:0}
-.table tbody+tbody{border-top:2px solid #bfbfbf}
+.table tbody+tbody{border-top:2px solid #d6b161}
.table .table{background-color:#fff}
.table-condensed thead>tr>th,.table-condensed tbody>tr>th,.table-condensed tfoot>tr>th,.table-condensed thead>tr>td,.table-condensed tbody>tr>td,.table-condensed tfoot>tr>td{padding:5px}
-.table-bordered{border:1px solid #bfbfbf}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #bfbfbf}
+.table-bordered{border:1px solid #d6b161}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #d6b161}
.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}
.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}
.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}
@@ -133,7 +133,7 @@
.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th{background-color:#f7b0ae;border-color:#c61913}
.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fce1ba;border-color:#e28709}
.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th{background-color:#fbd6a2;border-color:#c97908}
-@media (max-width:768px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;overflow-x:scroll;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #bfbfbf;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0;background-color:#fff}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap} .table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0} .table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0} .table-responsive>.table-bordered>thead>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>thead>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}
+@media (max-width:768px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;overflow-x:scroll;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #d6b161;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0;background-color:#fff}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap} .table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0} .table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0} .table-responsive>.table-bordered>thead>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>thead>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}
legend{display:block;width:100%;padding:0;margin-bottom:17px;font-size:18px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #bfbfbf}
label{display:inline-block;margin-bottom:5px;font-weight:bold}
input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
@@ -148,7 +148,7 @@
.form-control::-moz-placeholder{color:#999}
.form-control:-ms-input-placeholder{color:#999}
.form-control::-webkit-input-placeholder{color:#999}
-.form-control{display:block;width:100%;height:27px;padding:4px 10px;font-size:12px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;border:1px solid #bfbfbf;border-radius:3px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s, box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s, box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6)}
+.form-control{display:block;width:100%;height:27px;padding:4px 10px;font-size:12px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;border:1px solid #aaa;border-radius:3px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s, box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s, box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6)}
.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}
textarea.form-control{height:auto}
.form-group{margin-bottom:15px}
@@ -202,9 +202,9 @@
.btn-info{color:#fff;background-color:#3186a0;border-color:#010304}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#276c81;border-color:#000}
.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}
.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#3186a0;border-color:#010304}
-.btn-link{color:#5f6990;font-weight:normal;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}
+.btn-link{color:#303030;font-weight:normal;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}
.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}
-.btn-link:hover,.btn-link:focus{color:#404862;text-decoration:underline;background-color:transparent}
+.btn-link:hover,.btn-link:focus{color:#0a0a0a;text-decoration:underline;background-color:transparent}
.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}
.btn-lg{padding:8px 14px;font-size:15px;line-height:1.33;border-radius:5px}
.btn-sm,.btn-xs{padding:3px 8px;font-size:11px;line-height:1.5;border-radius:2px}
@@ -486,7 +486,7 @@
textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}
.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}
.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}
-.input-group-addon{padding:4px 10px;font-size:12px;font-weight:normal;line-height:1;text-align:center;background-color:#eee;border:1px solid #bfbfbf;border-radius:3px}.input-group-addon.input-sm{padding:3px 8px;font-size:11px;border-radius:2px}
+.input-group-addon{padding:4px 10px;font-size:12px;font-weight:normal;line-height:1;text-align:center;background-color:#eee;border:1px solid #aaa;border-radius:3px}.input-group-addon.input-sm{padding:3px 8px;font-size:11px;border-radius:2px}
.input-group-addon.input-lg{padding:8px 14px;font-size:15px;border-radius:5px}
.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}
.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}
@@ -502,7 +502,7 @@
.nav:after{clear:both}
.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:4px 10px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}
.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;background-color:transparent;cursor:not-allowed}
-.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#5f6990}
+.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#303030}
.nav .nav-divider{height:1px;margin:7.5px 0;overflow:hidden;background-color:#e5e5e5}
.nav>li>a>img{max-width:none}
.nav-tabs{border-bottom:1px solid #bfbfbf}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:3px 3px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #bfbfbf}
@@ -526,8 +526,8 @@
.tabbable:after{clear:both}
.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}
.tab-content>.active,.pill-content>.active{display:block}
-.nav .caret{border-top-color:#5f6990;border-bottom-color:#5f6990}
-.nav a:hover .caret{border-top-color:#404862;border-bottom-color:#404862}
+.nav .caret{border-top-color:#303030;border-bottom-color:#303030}
+.nav a:hover .caret{border-top-color:#0a0a0a;border-bottom-color:#0a0a0a}
.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}
.navbar{position:relative;z-index:1000;min-height:33px;margin-bottom:17px;border:1px solid transparent}.navbar:before,.navbar:after{content:" ";display:table;}
.navbar:after{clear:both}
@@ -617,7 +617,7 @@
.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:11px;font-weight:bold;color:#fff;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center;background-color:#999;border-radius:10px}.badge:empty{display:none}
a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}
.btn .badge{position:relative;top:-1px}
-a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#5f6990;background-color:#fff}
+a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#303030;background-color:#fff}
.nav-pills>li>a>.badge{margin-left:3px}
.jumbotron{padding:30px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1{line-height:1;color:inherit}
.jumbotron p{line-height:1.4}
@@ -672,7 +672,7 @@
.panel>.list-group .list-group-item:last-child{border-bottom:0}
.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}
.panel>.table{margin-bottom:0}
-.panel>.panel-body+.table{border-top:1px solid #bfbfbf}
+.panel>.panel-body+.table{border-top:1px solid #d6b161}
.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:2px;border-top-left-radius:2px}
.panel-title{margin-top:0;margin-bottom:0;font-size:14px}.panel-title>a{color:inherit}
.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #bfbfbf;border-bottom-right-radius:2px;border-bottom-left-radius:2px}
@@ -1454,7 +1454,7 @@
select{padding:2px;font-size:12px;line-height:1.428571429}
select,input,textarea{font:inherit}
.form-row select,.form-row textarea,.form-row input[type="text"],.form-row input[type="file"],.form-row input[type="password"]{max-width:90%}
-textarea,input[type="text"],input[type="password"]{font-size:12px;line-height:1.428571429;border:1px solid #bfbfbf;padding:3px}
+textarea,input[type="text"],input[type="password"]{font-size:12px;line-height:1.428571429;border:1px solid #aaa;padding:3px}
input[type="submit"],button{display:inline-block;padding:4px 10px;margin-bottom:0;font-size:12px;font-weight:normal;line-height:1.428571429;text-align:center;vertical-align:middle;cursor:pointer;border:1px solid transparent;border-radius:3px;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:normal;color:#333;background-color:#f2f2f2;border-color:#bfbfbf}input[type="submit"]:focus,button:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
input[type="submit"]:hover,button:hover,input[type="submit"]:focus,button:focus{color:#333;text-decoration:none}
input[type="submit"]:active,button:active,input[type="submit"].active,button.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}
@@ -1465,7 +1465,7 @@
input[type="submit"].btn-primary,button.btn-primary{color:#fff;background-color:#5f6990;border-color:#0e0f15}input[type="submit"].btn-primary:hover,button.btn-primary:hover,input[type="submit"].btn-primary:focus,button.btn-primary:focus,input[type="submit"].btn-primary:active,button.btn-primary:active,input[type="submit"].btn-primary.active,button.btn-primary.active,.open .dropdown-toggleinput[type="submit"].btn-primary,.open .dropdown-togglebutton.btn-primary{color:#fff;background-color:#4e5777;border-color:#000}
input[type="submit"].btn-primary:active,button.btn-primary:active,input[type="submit"].btn-primary.active,button.btn-primary.active,.open .dropdown-toggleinput[type="submit"].btn-primary,.open .dropdown-togglebutton.btn-primary{background-image:none}
input[type="submit"].btn-primary.disabled,button.btn-primary.disabled,input[type="submit"].btn-primary[disabled],button.btn-primary[disabled],fieldset[disabled] input[type="submit"].btn-primary,fieldset[disabled] button.btn-primary,input[type="submit"].btn-primary.disabled:hover,button.btn-primary.disabled:hover,input[type="submit"].btn-primary[disabled]:hover,button.btn-primary[disabled]:hover,fieldset[disabled] input[type="submit"].btn-primary:hover,fieldset[disabled] button.btn-primary:hover,input[type="submit"].btn-primary.disabled:focus,button.btn-primary.disabled:focus,input[type="submit"].btn-primary[disabled]:focus,button.btn-primary[disabled]:focus,fieldset[disabled] input[type="submit"].btn-primary:focus,fieldset[disabled] button.btn-primary:focus,input[type="submit"].btn-primary.disabled:active,button.btn-primary.disabled:active,input[type="submit"].btn-primary[disabled]:active,button.btn-primary[disabled]:active,fieldset[disabled] input[type="submit"].btn-primary:active,fieldset[disabled] button.btn-primary:active,input[type="submit"].btn-primary.disabled.active,button.btn-primary.disabled.active,input[type="submit"].btn-primary[disabled].active,button.btn-primary[disabled].active,fieldset[disabled] input[type="submit"].btn-primary.active,fieldset[disabled] button.btn-primary.active{background-color:#5f6990;border-color:#0e0f15}
-.search-query{display:inline-block;padding:4px;font-size:12px;line-height:1.428571429;color:#555;border:1px solid #bfbfbf;padding-left:14px !important;padding-right:14px;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;max-width:auto}
+.search-query{display:inline-block;padding:4px;font-size:12px;line-height:1.428571429;color:#555;border:1px solid #aaa;padding-left:14px !important;padding-right:14px;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;max-width:auto}
.search-query:focus{border-color:rgba(24,132,218,0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);outline:0;outline:thin dotted \9;}
.search-spinner{position:absolute;display:none;right:6px;top:9px}
#search-clear-btn{position:absolute;right:6px;top:5px;display:block;font-size:1.4em;text-decoration:none;color:#888;font-family:FontAwesome;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#search-clear-btn:before{content:"\f057"}
@@ -1506,9 +1506,9 @@
table.tabletip th{white-space:nowrap;border-bottom:1px solid #444;padding-right:3px}
table.tabletip td{border-bottom:1px solid #ddd}
table.tabletip tbody tr:hover td{background-color:#eee}
-table.colored{border-top:solid #bfbfbf 1px;border-bottom:solid #bfbfbf 1px}
+table.colored{border-top:solid #d6b161 1px;border-bottom:solid #d6b161 1px}
table.colored td,table.colored th{text-align:left;padding:5px;line-height:1.428571429}
-table.colored tr.header{background:#ebd9b2;color:#000;background-repeat:repeat-x;background-position:top;border-bottom:solid #bfbfbf 1px;font-weight:bold}
+table.colored tr.header{background:#ebd9b2;color:#000;background-repeat:repeat-x;background-position:top;border-bottom:solid #d6b161 1px;font-weight:bold}
table.colored tr{background:#fff}
table.colored tr.odd_row{background:#f9f9f9}
div.debug{margin:10px;padding:5px;background:#FFFF99;border:solid #FFFF33 1px;color:black}
@@ -1519,7 +1519,7 @@
.grid tbody td{line-height:1.428571429;border-top:solid #DDDDDD 1px;border-bottom:solid #DDDDDD 1px;padding:5px}
.grid tbody td:empty{padding:0}
.grid thead tr{height:2em}
-.grid thead th{line-height:1.428571429;background:#ebd9b2;color:#000;border-top:solid #bfbfbf 1px;border-bottom:solid #bfbfbf 1px;padding:5px;text-align:left;white-space:nowrap}
+.grid thead th{line-height:1.428571429;background:#ebd9b2;color:#000;border-top:solid #d6b161 1px;border-bottom:solid #d6b161 1px;padding:5px;text-align:left;white-space:nowrap}
.grid tfoot td{background-color:#F8F8F8;border-top:solid #DDDDDD 1px;border-bottom:solid #DDDDDD 1px;padding:5px}
.grid .current{background-color:#EEEEFF}
.count-box{min-width:1.1em;padding:5px;border-width:1px;border-style:solid;text-align:center;display:inline-block}
@@ -1618,7 +1618,7 @@
.icon-btn-group .icon-btn:only-child{margin:0px;border-radius:3px}
.search-input .search-query{width:100%;padding-right:24px}
.search-input .search-clear,.search-input .search-loading{position:relative;display:inline-block;float:right;margin-top:-23px;margin-right:4px;font-size:1.4em;line-height:23px;color:grey}
-.search-input .search-clear:hover{color:#5f6990}
+.search-input .search-clear:hover{color:#303030}
#history-refresh-button,#history-options-button{display:inline-block;height:22px;width:22px;text-align:center;line-height:19px;font-size:1.2em;padding:0px}
.history-panel .dataset{border:1px solid #bfbfbf}.history-panel .dataset .vertical-spacing{margin-bottom:8px}
.history-panel .dataset .info-section{border-radius:3px;border:1px solid rgba(153,153,153,0.30000000000000004);padding:4px}
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: martenson: libraries: refactor into separate files for model/views/main+router, showing infoicon for public libraries
by commits-noreply@bitbucket.org 24 Mar '14
by commits-noreply@bitbucket.org 24 Mar '14
24 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/68d35caf407f/
Changeset: 68d35caf407f
User: martenson
Date: 2014-03-24 20:12:48
Summary: libraries: refactor into separate files for model/views/main+router, showing infoicon for public libraries
Affected #: 12 files
diff -r 33cc6056d83760e5e3b98999b01ecb260423d33c -r 68d35caf407f367c3447a1a6675d6705c8daacf4 lib/galaxy/webapps/galaxy/api/libraries.py
--- a/lib/galaxy/webapps/galaxy/api/libraries.py
+++ b/lib/galaxy/webapps/galaxy/api/libraries.py
@@ -55,10 +55,12 @@
libraries = []
for library in query:
item = library.to_dict( view='element', value_mapper={ 'id' : trans.security.encode_id , 'root_folder_id' : trans.security.encode_id } )
+ if trans.app.security_agent.library_is_public( library, contents=False ):
+ item[ 'public' ] = True
libraries.append( item )
return libraries
- @expose_api
+ @expose_api_anonymous
def show( self, trans, id, deleted='False', **kwd ):
"""
show( self, trans, id, deleted='False', **kwd )
@@ -139,6 +141,9 @@
.. note:: Currently, only admin users can update libraries. Also the library must not be `deleted`.
+ :param id: the encoded id of the library
+ :type id: an encoded id string
+
:param payload: (required) dictionary structure containing::
'name': new library's name, cannot be empty
'description': new library's description
@@ -192,7 +197,7 @@
.. note:: Currently, only admin users can un/delete libraries.
:param id: the encoded id of the library to un/delete
- :type id: str
+ :type id: an encoded id string
:param undelete: (optional) flag specifying whether the item should be deleted or undeleted, defaults to false:
:type undelete: bool
diff -r 33cc6056d83760e5e3b98999b01ecb260423d33c -r 68d35caf407f367c3447a1a6675d6705c8daacf4 static/scripts/galaxy.library.js
--- a/static/scripts/galaxy.library.js
+++ b/static/scripts/galaxy.library.js
@@ -1,1192 +1,26 @@
-// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
-// === GALAXY LIBRARY MODULE ====
-// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// === MAIN GALAXY LIBRARY MODULE ====
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// global variables
-var view = null;
var library_router = null;
-var responses = [];
// dependencies
define([
"galaxy.masthead",
"utils/utils",
- "libs/toastr"], function(mod_masthead, mod_utils, mod_toastr) {
-
-// MMMMMMMMMMMMMMM
-// === Models ====
-// MMMMMMMMMMMMMMM
-
- // LIBRARY
- var Library = Backbone.Model.extend({
- urlRoot: '/api/libraries/'
- });
-
- // FOLDER AS MODEL
- var FolderAsModel = Backbone.Model.extend({
- urlRoot: '/api/folders'
- });
-
- // LIBRARIES
- var Libraries = Backbone.Collection.extend({
- url: '/api/libraries',
-
- model: Library,
-
- sort_key: 'name', // default
-
- sort_order: null, // default
-
- });
-
- // ITEM
- var Item = Backbone.Model.extend({
- urlRoot : '/api/libraries/datasets'
- });
-
- // FOLDER AS COLLECTION
- var Folder = Backbone.Collection.extend({
- model: Item
- });
-
- // CONTAINER for folder contents (folders, items and metadata).
- var FolderContainer = Backbone.Model.extend({
- defaults : {
- folder : new Folder(),
- full_path : "unknown",
- urlRoot : "/api/folders/",
- id : "unknown"
- },
- parse : function(obj) {
- this.full_path = obj[0].full_path;
- // update the inner collection
- this.get("folder").reset(obj[1].folder_contents);
- return obj;
- }
- });
-
- // HISTORY ITEM
- var HistoryItem = Backbone.Model.extend({
- urlRoot : '/api/histories/'
- });
-
- // HISTORY
- var GalaxyHistory = Backbone.Model.extend({
- url : '/api/histories/'
- });
-
- // HISTORIES
- var GalaxyHistories = Backbone.Collection.extend({
- url : '/api/histories',
- model : GalaxyHistory
- });
-
-// MMMMMMMMMMMMMM
-// === VIEWS ====
-// MMMMMMMMMMMMMM
-
-//main view for folder browsing
-var FolderContentView = Backbone.View.extend({
- // main element definition
- el : '#center',
- // progress percentage
- progress: 0,
- // progress rate per one item
- progressStep: 1,
- // last selected history in modal for UX
- lastSelectedHistory: '',
- // self modal
- modal : null,
- // loaded folders
- folders : null,
-
- // initialize
- initialize : function(){
- this.folders = [];
- this.queue = jQuery.Deferred();
- this.queue.resolve();
- },
-
-// MMMMMMMMMMMMMMMMMM
-// === TEMPLATES ====
-// MMMMMMMMMMMMMMMMMM
-
- // main template for folder browsing
- templateFolder : function (){
- var tmpl_array = [];
-
- // CONTAINER
- tmpl_array.push('<div class="library_container" style="width: 90%; margin: auto; margin-top: 2em; ">');
- tmpl_array.push('<h3>Data Libraries Beta Test. This is work in progress. Please report problems & ideas via <a href="mailto:galaxy-bugs@bx.psu.edu?Subject=DataLibrariesBeta_Feedback" target="_blank">email</a> and <a href="https://trello.com/c/nwYQNFPK/56-data-library-ui-progressive-display-of-fol…" target="_blank">Trello</a>.</h3>');
-
- // TOOLBAR
- tmpl_array.push('<div id="library_folder_toolbar" >');
- tmpl_array.push(' <button title="Create New Folder" id="toolbtn_create_folder" class="primary-button" type="button"><span class="fa fa-plus"></span><span class="fa fa-folder-close"></span> folder</button>');
- tmpl_array.push(' <button title="Import selected datasets into history" id="toolbtn_bulk_import" class="primary-button" style="display: none; margin-left: 0.5em;" type="button"><span class="fa fa-book"></span> to history</button>');
- tmpl_array.push(' <div id="toolbtn_dl" class="btn-group" style="margin-left: 0.5em; display: none; ">');
- tmpl_array.push(' <button title="Download selected datasets" id="drop_toggle" type="button" class="primary-button dropdown-toggle" data-toggle="dropdown">');
- tmpl_array.push(' <span class="fa fa-download"></span> download <span class="caret"></span>');
- tmpl_array.push(' </button>');
- tmpl_array.push(' <ul class="dropdown-menu" role="menu">');
- tmpl_array.push(' <li><a href="#/folders/<%= id %>/download/tgz">.tar.gz</a></li>');
- tmpl_array.push(' <li><a href="#/folders/<%= id %>/download/tbz">.tar.bz</a></li>');
- tmpl_array.push(' <li><a href="#/folders/<%= id %>/download/zip">.zip</a></li>');
- tmpl_array.push(' </ul>');
- tmpl_array.push(' </div>');
-
- tmpl_array.push('</div>');
-
- // BREADCRUMBS
- tmpl_array.push('<ol class="breadcrumb">');
- tmpl_array.push(' <li><a title="Return to the list of libraries" href="#">Libraries</a></li>');
- tmpl_array.push(' <% _.each(path, function(path_item) { %>');
- tmpl_array.push(' <% if (path_item[0] != id) { %>');
- tmpl_array.push(' <li><a title="Return to this folder" href="#/folders/<%- path_item[0] %>"><%- path_item[1] %></a></li> ');
- tmpl_array.push( '<% } else { %>');
- tmpl_array.push(' <li class="active"><span title="You are in this folder"><%- path_item[1] %></span></li>');
- tmpl_array.push(' <% } %>');
- tmpl_array.push(' <% }); %>');
- tmpl_array.push('</ol>');
-
-
- // FOLDER CONTENT
- tmpl_array.push('<table id="folder_table" class="grid table table-condensed">');
- tmpl_array.push(' <thead>');
- tmpl_array.push(' <th class="button_heading"></th>');
- tmpl_array.push(' <th style="text-align: center; width: 20px; "><input id="select-all-checkboxes" style="margin: 0;" type="checkbox"></th>');
- tmpl_array.push(' <th>name</th>');
- tmpl_array.push(' <th>data type</th>');
- tmpl_array.push(' <th>size</th>');
- tmpl_array.push(' <th>date (UTC)</th>');
- tmpl_array.push(' </thead>');
- tmpl_array.push(' <tbody>');
- tmpl_array.push(' <td><a href="#<% if (upper_folder_id !== 0){ print("folders/" + upper_folder_id)} %>" title="Go to parent folder" class="btn_open_folder btn btn-default btn-xs">..<a></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' </tr>');
- tmpl_array.push(' <% _.each(items, function(content_item) { %>');
- tmpl_array.push(' <% if (content_item.get("type") === "folder") { %>'); // folder
- tmpl_array.push(' <tr class="folder_row light" id="<%- content_item.id %>">');
- tmpl_array.push(' <td>');
- tmpl_array.push(' <span title="Folder" class="fa fa-folder-o"></span>');
- tmpl_array.push(' </td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td>');
- tmpl_array.push(' <a href="#folders/<%- content_item.id %>"><%- content_item.get("name") %></a>');
- tmpl_array.push(' <% if (content_item.get("item_count") === 0) { %>'); // empty folder
- tmpl_array.push(' <span class="muted">(empty folder)</span>');
- tmpl_array.push(' <% } %>');
- tmpl_array.push(' </td>');
- tmpl_array.push(' <td>folder</td>');
- tmpl_array.push(' <td><%= _.escape(content_item.get("item_count")) %> item(s)</td>'); // size
- tmpl_array.push(' <td><%= _.escape(content_item.get("time_updated")) %></td>'); // time updated
- tmpl_array.push(' </tr>');
- tmpl_array.push(' <% } else { %>');
- tmpl_array.push(' <tr class="dataset_row light" id="<%- content_item.id %>">');
- tmpl_array.push(' <td>');
- tmpl_array.push(' <span title="Dataset" class="fa fa-file-o"></span>');
- tmpl_array.push(' </td>');
- tmpl_array.push(' <td style="text-align: center; "><input style="margin: 0;" type="checkbox"></td>');
- tmpl_array.push(' <td><a href="#" class="library-dataset"><%- content_item.get("name") %><a></td>'); // dataset
- tmpl_array.push(' <td><%= _.escape(content_item.get("data_type")) %></td>'); // data type
- tmpl_array.push(' <td><%= _.escape(content_item.get("readable_size")) %></td>'); // size
- tmpl_array.push(' <td><%= _.escape(content_item.get("time_updated")) %></td>'); // time updated
- tmpl_array.push(' </tr>');
- tmpl_array.push(' <% } %> ');
- tmpl_array.push(' <% }); %>');
- tmpl_array.push(' ');
- tmpl_array.push(' </tbody>');
- tmpl_array.push('</table>');
-
- tmpl_array.push('</div>');
- return tmpl_array.join('');
- },
- templateDatasetModal : function(){
- var tmpl_array = [];
-
- tmpl_array.push('<div class="modal_table">');
- tmpl_array.push(' <table class="grid table table-striped table-condensed">');
- tmpl_array.push(' <tr>');
- tmpl_array.push(' <th scope="row" id="id_row" data-id="<%= _.escape(item.get("ldda_id")) %>">Name</th>');
- tmpl_array.push(' <td><%= _.escape(item.get("name")) %></td>');
- tmpl_array.push(' </tr>');
- tmpl_array.push(' <tr>');
- tmpl_array.push(' <th scope="row">Data type</th>');
- tmpl_array.push(' <td><%= _.escape(item.get("data_type")) %></td>');
- tmpl_array.push(' </tr>');
- tmpl_array.push(' <tr>');
- tmpl_array.push(' <th scope="row">Genome build</th>');
- tmpl_array.push(' <td><%= _.escape(item.get("genome_build")) %></td>');
- tmpl_array.push(' </tr>');
- tmpl_array.push(' <th scope="row">Size</th>');
- tmpl_array.push(' <td><%= _.escape(size) %></td>');
- tmpl_array.push(' </tr>');
- tmpl_array.push(' <tr>');
- tmpl_array.push(' <th scope="row">Date uploaded (UTC)</th>');
- tmpl_array.push(' <td><%= _.escape(item.get("date_uploaded")) %></td>');
- tmpl_array.push(' </tr>');
- tmpl_array.push(' <tr>');
- tmpl_array.push(' <th scope="row">Uploaded by</th>');
- tmpl_array.push(' <td><%= _.escape(item.get("uploaded_by")) %></td>');
- tmpl_array.push(' </tr>');
- tmpl_array.push(' <tr scope="row">');
- tmpl_array.push(' <th scope="row">Data Lines</th>');
- tmpl_array.push(' <td scope="row"><%= _.escape(item.get("metadata_data_lines")) %></td>');
- tmpl_array.push(' </tr>');
- tmpl_array.push(' <th scope="row">Comment Lines</th>');
- tmpl_array.push(' <% if (item.get("metadata_comment_lines") === "") { %>');
- tmpl_array.push(' <td scope="row"><%= _.escape(item.get("metadata_comment_lines")) %></td>');
- tmpl_array.push(' <% } else { %>');
- tmpl_array.push(' <td scope="row">unknown</td>');
- tmpl_array.push(' <% } %>');
- tmpl_array.push(' </tr>');
- tmpl_array.push(' <tr>');
- tmpl_array.push(' <th scope="row">Number of Columns</th>');
- tmpl_array.push(' <td scope="row"><%= _.escape(item.get("metadata_columns")) %></td>');
- tmpl_array.push(' </tr>');
- tmpl_array.push(' <tr>');
- tmpl_array.push(' <th scope="row">Column Types</th>');
- tmpl_array.push(' <td scope="row"><%= _.escape(item.get("metadata_column_types")) %></td>');
- tmpl_array.push(' </tr>');
- tmpl_array.push(' <tr>');
- tmpl_array.push(' <th scope="row">Miscellaneous information</th>');
- tmpl_array.push(' <td scope="row"><%= _.escape(item.get("misc_blurb")) %></td>');
- tmpl_array.push(' </tr>');
- tmpl_array.push(' </table>');
- tmpl_array.push(' <pre class="peek">');
- tmpl_array.push(' </pre>');
- tmpl_array.push('</div>');
-
- return tmpl_array.join('');
- },
-
- templateHistorySelectInModal : function(){
- var tmpl_array = [];
-
- tmpl_array.push('<span id="history_modal_combo" style="width:100%; margin-left: 1em; margin-right: 1em; ">');
- tmpl_array.push('Select history: ');
- tmpl_array.push('<select id="dataset_import_single" name="dataset_import_single" style="width:40%; margin-bottom: 1em; "> ');
- tmpl_array.push(' <% _.each(histories, function(history) { %>'); //history select box
- tmpl_array.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');
- tmpl_array.push(' <% }); %>');
- tmpl_array.push('</select>');
- tmpl_array.push('</span>');
-
- return tmpl_array.join('');
- },
-
- templateBulkImportInModal : function(){
- var tmpl_array = [];
-
- tmpl_array.push('<span id="history_modal_combo_bulk" style="width:90%; margin-left: 1em; margin-right: 1em; ">');
- tmpl_array.push('Select history: ');
- tmpl_array.push('<select id="dataset_import_bulk" name="dataset_import_bulk" style="width:50%; margin-bottom: 1em; "> ');
- tmpl_array.push(' <% _.each(histories, function(history) { %>'); //history select box
- tmpl_array.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');
- tmpl_array.push(' <% }); %>');
- tmpl_array.push('</select>');
- tmpl_array.push('</span>');
-
- return tmpl_array.join('');
- },
-
- templateProgressBar : function (){
- var tmpl_array = [];
-
- tmpl_array.push('<div class="import_text">');
- tmpl_array.push('Importing selected datasets to history <b><%= _.escape(history_name) %></b>');
- tmpl_array.push('</div>');
- tmpl_array.push('<div class="progress">');
- tmpl_array.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');
- tmpl_array.push(' <span class="completion_span">0% Complete</span>');
- tmpl_array.push(' </div>');
- tmpl_array.push('</div>');
- tmpl_array.push('');
-
- return tmpl_array.join('');
- },
-
- templateNewFolderInModal: function(){
- tmpl_array = [];
-
- tmpl_array.push('<div id="new_folder_modal">');
- tmpl_array.push('<form>');
- tmpl_array.push('<input type="text" name="Name" value="" placeholder="Name">');
- tmpl_array.push('<input type="text" name="Description" value="" placeholder="Description">');
- tmpl_array.push('</form>');
- tmpl_array.push('</div>');
-
- return tmpl_array.join('');
- },
-
-// MMMMMMMMMMMMMMM
-// === EVENTS ====
-// MMMMMMMMMMMMMMM
-
- // event binding
- events: {
- 'click #select-all-checkboxes' : 'selectAll',
- 'click #toolbtn_bulk_import' : 'modalBulkImport',
- 'click #toolbtn_dl' : 'bulkDownload',
- 'click #toolbtn_create_folder' : 'createFolderFromModal',
- 'click .library-dataset' : 'showDatasetDetails',
- 'click .dataset_row' : 'selectClickedRow'
- },
-
-// MMMMMMMMMMMMMMMMMM
-// === FUNCTIONS ====
-// MMMMMMMMMMMMMMMMMM
-
- //render the folder view
- render: function (options) {
- //hack to show scrollbars
- $("#center").css('overflow','auto');
-
- view = this;
- var that = this;
-
- var folderContainer = new FolderContainer({id: options.id});
- folderContainer.url = folderContainer.attributes.urlRoot + options.id + '/contents';
-
- folderContainer.fetch({
- success: function (container) {
-
- // prepare nice size strings
- for (var i = 0; i < folderContainer.attributes.folder.models.length; i++) {
- var model = folderContainer.attributes.folder.models[i]
- if (model.get('type') === 'file'){
- model.set('readable_size', that.size_to_string(model.get('file_size')))
- }
- };
-
- // find the upper id
- var path = folderContainer.full_path;
- var upper_folder_id;
- if (path.length === 1){ // library is above us
- upper_folder_id = 0;
- } else {
- upper_folder_id = path[path.length-2][0];
- }
-
- var template = _.template(that.templateFolder(), { path: folderContainer.full_path, items: folderContainer.attributes.folder.models, id: options.id, upper_folder_id: upper_folder_id });
- // var template = _.template(that.templateFolder(), { path: folderContainer.full_path, items: folderContainer.attributes.folder.models, id: options.id });
- that.$el.html(template);
-
- },
- error: function(){
- mod_toastr.error('An error occured :(');
- }
- })
- },
-
- // convert size to nice string
- size_to_string : function (size)
- {
- // identify unit
- var unit = "";
- if (size >= 100000000000) { size = size / 100000000000; unit = "TB"; } else
- if (size >= 100000000) { size = size / 100000000; unit = "GB"; } else
- if (size >= 100000) { size = size / 100000; unit = "MB"; } else
- if (size >= 100) { size = size / 100; unit = "KB"; } else
- { size = size * 10; unit = "b"; }
- // return formatted string
- return (Math.round(size) / 10) + unit;
- },
-
- //show modal with current dataset info
- showDatasetDetails : function(event){
- // prevent default
- event.preventDefault();
-
- //TODO check whether we already have the data
-
- //load the ID of the row
- var id = $(event.target).parent().parent().parent().attr('id');
- if (typeof id === 'undefined'){
- id = $(event.target).parent().attr('id');
- }
- if (typeof id === 'undefined'){
- id = $(event.target).parent().parent().attr('id')
- }
-
- //create new item
- var item = new Item();
- var histories = new GalaxyHistories();
- item.id = id;
- var self = this;
-
- //fetch the dataset info
- item.fetch({
- success: function (item) {
- // TODO can render here already
- //fetch user histories for import purposes
- histories.fetch({
- success: function (histories){
- self.renderModalAfterFetch(item, histories)
- },
- error: function(){
- mod_toastr.error('An error occured during fetching histories:(');
- self.renderModalAfterFetch(item)
- }
- });
- },
- error: function(){
- mod_toastr.error('An error occured during loading dataset details :(');
- }
- });
- },
-
- // show the current dataset in a modal
- renderModalAfterFetch : function(item, histories){
- var size = this.size_to_string(item.get('file_size'));
- var template = _.template(this.templateDatasetModal(), { item : item, size : size });
- // make modal
- var self = this;
- this.modal = Galaxy.modal;
- this.modal.show({
- closing_events : true,
- title : 'Dataset Details',
- body : template,
- buttons : {
- 'Import' : function() { self.importCurrentIntoHistory() },
- 'Download' : function() { self.downloadCurrent() },
- 'Close' : function() { self.modal.hide() }
- }
- });
-
- $(".peek").html('Peek:' + item.get("peek"));
-
- // show the import-into-history footer only if the request for histories succeeded
- if (typeof history.models !== undefined){
- var history_footer_tmpl = _.template(this.templateHistorySelectInModal(), {histories : histories.models});
- $(this.modal.elMain).find('.buttons').prepend(history_footer_tmpl);
- // preset last selected history if we know it
- if (self.lastSelectedHistory.length > 0) {
- $(this.modal.elMain).find('#dataset_import_single').val(self.lastSelectedHistory);
- }
- }
- },
-
- // download dataset shown currently in modal
- downloadCurrent : function(){
- //disable the buttons
- this.modal.disableButton('Import');
- this.modal.disableButton('Download');
-
- var library_dataset_id = [];
- library_dataset_id.push($('#id_row').attr('data-id'));
- var url = '/api/libraries/datasets/download/uncompressed';
- var data = {'ldda_ids' : library_dataset_id};
-
- // we assume the view is existent
- folderContentView.processDownload(url, data);
- this.modal.enableButton('Import');
- this.modal.enableButton('Download');
- },
-
- // import dataset shown currently in modal into selected history
- importCurrentIntoHistory : function(){
- //disable the buttons
- this.modal.disableButton('Import');
- this.modal.disableButton('Download');
-
- var history_id = $(this.modal.elMain).find('select[name=dataset_import_single] option:selected').val();
- this.lastSelectedHistory = history_id; //save selected history for further use
-
- var library_dataset_id = $('#id_row').attr('data-id');
- var historyItem = new HistoryItem();
- var self = this;
- historyItem.url = historyItem.urlRoot + history_id + '/contents';
-
- // save the dataset into selected history
- historyItem.save({ content : library_dataset_id, source : 'library' }, { success : function(){
- mod_toastr.success('Dataset imported');
- //enable the buttons
- self.modal.enableButton('Import');
- self.modal.enableButton('Download');
- }, error : function(){
- mod_toastr.error('An error occured! Dataset not imported. Please try again.')
- //enable the buttons
- self.modal.enableButton('Import');
- self.modal.enableButton('Download');
- }
- });
- },
-
- // select all datasets
- selectAll : function (event) {
- var selected = event.target.checked;
- that = this;
- // Iterate each checkbox
- $(':checkbox').each(function () {
- this.checked = selected;
- $row = $(this.parentElement.parentElement);
- // Change color of selected/unselected
- (selected) ? that.makeDarkRow($row) : that.makeWhiteRow($row);
- });
- // Show the tools in menu
- this.checkTools();
- },
-
- // Check checkbox on row itself or row checkbox click
- selectClickedRow : function (event) {
- var checkbox = '';
- var $row;
- var source;
- if (event.target.localName === 'input'){
- checkbox = event.target;
- $row = $(event.target.parentElement.parentElement);
- source = 'input';
- } else if (event.target.localName === 'td') {
- checkbox = $("#" + event.target.parentElement.id).find(':checkbox')[0];
- $row = $(event.target.parentElement);
- source = 'td';
- }
-
- if (checkbox.checked){
- if (source==='td'){
- checkbox.checked = '';
- this.makeWhiteRow($row);
- } else if (source==='input') {
- this.makeDarkRow($row);
- }
- } else {
- if (source==='td'){
- checkbox.checked = 'selected';
- this.makeDarkRow($row);
- } else if (source==='input') {
- this.makeWhiteRow($row);
- }
- }
- this.checkTools();
- },
-
- makeDarkRow: function($row){
- $row.removeClass('light');
- $row.find('a').removeClass('light');
- $row.addClass('dark');
- $row.find('a').addClass('dark');
- $row.find('span').removeClass('fa-file-o');
- $row.find('span').addClass('fa-file');
-
- },
-
- makeWhiteRow: function($row){
- $row.removeClass('dark');
- $row.find('a').removeClass('dark');
- $row.addClass('light');
- $row.find('a').addClass('light');
- $row.find('span').addClass('fa-file-o');
- $row.find('span').removeClass('fa-file');
- },
-
- // show toolbar in case something is selected
- checkTools : function(){
- var checkedValues = $('#folder_table').find(':checked');
- if(checkedValues.length > 0){
- $('#toolbtn_bulk_import').show();
- $('#toolbtn_dl').show();
- } else {
- $('#toolbtn_bulk_import').hide();
- $('#toolbtn_dl').hide();
- }
- },
-
- // show bulk import modal
- modalBulkImport : function(){
- var self = this;
- // fetch histories
- var histories = new GalaxyHistories();
- histories.fetch({
- success: function (histories){
- // make modal
- var history_modal_tmpl = _.template(self.templateBulkImportInModal(), {histories : histories.models});
- self.modal = Galaxy.modal;
- self.modal.show({
- closing_events : true,
- title : 'Import into History',
- body : history_modal_tmpl,
- buttons : {
- 'Import' : function() {self.importAllIntoHistory()},
- 'Close' : function() {self.modal.hide();}
- }
- });
- },
- error: function(){
- mod_toastr.error('An error occured :(');
- }
- });
- },
-
- // import all selected datasets into history
- importAllIntoHistory : function (){
- //disable the button to prevent multiple submission
- this.modal.disableButton('Import');
-
- var history_id = $("select[name=dataset_import_bulk] option:selected").val();
- var history_name = $("select[name=dataset_import_bulk] option:selected").text();
-
- var dataset_ids = [];
- $('#folder_table').find(':checked').each(function(){
- if (this.parentElement.parentElement.id != '') {
- dataset_ids.push(this.parentElement.parentElement.id);
- }
- });
- var progress_bar_tmpl = _.template(this.templateProgressBar(), { history_name : history_name });
- $(this.modal.elMain).find('.modal-body').html(progress_bar_tmpl);
-
- // init the progress bar
- var progressStep = 100 / dataset_ids.length;
- this.initProgress(progressStep);
-
- // prepare the dataset objects to be imported
- var datasets_to_import = [];
- for (var i = dataset_ids.length - 1; i >= 0; i--) {
- library_dataset_id = dataset_ids[i];
- var historyItem = new HistoryItem();
- var self = this;
- historyItem.url = historyItem.urlRoot + history_id + '/contents';
- historyItem.content = library_dataset_id;
- historyItem.source = 'library';
- datasets_to_import.push(historyItem);
- };
-
- // call the recursive function to call ajax one after each other (request FIFO queue)
- this.chainCall(datasets_to_import);
- },
-
- chainCall: function(history_item_set){
- var self = this;
- var popped_item = history_item_set.pop();
- if (typeof popped_item === "undefined") {
- mod_toastr.success('All datasets imported');
- this.modal.hide();
- return
- }
- var promise = $.when(popped_item.save({content: popped_item.content, source: popped_item.source})).done(function(a1){
- self.updateProgress();
- responses.push(a1);
- self.chainCall(history_item_set);
- });
- },
-
- initProgress: function(progressStep){
- this.progress = 0;
- this.progressStep = progressStep;
- },
- updateProgress: function(){
- this.progress += this.progressStep;
- $('.progress-bar-import').width(Math.round(this.progress) + '%');
- txt_representation = Math.round(this.progress) + '% Complete';
- $('.completion_span').text(txt_representation);
- },
-
-
-
- // download selected datasets
- download : function(folder_id, format){
- var dataset_ids = [];
- $('#folder_table').find(':checked').each(function(){
- if (this.parentElement.parentElement.id != '') {
- dataset_ids.push(this.parentElement.parentElement.id);
- }
- });
-
- var url = '/api/libraries/datasets/download/' + format;
- var data = {'ldda_ids' : dataset_ids};
- this.processDownload(url, data, 'get');
- },
-
- // create hidden form and submit through POST to initialize download
- processDownload: function(url, data, method){
- //url and data options required
- if( url && data ){
- //data can be string of parameters or array/object
- data = typeof data == 'string' ? data : $.param(data);
- //split params into form inputs
- var inputs = '';
- $.each(data.split('&'), function(){
- var pair = this.split('=');
- inputs+='<input type="hidden" name="'+ pair[0] +'" value="'+ pair[1] +'" />';
- });
- //send request
- $('<form action="'+ url +'" method="'+ (method||'post') +'">'+inputs+'</form>')
- .appendTo('body').submit().remove();
-
- mod_toastr.info('Your download will begin soon');
- };
- },
-
- // shows modal for creating folder
- createFolderFromModal: function(){
- event.preventDefault();
- event.stopPropagation();
-
- // create modal
- var self = this;
- this.modal = Galaxy.modal;
- this.modal.show({
- closing_events : true,
- title : 'Create New Folder',
- body : this.templateNewFolderInModal(),
- buttons : {
- 'Create' : function() {self.create_new_folder_event()},
- 'Close' : function() {self.modal.hide(); self.modal = null;}
- }
- });
- },
-
- // create the new folder from modal
- create_new_folder_event: function(){
- var folderDetails = this.serialize_new_folder();
- if (this.validate_new_folder(folderDetails)){
- var folder = new FolderAsModel();
-
- url_items = Backbone.history.fragment.split('/');
- current_folder_id = url_items[url_items.length-1];
- folder.url = folder.urlRoot + '/' + current_folder_id ;
-
- var self = this;
- folder.save(folderDetails, {
- success: function (folder) {
- self.modal.hide();
- mod_toastr.success('Folder created');
- self.render({id: current_folder_id});
- },
- error: function(){
- mod_toastr.error('An error occured :(');
- }
- });
- } else {
- mod_toastr.error('Folder\'s name is missing');
- }
- return false;
- },
-
- // serialize data from the form
- serialize_new_folder : function(){
- return {
- name: $("input[name='Name']").val(),
- description: $("input[name='Description']").val()
- };
- },
-
- // validate new library info
- validate_new_folder: function(folderDetails){
- return folderDetails.name !== '';
- }
-
- });
-
-// galaxy library view
-var GalaxyLibraryview = Backbone.View.extend({
- el: '#libraries_element',
-
- events: {
- 'click .edit_library_btn' : 'edit_button_event',
- 'click .save_library_btn' : 'save_library_modification',
- 'click .cancel_library_btn' : 'cancel_library_modification',
- 'click .delete_library_btn' : 'delete_library',
- 'click .undelete_library_btn' : 'undelete_library'
- },
-
- modal: null,
-
- collection: null,
-
- // initialize
- initialize : function(){
- var viewContext = this;
- this.collection = new Libraries();
-
- this.collection.fetch({
- success: function(libraries){
- viewContext.render();
- // initialize the library tooltips
- $("#center [data-toggle]").tooltip();
- // modification of upper DOM element to show scrollbars due to the #center element inheritance
- $("#center").css('overflow','auto');
- },
- error: function(model, response){
- mod_toastr.error('An error occured. Please try again.');
- }
- })
- },
-
- /** Renders the libraries table either from the object's own collection,
- or from a given array of library models,
- or renders an empty list in case no data is given. */
- render: function (options) {
- var template = this.templateLibraryList();
- var libraries_to_render = null;
- var include_deleted = false;
- var models = null
- if (typeof options !== 'undefined'){
- include_deleted = typeof options.with_deleted !== 'undefined' ? options.with_deleted : false;
- models = typeof options.models !== 'undefined' ? options.models : null;
- }
-
- if (this.collection !== null && models === null){
- if (include_deleted){ // show all the libraries
- libraries_to_render = this.collection.models;
- } else{ // show only undeleted libraries
- libraries_to_render = this.collection.where({deleted: false});;
- }
- } else if (models !== null){
- libraries_to_render = models;
- } else {
- libraries_to_render = [];
- }
-
- this.$el.html(template({libraries: libraries_to_render, order: this.collection.sort_order}));
- },
-
- /** Sorts the underlying collection according to the parameters received through URL.
- Currently supports only sorting by name. */
- sortLibraries: function(sort_by, order){
- if (sort_by === 'name'){
- if (order === 'asc'){
- this.collection.sort_order = 'asc';
- this.collection.comparator = function(libraryA, libraryB){
- if (libraryA.get('name').toLowerCase() > libraryB.get('name').toLowerCase()) return 1; // after
- if (libraryB.get('name').toLowerCase() > libraryA.get('name').toLowerCase()) return -1; // before
- return 0; // equal
- }
- } else if (order === 'desc'){
- this.collection.sort_order = 'desc';
- this.collection.comparator = function(libraryA, libraryB){
- if (libraryA.get('name').toLowerCase() > libraryB.get('name').toLowerCase()) return -1; // before
- if (libraryB.get('name').toLowerCase() > libraryA.get('name').toLowerCase()) return 1; // after
- return 0; // equal
- }
- }
- this.collection.sort();
- }
-
- },
-
-// MMMMMMMMMMMMMMMMMM
-// === TEMPLATES ====
-// MMMMMMMMMMMMMMMMMM
-
- templateLibraryList: function(){
- tmpl_array = [];
-
- tmpl_array.push('<div class="library_container table-responsive">');
- tmpl_array.push('<% if(libraries.length === 0) { %>');
- tmpl_array.push("<div>I see no libraries. Why don't you create one?</div>");
- tmpl_array.push('<% } else{ %>');
- tmpl_array.push('<table class="grid table table-condensed">');
- tmpl_array.push(' <thead>');
- tmpl_array.push(' <th style="width:30%;"><a title="Click to reverse order" href="#sort/name/<% if(order==="desc"||order===null){print("asc")}else{print("desc")} %>">name</a><span title="Sorted alphabetically" class="fa fa-sort-alpha-<%- order %>"></span></th>');
- tmpl_array.push(' <th style="width:22%;">description</th>');
- tmpl_array.push(' <th style="width:22%;">synopsis</th> ');
- tmpl_array.push(' <th style="width:26%;"></th> ');
- tmpl_array.push(' </thead>');
- tmpl_array.push(' <tbody>');
- tmpl_array.push(' <% _.each(libraries, function(library) { %>');
- tmpl_array.push(' <tr class="<% if(library.get("deleted") === true){print("active");}%>" data-id="<%- library.get("id") %>">');
- tmpl_array.push(' <td><a href="#folders/<%- library.get("root_folder_id") %>"><%- library.get("name") %></a></td>');
- tmpl_array.push(' <td><%= _.escape(library.get("description")) %></td>');
- tmpl_array.push(' <td><%= _.escape(library.get("synopsis")) %></td>');
- tmpl_array.push(' <td class="right-center">');
- tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Modify library" class="primary-button btn-xs edit_library_btn" type="button"><span class="fa fa-pencil"></span></button>');
- tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Save changes" class="primary-button btn-xs save_library_btn" type="button" style="display:none;"><span class="fa fa-floppy-o"> Save</span></button>');
- tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Discard changes" class="primary-button btn-xs cancel_library_btn" type="button" style="display:none;"><span class="fa fa-times"> Cancel</span></button>');
- tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Delete library (can be undeleted later)" class="primary-button btn-xs delete_library_btn" type="button" style="display:none;"><span class="fa fa-trash-o"> Delete</span></button>');
- tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Undelete library" class="primary-button btn-xs undelete_library_btn" type="button" style="display:none;"><span class="fa fa-unlock"> Undelete</span></button>');
- tmpl_array.push(' </td>');
- tmpl_array.push(' </tr>');
- tmpl_array.push(' <% }); %>');
- tmpl_array.push(' </tbody>');
- tmpl_array.push('</table>');
- tmpl_array.push('<% }%>');
- tmpl_array.push('</div>');
-
- return _.template(tmpl_array.join(''));
- },
-
- templateNewLibraryInModal: function(){
- tmpl_array = [];
-
- tmpl_array.push('<div id="new_library_modal">');
- tmpl_array.push(' <form>');
- tmpl_array.push(' <input type="text" name="Name" value="" placeholder="Name">');
- tmpl_array.push(' <input type="text" name="Description" value="" placeholder="Description">');
- tmpl_array.push(' <input type="text" name="Synopsis" value="" placeholder="Synopsis">');
- tmpl_array.push(' </form>');
- tmpl_array.push('</div>');
-
- return tmpl_array.join('');
- },
-
- save_library_modification: function(event){
- var $library_row = $(event.target).closest('tr');
- var library = this.collection.get($library_row.data('id'));
-
- var is_changed = false;
-
- var new_name = $library_row.find('.input_library_name').val();
- if (typeof new_name !== 'undefined' && new_name !== library.get('name') ){
- if (new_name.length > 2){
- library.set("name", new_name);
- is_changed = true;
- } else{
- mod_toastr.warning('Library name has to be at least 3 characters long');
- return
- }
- }
-
- var new_description = $library_row.find('.input_library_description').val();
- if (typeof new_description !== 'undefined' && new_description !== library.get('description') ){
- library.set("description", new_description);
- is_changed = true;
- }
-
- var new_synopsis = $library_row.find('.input_library_synopsis').val();
- if (typeof new_synopsis !== 'undefined' && new_synopsis !== library.get('synopsis') ){
- library.set("synopsis", new_synopsis);
- is_changed = true;
- }
-
- if (is_changed){
- library.save(null, {
- patch: true,
- success: function(library) {
- mod_toastr.success('Changes to library saved');
- galaxyLibraryview.toggle_library_modification($library_row);
- },
- error: function(model, response){
- mod_toastr.error('An error occured during updating the library :(');
- }
- });
- }
- },
-
- edit_button_event: function(event){
- this.toggle_library_modification($(event.target).closest('tr'));
- },
-
- toggle_library_modification: function($library_row){
- var library = this.collection.get($library_row.data('id'));
-
- $library_row.find('.edit_library_btn').toggle();
- $library_row.find('.save_library_btn').toggle();
- $library_row.find('.cancel_library_btn').toggle();
- if (library.get('deleted')){
- $library_row.find('.undelete_library_btn').toggle();
- } else {
- $library_row.find('.delete_library_btn').toggle();
- }
-
- if ($library_row.find('.edit_library_btn').is(':hidden')){
- // library name
- var current_library_name = library.get('name');
- var new_html = '<input type="text" class="form-control input_library_name" placeholder="name">';
- $library_row.children('td').eq(0).html(new_html);
- if (typeof current_library_name !== undefined){
- $library_row.find('.input_library_name').val(current_library_name);
- }
- // library description
- var current_library_description = library.get('description');
- var new_html = '<input type="text" class="form-control input_library_description" placeholder="description">';
- $library_row.children('td').eq(1).html(new_html);
- if (typeof current_library_description !== undefined){
- $library_row.find('.input_library_description').val(current_library_description);
- }
- // library synopsis
- var current_library_synopsis = library.get('synopsis');
- var new_html = '<input type="text" class="form-control input_library_synopsis" placeholder="synopsis">';
- $library_row.children('td').eq(2).html(new_html);
- if (typeof current_library_synopsis !== undefined){
- $library_row.find('.input_library_synopsis').val(current_library_synopsis);
- }
- } else {
- $library_row.children('td').eq(0).html(library.get('name'));
- $library_row.children('td').eq(1).html(library.get('description'));
- $library_row.children('td').eq(2).html(library.get('synopsis'));
- }
-
- },
-
- cancel_library_modification: function(event){
- var $library_row = $(event.target).closest('tr');
- var library = this.collection.get($library_row.data('id'));
- this.toggle_library_modification($library_row);
-
- $library_row.children('td').eq(0).html(library.get('name'));
- $library_row.children('td').eq(1).html(library.get('description'));
- $library_row.children('td').eq(2).html(library.get('synopsis'));
- },
-
- undelete_library: function(event){
- var $library_row = $(event.target).closest('tr');
- var library = this.collection.get($library_row.data('id'));
- this.toggle_library_modification($library_row);
-
- // mark the library undeleted
- library.url = library.urlRoot + library.id + '?undelete=true';
- library.destroy({
- success: function (library) {
- // add the newly undeleted library back to the collection
- // backbone does not accept changes through destroy, so update it too
- library.set('deleted', false);
- galaxyLibraryview.collection.add(library);
- $library_row.removeClass('active');
- mod_toastr.success('Library has been undeleted');
- },
- error: function(){
- mod_toastr.error('An error occured while undeleting the library :(');
- }
- });
- },
-
- delete_library: function(event){
- var $library_row = $(event.target).closest('tr');
- var library = this.collection.get($library_row.data('id'));
- this.toggle_library_modification($library_row);
-
- // mark the library deleted
- library.destroy({
- success: function (library) {
- // add the new deleted library back to the collection
- $library_row.remove();
- library.set('deleted', true);
- galaxyLibraryview.collection.add(library);
- mod_toastr.success('Library has been marked deleted');
- },
- error: function(){
- mod_toastr.error('An error occured during deleting the library :(');
- }
- });
-
- },
-
- redirectToHome: function(){
- window.location = '../';
- },
- redirectToLogin: function(){
- window.location = '/user/login';
- },
-
- // show/hide create library modal
- show_library_modal : function (event){
- event.preventDefault();
- event.stopPropagation();
-
- // create modal
- var self = this;
- this.modal = Galaxy.modal;
- this.modal.show({
- closing_events : true,
- title : 'Create New Library',
- body : this.templateNewLibraryInModal(),
- buttons : {
- 'Create' : function() {self.create_new_library_event()},
- 'Close' : function() {self.modal.hide();}
- }
- });
- },
-
- // create the new library from modal
- create_new_library_event: function(){
- var libraryDetails = this.serialize_new_library();
- if (this.validate_new_library(libraryDetails)){
- var library = new Library();
- var self = this;
- library.save(libraryDetails, {
- success: function (library) {
- self.collection.add(library);
- self.modal.hide();
- self.clear_library_modal();
- self.render();
- mod_toastr.success('Library created');
- },
- error: function(){
- mod_toastr.error('An error occured :(');
- }
- });
- } else {
- mod_toastr.error('Library\'s name is missing');
- }
- return false;
- },
-
- // clear the library modal once saved
- clear_library_modal : function(){
- $("input[name='Name']").val('');
- $("input[name='Description']").val('');
- $("input[name='Synopsis']").val('');
- },
-
- // serialize data from the form
- serialize_new_library : function(){
- return {
- name: $("input[name='Name']").val(),
- description: $("input[name='Description']").val(),
- synopsis: $("input[name='Synopsis']").val()
- };
- },
-
- // validate new library info
- validate_new_library: function(libraryDetails){
- return libraryDetails.name !== '';
- }
-});
-
-var ToolbarView = Backbone.View.extend({
- el: '#center',
-
- events: {
- 'click #create_new_library_btn' : 'delegate_modal',
- 'click #include_deleted_chk' : 'check_include_deleted'
- },
-
- initialize: function(){
- this.render();
- },
-
- delegate_modal: function(event){
- // probably should refactor to have this functionality in this view, not in the library view
- galaxyLibraryview.show_library_modal(event);
- },
-
- // include or exclude deleted libraries from the view
- check_include_deleted: function(event){
- if (event.target.checked){
- galaxyLibraryview.render( {'with_deleted': true} );
- } else{
- galaxyLibraryview.render({'with_deleted': false});
- }
- },
-
- render: function(){
- var toolbar_template = this.templateToolBar()
- this.$el.html(toolbar_template())
- },
-
- templateToolBar: function(){
- tmpl_array = [];
-
- tmpl_array.push('<div id="libraries_container" style="width: 90%; margin: auto; margin-top:2em; overflow: auto !important; ">');
- // TOOLBAR
- tmpl_array.push(' <div id="toolbar_form" margin-top:0.5em; ">');
- tmpl_array.push(' <h3>Data Libraries Beta Test. This is work in progress. Please report problems & ideas via <a href="mailto:galaxy-bugs@bx.psu.edu?Subject=DataLibrariesBeta_Feedback" target="_blank">email</a> and <a href="https://trello.com/c/nwYQNFPK/56-data-library-ui-progressive-display-of-fol…" target="_blank">Trello</a>.</h3>');
- tmpl_array.push(' <div id="library_toolbar">');
- tmpl_array.push(' <input id="include_deleted_chk" style="margin: 0;" type="checkbox">include deleted</input>');
- tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Create New Library" id="create_new_library_btn" class="primary-button" type="button"><span class="fa fa-plus"></span> New Library</button>');
- tmpl_array.push(' </div>');
- tmpl_array.push(' </div>');
- tmpl_array.push(' <div id="libraries_element">');
- tmpl_array.push(' </div>');
- tmpl_array.push('</div>');
-
- return _.template(tmpl_array.join(''));
- }
-})
+ "libs/toastr",
+ "mvc/library/library-model",
+ "mvc/library/library-folderlist-view",
+ "mvc/library/library-librarylist-view",
+ "mvc/library/library-librarytoolbar-view"],
+function(mod_masthead,
+ mod_utils,
+ mod_toastr,
+ mod_library_model,
+ mod_folderlist_view,
+ mod_librarylist_view,
+ mod_librarytoolbar_view) {
//ROUTER
var LibraryRouter = Backbone.Router.extend({
@@ -1202,16 +36,17 @@
var GalaxyLibrary = Backbone.View.extend({
initialize : function(){
- toolbarView = new ToolbarView();
- galaxyLibraryview = new GalaxyLibraryview();
+ toolbarView = new mod_librarytoolbar_view.ToolbarView();
+ galaxyLibraryview = new mod_librarylist_view.GalaxyLibraryview();
library_router = new LibraryRouter();
- folderContentView = new FolderContentView();
+
+ folderContentView = null;
library_router.on('route:libraries', function() {
// initialize and render the toolbar first
- toolbarView = new ToolbarView();
+ toolbarView = new mod_librarytoolbar_view.ToolbarView();
// initialize and render libraries second
- galaxyLibraryview = new GalaxyLibraryview();
+ galaxyLibraryview = new mod_librarylist_view.GalaxyLibraryview();
});
library_router.on('route:sort_libraries', function(sort_by, order) {
@@ -1222,6 +57,7 @@
library_router.on('route:folder_content', function(id) {
// render folder contents
+ if (!folderContentView) {folderContentView = new mod_folderlist_view.FolderContentView();}
folderContentView.render({id: id});
});
diff -r 33cc6056d83760e5e3b98999b01ecb260423d33c -r 68d35caf407f367c3447a1a6675d6705c8daacf4 static/scripts/mvc/library/library-folderlist-view.js
--- /dev/null
+++ b/static/scripts/mvc/library/library-folderlist-view.js
@@ -0,0 +1,713 @@
+// dependencies
+define([
+ "galaxy.masthead",
+ "utils/utils",
+ "libs/toastr",
+ "mvc/library/library-model"],
+function(mod_masthead,
+ mod_utils,
+ mod_toastr,
+ mod_library_model) {
+
+ //main view for folder browsing
+var FolderContentView = Backbone.View.extend({
+ // main element definition
+ el : '#center',
+ // progress percentage
+ progress: 0,
+ // progress rate per one item
+ progressStep: 1,
+ // last selected history in modal for UX
+ lastSelectedHistory: '',
+ // self modal
+ modal : null,
+ // loaded folders
+ folders : null,
+
+ // initialize
+ initialize : function(){
+ this.folders = [];
+ this.queue = jQuery.Deferred();
+ this.queue.resolve();
+ },
+
+// MMMMMMMMMMMMMMMMMM
+// === TEMPLATES ====
+// MMMMMMMMMMMMMMMMMM
+
+ // main template for folder browsing
+ templateFolder : function (){
+ var tmpl_array = [];
+
+ // CONTAINER
+ tmpl_array.push('<div class="library_container" style="width: 90%; margin: auto; margin-top: 2em; ">');
+ tmpl_array.push('<h3>Data Libraries Beta Test. This is work in progress. Please report problems & ideas via <a href="mailto:galaxy-bugs@bx.psu.edu?Subject=DataLibrariesBeta_Feedback" target="_blank">email</a> and <a href="https://trello.com/c/nwYQNFPK/56-data-library-ui-progressive-display-of-fol…" target="_blank">Trello</a>.</h3>');
+
+ // TOOLBAR
+ tmpl_array.push('<div id="library_folder_toolbar" >');
+ tmpl_array.push(' <button title="Create New Folder" id="toolbtn_create_folder" class="primary-button" type="button"><span class="fa fa-plus"></span><span class="fa fa-folder-close"></span> folder</button>');
+ tmpl_array.push(' <button title="Import selected datasets into history" id="toolbtn_bulk_import" class="primary-button" style="display: none; margin-left: 0.5em;" type="button"><span class="fa fa-book"></span> to history</button>');
+ tmpl_array.push(' <div id="toolbtn_dl" class="btn-group" style="margin-left: 0.5em; display: none; ">');
+ tmpl_array.push(' <button title="Download selected datasets" id="drop_toggle" type="button" class="primary-button dropdown-toggle" data-toggle="dropdown">');
+ tmpl_array.push(' <span class="fa fa-download"></span> download <span class="caret"></span>');
+ tmpl_array.push(' </button>');
+ tmpl_array.push(' <ul class="dropdown-menu" role="menu">');
+ tmpl_array.push(' <li><a href="#/folders/<%= id %>/download/tgz">.tar.gz</a></li>');
+ tmpl_array.push(' <li><a href="#/folders/<%= id %>/download/tbz">.tar.bz</a></li>');
+ tmpl_array.push(' <li><a href="#/folders/<%= id %>/download/zip">.zip</a></li>');
+ tmpl_array.push(' </ul>');
+ tmpl_array.push(' </div>');
+
+ tmpl_array.push('</div>');
+
+ // BREADCRUMBS
+ tmpl_array.push('<ol class="breadcrumb">');
+ tmpl_array.push(' <li><a title="Return to the list of libraries" href="#">Libraries</a></li>');
+ tmpl_array.push(' <% _.each(path, function(path_item) { %>');
+ tmpl_array.push(' <% if (path_item[0] != id) { %>');
+ tmpl_array.push(' <li><a title="Return to this folder" href="#/folders/<%- path_item[0] %>"><%- path_item[1] %></a></li> ');
+ tmpl_array.push( '<% } else { %>');
+ tmpl_array.push(' <li class="active"><span title="You are in this folder"><%- path_item[1] %></span></li>');
+ tmpl_array.push(' <% } %>');
+ tmpl_array.push(' <% }); %>');
+ tmpl_array.push('</ol>');
+
+
+ // FOLDER CONTENT
+ tmpl_array.push('<table id="folder_table" class="grid table table-condensed">');
+ tmpl_array.push(' <thead>');
+ tmpl_array.push(' <th class="button_heading"></th>');
+ tmpl_array.push(' <th style="text-align: center; width: 20px; "><input id="select-all-checkboxes" style="margin: 0;" type="checkbox"></th>');
+ tmpl_array.push(' <th>name</th>');
+ tmpl_array.push(' <th>data type</th>');
+ tmpl_array.push(' <th>size</th>');
+ tmpl_array.push(' <th>date (UTC)</th>');
+ tmpl_array.push(' </thead>');
+ tmpl_array.push(' <tbody>');
+ tmpl_array.push(' <td><a href="#<% if (upper_folder_id !== 0){ print("folders/" + upper_folder_id)} %>" title="Go to parent folder" class="btn_open_folder btn btn-default btn-xs">..<a></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' </tr>');
+ tmpl_array.push(' <% _.each(items, function(content_item) { %>');
+ tmpl_array.push(' <% if (content_item.get("type") === "folder") { %>'); // folder
+ tmpl_array.push(' <tr class="folder_row light" id="<%- content_item.id %>">');
+ tmpl_array.push(' <td>');
+ tmpl_array.push(' <span title="Folder" class="fa fa-folder-o"></span>');
+ tmpl_array.push(' </td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td>');
+ tmpl_array.push(' <a href="#folders/<%- content_item.id %>"><%- content_item.get("name") %></a>');
+ tmpl_array.push(' <% if (content_item.get("item_count") === 0) { %>'); // empty folder
+ tmpl_array.push(' <span class="muted">(empty folder)</span>');
+ tmpl_array.push(' <% } %>');
+ tmpl_array.push(' </td>');
+ tmpl_array.push(' <td>folder</td>');
+ tmpl_array.push(' <td><%= _.escape(content_item.get("item_count")) %> item(s)</td>'); // size
+ tmpl_array.push(' <td><%= _.escape(content_item.get("time_updated")) %></td>'); // time updated
+ tmpl_array.push(' </tr>');
+ tmpl_array.push(' <% } else { %>');
+ tmpl_array.push(' <tr class="dataset_row light" id="<%- content_item.id %>">');
+ tmpl_array.push(' <td>');
+ tmpl_array.push(' <span title="Dataset" class="fa fa-file-o"></span>');
+ tmpl_array.push(' </td>');
+ tmpl_array.push(' <td style="text-align: center; "><input style="margin: 0;" type="checkbox"></td>');
+ tmpl_array.push(' <td><a href="#" class="library-dataset"><%- content_item.get("name") %><a></td>'); // dataset
+ tmpl_array.push(' <td><%= _.escape(content_item.get("data_type")) %></td>'); // data type
+ tmpl_array.push(' <td><%= _.escape(content_item.get("readable_size")) %></td>'); // size
+ tmpl_array.push(' <td><%= _.escape(content_item.get("time_updated")) %></td>'); // time updated
+ tmpl_array.push(' </tr>');
+ tmpl_array.push(' <% } %> ');
+ tmpl_array.push(' <% }); %>');
+ tmpl_array.push(' ');
+ tmpl_array.push(' </tbody>');
+ tmpl_array.push('</table>');
+
+ tmpl_array.push('</div>');
+ return tmpl_array.join('');
+ },
+ templateDatasetModal : function(){
+ var tmpl_array = [];
+
+ tmpl_array.push('<div class="modal_table">');
+ tmpl_array.push(' <table class="grid table table-striped table-condensed">');
+ tmpl_array.push(' <tr>');
+ tmpl_array.push(' <th scope="row" id="id_row" data-id="<%= _.escape(item.get("ldda_id")) %>">Name</th>');
+ tmpl_array.push(' <td><%= _.escape(item.get("name")) %></td>');
+ tmpl_array.push(' </tr>');
+ tmpl_array.push(' <tr>');
+ tmpl_array.push(' <th scope="row">Data type</th>');
+ tmpl_array.push(' <td><%= _.escape(item.get("data_type")) %></td>');
+ tmpl_array.push(' </tr>');
+ tmpl_array.push(' <tr>');
+ tmpl_array.push(' <th scope="row">Genome build</th>');
+ tmpl_array.push(' <td><%= _.escape(item.get("genome_build")) %></td>');
+ tmpl_array.push(' </tr>');
+ tmpl_array.push(' <th scope="row">Size</th>');
+ tmpl_array.push(' <td><%= _.escape(size) %></td>');
+ tmpl_array.push(' </tr>');
+ tmpl_array.push(' <tr>');
+ tmpl_array.push(' <th scope="row">Date uploaded (UTC)</th>');
+ tmpl_array.push(' <td><%= _.escape(item.get("date_uploaded")) %></td>');
+ tmpl_array.push(' </tr>');
+ tmpl_array.push(' <tr>');
+ tmpl_array.push(' <th scope="row">Uploaded by</th>');
+ tmpl_array.push(' <td><%= _.escape(item.get("uploaded_by")) %></td>');
+ tmpl_array.push(' </tr>');
+ tmpl_array.push(' <tr scope="row">');
+ tmpl_array.push(' <th scope="row">Data Lines</th>');
+ tmpl_array.push(' <td scope="row"><%= _.escape(item.get("metadata_data_lines")) %></td>');
+ tmpl_array.push(' </tr>');
+ tmpl_array.push(' <th scope="row">Comment Lines</th>');
+ tmpl_array.push(' <% if (item.get("metadata_comment_lines") === "") { %>');
+ tmpl_array.push(' <td scope="row"><%= _.escape(item.get("metadata_comment_lines")) %></td>');
+ tmpl_array.push(' <% } else { %>');
+ tmpl_array.push(' <td scope="row">unknown</td>');
+ tmpl_array.push(' <% } %>');
+ tmpl_array.push(' </tr>');
+ tmpl_array.push(' <tr>');
+ tmpl_array.push(' <th scope="row">Number of Columns</th>');
+ tmpl_array.push(' <td scope="row"><%= _.escape(item.get("metadata_columns")) %></td>');
+ tmpl_array.push(' </tr>');
+ tmpl_array.push(' <tr>');
+ tmpl_array.push(' <th scope="row">Column Types</th>');
+ tmpl_array.push(' <td scope="row"><%= _.escape(item.get("metadata_column_types")) %></td>');
+ tmpl_array.push(' </tr>');
+ tmpl_array.push(' <tr>');
+ tmpl_array.push(' <th scope="row">Miscellaneous information</th>');
+ tmpl_array.push(' <td scope="row"><%= _.escape(item.get("misc_blurb")) %></td>');
+ tmpl_array.push(' </tr>');
+ tmpl_array.push(' </table>');
+ tmpl_array.push(' <pre class="peek">');
+ tmpl_array.push(' </pre>');
+ tmpl_array.push('</div>');
+
+ return tmpl_array.join('');
+ },
+
+ templateHistorySelectInModal : function(){
+ var tmpl_array = [];
+
+ tmpl_array.push('<span id="history_modal_combo" style="width:100%; margin-left: 1em; margin-right: 1em; ">');
+ tmpl_array.push('Select history: ');
+ tmpl_array.push('<select id="dataset_import_single" name="dataset_import_single" style="width:40%; margin-bottom: 1em; "> ');
+ tmpl_array.push(' <% _.each(histories, function(history) { %>'); //history select box
+ tmpl_array.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');
+ tmpl_array.push(' <% }); %>');
+ tmpl_array.push('</select>');
+ tmpl_array.push('</span>');
+
+ return tmpl_array.join('');
+ },
+
+ templateBulkImportInModal : function(){
+ var tmpl_array = [];
+
+ tmpl_array.push('<span id="history_modal_combo_bulk" style="width:90%; margin-left: 1em; margin-right: 1em; ">');
+ tmpl_array.push('Select history: ');
+ tmpl_array.push('<select id="dataset_import_bulk" name="dataset_import_bulk" style="width:50%; margin-bottom: 1em; "> ');
+ tmpl_array.push(' <% _.each(histories, function(history) { %>'); //history select box
+ tmpl_array.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');
+ tmpl_array.push(' <% }); %>');
+ tmpl_array.push('</select>');
+ tmpl_array.push('</span>');
+
+ return tmpl_array.join('');
+ },
+
+ templateProgressBar : function (){
+ var tmpl_array = [];
+
+ tmpl_array.push('<div class="import_text">');
+ tmpl_array.push('Importing selected datasets to history <b><%= _.escape(history_name) %></b>');
+ tmpl_array.push('</div>');
+ tmpl_array.push('<div class="progress">');
+ tmpl_array.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');
+ tmpl_array.push(' <span class="completion_span">0% Complete</span>');
+ tmpl_array.push(' </div>');
+ tmpl_array.push('</div>');
+ tmpl_array.push('');
+
+ return tmpl_array.join('');
+ },
+
+ templateNewFolderInModal: function(){
+ tmpl_array = [];
+
+ tmpl_array.push('<div id="new_folder_modal">');
+ tmpl_array.push('<form>');
+ tmpl_array.push('<input type="text" name="Name" value="" placeholder="Name">');
+ tmpl_array.push('<input type="text" name="Description" value="" placeholder="Description">');
+ tmpl_array.push('</form>');
+ tmpl_array.push('</div>');
+
+ return tmpl_array.join('');
+ },
+
+// MMMMMMMMMMMMMMM
+// === EVENTS ====
+// MMMMMMMMMMMMMMM
+
+ // event binding
+ events: {
+ 'click #select-all-checkboxes' : 'selectAll',
+ 'click #toolbtn_bulk_import' : 'modalBulkImport',
+ 'click #toolbtn_dl' : 'bulkDownload',
+ 'click #toolbtn_create_folder' : 'createFolderFromModal',
+ 'click .library-dataset' : 'showDatasetDetails',
+ 'click .dataset_row' : 'selectClickedRow'
+ },
+
+// MMMMMMMMMMMMMMMMMM
+// === FUNCTIONS ====
+// MMMMMMMMMMMMMMMMMM
+
+ //render the folder view
+ render: function (options) {
+ //hack to show scrollbars
+ $("#center").css('overflow','auto');
+
+ view = this;
+ var that = this;
+
+ var folderContainer = new mod_library_model.FolderContainer({id: options.id});
+ folderContainer.url = folderContainer.attributes.urlRoot + options.id + '/contents';
+
+ folderContainer.fetch({
+ success: function (container) {
+
+ // prepare nice size strings
+ for (var i = 0; i < folderContainer.attributes.folder.models.length; i++) {
+ var model = folderContainer.attributes.folder.models[i]
+ if (model.get('type') === 'file'){
+ model.set('readable_size', that.size_to_string(model.get('file_size')))
+ }
+ };
+
+ // find the upper id
+ var path = folderContainer.full_path;
+ var upper_folder_id;
+ if (path.length === 1){ // library is above us
+ upper_folder_id = 0;
+ } else {
+ upper_folder_id = path[path.length-2][0];
+ }
+
+ var template = _.template(that.templateFolder(), { path: folderContainer.full_path, items: folderContainer.attributes.folder.models, id: options.id, upper_folder_id: upper_folder_id });
+ // var template = _.template(that.templateFolder(), { path: folderContainer.full_path, items: folderContainer.attributes.folder.models, id: options.id });
+ that.$el.html(template);
+
+ },
+ error: function(){
+ mod_toastr.error('An error occured :(');
+ }
+ })
+ },
+
+ // convert size to nice string
+ size_to_string : function (size)
+ {
+ // identify unit
+ var unit = "";
+ if (size >= 100000000000) { size = size / 100000000000; unit = "TB"; } else
+ if (size >= 100000000) { size = size / 100000000; unit = "GB"; } else
+ if (size >= 100000) { size = size / 100000; unit = "MB"; } else
+ if (size >= 100) { size = size / 100; unit = "KB"; } else
+ { size = size * 10; unit = "b"; }
+ // return formatted string
+ return (Math.round(size) / 10) + unit;
+ },
+
+ //show modal with current dataset info
+ showDatasetDetails : function(event){
+ // prevent default
+ event.preventDefault();
+
+ //TODO check whether we already have the data
+
+ //load the ID of the row
+ var id = $(event.target).parent().parent().parent().attr('id');
+ if (typeof id === 'undefined'){
+ id = $(event.target).parent().attr('id');
+ }
+ if (typeof id === 'undefined'){
+ id = $(event.target).parent().parent().attr('id')
+ }
+
+ //create new item
+ var item = new mod_library_model.Item();
+ var histories = new mod_library_model.GalaxyHistories();
+ item.id = id;
+ var self = this;
+
+ //fetch the dataset info
+ item.fetch({
+ success: function (item) {
+ // TODO can render here already
+ //fetch user histories for import purposes
+ histories.fetch({
+ success: function (histories){
+ self.renderModalAfterFetch(item, histories)
+ },
+ error: function(){
+ mod_toastr.error('An error occured during fetching histories:(');
+ self.renderModalAfterFetch(item)
+ }
+ });
+ },
+ error: function(){
+ mod_toastr.error('An error occured during loading dataset details :(');
+ }
+ });
+ },
+
+ // show the current dataset in a modal
+ renderModalAfterFetch : function(item, histories){
+ var size = this.size_to_string(item.get('file_size'));
+ var template = _.template(this.templateDatasetModal(), { item : item, size : size });
+ // make modal
+ var self = this;
+ this.modal = Galaxy.modal;
+ this.modal.show({
+ closing_events : true,
+ title : 'Dataset Details',
+ body : template,
+ buttons : {
+ 'Import' : function() { self.importCurrentIntoHistory() },
+ 'Download' : function() { self.downloadCurrent() },
+ 'Close' : function() { self.modal.hide() }
+ }
+ });
+
+ $(".peek").html('Peek:' + item.get("peek"));
+
+ // show the import-into-history footer only if the request for histories succeeded
+ if (typeof history.models !== undefined){
+ var history_footer_tmpl = _.template(this.templateHistorySelectInModal(), {histories : histories.models});
+ $(this.modal.elMain).find('.buttons').prepend(history_footer_tmpl);
+ // preset last selected history if we know it
+ if (self.lastSelectedHistory.length > 0) {
+ $(this.modal.elMain).find('#dataset_import_single').val(self.lastSelectedHistory);
+ }
+ }
+ },
+
+ // download dataset shown currently in modal
+ downloadCurrent : function(){
+ //disable the buttons
+ this.modal.disableButton('Import');
+ this.modal.disableButton('Download');
+
+ var library_dataset_id = [];
+ library_dataset_id.push($('#id_row').attr('data-id'));
+ var url = '/api/libraries/datasets/download/uncompressed';
+ var data = {'ldda_ids' : library_dataset_id};
+
+ // we assume the view is existent
+ folderContentView.processDownload(url, data);
+ this.modal.enableButton('Import');
+ this.modal.enableButton('Download');
+ },
+
+ // import dataset shown currently in modal into selected history
+ importCurrentIntoHistory : function(){
+ //disable the buttons
+ this.modal.disableButton('Import');
+ this.modal.disableButton('Download');
+
+ var history_id = $(this.modal.elMain).find('select[name=dataset_import_single] option:selected').val();
+ this.lastSelectedHistory = history_id; //save selected history for further use
+
+ var library_dataset_id = $('#id_row').attr('data-id');
+ var historyItem = new mod_library_model.HistoryItem();
+ var self = this;
+ historyItem.url = historyItem.urlRoot + history_id + '/contents';
+
+ // save the dataset into selected history
+ historyItem.save({ content : library_dataset_id, source : 'library' }, { success : function(){
+ mod_toastr.success('Dataset imported');
+ //enable the buttons
+ self.modal.enableButton('Import');
+ self.modal.enableButton('Download');
+ }, error : function(){
+ mod_toastr.error('An error occured! Dataset not imported. Please try again.')
+ //enable the buttons
+ self.modal.enableButton('Import');
+ self.modal.enableButton('Download');
+ }
+ });
+ },
+
+ // select all datasets
+ selectAll : function (event) {
+ var selected = event.target.checked;
+ that = this;
+ // Iterate each checkbox
+ $(':checkbox').each(function () {
+ this.checked = selected;
+ $row = $(this.parentElement.parentElement);
+ // Change color of selected/unselected
+ (selected) ? that.makeDarkRow($row) : that.makeWhiteRow($row);
+ });
+ // Show the tools in menu
+ this.checkTools();
+ },
+
+ // Check checkbox on row itself or row checkbox click
+ selectClickedRow : function (event) {
+ var checkbox = '';
+ var $row;
+ var source;
+ if (event.target.localName === 'input'){
+ checkbox = event.target;
+ $row = $(event.target.parentElement.parentElement);
+ source = 'input';
+ } else if (event.target.localName === 'td') {
+ checkbox = $("#" + event.target.parentElement.id).find(':checkbox')[0];
+ $row = $(event.target.parentElement);
+ source = 'td';
+ }
+
+ if (checkbox.checked){
+ if (source==='td'){
+ checkbox.checked = '';
+ this.makeWhiteRow($row);
+ } else if (source==='input') {
+ this.makeDarkRow($row);
+ }
+ } else {
+ if (source==='td'){
+ checkbox.checked = 'selected';
+ this.makeDarkRow($row);
+ } else if (source==='input') {
+ this.makeWhiteRow($row);
+ }
+ }
+ this.checkTools();
+ },
+
+ makeDarkRow: function($row){
+ $row.removeClass('light');
+ $row.find('a').removeClass('light');
+ $row.addClass('dark');
+ $row.find('a').addClass('dark');
+ $row.find('span').removeClass('fa-file-o');
+ $row.find('span').addClass('fa-file');
+
+ },
+
+ makeWhiteRow: function($row){
+ $row.removeClass('dark');
+ $row.find('a').removeClass('dark');
+ $row.addClass('light');
+ $row.find('a').addClass('light');
+ $row.find('span').addClass('fa-file-o');
+ $row.find('span').removeClass('fa-file');
+ },
+
+ // show toolbar in case something is selected
+ checkTools : function(){
+ var checkedValues = $('#folder_table').find(':checked');
+ if(checkedValues.length > 0){
+ $('#toolbtn_bulk_import').show();
+ $('#toolbtn_dl').show();
+ } else {
+ $('#toolbtn_bulk_import').hide();
+ $('#toolbtn_dl').hide();
+ }
+ },
+
+ // show bulk import modal
+ modalBulkImport : function(){
+ var self = this;
+ // fetch histories
+ var histories = new mod_library_model.GalaxyHistories();
+ histories.fetch({
+ success: function (histories){
+ // make modal
+ var history_modal_tmpl = _.template(self.templateBulkImportInModal(), {histories : histories.models});
+ self.modal = Galaxy.modal;
+ self.modal.show({
+ closing_events : true,
+ title : 'Import into History',
+ body : history_modal_tmpl,
+ buttons : {
+ 'Import' : function() {self.importAllIntoHistory()},
+ 'Close' : function() {self.modal.hide();}
+ }
+ });
+ },
+ error: function(){
+ mod_toastr.error('An error occured :(');
+ }
+ });
+ },
+
+ // import all selected datasets into history
+ importAllIntoHistory : function (){
+ //disable the button to prevent multiple submission
+ this.modal.disableButton('Import');
+
+ var history_id = $("select[name=dataset_import_bulk] option:selected").val();
+ var history_name = $("select[name=dataset_import_bulk] option:selected").text();
+
+ var dataset_ids = [];
+ $('#folder_table').find(':checked').each(function(){
+ if (this.parentElement.parentElement.id != '') {
+ dataset_ids.push(this.parentElement.parentElement.id);
+ }
+ });
+ var progress_bar_tmpl = _.template(this.templateProgressBar(), { history_name : history_name });
+ $(this.modal.elMain).find('.modal-body').html(progress_bar_tmpl);
+
+ // init the progress bar
+ var progressStep = 100 / dataset_ids.length;
+ this.initProgress(progressStep);
+
+ // prepare the dataset objects to be imported
+ var datasets_to_import = [];
+ for (var i = dataset_ids.length - 1; i >= 0; i--) {
+ library_dataset_id = dataset_ids[i];
+ var historyItem = new mod_library_model.HistoryItem();
+ var self = this;
+ historyItem.url = historyItem.urlRoot + history_id + '/contents';
+ historyItem.content = library_dataset_id;
+ historyItem.source = 'library';
+ datasets_to_import.push(historyItem);
+ };
+
+ // call the recursive function to call ajax one after each other (request FIFO queue)
+ this.chainCall(datasets_to_import);
+ },
+
+ chainCall: function(history_item_set){
+ var self = this;
+ var popped_item = history_item_set.pop();
+ if (typeof popped_item === "undefined") {
+ mod_toastr.success('All datasets imported');
+ this.modal.hide();
+ return
+ }
+ var promise = $.when(popped_item.save({content: popped_item.content, source: popped_item.source})).done(function(a1){
+ self.updateProgress();
+ // responses.push(a1);
+ self.chainCall(history_item_set);
+ });
+ },
+
+ initProgress: function(progressStep){
+ this.progress = 0;
+ this.progressStep = progressStep;
+ },
+ updateProgress: function(){
+ this.progress += this.progressStep;
+ $('.progress-bar-import').width(Math.round(this.progress) + '%');
+ txt_representation = Math.round(this.progress) + '% Complete';
+ $('.completion_span').text(txt_representation);
+ },
+
+
+
+ // download selected datasets
+ download : function(folder_id, format){
+ var dataset_ids = [];
+ $('#folder_table').find(':checked').each(function(){
+ if (this.parentElement.parentElement.id != '') {
+ dataset_ids.push(this.parentElement.parentElement.id);
+ }
+ });
+
+ var url = '/api/libraries/datasets/download/' + format;
+ var data = {'ldda_ids' : dataset_ids};
+ this.processDownload(url, data, 'get');
+ },
+
+ // create hidden form and submit through POST to initialize download
+ processDownload: function(url, data, method){
+ //url and data options required
+ if( url && data ){
+ //data can be string of parameters or array/object
+ data = typeof data == 'string' ? data : $.param(data);
+ //split params into form inputs
+ var inputs = '';
+ $.each(data.split('&'), function(){
+ var pair = this.split('=');
+ inputs+='<input type="hidden" name="'+ pair[0] +'" value="'+ pair[1] +'" />';
+ });
+ //send request
+ $('<form action="'+ url +'" method="'+ (method||'post') +'">'+inputs+'</form>')
+ .appendTo('body').submit().remove();
+
+ mod_toastr.info('Your download will begin soon');
+ };
+ },
+
+ // shows modal for creating folder
+ createFolderFromModal: function(){
+ event.preventDefault();
+ event.stopPropagation();
+
+ // create modal
+ var self = this;
+ this.modal = Galaxy.modal;
+ this.modal.show({
+ closing_events : true,
+ title : 'Create New Folder',
+ body : this.templateNewFolderInModal(),
+ buttons : {
+ 'Create' : function() {self.create_new_folder_event()},
+ 'Close' : function() {self.modal.hide(); self.modal = null;}
+ }
+ });
+ },
+
+ // create the new folder from modal
+ create_new_folder_event: function(){
+ var folderDetails = this.serialize_new_folder();
+ if (this.validate_new_folder(folderDetails)){
+ var folder = new mod_library_model.FolderAsModel();
+
+ url_items = Backbone.history.fragment.split('/');
+ current_folder_id = url_items[url_items.length-1];
+ folder.url = folder.urlRoot + '/' + current_folder_id ;
+
+ var self = this;
+ folder.save(folderDetails, {
+ success: function (folder) {
+ self.modal.hide();
+ mod_toastr.success('Folder created');
+ self.render({id: current_folder_id});
+ },
+ error: function(){
+ mod_toastr.error('An error occured :(');
+ }
+ });
+ } else {
+ mod_toastr.error('Folder\'s name is missing');
+ }
+ return false;
+ },
+
+ // serialize data from the form
+ serialize_new_folder : function(){
+ return {
+ name: $("input[name='Name']").val(),
+ description: $("input[name='Description']").val()
+ };
+ },
+
+ // validate new library info
+ validate_new_folder: function(folderDetails){
+ return folderDetails.name !== '';
+ }
+
+ });
+
+// return
+return {
+ FolderContentView: FolderContentView
+};
+
+});
This diff is so big that we needed to truncate the remainder.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: martenson: libraries - exposed to anonymous users, allowed editing, deleting, undeleting, improved 'include deleted' filter, refactoring toolbar to have its own view
by commits-noreply@bitbucket.org 24 Mar '14
by commits-noreply@bitbucket.org 24 Mar '14
24 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/33cc6056d837/
Changeset: 33cc6056d837
User: martenson
Date: 2014-03-24 16:16:36
Summary: libraries - exposed to anonymous users, allowed editing, deleting, undeleting, improved 'include deleted' filter, refactoring toolbar to have its own view
Affected #: 6 files
diff -r fa0968cfe3c3fec5869168bd7dd68829024f1ec3 -r 33cc6056d83760e5e3b98999b01ecb260423d33c lib/galaxy/webapps/galaxy/buildapp.py
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -209,7 +209,7 @@
'/api/libraries/:id',
controller='libraries',
action='update',
- conditions=dict( method=[ "PATCH" ] ) )
+ conditions=dict( method=[ "PATCH", 'PUT' ] ) )
webapp.mapper.connect( 'show_lda_item',
'/api/libraries/datasets/:id',
diff -r fa0968cfe3c3fec5869168bd7dd68829024f1ec3 -r 33cc6056d83760e5e3b98999b01ecb260423d33c static/scripts/galaxy.library.js
--- a/static/scripts/galaxy.library.js
+++ b/static/scripts/galaxy.library.js
@@ -19,7 +19,7 @@
// LIBRARY
var Library = Backbone.Model.extend({
- urlRoot: '/api/libraries'
+ urlRoot: '/api/libraries/'
});
// FOLDER AS MODEL
@@ -122,7 +122,7 @@
// TOOLBAR
tmpl_array.push('<div id="library_folder_toolbar" >');
tmpl_array.push(' <button title="Create New Folder" id="toolbtn_create_folder" class="primary-button" type="button"><span class="fa fa-plus"></span><span class="fa fa-folder-close"></span> folder</button>');
- tmpl_array.push(' <button title="Import selected datasets into history" id="toolbtn_bulk_import" class="primary-button" style="display: none; margin-left: 0.5em;" type="button"><span class="fa fa-external-link"></span> to history</button>');
+ tmpl_array.push(' <button title="Import selected datasets into history" id="toolbtn_bulk_import" class="primary-button" style="display: none; margin-left: 0.5em;" type="button"><span class="fa fa-book"></span> to history</button>');
tmpl_array.push(' <div id="toolbtn_dl" class="btn-group" style="margin-left: 0.5em; display: none; ">');
tmpl_array.push(' <button title="Download selected datasets" id="drop_toggle" type="button" class="primary-button dropdown-toggle" data-toggle="dropdown">');
tmpl_array.push(' <span class="fa fa-download"></span> download <span class="caret"></span>');
@@ -208,7 +208,7 @@
var tmpl_array = [];
tmpl_array.push('<div class="modal_table">');
- tmpl_array.push(' <table class="table table-striped table-condensed">');
+ tmpl_array.push(' <table class="grid table table-striped table-condensed">');
tmpl_array.push(' <tr>');
tmpl_array.push(' <th scope="row" id="id_row" data-id="<%= _.escape(item.get("ldda_id")) %>">Name</th>');
tmpl_array.push(' <td><%= _.escape(item.get("name")) %></td>');
@@ -266,9 +266,9 @@
templateHistorySelectInModal : function(){
var tmpl_array = [];
- tmpl_array.push('<span id="history_modal_combo" style="width:90%; margin-left: 1em; margin-right: 1em; ">');
+ tmpl_array.push('<span id="history_modal_combo" style="width:100%; margin-left: 1em; margin-right: 1em; ">');
tmpl_array.push('Select history: ');
- tmpl_array.push('<select id="dataset_import_single" name="dataset_import_single" style="width:50%; margin-bottom: 1em; "> ');
+ tmpl_array.push('<select id="dataset_import_single" name="dataset_import_single" style="width:40%; margin-bottom: 1em; "> ');
tmpl_array.push(' <% _.each(histories, function(history) { %>'); //history select box
tmpl_array.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');
tmpl_array.push(' <% }); %>');
@@ -457,7 +457,7 @@
}
});
- $(".peek").html(item.get("peek"));
+ $(".peek").html('Peek:' + item.get("peek"));
// show the import-into-history footer only if the request for histories succeeded
if (typeof history.models !== undefined){
@@ -783,10 +783,14 @@
// galaxy library view
var GalaxyLibraryview = Backbone.View.extend({
- el: '#center',
+ el: '#libraries_element',
events: {
- 'click #create_new_library_btn' : 'show_library_modal'
+ 'click .edit_library_btn' : 'edit_button_event',
+ 'click .save_library_btn' : 'save_library_modification',
+ 'click .cancel_library_btn' : 'cancel_library_modification',
+ 'click .delete_library_btn' : 'delete_library',
+ 'click .undelete_library_btn' : 'undelete_library'
},
modal: null,
@@ -801,19 +805,15 @@
this.collection.fetch({
success: function(libraries){
viewContext.render();
+ // initialize the library tooltips
+ $("#center [data-toggle]").tooltip();
+ // modification of upper DOM element to show scrollbars due to the #center element inheritance
+ $("#center").css('overflow','auto');
},
error: function(model, response){
-
- if (response.statusCode().status === 403){ //TODO open to public
- mod_toastr.info('Please log in first. Redirecting to login page in 3s.');
- setTimeout(that.redirectToLogin, 3000);
- } else {
- mod_toastr.error('An error occured. Please try again.');
- }
+ mod_toastr.error('An error occured. Please try again.');
}
})
- // modification of upper DOM element to show scrollbars due to the #center element inheritance
- $("#center").css('overflow','auto');
},
/** Renders the libraries table either from the object's own collection,
@@ -875,39 +875,40 @@
templateLibraryList: function(){
tmpl_array = [];
- tmpl_array.push('<div class="library_container" style="width: 90%; margin: auto; margin-top: 2em; overflow: auto !important; ">');
-
- tmpl_array.push('<h3>Data Libraries Beta Test. This is work in progress. Please report problems & ideas via <a href="mailto:galaxy-bugs@bx.psu.edu?Subject=DataLibrariesBeta_Feedback" target="_blank">email</a> and <a href="https://trello.com/c/nwYQNFPK/56-data-library-ui-progressive-display-of-fol…" target="_blank">Trello</a>.</h3>');
- tmpl_array.push('<div id="library_toolbar">');
- tmpl_array.push(' <button title="Create New Library" id="create_new_library_btn" class="primary-button" type="button"><span class="fa fa-plus"></span> New Library</button>');
- tmpl_array.push('</div>');
-
+ tmpl_array.push('<div class="library_container table-responsive">');
tmpl_array.push('<% if(libraries.length === 0) { %>');
tmpl_array.push("<div>I see no libraries. Why don't you create one?</div>");
tmpl_array.push('<% } else{ %>');
tmpl_array.push('<table class="grid table table-condensed">');
tmpl_array.push(' <thead>');
- tmpl_array.push(' <th><a title="Click to reverse order" href="#sort/name/<% if(order==="desc"||order===null){print("asc")}else{print("desc")} %>">name</a><span title="Sorted alphabetically" class="fa fa-sort-alpha-<%- order %>"></span></th>');
- tmpl_array.push(' <th>description</th>');
- tmpl_array.push(' <th>synopsis</th> ');
+ tmpl_array.push(' <th style="width:30%;"><a title="Click to reverse order" href="#sort/name/<% if(order==="desc"||order===null){print("asc")}else{print("desc")} %>">name</a><span title="Sorted alphabetically" class="fa fa-sort-alpha-<%- order %>"></span></th>');
+ tmpl_array.push(' <th style="width:22%;">description</th>');
+ tmpl_array.push(' <th style="width:22%;">synopsis</th> ');
+ tmpl_array.push(' <th style="width:26%;"></th> ');
tmpl_array.push(' </thead>');
tmpl_array.push(' <tbody>');
tmpl_array.push(' <% _.each(libraries, function(library) { %>');
- tmpl_array.push(' <tr>');
+ tmpl_array.push(' <tr class="<% if(library.get("deleted") === true){print("active");}%>" data-id="<%- library.get("id") %>">');
tmpl_array.push(' <td><a href="#folders/<%- library.get("root_folder_id") %>"><%- library.get("name") %></a></td>');
tmpl_array.push(' <td><%= _.escape(library.get("description")) %></td>');
tmpl_array.push(' <td><%= _.escape(library.get("synopsis")) %></td>');
+ tmpl_array.push(' <td class="right-center">');
+ tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Modify library" class="primary-button btn-xs edit_library_btn" type="button"><span class="fa fa-pencil"></span></button>');
+ tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Save changes" class="primary-button btn-xs save_library_btn" type="button" style="display:none;"><span class="fa fa-floppy-o"> Save</span></button>');
+ tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Discard changes" class="primary-button btn-xs cancel_library_btn" type="button" style="display:none;"><span class="fa fa-times"> Cancel</span></button>');
+ tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Delete library (can be undeleted later)" class="primary-button btn-xs delete_library_btn" type="button" style="display:none;"><span class="fa fa-trash-o"> Delete</span></button>');
+ tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Undelete library" class="primary-button btn-xs undelete_library_btn" type="button" style="display:none;"><span class="fa fa-unlock"> Undelete</span></button>');
+ tmpl_array.push(' </td>');
tmpl_array.push(' </tr>');
tmpl_array.push(' <% }); %>');
tmpl_array.push(' </tbody>');
tmpl_array.push('</table>');
tmpl_array.push('<% }%>');
-
tmpl_array.push('</div>');
return _.template(tmpl_array.join(''));
},
-
+
templateNewLibraryInModal: function(){
tmpl_array = [];
@@ -922,6 +923,148 @@
return tmpl_array.join('');
},
+ save_library_modification: function(event){
+ var $library_row = $(event.target).closest('tr');
+ var library = this.collection.get($library_row.data('id'));
+
+ var is_changed = false;
+
+ var new_name = $library_row.find('.input_library_name').val();
+ if (typeof new_name !== 'undefined' && new_name !== library.get('name') ){
+ if (new_name.length > 2){
+ library.set("name", new_name);
+ is_changed = true;
+ } else{
+ mod_toastr.warning('Library name has to be at least 3 characters long');
+ return
+ }
+ }
+
+ var new_description = $library_row.find('.input_library_description').val();
+ if (typeof new_description !== 'undefined' && new_description !== library.get('description') ){
+ library.set("description", new_description);
+ is_changed = true;
+ }
+
+ var new_synopsis = $library_row.find('.input_library_synopsis').val();
+ if (typeof new_synopsis !== 'undefined' && new_synopsis !== library.get('synopsis') ){
+ library.set("synopsis", new_synopsis);
+ is_changed = true;
+ }
+
+ if (is_changed){
+ library.save(null, {
+ patch: true,
+ success: function(library) {
+ mod_toastr.success('Changes to library saved');
+ galaxyLibraryview.toggle_library_modification($library_row);
+ },
+ error: function(model, response){
+ mod_toastr.error('An error occured during updating the library :(');
+ }
+ });
+ }
+ },
+
+ edit_button_event: function(event){
+ this.toggle_library_modification($(event.target).closest('tr'));
+ },
+
+ toggle_library_modification: function($library_row){
+ var library = this.collection.get($library_row.data('id'));
+
+ $library_row.find('.edit_library_btn').toggle();
+ $library_row.find('.save_library_btn').toggle();
+ $library_row.find('.cancel_library_btn').toggle();
+ if (library.get('deleted')){
+ $library_row.find('.undelete_library_btn').toggle();
+ } else {
+ $library_row.find('.delete_library_btn').toggle();
+ }
+
+ if ($library_row.find('.edit_library_btn').is(':hidden')){
+ // library name
+ var current_library_name = library.get('name');
+ var new_html = '<input type="text" class="form-control input_library_name" placeholder="name">';
+ $library_row.children('td').eq(0).html(new_html);
+ if (typeof current_library_name !== undefined){
+ $library_row.find('.input_library_name').val(current_library_name);
+ }
+ // library description
+ var current_library_description = library.get('description');
+ var new_html = '<input type="text" class="form-control input_library_description" placeholder="description">';
+ $library_row.children('td').eq(1).html(new_html);
+ if (typeof current_library_description !== undefined){
+ $library_row.find('.input_library_description').val(current_library_description);
+ }
+ // library synopsis
+ var current_library_synopsis = library.get('synopsis');
+ var new_html = '<input type="text" class="form-control input_library_synopsis" placeholder="synopsis">';
+ $library_row.children('td').eq(2).html(new_html);
+ if (typeof current_library_synopsis !== undefined){
+ $library_row.find('.input_library_synopsis').val(current_library_synopsis);
+ }
+ } else {
+ $library_row.children('td').eq(0).html(library.get('name'));
+ $library_row.children('td').eq(1).html(library.get('description'));
+ $library_row.children('td').eq(2).html(library.get('synopsis'));
+ }
+
+ },
+
+ cancel_library_modification: function(event){
+ var $library_row = $(event.target).closest('tr');
+ var library = this.collection.get($library_row.data('id'));
+ this.toggle_library_modification($library_row);
+
+ $library_row.children('td').eq(0).html(library.get('name'));
+ $library_row.children('td').eq(1).html(library.get('description'));
+ $library_row.children('td').eq(2).html(library.get('synopsis'));
+ },
+
+ undelete_library: function(event){
+ var $library_row = $(event.target).closest('tr');
+ var library = this.collection.get($library_row.data('id'));
+ this.toggle_library_modification($library_row);
+
+ // mark the library undeleted
+ library.url = library.urlRoot + library.id + '?undelete=true';
+ library.destroy({
+ success: function (library) {
+ // add the newly undeleted library back to the collection
+ // backbone does not accept changes through destroy, so update it too
+ library.set('deleted', false);
+ galaxyLibraryview.collection.add(library);
+ $library_row.removeClass('active');
+ mod_toastr.success('Library has been undeleted');
+ },
+ error: function(){
+ mod_toastr.error('An error occured while undeleting the library :(');
+ }
+ });
+ },
+
+ delete_library: function(event){
+ var $library_row = $(event.target).closest('tr');
+ var library = this.collection.get($library_row.data('id'));
+ this.toggle_library_modification($library_row);
+
+ // mark the library deleted
+ library.destroy({
+ success: function (library) {
+ // add the new deleted library back to the collection
+ $library_row.remove();
+ library.set('deleted', true);
+ galaxyLibraryview.collection.add(library);
+ mod_toastr.success('Library has been marked deleted');
+ },
+ error: function(){
+ mod_toastr.error('An error occured during deleting the library :(');
+ }
+ });
+
+ },
+
redirectToHome: function(){
window.location = '../';
},
@@ -994,6 +1137,56 @@
}
});
+var ToolbarView = Backbone.View.extend({
+ el: '#center',
+
+ events: {
+ 'click #create_new_library_btn' : 'delegate_modal',
+ 'click #include_deleted_chk' : 'check_include_deleted'
+ },
+
+ initialize: function(){
+ this.render();
+ },
+
+ delegate_modal: function(event){
+ // probably should refactor to have this functionality in this view, not in the library view
+ galaxyLibraryview.show_library_modal(event);
+ },
+
+ // include or exclude deleted libraries from the view
+ check_include_deleted: function(event){
+ if (event.target.checked){
+ galaxyLibraryview.render( {'with_deleted': true} );
+ } else{
+ galaxyLibraryview.render({'with_deleted': false});
+ }
+ },
+
+ render: function(){
+ var toolbar_template = this.templateToolBar()
+ this.$el.html(toolbar_template())
+ },
+
+ templateToolBar: function(){
+ tmpl_array = [];
+
+ tmpl_array.push('<div id="libraries_container" style="width: 90%; margin: auto; margin-top:2em; overflow: auto !important; ">');
+ // TOOLBAR
+ tmpl_array.push(' <div id="toolbar_form" margin-top:0.5em; ">');
+ tmpl_array.push(' <h3>Data Libraries Beta Test. This is work in progress. Please report problems & ideas via <a href="mailto:galaxy-bugs@bx.psu.edu?Subject=DataLibrariesBeta_Feedback" target="_blank">email</a> and <a href="https://trello.com/c/nwYQNFPK/56-data-library-ui-progressive-display-of-fol…" target="_blank">Trello</a>.</h3>');
+ tmpl_array.push(' <div id="library_toolbar">');
+ tmpl_array.push(' <input id="include_deleted_chk" style="margin: 0;" type="checkbox">include deleted</input>');
+ tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Create New Library" id="create_new_library_btn" class="primary-button" type="button"><span class="fa fa-plus"></span> New Library</button>');
+ tmpl_array.push(' </div>');
+ tmpl_array.push(' </div>');
+ tmpl_array.push(' <div id="libraries_element">');
+ tmpl_array.push(' </div>');
+ tmpl_array.push('</div>');
+
+ return _.template(tmpl_array.join(''));
+ }
+})
//ROUTER
var LibraryRouter = Backbone.Router.extend({
@@ -1007,18 +1200,18 @@
// galaxy library wrapper View
var GalaxyLibrary = Backbone.View.extend({
- // folderContentView : null,
- // galaxyLibraryview : null,
initialize : function(){
-
+ toolbarView = new ToolbarView();
galaxyLibraryview = new GalaxyLibraryview();
library_router = new LibraryRouter();
folderContentView = new FolderContentView();
library_router.on('route:libraries', function() {
- // render libraries list
- galaxyLibraryview.render();
+ // initialize and render the toolbar first
+ toolbarView = new ToolbarView();
+ // initialize and render libraries second
+ galaxyLibraryview = new GalaxyLibraryview();
});
library_router.on('route:sort_libraries', function(sort_by, order) {
@@ -1028,9 +1221,7 @@
});
library_router.on('route:folder_content', function(id) {
- // if (this.folderContentView === null){
- // }
- // render folder's contents
+ // render folder contents
folderContentView.render({id: id});
});
diff -r fa0968cfe3c3fec5869168bd7dd68829024f1ec3 -r 33cc6056d83760e5e3b98999b01ecb260423d33c static/scripts/packed/galaxy.library.js
--- a/static/scripts/packed/galaxy.library.js
+++ b/static/scripts/packed/galaxy.library.js
@@ -1,1 +1,1 @@
-var view=null;var library_router=null;var responses=[];define(["galaxy.masthead","utils/utils","libs/toastr"],function(k,h,m){var f=Backbone.Model.extend({urlRoot:"/api/libraries"});var c=Backbone.Model.extend({urlRoot:"/api/folders"});var n=Backbone.Collection.extend({url:"/api/libraries",model:f,sort_key:"name",sort_order:null,});var i=Backbone.Model.extend({urlRoot:"/api/libraries/datasets"});var d=Backbone.Collection.extend({model:i});var e=Backbone.Model.extend({defaults:{folder:new d(),full_path:"unknown",urlRoot:"/api/folders/",id:"unknown"},parse:function(q){this.full_path=q[0].full_path;this.get("folder").reset(q[1].folder_contents);return q}});var b=Backbone.Model.extend({urlRoot:"/api/histories/"});var j=Backbone.Model.extend({url:"/api/histories/"});var o=Backbone.Collection.extend({url:"/api/histories",model:j});var l=Backbone.View.extend({el:"#center",progress:0,progressStep:1,lastSelectedHistory:"",modal:null,folders:null,initialize:function(){this.folders=[];this.queue=jQuery.Deferred();this.queue.resolve()},templateFolder:function(){var q=[];q.push('<div class="library_container" style="width: 90%; margin: auto; margin-top: 2em; ">');q.push('<h3>Data Libraries Beta Test. This is work in progress. Please report problems & ideas via <a href="mailto:galaxy-bugs@bx.psu.edu?Subject=DataLibrariesBeta_Feedback" target="_blank">email</a> and <a href="https://trello.com/c/nwYQNFPK/56-data-library-ui-progressive-display-of-fol…" target="_blank">Trello</a>.</h3>');q.push('<div id="library_folder_toolbar" >');q.push(' <button title="Create New Folder" id="toolbtn_create_folder" class="primary-button" type="button"><span class="fa fa-plus"></span><span class="fa fa-folder-close"></span> folder</button>');q.push(' <button title="Import selected datasets into history" id="toolbtn_bulk_import" class="primary-button" style="display: none; margin-left: 0.5em;" type="button"><span class="fa fa-external-link"></span> to history</button>');q.push(' <div id="toolbtn_dl" class="btn-group" style="margin-left: 0.5em; display: none; ">');q.push(' <button title="Download selected datasets" id="drop_toggle" type="button" class="primary-button dropdown-toggle" data-toggle="dropdown">');q.push(' <span class="fa fa-download"></span> download <span class="caret"></span>');q.push(" </button>");q.push(' <ul class="dropdown-menu" role="menu">');q.push(' <li><a href="#/folders/<%= id %>/download/tgz">.tar.gz</a></li>');q.push(' <li><a href="#/folders/<%= id %>/download/tbz">.tar.bz</a></li>');q.push(' <li><a href="#/folders/<%= id %>/download/zip">.zip</a></li>');q.push(" </ul>");q.push(" </div>");q.push("</div>");q.push('<ol class="breadcrumb">');q.push(' <li><a title="Return to the list of libraries" href="#">Libraries</a></li>');q.push(" <% _.each(path, function(path_item) { %>");q.push(" <% if (path_item[0] != id) { %>");q.push(' <li><a title="Return to this folder" href="#/folders/<%- path_item[0] %>"><%- path_item[1] %></a></li> ');q.push("<% } else { %>");q.push(' <li class="active"><span title="You are in this folder"><%- path_item[1] %></span></li>');q.push(" <% } %>");q.push(" <% }); %>");q.push("</ol>");q.push('<table id="folder_table" class="grid table table-condensed">');q.push(" <thead>");q.push(' <th class="button_heading"></th>');q.push(' <th style="text-align: center; width: 20px; "><input id="select-all-checkboxes" style="margin: 0;" type="checkbox"></th>');q.push(" <th>name</th>");q.push(" <th>data type</th>");q.push(" <th>size</th>");q.push(" <th>date (UTC)</th>");q.push(" </thead>");q.push(" <tbody>");q.push(' <td><a href="#<% if (upper_folder_id !== 0){ print("folders/" + upper_folder_id)} %>" title="Go to parent folder" class="btn_open_folder btn btn-default btn-xs">..<a></td>');q.push(" <td></td>");q.push(" <td></td>");q.push(" <td></td>");q.push(" <td></td>");q.push(" <td></td>");q.push(" </tr>");q.push(" <% _.each(items, function(content_item) { %>");q.push(' <% if (content_item.get("type") === "folder") { %>');q.push(' <tr class="folder_row light" id="<%- content_item.id %>">');q.push(" <td>");q.push(' <span title="Folder" class="fa fa-folder-o"></span>');q.push(" </td>");q.push(" <td></td>");q.push(" <td>");q.push(' <a href="#folders/<%- content_item.id %>"><%- content_item.get("name") %></a>');q.push(' <% if (content_item.get("item_count") === 0) { %>');q.push(' <span class="muted">(empty folder)</span>');q.push(" <% } %>");q.push(" </td>");q.push(" <td>folder</td>");q.push(' <td><%= _.escape(content_item.get("item_count")) %> item(s)</td>');q.push(' <td><%= _.escape(content_item.get("time_updated")) %></td>');q.push(" </tr>");q.push(" <% } else { %>");q.push(' <tr class="dataset_row light" id="<%- content_item.id %>">');q.push(" <td>");q.push(' <span title="Dataset" class="fa fa-file-o"></span>');q.push(" </td>");q.push(' <td style="text-align: center; "><input style="margin: 0;" type="checkbox"></td>');q.push(' <td><a href="#" class="library-dataset"><%- content_item.get("name") %><a></td>');q.push(' <td><%= _.escape(content_item.get("data_type")) %></td>');q.push(' <td><%= _.escape(content_item.get("readable_size")) %></td>');q.push(' <td><%= _.escape(content_item.get("time_updated")) %></td>');q.push(" </tr>");q.push(" <% } %> ");q.push(" <% }); %>");q.push(" ");q.push(" </tbody>");q.push("</table>");q.push("</div>");return q.join("")},templateDatasetModal:function(){var q=[];q.push('<div class="modal_table">');q.push(' <table class="table table-striped table-condensed">');q.push(" <tr>");q.push(' <th scope="row" id="id_row" data-id="<%= _.escape(item.get("ldda_id")) %>">Name</th>');q.push(' <td><%= _.escape(item.get("name")) %></td>');q.push(" </tr>");q.push(" <tr>");q.push(' <th scope="row">Data type</th>');q.push(' <td><%= _.escape(item.get("data_type")) %></td>');q.push(" </tr>");q.push(" <tr>");q.push(' <th scope="row">Genome build</th>');q.push(' <td><%= _.escape(item.get("genome_build")) %></td>');q.push(" </tr>");q.push(' <th scope="row">Size</th>');q.push(" <td><%= _.escape(size) %></td>");q.push(" </tr>");q.push(" <tr>");q.push(' <th scope="row">Date uploaded (UTC)</th>');q.push(' <td><%= _.escape(item.get("date_uploaded")) %></td>');q.push(" </tr>");q.push(" <tr>");q.push(' <th scope="row">Uploaded by</th>');q.push(' <td><%= _.escape(item.get("uploaded_by")) %></td>');q.push(" </tr>");q.push(' <tr scope="row">');q.push(' <th scope="row">Data Lines</th>');q.push(' <td scope="row"><%= _.escape(item.get("metadata_data_lines")) %></td>');q.push(" </tr>");q.push(' <th scope="row">Comment Lines</th>');q.push(' <% if (item.get("metadata_comment_lines") === "") { %>');q.push(' <td scope="row"><%= _.escape(item.get("metadata_comment_lines")) %></td>');q.push(" <% } else { %>");q.push(' <td scope="row">unknown</td>');q.push(" <% } %>");q.push(" </tr>");q.push(" <tr>");q.push(' <th scope="row">Number of Columns</th>');q.push(' <td scope="row"><%= _.escape(item.get("metadata_columns")) %></td>');q.push(" </tr>");q.push(" <tr>");q.push(' <th scope="row">Column Types</th>');q.push(' <td scope="row"><%= _.escape(item.get("metadata_column_types")) %></td>');q.push(" </tr>");q.push(" <tr>");q.push(' <th scope="row">Miscellaneous information</th>');q.push(' <td scope="row"><%= _.escape(item.get("misc_blurb")) %></td>');q.push(" </tr>");q.push(" </table>");q.push(' <pre class="peek">');q.push(" </pre>");q.push("</div>");return q.join("")},templateHistorySelectInModal:function(){var q=[];q.push('<span id="history_modal_combo" style="width:90%; margin-left: 1em; margin-right: 1em; ">');q.push("Select history: ");q.push('<select id="dataset_import_single" name="dataset_import_single" style="width:50%; margin-bottom: 1em; "> ');q.push(" <% _.each(histories, function(history) { %>");q.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');q.push(" <% }); %>");q.push("</select>");q.push("</span>");return q.join("")},templateBulkImportInModal:function(){var q=[];q.push('<span id="history_modal_combo_bulk" style="width:90%; margin-left: 1em; margin-right: 1em; ">');q.push("Select history: ");q.push('<select id="dataset_import_bulk" name="dataset_import_bulk" style="width:50%; margin-bottom: 1em; "> ');q.push(" <% _.each(histories, function(history) { %>");q.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');q.push(" <% }); %>");q.push("</select>");q.push("</span>");return q.join("")},templateProgressBar:function(){var q=[];q.push('<div class="import_text">');q.push("Importing selected datasets to history <b><%= _.escape(history_name) %></b>");q.push("</div>");q.push('<div class="progress">');q.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');q.push(' <span class="completion_span">0% Complete</span>');q.push(" </div>");q.push("</div>");q.push("");return q.join("")},templateNewFolderInModal:function(){tmpl_array=[];tmpl_array.push('<div id="new_folder_modal">');tmpl_array.push("<form>");tmpl_array.push('<input type="text" name="Name" value="" placeholder="Name">');tmpl_array.push('<input type="text" name="Description" value="" placeholder="Description">');tmpl_array.push("</form>");tmpl_array.push("</div>");return tmpl_array.join("")},events:{"click #select-all-checkboxes":"selectAll","click #toolbtn_bulk_import":"modalBulkImport","click #toolbtn_dl":"bulkDownload","click #toolbtn_create_folder":"createFolderFromModal","click .library-dataset":"showDatasetDetails","click .dataset_row":"selectClickedRow"},render:function(q){$("#center").css("overflow","auto");view=this;var s=this;var r=new e({id:q.id});r.url=r.attributes.urlRoot+q.id+"/contents";r.fetch({success:function(t){for(var v=0;v<r.attributes.folder.models.length;v++){var u=r.attributes.folder.models[v];if(u.get("type")==="file"){u.set("readable_size",s.size_to_string(u.get("file_size")))}}var x=r.full_path;var y;if(x.length===1){y=0}else{y=x[x.length-2][0]}var w=_.template(s.templateFolder(),{path:r.full_path,items:r.attributes.folder.models,id:q.id,upper_folder_id:y});s.$el.html(w)},error:function(){m.error("An error occured :(")}})},size_to_string:function(q){var r="";if(q>=100000000000){q=q/100000000000;r="TB"}else{if(q>=100000000){q=q/100000000;r="GB"}else{if(q>=100000){q=q/100000;r="MB"}else{if(q>=100){q=q/100;r="KB"}else{q=q*10;r="b"}}}}return(Math.round(q)/10)+r},showDatasetDetails:function(t){t.preventDefault();var u=$(t.target).parent().parent().parent().attr("id");if(typeof u==="undefined"){u=$(t.target).parent().attr("id")}if(typeof u==="undefined"){u=$(t.target).parent().parent().attr("id")}var s=new i();var r=new o();s.id=u;var q=this;s.fetch({success:function(v){r.fetch({success:function(w){q.renderModalAfterFetch(v,w)},error:function(){m.error("An error occured during fetching histories:(");q.renderModalAfterFetch(v)}})},error:function(){m.error("An error occured during loading dataset details :(")}})},renderModalAfterFetch:function(v,s){var t=this.size_to_string(v.get("file_size"));var u=_.template(this.templateDatasetModal(),{item:v,size:t});var r=this;this.modal=Galaxy.modal;this.modal.show({closing_events:true,title:"Dataset Details",body:u,buttons:{Import:function(){r.importCurrentIntoHistory()},Download:function(){r.downloadCurrent()},Close:function(){r.modal.hide()}}});$(".peek").html(v.get("peek"));if(typeof history.models!==undefined){var q=_.template(this.templateHistorySelectInModal(),{histories:s.models});$(this.modal.elMain).find(".buttons").prepend(q);if(r.lastSelectedHistory.length>0){$(this.modal.elMain).find("#dataset_import_single").val(r.lastSelectedHistory)}}},downloadCurrent:function(){this.modal.disableButton("Import");this.modal.disableButton("Download");var q=[];q.push($("#id_row").attr("data-id"));var r="/api/libraries/datasets/download/uncompressed";var s={ldda_ids:q};folderContentView.processDownload(r,s);this.modal.enableButton("Import");this.modal.enableButton("Download")},importCurrentIntoHistory:function(){this.modal.disableButton("Import");this.modal.disableButton("Download");var s=$(this.modal.elMain).find("select[name=dataset_import_single] option:selected").val();this.lastSelectedHistory=s;var q=$("#id_row").attr("data-id");var t=new b();var r=this;t.url=t.urlRoot+s+"/contents";t.save({content:q,source:"library"},{success:function(){m.success("Dataset imported");r.modal.enableButton("Import");r.modal.enableButton("Download")},error:function(){m.error("An error occured! Dataset not imported. Please try again.");r.modal.enableButton("Import");r.modal.enableButton("Download")}})},selectAll:function(r){var q=r.target.checked;that=this;$(":checkbox").each(function(){this.checked=q;$row=$(this.parentElement.parentElement);(q)?that.makeDarkRow($row):that.makeWhiteRow($row)});this.checkTools()},selectClickedRow:function(r){var t="";var q;var s;if(r.target.localName==="input"){t=r.target;q=$(r.target.parentElement.parentElement);s="input"}else{if(r.target.localName==="td"){t=$("#"+r.target.parentElement.id).find(":checkbox")[0];q=$(r.target.parentElement);s="td"}}if(t.checked){if(s==="td"){t.checked="";this.makeWhiteRow(q)}else{if(s==="input"){this.makeDarkRow(q)}}}else{if(s==="td"){t.checked="selected";this.makeDarkRow(q)}else{if(s==="input"){this.makeWhiteRow(q)}}}this.checkTools()},makeDarkRow:function(q){q.removeClass("light");q.find("a").removeClass("light");q.addClass("dark");q.find("a").addClass("dark");q.find("span").removeClass("fa-file-o");q.find("span").addClass("fa-file")},makeWhiteRow:function(q){q.removeClass("dark");q.find("a").removeClass("dark");q.addClass("light");q.find("a").addClass("light");q.find("span").addClass("fa-file-o");q.find("span").removeClass("fa-file")},checkTools:function(){var q=$("#folder_table").find(":checked");if(q.length>0){$("#toolbtn_bulk_import").show();$("#toolbtn_dl").show()}else{$("#toolbtn_bulk_import").hide();$("#toolbtn_dl").hide()}},modalBulkImport:function(){var r=this;var q=new o();q.fetch({success:function(s){var t=_.template(r.templateBulkImportInModal(),{histories:s.models});r.modal=Galaxy.modal;r.modal.show({closing_events:true,title:"Import into History",body:t,buttons:{Import:function(){r.importAllIntoHistory()},Close:function(){r.modal.hide()}}})},error:function(){m.error("An error occured :(")}})},importAllIntoHistory:function(){this.modal.disableButton("Import");var s=$("select[name=dataset_import_bulk] option:selected").val();var w=$("select[name=dataset_import_bulk] option:selected").text();var y=[];$("#folder_table").find(":checked").each(function(){if(this.parentElement.parentElement.id!=""){y.push(this.parentElement.parentElement.id)}});var x=_.template(this.templateProgressBar(),{history_name:w});$(this.modal.elMain).find(".modal-body").html(x);var t=100/y.length;this.initProgress(t);var q=[];for(var r=y.length-1;r>=0;r--){library_dataset_id=y[r];var u=new b();var v=this;u.url=u.urlRoot+s+"/contents";u.content=library_dataset_id;u.source="library";q.push(u)}this.chainCall(q)},chainCall:function(r){var q=this;var s=r.pop();if(typeof s==="undefined"){m.success("All datasets imported");this.modal.hide();return}var t=$.when(s.save({content:s.content,source:s.source})).done(function(u){q.updateProgress();responses.push(u);q.chainCall(r)})},initProgress:function(q){this.progress=0;this.progressStep=q},updateProgress:function(){this.progress+=this.progressStep;$(".progress-bar-import").width(Math.round(this.progress)+"%");txt_representation=Math.round(this.progress)+"% Complete";$(".completion_span").text(txt_representation)},download:function(q,u){var s=[];$("#folder_table").find(":checked").each(function(){if(this.parentElement.parentElement.id!=""){s.push(this.parentElement.parentElement.id)}});var r="/api/libraries/datasets/download/"+u;var t={ldda_ids:s};this.processDownload(r,t,"get")},processDownload:function(r,s,t){if(r&&s){s=typeof s=="string"?s:$.param(s);var q="";$.each(s.split("&"),function(){var u=this.split("=");q+='<input type="hidden" name="'+u[0]+'" value="'+u[1]+'" />'});$('<form action="'+r+'" method="'+(t||"post")+'">'+q+"</form>").appendTo("body").submit().remove();m.info("Your download will begin soon")}},createFolderFromModal:function(){event.preventDefault();event.stopPropagation();var q=this;this.modal=Galaxy.modal;this.modal.show({closing_events:true,title:"Create New Folder",body:this.templateNewFolderInModal(),buttons:{Create:function(){q.create_new_folder_event()},Close:function(){q.modal.hide();q.modal=null}}})},create_new_folder_event:function(){var q=this.serialize_new_folder();if(this.validate_new_folder(q)){var s=new c();url_items=Backbone.history.fragment.split("/");current_folder_id=url_items[url_items.length-1];s.url=s.urlRoot+"/"+current_folder_id;var r=this;s.save(q,{success:function(t){r.modal.hide();m.success("Folder created");r.render({id:current_folder_id})},error:function(){m.error("An error occured :(")}})}else{m.error("Folder's name is missing")}return false},serialize_new_folder:function(){return{name:$("input[name='Name']").val(),description:$("input[name='Description']").val()}},validate_new_folder:function(q){return q.name!==""}});var a=Backbone.View.extend({el:"#center",events:{"click #create_new_library_btn":"show_library_modal"},modal:null,collection:null,initialize:function(){var q=this;this.collection=new n();this.collection.fetch({success:function(r){q.render()},error:function(s,r){if(r.statusCode().status===403){m.info("Please log in first. Redirecting to login page in 3s.");setTimeout(that.redirectToLogin,3000)}else{m.error("An error occured. Please try again.")}}});$("#center").css("overflow","auto")},render:function(r){var s=this.templateLibraryList();var t=null;var q=false;var u=null;if(typeof r!=="undefined"){q=typeof r.with_deleted!=="undefined"?r.with_deleted:false;u=typeof r.models!=="undefined"?r.models:null}if(this.collection!==null&&u===null){if(q){t=this.collection.models}else{t=this.collection.where({deleted:false})}}else{if(u!==null){t=u}else{t=[]}}this.$el.html(s({libraries:t,order:this.collection.sort_order}))},sortLibraries:function(r,q){if(r==="name"){if(q==="asc"){this.collection.sort_order="asc";this.collection.comparator=function(t,s){if(t.get("name").toLowerCase()>s.get("name").toLowerCase()){return 1}if(s.get("name").toLowerCase()>t.get("name").toLowerCase()){return -1}return 0}}else{if(q==="desc"){this.collection.sort_order="desc";this.collection.comparator=function(t,s){if(t.get("name").toLowerCase()>s.get("name").toLowerCase()){return -1}if(s.get("name").toLowerCase()>t.get("name").toLowerCase()){return 1}return 0}}}this.collection.sort()}},templateLibraryList:function(){tmpl_array=[];tmpl_array.push('<div class="library_container" style="width: 90%; margin: auto; margin-top: 2em; overflow: auto !important; ">');tmpl_array.push('<h3>Data Libraries Beta Test. This is work in progress. Please report problems & ideas via <a href="mailto:galaxy-bugs@bx.psu.edu?Subject=DataLibrariesBeta_Feedback" target="_blank">email</a> and <a href="https://trello.com/c/nwYQNFPK/56-data-library-ui-progressive-display-of-fol…" target="_blank">Trello</a>.</h3>');tmpl_array.push('<div id="library_toolbar">');tmpl_array.push(' <button title="Create New Library" id="create_new_library_btn" class="primary-button" type="button"><span class="fa fa-plus"></span> New Library</button>');tmpl_array.push("</div>");tmpl_array.push("<% if(libraries.length === 0) { %>");tmpl_array.push("<div>I see no libraries. Why don't you create one?</div>");tmpl_array.push("<% } else{ %>");tmpl_array.push('<table class="grid table table-condensed">');tmpl_array.push(" <thead>");tmpl_array.push(' <th><a title="Click to reverse order" href="#sort/name/<% if(order==="desc"||order===null){print("asc")}else{print("desc")} %>">name</a><span title="Sorted alphabetically" class="fa fa-sort-alpha-<%- order %>"></span></th>');tmpl_array.push(" <th>description</th>");tmpl_array.push(" <th>synopsis</th> ");tmpl_array.push(" </thead>");tmpl_array.push(" <tbody>");tmpl_array.push(" <% _.each(libraries, function(library) { %>");tmpl_array.push(" <tr>");tmpl_array.push(' <td><a href="#folders/<%- library.get("root_folder_id") %>"><%- library.get("name") %></a></td>');tmpl_array.push(' <td><%= _.escape(library.get("description")) %></td>');tmpl_array.push(' <td><%= _.escape(library.get("synopsis")) %></td>');tmpl_array.push(" </tr>");tmpl_array.push(" <% }); %>");tmpl_array.push(" </tbody>");tmpl_array.push("</table>");tmpl_array.push("<% }%>");tmpl_array.push("</div>");return _.template(tmpl_array.join(""))},templateNewLibraryInModal:function(){tmpl_array=[];tmpl_array.push('<div id="new_library_modal">');tmpl_array.push(" <form>");tmpl_array.push(' <input type="text" name="Name" value="" placeholder="Name">');tmpl_array.push(' <input type="text" name="Description" value="" placeholder="Description">');tmpl_array.push(' <input type="text" name="Synopsis" value="" placeholder="Synopsis">');tmpl_array.push(" </form>");tmpl_array.push("</div>");return tmpl_array.join("")},redirectToHome:function(){window.location="../"},redirectToLogin:function(){window.location="/user/login"},show_library_modal:function(r){r.preventDefault();r.stopPropagation();var q=this;this.modal=Galaxy.modal;this.modal.show({closing_events:true,title:"Create New Library",body:this.templateNewLibraryInModal(),buttons:{Create:function(){q.create_new_library_event()},Close:function(){q.modal.hide()}}})},create_new_library_event:function(){var s=this.serialize_new_library();if(this.validate_new_library(s)){var r=new f();var q=this;r.save(s,{success:function(t){q.collection.add(t);q.modal.hide();q.clear_library_modal();q.render();m.success("Library created")},error:function(){m.error("An error occured :(")}})}else{m.error("Library's name is missing")}return false},clear_library_modal:function(){$("input[name='Name']").val("");$("input[name='Description']").val("");$("input[name='Synopsis']").val("")},serialize_new_library:function(){return{name:$("input[name='Name']").val(),description:$("input[name='Description']").val(),synopsis:$("input[name='Synopsis']").val()}},validate_new_library:function(q){return q.name!==""}});var p=Backbone.Router.extend({routes:{"":"libraries","sort/:sort_by/:order":"sort_libraries","folders/:id":"folder_content","folders/:folder_id/download/:format":"download"}});var g=Backbone.View.extend({initialize:function(){galaxyLibraryview=new a();library_router=new p();folderContentView=new l();library_router.on("route:libraries",function(){galaxyLibraryview.render()});library_router.on("route:sort_libraries",function(r,q){galaxyLibraryview.sortLibraries(r,q);galaxyLibraryview.render()});library_router.on("route:folder_content",function(q){folderContentView.render({id:q})});library_router.on("route:download",function(q,r){if($("#center").find(":checked").length===0){library_router.navigate("folders/"+q,{trigger:true,replace:true})}else{folderContentView.download(q,r);library_router.navigate("folders/"+q,{trigger:false,replace:true})}});Backbone.history.start({pushState:false})}});return{GalaxyApp:g}});
\ No newline at end of file
+var view=null;var library_router=null;var responses=[];define(["galaxy.masthead","utils/utils","libs/toastr"],function(l,i,n){var f=Backbone.Model.extend({urlRoot:"/api/libraries/"});var c=Backbone.Model.extend({urlRoot:"/api/folders"});var o=Backbone.Collection.extend({url:"/api/libraries",model:f,sort_key:"name",sort_order:null,});var j=Backbone.Model.extend({urlRoot:"/api/libraries/datasets"});var d=Backbone.Collection.extend({model:j});var e=Backbone.Model.extend({defaults:{folder:new d(),full_path:"unknown",urlRoot:"/api/folders/",id:"unknown"},parse:function(r){this.full_path=r[0].full_path;this.get("folder").reset(r[1].folder_contents);return r}});var b=Backbone.Model.extend({urlRoot:"/api/histories/"});var k=Backbone.Model.extend({url:"/api/histories/"});var p=Backbone.Collection.extend({url:"/api/histories",model:k});var m=Backbone.View.extend({el:"#center",progress:0,progressStep:1,lastSelectedHistory:"",modal:null,folders:null,initialize:function(){this.folders=[];this.queue=jQuery.Deferred();this.queue.resolve()},templateFolder:function(){var r=[];r.push('<div class="library_container" style="width: 90%; margin: auto; margin-top: 2em; ">');r.push('<h3>Data Libraries Beta Test. This is work in progress. Please report problems & ideas via <a href="mailto:galaxy-bugs@bx.psu.edu?Subject=DataLibrariesBeta_Feedback" target="_blank">email</a> and <a href="https://trello.com/c/nwYQNFPK/56-data-library-ui-progressive-display-of-fol…" target="_blank">Trello</a>.</h3>');r.push('<div id="library_folder_toolbar" >');r.push(' <button title="Create New Folder" id="toolbtn_create_folder" class="primary-button" type="button"><span class="fa fa-plus"></span><span class="fa fa-folder-close"></span> folder</button>');r.push(' <button title="Import selected datasets into history" id="toolbtn_bulk_import" class="primary-button" style="display: none; margin-left: 0.5em;" type="button"><span class="fa fa-book"></span> to history</button>');r.push(' <div id="toolbtn_dl" class="btn-group" style="margin-left: 0.5em; display: none; ">');r.push(' <button title="Download selected datasets" id="drop_toggle" type="button" class="primary-button dropdown-toggle" data-toggle="dropdown">');r.push(' <span class="fa fa-download"></span> download <span class="caret"></span>');r.push(" </button>");r.push(' <ul class="dropdown-menu" role="menu">');r.push(' <li><a href="#/folders/<%= id %>/download/tgz">.tar.gz</a></li>');r.push(' <li><a href="#/folders/<%= id %>/download/tbz">.tar.bz</a></li>');r.push(' <li><a href="#/folders/<%= id %>/download/zip">.zip</a></li>');r.push(" </ul>");r.push(" </div>");r.push("</div>");r.push('<ol class="breadcrumb">');r.push(' <li><a title="Return to the list of libraries" href="#">Libraries</a></li>');r.push(" <% _.each(path, function(path_item) { %>");r.push(" <% if (path_item[0] != id) { %>");r.push(' <li><a title="Return to this folder" href="#/folders/<%- path_item[0] %>"><%- path_item[1] %></a></li> ');r.push("<% } else { %>");r.push(' <li class="active"><span title="You are in this folder"><%- path_item[1] %></span></li>');r.push(" <% } %>");r.push(" <% }); %>");r.push("</ol>");r.push('<table id="folder_table" class="grid table table-condensed">');r.push(" <thead>");r.push(' <th class="button_heading"></th>');r.push(' <th style="text-align: center; width: 20px; "><input id="select-all-checkboxes" style="margin: 0;" type="checkbox"></th>');r.push(" <th>name</th>");r.push(" <th>data type</th>");r.push(" <th>size</th>");r.push(" <th>date (UTC)</th>");r.push(" </thead>");r.push(" <tbody>");r.push(' <td><a href="#<% if (upper_folder_id !== 0){ print("folders/" + upper_folder_id)} %>" title="Go to parent folder" class="btn_open_folder btn btn-default btn-xs">..<a></td>');r.push(" <td></td>");r.push(" <td></td>");r.push(" <td></td>");r.push(" <td></td>");r.push(" <td></td>");r.push(" </tr>");r.push(" <% _.each(items, function(content_item) { %>");r.push(' <% if (content_item.get("type") === "folder") { %>');r.push(' <tr class="folder_row light" id="<%- content_item.id %>">');r.push(" <td>");r.push(' <span title="Folder" class="fa fa-folder-o"></span>');r.push(" </td>");r.push(" <td></td>");r.push(" <td>");r.push(' <a href="#folders/<%- content_item.id %>"><%- content_item.get("name") %></a>');r.push(' <% if (content_item.get("item_count") === 0) { %>');r.push(' <span class="muted">(empty folder)</span>');r.push(" <% } %>");r.push(" </td>");r.push(" <td>folder</td>");r.push(' <td><%= _.escape(content_item.get("item_count")) %> item(s)</td>');r.push(' <td><%= _.escape(content_item.get("time_updated")) %></td>');r.push(" </tr>");r.push(" <% } else { %>");r.push(' <tr class="dataset_row light" id="<%- content_item.id %>">');r.push(" <td>");r.push(' <span title="Dataset" class="fa fa-file-o"></span>');r.push(" </td>");r.push(' <td style="text-align: center; "><input style="margin: 0;" type="checkbox"></td>');r.push(' <td><a href="#" class="library-dataset"><%- content_item.get("name") %><a></td>');r.push(' <td><%= _.escape(content_item.get("data_type")) %></td>');r.push(' <td><%= _.escape(content_item.get("readable_size")) %></td>');r.push(' <td><%= _.escape(content_item.get("time_updated")) %></td>');r.push(" </tr>");r.push(" <% } %> ");r.push(" <% }); %>");r.push(" ");r.push(" </tbody>");r.push("</table>");r.push("</div>");return r.join("")},templateDatasetModal:function(){var r=[];r.push('<div class="modal_table">');r.push(' <table class="grid table table-striped table-condensed">');r.push(" <tr>");r.push(' <th scope="row" id="id_row" data-id="<%= _.escape(item.get("ldda_id")) %>">Name</th>');r.push(' <td><%= _.escape(item.get("name")) %></td>');r.push(" </tr>");r.push(" <tr>");r.push(' <th scope="row">Data type</th>');r.push(' <td><%= _.escape(item.get("data_type")) %></td>');r.push(" </tr>");r.push(" <tr>");r.push(' <th scope="row">Genome build</th>');r.push(' <td><%= _.escape(item.get("genome_build")) %></td>');r.push(" </tr>");r.push(' <th scope="row">Size</th>');r.push(" <td><%= _.escape(size) %></td>");r.push(" </tr>");r.push(" <tr>");r.push(' <th scope="row">Date uploaded (UTC)</th>');r.push(' <td><%= _.escape(item.get("date_uploaded")) %></td>');r.push(" </tr>");r.push(" <tr>");r.push(' <th scope="row">Uploaded by</th>');r.push(' <td><%= _.escape(item.get("uploaded_by")) %></td>');r.push(" </tr>");r.push(' <tr scope="row">');r.push(' <th scope="row">Data Lines</th>');r.push(' <td scope="row"><%= _.escape(item.get("metadata_data_lines")) %></td>');r.push(" </tr>");r.push(' <th scope="row">Comment Lines</th>');r.push(' <% if (item.get("metadata_comment_lines") === "") { %>');r.push(' <td scope="row"><%= _.escape(item.get("metadata_comment_lines")) %></td>');r.push(" <% } else { %>");r.push(' <td scope="row">unknown</td>');r.push(" <% } %>");r.push(" </tr>");r.push(" <tr>");r.push(' <th scope="row">Number of Columns</th>');r.push(' <td scope="row"><%= _.escape(item.get("metadata_columns")) %></td>');r.push(" </tr>");r.push(" <tr>");r.push(' <th scope="row">Column Types</th>');r.push(' <td scope="row"><%= _.escape(item.get("metadata_column_types")) %></td>');r.push(" </tr>");r.push(" <tr>");r.push(' <th scope="row">Miscellaneous information</th>');r.push(' <td scope="row"><%= _.escape(item.get("misc_blurb")) %></td>');r.push(" </tr>");r.push(" </table>");r.push(' <pre class="peek">');r.push(" </pre>");r.push("</div>");return r.join("")},templateHistorySelectInModal:function(){var r=[];r.push('<span id="history_modal_combo" style="width:100%; margin-left: 1em; margin-right: 1em; ">');r.push("Select history: ");r.push('<select id="dataset_import_single" name="dataset_import_single" style="width:40%; margin-bottom: 1em; "> ');r.push(" <% _.each(histories, function(history) { %>");r.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');r.push(" <% }); %>");r.push("</select>");r.push("</span>");return r.join("")},templateBulkImportInModal:function(){var r=[];r.push('<span id="history_modal_combo_bulk" style="width:90%; margin-left: 1em; margin-right: 1em; ">');r.push("Select history: ");r.push('<select id="dataset_import_bulk" name="dataset_import_bulk" style="width:50%; margin-bottom: 1em; "> ');r.push(" <% _.each(histories, function(history) { %>");r.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');r.push(" <% }); %>");r.push("</select>");r.push("</span>");return r.join("")},templateProgressBar:function(){var r=[];r.push('<div class="import_text">');r.push("Importing selected datasets to history <b><%= _.escape(history_name) %></b>");r.push("</div>");r.push('<div class="progress">');r.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');r.push(' <span class="completion_span">0% Complete</span>');r.push(" </div>");r.push("</div>");r.push("");return r.join("")},templateNewFolderInModal:function(){tmpl_array=[];tmpl_array.push('<div id="new_folder_modal">');tmpl_array.push("<form>");tmpl_array.push('<input type="text" name="Name" value="" placeholder="Name">');tmpl_array.push('<input type="text" name="Description" value="" placeholder="Description">');tmpl_array.push("</form>");tmpl_array.push("</div>");return tmpl_array.join("")},events:{"click #select-all-checkboxes":"selectAll","click #toolbtn_bulk_import":"modalBulkImport","click #toolbtn_dl":"bulkDownload","click #toolbtn_create_folder":"createFolderFromModal","click .library-dataset":"showDatasetDetails","click .dataset_row":"selectClickedRow"},render:function(r){$("#center").css("overflow","auto");view=this;var t=this;var s=new e({id:r.id});s.url=s.attributes.urlRoot+r.id+"/contents";s.fetch({success:function(u){for(var w=0;w<s.attributes.folder.models.length;w++){var v=s.attributes.folder.models[w];if(v.get("type")==="file"){v.set("readable_size",t.size_to_string(v.get("file_size")))}}var y=s.full_path;var z;if(y.length===1){z=0}else{z=y[y.length-2][0]}var x=_.template(t.templateFolder(),{path:s.full_path,items:s.attributes.folder.models,id:r.id,upper_folder_id:z});t.$el.html(x)},error:function(){n.error("An error occured :(")}})},size_to_string:function(r){var s="";if(r>=100000000000){r=r/100000000000;s="TB"}else{if(r>=100000000){r=r/100000000;s="GB"}else{if(r>=100000){r=r/100000;s="MB"}else{if(r>=100){r=r/100;s="KB"}else{r=r*10;s="b"}}}}return(Math.round(r)/10)+s},showDatasetDetails:function(u){u.preventDefault();var v=$(u.target).parent().parent().parent().attr("id");if(typeof v==="undefined"){v=$(u.target).parent().attr("id")}if(typeof v==="undefined"){v=$(u.target).parent().parent().attr("id")}var t=new j();var s=new p();t.id=v;var r=this;t.fetch({success:function(w){s.fetch({success:function(x){r.renderModalAfterFetch(w,x)},error:function(){n.error("An error occured during fetching histories:(");r.renderModalAfterFetch(w)}})},error:function(){n.error("An error occured during loading dataset details :(")}})},renderModalAfterFetch:function(w,t){var u=this.size_to_string(w.get("file_size"));var v=_.template(this.templateDatasetModal(),{item:w,size:u});var s=this;this.modal=Galaxy.modal;this.modal.show({closing_events:true,title:"Dataset Details",body:v,buttons:{Import:function(){s.importCurrentIntoHistory()},Download:function(){s.downloadCurrent()},Close:function(){s.modal.hide()}}});$(".peek").html("Peek:"+w.get("peek"));if(typeof history.models!==undefined){var r=_.template(this.templateHistorySelectInModal(),{histories:t.models});$(this.modal.elMain).find(".buttons").prepend(r);if(s.lastSelectedHistory.length>0){$(this.modal.elMain).find("#dataset_import_single").val(s.lastSelectedHistory)}}},downloadCurrent:function(){this.modal.disableButton("Import");this.modal.disableButton("Download");var r=[];r.push($("#id_row").attr("data-id"));var s="/api/libraries/datasets/download/uncompressed";var t={ldda_ids:r};folderContentView.processDownload(s,t);this.modal.enableButton("Import");this.modal.enableButton("Download")},importCurrentIntoHistory:function(){this.modal.disableButton("Import");this.modal.disableButton("Download");var t=$(this.modal.elMain).find("select[name=dataset_import_single] option:selected").val();this.lastSelectedHistory=t;var r=$("#id_row").attr("data-id");var u=new b();var s=this;u.url=u.urlRoot+t+"/contents";u.save({content:r,source:"library"},{success:function(){n.success("Dataset imported");s.modal.enableButton("Import");s.modal.enableButton("Download")},error:function(){n.error("An error occured! Dataset not imported. Please try again.");s.modal.enableButton("Import");s.modal.enableButton("Download")}})},selectAll:function(s){var r=s.target.checked;that=this;$(":checkbox").each(function(){this.checked=r;$row=$(this.parentElement.parentElement);(r)?that.makeDarkRow($row):that.makeWhiteRow($row)});this.checkTools()},selectClickedRow:function(s){var u="";var r;var t;if(s.target.localName==="input"){u=s.target;r=$(s.target.parentElement.parentElement);t="input"}else{if(s.target.localName==="td"){u=$("#"+s.target.parentElement.id).find(":checkbox")[0];r=$(s.target.parentElement);t="td"}}if(u.checked){if(t==="td"){u.checked="";this.makeWhiteRow(r)}else{if(t==="input"){this.makeDarkRow(r)}}}else{if(t==="td"){u.checked="selected";this.makeDarkRow(r)}else{if(t==="input"){this.makeWhiteRow(r)}}}this.checkTools()},makeDarkRow:function(r){r.removeClass("light");r.find("a").removeClass("light");r.addClass("dark");r.find("a").addClass("dark");r.find("span").removeClass("fa-file-o");r.find("span").addClass("fa-file")},makeWhiteRow:function(r){r.removeClass("dark");r.find("a").removeClass("dark");r.addClass("light");r.find("a").addClass("light");r.find("span").addClass("fa-file-o");r.find("span").removeClass("fa-file")},checkTools:function(){var r=$("#folder_table").find(":checked");if(r.length>0){$("#toolbtn_bulk_import").show();$("#toolbtn_dl").show()}else{$("#toolbtn_bulk_import").hide();$("#toolbtn_dl").hide()}},modalBulkImport:function(){var s=this;var r=new p();r.fetch({success:function(t){var u=_.template(s.templateBulkImportInModal(),{histories:t.models});s.modal=Galaxy.modal;s.modal.show({closing_events:true,title:"Import into History",body:u,buttons:{Import:function(){s.importAllIntoHistory()},Close:function(){s.modal.hide()}}})},error:function(){n.error("An error occured :(")}})},importAllIntoHistory:function(){this.modal.disableButton("Import");var t=$("select[name=dataset_import_bulk] option:selected").val();var x=$("select[name=dataset_import_bulk] option:selected").text();var z=[];$("#folder_table").find(":checked").each(function(){if(this.parentElement.parentElement.id!=""){z.push(this.parentElement.parentElement.id)}});var y=_.template(this.templateProgressBar(),{history_name:x});$(this.modal.elMain).find(".modal-body").html(y);var u=100/z.length;this.initProgress(u);var r=[];for(var s=z.length-1;s>=0;s--){library_dataset_id=z[s];var v=new b();var w=this;v.url=v.urlRoot+t+"/contents";v.content=library_dataset_id;v.source="library";r.push(v)}this.chainCall(r)},chainCall:function(s){var r=this;var t=s.pop();if(typeof t==="undefined"){n.success("All datasets imported");this.modal.hide();return}var u=$.when(t.save({content:t.content,source:t.source})).done(function(v){r.updateProgress();responses.push(v);r.chainCall(s)})},initProgress:function(r){this.progress=0;this.progressStep=r},updateProgress:function(){this.progress+=this.progressStep;$(".progress-bar-import").width(Math.round(this.progress)+"%");txt_representation=Math.round(this.progress)+"% Complete";$(".completion_span").text(txt_representation)},download:function(r,v){var t=[];$("#folder_table").find(":checked").each(function(){if(this.parentElement.parentElement.id!=""){t.push(this.parentElement.parentElement.id)}});var s="/api/libraries/datasets/download/"+v;var u={ldda_ids:t};this.processDownload(s,u,"get")},processDownload:function(s,t,u){if(s&&t){t=typeof t=="string"?t:$.param(t);var r="";$.each(t.split("&"),function(){var v=this.split("=");r+='<input type="hidden" name="'+v[0]+'" value="'+v[1]+'" />'});$('<form action="'+s+'" method="'+(u||"post")+'">'+r+"</form>").appendTo("body").submit().remove();n.info("Your download will begin soon")}},createFolderFromModal:function(){event.preventDefault();event.stopPropagation();var r=this;this.modal=Galaxy.modal;this.modal.show({closing_events:true,title:"Create New Folder",body:this.templateNewFolderInModal(),buttons:{Create:function(){r.create_new_folder_event()},Close:function(){r.modal.hide();r.modal=null}}})},create_new_folder_event:function(){var r=this.serialize_new_folder();if(this.validate_new_folder(r)){var t=new c();url_items=Backbone.history.fragment.split("/");current_folder_id=url_items[url_items.length-1];t.url=t.urlRoot+"/"+current_folder_id;var s=this;t.save(r,{success:function(u){s.modal.hide();n.success("Folder created");s.render({id:current_folder_id})},error:function(){n.error("An error occured :(")}})}else{n.error("Folder's name is missing")}return false},serialize_new_folder:function(){return{name:$("input[name='Name']").val(),description:$("input[name='Description']").val()}},validate_new_folder:function(r){return r.name!==""}});var a=Backbone.View.extend({el:"#libraries_element",events:{"click .edit_library_btn":"edit_button_event","click .save_library_btn":"save_library_modification","click .cancel_library_btn":"cancel_library_modification","click .delete_library_btn":"delete_library","click .undelete_library_btn":"undelete_library"},modal:null,collection:null,initialize:function(){var r=this;this.collection=new o();this.collection.fetch({success:function(s){r.render();$("#center [data-toggle]").tooltip();$("#center").css("overflow","auto")},error:function(t,s){n.error("An error occured. Please try again.")}})},render:function(s){var t=this.templateLibraryList();var u=null;var r=false;var v=null;if(typeof s!=="undefined"){r=typeof s.with_deleted!=="undefined"?s.with_deleted:false;v=typeof s.models!=="undefined"?s.models:null}if(this.collection!==null&&v===null){if(r){u=this.collection.models}else{u=this.collection.where({deleted:false})}}else{if(v!==null){u=v}else{u=[]}}this.$el.html(t({libraries:u,order:this.collection.sort_order}))},sortLibraries:function(s,r){if(s==="name"){if(r==="asc"){this.collection.sort_order="asc";this.collection.comparator=function(u,t){if(u.get("name").toLowerCase()>t.get("name").toLowerCase()){return 1}if(t.get("name").toLowerCase()>u.get("name").toLowerCase()){return -1}return 0}}else{if(r==="desc"){this.collection.sort_order="desc";this.collection.comparator=function(u,t){if(u.get("name").toLowerCase()>t.get("name").toLowerCase()){return -1}if(t.get("name").toLowerCase()>u.get("name").toLowerCase()){return 1}return 0}}}this.collection.sort()}},templateLibraryList:function(){tmpl_array=[];tmpl_array.push('<div class="library_container table-responsive">');tmpl_array.push("<% if(libraries.length === 0) { %>");tmpl_array.push("<div>I see no libraries. Why don't you create one?</div>");tmpl_array.push("<% } else{ %>");tmpl_array.push('<table class="grid table table-condensed">');tmpl_array.push(" <thead>");tmpl_array.push(' <th style="width:30%;"><a title="Click to reverse order" href="#sort/name/<% if(order==="desc"||order===null){print("asc")}else{print("desc")} %>">name</a><span title="Sorted alphabetically" class="fa fa-sort-alpha-<%- order %>"></span></th>');tmpl_array.push(' <th style="width:22%;">description</th>');tmpl_array.push(' <th style="width:22%;">synopsis</th> ');tmpl_array.push(' <th style="width:26%;"></th> ');tmpl_array.push(" </thead>");tmpl_array.push(" <tbody>");tmpl_array.push(" <% _.each(libraries, function(library) { %>");tmpl_array.push(' <tr class="<% if(library.get("deleted") === true){print("active");}%>" data-id="<%- library.get("id") %>">');tmpl_array.push(' <td><a href="#folders/<%- library.get("root_folder_id") %>"><%- library.get("name") %></a></td>');tmpl_array.push(' <td><%= _.escape(library.get("description")) %></td>');tmpl_array.push(' <td><%= _.escape(library.get("synopsis")) %></td>');tmpl_array.push(' <td class="right-center">');tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Modify library" class="primary-button btn-xs edit_library_btn" type="button"><span class="fa fa-pencil"></span></button>');tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Save changes" class="primary-button btn-xs save_library_btn" type="button" style="display:none;"><span class="fa fa-floppy-o"> Save</span></button>');tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Discard changes" class="primary-button btn-xs cancel_library_btn" type="button" style="display:none;"><span class="fa fa-times"> Cancel</span></button>');tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Delete library (can be undeleted later)" class="primary-button btn-xs delete_library_btn" type="button" style="display:none;"><span class="fa fa-trash-o"> Delete</span></button>');tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Undelete library" class="primary-button btn-xs undelete_library_btn" type="button" style="display:none;"><span class="fa fa-unlock"> Undelete</span></button>');tmpl_array.push(" </td>");tmpl_array.push(" </tr>");tmpl_array.push(" <% }); %>");tmpl_array.push(" </tbody>");tmpl_array.push("</table>");tmpl_array.push("<% }%>");tmpl_array.push("</div>");return _.template(tmpl_array.join(""))},templateNewLibraryInModal:function(){tmpl_array=[];tmpl_array.push('<div id="new_library_modal">');tmpl_array.push(" <form>");tmpl_array.push(' <input type="text" name="Name" value="" placeholder="Name">');tmpl_array.push(' <input type="text" name="Description" value="" placeholder="Description">');tmpl_array.push(' <input type="text" name="Synopsis" value="" placeholder="Synopsis">');tmpl_array.push(" </form>");tmpl_array.push("</div>");return tmpl_array.join("")},save_library_modification:function(u){var t=$(u.target).closest("tr");var r=this.collection.get(t.data("id"));var s=false;var w=t.find(".input_library_name").val();if(typeof w!=="undefined"&&w!==r.get("name")){if(w.length>2){r.set("name",w);s=true}else{n.warning("Library name has to be at least 3 characters long");return}}var v=t.find(".input_library_description").val();if(typeof v!=="undefined"&&v!==r.get("description")){r.set("description",v);s=true}var x=t.find(".input_library_synopsis").val();if(typeof x!=="undefined"&&x!==r.get("synopsis")){r.set("synopsis",x);s=true}if(s){r.save(null,{patch:true,success:function(y){n.success("Changes to library saved");galaxyLibraryview.toggle_library_modification(t)},error:function(z,y){n.error("An error occured during updating the library :(")}})}},edit_button_event:function(r){this.toggle_library_modification($(r.target).closest("tr"))},toggle_library_modification:function(u){var r=this.collection.get(u.data("id"));u.find(".edit_library_btn").toggle();u.find(".save_library_btn").toggle();u.find(".cancel_library_btn").toggle();if(r.get("deleted")){u.find(".undelete_library_btn").toggle()}else{u.find(".delete_library_btn").toggle()}if(u.find(".edit_library_btn").is(":hidden")){var s=r.get("name");var w='<input type="text" class="form-control input_library_name" placeholder="name">';u.children("td").eq(0).html(w);if(typeof s!==undefined){u.find(".input_library_name").val(s)}var t=r.get("description");var w='<input type="text" class="form-control input_library_description" placeholder="description">';u.children("td").eq(1).html(w);if(typeof t!==undefined){u.find(".input_library_description").val(t)}var v=r.get("synopsis");var w='<input type="text" class="form-control input_library_synopsis" placeholder="synopsis">';u.children("td").eq(2).html(w);if(typeof v!==undefined){u.find(".input_library_synopsis").val(v)}}else{u.children("td").eq(0).html(r.get("name"));u.children("td").eq(1).html(r.get("description"));u.children("td").eq(2).html(r.get("synopsis"))}},cancel_library_modification:function(t){var s=$(t.target).closest("tr");var r=this.collection.get(s.data("id"));this.toggle_library_modification(s);s.children("td").eq(0).html(r.get("name"));s.children("td").eq(1).html(r.get("description"));s.children("td").eq(2).html(r.get("synopsis"))},undelete_library:function(t){var s=$(t.target).closest("tr");var r=this.collection.get(s.data("id"));this.toggle_library_modification(s);r.url=r.urlRoot+r.id+"?undelete=true";r.destroy({success:function(u){u.set("deleted",false);galaxyLibraryview.collection.add(u);s.removeClass("active");n.success("Library has been undeleted")},error:function(){n.error("An error occured while undeleting the library :(")}})},delete_library:function(t){var s=$(t.target).closest("tr");var r=this.collection.get(s.data("id"));this.toggle_library_modification(s);r.destroy({success:function(u){s.remove();u.set("deleted",true);galaxyLibraryview.collection.add(u);n.success("Library has been marked deleted")},error:function(){n.error("An error occured during deleting the library :(")}})},redirectToHome:function(){window.location="../"},redirectToLogin:function(){window.location="/user/login"},show_library_modal:function(s){s.preventDefault();s.stopPropagation();var r=this;this.modal=Galaxy.modal;this.modal.show({closing_events:true,title:"Create New Library",body:this.templateNewLibraryInModal(),buttons:{Create:function(){r.create_new_library_event()},Close:function(){r.modal.hide()}}})},create_new_library_event:function(){var t=this.serialize_new_library();if(this.validate_new_library(t)){var s=new f();var r=this;s.save(t,{success:function(u){r.collection.add(u);r.modal.hide();r.clear_library_modal();r.render();n.success("Library created")},error:function(){n.error("An error occured :(")}})}else{n.error("Library's name is missing")}return false},clear_library_modal:function(){$("input[name='Name']").val("");$("input[name='Description']").val("");$("input[name='Synopsis']").val("")},serialize_new_library:function(){return{name:$("input[name='Name']").val(),description:$("input[name='Description']").val(),synopsis:$("input[name='Synopsis']").val()}},validate_new_library:function(r){return r.name!==""}});var h=Backbone.View.extend({el:"#center",events:{"click #create_new_library_btn":"delegate_modal","click #include_deleted_chk":"check_include_deleted"},initialize:function(){this.render()},delegate_modal:function(r){galaxyLibraryview.show_library_modal(r)},check_include_deleted:function(r){if(r.target.checked){galaxyLibraryview.render({with_deleted:true})}else{galaxyLibraryview.render({with_deleted:false})}},render:function(){var r=this.templateToolBar();this.$el.html(r())},templateToolBar:function(){tmpl_array=[];tmpl_array.push('<div id="libraries_container" style="width: 90%; margin: auto; margin-top:2em; overflow: auto !important; ">');tmpl_array.push(' <div id="toolbar_form" margin-top:0.5em; ">');tmpl_array.push(' <h3>Data Libraries Beta Test. This is work in progress. Please report problems & ideas via <a href="mailto:galaxy-bugs@bx.psu.edu?Subject=DataLibrariesBeta_Feedback" target="_blank">email</a> and <a href="https://trello.com/c/nwYQNFPK/56-data-library-ui-progressive-display-of-fol…" target="_blank">Trello</a>.</h3>');tmpl_array.push(' <div id="library_toolbar">');tmpl_array.push(' <input id="include_deleted_chk" style="margin: 0;" type="checkbox">include deleted</input>');tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Create New Library" id="create_new_library_btn" class="primary-button" type="button"><span class="fa fa-plus"></span> New Library</button>');tmpl_array.push(" </div>");tmpl_array.push(" </div>");tmpl_array.push(' <div id="libraries_element">');tmpl_array.push(" </div>");tmpl_array.push("</div>");return _.template(tmpl_array.join(""))}});var q=Backbone.Router.extend({routes:{"":"libraries","sort/:sort_by/:order":"sort_libraries","folders/:id":"folder_content","folders/:folder_id/download/:format":"download"}});var g=Backbone.View.extend({initialize:function(){toolbarView=new h();galaxyLibraryview=new a();library_router=new q();folderContentView=new m();library_router.on("route:libraries",function(){toolbarView=new h();galaxyLibraryview=new a()});library_router.on("route:sort_libraries",function(s,r){galaxyLibraryview.sortLibraries(s,r);galaxyLibraryview.render()});library_router.on("route:folder_content",function(r){folderContentView.render({id:r})});library_router.on("route:download",function(r,s){if($("#center").find(":checked").length===0){library_router.navigate("folders/"+r,{trigger:true,replace:true})}else{folderContentView.download(r,s);library_router.navigate("folders/"+r,{trigger:false,replace:true})}});Backbone.history.start({pushState:false})}});return{GalaxyApp:g}});
\ No newline at end of file
diff -r fa0968cfe3c3fec5869168bd7dd68829024f1ec3 -r 33cc6056d83760e5e3b98999b01ecb260423d33c static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1295,6 +1295,7 @@
div.libraryItemBody{padding:4px 4px 2px 4px}
li.folderRow,li.datasetRow{border-top:solid 1px #c6bfa8}
li.folderRow:hover,li.datasetRow:hover{background-color:#f9f9f9}
+td.right-center{vertical-align:middle !important;text-align:right}
.library_table td{border-top:1px solid #5f6990 !important}
.library_table th{border-bottom:2px solid #5f6990 !important}
.library_table a{color:#0A143D}.library_table a:hover{color:maroon}
diff -r fa0968cfe3c3fec5869168bd7dd68829024f1ec3 -r 33cc6056d83760e5e3b98999b01ecb260423d33c static/style/blue/library.css
--- a/static/style/blue/library.css
+++ b/static/style/blue/library.css
@@ -6,6 +6,7 @@
div.libraryItemBody{padding:4px 4px 2px 4px}
li.folderRow,li.datasetRow{border-top:solid 1px #c6bfa8}
li.folderRow:hover,li.datasetRow:hover{background-color:#f9f9f9}
+td.right-center{vertical-align:middle !important;text-align:right}
.library_table td{border-top:1px solid #5f6990 !important}
.library_table th{border-bottom:2px solid #5f6990 !important}
.library_table a{color:#0A143D}.library_table a:hover{color:maroon}
diff -r fa0968cfe3c3fec5869168bd7dd68829024f1ec3 -r 33cc6056d83760e5e3b98999b01ecb260423d33c static/style/src/less/library.less
--- a/static/style/src/less/library.less
+++ b/static/style/src/less/library.less
@@ -29,6 +29,11 @@
background-color: @table-bg-accent;
}
+td.right-center{
+ vertical-align: middle !important;
+ text-align: right;
+
+}
.library_table{
td {
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: UI: Modularize scratch book and make it reusable as regular ui element, refactor charts
by commits-noreply@bitbucket.org 24 Mar '14
by commits-noreply@bitbucket.org 24 Mar '14
24 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/fa0968cfe3c3/
Changeset: fa0968cfe3c3
User: guerler
Date: 2014-03-24 09:50:52
Summary: UI: Modularize scratch book and make it reusable as regular ui element, refactor charts
Affected #: 16 files
diff -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 -r fa0968cfe3c3fec5869168bd7dd68829024f1ec3 config/plugins/visualizations/charts/static/app.js
--- a/config/plugins/visualizations/charts/static/app.js
+++ b/config/plugins/visualizations/charts/static/app.js
@@ -1,10 +1,10 @@
// dependencies
-define(['mvc/ui/ui-modal', 'mvc/ui/ui-portlet', 'plugin/library/ui', 'utils/utils', 'plugin/library/jobs', 'plugin/library/datasets',
- 'plugin/views/charts', 'plugin/views/chart',
- 'plugin/models/config', 'plugin/models/chart', 'plugin/models/charts', 'plugin/charts/types'],
- function( Modal, Portlet, Ui, Utils, Jobs, Datasets,
- ChartsView, ChartView,
- Config, Chart, Charts, Types
+define(['mvc/ui/ui-modal', 'mvc/ui/ui-portlet', 'plugin/library/ui', 'utils/utils', 'plugin/library/jobs', 'plugin/library/datasets', 'plugin/library/storage',
+ 'plugin/views/viewer', 'plugin/views/editor',
+ 'plugin/models/config', 'plugin/models/chart', 'plugin/charts/types'],
+ function( Modal, Portlet, Ui, Utils, Jobs, Datasets, Storage,
+ ViewerView, EditorView,
+ Config, Chart, Types
) {
// widget
@@ -23,91 +23,61 @@
this.modal = new Modal.View();
}
- // create configuration model
+ //
+ // models
+ //
this.config = new Config();
-
- // job/data /processor
- this.jobs = new Jobs(this);
-
- // create chart models
this.types = new Types();
this.chart = new Chart();
- this.charts = new Charts(null, this);
- // create dataset handler
+ //
+ // libraries
+ //
+ this.jobs = new Jobs(this);
this.datasets = new Datasets(this);
-
- // create views
- this.charts_view = new ChartsView(this);
- this.chart_view = new ChartView(this);
-
- // create portlet
- if (!this.options.config.widget) {
- this.portlet = new Portlet.View({icon : 'fa-bar-chart-o'});
- } else {
- this.portlet = $('<div></div>');
- }
+ this.storage = new Storage(this);
+
+ //
+ // views
+ //
+ this.viewer_view = new ViewerView(this);
+ this.editor_view = new EditorView(this);
// append views
- this.portlet.append(this.charts_view.$el);
- this.portlet.append(this.chart_view.$el);
+ this.$el.append(this.viewer_view.$el);
+ this.$el.append(this.editor_view.$el);
- // set element
- if (!this.options.config.widget) {
- this.setElement(this.portlet.$el);
+ // pick start screen
+ if (!this.storage.load()) {
+ // show editor
+ this.go('editor');
} else {
- this.setElement(this.portlet);
- }
-
- // events
- var self = this;
- this.config.on('change:title', function() {
- self._refreshTitle();
- });
-
- // render
- this.render();
-
- // load charts
- this.charts.load();
-
- // start with chart view
- if (this.charts.length == 0) {
- this.go('chart_view');
- } else {
- this.go('charts_view');
+ // show viewport
+ this.go('viewer');
+
+ // redraw chart
+ this.chart.trigger('redraw');
}
},
// loads a view and makes sure that all others are hidden
go: function(view_id) {
+ // hide all tooltips
+ $('.tooltip').hide();
+
// pick view
switch (view_id) {
- case 'chart_view' :
- this.chart_view.show();
- this.charts_view.hide();
+ case 'editor' :
+ this.editor_view.show();
+ this.viewer_view.hide();
break;
- case 'charts_view' :
- this.chart_view.hide();
- this.charts_view.show();
+ case 'viewer' :
+ this.editor_view.hide();
+ this.viewer_view.show();
break;
}
},
- // render
- render: function() {
- this._refreshTitle();
- },
-
- // refresh title
- _refreshTitle: function() {
- var title = this.config.get('title');
- if (title) {
- title = ' - ' + title;
- }
- this.portlet.title('Charts' + title);
- },
-
// execute command
execute: function(options) {
},
diff -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 -r fa0968cfe3c3fec5869168bd7dd68829024f1ec3 config/plugins/visualizations/charts/static/build-app.js
--- a/config/plugins/visualizations/charts/static/build-app.js
+++ b/config/plugins/visualizations/charts/static/build-app.js
@@ -3,4 +3,4 @@
// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore may be freely distributed under the MIT license.
-(function(){var e=this,t=e._,n={},r=Array.prototype,i=Object.prototype,s=Function.prototype,o=r.push,u=r.slice,a=r.concat,f=i.toString,l=i.hasOwnProperty,c=r.forEach,h=r.map,p=r.reduce,d=r.reduceRight,v=r.filter,m=r.every,g=r.some,y=r.indexOf,b=r.lastIndexOf,w=Array.isArray,E=Object.keys,S=s.bind,x=function(e){if(e instanceof x)return e;if(!(this instanceof x))return new x(e);this._wrapped=e};typeof exports!="undefined"?(typeof module!="undefined"&&module.exports&&(exports=module.exports=x),exports._=x):e._=x,x.VERSION="1.4.4";var T=x.each=x.forEach=function(e,t,r){if(e==null)return;if(c&&e.forEach===c)e.forEach(t,r);else if(e.length===+e.length){for(var i=0,s=e.length;i<s;i++)if(t.call(r,e[i],i,e)===n)return}else for(var o in e)if(x.has(e,o)&&t.call(r,e[o],o,e)===n)return};x.map=x.collect=function(e,t,n){var r=[];return e==null?r:h&&e.map===h?e.map(t,n):(T(e,function(e,i,s){r.push(t.call(n,e,i,s))}),r)};var N="Reduce of empty array with no initial value";x.reduce=x.foldl=x.inject=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(p&&e.reduce===p)return r&&(t=x.bind(t,r)),i?e.reduce(t,n):e.reduce(t);T(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError(N);return n},x.reduceRight=x.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(d&&e.reduceRight===d)return r&&(t=x.bind(t,r)),i?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=x.keys(e);s=o.length}T(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError(N);return n},x.find=x.detect=function(e,t,n){var r;return C(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},x.filter=x.select=function(e,t,n){var r=[];return e==null?r:v&&e.filter===v?e.filter(t,n):(T(e,function(e,i,s){t.call(n,e,i,s)&&r.push(e)}),r)},x.reject=function(e,t,n){return x.filter(e,function(e,r,i){return!t.call(n,e,r,i)},n)},x.every=x.all=function(e,t,r){t||(t=x.identity);var i=!0;return e==null?i:m&&e.every===m?e.every(t,r):(T(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var C=x.some=x.any=function(e,t,r){t||(t=x.identity);var i=!1;return e==null?i:g&&e.some===g?e.some(t,r):(T(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};x.contains=x.include=function(e,t){return e==null?!1:y&&e.indexOf===y?e.indexOf(t)!=-1:C(e,function(e){return e===t})},x.invoke=function(e,t){var n=u.call(arguments,2),r=x.isFunction(t);return x.map(e,function(e){return(r?t:e[t]).apply(e,n)})},x.pluck=function(e,t){return x.map(e,function(e){return e[t]})},x.where=function(e,t,n){return x.isEmpty(t)?n?void 0:[]:x[n?"find":"filter"](e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},x.findWhere=function(e,t){return x.where(e,t,!0)},x.max=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&x.isEmpty(e))return-Infinity;var r={computed:-Infinity,value:-Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},x.min=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&x.isEmpty(e))return Infinity;var r={computed:Infinity,value:Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o<r.computed&&(r={value:e,computed:o})}),r.value},x.shuffle=function(e){var t,n=0,r=[];return T(e,function(e){t=x.random(n++),r[n-1]=r[t],r[t]=e}),r};var k=function(e){return x.isFunction(e)?e:function(t){return t[e]}};x.sortBy=function(e,t,n){var r=k(t);return x.pluck(x.map(e,function(e,t,i){return{value:e,index:t,criteria:r.call(n,e,t,i)}}).sort(function(e,t){var n=e.criteria,r=t.criteria;if(n!==r){if(n>r||n===void 0)return 1;if(n<r||r===void 0)return-1}return e.index<t.index?-1:1}),"value")};var L=function(e,t,n,r){var i={},s=k(t==null?x.identity:t);return T(e,function(t,o){var u=s.call(n,t,o,e);r(i,u,t)}),i};x.groupBy=function(e,t,n){return L(e,t,n,function(e,t,n){(x.has(e,t)?e[t]:e[t]=[]).push(n)})},x.countBy=function(e,t,n){return L(e,t,n,function(e,t){x.has(e,t)||(e[t]=0),e[t]++})},x.sortedIndex=function(e,t,n,r){n=n==null?x.identity:k(n);var i=n.call(r,t),s=0,o=e.length;while(s<o){var u=s+o>>>1;n.call(r,e[u])<i?s=u+1:o=u}return s},x.toArray=function(e){return e?x.isArray(e)?u.call(e):e.length===+e.length?x.map(e,x.identity):x.values(e):[]},x.size=function(e){return e==null?0:e.length===+e.length?e.length:x.keys(e).length},x.first=x.head=x.take=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,0,t):e[0]},x.initial=function(e,t,n){return u.call(e,0,e.length-(t==null||n?1:t))},x.last=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,Math.max(e.length-t,0)):e[e.length-1]},x.rest=x.tail=x.drop=function(e,t,n){return u.call(e,t==null||n?1:t)},x.compact=function(e){return x.filter(e,x.identity)};var A=function(e,t,n){return T(e,function(e){x.isArray(e)?t?o.apply(n,e):A(e,t,n):n.push(e)}),n};x.flatten=function(e,t){return A(e,t,[])},x.without=function(e){return x.difference(e,u.call(arguments,1))},x.uniq=x.unique=function(e,t,n,r){x.isFunction(t)&&(r=n,n=t,t=!1);var i=n?x.map(e,n,r):e,s=[],o=[];return T(i,function(n,r){if(t?!r||o[o.length-1]!==n:!x.contains(o,n))o.push(n),s.push(e[r])}),s},x.union=function(){return x.uniq(a.apply(r,arguments))},x.intersection=function(e){var t=u.call(arguments,1);return x.filter(x.uniq(e),function(e){return x.every(t,function(t){return x.indexOf(t,e)>=0})})},x.difference=function(e){var t=a.apply(r,u.call(arguments,1));return x.filter(e,function(e){return!x.contains(t,e)})},x.zip=function(){var e=u.call(arguments),t=x.max(x.pluck(e,"length")),n=new Array(t);for(var r=0;r<t;r++)n[r]=x.pluck(e,""+r);return n},x.unzip=function(e){var t=[];return x.each(e,function(e,n){x.each(e,function(e,r){t.length<=r&&(t[r]=[]),t[r][n]=e})}),t},x.object=function(e,t){if(e==null)return{};var n={};for(var r=0,i=e.length;r<i;r++)t?n[e[r]]=t[r]:n[e[r][0]]=e[r][1];return n},x.indexOf=function(e,t,n){if(e==null)return-1;var r=0,i=e.length;if(n){if(typeof n!="number")return r=x.sortedIndex(e,t),e[r]===t?r:-1;r=n<0?Math.max(0,i+n):n}if(y&&e.indexOf===y)return e.indexOf(t,n);for(;r<i;r++)if(e[r]===t)return r;return-1},x.lastIndexOf=function(e,t,n){if(e==null)return-1;var r=n!=null;if(b&&e.lastIndexOf===b)return r?e.lastIndexOf(t,n):e.lastIndexOf(t);var i=r?n:e.length;while(i--)if(e[i]===t)return i;return-1},x.range=function(e,t,n){arguments.length<=1&&(t=e||0,e=0),n=arguments[2]||1;var r=Math.max(Math.ceil((t-e)/n),0),i=0,s=new Array(r);while(i<r)s[i++]=e,e+=n;return s};var O=function(){};x.bind=function(e,t){var n,r;if(e.bind===S&&S)return S.apply(e,u.call(arguments,1));if(!x.isFunction(e))throw new TypeError;return n=u.call(arguments,2),r=function(){if(this instanceof r){O.prototype=e.prototype;var i=new O;O.prototype=null;var s=e.apply(i,n.concat(u.call(arguments)));return Object(s)===s?s:i}return e.apply(t,n.concat(u.call(arguments)))}},x.partial=function(e){var t=u.call(arguments,1);return function(){return e.apply(this,t.concat(u.call(arguments)))}},x.bindAll=function(e){var t=u.call(arguments,1);if(t.length===0)throw new Error("bindAll must be passed function names");return T(t,function(t){e[t]=x.bind(e[t],e)}),e},x.memoize=function(e,t){var n={};return t||(t=x.identity),function(){var r=t.apply(this,arguments);return x.has(n,r)?n[r]:n[r]=e.apply(this,arguments)}},x.delay=function(e,t){var n=u.call(arguments,2);return setTimeout(function(){return e.apply(null,n)},t)},x.defer=function(e){return x.delay.apply(x,[e,1].concat(u.call(arguments,1)))},x.throttle=function(e,t,n){var r,i,s,o,u=0,a=function(){u=new Date,s=null,o=e.apply(r,i)};return function(){var f=new Date;!u&&n===!1&&(u=f);var l=t-(f-u);return r=this,i=arguments,l<=0?(clearTimeout(s),s=null,u=f,o=e.apply(r,i)):s||(s=setTimeout(a,l)),o}},x.debounce=function(e,t,n){var r,i;return function(){var s=this,o=arguments,u=function(){r=null,n||(i=e.apply(s,o))},a=n&&!r;return clearTimeout(r),r=setTimeout(u,t),a&&(i=e.apply(s,o)),i}},x.once=function(e){var t=!1,n;return function(){return t?n:(t=!0,n=e.apply(this,arguments),e=null,n)}},x.wrap=function(e,t){return function(){var n=[e];return o.apply(n,arguments),t.apply(this,n)}},x.compose=function(){var e=arguments;return function(){var t=arguments;for(var n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},x.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},x.keys=E||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)x.has(e,n)&&t.push(n);return t},x.values=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push(e[n]);return t},x.pairs=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push([n,e[n]]);return t},x.invert=function(e){var t={};for(var n in e)x.has(e,n)&&(t[e[n]]=n);return t},x.functions=x.methods=function(e){var t=[];for(var n in e)x.isFunction(e[n])&&t.push(n);return t.sort()},x.extend=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]=t[n]}),e},x.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return T(n,function(n){n in e&&(t[n]=e[n])}),t},x.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)x.contains(n,i)||(t[i]=e[i]);return t},x.defaults=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]===void 0&&(e[n]=t[n])}),e},x.clone=function(e){return x.isObject(e)?x.isArray(e)?e.slice():x.extend({},e):e},x.tap=function(e,t){return t(e),e};var M=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof x&&(e=e._wrapped),t instanceof x&&(t=t._wrapped);var i=f.call(e);if(i!=f.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=M(e[o],t[o],n,r)))break}else{var a=e.constructor,l=t.constructor;if(a!==l&&!(x.isFunction(a)&&a instanceof a&&x.isFunction(l)&&l instanceof l))return!1;for(var c in e)if(x.has(e,c)){o++;if(!(u=x.has(t,c)&&M(e[c],t[c],n,r)))break}if(u){for(c in t)if(x.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};x.isEqual=function(e,t){return M(e,t,[],[])},x.isEmpty=function(e){if(e==null)return!0;if(x.isArray(e)||x.isString(e))return e.length===0;for(var t in e)if(x.has(e,t))return!1;return!0},x.isElement=function(e){return!!e&&e.nodeType===1},x.isArray=w||function(e){return f.call(e)=="[object Array]"},x.isObject=function(e){return e===Object(e)},T(["Arguments","Function","String","Number","Date","RegExp"],function(e){x["is"+e]=function(t){return f.call(t)=="[object "+e+"]"}}),x.isArguments(arguments)||(x.isArguments=function(e){return!!e&&!!x.has(e,"callee")}),typeof /./!="function"&&(x.isFunction=function(e){return typeof e=="function"}),x.isFinite=function(e){return isFinite(e)&&!isNaN(parseFloat(e))},x.isNaN=function(e){return x.isNumber(e)&&e!=+e},x.isBoolean=function(e){return e===!0||e===!1||f.call(e)=="[object Boolean]"},x.isNull=function(e){return e===null},x.isUndefined=function(e){return e===void 0},x.has=function(e,t){return l.call(e,t)},x.noConflict=function(){return e._=t,this},x.identity=function(e){return e},x.times=function(e,t,n){var r=Array(e);for(var i=0;i<e;i++)r[i]=t.call(n,i);return r},x.random=function(e,t){return t==null&&(t=e,e=0),e+Math.floor(Math.random()*(t-e+1))};var _={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};_.unescape=x.invert(_.escape);var D={escape:new RegExp("["+x.keys(_.escape).join("")+"]","g"),unescape:new RegExp("("+x.keys(_.unescape).join("|")+")","g")};x.each(["escape","unescape"],function(e){x[e]=function(t){return t==null?"":(""+t).replace(D[e],function(t){return _[e][t]})}}),x.result=function(e,t){if(e==null)return void 0;var n=e[t];return x.isFunction(n)?n.call(e):n},x.mixin=function(e){T(x.functions(e),function(t){var n=x[t]=e[t];x.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),F.call(this,n.apply(x,e))}})};var P=0;x.uniqueId=function(e){var t=++P+"";return e?e+t:t},x.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var H=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},j=/\\|'|\r|\n|\t|\u2028|\u2029/g;x.template=function(e,t,n){var r;n=x.defaults({},n,x.templateSettings);var i=new RegExp([(n.escape||H).source,(n.interpolate||H).source,(n.evaluate||H).source].join("|")+"|$","g"),s=0,o="__p+='";e.replace(i,function(t,n,r,i,u){return o+=e.slice(s,u).replace(j,function(e){return"\\"+B[e]}),n&&(o+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'"),r&&(o+="'+\n((__t=("+r+"))==null?'':__t)+\n'"),i&&(o+="';\n"+i+"\n__p+='"),s=u+t.length,t}),o+="';\n",n.variable||(o="with(obj||{}){\n"+o+"}\n"),o="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+o+"return __p;\n";try{r=new Function(n.variable||"obj","_",o)}catch(u){throw u.source=o,u}if(t)return r(t,x);var a=function(e){return r.call(this,e,x)};return a.source="function("+(n.variable||"obj")+"){\n"+o+"}",a},x.chain=function(e){return x(e).chain()};var F=function(e){return this._chain?x(e).chain():e};x.mixin(x),T(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];x.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],F.call(this,n)}}),T(["concat","join","slice"],function(e){var t=r[e];x.prototype[e]=function(){return F.call(this,t.apply(this._wrapped,arguments))}}),x.extend(x.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this),define("libs/underscore",function(e){return function(){var t,n;return t||e._}}(this)),define("utils/utils",["libs/underscore"],function(e){function t(e,t,r){n("GET",e,{},t,r)}function n(e,t,n,r,i){if(e=="GET"||e=="DELETE")t.indexOf("?")==-1?t+="?":t+="&",t+=$.param(n);var s=new XMLHttpRequest;s.open(e,t,!0),s.setRequestHeader("Accept","application/json"),s.setRequestHeader("Cache-Control","no-cache"),s.setRequestHeader("X-Requested-With","XMLHttpRequest"),s.setRequestHeader("Content-Type","application/json"),s.onloadend=function(){var e=s.status;try{response=jQuery.parseJSON(s.responseText)}catch(t){response=s.responseText}e==200?r&&r(response):i&&i(response)},e=="GET"||e=="DELETE"?s.send():s.send(JSON.stringify(n))}function r(e,t){var n=$('<div class="'+e+'"></div>');n.appendTo(":eq(0)");var r=n.css(t);return n.remove(),r}function i(e){$('link[href^="'+e+'"]').length||$('<link href="'+galaxy_config.root+e+'" rel="stylesheet">').appendTo("head")}function s(t,n){return t?e.defaults(t,n):n}function o(e,t){var n="";if(e>=1e11)e/=1e11,n="TB";else if(e>=1e8)e/=1e8,n="GB";else if(e>=1e5)e/=1e5,n="MB";else if(e>=100)e/=100,n="KB";else{if(!(e>0))return"<strong>-</strong>";e*=10,n="b"}var r=Math.round(e)/10;return t?r+" "+n:"<strong>"+r+"</strong> "+n}function u(){return(new Date).getTime().toString(36)}function a(e){var t=$("<p></p>");return t.append(e),t}function f(){var e=new Date,t=(e.getHours()<10?"0":"")+e.getHours(),n=(e.getMinutes()<10?"0":"")+e.getMinutes(),r=e.getDate()+"/"+(e.getMonth()+1)+"/"+e.getFullYear()+", "+t+":"+n;return r}return{cssLoadFile:i,cssGetAttribute:r,get:t,merge:s,bytesToString:o,uuid:u,time:f,wrap:a,request:n}}),define("mvc/ui/ui-modal",["utils/utils"],function(e){var t=Backbone.View.extend({elMain:"body",optionsDefault:{title:"ui-modal",body:"",backdrop:!0,height:null,width:null,closing_events:!1},buttonList:{},initialize:function(e){e&&this._create(e)},show:function(e){this.initialize(e),this.options.height?(this.$body.css("height",this.options.height),this.$body.css("overflow","hidden")):this.$body.css("max-height",$(window).height()/2),this.options.width&&this.$dialog.css("width",this.options.width),this.visible?this.$el.show():this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.visible=!1,this.$el.fadeOut("fast")},enableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!1)},disableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!0)},showButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).show()},hideButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).hide()},getButton:function(e){var t=this.buttonList[e];return this.$buttons.find("#"+t)},scrollTop:function(){return this.$body.scrollTop()},_create:function(e){var t=this;this.options=_.defaults(e,this.optionsDefault),this.options.body=="progress"&&(this.options.body=$('<div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width:100%"></div></div>')),this.$el&&(this.$el.remove(),$(document).off("keyup")),this.setElement(this._template(this.options.title)),this.$dialog=this.$el.find(".modal-dialog"),this.$body=this.$el.find(".modal-body"),this.$footer=this.$el.find(".modal-footer"),this.$buttons=this.$el.find(".buttons"),this.$backdrop=this.$el.find(".modal-backdrop"),this.$body.html(this.options.body),this.options.backdrop||this.$backdrop.removeClass("in");if(this.options.buttons){this.buttonList={};var n=0;$.each(this.options.buttons,function(e,r){var i="button-"+n++;t.$buttons.append($('<button id="'+i+'"></button>').text(e).click(r)).append(" "),t.buttonList[e]=i})}else this.$footer.hide();$(this.elMain).append($(this.el)),this.options.closing_events&&(this.options.buttons.Pause||$(document).on("keyup",function(e){e.keyCode==27&&t.hide()}),this.$el.find(".modal-backdrop").on("click",function(){t.hide()}))},_template:function(e){return'<div class="modal"><div class="modal-backdrop fade in" style="z-index: -1;"></div><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" style="display: none;">×</button><h4 class="title">'+e+"</h4>"+"</div>"+'<div class="modal-body" style="position: static;"></div>'+'<div class="modal-footer">'+'<div class="buttons" style="float: right;"></div>'+"</div>"+"</div"+"</div>"+"</div>"}});return{View:t}}),define("mvc/ui/ui-portlet",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,optionsDefault:{title:"",icon:"",buttons:null,body:null,height:null,operations:null,placement:"bottom",overflow:"auto"},$title:null,$content:null,$buttons:null,$operations:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$content=this.$el.find("#content"),this.$title=this.$el.find("#title-text"),this.options.height&&(this.$el.find("#body").css("height",this.options.height),this.$el.find("#content").css("overflow",this.options.overflow)),this.$buttons=$(this.el).find("#buttons");if(this.options.buttons){var n=this;$.each(this.options.buttons,function(e,t){t.$el.prop("id",e),n.$buttons.append(t.$el)})}else this.$buttons.remove();this.$operations=$(this.el).find("#operations");if(this.options.operations){var n=this;$.each(this.options.operations,function(e,t){t.$el.prop("id",e),n.$operations.append(t.$el)})}this.options.body&&this.append(this.options.body)},append:function(t){this.$content.append(e.wrap(t))},content:function(){return this.$content},show:function(){this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},enableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!1)},disableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!0)},hideOperation:function(e){this.$operations.find("#"+e).hide()},showOperation:function(e){this.$operations.find("#"+e).show()},setOperation:function(e,t){var n=this.$operations.find("#"+e);n.off("click"),n.on("click",t)},title:function(e){var t=this.$title;return e&&t.html(e),t.html()},_template:function(e){var t='<div class="toolForm portlet-view no-highlight">';if(e.title||e.icon)t+='<div id="title" class="toolFormTitle portlet-title"><div id="operations" class="portlet-operations"/><div style="overflow: hidden;">',e.icon&&(t+='<div class="portlet-title-icon fa '+e.icon+'"> </div>'),t+='<div id="title-text" class="portlet-title-text">'+e.title+"</div>",t+="</div></div>";return t+='<div id="body" class="toolFormBody portlet-body">',e.placement=="top"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+='<div id="content" class="portlet-content"/>',e.placement=="bottom"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+="</div></div>",t}});return{View:t}}),define("plugin/library/ui-select",["utils/utils"],function(e){var t=Backbone.View.extend({optionsDefault:{id:"",cls:"",empty:"No data available",visible:!0,wait:!1},selected:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$select=this.$el.find("#select"),this.$icon=this.$el.find("#icon"),this.selected=this.options.value;var n=this;this.options.onchange&&this.$select.on("change",function(){n.value(n.$select.val())}),this._refresh(),this.options.visible||this.hide(),this.options.wait?this.wait():this.show()},value:function(e){var t=this.selected;e!==undefined&&(this.selected=e,this.$select.val(e));var n=this.selected;return n&&n!=t&&this.options.onchange&&this.options.onchange(n),n},text:function(){return this.$select.find("option:selected").text()},show:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-caret-down"),this.$select.show(),this.$el.show()},hide:function(){this.$el.hide()},wait:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-spinner fa-spin"),this.$select.hide()},disabled:function(){return this.$select.is(":disabled")},enable:function(){this.$select.prop("disabled",!1)},disable:function(){this.$select.prop("disabled",!0)},add:function(e){this.$select.append(this._templateOption(e)),this._refresh()},del:function(e){this.$select.find("option[value="+e+"]").remove(),this.$select.trigger("change"),this._refresh()},update:function(e){this.$select.find("option").remove();for(var t in e)this.$select.append(this._templateOption(e[t]));!this.selected&&e.length>0&&this.value(e[0].value),this._refresh()},_refresh:function(){this.$select.find("option[value=null]").remove();var e=this.$select.find("option").length;e==0?(this.$select.append(this._templateOption({value:"null",label:this.options.empty})),this.disable()):(this.enable(),this.selected&&this.$select.val(this.selected))},_exists:function(e){return 0!=this.$select.find("option[value="+e+"]").length},_templateOption:function(e){return'<option value="'+e.value+'">'+e.label+"</option>"},_template:function(e){var t='<div id="'+e.id+'" class="styled-select">'+'<div class="button">'+'<i id="icon"/>'+"</div>"+'<select id="select" class="select '+e.cls+" "+e.id+'">';for(key in e.data){var n=e.data[key],r="";if(n.value==e.value||n.value=="")r="selected";t+='<option value="'+n.value+'" '+r+">"+n.label+"</option>"}return t+="</select></div>",t}});return{View:t}}),define("plugin/library/ui",["utils/utils","plugin/library/ui-select"],function(e,t){var n=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options))},title:function(e){this.$el.find("b").html(e)},_template:function(e){return"<label><b>"+e.title+"</b></label>"},value:function(){return options.title}}),r=Backbone.View.extend({optionsDefault:{id:null,title:"","float":"right",cls:"btn-default",icon:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t='<button id="'+e.id+'" type="submit" style="margin-right: 5px; float: '+e.float+';" type="button" class="btn '+e.cls+'">';return e.icon&&(t+='<i class="icon fa '+e.icon+'"></i> '),t+=e.title+"</button>",t}}),i=Backbone.View.extend({optionsDefault:{"float":"right",icon:"",tooltip:"",placement:"bottom",title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){return'<div><span class="fa '+e.icon+'" style="font-size: 1.2em;"/> '+e.title+"</div>"}}),s=Backbone.View.extend({optionsDefault:{title:"",id:null,"float":"right",cls:"icon-btn",icon:"",tooltip:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t="";e.title&&(t="width: auto;");var n='<div id="'+e.id+'" style="margin-right: 5px; float: '+e.float+"; "+t+'" class="'+e.cls+'">';return e.title?n+='<div style="margin-right: 5px; margin-left: 5px;"><i class="icon fa '+e.icon+'"/> '+'<span style="position: relative; font-size: 0.8em; font-weight: normal; top: -1px;">'+e.title+"</span>"+"</div>":n+='<i class="icon fa '+e.icon+'"/>',n+="</div>",n}}),o=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick)},_template:function(e){return'<div><a href="javascript:void(0)">'+e.title+"</a></div>"}}),u=Backbone.View.extend({optionsDefault:{message:"",status:"info",persistent:!1},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement("<div></div>")},update:function(t){this.options=e.merge(t,this.optionsDefault);if(t.message!=""){this.$el.html(this._template(this.options)),this.$el.fadeIn();if(!t.persistent){var n=this;window.setTimeout(function(){n.$el.is(":visible")?n.$el.fadeOut():n.$el.hide()},3e3)}}else this.$el.fadeOut()},_template:function(e){return'<div class="alert alert-'+e.status+'" style="padding: 2px 2px 2px 10px;">'+e.message+"</div>"}}),a=Backbone.View.extend({optionsDefault:{onclick:null,searchword:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options));var n=this;this.options.onclick&&this.$el.on("submit",function(e){var t=n.$el.find("#search");n.options.onclick(t.val())})},_template:function(e){return'<div class="search"><form onsubmit="return false;"><input id="search" class="form-control input-sm" type="text" name="search" placeholder="Search..." value="'+e.searchword+'">'+'<button type="submit" class="btn search-btn">'+'<i class="fa fa-search"></i>'+"</button>"+"</form>"+"</div>"}}),f=Backbone.View.extend({optionsDefault:{title:"Unlabeled",body:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.body&&this.$el.find(".body").append(this.options.body)},_template:function(e){return'<div id="title" class="title">'+e.title+":"+"</div>"}}),l=Backbone.View.extend({optionsDefault:{id:"",title:"",target:"",href:"",onunload:null,onclick:null,visible:!0,icon:null,tag:""},$menu:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement($(this._template(this.options)));var n=$(this.el).find(".root"),r=this;n.on("click",function(e){e.preventDefault(),r.options.onclick&&r.options.onclick()}),this.options.visible||this.hide()},show:function(){$(this.el).show()},hide:function(){$(this.el).hide()},addMenu:function(t){var n={title:"",target:"",href:"",onclick:null,divider:!1,icon:null};n=e.merge(t,n),this.$menu||($(this.el).append(this._templateMenu()),this.$menu=$(this.el).find(".menu"));var r=$(this._templateMenuItem(n));r.on("click",function(e){e.preventDefault(),n.onclick&&n.onclick()}),this.$menu.append(r),n.divider&&this.$menu.append($(this._templateDivider()))},_templateMenuItem:function(e){var t='<li><a href="'+e.href+'" target="'+e.target+'">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),t+=" "+e.title+"</a>"+"</li>",t},_templateMenu:function(){return'<ul class="menu dropdown-menu pull-right" role="menu"></ul>'},_templateDivider:function(){return'<li class="divider"></li>'},_template:function(e){var t='<div id="'+e.id+'" class="button-menu btn-group">'+'<button type="button" class="root btn btn-default dropdown-toggle" data-toggle="dropdown">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),"</button></div>",t}}),c=Backbone.View.extend({optionsDefault:{value:"",type:"text",placeholder:"",disabled:!1,visible:!0},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.disabled&&this.$el.prop("disabled",!0),this.options.visible||this.$el.hide();var n=this;this.options.onchange&&this.$el.on("input",function(){n.options.onchange()})},value:function(e){return e!==undefined&&this.$el.val(e),this.$el.val()},_template:function(e){return'<input id="'+e.id+'" type="'+e.type+'" value="'+e.value+'" placeholder="'+e.placeholder+'" class="form-control">'}});return{Label:n,Button:r,Icon:i,ButtonIcon:s,Input:c,Anchor:o,Message:u,Searchbox:a,Title:f,Select:t,ButtonMenu:l}}),define("plugin/library/jobs",["utils/utils"],function(e){return Backbone.Model.extend({initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},cleanup:function(t){var n=t.get("dataset_id_job");if(n){var r=this;e.request("PUT",config.root+"api/histories/none/contents/"+n,{deleted:!0},function(){r._refreshHdas()})}},submit:function(t,n,r,i){var s=this,o=t.id,u=t.get("type"),a=this.app.types.get(u);data={tool_id:"rkit",inputs:{input:{id:t.get("dataset_id"),src:"hda"},module:u,columns:r,settings:n}},s.cleanup(t),t.state("submit","Sending job request..."),e.request("POST",config.root+"api/tools",data,function(e){if(!e.outputs||e.outputs.length==0)t.state("failed","Job submission failed. No response.");else{s._refreshHdas();var n=e.outputs[0];t.state("queued","Job has been queued..."),t.set("dataset_id_job",n.id),s._loop(n.id,function(e){switch(e.state){case"ok":return t.state("success","Job completed successfully..."),i(e),!0;case"error":return t.state("failed","Job has failed. Please check the history for details."),!0;case"running":return t.state("running","Job is running..."),!1}})}},function(e){var n="";e&&e.message&&e.message.data&&e.message.data.input&&(n=e.message.data.input+"."),t.state("failed","This visualization requires the R-kit. Please make sure it is installed. "+n)})},_loop:function(t,n){var r=this;e.request("GET",config.root+"api/jobs/"+t,{},function(e){n(e)||setTimeout(function(){r._loop(t,n)},r.app.config.get("query_timeout"))})},_refreshHdas:function(){Galaxy&&Galaxy.currHistoryPanel&&Galaxy.currHistoryPanel.refreshHdas()}})}),define("plugin/library/datasets",["utils/utils"],function(e){return Backbone.Collection.extend({list:{},initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},request:function(t,n,r){var i=this;if(t.groups)this._fetch(t,n);else{var s=this.list[t.id];if(s){n(s);return}e.request("GET",config.root+"api/datasets/"+t.id,{},function(e){switch(e.state){case"error":r&&r(e);break;default:i.list[t.id]=e,n(e)}})}},_fetch:function(t,n){var r=t.start?t.start:0,i=Math.abs(t.end-t.start),s=this.app.config.get("query_limit");if(!i||i>s)i=s;var o="",u={},a=0;for(var f in t.groups){var l=t.groups[f];for(var c in l.columns){var h=l.columns[c];o+=h+",",u[h]=a,a++}}if(a==0){n({});return}o=o.substring(0,o.length-1);var p=t.groups.slice(0);for(var f in p)p[f].values=[];var d=this;e.request("GET",config.root+"api/datasets/"+t.id,{data_type:"raw_data",provider:"dataset-column",limit:i,offset:r,indeces:o},function(e){for(var i in e.data){var s=e.data[i];for(var o in t.groups){var a=t.groups[o],f={x:parseInt(i)+r};for(var l in a.columns){var c=a.columns[l],h=u[c],d=s[h];if(isNaN(d)||!d)d=0;f[l]=d}p[o].values.push(f)}}n(p)})}})}),define("plugin/library/ui-table",["utils/utils"],function(e){var t=Backbone.View.extend({row:null,row_count:0,optionsDefault:{content:"No content available.",onchange:null,ondblclick:null,onconfirm:null},events:{click:"_onclick",dblclick:"_ondblclick"},first:!0,initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(t));this.$thead=n.find("thead"),this.$tbody=n.find("tbody"),this.$tmessage=n.find("tmessage"),this.setElement(n),this.row=$("<tr></tr>")},addHeader:function(e){var t=$("<th></th>");t.append(e),this.row.append(t)},appendHeader:function(){this.$thead.append(this.row),this.row=$("<tr></tr>")},add:function(e,t){var n=$("<td></td>");t&&n.css("width",t),n.append(e),this.row.append(n)},append:function(e){this._commit(e)},prepend:function(e){this._commit(e,!0)},remove:function(e){var t=this.$tbody.find("#"+e);t.length>0&&(t.remove(),this.row_count--,this._refresh())},removeAll:function(){this.$tbody.html(""),this.row_count=0,this._refresh()},value:function(e){this.before=this.$tbody.find(".current").attr("id"),e!==undefined&&(this.$tbody.find("tr").removeClass("current"),e&&this.$tbody.find("#"+e).addClass("current"));var t=this.$tbody.find(".current").attr("id");return t===undefined?null:(t!=this.before&&this.options.onchange&&this.options.onchange(e),t)},size:function(){return this.$tbody.find("tr").length},_commit:function(e,t){this.remove(e),this.row.attr("id",e),t?this.$tbody.prepend(this.row):this.$tbody.append(this.row),this.row=$("<tr></tr>"),this.row_count++,this._refresh()},_onclick:function(e){var t=this.value(),n=$(e.target).closest("tr").attr("id");n&&t!=n&&(this.options.onconfirm?this.options.onconfirm(n):this.value(n))},_ondblclick:function(e){var t=this.value();t&&this.options.ondblclick&&this.options.ondblclick(t)},_refresh:function(){this.row_count==0?this.$tmessage.show():this.$tmessage.hide()},_template:function(e){return'<div><table class="grid"><thead></thead><tbody style="cursor: pointer;"></tbody></table><tmessage>'+e.content+"</tmessage>"+"<div>"}});return{View:t}}),define("plugin/models/group",[],function(){return Backbone.Model.extend({defaults:{key:"Data label",date:""},reset:function(){this.clear({silent:!0}).set(this.defaults),this.trigger("reset",this)}})}),define("plugin/views/viewport",["mvc/ui/ui-portlet","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({list:{},optionsDefault:{height:300},initialize:function(t,r){this.app=t,this.options=n.merge(r,this.optionsDefault),this.portlet=new e.View({title:"title",height:this.options.height,overflow:"hidden"}),this.setElement(this.portlet.$el);var i=this;this.app.charts.on("remove",function(e){i._removeChart(e.id)}),this.app.charts.on("redraw",function(e){i._drawChart(e)})},showChart:function(e){this.show(),this.hideCharts();var t=this.list[e];if(t){var n=this.app.charts.get(e);this.portlet.title(n.get("title")),t.$el.show(),$(window).trigger("resize")}},hideCharts:function(){this.$el.find(".item").hide()},show:function(){$(".tooltip").hide(),this.$el.show()},hide:function(){$(".tooltip").hide(),this.$el.hide()},_drawChart:function(e){var t=this;if(!e.ready()){t.app.log("viewport:_drawChart()","Invalid attempt to draw chart before completion.");return}var n=e.id;this._removeChart(n);var r="#"+n,i=$(this._template({id:r}));this.portlet.append(i);var s=d3.select(i.find("svg")[0]);this.list[n]={svg:s,$el:i},e.off("change:state"),e.on("change:state",function(){var t=i.find("#info"),n=t.find("#icon");n.removeClass(),t.show(),t.find("#text").html(e.get("state_info"));var r=e.get("state");switch(r){case"ok":t.hide();break;case"failed":n.addClass("fa fa-warning");break;default:n.addClass("fa fa-spinner fa-spin")}}),e.state("wait","Please wait...");var o=e.get("type"),u=this.app.types.get(o),t=this;require(["plugin/charts/"+o+"/"+o],function(n){var r=new n(t.app,{svg:s});u.execute?t.app.jobs.submit(e,t._defaultSettingsString(e),t._defaultRequestString(e),function(){r.draw(e,t._defaultRequestDictionary(e))}):r.draw(e,t._defaultRequestDictionary(e))})},_removeChart:function(e){var t=this.list[e];t&&(t.svg.remove(),t.$el.remove())},_template:function(e){return'<div id="'+e.id.substr(1)+'" class="item">'+'<span id="info">'+'<span id="icon" style="font-size: 1.2em; display: inline-block;"/>'+'<span id="text" style="position: relative; margin-left: 5px; top: -1px; font-size: 1.0em;"/>'+"</span>"+'<svg style="height: auto;"/>'+"</div>"},_defaultRequestString:function(e){var t=this.app.types.get(e.get("type")),n="",r=0;return e.groups.each(function(e){for(var i in t.columns)n+=i+"_"+ ++r+":"+(parseInt(e.get(i))+1)+", "}),n.substring(0,n.length-2)},_defaultSettingsString:function(e){var t="";for(key in e.settings.attributes)t+=key+":"+e.settings.get(key)+", ";return t.substring(0,t.length-2)},_defaultRequestDictionary:function(e){var t=this.app.types.get(e.get("type")),n={id:e.get("dataset_id"),groups:[]},r=0;return e.groups.each(function(e){var i={};for(var s in t.columns)i[s]=e.get(s);n.groups.push({key:++r+":"+e.get("key"),columns:i})}),n}})}),define("plugin/views/charts",["mvc/ui/ui-portlet","plugin/library/ui-table","plugin/library/ui","utils/utils","plugin/models/group","plugin/views/viewport"],function(e,t,n,r,i,s){return Backbone.View.extend({initialize:function(i,o){this.app=i,this.viewport_view=new s(i),this.table=new t.View({content:"Add charts to this table.",ondblclick:function(e){u._showChartView(e)},onchange:function(e){var t=u.app.charts.get(e);u.app.config.set("title",t.get("title")),u.viewport_view.showChart(e)}});var u=this;this.portlet=new e.View({icon:"fa-list",title:"List of created charts:",height:100,operations:{"new":new n.ButtonIcon({icon:"fa-magic",tooltip:"Create a new Chart",title:"New",onclick:function(){u.app.go("chart_view"),u.app.chart.reset()}}),edit:new n.ButtonIcon({icon:"fa-gear",tooltip:"Customize this Chart",title:"Customize",onclick:function(){var e=u.table.value();if(!e)return;u._showChartView(e)}}),"delete":new n.ButtonIcon({icon:"fa-trash-o",tooltip:"Delete this Chart",title:"Delete",onclick:function(){var e=u.table.value();if(!e)return;var t=u.app.charts.get(e);u._wait(t,function(){u.app.modal.show({title:"Are you sure?",body:'The selected chart "'+t.get("title")+'" will be irreversibly deleted.',buttons:{Cancel:function(){u.app.modal.hide()},Delete:function(){u.app.modal.hide(),u.app.charts.remove(e),u.app.jobs.cleanup(t)}}})})}})}}),this.portlet.append(this.table.$el),this.app.options.config.widget||this.$el.append(this.portlet.$el),this.$el.append(r.wrap("")),this.$el.append(this.viewport_view.$el);var u=this;this.app.charts.on("add",function(e){u._addChart(e)}),this.app.charts.on("remove",function(e){u._removeChart(e)}),this.app.charts.on("change",function(e){u._changeChart(e)})},show:function(){this.$el.show()},hide:function(){$(".tooltip").hide(),this.$el.hide()},_addChart:function(e){var t=e.get("title");t==""&&(t="Untitled"),this.table.add(t);var n=this.app.types.get(e.get("type"));this.table.add(n.title),this.table.add("Last change: "+e.get("date")),this.table.prepend(e.get("id")),this.table.value(e.get("id"))},_removeChart:function(e){this.table.remove(e.id),this.app.charts.save(),this.table.size()==0?(this.app.go("chart_view"),this.app.chart.reset()):this.table.value(this.app.charts.last().id)},_changeChart:function(e){e.get("type")&&(this._addChart(e),this.table.value(e.id))},_showChartView:function(e){var t=this,n=this.app.charts.get(e);this._wait(n,function(){t.app.go("chart_view"),t.app.chart.copy(n)})},_wait:function(e,t){if(e.ready())t();else{var n=this;this.app.modal.show({title:"Please wait!",body:'The selected chart "'+e.get("title")+'" is currently being processed. Please wait...',buttons:{Close:function(){n.app.modal.hide()},Retry:function(){n.app.modal.hide(),setTimeout(function(){n._wait(e,t)},n.app.config.get("query_timeout"))}}})}}})}),define("mvc/ui/ui-tabs",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,list:{},$nav:null,$content:null,first_tab:null,optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(this.options));this.$nav=n.find(".tab-navigation"),this.$content=n.find(".tab-content"),this.setElement(n),this.list={};var r=this;this.options.operations&&$.each(this.options.operations,function(e,t){t.$el.prop("id",e),r.$nav.find(".operations").append(t.$el)});if(this.options.onnew){var i=$(this._template_tab_new(this.options));this.$nav.append(i),i.tooltip({title:"Add a new tab",placement:"bottom",container:r.$el}),i.on("click",function(e){i.tooltip("hide"),r.options.onnew()})}},add:function(e){var t=e.id,n={$title:$(this._template_tab(e)),$content:$(this._template_tab_content(e)),removable:e.ondel?!0:!1};this.list[t]=n,this.options.onnew?this.$nav.find("#new-tab").before(n.$title):this.$nav.append(n.$title),n.$content.append(e.$el),this.$content.append(n.$content),_.size(this.list)==1&&(n.$title.addClass("active"),n.$content.addClass("active"),this.first_tab=t);if(e.ondel){var r=this,i=n.$title.find("#delete");i.tooltip({title:"Delete this tab",placement:"bottom",container:r.$el}),i.on("click",function(){return i.tooltip("destroy"),r.$el.find(".tooltip").remove(),e.ondel(),!1})}e.onclick&&n.$title.on("click",function(){e.onclick()})},del:function(e){var t=this.list[e];t.$title.remove(),t.$content.remove(),delete t,this.first_tab==e&&(this.first_tab=null),this.first_tab!=null&&this.show(this.first_tab)},delRemovable:function(){for(var e in this.list){var t=this.list[e];t.removable&&this.del(e)}},show:function(e){this.$el.fadeIn("fast"),this.visible=!0,e&&this.list[e].$title.find("a").tab("show")},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},hideOperation:function(e){this.$nav.find("#"+e).hide()},showOperation:function(e){this.$nav.find("#"+e).show()},setOperation:function(e,t){var n=this.$nav.find("#"+e);n.off("click"),n.on("click",t)},title:function(e,t){var n=this.list[e].$title.find("#text");return t&&n.html(t),n.html()},_template:function(e){return'<div class="tabbable tabs-left"><ul class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div class="tab-content"/></div>'},_template_tab_new:function(e){return'<li id="new-tab"><a href="javascript:void(0);"><i style="font-size: 0.8em; margin-right: 5px;" class="fa fa-plus-circle"/>'+e.title_new+"</a>"+"</li>"},_template_tab:function(e){var t='<li id="title-'+e.id+'">'+'<a title="" href="#tab-'+e.id+'" data-toggle="tab" data-original-title="">'+'<span id="text">'+e.title+"</span>";return e.ondel&&(t+='<i id="delete" style="font-size: 0.8em; margin-left: 5px; cursor: pointer;" class="fa fa-minus-circle"/>'),t+="</a></li>",t},_template_tab_content:function(e){return'<div id="tab-'+e.id+'" class="tab-pane"/>'}});return{View:t}}),define("plugin/models/groups",["plugin/models/group"],function(e){return Backbone.Collection.extend({model:e})});var Visualization=Backbone.Model.extend({defaults:{config:{}},urlRoot:function(){var e="/api/visualizations";return window.galaxy_config&&galaxy_config.root?galaxy_config.root+e:e},initialize:function(e){_.isObject(e.config)&&_.isObject(this.defaults.config)&&_.defaults(e.config,this.defaults.config),this._setUpListeners()},_setUpListeners:function(){},set:function(e,t){if(e==="config"){var n=this.get("config");_.isObject(n)&&(t=_.extend(_.clone(n),t))}return Backbone.Model.prototype.set.call(this,e,t),this},toString:function(){var e=this.get("id")||"";return this.get("title")&&(e+=":"+this.get("title")),"Visualization("+e+")"}}),VisualizationCollection=Backbone.Collection.extend({model:Visualization,url:function(){return galaxy_config.root+"api/visualizations"},initialize:function(e,t){t=t||{}},set:function(e,t){var n=this;e=_.map(e,function(e){var t=n.get(e.id);if(!t)return e;var r=t.toJSON();return _.extend(r,e),r}),Backbone.Collection.prototype.set.call(this,e,t)},toString:function(){return["VisualizationCollection(",[this.historyId,this.length].join(),")"].join("")}});define("mvc/visualization/visualization-model",function(){}),define("plugin/models/chart",["plugin/models/groups","mvc/visualization/visualization-model"],function(e){return Backbone.Model.extend({defaults:{id:null,title:"",type:"",date:null,state:"ok",state_info:""},initialize:function(t){this.groups=new e,this.settings=new Backbone.Model},reset:function(){this.clear({silent:!0}).set(this.defaults),this.groups.reset(),this.settings.clear(),this.trigger("reset",this)},copy:function(e){var t=this;t.clear({silent:!0}).set(this.defaults),t.set(e.attributes),t.settings=e.settings.clone(),t.groups.reset(),e.groups.each(function(e){t.groups.add(e.clone())}),t.trigger("change",t)},state:function(e,t){this.set("state_info",t),this.set("state",e)},ready:function(){return this.get("state")=="ok"||this.get("state")=="failed"}})}),define("plugin/views/group",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({columns:[],initialize:function(r,i){this.app=r;var s=this;this.chart=this.app.chart,this.group=i.group,this.group_key=new t.Input({placeholder:"Data label",onchange:function(){s.group.set("key",s.group_key.value())}}),this.table=new e.View({content:"No data column."});var o=$("<div/>");o.append(n.wrap((new t.Label({title:"Provide a label:"})).$el)),o.append(n.wrap(this.group_key.$el)),o.append(n.wrap((new t.Label({title:"Select columns:"})).$el)),o.append(n.wrap(this.table.$el)),this.setElement(o);var s=this;this.chart.on("change:dataset_id",function(){s._refreshTable()}),this.chart.on("change:type",function(){s._refreshTable()}),this.group.on("change:key",function(){s._refreshGroupKey()}),this.group.on("change",function(){s._refreshGroup()}),this._refreshTable(),this._refreshGroupKey(),this._refreshGroup()},_refreshTable:function(){var e=this.chart.get("dataset_id"),n=this.chart.get("type");if(!e||!n)return;var r=this,i=this.app.types.get(n);this.table.removeAll();var s={};for(var o in i.columns){var u=this.group.get(o);u||this.group.set(o,0);var a=i.columns[o],f=new t.Select.View({id:"select_"+o,gid:o,onchange:function(e){r.group.set(this.gid,e)},value:u,wait:!0});this.table.add(a.title,"25%"),this.table.add(f.$el),this.table.append(o),s[o]=f}this.app.datasets.request({id:e},function(e){r.columns=[];var t=e.metadata_column_types;for(var n in t)(t[n]=="int"||t[n]=="float")&&r.columns.push({label:"Column: "+(parseInt(n)+1)+" ["+t[n]+"]",value:n});for(var n in s)s[n].update(r.columns),s[n].show()})},_refreshGroup:function(){this.group.set("date",n.time())},_refreshGroupKey:function(){var e=this.group.get("key");e===undefined&&(e=""),this.group_key.value(e)}})}),define("plugin/library/ui-table-form",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){var r=Backbone.View.extend({initialize:function(r){this.table_title=new t.Label({title:r.title}),this.table=new e.View({content:r.content});var i=$("<div/>");i.append(n.wrap(this.table_title.$el)),i.append(n.wrap(this.table.$el)),this.setElement(i)},title:function(e){this.table_title.title(e)},update:function(e,t){this.table.removeAll();for(var n in e)this._add(n,e[n],t)},_add:function(e,n,r){var i=null,s=n.type;switch(s){case"text":i=new t.Input({placeholder:n.placeholder,onchange:function(){r.set(e,i.value())}});break;case"select":i=new t.Select.View({data:n.data,onchange:function(){r.set(e,i.value())}});break;case"slider":i=new t.Input({placeholder:n.placeholder,onchange:function(){r.set(e,i.value())}});break;case"separator":i=$("<div/>");break;default:console.log("ui-table-form:_add","Unknown setting type ("+n.type+")");return}if(s!="separator"){r.get(e)||r.set(e,n.init),i.value(r.get(e));var o=$("<div/>");o.append(i.$el),o.append('<div class="toolParamHelp" style="font-size: 0.9em;">'+n.info+"</div>"),this.table.add('<span style="white-space: nowrap;">'+n.title+"</span>","25%"),this.table.add(o)}else this.table.add('<h6 style="white-space: nowrap;">'+n.title+":<h6/>"),this.table.add($("<div/>"));this.table.append(e)}});return{View:r}}),define("plugin/views/settings",["plugin/library/ui","plugin/library/ui-table-form","utils/utils"],function(e,t,n){return Backbone.View.extend({initialize:function(e,n){this.app=e;var r=this;this.chart=this.app.chart,this.form=new t.View({title:"Chart options:",content:"This chart type does not provide any options."}),this.setElement(this.form.$el);var r=this;this.chart.on("change",function(){r._refreshTable()})},_refreshTable:function(){var e=this.chart.get("type");if(!e)return;var t=this.app.types.get(e);this.form.title(t.title+":"),this.form.update(t.settings,this.chart.settings)}})}),define("plugin/views/chart",["mvc/ui/ui-tabs","plugin/library/ui-table","plugin/library/ui","utils/utils","plugin/models/chart","plugin/models/group","plugin/views/group","plugin/views/settings"],function(e,t,n,r,i,s,o,u){return Backbone.View.extend({optionsDefault:{header:!0,content:"No content available."},initialize:function(i,s){this.app=i,this.chart=this.app.chart,this.options=r.merge(s,this.optionsDefault);var o=this;this.table=new t.View({header:!1,onconfirm:function(e){o.chart.groups.length>0?o.app.modal.show({title:"Switching to another chart type?",body:"If you continue your settings and selections will be cleared.",buttons:{Cancel:function(){o.app.modal.hide()},Continue:function(){o.app.modal.hide(),o.table.value(e)}}}):o.table.value(e)},onchange:function(e){o.chart.groups.reset(),o.chart.settings.clear(),o.chart.set({type:e})},ondblclick:function(e){o.tabs.show("settings")},content:"No chart types available"});var a=0,f=i.types.attributes;for(var l in f){var c=f[l];this.table.add(++a+"."),c.execute?this.table.add(c.title+" (requires processing)"):this.table.add(c.title),this.table.append(l)}this.tabs=new e.View({title_new:"Add Data",onnew:function(){var e=o._addGroupModel();o.tabs.show(e.id)},operations:{save:new n.ButtonIcon({icon:"fa-save",tooltip:"Draw Chart",title:"Draw",onclick:function(){o.app.go("charts_view"),o._saveChart()}}),back:new n.ButtonIcon({icon:"fa-caret-left",tooltip:"Return to Viewer",title:"Return",onclick:function(){o.app.go("charts_view")}})}}),this.title=new n.Input({placeholder:"Chart title",onchange:function(){o.app.config.set("title",o.title.value())}});var h=$("<div/>");h.append(r.wrap((new n.Label({title:"Provide a chart title:"})).$el)),h.append(r.wrap(this.title.$el)),h.append(r.wrap((new n.Label({title:"Select a chart type:"})).$el)),h.append(r.wrap(this.table.$el)),this.tabs.add({id:"main",title:"Start",$el:h}),this.settings=new u(this.app),this.tabs.add({id:"settings",title:"Configuration",$el:this.settings.$el}),this.setElement(this.tabs.$el),this.tabs.hideOperation("back");var o=this;this.chart.on("change:title",function(e){o.title.value(e.get("title")),o.app.config.set("title",e.get("title"))}),this.chart.on("change:type",function(e){o.table.value(e.get("type"))}),this.chart.on("reset",function(e){o._resetChart()}),this.app.charts.on("add",function(e){o.tabs.showOperation("back")}),this.app.charts.on("remove",function(e){o.app.charts.length==0&&o.tabs.hideOperation("back")}),this.app.charts.on("reset",function(e){o.tabs.hideOperation("back")}),this.app.chart.groups.on("add",function(e){o._addGroup(e)}),this.app.chart.groups.on("remove",function(e){o._removeGroup(e)}),this.app.chart.groups.on("reset",function(e){o._removeAllGroups()}),this.app.chart.groups.on("change:key",function(e){o._refreshGroupKey()}),this._resetChart()},show:function(){this.$el.show()},hide:function(){$(".tooltip").hide(),this.$el.hide()},_refreshGroupKey:function(){var e=this,t=0;this.chart.groups.each(function(n){var r=n.get("key","");r==""&&(r="Chart data"),e.tabs.title(n.id,++t+": "+r)})},_addGroupModel:function(){var e=new s({id:r.uuid()});return this.chart.groups.add(e),e},_addGroup:function(e){var t=this,n=new o(this.app,{group:e}),r=t.chart.groups.length;this.tabs.add({id:e.id,$el:n.$el,ondel:function(){t.chart.groups.remove(e.id)}}),this._refreshGroupKey()},_removeGroup:function(e){this.tabs.del(e.id),this._refreshGroupKey()},_removeAllGroups:function(e){this.tabs.delRemovable()},_resetChart:function(){this.chart.set("id",r.uuid()),this.chart.set("type","bardiagram"),this.chart.set("dataset_id",this.app.options.config.dataset_id),this.chart.set("title","New Chart")},_saveChart:function(){this.chart.set({type:this.table.value(),title:this.title.value(),date:r.time()}),this.chart.groups.length==0&&this._addGroupModel();var e=this.app.charts.get(this.chart.id);e?e.copy(this.chart):(e=this.chart.clone(),e.copy(this.chart),this.app.charts.add(e)),e.trigger("redraw",e),this.app.charts.save()}})}),define("plugin/models/config",[],function(){return Backbone.Model.extend({defaults:{query_limit:1e3,query_timeout:500,title:"Create a new chart"}})}),define("plugin/models/charts",["plugin/models/chart","plugin/models/group"],function(e,t){return Backbone.Collection.extend({model:e,vis:null,initialize:function(e,t){this.app=t,this.id=this.app.options.id,this.vis=new Visualization({type:"charts",config:{dataset_id:this.app.options.config.dataset_id,charts:[]}}),this.id&&(this.vis.id=this.id);var n=this.app.options.config.charts;n&&(this.vis.get("config").charts=n)},save:function(){this.vis.get("config").charts=[];var e=this;this.each(function(t){var n={attributes:t.attributes,settings:t.settings.attributes,groups:[]};t.groups.each(function(e){n.groups.push(e.attributes)}),e.vis.get("config").charts.push(n)});var e=this;this.vis.save().fail(function(e,t,n){console.error(e,t,n),alert("Error loading data:\n"+e.responseText)}).then(function(t){t&&t.id&&(e.id=t.id)})},load:function(){var n=this.vis.get("config").charts;for(var r in n){var i=n[r],s=new e;s.set(i.attributes),s.settings.set(i.settings);for(var o in i.groups)s.groups.add(new t(i.groups[o]));s.state("ok","Loaded previously saved visualization."),this.add(s),s.trigger("redraw",s)}}})}),define("plugin/charts/_nvd3/config",[],function(){return{title:"",columns:{y:{title:"Values for y-axis"}},settings:{separator_label:{title:"X axis",type:"separator"},x_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"X-axis",placeholder:"Axis label"},x_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"f",data:[{label:"-- Do not show values --",value:"hide"},{label:"Float",value:"f"},{label:"Exponent",value:"e"},{label:"Integer",value:"d"},{label:"Percentage",value:"p"},{label:"Rounded",value:"r"},{label:"SI-prefix",value:"s"}]},x_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_tick:{title:"Y axis",type:"separator"},y_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"Y-axis",placeholder:"Axis label"},y_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"f",data:[{label:"-- Do not show values --",value:"hide"},{label:"Float",value:"f"},{label:"Exponent",value:"e"},{label:"Integer",value:"d"},{label:"Percentage",value:"p"},{label:"Rounded",value:"r"},{label:"SI-prefix",value:"s"}]},y_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_legend:{title:"Others",type:"separator"},show_legend:{title:"Show legend",info:"Would you like to add a legend?",type:"select",init:"true",data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]}}}}),define("plugin/charts/bardiagram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram"})}),define("plugin/charts/histogram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Histogram",execute:!0,columns:{y:{title:"Observations"}},settings:{x_axis_label:{init:"Breaks"},y_axis_label:{init:"Density"},y_axis_tick:{init:".3"}}})}),define("plugin/charts/horizontal/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram (horizontal)",settings:{x_axis_type:{init:"hide"}}})}),define("plugin/charts/line/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line chart"})}),define("plugin/charts/linewithfocus/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line with focus"})}),define("plugin/charts/piechart/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Pie chart"})}),define("plugin/charts/scatterplot/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Scatter plot",columns:{x:{title:"Values for x-axis"}}})}),define("plugin/charts/stackedarea/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Stacked area"})}),define("plugin/charts/types",["plugin/charts/bardiagram/config","plugin/charts/histogram/config","plugin/charts/horizontal/config","plugin/charts/line/config","plugin/charts/linewithfocus/config","plugin/charts/piechart/config","plugin/charts/scatterplot/config","plugin/charts/stackedarea/config"],function(e,t,n,r,i,s,o,u){return Backbone.Model.extend({defaults:{bardiagram:e,horizontal:n,histogram:t,line:r,linewithfocus:i,piechart:s,scatterplot:o,stackedarea:u}})}),define("plugin/app",["mvc/ui/ui-modal","mvc/ui/ui-portlet","plugin/library/ui","utils/utils","plugin/library/jobs","plugin/library/datasets","plugin/views/charts","plugin/views/chart","plugin/models/config","plugin/models/chart","plugin/models/charts","plugin/charts/types"],function(e,t,n,r,i,s,o,u,a,f,l,c){return Backbone.View.extend({initialize:function(n){this.options=n,Galaxy&&Galaxy.modal?this.modal=Galaxy.modal:this.modal=new e.View,this.config=new a,this.jobs=new i(this),this.types=new c,this.chart=new f,this.charts=new l(null,this),this.datasets=new s(this),this.charts_view=new o(this),this.chart_view=new u(this),this.options.config.widget?this.portlet=$("<div></div>"):this.portlet=new t.View({icon:"fa-bar-chart-o"}),this.portlet.append(this.charts_view.$el),this.portlet.append(this.chart_view.$el),this.options.config.widget?this.setElement(this.portlet):this.setElement(this.portlet.$el);var r=this;this.config.on("change:title",function(){r._refreshTitle()}),this.render(),this.charts.load(),this.charts.length==0?this.go("chart_view"):this.go("charts_view")},go:function(e){switch(e){case"chart_view":this.chart_view.show(),this.charts_view.hide();break;case"charts_view":this.chart_view.hide(),this.charts_view.show()}},render:function(){this._refreshTitle()},_refreshTitle:function(){var e=this.config.get("title");e&&(e=" - "+e),this.portlet.title("Charts"+e)},execute:function(e){},onunload:function(){},log:function(e,t){console.log(e+" "+t)}})});
\ No newline at end of file
+(function(){var e=this,t=e._,n={},r=Array.prototype,i=Object.prototype,s=Function.prototype,o=r.push,u=r.slice,a=r.concat,f=i.toString,l=i.hasOwnProperty,c=r.forEach,h=r.map,p=r.reduce,d=r.reduceRight,v=r.filter,m=r.every,g=r.some,y=r.indexOf,b=r.lastIndexOf,w=Array.isArray,E=Object.keys,S=s.bind,x=function(e){if(e instanceof x)return e;if(!(this instanceof x))return new x(e);this._wrapped=e};typeof exports!="undefined"?(typeof module!="undefined"&&module.exports&&(exports=module.exports=x),exports._=x):e._=x,x.VERSION="1.4.4";var T=x.each=x.forEach=function(e,t,r){if(e==null)return;if(c&&e.forEach===c)e.forEach(t,r);else if(e.length===+e.length){for(var i=0,s=e.length;i<s;i++)if(t.call(r,e[i],i,e)===n)return}else for(var o in e)if(x.has(e,o)&&t.call(r,e[o],o,e)===n)return};x.map=x.collect=function(e,t,n){var r=[];return e==null?r:h&&e.map===h?e.map(t,n):(T(e,function(e,i,s){r.push(t.call(n,e,i,s))}),r)};var N="Reduce of empty array with no initial value";x.reduce=x.foldl=x.inject=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(p&&e.reduce===p)return r&&(t=x.bind(t,r)),i?e.reduce(t,n):e.reduce(t);T(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError(N);return n},x.reduceRight=x.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(d&&e.reduceRight===d)return r&&(t=x.bind(t,r)),i?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=x.keys(e);s=o.length}T(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError(N);return n},x.find=x.detect=function(e,t,n){var r;return C(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},x.filter=x.select=function(e,t,n){var r=[];return e==null?r:v&&e.filter===v?e.filter(t,n):(T(e,function(e,i,s){t.call(n,e,i,s)&&r.push(e)}),r)},x.reject=function(e,t,n){return x.filter(e,function(e,r,i){return!t.call(n,e,r,i)},n)},x.every=x.all=function(e,t,r){t||(t=x.identity);var i=!0;return e==null?i:m&&e.every===m?e.every(t,r):(T(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var C=x.some=x.any=function(e,t,r){t||(t=x.identity);var i=!1;return e==null?i:g&&e.some===g?e.some(t,r):(T(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};x.contains=x.include=function(e,t){return e==null?!1:y&&e.indexOf===y?e.indexOf(t)!=-1:C(e,function(e){return e===t})},x.invoke=function(e,t){var n=u.call(arguments,2),r=x.isFunction(t);return x.map(e,function(e){return(r?t:e[t]).apply(e,n)})},x.pluck=function(e,t){return x.map(e,function(e){return e[t]})},x.where=function(e,t,n){return x.isEmpty(t)?n?void 0:[]:x[n?"find":"filter"](e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},x.findWhere=function(e,t){return x.where(e,t,!0)},x.max=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&x.isEmpty(e))return-Infinity;var r={computed:-Infinity,value:-Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},x.min=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&x.isEmpty(e))return Infinity;var r={computed:Infinity,value:Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o<r.computed&&(r={value:e,computed:o})}),r.value},x.shuffle=function(e){var t,n=0,r=[];return T(e,function(e){t=x.random(n++),r[n-1]=r[t],r[t]=e}),r};var k=function(e){return x.isFunction(e)?e:function(t){return t[e]}};x.sortBy=function(e,t,n){var r=k(t);return x.pluck(x.map(e,function(e,t,i){return{value:e,index:t,criteria:r.call(n,e,t,i)}}).sort(function(e,t){var n=e.criteria,r=t.criteria;if(n!==r){if(n>r||n===void 0)return 1;if(n<r||r===void 0)return-1}return e.index<t.index?-1:1}),"value")};var L=function(e,t,n,r){var i={},s=k(t==null?x.identity:t);return T(e,function(t,o){var u=s.call(n,t,o,e);r(i,u,t)}),i};x.groupBy=function(e,t,n){return L(e,t,n,function(e,t,n){(x.has(e,t)?e[t]:e[t]=[]).push(n)})},x.countBy=function(e,t,n){return L(e,t,n,function(e,t){x.has(e,t)||(e[t]=0),e[t]++})},x.sortedIndex=function(e,t,n,r){n=n==null?x.identity:k(n);var i=n.call(r,t),s=0,o=e.length;while(s<o){var u=s+o>>>1;n.call(r,e[u])<i?s=u+1:o=u}return s},x.toArray=function(e){return e?x.isArray(e)?u.call(e):e.length===+e.length?x.map(e,x.identity):x.values(e):[]},x.size=function(e){return e==null?0:e.length===+e.length?e.length:x.keys(e).length},x.first=x.head=x.take=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,0,t):e[0]},x.initial=function(e,t,n){return u.call(e,0,e.length-(t==null||n?1:t))},x.last=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,Math.max(e.length-t,0)):e[e.length-1]},x.rest=x.tail=x.drop=function(e,t,n){return u.call(e,t==null||n?1:t)},x.compact=function(e){return x.filter(e,x.identity)};var A=function(e,t,n){return T(e,function(e){x.isArray(e)?t?o.apply(n,e):A(e,t,n):n.push(e)}),n};x.flatten=function(e,t){return A(e,t,[])},x.without=function(e){return x.difference(e,u.call(arguments,1))},x.uniq=x.unique=function(e,t,n,r){x.isFunction(t)&&(r=n,n=t,t=!1);var i=n?x.map(e,n,r):e,s=[],o=[];return T(i,function(n,r){if(t?!r||o[o.length-1]!==n:!x.contains(o,n))o.push(n),s.push(e[r])}),s},x.union=function(){return x.uniq(a.apply(r,arguments))},x.intersection=function(e){var t=u.call(arguments,1);return x.filter(x.uniq(e),function(e){return x.every(t,function(t){return x.indexOf(t,e)>=0})})},x.difference=function(e){var t=a.apply(r,u.call(arguments,1));return x.filter(e,function(e){return!x.contains(t,e)})},x.zip=function(){var e=u.call(arguments),t=x.max(x.pluck(e,"length")),n=new Array(t);for(var r=0;r<t;r++)n[r]=x.pluck(e,""+r);return n},x.unzip=function(e){var t=[];return x.each(e,function(e,n){x.each(e,function(e,r){t.length<=r&&(t[r]=[]),t[r][n]=e})}),t},x.object=function(e,t){if(e==null)return{};var n={};for(var r=0,i=e.length;r<i;r++)t?n[e[r]]=t[r]:n[e[r][0]]=e[r][1];return n},x.indexOf=function(e,t,n){if(e==null)return-1;var r=0,i=e.length;if(n){if(typeof n!="number")return r=x.sortedIndex(e,t),e[r]===t?r:-1;r=n<0?Math.max(0,i+n):n}if(y&&e.indexOf===y)return e.indexOf(t,n);for(;r<i;r++)if(e[r]===t)return r;return-1},x.lastIndexOf=function(e,t,n){if(e==null)return-1;var r=n!=null;if(b&&e.lastIndexOf===b)return r?e.lastIndexOf(t,n):e.lastIndexOf(t);var i=r?n:e.length;while(i--)if(e[i]===t)return i;return-1},x.range=function(e,t,n){arguments.length<=1&&(t=e||0,e=0),n=arguments[2]||1;var r=Math.max(Math.ceil((t-e)/n),0),i=0,s=new Array(r);while(i<r)s[i++]=e,e+=n;return s};var O=function(){};x.bind=function(e,t){var n,r;if(e.bind===S&&S)return S.apply(e,u.call(arguments,1));if(!x.isFunction(e))throw new TypeError;return n=u.call(arguments,2),r=function(){if(this instanceof r){O.prototype=e.prototype;var i=new O;O.prototype=null;var s=e.apply(i,n.concat(u.call(arguments)));return Object(s)===s?s:i}return e.apply(t,n.concat(u.call(arguments)))}},x.partial=function(e){var t=u.call(arguments,1);return function(){return e.apply(this,t.concat(u.call(arguments)))}},x.bindAll=function(e){var t=u.call(arguments,1);if(t.length===0)throw new Error("bindAll must be passed function names");return T(t,function(t){e[t]=x.bind(e[t],e)}),e},x.memoize=function(e,t){var n={};return t||(t=x.identity),function(){var r=t.apply(this,arguments);return x.has(n,r)?n[r]:n[r]=e.apply(this,arguments)}},x.delay=function(e,t){var n=u.call(arguments,2);return setTimeout(function(){return e.apply(null,n)},t)},x.defer=function(e){return x.delay.apply(x,[e,1].concat(u.call(arguments,1)))},x.throttle=function(e,t,n){var r,i,s,o,u=0,a=function(){u=new Date,s=null,o=e.apply(r,i)};return function(){var f=new Date;!u&&n===!1&&(u=f);var l=t-(f-u);return r=this,i=arguments,l<=0?(clearTimeout(s),s=null,u=f,o=e.apply(r,i)):s||(s=setTimeout(a,l)),o}},x.debounce=function(e,t,n){var r,i;return function(){var s=this,o=arguments,u=function(){r=null,n||(i=e.apply(s,o))},a=n&&!r;return clearTimeout(r),r=setTimeout(u,t),a&&(i=e.apply(s,o)),i}},x.once=function(e){var t=!1,n;return function(){return t?n:(t=!0,n=e.apply(this,arguments),e=null,n)}},x.wrap=function(e,t){return function(){var n=[e];return o.apply(n,arguments),t.apply(this,n)}},x.compose=function(){var e=arguments;return function(){var t=arguments;for(var n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},x.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},x.keys=E||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)x.has(e,n)&&t.push(n);return t},x.values=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push(e[n]);return t},x.pairs=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push([n,e[n]]);return t},x.invert=function(e){var t={};for(var n in e)x.has(e,n)&&(t[e[n]]=n);return t},x.functions=x.methods=function(e){var t=[];for(var n in e)x.isFunction(e[n])&&t.push(n);return t.sort()},x.extend=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]=t[n]}),e},x.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return T(n,function(n){n in e&&(t[n]=e[n])}),t},x.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)x.contains(n,i)||(t[i]=e[i]);return t},x.defaults=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]===void 0&&(e[n]=t[n])}),e},x.clone=function(e){return x.isObject(e)?x.isArray(e)?e.slice():x.extend({},e):e},x.tap=function(e,t){return t(e),e};var M=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof x&&(e=e._wrapped),t instanceof x&&(t=t._wrapped);var i=f.call(e);if(i!=f.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=M(e[o],t[o],n,r)))break}else{var a=e.constructor,l=t.constructor;if(a!==l&&!(x.isFunction(a)&&a instanceof a&&x.isFunction(l)&&l instanceof l))return!1;for(var c in e)if(x.has(e,c)){o++;if(!(u=x.has(t,c)&&M(e[c],t[c],n,r)))break}if(u){for(c in t)if(x.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};x.isEqual=function(e,t){return M(e,t,[],[])},x.isEmpty=function(e){if(e==null)return!0;if(x.isArray(e)||x.isString(e))return e.length===0;for(var t in e)if(x.has(e,t))return!1;return!0},x.isElement=function(e){return!!e&&e.nodeType===1},x.isArray=w||function(e){return f.call(e)=="[object Array]"},x.isObject=function(e){return e===Object(e)},T(["Arguments","Function","String","Number","Date","RegExp"],function(e){x["is"+e]=function(t){return f.call(t)=="[object "+e+"]"}}),x.isArguments(arguments)||(x.isArguments=function(e){return!!e&&!!x.has(e,"callee")}),typeof /./!="function"&&(x.isFunction=function(e){return typeof e=="function"}),x.isFinite=function(e){return isFinite(e)&&!isNaN(parseFloat(e))},x.isNaN=function(e){return x.isNumber(e)&&e!=+e},x.isBoolean=function(e){return e===!0||e===!1||f.call(e)=="[object Boolean]"},x.isNull=function(e){return e===null},x.isUndefined=function(e){return e===void 0},x.has=function(e,t){return l.call(e,t)},x.noConflict=function(){return e._=t,this},x.identity=function(e){return e},x.times=function(e,t,n){var r=Array(e);for(var i=0;i<e;i++)r[i]=t.call(n,i);return r},x.random=function(e,t){return t==null&&(t=e,e=0),e+Math.floor(Math.random()*(t-e+1))};var _={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};_.unescape=x.invert(_.escape);var D={escape:new RegExp("["+x.keys(_.escape).join("")+"]","g"),unescape:new RegExp("("+x.keys(_.unescape).join("|")+")","g")};x.each(["escape","unescape"],function(e){x[e]=function(t){return t==null?"":(""+t).replace(D[e],function(t){return _[e][t]})}}),x.result=function(e,t){if(e==null)return void 0;var n=e[t];return x.isFunction(n)?n.call(e):n},x.mixin=function(e){T(x.functions(e),function(t){var n=x[t]=e[t];x.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),F.call(this,n.apply(x,e))}})};var P=0;x.uniqueId=function(e){var t=++P+"";return e?e+t:t},x.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var H=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},j=/\\|'|\r|\n|\t|\u2028|\u2029/g;x.template=function(e,t,n){var r;n=x.defaults({},n,x.templateSettings);var i=new RegExp([(n.escape||H).source,(n.interpolate||H).source,(n.evaluate||H).source].join("|")+"|$","g"),s=0,o="__p+='";e.replace(i,function(t,n,r,i,u){return o+=e.slice(s,u).replace(j,function(e){return"\\"+B[e]}),n&&(o+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'"),r&&(o+="'+\n((__t=("+r+"))==null?'':__t)+\n'"),i&&(o+="';\n"+i+"\n__p+='"),s=u+t.length,t}),o+="';\n",n.variable||(o="with(obj||{}){\n"+o+"}\n"),o="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+o+"return __p;\n";try{r=new Function(n.variable||"obj","_",o)}catch(u){throw u.source=o,u}if(t)return r(t,x);var a=function(e){return r.call(this,e,x)};return a.source="function("+(n.variable||"obj")+"){\n"+o+"}",a},x.chain=function(e){return x(e).chain()};var F=function(e){return this._chain?x(e).chain():e};x.mixin(x),T(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];x.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],F.call(this,n)}}),T(["concat","join","slice"],function(e){var t=r[e];x.prototype[e]=function(){return F.call(this,t.apply(this._wrapped,arguments))}}),x.extend(x.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this),define("libs/underscore",function(e){return function(){var t,n;return t||e._}}(this)),define("utils/utils",["libs/underscore"],function(e){function t(e,t,r){n("GET",e,{},t,r)}function n(e,t,n,r,i){if(e=="GET"||e=="DELETE")t.indexOf("?")==-1?t+="?":t+="&",t+=$.param(n);var s=new XMLHttpRequest;s.open(e,t,!0),s.setRequestHeader("Accept","application/json"),s.setRequestHeader("Cache-Control","no-cache"),s.setRequestHeader("X-Requested-With","XMLHttpRequest"),s.setRequestHeader("Content-Type","application/json"),s.onloadend=function(){var e=s.status;try{response=jQuery.parseJSON(s.responseText)}catch(t){response=s.responseText}e==200?r&&r(response):i&&i(response)},e=="GET"||e=="DELETE"?s.send():s.send(JSON.stringify(n))}function r(e,t){var n=$('<div class="'+e+'"></div>');n.appendTo(":eq(0)");var r=n.css(t);return n.remove(),r}function i(e){$('link[href^="'+e+'"]').length||$('<link href="'+galaxy_config.root+e+'" rel="stylesheet">').appendTo("head")}function s(t,n){return t?e.defaults(t,n):n}function o(e,t){var n="";if(e>=1e11)e/=1e11,n="TB";else if(e>=1e8)e/=1e8,n="GB";else if(e>=1e5)e/=1e5,n="MB";else if(e>=100)e/=100,n="KB";else{if(!(e>0))return"<strong>-</strong>";e*=10,n="b"}var r=Math.round(e)/10;return t?r+" "+n:"<strong>"+r+"</strong> "+n}function u(){return(new Date).getTime().toString(36)}function a(e){var t=$("<p></p>");return t.append(e),t}function f(){var e=new Date,t=(e.getHours()<10?"0":"")+e.getHours(),n=(e.getMinutes()<10?"0":"")+e.getMinutes(),r=e.getDate()+"/"+(e.getMonth()+1)+"/"+e.getFullYear()+", "+t+":"+n;return r}return{cssLoadFile:i,cssGetAttribute:r,get:t,merge:s,bytesToString:o,uuid:u,time:f,wrap:a,request:n}}),define("mvc/ui/ui-modal",["utils/utils"],function(e){var t=Backbone.View.extend({elMain:"body",optionsDefault:{title:"ui-modal",body:"",backdrop:!0,height:null,width:null,closing_events:!1},buttonList:{},initialize:function(e){e&&this._create(e)},show:function(e){this.initialize(e),this.options.height?(this.$body.css("height",this.options.height),this.$body.css("overflow","hidden")):this.$body.css("max-height",$(window).height()/2),this.options.width&&this.$dialog.css("width",this.options.width),this.visible?this.$el.show():this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.visible=!1,this.$el.fadeOut("fast")},enableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!1)},disableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!0)},showButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).show()},hideButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).hide()},getButton:function(e){var t=this.buttonList[e];return this.$buttons.find("#"+t)},scrollTop:function(){return this.$body.scrollTop()},_create:function(e){var t=this;this.options=_.defaults(e,this.optionsDefault),this.options.body=="progress"&&(this.options.body=$('<div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width:100%"></div></div>')),this.$el&&(this.$el.remove(),$(document).off("keyup")),this.setElement(this._template(this.options.title)),this.$dialog=this.$el.find(".modal-dialog"),this.$body=this.$el.find(".modal-body"),this.$footer=this.$el.find(".modal-footer"),this.$buttons=this.$el.find(".buttons"),this.$backdrop=this.$el.find(".modal-backdrop"),this.$body.html(this.options.body),this.options.backdrop||this.$backdrop.removeClass("in");if(this.options.buttons){this.buttonList={};var n=0;$.each(this.options.buttons,function(e,r){var i="button-"+n++;t.$buttons.append($('<button id="'+i+'"></button>').text(e).click(r)).append(" "),t.buttonList[e]=i})}else this.$footer.hide();$(this.elMain).append($(this.el)),this.options.closing_events&&(this.options.buttons.Pause||$(document).on("keyup",function(e){e.keyCode==27&&t.hide()}),this.$el.find(".modal-backdrop").on("click",function(){t.hide()}))},_template:function(e){return'<div class="modal"><div class="modal-backdrop fade in" style="z-index: -1;"></div><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" style="display: none;">×</button><h4 class="title">'+e+"</h4>"+"</div>"+'<div class="modal-body" style="position: static;"></div>'+'<div class="modal-footer">'+'<div class="buttons" style="float: right;"></div>'+"</div>"+"</div"+"</div>"+"</div>"}});return{View:t}}),define("mvc/ui/ui-portlet",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,optionsDefault:{title:"",icon:"",buttons:null,body:null,height:null,operations:null,placement:"bottom",overflow:"auto"},$title:null,$content:null,$buttons:null,$operations:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$content=this.$el.find("#content"),this.$title=this.$el.find("#title-text"),this.options.height&&(this.$el.find("#body").css("height",this.options.height),this.$el.find("#content").css("overflow",this.options.overflow)),this.$buttons=$(this.el).find("#buttons");if(this.options.buttons){var n=this;$.each(this.options.buttons,function(e,t){t.$el.prop("id",e),n.$buttons.append(t.$el)})}else this.$buttons.remove();this.$operations=$(this.el).find("#operations");if(this.options.operations){var n=this;$.each(this.options.operations,function(e,t){t.$el.prop("id",e),n.$operations.append(t.$el)})}this.options.body&&this.append(this.options.body)},append:function(t){this.$content.append(e.wrap(t))},content:function(){return this.$content},show:function(){this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},enableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!1)},disableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!0)},hideOperation:function(e){this.$operations.find("#"+e).hide()},showOperation:function(e){this.$operations.find("#"+e).show()},setOperation:function(e,t){var n=this.$operations.find("#"+e);n.off("click"),n.on("click",t)},title:function(e){var t=this.$title;return e&&t.html(e),t.html()},_template:function(e){var t='<div class="toolForm portlet-view no-highlight">';if(e.title||e.icon)t+='<div id="title" class="toolFormTitle portlet-title"><div id="operations" class="portlet-operations"/><div style="overflow: hidden;">',e.icon&&(t+='<div class="portlet-title-icon fa '+e.icon+'"> </div>'),t+='<div id="title-text" class="portlet-title-text">'+e.title+"</div>",t+="</div></div>";return t+='<div id="body" class="toolFormBody portlet-body">',e.placement=="top"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+='<div id="content" class="portlet-content"/>',e.placement=="bottom"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+="</div></div>",t}});return{View:t}}),define("plugin/library/ui-select",["utils/utils"],function(e){var t=Backbone.View.extend({optionsDefault:{id:"",cls:"",empty:"No data available",visible:!0,wait:!1},selected:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$select=this.$el.find("#select"),this.$icon=this.$el.find("#icon"),this.selected=this.options.value;var n=this;this.options.onchange&&this.$select.on("change",function(){n.value(n.$select.val())}),this._refresh(),this.options.visible||this.hide(),this.options.wait?this.wait():this.show()},value:function(e){var t=this.selected;e!==undefined&&(this.selected=e,this.$select.val(e));var n=this.selected;return n&&n!=t&&this.options.onchange&&this.options.onchange(n),n},text:function(){return this.$select.find("option:selected").text()},show:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-caret-down"),this.$select.show(),this.$el.show()},hide:function(){this.$el.hide()},wait:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-spinner fa-spin"),this.$select.hide()},disabled:function(){return this.$select.is(":disabled")},enable:function(){this.$select.prop("disabled",!1)},disable:function(){this.$select.prop("disabled",!0)},add:function(e){this.$select.append(this._templateOption(e)),this._refresh()},del:function(e){this.$select.find("option[value="+e+"]").remove(),this.$select.trigger("change"),this._refresh()},update:function(e){this.$select.find("option").remove();for(var t in e)this.$select.append(this._templateOption(e[t]));!this.selected&&e.length>0&&this.value(e[0].value),this._refresh()},_refresh:function(){this.$select.find("option[value=null]").remove();var e=this.$select.find("option").length;e==0?(this.$select.append(this._templateOption({value:"null",label:this.options.empty})),this.disable()):(this.enable(),this.selected&&this.$select.val(this.selected))},_exists:function(e){return 0!=this.$select.find("option[value="+e+"]").length},_templateOption:function(e){return'<option value="'+e.value+'">'+e.label+"</option>"},_template:function(e){var t='<div id="'+e.id+'" class="styled-select">'+'<div class="button">'+'<i id="icon"/>'+"</div>"+'<select id="select" class="select '+e.cls+" "+e.id+'">';for(key in e.data){var n=e.data[key],r="";if(n.value==e.value||n.value=="")r="selected";t+='<option value="'+n.value+'" '+r+">"+n.label+"</option>"}return t+="</select></div>",t}});return{View:t}}),define("plugin/library/ui",["utils/utils","plugin/library/ui-select"],function(e,t){var n=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options))},title:function(e){this.$el.find("b").html(e)},_template:function(e){return"<label><b>"+e.title+"</b></label>"},value:function(){return options.title}}),r=Backbone.View.extend({optionsDefault:{id:null,title:"","float":"right",cls:"btn-default",icon:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t='<button id="'+e.id+'" type="submit" style="margin-right: 5px; float: '+e.float+';" type="button" class="btn '+e.cls+'">';return e.icon&&(t+='<i class="icon fa '+e.icon+'"></i> '),t+=e.title+"</button>",t}}),i=Backbone.View.extend({optionsDefault:{"float":"right",icon:"",tooltip:"",placement:"bottom",title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){return'<div><span class="fa '+e.icon+'" style="font-size: 1.2em;"/> '+e.title+"</div>"}}),s=Backbone.View.extend({optionsDefault:{title:"",id:null,"float":"right",cls:"icon-btn",icon:"",tooltip:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t="";e.title&&(t="width: auto;");var n='<div id="'+e.id+'" style="margin-right: 5px; float: '+e.float+"; "+t+'" class="'+e.cls+'">';return e.title?n+='<div style="margin-right: 5px; margin-left: 5px;"><i class="icon fa '+e.icon+'"/> '+'<span style="position: relative; font-size: 0.8em; font-weight: normal; top: -1px;">'+e.title+"</span>"+"</div>":n+='<i class="icon fa '+e.icon+'"/>',n+="</div>",n}}),o=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick)},_template:function(e){return'<div><a href="javascript:void(0)">'+e.title+"</a></div>"}}),u=Backbone.View.extend({optionsDefault:{message:"",status:"info",persistent:!1},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement("<div></div>")},update:function(t){this.options=e.merge(t,this.optionsDefault);if(t.message!=""){this.$el.html(this._template(this.options)),this.$el.fadeIn();if(!t.persistent){var n=this;window.setTimeout(function(){n.$el.is(":visible")?n.$el.fadeOut():n.$el.hide()},3e3)}}else this.$el.fadeOut()},_template:function(e){return'<div class="alert alert-'+e.status+'" style="padding: 2px 2px 2px 10px;">'+e.message+"</div>"}}),a=Backbone.View.extend({optionsDefault:{onclick:null,searchword:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options));var n=this;this.options.onclick&&this.$el.on("submit",function(e){var t=n.$el.find("#search");n.options.onclick(t.val())})},_template:function(e){return'<div class="search"><form onsubmit="return false;"><input id="search" class="form-control input-sm" type="text" name="search" placeholder="Search..." value="'+e.searchword+'">'+'<button type="submit" class="btn search-btn">'+'<i class="fa fa-search"></i>'+"</button>"+"</form>"+"</div>"}}),f=Backbone.View.extend({optionsDefault:{title:"Unlabeled",body:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.body&&this.$el.find(".body").append(this.options.body)},_template:function(e){return'<div id="title" class="title">'+e.title+":"+"</div>"}}),l=Backbone.View.extend({optionsDefault:{id:"",title:"",target:"",href:"",onunload:null,onclick:null,visible:!0,icon:null,tag:""},$menu:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement($(this._template(this.options)));var n=$(this.el).find(".root"),r=this;n.on("click",function(e){e.preventDefault(),r.options.onclick&&r.options.onclick()}),this.options.visible||this.hide()},show:function(){$(this.el).show()},hide:function(){$(this.el).hide()},addMenu:function(t){var n={title:"",target:"",href:"",onclick:null,divider:!1,icon:null};n=e.merge(t,n),this.$menu||($(this.el).append(this._templateMenu()),this.$menu=$(this.el).find(".menu"));var r=$(this._templateMenuItem(n));r.on("click",function(e){e.preventDefault(),n.onclick&&n.onclick()}),this.$menu.append(r),n.divider&&this.$menu.append($(this._templateDivider()))},_templateMenuItem:function(e){var t='<li><a href="'+e.href+'" target="'+e.target+'">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),t+=" "+e.title+"</a>"+"</li>",t},_templateMenu:function(){return'<ul class="menu dropdown-menu pull-right" role="menu"></ul>'},_templateDivider:function(){return'<li class="divider"></li>'},_template:function(e){var t='<div id="'+e.id+'" class="button-menu btn-group">'+'<button type="button" class="root btn btn-default dropdown-toggle" data-toggle="dropdown">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),"</button></div>",t}}),c=Backbone.View.extend({optionsDefault:{value:"",type:"text",placeholder:"",disabled:!1,visible:!0},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.disabled&&this.$el.prop("disabled",!0),this.options.visible||this.$el.hide();var n=this;this.options.onchange&&this.$el.on("input",function(){n.options.onchange()})},value:function(e){return e!==undefined&&this.$el.val(e),this.$el.val()},_template:function(e){return'<input id="'+e.id+'" type="'+e.type+'" value="'+e.value+'" placeholder="'+e.placeholder+'" class="form-control">'}});return{Label:n,Button:r,Icon:i,ButtonIcon:s,Input:c,Anchor:o,Message:u,Searchbox:a,Title:f,Select:t,ButtonMenu:l}}),define("plugin/library/jobs",["utils/utils"],function(e){return Backbone.Model.extend({initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},cleanup:function(t){var n=t.get("dataset_id_job");if(n){var r=this;e.request("PUT",config.root+"api/histories/none/contents/"+n,{deleted:!0},function(){r._refreshHdas()})}},submit:function(t,n,r,i){var s=this,o=t.id,u=t.get("type"),a=this.app.types.get(u);data={tool_id:"rkit",inputs:{input:{id:t.get("dataset_id"),src:"hda"},module:u,columns:r,settings:n}},s.cleanup(t),t.state("submit","Sending job request..."),e.request("POST",config.root+"api/tools",data,function(e){if(!e.outputs||e.outputs.length==0)t.state("failed","Job submission failed. No response.");else{s._refreshHdas();var n=e.outputs[0];t.state("queued","Job has been queued..."),t.set("dataset_id_job",n.id),s._loop(n.id,function(e){switch(e.state){case"ok":return t.state("success","Job completed successfully..."),i(e),!0;case"error":return t.state("failed","Job has failed. Please check the history for details."),!0;case"running":return t.state("running","Job is running..."),!1}})}},function(e){var n="";e&&e.message&&e.message.data&&e.message.data.input&&(n=e.message.data.input+"."),t.state("failed","This visualization requires the R-kit. Please make sure it is installed. "+n)})},_loop:function(t,n){var r=this;e.request("GET",config.root+"api/jobs/"+t,{},function(e){n(e)||setTimeout(function(){r._loop(t,n)},r.app.config.get("query_timeout"))})},_refreshHdas:function(){Galaxy&&Galaxy.currHistoryPanel&&Galaxy.currHistoryPanel.refreshHdas()}})}),define("plugin/library/datasets",["utils/utils"],function(e){return Backbone.Collection.extend({list:{},initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},request:function(t,n,r){var i=this;if(t.groups)this._fetch(t,n);else{var s=this.list[t.id];if(s){n(s);return}e.request("GET",config.root+"api/datasets/"+t.id,{},function(e){switch(e.state){case"error":r&&r(e);break;default:i.list[t.id]=e,n(e)}})}},_fetch:function(t,n){var r=t.start?t.start:0,i=Math.abs(t.end-t.start),s=this.app.config.get("query_limit");if(!i||i>s)i=s;var o="",u={},a=0;for(var f in t.groups){var l=t.groups[f];for(var c in l.columns){var h=l.columns[c];o+=h+",",u[h]=a,a++}}if(a==0){n({});return}o=o.substring(0,o.length-1);var p=t.groups.slice(0);for(var f in p)p[f].values=[];var d=this;e.request("GET",config.root+"api/datasets/"+t.id,{data_type:"raw_data",provider:"dataset-column",limit:i,offset:r,indeces:o},function(e){for(var i in e.data){var s=e.data[i];for(var o in t.groups){var a=t.groups[o],f={x:parseInt(i)+r};for(var l in a.columns){var c=a.columns[l],h=u[c],d=s[h];if(isNaN(d)||!d)d=0;f[l]=d}p[o].values.push(f)}}n(p)})}})}),define("plugin/models/group",[],function(){return Backbone.Model.extend({defaults:{key:"Data label",date:""},reset:function(){this.clear({silent:!0}).set(this.defaults),this.trigger("reset",this)}})}),define("plugin/models/groups",["plugin/models/group"],function(e){return Backbone.Collection.extend({model:e})});var Visualization=Backbone.Model.extend({defaults:{config:{}},urlRoot:function(){var e="/api/visualizations";return window.galaxy_config&&galaxy_config.root?galaxy_config.root+e:e},initialize:function(e){_.isObject(e.config)&&_.isObject(this.defaults.config)&&_.defaults(e.config,this.defaults.config),this._setUpListeners()},_setUpListeners:function(){},set:function(e,t){if(e==="config"){var n=this.get("config");_.isObject(n)&&(t=_.extend(_.clone(n),t))}return Backbone.Model.prototype.set.call(this,e,t),this},toString:function(){var e=this.get("id")||"";return this.get("title")&&(e+=":"+this.get("title")),"Visualization("+e+")"}}),VisualizationCollection=Backbone.Collection.extend({model:Visualization,url:function(){return galaxy_config.root+"api/visualizations"},initialize:function(e,t){t=t||{}},set:function(e,t){var n=this;e=_.map(e,function(e){var t=n.get(e.id);if(!t)return e;var r=t.toJSON();return _.extend(r,e),r}),Backbone.Collection.prototype.set.call(this,e,t)},toString:function(){return["VisualizationCollection(",[this.historyId,this.length].join(),")"].join("")}});define("mvc/visualization/visualization-model",function(){}),define("plugin/models/chart",["plugin/models/groups","mvc/visualization/visualization-model"],function(e){return Backbone.Model.extend({defaults:{id:null,title:"",type:"",date:null,state:"ok",state_info:""},initialize:function(t){this.groups=new e,this.settings=new Backbone.Model},reset:function(){this.clear({silent:!0}).set(this.defaults),this.groups.reset(),this.settings.clear(),this.trigger("reset",this)},copy:function(e){var t=this;t.clear({silent:!0}).set(this.defaults),t.set(e.attributes),t.settings=e.settings.clone(),t.groups.reset(),e.groups.each(function(e){t.groups.add(e.clone())}),t.trigger("change",t)},state:function(e,t){this.set("state_info",t),this.set("state",e)},ready:function(){return this.get("state")=="ok"||this.get("state")=="failed"}})}),define("plugin/library/storage",["utils/utils","plugin/models/chart","plugin/models/group"],function(e,t,n){return Backbone.Model.extend({vis:null,initialize:function(e){this.app=e,this.chart=this.app.chart,this.options=this.app.options,this.id=this.options.id,this.vis=new Visualization({type:"charts",config:{dataset_id:this.options.config.dataset_id,chart_dict:{}}}),this.id&&(this.vis.id=this.id);var t=this.options.config.chart_dict;t&&(this.vis.get("config").chart_dict=t)},save:function(){var e=this.app.chart;this.vis.get("config").chart_dict={};var t=e.get("title");t!=""&&this.vis.set("title",t);var n={attributes:e.attributes,settings:e.settings.attributes,groups:[]};e.groups.each(function(e){n.groups.push(e.attributes)}),this.vis.get("config").chart_dict=n;var r=this;this.vis.save().fail(function(e,t,n){console.error(e,t,n),alert("Error loading data:\n"+e.responseText)}).then(function(e){e&&e.id&&(r.id=e.id)})},load:function(){var e=this.vis.get("config").chart_dict;if(!e.attributes)return!1;this.chart.set(e.attributes),this.chart.settings.set(e.settings);for(var t in e.groups)this.chart.groups.add(new n(e.groups[t]));return this.chart.state("ok","Loaded previously saved visualization."),!0}})}),define("plugin/views/viewport",["mvc/ui/ui-portlet","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({height:300,initialize:function(e,t){this.app=e,this.chart=this.app.chart,this.options=n.merge(t,this.optionsDefault),this.setElement($(this._template()));var r=this;this.chart.on("redraw",function(){r._draw(r.chart)})},show:function(){this.$el.show()},hide:function(){this.$el.hide()},_draw:function(e){var t=this;if(!e.ready()){this.app.log("viewport:_drawChart()","Invalid attempt to draw chart before completion.");return}this.svg&&this.svg.remove(),this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.setAttribute("height",this.height),this.$el.append(this.svg),this.svg=d3.select(this.$el.find("svg")[0]),e.off("change:state"),e.on("change:state",function(){var n=t.$el.find("#info"),r=n.find("#icon");r.removeClass(),n.show(),n.find("#text").html(e.get("state_info"));var i=e.get("state");switch(i){case"ok":n.hide();break;case"failed":r.addClass("fa fa-warning");break;default:r.addClass("fa fa-spinner fa-spin")}}),e.state("wait","Please wait...");var n=e.get("type"),r=this.app.types.get(n),t=this;require(["plugin/charts/"+n+"/"+n],function(n){var i=new n(t.app,{svg:t.svg});r.execute?t.app.jobs.submit(e,t._defaultSettingsString(e),t._defaultRequestString(e),function(){i.draw(e,t._defaultRequestDictionary(e))}):i.draw(e,t._defaultRequestDictionary(e))})},_template:function(){return'<div><div id="info" style="text-align: center; margin-top: 20px;"><span id="icon" style="font-size: 1.2em; display: inline-block;"/><span id="text" style="position: relative; margin-left: 5px; top: -1px; font-size: 1.0em;"/></div></div>'},_defaultRequestString:function(e){var t=this.app.types.get(e.get("type")),n="",r=0;return e.groups.each(function(e){for(var i in t.columns)n+=i+"_"+ ++r+":"+(parseInt(e.get(i))+1)+", "}),n.substring(0,n.length-2)},_defaultSettingsString:function(e){var t="";for(key in e.settings.attributes)t+=key+":"+e.settings.get(key)+", ";return t.substring(0,t.length-2)},_defaultRequestDictionary:function(e){var t=this.app.types.get(e.get("type")),n={id:e.get("dataset_id"),groups:[]},r=0;return e.groups.each(function(e){var i={};for(var s in t.columns)i[s]=e.get(s);n.groups.push({key:++r+":"+e.get("key"),columns:i})}),n}})}),define("plugin/views/viewer",["utils/utils","plugin/library/ui","mvc/ui/ui-portlet","plugin/models/group","plugin/views/viewport"],function(e,t,n,r,i){return Backbone.View.extend({initialize:function(e,r){this.app=e,this.chart=this.app.chart,this.viewport_view=new i(e);var s=this;this.portlet=new n.View({icon:"fa-bar-chart-o",title:"Viewport",operations:{edit_button:new t.ButtonIcon({icon:"fa-gear",tooltip:"Customize Chart",title:"Customize",onclick:function(){s._wait(s.app.chart,function(){s.app.go("editor")})}})}}),this.portlet.append(this.viewport_view.$el),this.setElement(this.portlet.$el);var s=this;this.chart.on("change:title",function(){s._refreshTitle()})},show:function(){this.$el.show(),$(window).trigger("resize")},hide:function(){this.$el.hide()},_refreshTitle:function(){var e=this.chart.get("title");e&&(e=" - "+e),this.portlet.title("Charts"+e)},_wait:function(e,t){if(e.ready())t();else{var n=this;this.app.modal.show({title:"Please wait!",body:"Your chart is currently being processed. Please wait...",buttons:{Close:function(){n.app.modal.hide()},Retry:function(){n.app.modal.hide(),setTimeout(function(){n._wait(e,t)},n.app.config.get("query_timeout"))}}})}}})}),define("mvc/ui/ui-tabs",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,list:{},$nav:null,$content:null,first_tab:null,optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(this.options));this.$nav=n.find(".tab-navigation"),this.$content=n.find(".tab-content"),this.setElement(n),this.list={};var r=this;this.options.operations&&$.each(this.options.operations,function(e,t){t.$el.prop("id",e),r.$nav.find(".operations").append(t.$el)});if(this.options.onnew){var i=$(this._template_tab_new(this.options));this.$nav.append(i),i.tooltip({title:"Add a new tab",placement:"bottom",container:r.$el}),i.on("click",function(e){i.tooltip("hide"),r.options.onnew()})}},add:function(e){var t=e.id,n={$title:$(this._template_tab(e)),$content:$(this._template_tab_content(e)),removable:e.ondel?!0:!1};this.list[t]=n,this.options.onnew?this.$nav.find("#new-tab").before(n.$title):this.$nav.append(n.$title),n.$content.append(e.$el),this.$content.append(n.$content),_.size(this.list)==1&&(n.$title.addClass("active"),n.$content.addClass("active"),this.first_tab=t);if(e.ondel){var r=this,i=n.$title.find("#delete");i.tooltip({title:"Delete this tab",placement:"bottom",container:r.$el}),i.on("click",function(){return i.tooltip("destroy"),r.$el.find(".tooltip").remove(),e.ondel(),!1})}e.onclick&&n.$title.on("click",function(){e.onclick()})},del:function(e){var t=this.list[e];t.$title.remove(),t.$content.remove(),delete t,this.first_tab==e&&(this.first_tab=null),this.first_tab!=null&&this.show(this.first_tab)},delRemovable:function(){for(var e in this.list){var t=this.list[e];t.removable&&this.del(e)}},show:function(e){this.$el.fadeIn("fast"),this.visible=!0,e&&this.list[e].$title.find("a").tab("show")},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},hideOperation:function(e){this.$nav.find("#"+e).hide()},showOperation:function(e){this.$nav.find("#"+e).show()},setOperation:function(e,t){var n=this.$nav.find("#"+e);n.off("click"),n.on("click",t)},title:function(e,t){var n=this.list[e].$title.find("#text");return t&&n.html(t),n.html()},_template:function(e){return'<div class="tabbable tabs-left"><ul class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div class="tab-content"/></div>'},_template_tab_new:function(e){return'<li id="new-tab"><a href="javascript:void(0);"><i style="font-size: 0.8em; margin-right: 5px;" class="fa fa-plus-circle"/>'+e.title_new+"</a>"+"</li>"},_template_tab:function(e){var t='<li id="title-'+e.id+'">'+'<a title="" href="#tab-'+e.id+'" data-toggle="tab" data-original-title="">'+'<span id="text">'+e.title+"</span>";return e.ondel&&(t+='<i id="delete" style="font-size: 0.8em; margin-left: 5px; cursor: pointer;" class="fa fa-minus-circle"/>'),t+="</a></li>",t},_template_tab_content:function(e){return'<div id="tab-'+e.id+'" class="tab-pane"/>'}});return{View:t}}),define("plugin/library/ui-table",["utils/utils"],function(e){var t=Backbone.View.extend({row:null,row_count:0,optionsDefault:{content:"No content available.",onchange:null,ondblclick:null,onconfirm:null},events:{click:"_onclick",dblclick:"_ondblclick"},first:!0,initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(t));this.$thead=n.find("thead"),this.$tbody=n.find("tbody"),this.$tmessage=n.find("tmessage"),this.setElement(n),this.row=$("<tr></tr>")},addHeader:function(e){var t=$("<th></th>");t.append(e),this.row.append(t)},appendHeader:function(){this.$thead.append(this.row),this.row=$("<tr></tr>")},add:function(e,t){var n=$("<td></td>");t&&n.css("width",t),n.append(e),this.row.append(n)},append:function(e){this._commit(e)},prepend:function(e){this._commit(e,!0)},remove:function(e){var t=this.$tbody.find("#"+e);t.length>0&&(t.remove(),this.row_count--,this._refresh())},removeAll:function(){this.$tbody.html(""),this.row_count=0,this._refresh()},value:function(e){this.before=this.$tbody.find(".current").attr("id"),e!==undefined&&(this.$tbody.find("tr").removeClass("current"),e&&this.$tbody.find("#"+e).addClass("current"));var t=this.$tbody.find(".current").attr("id");return t===undefined?null:(t!=this.before&&this.options.onchange&&this.options.onchange(e),t)},size:function(){return this.$tbody.find("tr").length},_commit:function(e,t){this.remove(e),this.row.attr("id",e),t?this.$tbody.prepend(this.row):this.$tbody.append(this.row),this.row=$("<tr></tr>"),this.row_count++,this._refresh()},_onclick:function(e){var t=this.value(),n=$(e.target).closest("tr").attr("id");n&&t!=n&&(this.options.onconfirm?this.options.onconfirm(n):this.value(n))},_ondblclick:function(e){var t=this.value();t&&this.options.ondblclick&&this.options.ondblclick(t)},_refresh:function(){this.row_count==0?this.$tmessage.show():this.$tmessage.hide()},_template:function(e){return'<div><table class="grid"><thead></thead><tbody style="cursor: pointer;"></tbody></table><tmessage>'+e.content+"</tmessage>"+"<div>"}});return{View:t}}),define("plugin/views/group",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({columns:[],initialize:function(r,i){this.app=r;var s=this;this.chart=this.app.chart,this.group=i.group,this.group_key=new t.Input({placeholder:"Data label",onchange:function(){s.group.set("key",s.group_key.value())}}),this.table=new e.View({content:"No data column."});var o=$("<div/>");o.append(n.wrap((new t.Label({title:"Provide a label:"})).$el)),o.append(n.wrap(this.group_key.$el)),o.append(n.wrap((new t.Label({title:"Select columns:"})).$el)),o.append(n.wrap(this.table.$el)),this.setElement(o);var s=this;this.chart.on("change:dataset_id",function(){s._refreshTable()}),this.chart.on("change:type",function(){s._refreshTable()}),this.group.on("change:key",function(){s._refreshGroupKey()}),this.group.on("change",function(){s._refreshGroup()}),this._refreshTable(),this._refreshGroupKey(),this._refreshGroup()},_refreshTable:function(){var e=this.chart.get("dataset_id"),n=this.chart.get("type");if(!e||!n)return;var r=this,i=this.app.types.get(n);this.table.removeAll();var s={};for(var o in i.columns){var u=this.group.get(o);u||this.group.set(o,0);var a=i.columns[o],f=new t.Select.View({id:"select_"+o,gid:o,onchange:function(e){r.group.set(this.gid,e)},value:u,wait:!0});this.table.add(a.title,"25%"),this.table.add(f.$el),this.table.append(o),s[o]=f}this.app.datasets.request({id:e},function(e){r.columns=[];var t=e.metadata_column_types;for(var n in t)(t[n]=="int"||t[n]=="float")&&r.columns.push({label:"Column: "+(parseInt(n)+1)+" ["+t[n]+"]",value:n});for(var n in s)s[n].update(r.columns),s[n].show()})},_refreshGroup:function(){this.group.set("date",n.time())},_refreshGroupKey:function(){var e=this.group.get("key");e===undefined&&(e=""),this.group_key.value(e)}})}),define("plugin/library/ui-table-form",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){var r=Backbone.View.extend({initialize:function(r){this.table_title=new t.Label({title:r.title}),this.table=new e.View({content:r.content});var i=$("<div/>");i.append(n.wrap(this.table_title.$el)),i.append(n.wrap(this.table.$el)),this.setElement(i)},title:function(e){this.table_title.title(e)},update:function(e,t){this.table.removeAll();for(var n in e)this._add(n,e[n],t)},_add:function(e,n,r){var i=null,s=n.type;switch(s){case"text":i=new t.Input({placeholder:n.placeholder,onchange:function(){r.set(e,i.value())}});break;case"select":i=new t.Select.View({data:n.data,onchange:function(){r.set(e,i.value())}});break;case"slider":i=new t.Input({placeholder:n.placeholder,onchange:function(){r.set(e,i.value())}});break;case"separator":i=$("<div/>");break;default:console.log("ui-table-form:_add","Unknown setting type ("+n.type+")");return}if(s!="separator"){r.get(e)||r.set(e,n.init),i.value(r.get(e));var o=$("<div/>");o.append(i.$el),o.append('<div class="toolParamHelp" style="font-size: 0.9em;">'+n.info+"</div>"),this.table.add('<span style="white-space: nowrap;">'+n.title+"</span>","25%"),this.table.add(o)}else this.table.add('<h6 style="white-space: nowrap;">'+n.title+":<h6/>"),this.table.add($("<div/>"));this.table.append(e)}});return{View:r}}),define("plugin/views/settings",["plugin/library/ui","plugin/library/ui-table-form","utils/utils"],function(e,t,n){return Backbone.View.extend({initialize:function(e,n){this.app=e;var r=this;this.chart=this.app.chart,this.form=new t.View({title:"Chart options:",content:"This chart type does not provide any options."}),this.setElement(this.form.$el);var r=this;this.chart.on("change",function(){r._refreshTable()})},_refreshTable:function(){var e=this.chart.get("type");if(!e)return;var t=this.app.types.get(e);this.form.title(t.title+":"),this.form.update(t.settings,this.chart.settings)}})}),define("plugin/views/editor",["mvc/ui/ui-tabs","plugin/library/ui-table","plugin/library/ui","mvc/ui/ui-portlet","utils/utils","plugin/models/chart","plugin/models/group","plugin/views/group","plugin/views/settings"],function(e,t,n,r,i,s,o,u,a){return Backbone.View.extend({optionsDefault:{header:!0,content:"No content available."},initialize:function(s,o){this.app=s,this.chart=this.app.chart,this.options=i.merge(o,this.optionsDefault),this.portlet=new r.View({icon:"fa-bar-chart-o",title:"Editor",operations:{save:new n.ButtonIcon({icon:"fa-save",tooltip:"Draw Chart",title:"Draw",onclick:function(){u.app.go("viewer"),u._saveChart()}}),back:new n.ButtonIcon({icon:"fa-caret-left",tooltip:"Return to Viewer",title:"Return",onclick:function(){u.app.go("viewer"),u.app.storage.load()}})}});var u=this;this.table=new t.View({header:!1,onconfirm:function(e){u.chart.groups.length>0?u.app.modal.show({title:"Switching to another chart type?",body:"If you continue your settings and selections will be cleared.",buttons:{Cancel:function(){u.app.modal.hide()},Continue:function(){u.app.modal.hide(),u.table.value(e)}}}):u.table.value(e)},onchange:function(e){u.chart.groups.reset(),u.chart.settings.clear(),u.chart.set({type:e})},ondblclick:function(e){u.tabs.show("settings")},content:"No chart types available"});var f=0,l=s.types.attributes;for(var c in l){var h=l[c];this.table.add(++f+"."),h.execute?this.table.add(h.title+" (requires processing)"):this.table.add(h.title),this.table.append(c)}this.tabs=new e.View({title_new:"Add Data",onnew:function(){var e=u._addGroupModel();u.tabs.show(e.id)}}),this.title=new n.Input({placeholder:"Chart title",onchange:function(){u.app.config.set("title",u.title.value())}});var p=$("<div/>");p.append(i.wrap((new n.Label({title:"Provide a chart title:"})).$el)),p.append(i.wrap(this.title.$el)),p.append(i.wrap((new n.Label({title:"Select a chart type:"})).$el)),p.append(i.wrap(this.table.$el)),this.tabs.add({id:"main",title:"Start",$el:p}),this.settings=new a(this.app),this.tabs.add({id:"settings",title:"Configuration",$el:this.settings.$el}),this.portlet.append(this.tabs.$el),this.setElement(this.portlet.$el),this.tabs.hideOperation("back");var u=this;this.chart.on("change:title",function(e){u._refreshTitle()}),this.chart.on("change:type",function(e){u.table.value(e.get("type"))}),this.chart.on("reset",function(e){u._resetChart()}),this.app.chart.on("redraw",function(e){u.portlet.showOperation("back")}),this.app.chart.groups.on("add",function(e){u._addGroup(e)}),this.app.chart.groups.on("remove",function(e){u._removeGroup(e)}),this.app.chart.groups.on("reset",function(e){u._removeAllGroups()}),this.app.chart.groups.on("change:key",function(e){u._refreshGroupKey()}),this._resetChart()},show:function(){this.$el.show()},hide:function(){this.$el.hide()},_refreshTitle:function(){var e=this.chart.get("title");e&&(e=" - "+e),this.portlet.title("Charts"+e)},_refreshGroupKey:function(){var e=this,t=0;this.chart.groups.each(function(n){var r=n.get("key","");r==""&&(r="Chart data"),e.tabs.title(n.id,++t+": "+r)})},_addGroupModel:function(){var e=new o({id:i.uuid()});return this.chart.groups.add(e),e},_addGroup:function(e){var t=this,n=new u(this.app,{group:e}),r=t.chart.groups.length;this.tabs.add({id:e.id,$el:n.$el,ondel:function(){t.chart.groups.remove(e.id)}}),this._refreshGroupKey()},_removeGroup:function(e){this.tabs.del(e.id),this._refreshGroupKey()},_removeAllGroups:function(e){this.tabs.delRemovable()},_resetChart:function(){this.chart.set("id",i.uuid()),this.chart.set("type","bardiagram"),this.chart.set("dataset_id",this.app.options.config.dataset_id),this.chart.set("title","New Chart"),this.portlet.hideOperation("back")},_saveChart:function(){this.chart.set({type:this.table.value(),title:this.title.value(),date:i.time()}),this.chart.groups.length==0&&this._addGroupModel(),this.chart.trigger("redraw"),this.app.storage.save()}})}),define("plugin/models/config",[],function(){return Backbone.Model.extend({defaults:{query_limit:1e3,query_timeout:500}})}),define("plugin/charts/_nvd3/config",[],function(){return{title:"",columns:{y:{title:"Values for y-axis"}},settings:{separator_label:{title:"X axis",type:"separator"},x_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"X-axis",placeholder:"Axis label"},x_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"f",data:[{label:"-- Do not show values --",value:"hide"},{label:"Float",value:"f"},{label:"Exponent",value:"e"},{label:"Integer",value:"d"},{label:"Percentage",value:"p"},{label:"Rounded",value:"r"},{label:"SI-prefix",value:"s"}]},x_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_tick:{title:"Y axis",type:"separator"},y_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"Y-axis",placeholder:"Axis label"},y_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"f",data:[{label:"-- Do not show values --",value:"hide"},{label:"Float",value:"f"},{label:"Exponent",value:"e"},{label:"Integer",value:"d"},{label:"Percentage",value:"p"},{label:"Rounded",value:"r"},{label:"SI-prefix",value:"s"}]},y_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_legend:{title:"Others",type:"separator"},show_legend:{title:"Show legend",info:"Would you like to add a legend?",type:"select",init:"true",data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]}}}}),define("plugin/charts/bardiagram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram"})}),define("plugin/charts/histogram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Histogram",execute:!0,columns:{y:{title:"Observations"}},settings:{x_axis_label:{init:"Breaks"},y_axis_label:{init:"Density"},y_axis_tick:{init:".3"}}})}),define("plugin/charts/horizontal/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram (horizontal)",settings:{x_axis_type:{init:"hide"}}})}),define("plugin/charts/line/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line chart"})}),define("plugin/charts/linewithfocus/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line with focus"})}),define("plugin/charts/piechart/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Pie chart"})}),define("plugin/charts/scatterplot/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Scatter plot",columns:{x:{title:"Values for x-axis"}}})}),define("plugin/charts/stackedarea/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Stacked area"})}),define("plugin/charts/types",["plugin/charts/bardiagram/config","plugin/charts/histogram/config","plugin/charts/horizontal/config","plugin/charts/line/config","plugin/charts/linewithfocus/config","plugin/charts/piechart/config","plugin/charts/scatterplot/config","plugin/charts/stackedarea/config"],function(e,t,n,r,i,s,o,u){return Backbone.Model.extend({defaults:{bardiagram:e,horizontal:n,histogram:t,line:r,linewithfocus:i,piechart:s,scatterplot:o,stackedarea:u}})}),define("plugin/app",["mvc/ui/ui-modal","mvc/ui/ui-portlet","plugin/library/ui","utils/utils","plugin/library/jobs","plugin/library/datasets","plugin/library/storage","plugin/views/viewer","plugin/views/editor","plugin/models/config","plugin/models/chart","plugin/charts/types"],function(e,t,n,r,i,s,o,u,a,f,l,c){return Backbone.View.extend({initialize:function(t){this.options=t,Galaxy&&Galaxy.modal?this.modal=Galaxy.modal:this.modal=new e.View,this.config=new f,this.types=new c,this.chart=new l,this.jobs=new i(this),this.datasets=new s(this),this.storage=new o(this),this.viewer_view=new u(this),this.editor_view=new a(this),this.$el.append(this.viewer_view.$el),this.$el.append(this.editor_view.$el),this.storage.load()?(this.go("viewer"),this.chart.trigger("redraw")):this.go("editor")},go:function(e){$(".tooltip").hide();switch(e){case"editor":this.editor_view.show(),this.viewer_view.hide();break;case"viewer":this.editor_view.hide(),this.viewer_view.show()}},execute:function(e){},onunload:function(){},log:function(e,t){console.log(e+" "+t)}})});
\ No newline at end of file
diff -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 -r fa0968cfe3c3fec5869168bd7dd68829024f1ec3 config/plugins/visualizations/charts/static/library/storage.js
--- /dev/null
+++ b/config/plugins/visualizations/charts/static/library/storage.js
@@ -0,0 +1,118 @@
+// dependencies
+define(['utils/utils', 'plugin/models/chart', 'plugin/models/group'], function(Utils, Chart, Group) {
+
+// collection
+return Backbone.Model.extend(
+{
+ // viz model
+ vis: null,
+
+ // initialize
+ initialize: function(app) {
+ // link app
+ this.app = app;
+
+ // link chart
+ this.chart = this.app.chart;
+
+ // link options
+ this.options = this.app.options;
+
+ // initialize parameters
+ this.id = this.options.id;
+
+ // create visualization
+ this.vis = new Visualization({
+ type : 'charts',
+ config : {
+ dataset_id : this.options.config.dataset_id,
+ chart_dict : {}
+ }
+ });
+
+ // add visualization id
+ if (this.id) {
+ this.vis.id = this.id;
+ }
+
+ // add charts
+ var chart_dict = this.options.config.chart_dict;
+ if (chart_dict) {
+ this.vis.get('config').chart_dict = chart_dict;
+ }
+ },
+
+ // pack and save nested chart model
+ save: function() {
+
+ // link chart
+ var chart = this.app.chart;
+
+ // reset
+ this.vis.get('config').chart_dict = {};
+
+ // set title
+ var title = chart.get('title');
+ if (title != '') {
+ this.vis.set('title', title);
+ }
+
+ // create chart dictionary
+ var chart_dict = {
+ attributes : chart.attributes,
+ settings : chart.settings.attributes,
+ groups : []
+ };
+
+ // append groups
+ chart.groups.each(function(group) {
+ chart_dict.groups.push(group.attributes);
+ });
+
+ // add chart to charts array
+ this.vis.get('config').chart_dict = chart_dict;
+
+ // save visualization
+ var self = this;
+ this.vis.save()
+ .fail(function(xhr, status, message) {
+ console.error(xhr, status, message);
+ alert( 'Error loading data:\n' + xhr.responseText );
+ })
+ .then(function(response) {
+ if (response && response.id) {
+ self.id = response.id;
+ }
+ });
+ },
+
+ // load nested models/collections from packed dictionary
+ load: function() {
+ // get charts array
+ var chart_dict = this.vis.get('config').chart_dict;
+
+ // check
+ if (!chart_dict.attributes) {
+ return false;
+ }
+
+ // main
+ this.chart.set(chart_dict.attributes);
+
+ // get settings
+ this.chart.settings.set(chart_dict.settings);
+
+ // get groups
+ for (var j in chart_dict.groups) {
+ this.chart.groups.add(new Group(chart_dict.groups[j]));
+ }
+
+ // reset status
+ this.chart.state('ok', 'Loaded previously saved visualization.');
+
+ // return
+ return true;
+ }
+});
+
+});
\ No newline at end of file
diff -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 -r fa0968cfe3c3fec5869168bd7dd68829024f1ec3 config/plugins/visualizations/charts/static/models/charts.js
--- a/config/plugins/visualizations/charts/static/models/charts.js
+++ /dev/null
@@ -1,114 +0,0 @@
-// dependencies
-define(['plugin/models/chart', 'plugin/models/group'], function(Chart, Group) {
-
-// collection
-return Backbone.Collection.extend(
-{
- // nested chart model contains collections
- model : Chart,
-
- // viz model
- vis: null,
-
- // initialize
- initialize: function(options, app) {
- // initialize parameters
- this.app = app;
- this.id = this.app.options.id;
-
- // create visualization
- this.vis = new Visualization({
- type : 'charts',
- config : {
- dataset_id : this.app.options.config.dataset_id,
- charts : []
- }
- });
-
- // add visualization id
- if (this.id) {
- this.vis.id = this.id;
- }
-
- // add charts
- var charts_array = this.app.options.config.charts;
- if (charts_array) {
- this.vis.get('config').charts = charts_array;
- }
- },
-
- // pack and save nested chart models
- save: function() {
- // reset
- this.vis.get('config').charts = [];
-
- // pack nested chart models into arrays attributes
- var self = this;
- this.each(function(chart) {
- // create chart dictionary
- var chart_dict = {
- attributes : chart.attributes,
- settings : chart.settings.attributes,
- groups : []
- };
-
- // append groups
- chart.groups.each(function(group) {
- chart_dict.groups.push(group.attributes);
- });
-
- // add chart to charts array
- self.vis.get('config').charts.push(chart_dict);
- });
-
- // save visualization
- var self = this;
- this.vis.save()
- .fail(function(xhr, status, message) {
- console.error(xhr, status, message);
- alert( 'Error loading data:\n' + xhr.responseText );
- })
- .then(function(response) {
- if (response && response.id) {
- self.id = response.id;
- }
- });
- },
-
- // load nested models/collections from packed dictionary
- load: function() {
- // get charts array
- var charts_array = this.vis.get('config').charts;
-
- // unpack chart models
- for (var i in charts_array) {
- // get chart details
- var chart_dict = charts_array[i];
-
- // construct chart model
- var chart = new Chart();
-
- // main
- chart.set(chart_dict.attributes);
-
- // get settings
- chart.settings.set(chart_dict.settings);
-
- // get groups
- for (var j in chart_dict.groups) {
- chart.groups.add(new Group(chart_dict.groups[j]));
- }
-
- // reset status
- chart.state('ok', 'Loaded previously saved visualization.');
-
- // add to collection
- this.add(chart);
-
- // trigger
- chart.trigger('redraw', chart);
- }
- }
-});
-
-});
\ No newline at end of file
diff -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 -r fa0968cfe3c3fec5869168bd7dd68829024f1ec3 config/plugins/visualizations/charts/static/models/config.js
--- a/config/plugins/visualizations/charts/static/models/config.js
+++ b/config/plugins/visualizations/charts/static/models/config.js
@@ -7,8 +7,7 @@
// options
defaults : {
query_limit : 1000,
- query_timeout : 500,
- title : 'Create a new chart'
+ query_timeout : 500
}
});
diff -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 -r fa0968cfe3c3fec5869168bd7dd68829024f1ec3 config/plugins/visualizations/charts/static/views/chart.js
--- a/config/plugins/visualizations/charts/static/views/chart.js
+++ /dev/null
@@ -1,321 +0,0 @@
-// dependencies
-define(['mvc/ui/ui-tabs', 'plugin/library/ui-table', 'plugin/library/ui', 'utils/utils',
- 'plugin/models/chart', 'plugin/models/group',
- 'plugin/views/group', 'plugin/views/settings'],
- function(Tabs, Table, Ui, Utils, Chart, Group, GroupView, SettingsView) {
-
-// widget
-return Backbone.View.extend(
-{
- // defaults options
- optionsDefault: {
- header : true,
- content : 'No content available.'
- },
-
- // initialize
- initialize: function(app, options)
- {
- // link application
- this.app = app;
-
- // get current chart object
- this.chart = this.app.chart;
-
- // configure options
- this.options = Utils.merge(options, this.optionsDefault);
-
- //
- // table with chart types
- //
- var self = this;
- this.table = new Table.View({
- header : false,
- onconfirm : function(type) {
- if (self.chart.groups.length > 0) {
- // show modal
- self.app.modal.show({
- title : 'Switching to another chart type?',
- body : 'If you continue your settings and selections will be cleared.',
- buttons : {
- 'Cancel' : function() {
- // hide modal
- self.app.modal.hide();
- },
- 'Continue' : function() {
- // hide modal
- self.app.modal.hide();
-
- // confirm
- self.table.value(type);
- }
- }
- });
- } else {
- // confirm
- self.table.value(type);
- }
- },
- onchange : function(type) {
- // reset type relevant chart content
- self.chart.groups.reset();
- self.chart.settings.clear();
-
- // update chart type
- self.chart.set({type: type});
- },
- ondblclick : function(chart_id) {
- self.tabs.show('settings');
- },
- content: 'No chart types available'
- });
-
- // load chart types into table
- var types_n = 0;
- var types = app.types.attributes;
- for (var id in types){
- var chart_type = types[id];
- this.table.add (++types_n + '.');
- if (chart_type.execute) {
- this.table.add(chart_type.title + ' (requires processing)');
- } else {
- this.table.add (chart_type.title);
- }
- this.table.append(id);
- }
-
- //
- // tabs
- //
- this.tabs = new Tabs.View({
- title_new : 'Add Data',
- onnew : function() {
- var group = self._addGroupModel();
- self.tabs.show(group.id);
- },
- operations : {
- 'save' : new Ui.ButtonIcon({
- icon : 'fa-save',
- tooltip : 'Draw Chart',
- title : 'Draw',
- onclick : function() {
- // show charts
- self.app.go('charts_view');
-
- // save chart
- self._saveChart();
- }
- }),
- 'back' : new Ui.ButtonIcon({
- icon : 'fa-caret-left',
- tooltip : 'Return to Viewer',
- title : 'Return',
- onclick : function() {
- self.app.go('charts_view');
- }
- })
- }
- });
-
- //
- // main/default tab
- //
-
- // construct elements
- this.title = new Ui.Input({
- placeholder: 'Chart title',
- onchange: function() {
- self.app.config.set('title', self.title.value());
- }
- });
-
- // append element
- var $main = $('<div/>');
- $main.append(Utils.wrap((new Ui.Label({ title : 'Provide a chart title:'})).$el));
- $main.append(Utils.wrap(this.title.$el));
- $main.append(Utils.wrap((new Ui.Label({ title : 'Select a chart type:'})).$el));
- $main.append(Utils.wrap(this.table.$el));
-
- // add tab
- this.tabs.add({
- id : 'main',
- title : 'Start',
- $el : $main
- });
-
- //
- // main settings tab
- //
-
- // create settings view
- this.settings = new SettingsView(this.app);
-
- // add tab
- this.tabs.add({
- id : 'settings',
- title : 'Configuration',
- $el : this.settings.$el
- });
-
- // elements
- this.setElement(this.tabs.$el);
-
- // hide back button on startup
- this.tabs.hideOperation('back');
-
- // chart events
- var self = this;
- this.chart.on('change:title', function(chart) {
- self.title.value(chart.get('title'));
- self.app.config.set('title', chart.get('title'));
- });
- this.chart.on('change:type', function(chart) {
- self.table.value(chart.get('type'));
- });
- this.chart.on('reset', function(chart) {
- self._resetChart();
- });
-
- // charts events
- this.app.charts.on('add', function(chart) {
- self.tabs.showOperation('back');
- });
- this.app.charts.on('remove', function(chart) {
- if (self.app.charts.length == 0) {
- self.tabs.hideOperation('back');
- }
- });
- this.app.charts.on('reset', function(chart) {
- self.tabs.hideOperation('back');
- });
-
- // groups events
- this.app.chart.groups.on('add', function(group) {
- self._addGroup(group);
- });
- this.app.chart.groups.on('remove', function(group) {
- self._removeGroup(group);
- });
- this.app.chart.groups.on('reset', function(group) {
- self._removeAllGroups();
- });
- this.app.chart.groups.on('change:key', function(group) {
- self._refreshGroupKey();
- });
-
- // reset
- this._resetChart();
- },
-
- // hide
- show: function() {
- this.$el.show();
- },
-
- // hide
- hide: function() {
- $('.tooltip').hide();
- this.$el.hide();
- },
-
- // update
- _refreshGroupKey: function() {
- var self = this;
- var counter = 0;
- this.chart.groups.each(function(group) {
- var title = group.get('key', '');
- if (title == '') {
- title = 'Chart data';
- }
- self.tabs.title(group.id, ++counter + ': ' + title);
- });
- },
-
- // new group
- _addGroupModel: function() {
- var group = new Group({
- id : Utils.uuid()
- });
- this.chart.groups.add(group);
- return group;
- },
-
- // add group
- _addGroup: function(group) {
- // link this
- var self = this;
-
- // create view
- var group_view = new GroupView(this.app, {group: group});
-
- // number of groups
- var count = self.chart.groups.length;
-
- // add new tab
- this.tabs.add({
- id : group.id,
- $el : group_view.$el,
- ondel : function() {
- self.chart.groups.remove(group.id);
- }
- });
-
- // update titles
- this._refreshGroupKey();
- },
-
- // remove group
- _removeGroup: function(group) {
- this.tabs.del(group.id);
-
- // update titles
- this._refreshGroupKey();
- },
-
- // remove group
- _removeAllGroups: function(group) {
- this.tabs.delRemovable();
- },
-
- // reset
- _resetChart: function() {
- // reset chart details
- this.chart.set('id', Utils.uuid());
- this.chart.set('type', 'bardiagram');
- this.chart.set('dataset_id', this.app.options.config.dataset_id);
- this.chart.set('title', 'New Chart');
- },
-
- // create chart
- _saveChart: function() {
- // update chart data
- this.chart.set({
- type : this.table.value(),
- title : this.title.value(),
- date : Utils.time()
- });
-
- // ensure that data group is available
- if (this.chart.groups.length == 0) {
- this._addGroupModel();
- }
-
- // create/get chart
- var current = this.app.charts.get(this.chart.id);
- if (!current) {
- current = this.chart.clone();
- current.copy(this.chart);
- this.app.charts.add(current);
- } else {
- current.copy(this.chart);
- }
-
- // trigger redraw
- current.trigger('redraw', current);
-
- // save
- this.app.charts.save();
- }
-});
-
-});
\ No newline at end of file
diff -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 -r fa0968cfe3c3fec5869168bd7dd68829024f1ec3 config/plugins/visualizations/charts/static/views/charts.js
--- a/config/plugins/visualizations/charts/static/views/charts.js
+++ /dev/null
@@ -1,227 +0,0 @@
-// dependencies
-define(['mvc/ui/ui-portlet', 'plugin/library/ui-table', 'plugin/library/ui', 'utils/utils', 'plugin/models/group', 'plugin/views/viewport',], function(Portlet, Table, Ui, Utils, Group, ViewportView) {
-
-// widget
-return Backbone.View.extend(
-{
- // initialize
- initialize: function(app, options)
- {
- // link app
- this.app = app;
-
- // create viewport
- this.viewport_view = new ViewportView(app);
-
- // table
- this.table = new Table.View({
- content : 'Add charts to this table.',
- ondblclick : function(chart_id) {
- // attempt to load chart editor
- self._showChartView(chart_id);
- },
- onchange : function(chart_id) {
- // get chart
- var chart = self.app.charts.get(chart_id);
-
- // update main title
- self.app.config.set('title', chart.get('title'));
-
- // show viewport
- self.viewport_view.showChart(chart_id);
- }
- });
-
- // add table to portlet
- var self = this;
- this.portlet = new Portlet.View({
- icon : 'fa-list',
- title : 'List of created charts:',
- height : 100,
- operations : {
- 'new' : new Ui.ButtonIcon({
- icon : 'fa-magic',
- tooltip : 'Create a new Chart',
- title : 'New',
- onclick : function() {
- self.app.go('chart_view');
- self.app.chart.reset();
- }
- }),
- 'edit' : new Ui.ButtonIcon({
- icon : 'fa-gear',
- tooltip : 'Customize this Chart',
- title : 'Customize',
- onclick : function() {
- // check if element has been selected
- var chart_id = self.table.value();
- if (!chart_id) {
- return;
- }
-
- // attempt to load chart editor
- self._showChartView(chart_id);
- }
- }),
- 'delete' : new Ui.ButtonIcon({
- icon : 'fa-trash-o',
- tooltip : 'Delete this Chart',
- title : 'Delete',
- onclick : function() {
-
- // check if element has been selected
- var chart_id = self.table.value();
- if (!chart_id) {
- return;
- }
-
- // title
- var chart = self.app.charts.get(chart_id);
-
- // make sure that chart is ready
- self._wait (chart, function() {
- self.app.modal.show({
- title : 'Are you sure?',
- body : 'The selected chart "' + chart.get('title') + '" will be irreversibly deleted.',
- buttons : {
- 'Cancel' : function() {self.app.modal.hide();},
- 'Delete' : function() {
- // hide modal
- self.app.modal.hide();
-
- // remove chart
- self.app.charts.remove(chart_id);
-
- // cleanup
- self.app.jobs.cleanup(chart);
- }
- }
- });
- });
- }
- }),
- }
- });
- this.portlet.append(this.table.$el);
-
- // append portlet with table
- if (!this.app.options.config.widget) {
- this.$el.append(this.portlet.$el);
- }
-
- // append view port
- this.$el.append(Utils.wrap(''));
- this.$el.append(this.viewport_view.$el);
-
- // events
- var self = this;
- this.app.charts.on('add', function(chart) {
- // add
- self._addChart(chart);
- });
- this.app.charts.on('remove', function(chart) {
- // remove
- self._removeChart(chart);
- });
- this.app.charts.on('change', function(chart) {
- // replace
- self._changeChart(chart);
- });
- },
-
- // show
- show: function() {
- this.$el.show();
- },
-
- // hide
- hide: function() {
- $('.tooltip').hide();
- this.$el.hide();
- },
-
- // add
- _addChart: function(chart) {
- // add title to table
- var title = chart.get('title');
- if (title == '') {
- title = 'Untitled';
- }
- this.table.add(title);
-
- // get chart type
- var type = this.app.types.get(chart.get('type'));
- this.table.add(type.title);
-
- // add additional columns
- this.table.add('Last change: ' + chart.get('date'));
- this.table.prepend(chart.get('id'));
- this.table.value(chart.get('id'));
- },
-
- // remove
- _removeChart: function(chart) {
- // remove from to table
- this.table.remove(chart.id);
-
- // save
- this.app.charts.save();
-
- // check if table is empty
- if (this.table.size() == 0) {
- this.app.go('chart_view');
- this.app.chart.reset();
- } else {
- // select available chart
- this.table.value(this.app.charts.last().id);
- }
- },
-
- // change
- _changeChart: function(chart) {
- if (chart.get('type')) {
- // add chart
- this._addChart(chart);
-
- // select available chart
- this.table.value(chart.id);
- }
- },
-
- // show chart editor
- _showChartView: function(chart_id) {
- var self = this;
- var chart = this.app.charts.get(chart_id);
- this._wait (chart, function() {
- self.app.go('chart_view');
- self.app.chart.copy(chart);
- });
- },
-
- // wait for chart to be ready
- _wait: function(chart, callback) {
- // get chart
- if (chart.ready()) {
- callback();
- } else {
- // show modal
- var self = this;
- this.app.modal.show({
- title : 'Please wait!',
- body : 'The selected chart "' + chart.get('title') + '" is currently being processed. Please wait...',
- buttons : {
- 'Close' : function() {self.app.modal.hide();},
- 'Retry' : function() {
- // hide modal
- self.app.modal.hide();
-
- // retry
- setTimeout(function() { self._wait(chart, callback); }, self.app.config.get('query_timeout'));
- }
- }
- });
- }
- }
-});
-
-});
\ No newline at end of file
diff -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 -r fa0968cfe3c3fec5869168bd7dd68829024f1ec3 config/plugins/visualizations/charts/static/views/editor.js
--- /dev/null
+++ b/config/plugins/visualizations/charts/static/views/editor.js
@@ -0,0 +1,324 @@
+// dependencies
+define(['mvc/ui/ui-tabs', 'plugin/library/ui-table', 'plugin/library/ui', 'mvc/ui/ui-portlet', 'utils/utils',
+ 'plugin/models/chart', 'plugin/models/group',
+ 'plugin/views/group', 'plugin/views/settings'],
+ function(Tabs, Table, Ui, Portlet, Utils, Chart, Group, GroupView, SettingsView) {
+
+// widget
+return Backbone.View.extend(
+{
+ // defaults options
+ optionsDefault: {
+ header : true,
+ content : 'No content available.'
+ },
+
+ // initialize
+ initialize: function(app, options)
+ {
+ // link application
+ this.app = app;
+
+ // get current chart object
+ this.chart = this.app.chart;
+
+ // configure options
+ this.options = Utils.merge(options, this.optionsDefault);
+
+ // create portlet
+ this.portlet = new Portlet.View({
+ icon : 'fa-bar-chart-o',
+ title: 'Editor',
+ operations : {
+ 'save' : new Ui.ButtonIcon({
+ icon : 'fa-save',
+ tooltip : 'Draw Chart',
+ title : 'Draw',
+ onclick : function() {
+ // show viewport
+ self.app.go('viewer');
+
+ // save chart
+ self._saveChart();
+ }
+ }),
+ 'back' : new Ui.ButtonIcon({
+ icon : 'fa-caret-left',
+ tooltip : 'Return to Viewer',
+ title : 'Return',
+ onclick : function() {
+ // show viewport
+ self.app.go('viewer');
+
+ // reset chart
+ self.app.storage.load();
+ }
+ })
+ }
+ });
+
+ //
+ // table with chart types
+ //
+ var self = this;
+ this.table = new Table.View({
+ header : false,
+ onconfirm : function(type) {
+ if (self.chart.groups.length > 0) {
+ // show modal
+ self.app.modal.show({
+ title : 'Switching to another chart type?',
+ body : 'If you continue your settings and selections will be cleared.',
+ buttons : {
+ 'Cancel' : function() {
+ // hide modal
+ self.app.modal.hide();
+ },
+ 'Continue' : function() {
+ // hide modal
+ self.app.modal.hide();
+
+ // confirm
+ self.table.value(type);
+ }
+ }
+ });
+ } else {
+ // confirm
+ self.table.value(type);
+ }
+ },
+ onchange : function(type) {
+ // reset type relevant chart content
+ self.chart.groups.reset();
+ self.chart.settings.clear();
+
+ // update chart type
+ self.chart.set({type: type});
+ },
+ ondblclick : function(chart_id) {
+ self.tabs.show('settings');
+ },
+ content: 'No chart types available'
+ });
+
+ // load chart types into table
+ var types_n = 0;
+ var types = app.types.attributes;
+ for (var id in types){
+ var chart_type = types[id];
+ this.table.add (++types_n + '.');
+ if (chart_type.execute) {
+ this.table.add(chart_type.title + ' (requires processing)');
+ } else {
+ this.table.add (chart_type.title);
+ }
+ this.table.append(id);
+ }
+
+ //
+ // tabs
+ //
+ this.tabs = new Tabs.View({
+ title_new : 'Add Data',
+ onnew : function() {
+ var group = self._addGroupModel();
+ self.tabs.show(group.id);
+ }
+ });
+
+ //
+ // main/default tab
+ //
+
+ // construct elements
+ this.title = new Ui.Input({
+ placeholder: 'Chart title',
+ onchange: function() {
+ self.app.config.set('title', self.title.value());
+ }
+ });
+
+ // append element
+ var $main = $('<div/>');
+ $main.append(Utils.wrap((new Ui.Label({ title : 'Provide a chart title:'})).$el));
+ $main.append(Utils.wrap(this.title.$el));
+ $main.append(Utils.wrap((new Ui.Label({ title : 'Select a chart type:'})).$el));
+ $main.append(Utils.wrap(this.table.$el));
+
+ // add tab
+ this.tabs.add({
+ id : 'main',
+ title : 'Start',
+ $el : $main
+ });
+
+ //
+ // main settings tab
+ //
+
+ // create settings view
+ this.settings = new SettingsView(this.app);
+
+ // add tab
+ this.tabs.add({
+ id : 'settings',
+ title : 'Configuration',
+ $el : this.settings.$el
+ });
+
+ // append tabs
+ this.portlet.append(this.tabs.$el);
+
+ // elements
+ this.setElement(this.portlet.$el);
+
+ // hide back button on startup
+ this.tabs.hideOperation('back');
+
+ // chart events
+ var self = this;
+ this.chart.on('change:title', function(chart) {
+ self._refreshTitle();
+ });
+ this.chart.on('change:type', function(chart) {
+ self.table.value(chart.get('type'));
+ });
+ this.chart.on('reset', function(chart) {
+ self._resetChart();
+ });
+ this.app.chart.on('redraw', function(chart) {
+ self.portlet.showOperation('back');
+ });
+
+ // groups events
+ this.app.chart.groups.on('add', function(group) {
+ self._addGroup(group);
+ });
+ this.app.chart.groups.on('remove', function(group) {
+ self._removeGroup(group);
+ });
+ this.app.chart.groups.on('reset', function(group) {
+ self._removeAllGroups();
+ });
+ this.app.chart.groups.on('change:key', function(group) {
+ self._refreshGroupKey();
+ });
+
+ // reset
+ this._resetChart();
+ },
+
+ // hide
+ show: function() {
+ this.$el.show();
+ },
+
+ // hide
+ hide: function() {
+ this.$el.hide();
+ },
+
+ // refresh title
+ _refreshTitle: function() {
+ var title = this.chart.get('title');
+ if (title) {
+ title = ' - ' + title;
+ }
+ this.portlet.title('Charts' + title);
+ },
+
+ // update
+ _refreshGroupKey: function() {
+ var self = this;
+ var counter = 0;
+ this.chart.groups.each(function(group) {
+ var title = group.get('key', '');
+ if (title == '') {
+ title = 'Chart data';
+ }
+ self.tabs.title(group.id, ++counter + ': ' + title);
+ });
+ },
+
+ // new group
+ _addGroupModel: function() {
+ var group = new Group({
+ id : Utils.uuid()
+ });
+ this.chart.groups.add(group);
+ return group;
+ },
+
+ // add group
+ _addGroup: function(group) {
+ // link this
+ var self = this;
+
+ // create view
+ var group_view = new GroupView(this.app, {group: group});
+
+ // number of groups
+ var count = self.chart.groups.length;
+
+ // add new tab
+ this.tabs.add({
+ id : group.id,
+ $el : group_view.$el,
+ ondel : function() {
+ self.chart.groups.remove(group.id);
+ }
+ });
+
+ // update titles
+ this._refreshGroupKey();
+ },
+
+ // remove group
+ _removeGroup: function(group) {
+ this.tabs.del(group.id);
+
+ // update titles
+ this._refreshGroupKey();
+ },
+
+ // remove group
+ _removeAllGroups: function(group) {
+ this.tabs.delRemovable();
+ },
+
+ // reset
+ _resetChart: function() {
+ // reset chart details
+ this.chart.set('id', Utils.uuid());
+ this.chart.set('type', 'bardiagram');
+ this.chart.set('dataset_id', this.app.options.config.dataset_id);
+ this.chart.set('title', 'New Chart');
+
+ // reset back button
+ this.portlet.hideOperation('back');
+ },
+
+ // create chart
+ _saveChart: function() {
+ // update chart data
+ this.chart.set({
+ type : this.table.value(),
+ title : this.title.value(),
+ date : Utils.time()
+ });
+
+ // ensure that data group is available
+ if (this.chart.groups.length == 0) {
+ this._addGroupModel();
+ }
+
+ // trigger redraw
+ this.chart.trigger('redraw');
+
+ // save
+ this.app.storage.save();
+ }
+});
+
+});
\ No newline at end of file
diff -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 -r fa0968cfe3c3fec5869168bd7dd68829024f1ec3 config/plugins/visualizations/charts/static/views/viewer.js
--- /dev/null
+++ b/config/plugins/visualizations/charts/static/views/viewer.js
@@ -0,0 +1,106 @@
+// dependencies
+define(['utils/utils', 'plugin/library/ui', 'mvc/ui/ui-portlet',
+ 'plugin/models/group', 'plugin/views/viewport',],
+ function(Utils, Ui, Portlet, Group, ViewportView) {
+
+// widget
+return Backbone.View.extend(
+{
+ // initialize
+ initialize: function(app, options)
+ {
+ // link app
+ this.app = app;
+
+ // link chart
+ this.chart = this.app.chart;
+
+ // create viewport
+ this.viewport_view = new ViewportView(app);
+
+ // link this
+ var self = this;
+
+ // create portlet
+ this.portlet = new Portlet.View({
+ icon : 'fa-bar-chart-o',
+ title: 'Viewport',
+ operations: {
+ edit_button: new Ui.ButtonIcon({
+ icon : 'fa-gear',
+ tooltip : 'Customize Chart',
+ title : 'Customize',
+ onclick : function() {
+ // attempt to load chart editor
+ self._wait (self.app.chart, function() {
+ self.app.go('editor');
+ });
+ }
+ })
+
+ }
+ });
+
+ // append view port
+ this.portlet.append(this.viewport_view.$el);
+
+ // set element
+ this.setElement(this.portlet.$el);
+
+ // events
+ var self = this;
+ this.chart.on('change:title', function() {
+ self._refreshTitle();
+ });
+ },
+
+ // show
+ show: function() {
+ // show element
+ this.$el.show();
+
+ // trigger resize to refresh d3 element
+ $(window).trigger('resize');
+ },
+
+ // hide
+ hide: function() {
+ this.$el.hide();
+ },
+
+ // refresh title
+ _refreshTitle: function() {
+ var title = this.chart.get('title');
+ if (title) {
+ title = ' - ' + title;
+ }
+ this.portlet.title('Charts' + title);
+ },
+
+ // wait for chart to be ready
+ _wait: function(chart, callback) {
+ // get chart
+ if (chart.ready()) {
+ callback();
+ } else {
+ // show modal
+ var self = this;
+ this.app.modal.show({
+ title : 'Please wait!',
+ body : 'Your chart is currently being processed. Please wait...',
+ buttons : {
+ 'Close' : function() {self.app.modal.hide();},
+ 'Retry' : function() {
+ // hide modal
+ self.app.modal.hide();
+
+ // retry
+ setTimeout(function() { self._wait(chart, callback); }, self.app.config.get('query_timeout'));
+ }
+ }
+ });
+ }
+ }
+});
+
+});
\ No newline at end of file
diff -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 -r fa0968cfe3c3fec5869168bd7dd68829024f1ec3 config/plugins/visualizations/charts/static/views/viewport.js
--- a/config/plugins/visualizations/charts/static/views/viewport.js
+++ b/config/plugins/visualizations/charts/static/views/viewport.js
@@ -5,14 +5,8 @@
// widget
return Backbone.View.extend(
{
- // list
- list: {},
-
- // options
- optionsDefault :
- {
- height : 300
- },
+ // height
+ height : 300,
// initialize
initialize: function(app, options)
@@ -20,117 +14,63 @@
// link app
this.app = app;
+ // link chart
+ this.chart = this.app.chart;
+
// link options
this.options = Utils.merge(options, this.optionsDefault);
- // add table to portlet
- this.portlet = new Portlet.View({
- title : 'title',
- height : this.options.height,
- overflow : 'hidden'
- });
-
- // set this element
- this.setElement(this.portlet.$el);
+ // create element
+ this.setElement($(this._template()));
// events
var self = this;
-
- // remove
- this.app.charts.on('remove', function(chart) {
- self._removeChart(chart.id);
- });
-
- // redraw
- this.app.charts.on('redraw', function(chart) {
- self._drawChart(chart);
+ this.chart.on('redraw', function() {
+ self._draw(self.chart);
});
},
// show
- showChart: function(chart_id) {
- // show
- this.show();
-
- // hide all
- this.hideCharts();
-
- // identify selected item from list
- var item = this.list[chart_id];
- if (item) {
- // get chart
- var chart = this.app.charts.get(chart_id);
-
- // update portlet
- this.portlet.title(chart.get('title'));
-
- // show selected chart
- item.$el.show();
-
- // this trigger d3 update events
- $(window).trigger('resize');
- }
- },
-
- // hide charts
- hideCharts: function() {
- this.$el.find('.item').hide();
- },
-
- // show
show: function() {
- $('.tooltip').hide();
this.$el.show();
},
// hide
hide: function() {
- $('.tooltip').hide();
this.$el.hide();
},
// add
- _drawChart: function(chart) {
+ _draw: function(chart) {
// link this
var self = this;
// check
if (!chart.ready()) {
- self.app.log('viewport:_drawChart()', 'Invalid attempt to draw chart before completion.');
+ this.app.log('viewport:_drawChart()', 'Invalid attempt to draw chart before completion.');
return;
}
-
- // backup chart details
- var chart_id = chart.id;
-
- // make sure that svg does not exist already
- this._removeChart(chart_id);
-
- // create id
- var id = '#' + chart_id;
- // create element
- var $chart_el = $(this._template({id: id}));
+ // clear svg
+ if (this.svg) {
+ this.svg.remove();
+ }
- // add to portlet
- this.portlet.append($chart_el);
+ // create
+ this.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+ this.svg.setAttribute('height', this.height);
+ this.$el.append(this.svg);
// find svg element
- var svg = d3.select($chart_el.find('svg')[0]);
-
- // add chart to list
- this.list[chart_id] = {
- svg : svg,
- $el : $chart_el
- }
-
+ this.svg = d3.select(this.$el.find('svg')[0]);
+
// clear all previous handlers (including redraw listeners)
chart.off('change:state');
// link status handler
chart.on('change:state', function() {
// get info element
- var $info = $chart_el.find('#info');
+ var $info = self.$el.find('#info');
// get icon
var $icon = $info.find('#icon');
@@ -168,7 +108,7 @@
var self = this;
require(['plugin/charts/' + chart_type + '/' + chart_type], function(ChartView) {
// create chart
- var view = new ChartView(self.app, {svg : svg});
+ var view = new ChartView(self.app, {svg : self.svg});
// request data
if (chart_settings.execute) {
@@ -181,31 +121,18 @@
});
},
- // remove
- _removeChart: function(id) {
- var item = this.list[id];
- if (item) {
- // remove svg element
- item.svg.remove();
-
- // find div element (if any)
- item.$el.remove();
- }
- },
-
// template
- _template: function(options) {
- return '<div id="' + options.id.substr(1) + '" class="item">' +
- '<span id="info">' +
+ _template: function() {
+ return '<div>' +
+ '<div id="info" style="text-align: center; margin-top: 20px;">' +
'<span id="icon" style="font-size: 1.2em; display: inline-block;"/>' +
'<span id="text" style="position: relative; margin-left: 5px; top: -1px; font-size: 1.0em;"/>' +
- '</span>' +
- '<svg style="height: auto;"/>' +
+ '</div>' +
'</div>';
},
// create default chart request
- _defaultRequestString : function(chart) {
+ _defaultRequestString: function(chart) {
// get chart settings
var chart_settings = this.app.types.get(chart.get('type'));
@@ -226,7 +153,7 @@
},
// create default chart request
- _defaultSettingsString : function(chart) {
+ _defaultSettingsString: function(chart) {
// configure settings
var settings_string = '';
@@ -241,7 +168,7 @@
},
// create default chart request
- _defaultRequestDictionary : function(chart) {
+ _defaultRequestDictionary: function(chart) {
// get chart settings
var chart_settings = this.app.types.get(chart.get('type'));
This diff is so big that we needed to truncate the remainder.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: Charts: Save/read from backend
by commits-noreply@bitbucket.org 22 Mar '14
by commits-noreply@bitbucket.org 22 Mar '14
22 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/e7dfb71eeb79/
Changeset: e7dfb71eeb79
User: guerler
Date: 2014-03-22 18:38:48
Summary: Charts: Save/read from backend
Affected #: 8 files
diff -r dec159841d670560582aadc1327bec0673f7003a -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 config/plugins/visualizations/charts/static/app.js
--- a/config/plugins/visualizations/charts/static/app.js
+++ b/config/plugins/visualizations/charts/static/app.js
@@ -32,7 +32,7 @@
// create chart models
this.types = new Types();
this.chart = new Chart();
- this.charts = new Charts();
+ this.charts = new Charts(null, this);
// create dataset handler
this.datasets = new Datasets(this);
@@ -59,9 +59,6 @@
this.setElement(this.portlet);
}
- // start with chart view
- this.go('chart_view');
-
// events
var self = this;
this.config.on('change:title', function() {
@@ -70,6 +67,16 @@
// render
this.render();
+
+ // load charts
+ this.charts.load();
+
+ // start with chart view
+ if (this.charts.length == 0) {
+ this.go('chart_view');
+ } else {
+ this.go('charts_view');
+ }
},
// loads a view and makes sure that all others are hidden
diff -r dec159841d670560582aadc1327bec0673f7003a -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 config/plugins/visualizations/charts/static/build-app.js
--- a/config/plugins/visualizations/charts/static/build-app.js
+++ b/config/plugins/visualizations/charts/static/build-app.js
@@ -3,4 +3,4 @@
// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore may be freely distributed under the MIT license.
-(function(){var e=this,t=e._,n={},r=Array.prototype,i=Object.prototype,s=Function.prototype,o=r.push,u=r.slice,a=r.concat,f=i.toString,l=i.hasOwnProperty,c=r.forEach,h=r.map,p=r.reduce,d=r.reduceRight,v=r.filter,m=r.every,g=r.some,y=r.indexOf,b=r.lastIndexOf,w=Array.isArray,E=Object.keys,S=s.bind,x=function(e){if(e instanceof x)return e;if(!(this instanceof x))return new x(e);this._wrapped=e};typeof exports!="undefined"?(typeof module!="undefined"&&module.exports&&(exports=module.exports=x),exports._=x):e._=x,x.VERSION="1.4.4";var T=x.each=x.forEach=function(e,t,r){if(e==null)return;if(c&&e.forEach===c)e.forEach(t,r);else if(e.length===+e.length){for(var i=0,s=e.length;i<s;i++)if(t.call(r,e[i],i,e)===n)return}else for(var o in e)if(x.has(e,o)&&t.call(r,e[o],o,e)===n)return};x.map=x.collect=function(e,t,n){var r=[];return e==null?r:h&&e.map===h?e.map(t,n):(T(e,function(e,i,s){r.push(t.call(n,e,i,s))}),r)};var N="Reduce of empty array with no initial value";x.reduce=x.foldl=x.inject=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(p&&e.reduce===p)return r&&(t=x.bind(t,r)),i?e.reduce(t,n):e.reduce(t);T(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError(N);return n},x.reduceRight=x.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(d&&e.reduceRight===d)return r&&(t=x.bind(t,r)),i?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=x.keys(e);s=o.length}T(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError(N);return n},x.find=x.detect=function(e,t,n){var r;return C(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},x.filter=x.select=function(e,t,n){var r=[];return e==null?r:v&&e.filter===v?e.filter(t,n):(T(e,function(e,i,s){t.call(n,e,i,s)&&r.push(e)}),r)},x.reject=function(e,t,n){return x.filter(e,function(e,r,i){return!t.call(n,e,r,i)},n)},x.every=x.all=function(e,t,r){t||(t=x.identity);var i=!0;return e==null?i:m&&e.every===m?e.every(t,r):(T(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var C=x.some=x.any=function(e,t,r){t||(t=x.identity);var i=!1;return e==null?i:g&&e.some===g?e.some(t,r):(T(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};x.contains=x.include=function(e,t){return e==null?!1:y&&e.indexOf===y?e.indexOf(t)!=-1:C(e,function(e){return e===t})},x.invoke=function(e,t){var n=u.call(arguments,2),r=x.isFunction(t);return x.map(e,function(e){return(r?t:e[t]).apply(e,n)})},x.pluck=function(e,t){return x.map(e,function(e){return e[t]})},x.where=function(e,t,n){return x.isEmpty(t)?n?void 0:[]:x[n?"find":"filter"](e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},x.findWhere=function(e,t){return x.where(e,t,!0)},x.max=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&x.isEmpty(e))return-Infinity;var r={computed:-Infinity,value:-Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},x.min=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&x.isEmpty(e))return Infinity;var r={computed:Infinity,value:Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o<r.computed&&(r={value:e,computed:o})}),r.value},x.shuffle=function(e){var t,n=0,r=[];return T(e,function(e){t=x.random(n++),r[n-1]=r[t],r[t]=e}),r};var k=function(e){return x.isFunction(e)?e:function(t){return t[e]}};x.sortBy=function(e,t,n){var r=k(t);return x.pluck(x.map(e,function(e,t,i){return{value:e,index:t,criteria:r.call(n,e,t,i)}}).sort(function(e,t){var n=e.criteria,r=t.criteria;if(n!==r){if(n>r||n===void 0)return 1;if(n<r||r===void 0)return-1}return e.index<t.index?-1:1}),"value")};var L=function(e,t,n,r){var i={},s=k(t==null?x.identity:t);return T(e,function(t,o){var u=s.call(n,t,o,e);r(i,u,t)}),i};x.groupBy=function(e,t,n){return L(e,t,n,function(e,t,n){(x.has(e,t)?e[t]:e[t]=[]).push(n)})},x.countBy=function(e,t,n){return L(e,t,n,function(e,t){x.has(e,t)||(e[t]=0),e[t]++})},x.sortedIndex=function(e,t,n,r){n=n==null?x.identity:k(n);var i=n.call(r,t),s=0,o=e.length;while(s<o){var u=s+o>>>1;n.call(r,e[u])<i?s=u+1:o=u}return s},x.toArray=function(e){return e?x.isArray(e)?u.call(e):e.length===+e.length?x.map(e,x.identity):x.values(e):[]},x.size=function(e){return e==null?0:e.length===+e.length?e.length:x.keys(e).length},x.first=x.head=x.take=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,0,t):e[0]},x.initial=function(e,t,n){return u.call(e,0,e.length-(t==null||n?1:t))},x.last=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,Math.max(e.length-t,0)):e[e.length-1]},x.rest=x.tail=x.drop=function(e,t,n){return u.call(e,t==null||n?1:t)},x.compact=function(e){return x.filter(e,x.identity)};var A=function(e,t,n){return T(e,function(e){x.isArray(e)?t?o.apply(n,e):A(e,t,n):n.push(e)}),n};x.flatten=function(e,t){return A(e,t,[])},x.without=function(e){return x.difference(e,u.call(arguments,1))},x.uniq=x.unique=function(e,t,n,r){x.isFunction(t)&&(r=n,n=t,t=!1);var i=n?x.map(e,n,r):e,s=[],o=[];return T(i,function(n,r){if(t?!r||o[o.length-1]!==n:!x.contains(o,n))o.push(n),s.push(e[r])}),s},x.union=function(){return x.uniq(a.apply(r,arguments))},x.intersection=function(e){var t=u.call(arguments,1);return x.filter(x.uniq(e),function(e){return x.every(t,function(t){return x.indexOf(t,e)>=0})})},x.difference=function(e){var t=a.apply(r,u.call(arguments,1));return x.filter(e,function(e){return!x.contains(t,e)})},x.zip=function(){var e=u.call(arguments),t=x.max(x.pluck(e,"length")),n=new Array(t);for(var r=0;r<t;r++)n[r]=x.pluck(e,""+r);return n},x.unzip=function(e){var t=[];return x.each(e,function(e,n){x.each(e,function(e,r){t.length<=r&&(t[r]=[]),t[r][n]=e})}),t},x.object=function(e,t){if(e==null)return{};var n={};for(var r=0,i=e.length;r<i;r++)t?n[e[r]]=t[r]:n[e[r][0]]=e[r][1];return n},x.indexOf=function(e,t,n){if(e==null)return-1;var r=0,i=e.length;if(n){if(typeof n!="number")return r=x.sortedIndex(e,t),e[r]===t?r:-1;r=n<0?Math.max(0,i+n):n}if(y&&e.indexOf===y)return e.indexOf(t,n);for(;r<i;r++)if(e[r]===t)return r;return-1},x.lastIndexOf=function(e,t,n){if(e==null)return-1;var r=n!=null;if(b&&e.lastIndexOf===b)return r?e.lastIndexOf(t,n):e.lastIndexOf(t);var i=r?n:e.length;while(i--)if(e[i]===t)return i;return-1},x.range=function(e,t,n){arguments.length<=1&&(t=e||0,e=0),n=arguments[2]||1;var r=Math.max(Math.ceil((t-e)/n),0),i=0,s=new Array(r);while(i<r)s[i++]=e,e+=n;return s};var O=function(){};x.bind=function(e,t){var n,r;if(e.bind===S&&S)return S.apply(e,u.call(arguments,1));if(!x.isFunction(e))throw new TypeError;return n=u.call(arguments,2),r=function(){if(this instanceof r){O.prototype=e.prototype;var i=new O;O.prototype=null;var s=e.apply(i,n.concat(u.call(arguments)));return Object(s)===s?s:i}return e.apply(t,n.concat(u.call(arguments)))}},x.partial=function(e){var t=u.call(arguments,1);return function(){return e.apply(this,t.concat(u.call(arguments)))}},x.bindAll=function(e){var t=u.call(arguments,1);if(t.length===0)throw new Error("bindAll must be passed function names");return T(t,function(t){e[t]=x.bind(e[t],e)}),e},x.memoize=function(e,t){var n={};return t||(t=x.identity),function(){var r=t.apply(this,arguments);return x.has(n,r)?n[r]:n[r]=e.apply(this,arguments)}},x.delay=function(e,t){var n=u.call(arguments,2);return setTimeout(function(){return e.apply(null,n)},t)},x.defer=function(e){return x.delay.apply(x,[e,1].concat(u.call(arguments,1)))},x.throttle=function(e,t,n){var r,i,s,o,u=0,a=function(){u=new Date,s=null,o=e.apply(r,i)};return function(){var f=new Date;!u&&n===!1&&(u=f);var l=t-(f-u);return r=this,i=arguments,l<=0?(clearTimeout(s),s=null,u=f,o=e.apply(r,i)):s||(s=setTimeout(a,l)),o}},x.debounce=function(e,t,n){var r,i;return function(){var s=this,o=arguments,u=function(){r=null,n||(i=e.apply(s,o))},a=n&&!r;return clearTimeout(r),r=setTimeout(u,t),a&&(i=e.apply(s,o)),i}},x.once=function(e){var t=!1,n;return function(){return t?n:(t=!0,n=e.apply(this,arguments),e=null,n)}},x.wrap=function(e,t){return function(){var n=[e];return o.apply(n,arguments),t.apply(this,n)}},x.compose=function(){var e=arguments;return function(){var t=arguments;for(var n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},x.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},x.keys=E||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)x.has(e,n)&&t.push(n);return t},x.values=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push(e[n]);return t},x.pairs=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push([n,e[n]]);return t},x.invert=function(e){var t={};for(var n in e)x.has(e,n)&&(t[e[n]]=n);return t},x.functions=x.methods=function(e){var t=[];for(var n in e)x.isFunction(e[n])&&t.push(n);return t.sort()},x.extend=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]=t[n]}),e},x.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return T(n,function(n){n in e&&(t[n]=e[n])}),t},x.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)x.contains(n,i)||(t[i]=e[i]);return t},x.defaults=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]===void 0&&(e[n]=t[n])}),e},x.clone=function(e){return x.isObject(e)?x.isArray(e)?e.slice():x.extend({},e):e},x.tap=function(e,t){return t(e),e};var M=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof x&&(e=e._wrapped),t instanceof x&&(t=t._wrapped);var i=f.call(e);if(i!=f.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=M(e[o],t[o],n,r)))break}else{var a=e.constructor,l=t.constructor;if(a!==l&&!(x.isFunction(a)&&a instanceof a&&x.isFunction(l)&&l instanceof l))return!1;for(var c in e)if(x.has(e,c)){o++;if(!(u=x.has(t,c)&&M(e[c],t[c],n,r)))break}if(u){for(c in t)if(x.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};x.isEqual=function(e,t){return M(e,t,[],[])},x.isEmpty=function(e){if(e==null)return!0;if(x.isArray(e)||x.isString(e))return e.length===0;for(var t in e)if(x.has(e,t))return!1;return!0},x.isElement=function(e){return!!e&&e.nodeType===1},x.isArray=w||function(e){return f.call(e)=="[object Array]"},x.isObject=function(e){return e===Object(e)},T(["Arguments","Function","String","Number","Date","RegExp"],function(e){x["is"+e]=function(t){return f.call(t)=="[object "+e+"]"}}),x.isArguments(arguments)||(x.isArguments=function(e){return!!e&&!!x.has(e,"callee")}),typeof /./!="function"&&(x.isFunction=function(e){return typeof e=="function"}),x.isFinite=function(e){return isFinite(e)&&!isNaN(parseFloat(e))},x.isNaN=function(e){return x.isNumber(e)&&e!=+e},x.isBoolean=function(e){return e===!0||e===!1||f.call(e)=="[object Boolean]"},x.isNull=function(e){return e===null},x.isUndefined=function(e){return e===void 0},x.has=function(e,t){return l.call(e,t)},x.noConflict=function(){return e._=t,this},x.identity=function(e){return e},x.times=function(e,t,n){var r=Array(e);for(var i=0;i<e;i++)r[i]=t.call(n,i);return r},x.random=function(e,t){return t==null&&(t=e,e=0),e+Math.floor(Math.random()*(t-e+1))};var _={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};_.unescape=x.invert(_.escape);var D={escape:new RegExp("["+x.keys(_.escape).join("")+"]","g"),unescape:new RegExp("("+x.keys(_.unescape).join("|")+")","g")};x.each(["escape","unescape"],function(e){x[e]=function(t){return t==null?"":(""+t).replace(D[e],function(t){return _[e][t]})}}),x.result=function(e,t){if(e==null)return void 0;var n=e[t];return x.isFunction(n)?n.call(e):n},x.mixin=function(e){T(x.functions(e),function(t){var n=x[t]=e[t];x.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),F.call(this,n.apply(x,e))}})};var P=0;x.uniqueId=function(e){var t=++P+"";return e?e+t:t},x.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var H=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},j=/\\|'|\r|\n|\t|\u2028|\u2029/g;x.template=function(e,t,n){var r;n=x.defaults({},n,x.templateSettings);var i=new RegExp([(n.escape||H).source,(n.interpolate||H).source,(n.evaluate||H).source].join("|")+"|$","g"),s=0,o="__p+='";e.replace(i,function(t,n,r,i,u){return o+=e.slice(s,u).replace(j,function(e){return"\\"+B[e]}),n&&(o+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'"),r&&(o+="'+\n((__t=("+r+"))==null?'':__t)+\n'"),i&&(o+="';\n"+i+"\n__p+='"),s=u+t.length,t}),o+="';\n",n.variable||(o="with(obj||{}){\n"+o+"}\n"),o="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+o+"return __p;\n";try{r=new Function(n.variable||"obj","_",o)}catch(u){throw u.source=o,u}if(t)return r(t,x);var a=function(e){return r.call(this,e,x)};return a.source="function("+(n.variable||"obj")+"){\n"+o+"}",a},x.chain=function(e){return x(e).chain()};var F=function(e){return this._chain?x(e).chain():e};x.mixin(x),T(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];x.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],F.call(this,n)}}),T(["concat","join","slice"],function(e){var t=r[e];x.prototype[e]=function(){return F.call(this,t.apply(this._wrapped,arguments))}}),x.extend(x.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this),define("libs/underscore",function(e){return function(){var t,n;return t||e._}}(this)),define("utils/utils",["libs/underscore"],function(e){function t(e,t,r){n("GET",e,{},t,r)}function n(e,t,n,r,i){if(e=="GET"||e=="DELETE")t.indexOf("?")==-1?t+="?":t+="&",t+=$.param(n);var s=new XMLHttpRequest;s.open(e,t,!0),s.setRequestHeader("Accept","application/json"),s.setRequestHeader("Cache-Control","no-cache"),s.setRequestHeader("X-Requested-With","XMLHttpRequest"),s.setRequestHeader("Content-Type","application/json"),s.onloadend=function(){var e=s.status;try{response=jQuery.parseJSON(s.responseText)}catch(t){response=s.responseText}e==200?r&&r(response):i&&i(response)},e=="GET"||e=="DELETE"?s.send():s.send(JSON.stringify(n))}function r(e,t){var n=$('<div class="'+e+'"></div>');n.appendTo(":eq(0)");var r=n.css(t);return n.remove(),r}function i(e){$('link[href^="'+e+'"]').length||$('<link href="'+galaxy_config.root+e+'" rel="stylesheet">').appendTo("head")}function s(t,n){return t?e.defaults(t,n):n}function o(e,t){var n="";if(e>=1e11)e/=1e11,n="TB";else if(e>=1e8)e/=1e8,n="GB";else if(e>=1e5)e/=1e5,n="MB";else if(e>=100)e/=100,n="KB";else{if(!(e>0))return"<strong>-</strong>";e*=10,n="b"}var r=Math.round(e)/10;return t?r+" "+n:"<strong>"+r+"</strong> "+n}function u(){return(new Date).getTime().toString(36)}function a(e){var t=$("<p></p>");return t.append(e),t}function f(){var e=new Date,t=(e.getHours()<10?"0":"")+e.getHours(),n=(e.getMinutes()<10?"0":"")+e.getMinutes(),r=e.getDate()+"/"+(e.getMonth()+1)+"/"+e.getFullYear()+", "+t+":"+n;return r}return{cssLoadFile:i,cssGetAttribute:r,get:t,merge:s,bytesToString:o,uuid:u,time:f,wrap:a,request:n}}),define("mvc/ui/ui-modal",["utils/utils"],function(e){var t=Backbone.View.extend({elMain:"body",optionsDefault:{title:"ui-modal",body:"",backdrop:!0,height:null,width:null,closing_events:!1},buttonList:{},initialize:function(e){e&&this._create(e)},show:function(e){this.initialize(e),this.options.height?(this.$body.css("height",this.options.height),this.$body.css("overflow","hidden")):this.$body.css("max-height",$(window).height()/2),this.options.width&&this.$dialog.css("width",this.options.width),this.visible?this.$el.show():this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.visible=!1,this.$el.fadeOut("fast")},enableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!1)},disableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!0)},showButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).show()},hideButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).hide()},getButton:function(e){var t=this.buttonList[e];return this.$buttons.find("#"+t)},scrollTop:function(){return this.$body.scrollTop()},_create:function(e){var t=this;this.options=_.defaults(e,this.optionsDefault),this.options.body=="progress"&&(this.options.body=$('<div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width:100%"></div></div>')),this.$el&&(this.$el.remove(),$(document).off("keyup")),this.setElement(this._template(this.options.title)),this.$dialog=this.$el.find(".modal-dialog"),this.$body=this.$el.find(".modal-body"),this.$footer=this.$el.find(".modal-footer"),this.$buttons=this.$el.find(".buttons"),this.$backdrop=this.$el.find(".modal-backdrop"),this.$body.html(this.options.body),this.options.backdrop||this.$backdrop.removeClass("in");if(this.options.buttons){this.buttonList={};var n=0;$.each(this.options.buttons,function(e,r){var i="button-"+n++;t.$buttons.append($('<button id="'+i+'"></button>').text(e).click(r)).append(" "),t.buttonList[e]=i})}else this.$footer.hide();$(this.elMain).append($(this.el)),this.options.closing_events&&(this.options.buttons.Pause||$(document).on("keyup",function(e){e.keyCode==27&&t.hide()}),this.$el.find(".modal-backdrop").on("click",function(){t.hide()}))},_template:function(e){return'<div class="modal"><div class="modal-backdrop fade in" style="z-index: -1;"></div><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" style="display: none;">×</button><h4 class="title">'+e+"</h4>"+"</div>"+'<div class="modal-body" style="position: static;"></div>'+'<div class="modal-footer">'+'<div class="buttons" style="float: right;"></div>'+"</div>"+"</div"+"</div>"+"</div>"}});return{View:t}}),define("mvc/ui/ui-portlet",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,optionsDefault:{title:"",icon:"",buttons:null,body:null,height:null,operations:null,placement:"bottom",overflow:"auto"},$title:null,$content:null,$buttons:null,$operations:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$content=this.$el.find("#content"),this.$title=this.$el.find("#title-text"),this.options.height&&(this.$el.find("#body").css("height",this.options.height),this.$el.find("#content").css("overflow",this.options.overflow)),this.$buttons=$(this.el).find("#buttons");if(this.options.buttons){var n=this;$.each(this.options.buttons,function(e,t){t.$el.prop("id",e),n.$buttons.append(t.$el)})}else this.$buttons.remove();this.$operations=$(this.el).find("#operations");if(this.options.operations){var n=this;$.each(this.options.operations,function(e,t){t.$el.prop("id",e),n.$operations.append(t.$el)})}this.options.body&&this.append(this.options.body)},append:function(t){this.$content.append(e.wrap(t))},content:function(){return this.$content},show:function(){this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},enableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!1)},disableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!0)},hideOperation:function(e){this.$operations.find("#"+e).hide()},showOperation:function(e){this.$operations.find("#"+e).show()},setOperation:function(e,t){var n=this.$operations.find("#"+e);n.off("click"),n.on("click",t)},title:function(e){var t=this.$title;return e&&t.html(e),t.html()},_template:function(e){var t='<div class="toolForm portlet-view no-highlight">';if(e.title||e.icon)t+='<div id="title" class="toolFormTitle portlet-title"><div id="operations" class="portlet-operations"/><div style="overflow: hidden;">',e.icon&&(t+='<div class="portlet-title-icon fa '+e.icon+'"> </div>'),t+='<div id="title-text" class="portlet-title-text">'+e.title+"</div>",t+="</div></div>";return t+='<div id="body" class="toolFormBody portlet-body">',e.placement=="top"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+='<div id="content" class="portlet-content"/>',e.placement=="bottom"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+="</div></div>",t}});return{View:t}}),define("plugin/library/ui-select",["utils/utils"],function(e){var t=Backbone.View.extend({optionsDefault:{id:"",cls:"",empty:"No data available",visible:!0,wait:!1},selected:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$select=this.$el.find("#select"),this.$icon=this.$el.find("#icon"),this.selected=this.options.value;var n=this;this.options.onchange&&this.$select.on("change",function(){n.value(n.$select.val())}),this._refresh(),this.options.visible||this.hide(),this.options.wait?this.wait():this.show()},value:function(e){var t=this.selected;e!==undefined&&(this.selected=e,this.$select.val(e));var n=this.selected;return n&&n!=t&&this.options.onchange&&this.options.onchange(n),n},text:function(){return this.$select.find("option:selected").text()},show:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-caret-down"),this.$select.show(),this.$el.show()},hide:function(){this.$el.hide()},wait:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-spinner fa-spin"),this.$select.hide()},disabled:function(){return this.$select.is(":disabled")},enable:function(){this.$select.prop("disabled",!1)},disable:function(){this.$select.prop("disabled",!0)},add:function(e){this.$select.append(this._templateOption(e)),this._refresh()},del:function(e){this.$select.find("option[value="+e+"]").remove(),this.$select.trigger("change"),this._refresh()},update:function(e){this.$select.find("option").remove();for(var t in e)this.$select.append(this._templateOption(e[t]));!this.selected&&e.length>0&&this.value(e[0].value),this._refresh()},_refresh:function(){this.$select.find("option[value=null]").remove();var e=this.$select.find("option").length;e==0?(this.$select.append(this._templateOption({value:"null",label:this.options.empty})),this.disable()):(this.enable(),this.selected&&this.$select.val(this.selected))},_exists:function(e){return 0!=this.$select.find("option[value="+e+"]").length},_templateOption:function(e){return'<option value="'+e.value+'">'+e.label+"</option>"},_template:function(e){var t='<div id="'+e.id+'" class="styled-select">'+'<div class="button">'+'<i id="icon"/>'+"</div>"+'<select id="select" class="select '+e.cls+" "+e.id+'">';for(key in e.data){var n=e.data[key],r="";if(n.value==e.value||n.value=="")r="selected";t+='<option value="'+n.value+'" '+r+">"+n.label+"</option>"}return t+="</select></div>",t}});return{View:t}}),define("plugin/library/ui",["utils/utils","plugin/library/ui-select"],function(e,t){var n=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options))},title:function(e){this.$el.find("b").html(e)},_template:function(e){return"<label><b>"+e.title+"</b></label>"},value:function(){return options.title}}),r=Backbone.View.extend({optionsDefault:{id:null,title:"","float":"right",cls:"btn-default",icon:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t='<button id="'+e.id+'" type="submit" style="margin-right: 5px; float: '+e.float+';" type="button" class="btn '+e.cls+'">';return e.icon&&(t+='<i class="icon fa '+e.icon+'"></i> '),t+=e.title+"</button>",t}}),i=Backbone.View.extend({optionsDefault:{"float":"right",icon:"",tooltip:"",placement:"bottom",title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){return'<div><span class="fa '+e.icon+'" style="font-size: 1.2em;"/> '+e.title+"</div>"}}),s=Backbone.View.extend({optionsDefault:{title:"",id:null,"float":"right",cls:"icon-btn",icon:"",tooltip:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t="";e.title&&(t="width: auto;");var n='<div id="'+e.id+'" style="margin-right: 5px; float: '+e.float+"; "+t+'" class="'+e.cls+'">';return e.title?n+='<div style="margin-right: 5px; margin-left: 5px;"><i class="icon fa '+e.icon+'"/> '+'<span style="position: relative; font-size: 0.8em; font-weight: normal; top: -1px;">'+e.title+"</span>"+"</div>":n+='<i class="icon fa '+e.icon+'"/>',n+="</div>",n}}),o=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick)},_template:function(e){return'<div><a href="javascript:void(0)">'+e.title+"</a></div>"}}),u=Backbone.View.extend({optionsDefault:{message:"",status:"info",persistent:!1},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement("<div></div>")},update:function(t){this.options=e.merge(t,this.optionsDefault);if(t.message!=""){this.$el.html(this._template(this.options)),this.$el.fadeIn();if(!t.persistent){var n=this;window.setTimeout(function(){n.$el.is(":visible")?n.$el.fadeOut():n.$el.hide()},3e3)}}else this.$el.fadeOut()},_template:function(e){return'<div class="alert alert-'+e.status+'" style="padding: 2px 2px 2px 10px;">'+e.message+"</div>"}}),a=Backbone.View.extend({optionsDefault:{onclick:null,searchword:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options));var n=this;this.options.onclick&&this.$el.on("submit",function(e){var t=n.$el.find("#search");n.options.onclick(t.val())})},_template:function(e){return'<div class="search"><form onsubmit="return false;"><input id="search" class="form-control input-sm" type="text" name="search" placeholder="Search..." value="'+e.searchword+'">'+'<button type="submit" class="btn search-btn">'+'<i class="fa fa-search"></i>'+"</button>"+"</form>"+"</div>"}}),f=Backbone.View.extend({optionsDefault:{title:"Unlabeled",body:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.body&&this.$el.find(".body").append(this.options.body)},_template:function(e){return'<div id="title" class="title">'+e.title+":"+"</div>"}}),l=Backbone.View.extend({optionsDefault:{id:"",title:"",target:"",href:"",onunload:null,onclick:null,visible:!0,icon:null,tag:""},$menu:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement($(this._template(this.options)));var n=$(this.el).find(".root"),r=this;n.on("click",function(e){e.preventDefault(),r.options.onclick&&r.options.onclick()}),this.options.visible||this.hide()},show:function(){$(this.el).show()},hide:function(){$(this.el).hide()},addMenu:function(t){var n={title:"",target:"",href:"",onclick:null,divider:!1,icon:null};n=e.merge(t,n),this.$menu||($(this.el).append(this._templateMenu()),this.$menu=$(this.el).find(".menu"));var r=$(this._templateMenuItem(n));r.on("click",function(e){e.preventDefault(),n.onclick&&n.onclick()}),this.$menu.append(r),n.divider&&this.$menu.append($(this._templateDivider()))},_templateMenuItem:function(e){var t='<li><a href="'+e.href+'" target="'+e.target+'">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),t+=" "+e.title+"</a>"+"</li>",t},_templateMenu:function(){return'<ul class="menu dropdown-menu pull-right" role="menu"></ul>'},_templateDivider:function(){return'<li class="divider"></li>'},_template:function(e){var t='<div id="'+e.id+'" class="button-menu btn-group">'+'<button type="button" class="root btn btn-default dropdown-toggle" data-toggle="dropdown">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),"</button></div>",t}}),c=Backbone.View.extend({optionsDefault:{value:"",type:"text",placeholder:"",disabled:!1,visible:!0},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.disabled&&this.$el.prop("disabled",!0),this.options.visible||this.$el.hide();var n=this;this.options.onchange&&this.$el.on("input",function(){n.options.onchange()})},value:function(e){return e!==undefined&&this.$el.val(e),this.$el.val()},_template:function(e){return'<input id="'+e.id+'" type="'+e.type+'" value="'+e.value+'" placeholder="'+e.placeholder+'" class="form-control">'}});return{Label:n,Button:r,Icon:i,ButtonIcon:s,Input:c,Anchor:o,Message:u,Searchbox:a,Title:f,Select:t,ButtonMenu:l}}),define("plugin/library/jobs",["utils/utils"],function(e){return Backbone.Model.extend({initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},submit:function(t,n,r,i){var s=this,o=t.id,u=t.get("type"),a=this.app.types.get(u);data={tool_id:"rkit",inputs:{input:{id:t.get("dataset_id"),src:"hda"},module:u,columns:r,settings:n}};var f=t.get("dataset_id_job");f&&e.request("PUT",config.root+"api/histories/"+t.get("history_id")+"/contents/"+f,{deleted:!0}),t.state("submit","Sending job request..."),e.request("POST",config.root+"api/tools",data,function(e){if(!e.outputs||e.outputs.length==0)t.state("failed","Job submission failed. No response.");else{Galaxy&&Galaxy.currHistoryPanel&&Galaxy.currHistoryPanel.refreshHdas();var n=e.outputs[0];t.state("queued","Job has been queued..."),t.set("dataset_id_job",n.id),s._loop(n.id,function(e){switch(e.state){case"ok":return t.state("success","Job completed successfully..."),i(e),!0;case"error":return t.state("failed","Job has failed. Please check the history for details."),!0;case"running":return t.state("running","Job is running..."),!1}})}},function(e){var n="";e&&e.message&&e.message.data&&e.message.data.input&&(n=e.message.data.input+"."),t.state("failed","This visualization requires the R-kit. Please make sure it is installed. "+n)})},_loop:function(t,n){var r=this;e.request("GET",config.root+"api/jobs/"+t,{},function(e){n(e)||setTimeout(function(){r._loop(t,n)},r.app.config.get("query_timeout"))})}})}),define("plugin/library/datasets",["utils/utils"],function(e){return Backbone.Collection.extend({list:{},initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},request:function(t,n,r){var i=this;if(t.groups)this._fetch(t,n);else{var s=this.list[t.id];if(s){n(s);return}e.request("GET",config.root+"api/datasets/"+t.id,{},function(e){switch(e.state){case"error":r&&r(e);break;default:i.list[t.id]=e,n(e)}})}},_fetch:function(t,n){var r=t.start?t.start:0,i=Math.abs(t.end-t.start),s=this.app.config.get("query_limit");if(!i||i>s)i=s;var o="",u={},a=0;for(var f in t.groups){var l=t.groups[f];for(var c in l.columns){var h=l.columns[c];o+=h+",",u[h]=a,a++}}if(a==0){n({});return}o=o.substring(0,o.length-1);var p=t.groups.slice(0);for(var f in p)p[f].values=[];var d=this;e.request("GET",config.root+"api/datasets/"+t.id,{data_type:"raw_data",provider:"dataset-column",limit:i,offset:r,indeces:o},function(e){for(var i in e.data){var s=e.data[i];for(var o in t.groups){var a=t.groups[o],f={x:parseInt(i)+r};for(var l in a.columns){var c=a.columns[l],h=u[c],d=s[h];if(isNaN(d)||!d)d=0;f[l]=d}p[o].values.push(f)}}n(p)})}})}),define("plugin/library/ui-table",["utils/utils"],function(e){var t=Backbone.View.extend({row:null,row_count:0,optionsDefault:{content:"No content available.",onchange:null,ondblclick:null,onconfirm:null},events:{click:"_onclick",dblclick:"_ondblclick"},first:!0,initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(t));this.$thead=n.find("thead"),this.$tbody=n.find("tbody"),this.$tmessage=n.find("tmessage"),this.setElement(n),this.row=$("<tr></tr>")},addHeader:function(e){var t=$("<th></th>");t.append(e),this.row.append(t)},appendHeader:function(){this.$thead.append(this.row),this.row=$("<tr></tr>")},add:function(e,t){var n=$("<td></td>");t&&n.css("width",t),n.append(e),this.row.append(n)},append:function(e){this._commit(e)},prepend:function(e){this._commit(e,!0)},remove:function(e){var t=this.$tbody.find("#"+e);t.length>0&&(t.remove(),this.row_count--,this._refresh())},removeAll:function(){this.$tbody.html(""),this.row_count=0,this._refresh()},value:function(e){this.before=this.$tbody.find(".current").attr("id"),e!==undefined&&(this.$tbody.find("tr").removeClass("current"),e&&this.$tbody.find("#"+e).addClass("current"));var t=this.$tbody.find(".current").attr("id");return t===undefined?null:(t!=this.before&&this.options.onchange&&this.options.onchange(e),t)},size:function(){return this.$tbody.find("tr").length},_commit:function(e,t){this.remove(e),this.row.attr("id",e),t?this.$tbody.prepend(this.row):this.$tbody.append(this.row),this.row=$("<tr></tr>"),this.row_count++,this._refresh()},_onclick:function(e){var t=this.value(),n=$(e.target).closest("tr").attr("id");n&&t!=n&&(this.options.onconfirm?this.options.onconfirm(n):this.value(n))},_ondblclick:function(e){var t=this.value();t&&this.options.ondblclick&&this.options.ondblclick(t)},_refresh:function(){this.row_count==0?this.$tmessage.show():this.$tmessage.hide()},_template:function(e){return'<div><table class="grid"><thead></thead><tbody style="cursor: pointer;"></tbody></table><tmessage>'+e.content+"</tmessage>"+"<div>"}});return{View:t}}),define("plugin/models/group",[],function(){return Backbone.Model.extend({defaults:{key:"Data label",date:""},reset:function(){this.clear({silent:!0}).set(this.defaults),this.trigger("reset",this)}})}),define("plugin/views/viewport",["mvc/ui/ui-portlet","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({list:{},optionsDefault:{height:300},initialize:function(t,r){this.app=t,this.options=n.merge(r,this.optionsDefault),this.portlet=new e.View({title:"title",height:this.options.height,overflow:"hidden"}),this.setElement(this.portlet.$el);var i=this;this.app.charts.on("remove",function(e){i._removeChart(e.id)}),this.app.charts.on("redraw",function(e){e.ready()?i._refreshChart(e):e.on("change:state",function(){e.ready()&&i._refreshChart(e)})})},showChart:function(e){this.show(),this.hideCharts();var t=this.list[e];if(t){var n=self.app.charts.get(e);this.portlet.title(n.get("title")),t.$el.show(),$(window).trigger("resize")}},hideCharts:function(){this.$el.find(".item").hide()},show:function(){$(".tooltip").hide(),this.$el.show()},hide:function(){$(".tooltip").hide(),this.$el.hide()},_refreshChart:function(e){var t=this;if(!e.ready()){t.app.log("viewport:_refreshChart()","Invalid attempt to refresh chart before completion.");return}var n=e.id;this._removeChart(n);var r="#"+n,i=$(this._template({id:r}));this.portlet.append(i);var s=d3.select(r+" svg");this.list[n]={svg:s,$el:i},this.showChart(n),e.off("change:state"),e.on("change:state",function(){var t=i.find("#info"),n=t.find("#icon");n.removeClass(),t.show(),t.find("#text").html(e.get("state_info"));var r=e.get("state");switch(r){case"ok":t.hide();break;case"failed":n.addClass("fa fa-warning");break;default:n.addClass("fa fa-spinner fa-spin")}}),e.state("wait","Please wait...");var o=e.get("type"),u=this.app.types.get(o),t=this;require(["plugin/charts/"+o+"/"+o],function(n){var r=new n(t.app,{svg:s});u.execute?t.app.jobs.submit(e,t._defaultSettingsString(e),t._defaultRequestString(e),function(){r.draw(e,t._defaultRequestDictionary(e))}):r.draw(e,t._defaultRequestDictionary(e))})},_removeChart:function(e){var t=this.list[e];t&&(t.svg.remove(),t.$el.remove())},_template:function(e){return'<div id="'+e.id.substr(1)+'" class="item">'+'<span id="info">'+'<span id="icon" style="font-size: 1.2em; display: inline-block;"/>'+'<span id="text" style="position: relative; margin-left: 5px; top: -1px; font-size: 1.0em;"/>'+"</span>"+'<svg style="height: auto;"/>'+"</div>"},_defaultRequestString:function(e){var t=this.app.types.get(e.get("type")),n="",r=0;return e.groups.each(function(e){for(var i in t.columns)n+=i+"_"+ ++r+":"+(parseInt(e.get(i))+1)+", "}),n.substring(0,n.length-2)},_defaultSettingsString:function(e){var t="";for(key in e.settings.attributes)t+=key+":"+e.settings.get(key)+", ";return t.substring(0,t.length-2)},_defaultRequestDictionary:function(e){var t=this.app.types.get(e.get("type")),n={id:e.get("dataset_id"),groups:[]},r=0;return e.groups.each(function(e){var i={};for(var s in t.columns)i[s]=e.get(s);n.groups.push({key:++r+":"+e.get("key"),columns:i})}),n}})}),define("plugin/views/charts",["mvc/ui/ui-portlet","plugin/library/ui-table","plugin/library/ui","utils/utils","plugin/models/group","plugin/views/viewport"],function(e,t,n,r,i,s){return Backbone.View.extend({initialize:function(i,o){this.app=i,this.viewport_view=new s(i),this.table=new t.View({content:"Add charts to this table.",ondblclick:function(e){u._showChartView(e)},onchange:function(e){var t=u.app.charts.get(e);u.app.config.set("title",t.get("title")),u.viewport_view.showChart(e)}});var u=this;this.portlet=new e.View({icon:"fa-list",title:"List of created charts:",height:100,operations:{"new":new n.ButtonIcon({icon:"fa-magic",tooltip:"Create a new Chart",title:"New",onclick:function(){u.app.go("chart_view"),u.app.chart.reset()}}),edit:new n.ButtonIcon({icon:"fa-gear",tooltip:"Customize this Chart",title:"Customize",onclick:function(){var e=u.table.value();if(!e)return;u._showChartView(e)}}),"delete":new n.ButtonIcon({icon:"fa-trash-o",tooltip:"Delete this Chart",title:"Delete",onclick:function(){var e=u.table.value();if(!e)return;var t=u.app.charts.get(e);u.app.modal.show({title:"Are you sure?",body:'The selected chart "'+t.get("title")+'" will be irreversibly deleted.',buttons:{Cancel:function(){u.app.modal.hide()},Delete:function(){u.app.modal.hide(),u.app.charts.remove(e)}}})}})}}),this.portlet.append(this.table.$el),this.app.options.config.widget||this.$el.append(this.portlet.$el),this.$el.append(r.wrap("")),this.$el.append(this.viewport_view.$el);var u=this;this.app.charts.on("add",function(e){u._addChart(e)}),this.app.charts.on("remove",function(e){u._removeChart(e)}),this.app.charts.on("change",function(e){u._changeChart(e)})},show:function(){this.$el.show()},hide:function(){$(".tooltip").hide(),this.$el.hide()},_addChart:function(e){var t=e.get("title");t==""&&(t="Untitled"),this.table.add(t);var n=this.app.types.get(e.get("type"));this.table.add(n.title),this.table.add("Last change: "+e.get("date")),this.table.prepend(e.get("id")),this.table.value(e.get("id"))},_removeChart:function(e){this.table.remove(e.id),this.app.charts.save(),this.table.size()==0?(this.app.go("chart_view"),this.app.chart.reset()):this.table.value(this.app.charts.last().id)},_changeChart:function(e){e.get("type")&&(this._addChart(e),this.table.value(e.id))},_showChartView:function(e){var t=this.app.charts.get(e);if(t.ready())this.app.go("chart_view"),this.app.chart.copy(t);else{var n=this;this.app.modal.show({title:"Please wait!",body:'The selected chart "'+t.get("title")+'" is currently being processed. Please wait...',buttons:{Close:function(){n.app.modal.hide()},Retry:function(){n.app.modal.hide(),n._showChartView(e)}}})}}})}),define("mvc/ui/ui-tabs",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,list:{},$nav:null,$content:null,first_tab:null,optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(this.options));this.$nav=n.find(".tab-navigation"),this.$content=n.find(".tab-content"),this.setElement(n),this.list={};var r=this;this.options.operations&&$.each(this.options.operations,function(e,t){t.$el.prop("id",e),r.$nav.find(".operations").append(t.$el)});if(this.options.onnew){var i=$(this._template_tab_new(this.options));this.$nav.append(i),i.tooltip({title:"Add a new tab",placement:"bottom",container:r.$el}),i.on("click",function(e){i.tooltip("hide"),r.options.onnew()})}},add:function(e){var t=e.id,n={$title:$(this._template_tab(e)),$content:$(this._template_tab_content(e)),removable:e.ondel?!0:!1};this.list[t]=n,this.options.onnew?this.$nav.find("#new-tab").before(n.$title):this.$nav.append(n.$title),n.$content.append(e.$el),this.$content.append(n.$content),_.size(this.list)==1&&(n.$title.addClass("active"),n.$content.addClass("active"),this.first_tab=t);if(e.ondel){var r=this,i=n.$title.find("#delete");i.tooltip({title:"Delete this tab",placement:"bottom",container:r.$el}),i.on("click",function(){return i.tooltip("destroy"),r.$el.find(".tooltip").remove(),e.ondel(),!1})}e.onclick&&n.$title.on("click",function(){e.onclick()})},del:function(e){var t=this.list[e];t.$title.remove(),t.$content.remove(),delete t,this.first_tab==e&&(this.first_tab=null),this.first_tab!=null&&this.show(this.first_tab)},delRemovable:function(){for(var e in this.list){var t=this.list[e];t.removable&&this.del(e)}},show:function(e){this.$el.fadeIn("fast"),this.visible=!0,e&&this.list[e].$title.find("a").tab("show")},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},hideOperation:function(e){this.$nav.find("#"+e).hide()},showOperation:function(e){this.$nav.find("#"+e).show()},setOperation:function(e,t){var n=this.$nav.find("#"+e);n.off("click"),n.on("click",t)},title:function(e,t){var n=this.list[e].$title.find("#text");return t&&n.html(t),n.html()},_template:function(e){return'<div class="tabbable tabs-left"><ul class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div class="tab-content"/></div>'},_template_tab_new:function(e){return'<li id="new-tab"><a href="javascript:void(0);"><i style="font-size: 0.8em; margin-right: 5px;" class="fa fa-plus-circle"/>'+e.title_new+"</a>"+"</li>"},_template_tab:function(e){var t='<li id="title-'+e.id+'">'+'<a title="" href="#tab-'+e.id+'" data-toggle="tab" data-original-title="">'+'<span id="text">'+e.title+"</span>";return e.ondel&&(t+='<i id="delete" style="font-size: 0.8em; margin-left: 5px; cursor: pointer;" class="fa fa-minus-circle"/>'),t+="</a></li>",t},_template_tab_content:function(e){return'<div id="tab-'+e.id+'" class="tab-pane"/>'}});return{View:t}}),define("plugin/models/groups",["plugin/models/group"],function(e){return Backbone.Collection.extend({model:e})});var Visualization=Backbone.Model.extend({defaults:{config:{}},urlRoot:function(){var e="/api/visualizations";return window.galaxy_config&&galaxy_config.root?galaxy_config.root+e:e},initialize:function(e){_.isObject(e.config)&&_.isObject(this.defaults.config)&&_.defaults(e.config,this.defaults.config),this._setUpListeners()},_setUpListeners:function(){},set:function(e,t){if(e==="config"){var n=this.get("config");_.isObject(n)&&(t=_.extend(_.clone(n),t))}return Backbone.Model.prototype.set.call(this,e,t),this},toString:function(){var e=this.get("id")||"";return this.get("title")&&(e+=":"+this.get("title")),"Visualization("+e+")"}}),VisualizationCollection=Backbone.Collection.extend({model:Visualization,url:function(){return galaxy_config.root+"api/visualizations"},initialize:function(e,t){t=t||{}},set:function(e,t){var n=this;e=_.map(e,function(e){var t=n.get(e.id);if(!t)return e;var r=t.toJSON();return _.extend(r,e),r}),Backbone.Collection.prototype.set.call(this,e,t)},toString:function(){return["VisualizationCollection(",[this.historyId,this.length].join(),")"].join("")}});define("mvc/visualization/visualization-model",function(){}),define("plugin/models/chart",["plugin/models/groups","mvc/visualization/visualization-model"],function(e){return Backbone.Model.extend({defaults:{id:null,title:"",type:"",date:null,state:"ok",state_info:""},initialize:function(t){this.groups=new e,this.settings=new Backbone.Model},reset:function(){this.clear({silent:!0}).set(this.defaults),this.groups.reset(),this.settings.clear(),this.trigger("reset",this)},copy:function(e){var t=this;t.clear({silent:!0}).set(this.defaults),t.set(e.attributes),t.settings=e.settings.clone(),t.groups.reset(),e.groups.each(function(e){t.groups.add(e.clone())}),t.trigger("change",t)},state:function(e,t){this.set("state_info",t),this.set("state",e)},ready:function(){return this.get("state")=="ok"||this.get("state")=="failed"}})}),define("plugin/views/group",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({columns:[],initialize:function(r,i){this.app=r;var s=this;this.chart=this.app.chart,this.group=i.group,this.group_key=new t.Input({placeholder:"Data label",onchange:function(){s.group.set("key",s.group_key.value())}}),this.table=new e.View({content:"No data column."});var o=$("<div/>");o.append(n.wrap((new t.Label({title:"Provide a label:"})).$el)),o.append(n.wrap(this.group_key.$el)),o.append(n.wrap((new t.Label({title:"Select columns:"})).$el)),o.append(n.wrap(this.table.$el)),this.setElement(o);var s=this;this.chart.on("change:dataset_id",function(){s._refreshTable()}),this.chart.on("change:type",function(){s._refreshTable()}),this.group.on("change:key",function(){s._refreshGroupKey()}),this.group.on("change",function(){s._refreshGroup()}),this._refreshTable(),this._refreshGroupKey(),this._refreshGroup()},_refreshTable:function(){var e=this.chart.get("dataset_id"),n=this.chart.get("type");if(!e||!n)return;var r=this,i=this.app.types.get(n);this.table.removeAll();var s={};for(var o in i.columns){var u=this.group.get(o);u||this.group.set(o,0);var a=i.columns[o],f=new t.Select.View({id:"select_"+o,gid:o,onchange:function(e){r.group.set(this.gid,e)},value:u,wait:!0});this.table.add(a.title,"25%"),this.table.add(f.$el),this.table.append(o),s[o]=f}this.app.datasets.request({id:e},function(e){r.columns=[];var t=e.metadata_column_types;for(var n in t)(t[n]=="int"||t[n]=="float")&&r.columns.push({label:"Column: "+(parseInt(n)+1)+" ["+t[n]+"]",value:n});for(var n in s)s[n].update(r.columns),s[n].show()})},_refreshGroup:function(){this.group.set("date",n.time())},_refreshGroupKey:function(){var e=this.group.get("key");e===undefined&&(e=""),this.group_key.value(e)}})}),define("plugin/library/ui-table-form",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){var r=Backbone.View.extend({initialize:function(r){this.table_title=new t.Label({title:r.title}),this.table=new e.View({content:r.content});var i=$("<div/>");i.append(n.wrap(this.table_title.$el)),i.append(n.wrap(this.table.$el)),this.setElement(i)},title:function(e){this.table_title.title(e)},update:function(e,t){this.table.removeAll();for(var n in e)this._add(n,e[n],t)},_add:function(e,n,r){var i=null,s=n.type;switch(s){case"text":i=new t.Input({placeholder:n.placeholder,onchange:function(){r.set(e,i.value())}});break;case"select":i=new t.Select.View({data:n.data,onchange:function(){r.set(e,i.value())}});break;case"slider":i=new t.Input({placeholder:n.placeholder,onchange:function(){r.set(e,i.value())}});break;case"separator":i=$("<div/>");break;default:console.log("ui-table-form:_add","Unknown setting type ("+n.type+")");return}if(s!="separator"){r.get(e)||r.set(e,n.init),i.value(r.get(e));var o=$("<div/>");o.append(i.$el),o.append('<div class="toolParamHelp" style="font-size: 0.9em;">'+n.info+"</div>"),this.table.add('<span style="white-space: nowrap;">'+n.title+"</span>","25%"),this.table.add(o)}else this.table.add('<h6 style="white-space: nowrap;">'+n.title+":<h6/>"),this.table.add($("<div/>"));this.table.append(e)}});return{View:r}}),define("plugin/views/settings",["plugin/library/ui","plugin/library/ui-table-form","utils/utils"],function(e,t,n){return Backbone.View.extend({initialize:function(e,n){this.app=e;var r=this;this.chart=this.app.chart,this.form=new t.View({title:"Chart options:",content:"This chart type does not provide any options."}),this.setElement(this.form.$el);var r=this;this.chart.on("change",function(){r._refreshTable()})},_refreshTable:function(){var e=this.chart.get("type");if(!e)return;var t=this.app.types.get(e);this.form.title(t.title+":"),this.form.update(t.settings,this.chart.settings)}})}),define("plugin/views/chart",["mvc/ui/ui-tabs","plugin/library/ui-table","plugin/library/ui","utils/utils","plugin/models/chart","plugin/models/group","plugin/views/group","plugin/views/settings"],function(e,t,n,r,i,s,o,u){return Backbone.View.extend({optionsDefault:{header:!0,content:"No content available."},initialize:function(i,s){this.app=i,this.chart=this.app.chart,this.options=r.merge(s,this.optionsDefault);var o=this;this.table=new t.View({header:!1,onconfirm:function(e){o.chart.groups.length>0?o.app.modal.show({title:"Switching to another chart type?",body:"If you continue your settings and selections will be cleared.",buttons:{Cancel:function(){o.app.modal.hide()},Continue:function(){o.app.modal.hide(),o.table.value(e)}}}):o.table.value(e)},onchange:function(e){o.chart.groups.reset(),o.chart.settings.clear(),o.chart.set({type:e})},ondblclick:function(e){o.tabs.show("settings")},content:"No chart types available"});var a=0,f=i.types.attributes;for(var l in f){var c=f[l];this.table.add(++a+"."),c.execute?this.table.add(c.title+" (requires processing)"):this.table.add(c.title),this.table.append(l)}this.tabs=new e.View({title_new:"Add Data",onnew:function(){var e=o._addGroupModel();o.tabs.show(e.id)},operations:{save:new n.ButtonIcon({icon:"fa-save",tooltip:"Draw Chart",title:"Draw",onclick:function(){o.app.go("charts_view"),o._saveChart()}}),back:new n.ButtonIcon({icon:"fa-caret-left",tooltip:"Return to Viewer",title:"Return",onclick:function(){o.app.go("charts_view")}})}}),this.title=new n.Input({placeholder:"Chart title",onchange:function(){o.app.config.set("title",o.title.value())}});var h=$("<div/>");h.append(r.wrap((new n.Label({title:"Provide a chart title:"})).$el)),h.append(r.wrap(this.title.$el)),h.append(r.wrap((new n.Label({title:"Select a chart type:"})).$el)),h.append(r.wrap(this.table.$el)),this.tabs.add({id:"main",title:"Start",$el:h}),this.settings=new u(this.app),this.tabs.add({id:"settings",title:"Configuration",$el:this.settings.$el}),this.setElement(this.tabs.$el),this.tabs.hideOperation("back");var o=this;this.chart.on("change:title",function(e){o.title.value(e.get("title")),o.app.config.set("title",e.get("title"))}),this.chart.on("change:type",function(e){o.table.value(e.get("type"))}),this.chart.on("reset",function(e){o._resetChart()}),this.app.charts.on("add",function(e){o.tabs.showOperation("back")}),this.app.charts.on("remove",function(e){o.app.charts.length==0&&o.tabs.hideOperation("back")}),this.app.charts.on("reset",function(e){o.tabs.hideOperation("back")}),this.app.chart.groups.on("add",function(e){o._addGroup(e)}),this.app.chart.groups.on("remove",function(e){o._removeGroup(e)}),this.app.chart.groups.on("reset",function(e){o._removeAllGroups()}),this.app.chart.groups.on("change:key",function(e){o._refreshGroupKey()}),this._resetChart()},show:function(){this.$el.show()},hide:function(){$(".tooltip").hide(),this.$el.hide()},_refreshGroupKey:function(){var e=this,t=0;this.chart.groups.each(function(n){var r=n.get("key","");r==""&&(r="Chart data"),e.tabs.title(n.id,++t+": "+r)})},_addGroupModel:function(){var e=new s({id:r.uuid()});return this.chart.groups.add(e),e},_addGroup:function(e){var t=this,n=new o(this.app,{group:e}),r=t.chart.groups.length;this.tabs.add({id:e.id,$el:n.$el,ondel:function(){t.chart.groups.remove(e.id)}}),this._refreshGroupKey()},_removeGroup:function(e){this.tabs.del(e.id),this._refreshGroupKey()},_removeAllGroups:function(e){this.tabs.delRemovable()},_resetChart:function(){this.chart.set("id",r.uuid()),this.chart.set("type","bardiagram"),this.chart.set("dataset_id",this.app.options.config.dataset_id),this.chart.set("title","New Chart")},_saveChart:function(){this.chart.set({type:this.table.value(),title:this.title.value(),date:r.time()}),this.chart.groups.length==0&&this._addGroupModel();var e=this.app.charts.get(this.chart.id);e?e.copy(this.chart):(e=this.chart.clone(),e.copy(this.chart),this.app.charts.add(e)),e.trigger("redraw",e),this.app.charts.save()}})}),define("plugin/models/config",[],function(){return Backbone.Model.extend({defaults:{query_limit:1e3,query_timeout:500,title:"Create a new chart"}})}),define("plugin/models/charts",["plugin/models/chart"],function(e){return Backbone.Collection.extend({model:e,save:function(){var e=new Visualization({type:"charts",config:{charts:[]}});e.save().fail(function(e,t,n){console.error(e,t,n),alert("Error loading data:\n"+e.responseText)})}})}),define("plugin/charts/_nvd3/config",[],function(){return{title:"",columns:{y:{title:"Values for y-axis"}},settings:{separator_label:{title:"X axis",type:"separator"},x_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"X-axis",placeholder:"Axis label"},x_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"f",data:[{label:"-- Do not show values --",value:"hide"},{label:"Float",value:"f"},{label:"Exponent",value:"e"},{label:"Integer",value:"d"},{label:"Percentage",value:"p"},{label:"Rounded",value:"r"},{label:"SI-prefix",value:"s"}]},x_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_tick:{title:"Y axis",type:"separator"},y_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"Y-axis",placeholder:"Axis label"},y_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"f",data:[{label:"-- Do not show values --",value:"hide"},{label:"Float",value:"f"},{label:"Exponent",value:"e"},{label:"Integer",value:"d"},{label:"Percentage",value:"p"},{label:"Rounded",value:"r"},{label:"SI-prefix",value:"s"}]},y_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_legend:{title:"Others",type:"separator"},show_legend:{title:"Show legend",info:"Would you like to add a legend?",type:"select",init:"true",data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]}}}}),define("plugin/charts/bardiagram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram"})}),define("plugin/charts/histogram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Histogram",execute:!0,columns:{y:{title:"Observations"}},settings:{x_axis_label:{init:"Breaks"},y_axis_label:{init:"Density"},y_axis_tick:{init:".3"}}})}),define("plugin/charts/horizontal/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram (horizontal)",settings:{x_axis_type:{init:"hide"}}})}),define("plugin/charts/line/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line chart"})}),define("plugin/charts/linewithfocus/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line with focus"})}),define("plugin/charts/piechart/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Pie chart"})}),define("plugin/charts/scatterplot/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Scatter plot",columns:{x:{title:"Values for x-axis"}}})}),define("plugin/charts/stackedarea/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Stacked area"})}),define("plugin/charts/types",["plugin/charts/bardiagram/config","plugin/charts/histogram/config","plugin/charts/horizontal/config","plugin/charts/line/config","plugin/charts/linewithfocus/config","plugin/charts/piechart/config","plugin/charts/scatterplot/config","plugin/charts/stackedarea/config"],function(e,t,n,r,i,s,o,u){return Backbone.Model.extend({defaults:{bardiagram:e,horizontal:n,histogram:t,line:r,linewithfocus:i,piechart:s,scatterplot:o,stackedarea:u}})}),define("plugin/app",["mvc/ui/ui-modal","mvc/ui/ui-portlet","plugin/library/ui","utils/utils","plugin/library/jobs","plugin/library/datasets","plugin/views/charts","plugin/views/chart","plugin/models/config","plugin/models/chart","plugin/models/charts","plugin/charts/types"],function(e,t,n,r,i,s,o,u,a,f,l,c){return Backbone.View.extend({initialize:function(n){this.options=n,Galaxy&&Galaxy.modal?this.modal=Galaxy.modal:this.modal=new e.View,this.config=new a,this.jobs=new i(this),this.types=new c,this.chart=new f,this.charts=new l,this.datasets=new s(this),this.charts_view=new o(this),this.chart_view=new u(this),this.options.config.widget?this.portlet=$("<div></div>"):this.portlet=new t.View({icon:"fa-bar-chart-o"}),this.portlet.append(this.charts_view.$el),this.portlet.append(this.chart_view.$el),this.options.config.widget?this.setElement(this.portlet):this.setElement(this.portlet.$el),this.go("chart_view");var r=this;this.config.on("change:title",function(){r._refreshTitle()}),this.render()},go:function(e){switch(e){case"chart_view":this.chart_view.show(),this.charts_view.hide();break;case"charts_view":this.chart_view.hide(),this.charts_view.show()}},render:function(){this._refreshTitle()},_refreshTitle:function(){var e=this.config.get("title");e&&(e=" - "+e),this.portlet.title("Charts"+e)},execute:function(e){},onunload:function(){},log:function(e,t){console.log(e+" "+t)}})});
\ No newline at end of file
+(function(){var e=this,t=e._,n={},r=Array.prototype,i=Object.prototype,s=Function.prototype,o=r.push,u=r.slice,a=r.concat,f=i.toString,l=i.hasOwnProperty,c=r.forEach,h=r.map,p=r.reduce,d=r.reduceRight,v=r.filter,m=r.every,g=r.some,y=r.indexOf,b=r.lastIndexOf,w=Array.isArray,E=Object.keys,S=s.bind,x=function(e){if(e instanceof x)return e;if(!(this instanceof x))return new x(e);this._wrapped=e};typeof exports!="undefined"?(typeof module!="undefined"&&module.exports&&(exports=module.exports=x),exports._=x):e._=x,x.VERSION="1.4.4";var T=x.each=x.forEach=function(e,t,r){if(e==null)return;if(c&&e.forEach===c)e.forEach(t,r);else if(e.length===+e.length){for(var i=0,s=e.length;i<s;i++)if(t.call(r,e[i],i,e)===n)return}else for(var o in e)if(x.has(e,o)&&t.call(r,e[o],o,e)===n)return};x.map=x.collect=function(e,t,n){var r=[];return e==null?r:h&&e.map===h?e.map(t,n):(T(e,function(e,i,s){r.push(t.call(n,e,i,s))}),r)};var N="Reduce of empty array with no initial value";x.reduce=x.foldl=x.inject=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(p&&e.reduce===p)return r&&(t=x.bind(t,r)),i?e.reduce(t,n):e.reduce(t);T(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError(N);return n},x.reduceRight=x.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(d&&e.reduceRight===d)return r&&(t=x.bind(t,r)),i?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=x.keys(e);s=o.length}T(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError(N);return n},x.find=x.detect=function(e,t,n){var r;return C(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},x.filter=x.select=function(e,t,n){var r=[];return e==null?r:v&&e.filter===v?e.filter(t,n):(T(e,function(e,i,s){t.call(n,e,i,s)&&r.push(e)}),r)},x.reject=function(e,t,n){return x.filter(e,function(e,r,i){return!t.call(n,e,r,i)},n)},x.every=x.all=function(e,t,r){t||(t=x.identity);var i=!0;return e==null?i:m&&e.every===m?e.every(t,r):(T(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var C=x.some=x.any=function(e,t,r){t||(t=x.identity);var i=!1;return e==null?i:g&&e.some===g?e.some(t,r):(T(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};x.contains=x.include=function(e,t){return e==null?!1:y&&e.indexOf===y?e.indexOf(t)!=-1:C(e,function(e){return e===t})},x.invoke=function(e,t){var n=u.call(arguments,2),r=x.isFunction(t);return x.map(e,function(e){return(r?t:e[t]).apply(e,n)})},x.pluck=function(e,t){return x.map(e,function(e){return e[t]})},x.where=function(e,t,n){return x.isEmpty(t)?n?void 0:[]:x[n?"find":"filter"](e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},x.findWhere=function(e,t){return x.where(e,t,!0)},x.max=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&x.isEmpty(e))return-Infinity;var r={computed:-Infinity,value:-Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},x.min=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&x.isEmpty(e))return Infinity;var r={computed:Infinity,value:Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o<r.computed&&(r={value:e,computed:o})}),r.value},x.shuffle=function(e){var t,n=0,r=[];return T(e,function(e){t=x.random(n++),r[n-1]=r[t],r[t]=e}),r};var k=function(e){return x.isFunction(e)?e:function(t){return t[e]}};x.sortBy=function(e,t,n){var r=k(t);return x.pluck(x.map(e,function(e,t,i){return{value:e,index:t,criteria:r.call(n,e,t,i)}}).sort(function(e,t){var n=e.criteria,r=t.criteria;if(n!==r){if(n>r||n===void 0)return 1;if(n<r||r===void 0)return-1}return e.index<t.index?-1:1}),"value")};var L=function(e,t,n,r){var i={},s=k(t==null?x.identity:t);return T(e,function(t,o){var u=s.call(n,t,o,e);r(i,u,t)}),i};x.groupBy=function(e,t,n){return L(e,t,n,function(e,t,n){(x.has(e,t)?e[t]:e[t]=[]).push(n)})},x.countBy=function(e,t,n){return L(e,t,n,function(e,t){x.has(e,t)||(e[t]=0),e[t]++})},x.sortedIndex=function(e,t,n,r){n=n==null?x.identity:k(n);var i=n.call(r,t),s=0,o=e.length;while(s<o){var u=s+o>>>1;n.call(r,e[u])<i?s=u+1:o=u}return s},x.toArray=function(e){return e?x.isArray(e)?u.call(e):e.length===+e.length?x.map(e,x.identity):x.values(e):[]},x.size=function(e){return e==null?0:e.length===+e.length?e.length:x.keys(e).length},x.first=x.head=x.take=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,0,t):e[0]},x.initial=function(e,t,n){return u.call(e,0,e.length-(t==null||n?1:t))},x.last=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,Math.max(e.length-t,0)):e[e.length-1]},x.rest=x.tail=x.drop=function(e,t,n){return u.call(e,t==null||n?1:t)},x.compact=function(e){return x.filter(e,x.identity)};var A=function(e,t,n){return T(e,function(e){x.isArray(e)?t?o.apply(n,e):A(e,t,n):n.push(e)}),n};x.flatten=function(e,t){return A(e,t,[])},x.without=function(e){return x.difference(e,u.call(arguments,1))},x.uniq=x.unique=function(e,t,n,r){x.isFunction(t)&&(r=n,n=t,t=!1);var i=n?x.map(e,n,r):e,s=[],o=[];return T(i,function(n,r){if(t?!r||o[o.length-1]!==n:!x.contains(o,n))o.push(n),s.push(e[r])}),s},x.union=function(){return x.uniq(a.apply(r,arguments))},x.intersection=function(e){var t=u.call(arguments,1);return x.filter(x.uniq(e),function(e){return x.every(t,function(t){return x.indexOf(t,e)>=0})})},x.difference=function(e){var t=a.apply(r,u.call(arguments,1));return x.filter(e,function(e){return!x.contains(t,e)})},x.zip=function(){var e=u.call(arguments),t=x.max(x.pluck(e,"length")),n=new Array(t);for(var r=0;r<t;r++)n[r]=x.pluck(e,""+r);return n},x.unzip=function(e){var t=[];return x.each(e,function(e,n){x.each(e,function(e,r){t.length<=r&&(t[r]=[]),t[r][n]=e})}),t},x.object=function(e,t){if(e==null)return{};var n={};for(var r=0,i=e.length;r<i;r++)t?n[e[r]]=t[r]:n[e[r][0]]=e[r][1];return n},x.indexOf=function(e,t,n){if(e==null)return-1;var r=0,i=e.length;if(n){if(typeof n!="number")return r=x.sortedIndex(e,t),e[r]===t?r:-1;r=n<0?Math.max(0,i+n):n}if(y&&e.indexOf===y)return e.indexOf(t,n);for(;r<i;r++)if(e[r]===t)return r;return-1},x.lastIndexOf=function(e,t,n){if(e==null)return-1;var r=n!=null;if(b&&e.lastIndexOf===b)return r?e.lastIndexOf(t,n):e.lastIndexOf(t);var i=r?n:e.length;while(i--)if(e[i]===t)return i;return-1},x.range=function(e,t,n){arguments.length<=1&&(t=e||0,e=0),n=arguments[2]||1;var r=Math.max(Math.ceil((t-e)/n),0),i=0,s=new Array(r);while(i<r)s[i++]=e,e+=n;return s};var O=function(){};x.bind=function(e,t){var n,r;if(e.bind===S&&S)return S.apply(e,u.call(arguments,1));if(!x.isFunction(e))throw new TypeError;return n=u.call(arguments,2),r=function(){if(this instanceof r){O.prototype=e.prototype;var i=new O;O.prototype=null;var s=e.apply(i,n.concat(u.call(arguments)));return Object(s)===s?s:i}return e.apply(t,n.concat(u.call(arguments)))}},x.partial=function(e){var t=u.call(arguments,1);return function(){return e.apply(this,t.concat(u.call(arguments)))}},x.bindAll=function(e){var t=u.call(arguments,1);if(t.length===0)throw new Error("bindAll must be passed function names");return T(t,function(t){e[t]=x.bind(e[t],e)}),e},x.memoize=function(e,t){var n={};return t||(t=x.identity),function(){var r=t.apply(this,arguments);return x.has(n,r)?n[r]:n[r]=e.apply(this,arguments)}},x.delay=function(e,t){var n=u.call(arguments,2);return setTimeout(function(){return e.apply(null,n)},t)},x.defer=function(e){return x.delay.apply(x,[e,1].concat(u.call(arguments,1)))},x.throttle=function(e,t,n){var r,i,s,o,u=0,a=function(){u=new Date,s=null,o=e.apply(r,i)};return function(){var f=new Date;!u&&n===!1&&(u=f);var l=t-(f-u);return r=this,i=arguments,l<=0?(clearTimeout(s),s=null,u=f,o=e.apply(r,i)):s||(s=setTimeout(a,l)),o}},x.debounce=function(e,t,n){var r,i;return function(){var s=this,o=arguments,u=function(){r=null,n||(i=e.apply(s,o))},a=n&&!r;return clearTimeout(r),r=setTimeout(u,t),a&&(i=e.apply(s,o)),i}},x.once=function(e){var t=!1,n;return function(){return t?n:(t=!0,n=e.apply(this,arguments),e=null,n)}},x.wrap=function(e,t){return function(){var n=[e];return o.apply(n,arguments),t.apply(this,n)}},x.compose=function(){var e=arguments;return function(){var t=arguments;for(var n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},x.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},x.keys=E||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)x.has(e,n)&&t.push(n);return t},x.values=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push(e[n]);return t},x.pairs=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push([n,e[n]]);return t},x.invert=function(e){var t={};for(var n in e)x.has(e,n)&&(t[e[n]]=n);return t},x.functions=x.methods=function(e){var t=[];for(var n in e)x.isFunction(e[n])&&t.push(n);return t.sort()},x.extend=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]=t[n]}),e},x.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return T(n,function(n){n in e&&(t[n]=e[n])}),t},x.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)x.contains(n,i)||(t[i]=e[i]);return t},x.defaults=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]===void 0&&(e[n]=t[n])}),e},x.clone=function(e){return x.isObject(e)?x.isArray(e)?e.slice():x.extend({},e):e},x.tap=function(e,t){return t(e),e};var M=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof x&&(e=e._wrapped),t instanceof x&&(t=t._wrapped);var i=f.call(e);if(i!=f.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=M(e[o],t[o],n,r)))break}else{var a=e.constructor,l=t.constructor;if(a!==l&&!(x.isFunction(a)&&a instanceof a&&x.isFunction(l)&&l instanceof l))return!1;for(var c in e)if(x.has(e,c)){o++;if(!(u=x.has(t,c)&&M(e[c],t[c],n,r)))break}if(u){for(c in t)if(x.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};x.isEqual=function(e,t){return M(e,t,[],[])},x.isEmpty=function(e){if(e==null)return!0;if(x.isArray(e)||x.isString(e))return e.length===0;for(var t in e)if(x.has(e,t))return!1;return!0},x.isElement=function(e){return!!e&&e.nodeType===1},x.isArray=w||function(e){return f.call(e)=="[object Array]"},x.isObject=function(e){return e===Object(e)},T(["Arguments","Function","String","Number","Date","RegExp"],function(e){x["is"+e]=function(t){return f.call(t)=="[object "+e+"]"}}),x.isArguments(arguments)||(x.isArguments=function(e){return!!e&&!!x.has(e,"callee")}),typeof /./!="function"&&(x.isFunction=function(e){return typeof e=="function"}),x.isFinite=function(e){return isFinite(e)&&!isNaN(parseFloat(e))},x.isNaN=function(e){return x.isNumber(e)&&e!=+e},x.isBoolean=function(e){return e===!0||e===!1||f.call(e)=="[object Boolean]"},x.isNull=function(e){return e===null},x.isUndefined=function(e){return e===void 0},x.has=function(e,t){return l.call(e,t)},x.noConflict=function(){return e._=t,this},x.identity=function(e){return e},x.times=function(e,t,n){var r=Array(e);for(var i=0;i<e;i++)r[i]=t.call(n,i);return r},x.random=function(e,t){return t==null&&(t=e,e=0),e+Math.floor(Math.random()*(t-e+1))};var _={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};_.unescape=x.invert(_.escape);var D={escape:new RegExp("["+x.keys(_.escape).join("")+"]","g"),unescape:new RegExp("("+x.keys(_.unescape).join("|")+")","g")};x.each(["escape","unescape"],function(e){x[e]=function(t){return t==null?"":(""+t).replace(D[e],function(t){return _[e][t]})}}),x.result=function(e,t){if(e==null)return void 0;var n=e[t];return x.isFunction(n)?n.call(e):n},x.mixin=function(e){T(x.functions(e),function(t){var n=x[t]=e[t];x.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),F.call(this,n.apply(x,e))}})};var P=0;x.uniqueId=function(e){var t=++P+"";return e?e+t:t},x.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var H=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},j=/\\|'|\r|\n|\t|\u2028|\u2029/g;x.template=function(e,t,n){var r;n=x.defaults({},n,x.templateSettings);var i=new RegExp([(n.escape||H).source,(n.interpolate||H).source,(n.evaluate||H).source].join("|")+"|$","g"),s=0,o="__p+='";e.replace(i,function(t,n,r,i,u){return o+=e.slice(s,u).replace(j,function(e){return"\\"+B[e]}),n&&(o+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'"),r&&(o+="'+\n((__t=("+r+"))==null?'':__t)+\n'"),i&&(o+="';\n"+i+"\n__p+='"),s=u+t.length,t}),o+="';\n",n.variable||(o="with(obj||{}){\n"+o+"}\n"),o="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+o+"return __p;\n";try{r=new Function(n.variable||"obj","_",o)}catch(u){throw u.source=o,u}if(t)return r(t,x);var a=function(e){return r.call(this,e,x)};return a.source="function("+(n.variable||"obj")+"){\n"+o+"}",a},x.chain=function(e){return x(e).chain()};var F=function(e){return this._chain?x(e).chain():e};x.mixin(x),T(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];x.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],F.call(this,n)}}),T(["concat","join","slice"],function(e){var t=r[e];x.prototype[e]=function(){return F.call(this,t.apply(this._wrapped,arguments))}}),x.extend(x.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this),define("libs/underscore",function(e){return function(){var t,n;return t||e._}}(this)),define("utils/utils",["libs/underscore"],function(e){function t(e,t,r){n("GET",e,{},t,r)}function n(e,t,n,r,i){if(e=="GET"||e=="DELETE")t.indexOf("?")==-1?t+="?":t+="&",t+=$.param(n);var s=new XMLHttpRequest;s.open(e,t,!0),s.setRequestHeader("Accept","application/json"),s.setRequestHeader("Cache-Control","no-cache"),s.setRequestHeader("X-Requested-With","XMLHttpRequest"),s.setRequestHeader("Content-Type","application/json"),s.onloadend=function(){var e=s.status;try{response=jQuery.parseJSON(s.responseText)}catch(t){response=s.responseText}e==200?r&&r(response):i&&i(response)},e=="GET"||e=="DELETE"?s.send():s.send(JSON.stringify(n))}function r(e,t){var n=$('<div class="'+e+'"></div>');n.appendTo(":eq(0)");var r=n.css(t);return n.remove(),r}function i(e){$('link[href^="'+e+'"]').length||$('<link href="'+galaxy_config.root+e+'" rel="stylesheet">').appendTo("head")}function s(t,n){return t?e.defaults(t,n):n}function o(e,t){var n="";if(e>=1e11)e/=1e11,n="TB";else if(e>=1e8)e/=1e8,n="GB";else if(e>=1e5)e/=1e5,n="MB";else if(e>=100)e/=100,n="KB";else{if(!(e>0))return"<strong>-</strong>";e*=10,n="b"}var r=Math.round(e)/10;return t?r+" "+n:"<strong>"+r+"</strong> "+n}function u(){return(new Date).getTime().toString(36)}function a(e){var t=$("<p></p>");return t.append(e),t}function f(){var e=new Date,t=(e.getHours()<10?"0":"")+e.getHours(),n=(e.getMinutes()<10?"0":"")+e.getMinutes(),r=e.getDate()+"/"+(e.getMonth()+1)+"/"+e.getFullYear()+", "+t+":"+n;return r}return{cssLoadFile:i,cssGetAttribute:r,get:t,merge:s,bytesToString:o,uuid:u,time:f,wrap:a,request:n}}),define("mvc/ui/ui-modal",["utils/utils"],function(e){var t=Backbone.View.extend({elMain:"body",optionsDefault:{title:"ui-modal",body:"",backdrop:!0,height:null,width:null,closing_events:!1},buttonList:{},initialize:function(e){e&&this._create(e)},show:function(e){this.initialize(e),this.options.height?(this.$body.css("height",this.options.height),this.$body.css("overflow","hidden")):this.$body.css("max-height",$(window).height()/2),this.options.width&&this.$dialog.css("width",this.options.width),this.visible?this.$el.show():this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.visible=!1,this.$el.fadeOut("fast")},enableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!1)},disableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!0)},showButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).show()},hideButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).hide()},getButton:function(e){var t=this.buttonList[e];return this.$buttons.find("#"+t)},scrollTop:function(){return this.$body.scrollTop()},_create:function(e){var t=this;this.options=_.defaults(e,this.optionsDefault),this.options.body=="progress"&&(this.options.body=$('<div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width:100%"></div></div>')),this.$el&&(this.$el.remove(),$(document).off("keyup")),this.setElement(this._template(this.options.title)),this.$dialog=this.$el.find(".modal-dialog"),this.$body=this.$el.find(".modal-body"),this.$footer=this.$el.find(".modal-footer"),this.$buttons=this.$el.find(".buttons"),this.$backdrop=this.$el.find(".modal-backdrop"),this.$body.html(this.options.body),this.options.backdrop||this.$backdrop.removeClass("in");if(this.options.buttons){this.buttonList={};var n=0;$.each(this.options.buttons,function(e,r){var i="button-"+n++;t.$buttons.append($('<button id="'+i+'"></button>').text(e).click(r)).append(" "),t.buttonList[e]=i})}else this.$footer.hide();$(this.elMain).append($(this.el)),this.options.closing_events&&(this.options.buttons.Pause||$(document).on("keyup",function(e){e.keyCode==27&&t.hide()}),this.$el.find(".modal-backdrop").on("click",function(){t.hide()}))},_template:function(e){return'<div class="modal"><div class="modal-backdrop fade in" style="z-index: -1;"></div><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" style="display: none;">×</button><h4 class="title">'+e+"</h4>"+"</div>"+'<div class="modal-body" style="position: static;"></div>'+'<div class="modal-footer">'+'<div class="buttons" style="float: right;"></div>'+"</div>"+"</div"+"</div>"+"</div>"}});return{View:t}}),define("mvc/ui/ui-portlet",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,optionsDefault:{title:"",icon:"",buttons:null,body:null,height:null,operations:null,placement:"bottom",overflow:"auto"},$title:null,$content:null,$buttons:null,$operations:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$content=this.$el.find("#content"),this.$title=this.$el.find("#title-text"),this.options.height&&(this.$el.find("#body").css("height",this.options.height),this.$el.find("#content").css("overflow",this.options.overflow)),this.$buttons=$(this.el).find("#buttons");if(this.options.buttons){var n=this;$.each(this.options.buttons,function(e,t){t.$el.prop("id",e),n.$buttons.append(t.$el)})}else this.$buttons.remove();this.$operations=$(this.el).find("#operations");if(this.options.operations){var n=this;$.each(this.options.operations,function(e,t){t.$el.prop("id",e),n.$operations.append(t.$el)})}this.options.body&&this.append(this.options.body)},append:function(t){this.$content.append(e.wrap(t))},content:function(){return this.$content},show:function(){this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},enableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!1)},disableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!0)},hideOperation:function(e){this.$operations.find("#"+e).hide()},showOperation:function(e){this.$operations.find("#"+e).show()},setOperation:function(e,t){var n=this.$operations.find("#"+e);n.off("click"),n.on("click",t)},title:function(e){var t=this.$title;return e&&t.html(e),t.html()},_template:function(e){var t='<div class="toolForm portlet-view no-highlight">';if(e.title||e.icon)t+='<div id="title" class="toolFormTitle portlet-title"><div id="operations" class="portlet-operations"/><div style="overflow: hidden;">',e.icon&&(t+='<div class="portlet-title-icon fa '+e.icon+'"> </div>'),t+='<div id="title-text" class="portlet-title-text">'+e.title+"</div>",t+="</div></div>";return t+='<div id="body" class="toolFormBody portlet-body">',e.placement=="top"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+='<div id="content" class="portlet-content"/>',e.placement=="bottom"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+="</div></div>",t}});return{View:t}}),define("plugin/library/ui-select",["utils/utils"],function(e){var t=Backbone.View.extend({optionsDefault:{id:"",cls:"",empty:"No data available",visible:!0,wait:!1},selected:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$select=this.$el.find("#select"),this.$icon=this.$el.find("#icon"),this.selected=this.options.value;var n=this;this.options.onchange&&this.$select.on("change",function(){n.value(n.$select.val())}),this._refresh(),this.options.visible||this.hide(),this.options.wait?this.wait():this.show()},value:function(e){var t=this.selected;e!==undefined&&(this.selected=e,this.$select.val(e));var n=this.selected;return n&&n!=t&&this.options.onchange&&this.options.onchange(n),n},text:function(){return this.$select.find("option:selected").text()},show:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-caret-down"),this.$select.show(),this.$el.show()},hide:function(){this.$el.hide()},wait:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-spinner fa-spin"),this.$select.hide()},disabled:function(){return this.$select.is(":disabled")},enable:function(){this.$select.prop("disabled",!1)},disable:function(){this.$select.prop("disabled",!0)},add:function(e){this.$select.append(this._templateOption(e)),this._refresh()},del:function(e){this.$select.find("option[value="+e+"]").remove(),this.$select.trigger("change"),this._refresh()},update:function(e){this.$select.find("option").remove();for(var t in e)this.$select.append(this._templateOption(e[t]));!this.selected&&e.length>0&&this.value(e[0].value),this._refresh()},_refresh:function(){this.$select.find("option[value=null]").remove();var e=this.$select.find("option").length;e==0?(this.$select.append(this._templateOption({value:"null",label:this.options.empty})),this.disable()):(this.enable(),this.selected&&this.$select.val(this.selected))},_exists:function(e){return 0!=this.$select.find("option[value="+e+"]").length},_templateOption:function(e){return'<option value="'+e.value+'">'+e.label+"</option>"},_template:function(e){var t='<div id="'+e.id+'" class="styled-select">'+'<div class="button">'+'<i id="icon"/>'+"</div>"+'<select id="select" class="select '+e.cls+" "+e.id+'">';for(key in e.data){var n=e.data[key],r="";if(n.value==e.value||n.value=="")r="selected";t+='<option value="'+n.value+'" '+r+">"+n.label+"</option>"}return t+="</select></div>",t}});return{View:t}}),define("plugin/library/ui",["utils/utils","plugin/library/ui-select"],function(e,t){var n=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options))},title:function(e){this.$el.find("b").html(e)},_template:function(e){return"<label><b>"+e.title+"</b></label>"},value:function(){return options.title}}),r=Backbone.View.extend({optionsDefault:{id:null,title:"","float":"right",cls:"btn-default",icon:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t='<button id="'+e.id+'" type="submit" style="margin-right: 5px; float: '+e.float+';" type="button" class="btn '+e.cls+'">';return e.icon&&(t+='<i class="icon fa '+e.icon+'"></i> '),t+=e.title+"</button>",t}}),i=Backbone.View.extend({optionsDefault:{"float":"right",icon:"",tooltip:"",placement:"bottom",title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){return'<div><span class="fa '+e.icon+'" style="font-size: 1.2em;"/> '+e.title+"</div>"}}),s=Backbone.View.extend({optionsDefault:{title:"",id:null,"float":"right",cls:"icon-btn",icon:"",tooltip:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t="";e.title&&(t="width: auto;");var n='<div id="'+e.id+'" style="margin-right: 5px; float: '+e.float+"; "+t+'" class="'+e.cls+'">';return e.title?n+='<div style="margin-right: 5px; margin-left: 5px;"><i class="icon fa '+e.icon+'"/> '+'<span style="position: relative; font-size: 0.8em; font-weight: normal; top: -1px;">'+e.title+"</span>"+"</div>":n+='<i class="icon fa '+e.icon+'"/>',n+="</div>",n}}),o=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick)},_template:function(e){return'<div><a href="javascript:void(0)">'+e.title+"</a></div>"}}),u=Backbone.View.extend({optionsDefault:{message:"",status:"info",persistent:!1},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement("<div></div>")},update:function(t){this.options=e.merge(t,this.optionsDefault);if(t.message!=""){this.$el.html(this._template(this.options)),this.$el.fadeIn();if(!t.persistent){var n=this;window.setTimeout(function(){n.$el.is(":visible")?n.$el.fadeOut():n.$el.hide()},3e3)}}else this.$el.fadeOut()},_template:function(e){return'<div class="alert alert-'+e.status+'" style="padding: 2px 2px 2px 10px;">'+e.message+"</div>"}}),a=Backbone.View.extend({optionsDefault:{onclick:null,searchword:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options));var n=this;this.options.onclick&&this.$el.on("submit",function(e){var t=n.$el.find("#search");n.options.onclick(t.val())})},_template:function(e){return'<div class="search"><form onsubmit="return false;"><input id="search" class="form-control input-sm" type="text" name="search" placeholder="Search..." value="'+e.searchword+'">'+'<button type="submit" class="btn search-btn">'+'<i class="fa fa-search"></i>'+"</button>"+"</form>"+"</div>"}}),f=Backbone.View.extend({optionsDefault:{title:"Unlabeled",body:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.body&&this.$el.find(".body").append(this.options.body)},_template:function(e){return'<div id="title" class="title">'+e.title+":"+"</div>"}}),l=Backbone.View.extend({optionsDefault:{id:"",title:"",target:"",href:"",onunload:null,onclick:null,visible:!0,icon:null,tag:""},$menu:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement($(this._template(this.options)));var n=$(this.el).find(".root"),r=this;n.on("click",function(e){e.preventDefault(),r.options.onclick&&r.options.onclick()}),this.options.visible||this.hide()},show:function(){$(this.el).show()},hide:function(){$(this.el).hide()},addMenu:function(t){var n={title:"",target:"",href:"",onclick:null,divider:!1,icon:null};n=e.merge(t,n),this.$menu||($(this.el).append(this._templateMenu()),this.$menu=$(this.el).find(".menu"));var r=$(this._templateMenuItem(n));r.on("click",function(e){e.preventDefault(),n.onclick&&n.onclick()}),this.$menu.append(r),n.divider&&this.$menu.append($(this._templateDivider()))},_templateMenuItem:function(e){var t='<li><a href="'+e.href+'" target="'+e.target+'">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),t+=" "+e.title+"</a>"+"</li>",t},_templateMenu:function(){return'<ul class="menu dropdown-menu pull-right" role="menu"></ul>'},_templateDivider:function(){return'<li class="divider"></li>'},_template:function(e){var t='<div id="'+e.id+'" class="button-menu btn-group">'+'<button type="button" class="root btn btn-default dropdown-toggle" data-toggle="dropdown">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),"</button></div>",t}}),c=Backbone.View.extend({optionsDefault:{value:"",type:"text",placeholder:"",disabled:!1,visible:!0},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.disabled&&this.$el.prop("disabled",!0),this.options.visible||this.$el.hide();var n=this;this.options.onchange&&this.$el.on("input",function(){n.options.onchange()})},value:function(e){return e!==undefined&&this.$el.val(e),this.$el.val()},_template:function(e){return'<input id="'+e.id+'" type="'+e.type+'" value="'+e.value+'" placeholder="'+e.placeholder+'" class="form-control">'}});return{Label:n,Button:r,Icon:i,ButtonIcon:s,Input:c,Anchor:o,Message:u,Searchbox:a,Title:f,Select:t,ButtonMenu:l}}),define("plugin/library/jobs",["utils/utils"],function(e){return Backbone.Model.extend({initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},cleanup:function(t){var n=t.get("dataset_id_job");if(n){var r=this;e.request("PUT",config.root+"api/histories/none/contents/"+n,{deleted:!0},function(){r._refreshHdas()})}},submit:function(t,n,r,i){var s=this,o=t.id,u=t.get("type"),a=this.app.types.get(u);data={tool_id:"rkit",inputs:{input:{id:t.get("dataset_id"),src:"hda"},module:u,columns:r,settings:n}},s.cleanup(t),t.state("submit","Sending job request..."),e.request("POST",config.root+"api/tools",data,function(e){if(!e.outputs||e.outputs.length==0)t.state("failed","Job submission failed. No response.");else{s._refreshHdas();var n=e.outputs[0];t.state("queued","Job has been queued..."),t.set("dataset_id_job",n.id),s._loop(n.id,function(e){switch(e.state){case"ok":return t.state("success","Job completed successfully..."),i(e),!0;case"error":return t.state("failed","Job has failed. Please check the history for details."),!0;case"running":return t.state("running","Job is running..."),!1}})}},function(e){var n="";e&&e.message&&e.message.data&&e.message.data.input&&(n=e.message.data.input+"."),t.state("failed","This visualization requires the R-kit. Please make sure it is installed. "+n)})},_loop:function(t,n){var r=this;e.request("GET",config.root+"api/jobs/"+t,{},function(e){n(e)||setTimeout(function(){r._loop(t,n)},r.app.config.get("query_timeout"))})},_refreshHdas:function(){Galaxy&&Galaxy.currHistoryPanel&&Galaxy.currHistoryPanel.refreshHdas()}})}),define("plugin/library/datasets",["utils/utils"],function(e){return Backbone.Collection.extend({list:{},initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},request:function(t,n,r){var i=this;if(t.groups)this._fetch(t,n);else{var s=this.list[t.id];if(s){n(s);return}e.request("GET",config.root+"api/datasets/"+t.id,{},function(e){switch(e.state){case"error":r&&r(e);break;default:i.list[t.id]=e,n(e)}})}},_fetch:function(t,n){var r=t.start?t.start:0,i=Math.abs(t.end-t.start),s=this.app.config.get("query_limit");if(!i||i>s)i=s;var o="",u={},a=0;for(var f in t.groups){var l=t.groups[f];for(var c in l.columns){var h=l.columns[c];o+=h+",",u[h]=a,a++}}if(a==0){n({});return}o=o.substring(0,o.length-1);var p=t.groups.slice(0);for(var f in p)p[f].values=[];var d=this;e.request("GET",config.root+"api/datasets/"+t.id,{data_type:"raw_data",provider:"dataset-column",limit:i,offset:r,indeces:o},function(e){for(var i in e.data){var s=e.data[i];for(var o in t.groups){var a=t.groups[o],f={x:parseInt(i)+r};for(var l in a.columns){var c=a.columns[l],h=u[c],d=s[h];if(isNaN(d)||!d)d=0;f[l]=d}p[o].values.push(f)}}n(p)})}})}),define("plugin/library/ui-table",["utils/utils"],function(e){var t=Backbone.View.extend({row:null,row_count:0,optionsDefault:{content:"No content available.",onchange:null,ondblclick:null,onconfirm:null},events:{click:"_onclick",dblclick:"_ondblclick"},first:!0,initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(t));this.$thead=n.find("thead"),this.$tbody=n.find("tbody"),this.$tmessage=n.find("tmessage"),this.setElement(n),this.row=$("<tr></tr>")},addHeader:function(e){var t=$("<th></th>");t.append(e),this.row.append(t)},appendHeader:function(){this.$thead.append(this.row),this.row=$("<tr></tr>")},add:function(e,t){var n=$("<td></td>");t&&n.css("width",t),n.append(e),this.row.append(n)},append:function(e){this._commit(e)},prepend:function(e){this._commit(e,!0)},remove:function(e){var t=this.$tbody.find("#"+e);t.length>0&&(t.remove(),this.row_count--,this._refresh())},removeAll:function(){this.$tbody.html(""),this.row_count=0,this._refresh()},value:function(e){this.before=this.$tbody.find(".current").attr("id"),e!==undefined&&(this.$tbody.find("tr").removeClass("current"),e&&this.$tbody.find("#"+e).addClass("current"));var t=this.$tbody.find(".current").attr("id");return t===undefined?null:(t!=this.before&&this.options.onchange&&this.options.onchange(e),t)},size:function(){return this.$tbody.find("tr").length},_commit:function(e,t){this.remove(e),this.row.attr("id",e),t?this.$tbody.prepend(this.row):this.$tbody.append(this.row),this.row=$("<tr></tr>"),this.row_count++,this._refresh()},_onclick:function(e){var t=this.value(),n=$(e.target).closest("tr").attr("id");n&&t!=n&&(this.options.onconfirm?this.options.onconfirm(n):this.value(n))},_ondblclick:function(e){var t=this.value();t&&this.options.ondblclick&&this.options.ondblclick(t)},_refresh:function(){this.row_count==0?this.$tmessage.show():this.$tmessage.hide()},_template:function(e){return'<div><table class="grid"><thead></thead><tbody style="cursor: pointer;"></tbody></table><tmessage>'+e.content+"</tmessage>"+"<div>"}});return{View:t}}),define("plugin/models/group",[],function(){return Backbone.Model.extend({defaults:{key:"Data label",date:""},reset:function(){this.clear({silent:!0}).set(this.defaults),this.trigger("reset",this)}})}),define("plugin/views/viewport",["mvc/ui/ui-portlet","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({list:{},optionsDefault:{height:300},initialize:function(t,r){this.app=t,this.options=n.merge(r,this.optionsDefault),this.portlet=new e.View({title:"title",height:this.options.height,overflow:"hidden"}),this.setElement(this.portlet.$el);var i=this;this.app.charts.on("remove",function(e){i._removeChart(e.id)}),this.app.charts.on("redraw",function(e){i._drawChart(e)})},showChart:function(e){this.show(),this.hideCharts();var t=this.list[e];if(t){var n=this.app.charts.get(e);this.portlet.title(n.get("title")),t.$el.show(),$(window).trigger("resize")}},hideCharts:function(){this.$el.find(".item").hide()},show:function(){$(".tooltip").hide(),this.$el.show()},hide:function(){$(".tooltip").hide(),this.$el.hide()},_drawChart:function(e){var t=this;if(!e.ready()){t.app.log("viewport:_drawChart()","Invalid attempt to draw chart before completion.");return}var n=e.id;this._removeChart(n);var r="#"+n,i=$(this._template({id:r}));this.portlet.append(i);var s=d3.select(i.find("svg")[0]);this.list[n]={svg:s,$el:i},e.off("change:state"),e.on("change:state",function(){var t=i.find("#info"),n=t.find("#icon");n.removeClass(),t.show(),t.find("#text").html(e.get("state_info"));var r=e.get("state");switch(r){case"ok":t.hide();break;case"failed":n.addClass("fa fa-warning");break;default:n.addClass("fa fa-spinner fa-spin")}}),e.state("wait","Please wait...");var o=e.get("type"),u=this.app.types.get(o),t=this;require(["plugin/charts/"+o+"/"+o],function(n){var r=new n(t.app,{svg:s});u.execute?t.app.jobs.submit(e,t._defaultSettingsString(e),t._defaultRequestString(e),function(){r.draw(e,t._defaultRequestDictionary(e))}):r.draw(e,t._defaultRequestDictionary(e))})},_removeChart:function(e){var t=this.list[e];t&&(t.svg.remove(),t.$el.remove())},_template:function(e){return'<div id="'+e.id.substr(1)+'" class="item">'+'<span id="info">'+'<span id="icon" style="font-size: 1.2em; display: inline-block;"/>'+'<span id="text" style="position: relative; margin-left: 5px; top: -1px; font-size: 1.0em;"/>'+"</span>"+'<svg style="height: auto;"/>'+"</div>"},_defaultRequestString:function(e){var t=this.app.types.get(e.get("type")),n="",r=0;return e.groups.each(function(e){for(var i in t.columns)n+=i+"_"+ ++r+":"+(parseInt(e.get(i))+1)+", "}),n.substring(0,n.length-2)},_defaultSettingsString:function(e){var t="";for(key in e.settings.attributes)t+=key+":"+e.settings.get(key)+", ";return t.substring(0,t.length-2)},_defaultRequestDictionary:function(e){var t=this.app.types.get(e.get("type")),n={id:e.get("dataset_id"),groups:[]},r=0;return e.groups.each(function(e){var i={};for(var s in t.columns)i[s]=e.get(s);n.groups.push({key:++r+":"+e.get("key"),columns:i})}),n}})}),define("plugin/views/charts",["mvc/ui/ui-portlet","plugin/library/ui-table","plugin/library/ui","utils/utils","plugin/models/group","plugin/views/viewport"],function(e,t,n,r,i,s){return Backbone.View.extend({initialize:function(i,o){this.app=i,this.viewport_view=new s(i),this.table=new t.View({content:"Add charts to this table.",ondblclick:function(e){u._showChartView(e)},onchange:function(e){var t=u.app.charts.get(e);u.app.config.set("title",t.get("title")),u.viewport_view.showChart(e)}});var u=this;this.portlet=new e.View({icon:"fa-list",title:"List of created charts:",height:100,operations:{"new":new n.ButtonIcon({icon:"fa-magic",tooltip:"Create a new Chart",title:"New",onclick:function(){u.app.go("chart_view"),u.app.chart.reset()}}),edit:new n.ButtonIcon({icon:"fa-gear",tooltip:"Customize this Chart",title:"Customize",onclick:function(){var e=u.table.value();if(!e)return;u._showChartView(e)}}),"delete":new n.ButtonIcon({icon:"fa-trash-o",tooltip:"Delete this Chart",title:"Delete",onclick:function(){var e=u.table.value();if(!e)return;var t=u.app.charts.get(e);u._wait(t,function(){u.app.modal.show({title:"Are you sure?",body:'The selected chart "'+t.get("title")+'" will be irreversibly deleted.',buttons:{Cancel:function(){u.app.modal.hide()},Delete:function(){u.app.modal.hide(),u.app.charts.remove(e),u.app.jobs.cleanup(t)}}})})}})}}),this.portlet.append(this.table.$el),this.app.options.config.widget||this.$el.append(this.portlet.$el),this.$el.append(r.wrap("")),this.$el.append(this.viewport_view.$el);var u=this;this.app.charts.on("add",function(e){u._addChart(e)}),this.app.charts.on("remove",function(e){u._removeChart(e)}),this.app.charts.on("change",function(e){u._changeChart(e)})},show:function(){this.$el.show()},hide:function(){$(".tooltip").hide(),this.$el.hide()},_addChart:function(e){var t=e.get("title");t==""&&(t="Untitled"),this.table.add(t);var n=this.app.types.get(e.get("type"));this.table.add(n.title),this.table.add("Last change: "+e.get("date")),this.table.prepend(e.get("id")),this.table.value(e.get("id"))},_removeChart:function(e){this.table.remove(e.id),this.app.charts.save(),this.table.size()==0?(this.app.go("chart_view"),this.app.chart.reset()):this.table.value(this.app.charts.last().id)},_changeChart:function(e){e.get("type")&&(this._addChart(e),this.table.value(e.id))},_showChartView:function(e){var t=this,n=this.app.charts.get(e);this._wait(n,function(){t.app.go("chart_view"),t.app.chart.copy(n)})},_wait:function(e,t){if(e.ready())t();else{var n=this;this.app.modal.show({title:"Please wait!",body:'The selected chart "'+e.get("title")+'" is currently being processed. Please wait...',buttons:{Close:function(){n.app.modal.hide()},Retry:function(){n.app.modal.hide(),setTimeout(function(){n._wait(e,t)},n.app.config.get("query_timeout"))}}})}}})}),define("mvc/ui/ui-tabs",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,list:{},$nav:null,$content:null,first_tab:null,optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(this.options));this.$nav=n.find(".tab-navigation"),this.$content=n.find(".tab-content"),this.setElement(n),this.list={};var r=this;this.options.operations&&$.each(this.options.operations,function(e,t){t.$el.prop("id",e),r.$nav.find(".operations").append(t.$el)});if(this.options.onnew){var i=$(this._template_tab_new(this.options));this.$nav.append(i),i.tooltip({title:"Add a new tab",placement:"bottom",container:r.$el}),i.on("click",function(e){i.tooltip("hide"),r.options.onnew()})}},add:function(e){var t=e.id,n={$title:$(this._template_tab(e)),$content:$(this._template_tab_content(e)),removable:e.ondel?!0:!1};this.list[t]=n,this.options.onnew?this.$nav.find("#new-tab").before(n.$title):this.$nav.append(n.$title),n.$content.append(e.$el),this.$content.append(n.$content),_.size(this.list)==1&&(n.$title.addClass("active"),n.$content.addClass("active"),this.first_tab=t);if(e.ondel){var r=this,i=n.$title.find("#delete");i.tooltip({title:"Delete this tab",placement:"bottom",container:r.$el}),i.on("click",function(){return i.tooltip("destroy"),r.$el.find(".tooltip").remove(),e.ondel(),!1})}e.onclick&&n.$title.on("click",function(){e.onclick()})},del:function(e){var t=this.list[e];t.$title.remove(),t.$content.remove(),delete t,this.first_tab==e&&(this.first_tab=null),this.first_tab!=null&&this.show(this.first_tab)},delRemovable:function(){for(var e in this.list){var t=this.list[e];t.removable&&this.del(e)}},show:function(e){this.$el.fadeIn("fast"),this.visible=!0,e&&this.list[e].$title.find("a").tab("show")},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},hideOperation:function(e){this.$nav.find("#"+e).hide()},showOperation:function(e){this.$nav.find("#"+e).show()},setOperation:function(e,t){var n=this.$nav.find("#"+e);n.off("click"),n.on("click",t)},title:function(e,t){var n=this.list[e].$title.find("#text");return t&&n.html(t),n.html()},_template:function(e){return'<div class="tabbable tabs-left"><ul class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div class="tab-content"/></div>'},_template_tab_new:function(e){return'<li id="new-tab"><a href="javascript:void(0);"><i style="font-size: 0.8em; margin-right: 5px;" class="fa fa-plus-circle"/>'+e.title_new+"</a>"+"</li>"},_template_tab:function(e){var t='<li id="title-'+e.id+'">'+'<a title="" href="#tab-'+e.id+'" data-toggle="tab" data-original-title="">'+'<span id="text">'+e.title+"</span>";return e.ondel&&(t+='<i id="delete" style="font-size: 0.8em; margin-left: 5px; cursor: pointer;" class="fa fa-minus-circle"/>'),t+="</a></li>",t},_template_tab_content:function(e){return'<div id="tab-'+e.id+'" class="tab-pane"/>'}});return{View:t}}),define("plugin/models/groups",["plugin/models/group"],function(e){return Backbone.Collection.extend({model:e})});var Visualization=Backbone.Model.extend({defaults:{config:{}},urlRoot:function(){var e="/api/visualizations";return window.galaxy_config&&galaxy_config.root?galaxy_config.root+e:e},initialize:function(e){_.isObject(e.config)&&_.isObject(this.defaults.config)&&_.defaults(e.config,this.defaults.config),this._setUpListeners()},_setUpListeners:function(){},set:function(e,t){if(e==="config"){var n=this.get("config");_.isObject(n)&&(t=_.extend(_.clone(n),t))}return Backbone.Model.prototype.set.call(this,e,t),this},toString:function(){var e=this.get("id")||"";return this.get("title")&&(e+=":"+this.get("title")),"Visualization("+e+")"}}),VisualizationCollection=Backbone.Collection.extend({model:Visualization,url:function(){return galaxy_config.root+"api/visualizations"},initialize:function(e,t){t=t||{}},set:function(e,t){var n=this;e=_.map(e,function(e){var t=n.get(e.id);if(!t)return e;var r=t.toJSON();return _.extend(r,e),r}),Backbone.Collection.prototype.set.call(this,e,t)},toString:function(){return["VisualizationCollection(",[this.historyId,this.length].join(),")"].join("")}});define("mvc/visualization/visualization-model",function(){}),define("plugin/models/chart",["plugin/models/groups","mvc/visualization/visualization-model"],function(e){return Backbone.Model.extend({defaults:{id:null,title:"",type:"",date:null,state:"ok",state_info:""},initialize:function(t){this.groups=new e,this.settings=new Backbone.Model},reset:function(){this.clear({silent:!0}).set(this.defaults),this.groups.reset(),this.settings.clear(),this.trigger("reset",this)},copy:function(e){var t=this;t.clear({silent:!0}).set(this.defaults),t.set(e.attributes),t.settings=e.settings.clone(),t.groups.reset(),e.groups.each(function(e){t.groups.add(e.clone())}),t.trigger("change",t)},state:function(e,t){this.set("state_info",t),this.set("state",e)},ready:function(){return this.get("state")=="ok"||this.get("state")=="failed"}})}),define("plugin/views/group",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({columns:[],initialize:function(r,i){this.app=r;var s=this;this.chart=this.app.chart,this.group=i.group,this.group_key=new t.Input({placeholder:"Data label",onchange:function(){s.group.set("key",s.group_key.value())}}),this.table=new e.View({content:"No data column."});var o=$("<div/>");o.append(n.wrap((new t.Label({title:"Provide a label:"})).$el)),o.append(n.wrap(this.group_key.$el)),o.append(n.wrap((new t.Label({title:"Select columns:"})).$el)),o.append(n.wrap(this.table.$el)),this.setElement(o);var s=this;this.chart.on("change:dataset_id",function(){s._refreshTable()}),this.chart.on("change:type",function(){s._refreshTable()}),this.group.on("change:key",function(){s._refreshGroupKey()}),this.group.on("change",function(){s._refreshGroup()}),this._refreshTable(),this._refreshGroupKey(),this._refreshGroup()},_refreshTable:function(){var e=this.chart.get("dataset_id"),n=this.chart.get("type");if(!e||!n)return;var r=this,i=this.app.types.get(n);this.table.removeAll();var s={};for(var o in i.columns){var u=this.group.get(o);u||this.group.set(o,0);var a=i.columns[o],f=new t.Select.View({id:"select_"+o,gid:o,onchange:function(e){r.group.set(this.gid,e)},value:u,wait:!0});this.table.add(a.title,"25%"),this.table.add(f.$el),this.table.append(o),s[o]=f}this.app.datasets.request({id:e},function(e){r.columns=[];var t=e.metadata_column_types;for(var n in t)(t[n]=="int"||t[n]=="float")&&r.columns.push({label:"Column: "+(parseInt(n)+1)+" ["+t[n]+"]",value:n});for(var n in s)s[n].update(r.columns),s[n].show()})},_refreshGroup:function(){this.group.set("date",n.time())},_refreshGroupKey:function(){var e=this.group.get("key");e===undefined&&(e=""),this.group_key.value(e)}})}),define("plugin/library/ui-table-form",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){var r=Backbone.View.extend({initialize:function(r){this.table_title=new t.Label({title:r.title}),this.table=new e.View({content:r.content});var i=$("<div/>");i.append(n.wrap(this.table_title.$el)),i.append(n.wrap(this.table.$el)),this.setElement(i)},title:function(e){this.table_title.title(e)},update:function(e,t){this.table.removeAll();for(var n in e)this._add(n,e[n],t)},_add:function(e,n,r){var i=null,s=n.type;switch(s){case"text":i=new t.Input({placeholder:n.placeholder,onchange:function(){r.set(e,i.value())}});break;case"select":i=new t.Select.View({data:n.data,onchange:function(){r.set(e,i.value())}});break;case"slider":i=new t.Input({placeholder:n.placeholder,onchange:function(){r.set(e,i.value())}});break;case"separator":i=$("<div/>");break;default:console.log("ui-table-form:_add","Unknown setting type ("+n.type+")");return}if(s!="separator"){r.get(e)||r.set(e,n.init),i.value(r.get(e));var o=$("<div/>");o.append(i.$el),o.append('<div class="toolParamHelp" style="font-size: 0.9em;">'+n.info+"</div>"),this.table.add('<span style="white-space: nowrap;">'+n.title+"</span>","25%"),this.table.add(o)}else this.table.add('<h6 style="white-space: nowrap;">'+n.title+":<h6/>"),this.table.add($("<div/>"));this.table.append(e)}});return{View:r}}),define("plugin/views/settings",["plugin/library/ui","plugin/library/ui-table-form","utils/utils"],function(e,t,n){return Backbone.View.extend({initialize:function(e,n){this.app=e;var r=this;this.chart=this.app.chart,this.form=new t.View({title:"Chart options:",content:"This chart type does not provide any options."}),this.setElement(this.form.$el);var r=this;this.chart.on("change",function(){r._refreshTable()})},_refreshTable:function(){var e=this.chart.get("type");if(!e)return;var t=this.app.types.get(e);this.form.title(t.title+":"),this.form.update(t.settings,this.chart.settings)}})}),define("plugin/views/chart",["mvc/ui/ui-tabs","plugin/library/ui-table","plugin/library/ui","utils/utils","plugin/models/chart","plugin/models/group","plugin/views/group","plugin/views/settings"],function(e,t,n,r,i,s,o,u){return Backbone.View.extend({optionsDefault:{header:!0,content:"No content available."},initialize:function(i,s){this.app=i,this.chart=this.app.chart,this.options=r.merge(s,this.optionsDefault);var o=this;this.table=new t.View({header:!1,onconfirm:function(e){o.chart.groups.length>0?o.app.modal.show({title:"Switching to another chart type?",body:"If you continue your settings and selections will be cleared.",buttons:{Cancel:function(){o.app.modal.hide()},Continue:function(){o.app.modal.hide(),o.table.value(e)}}}):o.table.value(e)},onchange:function(e){o.chart.groups.reset(),o.chart.settings.clear(),o.chart.set({type:e})},ondblclick:function(e){o.tabs.show("settings")},content:"No chart types available"});var a=0,f=i.types.attributes;for(var l in f){var c=f[l];this.table.add(++a+"."),c.execute?this.table.add(c.title+" (requires processing)"):this.table.add(c.title),this.table.append(l)}this.tabs=new e.View({title_new:"Add Data",onnew:function(){var e=o._addGroupModel();o.tabs.show(e.id)},operations:{save:new n.ButtonIcon({icon:"fa-save",tooltip:"Draw Chart",title:"Draw",onclick:function(){o.app.go("charts_view"),o._saveChart()}}),back:new n.ButtonIcon({icon:"fa-caret-left",tooltip:"Return to Viewer",title:"Return",onclick:function(){o.app.go("charts_view")}})}}),this.title=new n.Input({placeholder:"Chart title",onchange:function(){o.app.config.set("title",o.title.value())}});var h=$("<div/>");h.append(r.wrap((new n.Label({title:"Provide a chart title:"})).$el)),h.append(r.wrap(this.title.$el)),h.append(r.wrap((new n.Label({title:"Select a chart type:"})).$el)),h.append(r.wrap(this.table.$el)),this.tabs.add({id:"main",title:"Start",$el:h}),this.settings=new u(this.app),this.tabs.add({id:"settings",title:"Configuration",$el:this.settings.$el}),this.setElement(this.tabs.$el),this.tabs.hideOperation("back");var o=this;this.chart.on("change:title",function(e){o.title.value(e.get("title")),o.app.config.set("title",e.get("title"))}),this.chart.on("change:type",function(e){o.table.value(e.get("type"))}),this.chart.on("reset",function(e){o._resetChart()}),this.app.charts.on("add",function(e){o.tabs.showOperation("back")}),this.app.charts.on("remove",function(e){o.app.charts.length==0&&o.tabs.hideOperation("back")}),this.app.charts.on("reset",function(e){o.tabs.hideOperation("back")}),this.app.chart.groups.on("add",function(e){o._addGroup(e)}),this.app.chart.groups.on("remove",function(e){o._removeGroup(e)}),this.app.chart.groups.on("reset",function(e){o._removeAllGroups()}),this.app.chart.groups.on("change:key",function(e){o._refreshGroupKey()}),this._resetChart()},show:function(){this.$el.show()},hide:function(){$(".tooltip").hide(),this.$el.hide()},_refreshGroupKey:function(){var e=this,t=0;this.chart.groups.each(function(n){var r=n.get("key","");r==""&&(r="Chart data"),e.tabs.title(n.id,++t+": "+r)})},_addGroupModel:function(){var e=new s({id:r.uuid()});return this.chart.groups.add(e),e},_addGroup:function(e){var t=this,n=new o(this.app,{group:e}),r=t.chart.groups.length;this.tabs.add({id:e.id,$el:n.$el,ondel:function(){t.chart.groups.remove(e.id)}}),this._refreshGroupKey()},_removeGroup:function(e){this.tabs.del(e.id),this._refreshGroupKey()},_removeAllGroups:function(e){this.tabs.delRemovable()},_resetChart:function(){this.chart.set("id",r.uuid()),this.chart.set("type","bardiagram"),this.chart.set("dataset_id",this.app.options.config.dataset_id),this.chart.set("title","New Chart")},_saveChart:function(){this.chart.set({type:this.table.value(),title:this.title.value(),date:r.time()}),this.chart.groups.length==0&&this._addGroupModel();var e=this.app.charts.get(this.chart.id);e?e.copy(this.chart):(e=this.chart.clone(),e.copy(this.chart),this.app.charts.add(e)),e.trigger("redraw",e),this.app.charts.save()}})}),define("plugin/models/config",[],function(){return Backbone.Model.extend({defaults:{query_limit:1e3,query_timeout:500,title:"Create a new chart"}})}),define("plugin/models/charts",["plugin/models/chart","plugin/models/group"],function(e,t){return Backbone.Collection.extend({model:e,vis:null,initialize:function(e,t){this.app=t,this.id=this.app.options.id,this.vis=new Visualization({type:"charts",config:{dataset_id:this.app.options.config.dataset_id,charts:[]}}),this.id&&(this.vis.id=this.id);var n=this.app.options.config.charts;n&&(this.vis.get("config").charts=n)},save:function(){this.vis.get("config").charts=[];var e=this;this.each(function(t){var n={attributes:t.attributes,settings:t.settings.attributes,groups:[]};t.groups.each(function(e){n.groups.push(e.attributes)}),e.vis.get("config").charts.push(n)});var e=this;this.vis.save().fail(function(e,t,n){console.error(e,t,n),alert("Error loading data:\n"+e.responseText)}).then(function(t){t&&t.id&&(e.id=t.id)})},load:function(){var n=this.vis.get("config").charts;for(var r in n){var i=n[r],s=new e;s.set(i.attributes),s.settings.set(i.settings);for(var o in i.groups)s.groups.add(new t(i.groups[o]));s.state("ok","Loaded previously saved visualization."),this.add(s),s.trigger("redraw",s)}}})}),define("plugin/charts/_nvd3/config",[],function(){return{title:"",columns:{y:{title:"Values for y-axis"}},settings:{separator_label:{title:"X axis",type:"separator"},x_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"X-axis",placeholder:"Axis label"},x_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"f",data:[{label:"-- Do not show values --",value:"hide"},{label:"Float",value:"f"},{label:"Exponent",value:"e"},{label:"Integer",value:"d"},{label:"Percentage",value:"p"},{label:"Rounded",value:"r"},{label:"SI-prefix",value:"s"}]},x_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_tick:{title:"Y axis",type:"separator"},y_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"Y-axis",placeholder:"Axis label"},y_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"f",data:[{label:"-- Do not show values --",value:"hide"},{label:"Float",value:"f"},{label:"Exponent",value:"e"},{label:"Integer",value:"d"},{label:"Percentage",value:"p"},{label:"Rounded",value:"r"},{label:"SI-prefix",value:"s"}]},y_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_legend:{title:"Others",type:"separator"},show_legend:{title:"Show legend",info:"Would you like to add a legend?",type:"select",init:"true",data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]}}}}),define("plugin/charts/bardiagram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram"})}),define("plugin/charts/histogram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Histogram",execute:!0,columns:{y:{title:"Observations"}},settings:{x_axis_label:{init:"Breaks"},y_axis_label:{init:"Density"},y_axis_tick:{init:".3"}}})}),define("plugin/charts/horizontal/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram (horizontal)",settings:{x_axis_type:{init:"hide"}}})}),define("plugin/charts/line/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line chart"})}),define("plugin/charts/linewithfocus/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line with focus"})}),define("plugin/charts/piechart/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Pie chart"})}),define("plugin/charts/scatterplot/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Scatter plot",columns:{x:{title:"Values for x-axis"}}})}),define("plugin/charts/stackedarea/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Stacked area"})}),define("plugin/charts/types",["plugin/charts/bardiagram/config","plugin/charts/histogram/config","plugin/charts/horizontal/config","plugin/charts/line/config","plugin/charts/linewithfocus/config","plugin/charts/piechart/config","plugin/charts/scatterplot/config","plugin/charts/stackedarea/config"],function(e,t,n,r,i,s,o,u){return Backbone.Model.extend({defaults:{bardiagram:e,horizontal:n,histogram:t,line:r,linewithfocus:i,piechart:s,scatterplot:o,stackedarea:u}})}),define("plugin/app",["mvc/ui/ui-modal","mvc/ui/ui-portlet","plugin/library/ui","utils/utils","plugin/library/jobs","plugin/library/datasets","plugin/views/charts","plugin/views/chart","plugin/models/config","plugin/models/chart","plugin/models/charts","plugin/charts/types"],function(e,t,n,r,i,s,o,u,a,f,l,c){return Backbone.View.extend({initialize:function(n){this.options=n,Galaxy&&Galaxy.modal?this.modal=Galaxy.modal:this.modal=new e.View,this.config=new a,this.jobs=new i(this),this.types=new c,this.chart=new f,this.charts=new l(null,this),this.datasets=new s(this),this.charts_view=new o(this),this.chart_view=new u(this),this.options.config.widget?this.portlet=$("<div></div>"):this.portlet=new t.View({icon:"fa-bar-chart-o"}),this.portlet.append(this.charts_view.$el),this.portlet.append(this.chart_view.$el),this.options.config.widget?this.setElement(this.portlet):this.setElement(this.portlet.$el);var r=this;this.config.on("change:title",function(){r._refreshTitle()}),this.render(),this.charts.load(),this.charts.length==0?this.go("chart_view"):this.go("charts_view")},go:function(e){switch(e){case"chart_view":this.chart_view.show(),this.charts_view.hide();break;case"charts_view":this.chart_view.hide(),this.charts_view.show()}},render:function(){this._refreshTitle()},_refreshTitle:function(){var e=this.config.get("title");e&&(e=" - "+e),this.portlet.title("Charts"+e)},execute:function(e){},onunload:function(){},log:function(e,t){console.log(e+" "+t)}})});
\ No newline at end of file
diff -r dec159841d670560582aadc1327bec0673f7003a -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 config/plugins/visualizations/charts/static/charts/_nvd3/nvd3.js
--- a/config/plugins/visualizations/charts/static/charts/_nvd3/nvd3.js
+++ b/config/plugins/visualizations/charts/static/charts/_nvd3/nvd3.js
@@ -65,7 +65,7 @@
nv.utils.windowResize(nvd3_model.update);
// set chart state
- chart.set('state', 'ok');
+ chart.state('ok', 'Chart has been drawn.');
});
});
}
diff -r dec159841d670560582aadc1327bec0673f7003a -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 config/plugins/visualizations/charts/static/library/jobs.js
--- a/config/plugins/visualizations/charts/static/library/jobs.js
+++ b/config/plugins/visualizations/charts/static/library/jobs.js
@@ -13,6 +13,20 @@
this.options = Utils.merge(options, this.optionsDefault);
},
+ // clean
+ cleanup: function(chart) {
+ // cleanup previous dataset file
+ var previous = chart.get('dataset_id_job');
+ if (previous) {
+ var self = this;
+ Utils.request('PUT', config.root + 'api/histories/none/contents/' + previous, { deleted: true }, function() {
+ // update galaxy history
+ self._refreshHdas();
+ });
+ }
+
+ },
+
// create job
submit: function(chart, settings_string, columns_string, callback) {
// link this
@@ -39,11 +53,8 @@
}
}
- // cleanup previous dataset file
- var previous = chart.get('dataset_id_job');
- if (previous) {
- Utils.request('PUT', config.root + 'api/histories/' + chart.get('history_id') + '/contents/' + previous, { deleted: true });
- }
+ // cleanup
+ self.cleanup(chart);
// set chart state
chart.state('submit', 'Sending job request...');
@@ -56,9 +67,7 @@
chart.state('failed', 'Job submission failed. No response.');
} else {
// update galaxy history
- if (Galaxy && Galaxy.currHistoryPanel) {
- Galaxy.currHistoryPanel.refreshHdas();
- }
+ self._refreshHdas();
// get dataset
var job = response.outputs[0];
@@ -105,6 +114,14 @@
setTimeout(function() { self._loop(id, callback); }, self.app.config.get('query_timeout'));
}
});
+ },
+
+ // refresh history panel
+ _refreshHdas: function() {
+ // update galaxy history
+ if (Galaxy && Galaxy.currHistoryPanel) {
+ Galaxy.currHistoryPanel.refreshHdas();
+ }
}
});
diff -r dec159841d670560582aadc1327bec0673f7003a -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 config/plugins/visualizations/charts/static/models/charts.js
--- a/config/plugins/visualizations/charts/static/models/charts.js
+++ b/config/plugins/visualizations/charts/static/models/charts.js
@@ -1,30 +1,113 @@
// dependencies
-define(['plugin/models/chart'], function(Chart) {
+define(['plugin/models/chart', 'plugin/models/group'], function(Chart, Group) {
// collection
return Backbone.Collection.extend(
{
- model: Chart,
+ // nested chart model contains collections
+ model : Chart,
- // save charts
- save: function() {
+ // viz model
+ vis: null,
+
+ // initialize
+ initialize: function(options, app) {
+ // initialize parameters
+ this.app = app;
+ this.id = this.app.options.id;
+
// create visualization
- var vis = new Visualization({
- type : 'charts',
+ this.vis = new Visualization({
+ type : 'charts',
config : {
- charts : []
+ dataset_id : this.app.options.config.dataset_id,
+ charts : []
}
});
- // copy attributes
- //vis.set(this.attributes);
+ // add visualization id
+ if (this.id) {
+ this.vis.id = this.id;
+ }
+
+ // add charts
+ var charts_array = this.app.options.config.charts;
+ if (charts_array) {
+ this.vis.get('config').charts = charts_array;
+ }
+ },
+
+ // pack and save nested chart models
+ save: function() {
+ // reset
+ this.vis.get('config').charts = [];
+
+ // pack nested chart models into arrays attributes
+ var self = this;
+ this.each(function(chart) {
+ // create chart dictionary
+ var chart_dict = {
+ attributes : chart.attributes,
+ settings : chart.settings.attributes,
+ groups : []
+ };
+
+ // append groups
+ chart.groups.each(function(group) {
+ chart_dict.groups.push(group.attributes);
+ });
+
+ // add chart to charts array
+ self.vis.get('config').charts.push(chart_dict);
+ });
// save visualization
- vis.save()
- .fail( function( xhr, status, message ){
- console.error( xhr, status, message );
- alert( 'Error loading data:\n' + xhr.responseText );
+ var self = this;
+ this.vis.save()
+ .fail(function(xhr, status, message) {
+ console.error(xhr, status, message);
+ alert( 'Error loading data:\n' + xhr.responseText );
+ })
+ .then(function(response) {
+ if (response && response.id) {
+ self.id = response.id;
+ }
});
+ },
+
+ // load nested models/collections from packed dictionary
+ load: function() {
+ // get charts array
+ var charts_array = this.vis.get('config').charts;
+
+ // unpack chart models
+ for (var i in charts_array) {
+ // get chart details
+ var chart_dict = charts_array[i];
+
+ // construct chart model
+ var chart = new Chart();
+
+ // main
+ chart.set(chart_dict.attributes);
+
+ // get settings
+ chart.settings.set(chart_dict.settings);
+
+ // get groups
+ for (var j in chart_dict.groups) {
+ chart.groups.add(new Group(chart_dict.groups[j]));
+ }
+
+ // reset status
+ chart.state('ok', 'Loaded previously saved visualization.');
+
+ // add to collection
+ this.add(chart);
+
+ // trigger
+ chart.trigger('redraw', chart);
+ }
}
});
diff -r dec159841d670560582aadc1327bec0673f7003a -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 config/plugins/visualizations/charts/static/views/charts.js
--- a/config/plugins/visualizations/charts/static/views/charts.js
+++ b/config/plugins/visualizations/charts/static/views/charts.js
@@ -78,20 +78,25 @@
// title
var chart = self.app.charts.get(chart_id);
- // show modal
- self.app.modal.show({
- title : 'Are you sure?',
- body : 'The selected chart "' + chart.get('title') + '" will be irreversibly deleted.',
- buttons : {
- 'Cancel' : function() {self.app.modal.hide();},
- 'Delete' : function() {
- // hide modal
- self.app.modal.hide();
-
- // remove chart
- self.app.charts.remove(chart_id);
+ // make sure that chart is ready
+ self._wait (chart, function() {
+ self.app.modal.show({
+ title : 'Are you sure?',
+ body : 'The selected chart "' + chart.get('title') + '" will be irreversibly deleted.',
+ buttons : {
+ 'Cancel' : function() {self.app.modal.hide();},
+ 'Delete' : function() {
+ // hide modal
+ self.app.modal.hide();
+
+ // remove chart
+ self.app.charts.remove(chart_id);
+
+ // cleanup
+ self.app.jobs.cleanup(chart);
+ }
}
- }
+ });
});
}
}),
@@ -185,14 +190,19 @@
// show chart editor
_showChartView: function(chart_id) {
+ var self = this;
+ var chart = this.app.charts.get(chart_id);
+ this._wait (chart, function() {
+ self.app.go('chart_view');
+ self.app.chart.copy(chart);
+ });
+ },
+
+ // wait for chart to be ready
+ _wait: function(chart, callback) {
// get chart
- var chart = this.app.charts.get(chart_id);
if (chart.ready()) {
- // show chart view
- this.app.go('chart_view');
-
- // load chart into view
- this.app.chart.copy(chart);
+ callback();
} else {
// show modal
var self = this;
@@ -206,7 +216,7 @@
self.app.modal.hide();
// retry
- self._showChartView(chart_id);
+ setTimeout(function() { self._wait(chart, callback); }, self.app.config.get('query_timeout'));
}
}
});
diff -r dec159841d670560582aadc1327bec0673f7003a -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 config/plugins/visualizations/charts/static/views/viewport.js
--- a/config/plugins/visualizations/charts/static/views/viewport.js
+++ b/config/plugins/visualizations/charts/static/views/viewport.js
@@ -43,17 +43,7 @@
// redraw
this.app.charts.on('redraw', function(chart) {
- // redraw if chart is not currently processed
- if (chart.ready()) {
- self._refreshChart(chart);
- } else {
- // redraw once current drawing process has finished
- chart.on('change:state', function() {
- if (chart.ready()) {
- self._refreshChart(chart);
- }
- });
- }
+ self._drawChart(chart);
});
},
@@ -69,7 +59,7 @@
var item = this.list[chart_id];
if (item) {
// get chart
- var chart = self.app.charts.get(chart_id);
+ var chart = this.app.charts.get(chart_id);
// update portlet
this.portlet.title(chart.get('title'));
@@ -100,13 +90,13 @@
},
// add
- _refreshChart: function(chart) {
+ _drawChart: function(chart) {
// link this
var self = this;
// check
if (!chart.ready()) {
- self.app.log('viewport:_refreshChart()', 'Invalid attempt to refresh chart before completion.');
+ self.app.log('viewport:_drawChart()', 'Invalid attempt to draw chart before completion.');
return;
}
@@ -126,7 +116,7 @@
this.portlet.append($chart_el);
// find svg element
- var svg = d3.select(id + ' svg');
+ var svg = d3.select($chart_el.find('svg')[0]);
// add chart to list
this.list[chart_id] = {
@@ -134,9 +124,6 @@
$el : $chart_el
}
- // show chart from list
- this.showChart(chart_id);
-
// clear all previous handlers (including redraw listeners)
chart.off('change:state');
@@ -172,7 +159,7 @@
// set chart state
chart.state('wait', 'Please wait...');
-
+
// identify chart type
var chart_type = chart.get('type');
var chart_settings = this.app.types.get(chart_type);
diff -r dec159841d670560582aadc1327bec0673f7003a -r e7dfb71eeb796d0cf560ffa48445d243aeb37a67 config/plugins/visualizations/charts/templates/charts.mako
--- a/config/plugins/visualizations/charts/templates/charts.mako
+++ b/config/plugins/visualizations/charts/templates/charts.mako
@@ -71,9 +71,10 @@
require(['plugin/app'], function(App) {
// load options
var options = {
+ id : ${h.to_json_string( visualization_id )} || undefined,
config : ${h.to_json_string( config )}
}
- console.log(options);
+
// create application
app = new App(options);
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: Charts/Ui: Improvements and fixes
by commits-noreply@bitbucket.org 21 Mar '14
by commits-noreply@bitbucket.org 21 Mar '14
21 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/dec159841d67/
Changeset: dec159841d67
User: guerler
Date: 2014-03-21 05:05:21
Summary: Charts/Ui: Improvements and fixes
Affected #: 17 files
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a config/plugins/visualizations/charts/static/app.js
--- a/config/plugins/visualizations/charts/static/app.js
+++ b/config/plugins/visualizations/charts/static/app.js
@@ -59,8 +59,8 @@
this.setElement(this.portlet);
}
- // hide views
- this.charts_view.$el.hide();
+ // start with chart view
+ this.go('chart_view');
// events
var self = this;
@@ -72,6 +72,21 @@
this.render();
},
+ // loads a view and makes sure that all others are hidden
+ go: function(view_id) {
+ // pick view
+ switch (view_id) {
+ case 'chart_view' :
+ this.chart_view.show();
+ this.charts_view.hide();
+ break;
+ case 'charts_view' :
+ this.chart_view.hide();
+ this.charts_view.show();
+ break;
+ }
+ },
+
// render
render: function() {
this._refreshTitle();
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a config/plugins/visualizations/charts/static/build-app.js
--- a/config/plugins/visualizations/charts/static/build-app.js
+++ b/config/plugins/visualizations/charts/static/build-app.js
@@ -3,4 +3,4 @@
// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore may be freely distributed under the MIT license.
-(function(){var e=this,t=e._,n={},r=Array.prototype,i=Object.prototype,s=Function.prototype,o=r.push,u=r.slice,a=r.concat,f=i.toString,l=i.hasOwnProperty,c=r.forEach,h=r.map,p=r.reduce,d=r.reduceRight,v=r.filter,m=r.every,g=r.some,y=r.indexOf,b=r.lastIndexOf,w=Array.isArray,E=Object.keys,S=s.bind,x=function(e){if(e instanceof x)return e;if(!(this instanceof x))return new x(e);this._wrapped=e};typeof exports!="undefined"?(typeof module!="undefined"&&module.exports&&(exports=module.exports=x),exports._=x):e._=x,x.VERSION="1.4.4";var T=x.each=x.forEach=function(e,t,r){if(e==null)return;if(c&&e.forEach===c)e.forEach(t,r);else if(e.length===+e.length){for(var i=0,s=e.length;i<s;i++)if(t.call(r,e[i],i,e)===n)return}else for(var o in e)if(x.has(e,o)&&t.call(r,e[o],o,e)===n)return};x.map=x.collect=function(e,t,n){var r=[];return e==null?r:h&&e.map===h?e.map(t,n):(T(e,function(e,i,s){r.push(t.call(n,e,i,s))}),r)};var N="Reduce of empty array with no initial value";x.reduce=x.foldl=x.inject=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(p&&e.reduce===p)return r&&(t=x.bind(t,r)),i?e.reduce(t,n):e.reduce(t);T(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError(N);return n},x.reduceRight=x.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(d&&e.reduceRight===d)return r&&(t=x.bind(t,r)),i?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=x.keys(e);s=o.length}T(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError(N);return n},x.find=x.detect=function(e,t,n){var r;return C(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},x.filter=x.select=function(e,t,n){var r=[];return e==null?r:v&&e.filter===v?e.filter(t,n):(T(e,function(e,i,s){t.call(n,e,i,s)&&r.push(e)}),r)},x.reject=function(e,t,n){return x.filter(e,function(e,r,i){return!t.call(n,e,r,i)},n)},x.every=x.all=function(e,t,r){t||(t=x.identity);var i=!0;return e==null?i:m&&e.every===m?e.every(t,r):(T(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var C=x.some=x.any=function(e,t,r){t||(t=x.identity);var i=!1;return e==null?i:g&&e.some===g?e.some(t,r):(T(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};x.contains=x.include=function(e,t){return e==null?!1:y&&e.indexOf===y?e.indexOf(t)!=-1:C(e,function(e){return e===t})},x.invoke=function(e,t){var n=u.call(arguments,2),r=x.isFunction(t);return x.map(e,function(e){return(r?t:e[t]).apply(e,n)})},x.pluck=function(e,t){return x.map(e,function(e){return e[t]})},x.where=function(e,t,n){return x.isEmpty(t)?n?void 0:[]:x[n?"find":"filter"](e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},x.findWhere=function(e,t){return x.where(e,t,!0)},x.max=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&x.isEmpty(e))return-Infinity;var r={computed:-Infinity,value:-Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},x.min=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&x.isEmpty(e))return Infinity;var r={computed:Infinity,value:Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o<r.computed&&(r={value:e,computed:o})}),r.value},x.shuffle=function(e){var t,n=0,r=[];return T(e,function(e){t=x.random(n++),r[n-1]=r[t],r[t]=e}),r};var k=function(e){return x.isFunction(e)?e:function(t){return t[e]}};x.sortBy=function(e,t,n){var r=k(t);return x.pluck(x.map(e,function(e,t,i){return{value:e,index:t,criteria:r.call(n,e,t,i)}}).sort(function(e,t){var n=e.criteria,r=t.criteria;if(n!==r){if(n>r||n===void 0)return 1;if(n<r||r===void 0)return-1}return e.index<t.index?-1:1}),"value")};var L=function(e,t,n,r){var i={},s=k(t==null?x.identity:t);return T(e,function(t,o){var u=s.call(n,t,o,e);r(i,u,t)}),i};x.groupBy=function(e,t,n){return L(e,t,n,function(e,t,n){(x.has(e,t)?e[t]:e[t]=[]).push(n)})},x.countBy=function(e,t,n){return L(e,t,n,function(e,t){x.has(e,t)||(e[t]=0),e[t]++})},x.sortedIndex=function(e,t,n,r){n=n==null?x.identity:k(n);var i=n.call(r,t),s=0,o=e.length;while(s<o){var u=s+o>>>1;n.call(r,e[u])<i?s=u+1:o=u}return s},x.toArray=function(e){return e?x.isArray(e)?u.call(e):e.length===+e.length?x.map(e,x.identity):x.values(e):[]},x.size=function(e){return e==null?0:e.length===+e.length?e.length:x.keys(e).length},x.first=x.head=x.take=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,0,t):e[0]},x.initial=function(e,t,n){return u.call(e,0,e.length-(t==null||n?1:t))},x.last=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,Math.max(e.length-t,0)):e[e.length-1]},x.rest=x.tail=x.drop=function(e,t,n){return u.call(e,t==null||n?1:t)},x.compact=function(e){return x.filter(e,x.identity)};var A=function(e,t,n){return T(e,function(e){x.isArray(e)?t?o.apply(n,e):A(e,t,n):n.push(e)}),n};x.flatten=function(e,t){return A(e,t,[])},x.without=function(e){return x.difference(e,u.call(arguments,1))},x.uniq=x.unique=function(e,t,n,r){x.isFunction(t)&&(r=n,n=t,t=!1);var i=n?x.map(e,n,r):e,s=[],o=[];return T(i,function(n,r){if(t?!r||o[o.length-1]!==n:!x.contains(o,n))o.push(n),s.push(e[r])}),s},x.union=function(){return x.uniq(a.apply(r,arguments))},x.intersection=function(e){var t=u.call(arguments,1);return x.filter(x.uniq(e),function(e){return x.every(t,function(t){return x.indexOf(t,e)>=0})})},x.difference=function(e){var t=a.apply(r,u.call(arguments,1));return x.filter(e,function(e){return!x.contains(t,e)})},x.zip=function(){var e=u.call(arguments),t=x.max(x.pluck(e,"length")),n=new Array(t);for(var r=0;r<t;r++)n[r]=x.pluck(e,""+r);return n},x.unzip=function(e){var t=[];return x.each(e,function(e,n){x.each(e,function(e,r){t.length<=r&&(t[r]=[]),t[r][n]=e})}),t},x.object=function(e,t){if(e==null)return{};var n={};for(var r=0,i=e.length;r<i;r++)t?n[e[r]]=t[r]:n[e[r][0]]=e[r][1];return n},x.indexOf=function(e,t,n){if(e==null)return-1;var r=0,i=e.length;if(n){if(typeof n!="number")return r=x.sortedIndex(e,t),e[r]===t?r:-1;r=n<0?Math.max(0,i+n):n}if(y&&e.indexOf===y)return e.indexOf(t,n);for(;r<i;r++)if(e[r]===t)return r;return-1},x.lastIndexOf=function(e,t,n){if(e==null)return-1;var r=n!=null;if(b&&e.lastIndexOf===b)return r?e.lastIndexOf(t,n):e.lastIndexOf(t);var i=r?n:e.length;while(i--)if(e[i]===t)return i;return-1},x.range=function(e,t,n){arguments.length<=1&&(t=e||0,e=0),n=arguments[2]||1;var r=Math.max(Math.ceil((t-e)/n),0),i=0,s=new Array(r);while(i<r)s[i++]=e,e+=n;return s};var O=function(){};x.bind=function(e,t){var n,r;if(e.bind===S&&S)return S.apply(e,u.call(arguments,1));if(!x.isFunction(e))throw new TypeError;return n=u.call(arguments,2),r=function(){if(this instanceof r){O.prototype=e.prototype;var i=new O;O.prototype=null;var s=e.apply(i,n.concat(u.call(arguments)));return Object(s)===s?s:i}return e.apply(t,n.concat(u.call(arguments)))}},x.partial=function(e){var t=u.call(arguments,1);return function(){return e.apply(this,t.concat(u.call(arguments)))}},x.bindAll=function(e){var t=u.call(arguments,1);if(t.length===0)throw new Error("bindAll must be passed function names");return T(t,function(t){e[t]=x.bind(e[t],e)}),e},x.memoize=function(e,t){var n={};return t||(t=x.identity),function(){var r=t.apply(this,arguments);return x.has(n,r)?n[r]:n[r]=e.apply(this,arguments)}},x.delay=function(e,t){var n=u.call(arguments,2);return setTimeout(function(){return e.apply(null,n)},t)},x.defer=function(e){return x.delay.apply(x,[e,1].concat(u.call(arguments,1)))},x.throttle=function(e,t,n){var r,i,s,o,u=0,a=function(){u=new Date,s=null,o=e.apply(r,i)};return function(){var f=new Date;!u&&n===!1&&(u=f);var l=t-(f-u);return r=this,i=arguments,l<=0?(clearTimeout(s),s=null,u=f,o=e.apply(r,i)):s||(s=setTimeout(a,l)),o}},x.debounce=function(e,t,n){var r,i;return function(){var s=this,o=arguments,u=function(){r=null,n||(i=e.apply(s,o))},a=n&&!r;return clearTimeout(r),r=setTimeout(u,t),a&&(i=e.apply(s,o)),i}},x.once=function(e){var t=!1,n;return function(){return t?n:(t=!0,n=e.apply(this,arguments),e=null,n)}},x.wrap=function(e,t){return function(){var n=[e];return o.apply(n,arguments),t.apply(this,n)}},x.compose=function(){var e=arguments;return function(){var t=arguments;for(var n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},x.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},x.keys=E||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)x.has(e,n)&&t.push(n);return t},x.values=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push(e[n]);return t},x.pairs=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push([n,e[n]]);return t},x.invert=function(e){var t={};for(var n in e)x.has(e,n)&&(t[e[n]]=n);return t},x.functions=x.methods=function(e){var t=[];for(var n in e)x.isFunction(e[n])&&t.push(n);return t.sort()},x.extend=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]=t[n]}),e},x.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return T(n,function(n){n in e&&(t[n]=e[n])}),t},x.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)x.contains(n,i)||(t[i]=e[i]);return t},x.defaults=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]===void 0&&(e[n]=t[n])}),e},x.clone=function(e){return x.isObject(e)?x.isArray(e)?e.slice():x.extend({},e):e},x.tap=function(e,t){return t(e),e};var M=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof x&&(e=e._wrapped),t instanceof x&&(t=t._wrapped);var i=f.call(e);if(i!=f.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=M(e[o],t[o],n,r)))break}else{var a=e.constructor,l=t.constructor;if(a!==l&&!(x.isFunction(a)&&a instanceof a&&x.isFunction(l)&&l instanceof l))return!1;for(var c in e)if(x.has(e,c)){o++;if(!(u=x.has(t,c)&&M(e[c],t[c],n,r)))break}if(u){for(c in t)if(x.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};x.isEqual=function(e,t){return M(e,t,[],[])},x.isEmpty=function(e){if(e==null)return!0;if(x.isArray(e)||x.isString(e))return e.length===0;for(var t in e)if(x.has(e,t))return!1;return!0},x.isElement=function(e){return!!e&&e.nodeType===1},x.isArray=w||function(e){return f.call(e)=="[object Array]"},x.isObject=function(e){return e===Object(e)},T(["Arguments","Function","String","Number","Date","RegExp"],function(e){x["is"+e]=function(t){return f.call(t)=="[object "+e+"]"}}),x.isArguments(arguments)||(x.isArguments=function(e){return!!e&&!!x.has(e,"callee")}),typeof /./!="function"&&(x.isFunction=function(e){return typeof e=="function"}),x.isFinite=function(e){return isFinite(e)&&!isNaN(parseFloat(e))},x.isNaN=function(e){return x.isNumber(e)&&e!=+e},x.isBoolean=function(e){return e===!0||e===!1||f.call(e)=="[object Boolean]"},x.isNull=function(e){return e===null},x.isUndefined=function(e){return e===void 0},x.has=function(e,t){return l.call(e,t)},x.noConflict=function(){return e._=t,this},x.identity=function(e){return e},x.times=function(e,t,n){var r=Array(e);for(var i=0;i<e;i++)r[i]=t.call(n,i);return r},x.random=function(e,t){return t==null&&(t=e,e=0),e+Math.floor(Math.random()*(t-e+1))};var _={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};_.unescape=x.invert(_.escape);var D={escape:new RegExp("["+x.keys(_.escape).join("")+"]","g"),unescape:new RegExp("("+x.keys(_.unescape).join("|")+")","g")};x.each(["escape","unescape"],function(e){x[e]=function(t){return t==null?"":(""+t).replace(D[e],function(t){return _[e][t]})}}),x.result=function(e,t){if(e==null)return void 0;var n=e[t];return x.isFunction(n)?n.call(e):n},x.mixin=function(e){T(x.functions(e),function(t){var n=x[t]=e[t];x.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),F.call(this,n.apply(x,e))}})};var P=0;x.uniqueId=function(e){var t=++P+"";return e?e+t:t},x.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var H=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},j=/\\|'|\r|\n|\t|\u2028|\u2029/g;x.template=function(e,t,n){var r;n=x.defaults({},n,x.templateSettings);var i=new RegExp([(n.escape||H).source,(n.interpolate||H).source,(n.evaluate||H).source].join("|")+"|$","g"),s=0,o="__p+='";e.replace(i,function(t,n,r,i,u){return o+=e.slice(s,u).replace(j,function(e){return"\\"+B[e]}),n&&(o+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'"),r&&(o+="'+\n((__t=("+r+"))==null?'':__t)+\n'"),i&&(o+="';\n"+i+"\n__p+='"),s=u+t.length,t}),o+="';\n",n.variable||(o="with(obj||{}){\n"+o+"}\n"),o="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+o+"return __p;\n";try{r=new Function(n.variable||"obj","_",o)}catch(u){throw u.source=o,u}if(t)return r(t,x);var a=function(e){return r.call(this,e,x)};return a.source="function("+(n.variable||"obj")+"){\n"+o+"}",a},x.chain=function(e){return x(e).chain()};var F=function(e){return this._chain?x(e).chain():e};x.mixin(x),T(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];x.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],F.call(this,n)}}),T(["concat","join","slice"],function(e){var t=r[e];x.prototype[e]=function(){return F.call(this,t.apply(this._wrapped,arguments))}}),x.extend(x.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this),define("libs/underscore",function(e){return function(){var t,n;return t||e._}}(this)),define("utils/utils",["libs/underscore"],function(e){function t(e,t,r){n("GET",e,{},t,r)}function n(e,t,n,r,i){if(e=="GET"||e=="DELETE")t.indexOf("?")==-1?t+="?":t+="&",t+=$.param(n);var s=new XMLHttpRequest;s.open(e,t,!0),s.setRequestHeader("Accept","application/json"),s.setRequestHeader("Cache-Control","no-cache"),s.setRequestHeader("X-Requested-With","XMLHttpRequest"),s.setRequestHeader("Content-Type","application/json"),s.onloadend=function(){var e=s.status;try{response=jQuery.parseJSON(s.responseText)}catch(t){response=s.responseText}e==200?r&&r(response):i&&i(response)},e=="GET"||e=="DELETE"?s.send():s.send(JSON.stringify(n))}function r(e,t){var n=$('<div class="'+e+'"></div>');n.appendTo(":eq(0)");var r=n.css(t);return n.remove(),r}function i(e){$('link[href^="'+e+'"]').length||$('<link href="'+galaxy_config.root+e+'" rel="stylesheet">').appendTo("head")}function s(t,n){return t?e.defaults(t,n):n}function o(e,t){var n="";if(e>=1e11)e/=1e11,n="TB";else if(e>=1e8)e/=1e8,n="GB";else if(e>=1e5)e/=1e5,n="MB";else if(e>=100)e/=100,n="KB";else{if(!(e>0))return"<strong>-</strong>";e*=10,n="b"}var r=Math.round(e)/10;return t?r+" "+n:"<strong>"+r+"</strong> "+n}function u(){return(new Date).getTime().toString(36)}function a(e){var t=$("<p></p>");return t.append(e),t}function f(){var e=new Date,t=(e.getHours()<10?"0":"")+e.getHours(),n=(e.getMinutes()<10?"0":"")+e.getMinutes(),r=e.getDate()+"/"+(e.getMonth()+1)+"/"+e.getFullYear()+", "+t+":"+n;return r}return{cssLoadFile:i,cssGetAttribute:r,get:t,merge:s,bytesToString:o,uuid:u,time:f,wrap:a,request:n}}),define("mvc/ui/ui-modal",["utils/utils"],function(e){var t=Backbone.View.extend({elMain:"body",optionsDefault:{title:"ui-modal",body:"",backdrop:!0,height:null,width:null,closing_events:!1},buttonList:{},initialize:function(e){e&&this._create(e)},show:function(e){this.initialize(e),this.options.height?(this.$body.css("height",this.options.height),this.$body.css("overflow","hidden")):this.$body.css("max-height",$(window).height()/2),this.options.width&&this.$dialog.css("width",this.options.width),this.visible?this.$el.show():this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.visible=!1,this.$el.fadeOut("fast")},enableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!1)},disableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!0)},showButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).show()},hideButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).hide()},getButton:function(e){var t=this.buttonList[e];return this.$buttons.find("#"+t)},scrollTop:function(){return this.$body.scrollTop()},_create:function(e){var t=this;this.options=_.defaults(e,this.optionsDefault),this.options.body=="progress"&&(this.options.body=$('<div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width:100%"></div></div>')),this.$el&&(this.$el.remove(),$(document).off("keyup")),this.setElement(this._template(this.options.title)),this.$dialog=this.$el.find(".modal-dialog"),this.$body=this.$el.find(".modal-body"),this.$footer=this.$el.find(".modal-footer"),this.$buttons=this.$el.find(".buttons"),this.$backdrop=this.$el.find(".modal-backdrop"),this.$body.html(this.options.body),this.options.backdrop||this.$backdrop.removeClass("in");if(this.options.buttons){this.buttonList={};var n=0;$.each(this.options.buttons,function(e,r){var i="button-"+n++;t.$buttons.append($('<button id="'+i+'"></button>').text(e).click(r)).append(" "),t.buttonList[e]=i})}else this.$footer.hide();$(this.elMain).append($(this.el)),this.options.closing_events&&(this.options.buttons.Pause||$(document).on("keyup",function(e){e.keyCode==27&&t.hide()}),this.$el.find(".modal-backdrop").on("click",function(){t.hide()}))},_template:function(e){return'<div class="modal"><div class="modal-backdrop fade in" style="z-index: -1;"></div><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" style="display: none;">×</button><h4 class="title">'+e+"</h4>"+"</div>"+'<div class="modal-body" style="position: static;"></div>'+'<div class="modal-footer">'+'<div class="buttons" style="float: right;"></div>'+"</div>"+"</div"+"</div>"+"</div>"}});return{View:t}}),define("mvc/ui/ui-portlet",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,optionsDefault:{title:"",icon:"",buttons:null,body:null,height:null,operations:null,placement:"bottom",overflow:"auto"},$title:null,$content:null,$buttons:null,$operations:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$content=this.$el.find("#content"),this.$title=this.$el.find("#title-text"),this.options.height&&(this.$el.find("#body").css("height",this.options.height),this.$el.find("#content").css("overflow",this.options.overflow)),this.$buttons=$(this.el).find("#buttons");if(this.options.buttons){var n=this;$.each(this.options.buttons,function(e,t){t.$el.prop("id",e),n.$buttons.append(t.$el)})}else this.$buttons.remove();this.$operations=$(this.el).find("#operations");if(this.options.operations){var n=this;$.each(this.options.operations,function(e,t){t.$el.prop("id",e),n.$operations.append(t.$el)})}this.options.body&&this.append(this.options.body)},append:function(t){this.$content.append(e.wrap(t))},content:function(){return this.$content},show:function(){this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},enableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!1)},disableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!0)},hideOperation:function(e){this.$operations.find("#"+e).hide()},showOperation:function(e){this.$operations.find("#"+e).show()},setOperation:function(e,t){var n=this.$operations.find("#"+e);n.off("click"),n.on("click",t)},title:function(e){var t=this.$title;return e&&t.html(e),t.html()},_template:function(e){var t='<div class="toolForm">';if(e.title||e.icon)t+='<div id="title" class="toolFormTitle" style="overflow: hidden;"><div id="operations" style="float: right;"></div><div style="overflow: hidden;">',e.icon&&(t+='<i style="padding-top: 3px; float: left; font-size: 1.2em" class="icon fa '+e.icon+'"> </i>'),t+='<div id="title-text" style="padding-top: 2px; float: left;">'+e.title+"</div>",t+="</div></div>";return t+='<div id="body" class="toolFormBody">',e.placement=="top"&&(t+='<div id="buttons" class="buttons" style="height: 50px; padding: 10px;"></div>'),t+='<div id="content" class="content" style="height: inherit; padding: 10px;"></div>',e.placement=="bottom"&&(t+='<div id="buttons" class="buttons" style="height: 50px; padding: 10px;"></div>'),t+="</div></div>",t}});return{View:t}}),define("plugin/library/ui-select",["utils/utils"],function(e){var t=Backbone.View.extend({optionsDefault:{id:"",cls:"",empty:"No data available",visible:!0,wait:!1},selected:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$select=this.$el.find("#select"),this.$icon=this.$el.find("#icon"),this.selected=this.options.value;var n=this;this.options.onchange&&this.$select.on("change",function(){n.value(n.$select.val())}),this._refresh(),this.options.visible||this.hide(),this.options.wait?this.wait():this.show()},value:function(e){var t=this.selected;e!==undefined&&(this.selected=e,this.$select.val(e));var n=this.selected;return n&&n!=t&&this.options.onchange&&this.options.onchange(n),n},text:function(){return this.$select.find("option:selected").text()},show:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-caret-down"),this.$select.show(),this.$el.show()},hide:function(){this.$el.hide()},wait:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-spinner fa-spin"),this.$select.hide()},disabled:function(){return this.$select.is(":disabled")},enable:function(){this.$select.prop("disabled",!1)},disable:function(){this.$select.prop("disabled",!0)},add:function(e){this.$select.append(this._templateOption(e)),this._refresh()},del:function(e){this.$select.find("option[value="+e+"]").remove(),this.$select.trigger("change"),this._refresh()},update:function(e){this.$select.find("option").remove();for(var t in e)this.$select.append(this._templateOption(e[t]));!this.selected&&e.length>0&&this.value(e[0].value),this._refresh()},_refresh:function(){this.$select.find("option[value=null]").remove();var e=this.$select.find("option").length;e==0?(this.$select.append(this._templateOption({value:"null",label:this.options.empty})),this.disable()):(this.enable(),this.selected&&this.$select.val(this.selected))},_exists:function(e){return 0!=this.$select.find("option[value="+e+"]").length},_templateOption:function(e){return'<option value="'+e.value+'">'+e.label+"</option>"},_template:function(e){var t='<div id="'+e.id+'" class="styled-select">'+'<div class="button">'+'<i id="icon"/>'+"</div>"+'<select id="select" class="select '+e.cls+" "+e.id+'">';for(key in e.data){var n=e.data[key],r="";if(n.value==e.value||n.value=="")r="selected";t+='<option value="'+n.value+'" '+r+">"+n.label+"</option>"}return t+="</select></div>",t}});return{View:t}}),define("plugin/library/ui",["utils/utils","plugin/library/ui-select"],function(e,t){var n=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options))},title:function(e){this.$el.find("b").html(e)},_template:function(e){return"<label><b>"+e.title+"</b></label>"},value:function(){return options.title}}),r=Backbone.View.extend({optionsDefault:{id:null,title:"","float":"right",cls:"btn-default",icon:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t='<button id="'+e.id+'" type="submit" style="margin-right: 5px; float: '+e.float+';" type="button" class="btn '+e.cls+'">';return e.icon&&(t+='<i class="icon fa '+e.icon+'"></i> '),t+=e.title+"</button>",t}}),i=Backbone.View.extend({optionsDefault:{"float":"right",icon:"",tooltip:"",placement:"bottom",title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){return'<div><span class="fa '+e.icon+'" style="font-size: 1.2em;"/> '+e.title+"</div>"}}),s=Backbone.View.extend({optionsDefault:{title:"",id:null,"float":"right",cls:"icon-btn",icon:"",tooltip:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t="";e.title&&(t="width: auto;");var n='<div id="'+e.id+'" style="margin-right: 5px; float: '+e.float+"; "+t+'" class="'+e.cls+'">';return e.title?n+='<div style="margin-right: 5px; margin-left: 5px;"><i class="icon fa '+e.icon+'"/> '+'<span style="position: relative; font-size: 0.8em; font-weight: normal; top: -1px;">'+e.title+"</span>"+"</div>":n+='<i class="icon fa '+e.icon+'"/>',n+="</div>",n}}),o=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick)},_template:function(e){return'<div><a href="javascript:void(0)">'+e.title+"</a></div>"}}),u=Backbone.View.extend({optionsDefault:{message:"",status:"info",persistent:!1},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement("<div></div>")},update:function(t){this.options=e.merge(t,this.optionsDefault);if(t.message!=""){this.$el.html(this._template(this.options)),this.$el.fadeIn();if(!t.persistent){var n=this;window.setTimeout(function(){n.$el.is(":visible")?n.$el.fadeOut():n.$el.hide()},3e3)}}else this.$el.fadeOut()},_template:function(e){return'<div class="alert alert-'+e.status+'" style="padding: 2px 2px 2px 10px;">'+e.message+"</div>"}}),a=Backbone.View.extend({optionsDefault:{onclick:null,searchword:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options));var n=this;this.options.onclick&&this.$el.on("submit",function(e){var t=n.$el.find("#search");n.options.onclick(t.val())})},_template:function(e){return'<div class="search"><form onsubmit="return false;"><input id="search" class="form-control input-sm" type="text" name="search" placeholder="Search..." value="'+e.searchword+'">'+'<button type="submit" class="btn search-btn">'+'<i class="fa fa-search"></i>'+"</button>"+"</form>"+"</div>"}}),f=Backbone.View.extend({optionsDefault:{title:"Unlabeled",body:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.body&&this.$el.find(".body").append(this.options.body)},_template:function(e){return'<div id="title" class="title">'+e.title+":"+"</div>"}}),l=Backbone.View.extend({optionsDefault:{id:"",title:"",target:"",href:"",onunload:null,onclick:null,visible:!0,icon:null,tag:""},$menu:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement($(this._template(this.options)));var n=$(this.el).find(".root"),r=this;n.on("click",function(e){e.preventDefault(),r.options.onclick&&r.options.onclick()}),this.options.visible||this.hide()},show:function(){$(this.el).show()},hide:function(){$(this.el).hide()},addMenu:function(t){var n={title:"",target:"",href:"",onclick:null,divider:!1,icon:null};n=e.merge(t,n),this.$menu||($(this.el).append(this._templateMenu()),this.$menu=$(this.el).find(".menu"));var r=$(this._templateMenuItem(n));r.on("click",function(e){e.preventDefault(),n.onclick&&n.onclick()}),this.$menu.append(r),n.divider&&this.$menu.append($(this._templateDivider()))},_templateMenuItem:function(e){var t='<li><a href="'+e.href+'" target="'+e.target+'">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),t+=" "+e.title+"</a>"+"</li>",t},_templateMenu:function(){return'<ul class="menu dropdown-menu pull-right" role="menu"></ul>'},_templateDivider:function(){return'<li class="divider"></li>'},_template:function(e){var t='<div id="'+e.id+'" class="button-menu btn-group">'+'<button type="button" class="root btn btn-default dropdown-toggle" data-toggle="dropdown">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),"</button></div>",t}}),c=Backbone.View.extend({optionsDefault:{value:"",type:"text",placeholder:"",disabled:!1,visible:!0},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.disabled&&this.$el.prop("disabled",!0),this.options.visible||this.$el.hide();var n=this;this.options.onchange&&this.$el.on("input",function(){n.options.onchange()})},value:function(e){return e!==undefined&&this.$el.val(e),this.$el.val()},_template:function(e){return'<input id="'+e.id+'" type="'+e.type+'" value="'+e.value+'" placeholder="'+e.placeholder+'" class="form-control">'}});return{Label:n,Button:r,Icon:i,ButtonIcon:s,Input:c,Anchor:o,Message:u,Searchbox:a,Title:f,Select:t,ButtonMenu:l}}),define("plugin/library/jobs",["utils/utils"],function(e){return Backbone.Model.extend({initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},submit:function(t,n,r,i){var s=this,o=t.id,u=t.get("type"),a=this.app.types.get(u);data={tool_id:"rkit",inputs:{input:{id:t.get("dataset_id"),src:"hda"},module:u,columns:r,settings:n}};var f=t.get("dataset_id_job");f&&e.request("PUT",config.root+"api/histories/"+t.get("history_id")+"/contents/"+f,{deleted:!0}),t.state("submit","Sending job request..."),e.request("POST",config.root+"api/tools",data,function(e){if(!e.outputs||e.outputs.length==0)t.state("failed","Job submission failed. No response.");else{Galaxy&&Galaxy.currHistoryPanel&&Galaxy.currHistoryPanel.refreshHdas();var n=e.outputs[0];t.state("queued","Job has been queued..."),t.set("dataset_id_job",n.id),s._loop(n.id,function(e){switch(e.state){case"ok":return t.state("success","Job completed successfully..."),i(e),!0;case"error":return t.state("failed","Job has failed. Please check the history for details."),!0;case"running":return t.state("running","Job is running..."),!1}})}},function(e){var n="";e&&e.message&&e.message.data&&e.message.data.input&&(n=e.message.data.input+"."),t.state("failed","This visualization requires processing by the R-kit. Please make sure that it is installed. "+n)})},_loop:function(t,n){var r=this;e.request("GET",config.root+"api/jobs/"+t,{},function(e){n(e)||setTimeout(function(){r._loop(t,n)},r.app.config.get("query_timeout"))})}})}),define("plugin/library/datasets",["utils/utils"],function(e){return Backbone.Collection.extend({list:{},initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},request:function(t,n,r){var i=this;if(t.groups)this._fetch(t,n);else{var s=this.list[t.id];if(s){n(s);return}e.request("GET",config.root+"api/datasets/"+t.id,{},function(e){switch(e.state){case"error":r&&r(e);break;default:i.list[t.id]=e,n(e)}})}},_fetch:function(t,n){var r=t.start?t.start:0,i=Math.abs(t.end-t.start),s=this.app.config.get("query_limit");if(!i||i>s)i=s;var o="",u={},a=0;for(var f in t.groups){var l=t.groups[f];for(var c in l.columns){var h=l.columns[c];o+=h+",",u[h]=a,a++}}if(a==0){n({});return}o=o.substring(0,o.length-1);var p=t.groups.slice(0);for(var f in p)p[f].values=[];var d=this;e.request("GET",config.root+"api/datasets/"+t.id,{data_type:"raw_data",provider:"dataset-column",limit:i,offset:r,indeces:o},function(e){for(var i in e.data){var s=e.data[i];for(var o in t.groups){var a=t.groups[o],f={x:parseInt(i)+r};for(var l in a.columns){var c=a.columns[l],h=u[c],d=s[h];if(isNaN(d)||!d)d=0;f[l]=d}p[o].values.push(f)}}n(p)})}})}),define("plugin/library/ui-table",["utils/utils"],function(e){return Backbone.View.extend({row:null,row_count:0,optionsDefault:{content:"No content available.",onchange:null,ondblclick:null,onconfirm:null},events:{click:"_onclick",dblclick:"_ondblclick"},first:!0,initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(t));this.$thead=n.find("thead"),this.$tbody=n.find("tbody"),this.$tmessage=n.find("tmessage"),this.setElement(n),this.row=$("<tr></tr>")},addHeader:function(e){var t=$("<th></th>");t.append(e),this.row.append(t)},appendHeader:function(){this.$thead.append(this.row),this.row=$("<tr></tr>")},add:function(e,t){var n=$("<td></td>");t&&n.css("width",t),n.append(e),this.row.append(n)},append:function(e){this._commit(e)},prepend:function(e){this._commit(e,!0)},remove:function(e){var t=this.$tbody.find("#"+e);t.length>0&&(t.remove(),this.row_count--,this._refresh())},removeAll:function(){this.$tbody.html(""),this.row_count=0,this._refresh()},value:function(e){this.before=this.$tbody.find(".current").attr("id"),e!==undefined&&(this.$tbody.find("tr").removeClass("current"),e&&this.$tbody.find("#"+e).addClass("current"));var t=this.$tbody.find(".current").attr("id");return t===undefined?null:(t!=this.before&&this.options.onchange&&this.options.onchange(e),t)},size:function(){return this.$tbody.find("tr").length},_commit:function(e,t){this.remove(e),this.row.attr("id",e),t?this.$tbody.prepend(this.row):this.$tbody.append(this.row),this.row=$("<tr></tr>"),this.row_count++,this._refresh()},_onclick:function(e){var t=this.value(),n=$(e.target).closest("tr").attr("id");n&&t!=n&&(this.options.onconfirm?this.options.onconfirm(n):this.value(n))},_ondblclick:function(e){var t=this.value();t&&this.options.ondblclick&&this.options.ondblclick(t)},_refresh:function(){this.row_count==0?this.$tmessage.show():this.$tmessage.hide()},_template:function(e){return'<div><table class="grid"><thead></thead><tbody style="cursor: pointer;"></tbody></table><tmessage>'+e.content+"</tmessage>"+"<div>"}})}),define("plugin/models/group",[],function(){return Backbone.Model.extend({defaults:{key:"Data label",date:""},reset:function(){this.clear({silent:!0}).set(this.defaults),this.trigger("reset",this)}})}),define("plugin/views/viewport",["mvc/ui/ui-portlet","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({list:{},optionsDefault:{height:300},initialize:function(r,i){this.app=r,this.options=n.merge(i,this.optionsDefault),this.portlet=new e.View({title:"title",height:this.options.height,overflow:"hidden",operations:{edit:new t.ButtonIcon({icon:"fa-gear",tooltip:"Customize Chart",title:"Customize"})}}),this.setElement(this.portlet.$el);var s=this;this.app.charts.on("remove",function(e){s._removeChart(e.id)}),this.app.charts.on("redraw",function(e){e.ready()?s._refreshChart(e):e.on("change:state",function(){e.ready()&&s._refreshChart(e)})})},showChart:function(e){this.show(),this.hideCharts();var t=this.list[e];if(t){var n=self.app.charts.get(e);this.portlet.title(n.get("title")),this.portlet.setOperation("edit",function(){self.app.chart.copy(n),self.app.charts_view.hide(),self.app.chart_view.$el.show()}),t.$el.show(),$(window).trigger("resize")}},hideCharts:function(){this.$el.find(".item").hide()},show:function(){$(".tooltip").hide(),this.$el.show()},hide:function(){$(".tooltip").hide(),this.$el.hide()},_refreshChart:function(e){var t=this;if(!e.ready()){t.app.log("viewport:_refreshChart()","Invalid attempt to refresh chart before completion.");return}var n=e.id;this._removeChart(n);var r="#"+n,i=$(this._template({id:r}));this.portlet.append(i);var s=d3.select(r+" svg");this.list[n]={svg:s,$el:i},this.showChart(n),e.off("change:state"),e.on("change:state",function(){var t=i.find("#info"),n=t.find("#icon");n.removeClass(),t.show(),t.find("#text").html(e.get("state_info"));var r=e.get("state");switch(r){case"ok":t.hide();break;case"failed":n.addClass("fa fa-warning");break;default:n.addClass("fa fa-spinner fa-spin")}}),e.state("wait","Please wait...");var o=e.get("type"),u=this.app.types.get(o),t=this;require(["plugin/charts/"+o+"/"+o],function(n){var r=new n(t.app,{svg:s});u.execute?t.app.jobs.submit(e,t._defaultSettingsString(e),t._defaultRequestString(e),function(){r.draw(e,t._defaultRequestDictionary(e))}):r.draw(e,t._defaultRequestDictionary(e))})},_removeChart:function(e){var t=this.list[e];t&&(t.svg.remove(),t.$el.remove())},_template:function(e){return'<div id="'+e.id.substr(1)+'" class="item">'+'<span id="info">'+'<span id="icon" style="font-size: 1.2em; display: inline-block;"/>'+'<span id="text" style="position: relative; margin-left: 5px; top: -1px; font-size: 1.0em;"/>'+"</span>"+'<svg style="height: auto;"/>'+"</div>"},_defaultRequestString:function(e){var t=this.app.types.get(e.get("type")),n="",r=0;return e.groups.each(function(e){for(var i in t.columns)n+=i+"_"+ ++r+":"+(parseInt(e.get(i))+1)+", "}),n.substring(0,n.length-2)},_defaultSettingsString:function(e){var t="";for(key in e.settings.attributes)t+=key+":"+e.settings.get(key)+", ";return t.substring(0,t.length-2)},_defaultRequestDictionary:function(e){var t=this.app.types.get(e.get("type")),n={id:e.get("dataset_id"),groups:[]},r=0;return e.groups.each(function(e){var i={};for(var s in t.columns)i[s]=e.get(s);n.groups.push({key:++r+":"+e.get("key"),columns:i})}),n}})}),define("plugin/views/charts",["mvc/ui/ui-portlet","plugin/library/ui-table","plugin/library/ui","utils/utils","plugin/models/group","plugin/views/viewport"],function(e,t,n,r,i,s){return Backbone.View.extend({initialize:function(i,o){this.app=i,this.viewport_view=new s(i),this.table=new t({content:"Add charts to this table.",ondblclick:function(e){var t=u.app.charts.get(e);u.app.chart.copy(t),u.hide(),u.app.chart_view.$el.show()},onchange:function(e){var t=u.app.charts.get(e);u.app.config.set("title",t.get("title")),u.viewport_view.showChart(e)}});var u=this;this.portlet=new e.View({icon:"fa-list",title:"List of created charts:",height:100,operations:{"new":new n.ButtonIcon({icon:"fa-magic",tooltip:"Create a new Chart",title:"New",onclick:function(){u.hide(),u.app.chart.reset(),u.app.chart_view.$el.show()}}),"delete":new n.ButtonIcon({icon:"fa-trash-o",tooltip:"Delete this Chart",title:"Delete",onclick:function(){var e=u.table.value();if(!e)return;var t=u.app.charts.get(e);u.app.modal.show({title:"Are you sure?",body:'The selected chart "'+t.get("title")+'" will be irreversibly deleted.',buttons:{Cancel:function(){u.app.modal.hide()},Delete:function(){u.app.modal.hide(),u.app.charts.remove(e)}}})}})}}),this.portlet.append(this.table.$el),this.app.options.config.widget||this.$el.append(this.portlet.$el),this.$el.append(r.wrap("")),this.$el.append(this.viewport_view.$el);var u=this;this.app.charts.on("add",function(e){u._addChart(e)}),this.app.charts.on("remove",function(e){u._removeChart(e)}),this.app.charts.on("change",function(e){u._changeChart(e)})},hide:function(){$(".tooltip").hide(),this.$el.hide()},_addChart:function(e){var t=e.get("title");t==""&&(t="Untitled"),this.table.add(t);var n=this.app.types.get(e.get("type"));this.table.add(n.title),this.table.add("Last change: "+e.get("date")),this.table.prepend(e.get("id")),this.table.value(e.get("id"))},_removeChart:function(e){this.table.remove(e.id),this.table.size()==0?(this.hide(),this.app.chart.reset(),this.app.chart_view.$el.show()):this.table.value(this.app.charts.last().id)},_changeChart:function(e){e.get("type")&&(this._addChart(e),this.table.value(e.id))}})}),define("mvc/ui/ui-tabs",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,list:{},$nav:null,$content:null,first_tab:null,optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(this.options));this.$nav=n.find(".tab-navigation"),this.$content=n.find(".tab-content"),this.setElement(n),this.list={};var r=this;this.options.operations&&$.each(this.options.operations,function(e,t){t.$el.prop("id",e),r.$nav.find(".operations").append(t.$el)});if(this.options.onnew){var i=$(this._template_tab_new(this.options));this.$nav.append(i),i.tooltip({title:"Add a new tab",placement:"bottom",container:r.$el}),i.on("click",function(e){i.tooltip("hide"),r.options.onnew()})}},add:function(e){var t=e.id,n={$title:$(this._template_tab(e)),$content:$(this._template_tab_content(e)),removable:e.ondel?!0:!1};this.list[t]=n,this.options.onnew?this.$nav.find("#new-tab").before(n.$title):this.$nav.append(n.$title),n.$content.append(e.$el),this.$content.append(n.$content),_.size(this.list)==1&&(n.$title.addClass("active"),n.$content.addClass("active"),this.first_tab=t);if(e.ondel){var r=this,i=n.$title.find("#delete");i.tooltip({title:"Delete this tab",placement:"bottom",container:r.$el}),i.on("click",function(){return i.tooltip("destroy"),r.$el.find(".tooltip").remove(),e.ondel(),!1})}e.onclick&&n.$title.on("click",function(){e.onclick()})},del:function(e){var t=this.list[e];t.$title.remove(),t.$content.remove(),delete t,this.first_tab==e&&(this.first_tab=null),this.first_tab!=null&&this.show(this.first_tab)},delRemovable:function(){for(var e in this.list){var t=this.list[e];t.removable&&this.del(e)}},show:function(e){this.$el.fadeIn("fast"),this.visible=!0,e&&this.list[e].$title.find("a").tab("show")},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},hideOperation:function(e){this.$nav.find("#"+e).hide()},showOperation:function(e){this.$nav.find("#"+e).show()},setOperation:function(e,t){var n=this.$nav.find("#"+e);n.off("click"),n.on("click",t)},title:function(e,t){var n=this.list[e].$title.find("#text");return t&&n.html(t),n.html()},_template:function(e){return'<div class="tabbable tabs-left"><ul class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div class="tab-content"/></div>'},_template_tab_new:function(e){return'<li id="new-tab"><a href="javascript:void(0);"><i style="font-size: 0.8em; margin-right: 5px;" class="fa fa-plus-circle"/>'+e.title_new+"</a>"+"</li>"},_template_tab:function(e){var t='<li id="title-'+e.id+'">'+'<a title="" href="#tab-'+e.id+'" data-toggle="tab" data-original-title="">'+'<span id="text">'+e.title+"</span>";return e.ondel&&(t+='<i id="delete" style="font-size: 0.8em; margin-left: 5px; cursor: pointer;" class="fa fa-minus-circle"/>'),t+="</a></li>",t},_template_tab_content:function(e){return'<div id="tab-'+e.id+'" class="tab-pane"/>'}});return{View:t}}),define("plugin/models/groups",["plugin/models/group"],function(e){return Backbone.Collection.extend({model:e})});var Visualization=Backbone.Model.extend(LoggableMixin).extend({defaults:{config:{}},urlRoot:function(){var e="/api/visualizations";return window.galaxy_config&&galaxy_config.root?galaxy_config.root+e:e},initialize:function(e){this.log(this+".initialize",e,this.attributes),_.isObject(e.config)&&_.isObject(this.defaults.config)&&_.defaults(e.config,this.defaults.config),this._setUpListeners()},_setUpListeners:function(){},set:function(e,t){if(e==="config"){var n=this.get("config");_.isObject(n)&&(t=_.extend(_.clone(n),t))}return Backbone.Model.prototype.set.call(this,e,t),this},toString:function(){var e=this.get("id")||"";return this.get("title")&&(e+=":"+this.get("title")),"Visualization("+e+")"}}),VisualizationCollection=Backbone.Collection.extend(LoggableMixin).extend({model:Visualization,url:function(){return galaxy_config.root+"api/visualizations"},initialize:function(e,t){t=t||{}},set:function(e,t){var n=this;e=_.map(e,function(e){var t=n.get(e.id);if(!t)return e;var r=t.toJSON();return _.extend(r,e),r}),Backbone.Collection.prototype.set.call(this,e,t)},toString:function(){return["VisualizationCollection(",[this.historyId,this.length].join(),")"].join("")}});define("mvc/visualization/visualization-model",function(){}),define("plugin/models/chart",["plugin/models/groups","mvc/visualization/visualization-model"],function(e){return Backbone.Model.extend({defaults:{id:null,title:"",type:"",date:null,state:"ok",state_info:""},initialize:function(t){this.groups=new e,this.settings=new Backbone.Model},reset:function(){this.clear({silent:!0}).set(this.defaults),this.groups.reset(),this.settings.clear(),this.trigger("reset",this)},copy:function(e){var t=this;t.clear({silent:!0}).set(this.defaults),t.set(e.attributes),t.settings=e.settings.clone(),t.groups.reset(),e.groups.each(function(e){t.groups.add(e.clone())}),t.trigger("change",t)},state:function(e,t){this.set("state_info",t),this.set("state",e)},ready:function(){return this.get("state")=="ok"||this.get("state")=="failed"},save:function(){}})}),define("plugin/views/group",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({columns:[],initialize:function(r,i){this.app=r;var s=this;this.chart=this.app.chart,this.group=i.group,this.group_key=new t.Input({placeholder:"Data label",onchange:function(){s.group.set("key",s.group_key.value())}}),this.table=new e({content:"No data column."});var o=$("<div/>");o.append(n.wrap((new t.Label({title:"Provide a label:"})).$el)),o.append(n.wrap(this.group_key.$el)),o.append(n.wrap((new t.Label({title:"Select columns:"})).$el)),o.append(n.wrap(this.table.$el)),this.setElement(o);var s=this;this.chart.on("change:dataset_id",function(){s._refreshTable()}),this.chart.on("change:type",function(){s._refreshTable()}),this.group.on("change:key",function(){s._refreshGroupKey()}),this.group.on("change",function(){s._refreshGroup()}),this._refreshTable(),this._refreshGroupKey(),this._refreshGroup()},_refreshTable:function(){var e=this.chart.get("dataset_id"),n=this.chart.get("type");if(!e||!n)return;var r=this,i=this.app.types.get(n);this.table.removeAll();var s={};for(var o in i.columns){var u=this.group.get(o);u||this.group.set(o,0);var a=i.columns[o],f=new t.Select.View({id:"select_"+o,gid:o,onchange:function(e){r.group.set(this.gid,e)},value:u,wait:!0});this.table.add(a.title,"25%"),this.table.add(f.$el),this.table.append(o),s[o]=f}this.app.datasets.request({id:e},function(e){r.columns=[];var t=e.metadata_column_types;for(var n in t)(t[n]=="int"||t[n]=="float")&&r.columns.push({label:"Column: "+(parseInt(n)+1)+" ["+t[n]+"]",value:n});for(var n in s)s[n].update(r.columns),s[n].show()})},_refreshGroup:function(){this.group.set("date",n.time())},_refreshGroupKey:function(){var e=this.group.get("key");e===undefined&&(e=""),this.group_key.value(e)}})}),define("plugin/library/ui-table-form",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){var r=Backbone.View.extend({initialize:function(r){this.table_title=new t.Label({title:r.title}),this.table=new e({content:r.content});var i=$("<div/>");i.append(n.wrap(this.table_title.$el)),i.append(n.wrap(this.table.$el)),this.setElement(i)},title:function(e){this.table_title.title(e)},update:function(e,t){this.table.removeAll();for(var n in e)this._add(n,e[n],t)},_add:function(e,n,r){var i=null,s=n.type;switch(s){case"text":i=new t.Input({placeholder:n.placeholder,onchange:function(){r.set(e,i.value())}});break;case"select":i=new t.Select.View({data:n.data,onchange:function(){r.set(e,i.value())}});break;case"slider":i=new t.Input({placeholder:n.placeholder,onchange:function(){r.set(e,i.value())}});break;case"separator":i=$("<div/>");break;default:console.log("ui-table-form:_add","Unknown setting type ("+n.type+")");return}if(s!="separator"){r.get(e)||r.set(e,n.init),i.value(r.get(e));var o=$("<div/>");o.append(i.$el),o.append('<div class="toolParamHelp" style="font-size: 0.9em;">'+n.info+"</div>"),this.table.add('<span style="white-space: nowrap;">'+n.title+"</span>","25%"),this.table.add(o)}else this.table.add('<h6 style="white-space: nowrap;">'+n.title+":<h6/>"),this.table.add($("<div/>"));this.table.append(e)}});return{View:r}}),define("plugin/views/settings",["plugin/library/ui","plugin/library/ui-table-form","utils/utils"],function(e,t,n){return Backbone.View.extend({initialize:function(e,n){this.app=e;var r=this;this.chart=this.app.chart,this.form=new t.View({title:"Chart options:",content:"This chart type does not provide any options."}),this.setElement(this.form.$el);var r=this;this.chart.on("change",function(){r._refreshTable()})},_refreshTable:function(){var e=this.chart.get("type");if(!e)return;var t=this.app.types.get(e);this.form.title(t.title+":"),this.form.update(t.settings,this.chart.settings)}})}),define("plugin/views/chart",["mvc/ui/ui-tabs","plugin/library/ui-table","plugin/library/ui","utils/utils","plugin/models/chart","plugin/models/group","plugin/views/group","plugin/views/settings"],function(e,t,n,r,i,s,o,u){return Backbone.View.extend({optionsDefault:{header:!0,content:"No content available."},initialize:function(i,s){this.app=i,this.chart=this.app.chart,this.options=r.merge(s,this.optionsDefault);var o=this;this.table=new t({header:!1,onconfirm:function(e){o.chart.groups.length>0?o.app.modal.show({title:"Switching to another chart type?",body:"If you continue your settings and selections will be reseted.",buttons:{Cancel:function(){o.app.modal.hide()},Continue:function(){o.app.modal.hide(),o.table.value(e)}}}):o.table.value(e)},onchange:function(e){o.chart.groups.reset(),o.chart.settings.clear(),o.chart.set({type:e})},ondblclick:function(e){o.tabs.show("settings")},content:"No chart types available"});var a=0,f=i.types.attributes;for(var l in f){var c=f[l];this.table.add(++a+"."),c.execute?this.table.add(c.title+" (requires processing)"):this.table.add(c.title),this.table.append(l)}this.tabs=new e.View({title_new:"Add Data",onnew:function(){var e=o._addGroupModel();o.tabs.show(e.id)},operations:{save:new n.ButtonIcon({icon:"fa-save",tooltip:"Draw Chart",title:"Draw",onclick:function(){o.chart.groups.length==0&&o._addGroupModel(),o._saveChart(),o.hide(),o.app.charts_view.$el.show()}}),back:new n.ButtonIcon({icon:"fa-caret-left",tooltip:"Return to Viewer",title:"Return",onclick:function(){o.hide(),o.app.charts_view.$el.show()}})}}),this.title=new n.Input({placeholder:"Chart title",onchange:function(){o.app.config.set("title",o.title.value())}});var h=$("<div/>");h.append(r.wrap((new n.Label({title:"Provide a chart title:"})).$el)),h.append(r.wrap(this.title.$el)),h.append(r.wrap((new n.Label({title:"Select a chart type:"})).$el)),h.append(r.wrap(this.table.$el)),this.tabs.add({id:"main",title:"Start",$el:h}),this.settings=new u(this.app),this.tabs.add({id:"settings",title:"Configuration",$el:this.settings.$el}),this.setElement(this.tabs.$el),this.tabs.hideOperation("back");var o=this;this.chart.on("change:title",function(e){o.title.value(e.get("title")),o.app.config.set("title",e.get("title"))}),this.chart.on("change:type",function(e){o.table.value(e.get("type"))}),this.chart.on("reset",function(e){o._resetChart()}),this.app.charts.on("add",function(e){o.tabs.showOperation("back")}),this.app.charts.on("remove",function(e){o.app.charts.length==0&&o.tabs.hideOperation("back")}),this.app.charts.on("reset",function(e){o.tabs.hideOperation("back")}),this.app.chart.groups.on("add",function(e){o._addGroup(e)}),this.app.chart.groups.on("remove",function(e){o._removeGroup(e)}),this.app.chart.groups.on("reset",function(e){o._removeAllGroups()}),this.app.chart.groups.on("change:key",function(e){o._refreshGroupKey()}),this._resetChart()},hide:function(){$(".tooltip").hide(),this.$el.hide()},_refreshGroupKey:function(){var e=this,t=0;this.chart.groups.each(function(n){var r=n.get("key","");r==""&&(r="Chart data"),e.tabs.title(n.id,++t+": "+r)})},_addGroupModel:function(){var e=new s({id:r.uuid()});return this.chart.groups.add(e),e},_addGroup:function(e){var t=this,n=new o(this.app,{group:e}),r=t.chart.groups.length;this.tabs.add({id:e.id,$el:n.$el,ondel:function(){t.chart.groups.remove(e.id)}}),this._refreshGroupKey()},_removeGroup:function(e){this.tabs.del(e.id),this._refreshGroupKey()},_removeAllGroups:function(e){this.tabs.delRemovable()},_resetChart:function(){this.chart.set("id",r.uuid()),this.chart.set("type","bardiagram"),this.chart.set("dataset_id",this.app.options.config.dataset_id),this.chart.set("title","New Chart")},_saveChart:function(){this.chart.set({type:this.table.value(),title:this.title.value(),date:r.time()});var e=this.app.charts.get(this.chart.id);e?e.copy(this.chart):(e=this.chart.clone(),e.copy(this.chart),this.app.charts.add(e)),e.save(),e.trigger("redraw",e)}})}),define("plugin/models/config",[],function(){return Backbone.Model.extend({defaults:{query_limit:1e3,query_timeout:500,title:"Create a new chart"}})}),define("plugin/models/charts",["plugin/models/chart"],function(e){return Backbone.Collection.extend({model:e})}),define("plugin/charts/_nvd3/config",[],function(){return{title:"",columns:{y:{title:"Values for y-axis"}},settings:{separator_label:{title:"X axis",type:"separator"},x_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"X-axis",placeholder:"Axis label"},x_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"f",data:[{label:"-- Do not show values --",value:"hide"},{label:"Float",value:"f"},{label:"Exponent",value:"e"},{label:"Integer",value:"d"},{label:"Percentage",value:"p"},{label:"Rounded",value:"r"},{label:"SI-prefix",value:"s"}]},x_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_tick:{title:"Y axis",type:"separator"},y_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"Y-axis",placeholder:"Axis label"},y_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"f",data:[{label:"-- Do not show values --",value:"hide"},{label:"Float",value:"f"},{label:"Exponent",value:"e"},{label:"Integer",value:"d"},{label:"Percentage",value:"p"},{label:"Rounded",value:"r"},{label:"SI-prefix",value:"s"}]},y_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_legend:{title:"Others",type:"separator"},show_legend:{title:"Show legend",info:"Would you like to add a legend?",type:"select",init:"true",data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]}}}}),define("plugin/charts/bardiagram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram"})}),define("plugin/charts/histogram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Histogram",execute:!0,columns:{y:{title:"Observations"}},settings:{x_axis_label:{init:"Breaks"},y_axis_label:{init:"Density"},y_axis_tick:{init:".3"},separator_custom:{title:"Advanced",type:"separator"},bin_size:{title:"Bin size",info:"Provide the bin size for the histogram.",type:"select",init:1,data:[{label:"0.001",value:"0.001"},{label:"0.01",value:"0.01"},{label:"0.1",value:"0.1"},{label:"1",value:"1"},{label:"10",value:"10"},{label:"100",value:"100"},{label:"1000",value:"1000"}]}}})}),define("plugin/charts/horizontal/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram (horizontal)",settings:{x_axis_type:{init:"hide"}}})}),define("plugin/charts/line/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line chart"})}),define("plugin/charts/linewithfocus/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line with focus"})}),define("plugin/charts/piechart/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Pie chart"})}),define("plugin/charts/scatterplot/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Scatter plot",columns:{x:{title:"Values for x-axis"}}})}),define("plugin/charts/stackedarea/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Stacked area"})}),define("plugin/charts/types",["plugin/charts/bardiagram/config","plugin/charts/histogram/config","plugin/charts/horizontal/config","plugin/charts/line/config","plugin/charts/linewithfocus/config","plugin/charts/piechart/config","plugin/charts/scatterplot/config","plugin/charts/stackedarea/config"],function(e,t,n,r,i,s,o,u){return Backbone.Model.extend({defaults:{bardiagram:e,horizontal:n,histogram:t,line:r,linewithfocus:i,piechart:s,scatterplot:o,stackedarea:u}})}),define("plugin/app",["mvc/ui/ui-modal","mvc/ui/ui-portlet","plugin/library/ui","utils/utils","plugin/library/jobs","plugin/library/datasets","plugin/views/charts","plugin/views/chart","plugin/models/config","plugin/models/chart","plugin/models/charts","plugin/charts/types"],function(e,t,n,r,i,s,o,u,a,f,l,c){return Backbone.View.extend({initialize:function(n){this.options=n,Galaxy&&Galaxy.modal?this.modal=Galaxy.modal:this.modal=new e.View,this.config=new a,this.jobs=new i(this),this.types=new c,this.chart=new f,this.charts=new l,this.datasets=new s(this),this.charts_view=new o(this),this.chart_view=new u(this),this.options.config.widget?this.portlet=$("<div></div>"):this.portlet=new t.View({icon:"fa-bar-chart-o"}),this.portlet.append(this.charts_view.$el),this.portlet.append(this.chart_view.$el),this.options.config.widget?this.setElement(this.portlet):this.setElement(this.portlet.$el),this.charts_view.$el.hide();var r=this;this.config.on("change:title",function(){r._refreshTitle()}),this.render()},render:function(){this._refreshTitle()},_refreshTitle:function(){var e=this.config.get("title");e&&(e=" - "+e),this.portlet.title("Charts"+e)},execute:function(e){},onunload:function(){},log:function(e,t){console.log(e+" "+t)}})});
\ No newline at end of file
+(function(){var e=this,t=e._,n={},r=Array.prototype,i=Object.prototype,s=Function.prototype,o=r.push,u=r.slice,a=r.concat,f=i.toString,l=i.hasOwnProperty,c=r.forEach,h=r.map,p=r.reduce,d=r.reduceRight,v=r.filter,m=r.every,g=r.some,y=r.indexOf,b=r.lastIndexOf,w=Array.isArray,E=Object.keys,S=s.bind,x=function(e){if(e instanceof x)return e;if(!(this instanceof x))return new x(e);this._wrapped=e};typeof exports!="undefined"?(typeof module!="undefined"&&module.exports&&(exports=module.exports=x),exports._=x):e._=x,x.VERSION="1.4.4";var T=x.each=x.forEach=function(e,t,r){if(e==null)return;if(c&&e.forEach===c)e.forEach(t,r);else if(e.length===+e.length){for(var i=0,s=e.length;i<s;i++)if(t.call(r,e[i],i,e)===n)return}else for(var o in e)if(x.has(e,o)&&t.call(r,e[o],o,e)===n)return};x.map=x.collect=function(e,t,n){var r=[];return e==null?r:h&&e.map===h?e.map(t,n):(T(e,function(e,i,s){r.push(t.call(n,e,i,s))}),r)};var N="Reduce of empty array with no initial value";x.reduce=x.foldl=x.inject=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(p&&e.reduce===p)return r&&(t=x.bind(t,r)),i?e.reduce(t,n):e.reduce(t);T(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError(N);return n},x.reduceRight=x.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(d&&e.reduceRight===d)return r&&(t=x.bind(t,r)),i?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=x.keys(e);s=o.length}T(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError(N);return n},x.find=x.detect=function(e,t,n){var r;return C(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},x.filter=x.select=function(e,t,n){var r=[];return e==null?r:v&&e.filter===v?e.filter(t,n):(T(e,function(e,i,s){t.call(n,e,i,s)&&r.push(e)}),r)},x.reject=function(e,t,n){return x.filter(e,function(e,r,i){return!t.call(n,e,r,i)},n)},x.every=x.all=function(e,t,r){t||(t=x.identity);var i=!0;return e==null?i:m&&e.every===m?e.every(t,r):(T(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var C=x.some=x.any=function(e,t,r){t||(t=x.identity);var i=!1;return e==null?i:g&&e.some===g?e.some(t,r):(T(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};x.contains=x.include=function(e,t){return e==null?!1:y&&e.indexOf===y?e.indexOf(t)!=-1:C(e,function(e){return e===t})},x.invoke=function(e,t){var n=u.call(arguments,2),r=x.isFunction(t);return x.map(e,function(e){return(r?t:e[t]).apply(e,n)})},x.pluck=function(e,t){return x.map(e,function(e){return e[t]})},x.where=function(e,t,n){return x.isEmpty(t)?n?void 0:[]:x[n?"find":"filter"](e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},x.findWhere=function(e,t){return x.where(e,t,!0)},x.max=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&x.isEmpty(e))return-Infinity;var r={computed:-Infinity,value:-Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},x.min=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&x.isEmpty(e))return Infinity;var r={computed:Infinity,value:Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o<r.computed&&(r={value:e,computed:o})}),r.value},x.shuffle=function(e){var t,n=0,r=[];return T(e,function(e){t=x.random(n++),r[n-1]=r[t],r[t]=e}),r};var k=function(e){return x.isFunction(e)?e:function(t){return t[e]}};x.sortBy=function(e,t,n){var r=k(t);return x.pluck(x.map(e,function(e,t,i){return{value:e,index:t,criteria:r.call(n,e,t,i)}}).sort(function(e,t){var n=e.criteria,r=t.criteria;if(n!==r){if(n>r||n===void 0)return 1;if(n<r||r===void 0)return-1}return e.index<t.index?-1:1}),"value")};var L=function(e,t,n,r){var i={},s=k(t==null?x.identity:t);return T(e,function(t,o){var u=s.call(n,t,o,e);r(i,u,t)}),i};x.groupBy=function(e,t,n){return L(e,t,n,function(e,t,n){(x.has(e,t)?e[t]:e[t]=[]).push(n)})},x.countBy=function(e,t,n){return L(e,t,n,function(e,t){x.has(e,t)||(e[t]=0),e[t]++})},x.sortedIndex=function(e,t,n,r){n=n==null?x.identity:k(n);var i=n.call(r,t),s=0,o=e.length;while(s<o){var u=s+o>>>1;n.call(r,e[u])<i?s=u+1:o=u}return s},x.toArray=function(e){return e?x.isArray(e)?u.call(e):e.length===+e.length?x.map(e,x.identity):x.values(e):[]},x.size=function(e){return e==null?0:e.length===+e.length?e.length:x.keys(e).length},x.first=x.head=x.take=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,0,t):e[0]},x.initial=function(e,t,n){return u.call(e,0,e.length-(t==null||n?1:t))},x.last=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,Math.max(e.length-t,0)):e[e.length-1]},x.rest=x.tail=x.drop=function(e,t,n){return u.call(e,t==null||n?1:t)},x.compact=function(e){return x.filter(e,x.identity)};var A=function(e,t,n){return T(e,function(e){x.isArray(e)?t?o.apply(n,e):A(e,t,n):n.push(e)}),n};x.flatten=function(e,t){return A(e,t,[])},x.without=function(e){return x.difference(e,u.call(arguments,1))},x.uniq=x.unique=function(e,t,n,r){x.isFunction(t)&&(r=n,n=t,t=!1);var i=n?x.map(e,n,r):e,s=[],o=[];return T(i,function(n,r){if(t?!r||o[o.length-1]!==n:!x.contains(o,n))o.push(n),s.push(e[r])}),s},x.union=function(){return x.uniq(a.apply(r,arguments))},x.intersection=function(e){var t=u.call(arguments,1);return x.filter(x.uniq(e),function(e){return x.every(t,function(t){return x.indexOf(t,e)>=0})})},x.difference=function(e){var t=a.apply(r,u.call(arguments,1));return x.filter(e,function(e){return!x.contains(t,e)})},x.zip=function(){var e=u.call(arguments),t=x.max(x.pluck(e,"length")),n=new Array(t);for(var r=0;r<t;r++)n[r]=x.pluck(e,""+r);return n},x.unzip=function(e){var t=[];return x.each(e,function(e,n){x.each(e,function(e,r){t.length<=r&&(t[r]=[]),t[r][n]=e})}),t},x.object=function(e,t){if(e==null)return{};var n={};for(var r=0,i=e.length;r<i;r++)t?n[e[r]]=t[r]:n[e[r][0]]=e[r][1];return n},x.indexOf=function(e,t,n){if(e==null)return-1;var r=0,i=e.length;if(n){if(typeof n!="number")return r=x.sortedIndex(e,t),e[r]===t?r:-1;r=n<0?Math.max(0,i+n):n}if(y&&e.indexOf===y)return e.indexOf(t,n);for(;r<i;r++)if(e[r]===t)return r;return-1},x.lastIndexOf=function(e,t,n){if(e==null)return-1;var r=n!=null;if(b&&e.lastIndexOf===b)return r?e.lastIndexOf(t,n):e.lastIndexOf(t);var i=r?n:e.length;while(i--)if(e[i]===t)return i;return-1},x.range=function(e,t,n){arguments.length<=1&&(t=e||0,e=0),n=arguments[2]||1;var r=Math.max(Math.ceil((t-e)/n),0),i=0,s=new Array(r);while(i<r)s[i++]=e,e+=n;return s};var O=function(){};x.bind=function(e,t){var n,r;if(e.bind===S&&S)return S.apply(e,u.call(arguments,1));if(!x.isFunction(e))throw new TypeError;return n=u.call(arguments,2),r=function(){if(this instanceof r){O.prototype=e.prototype;var i=new O;O.prototype=null;var s=e.apply(i,n.concat(u.call(arguments)));return Object(s)===s?s:i}return e.apply(t,n.concat(u.call(arguments)))}},x.partial=function(e){var t=u.call(arguments,1);return function(){return e.apply(this,t.concat(u.call(arguments)))}},x.bindAll=function(e){var t=u.call(arguments,1);if(t.length===0)throw new Error("bindAll must be passed function names");return T(t,function(t){e[t]=x.bind(e[t],e)}),e},x.memoize=function(e,t){var n={};return t||(t=x.identity),function(){var r=t.apply(this,arguments);return x.has(n,r)?n[r]:n[r]=e.apply(this,arguments)}},x.delay=function(e,t){var n=u.call(arguments,2);return setTimeout(function(){return e.apply(null,n)},t)},x.defer=function(e){return x.delay.apply(x,[e,1].concat(u.call(arguments,1)))},x.throttle=function(e,t,n){var r,i,s,o,u=0,a=function(){u=new Date,s=null,o=e.apply(r,i)};return function(){var f=new Date;!u&&n===!1&&(u=f);var l=t-(f-u);return r=this,i=arguments,l<=0?(clearTimeout(s),s=null,u=f,o=e.apply(r,i)):s||(s=setTimeout(a,l)),o}},x.debounce=function(e,t,n){var r,i;return function(){var s=this,o=arguments,u=function(){r=null,n||(i=e.apply(s,o))},a=n&&!r;return clearTimeout(r),r=setTimeout(u,t),a&&(i=e.apply(s,o)),i}},x.once=function(e){var t=!1,n;return function(){return t?n:(t=!0,n=e.apply(this,arguments),e=null,n)}},x.wrap=function(e,t){return function(){var n=[e];return o.apply(n,arguments),t.apply(this,n)}},x.compose=function(){var e=arguments;return function(){var t=arguments;for(var n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},x.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},x.keys=E||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)x.has(e,n)&&t.push(n);return t},x.values=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push(e[n]);return t},x.pairs=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push([n,e[n]]);return t},x.invert=function(e){var t={};for(var n in e)x.has(e,n)&&(t[e[n]]=n);return t},x.functions=x.methods=function(e){var t=[];for(var n in e)x.isFunction(e[n])&&t.push(n);return t.sort()},x.extend=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]=t[n]}),e},x.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return T(n,function(n){n in e&&(t[n]=e[n])}),t},x.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)x.contains(n,i)||(t[i]=e[i]);return t},x.defaults=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]===void 0&&(e[n]=t[n])}),e},x.clone=function(e){return x.isObject(e)?x.isArray(e)?e.slice():x.extend({},e):e},x.tap=function(e,t){return t(e),e};var M=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof x&&(e=e._wrapped),t instanceof x&&(t=t._wrapped);var i=f.call(e);if(i!=f.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=M(e[o],t[o],n,r)))break}else{var a=e.constructor,l=t.constructor;if(a!==l&&!(x.isFunction(a)&&a instanceof a&&x.isFunction(l)&&l instanceof l))return!1;for(var c in e)if(x.has(e,c)){o++;if(!(u=x.has(t,c)&&M(e[c],t[c],n,r)))break}if(u){for(c in t)if(x.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};x.isEqual=function(e,t){return M(e,t,[],[])},x.isEmpty=function(e){if(e==null)return!0;if(x.isArray(e)||x.isString(e))return e.length===0;for(var t in e)if(x.has(e,t))return!1;return!0},x.isElement=function(e){return!!e&&e.nodeType===1},x.isArray=w||function(e){return f.call(e)=="[object Array]"},x.isObject=function(e){return e===Object(e)},T(["Arguments","Function","String","Number","Date","RegExp"],function(e){x["is"+e]=function(t){return f.call(t)=="[object "+e+"]"}}),x.isArguments(arguments)||(x.isArguments=function(e){return!!e&&!!x.has(e,"callee")}),typeof /./!="function"&&(x.isFunction=function(e){return typeof e=="function"}),x.isFinite=function(e){return isFinite(e)&&!isNaN(parseFloat(e))},x.isNaN=function(e){return x.isNumber(e)&&e!=+e},x.isBoolean=function(e){return e===!0||e===!1||f.call(e)=="[object Boolean]"},x.isNull=function(e){return e===null},x.isUndefined=function(e){return e===void 0},x.has=function(e,t){return l.call(e,t)},x.noConflict=function(){return e._=t,this},x.identity=function(e){return e},x.times=function(e,t,n){var r=Array(e);for(var i=0;i<e;i++)r[i]=t.call(n,i);return r},x.random=function(e,t){return t==null&&(t=e,e=0),e+Math.floor(Math.random()*(t-e+1))};var _={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};_.unescape=x.invert(_.escape);var D={escape:new RegExp("["+x.keys(_.escape).join("")+"]","g"),unescape:new RegExp("("+x.keys(_.unescape).join("|")+")","g")};x.each(["escape","unescape"],function(e){x[e]=function(t){return t==null?"":(""+t).replace(D[e],function(t){return _[e][t]})}}),x.result=function(e,t){if(e==null)return void 0;var n=e[t];return x.isFunction(n)?n.call(e):n},x.mixin=function(e){T(x.functions(e),function(t){var n=x[t]=e[t];x.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),F.call(this,n.apply(x,e))}})};var P=0;x.uniqueId=function(e){var t=++P+"";return e?e+t:t},x.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var H=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},j=/\\|'|\r|\n|\t|\u2028|\u2029/g;x.template=function(e,t,n){var r;n=x.defaults({},n,x.templateSettings);var i=new RegExp([(n.escape||H).source,(n.interpolate||H).source,(n.evaluate||H).source].join("|")+"|$","g"),s=0,o="__p+='";e.replace(i,function(t,n,r,i,u){return o+=e.slice(s,u).replace(j,function(e){return"\\"+B[e]}),n&&(o+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'"),r&&(o+="'+\n((__t=("+r+"))==null?'':__t)+\n'"),i&&(o+="';\n"+i+"\n__p+='"),s=u+t.length,t}),o+="';\n",n.variable||(o="with(obj||{}){\n"+o+"}\n"),o="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+o+"return __p;\n";try{r=new Function(n.variable||"obj","_",o)}catch(u){throw u.source=o,u}if(t)return r(t,x);var a=function(e){return r.call(this,e,x)};return a.source="function("+(n.variable||"obj")+"){\n"+o+"}",a},x.chain=function(e){return x(e).chain()};var F=function(e){return this._chain?x(e).chain():e};x.mixin(x),T(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];x.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],F.call(this,n)}}),T(["concat","join","slice"],function(e){var t=r[e];x.prototype[e]=function(){return F.call(this,t.apply(this._wrapped,arguments))}}),x.extend(x.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this),define("libs/underscore",function(e){return function(){var t,n;return t||e._}}(this)),define("utils/utils",["libs/underscore"],function(e){function t(e,t,r){n("GET",e,{},t,r)}function n(e,t,n,r,i){if(e=="GET"||e=="DELETE")t.indexOf("?")==-1?t+="?":t+="&",t+=$.param(n);var s=new XMLHttpRequest;s.open(e,t,!0),s.setRequestHeader("Accept","application/json"),s.setRequestHeader("Cache-Control","no-cache"),s.setRequestHeader("X-Requested-With","XMLHttpRequest"),s.setRequestHeader("Content-Type","application/json"),s.onloadend=function(){var e=s.status;try{response=jQuery.parseJSON(s.responseText)}catch(t){response=s.responseText}e==200?r&&r(response):i&&i(response)},e=="GET"||e=="DELETE"?s.send():s.send(JSON.stringify(n))}function r(e,t){var n=$('<div class="'+e+'"></div>');n.appendTo(":eq(0)");var r=n.css(t);return n.remove(),r}function i(e){$('link[href^="'+e+'"]').length||$('<link href="'+galaxy_config.root+e+'" rel="stylesheet">').appendTo("head")}function s(t,n){return t?e.defaults(t,n):n}function o(e,t){var n="";if(e>=1e11)e/=1e11,n="TB";else if(e>=1e8)e/=1e8,n="GB";else if(e>=1e5)e/=1e5,n="MB";else if(e>=100)e/=100,n="KB";else{if(!(e>0))return"<strong>-</strong>";e*=10,n="b"}var r=Math.round(e)/10;return t?r+" "+n:"<strong>"+r+"</strong> "+n}function u(){return(new Date).getTime().toString(36)}function a(e){var t=$("<p></p>");return t.append(e),t}function f(){var e=new Date,t=(e.getHours()<10?"0":"")+e.getHours(),n=(e.getMinutes()<10?"0":"")+e.getMinutes(),r=e.getDate()+"/"+(e.getMonth()+1)+"/"+e.getFullYear()+", "+t+":"+n;return r}return{cssLoadFile:i,cssGetAttribute:r,get:t,merge:s,bytesToString:o,uuid:u,time:f,wrap:a,request:n}}),define("mvc/ui/ui-modal",["utils/utils"],function(e){var t=Backbone.View.extend({elMain:"body",optionsDefault:{title:"ui-modal",body:"",backdrop:!0,height:null,width:null,closing_events:!1},buttonList:{},initialize:function(e){e&&this._create(e)},show:function(e){this.initialize(e),this.options.height?(this.$body.css("height",this.options.height),this.$body.css("overflow","hidden")):this.$body.css("max-height",$(window).height()/2),this.options.width&&this.$dialog.css("width",this.options.width),this.visible?this.$el.show():this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.visible=!1,this.$el.fadeOut("fast")},enableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!1)},disableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!0)},showButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).show()},hideButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).hide()},getButton:function(e){var t=this.buttonList[e];return this.$buttons.find("#"+t)},scrollTop:function(){return this.$body.scrollTop()},_create:function(e){var t=this;this.options=_.defaults(e,this.optionsDefault),this.options.body=="progress"&&(this.options.body=$('<div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width:100%"></div></div>')),this.$el&&(this.$el.remove(),$(document).off("keyup")),this.setElement(this._template(this.options.title)),this.$dialog=this.$el.find(".modal-dialog"),this.$body=this.$el.find(".modal-body"),this.$footer=this.$el.find(".modal-footer"),this.$buttons=this.$el.find(".buttons"),this.$backdrop=this.$el.find(".modal-backdrop"),this.$body.html(this.options.body),this.options.backdrop||this.$backdrop.removeClass("in");if(this.options.buttons){this.buttonList={};var n=0;$.each(this.options.buttons,function(e,r){var i="button-"+n++;t.$buttons.append($('<button id="'+i+'"></button>').text(e).click(r)).append(" "),t.buttonList[e]=i})}else this.$footer.hide();$(this.elMain).append($(this.el)),this.options.closing_events&&(this.options.buttons.Pause||$(document).on("keyup",function(e){e.keyCode==27&&t.hide()}),this.$el.find(".modal-backdrop").on("click",function(){t.hide()}))},_template:function(e){return'<div class="modal"><div class="modal-backdrop fade in" style="z-index: -1;"></div><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" style="display: none;">×</button><h4 class="title">'+e+"</h4>"+"</div>"+'<div class="modal-body" style="position: static;"></div>'+'<div class="modal-footer">'+'<div class="buttons" style="float: right;"></div>'+"</div>"+"</div"+"</div>"+"</div>"}});return{View:t}}),define("mvc/ui/ui-portlet",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,optionsDefault:{title:"",icon:"",buttons:null,body:null,height:null,operations:null,placement:"bottom",overflow:"auto"},$title:null,$content:null,$buttons:null,$operations:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$content=this.$el.find("#content"),this.$title=this.$el.find("#title-text"),this.options.height&&(this.$el.find("#body").css("height",this.options.height),this.$el.find("#content").css("overflow",this.options.overflow)),this.$buttons=$(this.el).find("#buttons");if(this.options.buttons){var n=this;$.each(this.options.buttons,function(e,t){t.$el.prop("id",e),n.$buttons.append(t.$el)})}else this.$buttons.remove();this.$operations=$(this.el).find("#operations");if(this.options.operations){var n=this;$.each(this.options.operations,function(e,t){t.$el.prop("id",e),n.$operations.append(t.$el)})}this.options.body&&this.append(this.options.body)},append:function(t){this.$content.append(e.wrap(t))},content:function(){return this.$content},show:function(){this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},enableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!1)},disableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!0)},hideOperation:function(e){this.$operations.find("#"+e).hide()},showOperation:function(e){this.$operations.find("#"+e).show()},setOperation:function(e,t){var n=this.$operations.find("#"+e);n.off("click"),n.on("click",t)},title:function(e){var t=this.$title;return e&&t.html(e),t.html()},_template:function(e){var t='<div class="toolForm portlet-view no-highlight">';if(e.title||e.icon)t+='<div id="title" class="toolFormTitle portlet-title"><div id="operations" class="portlet-operations"/><div style="overflow: hidden;">',e.icon&&(t+='<div class="portlet-title-icon fa '+e.icon+'"> </div>'),t+='<div id="title-text" class="portlet-title-text">'+e.title+"</div>",t+="</div></div>";return t+='<div id="body" class="toolFormBody portlet-body">',e.placement=="top"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+='<div id="content" class="portlet-content"/>',e.placement=="bottom"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+="</div></div>",t}});return{View:t}}),define("plugin/library/ui-select",["utils/utils"],function(e){var t=Backbone.View.extend({optionsDefault:{id:"",cls:"",empty:"No data available",visible:!0,wait:!1},selected:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$select=this.$el.find("#select"),this.$icon=this.$el.find("#icon"),this.selected=this.options.value;var n=this;this.options.onchange&&this.$select.on("change",function(){n.value(n.$select.val())}),this._refresh(),this.options.visible||this.hide(),this.options.wait?this.wait():this.show()},value:function(e){var t=this.selected;e!==undefined&&(this.selected=e,this.$select.val(e));var n=this.selected;return n&&n!=t&&this.options.onchange&&this.options.onchange(n),n},text:function(){return this.$select.find("option:selected").text()},show:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-caret-down"),this.$select.show(),this.$el.show()},hide:function(){this.$el.hide()},wait:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-spinner fa-spin"),this.$select.hide()},disabled:function(){return this.$select.is(":disabled")},enable:function(){this.$select.prop("disabled",!1)},disable:function(){this.$select.prop("disabled",!0)},add:function(e){this.$select.append(this._templateOption(e)),this._refresh()},del:function(e){this.$select.find("option[value="+e+"]").remove(),this.$select.trigger("change"),this._refresh()},update:function(e){this.$select.find("option").remove();for(var t in e)this.$select.append(this._templateOption(e[t]));!this.selected&&e.length>0&&this.value(e[0].value),this._refresh()},_refresh:function(){this.$select.find("option[value=null]").remove();var e=this.$select.find("option").length;e==0?(this.$select.append(this._templateOption({value:"null",label:this.options.empty})),this.disable()):(this.enable(),this.selected&&this.$select.val(this.selected))},_exists:function(e){return 0!=this.$select.find("option[value="+e+"]").length},_templateOption:function(e){return'<option value="'+e.value+'">'+e.label+"</option>"},_template:function(e){var t='<div id="'+e.id+'" class="styled-select">'+'<div class="button">'+'<i id="icon"/>'+"</div>"+'<select id="select" class="select '+e.cls+" "+e.id+'">';for(key in e.data){var n=e.data[key],r="";if(n.value==e.value||n.value=="")r="selected";t+='<option value="'+n.value+'" '+r+">"+n.label+"</option>"}return t+="</select></div>",t}});return{View:t}}),define("plugin/library/ui",["utils/utils","plugin/library/ui-select"],function(e,t){var n=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options))},title:function(e){this.$el.find("b").html(e)},_template:function(e){return"<label><b>"+e.title+"</b></label>"},value:function(){return options.title}}),r=Backbone.View.extend({optionsDefault:{id:null,title:"","float":"right",cls:"btn-default",icon:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t='<button id="'+e.id+'" type="submit" style="margin-right: 5px; float: '+e.float+';" type="button" class="btn '+e.cls+'">';return e.icon&&(t+='<i class="icon fa '+e.icon+'"></i> '),t+=e.title+"</button>",t}}),i=Backbone.View.extend({optionsDefault:{"float":"right",icon:"",tooltip:"",placement:"bottom",title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){return'<div><span class="fa '+e.icon+'" style="font-size: 1.2em;"/> '+e.title+"</div>"}}),s=Backbone.View.extend({optionsDefault:{title:"",id:null,"float":"right",cls:"icon-btn",icon:"",tooltip:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t="";e.title&&(t="width: auto;");var n='<div id="'+e.id+'" style="margin-right: 5px; float: '+e.float+"; "+t+'" class="'+e.cls+'">';return e.title?n+='<div style="margin-right: 5px; margin-left: 5px;"><i class="icon fa '+e.icon+'"/> '+'<span style="position: relative; font-size: 0.8em; font-weight: normal; top: -1px;">'+e.title+"</span>"+"</div>":n+='<i class="icon fa '+e.icon+'"/>',n+="</div>",n}}),o=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick)},_template:function(e){return'<div><a href="javascript:void(0)">'+e.title+"</a></div>"}}),u=Backbone.View.extend({optionsDefault:{message:"",status:"info",persistent:!1},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement("<div></div>")},update:function(t){this.options=e.merge(t,this.optionsDefault);if(t.message!=""){this.$el.html(this._template(this.options)),this.$el.fadeIn();if(!t.persistent){var n=this;window.setTimeout(function(){n.$el.is(":visible")?n.$el.fadeOut():n.$el.hide()},3e3)}}else this.$el.fadeOut()},_template:function(e){return'<div class="alert alert-'+e.status+'" style="padding: 2px 2px 2px 10px;">'+e.message+"</div>"}}),a=Backbone.View.extend({optionsDefault:{onclick:null,searchword:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options));var n=this;this.options.onclick&&this.$el.on("submit",function(e){var t=n.$el.find("#search");n.options.onclick(t.val())})},_template:function(e){return'<div class="search"><form onsubmit="return false;"><input id="search" class="form-control input-sm" type="text" name="search" placeholder="Search..." value="'+e.searchword+'">'+'<button type="submit" class="btn search-btn">'+'<i class="fa fa-search"></i>'+"</button>"+"</form>"+"</div>"}}),f=Backbone.View.extend({optionsDefault:{title:"Unlabeled",body:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.body&&this.$el.find(".body").append(this.options.body)},_template:function(e){return'<div id="title" class="title">'+e.title+":"+"</div>"}}),l=Backbone.View.extend({optionsDefault:{id:"",title:"",target:"",href:"",onunload:null,onclick:null,visible:!0,icon:null,tag:""},$menu:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement($(this._template(this.options)));var n=$(this.el).find(".root"),r=this;n.on("click",function(e){e.preventDefault(),r.options.onclick&&r.options.onclick()}),this.options.visible||this.hide()},show:function(){$(this.el).show()},hide:function(){$(this.el).hide()},addMenu:function(t){var n={title:"",target:"",href:"",onclick:null,divider:!1,icon:null};n=e.merge(t,n),this.$menu||($(this.el).append(this._templateMenu()),this.$menu=$(this.el).find(".menu"));var r=$(this._templateMenuItem(n));r.on("click",function(e){e.preventDefault(),n.onclick&&n.onclick()}),this.$menu.append(r),n.divider&&this.$menu.append($(this._templateDivider()))},_templateMenuItem:function(e){var t='<li><a href="'+e.href+'" target="'+e.target+'">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),t+=" "+e.title+"</a>"+"</li>",t},_templateMenu:function(){return'<ul class="menu dropdown-menu pull-right" role="menu"></ul>'},_templateDivider:function(){return'<li class="divider"></li>'},_template:function(e){var t='<div id="'+e.id+'" class="button-menu btn-group">'+'<button type="button" class="root btn btn-default dropdown-toggle" data-toggle="dropdown">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),"</button></div>",t}}),c=Backbone.View.extend({optionsDefault:{value:"",type:"text",placeholder:"",disabled:!1,visible:!0},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.disabled&&this.$el.prop("disabled",!0),this.options.visible||this.$el.hide();var n=this;this.options.onchange&&this.$el.on("input",function(){n.options.onchange()})},value:function(e){return e!==undefined&&this.$el.val(e),this.$el.val()},_template:function(e){return'<input id="'+e.id+'" type="'+e.type+'" value="'+e.value+'" placeholder="'+e.placeholder+'" class="form-control">'}});return{Label:n,Button:r,Icon:i,ButtonIcon:s,Input:c,Anchor:o,Message:u,Searchbox:a,Title:f,Select:t,ButtonMenu:l}}),define("plugin/library/jobs",["utils/utils"],function(e){return Backbone.Model.extend({initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},submit:function(t,n,r,i){var s=this,o=t.id,u=t.get("type"),a=this.app.types.get(u);data={tool_id:"rkit",inputs:{input:{id:t.get("dataset_id"),src:"hda"},module:u,columns:r,settings:n}};var f=t.get("dataset_id_job");f&&e.request("PUT",config.root+"api/histories/"+t.get("history_id")+"/contents/"+f,{deleted:!0}),t.state("submit","Sending job request..."),e.request("POST",config.root+"api/tools",data,function(e){if(!e.outputs||e.outputs.length==0)t.state("failed","Job submission failed. No response.");else{Galaxy&&Galaxy.currHistoryPanel&&Galaxy.currHistoryPanel.refreshHdas();var n=e.outputs[0];t.state("queued","Job has been queued..."),t.set("dataset_id_job",n.id),s._loop(n.id,function(e){switch(e.state){case"ok":return t.state("success","Job completed successfully..."),i(e),!0;case"error":return t.state("failed","Job has failed. Please check the history for details."),!0;case"running":return t.state("running","Job is running..."),!1}})}},function(e){var n="";e&&e.message&&e.message.data&&e.message.data.input&&(n=e.message.data.input+"."),t.state("failed","This visualization requires the R-kit. Please make sure it is installed. "+n)})},_loop:function(t,n){var r=this;e.request("GET",config.root+"api/jobs/"+t,{},function(e){n(e)||setTimeout(function(){r._loop(t,n)},r.app.config.get("query_timeout"))})}})}),define("plugin/library/datasets",["utils/utils"],function(e){return Backbone.Collection.extend({list:{},initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},request:function(t,n,r){var i=this;if(t.groups)this._fetch(t,n);else{var s=this.list[t.id];if(s){n(s);return}e.request("GET",config.root+"api/datasets/"+t.id,{},function(e){switch(e.state){case"error":r&&r(e);break;default:i.list[t.id]=e,n(e)}})}},_fetch:function(t,n){var r=t.start?t.start:0,i=Math.abs(t.end-t.start),s=this.app.config.get("query_limit");if(!i||i>s)i=s;var o="",u={},a=0;for(var f in t.groups){var l=t.groups[f];for(var c in l.columns){var h=l.columns[c];o+=h+",",u[h]=a,a++}}if(a==0){n({});return}o=o.substring(0,o.length-1);var p=t.groups.slice(0);for(var f in p)p[f].values=[];var d=this;e.request("GET",config.root+"api/datasets/"+t.id,{data_type:"raw_data",provider:"dataset-column",limit:i,offset:r,indeces:o},function(e){for(var i in e.data){var s=e.data[i];for(var o in t.groups){var a=t.groups[o],f={x:parseInt(i)+r};for(var l in a.columns){var c=a.columns[l],h=u[c],d=s[h];if(isNaN(d)||!d)d=0;f[l]=d}p[o].values.push(f)}}n(p)})}})}),define("plugin/library/ui-table",["utils/utils"],function(e){var t=Backbone.View.extend({row:null,row_count:0,optionsDefault:{content:"No content available.",onchange:null,ondblclick:null,onconfirm:null},events:{click:"_onclick",dblclick:"_ondblclick"},first:!0,initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(t));this.$thead=n.find("thead"),this.$tbody=n.find("tbody"),this.$tmessage=n.find("tmessage"),this.setElement(n),this.row=$("<tr></tr>")},addHeader:function(e){var t=$("<th></th>");t.append(e),this.row.append(t)},appendHeader:function(){this.$thead.append(this.row),this.row=$("<tr></tr>")},add:function(e,t){var n=$("<td></td>");t&&n.css("width",t),n.append(e),this.row.append(n)},append:function(e){this._commit(e)},prepend:function(e){this._commit(e,!0)},remove:function(e){var t=this.$tbody.find("#"+e);t.length>0&&(t.remove(),this.row_count--,this._refresh())},removeAll:function(){this.$tbody.html(""),this.row_count=0,this._refresh()},value:function(e){this.before=this.$tbody.find(".current").attr("id"),e!==undefined&&(this.$tbody.find("tr").removeClass("current"),e&&this.$tbody.find("#"+e).addClass("current"));var t=this.$tbody.find(".current").attr("id");return t===undefined?null:(t!=this.before&&this.options.onchange&&this.options.onchange(e),t)},size:function(){return this.$tbody.find("tr").length},_commit:function(e,t){this.remove(e),this.row.attr("id",e),t?this.$tbody.prepend(this.row):this.$tbody.append(this.row),this.row=$("<tr></tr>"),this.row_count++,this._refresh()},_onclick:function(e){var t=this.value(),n=$(e.target).closest("tr").attr("id");n&&t!=n&&(this.options.onconfirm?this.options.onconfirm(n):this.value(n))},_ondblclick:function(e){var t=this.value();t&&this.options.ondblclick&&this.options.ondblclick(t)},_refresh:function(){this.row_count==0?this.$tmessage.show():this.$tmessage.hide()},_template:function(e){return'<div><table class="grid"><thead></thead><tbody style="cursor: pointer;"></tbody></table><tmessage>'+e.content+"</tmessage>"+"<div>"}});return{View:t}}),define("plugin/models/group",[],function(){return Backbone.Model.extend({defaults:{key:"Data label",date:""},reset:function(){this.clear({silent:!0}).set(this.defaults),this.trigger("reset",this)}})}),define("plugin/views/viewport",["mvc/ui/ui-portlet","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({list:{},optionsDefault:{height:300},initialize:function(t,r){this.app=t,this.options=n.merge(r,this.optionsDefault),this.portlet=new e.View({title:"title",height:this.options.height,overflow:"hidden"}),this.setElement(this.portlet.$el);var i=this;this.app.charts.on("remove",function(e){i._removeChart(e.id)}),this.app.charts.on("redraw",function(e){e.ready()?i._refreshChart(e):e.on("change:state",function(){e.ready()&&i._refreshChart(e)})})},showChart:function(e){this.show(),this.hideCharts();var t=this.list[e];if(t){var n=self.app.charts.get(e);this.portlet.title(n.get("title")),t.$el.show(),$(window).trigger("resize")}},hideCharts:function(){this.$el.find(".item").hide()},show:function(){$(".tooltip").hide(),this.$el.show()},hide:function(){$(".tooltip").hide(),this.$el.hide()},_refreshChart:function(e){var t=this;if(!e.ready()){t.app.log("viewport:_refreshChart()","Invalid attempt to refresh chart before completion.");return}var n=e.id;this._removeChart(n);var r="#"+n,i=$(this._template({id:r}));this.portlet.append(i);var s=d3.select(r+" svg");this.list[n]={svg:s,$el:i},this.showChart(n),e.off("change:state"),e.on("change:state",function(){var t=i.find("#info"),n=t.find("#icon");n.removeClass(),t.show(),t.find("#text").html(e.get("state_info"));var r=e.get("state");switch(r){case"ok":t.hide();break;case"failed":n.addClass("fa fa-warning");break;default:n.addClass("fa fa-spinner fa-spin")}}),e.state("wait","Please wait...");var o=e.get("type"),u=this.app.types.get(o),t=this;require(["plugin/charts/"+o+"/"+o],function(n){var r=new n(t.app,{svg:s});u.execute?t.app.jobs.submit(e,t._defaultSettingsString(e),t._defaultRequestString(e),function(){r.draw(e,t._defaultRequestDictionary(e))}):r.draw(e,t._defaultRequestDictionary(e))})},_removeChart:function(e){var t=this.list[e];t&&(t.svg.remove(),t.$el.remove())},_template:function(e){return'<div id="'+e.id.substr(1)+'" class="item">'+'<span id="info">'+'<span id="icon" style="font-size: 1.2em; display: inline-block;"/>'+'<span id="text" style="position: relative; margin-left: 5px; top: -1px; font-size: 1.0em;"/>'+"</span>"+'<svg style="height: auto;"/>'+"</div>"},_defaultRequestString:function(e){var t=this.app.types.get(e.get("type")),n="",r=0;return e.groups.each(function(e){for(var i in t.columns)n+=i+"_"+ ++r+":"+(parseInt(e.get(i))+1)+", "}),n.substring(0,n.length-2)},_defaultSettingsString:function(e){var t="";for(key in e.settings.attributes)t+=key+":"+e.settings.get(key)+", ";return t.substring(0,t.length-2)},_defaultRequestDictionary:function(e){var t=this.app.types.get(e.get("type")),n={id:e.get("dataset_id"),groups:[]},r=0;return e.groups.each(function(e){var i={};for(var s in t.columns)i[s]=e.get(s);n.groups.push({key:++r+":"+e.get("key"),columns:i})}),n}})}),define("plugin/views/charts",["mvc/ui/ui-portlet","plugin/library/ui-table","plugin/library/ui","utils/utils","plugin/models/group","plugin/views/viewport"],function(e,t,n,r,i,s){return Backbone.View.extend({initialize:function(i,o){this.app=i,this.viewport_view=new s(i),this.table=new t.View({content:"Add charts to this table.",ondblclick:function(e){u._showChartView(e)},onchange:function(e){var t=u.app.charts.get(e);u.app.config.set("title",t.get("title")),u.viewport_view.showChart(e)}});var u=this;this.portlet=new e.View({icon:"fa-list",title:"List of created charts:",height:100,operations:{"new":new n.ButtonIcon({icon:"fa-magic",tooltip:"Create a new Chart",title:"New",onclick:function(){u.app.go("chart_view"),u.app.chart.reset()}}),edit:new n.ButtonIcon({icon:"fa-gear",tooltip:"Customize this Chart",title:"Customize",onclick:function(){var e=u.table.value();if(!e)return;u._showChartView(e)}}),"delete":new n.ButtonIcon({icon:"fa-trash-o",tooltip:"Delete this Chart",title:"Delete",onclick:function(){var e=u.table.value();if(!e)return;var t=u.app.charts.get(e);u.app.modal.show({title:"Are you sure?",body:'The selected chart "'+t.get("title")+'" will be irreversibly deleted.',buttons:{Cancel:function(){u.app.modal.hide()},Delete:function(){u.app.modal.hide(),u.app.charts.remove(e)}}})}})}}),this.portlet.append(this.table.$el),this.app.options.config.widget||this.$el.append(this.portlet.$el),this.$el.append(r.wrap("")),this.$el.append(this.viewport_view.$el);var u=this;this.app.charts.on("add",function(e){u._addChart(e)}),this.app.charts.on("remove",function(e){u._removeChart(e)}),this.app.charts.on("change",function(e){u._changeChart(e)})},show:function(){this.$el.show()},hide:function(){$(".tooltip").hide(),this.$el.hide()},_addChart:function(e){var t=e.get("title");t==""&&(t="Untitled"),this.table.add(t);var n=this.app.types.get(e.get("type"));this.table.add(n.title),this.table.add("Last change: "+e.get("date")),this.table.prepend(e.get("id")),this.table.value(e.get("id"))},_removeChart:function(e){this.table.remove(e.id),this.app.charts.save(),this.table.size()==0?(this.app.go("chart_view"),this.app.chart.reset()):this.table.value(this.app.charts.last().id)},_changeChart:function(e){e.get("type")&&(this._addChart(e),this.table.value(e.id))},_showChartView:function(e){var t=this.app.charts.get(e);if(t.ready())this.app.go("chart_view"),this.app.chart.copy(t);else{var n=this;this.app.modal.show({title:"Please wait!",body:'The selected chart "'+t.get("title")+'" is currently being processed. Please wait...',buttons:{Close:function(){n.app.modal.hide()},Retry:function(){n.app.modal.hide(),n._showChartView(e)}}})}}})}),define("mvc/ui/ui-tabs",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,list:{},$nav:null,$content:null,first_tab:null,optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(this.options));this.$nav=n.find(".tab-navigation"),this.$content=n.find(".tab-content"),this.setElement(n),this.list={};var r=this;this.options.operations&&$.each(this.options.operations,function(e,t){t.$el.prop("id",e),r.$nav.find(".operations").append(t.$el)});if(this.options.onnew){var i=$(this._template_tab_new(this.options));this.$nav.append(i),i.tooltip({title:"Add a new tab",placement:"bottom",container:r.$el}),i.on("click",function(e){i.tooltip("hide"),r.options.onnew()})}},add:function(e){var t=e.id,n={$title:$(this._template_tab(e)),$content:$(this._template_tab_content(e)),removable:e.ondel?!0:!1};this.list[t]=n,this.options.onnew?this.$nav.find("#new-tab").before(n.$title):this.$nav.append(n.$title),n.$content.append(e.$el),this.$content.append(n.$content),_.size(this.list)==1&&(n.$title.addClass("active"),n.$content.addClass("active"),this.first_tab=t);if(e.ondel){var r=this,i=n.$title.find("#delete");i.tooltip({title:"Delete this tab",placement:"bottom",container:r.$el}),i.on("click",function(){return i.tooltip("destroy"),r.$el.find(".tooltip").remove(),e.ondel(),!1})}e.onclick&&n.$title.on("click",function(){e.onclick()})},del:function(e){var t=this.list[e];t.$title.remove(),t.$content.remove(),delete t,this.first_tab==e&&(this.first_tab=null),this.first_tab!=null&&this.show(this.first_tab)},delRemovable:function(){for(var e in this.list){var t=this.list[e];t.removable&&this.del(e)}},show:function(e){this.$el.fadeIn("fast"),this.visible=!0,e&&this.list[e].$title.find("a").tab("show")},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},hideOperation:function(e){this.$nav.find("#"+e).hide()},showOperation:function(e){this.$nav.find("#"+e).show()},setOperation:function(e,t){var n=this.$nav.find("#"+e);n.off("click"),n.on("click",t)},title:function(e,t){var n=this.list[e].$title.find("#text");return t&&n.html(t),n.html()},_template:function(e){return'<div class="tabbable tabs-left"><ul class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div class="tab-content"/></div>'},_template_tab_new:function(e){return'<li id="new-tab"><a href="javascript:void(0);"><i style="font-size: 0.8em; margin-right: 5px;" class="fa fa-plus-circle"/>'+e.title_new+"</a>"+"</li>"},_template_tab:function(e){var t='<li id="title-'+e.id+'">'+'<a title="" href="#tab-'+e.id+'" data-toggle="tab" data-original-title="">'+'<span id="text">'+e.title+"</span>";return e.ondel&&(t+='<i id="delete" style="font-size: 0.8em; margin-left: 5px; cursor: pointer;" class="fa fa-minus-circle"/>'),t+="</a></li>",t},_template_tab_content:function(e){return'<div id="tab-'+e.id+'" class="tab-pane"/>'}});return{View:t}}),define("plugin/models/groups",["plugin/models/group"],function(e){return Backbone.Collection.extend({model:e})});var Visualization=Backbone.Model.extend({defaults:{config:{}},urlRoot:function(){var e="/api/visualizations";return window.galaxy_config&&galaxy_config.root?galaxy_config.root+e:e},initialize:function(e){_.isObject(e.config)&&_.isObject(this.defaults.config)&&_.defaults(e.config,this.defaults.config),this._setUpListeners()},_setUpListeners:function(){},set:function(e,t){if(e==="config"){var n=this.get("config");_.isObject(n)&&(t=_.extend(_.clone(n),t))}return Backbone.Model.prototype.set.call(this,e,t),this},toString:function(){var e=this.get("id")||"";return this.get("title")&&(e+=":"+this.get("title")),"Visualization("+e+")"}}),VisualizationCollection=Backbone.Collection.extend({model:Visualization,url:function(){return galaxy_config.root+"api/visualizations"},initialize:function(e,t){t=t||{}},set:function(e,t){var n=this;e=_.map(e,function(e){var t=n.get(e.id);if(!t)return e;var r=t.toJSON();return _.extend(r,e),r}),Backbone.Collection.prototype.set.call(this,e,t)},toString:function(){return["VisualizationCollection(",[this.historyId,this.length].join(),")"].join("")}});define("mvc/visualization/visualization-model",function(){}),define("plugin/models/chart",["plugin/models/groups","mvc/visualization/visualization-model"],function(e){return Backbone.Model.extend({defaults:{id:null,title:"",type:"",date:null,state:"ok",state_info:""},initialize:function(t){this.groups=new e,this.settings=new Backbone.Model},reset:function(){this.clear({silent:!0}).set(this.defaults),this.groups.reset(),this.settings.clear(),this.trigger("reset",this)},copy:function(e){var t=this;t.clear({silent:!0}).set(this.defaults),t.set(e.attributes),t.settings=e.settings.clone(),t.groups.reset(),e.groups.each(function(e){t.groups.add(e.clone())}),t.trigger("change",t)},state:function(e,t){this.set("state_info",t),this.set("state",e)},ready:function(){return this.get("state")=="ok"||this.get("state")=="failed"}})}),define("plugin/views/group",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({columns:[],initialize:function(r,i){this.app=r;var s=this;this.chart=this.app.chart,this.group=i.group,this.group_key=new t.Input({placeholder:"Data label",onchange:function(){s.group.set("key",s.group_key.value())}}),this.table=new e.View({content:"No data column."});var o=$("<div/>");o.append(n.wrap((new t.Label({title:"Provide a label:"})).$el)),o.append(n.wrap(this.group_key.$el)),o.append(n.wrap((new t.Label({title:"Select columns:"})).$el)),o.append(n.wrap(this.table.$el)),this.setElement(o);var s=this;this.chart.on("change:dataset_id",function(){s._refreshTable()}),this.chart.on("change:type",function(){s._refreshTable()}),this.group.on("change:key",function(){s._refreshGroupKey()}),this.group.on("change",function(){s._refreshGroup()}),this._refreshTable(),this._refreshGroupKey(),this._refreshGroup()},_refreshTable:function(){var e=this.chart.get("dataset_id"),n=this.chart.get("type");if(!e||!n)return;var r=this,i=this.app.types.get(n);this.table.removeAll();var s={};for(var o in i.columns){var u=this.group.get(o);u||this.group.set(o,0);var a=i.columns[o],f=new t.Select.View({id:"select_"+o,gid:o,onchange:function(e){r.group.set(this.gid,e)},value:u,wait:!0});this.table.add(a.title,"25%"),this.table.add(f.$el),this.table.append(o),s[o]=f}this.app.datasets.request({id:e},function(e){r.columns=[];var t=e.metadata_column_types;for(var n in t)(t[n]=="int"||t[n]=="float")&&r.columns.push({label:"Column: "+(parseInt(n)+1)+" ["+t[n]+"]",value:n});for(var n in s)s[n].update(r.columns),s[n].show()})},_refreshGroup:function(){this.group.set("date",n.time())},_refreshGroupKey:function(){var e=this.group.get("key");e===undefined&&(e=""),this.group_key.value(e)}})}),define("plugin/library/ui-table-form",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){var r=Backbone.View.extend({initialize:function(r){this.table_title=new t.Label({title:r.title}),this.table=new e.View({content:r.content});var i=$("<div/>");i.append(n.wrap(this.table_title.$el)),i.append(n.wrap(this.table.$el)),this.setElement(i)},title:function(e){this.table_title.title(e)},update:function(e,t){this.table.removeAll();for(var n in e)this._add(n,e[n],t)},_add:function(e,n,r){var i=null,s=n.type;switch(s){case"text":i=new t.Input({placeholder:n.placeholder,onchange:function(){r.set(e,i.value())}});break;case"select":i=new t.Select.View({data:n.data,onchange:function(){r.set(e,i.value())}});break;case"slider":i=new t.Input({placeholder:n.placeholder,onchange:function(){r.set(e,i.value())}});break;case"separator":i=$("<div/>");break;default:console.log("ui-table-form:_add","Unknown setting type ("+n.type+")");return}if(s!="separator"){r.get(e)||r.set(e,n.init),i.value(r.get(e));var o=$("<div/>");o.append(i.$el),o.append('<div class="toolParamHelp" style="font-size: 0.9em;">'+n.info+"</div>"),this.table.add('<span style="white-space: nowrap;">'+n.title+"</span>","25%"),this.table.add(o)}else this.table.add('<h6 style="white-space: nowrap;">'+n.title+":<h6/>"),this.table.add($("<div/>"));this.table.append(e)}});return{View:r}}),define("plugin/views/settings",["plugin/library/ui","plugin/library/ui-table-form","utils/utils"],function(e,t,n){return Backbone.View.extend({initialize:function(e,n){this.app=e;var r=this;this.chart=this.app.chart,this.form=new t.View({title:"Chart options:",content:"This chart type does not provide any options."}),this.setElement(this.form.$el);var r=this;this.chart.on("change",function(){r._refreshTable()})},_refreshTable:function(){var e=this.chart.get("type");if(!e)return;var t=this.app.types.get(e);this.form.title(t.title+":"),this.form.update(t.settings,this.chart.settings)}})}),define("plugin/views/chart",["mvc/ui/ui-tabs","plugin/library/ui-table","plugin/library/ui","utils/utils","plugin/models/chart","plugin/models/group","plugin/views/group","plugin/views/settings"],function(e,t,n,r,i,s,o,u){return Backbone.View.extend({optionsDefault:{header:!0,content:"No content available."},initialize:function(i,s){this.app=i,this.chart=this.app.chart,this.options=r.merge(s,this.optionsDefault);var o=this;this.table=new t.View({header:!1,onconfirm:function(e){o.chart.groups.length>0?o.app.modal.show({title:"Switching to another chart type?",body:"If you continue your settings and selections will be cleared.",buttons:{Cancel:function(){o.app.modal.hide()},Continue:function(){o.app.modal.hide(),o.table.value(e)}}}):o.table.value(e)},onchange:function(e){o.chart.groups.reset(),o.chart.settings.clear(),o.chart.set({type:e})},ondblclick:function(e){o.tabs.show("settings")},content:"No chart types available"});var a=0,f=i.types.attributes;for(var l in f){var c=f[l];this.table.add(++a+"."),c.execute?this.table.add(c.title+" (requires processing)"):this.table.add(c.title),this.table.append(l)}this.tabs=new e.View({title_new:"Add Data",onnew:function(){var e=o._addGroupModel();o.tabs.show(e.id)},operations:{save:new n.ButtonIcon({icon:"fa-save",tooltip:"Draw Chart",title:"Draw",onclick:function(){o.app.go("charts_view"),o._saveChart()}}),back:new n.ButtonIcon({icon:"fa-caret-left",tooltip:"Return to Viewer",title:"Return",onclick:function(){o.app.go("charts_view")}})}}),this.title=new n.Input({placeholder:"Chart title",onchange:function(){o.app.config.set("title",o.title.value())}});var h=$("<div/>");h.append(r.wrap((new n.Label({title:"Provide a chart title:"})).$el)),h.append(r.wrap(this.title.$el)),h.append(r.wrap((new n.Label({title:"Select a chart type:"})).$el)),h.append(r.wrap(this.table.$el)),this.tabs.add({id:"main",title:"Start",$el:h}),this.settings=new u(this.app),this.tabs.add({id:"settings",title:"Configuration",$el:this.settings.$el}),this.setElement(this.tabs.$el),this.tabs.hideOperation("back");var o=this;this.chart.on("change:title",function(e){o.title.value(e.get("title")),o.app.config.set("title",e.get("title"))}),this.chart.on("change:type",function(e){o.table.value(e.get("type"))}),this.chart.on("reset",function(e){o._resetChart()}),this.app.charts.on("add",function(e){o.tabs.showOperation("back")}),this.app.charts.on("remove",function(e){o.app.charts.length==0&&o.tabs.hideOperation("back")}),this.app.charts.on("reset",function(e){o.tabs.hideOperation("back")}),this.app.chart.groups.on("add",function(e){o._addGroup(e)}),this.app.chart.groups.on("remove",function(e){o._removeGroup(e)}),this.app.chart.groups.on("reset",function(e){o._removeAllGroups()}),this.app.chart.groups.on("change:key",function(e){o._refreshGroupKey()}),this._resetChart()},show:function(){this.$el.show()},hide:function(){$(".tooltip").hide(),this.$el.hide()},_refreshGroupKey:function(){var e=this,t=0;this.chart.groups.each(function(n){var r=n.get("key","");r==""&&(r="Chart data"),e.tabs.title(n.id,++t+": "+r)})},_addGroupModel:function(){var e=new s({id:r.uuid()});return this.chart.groups.add(e),e},_addGroup:function(e){var t=this,n=new o(this.app,{group:e}),r=t.chart.groups.length;this.tabs.add({id:e.id,$el:n.$el,ondel:function(){t.chart.groups.remove(e.id)}}),this._refreshGroupKey()},_removeGroup:function(e){this.tabs.del(e.id),this._refreshGroupKey()},_removeAllGroups:function(e){this.tabs.delRemovable()},_resetChart:function(){this.chart.set("id",r.uuid()),this.chart.set("type","bardiagram"),this.chart.set("dataset_id",this.app.options.config.dataset_id),this.chart.set("title","New Chart")},_saveChart:function(){this.chart.set({type:this.table.value(),title:this.title.value(),date:r.time()}),this.chart.groups.length==0&&this._addGroupModel();var e=this.app.charts.get(this.chart.id);e?e.copy(this.chart):(e=this.chart.clone(),e.copy(this.chart),this.app.charts.add(e)),e.trigger("redraw",e),this.app.charts.save()}})}),define("plugin/models/config",[],function(){return Backbone.Model.extend({defaults:{query_limit:1e3,query_timeout:500,title:"Create a new chart"}})}),define("plugin/models/charts",["plugin/models/chart"],function(e){return Backbone.Collection.extend({model:e,save:function(){var e=new Visualization({type:"charts",config:{charts:[]}});e.save().fail(function(e,t,n){console.error(e,t,n),alert("Error loading data:\n"+e.responseText)})}})}),define("plugin/charts/_nvd3/config",[],function(){return{title:"",columns:{y:{title:"Values for y-axis"}},settings:{separator_label:{title:"X axis",type:"separator"},x_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"X-axis",placeholder:"Axis label"},x_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"f",data:[{label:"-- Do not show values --",value:"hide"},{label:"Float",value:"f"},{label:"Exponent",value:"e"},{label:"Integer",value:"d"},{label:"Percentage",value:"p"},{label:"Rounded",value:"r"},{label:"SI-prefix",value:"s"}]},x_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_tick:{title:"Y axis",type:"separator"},y_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"Y-axis",placeholder:"Axis label"},y_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"f",data:[{label:"-- Do not show values --",value:"hide"},{label:"Float",value:"f"},{label:"Exponent",value:"e"},{label:"Integer",value:"d"},{label:"Percentage",value:"p"},{label:"Rounded",value:"r"},{label:"SI-prefix",value:"s"}]},y_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_legend:{title:"Others",type:"separator"},show_legend:{title:"Show legend",info:"Would you like to add a legend?",type:"select",init:"true",data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]}}}}),define("plugin/charts/bardiagram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram"})}),define("plugin/charts/histogram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Histogram",execute:!0,columns:{y:{title:"Observations"}},settings:{x_axis_label:{init:"Breaks"},y_axis_label:{init:"Density"},y_axis_tick:{init:".3"}}})}),define("plugin/charts/horizontal/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram (horizontal)",settings:{x_axis_type:{init:"hide"}}})}),define("plugin/charts/line/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line chart"})}),define("plugin/charts/linewithfocus/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line with focus"})}),define("plugin/charts/piechart/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Pie chart"})}),define("plugin/charts/scatterplot/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Scatter plot",columns:{x:{title:"Values for x-axis"}}})}),define("plugin/charts/stackedarea/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Stacked area"})}),define("plugin/charts/types",["plugin/charts/bardiagram/config","plugin/charts/histogram/config","plugin/charts/horizontal/config","plugin/charts/line/config","plugin/charts/linewithfocus/config","plugin/charts/piechart/config","plugin/charts/scatterplot/config","plugin/charts/stackedarea/config"],function(e,t,n,r,i,s,o,u){return Backbone.Model.extend({defaults:{bardiagram:e,horizontal:n,histogram:t,line:r,linewithfocus:i,piechart:s,scatterplot:o,stackedarea:u}})}),define("plugin/app",["mvc/ui/ui-modal","mvc/ui/ui-portlet","plugin/library/ui","utils/utils","plugin/library/jobs","plugin/library/datasets","plugin/views/charts","plugin/views/chart","plugin/models/config","plugin/models/chart","plugin/models/charts","plugin/charts/types"],function(e,t,n,r,i,s,o,u,a,f,l,c){return Backbone.View.extend({initialize:function(n){this.options=n,Galaxy&&Galaxy.modal?this.modal=Galaxy.modal:this.modal=new e.View,this.config=new a,this.jobs=new i(this),this.types=new c,this.chart=new f,this.charts=new l,this.datasets=new s(this),this.charts_view=new o(this),this.chart_view=new u(this),this.options.config.widget?this.portlet=$("<div></div>"):this.portlet=new t.View({icon:"fa-bar-chart-o"}),this.portlet.append(this.charts_view.$el),this.portlet.append(this.chart_view.$el),this.options.config.widget?this.setElement(this.portlet):this.setElement(this.portlet.$el),this.go("chart_view");var r=this;this.config.on("change:title",function(){r._refreshTitle()}),this.render()},go:function(e){switch(e){case"chart_view":this.chart_view.show(),this.charts_view.hide();break;case"charts_view":this.chart_view.hide(),this.charts_view.show()}},render:function(){this._refreshTitle()},_refreshTitle:function(){var e=this.config.get("title");e&&(e=" - "+e),this.portlet.title("Charts"+e)},execute:function(e){},onunload:function(){},log:function(e,t){console.log(e+" "+t)}})});
\ No newline at end of file
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a config/plugins/visualizations/charts/static/charts/histogram/config.js
--- a/config/plugins/visualizations/charts/static/charts/histogram/config.js
+++ b/config/plugins/visualizations/charts/static/charts/histogram/config.js
@@ -17,46 +17,6 @@
},
y_axis_tick : {
init : '.3'
- },
- separator_custom : {
- title : 'Advanced',
- type : 'separator'
- },
- bin_size : {
- title : 'Bin size',
- info : 'Provide the bin size for the histogram.',
- type : 'select',
- init : 1,
- data : [
- {
- label : '0.001',
- value : '0.001'
- },
- {
- label : '0.01',
- value : '0.01'
- },
- {
- label : '0.1',
- value : '0.1'
- },
- {
- label : '1',
- value : '1'
- },
- {
- label : '10',
- value : '10'
- },
- {
- label : '100',
- value : '100'
- },
- {
- label : '1000',
- value : '1000'
- }
- ]
}
}
});
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a config/plugins/visualizations/charts/static/library/jobs.js
--- a/config/plugins/visualizations/charts/static/library/jobs.js
+++ b/config/plugins/visualizations/charts/static/library/jobs.js
@@ -92,7 +92,7 @@
if (response && response.message && response.message.data && response.message.data.input) {
message = response.message.data.input + '.';
}
- chart.state('failed', 'This visualization requires processing by the R-kit. Please make sure that it is installed. ' + message);
+ chart.state('failed', 'This visualization requires the R-kit. Please make sure it is installed. ' + message);
}
);
},
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a config/plugins/visualizations/charts/static/library/ui-table-form.js
--- a/config/plugins/visualizations/charts/static/library/ui-table-form.js
+++ b/config/plugins/visualizations/charts/static/library/ui-table-form.js
@@ -9,7 +9,7 @@
initialize: function(options) {
// ui elements
this.table_title = new Ui.Label({title: options.title});
- this.table = new Table({content: options.content});
+ this.table = new Table.View({content: options.content});
// create element
var $view = $('<div/>');
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a config/plugins/visualizations/charts/static/library/ui-table.js
--- a/config/plugins/visualizations/charts/static/library/ui-table.js
+++ b/config/plugins/visualizations/charts/static/library/ui-table.js
@@ -1,8 +1,6 @@
-// dependencies
define(['utils/utils'], function(Utils) {
-// return
-return Backbone.View.extend(
+var View = Backbone.View.extend(
{
// current row
row: null,
@@ -202,4 +200,8 @@
}
});
+return {
+ View: View
+}
+
});
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a config/plugins/visualizations/charts/static/models/chart.js
--- a/config/plugins/visualizations/charts/static/models/chart.js
+++ b/config/plugins/visualizations/charts/static/models/chart.js
@@ -58,25 +58,6 @@
ready: function() {
return (this.get('state') == 'ok') || (this.get('state') == 'failed');
- },
-
- // save charts
- save: function() {
- /*/ create visualization
- var vis = new Visualization({
- type : 'charts',
- config : this.attributes
- });
-
- // copy attributes
- //vis.set(this.attributes);
-
- // save visualization
- vis.save()
- .fail( function( xhr, status, message ){
- console.error( xhr, status, message );
- alert( 'Error loading data:\n' + xhr.responseText );
- });*/
}
});
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a config/plugins/visualizations/charts/static/models/charts.js
--- a/config/plugins/visualizations/charts/static/models/charts.js
+++ b/config/plugins/visualizations/charts/static/models/charts.js
@@ -4,7 +4,28 @@
// collection
return Backbone.Collection.extend(
{
- model: Chart
+ model: Chart,
+
+ // save charts
+ save: function() {
+ // create visualization
+ var vis = new Visualization({
+ type : 'charts',
+ config : {
+ charts : []
+ }
+ });
+
+ // copy attributes
+ //vis.set(this.attributes);
+
+ // save visualization
+ vis.save()
+ .fail( function( xhr, status, message ){
+ console.error( xhr, status, message );
+ alert( 'Error loading data:\n' + xhr.responseText );
+ });
+ }
});
});
\ No newline at end of file
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a config/plugins/visualizations/charts/static/views/chart.js
--- a/config/plugins/visualizations/charts/static/views/chart.js
+++ b/config/plugins/visualizations/charts/static/views/chart.js
@@ -29,14 +29,14 @@
// table with chart types
//
var self = this;
- this.table = new Table({
+ this.table = new Table.View({
header : false,
onconfirm : function(type) {
if (self.chart.groups.length > 0) {
// show modal
self.app.modal.show({
title : 'Switching to another chart type?',
- body : 'If you continue your settings and selections will be reseted.',
+ body : 'If you continue your settings and selections will be cleared.',
buttons : {
'Cancel' : function() {
// hide modal
@@ -99,17 +99,11 @@
tooltip : 'Draw Chart',
title : 'Draw',
onclick : function() {
- // ensure that data group is available
- if (self.chart.groups.length == 0) {
- self._addGroupModel();
- }
+ // show charts
+ self.app.go('charts_view');
// save chart
self._saveChart();
-
- // show charts
- self.hide();
- self.app.charts_view.$el.show();
}
}),
'back' : new Ui.ButtonIcon({
@@ -117,8 +111,7 @@
tooltip : 'Return to Viewer',
title : 'Return',
onclick : function() {
- self.hide();
- self.app.charts_view.$el.show();
+ self.app.go('charts_view');
}
})
}
@@ -215,6 +208,11 @@
},
// hide
+ show: function() {
+ this.$el.show();
+ },
+
+ // hide
hide: function() {
$('.tooltip').hide();
this.$el.hide();
@@ -297,6 +295,11 @@
date : Utils.time()
});
+ // ensure that data group is available
+ if (this.chart.groups.length == 0) {
+ this._addGroupModel();
+ }
+
// create/get chart
var current = this.app.charts.get(this.chart.id);
if (!current) {
@@ -307,11 +310,11 @@
current.copy(this.chart);
}
- // save
- current.save();
-
// trigger redraw
current.trigger('redraw', current);
+
+ // save
+ this.app.charts.save();
}
});
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a config/plugins/visualizations/charts/static/views/charts.js
--- a/config/plugins/visualizations/charts/static/views/charts.js
+++ b/config/plugins/visualizations/charts/static/views/charts.js
@@ -14,18 +14,11 @@
this.viewport_view = new ViewportView(app);
// table
- this.table = new Table({
+ this.table = new Table.View({
content : 'Add charts to this table.',
ondblclick : function(chart_id) {
- // get chart
- var chart = self.app.charts.get(chart_id);
- self.app.chart.copy(chart);
-
- // hide this element
- self.hide();
-
- // show chart view
- self.app.chart_view.$el.show();
+ // attempt to load chart editor
+ self._showChartView(chart_id);
},
onchange : function(chart_id) {
// get chart
@@ -47,32 +40,46 @@
height : 100,
operations : {
'new' : new Ui.ButtonIcon({
- icon : 'fa-magic',
- tooltip: 'Create a new Chart',
- title: 'New',
- onclick: function() {
- self.hide();
- self.app.chart.reset();
- self.app.chart_view.$el.show();
- }
- }),
+ icon : 'fa-magic',
+ tooltip : 'Create a new Chart',
+ title : 'New',
+ onclick : function() {
+ self.app.go('chart_view');
+ self.app.chart.reset();
+ }
+ }),
+ 'edit' : new Ui.ButtonIcon({
+ icon : 'fa-gear',
+ tooltip : 'Customize this Chart',
+ title : 'Customize',
+ onclick : function() {
+ // check if element has been selected
+ var chart_id = self.table.value();
+ if (!chart_id) {
+ return;
+ }
+
+ // attempt to load chart editor
+ self._showChartView(chart_id);
+ }
+ }),
'delete' : new Ui.ButtonIcon({
- icon : 'fa-trash-o',
- tooltip: 'Delete this Chart',
- title: 'Delete',
- onclick: function() {
+ icon : 'fa-trash-o',
+ tooltip : 'Delete this Chart',
+ title : 'Delete',
+ onclick : function() {
- // check if element has been selected
- var chart_id = self.table.value();
- if (!chart_id) {
- return;
- }
-
- // title
- var chart = self.app.charts.get(chart_id);
-
- // show modal
- self.app.modal.show({
+ // check if element has been selected
+ var chart_id = self.table.value();
+ if (!chart_id) {
+ return;
+ }
+
+ // title
+ var chart = self.app.charts.get(chart_id);
+
+ // show modal
+ self.app.modal.show({
title : 'Are you sure?',
body : 'The selected chart "' + chart.get('title') + '" will be irreversibly deleted.',
buttons : {
@@ -116,7 +123,12 @@
self._changeChart(chart);
});
},
-
+
+ // show
+ show: function() {
+ this.$el.show();
+ },
+
// hide
hide: function() {
$('.tooltip').hide();
@@ -147,11 +159,13 @@
// remove from to table
this.table.remove(chart.id);
+ // save
+ this.app.charts.save();
+
// check if table is empty
if (this.table.size() == 0) {
- this.hide();
+ this.app.go('chart_view');
this.app.chart.reset();
- this.app.chart_view.$el.show();
} else {
// select available chart
this.table.value(this.app.charts.last().id);
@@ -167,6 +181,36 @@
// select available chart
this.table.value(chart.id);
}
+ },
+
+ // show chart editor
+ _showChartView: function(chart_id) {
+ // get chart
+ var chart = this.app.charts.get(chart_id);
+ if (chart.ready()) {
+ // show chart view
+ this.app.go('chart_view');
+
+ // load chart into view
+ this.app.chart.copy(chart);
+ } else {
+ // show modal
+ var self = this;
+ this.app.modal.show({
+ title : 'Please wait!',
+ body : 'The selected chart "' + chart.get('title') + '" is currently being processed. Please wait...',
+ buttons : {
+ 'Close' : function() {self.app.modal.hide();},
+ 'Retry' : function() {
+ // hide modal
+ self.app.modal.hide();
+
+ // retry
+ self._showChartView(chart_id);
+ }
+ }
+ });
+ }
}
});
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a config/plugins/visualizations/charts/static/views/group.js
--- a/config/plugins/visualizations/charts/static/views/group.js
+++ b/config/plugins/visualizations/charts/static/views/group.js
@@ -29,7 +29,7 @@
self.group.set('key', self.group_key.value());
}
});
- this.table = new Table({content: 'No data column.'});
+ this.table = new Table.View({content: 'No data column.'});
// create element
var $view = $('<div/>');
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a config/plugins/visualizations/charts/static/views/viewport.js
--- a/config/plugins/visualizations/charts/static/views/viewport.js
+++ b/config/plugins/visualizations/charts/static/views/viewport.js
@@ -27,14 +27,7 @@
this.portlet = new Portlet.View({
title : 'title',
height : this.options.height,
- overflow : 'hidden',
- operations : {
- 'edit' : new Ui.ButtonIcon({
- icon : 'fa-gear',
- tooltip : 'Customize Chart',
- title : 'Customize'
- })
- }
+ overflow : 'hidden'
});
// set this element
@@ -80,15 +73,7 @@
// update portlet
this.portlet.title(chart.get('title'));
- this.portlet.setOperation('edit', function() {
- // get chart
- self.app.chart.copy(chart);
-
- // show edit
- self.app.charts_view.hide();
- self.app.chart_view.$el.show();
- });
-
+
// show selected chart
item.$el.show();
@@ -124,7 +109,7 @@
self.app.log('viewport:_refreshChart()', 'Invalid attempt to refresh chart before completion.');
return;
}
-
+
// backup chart details
var chart_id = chart.id;
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a config/plugins/visualizations/charts/templates/charts.mako
--- a/config/plugins/visualizations/charts/templates/charts.mako
+++ b/config/plugins/visualizations/charts/templates/charts.mako
@@ -15,8 +15,7 @@
'libs/require',
'libs/underscore',
'libs/backbone/backbone',
- 'libs/d3',
- 'mvc/base-mvc')}
+ 'libs/d3')}
## css
${h.css( 'base' )}
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a static/scripts/mvc/ui/ui-portlet.js
--- a/static/scripts/mvc/ui/ui-portlet.js
+++ b/static/scripts/mvc/ui/ui-portlet.js
@@ -141,31 +141,31 @@
// fill template
_template: function(options) {
- var tmpl = '<div class="toolForm">';
+ var tmpl = '<div class="toolForm portlet-view no-highlight">';
if (options.title || options.icon) {
- tmpl += '<div id="title" class="toolFormTitle" style="overflow: hidden;">' +
- '<div id="operations" style="float: right;"></div>' +
+ tmpl += '<div id="title" class="toolFormTitle portlet-title">' +
+ '<div id="operations" class="portlet-operations"/>' +
'<div style="overflow: hidden;">';
if (options.icon)
- tmpl += '<i style="padding-top: 3px; float: left; font-size: 1.2em" class="icon fa ' + options.icon + '"> </i>';
+ tmpl += '<div class="portlet-title-icon fa ' + options.icon + '"> </div>';
- tmpl += '<div id="title-text" style="padding-top: 2px; float: left;">' + options.title + '</div>';
+ tmpl += '<div id="title-text" class="portlet-title-text">' + options.title + '</div>';
tmpl += '</div>' +
'</div>';
}
- tmpl += '<div id="body" class="toolFormBody">';
+ tmpl += '<div id="body" class="toolFormBody portlet-body">';
if (options.placement == 'top') {
- tmpl += '<div id="buttons" class="buttons" style="height: 50px; padding: 10px;"></div>';
+ tmpl += '<div id="buttons" class="portlet-buttons"/>';
}
- tmpl += '<div id="content" class="content" style="height: inherit; padding: 10px;"></div>';
+ tmpl += '<div id="content" class="portlet-content"/>';
if (options.placement == 'bottom') {
- tmpl += '<div id="buttons" class="buttons" style="height: 50px; padding: 10px;"></div>';
+ tmpl += '<div id="buttons" class="portlet-buttons"/>';
}
tmpl += '</div>' +
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a static/scripts/packed/mvc/ui/ui-portlet.js
--- a/static/scripts/packed/mvc/ui/ui-portlet.js
+++ b/static/scripts/packed/mvc/ui/ui-portlet.js
@@ -1,1 +1,1 @@
-define(["utils/utils"],function(a){var b=Backbone.View.extend({visible:false,optionsDefault:{title:"",icon:"",buttons:null,body:null,height:null,operations:null,placement:"bottom",overflow:"auto"},$title:null,$content:null,$buttons:null,$operations:null,initialize:function(d){this.options=a.merge(d,this.optionsDefault);this.setElement(this._template(this.options));this.$content=this.$el.find("#content");this.$title=this.$el.find("#title-text");if(this.options.height){this.$el.find("#body").css("height",this.options.height);this.$el.find("#content").css("overflow",this.options.overflow)}this.$buttons=$(this.el).find("#buttons");if(this.options.buttons){var c=this;$.each(this.options.buttons,function(e,f){f.$el.prop("id",e);c.$buttons.append(f.$el)})}else{this.$buttons.remove()}this.$operations=$(this.el).find("#operations");if(this.options.operations){var c=this;$.each(this.options.operations,function(e,f){f.$el.prop("id",e);c.$operations.append(f.$el)})}if(this.options.body){this.append(this.options.body)}},append:function(c){this.$content.append(a.wrap(c))},content:function(){return this.$content},show:function(){this.$el.fadeIn("fast");this.visible=true},hide:function(){this.$el.fadeOut("fast");this.visible=false},enableButton:function(c){this.$buttons.find("#"+c).prop("disabled",false)},disableButton:function(c){this.$buttons.find("#"+c).prop("disabled",true)},hideOperation:function(c){this.$operations.find("#"+c).hide()},showOperation:function(c){this.$operations.find("#"+c).show()},setOperation:function(e,d){var c=this.$operations.find("#"+e);c.off("click");c.on("click",d)},title:function(d){var c=this.$title;if(d){c.html(d)}return c.html()},_template:function(d){var c='<div class="toolForm">';if(d.title||d.icon){c+='<div id="title" class="toolFormTitle" style="overflow: hidden;"><div id="operations" style="float: right;"></div><div style="overflow: hidden;">';if(d.icon){c+='<i style="padding-top: 3px; float: left; font-size: 1.2em" class="icon fa '+d.icon+'"> </i>'}c+='<div id="title-text" style="padding-top: 2px; float: left;">'+d.title+"</div>";c+="</div></div>"}c+='<div id="body" class="toolFormBody">';if(d.placement=="top"){c+='<div id="buttons" class="buttons" style="height: 50px; padding: 10px;"></div>'}c+='<div id="content" class="content" style="height: inherit; padding: 10px;"></div>';if(d.placement=="bottom"){c+='<div id="buttons" class="buttons" style="height: 50px; padding: 10px;"></div>'}c+="</div></div>";return c}});return{View:b}});
\ No newline at end of file
+define(["utils/utils"],function(a){var b=Backbone.View.extend({visible:false,optionsDefault:{title:"",icon:"",buttons:null,body:null,height:null,operations:null,placement:"bottom",overflow:"auto"},$title:null,$content:null,$buttons:null,$operations:null,initialize:function(d){this.options=a.merge(d,this.optionsDefault);this.setElement(this._template(this.options));this.$content=this.$el.find("#content");this.$title=this.$el.find("#title-text");if(this.options.height){this.$el.find("#body").css("height",this.options.height);this.$el.find("#content").css("overflow",this.options.overflow)}this.$buttons=$(this.el).find("#buttons");if(this.options.buttons){var c=this;$.each(this.options.buttons,function(e,f){f.$el.prop("id",e);c.$buttons.append(f.$el)})}else{this.$buttons.remove()}this.$operations=$(this.el).find("#operations");if(this.options.operations){var c=this;$.each(this.options.operations,function(e,f){f.$el.prop("id",e);c.$operations.append(f.$el)})}if(this.options.body){this.append(this.options.body)}},append:function(c){this.$content.append(a.wrap(c))},content:function(){return this.$content},show:function(){this.$el.fadeIn("fast");this.visible=true},hide:function(){this.$el.fadeOut("fast");this.visible=false},enableButton:function(c){this.$buttons.find("#"+c).prop("disabled",false)},disableButton:function(c){this.$buttons.find("#"+c).prop("disabled",true)},hideOperation:function(c){this.$operations.find("#"+c).hide()},showOperation:function(c){this.$operations.find("#"+c).show()},setOperation:function(e,d){var c=this.$operations.find("#"+e);c.off("click");c.on("click",d)},title:function(d){var c=this.$title;if(d){c.html(d)}return c.html()},_template:function(d){var c='<div class="toolForm portlet-view no-highlight">';if(d.title||d.icon){c+='<div id="title" class="toolFormTitle portlet-title"><div id="operations" class="portlet-operations"/><div style="overflow: hidden;">';if(d.icon){c+='<div class="portlet-title-icon fa '+d.icon+'"> </div>'}c+='<div id="title-text" class="portlet-title-text">'+d.title+"</div>";c+="</div></div>"}c+='<div id="body" class="toolFormBody portlet-body">';if(d.placement=="top"){c+='<div id="buttons" class="portlet-buttons"/>'}c+='<div id="content" class="portlet-content"/>';if(d.placement=="bottom"){c+='<div id="buttons" class="portlet-buttons"/>'}c+="</div></div>";return c}});return{View:b}});
\ No newline at end of file
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1278,6 +1278,13 @@
.upload-ftp .upload-ftp-help{margin-bottom:10px}
.upload-ftp .upload-ftp-warning{text-align:center;margin-top:20px}
.upload-settings .upload-settings-cover{position:absolute;width:100%;height:100%;top:0px;left:0px;background:#fff;opacity:0.4;cursor:no-drop}
+.no-highlight{-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-ms-user-select:none;}
+.portlet-view{min-width:300px}.portlet-view .portlet-title-icon{float:left;font-size:1.2em;padding-top:3px}
+.portlet-view .portlet-title{overflow:hidden}
+.portlet-view .portlet-title-text{float:left;padding-top:1px}
+.portlet-view .portlet-operations{float:right;cursor:pointer}
+.portlet-view .portlet-buttons{height:50px;padding:10px}
+.portlet-view .portlet-content{height:inherit;padding:10px}
.popover-view{max-width:700px;display:none}.popover-view .popover-close{position:absolute;right:10px;top:7px;font-size:1.2em;cursor:pointer}
.popover-view .popover-title{padding:4px 10px}
.styled-select{position:relative;height:27px;overflow:hidden;border:1px solid #bfbfbf;-moz-border-radius:3px;border-radius:3px}.styled-select .button{position:relative;width:25px;height:100%;float:right;border-left:1px solid #bfbfbf;padding-left:9px;padding-top:4px;background:#f2f2f2}
diff -r aa1eee2bd24a4ba449449f16659701eb7481f301 -r dec159841d670560582aadc1327bec0673f7003a static/style/src/less/ui.less
--- a/static/style/src/less/ui.less
+++ b/static/style/src/less/ui.less
@@ -1,3 +1,44 @@
+.no-highlight {
+ -webkit-user-select: none; /* webkit (safari, chrome) browsers */
+ -moz-user-select: none; /* mozilla browsers */
+ -khtml-user-select: none; /* webkit (konqueror) browsers */
+ -ms-user-select: none; /* IE10+ */
+}
+
+.portlet-view {
+ min-width: 300px;
+
+ .portlet-title-icon {
+ float: left;
+ font-size: 1.2em;
+ padding-top: 3px;
+ }
+
+ .portlet-title {
+ overflow: hidden;
+ }
+
+ .portlet-title-text {
+ float: left;
+ padding-top: 1px;
+ }
+
+ .portlet-operations {
+ float: right;
+ cursor: pointer;
+ }
+
+ .portlet-buttons {
+ height: 50px;
+ padding: 10px;
+ }
+
+ .portlet-content {
+ height: inherit;
+ padding: 10px;
+ }
+}
+
.popover-view {
max-width: 700px;
display: none;
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: martenson: libraries - removal of id-encoding related bug in API commited in f7ebd14c2f9b260cdb6627e4abfd5c03f14c4900 and identified by jmchilton in https://bitbucket.org/galaxy/galaxy-central/commits/f7ebd14c2f9b260cdb6627e4abfd5c03f14c4900#comment-825140
by commits-noreply@bitbucket.org 20 Mar '14
by commits-noreply@bitbucket.org 20 Mar '14
20 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/aa1eee2bd24a/
Changeset: aa1eee2bd24a
User: martenson
Date: 2014-03-21 00:26:45
Summary: libraries - removal of id-encoding related bug in API commited in f7ebd14c2f9b260cdb6627e4abfd5c03f14c4900 and identified by jmchilton in https://bitbucket.org/galaxy/galaxy-central/commits/f7ebd14c2f9b260cdb6627e…
Affected #: 2 files
diff -r 29a9d6d904f3506f141253e2b1e97cf1aa55a081 -r aa1eee2bd24a4ba449449f16659701eb7481f301 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -2078,8 +2078,8 @@
# This needs to be a list
return [ ld for ld in self.datasets if ld.library_dataset_dataset_association and not ld.library_dataset_dataset_association.dataset.deleted ]
- def to_dict( self, view='collection' ):
- rval = super( LibraryFolder, self ).to_dict( view=view )
+ def to_dict( self, view='collection', value_mapper=None ):
+ rval = super( LibraryFolder, self ).to_dict( view=view, value_mapper=value_mapper )
info_association, inherited = self.get_info_association()
if info_association:
if inherited:
diff -r 29a9d6d904f3506f141253e2b1e97cf1aa55a081 -r aa1eee2bd24a4ba449449f16659701eb7481f301 lib/galaxy/webapps/galaxy/api/library_contents.py
--- a/lib/galaxy/webapps/galaxy/api/library_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/library_contents.py
@@ -123,11 +123,18 @@
class_name, content_id = self.__decode_library_content_id( trans, id )
if class_name == 'LibraryFolder':
content = self.get_library_folder( trans, content_id, check_ownership=False, check_accessible=True )
+ rval = content.to_dict( view='element', value_mapper={ 'id' : trans.security.encode_id } )
+ rval[ 'id' ] = 'F' + str( rval[ 'id' ] )
+ rval[ 'parent_id' ] = 'F' + str( trans.security.encode_id( rval[ 'parent_id' ] ) )
+ rval[ 'parent_library_id' ] = trans.security.encode_id( rval[ 'parent_library_id' ] )
else:
content = self.get_library_dataset( trans, content_id, check_ownership=False, check_accessible=True )
-
- return content.to_dict( view='element', value_mapper={ 'id' : trans.security.encode_id } )
- # return self.encode_all_ids( trans, content.to_dict( view='element' ) )
+ rval = content.to_dict( view='element')
+ rval[ 'id' ] = trans.security.encode_id( rval[ 'id' ] )
+ rval[ 'ldda_id' ] = trans.security.encode_id( rval[ 'ldda_id' ] )
+ rval[ 'folder_id' ] = 'F' + str( trans.security.encode_id( rval[ 'folder_id' ] ) )
+ rval[ 'parent_library_id' ] = trans.security.encode_id( rval[ 'parent_library_id' ] )
+ return rval
@web.expose_api
def create( self, trans, library_id, payload, **kwd ):
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: martenson: biostar: moved icon tooltips placement to the bottom for readability
by commits-noreply@bitbucket.org 20 Mar '14
by commits-noreply@bitbucket.org 20 Mar '14
20 Mar '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/29a9d6d904f3/
Changeset: 29a9d6d904f3
User: martenson
Date: 2014-03-20 22:30:47
Summary: biostar: moved icon tooltips placement to the bottom for readability
Affected #: 1 file
diff -r 86ea88b98bb7b2f2eb1fad554307d3e5d055d9ce -r 29a9d6d904f3506f141253e2b1e97cf1aa55a081 templates/webapps/galaxy/tool_form.mako
--- a/templates/webapps/galaxy/tool_form.mako
+++ b/templates/webapps/galaxy/tool_form.mako
@@ -327,9 +327,9 @@
Help from Biostar
<div class="icon-btn-group"><a href="${h.url_for( controller='biostar', action='biostar_tool_tag_redirect', tool_id=tool.id )}"
- target="_blank" class="icon-btn" title="Search for this tool"><span class="fa fa-search"></span></a>
+ target="_blank" class="icon-btn" title="Search for this tool" data-toggle="tooltip" data-placement="bottom"><span class="fa fa-search"></span></a><a href="${h.url_for( controller='biostar', action='biostar_tool_question_redirect', tool_id=tool.id )}"
- target="_blank" class="icon-btn" title="Ask a question about this tool"><span class="fa fa-question-circle"></a>
+ target="_blank" class="icon-btn" title="Ask a question about this tool" data-toggle="tooltip" data-placement="bottom"><span class="fa fa-question-circle"></a></div></span>
%endif
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0