galaxy-commits
Threads by month
- ----- 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
October 2012
- 1 participants
- 194 discussions
commit/galaxy-central: jgoecks: Add backbone model, collection, and view for configuration settings. Pack scripts.
by Bitbucket 19 Oct '12
by Bitbucket 19 Oct '12
19 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/8bcc04c4b710/
changeset: 8bcc04c4b710
user: jgoecks
date: 2012-10-19 17:55:49
summary: Add backbone model, collection, and view for configuration settings. Pack scripts.
affected #: 10 files
diff -r 4cd4f8bef29d17a7bca74e235031060e2289ebdc -r 8bcc04c4b710dbf4173a5fba6d2a3111e7c2b511 static/scripts/packed/templates/compiled/template-visualization-chartSettings.js
--- a/static/scripts/packed/templates/compiled/template-visualization-chartSettings.js
+++ b/static/scripts/packed/templates/compiled/template-visualization-chartSettings.js
@@ -1,3 +1,1 @@
-<<<<<<< local
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-chartSettings"]=b(function(f,m,e,l,k){e=e||f.helpers;var i="",c,h,g="function",j=this.escapeExpression,n=this;function d(p,o){return' checked="true"'}i+='<p class="help-text">\n Use the following controls to how the chart is displayed.\n The slide controls can be moved by the mouse or, if the \'handle\' is in focus, your keyboard\'s arrow keys.\n Move the focus between controls by using the tab or shift+tab keys on your keyboard.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n </p>\n \n <div id="datapointSize" class="form-input numeric-slider-input">\n <label for="datapointSize">Size of data point: </label>\n <div class="slider-output">';h=e.datapointSize;if(h){c=h.call(m,{hash:{}})}else{c=m.datapointSize;c=typeof c===g?c():c}i+=j(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n Size of the graphic representation of each data point\n </p>\n </div>\n\n <div id="animDuration" class="form-input checkbox-input">\n <label for="animated">Animate graph transitions?: </label>\n <input type="checkbox" id="animated"\n class="checkbox control"';c=m.animDuration;c=e["if"].call(m,c,{hash:{},inverse:n.noop,fn:n.program(1,d,k)});if(c||c===0){i+=c}i+=' />\n <p class="form-help help-text-small">\n Uncheck this to disable the animations used on the graph\n </p>\n </div>\n\n <div id="width" class="form-input numeric-slider-input">\n <label for="width">Graph width: </label>\n <div class="slider-output">';h=e.width;if(h){c=h.call(m,{hash:{}})}else{c=m.width;c=typeof c===g?c():c}i+=j(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including graph margins and axes)\n </p>\n </div>\n\n <div id="height" class="form-input numeric-slider-input">\n <label for="height">Graph height: </label>\n <div class="slider-output">';h=e.height;if(h){c=h.call(m,{hash:{}})}else{c=m.height;c=typeof c===g?c():c}i+=j(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including graph margins and axes)\n </p>\n </div>\n\n <div id="X-axis-label"class="text-input form-input">\n <label for="X-axis-label">Re-label the X axis: </label>\n <input type="text" name="X-axis-label" id="X-axis-label" value="';h=e.xLabel;if(h){c=h.call(m,{hash:{}})}else{c=m.xLabel;c=typeof c===g?c():c}i+=j(c)+'" />\n <p class="form-help help-text-small"></p>\n </div>\n\n <div id="Y-axis-label" class="text-input form-input">\n <label for="Y-axis-label">Re-label the Y axis: </label>\n <input type="text" name="Y-axis-label" id="Y-axis-label" value="';h=e.yLabel;if(h){c=h.call(m,{hash:{}})}else{c=m.yLabel;c=typeof c===g?c():c}i+=j(c)+'" />\n <p class="form-help help-text-small"></p>\n </div>\n\n <input id="render-button" type="button" value="Draw" />';return i})})();=======
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-chartSettings"]=b(function(f,m,e,l,k){e=e||f.helpers;var i="",c,h,g="function",j=this.escapeExpression,n=this;function d(p,o){return"checked"}i+='<p class="help-text">\n Use the following controls to how the chart is displayed.\n The slide controls can be moved by the mouse or, if the \'handle\' is in focus, your keyboard\'s arrow keys.\n Move the focus between controls by using the tab or shift+tab keys on your keyboard.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n </p>\n \n <div id="maxDataPoints" class="form-input numeric-slider-input">\n <label for="maxDataPoints">Maximum data points allowed on graph: </label>\n <div class="slider-output">';h=e.maxDataPoints;if(h){c=h.call(m,{hash:{}})}else{c=m.maxDataPoints;c=typeof c===g?c():c}i+=j(c)+'</div>\n <div style="clear: both;"></div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n Change the maximum number of data points displayable on this graph (higher values will\n load significantly slower)\n </p>\n </div>\n\n <div id="datapointSize" class="form-input numeric-slider-input">\n <label for="datapointSize">Size of data point: </label>\n <div class="slider-output">';h=e.datapointSize;if(h){c=h.call(m,{hash:{}})}else{c=m.datapointSize;c=typeof c===g?c():c}i+=j(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n Size of the graphic representation of each data point\n </p>\n </div>\n\n <div id="entryAnimDuration" class="form-input checkbox-input">\n <label for="animated">Animate graph transitions?: </label>\n <input type="checkbox" id="animated" class="checkbox control" value="';c=m.entryAnimDuration;c=e["if"].call(m,c,{hash:{},inverse:n.noop,fn:n.program(1,d,k)});if(c||c===0){i+=c}i+='" />\n <p class="form-help help-text-small">\n Uncheck this to disable the animations used on the graph\n </p>\n </div>\n\n <div id="width" class="form-input numeric-slider-input">\n <label for="width">Graph width: </label>\n <div class="slider-output">';h=e.width;if(h){c=h.call(m,{hash:{}})}else{c=m.width;c=typeof c===g?c():c}i+=j(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including graph margins and axes)\n </p>\n </div>\n\n <div id="height" class="form-input numeric-slider-input">\n <label for="height">Graph height: </label>\n <div class="slider-output">';h=e.height;if(h){c=h.call(m,{hash:{}})}else{c=m.height;c=typeof c===g?c():c}i+=j(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including graph margins and axes)\n </p>\n </div>\n\n <div id="X-axis-label"class="text-input form-input">\n <label for="X-axis-label">Re-label the X axis: </label>\n <input type="text" name="X-axis-label" id="X-axis-label" value="';h=e.xLabel;if(h){c=h.call(m,{hash:{}})}else{c=m.xLabel;c=typeof c===g?c():c}i+=j(c)+'" />\n <p class="form-help help-text-small"></p>\n </div>\n\n <div id="Y-axis-label" class="text-input form-input">\n <label for="Y-axis-label">Re-label the Y axis: </label>\n <input type="text" name="Y-axis-label" id="Y-axis-label" value="';h=e.yLabel;if(h){c=h.call(m,{hash:{}})}else{c=m.yLabel;c=typeof c===g?c():c}i+=j(c)+'" />\n <p class="form-help help-text-small"></p>\n </div>\n\n <input id="render-button" type="button" value="Draw" />';return i})})();>>>>>>> other
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-chartSettings"]=b(function(f,m,e,l,k){e=e||f.helpers;var i="",c,h,g="function",j=this.escapeExpression,n=this;function d(p,o){return' checked="true"'}i+='<p class="help-text">\n Use the following controls to how the chart is displayed.\n The slide controls can be moved by the mouse or, if the \'handle\' is in focus, your keyboard\'s arrow keys.\n Move the focus between controls by using the tab or shift+tab keys on your keyboard.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n </p>\n \n <div id="datapointSize" class="form-input numeric-slider-input">\n <label for="datapointSize">Size of data point: </label>\n <div class="slider-output">';h=e.datapointSize;if(h){c=h.call(m,{hash:{}})}else{c=m.datapointSize;c=typeof c===g?c():c}i+=j(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n Size of the graphic representation of each data point\n </p>\n </div>\n\n <div id="animDuration" class="form-input checkbox-input">\n <label for="animated">Animate graph transitions?: </label>\n <input type="checkbox" id="animated"\n class="checkbox control"';c=m.animDuration;c=e["if"].call(m,c,{hash:{},inverse:n.noop,fn:n.program(1,d,k)});if(c||c===0){i+=c}i+=' />\n <p class="form-help help-text-small">\n Uncheck this to disable the animations used on the graph\n </p>\n </div>\n\n <div id="width" class="form-input numeric-slider-input">\n <label for="width">Graph width: </label>\n <div class="slider-output">';h=e.width;if(h){c=h.call(m,{hash:{}})}else{c=m.width;c=typeof c===g?c():c}i+=j(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including graph margins and axes)\n </p>\n </div>\n\n <div id="height" class="form-input numeric-slider-input">\n <label for="height">Graph height: </label>\n <div class="slider-output">';h=e.height;if(h){c=h.call(m,{hash:{}})}else{c=m.height;c=typeof c===g?c():c}i+=j(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including graph margins and axes)\n </p>\n </div>\n\n <div id="X-axis-label"class="text-input form-input">\n <label for="X-axis-label">Re-label the X axis: </label>\n <input type="text" name="X-axis-label" id="X-axis-label" value="';h=e.xLabel;if(h){c=h.call(m,{hash:{}})}else{c=m.xLabel;c=typeof c===g?c():c}i+=j(c)+'" />\n <p class="form-help help-text-small"></p>\n </div>\n\n <div id="Y-axis-label" class="text-input form-input">\n <label for="Y-axis-label">Re-label the Y axis: </label>\n <input type="text" name="Y-axis-label" id="Y-axis-label" value="';h=e.yLabel;if(h){c=h.call(m,{hash:{}})}else{c=m.yLabel;c=typeof c===g?c():c}i+=j(c)+'" />\n <p class="form-help help-text-small"></p>\n </div>\n\n <input id="render-button" type="button" value="Draw" />';return i})})();
\ No newline at end of file
diff -r 4cd4f8bef29d17a7bca74e235031060e2289ebdc -r 8bcc04c4b710dbf4173a5fba6d2a3111e7c2b511 static/scripts/packed/utils/LazyDataLoader.js
--- a/static/scripts/packed/utils/LazyDataLoader.js
+++ b/static/scripts/packed/utils/LazyDataLoader.js
@@ -1,3 +1,1 @@
-<<<<<<< local
-function LazyDataLoader(c){var a=this,d="loaded.new",b="complete";ERROR_EVENT="error";jQuery.extend(a,LoggableMixin);jQuery.extend(a,{total:undefined,url:undefined,currentIntervalId:undefined,data:[],delay:500,start:0,size:1000,initialize:function(e){jQuery.extend(a,e);if(e.hasOwnProperty("initialize")){e.initialize.call(a,e)}this.log(this+" initialized:",a)},buildUrl:function(f,e){return this.url+"&"+jQuery.param({start_val:f,max_vals:e})},ajaxErrorFn:function(g,e,f){},load:function(h){this.log(this+".load");if(!a.url){throw (a+" requires a url")}if(this.total===null){this.log("\t total is null (will load all)")}else{this.log("\t total:",this.total)}var g=a.size;if((a.total!==null)&&(a.total<a.size)){g=a.total}a.log(a+"\t beginning recursion");f(a.start,g);function f(k,j){a.log(a+".loadHelper, start:",k,"size:",j);var i=a.buildUrl(k,j);a.log("\t url:",i);jQuery.ajax({url:a.buildUrl(k,j),dataType:"json",error:function(n,l,m){a.log("\t ajax error, status:",l,"error:",m);if(a.currentIntervalId){clearInterval(a.currentIntervalId)}$(a).trigger(ERROR_EVENT,[l,m]);a.ajaxErrorFn(n,l,m)},success:function(l){a.log("\t ajax success, response:",l,"next:",m,"remainder:",n);if(l!==null){a.data.push(l);$(a).trigger(d,[l,k,j]);var m=k+j,n=a.size;if(a.total!==null){n=Math.min(a.total-m,a.size)}a.log("\t next recursion, start:",m,"size:",n);if(a.total===null||n>0){a.currentIntervalId=setTimeout(function(){f(m,n)},a.delay);a.log("\t currentIntervalId:",a.currentIntervalId)}else{e()}}else{e()}}})}function e(){a.log(a+".loadHelper, has finished:",a.data);$(a).trigger(b,[a.data,a.total]);if(h){h(a.data)}}},toString:function(){return"LazyDataLoader"}});a.initialize(c);return a};=======
-function LazyDataLoader(b){var a=this;jQuery.extend(a,LoggableMixin);jQuery.extend(a,{total:undefined,url:undefined,currentIntervalId:undefined,loadedPartialEvent:undefined,loadedAllEvent:undefined,data:[],delay:500,start:0,size:1000,initialize:function(c){jQuery.extend(a,c);if(c.hasOwnProperty("initialize")){c.initialize.call(a,c)}if(!a.total){throw (a+" requires a total (total size of the data)")}if(!a.url){throw (a+" requires a url")}this.log(this+" initialized:",a)},buildUrl:function(d,c){return a.url+"&"+jQuery.param({start_val:d,max_vals:c})},ajaxErrorFn:function(e,c,d){alert(a+" ERROR:"+c+"\n"+d)},load:function(d){function c(g,f){a.log(a+".loadHelper, start:",g,"size:",f);var e=a.buildUrl(g,f);a.log("\t url:",e);jQuery.ajax({url:a.buildUrl(g,f),dataType:"json",error:function(j,h,i){a.log("\t ajax error, status:",h,"error:",i);if(a.currentIntervalId){clearInterval(a.currentIntervalId)}a.ajaxErrorFn(j,h,i)},success:function(h){var i=g+f,j=Math.min(a.total-i,a.size);a.log("\t ajax success, next:",i,"remainder:",j);a.data.push(h);if(a.loadedPartialEvent){a.log("\t firing:",a.loadedPartialEvent);$(a).trigger(a.loadedPartialEvent,h,g,f)}if(j>0){a.currentIntervalId=setTimeout(function(){c(i,j)},a.delay);a.log("\t currentIntervalId:",a.currentIntervalId)}else{a.log(a+".loadHelper, has finished:",a.data);if(a.loadedAllEvent){a.log("\t firing:",a.loadedAllEvent);$(a).trigger(a.loadedAllEvent,a.data,a.total)}if(d){d(a.data)}}}})}c(a.start,Math.min(a.total,a.size))},toString:function(){return"LazyDataLoader"}});a.initialize(b);return a};>>>>>>> other
+function LazyDataLoader(c){var a=this,d="loaded.new",b="complete";ERROR_EVENT="error";jQuery.extend(a,LoggableMixin);jQuery.extend(a,{total:undefined,url:undefined,currentIntervalId:undefined,data:[],delay:500,start:0,size:1000,initialize:function(e){jQuery.extend(a,e);if(e.hasOwnProperty("initialize")){e.initialize.call(a,e)}this.log(this+" initialized:",a)},buildUrl:function(f,e){return this.url+"&"+jQuery.param({start_val:f,max_vals:e})},ajaxErrorFn:function(g,e,f){},load:function(h){this.log(this+".load");if(!a.url){throw (a+" requires a url")}if(this.total===null){this.log("\t total is null (will load all)")}else{this.log("\t total:",this.total)}var g=a.size;if((a.total!==null)&&(a.total<a.size)){g=a.total}a.log(a+"\t beginning recursion");f(a.start,g);function f(k,j){a.log(a+".loadHelper, start:",k,"size:",j);var i=a.buildUrl(k,j);a.log("\t url:",i);jQuery.ajax({url:a.buildUrl(k,j),dataType:"json",error:function(n,l,m){a.log("\t ajax error, status:",l,"error:",m);if(a.currentIntervalId){clearInterval(a.currentIntervalId)}$(a).trigger(ERROR_EVENT,[l,m]);a.ajaxErrorFn(n,l,m)},success:function(l){a.log("\t ajax success, response:",l,"next:",m,"remainder:",n);if(l!==null){a.data.push(l);$(a).trigger(d,[l,k,j]);var m=k+j,n=a.size;if(a.total!==null){n=Math.min(a.total-m,a.size)}a.log("\t next recursion, start:",m,"size:",n);if(a.total===null||n>0){a.currentIntervalId=setTimeout(function(){f(m,n)},a.delay);a.log("\t currentIntervalId:",a.currentIntervalId)}else{e()}}else{e()}}})}function e(){a.log(a+".loadHelper, has finished:",a.data);$(a).trigger(b,[a.data,a.total]);if(h){h(a.data)}}},toString:function(){return"LazyDataLoader"}});a.initialize(c);return a};
\ No newline at end of file
diff -r 4cd4f8bef29d17a7bca74e235031060e2289ebdc -r 8bcc04c4b710dbf4173a5fba6d2a3111e7c2b511 static/scripts/packed/utils/config.js
--- /dev/null
+++ b/static/scripts/packed/utils/config.js
@@ -0,0 +1,1 @@
+define(["libs/underscore","viz/trackster/util"],function(b,e){var c=Backbone.Model.extend({defaults:{key:null,value:null,type:"text",label:null,options:null,hidden:false},initialize:function(f){var g=this.get("key");this.set("id",g);var h=b.find(c.known_settings,function(i){return i.key===g});if(h){this.set(b.extend({},h,f))}if(this.get("type")==="color"){this.set("value",e.get_random_color())}this.on("change:value",this.cast_value,this)},cast_value:function(){var f=this.get("type"),g=this.get("value");if(f==="float"){g=parseFloat(g)}else{if(f==="int"){g=parseInt(g,10)}}this.set("value")}},{known_settings:[{key:"name",label:"Name",type:"text",default_value:""},{key:"color",label:"Color",type:"color",default_value:undefined},{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:32,hidden:true},{key:"pos_color",label:"Positive Color",type:"color",default_value:"4169E1"},{key:"negative_color",label:"Negative Color",type:"color",default_value:"FF8C00"},{key:"block_color",label:"Block color",type:"color",default_value:undefined},{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:undefined},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"Clear value to set automatically"},{key:"mode",type:"string",default_value:this.mode,hidden:true}]});var d=Backbone.Collection.extend({model:c,to_key_value_dict:function(){var f={};this.each(function(g){f[g.get("key")]=g.get("value")});return f},restore_values:function(g){var f=this;b.keys(g,function(h){var i=f.find(function(j){return j.get("key")===h});if(i){i.set("value",g.key)}})},get_value:function(f){return this.get(f).get("value")}},{from_config_dict:function(g){var f=b.map(b.keys(g),function(h){return{key:h,value:g[h]}});return new d(f)}});var a=Backbone.View.extend({className:"config-settings-view",render:function(){var i=this.model;var f=this.$el;var h;function g(n,j){for(var r=0;r<n.length;r++){h=n[r];if(h.hidden){continue}var l="param_"+r;var v=i.values[h.key];var x=$("<div class='form-row' />").appendTo(j);x.append($("<label />").attr("for",l).text(h.label+":"));if(type==="bool"){x.append($('<input type="checkbox" />').attr("id",l).attr("name",l).attr("checked",v))}else{if(type==="text"){x.append($('<input type="text"/>').attr("id",l).val(v).click(function(){$(this).select()}))}else{if(type==="select"){var t=$("<select />").attr("id",l);for(var p=0;p<h.options.length;p++){$("<option/>").text(h.options[p].label).attr("value",h.options[p].value).appendTo(t)}t.val(v);x.append(t)}else{if(type==="color"){var w=$("<div/>").appendTo(x),s=$("<input />").attr("id",l).attr("name",l).val(v).css("float","left").appendTo(w).click(function(z){$(".bs-tooltip").removeClass("in");var y=$(this).siblings(".bs-tooltip").addClass("in");y.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(y).height()/2)+($(this).height()/2)}).show();y.click(function(A){A.stopPropagation()});$(document).bind("click.color-picker",function(){y.hide();$(document).unbind("click.color-picker")});z.stopPropagation()}),q=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(w).attr("title","Set new random color").tooltip(),u=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(w).hide(),m=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(u),k=$("<div class='tooltip-arrow'></div>").appendTo(u),o=$.farbtastic(m,{width:100,height:100,callback:s,color:v});w.append($("<div/>").css("clear","both"));(function(y){q.click(function(){y.setColor(e.get_random_color())})})(o)}else{x.append($("<input />").attr("id",l).attr("name",l).val(v))}}}}if(h.help){x.append($("<div class='help'/>").text(h.help))}}}g(this.params,f);return this},render_in_modal:function(){var h=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},f=function(){this.update_from_form();hide_modal();$(window).unbind("keypress.check_enter_esc")},g=function(i){if((i.keyCode||i.which)===27){h()}else{if((i.keyCode||i.which)===13){f()}}};$(window).bind("keypress.check_enter_esc",g);if(this.$el.children().length===0){this.render()}show_modal("Configure",drawable.config.build_form(),{Cancel:h,OK:f})},update_from_form:function(){var f=this;this.collection.each(function(h,g){if(!h.get("hidden")){var j="param_"+g;var i=f.$el.find("#"+j).val();if(type==="bool"){i=container.find("#"+j).is(":checked")}h.set("value",i)}})}});return{ConfigSettingCollection:d,ConfigSettingCollectionView:a}});
\ No newline at end of file
diff -r 4cd4f8bef29d17a7bca74e235031060e2289ebdc -r 8bcc04c4b710dbf4173a5fba6d2a3111e7c2b511 static/scripts/packed/viz/circster.js
--- a/static/scripts/packed/viz/circster.js
+++ b/static/scripts/packed/viz/circster.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","libs/d3","viz/visualization"],function(i,k,j){var f=function(){this.initialize&&this.initialize.apply(this,arguments)};f.extend=Backbone.Model.extend;var l=Backbone.Model.extend({is_visible:function(p,m){var n=p.getBoundingClientRect(),o=$("svg")[0].getBoundingClientRect();if(n.right<0||n.left>o.right||n.bottom<0||n.top>o.bottom){return false}return true}});var e=Backbone.Model.extend({defaults:{prefs:{color:"#ccc"}}});var b=Backbone.View.extend({className:"circster",initialize:function(m){this.total_gap=m.total_gap;this.genome=m.genome;this.dataset_arc_height=m.dataset_arc_height;this.track_gap=5;this.label_arc_height=20;this.scale=1},render:function(){var v=this,s=this.dataset_arc_height,m=v.$el.width(),u=v.$el.height(),n=Math.min(m,u)/2-this.model.get("tracks").length*(this.dataset_arc_height+this.track_gap)-(this.label_arc_height+this.track_gap),t=this.model.get("tracks"),p=t.map(function(w,y){var z=n+y*(s+v.track_gap),x=(w.get("track_type")==="LineTrack"?g:h);return new x({track:w,track_index:y,radius_bounds:[z,z+s],genome:v.genome,total_gap:v.total_gap})});var q=k.select(v.$el[0]).append("svg").attr("width",m).attr("height",u).attr("pointer-events","all").append("svg:g").call(k.behavior.zoom().on("zoom",function(){var w=k.event.scale;q.attr("transform","translate("+k.event.translate+") scale("+w+")");if(v.scale!==w){if(v.zoom_drag_timeout){clearTimeout(v.zoom_drag_timeout)}v.zoom_drag_timeout=setTimeout(function(){i.each(p,function(x){x.update_scale(w)})},400)}})).attr("transform","translate("+m/2+","+u/2+")").append("svg:g");i.each(p,function(w){w.render(q)});var r=n+t.length*(s+v.track_gap)+v.track_gap;var o=new a({track:new e(),track_index:t.length,radius_bounds:[r,r],genome:v.genome,total_gap:v.total_gap});o.render(q)}});var c=f.extend({initialize:function(m){this.options=m;this.options.bg_stroke="ccc";this.options.loading_bg_fill="000";this.options.bg_fill="ccc";this.options.chroms_layout=this._chroms_layout();this.options.data_bounds=[];this.options.scale=1;this.options.parent_elt=null},render:function(t){this.options.parent_elt=t.append("g").attr("id","parent-"+this.options.track_index);var r=this.options.parent_elt;var m=this.options.chroms_layout,q=k.svg.arc().innerRadius(this.options.radius_bounds[0]).outerRadius(this.options.radius_bounds[1]),o=r.selectAll("g").data(m).enter().append("svg:g"),p=o.append("path").attr("d",q).style("stroke",this.options.bg_stroke).style("fill",this.options.loading_bg_fill);p.append("title").text(function(v){return v.data.chrom});var u=this,n=u.options.track.get("data_manager"),s=(n?n.data_is_ready():true);$.when(s).then(function(){$.when(u._render_data(r)).then(function(){var v=u.options.track.get("prefs"),w=v.block_color;if(!w){w=v.color}r.selectAll("path.chrom-data").style("stroke",w).style("fill",w);p.style("fill",u.options.bg_fill)})})},update_scale:function(p){var o=this.options.scale;this.options.scale=p;if(p<=o){return}var n=this,m=new l();this.options.parent_elt.selectAll("path.chrom-data").filter(function(r,q){return m.is_visible(this)}).each(function(v,s){var u=k.select(this),r=u.attr("chrom"),t=n.options.genome.get_chrom_region(r),q=n.options.track.get("data_manager").get_more_detailed_data(t,"Coverage",0,p);$.when(q).then(function(z){u.remove();n._update_data_bounds();var y=i.find(n.options.chroms_layout,function(A){return A.data.chrom===r});var w=n.options.track.get("prefs"),x=w.block_color;if(!x){x=w.color}n._render_chrom_data(n.options.parent_elt,y,z).style("stroke",x).style("fill",x)})});return n},_update_data_bounds:function(){},_render_data:function(p){var o=this,n=this.options.chroms_layout,m=this.options.track,q=$.Deferred();$.when(m.get("data_manager").get_genome_wide_data(this.options.genome)).then(function(r){o.options.data_bounds=o.get_data_bounds(r);layout_and_data=i.zip(n,r),chroms_data_layout=i.map(layout_and_data,function(s){var t=s[0],u=s[1];return o._render_chrom_data(p,t,u)});q.resolve(p)});return q},_render_chrom_data:function(m,n,o){},_compute_path_data:function(m,n){},_chroms_layout:function(){var n=this.options.genome.get_chroms_info(),p=k.layout.pie().value(function(r){return r.len}).sort(null),q=p(n),m=this.options.total_gap/n.length,o=i.map(q,function(t,s){var r=t.endAngle-m;t.endAngle=(r>t.startAngle?r:t.startAngle);return t});return o}});var a=c.extend({initialize:function(m){this.options=m;this.options.bg_stroke="fff";this.options.bg_fill="fff";this.options.chroms_layout=this._chroms_layout()},_render_data:function(n){var m=n.selectAll("g");m.selectAll("path").attr("id",function(o){return"label-"+o.data.chrom});m.append("svg:text").filter(function(o){return o.endAngle-o.startAngle>0.08}).attr("text-anchor","middle").append("svg:textPath").attr("xlink:href",function(o){return"#label-"+o.data.chrom}).attr("startOffset","25%").text(function(o){return o.data.chrom})}});var d=c.extend({_render_chrom_data:function(m,p,n){if(typeof n==="string"||!n.data||n.data.length===0){return null}var q=this._compute_path_data(p,n.data);var o=m.datum(n.data),r=o.append("path").attr("class","chrom-data").attr("chrom",p.data.chrom).attr("d",q);return r},_compute_path_data:function(o,p){var m=k.scale.linear().domain(this.options.data_bounds).range(this.options.radius_bounds);var q=k.scale.linear().domain([0,p.length]).range([o.startAngle,o.endAngle]);var n=k.svg.line.radial().interpolate("linear").radius(function(r){return m(r[1])}).angle(function(s,r){return q(r)});return k.svg.area.radial().interpolate(n.interpolate()).innerRadius(m(0)).outerRadius(n.radius()).angle(n.angle())},get_data_bounds:function(m){}});var h=d.extend({get_data_bounds:function(n){var m=i.map(n,function(o){if(typeof o==="string"||!o.max){return 0}return o.max});return[0,(m&&typeof m!=="string"?i.max(m):0)]}});var g=d.extend({get_data_bounds:function(n){var m=i.flatten(i.map(n,function(o){if(o){return i.map(o.data,function(q){return q[1]})}else{return 0}}));return[i.min(m),i.max(m)]}});return{CircsterView:b}});
\ No newline at end of file
+define(["libs/underscore","libs/d3","viz/visualization"],function(g,j,h){var k=Backbone.Model.extend({is_visible:function(o,l){var m=o.getBoundingClientRect(),n=$("svg")[0].getBoundingClientRect();if(m.right<0||m.left>n.right||m.bottom<0||m.top>n.bottom){return false}return true}});var c=Backbone.Model.extend({defaults:{prefs:{color:"#ccc"}}});var a=Backbone.View.extend({className:"circster",initialize:function(l){this.total_gap=l.total_gap;this.genome=l.genome;this.dataset_arc_height=l.dataset_arc_height;this.track_gap=5;this.label_arc_height=20;this.scale=1;this.track_views=null;this.model.get("tracks").on("add",this.add_track,this)},get_tracks_bounds:function(){var n=this.dataset_arc_height,l=Math.min(this.$el.width(),this.$el.height()),p=l/2-this.model.get("tracks").length*(this.dataset_arc_height+this.track_gap)-(this.label_arc_height+this.track_gap),o=j.range(p,l/2,this.dataset_arc_height+this.track_gap);var m=this;return g.map(o,function(q){return[q,q+m.dataset_arc_height]})},render:function(){var o=this,q=this.dataset_arc_height,r=o.$el.width(),l=o.$el.height(),p=this.model.get("tracks"),s=this.get_tracks_bounds(),n=j.select(o.$el[0]).append("svg").attr("width",r).attr("height",l).attr("pointer-events","all").append("svg:g").call(j.behavior.zoom().on("zoom",function(){var t=j.event.scale;n.attr("transform","translate("+j.event.translate+") scale("+t+")");if(o.scale!==t){if(o.zoom_drag_timeout){clearTimeout(o.zoom_drag_timeout)}o.zoom_drag_timeout=setTimeout(function(){g.each(o.track_views,function(u){u.update_scale(t)})},400)}})).attr("transform","translate("+r/2+","+l/2+")").append("svg:g").attr("class","tracks");this.track_views=p.map(function(t,u){track_view_class=(t.get("track_type")==="LineTrack"?d:e);return new track_view_class({el:n.append("g")[0],track:t,radius_bounds:s[u],genome:o.genome,total_gap:o.total_gap})});g.each(this.track_views,function(t){t.render()});var m=s[p.length];m[1]=m[0];this.label_track_view=new b({el:n.append("g")[0],track:new c(),radius_bounds:m,genome:o.genome,total_gap:o.total_gap});this.label_track_view.render()},add_track:function(o){var n=this.get_tracks_bounds();g.each(this.track_views,function(p,q){p.update_radius_bounds(n[q])});var m=this.track_views.length;track_view_class=(o.get("track_type")==="LineTrack"?d:e),track_view=new track_view_class({el:j.select("g.tracks").append("g")[0],track:o,radius_bounds:n[m],genome:this.genome,total_gap:this.total_gap});track_view.render();this.track_views.push(track_view);var l=n[n.length-1];l[1]=l[0];this.label_track_view.update_radius_bounds(l)}});var i=Backbone.View.extend({tagName:"g",initialize:function(l){this.options=l;this.options.bg_stroke="ccc";this.options.loading_bg_fill="000";this.options.bg_fill="ccc";this.options.chroms_layout=this._chroms_layout();this.options.data_bounds=[];this.options.scale=1;this.options.parent_elt=j.select(this.$el[0])},render:function(){var p=this.options.parent_elt;if(!p){console.log("no parent elt")}var o=this.options.chroms_layout,r=j.svg.arc().innerRadius(this.options.radius_bounds[0]).outerRadius(this.options.radius_bounds[1]),l=p.selectAll("g").data(o).enter().append("svg:g"),n=l.append("path").attr("d",r).attr("class","chrom-background").style("stroke",this.options.bg_stroke).style("fill",this.options.loading_bg_fill);n.append("title").text(function(t){return t.data.chrom});var m=this,q=m.options.track.get("data_manager"),s=(q?q.data_is_ready():true);$.when(s).then(function(){$.when(m._render_data(p)).then(function(){var t=m.options.track.get("prefs"),u=t.block_color;if(!u){u=t.color}p.selectAll("path.chrom-data").style("stroke",u).style("fill",u);n.style("fill",m.options.bg_fill)})})},update_radius_bounds:function(r){this.options.radius_bounds=r;var p=j.svg.arc().innerRadius(this.options.radius_bounds[0]).outerRadius(this.options.radius_bounds[1]);this.options.parent_elt.selectAll("g>path.chrom-background").transition().duration(1000).attr("d",p);var m=this.options.track,o=this.options.chroms_layout,l=this.options.parent_elt.selectAll("g>path.chrom-data"),q=l[0].length;if(q>0){var n=this;$.when(m.get("data_manager").get_genome_wide_data(this.options.genome)).then(function(t){var s=g.reject(g.map(t,function(u,v){var w=null,x=n._compute_path_data(o[v],u);if(x){w=x(u.data)}return w}),function(u){return u===null});l.each(function(v,u){j.select(this).transition().duration(1000).attr("d",s[u])})})}},update_scale:function(o){var n=this.options.scale;this.options.scale=o;if(o<=n){return}var m=this,l=new k();this.options.parent_elt.selectAll("path.chrom-data").filter(function(q,p){return l.is_visible(this)}).each(function(u,r){var t=j.select(this),q=t.attr("chrom"),s=m.options.genome.get_chrom_region(q),p=m.options.track.get("data_manager").get_more_detailed_data(s,"Coverage",0,o);$.when(p).then(function(y){t.remove();m._update_data_bounds();var x=g.find(m.options.chroms_layout,function(z){return z.data.chrom===q});var v=m.options.track.get("prefs"),w=v.block_color;if(!w){w=v.color}m._render_chrom_data(m.options.parent_elt,x,y).style("stroke",w).style("fill",w)})});return m},_update_data_bounds:function(){},_render_data:function(o){var n=this,m=this.options.chroms_layout,l=this.options.track,p=$.Deferred();$.when(l.get("data_manager").get_genome_wide_data(this.options.genome)).then(function(q){n.options.data_bounds=n.get_data_bounds(q);layout_and_data=g.zip(m,q),chroms_data_layout=g.map(layout_and_data,function(r){var s=r[0],t=r[1];return n._render_chrom_data(o,s,t)});p.resolve(o)});return p},_render_chrom_data:function(l,m,n){},_compute_path_data:function(m,l){},_chroms_layout:function(){var m=this.options.genome.get_chroms_info(),o=j.layout.pie().value(function(q){return q.len}).sort(null),p=o(m),l=this.options.total_gap/m.length,n=g.map(p,function(s,r){var q=s.endAngle-l;s.endAngle=(q>s.startAngle?q:s.startAngle);return s});return n}});var b=i.extend({initialize:function(l){i.prototype.initialize.call(this,l);this.options.bg_stroke="fff";this.options.bg_fill="fff"},_render_data:function(m){var l=m.selectAll("g");l.selectAll("path").attr("id",function(n){return"label-"+n.data.chrom});l.append("svg:text").filter(function(n){return n.endAngle-n.startAngle>0.08}).attr("text-anchor","middle").append("svg:textPath").attr("xlink:href",function(n){return"#label-"+n.data.chrom}).attr("startOffset","25%").text(function(n){return n.data.chrom})}});var f=i.extend({_render_chrom_data:function(l,o,m){var p=this._compute_path_data(o,m);if(!p){return null}var n=l.datum(m.data),q=n.append("path").attr("class","chrom-data").attr("chrom",o.data.chrom).attr("d",p);return q},_compute_path_data:function(o,n){if(typeof n==="string"||!n.data||n.data.length===0){return null}var l=j.scale.linear().domain(this.options.data_bounds).range(this.options.radius_bounds);var p=j.scale.linear().domain([0,n.data.length]).range([o.startAngle,o.endAngle]);var m=j.svg.line.radial().interpolate("linear").radius(function(q){return l(q[1])}).angle(function(r,q){return p(q)});return j.svg.area.radial().interpolate(m.interpolate()).innerRadius(l(0)).outerRadius(m.radius()).angle(m.angle())},get_data_bounds:function(l){}});var e=f.extend({get_data_bounds:function(m){var l=g.map(m,function(n){if(typeof n==="string"||!n.max){return 0}return n.max});return[0,(l&&typeof l!=="string"?g.max(l):0)]}});var d=f.extend({get_data_bounds:function(m){var l=g.flatten(g.map(m,function(n){if(n){return g.map(n.data,function(o){return o[1]})}else{return 0}}));return[g.min(l),g.max(l)]}});return{CircsterView:a}});
\ No newline at end of file
diff -r 4cd4f8bef29d17a7bca74e235031060e2289ebdc -r 8bcc04c4b710dbf4173a5fba6d2a3111e7c2b511 static/scripts/packed/viz/scatterplot.js
--- a/static/scripts/packed/viz/scatterplot.js
+++ b/static/scripts/packed/viz/scatterplot.js
@@ -1,3 +1,1 @@
-<<<<<<< local
-define(["../libs/underscore","../mvc/base-mvc","../utils/LazyDataLoader","../templates/compiled/template-visualization-scatterplotControlForm","../templates/compiled/template-visualization-statsTable","../templates/compiled/template-visualization-chartSettings","../libs/d3","../libs/bootstrap","../libs/jquery/jquery-ui-1.8.23.custom.min"],function(){function a(f){var d=10,h=7,g=10,e=8,c=5;this.log=function(){if(this.debugging&&console&&console.debug){var i=Array.prototype.slice.call(arguments);i.unshift(this.toString());console.debug.apply(console,i)}};this.log("new TwoVarScatterplot:",f);this.defaults={id:"TwoVarScatterplot",containerSelector:"body",maxDataPoints:30000,datapointSize:4,animDuration:500,xNumTicks:10,yNumTicks:10,xAxisLabelBumpY:40,yAxisLabelBumpX:-35,width:500,height:500,marginTop:50,marginRight:50,marginBottom:50,marginLeft:50,xMin:null,xMax:null,yMin:null,yMax:null,xLabel:"X",yLabel:"Y"};this.config=_.extend({},this.defaults,f);this.updateConfig=function(i,j){_.extend(this.config,i)};this.toString=function(){return this.config.id};this.translateStr=function(i,j){return"translate("+i+","+j+")"};this.rotateStr=function(j,i,k){return"rotate("+j+","+i+","+k+")"};this.svg=d3.select(this.config.containerSelector).append("svg:svg").attr("class","chart");this.content=this.svg.append("svg:g").attr("class","content").attr("id",this.config.id);this.xAxis=this.content.append("g").attr("class","axis").attr("id","x-axis");this.xAxisLabel=this.xAxis.append("text").attr("class","axis-label").attr("id","x-axis-label");this.yAxis=this.content.append("g").attr("class","axis").attr("id","y-axis");this.yAxisLabel=this.yAxis.append("text").attr("class","axis-label").attr("id","y-axis-label");this.adjustChartDimensions=function(l,j,i,k){l=l||0;j=j||0;i=i||0;k=k||0;this.svg.attr("width",this.config.width+(this.config.marginRight+j)+(this.config.marginLeft+k)).attr("height",this.config.height+(this.config.marginTop+l)+(this.config.marginBottom+i)).style("display","block");this.content=this.svg.select("g.content").attr("transform",this.translateStr(this.config.marginLeft+k,this.config.marginTop+l))};this.preprocessData=function(k,j,i){return(k.length>this.config.maxDataPoints)?(k.slice(0,this.config.maxDataPoints)):(k)};this.setUpDomains=function(i,k,j){this.xMin=this.config.xMin||(j)?(j[0].min):(d3.min(i));this.xMax=this.config.xMax||(j)?(j[0].max):(d3.max(i));this.yMin=this.config.yMin||(j)?(j[1].min):(d3.min(k));this.yMax=this.config.yMax||(j)?(j[1].max):(d3.max(k))};this.setUpScales=function(){this.xScale=d3.scale.linear().domain([this.xMin,this.xMax]).range([0,this.config.width]),this.yScale=d3.scale.linear().domain([this.yMin,this.yMax]).range([this.config.height,0])};this.setUpXAxis=function(){this.xAxisFn=d3.svg.axis().scale(this.xScale).ticks(this.config.xNumTicks).orient("bottom");this.xAxis.attr("transform",this.translateStr(0,this.config.height)).call(this.xAxisFn);this.xLongestLabel=d3.max(_.map([this.xMin,this.xMax],function(i){return(String(i)).length}));if(this.xLongestLabel>=c){this.xAxis.selectAll("g").filter(":nth-child(odd)").style("display","none")}this.xAxisLabel.attr("x",this.config.width/2).attr("y",this.config.xAxisLabelBumpY).attr("text-anchor","middle").text(this.config.xLabel)};this.setUpYAxis=function(){this.yAxisFn=d3.svg.axis().scale(this.yScale).ticks(this.config.yNumTicks).orient("left");this.yAxis.call(this.yAxisFn);var i=this.yAxis.selectAll("text").filter(function(m,l){return l!==0});this.yLongestLabel=d3.max(i[0].map(function(m,l){return(d3.select(m).text()).length}))||0;var j=d+(this.yLongestLabel*h)+e+g;this.config.yAxisLabelBumpX=-(j-g);if(this.config.marginLeft<j){var k=(j)-this.config.marginLeft;k=(k<0)?(0):(k);this.adjustChartDimensions(0,0,0,k)}this.yAxisLabel.attr("x",this.config.yAxisLabelBumpX).attr("y",this.config.height/2).attr("text-anchor","middle").attr("transform",this.rotateStr(-90,this.config.yAxisLabelBumpX,this.config.height/2)).text(this.config.yLabel)};this.renderGrid=function(){this.vGridLines=this.content.selectAll("line.v-grid-line").data(this.xScale.ticks(this.xAxisFn.ticks()[0]));this.vGridLines.enter().append("svg:line").classed("grid-line v-grid-line",true);this.vGridLines.attr("x1",this.xScale).attr("y1",0).attr("x2",this.xScale).attr("y2",this.config.height);this.vGridLines.exit().remove();this.hGridLines=this.content.selectAll("line.h-grid-line").data(this.yScale.ticks(this.yAxisFn.ticks()[0]));this.hGridLines.enter().append("svg:line").classed("grid-line h-grid-line",true);this.hGridLines.attr("x1",0).attr("y1",this.yScale).attr("x2",this.config.width).attr("y2",this.yScale);this.hGridLines.exit().remove()};this.glyphEnterState=function(i){};this.glyphFinalState=function(i){};this.glyphExitState=function(i){};this.renderDatapoints=function(i,l,j){this.log(this+".renderDatapoints",arguments);var k=0;this.datapoints=this.addDatapoints(i,l,j,".glyph");this.datapoints.exit().each(function(){k+=1}).transition().duration(this.config.animDuration).attr("cy",this.config.height).attr("r",0).remove();this.log(k," glyphs removed")};this.addDatapoints=function(m,k,i,l){this.log(this+".addDatapoints",arguments);var p=this,o=0,q=function(s,r){return p.xScale(m[r])},j=function(s,r){return p.yScale(k[r])};var n=this.content.selectAll(l);this.log("existing datapoints:",n);n=n.data(m);o=0;n.enter().append("svg:circle").each(function(){o+=1}).classed("glyph",true).attr("cx",q).attr("cy",j).attr("r",0);this.log(o," new glyphs created");o=0;n.transition().duration(this.config.animDuration).each(function(){o+=1}).attr("cx",q).attr("cy",j).attr("r",p.config.datapointSize);this.log(o," existing glyphs transitioned");if(i){n.attr("data",function(s,r){return(i[r])})}n.attr("title",function(s,r){return((i)?(i[r]+": "):(""))+m[r]+", "+k[r]});n.on("mouseover",function(){var r=d3.select(this);r.style("fill","red").style("fill-opacity",1);p.content.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",r.attr("cx")).attr("y1",r.attr("cy")).attr("x2",0).attr("y2",r.attr("cy")).classed("hoverline",true);p.content.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",r.attr("cx")).attr("y1",r.attr("cy")).attr("x2",r.attr("cx")).attr("y2",p.config.height).classed("hoverline",true)}).on("mouseout",function(){d3.select(this).style("fill","black").style("fill-opacity",0.2);d3.selectAll(".hoverline").remove()});return n};this.render=function(k,l){this.log(this+".render",arguments);var i=k[0],m=k[1],j=(k.length>2)?(k[2]):(undefined);i=this.preprocessData(i);m=this.preprocessData(m);this.log("xCol len",i.length,"yCol len",m.length);this.setUpDomains(i,m,l);this.setUpScales();this.adjustChartDimensions();this.setUpXAxis();this.setUpYAxis();this.renderGrid();this.renderDatapoints(i,m,j)}}var b=BaseView.extend(LoggableMixin).extend({className:"scatterplot-settings-form",dataLoadDelay:500,dataLoadSize:3001,loadingIndicatorImage:"loading_large_white_bg.gif",initialize:function(c){if(this.logger){window.form=this}this.dataset=null;this.chartConfig=null;this.plot=null;this.loader=null;this.$statsPanel=null;this.$chartSettingsPanel=null;this.$dataSettingsPanel=null;this.dataFetch=null;this.initializeFromAttributes(c);this.initializeChart(c);this.initializeDataLoader(c)},initializeFromAttributes:function(c){if(!c||!c.dataset){throw ("ScatterplotView requires a dataset")}else{this.dataset=c.dataset}if(jQuery.type(this.dataset.metadata_column_types)==="string"){this.dataset.metadata_column_types=this.dataset.metadata_column_types.split(", ")}this.log("dataset:",this.dataset);if(!c.apiDatasetsURL){throw ("ScatterplotView requires a apiDatasetsURL")}else{this.dataURL=c.apiDatasetsURL+"/"+this.dataset.id+"?"}this.log("this.dataURL:",this.dataURL)},initializeChart:function(c){this.chartConfig=c.chartConfig||{};if(this.logger){this.chartConfig.debugging=true}this.log("initial chartConfig:",this.chartConfig);this.plot=new a(this.chartConfig);this.chartConfig=this.plot.config},initializeDataLoader:function(d){var c=this;this.loader=new LazyDataLoader({logger:(this.logger)?(this.logger):(null),url:null,start:d.start||0,total:d.total||this.dataset.metadata_data_lines,delay:this.dataLoadDelay,size:this.dataLoadSize,buildUrl:function(f,e){return this.url+"&"+jQuery.param({start_val:f,max_vals:e})}});$(this.loader).bind("error",function(g,e,f){c.log("ERROR:",e,f);alert("ERROR fetching data:\n"+e+"\n"+f);c.hideLoadingIndicator()})},render:function(){var c=this,d={config:this.chartConfig,allColumns:[],numericColumns:[],loadingIndicatorImagePath:galaxy_paths.get("image_path")+"/"+this.loadingIndicatorImage};_.each(this.dataset.metadata_column_types,function(g,f){var e="column "+(f+1);if(c.dataset.metadata_column_names){e=c.dataset.metadata_column_names[f]}if(g==="int"||g==="float"){d.numericColumns.push({index:f,name:e})}d.allColumns.push({index:f,name:e})});this.$el.append(b.templates.form(d));this.$dataSettingsPanel=this.$el.find(".tab-pane#data-settings");this.$chartSettingsPanel=this._render_chartSettings();this.$statsPanel=this.$el.find(".tab-pane#chart-stats");return this},_render_chartSettings:function(){var c=this,d=this.$el.find(".tab-pane#chart-settings"),e={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};d.append(b.templates.chartSettings(this.chartConfig));d.find(".numeric-slider-input").each(function(){var h=$(this),g=h.find(".slider-output"),i=h.find(".slider"),j=h.attr("id");function f(){var l=$(this),k=l.slider("value");g.text(k)}i.slider(_.extend(e[j],{value:c.chartConfig[j],change:f,slide:f}))});return d},events:{"click #include-id-checkbox":"toggleThirdColumnSelector","click #data-settings #render-button":"renderPlot","click #chart-settings #render-button":"changeChartSettings"},toggleThirdColumnSelector:function(){this.$el.find('select[name="ID"]').parent().toggle()},showLoadingIndicator:function(d,e){d=d||"";var c=this.$el.find("div#loading-indicator");messageBox=c.find(".loading-message");if(c.is(":visible")){if(d){messageBox.fadeOut("fast",function(){messageBox.text(d);messageBox.fadeIn("fast",e)})}else{e()}}else{if(d){messageBox.text(d)}c.fadeIn("fast",e)}},hideLoadingIndicator:function(c){this.$el.find("div#loading-indicator").fadeOut("fast",c)},renderPlot:function(){var c=this;c.data=null;c.meta=null;_.extend(this.chartConfig,this.getGraphSettings());this.log("this.chartConfig:",this.chartConfig);this.plot.updateConfig(this.chartConfig,false);this.loader.url=this.dataURL+"&"+jQuery.param(this.getDataSettings());this.log("this.loader, url:",this.loader.url,"total:",this.loader.total);$(this.loader).bind("loaded.new",function(e,d){c.log(c+" loaded.new",d);c.postProcessDataFetchResponse(d);c.log("postprocessed data:",c.data,"meta:",c.meta);c.showLoadingIndicator("Rendering...",function(){c.$el.find("ul.nav").find('a[href="#chart-stats"]').tab("show");c.plot.render(c.data,c.meta);c.renderStats(c.data,c.meta);c.hideLoadingIndicator()})});$(this.loader).bind("complete",function(d,e){c.log("complete",e);$(c.loader).unbind()});c.showLoadingIndicator("Fetching data...",function(){c.loader.load()})},renderStats:function(){this.$statsPanel.html(b.templates.statsTable({stats:[{name:"Count",xval:this.meta[0].count,yval:this.meta[1].count},{name:"Min",xval:this.meta[0].min,yval:this.meta[1].min},{name:"Max",xval:this.meta[0].max,yval:this.meta[1].max},{name:"Sum",xval:this.meta[0].sum,yval:this.meta[1].sum},{name:"Mean",xval:this.meta[0].mean,yval:this.meta[1].mean},{name:"Median",xval:this.meta[0].median,yval:this.meta[1].median}]}))},changeChartSettings:function(){var c=this;newGraphSettings=this.getGraphSettings();this.log("newGraphSettings:",newGraphSettings);_.extend(this.chartConfig,newGraphSettings);this.log("this.chartConfig:",this.chartConfig);this.plot.updateConfig(this.chartConfig,false);if(c.data&&c.meta){c.showLoadingIndicator("Rendering...",function(){c.plot.render(c.data,c.meta);c.hideLoadingIndicator()})}else{this.renderPlot()}},postProcessDataFetchResponse:function(c){this.postProcessData(c.data);this.postProcessMeta(c.meta)},postProcessData:function(d){var c=this;if(c.data){_.each(d,function(f,e){c.data[e]=c.data[e].concat(f)})}else{c.data=d}},postProcessMeta:function(e){var c=this,d=this.dataset.metadata_column_types;if(c.meta){_.each(e,function(g,f){var k=c.meta[f],i=d[f];c.log(f+" postprocessing meta:",g);k.count+=(g.count)?(g.count):(0);c.log(f,"count:",k.count);if((i==="int")||(i==="float")){k.min=Math.min(g.min,k.min);k.max=Math.max(g.max,k.max);k.sum=g.sum+k.sum;k.mean=(k.count)?(k.sum/k.count):(null);var h=c.data[f].slice().sort(),j=Math.floor(h.length/2);if(h.length%2===0){k.median=((h[j]+h[(j+1)])/2)}else{k.median=h[j]}}})}else{c.meta=e;c.log("initial meta:",c.meta)}},getDataSettings:function(){var d=this.getColumnSelections(),c=[];this.log("columnSelections:",d);c=[d.X.colIndex,d.Y.colIndex];if(this.$dataSettingsPanel.find("#include-id-checkbox").attr("checked")){c.push(d.ID.colIndex)}var e={data_type:"raw_data",columns:"["+c+"]"};this.log("params:",e);return e},getColumnSelections:function(){var c={};this.$dataSettingsPanel.find("div.column-select select").each(function(){var d=$(this),e=d.val();c[d.attr("name")]={colIndex:e,colName:d.children('[value="'+e+'"]').text()}});return c},getGraphSettings:function(){var e={},f=this.getColumnSelections();e.datapointSize=this.$chartSettingsPanel.find("#datapointSize.numeric-slider-input").find(".slider").slider("value");e.width=this.$chartSettingsPanel.find("#width.numeric-slider-input").find(".slider").slider("value");e.height=this.$chartSettingsPanel.find("#height.numeric-slider-input").find(".slider").slider("value");var d=this.$chartSettingsPanel.find("input#X-axis-label").val(),c=this.$chartSettingsPanel.find("input#Y-axis-label").val();e.xLabel=(d==="X")?(f.X.colName):(d);e.yLabel=(c==="Y")?(f.Y.colName):(c);e.animDuration=10;if(this.$chartSettingsPanel.find("#animDuration.checkbox-input").is(":checked")){e.animDuration=500}this.log("graphSettings:",e);return e},toString:function(){return"ScatterplotControlForm("+this.dataset.id+")"}});b.templates={form:Handlebars.templates["template-visualization-scatterplotControlForm"],statsTable:Handlebars.templates["template-visualization-statsTable"],chartSettings:Handlebars.templates["template-visualization-chartSettings"]};return{LazyDataLoader:LazyDataLoader,TwoVarScatterplot:a,ScatterplotControlForm:b}});=======
-define(["../libs/underscore","../mvc/base-mvc","../utils/LazyDataLoader","../templates/compiled/template-visualization-scatterplotControlForm","../templates/compiled/template-visualization-statsTable","../templates/compiled/template-visualization-chartSettings","../libs/d3","../libs/bootstrap","../libs/jquery/jquery-ui-1.8.23.custom.min"],function(){function a(f){var d=10,h=7,g=10,e=8,c=5;this.debugging=true;this.log=function(){if(this.debugging&&console&&console.debug){var i=Array.prototype.slice.call(arguments);i.unshift(this.toString());console.debug.apply(console,i)}};this.log("new TwoVarScatterplot:",f);this.defaults={id:"TwoVarScatterplot",containerSelector:"body",maxDataPoints:10000,datapointSize:4,entryAnimDuration:500,xNumTicks:10,yNumTicks:10,xAxisLabelBumpY:40,yAxisLabelBumpX:-35,width:500,height:500,marginTop:50,marginRight:50,marginBottom:50,marginLeft:50,xMin:null,xMax:null,yMin:null,yMax:null,xLabel:"X",yLabel:"Y"};this.config=_.extend({},this.defaults,f);this.updateConfig=function(i,j){_.extend(this.config,i)};this.toString=function(){return this.config.id};this.translateStr=function(i,j){return"translate("+i+","+j+")"};this.rotateStr=function(j,i,k){return"rotate("+j+","+i+","+k+")"};this.svg=d3.select(this.config.containerSelector).append("svg:svg").attr("class","chart");this.content=this.svg.append("svg:g").attr("class","content").attr("id",this.config.id);this.xAxis=this.content.append("g").attr("class","axis").attr("id","x-axis");this.xAxisLabel=this.xAxis.append("text").attr("class","axis-label").attr("id","x-axis-label");this.yAxis=this.content.append("g").attr("class","axis").attr("id","y-axis");this.yAxisLabel=this.yAxis.append("text").attr("class","axis-label").attr("id","y-axis-label");this.adjustChartDimensions=function(l,j,i,k){l=l||0;j=j||0;i=i||0;k=k||0;this.svg.attr("width",this.config.width+(this.config.marginRight+j)+(this.config.marginLeft+k)).attr("height",this.config.height+(this.config.marginTop+l)+(this.config.marginBottom+i)).style("display","block");this.content=this.svg.select("g.content").attr("transform",this.translateStr(this.config.marginLeft+k,this.config.marginTop+l))};this.preprocessData=function(k,j,i){return(k.length>this.config.maxDataPoints)?(k.slice(0,this.config.maxDataPoints)):(k)};this.setUpDomains=function(i,k,j){this.xMin=this.config.xMin||(j)?(j[0].min):(d3.min(i));this.xMax=this.config.xMax||(j)?(j[0].max):(d3.max(i));this.yMin=this.config.yMin||(j)?(j[1].min):(d3.min(k));this.yMax=this.config.yMax||(j)?(j[1].max):(d3.max(k))};this.setUpScales=function(){this.xScale=d3.scale.linear().domain([this.xMin,this.xMax]).range([0,this.config.width]),this.yScale=d3.scale.linear().domain([this.yMin,this.yMax]).range([this.config.height,0])};this.setUpXAxis=function(){this.xAxisFn=d3.svg.axis().scale(this.xScale).ticks(this.config.xNumTicks).orient("bottom");this.xAxis.attr("transform",this.translateStr(0,this.config.height)).call(this.xAxisFn);this.xLongestLabel=d3.max(_.map([this.xMin,this.xMax],function(i){return(String(i)).length}));if(this.xLongestLabel>=c){this.xAxis.selectAll("g").filter(":nth-child(odd)").style("display","none")}this.xAxisLabel.attr("x",this.config.width/2).attr("y",this.config.xAxisLabelBumpY).attr("text-anchor","middle").text(this.config.xLabel)};this.setUpYAxis=function(){this.yAxisFn=d3.svg.axis().scale(this.yScale).ticks(this.config.yNumTicks).orient("left");this.yAxis.call(this.yAxisFn);var i=this.yAxis.selectAll("text").filter(function(m,l){return l!==0});this.yLongestLabel=d3.max(i[0].map(function(m,l){return(d3.select(m).text()).length}))||0;var j=d+(this.yLongestLabel*h)+e+g;this.config.yAxisLabelBumpX=-(j-g);if(this.config.marginLeft<j){var k=(j)-this.config.marginLeft;k=(k<0)?(0):(k);this.adjustChartDimensions(0,0,0,k)}this.yAxisLabel.attr("x",this.config.yAxisLabelBumpX).attr("y",this.config.height/2).attr("text-anchor","middle").attr("transform",this.rotateStr(-90,this.config.yAxisLabelBumpX,this.config.height/2)).text(this.config.yLabel)};this.renderGrid=function(){this.vGridLines=this.content.selectAll("line.v-grid-line").data(this.xScale.ticks(this.xAxisFn.ticks()[0]));this.vGridLines.enter().append("svg:line").classed("grid-line v-grid-line",true);this.vGridLines.attr("x1",this.xScale).attr("y1",0).attr("x2",this.xScale).attr("y2",this.config.height);this.vGridLines.exit().remove();this.hGridLines=this.content.selectAll("line.h-grid-line").data(this.yScale.ticks(this.yAxisFn.ticks()[0]));this.hGridLines.enter().append("svg:line").classed("grid-line h-grid-line",true);this.hGridLines.attr("x1",0).attr("y1",this.yScale).attr("x2",this.config.width).attr("y2",this.yScale);this.hGridLines.exit().remove()};this.glyphEnterState=function(i){};this.glyphFinalState=function(i){};this.glyphExitState=function(i){};this.renderDatapoints=function(i,l,j){this.log(this+".renderDatapoints",arguments);var k=0;this.datapoints=this.addDatapoints(i,l,j,".glyph");this.datapoints.exit().each(function(){k+=1}).transition().duration(this.config.entryAnimDuration).attr("cy",this.config.height).attr("r",0).remove();this.log(k," glyphs removed")};this.addDatapoints=function(m,k,i,l){this.log(this+".addDatapoints",arguments);var p=this,o=0,q=function(s,r){return p.xScale(m[r])},j=function(s,r){return p.yScale(k[r])};var n=this.content.selectAll(l);this.log("existing datapoints:",n);n=n.data(m);o=0;n.enter().append("svg:circle").each(function(){o+=1}).classed("glyph",true).attr("cx",q).attr("cy",j).attr("r",0);this.log(o," new glyphs created");o=0;n.transition().duration(this.config.entryAnimDuration).each(function(){o+=1}).attr("cx",q).attr("cy",j).attr("r",p.config.datapointSize);this.log(o," existing glyphs transitioned");if(i){n.attr("data",function(s,r){return(i[r])})}n.attr("title",function(s,r){return((i)?(i[r]+": "):(""))+m[r]+", "+k[r]});n.on("mouseover",function(){var r=d3.select(this);r.style("fill","red").style("fill-opacity",1);p.content.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",r.attr("cx")).attr("y1",r.attr("cy")).attr("x2",0).attr("y2",r.attr("cy")).classed("hoverline",true);p.content.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",r.attr("cx")).attr("y1",r.attr("cy")).attr("x2",r.attr("cx")).attr("y2",p.config.height).classed("hoverline",true)}).on("mouseout",function(){d3.select(this).style("fill","black").style("fill-opacity",0.2);d3.selectAll(".hoverline").remove()});return n};this.render=function(k,l){this.log(this+".render",arguments);var i=k[0],m=k[1],j=(k.length>2)?(k[2]):(undefined);i=this.preprocessData(i);m=this.preprocessData(m);this.log("xCol len",i.length,"yCol len",m.length);this.setUpDomains(i,m,l);this.setUpScales();this.adjustChartDimensions();this.setUpXAxis();this.setUpYAxis();this.renderGrid();this.renderDatapoints(i,m,j)}}var b=BaseView.extend(LoggableMixin).extend({className:"scatterplot-settings-form",loadingIndicatorImage:"loading_large_white_bg.gif",initialize:function(c){if(!c||!c.dataset){throw ("ScatterplotView requires a dataset")}else{this.dataset=c.dataset}this.apiDatasetsURL=c.apiDatasetsURL;this.chartConfig=c.chartConfig||{};this.log("initial chartConfig:",this.chartConfig);this.plot=new a(this.chartConfig);this.chartConfig=this.plot.config;this.$statsPanel=null;this.$chartSettingsPanel=null;this.$dataSettingsPanel=null;this.dataFetch=null},render:function(){var c=this,d={config:this.chartConfig,allColumns:[],numericColumns:[],loadingIndicatorImagePath:galaxy_paths.get("image_path")+"/"+this.loadingIndicatorImage};_.each(this.dataset.metadata_column_types.split(", "),function(g,f){var e="column "+(f+1);if(c.dataset.metadata_column_names){e=c.dataset.metadata_column_names[f]}if(g==="int"||g==="float"){d.numericColumns.push({index:f,name:e})}d.allColumns.push({index:f,name:e})});this.$el.append(b.templates.form(d));this.$dataSettingsPanel=this.$el.find(".tab-pane#data-settings");this.$chartSettingsPanel=this._render_chartSettings();this.$statsPanel=this.$el.find(".tab-pane#chart-stats");return this},_render_chartSettings:function(){var c=this,d=this.$el.find(".tab-pane#chart-settings"),e={maxDataPoints:{min:1000,max:30000,step:100},datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};d.append(b.templates.chartSettings(this.chartConfig));d.find(".numeric-slider-input").each(function(){var h=$(this),g=h.find(".slider-output"),i=h.find(".slider"),j=h.attr("id");c.log("slider set up","this:",h,"slider:",i,"id",j);function f(){var l=$(this),k=l.slider("value");g.text(k);c.chartConfig[j]=k}i.slider(_.extend(e[j],{value:c.chartConfig[j],change:f,slide:f}))});return d},events:{"click #render-button":"renderPlot","click #include-id-checkbox":"toggleThirdColumnSelector"},toggleThirdColumnSelector:function(){this.$el.find('select[name="ID"]').parent().toggle()},showLoadingIndicator:function(d,e){d=d||"";var c=this.$el.find("div#loading-indicator");messageBox=c.find(".loading-message");if(c.is(":visible")){if(d){messageBox.fadeOut("fast",function(){messageBox.text(d);messageBox.fadeIn("fast",e)})}else{e()}}else{if(d){messageBox.text(d)}c.fadeIn("fast",e)}},hideLoadingIndicator:function(c){this.$el.find("div#loading-indicator").fadeOut("fast",c)},getColumnVals:function(){var c={};this.$el.find("div.column-select select").each(function(){var d=$(this),e=d.val();c[d.attr("name")]={colIndex:e,colName:d.children('[value="'+e+'"]').text()}});return c},fetchData:function(f,d){var c=this,e=this.apiDatasetsURL+"/"+this.dataset.id+"?data_type=raw_data&"+jQuery.param(f);this.log("url:",e);this.showLoadingIndicator("Fetching data...",function(){jQuery.ajax({url:e,dataType:"json",success:d,error:function(i,g,h){c.hideLoadingIndicator();alert("ERROR:"+g+"\n"+h)}})})},renderPlot:function(){var e=this,g=this.getColumnVals(),f=[];this.log("columnSelections:",g);this.log(g.X.val,g.Y.val);this.xColIndex=g.X.colIndex;this.yColIndex=g.Y.colIndex;f=[this.xColIndex,this.yColIndex];if($("#include-id-checkbox").attr("checked")){f.push(g.ID.colIndex)}var d=this.$chartSettingsPanel.find("input#X-axis-label").val(),c=this.$chartSettingsPanel.find("input#Y-axis-label").val();this.chartConfig.xLabel=(d==="X")?(g.X.colName):(d);this.chartConfig.yLabel=(c==="Y")?(g.Y.colName):(c);e.plot.updateConfig(this.chartConfig,false);var h={columns:"["+f+"]"};this.fetchData(h,function(i){e.dataFetch=i;e.showLoadingIndicator("Rendering...",function(){e.plot.render(i.data,i.meta);e.renderStats(i.data,i.meta);e.$el.find("ul.nav").find('a[href="#chart-stats"]').tab("show");e.hideLoadingIndicator()})})},renderStats:function(){this.$statsPanel.html(b.templates.statsTable({stats:[{name:"Count",xval:this.dataFetch.meta[0].count,yval:this.dataFetch.meta[1].count},{name:"Min",xval:this.dataFetch.meta[0].min,yval:this.dataFetch.meta[1].min},{name:"Max",xval:this.dataFetch.meta[0].max,yval:this.dataFetch.meta[1].max},{name:"Mean",xval:this.dataFetch.meta[0].mean,yval:this.dataFetch.meta[1].mean},{name:"Median",xval:this.dataFetch.meta[0].median,yval:this.dataFetch.meta[1].median}]}))},toString:function(){return"ScatterplotControlForm("+attributes.dataset.id+")"}});b.templates={form:Handlebars.templates["template-visualization-scatterplotControlForm"],statsTable:Handlebars.templates["template-visualization-statsTable"],chartSettings:Handlebars.templates["template-visualization-chartSettings"]};return{LazyDataLoader:LazyDataLoader,TwoVarScatterplot:a,ScatterplotControlForm:b}});>>>>>>> other
+define(["../libs/underscore","../mvc/base-mvc","../utils/LazyDataLoader","../templates/compiled/template-visualization-scatterplotControlForm","../templates/compiled/template-visualization-statsTable","../templates/compiled/template-visualization-chartSettings","../libs/d3","../libs/bootstrap","../libs/jquery/jquery-ui-1.8.23.custom.min"],function(){function a(f){var d=10,h=7,g=10,e=8,c=5;this.log=function(){if(this.debugging&&console&&console.debug){var i=Array.prototype.slice.call(arguments);i.unshift(this.toString());console.debug.apply(console,i)}};this.log("new TwoVarScatterplot:",f);this.defaults={id:"TwoVarScatterplot",containerSelector:"body",maxDataPoints:30000,datapointSize:4,animDuration:500,xNumTicks:10,yNumTicks:10,xAxisLabelBumpY:40,yAxisLabelBumpX:-35,width:500,height:500,marginTop:50,marginRight:50,marginBottom:50,marginLeft:50,xMin:null,xMax:null,yMin:null,yMax:null,xLabel:"X",yLabel:"Y"};this.config=_.extend({},this.defaults,f);this.updateConfig=function(i,j){_.extend(this.config,i)};this.toString=function(){return this.config.id};this.translateStr=function(i,j){return"translate("+i+","+j+")"};this.rotateStr=function(j,i,k){return"rotate("+j+","+i+","+k+")"};this.svg=d3.select(this.config.containerSelector).append("svg:svg").attr("class","chart");this.content=this.svg.append("svg:g").attr("class","content").attr("id",this.config.id);this.xAxis=this.content.append("g").attr("class","axis").attr("id","x-axis");this.xAxisLabel=this.xAxis.append("text").attr("class","axis-label").attr("id","x-axis-label");this.yAxis=this.content.append("g").attr("class","axis").attr("id","y-axis");this.yAxisLabel=this.yAxis.append("text").attr("class","axis-label").attr("id","y-axis-label");this.adjustChartDimensions=function(l,j,i,k){l=l||0;j=j||0;i=i||0;k=k||0;this.svg.attr("width",this.config.width+(this.config.marginRight+j)+(this.config.marginLeft+k)).attr("height",this.config.height+(this.config.marginTop+l)+(this.config.marginBottom+i)).style("display","block");this.content=this.svg.select("g.content").attr("transform",this.translateStr(this.config.marginLeft+k,this.config.marginTop+l))};this.preprocessData=function(k,j,i){return(k.length>this.config.maxDataPoints)?(k.slice(0,this.config.maxDataPoints)):(k)};this.setUpDomains=function(i,k,j){this.xMin=this.config.xMin||(j)?(j[0].min):(d3.min(i));this.xMax=this.config.xMax||(j)?(j[0].max):(d3.max(i));this.yMin=this.config.yMin||(j)?(j[1].min):(d3.min(k));this.yMax=this.config.yMax||(j)?(j[1].max):(d3.max(k))};this.setUpScales=function(){this.xScale=d3.scale.linear().domain([this.xMin,this.xMax]).range([0,this.config.width]),this.yScale=d3.scale.linear().domain([this.yMin,this.yMax]).range([this.config.height,0])};this.setUpXAxis=function(){this.xAxisFn=d3.svg.axis().scale(this.xScale).ticks(this.config.xNumTicks).orient("bottom");this.xAxis.attr("transform",this.translateStr(0,this.config.height)).call(this.xAxisFn);this.xLongestLabel=d3.max(_.map([this.xMin,this.xMax],function(i){return(String(i)).length}));if(this.xLongestLabel>=c){this.xAxis.selectAll("g").filter(":nth-child(odd)").style("display","none")}this.xAxisLabel.attr("x",this.config.width/2).attr("y",this.config.xAxisLabelBumpY).attr("text-anchor","middle").text(this.config.xLabel)};this.setUpYAxis=function(){this.yAxisFn=d3.svg.axis().scale(this.yScale).ticks(this.config.yNumTicks).orient("left");this.yAxis.call(this.yAxisFn);var i=this.yAxis.selectAll("text").filter(function(m,l){return l!==0});this.yLongestLabel=d3.max(i[0].map(function(m,l){return(d3.select(m).text()).length}))||0;var j=d+(this.yLongestLabel*h)+e+g;this.config.yAxisLabelBumpX=-(j-g);if(this.config.marginLeft<j){var k=(j)-this.config.marginLeft;k=(k<0)?(0):(k);this.adjustChartDimensions(0,0,0,k)}this.yAxisLabel.attr("x",this.config.yAxisLabelBumpX).attr("y",this.config.height/2).attr("text-anchor","middle").attr("transform",this.rotateStr(-90,this.config.yAxisLabelBumpX,this.config.height/2)).text(this.config.yLabel)};this.renderGrid=function(){this.vGridLines=this.content.selectAll("line.v-grid-line").data(this.xScale.ticks(this.xAxisFn.ticks()[0]));this.vGridLines.enter().append("svg:line").classed("grid-line v-grid-line",true);this.vGridLines.attr("x1",this.xScale).attr("y1",0).attr("x2",this.xScale).attr("y2",this.config.height);this.vGridLines.exit().remove();this.hGridLines=this.content.selectAll("line.h-grid-line").data(this.yScale.ticks(this.yAxisFn.ticks()[0]));this.hGridLines.enter().append("svg:line").classed("grid-line h-grid-line",true);this.hGridLines.attr("x1",0).attr("y1",this.yScale).attr("x2",this.config.width).attr("y2",this.yScale);this.hGridLines.exit().remove()};this.glyphEnterState=function(i){};this.glyphFinalState=function(i){};this.glyphExitState=function(i){};this.renderDatapoints=function(i,l,j){this.log(this+".renderDatapoints",arguments);var k=0;this.datapoints=this.addDatapoints(i,l,j,".glyph");this.datapoints.exit().each(function(){k+=1}).transition().duration(this.config.animDuration).attr("cy",this.config.height).attr("r",0).remove();this.log(k," glyphs removed")};this.addDatapoints=function(m,k,i,l){this.log(this+".addDatapoints",arguments);var p=this,o=0,q=function(s,r){return p.xScale(m[r])},j=function(s,r){return p.yScale(k[r])};var n=this.content.selectAll(l);this.log("existing datapoints:",n);n=n.data(m);o=0;n.enter().append("svg:circle").each(function(){o+=1}).classed("glyph",true).attr("cx",q).attr("cy",j).attr("r",0);this.log(o," new glyphs created");o=0;n.transition().duration(this.config.animDuration).each(function(){o+=1}).attr("cx",q).attr("cy",j).attr("r",p.config.datapointSize);this.log(o," existing glyphs transitioned");if(i){n.attr("data",function(s,r){return(i[r])})}n.attr("title",function(s,r){return((i)?(i[r]+": "):(""))+m[r]+", "+k[r]});n.on("mouseover",function(){var r=d3.select(this);r.style("fill","red").style("fill-opacity",1);p.content.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",r.attr("cx")).attr("y1",r.attr("cy")).attr("x2",0).attr("y2",r.attr("cy")).classed("hoverline",true);p.content.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",r.attr("cx")).attr("y1",r.attr("cy")).attr("x2",r.attr("cx")).attr("y2",p.config.height).classed("hoverline",true)}).on("mouseout",function(){d3.select(this).style("fill","black").style("fill-opacity",0.2);d3.selectAll(".hoverline").remove()});return n};this.render=function(k,l){this.log(this+".render",arguments);var i=k[0],m=k[1],j=(k.length>2)?(k[2]):(undefined);i=this.preprocessData(i);m=this.preprocessData(m);this.log("xCol len",i.length,"yCol len",m.length);this.setUpDomains(i,m,l);this.setUpScales();this.adjustChartDimensions();this.setUpXAxis();this.setUpYAxis();this.renderGrid();this.renderDatapoints(i,m,j)}}var b=BaseView.extend(LoggableMixin).extend({className:"scatterplot-settings-form",dataLoadDelay:500,dataLoadSize:3001,loadingIndicatorImage:"loading_large_white_bg.gif",initialize:function(c){if(this.logger){window.form=this}this.dataset=null;this.chartConfig=null;this.plot=null;this.loader=null;this.$statsPanel=null;this.$chartSettingsPanel=null;this.$dataSettingsPanel=null;this.dataFetch=null;this.initializeFromAttributes(c);this.initializeChart(c);this.initializeDataLoader(c)},initializeFromAttributes:function(c){if(!c||!c.dataset){throw ("ScatterplotView requires a dataset")}else{this.dataset=c.dataset}if(jQuery.type(this.dataset.metadata_column_types)==="string"){this.dataset.metadata_column_types=this.dataset.metadata_column_types.split(", ")}this.log("dataset:",this.dataset);if(!c.apiDatasetsURL){throw ("ScatterplotView requires a apiDatasetsURL")}else{this.dataURL=c.apiDatasetsURL+"/"+this.dataset.id+"?"}this.log("this.dataURL:",this.dataURL)},initializeChart:function(c){this.chartConfig=c.chartConfig||{};if(this.logger){this.chartConfig.debugging=true}this.log("initial chartConfig:",this.chartConfig);this.plot=new a(this.chartConfig);this.chartConfig=this.plot.config},initializeDataLoader:function(d){var c=this;this.loader=new LazyDataLoader({logger:(this.logger)?(this.logger):(null),url:null,start:d.start||0,total:d.total||this.dataset.metadata_data_lines,delay:this.dataLoadDelay,size:this.dataLoadSize,buildUrl:function(f,e){return this.url+"&"+jQuery.param({start_val:f,max_vals:e})}});$(this.loader).bind("error",function(g,e,f){c.log("ERROR:",e,f);alert("ERROR fetching data:\n"+e+"\n"+f);c.hideLoadingIndicator()})},render:function(){var c=this,d={config:this.chartConfig,allColumns:[],numericColumns:[],loadingIndicatorImagePath:galaxy_paths.get("image_path")+"/"+this.loadingIndicatorImage};_.each(this.dataset.metadata_column_types,function(g,f){var e="column "+(f+1);if(c.dataset.metadata_column_names){e=c.dataset.metadata_column_names[f]}if(g==="int"||g==="float"){d.numericColumns.push({index:f,name:e})}d.allColumns.push({index:f,name:e})});this.$el.append(b.templates.form(d));this.$dataSettingsPanel=this.$el.find(".tab-pane#data-settings");this.$chartSettingsPanel=this._render_chartSettings();this.$statsPanel=this.$el.find(".tab-pane#chart-stats");return this},_render_chartSettings:function(){var c=this,d=this.$el.find(".tab-pane#chart-settings"),e={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};d.append(b.templates.chartSettings(this.chartConfig));d.find(".numeric-slider-input").each(function(){var h=$(this),g=h.find(".slider-output"),i=h.find(".slider"),j=h.attr("id");function f(){var l=$(this),k=l.slider("value");g.text(k)}i.slider(_.extend(e[j],{value:c.chartConfig[j],change:f,slide:f}))});return d},events:{"click #include-id-checkbox":"toggleThirdColumnSelector","click #data-settings #render-button":"renderPlot","click #chart-settings #render-button":"changeChartSettings"},toggleThirdColumnSelector:function(){this.$el.find('select[name="ID"]').parent().toggle()},showLoadingIndicator:function(d,e){d=d||"";var c=this.$el.find("div#loading-indicator");messageBox=c.find(".loading-message");if(c.is(":visible")){if(d){messageBox.fadeOut("fast",function(){messageBox.text(d);messageBox.fadeIn("fast",e)})}else{e()}}else{if(d){messageBox.text(d)}c.fadeIn("fast",e)}},hideLoadingIndicator:function(c){this.$el.find("div#loading-indicator").fadeOut("fast",c)},renderPlot:function(){var c=this;c.data=null;c.meta=null;_.extend(this.chartConfig,this.getGraphSettings());this.log("this.chartConfig:",this.chartConfig);this.plot.updateConfig(this.chartConfig,false);this.loader.url=this.dataURL+"&"+jQuery.param(this.getDataSettings());this.log("this.loader, url:",this.loader.url,"total:",this.loader.total);$(this.loader).bind("loaded.new",function(e,d){c.log(c+" loaded.new",d);c.postProcessDataFetchResponse(d);c.log("postprocessed data:",c.data,"meta:",c.meta);c.showLoadingIndicator("Rendering...",function(){c.$el.find("ul.nav").find('a[href="#chart-stats"]').tab("show");c.plot.render(c.data,c.meta);c.renderStats(c.data,c.meta);c.hideLoadingIndicator()})});$(this.loader).bind("complete",function(d,e){c.log("complete",e);$(c.loader).unbind()});c.showLoadingIndicator("Fetching data...",function(){c.loader.load()})},renderStats:function(){this.$statsPanel.html(b.templates.statsTable({stats:[{name:"Count",xval:this.meta[0].count,yval:this.meta[1].count},{name:"Min",xval:this.meta[0].min,yval:this.meta[1].min},{name:"Max",xval:this.meta[0].max,yval:this.meta[1].max},{name:"Sum",xval:this.meta[0].sum,yval:this.meta[1].sum},{name:"Mean",xval:this.meta[0].mean,yval:this.meta[1].mean},{name:"Median",xval:this.meta[0].median,yval:this.meta[1].median}]}))},changeChartSettings:function(){var c=this;newGraphSettings=this.getGraphSettings();this.log("newGraphSettings:",newGraphSettings);_.extend(this.chartConfig,newGraphSettings);this.log("this.chartConfig:",this.chartConfig);this.plot.updateConfig(this.chartConfig,false);if(c.data&&c.meta){c.showLoadingIndicator("Rendering...",function(){c.plot.render(c.data,c.meta);c.hideLoadingIndicator()})}else{this.renderPlot()}},postProcessDataFetchResponse:function(c){this.postProcessData(c.data);this.postProcessMeta(c.meta)},postProcessData:function(d){var c=this;if(c.data){_.each(d,function(f,e){c.data[e]=c.data[e].concat(f)})}else{c.data=d}},postProcessMeta:function(e){var c=this,d=this.dataset.metadata_column_types;if(c.meta){_.each(e,function(g,f){var k=c.meta[f],i=d[f];c.log(f+" postprocessing meta:",g);k.count+=(g.count)?(g.count):(0);c.log(f,"count:",k.count);if((i==="int")||(i==="float")){k.min=Math.min(g.min,k.min);k.max=Math.max(g.max,k.max);k.sum=g.sum+k.sum;k.mean=(k.count)?(k.sum/k.count):(null);var h=c.data[f].slice().sort(),j=Math.floor(h.length/2);if(h.length%2===0){k.median=((h[j]+h[(j+1)])/2)}else{k.median=h[j]}}})}else{c.meta=e;c.log("initial meta:",c.meta)}},getDataSettings:function(){var d=this.getColumnSelections(),c=[];this.log("columnSelections:",d);c=[d.X.colIndex,d.Y.colIndex];if(this.$dataSettingsPanel.find("#include-id-checkbox").attr("checked")){c.push(d.ID.colIndex)}var e={data_type:"raw_data",columns:"["+c+"]"};this.log("params:",e);return e},getColumnSelections:function(){var c={};this.$dataSettingsPanel.find("div.column-select select").each(function(){var d=$(this),e=d.val();c[d.attr("name")]={colIndex:e,colName:d.children('[value="'+e+'"]').text()}});return c},getGraphSettings:function(){var e={},f=this.getColumnSelections();e.datapointSize=this.$chartSettingsPanel.find("#datapointSize.numeric-slider-input").find(".slider").slider("value");e.width=this.$chartSettingsPanel.find("#width.numeric-slider-input").find(".slider").slider("value");e.height=this.$chartSettingsPanel.find("#height.numeric-slider-input").find(".slider").slider("value");var d=this.$chartSettingsPanel.find("input#X-axis-label").val(),c=this.$chartSettingsPanel.find("input#Y-axis-label").val();e.xLabel=(d==="X")?(f.X.colName):(d);e.yLabel=(c==="Y")?(f.Y.colName):(c);e.animDuration=10;if(this.$chartSettingsPanel.find("#animDuration.checkbox-input").is(":checked")){e.animDuration=500}this.log("graphSettings:",e);return e},toString:function(){return"ScatterplotControlForm("+this.dataset.id+")"}});b.templates={form:Handlebars.templates["template-visualization-scatterplotControlForm"],statsTable:Handlebars.templates["template-visualization-statsTable"],chartSettings:Handlebars.templates["template-visualization-chartSettings"]};return{LazyDataLoader:LazyDataLoader,TwoVarScatterplot:a,ScatterplotControlForm:b}});
\ No newline at end of file
diff -r 4cd4f8bef29d17a7bca74e235031060e2289ebdc -r 8bcc04c4b710dbf4173a5fba6d2a3111e7c2b511 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","mvc/data","viz/trackster/filters"],function(ab,x,l,u,L,Z,i){var q=ab.extend;var V=function(ac){return("isResolved" in ac)};var n={};var k=function(ac,ad){n[ac.attr("id")]=ad};var m=function(ac,ae,ag,af){ag=".group";var ad={};n[ac.attr("id")]=af;ac.bind("drag",{handle:"."+ae,relative:true},function(ao,ap){var an=$(this),at=$(this).parent(),ak=at.children(),am=n[$(this).attr("id")],aj,ai,aq,ah,al;ai=$(this).parents(ag);if(ai.length!==0){aq=ai.position().top;ah=aq+ai.outerHeight();if(ap.offsetY<aq){$(this).insertBefore(ai);var ar=n[ai.attr("id")];ar.remove_drawable(am);ar.container.add_drawable_before(am,ar);return}else{if(ap.offsetY>ah){$(this).insertAfter(ai);var ar=n[ai.attr("id")];ar.remove_drawable(am);ar.container.add_drawable(am);return}}}ai=null;for(al=0;al<ak.length;al++){aj=$(ak.get(al));aq=aj.position().top;ah=aq+aj.outerHeight();if(aj.is(ag)&&this!==aj.get(0)&&ap.offsetY>=aq&&ap.offsetY<=ah){if(ap.offsetY-aq<ah-ap.offsetY){aj.find(".content-div").prepend(this)}else{aj.find(".content-div").append(this)}if(am.container){am.container.remove_drawable(am)}n[aj.attr("id")].add_drawable(am);return}}for(al=0;al<ak.length;al++){aj=$(ak.get(al));if(ap.offsetY<aj.position().top&&!(aj.hasClass("reference-track")||aj.hasClass("intro"))){break}}if(al===ak.length){if(this!==ak.get(al-1)){at.append(this);n[at.attr("id")].move_drawable(am,al)}}else{if(this!==ak.get(al)){$(this).insertBefore(ak.get(al));n[at.attr("id")].move_drawable(am,(ap.deltaY>0?al-1:al))}}}).bind("dragstart",function(){ad["border-top"]=ac.css("border-top");ad["border-bottom"]=ac.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(ad)})};exports.moveable=m;var aa=16,G=9,D=20,A=100,I=12000,S=400,K=5000,w=100,o="There was an error in indexing this dataset. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",v="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",y="Tool cannot be rerun: ",a="Loading data...",U="Ready for display",Q=10,H=20;function W(ad,ac){if(!ac){ac=0}var ae=Math.pow(10,ac);return Math.round(ad*ae)/ae}var r=function(ad,ac,af){if(!r.id_counter){r.id_counter=0}this.id=r.id_counter++;this.name=af.name;this.view=ad;this.container=ac;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:af.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=af.drag_handle_class;this.is_overview=false;this.action_icons={};this.content_visible=true;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/>").css("float","left").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(ag){ag.stopPropagation()});var ae=this;this.container_div.hover(function(){ae.icons_div.show()},function(){ae.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};r.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ac){if(ac.content_visible){ac.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ac.hide_contents();ac.content_visible=false}else{ac.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ac.content_visible=true;ac.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(ad){var af=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ac=function(){ad.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},ae=function(ag){if((ag.keyCode||ag.which)===27){af()}else{if((ag.keyCode||ag.which)===13){ac()}}};$(window).bind("keypress.check_enter_esc",ae);show_modal("Configure",ad.config.build_form(),{Cancel:af,OK:ac})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.remove()}}];q(r.prototype,{init:function(){},changed:function(){this.view.changed()},can_draw:function(){if(this.enabled&&this.content_visible){return true}return false},request_draw:function(){},_draw:function(){},to_dict:function(){},set_name:function(ac){this.old_name=this.name;this.name=ac;this.name_div.text(this.name)},revert_name:function(){if(this.old_name){this.name=this.old_name;this.name_div.text(this.name)}},remove:function(){this.changed();this.container.remove_drawable(this);var ac=this.view;this.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ad,ai,ah,ag,ac,af){var ae=this;this.action_icons[ad]=$("<a/>").attr("href","javascript:void(0);").attr("title",ai).addClass("icon-button").addClass(ah).tooltip().click(function(){ag(ae)}).appendTo(this.icons_div);if(af){this.action_icons[ad].hide()}},build_action_icons:function(ac){var ae;for(var ad=0;ad<ac.length;ad++){ae=ac[ad];this.add_action_icon(ae.name,ae.title,ae.css_class,ae.on_click_fn,ae.prepend,ae.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var z=function(ad,ac,ae){r.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};q(z.prototype,r.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=p(ae[ac],this.view,this);this.add_drawable(ad)}},init:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].init()}},_draw:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac]._draw()}},to_dict:function(){var ad=[];for(var ac=0;ac<this.drawables.length;ac++){ad.push(this.drawables[ac].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:ad}},add_drawable:function(ac){this.drawables.push(ac);ac.container=this;this.changed()},add_drawable_before:function(ae,ac){this.changed();var ad=this.drawables.indexOf(ac);if(ad!==-1){this.drawables.splice(ad,0,ae);return true}return false},replace_drawable:function(ae,ac,ad){var af=this.drawables.indexOf(ae);if(af!==-1){this.drawables[af]=ac;if(ad){ae.container_div.replaceWith(ac.container_div)}this.changed()}return af},remove_drawable:function(ad){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);ad.container=null;this.changed();return true}return false},move_drawable:function(ad,ae){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);this.drawables.splice(ae,0,ad);this.changed();return true}return false},get_drawables:function(){return this.drawables}});var P=function(ad,ac,af){q(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});z.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);m(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new i.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in af){this.unpack_drawables(af.drawables)}if("filters" in af){var ae=this.filters_manager;this.filters_manager=new i.FiltersManager(this,af.filters);ae.parent_div.replaceWith(this.filters_manager.parent_div);if(af.filters.visible){this.setup_multitrack_filtering()}}};q(P.prototype,r.prototype,z.prototype,{action_icons_def:[r.prototype.action_icons_def[0],r.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters();ac._restore_filter_managers()}else{ac.setup_multitrack_filtering();ac.request_draw(true)}ac.filters_manager.toggle()}},r.prototype.action_icons_def[2]],build_container_div:function(){var ac=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ac)}return ac},build_header_div:function(){var ac=$("<div/>").addClass("track-header");ac.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(ac);return ac},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ae=this.drawables.length;if(ae===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ae===1){if(this.drawables[0] instanceof f){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var al,ak,ai,ao=true,ag=this.drawables[0].get_type(),ac=0;for(al=0;al<ae;al++){ai=this.drawables[al];if(ai.get_type()!==ag){can_composite=false;break}if(ai instanceof c){ac++}}if(ao||ac===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(ac>1&&ac===this.drawables.length){var ap={},ad;ai=this.drawables[0];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];ap[ad.name]=[ad]}for(al=1;al<this.drawables.length;al++){ai=this.drawables[al];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];if(ad.name in ap){ap[ad.name].push(ad)}}}this.filters_manager.remove_all();var af,ah,aj,am;for(var an in ap){af=ap[an];if(af.length===ac){ah=new i.NumberFilter({name:af[0].name,index:af[0].index});this.filters_manager.add_filter(ah)}}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 ac=0;ac<this.drawables.length;ac++){this.drawables[ac].filters_manager=this.saved_filters_managers[ac]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ac=0;ac<this.drawables.length;ac++){drawable=this.drawables[ac];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ag=[];for(var ad=0;ad<this.drawables.length;ad++){ag.push(this.drawables[ad].name)}var ae="Composite Track of "+this.drawables.length+" tracks ("+ag.join(", ")+")";var af=new f(this.view,this.view,{name:ae,drawables:this.drawables});var ac=this.container.replace_drawable(this,af,true);af.request_draw()},add_drawable:function(ac){z.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){z.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=q(z.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ac},request_draw:function(ac,ae){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].request_draw(ac,ae)}}});var Y=function(ac){q(ac,{obj_type:"View"});z.call(this,"View",ac.container,ac);this.chrom=null;this.vis_id=ac.vis_id;this.dbkey=ac.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.init();this.canvas_manager=new x.CanvasManager(this.container.get(0).ownerDocument);this.reset()};ab.extend(Y.prototype,Backbone.Events);q(Y.prototype,z.prototype,{init:function(){this.requested_redraw=false;var ae=this.container,ac=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ae);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ae);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ae);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;k(this.viewport_container,ac);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(){x.select_datasets(select_datasets_url,add_track_async_url,function(ag){ab.each(ag,function(ah){ac.add_drawable(p(ah,ac,ac))})})});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("href","javascript:void(0);").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"}).css("width","15em").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var ad=function(ag){if(ag.type==="focusout"||(ag.keyCode||ag.which)===13||(ag.keyCode||ag.which)===27){if((ag.keyCode||ag.which)!==27){ac.go_to($(this).val())}$(this).hide();$(this).val("");ac.location_span.show();ac.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ad).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").attr("original-title","Click to change location").tooltip({placement:"bottom"}).appendTo(this.nav_controls);this.location_span.click(function(){ac.location_span.hide();ac.chrom_select.hide();ac.nav_input.val(ac.chrom+":"+ac.low+"-"+ac.high);ac.nav_input.css("display","inline-block");ac.nav_input.select();ac.nav_input.focus();ac.nav_input.autocomplete({source:function(ai,ag){var aj=[],ah=$.map(ac.get_drawables(),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(){ac.zoom_out();ac.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ac.zoom_in();ac.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ac.change_chrom(ac.chrom_select.val())});this.browser_content_div.click(function(ag){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ag){ac.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/ac.viewport_container.width()*(ac.max_high-ac.max_low));ac.move_delta(-ah)});this.overview_close.click(function(){ac.reset_overview()});this.viewport_container.bind("draginit",function(ag,ah){if(ag.clientX>ac.viewport_container.width()-16){return false}}).bind("dragstart",function(ag,ah){ah.original_low=ac.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/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}).bind("mousewheel",function(ai,ak,ah,ag){if(ah){ah*=50;var aj=Math.round(-ah/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}});this.top_labeltrack.bind("dragstart",function(ag,ah){return $("<div />").css({height:ac.browser_content_div.height()+ac.top_labeltrack.height()+ac.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(ak,al){$(al.proxy).css({left:Math.min(ak.pageX,al.startX)-ac.container.offset().left,width:Math.abs(ak.pageX-al.startX)});var ah=Math.min(ak.pageX,al.startX)-ac.container.offset().left,ag=Math.max(ak.pageX,al.startX)-ac.container.offset().left,aj=(ac.high-ac.low),ai=ac.viewport_container.width();ac.update_location(Math.round(ah/ai*aj)+ac.low,Math.round(ag/ai*aj)+ac.low)}).bind("dragend",function(al,am){var ah=Math.min(al.pageX,am.startX),ag=Math.max(al.pageX,am.startX),aj=(ac.high-ac.low),ai=ac.viewport_container.width(),ak=ac.low;ac.low=Math.round(ah/ai*aj)+ak;ac.high=Math.round(ag/ai*aj)+ak;$(am.proxy).remove();ac.request_redraw()});this.add_label_track(new X(this,{content_div:this.top_labeltrack}));this.add_label_track(new X(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ac.resize_window()},500)});$(document).bind("redraw",function(){ac.redraw()});this.reset();$(window).trigger("resize")},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(ad,af,ac,ag){if(this.timer){clearTimeout(this.timer)}if(ag){var ae=this;this.timer=setTimeout(function(){ae.trigger("navigate",ad+":"+af+"-"+ac)},500)}else{view.trigger("navigate",ad+":"+af+"-"+ac)}},update_location:function(ac,ae){this.location_span.text(commatize(ac)+" - "+commatize(ae));this.nav_input.val(this.chrom+":"+commatize(ac)+"-"+commatize(ae));var ad=view.chrom_select.val();if(ad!==""){this.trigger_navigate(ad,view.low,view.high,true)}},load_chroms:function(ae){ae.num=w;var ac=this,ad=$.Deferred();$.ajax({url:chrom_url+"/"+this.dbkey,data:ae,dataType:"json",success:function(ag){if(ag.chrom_info.length===0){return}if(ag.reference){ac.add_label_track(new B(ac))}ac.chrom_data=ag.chrom_info;var aj='<option value="">Select Chrom/Contig</option>';for(var ai=0,af=ac.chrom_data.length;ai<af;ai++){var ah=ac.chrom_data[ai].chrom;aj+='<option value="'+ah+'">'+ah+"</option>"}if(ag.prev_chroms){aj+='<option value="previous">Previous '+w+"</option>"}if(ag.next_chroms){aj+='<option value="next">Next '+w+"</option>"}ac.chrom_select.html(aj);ac.chrom_start_index=ag.start_index;ad.resolve(ag)},error:function(){alert("Could not load chroms for this dbkey:",ac.dbkey)}});return ad},change_chrom:function(ah,ad,aj){var ae=this;if(!ae.chrom_data){ae.load_chroms_deferred.then(function(){ae.change_chrom(ah,ad,aj)});return}if(!ah||ah==="None"){return}if(ah==="previous"){ae.load_chroms({low:this.chrom_start_index-w});return}if(ah==="next"){ae.load_chroms({low:this.chrom_start_index+w});return}var ai=$.grep(ae.chrom_data,function(ak,al){return ak.chrom===ah})[0];if(ai===undefined){ae.load_chroms({chrom:ah},function(){ae.change_chrom(ah,ad,aj)});return}else{if(ah!==ae.chrom){ae.chrom=ah;ae.chrom_select.val(ae.chrom);ae.max_high=ai.len-1;ae.reset();ae.request_redraw(true);for(var ag=0,ac=ae.drawables.length;ag<ac;ag++){var af=ae.drawables[ag];if(af.init){af.init()}}if(ae.reference_track){ae.reference_track.init()}}if(ad!==undefined&&aj!==undefined){ae.low=Math.max(ad,0);ae.high=Math.min(aj,ae.max_high)}else{ae.low=0;ae.high=ae.max_high}ae.reset_overview();ae.request_redraw()}},go_to:function(ag){ag=ag.replace(/ |,/g,"");var ak=this,ac,af,ad=ag.split(":"),ai=ad[0],aj=ad[1];if(aj!==undefined){try{var ah=aj.split("-");ac=parseInt(ah[0],10);af=parseInt(ah[1],10)}catch(ae){return false}}ak.change_chrom(ai,ac,af)},move_fraction:function(ae){var ac=this;var ad=ac.high-ac.low;this.move_delta(ae*ad)},move_delta:function(af){var ac=this;var ae=ac.high-ac.low;if(ac.low-af<ac.max_low){ac.low=ac.max_low;ac.high=ac.max_low+ae}else{if(ac.high-af>ac.max_high){ac.high=ac.max_high;ac.low=ac.max_high-ae}else{ac.high-=af;ac.low-=af}}ac.request_redraw();var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){z.prototype.add_drawable.call(this,ac);ac.init();this.changed();this.update_intro_div()},add_label_track:function(ac){ac.view=this;ac.init();this.label_tracks.push(ac)},remove_drawable:function(ae,ad){z.prototype.remove_drawable.call(this,ae);if(ad){var ac=this;ae.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ak,ac,aj,al){var ai=this,ah=(al?[al]:ai.drawables),ae;var ad;for(var ag=0;ag<ah.length;ag++){ad=ah[ag];ae=-1;for(var af=0;af<ai.tracks_to_be_redrawn.length;af++){if(ai.tracks_to_be_redrawn[af][0]===ad){ae=af;break}}if(ae<0){ai.tracks_to_be_redrawn.push([ad,ac,aj])}else{ai.tracks_to_be_redrawn[ag][1]=ac;ai.tracks_to_be_redrawn[ag][2]=aj}}if(!this.requested_redraw){requestAnimationFrame(function(){ai._redraw(ak)});this.requested_redraw=true}},_redraw:function(am){this.requested_redraw=false;var aj=this.low,af=this.high;if(aj<this.max_low){aj=this.max_low}if(af>this.max_high){af=this.max_high}var al=this.high-this.low;if(this.high!==0&&al<this.min_separation){af=aj+this.min_separation}this.low=Math.floor(aj);this.high=Math.ceil(af);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=this.viewport_container.width()/(this.high-this.low);var ac=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ai=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var an=13;this.overview_box.css({left:ac,width:Math.max(an,ai)}).show();if(ai<an){this.overview_box.css("left",ac-(an-ai)/2)}if(this.overview_highlight){this.overview_highlight.css({left:ac,width:ai})}if(!am){var ae,ad,ak;for(var ag=0,ah=this.tracks_to_be_redrawn.length;ag<ah;ag++){ae=this.tracks_to_be_redrawn[ag][0];ad=this.tracks_to_be_redrawn[ag][1];ak=this.tracks_to_be_redrawn[ag][2];if(ae){ae._draw(ad,ak)}}this.tracks_to_be_redrawn=[];for(ag=0,ah=this.label_tracks.length;ag<ah;ag++){this.label_tracks[ag]._draw()}}},zoom_in:function(ad,ae){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var af=this.high-this.low,ag=af/2+this.low,ac=(af/this.zoom_factor)/2;if(ad){ag=ad/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ag-ac);this.high=Math.round(ag+ac);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ad=this.high-this.low,ae=ad/2+this.low,ac=(ad*this.zoom_factor)/2;this.low=Math.round(ae-ac);this.high=Math.round(ae+ac);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(ae){if(this.overview_drawable){if(this.overview_drawable.dataset_id===ae.dataset_id){return}this.overview_viewport.find(".track").remove()}var ad=ae.copy({content_div:this.overview_viewport}),ac=this;ad.header_div.hide();ad.is_overview=true;ac.overview_drawable=ad;this.overview_drawable.postdraw_actions=function(){ac.overview_highlight.show().height(ac.overview_drawable.content_div.height());ac.overview_viewport.height(ac.overview_drawable.content_div.height()+ac.overview_box.outerHeight());ac.overview_close.show();ac.resize_window()};ac.overview_drawable.request_draw();this.changed()},reset_overview:function(){$(".bs-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 s=function(ae,aj,af){this.track=ae;this.name=aj.name;this.params=[];var aq=aj.params;for(var ag=0;ag<aq.length;ag++){var al=aq[ag],ad=al.name,ap=al.label,ah=unescape(al.html),ar=al.value,an=al.type;if(an==="number"){this.params.push(new e(ad,ap,ah,(ad in af?af[ad]:ar),al.min,al.max))}else{if(an==="select"){this.params.push(new N(ad,ap,ah,(ad in af?af[ad]:ar)))}else{console.log("WARNING: unrecognized tool parameter type:",ad,an)}}}this.parent_div=$("<div/>").addClass("dynamic-tool").hide();this.parent_div.bind("drag",function(au){au.stopPropagation()}).click(function(au){au.stopPropagation()}).bind("dblclick",function(au){au.stopPropagation()});var ao=$("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);var am=this.params;var ak=this;$.each(this.params,function(av,ay){var ax=$("<div>").addClass("param-row").appendTo(ak.parent_div);var au=$("<div>").addClass("param-label").text(ay.label).appendTo(ax);var aw=$("<div/>").addClass("param-input").html(ay.html).appendTo(ax);aw.find(":input").val(ay.value);$("<div style='clear: both;'/>").appendTo(ax)});this.parent_div.find("input").click(function(){$(this).select()});var at=$("<div>").addClass("param-row").appendTo(this.parent_div);var ai=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(at);var ac=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(at);ac.click(function(){ak.run_on_region()});ai.click(function(){ak.run_on_dataset()});if("visible" in af&&af.visible){this.parent_div.show()}};q(s.prototype,{update_params:function(){for(var ac=0;ac<this.params.length;ac++){this.params[ac].update_value()}},state_dict:function(){var ad={};for(var ac=0;ac<this.params.length;ac++){ad[this.params[ac].name]=this.params[ac].value}ad.visible=this.parent_div.is(":visible");return ad},get_param_values_dict:function(){var ac={};this.parent_div.find(":input").each(function(){var ad=$(this).attr("name"),ae=$(this).val();ac[ad]=ae});return ac},get_param_values:function(){var ac=[];this.parent_div.find(":input").each(function(){var ad=$(this).attr("name"),ae=$(this).val();if(ad){ac[ac.length]=ae}});return ac},run_on_dataset:function(){var ac=this;ac.run({target_dataset_id:this.track.original_dataset_id,tool_id:ac.name},null,function(ad){show_modal(ac.name+" is Running",ac.name+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var ad={target_dataset_id:this.track.original_dataset_id,action:"rerun",tool_id:this.name,regions:[{chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}]},ah=this.track,ae=ad.tool_id+ah.tool_region_and_parameters_str(ad.chrom,ad.low,ad.high),ac;if(ah.container===view){var ag=new P(view,view,{name:this.name});var af=ah.container.replace_drawable(ah,ag,false);ag.container_div.insertBefore(ah.view.content_div.children()[af]);ag.add_drawable(ah);ah.container_div.appendTo(ag.content_div);ac=ag}else{ac=ah.container}var ai=new ah.constructor(view,ac,{name:ae,hda_ldda:"hda"});ai.init_for_tool_data();ai.change_mode(ah.mode);ai.set_filters_manager(ah.filters_manager.copy(ai));ai.update_icons();ac.add_drawable(ai);ai.tiles_div.text("Starting job.");this.update_params();this.run(ad,ai,function(aj){ai.set_dataset(new Z.Dataset(aj));ai.tiles_div.text("Running job.");ai.init()})},run:function(ac,ae,af){ac.inputs=this.get_param_values_dict();var ad=new l.ServerStateDeferred({ajax_settings:{url:galaxy_paths.get("tool_url"),data:JSON.stringify(ac),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ag){return ag!=="pending"}});$.when(ad.go()).then(function(ag){if(ag==="no converter"){ae.container_div.addClass("error");ae.content_div.text(J)}else{if(ag.error){ae.container_div.addClass("error");ae.content_div.text(y+ag.message)}else{af(ag)}}})}});var N=function(ad,ac,ae,af){this.name=ad;this.label=ac;this.html=$(ae);this.value=af};q(N.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ae,ad,ag,ah,af,ac){N.call(this,ae,ad,ag,ah);this.min=af;this.max=ac};q(e.prototype,N.prototype,{update_value:function(){N.prototype.update_value.call(this);this.value=parseFloat(this.value)}});var C=function(ac,ad){L.Scaler.call(this,ad);this.filter=ac};C.prototype.gen_val=function(ac){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(ac[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var F=function(ac){this.track=ac.track;this.params=ac.params;this.values={};this.restore_values((ac.saved_values?ac.saved_values:{}));this.onchange=ac.onchange};q(F.prototype,{restore_values:function(ac){var ad=this;$.each(this.params,function(ae,af){if(ac[af.key]!==undefined){ad.values[af.key]=ac[af.key]}else{ad.values[af.key]=af.default_value}})},build_form:function(){var af=this;var ac=$("<div />");var ae;function ad(ak,ag){for(var ao=0;ao<ak.length;ao++){ae=ak[ao];if(ae.hidden){continue}var ai="param_"+ao;var at=af.values[ae.key];var av=$("<div class='form-row' />").appendTo(ag);av.append($("<label />").attr("for",ai).text(ae.label+":"));if(ae.type==="bool"){av.append($('<input type="checkbox" />').attr("id",ai).attr("name",ai).attr("checked",at))}else{if(ae.type==="text"){av.append($('<input type="text"/>').attr("id",ai).val(at).click(function(){$(this).select()}))}else{if(ae.type==="select"){var aq=$("<select />").attr("id",ai);for(var am=0;am<ae.options.length;am++){$("<option/>").text(ae.options[am].label).attr("value",ae.options[am].value).appendTo(aq)}aq.val(at);av.append(aq)}else{if(ae.type==="color"){var au=$("<div/>").appendTo(av),ap=$("<input />").attr("id",ai).attr("name",ai).val(at).css("float","left").appendTo(au).click(function(ax){$(".bs-tooltip").removeClass("in");var aw=$(this).siblings(".bs-tooltip").addClass("in");aw.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(aw).height()/2)+($(this).height()/2)}).show();aw.click(function(ay){ay.stopPropagation()});$(document).bind("click.color-picker",function(){aw.hide();$(document).unbind("click.color-picker")});ax.stopPropagation()}),an=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(au).attr("title","Set new random color").tooltip(),ar=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(au).hide(),aj=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(ar),ah=$("<div class='tooltip-arrow'></div>").appendTo(ar),al=$.farbtastic(aj,{width:100,height:100,callback:ap,color:at});au.append($("<div/>").css("clear","both"));(function(aw){an.click(function(){aw.setColor(l.get_random_color())})})(al)}else{av.append($("<input />").attr("id",ai).attr("name",ai).val(at))}}}}if(ae.help){av.append($("<div class='help'/>").text(ae.help))}}}ad(this.params,ac);return ac},update_from_form:function(ac){var ae=this;var ad=false;$.each(this.params,function(af,ah){if(!ah.hidden){var ai="param_"+af;var ag=ac.find("#"+ai).val();if(ah.type==="float"){ag=parseFloat(ag)}else{if(ah.type==="int"){ag=parseInt(ag)}else{if(ah.type==="bool"){ag=ac.find("#"+ai).is(":checked")}}}if(ag!==ae.values[ah.key]){ae.values[ah.key]=ag;ad=true}}});if(ad){this.onchange();this.track.changed()}}});var b=function(ac,ag,ae,ad,af){this.track=ac;this.region=ag;this.low=ag.get("start");this.high=ag.get("end");this.resolution=ae;this.html_elt=$("<div class='track-tile'/>").append(ad).height($(ad).attr("height"));this.data=af;this.stale=false};b.prototype.predisplay_actions=function(){};var j=function(ac,ah,ae,ad,af,ag){b.call(this,ac,ah,ae,ad,af);this.max_val=ag};q(j.prototype,b.prototype);var O=function(af,an,ag,ae,ai,ap,aj,aq,ad,am){b.call(this,af,an,ag,ae,ai);this.mode=aj;this.all_slotted=ad;this.feature_mapper=am;this.has_icons=false;if(aq){this.has_icons=true;var ak=this;ae=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:D-1,width:ae.width}).prependTo(this.html_elt);var al=new x.GenomeRegion({chrom:af.view.chrom,start:this.low,end:this.high}),ao=ai.length,ah=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+ao+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ac=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+ao+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ah.click(function(){ak.stale=true;af.data_manager.get_more_data(al,af.mode,ak.resolution,{},af.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();af.request_draw(true)}).dblclick(function(ar){ar.stopPropagation()});ac.click(function(){ak.stale=true;af.data_manager.get_more_data(al,af.mode,ak.resolution,{},af.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();af.request_draw(true)}).dblclick(function(ar){ar.stopPropagation()})}};q(O.prototype,b.prototype);O.prototype.predisplay_actions=function(){var ad=this,ac={};if(ad.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(ao){if(!this.hovered){return}var aj=$(this).offset(),an=ao.pageX-aj.left,am=ao.pageY-aj.top,at=ad.feature_mapper.get_feature_data(an,am),ak=(at?at[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!ak||$(this).attr("id")!==ak.toString()){$(this).remove()}});if(at){var af=ac[ak];if(!af){var ak=at[0],ap={name:at[3],start:at[1],end:at[2],strand:at[4]},ai=ad.track.filters_manager.filters,ah;for(var al=0;al<ai.length;al++){ah=ai[al];ap[ah.name]=at[ah.index]}var af=$("<div/>").attr("id",ak).addClass("feature-popup"),au=$("<table/>"),ar,aq,av;for(ar in ap){aq=ap[ar];av=$("<tr/>").appendTo(au);$("<th/>").appendTo(av).text(ar);$("<td/>").attr("align","left").appendTo(av).text(typeof(aq)==="number"?W(aq,2):aq)}af.append($("<div class='feature-popup-inner'>").append(au));ac[ak]=af}af.appendTo($(this).parents(".track-content").children(".overlay"));var ag=an+parseInt(ad.html_elt.css("left"))-af.width()/2,ae=am+parseInt(ad.html_elt.css("top"))+7;af.css("left",ag+"px").css("top",ae+"px")}else{if(!ao.isPropagationStopped()){ao.stopPropagation();$(this).siblings().each(function(){$(this).trigger(ao)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var g=function(ad,ac,ae){q(ae,{drag_handle_class:"draghandle"});r.call(this,ad,ac,ae);this.dataset=new Z.Dataset({id:ae.dataset_id,hda_ldda:ae.hda_ldda});this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ae?ae.data_query_wait:K);this.data_manager=("data_manager" in ae?ae.data_manager:new x.GenomeDataManager({dataset:this.dataset,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=0;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 ae)||ae.resize){this.add_resize_handle()}}};q(g.prototype,r.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},r.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(ac){ac.view.set_overview(ac)}},r.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters()}else{ac.filters_manager.init_filters()}ac.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ac){ac.dynamic_tool_div.toggle();if(ac.dynamic_tool_div.is(":visible")){ac.set_name(ac.name+ac.tool_region_and_parameters_str())}else{ac.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ac){var af='<strong>Tool</strong>: <%= track.tool.name %><br/><strong>Dataset</strong>: <%= track.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>',ae=ab.template(af,{track:ac});var ah=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ad=function(){var aj=$('select[name="regions"] option:selected').val(),al,ai=new x.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new x.GenomeRegion({from_str:$(am).children(".position").text()})});if(aj==="cur"){al=[ai]}else{if(aj==="bookmarks"){al=ak}else{al=[ai].concat(ak)}}hide_modal();window.location.href=galaxy_paths.get("sweepster_url")+"?"+$.param({dataset_id:ac.dataset_id,hda_ldda:ac.hda_ldda,regions:JSON.stringify(new Backbone.Collection(al).toJSON())})},ag=function(ai){if((ai.keyCode||ai.which)===27){ah()}else{if((ai.keyCode||ai.which)===13){ad()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",ae,{No:ah,Yes:ad})}},r.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset_id&&r.prototype.can_draw.call(this)){return true}return false},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id).css("position","relative")},build_header_div:function(){var ac=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ac)}this.name_div=$("<div/>").addClass("track-name").appendTo(ac).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ac},on_resize:function(){},add_resize_handle:function(){var ac=this;var af=false;var ae=false;var ad=$("<div class='track-resize'>");$(ac.container_div).hover(function(){if(ac.content_visible){af=true;ad.show()}},function(){af=false;if(!ae){ad.hide()}});ad.hide().bind("dragstart",function(ag,ah){ae=true;ah.original_height=$(ac.content_div).height()}).bind("drag",function(ah,ai){var ag=Math.min(Math.max(ai.original_height+ai.deltaY,ac.min_height_px),ac.max_height_px);$(ac.tiles_div).css("height",ag);ac.visible_height_px=(ac.max_height_px===ag?0:ag);ac.on_resize()}).bind("dragend",function(ag,ah){ac.tile_cache.clear();ae=false;if(!af){ad.hide()}ac.config.values.height=ac.visible_height_px;ac.changed()}).appendTo(ac.container_div)},set_display_modes:function(af,ai){this.display_modes=af;this.mode=(ai?ai:(this.config&&this.config.values.mode?this.config.values.mode:this.display_modes[0]));this.action_icons.mode_icon.attr("title","Set display mode (now: "+this.mode+")");var ad=this,ag={};for(var ae=0,ac=ad.display_modes.length;ae<ac;ae++){var ah=ad.display_modes[ae];ag[ah]=function(aj){return function(){ad.change_mode(aj);ad.icons_div.show();ad.container_div.mouseleave(function(){ad.icons_div.hide()})}}(ah)}make_popupmenu(this.action_icons.mode_icon,ag)},build_action_icons:function(){r.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 X){return"LabelTrack"}else{if(this instanceof B){return"ReferenceTrack"}else{if(this instanceof h){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof R){return"VcfTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.content_div.css("height","auto");ad.tiles_div.children().remove();ad.container_div.removeClass("nodata error pending");if(!ad.dataset_id){return}var ac=$.Deferred(),ae={hda_ldda:ad.hda_ldda,data_type:this.dataset_check_type,chrom:ad.view.chrom};$.getJSON(this.dataset.url(),ae,function(af){if(!af||af==="error"||af.kind==="error"){ad.container_div.addClass("error");ad.tiles_div.text(o);if(af.message){var ag=$(" <a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+af.message+"</pre>",{Close:hide_modal})});ad.tiles_div.append(ag)}}else{if(af==="no converter"){ad.container_div.addClass("error");ad.tiles_div.text(J)}else{if(af==="no data"||(af.data!==undefined&&(af.data===null||af.data.length===0))){ad.container_div.addClass("nodata");ad.tiles_div.text(E)}else{if(af==="pending"){ad.container_div.addClass("pending");ad.tiles_div.html(v);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(af==="data"||af.status==="data"){if(af.valid_chroms){ad.valid_chroms=af.valid_chroms;ad.update_icons()}ad.tiles_div.text(U);if(ad.view.chrom){ad.tiles_div.text("");ad.tiles_div.css("height",ad.visible_height_px+"px");ad.enabled=true;$.when(ad.predraw_init()).done(function(){ac.resolve();ad.container_div.removeClass("nodata error pending");ad.request_draw()})}else{ac.resolve()}}}}}}});this.update_icons();return ac},predraw_init:function(){},get_drawables:function(){return this}});var M=function(ae,ad,af){g.call(this,ae,ad,af);var ac=this;m(ac.container_div,ac.drag_handle_class,".group",ac);this.filters_manager=new i.FiltersManager(this,("filters" in af?af.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=("tool" in af&&af.tool?new s(this,af.tool,af.tool_state):null);this.tile_cache=new x.Cache(Q);if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){this.dynamic_tool_div=this.tool.parent_div;this.header_div.after(this.dynamic_tool_div)}}this.tiles_div=$("<div/>").addClass("tiles").appendTo(this.content_div);this.overlay_div=$("<div/>").addClass("overlay").appendTo(this.content_div);if(af.mode){this.change_mode(af.mode)}};q(M.prototype,r.prototype,g.prototype,{action_icons_def:g.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(ac){$(".bs-tooltip").remove();ac.slotters[ac.view.resolution_px_b].max_rows*=2;ac.request_draw(true)},hide:true}]),copy:function(ac){var ad=this.to_dict();q(ad,{data_manager:this.data_manager});var ae=new this.constructor(this.view,ac,ad);ae.change_mode(this.mode);ae.enabled=this.enabled;return ae},set_filters_manager:function(ac){this.filters_manager=ac;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,hda_ldda:this.hda_ldda,dataset_id:this.dataset_id,prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.values.mode=ad;ac.tile_cache.clear();ac.request_draw();this.action_icons.mode_icon.attr("title","Set display mode (now: "+ac.mode+")");return ac},update_icons:function(){var ac=this;if(ac.filters_available){ac.action_icons.filters_icon.show()}else{ac.action_icons.filters_icon.hide()}if(ac.tool){ac.action_icons.tools_icon.show();ac.action_icons.param_space_viz_icon.show()}else{ac.action_icons.tools_icon.hide();ac.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ad,ae,ac){return ad+"_"+ae+"_"+ac},request_draw:function(ad,ac){this.view.request_redraw(false,ad,ac,this)},before_draw:function(){},_draw:function(ad,an){if(!this.can_draw()){return}var al=this.view.low,ah=this.view.high,aj=ah-al,ae=this.view.container.width(),ap=this.view.resolution_px_b,ag=this.view.resolution_b_px;if(this.is_overview){al=this.view.max_low;ah=this.view.max_high;ag=(view.max_high-view.max_low)/ae;ap=1/ag}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(al/(ag*S)),ak=true,ao=[],ai=function(aq){return(aq&&"track" in aq)};while((ac*S*ag)<ah){var am=this.draw_helper(ad,ae,ac,ag,this.tiles_div,ap);if(ai(am)){ao.push(am)}else{ak=false}ac+=1}if(!an){this.tiles_div.children(".remove").removeClass("remove").remove()}var af=this;if(ak){this.tiles_div.children(".remove").remove();af.postdraw_actions(ao,ae,ap,an)}},postdraw_actions:function(ae,af,ah,ac){var ag=false;for(var ad=0;ad<ae.length;ad++){if(ae[ad].has_icons){ag=true;break}}if(ag){for(var ad=0;ad<ae.length;ad++){tile=ae[ad];if(!tile.has_icons){tile.html_elt.css("padding-top",D)}}}},draw_helper:function(ac,ao,au,ar,ah,ai,ap){var an=this,ax=this._gen_tile_cache_key(ao,ai,au),af=this._get_tile_bounds(au,ar);if(!ap){ap={}}var aw=(ac?undefined:an.tile_cache.get_elt(ax));if(aw){an.show_tile(aw,ah,ai);return aw}var al=true;var at=an.data_manager.get_data(af,an.mode,ar,an.data_url_extra_params);if(V(at)){al=false}var aj;if(view.reference_track&&ai>view.canvas_manager.char_width_px){aj=view.reference_track.data_manager.get_data(af,an.mode,ar,view.reference_track.data_url_extra_params);if(V(aj)){al=false}}if(al){q(at,ap.more_tile_data);var ak=an.mode;if(ak==="Auto"){ak=an.get_mode(at);an.update_auto_mode(ak)}var ae=an.view.canvas_manager.new_canvas(),av=af.get("start"),ad=af.get("end"),ao=Math.ceil((ad-av)*ai)+an.left_offset,am=an.get_canvas_height(at,ak,ai,ao);ae.width=ao;ae.height=am;var aq=ae.getContext("2d");aq.translate(this.left_offset,0);var aw=an.draw_tile(at,aq,ak,ar,af,ai,aj);if(aw!==undefined){an.tile_cache.set_elt(ax,aw);an.show_tile(aw,ah,ai)}return aw}var ag=$.Deferred();$.when(at,aj).then(function(){view.request_redraw(false,false,false,an);ag.resolve()});return ag},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},draw_tile:function(ac,ad,ah,af,ag,ai,ae){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ae,ah,ai){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var ag=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ai;if(this.left_offset){ag-=this.left_offset}ac.css({position:"absolute",top:0,left:ag});if(ac.hasClass("remove")){ac.removeClass("remove")}else{ah.append(ac)}ae.html_elt.height("auto");this.max_height_px=Math.max(this.max_height_px,ae.html_elt.height());ae.html_elt.parent().children().css("height",this.max_height_px+"px");var af=this.max_height_px;if(this.visible_height_px!==0){af=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",af+"px")},_get_tile_bounds:function(ac,ad){var af=Math.floor(ac*S*ad),ag=Math.ceil(S*ad),ae=(af+ag<=this.view.max_high?af+ag:this.view.max_high);return new x.GenomeRegion({chrom:this.view.chrom,start:af,end:ae})},tool_region_and_parameters_str:function(ae,ac,af){var ad=this,ag=(ae!==undefined&&ac!==undefined&&af!==undefined?ae+":"+ac+"-"+af:"all");return" - region=["+ag+"], parameters=["+ad.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(ac,ad){return true},can_subset:function(ac){return false},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state";this.normal_postdraw_actions=this.postdraw_actions;this.postdraw_actions=function(ae,af,ah,ac){var ad=this;ad.normal_postdraw_actions(ae,af,ah,ac);ad.dataset_check_type="converted_datasets_state";ad.data_query_wait=K;var ag=new l.ServerStateDeferred({url:ad.dataset_state_url,url_params:{dataset_id:ad.dataset_id,hda_ldda:ad.hda_ldda},interval:ad.data_query_wait,success_fn:function(ai){return ai!=="pending"}});$.when(ag.go()).then(function(){ad.data_manager.set("data_type","data")});ad.postdraw_actions=ad.normal_postdraw_actions}}});var X=function(ad,ac){var ae={resize:false};g.call(this,ad,ac,ae);this.container_div.addClass("label-track")};q(X.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},_draw:function(){var ae=this.view,af=ae.high-ae.low,ai=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/ai)*ai,ag=this.view.container.width(),ad=$("<div style='position: relative; height: 1.3em;'></div>");while(ac<ae.high){var ah=(ac-ae.low)/af*ag;ad.append($("<div class='label'>"+commatize(ac)+"</div>").css({position:"absolute",left:ah-1}));ac+=ai}this.content_div.children(":first").remove();this.content_div.append(ad)}});var f=function(ad,ac,ag){M.call(this,ad,ac,ag);this.drawables=[];this.left_offset=0;if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=p(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}if(this.drawables.length!==0){this.set_display_modes(this.drawables[0].display_modes,this.drawables[0].mode)}this.update_icons();this.obj_type="CompositeTrack"};q(f.prototype,M.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.show_group()}}].concat(M.prototype.action_icons_def),to_dict:z.prototype.to_dict,add_drawable:z.prototype.add_drawable,unpack_drawables:z.prototype.unpack_drawables,change_mode:function(ac){M.prototype.change_mode.call(this,ac);for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].change_mode(ac)}},init:function(){var ae=[];for(var ad=0;ad<this.drawables.length;ad++){ae.push(this.drawables[ad].init())}var ac=this;$.when.apply($,ae).then(function(){ac.enabled=true;ac.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:r.prototype.can_draw,draw_helper:function(ad,at,az,aw,ak,am,au){var ar=this,aD=this._gen_tile_cache_key(at,am,az),ah=this._get_tile_bounds(az,aw);if(!au){au={}}var aC=(ad?undefined:ar.tile_cache.get_elt(aD));if(aC){ar.show_tile(aC,ak,am);return aC}var al=[],ar,ap=true,ax,an;for(var ay=0;ay<this.drawables.length;ay++){ar=this.drawables[ay];ax=ar.data_manager.get_data(ah,ar.mode,aw,ar.data_url_extra_params);if(V(ax)){ap=false}al.push(ax);an=null;if(view.reference_track&&am>view.canvas_manager.char_width_px){an=view.reference_track.data_manager.get_data(ah,ar.mode,aw,view.reference_track.data_url_extra_params);if(V(an)){ap=false}}al.push(an)}if(ap){q(ax,au.more_tile_data);this.tile_predraw_init();var ag=ar.view.canvas_manager.new_canvas(),ai=ar._get_tile_bounds(az,aw),aA=ah.get("start"),ae=ah.get("end"),aB=0,at=Math.ceil((ae-aA)*am)+this.left_offset,aq=0,af=[],ay;var ac=0;for(ay=0;ay<this.drawables.length;ay++,aB+=2){ar=this.drawables[ay];ax=al[aB];var ao=ar.mode;if(ao==="Auto"){ao=ar.get_mode(ax);ar.update_auto_mode(ao)}af.push(ao);ac=ar.get_canvas_height(ax,ao,am,at);if(ac>aq){aq=ac}}ag.width=at;ag.height=(au.height?au.height:aq);aB=0;var av=ag.getContext("2d");av.translate(this.left_offset,0);av.globalAlpha=0.5;av.globalCompositeOperation="source-over";for(ay=0;ay<this.drawables.length;ay++,aB+=2){ar=this.drawables[ay];ax=al[aB];an=al[aB+1];aC=ar.draw_tile(ax,av,af[ay],aw,ah,am,an)}this.tile_cache.set_elt(aD,aC);this.show_tile(aC,ak,am);return aC}var aj=$.Deferred(),ar=this;$.when.apply($,al).then(function(){view.request_redraw(false,false,false,ar);aj.resolve()});return aj},show_group:function(){var af=new P(this.view,this.container,{name:this.name}),ac;for(var ae=0;ae<this.drawables.length;ae++){ac=this.drawables[ae];ac.update_icons();af.add_drawable(ac);ac.container=af;af.content_div.append(ac.container_div)}var ad=this.container.replace_drawable(this,af,true);af.request_draw()},tile_predraw_init:function(){var af=Number.MAX_VALUE,ac=-af,ad;for(var ae=0;ae<this.drawables.length;ae++){ad=this.drawables[ae];if(ad instanceof h){if(ad.prefs.min_value<af){af=ad.prefs.min_value}if(ad.prefs.max_value>ac){ac=ad.prefs.max_value}}}for(var ae=0;ae<this.drawables.length;ae++){ad=this.drawables[ae];ad.prefs.min_value=af;ad.prefs.max_value=ac}},postdraw_actions:function(ae,ah,aj,ad){M.prototype.postdraw_actions.call(this,ae,ah,aj,ad);var ag=-1;for(var af=0;af<ae.length;af++){var ac=ae[af].html_elt.find("canvas").height();if(ac>ag){ag=ac}}for(var af=0;af<ae.length;af++){var ai=ae[af];if(ai.html_elt.find("canvas").height()!==ag){this.draw_helper(true,ah,ai.index,ai.resolution,ai.html_elt.parent(),aj,{height:ag});ai.html_elt.remove()}}}});var B=function(ac){M.call(this,ac,{content_div:ac.top_labeltrack},{resize:false});ac.reference_track=this;this.left_offset=200;this.visible_height_px=12;this.container_div.addClass("reference-track");this.content_div.css("background","none");this.content_div.css("min-height","0px");this.content_div.css("border","none");this.data_url=reference_url+"/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new x.ReferenceTrackDataManager({data_url:this.data_url});this.hide_contents()};q(B.prototype,r.prototype,M.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},can_draw:r.prototype.can_draw,draw_helper:function(ag,ae,ac,ad,ah,ai,af){if(ai>this.view.canvas_manager.char_width_px){return M.prototype.draw_helper.call(this,ag,ae,ac,ad,ah,ai,af)}else{this.hide_contents();return null}},draw_tile:function(ak,al,ag,af,ai,am){var ae=this;if(am>this.view.canvas_manager.char_width_px){if(ak.data===null){this.hide_contents();return}var ad=al.canvas;al.font=al.canvas.manager.default_font;al.textAlign="center";ak=ak.data;for(var ah=0,aj=ak.length;ah<aj;ah++){var ac=Math.floor(ah*am);al.fillText(ak[ah],ac,10)}this.show_contents();return new b(ae,ai,af,ad,ak)}this.hide_contents()}});var h=function(ae,ad,af){var ac=this;this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";M.call(this,ae,ad,af);this.hda_ldda=af.hda_ldda;this.dataset_id=af.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Color",type:"color",default_value:l.get_random_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:32,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.set_min_value(ac.prefs.min_value);ac.set_max_value(ac.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};q(h.prototype,r.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ac){this.prefs.min_value=ac;$("#linetrack_"+this.dataset_id+"_minval").text(this.prefs.min_value);this.tile_cache.clear();this.request_draw()},set_max_value:function(ac){this.prefs.max_value=ac;$("#linetrack_"+this.dataset_id+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.request_draw()},predraw_init:function(){var ac=this;ac.vertical_range=undefined;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.hda_ldda},function(ad){ac.container_div.addClass("line-track");var ag=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=ag.min,ai=ag.max;ae=Math.floor(Math.min(0,Math.max(ae,ag.mean-2*ag.sd)));ai=Math.ceil(Math.max(0,Math.min(ai,ag.mean+2*ag.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ai;$("#track_"+ac.dataset_id+"_minval").val(ac.prefs.min_value);$("#track_"+ac.dataset_id+"_maxval").val(ac.prefs.max_value)}ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.total_frequency=ag.total_frequency;ac.container_div.find(".yaxislabel").remove();var ah=$("<div/>").text(W(ac.prefs.min_value,3)).make_text_editable({num_cols:6,on_finish:function(aj){$(".bs-tooltip").remove();var aj=parseFloat(aj);if(!isNaN(aj)){ac.set_min_value(aj)}},help_text:"Set min value"}).addClass("yaxislabel bottom").attr("id","linetrack_"+ac.dataset_id+"_minval").prependTo(ac.container_div),af=$("<div/>").text(W(ac.prefs.max_value,3)).make_text_editable({num_cols:6,on_finish:function(aj){$(".bs-tooltip").remove();var aj=parseFloat(aj);if(!isNaN(aj)){ac.set_max_value(aj)}},help_text:"Set max value"}).addClass("yaxislabel top").attr("id","linetrack_"+ac.dataset_id+"_maxval").prependTo(ac.container_div)})},draw_tile:function(al,aj,ae,ad,ag,ak){var ac=aj.canvas,af=ag.get("start"),ai=ag.get("end"),ah=new L.LinePainter(al.data,af,ai,this.prefs,ae);ah.draw(aj,ac.width,ac.height,ak);return new b(this,ag,ad,ac,al.data)},can_subset:function(ac){return false}});var t=function(ae,ad,af){var ac=this;this.display_modes=["Heatmap"];this.mode="Heatmap";M.call(this,ae,ad,af);this.hda_ldda=af.hda_ldda;this.dataset_id=af.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"pos_color",label:"Positive Color",type:"color",default_value:"4169E1"},{key:"negative_color",label:"Negative Color",type:"color",default_value:"FF8C00"},{key:"min_value",label:"Min Value",type:"float",default_value:0},{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}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.set_min_value(ac.prefs.min_value);ac.set_max_value(ac.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};q(t.prototype,r.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ac){this.prefs.min_value=ac;this.tile_cache.clear();this.request_draw()},set_max_value:function(ac){this.prefs.max_value=ac;this.tile_cache.clear();this.request_draw()},draw_tile:function(am,ak,ah,af,ad,al){var ae=ak.canvas,ac=this._get_tile_bounds(ad,af),ag=ac[0],aj=ac[1],ai=new L.DiagonalHeatmapPainter(am.data,ag,aj,this.prefs,ah);ai.draw(ak,ae.width,ae.height,al);return new b(this,ad,af,ae,am.data)}});var c=function(af,ae,ah){var ad=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];M.call(this,af,ae,ah);var ag=l.get_random_color(),ac=l.get_random_color([ag,"#ffffff"]);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:ag},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ac},{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:"histogram_max",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:this.visible_height_px,hidden:true}],saved_values:ah.prefs,onchange:function(){ad.set_name(ad.prefs.name);ad.tile_cache.clear();ad.set_painter_from_config();ad.request_draw()}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");this.hda_ldda=ah.hda_ldda;this.dataset_id=ah.dataset_id;this.original_dataset_id=ah.dataset_id;this.show_labels_scale=0.001;this.showing_details=false;this.summary_draw_height=30;this.slotters={};this.start_end_dct={};this.left_offset=200;this.set_painter_from_config()};q(c.prototype,r.prototype,M.prototype,{set_dataset:function(ac){this.dataset_id=ac.get("id");this.hda_ldda=ac.get("hda_ldda");this.dataset=ac;this.data_manager.set("dataset",ac)},set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},before_draw:function(){this.max_height_px=0},postdraw_actions:function(ar,am,ah,ag){M.prototype.postdraw_actions.call(this,ar,ag);var al=this,ao;if(al.mode==="Coverage"){var ad=-1;for(ao=0;ao<ar.length;ao++){var an=ar[ao].max_val;if(an>ad){ad=an}}for(ao=0;ao<ar.length;ao++){var au=ar[ao];if(au.max_val!==ad){au.html_elt.remove();al.draw_helper(true,am,au.index,au.resolution,au.html_elt.parent(),ah,{more_tile_data:{max:ad}})}}}if(al.filters_manager){var ai=al.filters_manager.filters;for(var aq=0;aq<ai.length;aq++){ai[aq].update_ui_elt()}var at=false,ac,aj;for(ao=0;ao<ar.length;ao++){if(ar[ao].data.length){ac=ar[ao].data[0];for(var aq=0;aq<ai.length;aq++){aj=ai[aq];if(aj.applies_to(ac)&&aj.min!==aj.max){at=true;break}}}}if(al.filters_available!==at){al.filters_available=at;if(!al.filters_available){al.filters_manager.hide()}al.update_icons()}}this.container_div.find(".yaxislabel").remove();var af=ar[0];if(af instanceof j){var ak=(this.prefs.histogram_max?this.prefs.histogram_max:af.max_val),ae=$("<div/>").text(ak).make_text_editable({num_cols:12,on_finish:function(av){$(".bs-tooltip").remove();var av=parseFloat(av);al.prefs.histogram_max=(!isNaN(av)?av:null);al.tile_cache.clear();al.request_draw()},help_text:"Set max value; leave blank to use default"}).addClass("yaxislabel top").css("color",this.prefs.label_color);this.container_div.prepend(ae)}if(af instanceof O){var ap=true;for(ao=0;ao<ar.length;ao++){if(!ar[ao].all_slotted){ap=false;break}}if(!ap){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(ac){var ac;if(this.mode==="Auto"){if(ac==="no_detail"){ac="feature spans"}else{if(ac==="summary_tree"){ac="coverage histogram"}}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ac+")")}},incremental_slots:function(ag,ac,af){var ad=this.view.canvas_manager.dummy_context,ae=this.slotters[ag];if(!ae||(ae.mode!==af)){ae=new (u.FeatureSlotter)(ag,af,A,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){if(ac.dataset_type==="summary_tree"){mode="summary_tree"}else{if(ac.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>I){mode="Squish"}else{mode="Pack"}}}return mode},get_canvas_height:function(ac,ag,ah,ad){if(ag==="summary_tree"||ag==="Coverage"){return this.summary_draw_height}else{var af=this.incremental_slots(ah,ac.data,ag);var ae=new (this.painter)(null,null,null,this.prefs,ag);return Math.max(aa,ae.get_required_height(af,ad))}},draw_tile:function(am,aq,ao,ar,af,aj,ae){var ap=this,ad=aq.canvas,ay=af.get("start"),ac=af.get("end"),ag=this.left_offset;if(ao==="summary_tree"||ao==="Coverage"){var aA=new L.SummaryTreePainter(am,ay,ac,this.prefs);aA.draw(aq,ad.width,ad.height,aj);return new j(ap,af,ar,ad,am.data,am.max)}var ai=[],an=this.slotters[aj].slots;all_slotted=true;if(am.data){var ak=this.filters_manager.filters;for(var at=0,av=am.data.length;at<av;at++){var ah=am.data[at];var au=false;var al;for(var ax=0,aC=ak.length;ax<aC;ax++){al=ak[ax];al.update_attrs(ah);if(!al.keep(ah)){au=true;break}}if(!au){ai.push(ah);if(!(ah[0] in an)){all_slotted=false}}}}var aB=(this.filters_manager.alpha_filter?new C(this.filters_manager.alpha_filter):null);var az=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null);var aA=new (this.painter)(ai,ay,ac,this.prefs,ao,aB,az,ae);var aw=null;aq.fillStyle=this.prefs.block_color;aq.font=aq.canvas.manager.default_font;aq.textAlign="right";if(am.data){aw=aA.draw(aq,ad.width,ad.height,aj,an);aw.translation=-ag}return new O(ap,af,ar,ad,am.data,aj,ao,am.message,all_slotted,aw)},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="summary_tree"}else{if(ac.extra_info==="no_detail"||ac.dataset_type==="summary_tree"){return false}else{return true}}}},can_subset:function(ac){if(ac.dataset_type==="summary_tree"||ac.message||ac.extra_info==="no_detail"){return false}return true}});var R=function(ad,ac,ae){c.call(this,ad,ac,ae);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:l.get_random_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_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ae.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter};q(R.prototype,r.prototype,M.prototype,c.prototype);var T=function(ae,ad,ag){c.call(this,ae,ad,ag);var af=l.get_random_color(),ac=l.get_random_color([af,"#ffffff"]);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block and sense strand color",type:"color",default_value:af},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ac},{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:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"Clear value to set automatically"},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter;this.update_icons()};q(T.prototype,r.prototype,M.prototype,c.prototype);var d={LineTrack:h,FeatureTrack:c,VcfTrack:R,ReadTrack:T,CompositeTrack:f,DrawableGroup:P};var p=function(ae,ad,ac){if("copy" in ae){return ae.copy(ac)}else{var af=ae.obj_type;if(!af){af=ae.track_type}return new d[af](ad,ac,ae)}};return{View:Y,DrawableGroup:P,LineTrack:h,FeatureTrack:c,DiagonalHeatmapTrack:t,ReadTrack:T,VcfTrack:R,CompositeTrack:f,object_from_template:p}});
\ No newline at end of file
+define(["libs/underscore","viz/visualization","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters","mvc/data","viz/trackster/filters"],function(ab,x,l,u,L,Z,i){var q=ab.extend;var V=function(ac){return("isResolved" in ac)};var n={};var k=function(ac,ad){n[ac.attr("id")]=ad};var m=function(ac,ae,ag,af){ag=".group";var ad={};n[ac.attr("id")]=af;ac.bind("drag",{handle:"."+ae,relative:true},function(ao,ap){var an=$(this),at=$(this).parent(),ak=at.children(),am=n[$(this).attr("id")],aj,ai,aq,ah,al;ai=$(this).parents(ag);if(ai.length!==0){aq=ai.position().top;ah=aq+ai.outerHeight();if(ap.offsetY<aq){$(this).insertBefore(ai);var ar=n[ai.attr("id")];ar.remove_drawable(am);ar.container.add_drawable_before(am,ar);return}else{if(ap.offsetY>ah){$(this).insertAfter(ai);var ar=n[ai.attr("id")];ar.remove_drawable(am);ar.container.add_drawable(am);return}}}ai=null;for(al=0;al<ak.length;al++){aj=$(ak.get(al));aq=aj.position().top;ah=aq+aj.outerHeight();if(aj.is(ag)&&this!==aj.get(0)&&ap.offsetY>=aq&&ap.offsetY<=ah){if(ap.offsetY-aq<ah-ap.offsetY){aj.find(".content-div").prepend(this)}else{aj.find(".content-div").append(this)}if(am.container){am.container.remove_drawable(am)}n[aj.attr("id")].add_drawable(am);return}}for(al=0;al<ak.length;al++){aj=$(ak.get(al));if(ap.offsetY<aj.position().top&&!(aj.hasClass("reference-track")||aj.hasClass("intro"))){break}}if(al===ak.length){if(this!==ak.get(al-1)){at.append(this);n[at.attr("id")].move_drawable(am,al)}}else{if(this!==ak.get(al)){$(this).insertBefore(ak.get(al));n[at.attr("id")].move_drawable(am,(ap.deltaY>0?al-1:al))}}}).bind("dragstart",function(){ad["border-top"]=ac.css("border-top");ad["border-bottom"]=ac.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(ad)})};exports.moveable=m;var aa=16,G=9,D=20,A=100,I=12000,S=400,K=5000,w=100,o="There was an error in indexing this dataset. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",v="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",y="Tool cannot be rerun: ",a="Loading data...",U="Ready for display",Q=10,H=20;function W(ad,ac){if(!ac){ac=0}var ae=Math.pow(10,ac);return Math.round(ad*ae)/ae}var r=function(ad,ac,af){if(!r.id_counter){r.id_counter=0}this.id=r.id_counter++;this.name=af.name;this.view=ad;this.container=ac;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:af.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=af.drag_handle_class;this.is_overview=false;this.action_icons={};this.content_visible=true;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/>").css("float","left").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(ag){ag.stopPropagation()});var ae=this;this.container_div.hover(function(){ae.icons_div.show()},function(){ae.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};r.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ac){if(ac.content_visible){ac.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ac.hide_contents();ac.content_visible=false}else{ac.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ac.content_visible=true;ac.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(ad){var af=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ac=function(){ad.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},ae=function(ag){if((ag.keyCode||ag.which)===27){af()}else{if((ag.keyCode||ag.which)===13){ac()}}};$(window).bind("keypress.check_enter_esc",ae);show_modal("Configure",ad.config.build_form(),{Cancel:af,OK:ac})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.remove()}}];q(r.prototype,{init:function(){},changed:function(){this.view.changed()},can_draw:function(){if(this.enabled&&this.content_visible){return true}return false},request_draw:function(){},_draw:function(){},to_dict:function(){},set_name:function(ac){this.old_name=this.name;this.name=ac;this.name_div.text(this.name)},revert_name:function(){if(this.old_name){this.name=this.old_name;this.name_div.text(this.name)}},remove:function(){this.changed();this.container.remove_drawable(this);var ac=this.view;this.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ad,ai,ah,ag,ac,af){var ae=this;this.action_icons[ad]=$("<a/>").attr("href","javascript:void(0);").attr("title",ai).addClass("icon-button").addClass(ah).tooltip().click(function(){ag(ae)}).appendTo(this.icons_div);if(af){this.action_icons[ad].hide()}},build_action_icons:function(ac){var ae;for(var ad=0;ad<ac.length;ad++){ae=ac[ad];this.add_action_icon(ae.name,ae.title,ae.css_class,ae.on_click_fn,ae.prepend,ae.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var z=function(ad,ac,ae){r.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};q(z.prototype,r.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=p(ae[ac],this.view,this);this.add_drawable(ad)}},init:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].init()}},_draw:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac]._draw()}},to_dict:function(){var ad=[];for(var ac=0;ac<this.drawables.length;ac++){ad.push(this.drawables[ac].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:ad}},add_drawable:function(ac){this.drawables.push(ac);ac.container=this;this.changed()},add_drawable_before:function(ae,ac){this.changed();var ad=this.drawables.indexOf(ac);if(ad!==-1){this.drawables.splice(ad,0,ae);return true}return false},replace_drawable:function(ae,ac,ad){var af=this.drawables.indexOf(ae);if(af!==-1){this.drawables[af]=ac;if(ad){ae.container_div.replaceWith(ac.container_div)}this.changed()}return af},remove_drawable:function(ad){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);ad.container=null;this.changed();return true}return false},move_drawable:function(ad,ae){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);this.drawables.splice(ae,0,ad);this.changed();return true}return false},get_drawables:function(){return this.drawables}});var P=function(ad,ac,af){q(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});z.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);m(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new i.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in af){this.unpack_drawables(af.drawables)}if("filters" in af){var ae=this.filters_manager;this.filters_manager=new i.FiltersManager(this,af.filters);ae.parent_div.replaceWith(this.filters_manager.parent_div);if(af.filters.visible){this.setup_multitrack_filtering()}}};q(P.prototype,r.prototype,z.prototype,{action_icons_def:[r.prototype.action_icons_def[0],r.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters();ac._restore_filter_managers()}else{ac.setup_multitrack_filtering();ac.request_draw(true)}ac.filters_manager.toggle()}},r.prototype.action_icons_def[2]],build_container_div:function(){var ac=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ac)}return ac},build_header_div:function(){var ac=$("<div/>").addClass("track-header");ac.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(ac);return ac},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ae=this.drawables.length;if(ae===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ae===1){if(this.drawables[0] instanceof f){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var al,ak,ai,ao=true,ag=this.drawables[0].get_type(),ac=0;for(al=0;al<ae;al++){ai=this.drawables[al];if(ai.get_type()!==ag){can_composite=false;break}if(ai instanceof c){ac++}}if(ao||ac===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(ac>1&&ac===this.drawables.length){var ap={},ad;ai=this.drawables[0];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];ap[ad.name]=[ad]}for(al=1;al<this.drawables.length;al++){ai=this.drawables[al];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];if(ad.name in ap){ap[ad.name].push(ad)}}}this.filters_manager.remove_all();var af,ah,aj,am;for(var an in ap){af=ap[an];if(af.length===ac){ah=new i.NumberFilter({name:af[0].name,index:af[0].index});this.filters_manager.add_filter(ah)}}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 ac=0;ac<this.drawables.length;ac++){this.drawables[ac].filters_manager=this.saved_filters_managers[ac]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ac=0;ac<this.drawables.length;ac++){drawable=this.drawables[ac];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ag=[];for(var ad=0;ad<this.drawables.length;ad++){ag.push(this.drawables[ad].name)}var ae="Composite Track of "+this.drawables.length+" tracks ("+ag.join(", ")+")";var af=new f(this.view,this.view,{name:ae,drawables:this.drawables});var ac=this.container.replace_drawable(this,af,true);af.request_draw()},add_drawable:function(ac){z.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){z.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=q(z.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ac},request_draw:function(ac,ae){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].request_draw(ac,ae)}}});var Y=function(ac){q(ac,{obj_type:"View"});z.call(this,"View",ac.container,ac);this.chrom=null;this.vis_id=ac.vis_id;this.dbkey=ac.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.init();this.canvas_manager=new x.CanvasManager(this.container.get(0).ownerDocument);this.reset()};ab.extend(Y.prototype,Backbone.Events);q(Y.prototype,z.prototype,{init:function(){this.requested_redraw=false;var ae=this.container,ac=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ae);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ae);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ae);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;k(this.viewport_container,ac);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(){x.select_datasets(select_datasets_url,add_track_async_url,ac.dbkey,function(ag){ab.each(ag,function(ah){ac.add_drawable(p(ah,ac,ac))})})});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("href","javascript:void(0);").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"}).css("width","15em").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var ad=function(ag){if(ag.type==="focusout"||(ag.keyCode||ag.which)===13||(ag.keyCode||ag.which)===27){if((ag.keyCode||ag.which)!==27){ac.go_to($(this).val())}$(this).hide();$(this).val("");ac.location_span.show();ac.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ad).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").attr("original-title","Click to change location").tooltip({placement:"bottom"}).appendTo(this.nav_controls);this.location_span.click(function(){ac.location_span.hide();ac.chrom_select.hide();ac.nav_input.val(ac.chrom+":"+ac.low+"-"+ac.high);ac.nav_input.css("display","inline-block");ac.nav_input.select();ac.nav_input.focus();ac.nav_input.autocomplete({source:function(ai,ag){var aj=[],ah=$.map(ac.get_drawables(),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(){ac.zoom_out();ac.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ac.zoom_in();ac.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ac.change_chrom(ac.chrom_select.val())});this.browser_content_div.click(function(ag){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ag){ac.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/ac.viewport_container.width()*(ac.max_high-ac.max_low));ac.move_delta(-ah)});this.overview_close.click(function(){ac.reset_overview()});this.viewport_container.bind("draginit",function(ag,ah){if(ag.clientX>ac.viewport_container.width()-16){return false}}).bind("dragstart",function(ag,ah){ah.original_low=ac.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/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}).bind("mousewheel",function(ai,ak,ah,ag){if(ah){ah*=50;var aj=Math.round(-ah/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}});this.top_labeltrack.bind("dragstart",function(ag,ah){return $("<div />").css({height:ac.browser_content_div.height()+ac.top_labeltrack.height()+ac.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(ak,al){$(al.proxy).css({left:Math.min(ak.pageX,al.startX)-ac.container.offset().left,width:Math.abs(ak.pageX-al.startX)});var ah=Math.min(ak.pageX,al.startX)-ac.container.offset().left,ag=Math.max(ak.pageX,al.startX)-ac.container.offset().left,aj=(ac.high-ac.low),ai=ac.viewport_container.width();ac.update_location(Math.round(ah/ai*aj)+ac.low,Math.round(ag/ai*aj)+ac.low)}).bind("dragend",function(al,am){var ah=Math.min(al.pageX,am.startX),ag=Math.max(al.pageX,am.startX),aj=(ac.high-ac.low),ai=ac.viewport_container.width(),ak=ac.low;ac.low=Math.round(ah/ai*aj)+ak;ac.high=Math.round(ag/ai*aj)+ak;$(am.proxy).remove();ac.request_redraw()});this.add_label_track(new X(this,{content_div:this.top_labeltrack}));this.add_label_track(new X(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ac.resize_window()},500)});$(document).bind("redraw",function(){ac.redraw()});this.reset();$(window).trigger("resize")},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(ad,af,ac,ag){if(this.timer){clearTimeout(this.timer)}if(ag){var ae=this;this.timer=setTimeout(function(){ae.trigger("navigate",ad+":"+af+"-"+ac)},500)}else{view.trigger("navigate",ad+":"+af+"-"+ac)}},update_location:function(ac,ae){this.location_span.text(commatize(ac)+" - "+commatize(ae));this.nav_input.val(this.chrom+":"+commatize(ac)+"-"+commatize(ae));var ad=view.chrom_select.val();if(ad!==""){this.trigger_navigate(ad,view.low,view.high,true)}},load_chroms:function(ae){ae.num=w;var ac=this,ad=$.Deferred();$.ajax({url:chrom_url+"/"+this.dbkey,data:ae,dataType:"json",success:function(ag){if(ag.chrom_info.length===0){return}if(ag.reference){ac.add_label_track(new B(ac))}ac.chrom_data=ag.chrom_info;var aj='<option value="">Select Chrom/Contig</option>';for(var ai=0,af=ac.chrom_data.length;ai<af;ai++){var ah=ac.chrom_data[ai].chrom;aj+='<option value="'+ah+'">'+ah+"</option>"}if(ag.prev_chroms){aj+='<option value="previous">Previous '+w+"</option>"}if(ag.next_chroms){aj+='<option value="next">Next '+w+"</option>"}ac.chrom_select.html(aj);ac.chrom_start_index=ag.start_index;ad.resolve(ag)},error:function(){alert("Could not load chroms for this dbkey:",ac.dbkey)}});return ad},change_chrom:function(ah,ad,aj){var ae=this;if(!ae.chrom_data){ae.load_chroms_deferred.then(function(){ae.change_chrom(ah,ad,aj)});return}if(!ah||ah==="None"){return}if(ah==="previous"){ae.load_chroms({low:this.chrom_start_index-w});return}if(ah==="next"){ae.load_chroms({low:this.chrom_start_index+w});return}var ai=$.grep(ae.chrom_data,function(ak,al){return ak.chrom===ah})[0];if(ai===undefined){ae.load_chroms({chrom:ah},function(){ae.change_chrom(ah,ad,aj)});return}else{if(ah!==ae.chrom){ae.chrom=ah;ae.chrom_select.val(ae.chrom);ae.max_high=ai.len-1;ae.reset();ae.request_redraw(true);for(var ag=0,ac=ae.drawables.length;ag<ac;ag++){var af=ae.drawables[ag];if(af.init){af.init()}}if(ae.reference_track){ae.reference_track.init()}}if(ad!==undefined&&aj!==undefined){ae.low=Math.max(ad,0);ae.high=Math.min(aj,ae.max_high)}else{ae.low=0;ae.high=ae.max_high}ae.reset_overview();ae.request_redraw()}},go_to:function(ag){ag=ag.replace(/ |,/g,"");var ak=this,ac,af,ad=ag.split(":"),ai=ad[0],aj=ad[1];if(aj!==undefined){try{var ah=aj.split("-");ac=parseInt(ah[0],10);af=parseInt(ah[1],10)}catch(ae){return false}}ak.change_chrom(ai,ac,af)},move_fraction:function(ae){var ac=this;var ad=ac.high-ac.low;this.move_delta(ae*ad)},move_delta:function(af){var ac=this;var ae=ac.high-ac.low;if(ac.low-af<ac.max_low){ac.low=ac.max_low;ac.high=ac.max_low+ae}else{if(ac.high-af>ac.max_high){ac.high=ac.max_high;ac.low=ac.max_high-ae}else{ac.high-=af;ac.low-=af}}ac.request_redraw();var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){z.prototype.add_drawable.call(this,ac);ac.init();this.changed();this.update_intro_div()},add_label_track:function(ac){ac.view=this;ac.init();this.label_tracks.push(ac)},remove_drawable:function(ae,ad){z.prototype.remove_drawable.call(this,ae);if(ad){var ac=this;ae.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ak,ac,aj,al){var ai=this,ah=(al?[al]:ai.drawables),ae;var ad;for(var ag=0;ag<ah.length;ag++){ad=ah[ag];ae=-1;for(var af=0;af<ai.tracks_to_be_redrawn.length;af++){if(ai.tracks_to_be_redrawn[af][0]===ad){ae=af;break}}if(ae<0){ai.tracks_to_be_redrawn.push([ad,ac,aj])}else{ai.tracks_to_be_redrawn[ag][1]=ac;ai.tracks_to_be_redrawn[ag][2]=aj}}if(!this.requested_redraw){requestAnimationFrame(function(){ai._redraw(ak)});this.requested_redraw=true}},_redraw:function(am){this.requested_redraw=false;var aj=this.low,af=this.high;if(aj<this.max_low){aj=this.max_low}if(af>this.max_high){af=this.max_high}var al=this.high-this.low;if(this.high!==0&&al<this.min_separation){af=aj+this.min_separation}this.low=Math.floor(aj);this.high=Math.ceil(af);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=this.viewport_container.width()/(this.high-this.low);var ac=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ai=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var an=13;this.overview_box.css({left:ac,width:Math.max(an,ai)}).show();if(ai<an){this.overview_box.css("left",ac-(an-ai)/2)}if(this.overview_highlight){this.overview_highlight.css({left:ac,width:ai})}if(!am){var ae,ad,ak;for(var ag=0,ah=this.tracks_to_be_redrawn.length;ag<ah;ag++){ae=this.tracks_to_be_redrawn[ag][0];ad=this.tracks_to_be_redrawn[ag][1];ak=this.tracks_to_be_redrawn[ag][2];if(ae){ae._draw(ad,ak)}}this.tracks_to_be_redrawn=[];for(ag=0,ah=this.label_tracks.length;ag<ah;ag++){this.label_tracks[ag]._draw()}}},zoom_in:function(ad,ae){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var af=this.high-this.low,ag=af/2+this.low,ac=(af/this.zoom_factor)/2;if(ad){ag=ad/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ag-ac);this.high=Math.round(ag+ac);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ad=this.high-this.low,ae=ad/2+this.low,ac=(ad*this.zoom_factor)/2;this.low=Math.round(ae-ac);this.high=Math.round(ae+ac);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(ae){if(this.overview_drawable){if(this.overview_drawable.dataset_id===ae.dataset_id){return}this.overview_viewport.find(".track").remove()}var ad=ae.copy({content_div:this.overview_viewport}),ac=this;ad.header_div.hide();ad.is_overview=true;ac.overview_drawable=ad;this.overview_drawable.postdraw_actions=function(){ac.overview_highlight.show().height(ac.overview_drawable.content_div.height());ac.overview_viewport.height(ac.overview_drawable.content_div.height()+ac.overview_box.outerHeight());ac.overview_close.show();ac.resize_window()};ac.overview_drawable.request_draw();this.changed()},reset_overview:function(){$(".bs-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 s=function(ae,aj,af){this.track=ae;this.name=aj.name;this.params=[];var aq=aj.params;for(var ag=0;ag<aq.length;ag++){var al=aq[ag],ad=al.name,ap=al.label,ah=unescape(al.html),ar=al.value,an=al.type;if(an==="number"){this.params.push(new e(ad,ap,ah,(ad in af?af[ad]:ar),al.min,al.max))}else{if(an==="select"){this.params.push(new N(ad,ap,ah,(ad in af?af[ad]:ar)))}else{console.log("WARNING: unrecognized tool parameter type:",ad,an)}}}this.parent_div=$("<div/>").addClass("dynamic-tool").hide();this.parent_div.bind("drag",function(au){au.stopPropagation()}).click(function(au){au.stopPropagation()}).bind("dblclick",function(au){au.stopPropagation()});var ao=$("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);var am=this.params;var ak=this;$.each(this.params,function(av,ay){var ax=$("<div>").addClass("param-row").appendTo(ak.parent_div);var au=$("<div>").addClass("param-label").text(ay.label).appendTo(ax);var aw=$("<div/>").addClass("param-input").html(ay.html).appendTo(ax);aw.find(":input").val(ay.value);$("<div style='clear: both;'/>").appendTo(ax)});this.parent_div.find("input").click(function(){$(this).select()});var at=$("<div>").addClass("param-row").appendTo(this.parent_div);var ai=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(at);var ac=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(at);ac.click(function(){ak.run_on_region()});ai.click(function(){ak.run_on_dataset()});if("visible" in af&&af.visible){this.parent_div.show()}};q(s.prototype,{update_params:function(){for(var ac=0;ac<this.params.length;ac++){this.params[ac].update_value()}},state_dict:function(){var ad={};for(var ac=0;ac<this.params.length;ac++){ad[this.params[ac].name]=this.params[ac].value}ad.visible=this.parent_div.is(":visible");return ad},get_param_values_dict:function(){var ac={};this.parent_div.find(":input").each(function(){var ad=$(this).attr("name"),ae=$(this).val();ac[ad]=ae});return ac},get_param_values:function(){var ac=[];this.parent_div.find(":input").each(function(){var ad=$(this).attr("name"),ae=$(this).val();if(ad){ac[ac.length]=ae}});return ac},run_on_dataset:function(){var ac=this;ac.run({target_dataset_id:this.track.original_dataset_id,tool_id:ac.name},null,function(ad){show_modal(ac.name+" is Running",ac.name+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var ad={target_dataset_id:this.track.original_dataset_id,action:"rerun",tool_id:this.name,regions:[{chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}]},ah=this.track,ae=ad.tool_id+ah.tool_region_and_parameters_str(ad.chrom,ad.low,ad.high),ac;if(ah.container===view){var ag=new P(view,view,{name:this.name});var af=ah.container.replace_drawable(ah,ag,false);ag.container_div.insertBefore(ah.view.content_div.children()[af]);ag.add_drawable(ah);ah.container_div.appendTo(ag.content_div);ac=ag}else{ac=ah.container}var ai=new ah.constructor(view,ac,{name:ae,hda_ldda:"hda"});ai.init_for_tool_data();ai.change_mode(ah.mode);ai.set_filters_manager(ah.filters_manager.copy(ai));ai.update_icons();ac.add_drawable(ai);ai.tiles_div.text("Starting job.");this.update_params();this.run(ad,ai,function(aj){ai.set_dataset(new Z.Dataset(aj));ai.tiles_div.text("Running job.");ai.init()})},run:function(ac,ae,af){ac.inputs=this.get_param_values_dict();var ad=new l.ServerStateDeferred({ajax_settings:{url:galaxy_paths.get("tool_url"),data:JSON.stringify(ac),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ag){return ag!=="pending"}});$.when(ad.go()).then(function(ag){if(ag==="no converter"){ae.container_div.addClass("error");ae.content_div.text(J)}else{if(ag.error){ae.container_div.addClass("error");ae.content_div.text(y+ag.message)}else{af(ag)}}})}});var N=function(ad,ac,ae,af){this.name=ad;this.label=ac;this.html=$(ae);this.value=af};q(N.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ae,ad,ag,ah,af,ac){N.call(this,ae,ad,ag,ah);this.min=af;this.max=ac};q(e.prototype,N.prototype,{update_value:function(){N.prototype.update_value.call(this);this.value=parseFloat(this.value)}});var C=function(ac,ad){L.Scaler.call(this,ad);this.filter=ac};C.prototype.gen_val=function(ac){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(ac[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var F=function(ac){this.track=ac.track;this.params=ac.params;this.values={};this.restore_values((ac.saved_values?ac.saved_values:{}));this.onchange=ac.onchange};q(F.prototype,{restore_values:function(ac){var ad=this;$.each(this.params,function(ae,af){if(ac[af.key]!==undefined){ad.values[af.key]=ac[af.key]}else{ad.values[af.key]=af.default_value}})},build_form:function(){var af=this;var ac=$("<div />");var ae;function ad(ak,ag){for(var ao=0;ao<ak.length;ao++){ae=ak[ao];if(ae.hidden){continue}var ai="param_"+ao;var at=af.values[ae.key];var av=$("<div class='form-row' />").appendTo(ag);av.append($("<label />").attr("for",ai).text(ae.label+":"));if(ae.type==="bool"){av.append($('<input type="checkbox" />').attr("id",ai).attr("name",ai).attr("checked",at))}else{if(ae.type==="text"){av.append($('<input type="text"/>').attr("id",ai).val(at).click(function(){$(this).select()}))}else{if(ae.type==="select"){var aq=$("<select />").attr("id",ai);for(var am=0;am<ae.options.length;am++){$("<option/>").text(ae.options[am].label).attr("value",ae.options[am].value).appendTo(aq)}aq.val(at);av.append(aq)}else{if(ae.type==="color"){var au=$("<div/>").appendTo(av),ap=$("<input />").attr("id",ai).attr("name",ai).val(at).css("float","left").appendTo(au).click(function(ax){$(".bs-tooltip").removeClass("in");var aw=$(this).siblings(".bs-tooltip").addClass("in");aw.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(aw).height()/2)+($(this).height()/2)}).show();aw.click(function(ay){ay.stopPropagation()});$(document).bind("click.color-picker",function(){aw.hide();$(document).unbind("click.color-picker")});ax.stopPropagation()}),an=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(au).attr("title","Set new random color").tooltip(),ar=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(au).hide(),aj=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(ar),ah=$("<div class='tooltip-arrow'></div>").appendTo(ar),al=$.farbtastic(aj,{width:100,height:100,callback:ap,color:at});au.append($("<div/>").css("clear","both"));(function(aw){an.click(function(){aw.setColor(l.get_random_color())})})(al)}else{av.append($("<input />").attr("id",ai).attr("name",ai).val(at))}}}}if(ae.help){av.append($("<div class='help'/>").text(ae.help))}}}ad(this.params,ac);return ac},update_from_form:function(ac){var ae=this;var ad=false;$.each(this.params,function(af,ah){if(!ah.hidden){var ai="param_"+af;var ag=ac.find("#"+ai).val();if(ah.type==="float"){ag=parseFloat(ag)}else{if(ah.type==="int"){ag=parseInt(ag)}else{if(ah.type==="bool"){ag=ac.find("#"+ai).is(":checked")}}}if(ag!==ae.values[ah.key]){ae.values[ah.key]=ag;ad=true}}});if(ad){this.onchange();this.track.changed()}}});var b=function(ac,ag,ae,ad,af){this.track=ac;this.region=ag;this.low=ag.get("start");this.high=ag.get("end");this.resolution=ae;this.html_elt=$("<div class='track-tile'/>").append(ad).height($(ad).attr("height"));this.data=af;this.stale=false};b.prototype.predisplay_actions=function(){};var j=function(ac,ah,ae,ad,af,ag){b.call(this,ac,ah,ae,ad,af);this.max_val=ag};q(j.prototype,b.prototype);var O=function(af,an,ag,ae,ai,ap,aj,aq,ad,am){b.call(this,af,an,ag,ae,ai);this.mode=aj;this.all_slotted=ad;this.feature_mapper=am;this.has_icons=false;if(aq){this.has_icons=true;var ak=this;ae=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:D-1,width:ae.width}).prependTo(this.html_elt);var al=new x.GenomeRegion({chrom:af.view.chrom,start:this.low,end:this.high}),ao=ai.length,ah=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+ao+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ac=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+ao+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ah.click(function(){ak.stale=true;af.data_manager.get_more_data(al,af.mode,ak.resolution,{},af.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();af.request_draw(true)}).dblclick(function(ar){ar.stopPropagation()});ac.click(function(){ak.stale=true;af.data_manager.get_more_data(al,af.mode,ak.resolution,{},af.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();af.request_draw(true)}).dblclick(function(ar){ar.stopPropagation()})}};q(O.prototype,b.prototype);O.prototype.predisplay_actions=function(){var ad=this,ac={};if(ad.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(ao){if(!this.hovered){return}var aj=$(this).offset(),an=ao.pageX-aj.left,am=ao.pageY-aj.top,at=ad.feature_mapper.get_feature_data(an,am),ak=(at?at[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!ak||$(this).attr("id")!==ak.toString()){$(this).remove()}});if(at){var af=ac[ak];if(!af){var ak=at[0],ap={name:at[3],start:at[1],end:at[2],strand:at[4]},ai=ad.track.filters_manager.filters,ah;for(var al=0;al<ai.length;al++){ah=ai[al];ap[ah.name]=at[ah.index]}var af=$("<div/>").attr("id",ak).addClass("feature-popup"),au=$("<table/>"),ar,aq,av;for(ar in ap){aq=ap[ar];av=$("<tr/>").appendTo(au);$("<th/>").appendTo(av).text(ar);$("<td/>").attr("align","left").appendTo(av).text(typeof(aq)==="number"?W(aq,2):aq)}af.append($("<div class='feature-popup-inner'>").append(au));ac[ak]=af}af.appendTo($(this).parents(".track-content").children(".overlay"));var ag=an+parseInt(ad.html_elt.css("left"))-af.width()/2,ae=am+parseInt(ad.html_elt.css("top"))+7;af.css("left",ag+"px").css("top",ae+"px")}else{if(!ao.isPropagationStopped()){ao.stopPropagation();$(this).siblings().each(function(){$(this).trigger(ao)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var g=function(ad,ac,ae){q(ae,{drag_handle_class:"draghandle"});r.call(this,ad,ac,ae);this.dataset=new Z.Dataset({id:ae.dataset_id,hda_ldda:ae.hda_ldda});this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ae?ae.data_query_wait:K);this.data_manager=("data_manager" in ae?ae.data_manager:new x.GenomeDataManager({dataset:this.dataset,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=0;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 ae)||ae.resize){this.add_resize_handle()}}};q(g.prototype,r.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},r.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(ac){ac.view.set_overview(ac)}},r.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters()}else{ac.filters_manager.init_filters()}ac.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ac){ac.dynamic_tool_div.toggle();if(ac.dynamic_tool_div.is(":visible")){ac.set_name(ac.name+ac.tool_region_and_parameters_str())}else{ac.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ac){var af='<strong>Tool</strong>: <%= track.tool.name %><br/><strong>Dataset</strong>: <%= track.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>',ae=ab.template(af,{track:ac});var ah=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ad=function(){var aj=$('select[name="regions"] option:selected').val(),al,ai=new x.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new x.GenomeRegion({from_str:$(am).children(".position").text()})});if(aj==="cur"){al=[ai]}else{if(aj==="bookmarks"){al=ak}else{al=[ai].concat(ak)}}hide_modal();window.location.href=galaxy_paths.get("sweepster_url")+"?"+$.param({dataset_id:ac.dataset_id,hda_ldda:ac.hda_ldda,regions:JSON.stringify(new Backbone.Collection(al).toJSON())})},ag=function(ai){if((ai.keyCode||ai.which)===27){ah()}else{if((ai.keyCode||ai.which)===13){ad()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",ae,{No:ah,Yes:ad})}},r.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset_id&&r.prototype.can_draw.call(this)){return true}return false},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id).css("position","relative")},build_header_div:function(){var ac=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ac)}this.name_div=$("<div/>").addClass("track-name").appendTo(ac).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ac},on_resize:function(){},add_resize_handle:function(){var ac=this;var af=false;var ae=false;var ad=$("<div class='track-resize'>");$(ac.container_div).hover(function(){if(ac.content_visible){af=true;ad.show()}},function(){af=false;if(!ae){ad.hide()}});ad.hide().bind("dragstart",function(ag,ah){ae=true;ah.original_height=$(ac.content_div).height()}).bind("drag",function(ah,ai){var ag=Math.min(Math.max(ai.original_height+ai.deltaY,ac.min_height_px),ac.max_height_px);$(ac.tiles_div).css("height",ag);ac.visible_height_px=(ac.max_height_px===ag?0:ag);ac.on_resize()}).bind("dragend",function(ag,ah){ac.tile_cache.clear();ae=false;if(!af){ad.hide()}ac.config.values.height=ac.visible_height_px;ac.changed()}).appendTo(ac.container_div)},set_display_modes:function(af,ai){this.display_modes=af;this.mode=(ai?ai:(this.config&&this.config.values.mode?this.config.values.mode:this.display_modes[0]));this.action_icons.mode_icon.attr("title","Set display mode (now: "+this.mode+")");var ad=this,ag={};for(var ae=0,ac=ad.display_modes.length;ae<ac;ae++){var ah=ad.display_modes[ae];ag[ah]=function(aj){return function(){ad.change_mode(aj);ad.icons_div.show();ad.container_div.mouseleave(function(){ad.icons_div.hide()})}}(ah)}make_popupmenu(this.action_icons.mode_icon,ag)},build_action_icons:function(){r.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 X){return"LabelTrack"}else{if(this instanceof B){return"ReferenceTrack"}else{if(this instanceof h){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof R){return"VcfTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.content_div.css("height","auto");ad.tiles_div.children().remove();ad.container_div.removeClass("nodata error pending");if(!ad.dataset_id){return}var ac=$.Deferred(),ae={hda_ldda:ad.hda_ldda,data_type:this.dataset_check_type,chrom:ad.view.chrom};$.getJSON(this.dataset.url(),ae,function(af){if(!af||af==="error"||af.kind==="error"){ad.container_div.addClass("error");ad.tiles_div.text(o);if(af.message){var ag=$(" <a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+af.message+"</pre>",{Close:hide_modal})});ad.tiles_div.append(ag)}}else{if(af==="no converter"){ad.container_div.addClass("error");ad.tiles_div.text(J)}else{if(af==="no data"||(af.data!==undefined&&(af.data===null||af.data.length===0))){ad.container_div.addClass("nodata");ad.tiles_div.text(E)}else{if(af==="pending"){ad.container_div.addClass("pending");ad.tiles_div.html(v);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(af==="data"||af.status==="data"){if(af.valid_chroms){ad.valid_chroms=af.valid_chroms;ad.update_icons()}ad.tiles_div.text(U);if(ad.view.chrom){ad.tiles_div.text("");ad.tiles_div.css("height",ad.visible_height_px+"px");ad.enabled=true;$.when(ad.predraw_init()).done(function(){ac.resolve();ad.container_div.removeClass("nodata error pending");ad.request_draw()})}else{ac.resolve()}}}}}}});this.update_icons();return ac},predraw_init:function(){},get_drawables:function(){return this}});var M=function(ae,ad,af){g.call(this,ae,ad,af);var ac=this;m(ac.container_div,ac.drag_handle_class,".group",ac);this.filters_manager=new i.FiltersManager(this,("filters" in af?af.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=("tool" in af&&af.tool?new s(this,af.tool,af.tool_state):null);this.tile_cache=new x.Cache(Q);if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){this.dynamic_tool_div=this.tool.parent_div;this.header_div.after(this.dynamic_tool_div)}}this.tiles_div=$("<div/>").addClass("tiles").appendTo(this.content_div);this.overlay_div=$("<div/>").addClass("overlay").appendTo(this.content_div);if(af.mode){this.change_mode(af.mode)}};q(M.prototype,r.prototype,g.prototype,{action_icons_def:g.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(ac){$(".bs-tooltip").remove();ac.slotters[ac.view.resolution_px_b].max_rows*=2;ac.request_draw(true)},hide:true}]),copy:function(ac){var ad=this.to_dict();q(ad,{data_manager:this.data_manager});var ae=new this.constructor(this.view,ac,ad);ae.change_mode(this.mode);ae.enabled=this.enabled;return ae},set_filters_manager:function(ac){this.filters_manager=ac;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,hda_ldda:this.hda_ldda,dataset_id:this.dataset_id,prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.values.mode=ad;ac.tile_cache.clear();ac.request_draw();this.action_icons.mode_icon.attr("title","Set display mode (now: "+ac.mode+")");return ac},update_icons:function(){var ac=this;if(ac.filters_available){ac.action_icons.filters_icon.show()}else{ac.action_icons.filters_icon.hide()}if(ac.tool){ac.action_icons.tools_icon.show();ac.action_icons.param_space_viz_icon.show()}else{ac.action_icons.tools_icon.hide();ac.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ad,ae,ac){return ad+"_"+ae+"_"+ac},request_draw:function(ad,ac){this.view.request_redraw(false,ad,ac,this)},before_draw:function(){},_draw:function(ad,an){if(!this.can_draw()){return}var al=this.view.low,ah=this.view.high,aj=ah-al,ae=this.view.container.width(),ap=this.view.resolution_px_b,ag=this.view.resolution_b_px;if(this.is_overview){al=this.view.max_low;ah=this.view.max_high;ag=(view.max_high-view.max_low)/ae;ap=1/ag}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(al/(ag*S)),ak=true,ao=[],ai=function(aq){return(aq&&"track" in aq)};while((ac*S*ag)<ah){var am=this.draw_helper(ad,ae,ac,ag,this.tiles_div,ap);if(ai(am)){ao.push(am)}else{ak=false}ac+=1}if(!an){this.tiles_div.children(".remove").removeClass("remove").remove()}var af=this;if(ak){this.tiles_div.children(".remove").remove();af.postdraw_actions(ao,ae,ap,an)}},postdraw_actions:function(ae,af,ah,ac){var ag=false;for(var ad=0;ad<ae.length;ad++){if(ae[ad].has_icons){ag=true;break}}if(ag){for(var ad=0;ad<ae.length;ad++){tile=ae[ad];if(!tile.has_icons){tile.html_elt.css("padding-top",D)}}}},draw_helper:function(ac,ao,au,ar,ah,ai,ap){var an=this,ax=this._gen_tile_cache_key(ao,ai,au),af=this._get_tile_bounds(au,ar);if(!ap){ap={}}var aw=(ac?undefined:an.tile_cache.get_elt(ax));if(aw){an.show_tile(aw,ah,ai);return aw}var al=true;var at=an.data_manager.get_data(af,an.mode,ar,an.data_url_extra_params);if(V(at)){al=false}var aj;if(view.reference_track&&ai>view.canvas_manager.char_width_px){aj=view.reference_track.data_manager.get_data(af,an.mode,ar,view.reference_track.data_url_extra_params);if(V(aj)){al=false}}if(al){q(at,ap.more_tile_data);var ak=an.mode;if(ak==="Auto"){ak=an.get_mode(at);an.update_auto_mode(ak)}var ae=an.view.canvas_manager.new_canvas(),av=af.get("start"),ad=af.get("end"),ao=Math.ceil((ad-av)*ai)+an.left_offset,am=an.get_canvas_height(at,ak,ai,ao);ae.width=ao;ae.height=am;var aq=ae.getContext("2d");aq.translate(this.left_offset,0);var aw=an.draw_tile(at,aq,ak,ar,af,ai,aj);if(aw!==undefined){an.tile_cache.set_elt(ax,aw);an.show_tile(aw,ah,ai)}return aw}var ag=$.Deferred();$.when(at,aj).then(function(){view.request_redraw(false,false,false,an);ag.resolve()});return ag},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},draw_tile:function(ac,ad,ah,af,ag,ai,ae){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ae,ah,ai){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var ag=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ai;if(this.left_offset){ag-=this.left_offset}ac.css({position:"absolute",top:0,left:ag});if(ac.hasClass("remove")){ac.removeClass("remove")}else{ah.append(ac)}ae.html_elt.height("auto");this.max_height_px=Math.max(this.max_height_px,ae.html_elt.height());ae.html_elt.parent().children().css("height",this.max_height_px+"px");var af=this.max_height_px;if(this.visible_height_px!==0){af=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",af+"px")},_get_tile_bounds:function(ac,ad){var af=Math.floor(ac*S*ad),ag=Math.ceil(S*ad),ae=(af+ag<=this.view.max_high?af+ag:this.view.max_high);return new x.GenomeRegion({chrom:this.view.chrom,start:af,end:ae})},tool_region_and_parameters_str:function(ae,ac,af){var ad=this,ag=(ae!==undefined&&ac!==undefined&&af!==undefined?ae+":"+ac+"-"+af:"all");return" - region=["+ag+"], parameters=["+ad.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(ac,ad){return true},can_subset:function(ac){return false},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state";this.normal_postdraw_actions=this.postdraw_actions;this.postdraw_actions=function(ae,af,ah,ac){var ad=this;ad.normal_postdraw_actions(ae,af,ah,ac);ad.dataset_check_type="converted_datasets_state";ad.data_query_wait=K;var ag=new l.ServerStateDeferred({url:ad.dataset_state_url,url_params:{dataset_id:ad.dataset_id,hda_ldda:ad.hda_ldda},interval:ad.data_query_wait,success_fn:function(ai){return ai!=="pending"}});$.when(ag.go()).then(function(){ad.data_manager.set("data_type","data")});ad.postdraw_actions=ad.normal_postdraw_actions}}});var X=function(ad,ac){var ae={resize:false};g.call(this,ad,ac,ae);this.container_div.addClass("label-track")};q(X.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},_draw:function(){var ae=this.view,af=ae.high-ae.low,ai=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/ai)*ai,ag=this.view.container.width(),ad=$("<div style='position: relative; height: 1.3em;'></div>");while(ac<ae.high){var ah=(ac-ae.low)/af*ag;ad.append($("<div class='label'>"+commatize(ac)+"</div>").css({position:"absolute",left:ah-1}));ac+=ai}this.content_div.children(":first").remove();this.content_div.append(ad)}});var f=function(ad,ac,ag){M.call(this,ad,ac,ag);this.drawables=[];this.left_offset=0;if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=p(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}if(this.drawables.length!==0){this.set_display_modes(this.drawables[0].display_modes,this.drawables[0].mode)}this.update_icons();this.obj_type="CompositeTrack"};q(f.prototype,M.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.show_group()}}].concat(M.prototype.action_icons_def),to_dict:z.prototype.to_dict,add_drawable:z.prototype.add_drawable,unpack_drawables:z.prototype.unpack_drawables,change_mode:function(ac){M.prototype.change_mode.call(this,ac);for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].change_mode(ac)}},init:function(){var ae=[];for(var ad=0;ad<this.drawables.length;ad++){ae.push(this.drawables[ad].init())}var ac=this;$.when.apply($,ae).then(function(){ac.enabled=true;ac.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:r.prototype.can_draw,draw_helper:function(ad,at,az,aw,ak,am,au){var ar=this,aD=this._gen_tile_cache_key(at,am,az),ah=this._get_tile_bounds(az,aw);if(!au){au={}}var aC=(ad?undefined:ar.tile_cache.get_elt(aD));if(aC){ar.show_tile(aC,ak,am);return aC}var al=[],ar,ap=true,ax,an;for(var ay=0;ay<this.drawables.length;ay++){ar=this.drawables[ay];ax=ar.data_manager.get_data(ah,ar.mode,aw,ar.data_url_extra_params);if(V(ax)){ap=false}al.push(ax);an=null;if(view.reference_track&&am>view.canvas_manager.char_width_px){an=view.reference_track.data_manager.get_data(ah,ar.mode,aw,view.reference_track.data_url_extra_params);if(V(an)){ap=false}}al.push(an)}if(ap){q(ax,au.more_tile_data);this.tile_predraw_init();var ag=ar.view.canvas_manager.new_canvas(),ai=ar._get_tile_bounds(az,aw),aA=ah.get("start"),ae=ah.get("end"),aB=0,at=Math.ceil((ae-aA)*am)+this.left_offset,aq=0,af=[],ay;var ac=0;for(ay=0;ay<this.drawables.length;ay++,aB+=2){ar=this.drawables[ay];ax=al[aB];var ao=ar.mode;if(ao==="Auto"){ao=ar.get_mode(ax);ar.update_auto_mode(ao)}af.push(ao);ac=ar.get_canvas_height(ax,ao,am,at);if(ac>aq){aq=ac}}ag.width=at;ag.height=(au.height?au.height:aq);aB=0;var av=ag.getContext("2d");av.translate(this.left_offset,0);av.globalAlpha=0.5;av.globalCompositeOperation="source-over";for(ay=0;ay<this.drawables.length;ay++,aB+=2){ar=this.drawables[ay];ax=al[aB];an=al[aB+1];aC=ar.draw_tile(ax,av,af[ay],aw,ah,am,an)}this.tile_cache.set_elt(aD,aC);this.show_tile(aC,ak,am);return aC}var aj=$.Deferred(),ar=this;$.when.apply($,al).then(function(){view.request_redraw(false,false,false,ar);aj.resolve()});return aj},show_group:function(){var af=new P(this.view,this.container,{name:this.name}),ac;for(var ae=0;ae<this.drawables.length;ae++){ac=this.drawables[ae];ac.update_icons();af.add_drawable(ac);ac.container=af;af.content_div.append(ac.container_div)}var ad=this.container.replace_drawable(this,af,true);af.request_draw()},tile_predraw_init:function(){var af=Number.MAX_VALUE,ac=-af,ad;for(var ae=0;ae<this.drawables.length;ae++){ad=this.drawables[ae];if(ad instanceof h){if(ad.prefs.min_value<af){af=ad.prefs.min_value}if(ad.prefs.max_value>ac){ac=ad.prefs.max_value}}}for(var ae=0;ae<this.drawables.length;ae++){ad=this.drawables[ae];ad.prefs.min_value=af;ad.prefs.max_value=ac}},postdraw_actions:function(ae,ah,aj,ad){M.prototype.postdraw_actions.call(this,ae,ah,aj,ad);var ag=-1;for(var af=0;af<ae.length;af++){var ac=ae[af].html_elt.find("canvas").height();if(ac>ag){ag=ac}}for(var af=0;af<ae.length;af++){var ai=ae[af];if(ai.html_elt.find("canvas").height()!==ag){this.draw_helper(true,ah,ai.index,ai.resolution,ai.html_elt.parent(),aj,{height:ag});ai.html_elt.remove()}}}});var B=function(ac){M.call(this,ac,{content_div:ac.top_labeltrack},{resize:false});ac.reference_track=this;this.left_offset=200;this.visible_height_px=12;this.container_div.addClass("reference-track");this.content_div.css("background","none");this.content_div.css("min-height","0px");this.content_div.css("border","none");this.data_url=reference_url+"/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new x.ReferenceTrackDataManager({data_url:this.data_url});this.hide_contents()};q(B.prototype,r.prototype,M.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},can_draw:r.prototype.can_draw,draw_helper:function(ag,ae,ac,ad,ah,ai,af){if(ai>this.view.canvas_manager.char_width_px){return M.prototype.draw_helper.call(this,ag,ae,ac,ad,ah,ai,af)}else{this.hide_contents();return null}},draw_tile:function(ak,al,ag,af,ai,am){var ae=this;if(am>this.view.canvas_manager.char_width_px){if(ak.data===null){this.hide_contents();return}var ad=al.canvas;al.font=al.canvas.manager.default_font;al.textAlign="center";ak=ak.data;for(var ah=0,aj=ak.length;ah<aj;ah++){var ac=Math.floor(ah*am);al.fillText(ak[ah],ac,10)}this.show_contents();return new b(ae,ai,af,ad,ak)}this.hide_contents()}});var h=function(ae,ad,af){var ac=this;this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";M.call(this,ae,ad,af);this.hda_ldda=af.hda_ldda;this.dataset_id=af.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Color",type:"color",default_value:l.get_random_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:32,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.set_min_value(ac.prefs.min_value);ac.set_max_value(ac.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};q(h.prototype,r.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ac){this.prefs.min_value=ac;$("#linetrack_"+this.dataset_id+"_minval").text(this.prefs.min_value);this.tile_cache.clear();this.request_draw()},set_max_value:function(ac){this.prefs.max_value=ac;$("#linetrack_"+this.dataset_id+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.request_draw()},predraw_init:function(){var ac=this;ac.vertical_range=undefined;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.hda_ldda},function(ad){ac.container_div.addClass("line-track");var ag=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=ag.min,ai=ag.max;ae=Math.floor(Math.min(0,Math.max(ae,ag.mean-2*ag.sd)));ai=Math.ceil(Math.max(0,Math.min(ai,ag.mean+2*ag.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ai;$("#track_"+ac.dataset_id+"_minval").val(ac.prefs.min_value);$("#track_"+ac.dataset_id+"_maxval").val(ac.prefs.max_value)}ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.total_frequency=ag.total_frequency;ac.container_div.find(".yaxislabel").remove();var ah=$("<div/>").text(W(ac.prefs.min_value,3)).make_text_editable({num_cols:6,on_finish:function(aj){$(".bs-tooltip").remove();var aj=parseFloat(aj);if(!isNaN(aj)){ac.set_min_value(aj)}},help_text:"Set min value"}).addClass("yaxislabel bottom").attr("id","linetrack_"+ac.dataset_id+"_minval").prependTo(ac.container_div),af=$("<div/>").text(W(ac.prefs.max_value,3)).make_text_editable({num_cols:6,on_finish:function(aj){$(".bs-tooltip").remove();var aj=parseFloat(aj);if(!isNaN(aj)){ac.set_max_value(aj)}},help_text:"Set max value"}).addClass("yaxislabel top").attr("id","linetrack_"+ac.dataset_id+"_maxval").prependTo(ac.container_div)})},draw_tile:function(al,aj,ae,ad,ag,ak){var ac=aj.canvas,af=ag.get("start"),ai=ag.get("end"),ah=new L.LinePainter(al.data,af,ai,this.prefs,ae);ah.draw(aj,ac.width,ac.height,ak);return new b(this,ag,ad,ac,al.data)},can_subset:function(ac){return false}});var t=function(ae,ad,af){var ac=this;this.display_modes=["Heatmap"];this.mode="Heatmap";M.call(this,ae,ad,af);this.hda_ldda=af.hda_ldda;this.dataset_id=af.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"pos_color",label:"Positive Color",type:"color",default_value:"4169E1"},{key:"negative_color",label:"Negative Color",type:"color",default_value:"FF8C00"},{key:"min_value",label:"Min Value",type:"float",default_value:0},{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}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.set_min_value(ac.prefs.min_value);ac.set_max_value(ac.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};q(t.prototype,r.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ac){this.prefs.min_value=ac;this.tile_cache.clear();this.request_draw()},set_max_value:function(ac){this.prefs.max_value=ac;this.tile_cache.clear();this.request_draw()},draw_tile:function(am,ak,ah,af,ad,al){var ae=ak.canvas,ac=this._get_tile_bounds(ad,af),ag=ac[0],aj=ac[1],ai=new L.DiagonalHeatmapPainter(am.data,ag,aj,this.prefs,ah);ai.draw(ak,ae.width,ae.height,al);return new b(this,ad,af,ae,am.data)}});var c=function(af,ae,ah){var ad=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];M.call(this,af,ae,ah);var ag=l.get_random_color(),ac=l.get_random_color([ag,"#ffffff"]);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:ag},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ac},{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:"histogram_max",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:this.visible_height_px,hidden:true}],saved_values:ah.prefs,onchange:function(){ad.set_name(ad.prefs.name);ad.tile_cache.clear();ad.set_painter_from_config();ad.request_draw()}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");this.hda_ldda=ah.hda_ldda;this.dataset_id=ah.dataset_id;this.original_dataset_id=ah.dataset_id;this.show_labels_scale=0.001;this.showing_details=false;this.summary_draw_height=30;this.slotters={};this.start_end_dct={};this.left_offset=200;this.set_painter_from_config()};q(c.prototype,r.prototype,M.prototype,{set_dataset:function(ac){this.dataset_id=ac.get("id");this.hda_ldda=ac.get("hda_ldda");this.dataset=ac;this.data_manager.set("dataset",ac)},set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},before_draw:function(){this.max_height_px=0},postdraw_actions:function(ar,am,ah,ag){M.prototype.postdraw_actions.call(this,ar,ag);var al=this,ao;if(al.mode==="Coverage"){var ad=-1;for(ao=0;ao<ar.length;ao++){var an=ar[ao].max_val;if(an>ad){ad=an}}for(ao=0;ao<ar.length;ao++){var au=ar[ao];if(au.max_val!==ad){au.html_elt.remove();al.draw_helper(true,am,au.index,au.resolution,au.html_elt.parent(),ah,{more_tile_data:{max:ad}})}}}if(al.filters_manager){var ai=al.filters_manager.filters;for(var aq=0;aq<ai.length;aq++){ai[aq].update_ui_elt()}var at=false,ac,aj;for(ao=0;ao<ar.length;ao++){if(ar[ao].data.length){ac=ar[ao].data[0];for(var aq=0;aq<ai.length;aq++){aj=ai[aq];if(aj.applies_to(ac)&&aj.min!==aj.max){at=true;break}}}}if(al.filters_available!==at){al.filters_available=at;if(!al.filters_available){al.filters_manager.hide()}al.update_icons()}}this.container_div.find(".yaxislabel").remove();var af=ar[0];if(af instanceof j){var ak=(this.prefs.histogram_max?this.prefs.histogram_max:af.max_val),ae=$("<div/>").text(ak).make_text_editable({num_cols:12,on_finish:function(av){$(".bs-tooltip").remove();var av=parseFloat(av);al.prefs.histogram_max=(!isNaN(av)?av:null);al.tile_cache.clear();al.request_draw()},help_text:"Set max value; leave blank to use default"}).addClass("yaxislabel top").css("color",this.prefs.label_color);this.container_div.prepend(ae)}if(af instanceof O){var ap=true;for(ao=0;ao<ar.length;ao++){if(!ar[ao].all_slotted){ap=false;break}}if(!ap){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(ac){var ac;if(this.mode==="Auto"){if(ac==="no_detail"){ac="feature spans"}else{if(ac==="summary_tree"){ac="coverage histogram"}}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ac+")")}},incremental_slots:function(ag,ac,af){var ad=this.view.canvas_manager.dummy_context,ae=this.slotters[ag];if(!ae||(ae.mode!==af)){ae=new (u.FeatureSlotter)(ag,af,A,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){if(ac.dataset_type==="summary_tree"){mode="summary_tree"}else{if(ac.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>I){mode="Squish"}else{mode="Pack"}}}return mode},get_canvas_height:function(ac,ag,ah,ad){if(ag==="summary_tree"||ag==="Coverage"){return this.summary_draw_height}else{var af=this.incremental_slots(ah,ac.data,ag);var ae=new (this.painter)(null,null,null,this.prefs,ag);return Math.max(aa,ae.get_required_height(af,ad))}},draw_tile:function(am,aq,ao,ar,af,aj,ae){var ap=this,ad=aq.canvas,ay=af.get("start"),ac=af.get("end"),ag=this.left_offset;if(ao==="summary_tree"||ao==="Coverage"){var aA=new L.SummaryTreePainter(am,ay,ac,this.prefs);aA.draw(aq,ad.width,ad.height,aj);return new j(ap,af,ar,ad,am.data,am.max)}var ai=[],an=this.slotters[aj].slots;all_slotted=true;if(am.data){var ak=this.filters_manager.filters;for(var at=0,av=am.data.length;at<av;at++){var ah=am.data[at];var au=false;var al;for(var ax=0,aC=ak.length;ax<aC;ax++){al=ak[ax];al.update_attrs(ah);if(!al.keep(ah)){au=true;break}}if(!au){ai.push(ah);if(!(ah[0] in an)){all_slotted=false}}}}var aB=(this.filters_manager.alpha_filter?new C(this.filters_manager.alpha_filter):null);var az=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null);var aA=new (this.painter)(ai,ay,ac,this.prefs,ao,aB,az,ae);var aw=null;aq.fillStyle=this.prefs.block_color;aq.font=aq.canvas.manager.default_font;aq.textAlign="right";if(am.data){aw=aA.draw(aq,ad.width,ad.height,aj,an);aw.translation=-ag}return new O(ap,af,ar,ad,am.data,aj,ao,am.message,all_slotted,aw)},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="summary_tree"}else{if(ac.extra_info==="no_detail"||ac.dataset_type==="summary_tree"){return false}else{return true}}}},can_subset:function(ac){if(ac.dataset_type==="summary_tree"||ac.message||ac.extra_info==="no_detail"){return false}return true}});var R=function(ad,ac,ae){c.call(this,ad,ac,ae);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:l.get_random_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_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ae.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter};q(R.prototype,r.prototype,M.prototype,c.prototype);var T=function(ae,ad,ag){c.call(this,ae,ad,ag);var af=l.get_random_color(),ac=l.get_random_color([af,"#ffffff"]);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block and sense strand color",type:"color",default_value:af},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ac},{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:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"Clear value to set automatically"},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter;this.update_icons()};q(T.prototype,r.prototype,M.prototype,c.prototype);var d={LineTrack:h,FeatureTrack:c,VcfTrack:R,ReadTrack:T,CompositeTrack:f,DrawableGroup:P};var p=function(ae,ad,ac){if("copy" in ae){return ae.copy(ac)}else{var af=ae.obj_type;if(!af){af=ae.track_type}return new d[af](ad,ac,ae)}};return{View:Y,DrawableGroup:P,LineTrack:h,FeatureTrack:c,DiagonalHeatmapTrack:t,ReadTrack:T,VcfTrack:R,CompositeTrack:f,object_from_template:p}});
\ No newline at end of file
diff -r 4cd4f8bef29d17a7bca74e235031060e2289ebdc -r 8bcc04c4b710dbf4173a5fba6d2a3111e7c2b511 static/scripts/packed/viz/trackster_ui.js
--- a/static/scripts/packed/viz/trackster_ui.js
+++ b/static/scripts/packed/viz/trackster_ui.js
@@ -1,1 +1,1 @@
-define(["base","libs/underscore","viz/trackster/slotting","viz/trackster/painters","viz/trackster/tracks","viz/visualization"],function(g,c,h,e,b,d){var a=b.object_from_template;var f=g.Base.extend({initialize:function(j){this.baseURL=j},createButtonMenu:function(){var j=this,k=create_icon_buttons_menu([{icon_class:"plus-button",title:"Add tracks",on_click:function(){d.select_datasets(select_datasets_url,add_track_async_url,{"f-dbkey":view.dbkey},function(l){c.each(l,function(m){view.add_drawable(a(m,view,view))})})}},{icon_class:"block--plus",title:"Add group",on_click:function(){view.add_drawable(new b.DrawableGroup(view,view,{name:"New Group"}))}},{icon_class:"bookmarks",title:"Bookmarks",on_click:function(){parent.force_right_panel(($("div#right").css("right")=="0px"?"hide":"show"))}},{icon_class:"globe",title:"Circster",on_click:function(){window.location=j.baseURL+"visualization/circster?id="+view.vis_id}},{icon_class:"disk--arrow",title:"Save",on_click:function(){show_modal("Saving...","progress");var l=[];$(".bookmark").each(function(){l.push({position:$(this).children(".position").text(),annotation:$(this).children(".annotation").text()})});var m=(view.overview_drawable?view.overview_drawable.name:null),n={id:view.vis_id,title:view.name,dbkey:view.dbkey,type:"trackster",datasets:view.to_dict(),viewport:{chrom:view.chrom,start:view.low,end:view.high,overview:m},bookmarks:l};$.ajax({url:galaxy_paths.get("visualization_url"),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(n)}}).success(function(o){hide_modal();view.vis_id=o.vis_id;view.has_changes=false;window.history.pushState({},"",o.url+window.location.hash)}).error(function(){show_modal("Could Not Save","Could not save visualization. Please try again later.",{Close:hide_modal})})}},{icon_class:"cross-circle",title:"Close",on_click:function(){window.location=j.baseURL+"visualization/list"}}],{tooltip_config:{placement:"bottom"}});this.buttonMenu=k;return k},add_bookmarks:function(){var j=this,k=this.baseURL;show_modal("Select dataset for new bookmarks","progress");$.ajax({url:this.baseURL+"/visualization/list_histories",data:{"f-dbkey":view.dbkey},error:function(){alert("Grid failed")},success:function(l){show_modal("Select dataset for new bookmarks",l,{Cancel:function(){hide_modal()},Insert:function(){$("input[name=id]:checked,input[name=ldda_ids]:checked").first().each(function(){var m,n=$(this).val();if($(this).attr("name")==="id"){m={hda_id:n}}else{m={ldda_id:n}}$.ajax({url:this.baseURL+"/visualization/bookmarks_from_dataset",data:m,dataType:"json"}).then(function(o){for(i=0;i<o.data.length;i++){var p=o.data[i];j.add_bookmark(p[0],p[1])}})});hide_modal()}})}})},add_bookmark:function(n,l,j){var p=$("#bookmarks-container"),r=$("<div/>").addClass("bookmark").appendTo(p);var s=$("<div/>").addClass("position").appendTo(r),o=$("<a href=''/>").text(n).appendTo(s).click(function(){view.go_to(n);return false}),m=$("<div/>").text(l).appendTo(r);if(j){var q=$("<div/>").addClass("delete-icon-container").prependTo(r).click(function(){r.slideUp("fast");r.remove();view.has_changes=true;return false}),k=$("<a href=''/>").addClass("icon-button delete").appendTo(q);m.make_text_editable({num_rows:3,use_textarea:true,help_text:"Edit bookmark note"}).addClass("annotation")}view.has_changes=true;return r},create_visualization:function(o,j,n,p,m){var l=this,k=new b.View(o);k.editor=true;$.when(k.load_chroms_deferred).then(function(){if(j){var y=j.chrom,q=j.start,v=j.end,s=j.overview;if(y&&(q!==undefined)&&v){k.change_chrom(y,q,v)}}if(n){var t,r,u;for(var w=0;w<n.length;w++){k.add_drawable(a(n[w],k,k))}}k.update_intro_div();var z;for(var w=0;w<k.drawables.length;w++){if(k.drawables[w].name===s){k.set_overview(k.drawables[w]);break}}if(p){var x;for(var w=0;w<p.length;w++){x=p[w];l.add_bookmark(x.position,x.annotation,m)}}k.has_changes=false});return k},init_keyboard_nav:function(j){$(document).keydown(function(k){if($(k.srcElement).is(":input")){return}switch(k.which){case 37:j.move_fraction(0.25);break;case 38:var l=Math.round(j.viewport_container.height()/15);j.viewport_container.scrollTop(j.viewport_container.scrollTop()-20);break;case 39:j.move_fraction(-0.25);break;case 40:var l=Math.round(j.viewport_container.height()/15);j.viewport_container.scrollTop(j.viewport_container.scrollTop()+20);break}})}});return{object_from_template:a,TracksterUI:f}});
\ No newline at end of file
+define(["base","libs/underscore","viz/trackster/slotting","viz/trackster/painters","viz/trackster/tracks","viz/visualization"],function(g,c,h,e,b,d){var a=b.object_from_template;var f=g.Base.extend({initialize:function(j){this.baseURL=j},createButtonMenu:function(){var j=this,k=create_icon_buttons_menu([{icon_class:"plus-button",title:"Add tracks",on_click:function(){d.select_datasets(select_datasets_url,add_track_async_url,view.dbkey,function(l){c.each(l,function(m){view.add_drawable(a(m,view,view))})})}},{icon_class:"block--plus",title:"Add group",on_click:function(){view.add_drawable(new b.DrawableGroup(view,view,{name:"New Group"}))}},{icon_class:"bookmarks",title:"Bookmarks",on_click:function(){parent.force_right_panel(($("div#right").css("right")=="0px"?"hide":"show"))}},{icon_class:"globe",title:"Circster",on_click:function(){window.location=j.baseURL+"visualization/circster?id="+view.vis_id}},{icon_class:"disk--arrow",title:"Save",on_click:function(){show_modal("Saving...","progress");var l=[];$(".bookmark").each(function(){l.push({position:$(this).children(".position").text(),annotation:$(this).children(".annotation").text()})});var m=(view.overview_drawable?view.overview_drawable.name:null),n={id:view.vis_id,title:view.name,dbkey:view.dbkey,type:"trackster",datasets:view.to_dict(),viewport:{chrom:view.chrom,start:view.low,end:view.high,overview:m},bookmarks:l};$.ajax({url:galaxy_paths.get("visualization_url"),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(n)}}).success(function(o){hide_modal();view.vis_id=o.vis_id;view.has_changes=false;window.history.pushState({},"",o.url+window.location.hash)}).error(function(){show_modal("Could Not Save","Could not save visualization. Please try again later.",{Close:hide_modal})})}},{icon_class:"cross-circle",title:"Close",on_click:function(){window.location=j.baseURL+"visualization/list"}}],{tooltip_config:{placement:"bottom"}});this.buttonMenu=k;return k},add_bookmarks:function(){var j=this,k=this.baseURL;show_modal("Select dataset for new bookmarks","progress");$.ajax({url:this.baseURL+"/visualization/list_histories",data:{"f-dbkey":view.dbkey},error:function(){alert("Grid failed")},success:function(l){show_modal("Select dataset for new bookmarks",l,{Cancel:function(){hide_modal()},Insert:function(){$("input[name=id]:checked,input[name=ldda_ids]:checked").first().each(function(){var m,n=$(this).val();if($(this).attr("name")==="id"){m={hda_id:n}}else{m={ldda_id:n}}$.ajax({url:this.baseURL+"/visualization/bookmarks_from_dataset",data:m,dataType:"json"}).then(function(o){for(i=0;i<o.data.length;i++){var p=o.data[i];j.add_bookmark(p[0],p[1])}})});hide_modal()}})}})},add_bookmark:function(n,l,j){var p=$("#bookmarks-container"),r=$("<div/>").addClass("bookmark").appendTo(p);var s=$("<div/>").addClass("position").appendTo(r),o=$("<a href=''/>").text(n).appendTo(s).click(function(){view.go_to(n);return false}),m=$("<div/>").text(l).appendTo(r);if(j){var q=$("<div/>").addClass("delete-icon-container").prependTo(r).click(function(){r.slideUp("fast");r.remove();view.has_changes=true;return false}),k=$("<a href=''/>").addClass("icon-button delete").appendTo(q);m.make_text_editable({num_rows:3,use_textarea:true,help_text:"Edit bookmark note"}).addClass("annotation")}view.has_changes=true;return r},create_visualization:function(o,j,n,p,m){var l=this,k=new b.View(o);k.editor=true;$.when(k.load_chroms_deferred).then(function(){if(j){var y=j.chrom,q=j.start,v=j.end,s=j.overview;if(y&&(q!==undefined)&&v){k.change_chrom(y,q,v)}}if(n){var t,r,u;for(var w=0;w<n.length;w++){k.add_drawable(a(n[w],k,k))}}k.update_intro_div();var z;for(var w=0;w<k.drawables.length;w++){if(k.drawables[w].name===s){k.set_overview(k.drawables[w]);break}}if(p){var x;for(var w=0;w<p.length;w++){x=p[w];l.add_bookmark(x.position,x.annotation,m)}}k.has_changes=false});return k},init_keyboard_nav:function(j){$(document).keydown(function(k){if($(k.srcElement).is(":input")){return}switch(k.which){case 37:j.move_fraction(0.25);break;case 38:var l=Math.round(j.viewport_container.height()/15);j.viewport_container.scrollTop(j.viewport_container.scrollTop()-20);break;case 39:j.move_fraction(-0.25);break;case 40:var l=Math.round(j.viewport_container.height()/15);j.viewport_container.scrollTop(j.viewport_container.scrollTop()+20);break}})}});return{object_from_template:a,TracksterUI:f}});
\ No newline at end of file
diff -r 4cd4f8bef29d17a7bca74e235031060e2289ebdc -r 8bcc04c4b710dbf4173a5fba6d2a3111e7c2b511 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"],function(r,i,k){var a=function(u,w,t,v){$.ajax({url:u,data:t,error:function(){alert("Grid failed")},success:function(x){show_modal("Select datasets for new tracks",x,{Cancel:function(){hide_modal()},Add:function(){var y=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var z={data_type:"track_config",hda_ldda:"hda"},A=$(this).val();if($(this).attr("name")!=="id"){z.hda_ldda="ldda"}y[y.length]=$.ajax({url:w+"/"+A,data:z,dataType:"json"})});$.when.apply($,y).then(function(){var z=(arguments[0] instanceof Array?$.map(arguments,function(A){return A[0]}):[arguments[0]]);v(z)});hide_modal()}})}})};var j=function(t){return("isResolved" in t)};var f=function(t){this.default_font=t!==undefined?t:"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")};r.extend(f.prototype,{load_pattern:function(t,x){var u=this.patterns,v=this.dummy_context,w=new Image();w.src=galaxy_paths.attributes.image_path+x;w.onload=function(){u[t]=v.createPattern(w,"repeat")}},get_pattern:function(t){return this.patterns[t]},new_canvas:function(){var t=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(t)}t.manager=this;return t}});var p=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(t){this.clear()},get_elt:function(u){var v=this.attributes.obj_cache,w=this.attributes.key_ary,t=w.indexOf(u);if(t!==-1){if(v[u].stale){w.splice(t,1);delete v[u]}else{this.move_key_to_end(u,t)}}return v[u]},set_elt:function(u,w){var x=this.attributes.obj_cache,y=this.attributes.key_ary,v=this.attributes.num_elements;if(!x[u]){if(y.length>=v){var t=y.shift();delete x[t]}y.push(u)}x[u]=w;return w},move_key_to_end:function(u,t){this.attributes.key_ary.splice(t,1);this.attributes.key_ary.push(u)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length}});var d=p.extend({defaults:r.extend({},p.prototype.defaults,{dataset:null,init_data:null,filters_manager:null,data_type:"data",data_mode_compatible:function(t,u){return true},can_subset:function(t){return false}}),initialize:function(t){p.prototype.initialize.call(this);var u=this.get("init_data");if(u){this.add_data(u)}},add_data:function(t){if(this.get("num_elements")<t.length){this.set("num_elements",t.length)}var u=this;r.each(t,function(v){u.set_data(v.region,v)})},data_is_ready:function(){var w=this.get("dataset"),v=$.Deferred(),t=(this.get("data_type")=="raw_data"?"state":this.get("data_type")=="data"?"converted_datasets_state":"error"),u=new k.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:w.get("hda_ldda"),data_type:t},dataType:"json"},interval:5000,success_fn:function(x){return x!=="pending"}});$.when(u.go()).then(function(x){v.resolve(x==="ok"||x==="data")});return v},search_features:function(t){var u=this.get("dataset"),v={query:t,hda_ldda:u.get("hda_ldda"),data_type:"features"};return $.getJSON(u.url(),v)},load_data:function(B,A,u,z){var x=this.get("dataset"),w={data_type:this.get("data_type"),chrom:B.get("chrom"),low:B.get("start"),high:B.get("end"),mode:A,resolution:u,hda_ldda:x.get("hda_ldda")};$.extend(w,z);var D=this.get("filters_manager");if(D){var E=[];var t=D.filters;for(var y=0;y<t.length;y++){E.push(t[y].name)}w.filter_cols=JSON.stringify(E)}var v=this,C=$.getJSON(x.url(),w,function(F){v.set_data(B,F)});this.set_data(B,C);return C},get_data:function(z,y,v,x){var A=this.get_elt(z);if(A&&(j(A)||this.get("data_mode_compatible")(A,y))){return A}var B=this.get("key_ary"),u=this.get("obj_cache"),C,t;for(var w=0;w<B.length;w++){C=B[w];t=new g({from_str:C});if(t.contains(z)){A=u[C];if(j(A)||(this.get("data_mode_compatible")(A,y)&&this.get("can_subset")(A))){this.move_key_to_end(C,w);return A}}}return this.load_data(z,y,v,x)},set_data:function(u,t){this.set_elt(u,t)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(B,A,w,z,x){var D=this._mark_stale(B);if(!(D&&this.get("data_mode_compatible")(D,A))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var v=B.get("start");if(x===this.DEEP_DATA_REQ){$.extend(z,{start_val:D.data.length+1})}else{if(x===this.BROAD_DATA_REQ){v=(D.max_high?D.max_high:D.data[D.data.length-1][2])+1}}var C=B.copy().set("start",v);var u=this,y=this.load_data(C,A,w,z),t=$.Deferred();this.set_data(B,t);$.when(y).then(function(E){if(E.data){E.data=D.data.concat(E.data);if(E.max_low){E.max_low=D.max_low}if(E.message){E.message=E.message.replace(/[0-9]+/,E.data.length)}}u.set_data(B,E);t.resolve(E)});return t},get_more_detailed_data:function(w,y,u,x,v){var t=this._mark_stale(w);if(!t){console.log("ERROR getting more detailed data: no current data");return}if(!v){v={}}if(t.dataset_type==="bigwig"){v.num_samples=t.data.length*x}else{if(t.dataset_type==="summary_tree"){v.level=Math.min(t.level-1,2)}}return this.load_data(w,y,u,v)},_mark_stale:function(u){var t=this.get_elt(u);if(!t){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),u.toString())}t.stale=true;return t},get_genome_wide_data:function(t){var v=this,x=true,w=r.map(t.get("chroms_info").chrom_info,function(z){var y=v.get_elt(new g({chrom:z.chrom,start:0,end:z.len}));if(!y){x=false}return y});if(x){return w}var u=$.Deferred();$.getJSON(this.get("dataset").url(),{data_type:"genome_data"},function(y){v.add_data(y.data);u.resolve(y.data)});return u},get_elt:function(t){return p.prototype.get_elt.call(this,t.toString())},set_elt:function(u,t){return p.prototype.set_elt.call(this,u.toString(),t)}});var n=d.extend({initialize:function(t){var u=new Backbone.Model();u.urlRoot=t.data_url;this.set("dataset",u)},load_data:function(v,w,t,u){if(t>1){return{data:null}}return d.prototype.load_data.call(this,v,w,t,u)}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(t){this.id=t.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(t){var u=r.find(this.get_chroms_info(),function(v){return v.chrom==t});return new g({chrom:u.chrom,end:u.len})}});var g=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0,DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006},initialize:function(u){if(u.from_str){var w=u.from_str.split(":"),v=w[0],t=w[1].split("-");this.set({chrom:v,start:parseInt(t[0],10),end:parseInt(t[1],10)})}},copy:function(){return new g({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.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(A){var u=this.get("chrom"),z=A.get("chrom"),y=this.get("start"),w=A.get("start"),x=this.get("end"),v=A.get("end"),t;if(u&&z&&u!==z){return this.get("DIF_CHROMS")}if(y<w){if(x<w){t=this.get("BEFORE")}else{if(x<=v){t=this.get("OVERLAP_START")}else{t=this.get("CONTAINS")}}}else{if(y>v){t=this.get("AFTER")}else{if(x<=v){t=this.get("CONTAINED_BY")}else{t=this.get("OVERLAP_END")}}}return t},contains:function(t){return this.compute_overlap(t)===this.get("CONTAINS")},overlaps:function(t){return r.intersection([this.compute_overlap(t)],[this.get("DIF_CHROMS"),this.get("BEFORE"),this.get("AFTER")]).length===0}});var m=Backbone.Collection.extend({model:g});var e=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:g}]});var q=Backbone.Collection.extend({model:e});var s=i.Dataset.extend({initialize:function(t){this.set("id",t.dataset_id);var u=this.get("preloaded_data");if(u){u=u.data}else{u=[]}this.set("data_manager",new d({dataset:this,init_data:u}))}});var o=Backbone.RelationalModel.extend({defaults:{title:"",type:""},url:function(){return galaxy_paths.get("visualization_url")},save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var l=o.extend({defaults:r.extend({},o.prototype.defaults,{dbkey:"",tracks:null,bookmarks:null,viewport:null}),relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:s}],add_track:function(t){this.get("tracks").push(t)}});var b=Backbone.Model.extend({});var h=Backbone.Router.extend({initialize:function(u){this.view=u.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var t=this;t.view.on("navigate",function(v){t.navigate(v)})},change_location:function(t){this.view.go_to(t)}});return{BackboneTrack:s,BrowserBookmark:e,BrowserBookmarkCollection:q,Cache:p,CanvasManager:f,Genome:c,GenomeDataManager:d,GenomeRegion:g,GenomeRegionCollection:m,GenomeVisualization:l,ReferenceTrackDataManager:n,TrackBrowserRouter:h,TrackConfig:b,Visualization:o,select_datasets:a}});
\ No newline at end of file
+define(["libs/underscore","mvc/data","viz/trackster/util","utils/config"],function(s,i,l,p){var a=function(u,x,v,w){$.ajax({url:u,data:(v?{"f-dbkey":v}:{}),error:function(){alert("Grid failed")},success:function(y){show_modal("Select datasets for new tracks",y,{Cancel:function(){hide_modal()},Add:function(){var z=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var A={data_type:"track_config",hda_ldda:"hda"},B=$(this).val();if($(this).attr("name")!=="id"){A.hda_ldda="ldda"}z[z.length]=$.ajax({url:x+"/"+B,data:A,dataType:"json"})});$.when.apply($,z).then(function(){var A=(arguments[0] instanceof Array?$.map(arguments,function(B){return B[0]}):[arguments[0]]);w(A)});hide_modal()}})}})};var j=function(u){return("isResolved" in u)};var f=function(u){this.default_font=u!==undefined?u:"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")};s.extend(f.prototype,{load_pattern:function(u,y){var v=this.patterns,w=this.dummy_context,x=new Image();x.src=galaxy_paths.attributes.image_path+y;x.onload=function(){v[u]=w.createPattern(x,"repeat")}},get_pattern:function(u){return this.patterns[u]},new_canvas:function(){var u=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(u)}u.manager=this;return u}});var q=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(u){this.clear()},get_elt:function(v){var w=this.attributes.obj_cache,x=this.attributes.key_ary,u=x.indexOf(v);if(u!==-1){if(w[v].stale){x.splice(u,1);delete w[v]}else{this.move_key_to_end(v,u)}}return w[v]},set_elt:function(v,x){var y=this.attributes.obj_cache,z=this.attributes.key_ary,w=this.attributes.num_elements;if(!y[v]){if(z.length>=w){var u=z.shift();delete y[u]}z.push(v)}y[v]=x;return x},move_key_to_end:function(v,u){this.attributes.key_ary.splice(u,1);this.attributes.key_ary.push(v)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length}});var d=q.extend({defaults:s.extend({},q.prototype.defaults,{dataset:null,init_data:null,filters_manager:null,data_type:"data",data_mode_compatible:function(u,v){return true},can_subset:function(u){return false}}),initialize:function(u){q.prototype.initialize.call(this);var v=this.get("init_data");if(v){this.add_data(v)}},add_data:function(u){if(this.get("num_elements")<u.length){this.set("num_elements",u.length)}var v=this;s.each(u,function(w){v.set_data(w.region,w)})},data_is_ready:function(){var x=this.get("dataset"),w=$.Deferred(),u=(this.get("data_type")=="raw_data"?"state":this.get("data_type")=="data"?"converted_datasets_state":"error"),v=new l.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:x.get("hda_ldda"),data_type:u},dataType:"json"},interval:5000,success_fn:function(y){return y!=="pending"}});$.when(v.go()).then(function(y){w.resolve(y==="ok"||y==="data")});return w},search_features:function(u){var v=this.get("dataset"),w={query:u,hda_ldda:v.get("hda_ldda"),data_type:"features"};return $.getJSON(v.url(),w)},load_data:function(C,B,v,A){var y=this.get("dataset"),x={data_type:this.get("data_type"),chrom:C.get("chrom"),low:C.get("start"),high:C.get("end"),mode:B,resolution:v,hda_ldda:y.get("hda_ldda")};$.extend(x,A);var E=this.get("filters_manager");if(E){var F=[];var u=E.filters;for(var z=0;z<u.length;z++){F.push(u[z].name)}x.filter_cols=JSON.stringify(F)}var w=this,D=$.getJSON(y.url(),x,function(G){w.set_data(C,G)});this.set_data(C,D);return D},get_data:function(A,z,w,y){var B=this.get_elt(A);if(B&&(j(B)||this.get("data_mode_compatible")(B,z))){return B}var C=this.get("key_ary"),v=this.get("obj_cache"),D,u;for(var x=0;x<C.length;x++){D=C[x];u=new g({from_str:D});if(u.contains(A)){B=v[D];if(j(B)||(this.get("data_mode_compatible")(B,z)&&this.get("can_subset")(B))){this.move_key_to_end(D,x);return B}}}return this.load_data(A,z,w,y)},set_data:function(v,u){this.set_elt(v,u)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(C,B,x,A,y){var E=this._mark_stale(C);if(!(E&&this.get("data_mode_compatible")(E,B))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var w=C.get("start");if(y===this.DEEP_DATA_REQ){$.extend(A,{start_val:E.data.length+1})}else{if(y===this.BROAD_DATA_REQ){w=(E.max_high?E.max_high:E.data[E.data.length-1][2])+1}}var D=C.copy().set("start",w);var v=this,z=this.load_data(D,B,x,A),u=$.Deferred();this.set_data(C,u);$.when(z).then(function(F){if(F.data){F.data=E.data.concat(F.data);if(F.max_low){F.max_low=E.max_low}if(F.message){F.message=F.message.replace(/[0-9]+/,F.data.length)}}v.set_data(C,F);u.resolve(F)});return u},get_more_detailed_data:function(x,z,v,y,w){var u=this._mark_stale(x);if(!u){console.log("ERROR getting more detailed data: no current data");return}if(!w){w={}}if(u.dataset_type==="bigwig"){w.num_samples=u.data.length*y}else{if(u.dataset_type==="summary_tree"){w.level=Math.min(u.level-1,2)}}return this.load_data(x,z,v,w)},_mark_stale:function(v){var u=this.get_elt(v);if(!u){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),v.toString())}u.stale=true;return u},get_genome_wide_data:function(u){var w=this,y=true,x=s.map(u.get("chroms_info").chrom_info,function(A){var z=w.get_elt(new g({chrom:A.chrom,start:0,end:A.len}));if(!z){y=false}return z});if(y){return x}var v=$.Deferred();$.getJSON(this.get("dataset").url(),{data_type:"genome_data"},function(z){w.add_data(z.data);v.resolve(z.data)});return v},get_elt:function(u){return q.prototype.get_elt.call(this,u.toString())},set_elt:function(v,u){return q.prototype.set_elt.call(this,v.toString(),u)}});var n=d.extend({initialize:function(u){var v=new Backbone.Model();v.urlRoot=u.data_url;this.set("dataset",v)},load_data:function(w,x,u,v){if(u>1){return{data:null}}return d.prototype.load_data.call(this,w,x,u,v)}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(u){this.id=u.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(u){var v=s.find(this.get_chroms_info(),function(w){return w.chrom==u});return new g({chrom:v.chrom,end:v.len})}});var g=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0,DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006},initialize:function(v){if(v.from_str){var x=v.from_str.split(":"),w=x[0],u=x[1].split("-");this.set({chrom:w,start:parseInt(u[0],10),end:parseInt(u[1],10)})}},copy:function(){return new g({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.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(B){var v=this.get("chrom"),A=B.get("chrom"),z=this.get("start"),x=B.get("start"),y=this.get("end"),w=B.get("end"),u;if(v&&A&&v!==A){return this.get("DIF_CHROMS")}if(z<x){if(y<x){u=this.get("BEFORE")}else{if(y<=w){u=this.get("OVERLAP_START")}else{u=this.get("CONTAINS")}}}else{if(z>w){u=this.get("AFTER")}else{if(y<=w){u=this.get("CONTAINED_BY")}else{u=this.get("OVERLAP_END")}}}return u},contains:function(u){return this.compute_overlap(u)===this.get("CONTAINS")},overlaps:function(u){return s.intersection([this.compute_overlap(u)],[this.get("DIF_CHROMS"),this.get("BEFORE"),this.get("AFTER")]).length===0}});var m=Backbone.Collection.extend({model:g});var e=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:g}]});var r=Backbone.Collection.extend({model:e});var t=i.Dataset.extend({initialize:function(u){this.set("id",u.dataset_id);this.set("settings",p.ConfigSettingCollection.from_config_dict(u.prefs));var v=this.get("preloaded_data");if(v){v=v.data}else{v=[]}this.set("data_manager",new d({dataset:this,init_data:v}))}});var o=Backbone.RelationalModel.extend({defaults:{title:"",type:""},url:function(){return galaxy_paths.get("visualization_url")},save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var k=o.extend({defaults:s.extend({},o.prototype.defaults,{dbkey:"",tracks:null,bookmarks:null,viewport:null}),relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:t}],add_tracks:function(u){this.get("tracks").add(u)}});var b=Backbone.Model.extend({});var h=Backbone.Router.extend({initialize:function(v){this.view=v.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var u=this;u.view.on("navigate",function(w){u.navigate(w)})},change_location:function(u){this.view.go_to(u)}});return{BackboneTrack:t,BrowserBookmark:e,BrowserBookmarkCollection:r,Cache:q,CanvasManager:f,Genome:c,GenomeDataManager:d,GenomeRegion:g,GenomeRegionCollection:m,GenomeVisualization:k,ReferenceTrackDataManager:n,TrackBrowserRouter:h,TrackConfig:b,Visualization:o,select_datasets:a}});
\ No newline at end of file
diff -r 4cd4f8bef29d17a7bca74e235031060e2289ebdc -r 8bcc04c4b710dbf4173a5fba6d2a3111e7c2b511 static/scripts/utils/config.js
--- /dev/null
+++ b/static/scripts/utils/config.js
@@ -0,0 +1,298 @@
+define(['libs/underscore', 'viz/trackster/util'], function(_, util_mod) {
+
+/**
+ * A configuration setting. Currently key is used as id.
+ */
+var ConfigSetting = Backbone.Model.extend({
+ defaults: {
+ key: null,
+ value: null,
+ type: 'text',
+ label: null,
+ options: null,
+ hidden: false
+ },
+
+ initialize: function(options) {
+ // Use key as id for now.
+ var key = this.get('key');
+ this.set('id', key);
+
+ // Set defaults based on key.
+ var defaults = _.find(ConfigSetting.known_settings, function(s) { return s.key === key; });
+ if (defaults) {
+ this.set(_.extend({}, defaults, options));
+ }
+
+ // If type color, get random color.
+ if (this.get('type') === 'color') {
+ this.set('value', util_mod.get_random_color());
+ }
+
+ // When value updated, cast is appropriately.
+ this.on('change:value', this.cast_value, this);
+ },
+
+ /**
+ * Cast value from string to appropriate type.
+ */
+ cast_value: function() {
+ var type = this.get('type'),
+ value = this.get('value');
+
+ if (type === 'float') {
+ value = parseFloat( value );
+ } else if (type === 'int') {
+ value = parseInt( value, 10 );
+ }
+ // TODO: handle casting from string to bool?
+
+ this.set('value');
+ }
+}, {
+ // Keep a master list of settings. This list is useful to fetching attributes based on key.
+ known_settings: [
+ { key: 'name', label: 'Name', type: 'text', default_value: '' },
+ { key: 'color', label: 'Color', type: 'color', default_value: undefined },
+ { 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: 32, hidden: true },
+ { key: 'pos_color', label: 'Positive Color', type: 'color', default_value: "4169E1" },
+ { key: 'negative_color', label: 'Negative Color', type: 'color', default_value: "FF8C00" },
+ { key: 'block_color', label: 'Block color', type: 'color', default_value: undefined },
+ { 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: undefined },
+ { key: 'show_differences', label: 'Show differences only', type: 'bool', default_value: true },
+ { key: 'histogram_max', label: 'Histogram maximum', type: 'float', default_value: null, help: 'Clear value to set automatically' },
+ { key: 'mode', type: 'string', default_value: this.mode, hidden: true }
+ ]
+});
+
+/**
+ * Collection of config settings.
+ */
+var ConfigSettingCollection = Backbone.Collection.extend({
+ model: ConfigSetting,
+
+ /**
+ * Save settings as a dictionary of key-value pairs.
+ * This function is needed for backwards compatibility.
+ */
+ to_key_value_dict: function() {
+ var rval = {};
+ this.each(function(setting) {
+ rval[setting.get('key')] = setting.get('value');
+ });
+
+ return rval;
+ },
+
+ /**
+ * Restore settings' values from a dictionary of key-value pairs.
+ * This function is needed for backwards compatibility.
+ */
+ restore_values: function(values) {
+ var self = this;
+ _.keys(values, function(key) {
+ var setting = self.find(function(s) { return s.get('key') === key; });
+ if (setting) {
+ setting.set('value', values.key);
+ }
+ });
+ },
+
+ /**
+ * Returns value for a given key.
+ */
+ get_value: function(key) {
+ return this.get(key).get('value');
+ }
+}, {
+ /**
+ * Utility function that creates a ConfigSettingsCollection from a standard dictionary
+ * with configuration key-value pairs.
+ */
+ from_config_dict: function(config_dict) {
+ // Create a list of key-value dicts suitable for sending to a collection.
+ var settings_list = _.map(_.keys(config_dict), function(key) {
+ return {
+ key: key,
+ value: config_dict[key]
+ };
+ });
+
+ return new ConfigSettingCollection(settings_list);
+ }
+});
+
+/**
+ * Viewer for config settings collection.
+ */
+var ConfigSettingCollectionView = Backbone.View.extend({
+ className: 'config-settings-view',
+
+ /**
+ * Renders form for editing configuration settings.
+ */
+ render: function() {
+ var track_config = this.model;
+ var container = this.$el;
+ var param;
+
+ // Function to process parameters recursively
+ function handle_params( params, container ) {
+ for ( var index = 0; index < params.length; index++ ) {
+ param = params[index];
+ // Hidden params have no representation in the form
+ if ( param.hidden ) { continue; }
+ // Build row for param
+ var id = 'param_' + index;
+ var value = track_config.values[ param.key ];
+ var row = $("<div class='form-row' />").appendTo( container );
+ row.append( $('<label />').attr("for", id ).text( param.label + ":" ) );
+ // Draw parameter as checkbox
+ if ( type === 'bool' ) {
+ row.append( $('<input type="checkbox" />').attr("id", id ).attr("name", id ).attr( 'checked', value ) );
+ // Draw parameter as textbox
+ } else if ( type === 'text' ) {
+ row.append( $('<input type="text"/>').attr("id", id ).val(value).click( function() { $(this).select(); }));
+ // Draw paramter as select area
+ } else if ( type === 'select' ) {
+ var select = $('<select />').attr("id", id);
+ for ( var i = 0; i < param.options.length; i++ ) {
+ $("<option/>").text( param.options[i].label ).attr( "value", param.options[i].value ).appendTo( select );
+ }
+ select.val( value );
+ row.append( select );
+ // Draw parameter as color picker
+ } else if ( type === 'color' ) {
+ var
+ container_div = $("<div/>").appendTo(row),
+ input = $('<input />').attr("id", id ).attr("name", id ).val( value ).css("float", "left")
+ .appendTo(container_div).click(function(e) {
+ // Hide other pickers.
+ $(".bs-tooltip").removeClass( "in" );
+
+ // Show input's color picker.
+ var tip = $(this).siblings(".bs-tooltip").addClass( "in" );
+ tip.css( {
+ // left: $(this).position().left + ( $(input).width() / 2 ) - 60,
+ // top: $(this).position().top + $(this.height)
+ left: $(this).position().left + $(this).width() + 5,
+ top: $(this).position().top - ( $(tip).height() / 2 ) + ( $(this).height() / 2 )
+ } ).show();
+
+ // Click management:
+
+ // Keep showing tip if clicking in tip.
+ tip.click(function(e) {
+ e.stopPropagation();
+ });
+
+ // Hide tip if clicking outside of tip.
+ $(document).bind( "click.color-picker", function() {
+ tip.hide();
+ $(document).unbind( "click.color-picker" );
+ });
+
+ // No propagation to avoid triggering document click (and tip hiding) above.
+ e.stopPropagation();
+ }),
+ // Icon for setting a new random color; behavior set below.
+ new_color_icon = $("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(container_div)
+ .attr("title", "Set new random color").tooltip(),
+ // Color picker in tool tip style.
+ tip = $( "<div class='bs-tooltip right' style='position: absolute;' />" ).appendTo(container_div).hide(),
+ // Inner div for padding purposes
+ tip_inner = $("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(tip),
+ tip_arrow = $("<div class='tooltip-arrow'></div>").appendTo(tip),
+ farb_obj = $.farbtastic(tip_inner, { width: 100, height: 100, callback: input, color: value });
+
+ // Clear floating.
+ container_div.append( $("<div/>").css("clear", "both"));
+
+ // Use function to fix farb_obj value.
+ (function(fixed_farb_obj) {
+ new_color_icon.click(function() {
+ fixed_farb_obj.setColor(util_mod.get_random_color());
+ });
+ })(farb_obj);
+
+ }
+ else {
+ row.append( $('<input />').attr("id", id ).attr("name", id ).val( value ) );
+ }
+ // Help text
+ if ( param.help ) {
+ row.append( $("<div class='help'/>").text( param.help ) );
+ }
+ }
+ }
+ // Handle top level parameters in order
+ handle_params( this.params, container );
+
+ return this;
+ },
+
+ /**
+ * Render view in modal.
+ */
+ render_in_modal: function() {
+ // Set up handlers for cancel, ok button and for handling esc key.
+ var cancel_fn = function() { hide_modal(); $(window).unbind("keypress.check_enter_esc"); },
+ ok_fn = function() {
+ this.update_from_form();
+ hide_modal();
+ $(window).unbind("keypress.check_enter_esc");
+ },
+ check_enter_esc = function(e) {
+ if ((e.keyCode || e.which) === 27) { // Escape key
+ cancel_fn();
+ } else if ((e.keyCode || e.which) === 13) { // Enter key
+ ok_fn();
+ }
+ };
+
+ // Set keypress handler.
+ $(window).bind("keypress.check_enter_esc", check_enter_esc);
+
+ // Show modal.
+ if (this.$el.children().length === 0) {
+ this.render();
+ }
+ show_modal("Configure", drawable.config.build_form(), {
+ "Cancel": cancel_fn,
+ "OK": ok_fn
+ });
+ },
+
+ /**
+ * Update settings with new values entered via form.
+ */
+ update_from_form: function() {
+ var self = this;
+ this.collection.each(function(setting, index) {
+ if ( !setting.get('hidden') ) {
+ // Set value from view.
+ var id = 'param_' + index;
+ var value = self.$el.find( '#' + id ).val();
+ if ( type === 'bool' ) {
+ value = container.find( '#' + id ).is( ':checked' );
+ }
+ setting.set('value', value);
+ }
+ });
+ }
+
+});
+
+return {
+ ConfigSettingCollection: ConfigSettingCollection,
+ ConfigSettingCollectionView: ConfigSettingCollectionView
+};
+
+});
\ No newline at end of file
diff -r 4cd4f8bef29d17a7bca74e235031060e2289ebdc -r 8bcc04c4b710dbf4173a5fba6d2a3111e7c2b511 static/scripts/viz/visualization.js
--- a/static/scripts/viz/visualization.js
+++ b/static/scripts/viz/visualization.js
@@ -1,4 +1,5 @@
-define( ["libs/underscore", "mvc/data", "viz/trackster/util" ], function(_, data_mod, util_mod) {
+define( ["libs/underscore", "mvc/data", "viz/trackster/util", "utils/config"],
+ function(_, data_mod, util_mod, config_mod) {
/**
* Model, view, and controller objects for Galaxy visualization framework.
@@ -729,6 +730,9 @@
// Dataset id is unique ID for now.
this.set('id', options.dataset_id);
+ // -- Set up config settings. --
+ this.set('settings', config_mod.ConfigSettingCollection.from_config_dict(options.prefs));
+
// Set up data manager.
var preloaded_data = this.get('preloaded_data');
if (preloaded_data) {
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: Pass ids instead of objects when managing reviews from certain tool shed locations.
by Bitbucket 18 Oct '12
by Bitbucket 18 Oct '12
18 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/4cd4f8bef29d/
changeset: 4cd4f8bef29d
user: greg
date: 2012-10-18 22:51:36
summary: Pass ids instead of objects when managing reviews from certain tool shed locations.
affected #: 4 files
diff -r 69744b8777c6a37b1b440cfb352789e116c34e6b -r 4cd4f8bef29d17a7bca74e235031060e2289ebdc lib/galaxy/webapps/community/controllers/repository.py
--- a/lib/galaxy/webapps/community/controllers/repository.py
+++ b/lib/galaxy/webapps/community/controllers/repository.py
@@ -1684,8 +1684,9 @@
id,
changeset_revision,
trans.security.encode_id( trans.user.id ) )
+ review_id = trans.security.encode_id( review.id )
else:
- review = None
+ review_id = None
return trans.fill_template( '/webapps/community/repository/manage_repository.mako',
cntrller=cntrller,
repo_name=repo_name,
@@ -1698,7 +1699,7 @@
repository_metadata_id=repository_metadata_id,
changeset_revision=changeset_revision,
reviewed_by_user=reviewed_by_user,
- review=review,
+ review_id=review_id,
changeset_revision_select_field=changeset_revision_select_field,
revision_label=revision_label,
selected_categories=selected_categories,
@@ -2340,11 +2341,12 @@
reviewed_by_user = changeset_revision_reviewed_by_user( trans, trans.user, repository, changeset_revision )
if reviewed_by_user:
review = get_review_by_repository_id_changeset_revision_user_id( trans,
- repository_id,
+ id,
changeset_revision,
trans.security.encode_id( trans.user.id ) )
+ review_id = trans.security.encode_id( review.id )
else:
- review = None
+ review_id = None
return trans.fill_template( '/webapps/community/repository/view_repository.mako',
cntrller=cntrller,
repo=repo,
@@ -2357,7 +2359,7 @@
alerts_check_box=alerts_check_box,
changeset_revision=changeset_revision,
reviewed_by_user=reviewed_by_user,
- review=review,
+ review_id=review_id,
changeset_revision_select_field=changeset_revision_select_field,
revision_label=revision_label,
is_malicious=is_malicious,
@@ -2421,11 +2423,12 @@
reviewed_by_user = changeset_revision_reviewed_by_user( trans, trans.user, repository, changeset_revision )
if reviewed_by_user:
review = get_review_by_repository_id_changeset_revision_user_id( trans,
- repository_id,
+ id,
changeset_revision,
trans.security.encode_id( trans.user.id ) )
+ review_id = trans.security.encode_id( review.id )
else:
- review = None
+ review_id = None
return trans.fill_template( "/webapps/community/repository/view_tool_metadata.mako",
repository=repository,
metadata=metadata,
@@ -2437,7 +2440,7 @@
changeset_revision_select_field=changeset_revision_select_field,
is_malicious=is_malicious,
reviewed_by_user=reviewed_by_user,
- review=review,
+ review_id=review_id,
message=message,
status=status )
diff -r 69744b8777c6a37b1b440cfb352789e116c34e6b -r 4cd4f8bef29d17a7bca74e235031060e2289ebdc templates/webapps/community/repository/manage_repository.mako
--- a/templates/webapps/community/repository/manage_repository.mako
+++ b/templates/webapps/community/repository/manage_repository.mako
@@ -49,7 +49,7 @@
<ul class="manage-table-actions">
%if reviewing_repository:
%if reviewed_by_user:
- <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( review.id ) )}">Manage my review of this revision</a>
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=review_id )}">Manage my review of this revision</a>
%else:
<a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
%endif
@@ -61,7 +61,7 @@
<div popupmenu="repository-${repository.id}-popup">
%if can_review_repository:
%if reviewed_by_user:
- <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( review.id ) )}">Manage my review of this revision</a>
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=review_id )}">Manage my review of this revision</a>
%else:
<a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
%endif
diff -r 69744b8777c6a37b1b440cfb352789e116c34e6b -r 4cd4f8bef29d17a7bca74e235031060e2289ebdc templates/webapps/community/repository/view_repository.mako
--- a/templates/webapps/community/repository/view_repository.mako
+++ b/templates/webapps/community/repository/view_repository.mako
@@ -42,7 +42,7 @@
%if trans.webapp.name == 'community':
%if reviewing_repository:
%if reviewed_by_user:
- <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( review.id ) )}">Manage my review of this revision</a>
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=review_id )}">Manage my review of this revision</a>
%else:
<a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
%endif
@@ -54,7 +54,7 @@
<div popupmenu="repository-${repository.id}-popup">
%if can_review_repository:
%if reviewed_by_user:
- <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( review.id ) )}">Manage my review of this revision</a>
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=review_id )}">Manage my review of this revision</a>
%else:
<a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
%endif
diff -r 69744b8777c6a37b1b440cfb352789e116c34e6b -r 4cd4f8bef29d17a7bca74e235031060e2289ebdc templates/webapps/community/repository/view_tool_metadata.mako
--- a/templates/webapps/community/repository/view_tool_metadata.mako
+++ b/templates/webapps/community/repository/view_tool_metadata.mako
@@ -55,7 +55,7 @@
<div popupmenu="repository-${repository.id}-popup">
%if can_review_repository:
%if reviewed_by_user:
- <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( review.id ) )}">Manage my review of this revision</a>
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=review_id )}">Manage my review of this revision</a>
%else:
<a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
%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
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/69744b8777c6/
changeset: 69744b8777c6
user: greg
date: 2012-10-18 22:35:06
summary: fix typo.
affected #: 1 file
diff -r 20d002e4e423f3c0559ae6c74ec3040754aa3b86 -r 69744b8777c6a37b1b440cfb352789e116c34e6b lib/galaxy/webapps/community/controllers/repository.py
--- a/lib/galaxy/webapps/community/controllers/repository.py
+++ b/lib/galaxy/webapps/community/controllers/repository.py
@@ -1681,7 +1681,7 @@
reviewed_by_user = changeset_revision_reviewed_by_user( trans, trans.user, repository, changeset_revision )
if reviewed_by_user:
review = get_review_by_repository_id_changeset_revision_user_id( trans,
- repository_id,
+ id,
changeset_revision,
trans.security.encode_id( trans.user.id ) )
else:
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: Be able to find the desired review when choosing to manage it from various places in the tool shed.
by Bitbucket 18 Oct '12
by Bitbucket 18 Oct '12
18 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/20d002e4e423/
changeset: 20d002e4e423
user: greg
date: 2012-10-18 22:32:33
summary: Be able to find the desired review when choosing to manage it from various places in the tool shed.
affected #: 4 files
diff -r 2914e5d87851afcc9cadb7de02200a1eb75cc7e5 -r 20d002e4e423f3c0559ae6c74ec3040754aa3b86 lib/galaxy/webapps/community/controllers/repository.py
--- a/lib/galaxy/webapps/community/controllers/repository.py
+++ b/lib/galaxy/webapps/community/controllers/repository.py
@@ -1679,6 +1679,13 @@
selected_categories = [ rca.category_id for rca in repository.categories ]
# Determine if the current changeset revision has been reviewed by the current user.
reviewed_by_user = changeset_revision_reviewed_by_user( trans, trans.user, repository, changeset_revision )
+ if reviewed_by_user:
+ review = get_review_by_repository_id_changeset_revision_user_id( trans,
+ repository_id,
+ changeset_revision,
+ trans.security.encode_id( trans.user.id ) )
+ else:
+ review = None
return trans.fill_template( '/webapps/community/repository/manage_repository.mako',
cntrller=cntrller,
repo_name=repo_name,
@@ -1691,6 +1698,7 @@
repository_metadata_id=repository_metadata_id,
changeset_revision=changeset_revision,
reviewed_by_user=reviewed_by_user,
+ review=review,
changeset_revision_select_field=changeset_revision_select_field,
revision_label=revision_label,
selected_categories=selected_categories,
@@ -2330,6 +2338,13 @@
status = 'error'
# Determine if the current changeset revision has been reviewed by the current user.
reviewed_by_user = changeset_revision_reviewed_by_user( trans, trans.user, repository, changeset_revision )
+ if reviewed_by_user:
+ review = get_review_by_repository_id_changeset_revision_user_id( trans,
+ repository_id,
+ changeset_revision,
+ trans.security.encode_id( trans.user.id ) )
+ else:
+ review = None
return trans.fill_template( '/webapps/community/repository/view_repository.mako',
cntrller=cntrller,
repo=repo,
@@ -2342,6 +2357,7 @@
alerts_check_box=alerts_check_box,
changeset_revision=changeset_revision,
reviewed_by_user=reviewed_by_user,
+ review=review,
changeset_revision_select_field=changeset_revision_select_field,
revision_label=revision_label,
is_malicious=is_malicious,
@@ -2403,6 +2419,13 @@
downloadable=False )
trans.app.config.tool_data_path = original_tool_data_path
reviewed_by_user = changeset_revision_reviewed_by_user( trans, trans.user, repository, changeset_revision )
+ if reviewed_by_user:
+ review = get_review_by_repository_id_changeset_revision_user_id( trans,
+ repository_id,
+ changeset_revision,
+ trans.security.encode_id( trans.user.id ) )
+ else:
+ review = None
return trans.fill_template( "/webapps/community/repository/view_tool_metadata.mako",
repository=repository,
metadata=metadata,
@@ -2414,6 +2437,7 @@
changeset_revision_select_field=changeset_revision_select_field,
is_malicious=is_malicious,
reviewed_by_user=reviewed_by_user,
+ review=review,
message=message,
status=status )
diff -r 2914e5d87851afcc9cadb7de02200a1eb75cc7e5 -r 20d002e4e423f3c0559ae6c74ec3040754aa3b86 templates/webapps/community/repository/manage_repository.mako
--- a/templates/webapps/community/repository/manage_repository.mako
+++ b/templates/webapps/community/repository/manage_repository.mako
@@ -49,7 +49,7 @@
<ul class="manage-table-actions">
%if reviewing_repository:
%if reviewed_by_user:
- <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Manage my review of this revision</a>
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( review.id ) )}">Manage my review of this revision</a>
%else:
<a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
%endif
@@ -61,7 +61,7 @@
<div popupmenu="repository-${repository.id}-popup">
%if can_review_repository:
%if reviewed_by_user:
- <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Manage my review of this revision</a>
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( review.id ) )}">Manage my review of this revision</a>
%else:
<a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
%endif
diff -r 2914e5d87851afcc9cadb7de02200a1eb75cc7e5 -r 20d002e4e423f3c0559ae6c74ec3040754aa3b86 templates/webapps/community/repository/view_repository.mako
--- a/templates/webapps/community/repository/view_repository.mako
+++ b/templates/webapps/community/repository/view_repository.mako
@@ -42,7 +42,7 @@
%if trans.webapp.name == 'community':
%if reviewing_repository:
%if reviewed_by_user:
- <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Manage my review of this revision</a>
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( review.id ) )}">Manage my review of this revision</a>
%else:
<a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
%endif
@@ -54,7 +54,7 @@
<div popupmenu="repository-${repository.id}-popup">
%if can_review_repository:
%if reviewed_by_user:
- <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Manage my review of this revision</a>
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( review.id ) )}">Manage my review of this revision</a>
%else:
<a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
%endif
diff -r 2914e5d87851afcc9cadb7de02200a1eb75cc7e5 -r 20d002e4e423f3c0559ae6c74ec3040754aa3b86 templates/webapps/community/repository/view_tool_metadata.mako
--- a/templates/webapps/community/repository/view_tool_metadata.mako
+++ b/templates/webapps/community/repository/view_tool_metadata.mako
@@ -55,7 +55,7 @@
<div popupmenu="repository-${repository.id}-popup">
%if can_review_repository:
%if reviewed_by_user:
- <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Manage my review of this revision</a>
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( review.id ) )}">Manage my review of this revision</a>
%else:
<a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
%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
commit/galaxy-central: greg: Add the ability to search for repositories in the new review grids.
by Bitbucket 18 Oct '12
by Bitbucket 18 Oct '12
18 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/2914e5d87851/
changeset: 2914e5d87851
user: greg
date: 2012-10-18 22:14:35
summary: Add the ability to search for repositories in the new review grids.
affected #: 1 file
diff -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 -r 2914e5d87851afcc9cadb7de02200a1eb75cc7e5 lib/galaxy/webapps/community/controllers/repository_review.py
--- a/lib/galaxy/webapps/community/controllers/repository_review.py
+++ b/lib/galaxy/webapps/community/controllers/repository_review.py
@@ -76,6 +76,11 @@
ReviewersColumn( "Reviewers",
attach_popup=False )
]
+ columns.append( grids.MulticolFilterColumn( "Search repository name, description",
+ cols_to_filter=[ columns[0], columns[1] ],
+ key="free-text-search",
+ visible=False,
+ filterable="standard" ) )
operations = [
grids.GridOperation( "Inspect repository revisions",
allow_multiple=False,
@@ -103,6 +108,11 @@
RepositoriesWithReviewsGrid.UserColumn( "Owner",
attach_popup=False )
]
+ columns.append( grids.MulticolFilterColumn( "Search repository name, description",
+ cols_to_filter=[ columns[0], columns[1] ],
+ key="free-text-search",
+ visible=False,
+ filterable="standard" ) )
operations = [ grids.GridOperation( "Inspect repository revisions",
allow_multiple=False,
condition=( lambda item: not item.deleted ),
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
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/0698fc666bd0/
changeset: 0698fc666bd0
user: greg
date: 2012-10-18 21:47:06
summary: Add the ability to review a defined (but flexible) set of repository components for repositories in the tool shed. Reviews are performed on specific revisions of the repository that are installable at the time of review. Each repository component can be reviewed and approved (or not) as well as rated. The repository revision is automatically rated as the average of all component ratings. The repository revision can be approved (or not) in addition to each component. Component reviews can be marked "private", in which case they are only accessible by the owner and the group of reviewers. The ability to review repositories is restricted by the tool shed's role-base access security components. Initially, all member of the Intergalactic Utilities Commission can review repositories.
affected #: 24 files
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 lib/galaxy/webapps/community/controllers/admin.py
--- a/lib/galaxy/webapps/community/controllers/admin.py
+++ b/lib/galaxy/webapps/community/controllers/admin.py
@@ -699,7 +699,7 @@
successful_count = 0
unsuccessful_count = 0
for repository_name_owner_str in repository_names_by_owner:
- repository_name_owner_list = repository_name_owner_str.split( '__ESEP__' )
+ repository_name_owner_list = repository_name_owner_str.split( STRSEP )
name = repository_name_owner_list[ 0 ]
owner = repository_name_owner_list[ 1 ]
repository = get_repository_by_name_and_owner( trans, name, owner )
@@ -737,7 +737,7 @@
trans.model.Repository.table.c.user_id ):
owner = repository.user.username
option_label = '%s (%s)' % ( repository.name, owner )
- option_value = '%s__ESEP__%s' % ( repository.name, owner )
+ option_value = '%s%s%s' % ( repository.name, STRSEP, owner )
repositories_select_field.add_option( option_label, option_value )
return trans.fill_template( '/webapps/community/admin/reset_metadata_on_selected_repositories.mako',
repositories_select_field=repositories_select_field,
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 lib/galaxy/webapps/community/controllers/common.py
--- a/lib/galaxy/webapps/community/controllers/common.py
+++ b/lib/galaxy/webapps/community/controllers/common.py
@@ -79,6 +79,9 @@
'${host}'
"""
+# String separator
+STRSEP = '__ESEP__'
+
# States for passing messages
SUCCESS, INFO, WARNING, ERROR = "done", "info", "warning", "error"
@@ -150,6 +153,15 @@
if repository_metadata:
return repository_metadata.malicious
return False
+def changeset_revision_reviewed_by_user( trans, user, repository, changeset_revision ):
+ """Determine if the current changeset revision has been reviewed by the current user."""
+ changeset_revision_reviewed_by_user = False
+ for reviewed_revision in repository.reviewed_revisions:
+ if reviewed_revision.changeset_revision == changeset_revision:
+ for review in repository.reviews:
+ if review.changeset_revision == changeset_revision and review.user == user:
+ return True
+ return False
def check_file_contents( trans ):
# See if any admin users have chosen to receive email alerts when a repository is updated.
# If so, the file contents of the update must be checked for inappropriate content.
@@ -386,7 +398,28 @@
"""Get all categories from the database"""
return trans.sa_session.query( trans.model.Category ) \
.filter( trans.model.Category.table.c.deleted==False ) \
- .order_by( trans.model.Category.table.c.name ).all()
+ .order_by( trans.model.Category.table.c.name ) \
+ .all()
+def get_component( trans, id ):
+ """Get a component from the database"""
+ return trans.sa_session.query( trans.model.Component ).get( trans.security.decode_id( id ) )
+def get_component_by_name( trans, name ):
+ return trans.sa_session.query( trans.app.model.Component ) \
+ .filter( trans.app.model.Component.table.c.name==name ) \
+ .first()
+def get_component_review( trans, id ):
+ """Get a component_review from the database"""
+ return trans.sa_session.query( trans.model.ComponentReview ).get( trans.security.decode_id( id ) )
+def get_component_review_by_repository_review_id_component_id( trans, repository_review_id, component_id ):
+ """Get a component_review from the database via repository_review_id and component_id"""
+ return trans.sa_session.query( trans.model.ComponentReview ) \
+ .filter( and_( trans.model.ComponentReview.table.c.repository_review_id == trans.security.decode_id( repository_review_id ),
+ trans.model.ComponentReview.table.c.component_id == trans.security.decode_id( component_id ) ) ) \
+ .first()
+def get_components( trans ):
+ return trans.sa_session.query( trans.app.model.Component ) \
+ .order_by( trans.app.model.Component.name ) \
+ .all()
def get_latest_repository_metadata( trans, decoded_repository_id ):
"""Get last metadata defined for a specified repository from the database"""
return trans.sa_session.query( trans.model.RepositoryMetadata ) \
@@ -469,6 +502,46 @@
return INITIAL_CHANGELOG_HASH
else:
previous_changeset_revision = current_changeset_revision
+def get_previous_repository_reviews( trans, repository, changeset_revision ):
+ """Return an ordered dictionary of repository reviews up to and including the received changeset revision."""
+ repo = hg.repository( get_configured_ui(), repository.repo_path )
+ reviewed_revision_hashes = [ reviewed_revisions.changeset_revision for reviewed_revisions in repository.reviewed_revisions ]
+ previous_reviews_dict = odict()
+ for changeset in reversed_upper_bounded_changelog( repo, changeset_revision ):
+ previous_changeset_revision = str( repo.changectx( changeset ) )
+ if previous_changeset_revision in reviewed_revision_hashes:
+ previous_rev, previous_changeset_revision_label = get_rev_label_from_changeset_revision( repo, previous_changeset_revision )
+ revision_reviews = get_reviews_by_repository_id_changeset_revision( trans, trans.security.encode_id( repository.id ), previous_changeset_revision )
+ previous_reviews_dict[ previous_changeset_revision ] = dict( changeset_revision_label=previous_changeset_revision_label,
+ reviews=revision_reviews )
+ return previous_reviews_dict
+def get_rev_label_changeset_revision_from_repository_metadata( repository_metadata, repository=None ):
+ if repository is None:
+ repository = repository_metadata.repository
+ repo = hg.repository( get_configured_ui(), repository.repo_path )
+ changeset_revision = repository_metadata.changeset_revision
+ ctx = get_changectx_for_changeset( repo, changeset_revision )
+ if ctx:
+ rev = '%04d' % ctx.rev()
+ label = "%s:%s" % ( str( ctx.rev() ), changeset_revision )
+ else:
+ rev = '-1'
+ label = "-1:%s" % changeset_revision
+ return rev, label, changeset_revision
+def get_rev_label_from_changeset_revision( repo, changeset_revision ):
+ ctx = get_changectx_for_changeset( repo, changeset_revision )
+ if ctx:
+ rev = '%04d' % ctx.rev()
+ label = "%s:%s" % ( str( ctx.rev() ), changeset_revision )
+ else:
+ rev = '-1'
+ label = "-1:%s" % changeset_revision
+ return rev, label
+def get_reversed_changelog_changesets( repo ):
+ reversed_changelog = []
+ for changeset in repo.changelog:
+ reversed_changelog.insert( 0, changeset )
+ return reversed_changelog
def get_repository( trans, id ):
"""Get a repository from the database via id"""
return trans.sa_session.query( trans.model.Repository ).get( trans.security.decode_id( id ) )
@@ -489,6 +562,41 @@
"""Get all metadata records for a specified repository."""
return trans.sa_session.query( trans.model.RepositoryMetadata ) \
.filter( trans.model.RepositoryMetadata.table.c.repository_id == trans.security.decode_id( id ) )
+def get_repository_metadata_revisions_for_review( repository, reviewed=True ):
+ repository_metadata_revisions = []
+ metadata_changeset_revision_hashes = []
+ if reviewed:
+ for metadata_revision in repository.metadata_revisions:
+ metadata_changeset_revision_hashes.append( metadata_revision.changeset_revision )
+ for review in repository.reviews:
+ if review.changeset_revision in metadata_changeset_revision_hashes:
+ rmcr_hashes = [ rmr.changeset_revision for rmr in repository_metadata_revisions ]
+ if review.changeset_revision not in rmcr_hashes:
+ repository_metadata_revisions.append( review.repository_metadata )
+ else:
+ for review in repository.reviews:
+ if review.changeset_revision not in metadata_changeset_revision_hashes:
+ metadata_changeset_revision_hashes.append( review.changeset_revision )
+ for metadata_revision in repository.metadata_revisions:
+ if metadata_revision.changeset_revision not in metadata_changeset_revision_hashes:
+ repository_metadata_revisions.append( metadata_revision )
+ return repository_metadata_revisions
+def get_review( trans, id ):
+ """Get a repository_review from the database via id"""
+ return trans.sa_session.query( trans.model.RepositoryReview ).get( trans.security.decode_id( id ) )
+def get_review_by_repository_id_changeset_revision_user_id( trans, repository_id, changeset_revision, user_id ):
+ """Get a repository_review from the database via repository id, changeset_revision and user_id"""
+ return trans.sa_session.query( trans.model.RepositoryReview ) \
+ .filter( and_( trans.model.RepositoryReview.repository_id == trans.security.decode_id( repository_id ),
+ trans.model.RepositoryReview.changeset_revision == changeset_revision,
+ trans.model.RepositoryReview.user_id == trans.security.decode_id( user_id ) ) ) \
+ .first()
+def get_reviews_by_repository_id_changeset_revision( trans, repository_id, changeset_revision ):
+ """Get all repository_reviews from the database via repository id and changeset_revision"""
+ return trans.sa_session.query( trans.model.RepositoryReview ) \
+ .filter( and_( trans.model.RepositoryReview.repository_id == trans.security.decode_id( repository_id ),
+ trans.model.RepositoryReview.changeset_revision == changeset_revision ) ) \
+ .all()
def get_revision_label( trans, repository, changeset_revision ):
"""
Return a string consisting of the human read-able
@@ -590,6 +698,15 @@
util.send_mail( frm, to, subject, body, trans.app.config )
except Exception, e:
log.exception( "An error occurred sending a tool shed repository update alert by email." )
+def has_previous_repository_reviews( trans, repository, changeset_revision ):
+ """Determine if a repository has a changeset revision review prior to the received changeset revision."""
+ repo = hg.repository( get_configured_ui(), repository.repo_path )
+ reviewed_revision_hashes = [ reviewed_revisions.changeset_revision for reviewed_revisions in repository.reviewed_revisions ]
+ for changeset in reversed_upper_bounded_changelog( repo, changeset_revision ):
+ previous_changeset_revision = str( repo.changectx( changeset ) )
+ if previous_changeset_revision in reviewed_revision_hashes:
+ return True
+ return False
def is_downloadable( metadata_dict ):
return 'datatypes' in metadata_dict or 'tools' in metadata_dict or 'workflows' in metadata_dict
def load_tool_from_changeset_revision( trans, repository_id, changeset_revision, tool_config_filename ):
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 lib/galaxy/webapps/community/controllers/repository.py
--- a/lib/galaxy/webapps/community/controllers/repository.py
+++ b/lib/galaxy/webapps/community/controllers/repository.py
@@ -110,14 +110,42 @@
def __init__( self, col_name ):
grids.GridColumn.__init__( self, col_name )
def get_value( self, trans, grid, repository ):
- """Display a SelectField whose options are the changeset_revision strings of all revisions of this repository."""
+ """Display a SelectField whose options are the changeset_revision strings of all metadata revisions of this repository."""
# A repository's metadata revisions may not all be installable, as some may contain only invalid tools.
- select_field = build_changeset_revision_select_field( trans, repository, downloadable_only=False )
+ select_field = build_changeset_revision_select_field( trans, repository, downloadable=False )
if len( select_field.options ) > 1:
return select_field.get_html()
elif len( select_field.options ) == 1:
return select_field.options[ 0 ][ 0 ]
return ''
+ class WithReviewsRevisionColumn( grids.GridColumn ):
+ def __init__( self, col_name ):
+ grids.GridColumn.__init__( self, col_name )
+ def get_value( self, trans, grid, repository ):
+ # Restrict to revisions that have been reviewed.
+ repository_metadata_revisions = get_repository_metadata_revisions_for_review( repository, reviewed=True )
+ if repository_metadata_revisions:
+ rval = ''
+ for repository_metadata in repository_metadata_revisions:
+ rev, label, changeset_revision = get_rev_label_changeset_revision_from_repository_metadata( repository_metadata, repository=repository )
+ rval += '<a href="manage_repository_reviews_of_revision'
+ rval += '?id=%s&changeset_revision=%s">%s</a><br/>' % ( trans.security.encode_id( repository.id ), changeset_revision, label )
+ return rval
+ return ''
+ class WithoutReviewsRevisionColumn( grids.GridColumn ):
+ def __init__( self, col_name ):
+ grids.GridColumn.__init__( self, col_name )
+ def get_value( self, trans, grid, repository ):
+ # Restrict the options to revisions that have not yet been reviewed.
+ repository_metadata_revisions = get_repository_metadata_revisions_for_review( repository, reviewed=False )
+ if repository_metadata_revisions:
+ rval = ''
+ for repository_metadata in repository_metadata_revisions:
+ rev, label, changeset_revision = get_rev_label_changeset_revision_from_repository_metadata( repository_metadata, repository=repository )
+ rval += '<a href="manage_repository_reviews_of_revision'
+ rval += '?id=%s&changeset_revision=%s">%s</a><br/>' % ( trans.security.encode_id( repository.id ), changeset_revision, label )
+ return rval
+ return ''
class TipRevisionColumn( grids.GridColumn ):
def __init__( self, col_name ):
grids.GridColumn.__init__( self, col_name )
@@ -224,8 +252,7 @@
columns = [
RepositoryListGrid.NameColumn( "Name",
key="name",
- link=( lambda item: dict( operation="view_or_manage_repository",
- id=item.id ) ),
+ link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ),
attach_popup=False ),
RepositoryListGrid.DescriptionColumn( "Synopsis",
key="description",
@@ -295,7 +322,7 @@
grids.GridColumn.__init__( self, col_name )
def get_value( self, trans, grid, repository ):
"""Display a SelectField whose options are the changeset_revision strings of all download-able revisions of this repository."""
- select_field = build_changeset_revision_select_field( trans, repository, downloadable_only=True )
+ select_field = build_changeset_revision_select_field( trans, repository, downloadable=True )
if len( select_field.options ) > 1:
return select_field.get_html()
elif len( select_field.options ) == 1:
@@ -511,17 +538,9 @@
if 'operation' in kwd:
operation = kwd['operation'].lower()
if operation == "view_or_manage_repository":
- repository_id = kwd[ 'id' ]
- repository = get_repository( trans, repository_id )
- is_admin = trans.user_is_admin()
- if is_admin or repository.user == trans.user:
- return trans.response.send_redirect( web.url_for( controller='repository',
- action='manage_repository',
- **kwd ) )
- else:
- return trans.response.send_redirect( web.url_for( controller='repository',
- action='view_repository',
- **kwd ) )
+ return trans.response.send_redirect( web.url_for( controller='repository',
+ action='view_or_manage_repository',
+ **kwd ) )
elif operation == "edit_repository":
return trans.response.send_redirect( web.url_for( controller='repository',
action='edit_repository',
@@ -546,6 +565,9 @@
if k.startswith( 'f-' ):
del kwd[ k ]
kwd[ 'f-email' ] = trans.user.email
+ elif operation == "reviewed_repositories_i_own":
+ return trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='reviewed_repositories_i_own' ) )
elif operation == "writable_repositories":
kwd[ 'username' ] = trans.user.username
return self.writable_repository_list_grid( trans, **kwd )
@@ -1385,8 +1407,17 @@
status = params.get( 'status', 'done' )
# See if there are any RepositoryMetadata records since menu items require them.
repository_metadata = trans.sa_session.query( model.RepositoryMetadata ).first()
+ # See if the current user owns any repositories that have been reviewed.
+ has_reviewed_repositories = False
+ current_user = trans.user
+ if current_user:
+ for repository in current_user.active_repositories:
+ if repository.reviewed_revisions:
+ has_reviewed_repositories = True
+ break
return trans.fill_template( '/webapps/community/index.mako',
repository_metadata=repository_metadata,
+ has_reviewed_repositories=has_reviewed_repositories,
message=message,
status=status )
@web.expose
@@ -1508,6 +1539,7 @@
params = util.Params( kwd )
message = util.restore_text( params.get( 'message', '' ) )
status = params.get( 'status', 'done' )
+ cntrller = params.get( 'cntrller', 'repository' )
repository = get_repository( trans, id )
repo_dir = repository.repo_path
repo = hg.repository( get_configured_ui(), repo_dir )
@@ -1614,7 +1646,7 @@
repository,
selected_value=changeset_revision,
add_id_to_name=False,
- downloadable_only=False )
+ downloadable=False )
revision_label = get_revision_label( trans, repository, repository.tip )
repository_metadata_id = None
metadata = None
@@ -1645,7 +1677,10 @@
malicious_check_box = CheckboxField( 'malicious', checked=is_malicious )
categories = get_categories( trans )
selected_categories = [ rca.category_id for rca in repository.categories ]
+ # Determine if the current changeset revision has been reviewed by the current user.
+ reviewed_by_user = changeset_revision_reviewed_by_user( trans, trans.user, repository, changeset_revision )
return trans.fill_template( '/webapps/community/repository/manage_repository.mako',
+ cntrller=cntrller,
repo_name=repo_name,
description=description,
long_description=long_description,
@@ -1655,6 +1690,7 @@
repository=repository,
repository_metadata_id=repository_metadata_id,
changeset_revision=changeset_revision,
+ reviewed_by_user=reviewed_by_user,
changeset_revision_select_field=changeset_revision_select_field,
revision_label=revision_label,
selected_categories=selected_categories,
@@ -1669,6 +1705,12 @@
message=message,
status=status )
@web.expose
+ @web.require_login( "review repository revision" )
+ def manage_repository_reviews_of_revision( self, trans, mine=False, **kwd ):
+ return trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='manage_repository_reviews_of_revision',
+ **kwd ) )
+ @web.expose
@web.require_login( "multi select email alerts" )
def multi_select_email_alerts( self, trans, **kwd ):
params = util.Params( kwd )
@@ -1726,7 +1768,7 @@
repository,
selected_value=changeset_revision,
add_id_to_name=False,
- downloadable_only=False )
+ downloadable=False )
return trans.fill_template( '/webapps/community/repository/preview_tools_in_changeset.mako',
repository=repository,
repository_metadata_id=repository_metadata_id,
@@ -2170,6 +2212,17 @@
message=message,
status=status )
@web.expose
+ def view_or_manage_repository( self, trans, **kwd ):
+ repository = get_repository( trans, kwd[ 'id' ] )
+ if trans.user_is_admin() or repository.user == trans.user:
+ return trans.response.send_redirect( web.url_for( controller='repository',
+ action='manage_repository',
+ **kwd ) )
+ else:
+ return trans.response.send_redirect( web.url_for( controller='repository',
+ action='view_repository',
+ **kwd ) )
+ @web.expose
def view_readme( self, trans, id, changeset_revision, **kwd ):
params = util.Params( kwd )
message = util.restore_text( params.get( 'message', '' ) )
@@ -2225,6 +2278,7 @@
params = util.Params( kwd )
message = util.restore_text( params.get( 'message', '' ) )
status = params.get( 'status', 'done' )
+ cntrller = params.get( 'cntrller', 'repository' )
repository = get_repository( trans, id )
repo = hg.repository( get_configured_ui(), repository.repo_path )
avg_rating, num_ratings = self.get_ave_item_rating_data( trans.sa_session, repository, webapp_model=trans.model )
@@ -2258,7 +2312,7 @@
repository,
selected_value=changeset_revision,
add_id_to_name=False,
- downloadable_only=False )
+ downloadable=False )
revision_label = get_revision_label( trans, repository, changeset_revision )
repository_metadata = get_repository_metadata_by_changeset_revision( trans, id, changeset_revision )
if repository_metadata:
@@ -2274,7 +2328,10 @@
else:
message += malicious_error
status = 'error'
+ # Determine if the current changeset revision has been reviewed by the current user.
+ reviewed_by_user = changeset_revision_reviewed_by_user( trans, trans.user, repository, changeset_revision )
return trans.fill_template( '/webapps/community/repository/view_repository.mako',
+ cntrller=cntrller,
repo=repo,
repository=repository,
repository_metadata_id=repository_metadata_id,
@@ -2284,6 +2341,7 @@
num_ratings=num_ratings,
alerts_check_box=alerts_check_box,
changeset_revision=changeset_revision,
+ reviewed_by_user=reviewed_by_user,
changeset_revision_select_field=changeset_revision_select_field,
revision_label=revision_label,
is_malicious=is_malicious,
@@ -2342,8 +2400,9 @@
repository,
selected_value=changeset_revision,
add_id_to_name=False,
- downloadable_only=False )
+ downloadable=False )
trans.app.config.tool_data_path = original_tool_data_path
+ reviewed_by_user = changeset_revision_reviewed_by_user( trans, trans.user, repository, changeset_revision )
return trans.fill_template( "/webapps/community/repository/view_tool_metadata.mako",
repository=repository,
metadata=metadata,
@@ -2354,29 +2413,44 @@
revision_label=revision_label,
changeset_revision_select_field=changeset_revision_select_field,
is_malicious=is_malicious,
+ reviewed_by_user=reviewed_by_user,
message=message,
status=status )
# ----- Utility methods -----
-def build_changeset_revision_select_field( trans, repository, selected_value=None, add_id_to_name=True, downloadable_only=False ):
- """Build a SelectField whose options are the changeset_rev strings of all downloadable revisions of the received repository."""
- repo = hg.repository( get_configured_ui(), repository.repo_path )
+
+def build_changeset_revision_select_field( trans, repository, selected_value=None, add_id_to_name=True,
+ downloadable=False, reviewed=False, not_reviewed=False ):
+ """Build a SelectField whose options are the changeset_rev strings of certain revisions of the received repository."""
options = []
changeset_tups = []
refresh_on_change_values = []
- if downloadable_only:
+ if downloadable:
+ # Restrict the options to downloadable revisions.
repository_metadata_revisions = repository.downloadable_revisions
+ elif reviewed:
+ # Restrict the options to revisions that have been reviewed.
+ repository_metadata_revisions = []
+ metadata_changeset_revision_hashes = []
+ for metadata_revision in repository.metadata_revisions:
+ metadata_changeset_revision_hashes.append( metadata_revision.changeset_revision )
+ for review in repository.reviews:
+ if review.changeset_revision in metadata_changeset_revision_hashes:
+ repository_metadata_revisions.append( review.repository_metadata )
+ elif not_reviewed:
+ # Restrict the options to revisions that have not yet been reviewed.
+ repository_metadata_revisions = []
+ reviewed_metadata_changeset_revision_hashes = []
+ for review in repository.reviews:
+ reviewed_metadata_changeset_revision_hashes.append( review.changeset_revision )
+ for metadata_revision in repository.metadata_revisions:
+ if metadata_revision.changeset_revision not in reviewed_metadata_changeset_revision_hashes:
+ repository_metadata_revisions.append( metadata_revision )
else:
+ # Restrict the options to all revisions that have associated metadata.
repository_metadata_revisions = repository.metadata_revisions
for repository_metadata in repository_metadata_revisions:
- changeset_revision = repository_metadata.changeset_revision
- ctx = get_changectx_for_changeset( repo, changeset_revision )
- if ctx:
- rev = '%04d' % ctx.rev()
- label = "%s:%s" % ( str( ctx.rev() ), changeset_revision )
- else:
- rev = '-1'
- label = "-1:%s" % changeset_revision
+ rev, label, changeset_revision = get_rev_label_changeset_revision_from_repository_metadata( repository_metadata, repository=repository )
changeset_tups.append( ( rev, label, changeset_revision ) )
refresh_on_change_values.append( changeset_revision )
# Sort options by the revision label. Even though the downloadable_revisions query sorts by update_time,
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 lib/galaxy/webapps/community/controllers/repository_review.py
--- /dev/null
+++ b/lib/galaxy/webapps/community/controllers/repository_review.py
@@ -0,0 +1,707 @@
+import os, logging
+from galaxy import util
+from galaxy.web.base.controller import *
+from galaxy.web.form_builder import SelectField, CheckboxField
+from galaxy.webapps.community import model
+from galaxy.web.framework.helpers import time_ago, iff, grids
+from galaxy.model.orm import *
+from sqlalchemy.sql.expression import func
+from common import *
+from repository import RepositoryListGrid
+from galaxy.util.shed_util import get_configured_ui
+from galaxy.util.odict import odict
+
+from galaxy import eggs
+eggs.require('mercurial')
+from mercurial import hg, ui, patch, commands
+
+log = logging.getLogger( __name__ )
+
+class ComponentGrid( grids.Grid ):
+ class NameColumn( grids.TextColumn ):
+ def get_value( self, trans, grid, component ):
+ return component.name
+ class DescriptionColumn( grids.TextColumn ):
+ def get_value( self, trans, grid, component ):
+ return component.description
+ title = "Repository review components"
+ model_class = model.Component
+ template='/webapps/community/repository_review/grid.mako'
+ default_sort_key = "name"
+ columns = [
+ NameColumn( "Name",
+ key="Component.name",
+ link=( lambda item: dict( operation="edit", id=item.id ) ),
+ attach_popup=False ),
+ DescriptionColumn( "Description",
+ key="Component.description",
+ attach_popup=False )
+ ]
+ default_filter = {}
+ global_actions = [
+ grids.GridAction( "Add new component",
+ dict( controller='repository_review', action='manage_components', operation='create' ) )
+ ]
+ operations = []
+ standard_filters = []
+ num_rows_per_page = 50
+ preserve_state = False
+ use_paging = True
+
+class RepositoriesWithReviewsGrid( RepositoryListGrid ):
+ class ReviewersColumn( grids.TextColumn ):
+ def get_value( self, trans, grid, repository ):
+ if repository.reviewers:
+ rval = ''
+ for user in repository.reviewers:
+ rval += '%s<br/>' % user.username
+ return rval
+ return ''
+ title = "All reviewed Repositories"
+ model_class = model.Repository
+ template='/webapps/community/repository_review/grid.mako'
+ default_sort_key = "Repository.name"
+ columns = [
+ RepositoryListGrid.NameColumn( "Repository name",
+ key="name",
+ link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ),
+ attach_popup=True ),
+ RepositoryListGrid.DescriptionColumn( "Synopsis",
+ key="description",
+ attach_popup=False ),
+ RepositoryListGrid.WithReviewsRevisionColumn( "Reviewed revisions" ),
+ RepositoryListGrid.WithoutReviewsRevisionColumn( "Revisions for review" ),
+ RepositoryListGrid.UserColumn( "Owner",
+ attach_popup=False ),
+ ReviewersColumn( "Reviewers",
+ attach_popup=False )
+ ]
+ operations = [
+ grids.GridOperation( "Inspect repository revisions",
+ allow_multiple=False,
+ condition=( lambda item: not item.deleted ),
+ async_compatible=False )
+ ]
+ def build_initial_query( self, trans, **kwd ):
+ return trans.sa_session.query( model.Repository ) \
+ .join( ( model.RepositoryReview.table, model.RepositoryReview.table.c.repository_id == model.Repository.table.c.id ) ) \
+ .join( ( model.User.table, model.User.table.c.id == model.Repository.table.c.user_id ) ) \
+ .outerjoin( ( model.ComponentReview.table, model.ComponentReview.table.c.repository_review_id == model.RepositoryReview.table.c.id ) ) \
+ .outerjoin( ( model.Component.table, model.Component.table.c.id == model.ComponentReview.table.c.component_id ) )
+
+class RepositoriesWithoutReviewsGrid( RepositoriesWithReviewsGrid ):
+ title = "Repositories with no reviews"
+ columns = [
+ RepositoriesWithReviewsGrid.NameColumn( "Repository name",
+ key="name",
+ link=( lambda item: dict( operation="view_or_manage_repository", id=item.id ) ),
+ attach_popup=True ),
+ RepositoriesWithReviewsGrid.DescriptionColumn( "Synopsis",
+ key="description",
+ attach_popup=False ),
+ RepositoriesWithReviewsGrid.WithoutReviewsRevisionColumn( "Revisions for review" ),
+ RepositoriesWithReviewsGrid.UserColumn( "Owner",
+ attach_popup=False )
+ ]
+ operations = [ grids.GridOperation( "Inspect repository revisions",
+ allow_multiple=False,
+ condition=( lambda item: not item.deleted ),
+ async_compatible=False ) ]
+ def build_initial_query( self, trans, **kwd ):
+ return trans.sa_session.query( model.Repository ) \
+ .filter( model.Repository.reviews == None ) \
+ .join( model.User.table )
+
+class RepositoriesReviewedByMeGrid( RepositoriesWithReviewsGrid ):
+ def build_initial_query( self, trans, **kwd ):
+ return trans.sa_session.query( model.Repository ) \
+ .join( ( model.RepositoryReview.table, model.RepositoryReview.table.c.repository_id == model.Repository.table.c.id ) ) \
+ .filter( model.RepositoryReview.table.c.user_id == trans.user.id ) \
+ .join( ( model.User.table, model.User.table.c.id == model.RepositoryReview.table.c.user_id ) ) \
+ .outerjoin( ( model.ComponentReview.table, model.ComponentReview.table.c.repository_review_id == model.RepositoryReview.table.c.id ) ) \
+ .outerjoin( ( model.Component.table, model.Component.table.c.id == model.ComponentReview.table.c.component_id ) )
+
+class RepositoryReviewsByUserGrid( grids.Grid ):
+ class RepositoryNameColumn( grids.TextColumn ):
+ def get_value( self, trans, grid, review ):
+ return review.repository.name
+ class RepositoryDescriptionColumn( grids.TextColumn ):
+ def get_value( self, trans, grid, review ):
+ return review.repository.description
+ class RevisionColumn( grids.TextColumn ):
+ def get_value( self, trans, grid, review ):
+ encoded_review_id = trans.security.encode_id( review.id )
+ rval = '<a class="action-button" href="'
+ if review.user == trans.user:
+ rval += 'edit_review'
+ else:
+ rval +='browse_review'
+ rval += '?id=%s">%s</a>' % ( encoded_review_id, get_revision_label( trans, review.repository, review.changeset_revision ) )
+ return rval
+ class RatingColumn( grids.TextColumn ):
+ def get_value( self, trans, grid, review ):
+ if review.rating:
+ rval = '<input '
+ rval += 'name="star1-%s" ' % trans.security.encode_id( review.id )
+ rval += 'type="radio" '
+ rval += 'class="community_rating_star star" '
+ rval += 'disabled="disabled" '
+ rval += 'value="%s"' % str( review.rating )
+ rval += '/>'
+ return rval
+ return ''
+ title = "Reviews by user"
+ model_class = model.RepositoryReview
+ template='/webapps/community/repository_review/grid.mako'
+ default_sort_key = 'repository_id'
+ columns = [
+ RepositoryNameColumn( "Repository Name",
+ model_class=model.Repository,
+ key="Repository.name",
+ attach_popup=False ),
+ RepositoryDescriptionColumn( "Description",
+ model_class=model.Repository,
+ key="Repository.description",
+ attach_popup=False ),
+ RevisionColumn( "Revision",
+ attach_popup=False ),
+ RatingColumn( "Rating",
+ attach_popup=False )
+ ]
+ # Override these
+ default_filter = {}
+ global_actions = []
+ operations = []
+ standard_filters = []
+ num_rows_per_page = 50
+ preserve_state = False
+ use_paging = True
+ def build_initial_query( self, trans, **kwd ):
+ user_id = trans.security.decode_id( kwd[ 'id' ] )
+ return trans.sa_session.query( self.model_class ) \
+ .filter( and_( model.RepositoryReview.table.c.deleted == False, \
+ model.RepositoryReview.table.c.user_id == user_id ) )
+
+class ReviewedRepositoriesIOwnGrid( RepositoriesWithReviewsGrid ):
+ def build_initial_query( self, trans, **kwd ):
+ return trans.sa_session.query( model.Repository ) \
+ .join( ( model.RepositoryReview.table, model.RepositoryReview.table.c.repository_id == model.Repository.table.c.id ) ) \
+ .filter( model.Repository.table.c.user_id == trans.user.id ) \
+ .join( ( model.User.table, model.User.table.c.id == model.RepositoryReview.table.c.user_id ) ) \
+ .outerjoin( ( model.ComponentReview.table, model.ComponentReview.table.c.repository_review_id == model.RepositoryReview.table.c.id ) ) \
+ .outerjoin( ( model.Component.table, model.Component.table.c.id == model.ComponentReview.table.c.component_id ) )
+
+class RepositoryReviewController( BaseUIController, ItemRatings ):
+
+ component_grid = ComponentGrid()
+ repositories_reviewed_by_me_grid = RepositoriesReviewedByMeGrid()
+ repositories_with_reviews_grid = RepositoriesWithReviewsGrid()
+ repositories_without_reviews_grid = RepositoriesWithoutReviewsGrid()
+ repository_reviews_by_user_grid = RepositoryReviewsByUserGrid()
+ reviewed_repositories_i_own_grid = ReviewedRepositoriesIOwnGrid()
+
+ @web.expose
+ @web.require_login( "approve repository review" )
+ def approve_repository_review( self, trans, **kwd ):
+ # The value of the received id is the encoded review id.
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ encoded_review_id = kwd[ 'id' ]
+ review = get_review( trans, encoded_review_id )
+ if kwd.get( 'approve_repository_review_button', False ):
+ approved_select_field_name = '%s%sapproved' % ( encoded_review_id, STRSEP )
+ approved_select_field_value = str( kwd[ approved_select_field_name ] )
+ review.approved = approved_select_field_value
+ trans.sa_session.add( review )
+ trans.sa_session.flush()
+ message = 'Approved value <b>%s</b> saved for this revision.' % approved_select_field_value
+ repository_id = trans.security.encode_id( review.repository_id )
+ changeset_revision = review.changeset_revision
+ return trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='manage_repository_reviews_of_revision',
+ id=repository_id,
+ changeset_revision=changeset_revision,
+ message=message,
+ status=status ) )
+ @web.expose
+ @web.require_login( "browse components" )
+ def browse_components( self, trans, **kwd ):
+ if 'operation' in kwd:
+ operation = kwd[ 'operation' ].lower()
+ if operation == "create":
+ return trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='create_component',
+ **kwd ) )
+ return self.component_grid( trans, **kwd )
+ @web.expose
+ @web.require_login( "browse review" )
+ def browse_review( self, trans, **kwd ):
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ review = get_review( trans, kwd[ 'id' ] )
+ repository = review.repository
+ repo = hg.repository( get_configured_ui(), repository.repo_path )
+ rev, changeset_revision_label = get_rev_label_from_changeset_revision( repo, review.changeset_revision )
+ return trans.fill_template( '/webapps/community/repository_review/browse_review.mako',
+ repository=repository,
+ changeset_revision_label=changeset_revision_label,
+ review=review,
+ message=message,
+ status=status )
+ def copy_review( self, trans, review_to_copy, review ):
+ for component_review in review_to_copy.component_reviews:
+ copied_component_review = trans.model.ComponentReview( repository_review_id=review.id,
+ component_id=component_review.component.id,
+ comment=component_review.comment,
+ private=component_review.private,
+ approved=component_review.approved,
+ rating=component_review.rating )
+ trans.sa_session.add( copied_component_review )
+ trans.sa_session.flush()
+ review.approved = review_to_copy.approved
+ review.rating = review_to_copy.rating
+ trans.sa_session.add( review )
+ trans.sa_session.flush()
+ @web.expose
+ @web.require_login( "create component" )
+ def create_component( self, trans, **kwd ):
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ name = util.restore_text( params.get( 'name', '' ) )
+ description = util.restore_text( params.get( 'description', '' ) )
+ if params.get( 'create_component_button', False ):
+ if not name or not description:
+ message = 'Enter a valid name and a description'
+ status = 'error'
+ elif get_component_by_name( trans, name ):
+ message = 'A component with that name already exists'
+ status = 'error'
+ else:
+ component = trans.app.model.Component( name=name, description=description )
+ trans.sa_session.add( component )
+ trans.sa_session.flush()
+ message = "Component '%s' has been created" % component.name
+ status = 'done'
+ trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='manage_components',
+ message=message,
+ status=status ) )
+ return trans.fill_template( '/webapps/community/repository_review/create_component.mako',
+ name=name,
+ description=description,
+ message=message,
+ status=status )
+ @web.expose
+ @web.require_login( "create review" )
+ def create_review( self, trans, **kwd ):
+ # The value of the received id is the encoded repository id.
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ repository_id = kwd.get( 'id', None )
+ changeset_revision = kwd.get( 'changeset_revision', None )
+ previous_review_id = kwd.get( 'previous_review_id', None )
+ create_without_copying = 'create_without_copying' in kwd
+ if repository_id:
+ if changeset_revision:
+ # Make sure there is not already a review of the revision by the user.
+ if get_review_by_repository_id_changeset_revision_user_id( trans,
+ repository_id,
+ changeset_revision,
+ trans.security.encode_id( trans.user.id ) ):
+ message = "You have already created a review for revision <b>%s</b> of repository <b>%s</b>." % ( changeset_revision, repository.name )
+ status = "error"
+ else:
+ repository = get_repository( trans, repository_id )
+ # See if there are any reviews for previous changeset revisions that the user can copy.
+ if not create_without_copying and not previous_review_id and has_previous_repository_reviews( trans, repository, changeset_revision ):
+ return trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='select_previous_review',
+ **kwd ) )
+ # A review can be initially performed only on an installable revision of a repository, so make sure we have metadata associated
+ # with the received changeset_revision.
+ repository_metadata = get_repository_metadata_by_changeset_revision( trans, repository_id, changeset_revision )
+ if repository_metadata:
+ metadata = repository_metadata.metadata
+ if metadata:
+ review = trans.app.model.RepositoryReview( repository_id=repository_metadata.repository_id,
+ changeset_revision=changeset_revision,
+ user_id=trans.user.id,
+ rating=None,
+ deleted=False )
+ trans.sa_session.add( review )
+ trans.sa_session.flush()
+ if previous_review_id:
+ review_to_copy = get_review( trans, previous_review_id )
+ self.copy_review( trans, review_to_copy, review )
+ review_id = trans.security.encode_id( review.id )
+ message = "Begin your review of revision <b>%s</b> of repository <b>%s</b>." \
+ % ( changeset_revision, repository.name )
+ status = 'done'
+ trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='edit_review',
+ id=review_id,
+ message=message,
+ status=status ) )
+ else:
+ message = "A new review cannot be created for revision <b>%s</b> of repository <b>%s</b>. Select a valid revision and try again." \
+ % ( changeset_revision, repository.name )
+ kwd[ 'message' ] = message
+ kwd[ 'status' ] = 'error'
+ else:
+ return trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='manage_repository_reviews',
+ **kwd ) )
+ return trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='view_or_manage_repository',
+ **kwd ) )
+ @web.expose
+ @web.require_login( "edit component" )
+ def edit_component( self, trans, **kwd ):
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ id = params.get( 'id', None )
+ if not id:
+ message = "No component ids received for editing"
+ trans.response.send_redirect( web.url_for( controller='admin',
+ action='manage_categories',
+ message=message,
+ status='error' ) )
+ component = get_component( trans, id )
+ if params.get( 'edit_component_button', False ):
+ new_description = util.restore_text( params.get( 'description', '' ) ).strip()
+ if component.description != new_description:
+ component.description = new_description
+ trans.sa_session.add( component )
+ trans.sa_session.flush()
+ message = "The information has been saved for the component named <b>%s</b>" % ( component.name )
+ status = 'done'
+ return trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='manage_components',
+ message=message,
+ status=status ) )
+ return trans.fill_template( '/webapps/community/repository_review/edit_component.mako',
+ component=component,
+ message=message,
+ status=status )
+ @web.expose
+ @web.require_login( "edit review" )
+ def edit_review( self, trans, **kwd ):
+ # The value of the received id is the encoded review id.
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ review_id = kwd.get( 'id', None )
+ review = get_review( trans, review_id )
+ components_dict = odict()
+ for component in get_components( trans ):
+ components_dict[ component.name ] = dict( component=component, component_review=None )
+ repository = review.repository
+ repo = hg.repository( get_configured_ui(), repository.repo_path )
+ for component_review in review.component_reviews:
+ if component_review and component_review.component:
+ component_name = component_review.component.name
+ if component_name in components_dict:
+ component_review_dict = components_dict[ component_name ]
+ component_review_dict[ 'component_review' ] = component_review
+ components_dict[ component_name ] = component_review_dict
+ # Handle a Save button click.
+ save_button_clicked = False
+ save_buttons = [ '%s%sreview_button' % ( component_name, STRSEP ) for component_name in components_dict.keys() ]
+ save_buttons.append( 'revision_approved_button' )
+ for save_button in save_buttons:
+ if save_button in kwd:
+ save_button_clicked = True
+ break
+ if save_button_clicked:
+ # Handle the revision_approved_select_field value.
+ revision_approved = kwd.get( 'revision_approved', None )
+ revision_approved_setting_changed = False
+ if revision_approved:
+ revision_approved = str( revision_approved )
+ if review.approved != revision_approved:
+ revision_approved_setting_changed = True
+ review.approved = revision_approved
+ trans.sa_session.add( review )
+ trans.sa_session.flush()
+ saved_component_names = []
+ for component_name in components_dict.keys():
+ flushed = False
+ # Retrieve the review information from the form.
+ # The star rating form field is a radio button list, so it will not be received if it was not clicked in the form.
+ # Due to this behavior, default the value to 0.
+ rating = 0
+ for k, v in kwd.items():
+ if k.startswith( '%s%s' % ( component_name, STRSEP ) ):
+ component_review_attr = k.replace( '%s%s' % ( component_name, STRSEP ), '' )
+ if component_review_attr == 'component_id':
+ component_id = str( v )
+ elif component_review_attr == 'comment':
+ comment = str( v )
+ elif component_review_attr == 'private':
+ private = CheckboxField.is_checked( str( v ) )
+ elif component_review_attr == 'approved':
+ approved = str( v )
+ elif component_review_attr == 'rating':
+ rating = int( str( v ) )
+ component = get_component( trans, component_id )
+ component_review = get_component_review_by_repository_review_id_component_id( trans, review_id, component_id )
+ if component_review:
+ # See if the existing component review should be updated.
+ if component_review.comment != comment or \
+ component_review.private != private or \
+ component_review.approved != approved or \
+ component_review.rating != rating:
+ component_review.comment = comment
+ component_review.private = private
+ component_review.approved = approved
+ component_review.rating = rating
+ trans.sa_session.add( component_review )
+ trans.sa_session.flush()
+ flushed = True
+ saved_component_names.append( component_name )
+ else:
+ # See if a new component_review should be created.
+ if comment or private or approved != trans.model.ComponentReview.approved_states.NO or rating:
+ component_review = trans.model.ComponentReview( repository_review_id=review.id,
+ component_id=component.id,
+ comment=comment,
+ approved=approved,
+ rating=rating )
+ trans.sa_session.add( component_review )
+ trans.sa_session.flush()
+ flushed = True
+ saved_component_names.append( component_name )
+ if flushed:
+ # Update the repository rating value to be the average of all component review ratings.
+ average_rating = trans.sa_session.query( func.avg( trans.model.ComponentReview.table.c.rating ) ) \
+ .filter( trans.model.ComponentReview.table.c.repository_review_id == review.id ) \
+ .scalar()
+ review.rating = int( average_rating )
+ trans.sa_session.add( review )
+ trans.sa_session.flush()
+ # Update the information in components_dict.
+ if component_name in components_dict:
+ component_review_dict = components_dict[ component_name ]
+ component_review_dict[ 'component_review' ] = component_review
+ components_dict[ component_name ] = component_review_dict
+ if revision_approved_setting_changed:
+ message += 'Approved value <b>%s</b> saved for this revision.<br/>' % review.approved
+ if saved_component_names:
+ message += 'Reviews were saved for components: %s' % ', '.join( saved_component_names )
+ if not revision_approved_setting_changed and not saved_component_names:
+ message += 'No changes were made to this review, so nothing was saved.'
+ if review and review.approved:
+ selected_value = review.approved
+ else:
+ selected_value = trans.model.ComponentReview.approved_states.NO
+ revision_approved_select_field = build_approved_select_field( trans,
+ name='revision_approved',
+ selected_value=selected_value,
+ for_component=False )
+ rev, changeset_revision_label = get_rev_label_from_changeset_revision( repo, review.changeset_revision )
+ return trans.fill_template( '/webapps/community/repository_review/edit_review.mako',
+ repository=repository,
+ review=review,
+ changeset_revision_label=changeset_revision_label,
+ revision_approved_select_field=revision_approved_select_field,
+ components_dict=components_dict,
+ message=message,
+ status=status )
+ @web.expose
+ @web.require_login( "manage components" )
+ def manage_components( self, trans, **kwd ):
+ if 'operation' in kwd:
+ operation = kwd['operation'].lower()
+ if operation == "create":
+ return trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='create_component',
+ **kwd ) )
+ elif operation == "edit":
+ return trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='edit_component',
+ **kwd ) )
+ if 'message' not in kwd:
+ message = "This is a list of repository components (features) that can be reviewed. You can add new components or change "
+ message += "the description of an existing component if appropriate. Click on the name link to change the description."
+ status = "warning"
+ kwd[ 'message' ] = message
+ kwd[ 'status' ] = status
+ return self.component_grid( trans, **kwd )
+ @web.expose
+ @web.require_login( "manage repositories reviewed by me" )
+ def manage_repositories_reviewed_by_me( self, trans, **kwd ):
+ # The value of the received id is the encoded repository id.
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ if 'operation' in kwd:
+ kwd[ 'mine' ] = True
+ return trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='manage_repositories_with_reviews',
+ **kwd ) )
+ self.repositories_reviewed_by_me_grid.title = 'Repositories reviewed by me'
+ return self.repositories_reviewed_by_me_grid( trans, **kwd )
+ @web.expose
+ @web.require_login( "manage repositories with reviews" )
+ def manage_repositories_with_reviews( self, trans, **kwd ):
+ # The value of the received id is the encoded repository id.
+ if 'operation' in kwd:
+ operation = kwd['operation'].lower()
+ if operation == "inspect repository revisions":
+ return trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='manage_repository_reviews',
+ **kwd ) )
+ if operation == "view_or_manage_repository":
+ return trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='view_or_manage_repository',
+ **kwd ) )
+ return self.repositories_with_reviews_grid( trans, **kwd )
+ @web.expose
+ @web.require_login( "manage repositories without reviews" )
+ def manage_repositories_without_reviews( self, trans, **kwd ):
+ if 'operation' in kwd:
+ operation = kwd['operation'].lower()
+ if operation == "inspect repository revisions":
+ return trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='create_review',
+ **kwd ) )
+ if operation == "view_or_manage_repository":
+ return trans.response.send_redirect( web.url_for( controller='repository_review',
+ action='view_or_manage_repository',
+ **kwd ) )
+ return self.repositories_without_reviews_grid( trans, **kwd )
+ @web.expose
+ @web.require_login( "manage repository reviews" )
+ def manage_repository_reviews( self, trans, mine=False, **kwd ):
+ # The value of the received id is the encoded repository id.
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ repository_id = kwd.get( 'id', None )
+ if repository_id:
+ repository = get_repository( trans, repository_id )
+ repo_dir = repository.repo_path
+ repo = hg.repository( get_configured_ui(), repo_dir )
+ metadata_revision_hashes = [ metadata_revision.changeset_revision for metadata_revision in repository.metadata_revisions ]
+ reviewed_revision_hashes = [ reviewed_revisions.changeset_revision for reviewed_revisions in repository.reviewed_revisions ]
+ reviews_dict = odict()
+ for changeset in get_reversed_changelog_changesets( repo ):
+ ctx = repo.changectx( changeset )
+ changeset_revision = str( ctx )
+ if changeset_revision in metadata_revision_hashes or changeset_revision in reviewed_revision_hashes:
+ rev, changeset_revision_label = get_rev_label_from_changeset_revision( repo, changeset_revision )
+ if changeset_revision in reviewed_revision_hashes:
+ # Find the review for this changeset_revision
+ repository_reviews = get_reviews_by_repository_id_changeset_revision( trans, repository_id, changeset_revision )
+ # Determine if the current user can add a review to this revision.
+ can_add_review = trans.user not in [ repository_review.user for repository_review in repository_reviews ]
+ repository_metadata = get_repository_metadata_by_changeset_revision( trans, repository_id, changeset_revision )
+ repository_metadata_reviews = util.listify( repository_metadata.reviews )
+ else:
+ repository_reviews = []
+ repository_metadata_reviews = []
+ can_add_review = True
+ installable = changeset_revision in metadata_revision_hashes
+ revision_dict = dict( changeset_revision_label=changeset_revision_label,
+ repository_reviews=repository_reviews,
+ repository_metadata_reviews=repository_metadata_reviews,
+ installable=installable,
+ can_add_review=can_add_review )
+ reviews_dict[ changeset_revision ] = revision_dict
+ return trans.fill_template( '/webapps/community/repository_review/reviews_of_repository.mako',
+ repository=repository,
+ reviews_dict=reviews_dict,
+ mine=mine,
+ message=message,
+ status=status )
+ @web.expose
+ @web.require_login( "manage repository reviews of revision" )
+ def manage_repository_reviews_of_revision( self, trans, **kwd ):
+ # The value of the received id is the encoded repository id.
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ repository_id = kwd.get( 'id', None )
+ changeset_revision = kwd.get( 'changeset_revision', None )
+ repository = get_repository( trans, repository_id )
+ repo_dir = repository.repo_path
+ repo = hg.repository( get_configured_ui(), repo_dir )
+ installable = changeset_revision in [ metadata_revision.changeset_revision for metadata_revision in repository.metadata_revisions ]
+ rev, changeset_revision_label = get_rev_label_from_changeset_revision( repo, changeset_revision )
+ reviews = get_reviews_by_repository_id_changeset_revision( trans, repository_id, changeset_revision )
+ return trans.fill_template( '/webapps/community/repository_review/reviews_of_changeset_revision.mako',
+ repository=repository,
+ changeset_revision=changeset_revision,
+ changeset_revision_label=changeset_revision_label,
+ reviews=reviews,
+ installable=installable,
+ message=message,
+ status=status )
+ @web.expose
+ @web.require_login( "repository reviews by user" )
+ def repository_reviews_by_user( self, trans, **kwd ):
+ # The user may not be the current user. The value of the received id is the encoded user id.
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ user = get_user( trans, kwd[ 'id' ] )
+ self.repository_reviews_by_user_grid.title = "All repository revision reviews for user '%s'" % user.username
+ return self.repository_reviews_by_user_grid( trans, **kwd )
+ @web.expose
+ @web.require_login( "reviewed repositories i own" )
+ def reviewed_repositories_i_own( self, trans, **kwd ):
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ return self.reviewed_repositories_i_own_grid( trans, **kwd )
+ @web.expose
+ @web.require_login( "select previous review" )
+ def select_previous_review( self, trans, **kwd ):
+ # The value of the received id is the encoded repository id.
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ repository = get_repository( trans, kwd[ 'id' ] )
+ changeset_revision = kwd.get( 'changeset_revision', None )
+ repo = hg.repository( get_configured_ui(), repository.repo_path )
+ previous_reviews_dict = get_previous_repository_reviews( trans, repository, changeset_revision )
+ rev, changeset_revision_label = get_rev_label_from_changeset_revision( repo, changeset_revision )
+ return trans.fill_template( '/webapps/community/repository_review/select_previous_review.mako',
+ repository=repository,
+ changeset_revision=changeset_revision,
+ changeset_revision_label=changeset_revision_label,
+ previous_reviews_dict=previous_reviews_dict,
+ message=message,
+ status=status )
+ @web.expose
+ @web.require_login( "view or manage repository" )
+ def view_or_manage_repository( self, trans, **kwd ):
+ repository = get_repository( trans, kwd[ 'id' ] )
+ if trans.user_is_admin() or repository.user == trans.user:
+ return trans.response.send_redirect( web.url_for( controller='repository',
+ action='manage_repository',
+ cntrller='repository_review',
+ **kwd ) )
+ else:
+ return trans.response.send_redirect( web.url_for( controller='repository',
+ action='view_repository',
+ cntrller='repository_review',
+ **kwd ) )
+
+# ----- Utility methods -----
+
+def build_approved_select_field( trans, name, selected_value=None, for_component=True ):
+ options = [ ( 'No', trans.model.ComponentReview.approved_states.NO ),
+ ( 'Yes', trans.model.ComponentReview.approved_states.YES ) ]
+ if for_component:
+ options.append( ( 'Not applicable', trans.model.ComponentReview.approved_states.NA ) )
+ select_field = SelectField( name=name )
+ for option_tup in options:
+ selected = selected_value and option_tup[1] == selected_value
+ select_field.add_option( option_tup[0], option_tup[1], selected=selected )
+ return select_field
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 lib/galaxy/webapps/community/controllers/upload.py
--- a/lib/galaxy/webapps/community/controllers/upload.py
+++ b/lib/galaxy/webapps/community/controllers/upload.py
@@ -85,7 +85,6 @@
isgzip = False
isbz2 = False
if uploaded_file:
-
if uncompress_file:
isgzip = is_gzip( uploaded_file_name )
if not isgzip:
@@ -208,12 +207,10 @@
repo = hg.repository( get_configured_ui(), repo_dir )
undesirable_dirs_removed = 0
undesirable_files_removed = 0
-
if upload_point is not None:
full_path = os.path.abspath( os.path.join( repo_dir, upload_point ) )
else:
full_path = os.path.abspath( repo_dir )
-
filenames_in_archive = []
for root, dirs, files in os.walk( uploaded_directory ):
for uploaded_file in files:
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 lib/galaxy/webapps/community/model/__init__.py
--- a/lib/galaxy/webapps/community/model/__init__.py
+++ b/lib/galaxy/webapps/community/model/__init__.py
@@ -25,6 +25,13 @@
self.purged = False
self.username = None
self.new_repo_alert = False
+ def all_roles( self ):
+ roles = [ ura.role for ura in self.roles ]
+ for group in [ uga.group for uga in self.groups ]:
+ for role in [ gra.role for gra in group.roles ]:
+ if role not in roles:
+ roles.append( role )
+ return roles
def set_password_cleartext( self, cleartext ):
"""Set 'self.password' to the digest of 'cleartext'."""
self.password = new_secure_hash( text_type=cleartext )
@@ -173,7 +180,32 @@
self.tool_versions = tool_versions or dict()
self.malicious = malicious
self.downloadable = downloadable
-
+
+class RepositoryReview( object ):
+ approved_states = Bunch( NO='no', YES='yes' )
+ def __init__( self, repository_id=None, changeset_revision=None, user_id=None, rating=None, deleted=False ):
+ self.repository_id = repository_id
+ self.changeset_revision = changeset_revision
+ self.user_id = user_id
+ self.rating = rating
+ self.deleted = deleted
+
+class ComponentReview( object ):
+ approved_states = Bunch( NO='no', YES='yes', NA='not_applicable' )
+ def __init__( self, repository_review_id=None, component_id=None, comment=None, private=False, approved=False, rating=None, deleted=False ):
+ self.repository_review_id = repository_review_id
+ self.component_id = component_id
+ self.comment = comment
+ self.private = private
+ self.approved = approved
+ self.rating = rating
+ self.deleted = deleted
+
+class Component( object ):
+ def __init__( self, name=None, description=None ):
+ self.name = name
+ self.description = description
+
class ItemRatingAssociation( object ):
def __init__( self, id=None, user=None, item=None, rating=0, comment='' ):
self.id = id
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 lib/galaxy/webapps/community/model/mapping.py
--- a/lib/galaxy/webapps/community/model/mapping.py
+++ b/lib/galaxy/webapps/community/model/mapping.py
@@ -124,6 +124,34 @@
Column( "malicious", Boolean, default=False ),
Column( "downloadable", Boolean, default=True ) )
+RepositoryReview.table = Table( "repository_review", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "repository_id", Integer, ForeignKey( "repository.id" ), index=True ),
+ Column( "changeset_revision", TrimmedString( 255 ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True, nullable=False ),
+ Column( "approved", TrimmedString( 255 ) ),
+ Column( "rating", Integer, index=True ),
+ Column( "deleted", Boolean, index=True, default=False ) )
+
+ComponentReview.table = Table( "component_review", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "repository_review_id", Integer, ForeignKey( "repository_review.id" ), index=True ),
+ Column( "component_id", Integer, ForeignKey( "component.id" ), index=True ),
+ Column( "comment", TEXT ),
+ Column( "private", Boolean, default=False ),
+ Column( "approved", TrimmedString( 255 ) ),
+ Column( "rating", Integer ),
+ Column( "deleted", Boolean, index=True, default=False ) )
+
+Component.table = Table( "component", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "name", TrimmedString( 255 ) ),
+ Column( "description", TEXT ) )
+
RepositoryRatingAssociation.table = Table( "repository_rating_association", metadata,
Column( "id", Integer, primary_key=True ),
Column( "create_time", DateTime, default=now ),
@@ -187,7 +215,7 @@
properties=dict( user=relation( User.mapper ) ) )
assign_mapper( context, Tag, Tag.table,
- properties=dict( children=relation(Tag, backref=backref( 'parent', remote_side=[Tag.table.c.id] ) ) ) )
+ properties=dict( children=relation(Tag, backref=backref( 'parent', remote_side=[ Tag.table.c.id ] ) ) ) )
assign_mapper( context, Category, Category.table,
properties=dict( repositories=relation( RepositoryCategoryAssociation ) ) )
@@ -201,10 +229,47 @@
primaryjoin=( ( Repository.table.c.id == RepositoryMetadata.table.c.repository_id ) & ( RepositoryMetadata.table.c.downloadable == True ) ),
order_by=desc( RepositoryMetadata.table.c.update_time ) ),
metadata_revisions=relation( RepositoryMetadata,
- order_by=desc( RepositoryMetadata.table.c.update_time ) ) ) )
+ order_by=desc( RepositoryMetadata.table.c.update_time ) ),
+ reviews=relation( RepositoryReview,
+ primaryjoin=( ( Repository.table.c.id == RepositoryReview.table.c.repository_id ) ) ),
+ reviewers=relation( User,
+ secondary=RepositoryReview.table,
+ primaryjoin=( Repository.table.c.id == RepositoryReview.table.c.repository_id ),
+ secondaryjoin=( RepositoryReview.table.c.user_id == User.table.c.id ) ),
+ reviewed_revisions=relation( RepositoryMetadata,
+ secondary=RepositoryReview.table,
+ foreign_keys=[ RepositoryMetadata.table.c.repository_id, RepositoryMetadata.table.c.changeset_revision ],
+ primaryjoin=( Repository.table.c.id == RepositoryMetadata.table.c.repository_id ),
+ secondaryjoin=( ( RepositoryMetadata.table.c.repository_id == RepositoryReview.table.c.repository_id ) & ( RepositoryMetadata.table.c.changeset_revision == RepositoryReview.table.c.changeset_revision ) ) ) ) )
assign_mapper( context, RepositoryMetadata, RepositoryMetadata.table,
- properties=dict( repository=relation( Repository ) ) )
+ properties=dict( repository=relation( Repository ),
+ reviews=relation( RepositoryReview,
+ foreign_keys=[ RepositoryMetadata.table.c.repository_id, RepositoryMetadata.table.c.changeset_revision ],
+ primaryjoin=( ( RepositoryMetadata.table.c.repository_id == RepositoryReview.table.c.repository_id ) & ( RepositoryMetadata.table.c.changeset_revision == RepositoryReview.table.c.changeset_revision ) ) ) ) )
+
+assign_mapper( context, RepositoryReview, RepositoryReview.table,
+ properties=dict( repository=relation( Repository,
+ primaryjoin=( RepositoryReview.table.c.repository_id == Repository.table.c.id ) ),
+ # Take case when using the mapper below! It should be used only when a new review is being created for a repository change set revision.
+ # Keep in mind that repository_metadata records can be removed from the database for certain change set revisions when metadata is being
+ # reset on a repository!
+ repository_metadata=relation( RepositoryMetadata,
+ foreign_keys=[ RepositoryReview.table.c.repository_id, RepositoryReview.table.c.changeset_revision ],
+ primaryjoin=( ( RepositoryReview.table.c.repository_id == RepositoryMetadata.table.c.repository_id ) & ( RepositoryReview.table.c.changeset_revision == RepositoryMetadata.table.c.changeset_revision ) ),
+ backref='review' ),
+ user=relation( User, backref="repository_reviews" ),
+ component_reviews=relation( ComponentReview,
+ primaryjoin=( ( RepositoryReview.table.c.id == ComponentReview.table.c.repository_review_id ) & ( ComponentReview.table.c.deleted == False ) ) ),
+ private_component_reviews=relation( ComponentReview,
+ primaryjoin=( ( RepositoryReview.table.c.id == ComponentReview.table.c.repository_review_id ) & ( ComponentReview.table.c.deleted == False ) & ( ComponentReview.table.c.private == True ) ) ) ) )
+
+assign_mapper( context, ComponentReview, ComponentReview.table,
+ properties=dict( repository_review=relation( RepositoryReview ),
+ component=relation( Component,
+ primaryjoin=( ComponentReview.table.c.component_id == Component.table.c.id ) ) ) )
+
+assign_mapper( context, Component, Component.table )
assign_mapper( context, RepositoryRatingAssociation, RepositoryRatingAssociation.table,
properties=dict( repository=relation( Repository ), user=relation( User ) ) )
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 lib/galaxy/webapps/community/model/migrate/versions/0013_add_review_tables.py
--- /dev/null
+++ b/lib/galaxy/webapps/community/model/migrate/versions/0013_add_review_tables.py
@@ -0,0 +1,212 @@
+"""
+Migration script to add the repository_review, component_review and component tables and the Repository Reviewer group and role.
+"""
+import datetime, logging, sys
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from migrate import *
+from migrate.changeset import *
+# Need our custom types, but don't import anything else from model
+from galaxy.model.custom_types import *
+
+log = logging.getLogger( __name__ )
+log.setLevel(logging.DEBUG)
+handler = logging.StreamHandler( sys.stdout )
+format = "%(name)s %(levelname)s %(asctime)s %(message)s"
+formatter = logging.Formatter( format )
+handler.setFormatter( formatter )
+log.addHandler( handler )
+
+metadata = MetaData( migrate_engine )
+db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) )
+
+IUC = 'Intergalactic Utilities Commission'
+NOW = datetime.datetime.utcnow
+REVIEWER = 'Repository Reviewer'
+ROLE_TYPE = 'system'
+
+def nextval( table, col='id' ):
+ if migrate_engine.name == 'postgres':
+ return "nextval('%s_%s_seq')" % ( table, col )
+ elif migrate_engine.name == 'mysql' or migrate_engine.name == 'sqlite':
+ return "null"
+ else:
+ raise Exception( 'Unable to convert data for unknown database type: %s' % migrate_engine.name )
+
+def localtimestamp():
+ if migrate_engine.name == 'postgres' or migrate_engine.name == 'mysql':
+ return "LOCALTIMESTAMP"
+ elif migrate_engine.name == 'sqlite':
+ return "current_date || ' ' || current_time"
+ else:
+ raise Exception( 'Unable to convert data for unknown database type: %s' % db )
+
+def boolean_false():
+ if migrate_engine.name == 'postgres' or migrate_engine.name == 'mysql':
+ return False
+ elif migrate_engine.name == 'sqlite':
+ return 0
+ else:
+ raise Exception( 'Unable to convert data for unknown database type: %s' % db )
+
+RepositoryReview_table = Table( "repository_review", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "create_time", DateTime, default=NOW ),
+ Column( "update_time", DateTime, default=NOW, onupdate=NOW ),
+ Column( "repository_id", Integer, ForeignKey( "repository.id" ), index=True ),
+ Column( "changeset_revision", TrimmedString( 255 ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True, nullable=False ),
+ Column( "approved", TrimmedString( 255 ) ),
+ Column( "rating", Integer, index=True ),
+ Column( "deleted", Boolean, index=True, default=False ) )
+
+ComponentReview_table = Table( "component_review", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "create_time", DateTime, default=NOW ),
+ Column( "update_time", DateTime, default=NOW, onupdate=NOW ),
+ Column( "repository_review_id", Integer, ForeignKey( "repository_review.id" ), index=True ),
+ Column( "component_id", Integer, ForeignKey( "component.id" ), index=True ),
+ Column( "comment", TEXT ),
+ Column( "private", Boolean, default=False ),
+ Column( "approved", TrimmedString( 255 ) ),
+ Column( "rating", Integer ),
+ Column( "deleted", Boolean, index=True, default=False ) )
+
+Component_table = Table( "component", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "name", TrimmedString( 255 ) ),
+ Column( "description", TEXT ) )
+
+def upgrade():
+ print __doc__
+ metadata.reflect()
+ # Create new review tables.
+ try:
+ Component_table.create()
+ except Exception, e:
+ print str(e)
+ log.debug( "Creating component table failed: %s" % str( e ) )
+ try:
+ RepositoryReview_table.create()
+ except Exception, e:
+ print str(e)
+ log.debug( "Creating repository_review table failed: %s" % str( e ) )
+ try:
+ ComponentReview_table.create()
+ except Exception, e:
+ print str(e)
+ log.debug( "Creating component_review table failed: %s" % str( e ) )
+ # Insert default Component values.
+ names = [ 'Data types', 'Functional tests', 'README', 'Tool dependencies', 'Tools', 'Workflows' ]
+ descriptions = [ 'Proprietary datatypes defined in a file named datatypes_conf.xml included in the repository',
+ 'Functional tests defined in each tool config included in the repository along with test data files',
+ 'An appropriately named file included in the repository that contains installation information or 3rd-party tool dependency licensing information',
+ 'Tool dependencies defined in a file named tool_dependencies.xml included in the repository for contained tools',
+ 'Galaxy tools included in the repository',
+ 'Exported Galaxy workflows included in the repository' ]
+ for tup in zip( names, descriptions ):
+ name, description = tup
+ cmd = "INSERT INTO component VALUES ("
+ cmd += "%s, " % nextval( 'component' )
+ cmd += "'%s', " % name
+ cmd += "'%s' " % description
+ cmd += ");"
+ db_session.execute( cmd )
+ # Insert a REVIEWER role into the role table.
+ cmd = "INSERT INTO role VALUES ("
+ cmd += "%s, " % nextval( 'role' )
+ cmd += "%s, " % localtimestamp()
+ cmd += "%s, " % localtimestamp()
+ cmd += "'%s', " % REVIEWER
+ cmd += "'A user or group member with this role can review repositories.', "
+ cmd += "'%s', " % ROLE_TYPE
+ cmd += "%s" % boolean_false()
+ cmd += ");"
+ db_session.execute( cmd )
+ # Get the id of the REVIEWER role.
+ cmd = "SELECT id FROM role WHERE name = '%s' and type = '%s';" % ( REVIEWER, ROLE_TYPE )
+ row = db_session.execute( cmd ).fetchone()
+ if row:
+ role_id = row[ 0 ]
+ else:
+ role_id = None
+ # Insert an IUC group into the galaxy_group table.
+ cmd = "INSERT INTO galaxy_group VALUES ("
+ cmd += "%s, " % nextval( 'galaxy_group' )
+ cmd += "%s, " % localtimestamp()
+ cmd += "%s, " % localtimestamp()
+ cmd += "'%s', " % IUC
+ cmd += "%s" % boolean_false()
+ cmd += ");"
+ db_session.execute( cmd )
+ # Get the id of the IUC group.
+ cmd = "SELECT id FROM galaxy_group WHERE name = '%s';" % ( IUC )
+ row = db_session.execute( cmd ).fetchone()
+ if row:
+ group_id = row[ 0 ]
+ else:
+ group_id = None
+ if group_id and role_id:
+ # Insert a group_role_association for the IUC group and the REVIEWER role.
+ cmd = "INSERT INTO group_role_association VALUES ("
+ cmd += "%s, " % nextval( 'group_role_association' )
+ cmd += "%d, " % int( group_id )
+ cmd += "%d, " % int( role_id )
+ cmd += "%s, " % localtimestamp()
+ cmd += "%s " % localtimestamp()
+ cmd += ");"
+ db_session.execute( cmd )
+
+def downgrade():
+ metadata.reflect()
+ # Drop review tables.
+ try:
+ ComponentReview_table.drop()
+ except Exception, e:
+ print str(e)
+ log.debug( "Dropping component_review table failed: %s" % str( e ) )
+ try:
+ RepositoryReview_table.drop()
+ except Exception, e:
+ print str(e)
+ log.debug( "Dropping repository_review table failed: %s" % str( e ) )
+ try:
+ Component_table.drop()
+ except Exception, e:
+ print str(e)
+ log.debug( "Dropping component table failed: %s" % str( e ) )
+ # Get the id of the REVIEWER group.
+ cmd = "SELECT id FROM galaxy_group WHERE name = '%s';" % ( IUC )
+ row = db_session.execute( cmd ).fetchone()
+ if row:
+ group_id = row[ 0 ]
+ else:
+ group_id = None
+ # Get the id of the REVIEWER role.
+ cmd = "SELECT id FROM role WHERE name = '%s' and type = '%s';" % ( REVIEWER, ROLE_TYPE )
+ row = db_session.execute( cmd ).fetchone()
+ if row:
+ role_id = row[ 0 ]
+ else:
+ role_id = None
+ # See if we have at least 1 user
+ cmd = "SELECT * FROM galaxy_user;"
+ users = db_session.execute( cmd ).fetchall()
+ if role_id:
+ if users:
+ # Delete all UserRoleAssociations for the REVIEWER role.
+ cmd = "DELETE FROM user_role_association WHERE role_id = %d;" % int( role_id )
+ db_session.execute( cmd )
+ if group_id:
+ # Delete all UserGroupAssociations for members of the IUC group.
+ cmd = "DELETE FROM user_group_association WHERE group_id = %d;" % int( group_id )
+ db_session.execute( cmd )
+ # Delete all GroupRoleAssociations for the IUC group and the REVIEWER role.
+ cmd = "DELETE FROM group_role_association WHERE group_id = %d and role_id = %d;" % ( int( group_id ), int( role_id ) )
+ db_session.execute( cmd )
+ # Delete the IUC group from the galaxy_group table.
+ cmd = "DELETE FROM galaxy_group WHERE id = %d;" % int( group_id )
+ db_session.execute( cmd )
+ # Delete the REVIEWER role from the role table.
+ cmd = "DELETE FROM role WHERE id = %d;" % int( role_id )
+ db_session.execute( cmd )
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 lib/galaxy/webapps/community/security/__init__.py
--- a/lib/galaxy/webapps/community/security/__init__.py
+++ b/lib/galaxy/webapps/community/security/__init__.py
@@ -121,6 +121,11 @@
else:
return None
return role
+ def get_repository_reviewer_role( self ):
+ return self.sa_session.query( self.model.Role ) \
+ .filter( and_( self.model.Role.table.c.name == 'Repository Reviewer',
+ self.model.Role.table.c.type == self.model.Role.types.SYSTEM ) ) \
+ .first()
def set_entity_group_associations( self, groups=[], users=[], roles=[], delete_existing_assocs=True ):
for group in groups:
if delete_existing_assocs:
@@ -158,6 +163,13 @@
if user:
return user.username in listify( repository.allow_push )
return False
+ def user_can_review_repositories( self, user ):
+ if user:
+ roles = user.all_roles()
+ if roles:
+ repository_reviewer_role = self.get_repository_reviewer_role()
+ return repository_reviewer_role and repository_reviewer_role in roles
+ return False
def get_permitted_actions( filter=None ):
'''Utility method to return a subset of RBACAgent's permitted actions'''
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 templates/admin/tool_shed_repository/view_tool_metadata.mako
--- a/templates/admin/tool_shed_repository/view_tool_metadata.mako
+++ b/templates/admin/tool_shed_repository/view_tool_metadata.mako
@@ -185,7 +185,6 @@
%>
%if tests:
<div class="form-row">
- <label>Functional tests:</label></td><table class="grid"><tr><td><b>name</b></td>
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 templates/webapps/community/admin/index.mako
--- a/templates/webapps/community/admin/index.mako
+++ b/templates/webapps/community/admin/index.mako
@@ -36,6 +36,7 @@
</%def><%def name="left_panel()">
+ <% can_review_repositories = trans.app.security_agent.user_can_review_repositories( trans.user ) %><div class="unified-panel-header" unselectable="on"><div class='unified-panel-header-inner'>Administration</div></div>
@@ -64,6 +65,31 @@
</div></div></div>
+ %if can_review_repositories:
+ <div class="toolSectionPad"></div>
+ <div class="toolSectionTitle">
+ Reviewing Repositories
+ </div>
+ <div class="toolSectionBody">
+ <div class="toolSectionBg">
+ %if trans.user.repository_reviews:
+ <div class="toolTitle">
+ <a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_repositories_reviewed_by_me' )}">Repositories reviewed by me</a>
+ </div>
+ %endif
+ <div class="toolTitle">
+ <a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_repositories_with_reviews' )}">All reviewed repositories</a>
+ </div>
+ <div class="toolTitle">
+ <a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_repositories_without_reviews' )}">Repositories with no reviews</a>
+ </div>
+ <div class="toolTitle">
+ <a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_components' )}">Manage review components</a>
+ </div>
+ </div>
+ </div>
+ %endif
+ <div class="toolSectionPad"></div><div class="toolSectionTitle">
Categories
</div>
@@ -91,12 +117,15 @@
</div></div></div>
+ <div class="toolSectionPad"></div><div class="toolSectionTitle">
Statistics
</div>
+ <div class="toolSectionBody"><div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='admin', action='regenerate_statistics' )}">View shed statistics</a></div>
+ </div></div></div></div>
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 templates/webapps/community/category/edit_category.mako
--- a/templates/webapps/community/category/edit_category.mako
+++ b/templates/webapps/community/category/edit_category.mako
@@ -8,7 +8,7 @@
<div class="toolForm"><div class="toolFormTitle">Change category name and description</div><div class="toolFormBody">
- <form name="library" action="${h.url_for( controller='admin', action='edit_category' )}" method="post" >
+ <form name="edit_category" action="${h.url_for( controller='admin', action='edit_category' )}" method="post" ><div class="form-row"><label>Name:</label><div style="float: left; width: 250px; margin-right: 10px;">
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 templates/webapps/community/index.mako
--- a/templates/webapps/community/index.mako
+++ b/templates/webapps/community/index.mako
@@ -37,6 +37,7 @@
</%def><%def name="left_panel()">
+ <% can_review_repositories = trans.app.security_agent.user_can_review_repositories( trans.user ) %><div class="unified-panel-header" unselectable="on"><div class='unified-panel-header-inner'>${trans.app.shed_counter.valid_tools} valid tools on ${trans.app.shed_counter.generation_time}</div></div>
@@ -72,6 +73,11 @@
<div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories', operation='repositories_i_own' )}">Repositories I own</a></div>
+ %if has_reviewed_repositories:
+ <div class="toolTitle">
+ <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories', operation='reviewed_repositories_i_own' )}">Reviewed repositories I own</a>
+ </div>
+ %endif
<div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories', operation='writable_repositories' )}">My writable repositories</a></div>
@@ -85,6 +91,30 @@
<div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='repository', action='create_repository' )}">Create new repository</a></div>
+ %if can_review_repositories:
+ <div class="toolSectionPad"></div>
+ <div class="toolSectionTitle">
+ Reviewing Repositories
+ </div>
+ <div class="toolSectionBody">
+ <div class="toolSectionBg">
+ %if trans.user.repository_reviews:
+ <div class="toolTitle">
+ <a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_repositories_reviewed_by_me' )}">Repositories reviewed by me</a>
+ </div>
+ %endif
+ <div class="toolTitle">
+ <a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_repositories_with_reviews' )}">All reviewed repositories</a>
+ </div>
+ <div class="toolTitle">
+ <a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_repositories_without_reviews' )}">Repositories with no reviews</a>
+ </div>
+ <div class="toolTitle">
+ <a target="galaxy_main" href="${h.url_for( controller='repository_review', action='manage_components' )}">Manage review components</a>
+ </div>
+ </div>
+ </div>
+ %endif
%else:
<div class="toolSectionPad"></div><div class="toolSectionTitle">
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 templates/webapps/community/repository/manage_repository.mako
--- a/templates/webapps/community/repository/manage_repository.mako
+++ b/templates/webapps/community/repository/manage_repository.mako
@@ -22,6 +22,12 @@
can_set_malicious = metadata and can_set_metadata and is_admin and changeset_revision == repository.tip
can_reset_all_metadata = is_admin and len( repo ) > 0
has_readme = metadata and 'readme' in metadata
+ can_review_repository = trans.app.security_agent.user_can_review_repositories( trans.user )
+ reviewing_repository = cntrller and cntrller == 'repository_review'
+ if changeset_revision == repository.tip:
+ tip_str = 'repository tip'
+ else:
+ tip_str = ''
%><%!
@@ -41,38 +47,53 @@
<br/><br/><ul class="manage-table-actions">
- %if is_new and can_upload:
- <a class="action-button" href="${h.url_for( controller='upload', action='upload', repository_id=trans.security.encode_id( repository.id ) )}">Upload files to repository</a>
+ %if reviewing_repository:
+ %if reviewed_by_user:
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Manage my review of this revision</a>
+ %else:
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
+ %endif
%else:
- <li><a class="action-button" id="repository-${repository.id}-popup" class="menubutton">Repository Actions</a></li>
- <div popupmenu="repository-${repository.id}-popup">
- %if can_upload:
- <a class="action-button" href="${h.url_for( controller='upload', action='upload', repository_id=trans.security.encode_id( repository.id ) )}">Upload files to repository</a>
- %endif
- %if has_readme:
- <a class="action-button" href="${h.url_for( controller='repository', action='view_readme', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">View README</a>
- %endif
- %if can_view_change_log:
- <a class="action-button" href="${h.url_for( controller='repository', action='view_changelog', id=trans.app.security.encode_id( repository.id ) )}">View change log</a>
- %endif
- %if can_rate:
- <a class="action-button" href="${h.url_for( controller='repository', action='rate_repository', id=trans.app.security.encode_id( repository.id ) )}">Rate repository</a>
- %endif
- %if can_browse_contents:
- <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">${browse_label}</a>
- %endif
- %if can_contact_owner:
- <a class="action-button" href="${h.url_for( controller='repository', action='contact_owner', id=trans.security.encode_id( repository.id ) )}">Contact repository owner</a>
- %endif
- %if can_reset_all_metadata:
- <a class="action-button" href="${h.url_for( controller='repository', action='reset_all_metadata', id=trans.security.encode_id( repository.id ) )}">Reset all repository metadata</a>
- %endif
- %if can_download:
- <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='gz' )}">Download as a .tar.gz file</a>
- <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='bz2' )}">Download as a .tar.bz2 file</a>
- <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='zip' )}">Download as a zip file</a>
- %endif
- </div>
+ %if is_new and can_upload:
+ <a class="action-button" href="${h.url_for( controller='upload', action='upload', repository_id=trans.security.encode_id( repository.id ) )}">Upload files to repository</a>
+ %else:
+ <li><a class="action-button" id="repository-${repository.id}-popup" class="menubutton">Repository Actions</a></li>
+ <div popupmenu="repository-${repository.id}-popup">
+ %if can_review_repository:
+ %if reviewed_by_user:
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Manage my review of this revision</a>
+ %else:
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
+ %endif
+ %endif
+ %if can_upload:
+ <a class="action-button" href="${h.url_for( controller='upload', action='upload', repository_id=trans.security.encode_id( repository.id ) )}">Upload files to repository</a>
+ %endif
+ %if has_readme:
+ <a class="action-button" href="${h.url_for( controller='repository', action='view_readme', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">View README</a>
+ %endif
+ %if can_view_change_log:
+ <a class="action-button" href="${h.url_for( controller='repository', action='view_changelog', id=trans.app.security.encode_id( repository.id ) )}">View change log</a>
+ %endif
+ %if can_rate:
+ <a class="action-button" href="${h.url_for( controller='repository', action='rate_repository', id=trans.app.security.encode_id( repository.id ) )}">Rate repository</a>
+ %endif
+ %if can_browse_contents:
+ <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">${browse_label}</a>
+ %endif
+ %if can_contact_owner:
+ <a class="action-button" href="${h.url_for( controller='repository', action='contact_owner', id=trans.security.encode_id( repository.id ) )}">Contact repository owner</a>
+ %endif
+ %if can_reset_all_metadata:
+ <a class="action-button" href="${h.url_for( controller='repository', action='reset_all_metadata', id=trans.security.encode_id( repository.id ) )}">Reset all repository metadata</a>
+ %endif
+ %if can_download:
+ <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='gz' )}">Download as a .tar.gz file</a>
+ <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='bz2' )}">Download as a .tar.bz2 file</a>
+ <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='zip' )}">Download as a zip file</a>
+ %endif
+ </div>
+ %endif
%endif
</ul>
@@ -86,15 +107,13 @@
<div class="toolFormBody"><form name="change_revision" id="change_revision" action="${h.url_for( controller='repository', action='manage_repository', id=trans.security.encode_id( repository.id ) )}" method="post" ><div class="form-row">
- <%
- if changeset_revision == repository.tip:
- tip_str = 'repository tip'
- else:
- tip_str = ''
- %>
${changeset_revision_select_field.get_html()} <i>${tip_str}</i><div class="toolParamHelp" style="clear: both;">
- Select a revision to inspect and download versions of tools from this repository.
+ %if reviewing_repository or can_review_repository:
+ Select a revision to inspect for adding or managing a review or for download or installation.
+ %else:
+ Select a revision to inspect for download or installation.
+ %endif
</div></div></form>
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 templates/webapps/community/repository/view_repository.mako
--- a/templates/webapps/community/repository/view_repository.mako
+++ b/templates/webapps/community/repository/view_repository.mako
@@ -18,6 +18,8 @@
else:
browse_label = 'Browse repository tip files'
has_readme = metadata and 'readme' in metadata
+ reviewing_repository = cntrller and cntrller == 'repository_review'
+ can_review_repository = trans.app.security_agent.user_can_review_repositories( trans.user )
%><%!
@@ -38,35 +40,50 @@
<br/><br/><ul class="manage-table-actions">
%if trans.webapp.name == 'community':
- %if is_new and can_upload:
- <li><a class="action-button" href="${h.url_for( controller='upload', action='upload', repository_id=trans.security.encode_id( repository.id ) )}">Upload files to repository</a></li>
+ %if reviewing_repository:
+ %if reviewed_by_user:
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Manage my review of this revision</a>
+ %else:
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
+ %endif
%else:
- <li><a class="action-button" id="repository-${repository.id}-popup" class="menubutton">Repository Actions</a></li>
- <div popupmenu="repository-${repository.id}-popup">
- %if can_upload:
- <a class="action-button" href="${h.url_for( controller='upload', action='upload', repository_id=trans.security.encode_id( repository.id ) )}">Upload files to repository</a>
- %endif
- %if has_readme:
- <a class="action-button" href="${h.url_for( controller='repository', action='view_readme', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">View README</a>
- %endif
- %if can_view_change_log:
- <a class="action-button" href="${h.url_for( controller='repository', action='view_changelog', id=trans.app.security.encode_id( repository.id ) )}">View change log</a>
- %endif
- %if can_rate:
- <a class="action-button" href="${h.url_for( controller='repository', action='rate_repository', id=trans.app.security.encode_id( repository.id ) )}">Rate repository</a>
- %endif
- %if can_browse_contents:
- <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">${browse_label}</a>
- %endif
- %if can_contact_owner:
- <a class="action-button" href="${h.url_for( controller='repository', action='contact_owner', id=trans.security.encode_id( repository.id ) )}">Contact repository owner</a>
- %endif
- %if can_download:
- <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='gz' )}">Download as a .tar.gz file</a>
- <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='bz2' )}">Download as a .tar.bz2 file</a>
- <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='zip' )}">Download as a zip file</a>
- %endif
- </div>
+ %if is_new and can_upload:
+ <li><a class="action-button" href="${h.url_for( controller='upload', action='upload', repository_id=trans.security.encode_id( repository.id ) )}">Upload files to repository</a></li>
+ %else:
+ <li><a class="action-button" id="repository-${repository.id}-popup" class="menubutton">Repository Actions</a></li>
+ <div popupmenu="repository-${repository.id}-popup">
+ %if can_review_repository:
+ %if reviewed_by_user:
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Manage my review of this revision</a>
+ %else:
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
+ %endif
+ %endif
+ %if can_upload:
+ <a class="action-button" href="${h.url_for( controller='upload', action='upload', repository_id=trans.security.encode_id( repository.id ) )}">Upload files to repository</a>
+ %endif
+ %if has_readme:
+ <a class="action-button" href="${h.url_for( controller='repository', action='view_readme', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">View README</a>
+ %endif
+ %if can_view_change_log:
+ <a class="action-button" href="${h.url_for( controller='repository', action='view_changelog', id=trans.app.security.encode_id( repository.id ) )}">View change log</a>
+ %endif
+ %if can_rate:
+ <a class="action-button" href="${h.url_for( controller='repository', action='rate_repository', id=trans.app.security.encode_id( repository.id ) )}">Rate repository</a>
+ %endif
+ %if can_browse_contents:
+ <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">${browse_label}</a>
+ %endif
+ %if can_contact_owner:
+ <a class="action-button" href="${h.url_for( controller='repository', action='contact_owner', id=trans.security.encode_id( repository.id ) )}">Contact repository owner</a>
+ %endif
+ %if can_download:
+ <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='gz' )}">Download as a .tar.gz file</a>
+ <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='bz2' )}">Download as a .tar.bz2 file</a>
+ <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, file_type='zip' )}">Download as a zip file</a>
+ %endif
+ </div>
+ %endif
%endif
%else:
<li><a class="action-button" href="${h.url_for( controller='repository', action='install_repositories_by_revision', repository_ids=trans.security.encode_id( repository.id ), changeset_revisions=changeset_revision )}">Install to local Galaxy</a></li>
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 templates/webapps/community/repository/view_tool_metadata.mako
--- a/templates/webapps/community/repository/view_tool_metadata.mako
+++ b/templates/webapps/community/repository/view_tool_metadata.mako
@@ -21,6 +21,7 @@
else:
browse_label = 'Browse repository tip files'
has_readme = metadata and 'readme' in metadata
+ can_review_repository = trans.app.security_agent.user_can_review_repositories( trans.user )
%><%!
@@ -52,6 +53,13 @@
%else:
<li><a class="action-button" id="repository-${repository.id}-popup" class="menubutton">Repository Actions</a></li><div popupmenu="repository-${repository.id}-popup">
+ %if can_review_repository:
+ %if reviewed_by_user:
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Manage my review of this revision</a>
+ %else:
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
+ %endif
+ %endif
%if can_manage:
<a class="action-button" href="${h.url_for( controller='repository', action='manage_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Manage repository</a>
%else:
@@ -274,7 +282,6 @@
%>
%if tests:
<div class="form-row">
- <label>Functional tests:</label></td><table class="grid"><tr><td><b>name</b></td>
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 templates/webapps/community/repository_review/browse_review.mako
--- /dev/null
+++ b/templates/webapps/community/repository_review/browse_review.mako
@@ -0,0 +1,125 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+<%namespace file="/webapps/community/common/common.mako" import="*" />
+
+<%
+ from galaxy.web.form_builder import CheckboxField
+ from galaxy.webapps.community.controllers.common import STRSEP
+ can_manage_repository = is_admin or repository.user == trans.user
+%>
+
+<%def name="stylesheets()">
+ ${h.css('base','panel_layout','jquery.rating')}
+</%def>
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ ${h.js( "libs/jquery/jquery.rating" )}
+</%def>
+
+<br/><br/>
+<ul class="manage-table-actions">
+ <li><a class="action-button" id="review-${review.id}-popup" class="menubutton">Review Actions</a></li>
+ <div popupmenu="review-${review.id}-popup">
+ %if can_manage_repository:
+ <a class="action-button" href="${h.url_for( controller='repository', action='manage_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=review.changeset_revision )}">Manage repository</a>
+ %else:
+ <a class="action-button" href="${h.url_for( controller='repository', action='view_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=review.changeset_revision )}">View repository</a>
+ %endif
+ </div>
+</ul>
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<div class="toolForm">
+ <div class="toolFormTitle">Review of repository '${repository.name}'</div>
+ <div class="toolFormBody">
+ <div class="form-row">
+ <label>Reviewer:</label>
+ ${review.user.username}
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Repository revision:</label>
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='view_or_manage_repository', id=trans.security.encode_id( repository.id ), changeset_revision=review.changeset_revision )}">${changeset_revision_label}</a>
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Repository owner:</label>
+ ${repository.user.username}
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Repository synopsis:</label>
+ ${repository.description}
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ %if review.component_reviews:
+ <table class="grid">
+ %for component_review in review.component_reviews:
+ <%
+ component = component_review.component
+
+ # Initialize Private check box.
+ private_check_box_name = '%s%sprivate' % ( component.name, STRSEP )
+ private_check_box = CheckboxField( name=private_check_box_name, checked=component_review.private )
+
+ # Initialize star rating.
+ rating_name = '%s%srating' % ( component.name, STRSEP )
+
+ review_comment = component_review.comment.replace( '\n', '<br/>' )
+ %>
+ <tr>
+ <td bgcolor="#D8D8D8"><b>${component.name}</b></td>
+ <td bgcolor="#D8D8D8">${component.description}</td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <table class="grid">
+ <tr>
+ <td>
+ <label>Private:</label>
+ ${private_check_box.get_html( disabled=True )}
+ <div class="toolParamHelp" style="clear: both;">
+ A private review can be accessed only by the owner of the repository and the IUC.
+ </div>
+ <div style="clear: both"></div>
+ </td>
+ </tr>
+ %if component_review.comment:
+ <tr>
+ <td>
+ <div overflow-wrap:normal;overflow:hidden;word-break:keep-all;word-wrap:break-word;line-break:strict;>
+ ${review_comment}
+ </div>
+ </td>
+ </tr>
+ %endif
+ <tr>
+ <td>
+ <label>Approved:</label>
+ ${component_review.approved}
+ <div style="clear: both"></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <label>Rating:</label>
+ ${render_star_rating( rating_name, component_review.rating, disabled=True )}
+ <div style="clear: both"></div>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ %endfor
+ </table>
+ %else:
+ This review has not yet been started.
+ %endif
+ </div>
+ </div>
+</div>
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 templates/webapps/community/repository_review/create_component.mako
--- /dev/null
+++ b/templates/webapps/community/repository_review/create_component.mako
@@ -0,0 +1,34 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ <script type="text/javascript">
+ $(function(){
+ $("input:text:first").focus();
+ })
+ </script>
+</%def>
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<div class="toolForm">
+ <div class="toolFormTitle">Create Component</div>
+ <div class="toolFormBody">
+ <form name="create_component" id="create_component" action="${h.url_for( controller='repository_review', action='create_component' )}" method="post" >
+ <div class="form-row">
+ <label>Name:</label>
+ <input name="name" type="textfield" value="${name}" size=40"/>
+ </div>
+ <div class="form-row">
+ <label>Description:</label>
+ <input name="description" type="textfield" value="${description}" size=40"/>
+ </div>
+ <div class="form-row">
+ <input type="submit" name="create_component_button" value="Save"/>
+ </div>
+ </form>
+ </div>
+</div>
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 templates/webapps/community/repository_review/edit_component.mako
--- /dev/null
+++ b/templates/webapps/community/repository_review/edit_component.mako
@@ -0,0 +1,37 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<div class="toolForm">
+ <div class="toolFormTitle">Change component description</div>
+ <div class="toolFormBody">
+ <form name="edit_component" action="${h.url_for( controller='repository_review', action='edit_component' )}" method="post" >
+ <div class="form-row">
+ <label>Name:</label>
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ ${component.name}
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Description:</label>
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ <input name="description" type="textfield" value="${component.description}" size=40"/>
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ <input type="hidden" name="id" value="${trans.security.encode_id( component.id )}"/>
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <input type="submit" name="edit_component_button" value="Save"/>
+ </div>
+ </form>
+ </div>
+</div>
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 templates/webapps/community/repository_review/edit_review.mako
--- /dev/null
+++ b/templates/webapps/community/repository_review/edit_review.mako
@@ -0,0 +1,173 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+<%namespace file="/webapps/community/common/common.mako" import="*" />
+
+<%
+ from galaxy.web.form_builder import CheckboxField
+ from galaxy.webapps.community.controllers.repository_review import build_approved_select_field
+ from galaxy.webapps.community.controllers.common import STRSEP
+ can_manage_repository = is_admin or repository.user == trans.user
+%>
+
+<%def name="stylesheets()">
+ ${h.css('base','panel_layout','jquery.rating')}
+</%def>
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ ${h.js( "libs/jquery/jquery.rating" )}
+</%def>
+
+<br/><br/>
+<ul class="manage-table-actions">
+ <li><a class="action-button" id="review-${review.id}-popup" class="menubutton">Review Actions</a></li>
+ <div popupmenu="review-${review.id}-popup">
+ %if can_manage_repository:
+ <a class="action-button" href="${h.url_for( controller='repository', action='manage_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=review.changeset_revision )}">Manage repository</a>
+ %else:
+ <a class="action-button" href="${h.url_for( controller='repository', action='view_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=review.changeset_revision )}">View repository</a>
+ %endif
+ </div>
+</ul>
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<div class="toolForm">
+ <div class="toolFormTitle">My review of repository '${repository.name}'</div>
+ <div class="toolFormBody">
+ <form name="edit_review" action="${h.url_for( controller='repository_review', action='edit_review', id=trans.security.encode_id( review.id ) )}" method="post" >
+ <div class="form-row">
+ <label>Repository revision:</label>
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='view_or_manage_repository', id=trans.security.encode_id( repository.id ), changeset_revision=review.changeset_revision )}">${changeset_revision_label}</a>
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Repository owner:</label>
+ ${repository.user.username}
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Repository synopsis:</label>
+ ${repository.description}
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Approve this repository revision?</label>
+ ${revision_approved_select_field.get_html()}
+ <div class="toolParamHelp" style="clear: both;">
+ Individual components below may be approved without approving the repository revision.
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <input type="submit" name="revision_approved_button" value="Save"/>
+ <div class="toolParamHelp" style="clear: both;">
+ All changes made on this page will be saved when any <b>Save</b> button is clicked.
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <table class="grid">
+ %for component_name, component_review_dict in components_dict.items():
+ <%
+ component = component_review_dict[ 'component' ]
+ encoded_component_id = trans.security.encode_id( component.id )
+
+ component_review = component_review_dict[ 'component_review' ]
+ if component_review:
+ comment = component_review.comment or ''
+ rating = component_review.rating
+ approved_select_field_selected_value = component_review.approved
+ private = component_review.private
+ else:
+ comment = ''
+ rating = 0
+ approved_select_field_selected_value = None
+ private = False
+
+ # Initialize Approved select field.
+ approved_select_field_name = '%s%sapproved' % ( component_name, STRSEP )
+ approved_select_field = build_approved_select_field( trans, name=approved_select_field_name, selected_value=approved_select_field_selected_value, for_component=True )
+
+ # Initialize Private check box.
+ private_check_box_name = '%s%sprivate' % ( component_name, STRSEP )
+ private_check_box = CheckboxField( name=private_check_box_name, checked=private )
+
+ # Initialize star rating.
+ rating_name = '%s%srating' % ( component_name, STRSEP )
+
+ # Initialize comment text area.
+ comment_name = '%s%scomment' % ( component_name, STRSEP )
+
+ # Initialize the component id form field name.
+ component_id_name = '%s%scomponent_id' % ( component_name, STRSEP )
+
+ # Initialize the Save button.
+ review_button_name = '%s%sreview_button' % ( component_name, STRSEP )
+ %>
+ <tr>
+ <td bgcolor="#D8D8D8"><b>${component.name}</b></td>
+ <td bgcolor="#D8D8D8">${component.description}</td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <table class="grid">
+ <tr>
+ <td>
+ <label>Mark private:</label>
+ ${private_check_box.get_html()}
+ <div class="toolParamHelp" style="clear: both;">
+ A private review can be accessed only by the owner of the repository and the IUC.
+ </div>
+ <div style="clear: both"></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <label>Comments:</label>
+ %if component_review:
+ <pre><textarea name="${comment_name}" rows="3" cols="80">${comment}</textarea></pre>
+ %else:
+ <textarea name="${comment_name}" rows="3" cols="80"></textarea>
+ %endif
+ <div style="clear: both"></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <label>Approved:</label>
+ ${approved_select_field.get_html()}
+ <div style="clear: both"></div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <label>Rating:</label>
+ ${render_star_rating( rating_name, rating )}
+ <div style="clear: both"></div>
+ <div class="toolParamHelp" style="clear: both;">
+ Rate this component only - the average of all component ratings defines the value of the repository rating.
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <input type="hidden" name="${component_id_name}" value="${encoded_component_id}"/>
+ <input type="submit" name="${review_button_name}" value="Save"/>
+ <div style="clear: both"></div>
+ <div class="toolParamHelp" style="clear: both;">
+ All changes made on this page will be saved when any <b>Save</b> button is clicked.
+ </div>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ %endfor
+ </table>
+ </div>
+ </form>
+ </div>
+</div>
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 templates/webapps/community/repository_review/grid.mako
--- /dev/null
+++ b/templates/webapps/community/repository_review/grid.mako
@@ -0,0 +1,1 @@
+<%inherit file="/grid_base.mako"/>
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 templates/webapps/community/repository_review/reviews_of_changeset_revision.mako
--- /dev/null
+++ b/templates/webapps/community/repository_review/reviews_of_changeset_revision.mako
@@ -0,0 +1,145 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+<%namespace file="/webapps/community/common/common.mako" import="*" />
+<%namespace file="/webapps/community/repository/common.mako" import="*" />
+
+<%
+ from galaxy.webapps.community.controllers.repository_review import build_approved_select_field
+ from galaxy.webapps.community.controllers.common import STRSEP
+ is_admin = trans.user_is_admin()
+ is_new = repository.is_new
+ can_browse_contents = not is_new
+ can_contact_owner = trans.user and trans.user != repository.user
+ can_manage = is_admin or repository.user == trans.user
+ can_push = trans.app.security_agent.can_push( trans.user, repository )
+ can_rate = not is_new and trans.user and repository.user != trans.user
+ can_view_change_log = not is_new
+ if can_push:
+ browse_label = 'Browse or delete repository tip files'
+ else:
+ browse_label = 'Browse repository tip files'
+ if installable:
+ installable_str = 'yes'
+ else:
+ installable_str = 'no'
+ can_review_repositories = trans.app.security_agent.user_can_review_repositories( trans.user )
+%>
+
+<%!
+ def inherit(context):
+ if context.get('use_panels'):
+ return '/webapps/community/base_panels.mako'
+ else:
+ return '/base.mako'
+%>
+<%inherit file="${inherit(context)}"/>
+
+<%def name="stylesheets()">
+ ${h.css('base','panel_layout','jquery.rating')}
+</%def>
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ ${h.js( "libs/jquery/jquery.rating" )}
+ ${common_javascripts(repository)}
+</%def>
+
+<br/><br/>
+<ul class="manage-table-actions">
+ <li><a class="action-button" id="repository-${repository.id}-popup" class="menubutton">Repository Actions</a></li>
+ <div popupmenu="repository-${repository.id}-popup">
+ %if can_manage:
+ <a class="action-button" href="${h.url_for( controller='repository', action='manage_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Manage repository</a>
+ %else:
+ <a class="action-button" href="${h.url_for( controller='repository', action='view_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">View repository</a>
+ %endif
+ %if can_view_change_log:
+ <a class="action-button" href="${h.url_for( controller='repository', action='view_changelog', id=trans.security.encode_id( repository.id ) )}">View change log</a>
+ %endif
+ %if can_rate:
+ <a class="action-button" href="${h.url_for( controller='repository', action='rate_repository', id=trans.security.encode_id( repository.id ) )}">Rate repository</a>
+ %endif
+ %if can_browse_contents:
+ <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.security.encode_id( repository.id ) )}">${browse_label}</a>
+ %endif
+ %if can_contact_owner:
+ <a class="action-button" href="${h.url_for( controller='repository', action='contact_owner', id=trans.security.encode_id( repository.id ) )}">Contact repository owner</a>
+ %endif
+ </div>
+</ul>
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<div class="toolForm">
+ <div class="toolFormTitle">Revision reviews of repository '${repository.name}'</div>
+ <div class="toolFormBody">
+ <div class="form-row">
+ <label>Revision:</label>
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='view_or_manage_repository', id=trans.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">${changeset_revision_label}</a>
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Revision is installable:</label>
+ ${installable_str}
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ %if reviews:
+ <table class="grid">
+ <tr>
+ <th>Reviewer</th>
+ <th>Repository rating</th>
+ <th>Approved</th>
+ <th></th>
+ </tr>
+ %for review in reviews:
+ <%
+ encoded_review_id = trans.security.encode_id( review.id )
+ approved_select_field_name = '%s%sapproved' % ( encoded_review_id, STRSEP )
+ approved_select_field_selected_value = review.approved
+ approved_select_field = build_approved_select_field( trans, name=approved_select_field_name, selected_value=approved_select_field_selected_value, for_component=False )
+ if review.approved not in [ None, 'None', 'none' ]:
+ approved_str = review.approved
+ else:
+ approved_str = ''
+ repository_rating_name = '%srepository_rating' % encoded_review_id
+ %>
+ <tr>
+ <td>
+ <div style="float:left;" class="menubutton split popup" id="${encoded_review_id}-popup">
+ <a class="view-info" href="${h.url_for( controller='repository_review', action='repository_reviews_by_user', id=trans.security.encode_id( review.user.id ) )}">${review.user.username}</a>
+ </div>
+ <div popupmenu="${encoded_review_id}-popup">
+ %if review.user == trans.user:
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='edit_review', id=encoded_review_id )}">Edit my review</a>
+ %else:
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='browse_review', id=encoded_review_id )}">Browse this review</a>
+ %endif
+ </div>
+ </td>
+ <td>${render_star_rating( repository_rating_name, review.rating, disabled=True )}</td>
+ %if review.user == trans.user:
+ <form name="approve_repository_review" action="${h.url_for( controller='repository_review', action='approve_repository_review', id=encoded_review_id ) }" method="post" >
+ <td>${approved_select_field.get_html()}</td>
+ <td><input type="submit" name="approve_repository_review_button" value="Save"/></td>
+ </form>
+ %else:
+ <td>${approved_str}</td>
+ <td></td>
+ %endif
+ </tr>
+ %endfor
+ </table>
+ %else:
+ <label>This repository revision has not yet been reviewed:</label>
+ %if can_review_repositories:
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
+ <div style="clear: both"></div>
+ %endif
+ %endif
+ </div>
+ <div style="clear: both"></div>
+ </div>
+</div>
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 templates/webapps/community/repository_review/reviews_of_repository.mako
--- /dev/null
+++ b/templates/webapps/community/repository_review/reviews_of_repository.mako
@@ -0,0 +1,123 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+<%namespace file="/webapps/community/common/common.mako" import="*" />
+<%namespace file="/webapps/community/repository/common.mako" import="*" />
+
+<%
+ is_admin = trans.user_is_admin()
+ is_new = repository.is_new
+ can_browse_contents = not is_new
+ can_contact_owner = trans.user and trans.user != repository.user
+ can_manage = is_admin or repository.user == trans.user
+ can_push = trans.app.security_agent.can_push( trans.user, repository )
+ can_rate = not is_new and trans.user and repository.user != trans.user
+ can_view_change_log = not is_new
+ if can_push:
+ browse_label = 'Browse or delete repository tip files'
+ else:
+ browse_label = 'Browse repository tip files'
+ if mine:
+ title = "My reviews of repository '%s'" % repository.name
+ review_revision_label = "Manage my review of this revision"
+ else:
+ title = "All reviews of repository '%s'" % repository.name
+ review_revision_label = "Inspect reviews of this revision"
+%>
+
+<%!
+ def inherit(context):
+ if context.get('use_panels'):
+ return '/webapps/community/base_panels.mako'
+ else:
+ return '/base.mako'
+%>
+<%inherit file="${inherit(context)}"/>
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ ${h.js( "libs/jquery/jquery.rating" )}
+ ${common_javascripts(repository)}
+</%def>
+
+<br/><br/>
+<ul class="manage-table-actions">
+ <li><a class="action-button" id="repository-${repository.id}-popup" class="menubutton">Repository Actions</a></li>
+ <div popupmenu="repository-${repository.id}-popup">
+ %if can_manage:
+ <a class="action-button" href="${h.url_for( controller='repository', action='manage_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=repository.tip )}">Manage repository</a>
+ %else:
+ <a class="action-button" href="${h.url_for( controller='repository', action='view_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=repository.tip )}">View repository</a>
+ %endif
+ %if can_view_change_log:
+ <a class="action-button" href="${h.url_for( controller='repository', action='view_changelog', id=trans.security.encode_id( repository.id ) )}">View change log</a>
+ %endif
+ %if can_rate:
+ <a class="action-button" href="${h.url_for( controller='repository', action='rate_repository', id=trans.security.encode_id( repository.id ) )}">Rate repository</a>
+ %endif
+ %if can_browse_contents:
+ <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.security.encode_id( repository.id ) )}">${browse_label}</a>
+ %endif
+ %if can_contact_owner:
+ <a class="action-button" href="${h.url_for( controller='repository', action='contact_owner', id=trans.security.encode_id( repository.id ) )}">Contact repository owner</a>
+ %endif
+ </div>
+</ul>
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<div class="toolForm">
+ <div class="toolFormTitle">${title}</div>
+ <div class="toolFormBody">
+ <div class="form-row">
+ <table class="grid">
+ <tr>
+ <th>Revision</th>
+ <th>Reviewers</th>
+ <th>Installable</th>
+ </tr>
+ %for changeset_revision, revision_dict in reviews_dict.items():
+ <%
+ changeset_revision_label = revision_dict[ 'changeset_revision_label' ]
+ repository_reviews = revision_dict[ 'repository_reviews' ]
+ repository_metadata_reviews = revision_dict[ 'repository_metadata_reviews' ]
+ reviewers_str = ''
+ if repository_reviews:
+ for repository_review in repository_reviews:
+ reviewers_str += '<a class="view-info" href="'
+ if repository_review.user == trans.user:
+ reviewers_str += 'edit_review'
+ else:
+ reviewers_str += 'browse_review'
+ reviewers_str += '?id=%s">%s</a>' % ( trans.security.encode_id( repository_review.id ), repository_review.user.username )
+ reviewers_str += ' | '
+ reviewers_str = reviewers_str.rstrip( '| ' )
+ if revision_dict[ 'installable' ]:
+ installable_str = 'yes'
+ else:
+ installable_str = ''
+ can_add_review = revision_dict[ 'can_add_review' ]
+ %>
+ <tr>
+ <td>
+ <div style="float:left;" class="menubutton split popup" id="${changeset_revision}-popup">
+ <a class="view-info" href="${h.url_for( controller='repository_review', action='view_or_manage_repository', id=trans.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">${changeset_revision_label}</a>
+ </div>
+ <div popupmenu="${changeset_revision}-popup">
+ %if repository_reviews:
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='manage_repository_reviews_of_revision', id=trans.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Browse reviews of this revision</a>
+ %elif can_add_review:
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Add a review to this revision</a>
+ %endif
+ </div>
+ </td>
+ <td>${reviewers_str}</td>
+ <td>${installable_str}</td>
+ </tr>
+ %endfor
+ </table>
+ </div>
+ <div style="clear: both"></div>
+ </div>
+</div>
diff -r 12fcd068b12eb844d7eded11bd70826c4275021c -r 0698fc666bd04a28b88f1472ac8eeb8dfb3a6423 templates/webapps/community/repository_review/select_previous_review.mako
--- /dev/null
+++ b/templates/webapps/community/repository_review/select_previous_review.mako
@@ -0,0 +1,127 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+<%namespace file="/webapps/community/common/common.mako" import="*" />
+<%namespace file="/webapps/community/repository/common.mako" import="*" />
+
+<%
+ is_admin = trans.user_is_admin()
+ is_new = repository.is_new
+ can_browse_contents = not is_new
+ can_contact_owner = trans.user and trans.user != repository.user
+ can_manage = is_admin or repository.user == trans.user
+ can_push = trans.app.security_agent.can_push( trans.user, repository )
+ can_rate = not is_new and trans.user and repository.user != trans.user
+ can_view_change_log = not is_new
+ if can_push:
+ browse_label = 'Browse or delete repository tip files'
+ else:
+ browse_label = 'Browse repository tip files'
+ can_review_repositories = trans.app.security_agent.user_can_review_repositories( trans.user )
+%>
+
+<%!
+ def inherit(context):
+ if context.get('use_panels'):
+ return '/webapps/community/base_panels.mako'
+ else:
+ return '/base.mako'
+%>
+<%inherit file="${inherit(context)}"/>
+
+<%def name="stylesheets()">
+ ${h.css('base','panel_layout','jquery.rating')}
+</%def>
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ ${h.js( "libs/jquery/jquery.rating" )}
+ ${common_javascripts(repository)}
+</%def>
+
+<br/><br/>
+<ul class="manage-table-actions">
+ <li><a class="action-button" id="repository-${repository.id}-popup" class="menubutton">Repository Actions</a></li>
+ <div popupmenu="repository-${repository.id}-popup">
+ %if can_manage:
+ <a class="action-button" href="${h.url_for( controller='repository', action='manage_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=repository.tip )}">Manage repository</a>
+ %else:
+ <a class="action-button" href="${h.url_for( controller='repository', action='view_repository', id=trans.app.security.encode_id( repository.id ), changeset_revision=repository.tip )}">View repository</a>
+ %endif
+ %if can_view_change_log:
+ <a class="action-button" href="${h.url_for( controller='repository', action='view_changelog', id=trans.security.encode_id( repository.id ) )}">View change log</a>
+ %endif
+ %if can_rate:
+ <a class="action-button" href="${h.url_for( controller='repository', action='rate_repository', id=trans.security.encode_id( repository.id ) )}">Rate repository</a>
+ %endif
+ %if can_browse_contents:
+ <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.security.encode_id( repository.id ) )}">${browse_label}</a>
+ %endif
+ %if can_contact_owner:
+ <a class="action-button" href="${h.url_for( controller='repository', action='contact_owner', id=trans.security.encode_id( repository.id ) )}">Contact repository owner</a>
+ %endif
+ </div>
+</ul>
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<div class="warningmessage">
+ You have elected to create a new review for revision <b>${changeset_revision_label}</b>of this repository. Since previous revisions have been reviewed,
+ you can select a previous review to copy to your new review, or click the <b>Create a review without copying</b> button.
+</div>
+
+<div class="toolForm">
+ <div class="toolFormTitle">Select previous revision review of repository '${repository.name}'</div>
+ <div class="toolFormBody">
+ <div class="form-row">
+ <label>Revision for new review:</label>
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='view_or_manage_repository', id=trans.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">${changeset_revision_label}</a>
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <table class="grid">
+ <tr>
+ </tr>
+ <td bgcolor="#D8D8D8" colspan="4"><b>Previous revision reviews of repository '${repository.name}' that can be copied to your new review</b></td>
+ <tr>
+ <th>Reviewer</th>
+ <th>Revision reviewed</th>
+ <th>Repository rating</th>
+ <th>Approved</th>
+ </tr>
+ %for previous_changeset_revision, previous_changeset_revision_dict in previous_reviews_dict.items():
+ <%
+ previous_changeset_revision_label = previous_changeset_revision_dict[ 'changeset_revision_label' ]
+ previous_reviews = previous_changeset_revision_dict[ 'reviews' ]
+ %>
+ %for review in previous_reviews:
+ <%
+ encoded_review_id = trans.security.encode_id( review.id )
+ if review.approved not in [ None, 'None', 'none' ]:
+ approved_str = review.approved
+ else:
+ approved_str = ''
+ repository_rating_name = '%srepository_rating' % encoded_review_id
+ %>
+ <tr>
+ <td>
+ <div style="float:left;" class="menubutton split popup" id="${encoded_review_id}-popup">
+ <a class="view-info" href="${h.url_for( controller='repository_review', action='browse_review', id=encoded_review_id )}">${review.user.username}</a>
+ </div>
+ <div popupmenu="${encoded_review_id}-popup">
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.security.encode_id( repository.id ), changeset_revision=changeset_revision, previous_review_id=encoded_review_id )}">Copy this review</a>
+ </div>
+ </td>
+ <td>${previous_changeset_revision_label}</td>
+ <td>${render_star_rating( repository_rating_name, review.rating, disabled=True )}</td>
+ <td>${approved_str}</td>
+ </tr>
+ %endfor
+ %endfor
+ </table>
+ </div>
+ <div style="clear: both"></div>
+ <a class="action-button" href="${h.url_for( controller='repository_review', action='create_review', id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision, create_without_copying=True )}">Create a review without copying</a>
+ </div>
+</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
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/d4aab233e2fd/
changeset: d4aab233e2fd
user: dan
date: 2012-10-18 17:22:12
summary: Unhide failed output datasets.
affected #: 1 file
diff -r ef498097758501bb1d174eaebeca1f11f9251360 -r d4aab233e2fd2195236a38fa6905c77e6bf61187 lib/galaxy/jobs/__init__.py
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -239,6 +239,7 @@
dataset.info = message
dataset.set_size()
dataset.dataset.set_total_size()
+ dataset.mark_unhidden()
if dataset.ext == 'auto':
dataset.extension = 'data'
# Update (non-library) job output datasets through the object store
@@ -379,6 +380,7 @@
# job's state:
if job.states.ERROR == job.state:
dataset.blurb = "error"
+ dataset.mark_unhidden()
elif dataset.has_data():
# If the tool was expected to set the extension, attempt to retrieve it
if dataset.ext == 'auto':
https://bitbucket.org/galaxy/galaxy-central/changeset/12fcd068b12e/
changeset: 12fcd068b12e
user: dan
date: 2012-10-18 17:22:12
summary: Do not hide failed datasets with HideDatasetAction post job action.
affected #: 1 file
diff -r d4aab233e2fd2195236a38fa6905c77e6bf61187 -r 12fcd068b12eb844d7eded11bd70826c4275021c lib/galaxy/jobs/actions/post.py
--- a/lib/galaxy/jobs/actions/post.py
+++ b/lib/galaxy/jobs/actions/post.py
@@ -230,7 +230,7 @@
@classmethod
def execute(cls, app, sa_session, action, job, replacement_dict):
for dataset_assoc in job.output_datasets:
- if action.output_name == '' or dataset_assoc.name == action.output_name:
+ if dataset_assoc.dataset.state != dataset_assoc.dataset.states.ERROR and ( action.output_name == '' or dataset_assoc.name == action.output_name ):
dataset_assoc.dataset.visible=False
@classmethod
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: smcmanus: Fixed minor issue with folder API's routing.
by Bitbucket 17 Oct '12
by Bitbucket 17 Oct '12
17 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/ef4980977585/
changeset: ef4980977585
user: smcmanus
date: 2012-10-18 04:55:00
summary: Fixed minor issue with folder API's routing.
affected #: 3 files
diff -r 4c5297ac9919dd00bb08399131f7adb5892a8891 -r ef498097758501bb1d174eaebeca1f11f9251360 lib/galaxy/webapps/galaxy/api/folder_contents.py
--- a/lib/galaxy/webapps/galaxy/api/folder_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/folder_contents.py
@@ -70,9 +70,7 @@
rval.append( dict( id = encoded_id,
type = content.api_type,
name = content.name,
- # TODO: calculate the folder's library id
- # (if necessary) and add library_id=X below:
- url = url_for( controller='folder_content', id=encoded_id ) ) )
+ url = url_for( 'folder_contents', folder_id=encoded_id ) ) )
return rval
@web.expose_api
diff -r 4c5297ac9919dd00bb08399131f7adb5892a8891 -r ef498097758501bb1d174eaebeca1f11f9251360 lib/galaxy/webapps/galaxy/buildapp.py
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -62,13 +62,12 @@
webapp.add_api_controllers( 'galaxy.webapps.galaxy.api', app )
# The /folders section is experimental at this point:
log.debug( "app.config.api_folders: %s" % app.config.api_folders )
- if app.config.api_folders:
- webapp.api_mapper.resource( 'folder', 'folders', path_prefix='/api' )
- webapp.api_mapper.resource( 'content', 'contents',
- controller='folder_contents',
- name_prefix='folder_',
- path_prefix='/api/folders/:folder_id',
- parent_resources=dict( member_name='folder', collection_name='folders' ) )
+ webapp.api_mapper.resource( 'folder', 'folders', path_prefix='/api' )
+ webapp.api_mapper.resource( 'content', 'contents',
+ controller='folder_contents',
+ name_prefix='folder_',
+ path_prefix='/api/folders/:folder_id',
+ parent_resources=dict( member_name='folder', collection_name='folders' ) )
webapp.api_mapper.resource( 'content',
'contents',
controller='library_contents',
diff -r 4c5297ac9919dd00bb08399131f7adb5892a8891 -r ef498097758501bb1d174eaebeca1f11f9251360 lib/galaxy/webapps/galaxy/controllers/library_common.py
--- a/lib/galaxy/webapps/galaxy/controllers/library_common.py
+++ b/lib/galaxy/webapps/galaxy/controllers/library_common.py
@@ -130,7 +130,6 @@
status = "info"
comptypes = get_comptypes( trans )
try:
- # SM: TODO: Add configuration variable asap.
if self.app.config.new_lib_browse:
pass
else:
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
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/4c5297ac9919/
changeset: 4c5297ac9919
user: smcmanus
date: 2012-10-18 00:01:45
summary: Minor cleanup
affected #: 1 file
diff -r 91512b8e1a6ce1c91bd05482afe9a6a774a2ab93 -r 4c5297ac9919dd00bb08399131f7adb5892a8891 lib/galaxy/webapps/galaxy/api/folder_contents.py
--- a/lib/galaxy/webapps/galaxy/api/folder_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/folder_contents.py
@@ -22,7 +22,6 @@
we want here. We could add a parameter to use the recursive
style, but this is meant to act similar to an "ls" directory listing.
"""
- log.debug( "FolderContentsController.index: enter" )
rval = []
current_user_roles = trans.get_current_user_roles()
@@ -30,19 +29,15 @@
admin = trans.user_is_admin()
rval = []
for subfolder in folder.active_folders:
- log.debug( "Subfolder type: %s" % type(subfolder) )
if not admin:
- log.debug( "calling check_folder_contents" )
can_access, folder_ids = trans.app.security_agent.check_folder_contents( trans.user, current_user_roles, subfolder )
if (admin or can_access) and not subfolder.deleted:
subfolder.api_type = 'folder'
rval.append( subfolder )
for ld in folder.datasets:
- log.debug( "Folder type: %s" % type(folder) )
if not admin:
can_access = trans.app.security_agent.can_access_dataset( current_user_roles, ld.library_dataset_dataset_association.dataset )
if (admin or can_access) and not ld.deleted:
- log.debug( "Folder attributes: %s" % dir(folder) )
ld.api_type = 'file'
rval.append( ld )
return rval
@@ -56,7 +51,6 @@
try:
folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( decoded_folder_id )
parent_library = folder.parent_library
- log.debug( "parent library type: %s" % type(parent_library) )
except:
folder = None
log.error( "FolderContentsController.index: Unable to retrieve folder %s"
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: smcmanus: Removed experimental code for improving library browsing performance
by Bitbucket 17 Oct '12
by Bitbucket 17 Oct '12
17 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/91512b8e1a6c/
changeset: 91512b8e1a6c
user: smcmanus
date: 2012-10-17 23:40:25
summary: Removed experimental code for improving library browsing performance
affected #: 5 files
diff -r ba9a8b52e8539693606b07811a6b2bf48b071ae2 -r 91512b8e1a6ce1c91bd05482afe9a6a774a2ab93 lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -235,8 +235,10 @@
self.running_functional_tests = string_as_bool( kwargs.get( 'running_functional_tests', False ) )
# Experimental: This will not be enabled by default and will hide
# nonproduction code.
- # The api_folders refers to whether the API exposes
+ # The api_folders refers to whether the API exposes the /folders section.
self.api_folders = string_as_bool( kwargs.get( 'api_folders', False ) )
+ # This is for testing new library browsing capabilities.
+ self.new_lib_browse = string_as_bool( kwargs.get( 'new_lib_browse', False ) )
def __read_tool_job_config( self, global_conf_parser, section, key ):
try:
diff -r ba9a8b52e8539693606b07811a6b2bf48b071ae2 -r 91512b8e1a6ce1c91bd05482afe9a6a774a2ab93 lib/galaxy/security/__init__.py
--- a/lib/galaxy/security/__init__.py
+++ b/lib/galaxy/security/__init__.py
@@ -256,7 +256,7 @@
def get_actions_for_items( self, trans, action, permission_items ):
# TODO: Rename this; it's a replacement for get_item_actions, but it
- # doesn't represent what it's really confusing.
+ # doesn't represent what it's really doing, which is confusing.
# TODO: Make this work for other classes besides lib_datasets.
# That should be as easy as checking the type and writing a query for each;
# we're avoiding using the SQLAlchemy backrefs because they can cause lots
@@ -1179,19 +1179,12 @@
return True, ''
action = self.permitted_actions.DATASET_ACCESS
- # SM: TODO: This is for timing debug. Delete it later.
- from datetime import datetime, timedelta
- query_start = datetime.now()
lddas = self.sa_session.query( self.model.LibraryDatasetDatasetAssociation ) \
.join( "library_dataset" ) \
.filter( self.model.LibraryDataset.folder == folder ) \
.join( "dataset" ) \
.options( eagerload_all( "dataset.actions" ) ) \
.all()
- query_end = datetime.now()
- query_delta = query_end - query_start
- #log.debug( "Check folder contents: join query time: %d.%.6d sec" %
- # ( query_delta.seconds, query_delta.microseconds ) )
for ldda in lddas:
ldda_access_permissions = self.get_item_actions( action, ldda.dataset )
diff -r ba9a8b52e8539693606b07811a6b2bf48b071ae2 -r 91512b8e1a6ce1c91bd05482afe9a6a774a2ab93 lib/galaxy/webapps/galaxy/api/folder_contents.py
--- a/lib/galaxy/webapps/galaxy/api/folder_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/folder_contents.py
@@ -25,6 +25,7 @@
log.debug( "FolderContentsController.index: enter" )
rval = []
current_user_roles = trans.get_current_user_roles()
+
def traverse( folder ):
admin = trans.user_is_admin()
rval = []
@@ -54,6 +55,8 @@
try:
folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( decoded_folder_id )
+ parent_library = folder.parent_library
+ log.debug( "parent library type: %s" % type(parent_library) )
except:
folder = None
log.error( "FolderContentsController.index: Unable to retrieve folder %s"
diff -r ba9a8b52e8539693606b07811a6b2bf48b071ae2 -r 91512b8e1a6ce1c91bd05482afe9a6a774a2ab93 lib/galaxy/webapps/galaxy/controllers/library_common.py
--- a/lib/galaxy/webapps/galaxy/controllers/library_common.py
+++ b/lib/galaxy/webapps/galaxy/controllers/library_common.py
@@ -131,17 +131,20 @@
comptypes = get_comptypes( trans )
try:
# SM: TODO: Add configuration variable asap.
- return trans.fill_template( 'library/common/browse_library.mako',
- cntrller=cntrller,
- use_panels=use_panels,
- library=library,
- created_ldda_ids=created_ldda_ids,
- hidden_folder_ids=hidden_folder_ids,
- show_deleted=show_deleted,
- comptypes=comptypes,
- current_user_roles=current_user_roles,
- message=message,
- status=status )
+ if self.app.config.new_lib_browse:
+ pass
+ else:
+ return trans.fill_template( 'library/common/browse_library.mako',
+ cntrller=cntrller,
+ use_panels=use_panels,
+ library=library,
+ created_ldda_ids=created_ldda_ids,
+ hidden_folder_ids=hidden_folder_ids,
+ show_deleted=show_deleted,
+ comptypes=comptypes,
+ current_user_roles=current_user_roles,
+ message=message,
+ status=status )
except Exception, e:
message = 'Error attempting to display contents of library (%s): %s.' % ( str( library.name ), str( e ) )
status = 'error'
diff -r ba9a8b52e8539693606b07811a6b2bf48b071ae2 -r 91512b8e1a6ce1c91bd05482afe9a6a774a2ab93 templates/library/common/browse_library_opt.mako
--- a/templates/library/common/browse_library_opt.mako
+++ /dev/null
@@ -1,622 +0,0 @@
-<%namespace file="/message.mako" import="render_msg" />
-<%namespace file="/library/common/library_item_info.mako" import="render_library_item_info" />
-<%namespace file="/library/common/common.mako" import="render_actions_on_multiple_items" />
-<%namespace file="/library/common/common.mako" import="render_compression_types_help" />
-<%namespace file="/library/common/common.mako" import="common_javascripts" />
-
-<%!
- def inherit(context):
- if context.get('use_panels'):
- return '/webapps/galaxy/base_panels.mako'
- else:
- return '/base.mako'
-%>
-<%inherit file="${inherit(context)}"/>
-
-<%def name="init()">
-<%
- self.has_left_panel=False
- self.has_right_panel=False
- self.message_box_visible=False
- self.active_view="user"
- self.overlay_visible=False
- self.has_accessible_datasets = False
-%>
-</%def>
-
-##
-## Override methods from base.mako and base_panels.mako
-##
-<%def name="center_panel()">
- <div style="overflow: auto; height: 100%;">
- <div class="page-container" style="padding: 10px;">
- ${render_content()}
- </div>
- </div>
-</%def>
-
-## Render the grid's basic elements. Each of these elements can be subclassed.
-<%def name="body()">
- ${render_content()}
-</%def>
-
-<%def name="title()">Browse data library</%def>
-<%def name="stylesheets()">
- ${parent.stylesheets()}
- ${h.css( "library" )}
-</%def>
-
-<%def name="javascripts()">
- ${parent.javascripts()}
- ${h.js("libs/json2")}
- ${h.js("libs/jquery/jstorage")}
- ${common_javascripts()}
- ${self.grid_javascripts()}
-</%def>
-
-<%def name="grid_javascripts()">
- <script type="text/javascript">
- var init_libraries = function() {
- var storage_id = "library-expand-state-${trans.security.encode_id(library.id)}";
-
- var restore_folder_state = function() {
- var state = $.jStorage.get(storage_id);
- if (state) {
- for (var id in state) {
- if (state[id] === true) {
- var row = $("#" + id),
- index = row.parent().children().index(row);
- row.addClass("expanded").show();
- row.siblings().filter("tr[parent='" + index + "']").show();
- }
- }
- }
- };
-
- var save_folder_state = function() {
- var state = {};
- $("tr.folderRow").each( function() {
- var folder = $(this);
- state[folder.attr("id")] = folder.hasClass("expanded");
- });
- $.jStorage.set(storage_id, state);
- };
-
- $("#library-grid").each(function() {
- var child_of_parent_cache = {};
- // Recursively fill in children and descendents of each row
- var process_row = function(q, parents) {
- // Find my index
- var parent = q.parent(),
- this_level = child_of_parent_cache[parent] || (child_of_parent_cache[parent] = parent.children());
-
- var index = this_level.index(q);
- // Find my immediate children
- var children = $(par_child_dict[index]);
- // Recursively handle them
- var descendents = children;
- children.each( function() {
- child_descendents = process_row( $(this), parents.add(q) );
- descendents = descendents.add(child_descendents);
- });
- // Set up expand / hide link
- var expand_fn = function() {
- if ( q.hasClass("expanded") ) {
- descendents.hide();
- descendents.removeClass("expanded");
- q.removeClass("expanded");
- } else {
- children.show();
- q.addClass("expanded");
- }
- save_folder_state();
- };
- $("." + q.attr("id") + "-click").click(expand_fn);
- // Check/uncheck boxes in subfolders.
- q.children("td").children("input[type=checkbox]").click( function() {
- if ( $(this).is(":checked") ) {
- descendents.find("input[type=checkbox]").attr("checked", true);
- } else {
- descendents.find("input[type=checkbox]").attr("checked", false);
- // If you uncheck a lower level checkbox, uncheck the boxes above it
- // (since deselecting a child means the parent is not fully selected any more).
- parents.children("td").children("input[type=checkbox]").attr("checked", false);
- }
- });
- // return descendents for use by parent
- return descendents;
- }
-
- // Initialize dict[parent_id] = rows_which_have_that_parent_id_as_parent_attr
- var par_child_dict = {},
- no_parent = [];
-
- $(this).find("tbody tr").each( function() {
- if ( $(this).attr("parent")) {
- var parent = $(this).attr("parent");
- if (par_child_dict[parent] !== undefined) {
- par_child_dict[parent].push(this);
- } else {
- par_child_dict[parent] = [this];
- }
- } else {
- no_parent.push(this);
- }
- });
-
- $(no_parent).each( function() {
- descendents = process_row( $(this), $([]) );
- descendents.hide();
- });
- });
-
- restore_folder_state();
- };
- $(function() {
- init_libraries();
- });
-
- // Looks for changes in dataset state using an async request. Keeps
- // calling itself (via setTimeout) until all datasets are in a terminal
- // state.
- var updater = function ( tracked_datasets ) {
- // Check if there are any items left to track
- var empty = true;
- for ( i in tracked_datasets ) {
- empty = false;
- break;
- }
- if ( ! empty ) {
- setTimeout( function() { updater_callback( tracked_datasets ) }, 3000 );
- }
- };
- var updater_callback = function ( tracked_datasets ) {
- // Build request data
- var ids = []
- var states = []
- $.each( tracked_datasets, function ( id, state ) {
- ids.push( id );
- states.push( state );
- });
- // Make ajax call
- $.ajax( {
- type: "POST",
- url: "${h.url_for( controller='library_common', action='library_item_updates' )}",
- dataType: "json",
- data: { ids: ids.join( "," ), states: states.join( "," ) },
- success : function ( data ) {
- $.each( data, function( id, val ) {
- // Replace HTML
- var cell = $("#libraryItem-" + id).find("#libraryItemInfo");
- cell.html( val.html );
- // If new state was terminal, stop tracking
- if (( val.state == "ok") || ( val.state == "error") || ( val.state == "empty") || ( val.state == "deleted" ) || ( val.state == "discarded" )) {
- delete tracked_datasets[ parseInt(id) ];
- } else {
- tracked_datasets[ parseInt(id) ] = val.state;
- }
- });
- updater( tracked_datasets );
- },
- error: function() {
- // Just retry, like the old method, should try to be smarter
- updater( tracked_datasets );
- }
- });
- };
- </script>
-</%def>
-
-<%def name="render_dataset( cntrller, ldda, library_dataset, can_modify, can_manage, selected, library, folder, pad, parent, row_counter, tracked_datasets, show_deleted=False, simple=False )">
- <%
- ## The received ldda must always be a LibraryDatasetDatasetAssociation object. The object id passed to methods
- ## from the drop down menu should be the ldda id to prevent id collision ( which could happen when displaying
- ## children, which are always lddas ). We also need to make sure we're displaying the latest version of this
- ## library_dataset, so we display the attributes from the ldda.
-
- from galaxy.webapps.galaxy.controllers.library_common import branch_deleted
-
- is_admin = trans.user_is_admin() and cntrller == 'library_admin'
- current_version = ( ldda == library_dataset.library_dataset_dataset_association )
- if current_version and ldda.state not in ( 'ok', 'error', 'empty', 'deleted', 'discarded' ):
- tracked_datasets[ldda.id] = ldda.state
- # SM: This causes a query to be emitted, but it quickly goes down a
- # rabbit hole of many possible inheritable cases. It may not be
- # possible to easily eliminate the extra query from this call.
- info_association, inherited = ldda.get_info_association( restrict=True )
- form_type = trans.model.FormDefinition.types.LIBRARY_INFO_TEMPLATE
- %>
- %if current_version and ( not ldda.library_dataset.deleted or show_deleted ):
- <tr class="datasetRow"
- %if parent is not None:
- parent="${parent}"
- %endif
- id="libraryItem-${ldda.id}">
- <td style="padding-left: ${pad+20}px;">
- <input style="float: left;" type="checkbox" name="ldda_ids" id="${trans.security.encode_id( ldda.id )}" value="${trans.security.encode_id( ldda.id )}"
- %if selected:
- checked="checked"
- %endif
- />
- %if simple:
- <label for="${trans.security.encode_id( ldda.id )}">${ util.unicodify( ldda.name )}</label>
- %else:
- <div style="float: left; margin-left: 1px;" class="menubutton split popup" id="dataset-${ldda.id}-popup">
- <a class="view-info" href="${h.url_for( controller='library_common', action='ldda_info', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), id=trans.security.encode_id( ldda.id ), use_panels=use_panels, show_deleted=show_deleted )}">
- %if ldda.library_dataset.deleted:
- <div class="libraryItem-error">${util.unicodify( ldda.name )}</div>
- %else:
- ${util.unicodify( ldda.name )}
- %endif
- </a>
- </div>
- %if not library.deleted:
- <div popupmenu="dataset-${ldda.id}-popup">
- %if not branch_deleted( folder ) and not ldda.library_dataset.deleted and can_modify:
- <a class="action-button" href="${h.url_for( controller='library_common', action='ldda_edit_info', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), id=trans.security.encode_id( ldda.id ), use_panels=use_panels, show_deleted=show_deleted )}">Edit information</a>
- <a class="action-button" href="${h.url_for( controller='library_common', action='move_library_item', cntrller=cntrller, item_type='ldda', item_id=trans.security.encode_id( ldda.id ), source_library_id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Move this dataset</a>
- %else:
- <a class="action-button" href="${h.url_for( controller='library_common', action='ldda_info', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), id=trans.security.encode_id( ldda.id ), use_panels=use_panels, show_deleted=show_deleted )}">View information</a>
- %endif
- %if not branch_deleted( folder ) and not ldda.library_dataset.deleted and can_modify and not info_association:
- <a class="action-button" href="${h.url_for( controller='library_common', action='add_template', cntrller=cntrller, item_type='ldda', form_type=form_type, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), ldda_id=trans.security.encode_id( ldda.id ), use_panels=use_panels, show_deleted=show_deleted )}">Use template</a>
- %endif
- %if not branch_deleted( folder ) and not ldda.library_dataset.deleted and can_modify and info_association:
- <a class="action-button" href="${h.url_for( controller='library_common', action='edit_template', cntrller=cntrller, item_type='ldda', form_type=form_type, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), ldda_id=trans.security.encode_id( ldda.id ), use_panels=use_panels, show_deleted=show_deleted )}">Edit template</a>
- <a class="action-button" href="${h.url_for( controller='library_common', action='delete_template', cntrller=cntrller, item_type='ldda', form_type=form_type, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), ldda_id=trans.security.encode_id( ldda.id ), use_panels=use_panels, show_deleted=show_deleted )}">Unuse template</a>
- %endif
- %if not branch_deleted( folder ) and not ldda.library_dataset.deleted and can_manage:
- %if not trans.app.security_agent.dataset_is_public( ldda.dataset ):
- <a class="action-button" href="${h.url_for( controller='library_common', action='make_library_item_public', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_type='ldda', id=trans.security.encode_id( ldda.dataset.id ), use_panels=use_panels, show_deleted=show_deleted )}">Make public</a>
- %endif
- <a class="action-button" href="${h.url_for( controller='library_common', action='ldda_permissions', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), id=trans.security.encode_id( ldda.id ), use_panels=use_panels, show_deleted=show_deleted )}">Edit permissions</a>
- %endif
- %if not branch_deleted( folder ) and not ldda.library_dataset.deleted and can_modify:
- <a class="action-button" href="${h.url_for( controller='library_common', action='upload_library_dataset', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), replace_id=trans.security.encode_id( library_dataset.id ), show_deleted=show_deleted )}">Upload a new version of this dataset</a>
- %endif
- %if not branch_deleted( folder ) and not ldda.library_dataset.deleted and ldda.has_data:
- <a class="action-button" href="${h.url_for( controller='library_common', action='import_datasets_to_histories', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), ldda_ids=trans.security.encode_id( ldda.id ), use_panels=use_panels, show_deleted=show_deleted )}">Import this dataset into selected histories</a>
- <a class="action-button" href="${h.url_for( controller='library_common', action='download_dataset_from_folder', cntrller=cntrller, id=trans.security.encode_id( ldda.id ), library_id=trans.security.encode_id( library.id ), use_panels=use_panels )}">Download this dataset</a>
- %endif
- %if can_modify:
- %if not library.deleted and not branch_deleted( folder ) and not ldda.library_dataset.deleted:
- <a class="action-button" confirm="Click OK to delete dataset '${util.unicodify( ldda.name )}'." href="${h.url_for( controller='library_common', action='delete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( library_dataset.id ), item_type='library_dataset', show_deleted=show_deleted )}">Delete this dataset</a>
- %elif not library.deleted and not branch_deleted( folder ) and not ldda.library_dataset.purged and ldda.library_dataset.deleted:
- <a class="action-button" href="${h.url_for( controller='library_common', action='undelete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( library_dataset.id ), item_type='library_dataset', show_deleted=show_deleted )}">Undelete this dataset</a>
- %endif
- %endif
- </div>
- %endif
- %endif
- </td>
- % if not simple:
- <td id="libraryItemInfo">${render_library_item_info( ldda )}</td>
- <td>${ldda.extension}</td>
- % endif
- <td>${ldda.create_time.strftime( "%Y-%m-%d" )}</td>
- <td>${ldda.get_size( nice_size=True )}</td>
- </tr>
- <%
- my_row = row_counter.count
- row_counter.increment()
- %>
- %endif
-</%def>
-
-<%def name="format_delta( tdelta )">
- <%
- from datetime import datetime
- return "%d.%.6d" % ( tdelta.seconds, tdelta.microseconds )
- %>
-</%def>
-
-<%def name="render_folder( cntrller, folder, folder_pad, created_ldda_ids, library, hidden_folder_ids, tracked_datasets, show_deleted=False, parent=None, row_counter=None, root_folder=False, simple=False )">
- <%
- from galaxy.webapps.galaxy.controllers.library_common import active_folders, active_folders_and_library_datasets, activatable_folders_and_library_datasets, map_library_datasets_to_lddas, branch_deleted, datasets_for_lddas
-
- # SM: DELETEME
- from datetime import datetime, timedelta
- import logging
- log = logging.getLogger( __name__ )
-
- is_admin = trans.user_is_admin() and cntrller == 'library_admin'
- has_accessible_library_datasets = trans.app.security_agent.has_accessible_library_datasets( trans, folder, trans.user, current_user_roles, search_downward=False )
-
- if root_folder:
- pad = folder_pad
- expander = h.url_for("/static/images/silk/resultset_bottom.png")
- folder_img = h.url_for("/static/images/silk/folder_page.png")
- else:
- pad = folder_pad + 20
- expander = h.url_for("/static/images/silk/resultset_next.png")
- folder_img = h.url_for("/static/images/silk/folder.png")
- # SM: If this is a comma-delimited list of LDDAs, then split them up
- # into a list. For anything else, turn created_ldda_ids into a single
- # item list.
- if created_ldda_ids:
- created_ldda_ids = util.listify( created_ldda_ids )
- if str( folder.id ) in hidden_folder_ids:
- return ""
- my_row = None
- if is_admin:
- can_add = can_modify = can_manage = True
- elif cntrller in [ 'library' ]:
- can_access, folder_ids = trans.app.security_agent.check_folder_contents( trans.user, current_user_roles, folder )
- if not can_access:
- can_show, folder_ids = \
- trans.app.security_agent.show_library_item( trans.user,
- current_user_roles,
- folder,
- [ trans.app.security_agent.permitted_actions.LIBRARY_ADD,
- trans.app.security_agent.permitted_actions.LIBRARY_MODIFY,
- trans.app.security_agent.permitted_actions.LIBRARY_MANAGE ] )
- if not can_show:
- return ""
- can_add = trans.app.security_agent.can_add_library_item( current_user_roles, folder )
- can_modify = trans.app.security_agent.can_modify_library_item( current_user_roles, folder )
- can_manage = trans.app.security_agent.can_manage_library_item( current_user_roles, folder )
- else:
- can_add = can_modify = can_manage = False
-
- form_type = trans.model.FormDefinition.types.LIBRARY_INFO_TEMPLATE
- info_association, inherited = folder.get_info_association( restrict=True )
- %>
- %if not root_folder and ( not folder.deleted or show_deleted ):
- <% encoded_id = trans.security.encode_id( folder.id ) %>
- <tr id="folder-${encoded_id}" class="folderRow libraryOrFolderRow"
- %if parent is not None:
- parent="${parent}"
- style="display: none;"
- %endif
- >
- <td style="padding-left: ${folder_pad}px;">
- <input type="checkbox" class="folderCheckbox"/>
- <span class="expandLink folder-${encoded_id}-click">
- <div style="float: left; margin-left: 2px;" class="menubutton split popup" id="folder_img-${folder.id}-popup">
- <a class="folder-${encoded_id}-click" href="javascript:void(0);">
- <span class="rowIcon"></span>
- %if folder.deleted:
- <div class="libraryItem-error">${folder.name}</div>
- %else:
- ${folder.name}
- %endif
- </a>
- </div>
- </span>
- %if not library.deleted:
- <div popupmenu="folder_img-${folder.id}-popup">
- %if not branch_deleted( folder ) and can_add:
- <a class="action-button" href="${h.url_for( controller='library_common', action='upload_library_dataset', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), use_panels=use_panels, show_deleted=show_deleted )}">Add datasets</a>
- <a class="action-button" href="${h.url_for( controller='library_common', action='create_folder', cntrller=cntrller, parent_id=trans.security.encode_id( folder.id ), library_id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Add sub-folder</a>
- %endif
- %if not branch_deleted( folder ):
- %if has_accessible_library_datasets:
- <a class="action-button" href="${h.url_for( controller='library_common', action='import_datasets_to_histories', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), use_panels=use_panels, show_deleted=show_deleted )}">Select datasets for import into selected histories</a>
- %endif
- %if can_modify:
- <a class="action-button" href="${h.url_for( controller='library_common', action='folder_info', cntrller=cntrller, id=trans.security.encode_id( folder.id ), library_id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Edit information</a>
- <a class="action-button" href="${h.url_for( controller='library_common', action='move_library_item', cntrller=cntrller, item_type='folder', item_id=trans.security.encode_id( folder.id ), source_library_id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Move this folder</a>
- %else:
- <a class="action-button" class="view-info" href="${h.url_for( controller='library_common', action='folder_info', cntrller=cntrller, id=trans.security.encode_id( folder.id ), library_id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">View information</a>
- %endif
- %endif
- %if not branch_deleted( folder ) and can_modify and not info_association:
- <a class="action-button" href="${h.url_for( controller='library_common', action='add_template', cntrller=cntrller, item_type='folder', form_type=form_type, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), use_panels=use_panels, show_deleted=show_deleted )}">Use template</a>
- %endif
- %if not branch_deleted( folder ) and can_modify and info_association:
- <a class="action-button" href="${h.url_for( controller='library_common', action='edit_template', cntrller=cntrller, item_type='folder', form_type=form_type, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), use_panels=use_panels, show_deleted=show_deleted )}">Edit template</a>
- <a class="action-button" href="${h.url_for( controller='library_common', action='delete_template', cntrller=cntrller, item_type='folder', form_type=form_type, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), use_panels=use_panels, show_deleted=show_deleted )}">Unuse template</a>
- %endif
- %if not branch_deleted( folder ) and can_manage:
- %if not trans.app.security_agent.folder_is_public( folder ):
- <a class="action-button" href="${h.url_for( controller='library_common', action='make_library_item_public', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_type='folder', id=trans.security.encode_id( folder.id ), use_panels=use_panels, show_deleted=show_deleted )}">Make public</a>
- %endif
- <a class="action-button" href="${h.url_for( controller='library_common', action='folder_permissions', cntrller=cntrller, id=trans.security.encode_id( folder.id ), library_id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Edit permissions</a>
- %endif
- %if can_modify:
- %if not library.deleted and not folder.deleted:
- <a class="action-button" confirm="Click OK to delete the folder '${folder.name}.'" href="${h.url_for( controller='library_common', action='delete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( folder.id ), item_type='folder', show_deleted=show_deleted )}">Delete this folder</a>
- %elif not library.deleted and folder.deleted and not folder.purged:
- <a class="action-button" href="${h.url_for( controller='library_common', action='undelete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( folder.id ), item_type='folder', show_deleted=show_deleted )}">Undelete this folder</a>
- %endif
- %endif
- </div>
- %endif
- <td>
- %if folder.description:
- ${folder.description}
- %endif
- <td colspan="3"></td>
- </tr>
- <%
- my_row = row_counter.count
- row_counter.increment()
- %>
- %endif
- <%
- # TODO: If show_deleted is set to True, then nothing is displayed. Why? This wasn't the case
- # in the past.
- if show_deleted:
- sub_folders, library_datasets = activatable_folders_and_library_datasets( trans, folder )
- else:
- sub_folders, library_datasets = active_folders_and_library_datasets( trans, folder )
- # Render all the subfolders:
- # TODO: Check permissions first.
- for sub_folder in sub_folders:
- render_folder( cntrller, sub_folder, pad, created_ldda_ids, library, [], tracked_datasets, show_deleted=show_deleted, parent=my_row, row_counter=row_counter, root_folder=False )
-
- # Map LibraryDatasets to LDDAs, then map LDDAs to Datasets.
- # Then determine which Datasets are accessible and which are not.
- # For every LibraryDataset, if there's an LDDA for it and it's
- # accessible then display it.
- if ( len( library_datasets ) > 0 ):
- lib_dataset_ldda_map = map_library_datasets_to_lddas( trans, library_datasets )
- dataset_list = datasets_for_lddas( trans, lib_dataset_ldda_map.values() )
- #can_access_datasets = trans.app.security_agent.dataset_access_mapping( trans, current_user_roles, dataset_list )
- can_access_datasets = trans.app.security_agent.dataset_permission_map_for_access( trans, current_user_roles, dataset_list )
- can_modify_datasets = trans.app.security_agent.item_permission_map_for_modify( trans, current_user_roles, dataset_list )
- can_manage_datasets = trans.app.security_agent.item_permission_map_for_manage( trans, current_user_roles, dataset_list )
- for library_dataset in library_datasets:
- ldda = lib_dataset_ldda_map[ library_dataset.id ]
- if ldda:
- # SMTODO: Fix awkard modify/manage permission checks.
- can_access = is_admin or can_access_datasets[ ldda.dataset_id ]
- can_modify = is_admin or ( cntrller in ['library', 'requests'] and can_modify_datasets[ ldda.dataset_id ])
- can_manage = is_admin or ( cntrller in ['library', 'requests'] and can_manage_datasets[ ldda.dataset_id ])
- selected = created_ldda_ids and str( ldda.id ) in created_ldda_ids
- if can_access:
- render_dataset( cntrller, ldda, library_dataset, can_modify, can_manage, selected, library, folder, pad, my_row, row_counter, tracked_datasets, show_deleted=show_deleted )
- %>
-</%def>
-
-<%def name="render_content(simple=False)">
- <%
- from galaxy import util
- from galaxy.webapps.galaxy.controllers.library_common import branch_deleted
- from time import strftime
- import logging
- log = logging.getLogger( __name__ )
-
- is_admin = trans.user_is_admin() and cntrller == 'library_admin'
-
- if is_admin:
- can_add = can_modify = can_manage = True
- elif cntrller in [ 'library', 'requests' ]:
- can_add = trans.app.security_agent.can_add_library_item( current_user_roles, library )
- can_modify = trans.app.security_agent.can_modify_library_item( current_user_roles, library )
- can_manage = trans.app.security_agent.can_manage_library_item( current_user_roles, library )
- else:
- can_add = can_modify = can_manage = False
-
- info_association, inherited = library.get_info_association()
- form_type = trans.model.FormDefinition.types.LIBRARY_INFO_TEMPLATE
-
- # SM: These are mostly display-specific; ignore them for now.
- # The has_accessible_folders determines if anything can be shown - use it.
- self.has_accessible_datasets = trans.app.security_agent.has_accessible_library_datasets( trans, library.root_folder, trans.user, current_user_roles )
- root_folder_has_accessible_library_datasets = trans.app.security_agent.has_accessible_library_datasets( trans, library.root_folder, trans.user, current_user_roles, search_downward=False )
- has_accessible_folders = is_admin or trans.app.security_agent.has_accessible_folders( trans, library.root_folder, trans.user, current_user_roles )
-
- tracked_datasets = {}
-
- class RowCounter( object ):
- def __init__( self ):
- self.count = 0
- def increment( self ):
- self.count += 1
- def __str__( self ):
- return str( self.count )
- %>
-
- <h2>Data Library “${library.name}”</h2>
-
- <ul class="manage-table-actions">
- %if not library.deleted and ( is_admin or can_add ):
- <li><a class="action-button" href="${h.url_for( controller='library_common', action='upload_library_dataset', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( library.root_folder.id ), use_panels=use_panels, show_deleted=show_deleted )}">Add datasets</a></li>
- <li><a class="action-button" href="${h.url_for( controller='library_common', action='create_folder', cntrller=cntrller, parent_id=trans.security.encode_id( library.root_folder.id ), library_id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Add folder</a></li>
- %endif
- %if ( ( not library.deleted ) and ( can_modify or can_manage ) ) or ( can_modify and not library.purged ) or ( library.purged ):
- <li><a class="action-button" id="library-${library.id}-popup" class="menubutton">Library Actions</a></li>
- <div popupmenu="library-${library.id}-popup">
- %if not library.deleted:
- %if can_modify:
- <a class="action-button" href="${h.url_for( controller='library_common', action='library_info', cntrller=cntrller, id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Edit information</a>
- <a class="action-button" confirm="Click OK to delete the library named '${library.name}'." href="${h.url_for( controller='library_common', action='delete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( library.id ), item_type='library' )}">Delete this data library</a>
- %if show_deleted:
- <a class="action-button" href="${h.url_for( controller='library_common', action='browse_library', cntrller=cntrller, id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=False )}">Hide deleted items</a>
- %else:
- <a class="action-button" href="${h.url_for( controller='library_common', action='browse_library', cntrller=cntrller, id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=True )}">Show deleted items</a>
- %endif
- %endif
- %if can_modify and not library.info_association:
- <a class="action-button" href="${h.url_for( controller='library_common', action='add_template', cntrller=cntrller, item_type='library', form_type=form_type, library_id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Use template</a>
- %endif
- %if can_modify and info_association:
- <a class="action-button" href="${h.url_for( controller='library_common', action='edit_template', cntrller=cntrller, item_type='library', form_type=form_type, library_id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Edit template</a>
- <a class="action-button" href="${h.url_for( controller='library_common', action='delete_template', cntrller=cntrller, item_type='library', form_type=form_type, library_id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Unuse template</a>
- %endif
- %if can_manage:
- %if not trans.app.security_agent.library_is_public( library, contents=True ):
- <a class="action-button" href="${h.url_for( controller='library_common', action='make_library_item_public', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_type='library', id=trans.security.encode_id( library.id ), contents=True, use_panels=use_panels, show_deleted=show_deleted )}">Make public</a>
- %endif
- <a class="action-button" href="${h.url_for( controller='library_common', action='library_permissions', cntrller=cntrller, id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Edit permissions</a>
- %endif
- %if root_folder_has_accessible_library_datasets:
- <a class="action-button" href="${h.url_for( controller='library_common', action='import_datasets_to_histories', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( library.root_folder.id ), use_panels=use_panels, show_deleted=show_deleted )}">Select datasets for import into selected histories</a>
- %endif
- %elif can_modify and not library.purged:
- <a class="action-button" href="${h.url_for( controller='library_common', action='undelete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( library.id ), item_type='library', use_panels=use_panels )}">Undelete this data library</a>
- %elif library.purged:
- <a class="action-button" href="${h.url_for( controller='library_common', action='browse_library', cntrller=cntrller, id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">This data library has been purged</a>
- %endif
- </div>
- %endif
- </ul>
-
- %if message:
- ${render_msg( message, status )}
- %endif
-
- %if library.synopsis not in [ '', 'None', None ]:
- <div class="libraryItemBody">
- ${library.synopsis}
- </div>
- %endif
-
- %if self.has_accessible_datasets:
- <form name="act_on_multiple_datasets" action="${h.url_for( controller='library_common', action='act_on_multiple_datasets', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}" onSubmit="javascript:return checkForm();" method="post">
- %endif
- %if has_accessible_folders:
- <table cellspacing="0" cellpadding="0" border="0" width="100%" class="grid" id="library-grid">
- <thead>
- <tr class="libraryTitle">
- <th>
- %if self.has_accessible_datasets:
- <input type="checkbox" id="checkAll" name=select_all_datasets_checkbox value="true" onclick='checkAllFields(1);'/><input type="hidden" name=select_all_datasets_checkbox value="true"/>
- %endif
- Name
- </th>
- % if not simple:
- <th>Message</th>
- <th>Data type</th>
- % endif
- <th>Date uploaded</th>
- <th>File size</th>
- </tr>
- </thead>
- <% row_counter = RowCounter() %>
- ## SM: Here is where we render the libraries based on admin/non-admin privileges:
- %if cntrller in [ 'library', 'requests' ]:
- ${self.render_folder( 'library', library.root_folder, 0, created_ldda_ids, library, hidden_folder_ids, tracked_datasets, show_deleted=show_deleted, parent=None, row_counter=row_counter, root_folder=True, simple=simple )}
- ## SM: TODO: WTF?
- %if not library.deleted and self.has_accessible_datasets and not simple:
- ${render_actions_on_multiple_items()}
- %endif
- %elif ( trans.user_is_admin() and cntrller in [ 'library_admin', 'requests_admin' ] ):
- ${self.render_folder( 'library_admin', library.root_folder, 0, created_ldda_ids, library, [], tracked_datasets, show_deleted=show_deleted, parent=None, row_counter=row_counter, root_folder=True )}
- ## SM: TODO: WTF?
- %if not library.deleted and not show_deleted and self.has_accessible_datasets:
- ${render_actions_on_multiple_items()}
- %endif
- %endif
- </table>
- %endif
- %if self.has_accessible_datasets:
- </form>
- %endif
-
- %if tracked_datasets:
- <script type="text/javascript">
- // Updater
- updater({${ ",".join( [ '"%s" : "%s"' % ( k, v ) for k, v in tracked_datasets.iteritems() ] ) }});
- </script>
- <!-- running: do not change this comment, used by TwillTestCase.library_wait -->
- %endif
-
- %if self.has_accessible_datasets and not simple:
- ${render_compression_types_help( comptypes )}
- %endif
- %if not has_accessible_folders:
- The data library '${library.name}' does not contain any datasets that you can access.
- %endif
-</%def>
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