galaxy-commits
Threads by month
- ----- 2026 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions
commit/galaxy-central: jgoecks: Make trackster compatible with backbone-relational v0.8.5
by commits-noreply@bitbucket.org 15 Aug '13
by commits-noreply@bitbucket.org 15 Aug '13
15 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/57348d7dcddf/
Changeset: 57348d7dcddf
User: jgoecks
Date: 2013-08-15 15:46:04
Summary: Make trackster compatible with backbone-relational v0.8.5
Affected #: 1 file
diff -r ebf6033a1cd4416602294b674628eb73da6fa663 -r 57348d7dcddfecf058916b3ff4d04fecb6a15301 static/scripts/viz/trackster/tracks.js
--- a/static/scripts/viz/trackster/tracks.js
+++ b/static/scripts/viz/trackster/tracks.js
@@ -2308,7 +2308,9 @@
//
// Attribute init.
//
- this.dataset = new data.Dataset(obj_dict.dataset);
+
+ // Only create dataset if it is defined.
+ this.dataset = (obj_dict.dataset ? new data.Dataset(obj_dict.dataset) : null);
this.dataset_check_type = 'converted_datasets_state';
this.data_url_extra_params = {};
this.data_query_wait = ('data_query_wait' in obj_dict ? obj_dict.data_query_wait : DEFAULT_DATA_QUERY_WAIT);
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/84c88d3644c0/
Changeset: 84c88d3644c0
User: jgoecks
Date: 2013-08-14 21:15:13
Summary: Update Backbone to v1.0.0 and Backbone-relational to v0.8.5
Affected #: 4 files
This diff is so big that we needed to truncate the remainder.
https://bitbucket.org/galaxy/galaxy-central/commits/ebf6033a1cd4/
Changeset: ebf6033a1cd4
User: jgoecks
Date: 2013-08-14 21:20:23
Summary: Tool panel refactoring: (a) make client-side code compatible with newest Backbone and Backbone-relational libraries; (b) use mixin rather than a base model on client; (c) add spacing between methods of server-side definition. Pack scripts.
Affected #: 4 files
diff -r 84c88d3644c0edc925fe2583276fbd32711f30a9 -r ebf6033a1cd4416602294b674628eb73da6fa663 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -94,6 +94,7 @@
class ToolBox( object ):
"""Container for a collection of tools"""
+
def __init__( self, config_filenames, tool_root_dir, app ):
"""
Create a toolbox from the config files named by `config_filenames`, using
@@ -144,6 +145,7 @@
# config files, adding or removing locally developed tools or workflows. The value of integrated_tool_panel
# will be False when things like functional tests are the caller.
self.write_integrated_tool_panel_config_file()
+
def init_tools( self, config_filename ):
"""
Read the configuration file and load each tool. The following tags are currently supported:
@@ -199,11 +201,13 @@
tool_path=tool_path,
config_elems=config_elems )
self.shed_tool_confs.append( shed_tool_conf_dict )
+
def get_shed_config_dict_by_filename( self, filename, default=None ):
for shed_config_dict in self.shed_tool_confs:
if shed_config_dict[ 'config_filename' ] == filename:
return shed_config_dict
return default
+
def __add_tool_to_tool_panel( self, tool_id, panel_component, section=False ):
# See if a version of this tool is already loaded into the tool panel. The value of panel_component
# will be a ToolSection (if the value of section=True) or self.tool_panel (if section=False).
@@ -239,6 +243,7 @@
del panel_dict[ loaded_version_key ]
panel_dict.insert( index, key, tool )
log.debug( "Loaded tool id: %s, version: %s into tool panel." % ( tool.id, tool.version ) )
+
def load_tool_panel( self ):
for key, val in self.integrated_tool_panel.items():
if key.startswith( 'tool_' ):
@@ -276,6 +281,7 @@
section.elems[ section_key ] = section_val
log.debug( "Loaded label: %s" % ( section_val.text ) )
self.tool_panel[ key ] = section
+
def load_integrated_tool_panel_keys( self ):
"""
Load the integrated tool panel keys, setting values for tools and workflows to None. The values will
@@ -308,6 +314,7 @@
elif elem.tag == 'label':
key = 'label_%s' % elem.get( 'id' )
self.integrated_tool_panel[ key ] = None
+
def write_integrated_tool_panel_config_file( self ):
"""
Write the current in-memory version of the integrated_tool_panel.xml file to disk. Since Galaxy administrators
@@ -350,6 +357,7 @@
os.close( fd )
shutil.move( filename, os.path.abspath( self.integrated_tool_panel_config ) )
os.chmod( self.integrated_tool_panel_config, 0644 )
+
def get_tool( self, tool_id, tool_version=None, get_all_versions=False ):
"""Attempt to locate a tool in the tool box."""
if tool_id in self.tools_by_id and not get_all_versions:
@@ -380,6 +388,7 @@
#No tool matches by version, simply return the first available tool found
return rval[0]
return None
+
def get_loaded_tools_by_lineage( self, tool_id ):
"""Get all loaded tools associated by lineage to the tool whose id is tool_id."""
tv = self.__get_tool_version( tool_id )
@@ -395,6 +404,7 @@
tool = self.tools_by_id[ tool_id ]
return [ tool ]
return []
+
def __get_tool_version( self, tool_id ):
"""Return a ToolVersion if one exists for the tool_id"""
return self.sa_session.query( self.app.model.ToolVersion ) \
@@ -527,6 +537,7 @@
integrated_panel_dict.insert( index, key, tool )
except:
log.exception( "Error reading tool from path: %s" % path )
+
def load_workflow_tag_set( self, elem, panel_dict, integrated_panel_dict, load_panel_dict, index=None ):
try:
# TODO: should id be encoded?
@@ -543,6 +554,7 @@
integrated_panel_dict.insert( index, key, workflow )
except:
log.exception( "Error loading workflow: %s" % workflow_id )
+
def load_label_tag_set( self, elem, panel_dict, integrated_panel_dict, load_panel_dict, index=None ):
label = ToolSectionLabel( elem )
key = 'label_' + label.id
@@ -552,6 +564,7 @@
integrated_panel_dict[ key ] = label
else:
integrated_panel_dict.insert( index, key, label )
+
def load_section_tag_set( self, elem, tool_path, load_panel_dict, index=None ):
key = 'section_' + elem.get( "id" )
if key in self.tool_panel:
@@ -580,6 +593,7 @@
self.integrated_tool_panel[ key ] = integrated_section
else:
self.integrated_tool_panel.insert( index, key, integrated_section )
+
def load_tool( self, config_file, guid=None, repository_id=None, **kwds ):
"""Load a single tool from the file named by `config_file` and return an instance of `Tool`."""
# Parse XML configuration file and get the root element
@@ -597,6 +611,7 @@
else:
ToolClass = Tool
return ToolClass( config_file, root, self.app, guid=guid, repository_id=repository_id, **kwds )
+
def reload_tool_by_id( self, tool_id ):
"""
Attempt to reload the tool identified by 'tool_id', if successful
@@ -634,6 +649,7 @@
message += "<b>version:</b> %s" % old_tool.version
status = 'done'
return message, status
+
def remove_tool_by_id( self, tool_id ):
"""
Attempt to remove the tool identified by 'tool_id'.
@@ -662,6 +678,7 @@
message += "<b>version:</b> %s" % tool.version
status = 'done'
return message, status
+
def load_workflow( self, workflow_id ):
"""
Return an instance of 'Workflow' identified by `id`,
@@ -670,11 +687,13 @@
id = self.app.security.decode_id( workflow_id )
stored = self.app.model.context.query( self.app.model.StoredWorkflow ).get( id )
return stored.latest_workflow
+
def init_dependency_manager( self ):
if self.app.config.use_tool_dependencies:
self.dependency_manager = DependencyManager( [ self.app.config.tool_dependency_dir ] )
else:
self.dependency_manager = None
+
@property
def sa_session( self ):
"""
@@ -683,9 +702,10 @@
return self.app.model.context
def to_dict( self, trans, in_panel=True, **kwds ):
- #
- # Dictify toolbox.
- #
+ """
+ Dictify toolbox.
+ """
+
context = Bunch( toolbox=self, trans=trans, **kwds )
if in_panel:
panel_elts = [ val for val in self.tool_panel.itervalues() ]
@@ -705,8 +725,8 @@
rval.append( elt.to_dict( trans, for_link=True ) )
else:
tools = []
- for id, tool in self.toolbox.tools_by_id.items():
- tools.append( tool.to_dict( trans ) )
+ for id, tool in self.tools_by_id.items():
+ tools.append( tool.to_dict( trans, for_link=True ) )
rval = tools
return rval
diff -r 84c88d3644c0edc925fe2583276fbd32711f30a9 -r ebf6033a1cd4416602294b674628eb73da6fa663 static/scripts/mvc/tools.js
--- a/static/scripts/mvc/tools.js
+++ b/static/scripts/mvc/tools.js
@@ -8,17 +8,13 @@
define( ["libs/underscore", "viz/trackster/util", "mvc/data", "libs/backbone/backbone-relational" ],
function(_, util, data) {
-
+
/**
- * Simple base model for any visible element. Includes useful attributes and ability
- * to set and track visibility.
+ * Mixin to enable model to track visibility.
*/
-var BaseModel = Backbone.RelationalModel.extend({
- defaults: {
- name: null,
- hidden: false
- },
-
+var VisibilityMixin = {
+ hidden: false,
+
show: function() {
this.set("hidden", false);
},
@@ -30,7 +26,8 @@
is_visible: function() {
return !this.attributes.hidden;
}
-});
+
+};
/**
* A tool parameter.
@@ -121,7 +118,7 @@
/**
* A Galaxy tool.
*/
-var Tool = BaseModel.extend({
+var Tool = Backbone.RelationalModel.extend({
// Default attributes.
defaults: {
id: null,
@@ -252,6 +249,7 @@
return run_deferred;
}
});
+_.extend(Tool.prototype, VisibilityMixin);
/**
* Tool view.
@@ -270,12 +268,12 @@
/**
* Label or section header in tool panel.
*/
-var ToolPanelLabel = BaseModel.extend({});
+var ToolPanelLabel = Backbone.Model.extend(VisibilityMixin);
/**
* Section of tool panel with elements (labels and tools).
*/
-var ToolPanelSection = BaseModel.extend({
+var ToolPanelSection = Backbone.Model.extend({
defaults: {
elems: [],
open: false
@@ -317,13 +315,14 @@
}
}
});
+_.extend(ToolPanelSection.prototype, VisibilityMixin);
/**
* Tool search that updates results when query is changed. Result value of null
* indicates that query was not run; if not null, results are from search using
* query.
*/
-var ToolSearch = BaseModel.extend({
+var ToolSearch = Backbone.Model.extend({
defaults: {
search_hint_string: "search tools",
min_chars_for_search: 3,
@@ -378,65 +377,48 @@
}
});
+_.extend(ToolSearch.prototype, VisibilityMixin);
/**
- * A collection of ToolPanelSections, Tools, and ToolPanelLabels. Collection
- * applies search results as they become available.
+ * Tool Panel.
*/
-var ToolPanel = Backbone.Collection.extend({
- // TODO: need to generate this using url_for
- url: "/tools",
- tools: new ToolCollection(),
-
+var ToolPanel = Backbone.Model.extend({
+
+ initialize: function(options) {
+ this.attributes.tool_search = options.tool_search;
+ this.attributes.tool_search.on("change:results", this.apply_search_results, this);
+ this.attributes.tools = options.tools;
+ this.attributes.layout = new Backbone.Collection( this.parse(options.layout) );
+ },
+
+ /**
+ * Parse tool panel dictionary and return collection of tool panel elements.
+ */
parse: function(response) {
// Recursive function to parse tool panel elements.
- var parse_elt = function(elt_dict) {
- var type = elt_dict.type;
- if (type === 'tool') {
- return new Tool(elt_dict);
- }
- else if (type === 'section') {
- // Parse elements.
- var elems = _.map(elt_dict.elems, parse_elt);
- elt_dict.elems = elems;
- return new ToolPanelSection(elt_dict);
- }
- else if (type === 'label') {
- return new ToolPanelLabel(elt_dict);
- }
- };
+ var self = this,
+ // Helper to recursively parse tool panel.
+ parse_elt = function(elt_dict) {
+ var type = elt_dict.type;
+ if (type === 'tool') {
+ return self.attributes.tools.get(elt_dict.id);
+ }
+ else if (type === 'section') {
+ // Parse elements.
+ var elems = _.map(elt_dict.elems, parse_elt);
+ elt_dict.elems = elems;
+ return new ToolPanelSection(elt_dict);
+ }
+ else if (type === 'label') {
+ return new ToolPanelLabel(elt_dict);
+ }
+ };
return _.map(response, parse_elt);
},
-
- initialize: function(options) {
- this.tool_search = options.tool_search;
- this.tool_search.on("change:results", this.apply_search_results, this);
- this.on("reset", this.populate_tools, this);
- },
-
- /**
- * Populate tool collection from panel elements.
- */
- populate_tools: function() {
- var self = this;
- self.tools = new ToolCollection();
- this.each(function(panel_elt) {
- if (panel_elt instanceof ToolPanelSection) {
- _.each(panel_elt.attributes.elems, function (section_elt) {
- if (section_elt instanceof Tool) {
- self.tools.push(section_elt);
- }
- });
- }
- else if (panel_elt instanceof Tool) {
- self.tools.push(panel_elt);
- }
- });
- },
-
+
clear_search_results: function() {
- this.each(function(panel_elt) {
+ this.get('layout').each(function(panel_elt) {
if (panel_elt instanceof ToolPanelSection) {
panel_elt.clear_search_results();
}
@@ -448,14 +430,14 @@
},
apply_search_results: function() {
- var results = this.tool_search.attributes.results;
+ var results = this.get('tool_search').get('results');
if (results === null) {
this.clear_search_results();
return;
}
var cur_label = null;
- this.each(function(panel_elt) {
+ this.get('layout').each(function(panel_elt) {
if (panel_elt instanceof ToolPanelLabel) {
cur_label = panel_elt;
cur_label.hide();
@@ -635,19 +617,19 @@
* Set up view.
*/
initialize: function() {
- this.collection.tool_search.on("change:results", this.handle_search_results, this);
+ this.model.get('tool_search').on("change:results", this.handle_search_results, this);
},
render: function() {
var self = this;
// Render search.
- var search_view = new ToolSearchView( {model: this.collection.tool_search} );
+ var search_view = new ToolSearchView( { model: this.model.get('tool_search') } );
search_view.render();
self.$el.append(search_view.$el);
// Render panel.
- this.collection.each(function(panel_elt) {
+ this.model.get('layout').each(function(panel_elt) {
if (panel_elt instanceof ToolPanelSection) {
var section_title_view = new ToolPanelSectionView({model: panel_elt});
section_title_view.render();
@@ -670,7 +652,7 @@
// Tool id is always the first class.
var
tool_id = $(this).attr('class').split(/\s+/)[0],
- tool = self.collection.tools.get(tool_id);
+ tool = self.model.get('tools').get(tool_id);
self.trigger("tool_link_click", e, tool);
});
@@ -679,7 +661,7 @@
},
handle_search_results: function() {
- var results = this.collection.tool_search.attributes.results;
+ var results = this.model.get('tool_search').get('results');
if (results && results.length === 0) {
$("#search-no-results").show();
}
@@ -752,6 +734,7 @@
ToolParameter: ToolParameter,
IntegerToolParameter: IntegerToolParameter,
Tool: Tool,
+ ToolCollection: ToolCollection,
ToolSearch: ToolSearch,
ToolPanel: ToolPanel,
ToolPanelView: ToolPanelView,
diff -r 84c88d3644c0edc925fe2583276fbd32711f30a9 -r ebf6033a1cd4416602294b674628eb73da6fa663 static/scripts/packed/mvc/tools.js
--- a/static/scripts/packed/mvc/tools.js
+++ b/static/scripts/packed/mvc/tools.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","viz/trackster/util","mvc/data","libs/backbone/backbone-relational"],function(t,a,u){var h=Backbone.RelationalModel.extend({defaults:{name:null,hidden:false},show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},is_visible:function(){return !this.attributes.hidden}});var d=Backbone.RelationalModel.extend({defaults:{name:null,label:null,type:null,value:null,html:null,num_samples:5},initialize:function(){this.attributes.html=unescape(this.attributes.html)},copy:function(){return new d(this.toJSON())},get_samples:function(){var w=this.get("type"),v=null;if(w==="number"){v=d3.scale.linear().domain([this.get("min"),this.get("max")]).ticks(this.get("num_samples"))}else{if(w==="select"){v=t.map(this.get("options"),function(x){return x[0]})}}return v},set_value:function(v){this.set("value",v||"")}},{TYPE_DICT:{number:c},create:function(v){var w=d.TYPE_DICT[v.type]||d;return new w(v)}});var c=d.extend({defaults:t.extend({},d.prototype.defaults,{min:null,max:null}),initialize:function(){d.prototype.initialize.call(this);if(this.attributes.min){this.attributes.min=parseInt(this.attributes.min,10)}if(this.attributes.max){this.attributes.max=parseInt(this.attributes.max,10)}},set_value:function(v){this.set("value",parseInt(v,10))}});var g=h.extend({defaults:{id:null,name:null,description:null,target:null,inputs:[]},initialize:function(v){this.attributes.inputs=new Backbone.Collection(t.map(v.inputs,function(w){return d.create(w)}))},urlRoot:galaxy_paths.get("tool_url"),copy:function(w){var x=new g(this.toJSON());if(w){var v=new Backbone.Collection();x.get("inputs").each(function(y){if(y.get_samples()){v.push(y)}});x.set("inputs",v)}return x},apply_search_results:function(v){(t.indexOf(v,this.attributes.id)!==-1?this.show():this.hide());return this.is_visible()},set_input_value:function(v,w){this.get("inputs").find(function(x){return x.get("name")===v}).set("value",w)},set_input_values:function(w){var v=this;t.each(t.keys(w),function(x){v.set_input_value(x,w[x])})},run:function(){return this._run()},rerun:function(w,v){return this._run({action:"rerun",target_dataset_id:w.id,regions:v})},get_inputs_dict:function(){var v={};this.get("inputs").each(function(w){v[w.get("name")]=w.get("value")});return v},_run:function(x){var y=t.extend({tool_id:this.id,inputs:this.get_inputs_dict()},x);var w=$.Deferred(),v=new a.ServerStateDeferred({ajax_settings:{url:this.urlRoot,data:JSON.stringify(y),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(z){return z!=="pending"}});$.when(v.go()).then(function(z){w.resolve(new u.DatasetCollection().reset(z))});return w}});var n=Backbone.View.extend({});var k=Backbone.Collection.extend({model:g});var o=h.extend({});var r=h.extend({defaults:{elems:[],open:false},clear_search_results:function(){t.each(this.attributes.elems,function(v){v.show()});this.show();this.set("open",false)},apply_search_results:function(w){var x=true,v;t.each(this.attributes.elems,function(y){if(y instanceof o){v=y;v.hide()}else{if(y instanceof g){if(y.apply_search_results(w)){x=false;if(v){v.show()}}}}});if(x){this.hide()}else{this.show();this.set("open",true)}}});var b=h.extend({defaults:{search_hint_string:"search tools",min_chars_for_search:3,spinner_url:"",clear_btn_url:"",search_url:"",visible:true,query:"",results:null,clear_key:27},initialize:function(){this.on("change:query",this.do_search)},do_search:function(){var x=this.attributes.query;if(x.length<this.attributes.min_chars_for_search){this.set("results",null);return}var w=x+"*";if(this.timer){clearTimeout(this.timer)}$("#search-clear-btn").hide();$("#search-spinner").show();var v=this;this.timer=setTimeout(function(){$.get(v.attributes.search_url,{query:w},function(y){v.set("results",y);$("#search-spinner").hide();$("#search-clear-btn").show()},"json")},200)},clear_search:function(){this.set("query","");this.set("results",null)}});var l=Backbone.Collection.extend({url:"/tools",tools:new k(),parse:function(v){var w=function(z){var y=z.type;if(y==="tool"){return new g(z)}else{if(y==="section"){var x=t.map(z.elems,w);z.elems=x;return new r(z)}else{if(y==="label"){return new o(z)}}}};return t.map(v,w)},initialize:function(v){this.tool_search=v.tool_search;this.tool_search.on("change:results",this.apply_search_results,this);this.on("reset",this.populate_tools,this)},populate_tools:function(){var v=this;v.tools=new k();this.each(function(w){if(w instanceof r){t.each(w.attributes.elems,function(x){if(x instanceof g){v.tools.push(x)}})}else{if(w instanceof g){v.tools.push(w)}}})},clear_search_results:function(){this.each(function(v){if(v instanceof r){v.clear_search_results()}else{v.show()}})},apply_search_results:function(){var w=this.tool_search.attributes.results;if(w===null){this.clear_search_results();return}var v=null;this.each(function(x){if(x instanceof o){v=x;v.hide()}else{if(x instanceof g){if(x.apply_search_results(w)){if(v){v.show()}}}else{v=null;x.apply_search_results(w)}}})}});var p=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){(this.model.attributes.hidden?this.$el.hide():this.$el.show())}});var j=p.extend({tagName:"div",template:Handlebars.templates.tool_link,render:function(){this.$el.append(this.template(this.model.toJSON()));return this}});var e=p.extend({tagName:"div",className:"toolPanelLabel",render:function(){this.$el.append($("<span/>").text(this.model.attributes.name));return this}});var i=p.extend({tagName:"div",className:"toolSectionWrapper",template:Handlebars.templates.panel_section,initialize:function(){p.prototype.initialize.call(this);this.model.on("change:open",this.update_open,this)},render:function(){this.$el.append(this.template(this.model.toJSON()));var v=this.$el.find(".toolSectionBody");t.each(this.model.attributes.elems,function(w){if(w instanceof g){var x=new j({model:w,className:"toolTitle"});x.render();v.append(x.$el)}else{if(w instanceof o){var y=new e({model:w});y.render();v.append(y.$el)}else{}}});return this},events:{"click .toolSectionTitle > a":"toggle"},toggle:function(){this.model.set("open",!this.model.attributes.open)},update_open:function(){(this.model.attributes.open?this.$el.children(".toolSectionBody").slideDown("fast"):this.$el.children(".toolSectionBody").slideUp("fast"))}});var m=Backbone.View.extend({tagName:"div",id:"tool-search",className:"bar",template:Handlebars.templates.tool_search,events:{click:"focus_and_select","keyup :input":"query_changed","click #search-clear-btn":"clear"},render:function(){this.$el.append(this.template(this.model.toJSON()));if(!this.model.is_visible()){this.$el.hide()}this.$el.find(".tooltip").tooltip();return this},focus_and_select:function(){this.$el.find(":input").focus().select()},clear:function(){this.model.clear_search();this.$el.find(":input").val(this.model.attributes.search_hint_string);this.focus_and_select();return false},query_changed:function(v){if((this.model.attributes.clear_key)&&(this.model.attributes.clear_key===v.which)){this.clear();return false}this.model.set("query",this.$el.find(":input").val())}});var s=Backbone.View.extend({tagName:"div",className:"toolMenu",initialize:function(){this.collection.tool_search.on("change:results",this.handle_search_results,this)},render:function(){var v=this;var w=new m({model:this.collection.tool_search});w.render();v.$el.append(w.$el);this.collection.each(function(y){if(y instanceof r){var x=new i({model:y});x.render();v.$el.append(x.$el)}else{if(y instanceof g){var z=new j({model:y,className:"toolTitleNoSection"});z.render();v.$el.append(z.$el)}else{if(y instanceof o){var A=new e({model:y});A.render();v.$el.append(A.$el)}}}});v.$el.find("a.tool-link").click(function(z){var y=$(this).attr("class").split(/\s+/)[0],x=v.collection.tools.get(y);v.trigger("tool_link_click",z,x)});return this},handle_search_results:function(){var v=this.collection.tool_search.attributes.results;if(v&&v.length===0){$("#search-no-results").show()}else{$("#search-no-results").hide()}}});var q=Backbone.View.extend({className:"toolForm",template:Handlebars.templates.tool_form,render:function(){this.$el.children().remove();this.$el.append(this.template(this.model.toJSON()))}});var f=Backbone.View.extend({className:"toolMenuAndView",initialize:function(){this.tool_panel_view=new s({collection:this.collection});this.tool_form_view=new q()},render:function(){this.tool_panel_view.render();this.tool_panel_view.$el.css("float","left");this.$el.append(this.tool_panel_view.$el);this.tool_form_view.$el.hide();this.$el.append(this.tool_form_view.$el);var v=this;this.tool_panel_view.on("tool_link_click",function(x,w){x.preventDefault();v.show_tool(w)})},show_tool:function(w){var v=this;w.fetch().done(function(){v.tool_form_view.model=w;v.tool_form_view.render();v.tool_form_view.$el.show();$("#left").width("650px")})}});return{ToolParameter:d,IntegerToolParameter:c,Tool:g,ToolSearch:b,ToolPanel:l,ToolPanelView:s,ToolFormView:q}});
\ No newline at end of file
+define(["libs/underscore","viz/trackster/util","mvc/data","libs/backbone/backbone-relational"],function(t,a,u){var e={hidden:false,show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},is_visible:function(){return !this.attributes.hidden}};var d=Backbone.RelationalModel.extend({defaults:{name:null,label:null,type:null,value:null,html:null,num_samples:5},initialize:function(){this.attributes.html=unescape(this.attributes.html)},copy:function(){return new d(this.toJSON())},get_samples:function(){var w=this.get("type"),v=null;if(w==="number"){v=d3.scale.linear().domain([this.get("min"),this.get("max")]).ticks(this.get("num_samples"))}else{if(w==="select"){v=t.map(this.get("options"),function(x){return x[0]})}}return v},set_value:function(v){this.set("value",v||"")}},{TYPE_DICT:{number:c},create:function(v){var w=d.TYPE_DICT[v.type]||d;return new w(v)}});var c=d.extend({defaults:t.extend({},d.prototype.defaults,{min:null,max:null}),initialize:function(){d.prototype.initialize.call(this);if(this.attributes.min){this.attributes.min=parseInt(this.attributes.min,10)}if(this.attributes.max){this.attributes.max=parseInt(this.attributes.max,10)}},set_value:function(v){this.set("value",parseInt(v,10))}});var h=Backbone.RelationalModel.extend({defaults:{id:null,name:null,description:null,target:null,inputs:[]},initialize:function(v){this.attributes.inputs=new Backbone.Collection(t.map(v.inputs,function(w){return d.create(w)}))},urlRoot:galaxy_paths.get("tool_url"),copy:function(w){var x=new h(this.toJSON());if(w){var v=new Backbone.Collection();x.get("inputs").each(function(y){if(y.get_samples()){v.push(y)}});x.set("inputs",v)}return x},apply_search_results:function(v){(t.indexOf(v,this.attributes.id)!==-1?this.show():this.hide());return this.is_visible()},set_input_value:function(v,w){this.get("inputs").find(function(x){return x.get("name")===v}).set("value",w)},set_input_values:function(w){var v=this;t.each(t.keys(w),function(x){v.set_input_value(x,w[x])})},run:function(){return this._run()},rerun:function(w,v){return this._run({action:"rerun",target_dataset_id:w.id,regions:v})},get_inputs_dict:function(){var v={};this.get("inputs").each(function(w){v[w.get("name")]=w.get("value")});return v},_run:function(x){var y=t.extend({tool_id:this.id,inputs:this.get_inputs_dict()},x);var w=$.Deferred(),v=new a.ServerStateDeferred({ajax_settings:{url:this.urlRoot,data:JSON.stringify(y),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(z){return z!=="pending"}});$.when(v.go()).then(function(z){w.resolve(new u.DatasetCollection().reset(z))});return w}});t.extend(h.prototype,e);var n=Backbone.View.extend({});var k=Backbone.Collection.extend({model:h});var o=Backbone.Model.extend(e);var r=Backbone.Model.extend({defaults:{elems:[],open:false},clear_search_results:function(){t.each(this.attributes.elems,function(v){v.show()});this.show();this.set("open",false)},apply_search_results:function(w){var x=true,v;t.each(this.attributes.elems,function(y){if(y instanceof o){v=y;v.hide()}else{if(y instanceof h){if(y.apply_search_results(w)){x=false;if(v){v.show()}}}}});if(x){this.hide()}else{this.show();this.set("open",true)}}});t.extend(r.prototype,e);var b=Backbone.Model.extend({defaults:{search_hint_string:"search tools",min_chars_for_search:3,spinner_url:"",clear_btn_url:"",search_url:"",visible:true,query:"",results:null,clear_key:27},initialize:function(){this.on("change:query",this.do_search)},do_search:function(){var x=this.attributes.query;if(x.length<this.attributes.min_chars_for_search){this.set("results",null);return}var w=x+"*";if(this.timer){clearTimeout(this.timer)}$("#search-clear-btn").hide();$("#search-spinner").show();var v=this;this.timer=setTimeout(function(){$.get(v.attributes.search_url,{query:w},function(y){v.set("results",y);$("#search-spinner").hide();$("#search-clear-btn").show()},"json")},200)},clear_search:function(){this.set("query","");this.set("results",null)}});t.extend(b.prototype,e);var l=Backbone.Model.extend({initialize:function(v){this.attributes.tool_search=v.tool_search;this.attributes.tool_search.on("change:results",this.apply_search_results,this);this.attributes.tools=v.tools;this.attributes.layout=new Backbone.Collection(this.parse(v.layout))},parse:function(w){var v=this,x=function(A){var z=A.type;if(z==="tool"){return v.attributes.tools.get(A.id)}else{if(z==="section"){var y=t.map(A.elems,x);A.elems=y;return new r(A)}else{if(z==="label"){return new o(A)}}}};return t.map(w,x)},clear_search_results:function(){this.get("layout").each(function(v){if(v instanceof r){v.clear_search_results()}else{v.show()}})},apply_search_results:function(){var w=this.get("tool_search").get("results");if(w===null){this.clear_search_results();return}var v=null;this.get("layout").each(function(x){if(x instanceof o){v=x;v.hide()}else{if(x instanceof h){if(x.apply_search_results(w)){if(v){v.show()}}}else{v=null;x.apply_search_results(w)}}})}});var p=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){(this.model.attributes.hidden?this.$el.hide():this.$el.show())}});var j=p.extend({tagName:"div",template:Handlebars.templates.tool_link,render:function(){this.$el.append(this.template(this.model.toJSON()));return this}});var f=p.extend({tagName:"div",className:"toolPanelLabel",render:function(){this.$el.append($("<span/>").text(this.model.attributes.name));return this}});var i=p.extend({tagName:"div",className:"toolSectionWrapper",template:Handlebars.templates.panel_section,initialize:function(){p.prototype.initialize.call(this);this.model.on("change:open",this.update_open,this)},render:function(){this.$el.append(this.template(this.model.toJSON()));var v=this.$el.find(".toolSectionBody");t.each(this.model.attributes.elems,function(w){if(w instanceof h){var x=new j({model:w,className:"toolTitle"});x.render();v.append(x.$el)}else{if(w instanceof o){var y=new f({model:w});y.render();v.append(y.$el)}else{}}});return this},events:{"click .toolSectionTitle > a":"toggle"},toggle:function(){this.model.set("open",!this.model.attributes.open)},update_open:function(){(this.model.attributes.open?this.$el.children(".toolSectionBody").slideDown("fast"):this.$el.children(".toolSectionBody").slideUp("fast"))}});var m=Backbone.View.extend({tagName:"div",id:"tool-search",className:"bar",template:Handlebars.templates.tool_search,events:{click:"focus_and_select","keyup :input":"query_changed","click #search-clear-btn":"clear"},render:function(){this.$el.append(this.template(this.model.toJSON()));if(!this.model.is_visible()){this.$el.hide()}this.$el.find(".tooltip").tooltip();return this},focus_and_select:function(){this.$el.find(":input").focus().select()},clear:function(){this.model.clear_search();this.$el.find(":input").val(this.model.attributes.search_hint_string);this.focus_and_select();return false},query_changed:function(v){if((this.model.attributes.clear_key)&&(this.model.attributes.clear_key===v.which)){this.clear();return false}this.model.set("query",this.$el.find(":input").val())}});var s=Backbone.View.extend({tagName:"div",className:"toolMenu",initialize:function(){this.model.get("tool_search").on("change:results",this.handle_search_results,this)},render:function(){var v=this;var w=new m({model:this.model.get("tool_search")});w.render();v.$el.append(w.$el);this.model.get("layout").each(function(y){if(y instanceof r){var x=new i({model:y});x.render();v.$el.append(x.$el)}else{if(y instanceof h){var z=new j({model:y,className:"toolTitleNoSection"});z.render();v.$el.append(z.$el)}else{if(y instanceof o){var A=new f({model:y});A.render();v.$el.append(A.$el)}}}});v.$el.find("a.tool-link").click(function(z){var y=$(this).attr("class").split(/\s+/)[0],x=v.model.get("tools").get(y);v.trigger("tool_link_click",z,x)});return this},handle_search_results:function(){var v=this.model.get("tool_search").get("results");if(v&&v.length===0){$("#search-no-results").show()}else{$("#search-no-results").hide()}}});var q=Backbone.View.extend({className:"toolForm",template:Handlebars.templates.tool_form,render:function(){this.$el.children().remove();this.$el.append(this.template(this.model.toJSON()))}});var g=Backbone.View.extend({className:"toolMenuAndView",initialize:function(){this.tool_panel_view=new s({collection:this.collection});this.tool_form_view=new q()},render:function(){this.tool_panel_view.render();this.tool_panel_view.$el.css("float","left");this.$el.append(this.tool_panel_view.$el);this.tool_form_view.$el.hide();this.$el.append(this.tool_form_view.$el);var v=this;this.tool_panel_view.on("tool_link_click",function(x,w){x.preventDefault();v.show_tool(w)})},show_tool:function(w){var v=this;w.fetch().done(function(){v.tool_form_view.model=w;v.tool_form_view.render();v.tool_form_view.$el.show();$("#left").width("650px")})}});return{ToolParameter:d,IntegerToolParameter:c,Tool:h,ToolCollection:k,ToolSearch:b,ToolPanel:l,ToolPanelView:s,ToolFormView:q}});
\ No newline at end of file
diff -r 84c88d3644c0edc925fe2583276fbd32711f30a9 -r ebf6033a1cd4416602294b674628eb73da6fa663 templates/webapps/galaxy/root/tool_menu.mako
--- a/templates/webapps/galaxy/root/tool_menu.mako
+++ b/templates/webapps/galaxy/root/tool_menu.mako
@@ -12,40 +12,45 @@
}
});
- require(["mvc/tools"], function(tools) {
+ require(["mvc/tools"], function(tools_mod) {
// Init. on document load.
$(function() {
- // Create tool search, tool panel, and tool panel view.
- var tool_search = new tools.ToolSearch({
- spinner_url: "${h.url_for('/static/images/loading_small_white_bg.gif')}",
- search_url: "${h.url_for( controller='root', action='tool_search' )}",
- hidden: false
- }),
- tool_panel = new tools.ToolPanel({ tool_search: tool_search }),
- tool_panel_view = new tools.ToolPanelView({ collection: tool_panel });
-
- // Add tool panel to Galaxy object.
- Galaxy.toolPanel = tool_panel;
-
## Populate tool panel if (a) anonymous use possible or (b) user is logged in.
%if trans.user or not trans.app.config.require_login:
- tool_panel.reset( tool_panel.parse( ${h.to_json_string( trans.app.toolbox.to_dict( trans ) )} ) );
+ // Create tool search, tool panel, and tool panel view.
+ var tool_search = new tools_mod.ToolSearch({
+ spinner_url: "${h.url_for('/static/images/loading_small_white_bg.gif')}",
+ search_url: "${h.url_for( controller='root', action='tool_search' )}",
+ hidden: false
+ }),
+ tools = new tools_mod.ToolCollection(
+ ${ h.to_json_string( trans.app.toolbox.to_dict( trans, in_panel=False ) ) }
+ ),
+ tool_panel = new tools_mod.ToolPanel({
+ tool_search: tool_search,
+ tools: tools,
+ layout: ${h.to_json_string( trans.app.toolbox.to_dict( trans ) )}
+ }),
+ tool_panel_view = new tools_mod.ToolPanelView({ model: tool_panel });
+
+ // Add tool panel to Galaxy object.
+ Galaxy.toolPanel = tool_panel;
+
+ // If there are tools, render panel and display everything.
+ if (tool_panel.get('layout').size() > 1) {
+ tool_panel_view.render();
+ $('.toolMenu').show();
+ }
+ $('.toolMenuContainer').prepend(tool_panel_view.$el);
+
+ // Minsize init hint.
+ $( "a[minsizehint]" ).click( function() {
+ if ( parent.handle_minwidth_hint ) {
+ parent.handle_minwidth_hint( $(this).attr( "minsizehint" ) );
+ }
+ });
%endif
-
- // If there are tools, render panel and display everything.
- if (tool_panel.length > 1) { // > 1 because tool_search counts as a model
- tool_panel_view.render();
- $('.toolMenu').show();
- }
- $('.toolMenuContainer').prepend(tool_panel_view.$el);
-
- // Minsize init hint.
- $( "a[minsizehint]" ).click( function() {
- if ( parent.handle_minwidth_hint ) {
- parent.handle_minwidth_hint( $(this).attr( "minsizehint" ) );
- }
- });
});
});
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: carlfeberhard: UI: change load order of user-related JS; pack scripts
by commits-noreply@bitbucket.org 14 Aug '13
by commits-noreply@bitbucket.org 14 Aug '13
14 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/2c3f4163da4e/
Changeset: 2c3f4163da4e
User: carlfeberhard
Date: 2013-08-14 19:09:51
Summary: UI: change load order of user-related JS; pack scripts
Affected #: 8 files
diff -r 3f85113b7476767ef1dc76c7f3312b423ff743db -r 2c3f4163da4ef47bb3f04da580e5015961dc0c67 static/scripts/packed/galaxy.autocom_tagging.js
--- a/static/scripts/packed/galaxy.autocom_tagging.js
+++ b/static/scripts/packed/galaxy.autocom_tagging.js
@@ -1,1 +1,1 @@
-function init_tag_click_function(b,a){$(b).find(".tag-name").each(function(){$(this).click(function(){var d=$(this).text();var c=d.split(":");a(c[0],c[1]);return true})})}jQuery.fn.autocomplete_tagging=function(m){var f={get_toggle_link_text_fn:function(n){var p="";var o=obj_length(n);if(o>0){p=o+(o>1?" Tags":" Tag")}else{p="Add tags"}return p},tag_click_fn:function(n,o){},editable:true,input_size:20,in_form:false,tags:{},use_toggle_link:true,item_id:"",add_tag_img:"",add_tag_img_rollover:"",delete_tag_img:"",ajax_autocomplete_tag_url:"",ajax_retag_url:"",ajax_delete_tag_url:"",ajax_add_tag_url:""};var d=jQuery.extend(f,m);var g=$(this);var b=g.find(".tag-area");var e=g.find(".toggle-link");var a=g.find(".tag-input");var l=g.find(".add-tag-button");e.click(function(){var n;if(b.is(":hidden")){n=function(){var o=$(this).find(".tag-button").length;if(o===0){b.click()}}}else{n=function(){b.blur()}}b.slideToggle("fast",n);return $(this)});if(d.editable){a.hide()}a.keyup(function(t){if(t.keyCode===27){$(this).trigger("blur")}else{if((t.keyCode===13)||(t.keyCode===188)||(t.keyCode===32)){var s=this.value;if(return_key_pressed_for_autocomplete===true){return_key_pressed_for_autocomplete=false;return false}if(s.indexOf(": ",s.length-2)!==-1){this.value=s.substring(0,s.length-1);return false}if((t.keyCode===188)||(t.keyCode===32)){s=s.substring(0,s.length-1)}s=$.trim(s);if(s.length<2){return false}this.value="";var q=j(s);var p=b.children(".tag-button");if(p.length!==0){var u=p.slice(p.length-1);u.after(q)}else{b.prepend(q)}var o=s.split(":");d.tags[o[0]]=o[1];var r=d.get_toggle_link_text_fn(d.tags);e.text(r);var n=$(this);$.ajax({url:d.ajax_add_tag_url,data:{new_tag:s},error:function(){q.remove();delete d.tags[o[0]];var v=d.get_toggle_link_text_fn(d.tags);e.text(v);alert("Add tag failed")},success:function(){n.flushCache()}});return false}}});var i=function(q,p,o,s,r){var n=s.split(":");return(n.length===1?n[0]:n[1])};var h={selectFirst:false,formatItem:i,autoFill:false,highlight:false};a.autocomplete(d.ajax_autocomplete_tag_url,h);g.find(".delete-tag-img").each(function(){c($(this))});init_tag_click_function($(this),d.tag_click_fn);l.click(function(){$(this).hide();b.click();return false});if(d.editable){b.bind("blur",function(n){if(obj_length(d.tags)>0){l.show();a.hide();b.removeClass("active-tag-area");b.addClass("tooltip")}else{}});b.click(function(p){var o=$(this).hasClass("active-tag-area");if($(p.target).hasClass("delete-tag-img")&&!o){return false}if($(p.target).hasClass("tag-name")&&!o){return false}$(this).removeClass("tooltip");$(this).addClass("active-tag-area");l.hide();a.show();a.focus();var n=function(r){var q=function(s,u){var t=s.attr("id");if(u!==s){s.blur();$(window).unbind("click.tagging_blur");$(this).addClass("tooltip")}};q(b,$(r.target))};$(window).bind("click.tagging_blur",n);return false})}if(d.use_toggle_link){b.hide()}function k(o,n){return o+(n?":"+n:"")}function c(n){$(n).mouseenter(function(){$(this).attr("src",d.delete_tag_img_rollover)});$(n).mouseleave(function(){$(this).attr("src",d.delete_tag_img)});$(n).click(function(){var t=$(this).parent();var s=t.find(".tag-name").eq(0);var r=s.text();var p=r.split(":");var v=p[0];var o=p[1];var u=t.prev();t.remove();delete d.tags[v];var q=d.get_toggle_link_text_fn(d.tags);e.text(q);$.ajax({url:d.ajax_delete_tag_url,data:{tag_name:v},error:function(){d.tags[v]=o;if(u.hasClass("tag-button")){u.after(t)}else{b.prepend(t)}alert("Remove tag failed");e.text(d.get_toggle_link_text_fn(d.tags));n.mouseenter(function(){$(this).attr("src",d.delete_tag_img_rollover)});n.mouseleave(function(){$(this).attr("src",d.delete_tag_img)})},success:function(){}});return true})}function j(n){var o=$("<img/>").attr("src",d.delete_tag_img).addClass("delete-tag-img");c(o);var p=$("<span>").text(n).addClass("tag-name");p.click(function(){var r=n.split(":");d.tag_click_fn(r[0],r[1]);return true});var q=$("<span></span>").addClass("tag-button");q.append(p);if(d.editable){q.append(o)}return q}};
\ No newline at end of file
+function init_tag_click_function(b,a){$(b).find(".tag-name").each(function(){$(this).click(function(){var d=$(this).text();var c=d.split(":");a(c[0],c[1]);return true})})}jQuery.fn.autocomplete_tagging=function(m){var f={get_toggle_link_text_fn:function(n){var p="";var o=obj_length(n);if(o>0){p=o+(o>1?" Tags":" Tag")}else{p="Add tags"}return p},tag_click_fn:function(n,o){},editable:true,input_size:20,in_form:false,tags:{},use_toggle_link:true,item_id:"",add_tag_img:"",add_tag_img_rollover:"",delete_tag_img:"",ajax_autocomplete_tag_url:"",ajax_retag_url:"",ajax_delete_tag_url:"",ajax_add_tag_url:""};var d=jQuery.extend(f,m);var g=$(this);var b=g.find(".tag-area");var e=g.find(".toggle-link");var a=g.find(".tag-input");var l=g.find(".add-tag-button");e.click(function(){var n;if(b.is(":hidden")){n=function(){var o=$(this).find(".tag-button").length;if(o===0){b.click()}}}else{n=function(){b.blur()}}b.slideToggle("fast",n);return $(this)});if(d.editable){a.hide()}a.keyup(function(t){if(t.keyCode===27){$(this).trigger("blur")}else{if((t.keyCode===13)||(t.keyCode===188)||(t.keyCode===32)){var s=this.value;if(s.indexOf(": ",s.length-2)!==-1){this.value=s.substring(0,s.length-1);return false}if((t.keyCode===188)||(t.keyCode===32)){s=s.substring(0,s.length-1)}s=$.trim(s);if(s.length<2){return false}this.value="";var q=j(s);var p=b.children(".tag-button");if(p.length!==0){var u=p.slice(p.length-1);u.after(q)}else{b.prepend(q)}var o=s.split(":");d.tags[o[0]]=o[1];var r=d.get_toggle_link_text_fn(d.tags);e.text(r);var n=$(this);$.ajax({url:d.ajax_add_tag_url,data:{new_tag:s},error:function(){q.remove();delete d.tags[o[0]];var v=d.get_toggle_link_text_fn(d.tags);e.text(v);alert("Add tag failed")},success:function(){n.data("autocompleter").cacheFlush()}});return false}}});var i=function(q,p,o,s,r){var n=s.split(":");return(n.length===1?n[0]:n[1])};var h={selectFirst:false,formatItem:i,autoFill:false,highlight:false};a.autocomplete(d.ajax_autocomplete_tag_url,h);g.find(".delete-tag-img").each(function(){c($(this))});init_tag_click_function($(this),d.tag_click_fn);l.click(function(){$(this).hide();b.click();return false});if(d.editable){b.bind("blur",function(n){if(obj_length(d.tags)>0){l.show();a.hide();b.removeClass("active-tag-area");b.addClass("tooltip")}else{}});b.click(function(p){var o=$(this).hasClass("active-tag-area");if($(p.target).hasClass("delete-tag-img")&&!o){return false}if($(p.target).hasClass("tag-name")&&!o){return false}$(this).removeClass("tooltip");$(this).addClass("active-tag-area");l.hide();a.show();a.focus();var n=function(r){var q=function(s,u){var t=s.attr("id");if(u!==s){s.blur();$(window).unbind("click.tagging_blur");$(this).addClass("tooltip")}};q(b,$(r.target))};$(window).bind("click.tagging_blur",n);return false})}if(d.use_toggle_link){b.hide()}function k(o,n){return o+(n?":"+n:"")}function c(n){$(n).mouseenter(function(){$(this).attr("src",d.delete_tag_img_rollover)});$(n).mouseleave(function(){$(this).attr("src",d.delete_tag_img)});$(n).click(function(){var t=$(this).parent();var s=t.find(".tag-name").eq(0);var r=s.text();var p=r.split(":");var v=p[0];var o=p[1];var u=t.prev();t.remove();delete d.tags[v];var q=d.get_toggle_link_text_fn(d.tags);e.text(q);$.ajax({url:d.ajax_delete_tag_url,data:{tag_name:v},error:function(){d.tags[v]=o;if(u.hasClass("tag-button")){u.after(t)}else{b.prepend(t)}alert("Remove tag failed");e.text(d.get_toggle_link_text_fn(d.tags));n.mouseenter(function(){$(this).attr("src",d.delete_tag_img_rollover)});n.mouseleave(function(){$(this).attr("src",d.delete_tag_img)})},success:function(){}});return true})}function j(n){var o=$("<img/>").attr("src",d.delete_tag_img).addClass("delete-tag-img");c(o);var p=$("<span>").text(n).addClass("tag-name");p.click(function(){var r=n.split(":");d.tag_click_fn(r[0],r[1]);return true});var q=$("<span></span>").addClass("tag-button");q.append(p);if(d.editable){q.append(o)}return q}};
\ No newline at end of file
diff -r 3f85113b7476767ef1dc76c7f3312b423ff743db -r 2c3f4163da4ef47bb3f04da580e5015961dc0c67 static/scripts/packed/libs/jquery/jquery.autocomplete.js
--- a/static/scripts/packed/libs/jquery/jquery.autocomplete.js
+++ b/static/scripts/packed/libs/jquery/jquery.autocomplete.js
@@ -1,1 +1,1 @@
-String.prototype.endsWith=function(a){return(this.match(a+"$")==a)};var return_key_pressed_for_autocomplete=false;(function(a){a.fn.extend({autocomplete:function(b,c){var d=typeof b=="string";c=a.extend({},a.Autocompleter.defaults,{url:d?b:null,data:d?null:b,delay:d?a.Autocompleter.defaults.delay:10,max:c&&!c.scroll?10:150},c);c.highlight=c.highlight||function(e){return e};c.formatMatch=c.formatMatch||c.formatItem;return this.each(function(){new a.Autocompleter(this,c)})},result:function(b){return this.bind("result",b)},search:function(b){return this.trigger("search",[b])},flushCache:function(){return this.trigger("flushCache")},setOptions:function(b){return this.trigger("setOptions",[b])},unautocomplete:function(){return this.trigger("unautocomplete")},showAllInCache:function(){return this.trigger("showAllInCache")}});a.Autocompleter=function(l,g){var c={UP:38,DOWN:40,DEL:46,TAB:9,RETURN:13,ESC:27,COMMA:188,PAGEUP:33,PAGEDOWN:34,BACKSPACE:8,COLON:16};var b=a(l).attr("autocomplete","off").addClass(g.inputClass);var j;var p="";var m=a.Autocompleter.Cache(g);var e=0;var u;var x={mouseDownOnSelect:false};var r=a.Autocompleter.Select(g,l,d,x);var w;a.browser.opera&&a(l.form).bind("submit.autocomplete",function(){if(w){w=false;return false}});b.bind((a.browser.mozilla?"keypress":"keydown")+".autocomplete",function(y){u=y.keyCode;switch(y.keyCode){case c.UP:y.preventDefault();if(r.visible()){r.prev()}else{t(0,true)}break;case c.DOWN:y.preventDefault();if(r.visible()){r.next()}else{t(0,true)}break;case c.PAGEUP:y.preventDefault();if(r.visible()){r.pageUp()}else{t(0,true)}break;case c.PAGEDOWN:y.preventDefault();if(r.visible()){r.pageDown()}else{t(0,true)}break;case g.multiple&&a.trim(g.multipleSeparator)==","&&c.COMMA:case c.TAB:case c.RETURN:if(y.keyCode==c.RETURN){return_key_pressed_for_autocomplete=false}if(d()){y.preventDefault();w=true;if(y.keyCode==c.RETURN){return_key_pressed_for_autocomplete=true}return false}case c.ESC:r.hide();break;case c.COLON:break;default:clearTimeout(j);j=setTimeout(t,g.delay);break}}).focus(function(){e++}).blur(function(){e=0;if(!x.mouseDownOnSelect){r.hide()}return this}).click(function(){if(e++>1&&!r.visible()){t(0,true)}return this}).bind("search",function(){var y=(arguments.length>1)?arguments[1]:null;function z(D,C){var A;if(C&&C.length){for(var B=0;B<C.length;B++){if(C[B].result.toLowerCase()==D.toLowerCase()){A=C[B];break}}}if(typeof y=="function"){y(A)}else{b.trigger("result",A&&[A.data,A.value])}}a.each(h(b.val()),function(A,B){f(B,z,z)});return this}).bind("flushCache",function(){m.flush()}).bind("setOptions",function(){a.extend(g,arguments[1]);if("data" in arguments[1]){m.populate()}}).bind("unautocomplete",function(){r.unbind();b.unbind();a(l.form).unbind(".autocomplete")}).bind("showAllInCache",function(){k("",m.load(""))});function d(){var z=r.selected();if(!z){return false}var y=z.result;p=y;if(g.multiple){var A=h(b.val());if(A.length>1){y=A.slice(0,A.length-1).join(g.multipleSeparator)+g.multipleSeparator+y}y+=g.multipleSeparator}b.val(y);v();b.trigger("result",[z.data,z.value]);return true}function t(A,z){if(u==c.DEL){r.hide();return}var y=b.val();if(!z&&y==p){return}p=y;y=i(y);if(y.length>=g.minChars){b.addClass(g.loadingClass);if(!g.matchCase){y=y.toLowerCase()}f(y,k,v)}else{n();r.hide()}}function h(z){if(!z){return[""]}var A=z.split(g.multipleSeparator);var y=[];a.each(A,function(B,C){if(a.trim(C)){y[B]=a.trim(C)}});return y}function i(y){if(!g.multiple){return y}var z=h(y);return z[z.length-1]}function q(y,z){if(g.autoFill&&(i(b.val()).toLowerCase()==y.toLowerCase())&&u!=c.BACKSPACE){b.val(b.val()+z.substring(i(p).length));a.Autocompleter.Selection(l,p.length,p.length+z.length)}}function s(){clearTimeout(j);j=setTimeout(v,200)}function v(){var y=r.visible();r.hide();clearTimeout(j);n();if(g.mustMatch){b.search(function(z){if(!z){if(g.multiple){var A=h(b.val()).slice(0,-1);b.val(A.join(g.multipleSeparator)+(A.length?g.multipleSeparator:""))}else{b.val("")}}})}if(y){a.Autocompleter.Selection(l,l.value.length,l.value.length)}}function k(z,y){if(y&&y.length&&e){n();r.display(y,z);q(z,y[0].value);r.show()}else{v()}}function f(z,B,y){if(!g.matchCase){z=z.toLowerCase()}var A=m.load(z);if(z.endsWith(":")){A=null}if(A&&A.length){B(z,A)}else{if((typeof g.url=="string")&&(g.url.length>0)){var C={timestamp:+new Date()};a.each(g.extraParams,function(D,E){C[D]=typeof E=="function"?E():E});a.ajax({mode:"abort",port:"autocomplete"+l.name,dataType:g.dataType,url:g.url,data:a.extend({q:i(z),limit:g.max},C),success:function(E){var D=g.parse&&g.parse(E)||o(E);m.add(z,D);B(z,D)}})}else{r.emptyList();y(z)}}}function o(B){var y=[];var A=B.split("\n");for(var z=0;z<A.length;z++){var C=a.trim(A[z]);if(C){C=C.split("|");y[y.length]={data:C,value:C[0],result:g.formatResult&&g.formatResult(C,C[0])||C[0]}}}return y}function n(){b.removeClass(g.loadingClass)}};a.Autocompleter.defaults={inputClass:"ac_input",resultsClass:"ac_results",loadingClass:"ac_loading",minChars:1,delay:400,matchCase:false,matchSubset:true,matchContains:false,cacheLength:10,max:100,mustMatch:false,extraParams:{},selectFirst:true,formatItem:function(b){return b[0]},formatMatch:null,autoFill:false,width:0,multiple:false,multipleSeparator:", ",highlight:function(c,b){if(b==""){return c}return c.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+b.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"<strong>$1</strong>")},scroll:true,scrollHeight:180};a.Autocompleter.Cache=function(c){var f={};var d=0;function h(l,k){if(!c.matchCase){l=l.toLowerCase()}var j=l.indexOf(k);if(j==-1){return false}return j==0||c.matchContains}function g(j,i){if(d>c.cacheLength){b()}if(!f[j]){d++}f[j]=i}function e(){if(!c.data){return false}var k={},j=0;if(!c.url){c.cacheLength=1}k[""]=[];for(var m=0,l=c.data.length;m<l;m++){var o=c.data[m];o=(typeof o=="string")?[o]:o;var n=c.formatMatch(o,m+1,c.data.length);if(n===false){continue}if(!k[n]){k[n]=[]}var p={value:n,data:o,result:c.formatResult&&c.formatResult(o)||n};k[n].push(p);if(j++<c.max){k[""].push(p)}}a.each(k,function(q,r){c.cacheLength++;g(q,r)})}setTimeout(e,25);function b(){f={};d=0}return{flush:b,add:g,populate:e,load:function(n){if(!c.cacheLength||!d){return null}if(!c.url&&c.matchContains){var m=[];for(var j in f){if(j.length>0){var o=f[j];a.each(o,function(p,k){if(h(k.value,n)){m.push(k)}})}}return m}else{if(f[n]){return f[n]}else{if(c.matchSubset){for(var l=n.length-1;l>=c.minChars;l--){var o=f[n.substr(0,l)];if(o){var m=[];a.each(o,function(p,k){if((k.data.indexOf("#Header")==0)||(h(k.value,n))){m[m.length]=k}});return m}}}}}return null}}};a.Autocompleter.Select=function(e,j,l,q){var i={ACTIVE:"ac_over"};var k,f=-1,s,m="",t=true,c,p;function o(){if(!t){return}c=a("<div/>").hide().addClass(e.resultsClass).css("position","absolute").bind("mouseleave",function(){c.hide()}).appendTo(document.body);p=a("<ul/>").appendTo(c).mouseover(function(u){if(r(u).nodeName&&r(u).nodeName.toUpperCase()=="LI"){f=a("li",p).removeClass(i.ACTIVE).index(r(u));if(!n(f)){a(r(u)).addClass(i.ACTIVE)}}}).click(function(u){f=a("li",p).index(r(u));if(n(f)){return}a(r(u)).addClass(i.ACTIVE);l();j.focus();return false}).mousedown(function(){q.mouseDownOnSelect=true}).mouseup(function(){q.mouseDownOnSelect=false});if(e.width>0){c.css("width",e.width)}t=false}function r(v){var u=v.target;while(u&&u.tagName!="LI"){u=u.parentNode}if(!u){return[]}return u}function n(u){dataAtPosition=s[u].data;return(dataAtPosition[0].indexOf("#Header")==0)}function h(u){k.slice(f,f+1).removeClass(i.ACTIVE);var v=false;do{g(u);v=n(f)}while(v);var x=k.slice(f,f+1).addClass(i.ACTIVE);if(e.scroll){var w=0;k.slice(0,f).each(function(){w+=this.offsetHeight});if((w+x[0].offsetHeight-p.scrollTop())>p[0].clientHeight){p.scrollTop(w+x[0].offsetHeight-p.innerHeight())}else{if(w<p.scrollTop()){p.scrollTop(w)}}}}function g(u){f+=u;if(f<0){f=k.size()-1}else{if(f>=k.size()){f=0}}}function b(u){return e.max&&e.max<u?e.max:u}function d(){p.empty();var v=b(s.length);for(var w=0;w<v;w++){if(!s[w]){continue}var x=e.formatItem(s[w].data,w+1,v,s[w].value,m);if(x===false){continue}if(n(w)){if(w!=v-1){var u=a("<li/>").html(s[w].data[1]).addClass("ac_header").appendTo(p)[0]}}else{var u=a("<li/>").html(e.highlight(x,m)).addClass(w%2==0?"ac_even":"ac_odd").appendTo(p)[0]}a.data(u,"ac_data",s[w])}k=p.find("li");if(e.selectFirst){k.slice(0,1).addClass(i.ACTIVE);f=0}if(a.fn.bgiframe){p.bgiframe()}}return{display:function(v,u){o();s=v;m=u;d()},next:function(){h(1)},prev:function(){h(-1)},pageUp:function(){if(f!=0&&f-8<0){h(-f)}else{h(-8)}},pageDown:function(){if(f!=k.size()-1&&f+8>k.size()){h(k.size()-1-f)}else{h(8)}},hide:function(){c&&c.hide();k&&k.removeClass(i.ACTIVE);f=-1},visible:function(){return c&&c.is(":visible")},current:function(){return this.visible()&&(k.filter("."+i.ACTIVE)[0]||e.selectFirst&&k[0])},show:function(){var w=a(j).offset();c.css({width:typeof e.width=="string"||e.width>0?e.width:a(j).width(),top:w.top+j.offsetHeight,left:w.left}).show();if(e.scroll){p.scrollTop(0);p.css({maxHeight:e.scrollHeight,overflow:"auto"});if(a.browser.msie&&typeof document.body.style.maxHeight==="undefined"){var u=0;k.each(function(){u+=this.offsetHeight});var v=u>e.scrollHeight;p.css("height",v?e.scrollHeight:u);if(!v){k.width(p.width()-parseInt(k.css("padding-left"))-parseInt(k.css("padding-right")))}}}},selected:function(){var u=k&&k.filter("."+i.ACTIVE).removeClass(i.ACTIVE);return u&&u.length&&a.data(u[0],"ac_data")},emptyList:function(){p&&p.empty()},unbind:function(){c&&c.remove()}}};a.Autocompleter.Selection=function(d,e,c){if(d.createTextRange){var b=d.createTextRange();b.collapse(true);b.moveStart("character",e);b.moveEnd("character",c);b.select()}else{if(d.setSelectionRange){d.setSelectionRange(e,c)}else{if(d.selectionStart){d.selectionStart=e;d.selectionEnd=c}}}d.focus()}})(jQuery);
\ No newline at end of file
+(function(e){e.fn.autocomplete=function(i){var h;if(arguments.length>1){h=i;i=arguments[1];i.url=h}else{if(typeof i==="string"){h=i;i={url:h}}}var j=e.extend({},e.fn.autocomplete.defaults,i);return this.each(function(){var k=e(this);k.data("autocompleter",new e.Autocompleter(k,e.meta?e.extend({},j,k.data()):j))})};e.fn.autocomplete.defaults={inputClass:"acInput",loadingClass:"acLoading",resultsClass:"acResults",selectClass:"acSelect",queryParamName:"q",extraParams:{},remoteDataType:false,lineSeparator:"\n",cellSeparator:"|",minChars:2,maxItemsToShow:10,delay:400,useCache:true,maxCacheLength:10,matchSubset:true,matchCase:false,matchInside:true,mustMatch:false,selectFirst:false,selectOnly:false,showResult:null,preventDefaultReturn:1,preventDefaultTab:0,autoFill:false,filterResults:true,filter:true,sortResults:true,sortFunction:null,onItemSelect:null,onNoMatch:null,onFinish:null,matchStringConverter:null,beforeUseConverter:null,autoWidth:"min-width",useDelimiter:false,delimiterChar:",",delimiterKeyCode:188,processData:null,onError:null,enabled:true};var d=function(h){var k,j;var i=typeof h;if(i==="string"){k=h;j={}}else{if(e.isArray(h)){k=h[0];j=h.slice(1)}else{if(i==="object"){k=h.value;j=h.data}}}k=String(k);if(typeof j!=="object"){j={}}return{value:k,data:j}};var g=function(k,h,j){var i=parseInt(k,10);j=j||{};if(isNaN(i)||(j.min&&i<j.min)){i=h}return i};var b=function(h,i){return[h,encodeURIComponent(i)].join("=")};var c=function(h,j){var i=[];e.each(j,function(k,l){i.push(b(k,l))});if(i.length){h+=h.indexOf("?")===-1?"?":"&";h+=i.join("&")}return h};var f=function(i,h,j){i=String(i.value);h=String(h.value);if(!j){i=i.toLowerCase();h=h.toLowerCase()}if(i>h){return 1}if(i<h){return -1}return 0};var a=function(q,k,h){var n=[];var o,l,m,s,p,r;r=String(q).replace("\r\n","\n").split(k);for(o=0;o<r.length;o++){s=r[o].split(h);m=[];for(l=0;l<s.length;l++){m.push(decodeURIComponent(s[l]))}p=m.shift();n.push({value:p,data:m})}return n};e.Autocompleter=function(i,j){if(!i||!(i instanceof e)||i.length!==1||(i.get(0).tagName.toUpperCase()!=="INPUT"&&i.get(0).tagName.toUpperCase()!=="TEXTAREA")){throw new Error("Invalid parameter for jquery.Autocompleter, jQuery object with one element with INPUT or TEXTAREA tag expected.")}var h=this;this.options=j;this.cacheData_={};this.cacheLength_=0;this.selectClass_="jquery-autocomplete-selected-item";this.keyTimeout_=null;this.finishTimeout_=null;this.lastKeyPressed_=null;this.lastProcessedValue_=null;this.lastSelectedValue_=null;this.active_=false;this.finishOnBlur_=true;this.options.minChars=g(this.options.minChars,e.fn.autocomplete.defaults.minChars,{min:0});this.options.maxItemsToShow=g(this.options.maxItemsToShow,e.fn.autocomplete.defaults.maxItemsToShow,{min:0});this.options.maxCacheLength=g(this.options.maxCacheLength,e.fn.autocomplete.defaults.maxCacheLength,{min:1});this.options.delay=g(this.options.delay,e.fn.autocomplete.defaults.delay,{min:0});if(this.options.preventDefaultReturn!=2){this.options.preventDefaultReturn=this.options.preventDefaultReturn?1:0}if(this.options.preventDefaultTab!=2){this.options.preventDefaultTab=this.options.preventDefaultTab?1:0}this.dom={};this.dom.$elem=i;this.dom.$elem.attr("autocomplete","off").addClass(this.options.inputClass);this.dom.$results=e("<div></div>").hide().addClass(this.options.resultsClass).css({position:"absolute"});e("body").append(this.dom.$results);i.keydown(function(l){h.lastKeyPressed_=l.keyCode;switch(h.lastKeyPressed_){case h.options.delimiterKeyCode:if(h.options.useDelimiter&&h.active_){h.selectCurrent()}break;case 35:case 36:case 16:case 17:case 18:case 37:case 39:break;case 38:l.preventDefault();if(h.active_){h.focusPrev()}else{h.activate()}return false;case 40:l.preventDefault();if(h.active_){h.focusNext()}else{h.activate()}return false;case 9:if(h.active_){h.selectCurrent();if(h.options.preventDefaultTab){l.preventDefault();return false}}if(h.options.preventDefaultTab===2){l.preventDefault();return false}break;case 13:if(h.active_){h.selectCurrent();if(h.options.preventDefaultReturn){l.preventDefault();return false}}if(h.options.preventDefaultReturn===2){l.preventDefault();return false}break;case 27:if(h.active_){l.preventDefault();h.deactivate(true);return false}break;default:h.activate()}});i.on("paste",function(){h.activate()});var k=function(){h.deactivate(true)};i.blur(function(){if(h.finishOnBlur_){h.finishTimeout_=setTimeout(k,200)}});i.parents("form").on("submit",k)};e.Autocompleter.prototype.position=function(){var n=this.dom.$elem.offset();var i=this.dom.$results.outerHeight();var k=e(window).outerHeight();var m=n.top+this.dom.$elem.outerHeight();var l=m+i;var h={top:m,left:n.left};if(l>k){var j=n.top-i;if(j>=0){h.top=j}}this.dom.$results.css(h)};e.Autocompleter.prototype.cacheRead=function(k){var m,j,i,h,l;if(this.options.useCache){k=String(k);m=k.length;if(this.options.matchSubset){j=1}else{j=m}while(j<=m){if(this.options.matchInside){h=m-j}else{h=0}l=0;while(l<=h){i=k.substr(0,j);if(this.cacheData_[i]!==undefined){return this.cacheData_[i]}l++}j++}}return false};e.Autocompleter.prototype.cacheWrite=function(h,i){if(this.options.useCache){if(this.cacheLength_>=this.options.maxCacheLength){this.cacheFlush()}h=String(h);if(this.cacheData_[h]!==undefined){this.cacheLength_++}this.cacheData_[h]=i;return this.cacheData_[h]}return false};e.Autocompleter.prototype.cacheFlush=function(){this.cacheData_={};this.cacheLength_=0};e.Autocompleter.prototype.callHook=function(j,i){var h=this.options[j];if(h&&e.isFunction(h)){return h(i,this)}return false};e.Autocompleter.prototype.activate=function(){if(!this.options.enabled){return}var h=this;if(this.keyTimeout_){clearTimeout(this.keyTimeout_)}this.keyTimeout_=setTimeout(function(){h.activateNow()},this.options.delay)};e.Autocompleter.prototype.activateNow=function(){var h=this.beforeUseConverter(this.dom.$elem.val());if(h!==this.lastProcessedValue_&&h!==this.lastSelectedValue_){this.fetchData(h)}};e.Autocompleter.prototype.fetchData=function(j){var i=this;var h=function(k,l){if(i.options.processData){k=i.options.processData(k)}i.showResults(i.filterResults(k,l),l)};this.lastProcessedValue_=j;if(j.length<this.options.minChars){h([],j)}else{if(this.options.data){h(this.options.data,j)}else{this.fetchRemoteData(j,function(k){h(k,j)})}}};e.Autocompleter.prototype.fetchRemoteData=function(k,m){var l=this.cacheRead(k);if(l){m(l)}else{var i=this;var h=i.options.remoteDataType==="json"?"json":"text";var j=function(o){var n=false;if(o!==false){n=i.parseRemoteData(o);i.cacheWrite(k,n)}i.dom.$elem.removeClass(i.options.loadingClass);m(n)};this.dom.$elem.addClass(this.options.loadingClass);e.ajax({url:this.makeUrl(k),success:j,error:function(n,p,o){if(e.isFunction(i.options.onError)){i.options.onError(n,p,o)}else{j(false)}},dataType:h})}};e.Autocompleter.prototype.setExtraParam=function(i,j){var h=e.trim(String(i));if(h){if(!this.options.extraParams){this.options.extraParams={}}if(this.options.extraParams[h]!==j){this.options.extraParams[h]=j;this.cacheFlush()}}return this};e.Autocompleter.prototype.makeUrl=function(k){var h=this;var i=this.options.url;var j=e.extend({},this.options.extraParams);if(this.options.queryParamName===false){i+=encodeURIComponent(k)}else{j[this.options.queryParamName]=k}return c(i,j)};e.Autocompleter.prototype.parseRemoteData=function(i){var h;var j=i;if(this.options.remoteDataType==="json"){h=typeof(i);switch(h){case"object":j=i;break;case"string":j=e.parseJSON(i);break;default:throw new Error("Unexpected remote data type: "+h)}return j}return a(j,this.options.lineSeparator,this.options.cellSeparator)};e.Autocompleter.prototype.defaultFilter=function(h,j){if(!h.value){return false}if(this.options.filterResults){var k=this.matchStringConverter(j);var l=this.matchStringConverter(h.value);if(!this.options.matchCase){k=k.toLowerCase();l=l.toLowerCase()}var i=l.indexOf(k);if(this.options.matchInside){return i>-1}else{return i===0}}return true};e.Autocompleter.prototype.filterResult=function(h,i){if(this.options.filter===false){return true}if(e.isFunction(this.options.filter)){return this.options.filter(h,i)}return this.defaultFilter(h,i)};e.Autocompleter.prototype.filterResults=function(l,m){var j=[];var k,h;for(k=0;k<l.length;k++){h=d(l[k]);if(this.filterResult(h,m)){j.push(h)}}if(this.options.sortResults){j=this.sortResults(j,m)}if(this.options.maxItemsToShow>0&&this.options.maxItemsToShow<j.length){j.length=this.options.maxItemsToShow}return j};e.Autocompleter.prototype.sortResults=function(j,k){var i=this;var h=this.options.sortFunction;if(!e.isFunction(h)){h=function(m,l,n){return f(m,l,i.options.matchCase)}}j.sort(function(m,l){return h(m,l,k,i.options)});return j};e.Autocompleter.prototype.matchStringConverter=function(k,i,h){var j=this.options.matchStringConverter;if(e.isFunction(j)){k=j(k,i,h)}return k};e.Autocompleter.prototype.beforeUseConverter=function(i){i=this.getValue(i);var h=this.options.beforeUseConverter;if(e.isFunction(h)){i=h(i)}return i};e.Autocompleter.prototype.enableFinishOnBlur=function(){this.finishOnBlur_=true};e.Autocompleter.prototype.disableFinishOnBlur=function(){this.finishOnBlur_=false};e.Autocompleter.prototype.createItemFromResult=function(h){var i=this;var j=e("<li/>");j.html(this.showResult(h.value,h.data));j.data({value:h.value,data:h.data}).click(function(){i.selectItem(j)}).mousedown(i.disableFinishOnBlur).mouseup(i.enableFinishOnBlur);return j};e.Autocompleter.prototype.getItems=function(){return e(">ul>li",this.dom.$results)};e.Autocompleter.prototype.showResults=function(l,h){var j=l.length;var r=this;var n=e("<ul></ul>");var m,s,p,q,o=false,k=false;if(j){for(m=0;m<j;m++){s=l[m];p=this.createItemFromResult(s);n.append(p);if(o===false){o=String(s.value);k=p;p.addClass(this.options.firstItemClass)}if(m===j-1){p.addClass(this.options.lastItemClass)}}this.dom.$results.html(n).show();this.position();if(this.options.autoWidth){q=this.dom.$elem.outerWidth()-this.dom.$results.outerWidth()+this.dom.$results.width();this.dom.$results.css(this.options.autoWidth,q)}this.getItems().hover(function(){r.focusItem(this)},function(){});if(this.autoFill(o,h)||this.options.selectFirst||(this.options.selectOnly&&j===1)){this.focusItem(k)}this.active_=true}else{this.hideResults();this.active_=false}};e.Autocompleter.prototype.showResult=function(i,h){if(e.isFunction(this.options.showResult)){return this.options.showResult(i,h)}else{return e("<p></p>").text(i).html()}};e.Autocompleter.prototype.autoFill=function(p,i){var m,n,q,k;if(this.options.autoFill&&this.lastKeyPressed_!==8){m=String(p).toLowerCase();n=String(i).toLowerCase();q=p.length;k=i.length;if(m.substr(0,k)===n){var o=this.getDelimiterOffsets();var j=o.start?" ":"";this.setValue(j+p);var h=k+o.start+j.length;var l=q+o.start+j.length;this.selectRange(h,l);return true}}return false};e.Autocompleter.prototype.focusNext=function(){this.focusMove(+1)};e.Autocompleter.prototype.focusPrev=function(){this.focusMove(-1)};e.Autocompleter.prototype.focusMove=function(h){var k=this.getItems();h=g(h,0);if(h){for(var j=0;j<k.length;j++){if(e(k[j]).hasClass(this.selectClass_)){this.focusItem(j+h);return}}}this.focusItem(0)};e.Autocompleter.prototype.focusItem=function(i){var h,j=this.getItems();if(j.length){j.removeClass(this.selectClass_).removeClass(this.options.selectClass);if(typeof i==="number"){if(i<0){i=0}else{if(i>=j.length){i=j.length-1}}h=e(j[i])}else{h=e(i)}if(h){h.addClass(this.selectClass_).addClass(this.options.selectClass)}}};e.Autocompleter.prototype.selectCurrent=function(){var h=e("li."+this.selectClass_,this.dom.$results);if(h.length===1){this.selectItem(h)}else{this.deactivate(false)}};e.Autocompleter.prototype.selectItem=function(n){var p=n.data("value");var j=n.data("data");var m=this.displayValue(p,j);var k=this.beforeUseConverter(m);this.lastProcessedValue_=k;this.lastSelectedValue_=k;var l=this.getDelimiterOffsets();var h=this.options.delimiterChar;var i=this.dom.$elem;var o=0;if(this.options.useDelimiter){if(i.val().substring(l.start-1,l.start)==h&&h!=" "){m=" "+m}if(i.val().substring(l.end,l.end+1)!=h&&this.lastKeyPressed_!=this.options.delimiterKeyCode){m=m+h}else{o=1}}this.setValue(m);this.setCaret(l.start+m.length+o);this.callHook("onItemSelect",{value:p,data:j});this.deactivate(true);i.focus()};e.Autocompleter.prototype.displayValue=function(i,h){if(e.isFunction(this.options.displayValue)){return this.options.displayValue(i,h)}return i};e.Autocompleter.prototype.hideResults=function(){this.dom.$results.hide()};e.Autocompleter.prototype.deactivate=function(h){if(this.finishTimeout_){clearTimeout(this.finishTimeout_)}if(this.keyTimeout_){clearTimeout(this.keyTimeout_)}if(h){if(this.lastProcessedValue_!==this.lastSelectedValue_){if(this.options.mustMatch){this.setValue("")}this.callHook("onNoMatch")}if(this.active_){this.callHook("onFinish")}this.lastKeyPressed_=null;this.lastProcessedValue_=null;this.lastSelectedValue_=null;this.active_=false}this.hideResults()};e.Autocompleter.prototype.selectRange=function(k,h){var j=this.dom.$elem.get(0);if(j.setSelectionRange){j.focus();j.setSelectionRange(k,h)}else{if(j.createTextRange){var i=j.createTextRange();i.collapse(true);i.moveEnd("character",h);i.moveStart("character",k);i.select()}}};e.Autocompleter.prototype.setCaret=function(h){this.selectRange(h,h)};e.Autocompleter.prototype.getCaret=function(){var j=this.dom.$elem;var m=j[0];var n,l,i,o,h,k;if(m.createTextRange){l=document.selection;if(m.tagName.toLowerCase()!="textarea"){n=j.val();i=l.createRange().duplicate();i.moveEnd("character",n.length);if(i.text===""){o=n.length}else{o=n.lastIndexOf(i.text)}i=l.createRange().duplicate();i.moveStart("character",-n.length);h=i.text.length}else{i=l.createRange();k=i.duplicate();k.moveToElementText(m);k.setEndPoint("EndToEnd",i);o=k.text.length-i.text.length;h=o+i.text.length}}else{o=j[0].selectionStart;h=j[0].selectionEnd}return{start:o,end:h}};e.Autocompleter.prototype.setValue=function(j){if(this.options.useDelimiter){var l=this.dom.$elem.val();var k=this.getDelimiterOffsets();var h=l.substring(0,k.start);var i=l.substring(k.end);j=h+j+i}this.dom.$elem.val(j)};e.Autocompleter.prototype.getValue=function(h){if(this.options.useDelimiter){var i=this.getDelimiterOffsets();return h.substring(i.start,i.end).trim()}else{return h}};e.Autocompleter.prototype.getDelimiterOffsets=function(){var k=this.dom.$elem.val();if(this.options.useDelimiter){var j=k.substring(0,this.getCaret().start);var l=j.lastIndexOf(this.options.delimiterChar)+1;var i=k.substring(this.getCaret().start);var h=i.indexOf(this.options.delimiterChar);if(h==-1){h=k.length}h+=this.getCaret().start}else{l=0;h=k.length}return{start:l,end:h}}})(jQuery);
\ No newline at end of file
diff -r 3f85113b7476767ef1dc76c7f3312b423ff743db -r 2c3f4163da4ef47bb3f04da580e5015961dc0c67 static/scripts/packed/libs/jquery/jquery.mousewheel.js
--- a/static/scripts/packed/libs/jquery/jquery.mousewheel.js
+++ b/static/scripts/packed/libs/jquery/jquery.mousewheel.js
@@ -1,1 +1,12 @@
-(function(c){var a=["DOMMouseScroll","mousewheel"];c.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var d=a.length;d;){this.addEventListener(a[--d],b,false)}}else{this.onmousewheel=b}},teardown:function(){if(this.removeEventListener){for(var d=a.length;d;){this.removeEventListener(a[--d],b,false)}}else{this.onmousewheel=null}}};c.fn.extend({mousewheel:function(d){return d?this.bind("mousewheel",d):this.trigger("mousewheel")},unmousewheel:function(d){return this.unbind("mousewheel",d)}});function b(i){var g=i||window.event,f=[].slice.call(arguments,1),j=0,h=true,e=0,d=0;i=c.event.fix(g);i.type="mousewheel";if(i.wheelDelta){j=i.wheelDelta/120}if(i.detail){j=-i.detail/3}d=j;if(g.axis!==undefined&&g.axis===g.HORIZONTAL_AXIS){d=0;e=-1*j}if(g.wheelDeltaY!==undefined){d=g.wheelDeltaY/120}if(g.wheelDeltaX!==undefined){e=-1*g.wheelDeltaX/120}f.unshift(i,j,e,d);return c.event.handle.apply(this,f)}})(jQuery);
\ No newline at end of file
+/* Copyright (c) 2013 Brandon Aaron (http://brandonaaron.net)
+ * Licensed under the MIT License (LICENSE.txt).
+ *
+ * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
+ * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
+ * Thanks to: Seamus Leahy for adding deltaX and deltaY
+ *
+ * Version: 3.1.3
+ *
+ * Requires: 1.2.2+
+ */
+(function(a){a(jQuery)}(function(e){var d=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"];var g="onwheel" in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"];var f,a;if(e.event.fixHooks){for(var b=d.length;b;){e.event.fixHooks[d[--b]]=e.event.mouseHooks}}e.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var h=g.length;h;){this.addEventListener(g[--h],c,false)}}else{this.onmousewheel=c}},teardown:function(){if(this.removeEventListener){for(var h=g.length;h;){this.removeEventListener(g[--h],c,false)}}else{this.onmousewheel=null}}};e.fn.extend({mousewheel:function(h){return h?this.bind("mousewheel",h):this.trigger("mousewheel")},unmousewheel:function(h){return this.unbind("mousewheel",h)}});function c(h){var i=h||window.event,n=[].slice.call(arguments,1),p=0,k=0,j=0,m=0,l=0,o;h=e.event.fix(i);h.type="mousewheel";if(i.wheelDelta){p=i.wheelDelta}if(i.detail){p=i.detail*-1}if(i.deltaY){j=i.deltaY*-1;p=j}if(i.deltaX){k=i.deltaX;p=k*-1}if(i.wheelDeltaY!==undefined){j=i.wheelDeltaY}if(i.wheelDeltaX!==undefined){k=i.wheelDeltaX*-1}m=Math.abs(p);if(!f||m<f){f=m}l=Math.max(Math.abs(j),Math.abs(k));if(!a||l<a){a=l}o=p>0?"floor":"ceil";p=Math[o](p/f);k=Math[o](k/a);j=Math[o](j/a);n.unshift(h,p,k,j);return(e.event.dispatch||e.event.handle).apply(this,n)}}));
\ No newline at end of file
diff -r 3f85113b7476767ef1dc76c7f3312b423ff743db -r 2c3f4163da4ef47bb3f04da580e5015961dc0c67 static/scripts/packed/mvc/tools.js
--- a/static/scripts/packed/mvc/tools.js
+++ b/static/scripts/packed/mvc/tools.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","viz/trackster/util","mvc/data","libs/backbone/backbone-relational"],function(q,a,r){var g=Backbone.RelationalModel.extend({defaults:{name:null,hidden:false},show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},is_visible:function(){return !this.attributes.hidden}});var c=Backbone.RelationalModel.extend({defaults:{name:null,label:null,type:null,value:null,num_samples:5},initialize:function(){this.attributes.html=unescape(this.attributes.html)},copy:function(){return new c(this.toJSON())},get_samples:function(){var u=this.get("type"),t=null;if(u==="number"){t=d3.scale.linear().domain([this.get("min"),this.get("max")]).ticks(this.get("num_samples"))}else{if(u==="select"){t=q.map(this.get("options"),function(v){return v[0]})}}return t}});var f=g.extend({defaults:{description:null,target:null,inputs:[]},relations:[{type:Backbone.HasMany,key:"inputs",relatedModel:c,reverseRelation:{key:"tool",includeInJSON:false}}],urlRoot:galaxy_paths.get("tool_url"),copy:function(u){var v=new f(this.toJSON());if(u){var t=new Backbone.Collection();v.get("inputs").each(function(w){if(w.get_samples()){t.push(w)}});v.set("inputs",t)}return v},apply_search_results:function(t){(q.indexOf(t,this.attributes.id)!==-1?this.show():this.hide());return this.is_visible()},set_input_value:function(t,u){this.get("inputs").find(function(v){return v.get("name")===t}).set("value",u)},set_input_values:function(u){var t=this;q.each(q.keys(u),function(v){t.set_input_value(v,u[v])})},run:function(){return this._run()},rerun:function(u,t){return this._run({action:"rerun",target_dataset_id:u.id,regions:t})},get_inputs_dict:function(){var t={};this.get("inputs").each(function(u){t[u.get("name")]=u.get("value")});return t},_run:function(v){var w=q.extend({tool_id:this.id,inputs:this.get_inputs_dict()},v);var u=$.Deferred(),t=new a.ServerStateDeferred({ajax_settings:{url:this.urlRoot,data:JSON.stringify(w),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(x){return x!=="pending"}});$.when(t.go()).then(function(x){u.resolve(new r.DatasetCollection().reset(x))});return u}});var j=Backbone.Collection.extend({model:f});var m=g.extend({});var p=g.extend({defaults:{elems:[],open:false},clear_search_results:function(){q.each(this.attributes.elems,function(t){t.show()});this.show();this.set("open",false)},apply_search_results:function(u){var v=true,t;q.each(this.attributes.elems,function(w){if(w instanceof m){t=w;t.hide()}else{if(w instanceof f){if(w.apply_search_results(u)){v=false;if(t){t.show()}}}}});if(v){this.hide()}else{this.show();this.set("open",true)}}});var b=g.extend({defaults:{search_hint_string:"search tools",min_chars_for_search:3,spinner_url:"",clear_btn_url:"",search_url:"",visible:true,query:"",results:null,clear_key:27},initialize:function(){this.on("change:query",this.do_search)},do_search:function(){var v=this.attributes.query;if(v.length<this.attributes.min_chars_for_search){this.set("results",null);return}var u=v+"*";if(this.timer){clearTimeout(this.timer)}$("#search-clear-btn").hide();$("#search-spinner").show();var t=this;this.timer=setTimeout(function(){$.get(t.attributes.search_url,{query:u},function(w){t.set("results",w);$("#search-spinner").hide();$("#search-clear-btn").show()},"json")},200)},clear_search:function(){this.set("query","");this.set("results",null)}});var k=Backbone.Collection.extend({url:"/tools",tools:new j(),parse:function(t){var u=function(x){var w=x.type;if(w==="tool"){return new f(x)}else{if(w==="section"){var v=q.map(x.elems,u);x.elems=v;return new p(x)}else{if(w==="label"){return new m(x)}}}};return q.map(t,u)},initialize:function(t){this.tool_search=t.tool_search;this.tool_search.on("change:results",this.apply_search_results,this);this.on("reset",this.populate_tools,this)},populate_tools:function(){var t=this;t.tools=new j();this.each(function(u){if(u instanceof p){q.each(u.attributes.elems,function(v){if(v instanceof f){t.tools.push(v)}})}else{if(u instanceof f){t.tools.push(u)}}})},clear_search_results:function(){this.each(function(t){if(t instanceof p){t.clear_search_results()}else{t.show()}})},apply_search_results:function(){var u=this.tool_search.attributes.results;if(u===null){this.clear_search_results();return}var t=null;this.each(function(v){if(v instanceof m){t=v;t.hide()}else{if(v instanceof f){if(v.apply_search_results(u)){if(t){t.show()}}}else{t=null;v.apply_search_results(u)}}})}});var n=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){(this.model.attributes.hidden?this.$el.hide():this.$el.show())}});var i=n.extend({tagName:"div",template:Handlebars.templates.tool_link,render:function(){this.$el.append(this.template(this.model.toJSON()));return this}});var d=n.extend({tagName:"div",className:"toolPanelLabel",render:function(){this.$el.append($("<span/>").text(this.model.attributes.name));return this}});var h=n.extend({tagName:"div",className:"toolSectionWrapper",template:Handlebars.templates.panel_section,initialize:function(){n.prototype.initialize.call(this);this.model.on("change:open",this.update_open,this)},render:function(){this.$el.append(this.template(this.model.toJSON()));var t=this.$el.find(".toolSectionBody");q.each(this.model.attributes.elems,function(u){if(u instanceof f){var v=new i({model:u,className:"toolTitle"});v.render();t.append(v.$el)}else{if(u instanceof m){var w=new d({model:u});w.render();t.append(w.$el)}else{}}});return this},events:{"click .toolSectionTitle > a":"toggle"},toggle:function(){this.model.set("open",!this.model.attributes.open)},update_open:function(){(this.model.attributes.open?this.$el.children(".toolSectionBody").slideDown("fast"):this.$el.children(".toolSectionBody").slideUp("fast"))}});var l=Backbone.View.extend({tagName:"div",id:"tool-search",className:"bar",template:Handlebars.templates.tool_search,events:{click:"focus_and_select","keyup :input":"query_changed","click #search-clear-btn":"clear"},render:function(){this.$el.append(this.template(this.model.toJSON()));if(!this.model.is_visible()){this.$el.hide()}this.$el.find(".tooltip").tooltip();return this},focus_and_select:function(){this.$el.find(":input").focus().select()},clear:function(){this.model.clear_search();this.$el.find(":input").val(this.model.attributes.search_hint_string);this.focus_and_select();return false},query_changed:function(t){if((this.model.attributes.clear_key)&&(this.model.attributes.clear_key===t.which)){this.clear();return false}this.model.set("query",this.$el.find(":input").val())}});var s=Backbone.View.extend({tagName:"div",className:"toolMenu",initialize:function(){this.collection.tool_search.on("change:results",this.handle_search_results,this)},render:function(){var t=this;var u=new l({model:this.collection.tool_search});u.render();t.$el.append(u.$el);this.collection.each(function(w){if(w instanceof p){var v=new h({model:w});v.render();t.$el.append(v.$el)}else{if(w instanceof f){var x=new i({model:w,className:"toolTitleNoSection"});x.render();t.$el.append(x.$el)}else{if(w instanceof m){var y=new d({model:w});y.render();t.$el.append(y.$el)}}}});t.$el.find("a.tool-link").click(function(x){var w=$(this).attr("class").split(/\s+/)[0],v=t.collection.tools.get(w);t.trigger("tool_link_click",x,v)});return this},handle_search_results:function(){var t=this.collection.tool_search.attributes.results;if(t&&t.length===0){$("#search-no-results").show()}else{$("#search-no-results").hide()}}});var o=Backbone.View.extend({className:"toolForm",template:Handlebars.templates.tool_form,render:function(){this.$el.children().remove();this.$el.append(this.template(this.model.toJSON()))}});var e=Backbone.View.extend({className:"toolMenuAndView",initialize:function(){this.tool_panel_view=new s({collection:this.collection});this.tool_form_view=new o()},render:function(){this.tool_panel_view.render();this.tool_panel_view.$el.css("float","left");this.$el.append(this.tool_panel_view.$el);this.tool_form_view.$el.hide();this.$el.append(this.tool_form_view.$el);var t=this;this.tool_panel_view.on("tool_link_click",function(v,u){v.preventDefault();t.show_tool(u)})},show_tool:function(u){var t=this;u.fetch().done(function(){t.tool_form_view.model=u;t.tool_form_view.render();t.tool_form_view.$el.show();$("#left").width("650px")})}});return{Tool:f,ToolSearch:b,ToolPanel:k,ToolPanelView:s,ToolFormView:o}});
\ No newline at end of file
+define(["libs/underscore","viz/trackster/util","mvc/data","libs/backbone/backbone-relational"],function(t,a,u){var h=Backbone.RelationalModel.extend({defaults:{name:null,hidden:false},show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},is_visible:function(){return !this.attributes.hidden}});var d=Backbone.RelationalModel.extend({defaults:{name:null,label:null,type:null,value:null,html:null,num_samples:5},initialize:function(){this.attributes.html=unescape(this.attributes.html)},copy:function(){return new d(this.toJSON())},get_samples:function(){var w=this.get("type"),v=null;if(w==="number"){v=d3.scale.linear().domain([this.get("min"),this.get("max")]).ticks(this.get("num_samples"))}else{if(w==="select"){v=t.map(this.get("options"),function(x){return x[0]})}}return v},set_value:function(v){this.set("value",v||"")}},{TYPE_DICT:{number:c},create:function(v){var w=d.TYPE_DICT[v.type]||d;return new w(v)}});var c=d.extend({defaults:t.extend({},d.prototype.defaults,{min:null,max:null}),initialize:function(){d.prototype.initialize.call(this);if(this.attributes.min){this.attributes.min=parseInt(this.attributes.min,10)}if(this.attributes.max){this.attributes.max=parseInt(this.attributes.max,10)}},set_value:function(v){this.set("value",parseInt(v,10))}});var g=h.extend({defaults:{id:null,name:null,description:null,target:null,inputs:[]},initialize:function(v){this.attributes.inputs=new Backbone.Collection(t.map(v.inputs,function(w){return d.create(w)}))},urlRoot:galaxy_paths.get("tool_url"),copy:function(w){var x=new g(this.toJSON());if(w){var v=new Backbone.Collection();x.get("inputs").each(function(y){if(y.get_samples()){v.push(y)}});x.set("inputs",v)}return x},apply_search_results:function(v){(t.indexOf(v,this.attributes.id)!==-1?this.show():this.hide());return this.is_visible()},set_input_value:function(v,w){this.get("inputs").find(function(x){return x.get("name")===v}).set("value",w)},set_input_values:function(w){var v=this;t.each(t.keys(w),function(x){v.set_input_value(x,w[x])})},run:function(){return this._run()},rerun:function(w,v){return this._run({action:"rerun",target_dataset_id:w.id,regions:v})},get_inputs_dict:function(){var v={};this.get("inputs").each(function(w){v[w.get("name")]=w.get("value")});return v},_run:function(x){var y=t.extend({tool_id:this.id,inputs:this.get_inputs_dict()},x);var w=$.Deferred(),v=new a.ServerStateDeferred({ajax_settings:{url:this.urlRoot,data:JSON.stringify(y),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(z){return z!=="pending"}});$.when(v.go()).then(function(z){w.resolve(new u.DatasetCollection().reset(z))});return w}});var n=Backbone.View.extend({});var k=Backbone.Collection.extend({model:g});var o=h.extend({});var r=h.extend({defaults:{elems:[],open:false},clear_search_results:function(){t.each(this.attributes.elems,function(v){v.show()});this.show();this.set("open",false)},apply_search_results:function(w){var x=true,v;t.each(this.attributes.elems,function(y){if(y instanceof o){v=y;v.hide()}else{if(y instanceof g){if(y.apply_search_results(w)){x=false;if(v){v.show()}}}}});if(x){this.hide()}else{this.show();this.set("open",true)}}});var b=h.extend({defaults:{search_hint_string:"search tools",min_chars_for_search:3,spinner_url:"",clear_btn_url:"",search_url:"",visible:true,query:"",results:null,clear_key:27},initialize:function(){this.on("change:query",this.do_search)},do_search:function(){var x=this.attributes.query;if(x.length<this.attributes.min_chars_for_search){this.set("results",null);return}var w=x+"*";if(this.timer){clearTimeout(this.timer)}$("#search-clear-btn").hide();$("#search-spinner").show();var v=this;this.timer=setTimeout(function(){$.get(v.attributes.search_url,{query:w},function(y){v.set("results",y);$("#search-spinner").hide();$("#search-clear-btn").show()},"json")},200)},clear_search:function(){this.set("query","");this.set("results",null)}});var l=Backbone.Collection.extend({url:"/tools",tools:new k(),parse:function(v){var w=function(z){var y=z.type;if(y==="tool"){return new g(z)}else{if(y==="section"){var x=t.map(z.elems,w);z.elems=x;return new r(z)}else{if(y==="label"){return new o(z)}}}};return t.map(v,w)},initialize:function(v){this.tool_search=v.tool_search;this.tool_search.on("change:results",this.apply_search_results,this);this.on("reset",this.populate_tools,this)},populate_tools:function(){var v=this;v.tools=new k();this.each(function(w){if(w instanceof r){t.each(w.attributes.elems,function(x){if(x instanceof g){v.tools.push(x)}})}else{if(w instanceof g){v.tools.push(w)}}})},clear_search_results:function(){this.each(function(v){if(v instanceof r){v.clear_search_results()}else{v.show()}})},apply_search_results:function(){var w=this.tool_search.attributes.results;if(w===null){this.clear_search_results();return}var v=null;this.each(function(x){if(x instanceof o){v=x;v.hide()}else{if(x instanceof g){if(x.apply_search_results(w)){if(v){v.show()}}}else{v=null;x.apply_search_results(w)}}})}});var p=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){(this.model.attributes.hidden?this.$el.hide():this.$el.show())}});var j=p.extend({tagName:"div",template:Handlebars.templates.tool_link,render:function(){this.$el.append(this.template(this.model.toJSON()));return this}});var e=p.extend({tagName:"div",className:"toolPanelLabel",render:function(){this.$el.append($("<span/>").text(this.model.attributes.name));return this}});var i=p.extend({tagName:"div",className:"toolSectionWrapper",template:Handlebars.templates.panel_section,initialize:function(){p.prototype.initialize.call(this);this.model.on("change:open",this.update_open,this)},render:function(){this.$el.append(this.template(this.model.toJSON()));var v=this.$el.find(".toolSectionBody");t.each(this.model.attributes.elems,function(w){if(w instanceof g){var x=new j({model:w,className:"toolTitle"});x.render();v.append(x.$el)}else{if(w instanceof o){var y=new e({model:w});y.render();v.append(y.$el)}else{}}});return this},events:{"click .toolSectionTitle > a":"toggle"},toggle:function(){this.model.set("open",!this.model.attributes.open)},update_open:function(){(this.model.attributes.open?this.$el.children(".toolSectionBody").slideDown("fast"):this.$el.children(".toolSectionBody").slideUp("fast"))}});var m=Backbone.View.extend({tagName:"div",id:"tool-search",className:"bar",template:Handlebars.templates.tool_search,events:{click:"focus_and_select","keyup :input":"query_changed","click #search-clear-btn":"clear"},render:function(){this.$el.append(this.template(this.model.toJSON()));if(!this.model.is_visible()){this.$el.hide()}this.$el.find(".tooltip").tooltip();return this},focus_and_select:function(){this.$el.find(":input").focus().select()},clear:function(){this.model.clear_search();this.$el.find(":input").val(this.model.attributes.search_hint_string);this.focus_and_select();return false},query_changed:function(v){if((this.model.attributes.clear_key)&&(this.model.attributes.clear_key===v.which)){this.clear();return false}this.model.set("query",this.$el.find(":input").val())}});var s=Backbone.View.extend({tagName:"div",className:"toolMenu",initialize:function(){this.collection.tool_search.on("change:results",this.handle_search_results,this)},render:function(){var v=this;var w=new m({model:this.collection.tool_search});w.render();v.$el.append(w.$el);this.collection.each(function(y){if(y instanceof r){var x=new i({model:y});x.render();v.$el.append(x.$el)}else{if(y instanceof g){var z=new j({model:y,className:"toolTitleNoSection"});z.render();v.$el.append(z.$el)}else{if(y instanceof o){var A=new e({model:y});A.render();v.$el.append(A.$el)}}}});v.$el.find("a.tool-link").click(function(z){var y=$(this).attr("class").split(/\s+/)[0],x=v.collection.tools.get(y);v.trigger("tool_link_click",z,x)});return this},handle_search_results:function(){var v=this.collection.tool_search.attributes.results;if(v&&v.length===0){$("#search-no-results").show()}else{$("#search-no-results").hide()}}});var q=Backbone.View.extend({className:"toolForm",template:Handlebars.templates.tool_form,render:function(){this.$el.children().remove();this.$el.append(this.template(this.model.toJSON()))}});var f=Backbone.View.extend({className:"toolMenuAndView",initialize:function(){this.tool_panel_view=new s({collection:this.collection});this.tool_form_view=new q()},render:function(){this.tool_panel_view.render();this.tool_panel_view.$el.css("float","left");this.$el.append(this.tool_panel_view.$el);this.tool_form_view.$el.hide();this.$el.append(this.tool_form_view.$el);var v=this;this.tool_panel_view.on("tool_link_click",function(x,w){x.preventDefault();v.show_tool(w)})},show_tool:function(w){var v=this;w.fetch().done(function(){v.tool_form_view.model=w;v.tool_form_view.render();v.tool_form_view.$el.show();$("#left").width("650px")})}});return{ToolParameter:d,IntegerToolParameter:c,Tool:g,ToolSearch:b,ToolPanel:l,ToolPanelView:s,ToolFormView:q}});
\ No newline at end of file
diff -r 3f85113b7476767ef1dc76c7f3312b423ff743db -r 2c3f4163da4ef47bb3f04da580e5015961dc0c67 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(g,l,i){var m=Backbone.Model.extend({is_visible:function(q,n){var o=q.getBoundingClientRect(),p=$("svg")[0].getBoundingClientRect();if(o.right<0||o.left>p.right||o.bottom<0||o.top>p.bottom){return false}return true}});var h={drawTicks:function(r,q,v,p,n){var u=r.append("g").selectAll("g").data(q).enter().append("g").selectAll("g").data(v).enter().append("g").attr("class","tick").attr("transform",function(w){return"rotate("+(w.angle*180/Math.PI-90)+")translate("+w.radius+",0)"});var t=[],s=[],o=function(w){return w.angle>Math.PI?"end":null};if(n){t=[0,0,0,-4];s=[4,0,"",".35em"];o=null}else{t=[1,0,4,0];s=[0,4,".35em",""]}u.append("line").attr("x1",t[0]).attr("y1",t[1]).attr("x2",t[2]).attr("y1",t[3]).style("stroke","#000");u.append("text").attr("x",s[0]).attr("y",s[1]).attr("dx",s[2]).attr("dy",s[3]).attr("text-anchor",o).attr("transform",p).text(function(w){return w.label})},formatNum:function(o,n){if(n===undefined){n=2}var q=null;if(o<1){q=o.toPrecision(n)}else{var p=Math.round(o.toPrecision(n));if(o<1000){q=p}else{if(o<1000000){q=Math.round((p/1000).toPrecision(3)).toFixed(0)+"K"}else{if(o<1000000000){q=Math.round((p/1000000).toPrecision(3)).toFixed(0)+"M"}}}}return q}};var c=Backbone.Model.extend({});var a=Backbone.View.extend({className:"circster",initialize:function(n){this.total_gap=n.total_gap;this.genome=n.genome;this.dataset_arc_height=n.dataset_arc_height;this.track_gap=10;this.label_arc_height=50;this.scale=1;this.circular_views=null;this.chords_views=null;this.model.get("tracks").on("add",this.add_track,this);this.model.get("tracks").on("remove",this.remove_track,this);this.get_circular_tracks()},get_circular_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")!=="DiagonalHeatmapTrack"})},get_chord_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")==="DiagonalHeatmapTrack"})},get_tracks_bounds:function(){var o=this.get_circular_tracks();dataset_arc_height=this.dataset_arc_height,min_dimension=Math.min(this.$el.width(),this.$el.height()),radius_start=min_dimension/2-o.length*(this.dataset_arc_height+this.track_gap)-(this.label_arc_height+this.track_gap),tracks_start_radii=l.range(radius_start,min_dimension/2,this.dataset_arc_height+this.track_gap);var n=this;return g.map(tracks_start_radii,function(p){return[p,p+n.dataset_arc_height]})},render:function(){var w=this,q=this.dataset_arc_height,n=w.$el.width(),v=w.$el.height(),s=this.get_circular_tracks(),p=this.get_chord_tracks(),r=this.get_tracks_bounds(),o=l.select(w.$el[0]).append("svg").attr("width",n).attr("height",v).attr("pointer-events","all").append("svg:g").call(l.behavior.zoom().on("zoom",function(){var x=l.event.scale;o.attr("transform","translate("+l.event.translate+") scale("+x+")");if(w.scale!==x){if(w.zoom_drag_timeout){clearTimeout(w.zoom_drag_timeout)}w.zoom_drag_timeout=setTimeout(function(){},400)}})).attr("transform","translate("+n/2+","+v/2+")").append("svg:g").attr("class","tracks");this.circular_views=s.map(function(y,z){var x=new d({el:o.append("g")[0],track:y,radius_bounds:r[z],genome:w.genome,total_gap:w.total_gap});x.render();return x});this.chords_views=p.map(function(y){var x=new j({el:o.append("g")[0],track:y,radius_bounds:r[0],genome:w.genome,total_gap:w.total_gap});x.render();return x});var u=this.circular_views[this.circular_views.length-1].radius_bounds[1],t=[u,u+this.label_arc_height];this.label_track_view=new b({el:o.append("g")[0],track:new c(),radius_bounds:t,genome:w.genome,total_gap:w.total_gap});this.label_track_view.render()},add_track:function(t){if(t.get("track_type")==="DiagonalHeatmapTrack"){var p=this.circular_views[0].radius_bounds,s=new j({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:p,genome:this.genome,total_gap:this.total_gap});s.render();this.chords_views.push(s)}else{var r=this.get_tracks_bounds();g.each(this.circular_views,function(u,v){u.update_radius_bounds(r[v])});g.each(this.chords_views,function(u){u.update_radius_bounds(r[0])});var q=this.circular_views.length,n=new d({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:r[q],genome:this.genome,total_gap:this.total_gap});n.render();this.circular_views.push(n);var o=r[r.length-1];o[1]=o[0];this.label_track_view.update_radius_bounds(o)}},remove_track:function(o,q,p){var n=this.circular_views[p.index];this.circular_views.splice(p.index,1);n.$el.remove();var r=this.get_tracks_bounds();g.each(this.circular_views,function(s,t){s.update_radius_bounds(r[t])})}});var k=Backbone.View.extend({tagName:"g",initialize:function(n){this.bg_stroke="ccc";this.loading_bg_fill="000";this.bg_fill="ccc";this.total_gap=n.total_gap;this.track=n.track;this.radius_bounds=n.radius_bounds;this.genome=n.genome;this.chroms_layout=this._chroms_layout();this.data_bounds=[];this.scale=1;this.parent_elt=l.select(this.$el[0])},get_fill_color:function(){var n=this.track.get("config").get_value("block_color");if(!n){n=this.track.get("config").get_value("color")}return n},render:function(){var r=this.parent_elt;if(!r){console.log("no parent elt")}var q=this.chroms_layout,t=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]),n=r.selectAll("g").data(q).enter().append("svg:g"),p=n.append("path").attr("d",t).attr("class","chrom-background").style("stroke",this.bg_stroke).style("fill",this.loading_bg_fill);p.append("title").text(function(v){return v.data.chrom});var o=this,s=o.track.get("data_manager"),u=(s?s.data_is_ready():true);$.when(u).then(function(){$.when(o._render_data(r)).then(function(){p.style("fill",o.bg_fill);o.render_labels()})})},render_labels:function(){},update_radius_bounds:function(o){this.radius_bounds=o;var n=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]);this.parent_elt.selectAll("g>path.chrom-background").transition().duration(1000).attr("d",n);this._transition_chrom_data();this._transition_labels()},update_scale:function(q){var p=this.scale;this.scale=q;if(q<=p){return}var o=this,n=new m();this.parent_elt.selectAll("path.chrom-data").filter(function(s,r){return n.is_visible(this)}).each(function(x,t){var w=l.select(this),s=w.attr("chrom"),v=o.genome.get_chrom_region(s),u=o.track.get("data_manager"),r;if(!u.can_get_more_detailed_data(v)){return}r=o.track.get("data_manager").get_more_detailed_data(v,"Coverage",0,q);$.when(r).then(function(A){w.remove();o._update_data_bounds();var z=g.find(o.chroms_layout,function(B){return B.data.chrom===s});var y=o.get_fill_color();o._render_chrom_data(o.parent_elt,z,A).style("stroke",y).style("fill",y)})});return o},_transition_chrom_data:function(){var o=this.track,q=this.chroms_layout,n=this.parent_elt.selectAll("g>path.chrom-data"),r=n[0].length;if(r>0){var p=this;$.when(o.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){var s=g.reject(g.map(t,function(u,v){var w=null,x=p._get_path_function(q[v],u);if(x){w=x(u.data)}return w}),function(u){return u===null});n.each(function(v,u){l.select(this).transition().duration(1000).attr("d",s[u])})})}},_transition_labels:function(){},_update_data_bounds:function(){var n=this.data_bounds;this.data_bounds=this.get_data_bounds(this.track.get("data_manager").get_genome_wide_data(this.genome));if(this.data_bounds[0]<n[0]||this.data_bounds[1]>n[1]){this._transition_chrom_data()}},_render_data:function(q){var p=this,o=this.chroms_layout,n=this.track,r=$.Deferred();$.when(n.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){p.data_bounds=p.get_data_bounds(t);layout_and_data=g.zip(o,t),chroms_data_layout=g.map(layout_and_data,function(u){var v=u[0],w=u[1];return p._render_chrom_data(q,v,w)});var s=p.get_fill_color();p.parent_elt.selectAll("path.chrom-data").style("stroke",s).style("fill",s);r.resolve(q)});return r},_render_chrom_data:function(n,o,p){},_get_path_function:function(o,n){},_chroms_layout:function(){var o=this.genome.get_chroms_info(),q=l.layout.pie().value(function(s){return s.len}).sort(null),r=q(o),n=this.total_gap/o.length,p=g.map(r,function(u,t){var s=u.endAngle-n;u.endAngle=(s>u.startAngle?s:u.startAngle);return u});return p}});var b=k.extend({initialize:function(n){k.prototype.initialize.call(this,n);this.innerRadius=this.radius_bounds[0];this.radius_bounds[0]=this.radius_bounds[1];this.bg_stroke="fff";this.bg_fill="fff";this.min_arc_len=0.08},_render_data:function(p){var o=this,n=p.selectAll("g");n.selectAll("path").attr("id",function(t){return"label-"+t.data.chrom});n.append("svg:text").filter(function(t){return t.endAngle-t.startAngle>o.min_arc_len}).attr("text-anchor","middle").append("svg:textPath").attr("xlink:href",function(t){return"#label-"+t.data.chrom}).attr("startOffset","25%").attr("font-weight","bold").text(function(t){return t.data.chrom});var q=function(v){var t=(v.endAngle-v.startAngle)/v.value,u=l.range(0,v.value,25000000).map(function(w,x){return{radius:o.innerRadius,angle:w*t+v.startAngle,label:x===0?0:(x%3?null:o.formatNum(w))}});if(u.length<4){u[u.length-1].label=o.formatNum(Math.round((u[u.length-1].angle-v.startAngle)/t))}return u};var s=function(t){return t.angle>Math.PI?"rotate(180)translate(-16)":null};var r=g.filter(this.chroms_layout,function(t){return t.endAngle-t.startAngle>o.min_arc_len});this.drawTicks(this.parent_elt,r,q,s)}});g.extend(b.prototype,h);var f=k.extend({_quantile:function(o,n){o.sort(l.ascending);return l.quantile(o,n)},_render_chrom_data:function(n,q,o){var r=this._get_path_function(q,o);if(!r){return null}var p=n.datum(o.data),s=p.append("path").attr("class","chrom-data").attr("chrom",q.data.chrom).attr("d",r);return s},_get_path_function:function(q,p){if(typeof p==="string"||!p.data||p.data.length===0){return null}var n=l.scale.linear().domain(this.data_bounds).range(this.radius_bounds).clamp(true);var r=l.scale.linear().domain([0,p.data.length]).range([q.startAngle,q.endAngle]);var o=l.svg.line.radial().interpolate("linear").radius(function(s){return n(s[1])}).angle(function(t,s){return r(s)});return l.svg.area.radial().interpolate(o.interpolate()).innerRadius(n(0)).outerRadius(o.radius()).angle(o.angle())},render_labels:function(){var n=this,q=function(){return"rotate(90)"};var p=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),o=g.filter(p,function(s,r){return r%3===0});this.drawTicks(this.parent_elt,o,this._data_bounds_ticks_fn(),q,true)},_transition_labels:function(){if(this.data_bounds.length===0){return}var o=this,q=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),p=g.filter(q,function(s,r){return r%3===0}),n=g.flatten(g.map(p,function(r){return o._data_bounds_ticks_fn()(r)}));this.parent_elt.selectAll("g.tick").data(n).transition().attr("transform",function(r){return"rotate("+(r.angle*180/Math.PI-90)+")translate("+r.radius+",0)"})},_data_bounds_ticks_fn:function(){var n=this;visibleChroms=0;return function(o){return[{radius:n.radius_bounds[0],angle:o.startAngle,label:n.formatNum(n.data_bounds[0])},{radius:n.radius_bounds[1],angle:o.startAngle,label:n.formatNum(n.data_bounds[1])}]}},get_data_bounds:function(n){}});g.extend(f.prototype,h);var d=f.extend({get_data_bounds:function(o){var n=g.flatten(g.map(o,function(p){if(p){return g.map(p.data,function(q){return q[1]})}else{return 0}}));return[g.min(n),this._quantile(n,0.98)]}});var j=k.extend({render:function(){var n=this;$.when(n.track.get("data_manager").data_is_ready()).then(function(){$.when(n.track.get("data_manager").get_genome_wide_data(n.genome)).then(function(q){var p=[],o=n.genome.get_chroms_info();g.each(q,function(u,t){var r=o[t].chrom;var s=g.map(u.data,function(w){var v=n._get_region_angle(r,w[1]),x=n._get_region_angle(w[3],w[4]);return{source:{startAngle:v,endAngle:v+0.01},target:{startAngle:x,endAngle:x+0.01}}});p=p.concat(s)});n.parent_elt.append("g").attr("class","chord").selectAll("path").data(p).enter().append("path").style("fill",n.get_fill_color()).attr("d",l.svg.chord().radius(n.radius_bounds[0])).style("opacity",1)})})},update_radius_bounds:function(n){this.radius_bounds=n;this.parent_elt.selectAll("path").transition().attr("d",l.svg.chord().radius(this.radius_bounds[0]))},_get_region_angle:function(p,n){var o=g.find(this.chroms_layout,function(q){return q.data.chrom===p});return o.endAngle-((o.endAngle-o.startAngle)*(o.data.len-n)/o.data.len)}});var e=Backbone.View.extend({initialize:function(){var n=new i.Genome(config.app.genome),o=new i.GenomeVisualization(config.app.viz_config),q=new a({el:$("#center .unified-panel-body"),total_gap:2*Math.PI*0.1,genome:n,model:o,dataset_arc_height:25});q.render();$("#center .unified-panel-header-inner").append(config.app.viz_config.title+" "+config.app.viz_config.dbkey);var p=create_icon_buttons_menu([{icon_class:"plus-button",title:"Add tracks",on_click:function(){i.select_datasets(config.root+"visualization/list_current_history_datasets",config.root+"api/datasets",o.get("dbkey"),function(r){o.add_tracks(r)})}},{icon_class:"disk--arrow",title:"Save",on_click:function(){show_modal("Saving...","progress");var r=config.app.viz_config;$.ajax({url:config.root+"visualization/save",type:"POST",dataType:"json",data:{id:r.vis_id,title:r.title,dbkey:r.dbkey,type:"trackster",vis_json:JSON.stringify(r)}}).success(function(s){hide_modal();r.vis_id=s.vis_id;r.has_changes=false;window.history.pushState({},"",s.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=config.root+"visualization/list"}}],{tooltip_config:{placement:"bottom"}});p.$el.attr("style","float: right");$("#center .unified-panel-header-inner").append(p.$el);$(".menu-button").tooltip({placement:"bottom"})}});return{GalaxyApp:e}});
\ No newline at end of file
+define(["libs/underscore","libs/d3","viz/visualization"],function(g,l,i){var m=Backbone.Model.extend({is_visible:function(q,n){var o=q.getBoundingClientRect(),p=$("svg")[0].getBoundingClientRect();if(o.right<0||o.left>p.right||o.bottom<0||o.top>p.bottom){return false}return true}});var h={drawTicks:function(r,q,v,p,n){var u=r.append("g").selectAll("g").data(q).enter().append("g").selectAll("g").data(v).enter().append("g").attr("class","tick").attr("transform",function(w){return"rotate("+(w.angle*180/Math.PI-90)+")translate("+w.radius+",0)"});var t=[],s=[],o=function(w){return w.angle>Math.PI?"end":null};if(n){t=[0,0,0,-4];s=[4,0,"",".35em"];o=null}else{t=[1,0,4,0];s=[0,4,".35em",""]}u.append("line").attr("x1",t[0]).attr("y1",t[1]).attr("x2",t[2]).attr("y1",t[3]).style("stroke","#000");u.append("text").attr("x",s[0]).attr("y",s[1]).attr("dx",s[2]).attr("dy",s[3]).attr("text-anchor",o).attr("transform",p).text(function(w){return w.label})},formatNum:function(o,n){if(n===undefined){n=2}if(o===null){return null}var q=null;if(o<1){q=o.toPrecision(n)}else{var p=Math.round(o.toPrecision(n));if(o<1000){q=p}else{if(o<1000000){q=Math.round((p/1000).toPrecision(3)).toFixed(0)+"K"}else{if(o<1000000000){q=Math.round((p/1000000).toPrecision(3)).toFixed(0)+"M"}}}}return q}};var c=Backbone.Model.extend({});var a=Backbone.View.extend({className:"circster",initialize:function(n){this.total_gap=n.total_gap;this.genome=n.genome;this.dataset_arc_height=n.dataset_arc_height;this.track_gap=10;this.label_arc_height=50;this.scale=1;this.circular_views=null;this.chords_views=null;this.model.get("tracks").on("add",this.add_track,this);this.model.get("tracks").on("remove",this.remove_track,this);this.get_circular_tracks()},get_circular_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")!=="DiagonalHeatmapTrack"})},get_chord_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")==="DiagonalHeatmapTrack"})},get_tracks_bounds:function(){var o=this.get_circular_tracks();dataset_arc_height=this.dataset_arc_height,min_dimension=Math.min(this.$el.width(),this.$el.height()),radius_start=min_dimension/2-o.length*(this.dataset_arc_height+this.track_gap)-(this.label_arc_height+this.track_gap),tracks_start_radii=l.range(radius_start,min_dimension/2,this.dataset_arc_height+this.track_gap);var n=this;return g.map(tracks_start_radii,function(p){return[p,p+n.dataset_arc_height]})},render:function(){var w=this,q=this.dataset_arc_height,n=w.$el.width(),v=w.$el.height(),s=this.get_circular_tracks(),p=this.get_chord_tracks(),r=this.get_tracks_bounds(),o=l.select(w.$el[0]).append("svg").attr("width",n).attr("height",v).attr("pointer-events","all").append("svg:g").call(l.behavior.zoom().on("zoom",function(){var x=l.event.scale;o.attr("transform","translate("+l.event.translate+") scale("+x+")");if(w.scale!==x){if(w.zoom_drag_timeout){clearTimeout(w.zoom_drag_timeout)}w.zoom_drag_timeout=setTimeout(function(){},400)}})).attr("transform","translate("+n/2+","+v/2+")").append("svg:g").attr("class","tracks");this.circular_views=s.map(function(y,z){var x=new d({el:o.append("g")[0],track:y,radius_bounds:r[z],genome:w.genome,total_gap:w.total_gap});x.render();return x});this.chords_views=p.map(function(y){var x=new j({el:o.append("g")[0],track:y,radius_bounds:r[0],genome:w.genome,total_gap:w.total_gap});x.render();return x});var u=this.circular_views[this.circular_views.length-1].radius_bounds[1],t=[u,u+this.label_arc_height];this.label_track_view=new b({el:o.append("g")[0],track:new c(),radius_bounds:t,genome:w.genome,total_gap:w.total_gap});this.label_track_view.render()},add_track:function(t){if(t.get("track_type")==="DiagonalHeatmapTrack"){var p=this.circular_views[0].radius_bounds,s=new j({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:p,genome:this.genome,total_gap:this.total_gap});s.render();this.chords_views.push(s)}else{var r=this.get_tracks_bounds();g.each(this.circular_views,function(u,v){u.update_radius_bounds(r[v])});g.each(this.chords_views,function(u){u.update_radius_bounds(r[0])});var q=this.circular_views.length,n=new d({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:r[q],genome:this.genome,total_gap:this.total_gap});n.render();this.circular_views.push(n);var o=r[r.length-1];o[1]=o[0];this.label_track_view.update_radius_bounds(o)}},remove_track:function(o,q,p){var n=this.circular_views[p.index];this.circular_views.splice(p.index,1);n.$el.remove();var r=this.get_tracks_bounds();g.each(this.circular_views,function(s,t){s.update_radius_bounds(r[t])})}});var k=Backbone.View.extend({tagName:"g",initialize:function(n){this.bg_stroke="ccc";this.loading_bg_fill="000";this.bg_fill="ccc";this.total_gap=n.total_gap;this.track=n.track;this.radius_bounds=n.radius_bounds;this.genome=n.genome;this.chroms_layout=this._chroms_layout();this.data_bounds=[];this.scale=1;this.parent_elt=l.select(this.$el[0])},get_fill_color:function(){var n=this.track.get("config").get_value("block_color");if(!n){n=this.track.get("config").get_value("color")}return n},render:function(){var r=this.parent_elt;if(!r){console.log("no parent elt")}var q=this.chroms_layout,t=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]),n=r.selectAll("g").data(q).enter().append("svg:g"),p=n.append("path").attr("d",t).attr("class","chrom-background").style("stroke",this.bg_stroke).style("fill",this.loading_bg_fill);p.append("title").text(function(v){return v.data.chrom});var o=this,s=o.track.get("data_manager"),u=(s?s.data_is_ready():true);$.when(u).then(function(){$.when(o._render_data(r)).then(function(){p.style("fill",o.bg_fill);o.render_labels()})})},render_labels:function(){},update_radius_bounds:function(o){this.radius_bounds=o;var n=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]);this.parent_elt.selectAll("g>path.chrom-background").transition().duration(1000).attr("d",n);this._transition_chrom_data();this._transition_labels()},update_scale:function(q){var p=this.scale;this.scale=q;if(q<=p){return}var o=this,n=new m();this.parent_elt.selectAll("path.chrom-data").filter(function(s,r){return n.is_visible(this)}).each(function(x,t){var w=l.select(this),s=w.attr("chrom"),v=o.genome.get_chrom_region(s),u=o.track.get("data_manager"),r;if(!u.can_get_more_detailed_data(v)){return}r=o.track.get("data_manager").get_more_detailed_data(v,"Coverage",0,q);$.when(r).then(function(A){w.remove();o._update_data_bounds();var z=g.find(o.chroms_layout,function(B){return B.data.chrom===s});var y=o.get_fill_color();o._render_chrom_data(o.parent_elt,z,A).style("stroke",y).style("fill",y)})});return o},_transition_chrom_data:function(){var o=this.track,q=this.chroms_layout,n=this.parent_elt.selectAll("g>path.chrom-data"),r=n[0].length;if(r>0){var p=this;$.when(o.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){var s=g.reject(g.map(t,function(u,v){var w=null,x=p._get_path_function(q[v],u);if(x){w=x(u.data)}return w}),function(u){return u===null});n.each(function(v,u){l.select(this).transition().duration(1000).attr("d",s[u])})})}},_transition_labels:function(){},_update_data_bounds:function(){var n=this.data_bounds;this.data_bounds=this.get_data_bounds(this.track.get("data_manager").get_genome_wide_data(this.genome));if(this.data_bounds[0]<n[0]||this.data_bounds[1]>n[1]){this._transition_chrom_data()}},_render_data:function(q){var p=this,o=this.chroms_layout,n=this.track,r=$.Deferred();$.when(n.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){p.data_bounds=p.get_data_bounds(t);layout_and_data=g.zip(o,t),chroms_data_layout=g.map(layout_and_data,function(u){var v=u[0],w=u[1];return p._render_chrom_data(q,v,w)});var s=p.get_fill_color();p.parent_elt.selectAll("path.chrom-data").style("stroke",s).style("fill",s);r.resolve(q)});return r},_render_chrom_data:function(n,o,p){},_get_path_function:function(o,n){},_chroms_layout:function(){var o=this.genome.get_chroms_info(),q=l.layout.pie().value(function(s){return s.len}).sort(null),r=q(o),n=this.total_gap/o.length,p=g.map(r,function(u,t){var s=u.endAngle-n;u.endAngle=(s>u.startAngle?s:u.startAngle);return u});return p}});var b=k.extend({initialize:function(n){k.prototype.initialize.call(this,n);this.innerRadius=this.radius_bounds[0];this.radius_bounds[0]=this.radius_bounds[1];this.bg_stroke="fff";this.bg_fill="fff";this.min_arc_len=0.08},_render_data:function(p){var o=this,n=p.selectAll("g");n.selectAll("path").attr("id",function(t){return"label-"+t.data.chrom});n.append("svg:text").filter(function(t){return t.endAngle-t.startAngle>o.min_arc_len}).attr("text-anchor","middle").append("svg:textPath").attr("xlink:href",function(t){return"#label-"+t.data.chrom}).attr("startOffset","25%").attr("font-weight","bold").text(function(t){return t.data.chrom});var q=function(v){var t=(v.endAngle-v.startAngle)/v.value,u=l.range(0,v.value,25000000).map(function(w,x){return{radius:o.innerRadius,angle:w*t+v.startAngle,label:x===0?0:(x%3?null:o.formatNum(w))}});if(u.length<4){u[u.length-1].label=o.formatNum(Math.round((u[u.length-1].angle-v.startAngle)/t))}return u};var s=function(t){return t.angle>Math.PI?"rotate(180)translate(-16)":null};var r=g.filter(this.chroms_layout,function(t){return t.endAngle-t.startAngle>o.min_arc_len});this.drawTicks(this.parent_elt,r,q,s)}});g.extend(b.prototype,h);var f=k.extend({_quantile:function(o,n){o.sort(l.ascending);return l.quantile(o,n)},_render_chrom_data:function(n,q,o){var r=this._get_path_function(q,o);if(!r){return null}var p=n.datum(o.data),s=p.append("path").attr("class","chrom-data").attr("chrom",q.data.chrom).attr("d",r);return s},_get_path_function:function(q,p){if(typeof p==="string"||!p.data||p.data.length===0){return null}var n=l.scale.linear().domain(this.data_bounds).range(this.radius_bounds).clamp(true);var r=l.scale.linear().domain([0,p.data.length]).range([q.startAngle,q.endAngle]);var o=l.svg.line.radial().interpolate("linear").radius(function(s){return n(s[1])}).angle(function(t,s){return r(s)});return l.svg.area.radial().interpolate(o.interpolate()).innerRadius(n(0)).outerRadius(o.radius()).angle(o.angle())},render_labels:function(){var n=this,q=function(){return"rotate(90)"};var p=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),o=g.filter(p,function(s,r){return r%3===0});this.drawTicks(this.parent_elt,o,this._data_bounds_ticks_fn(),q,true)},_transition_labels:function(){if(this.data_bounds.length===0){return}var o=this,q=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),p=g.filter(q,function(s,r){return r%3===0}),n=g.flatten(g.map(p,function(r){return o._data_bounds_ticks_fn()(r)}));this.parent_elt.selectAll("g.tick").data(n).transition().attr("transform",function(r){return"rotate("+(r.angle*180/Math.PI-90)+")translate("+r.radius+",0)"})},_data_bounds_ticks_fn:function(){var n=this;visibleChroms=0;return function(o){return[{radius:n.radius_bounds[0],angle:o.startAngle,label:n.formatNum(n.data_bounds[0])},{radius:n.radius_bounds[1],angle:o.startAngle,label:n.formatNum(n.data_bounds[1])}]}},get_data_bounds:function(n){}});g.extend(f.prototype,h);var d=f.extend({get_data_bounds:function(o){var n=g.flatten(g.map(o,function(p){if(p){return g.map(p.data,function(q){return q[1]})}else{return 0}}));return[g.min(n),this._quantile(n,0.98)]}});var j=k.extend({render:function(){var n=this;$.when(n.track.get("data_manager").data_is_ready()).then(function(){$.when(n.track.get("data_manager").get_genome_wide_data(n.genome)).then(function(q){var p=[],o=n.genome.get_chroms_info();g.each(q,function(u,t){var r=o[t].chrom;var s=g.map(u.data,function(w){var v=n._get_region_angle(r,w[1]),x=n._get_region_angle(w[3],w[4]);return{source:{startAngle:v,endAngle:v+0.01},target:{startAngle:x,endAngle:x+0.01}}});p=p.concat(s)});n.parent_elt.append("g").attr("class","chord").selectAll("path").data(p).enter().append("path").style("fill",n.get_fill_color()).attr("d",l.svg.chord().radius(n.radius_bounds[0])).style("opacity",1)})})},update_radius_bounds:function(n){this.radius_bounds=n;this.parent_elt.selectAll("path").transition().attr("d",l.svg.chord().radius(this.radius_bounds[0]))},_get_region_angle:function(p,n){var o=g.find(this.chroms_layout,function(q){return q.data.chrom===p});return o.endAngle-((o.endAngle-o.startAngle)*(o.data.len-n)/o.data.len)}});var e=Backbone.View.extend({initialize:function(){var n=new i.Genome(config.app.genome),o=new i.GenomeVisualization(config.app.viz_config),q=new a({el:$("#center .unified-panel-body"),total_gap:2*Math.PI*0.1,genome:n,model:o,dataset_arc_height:25});q.render();$("#center .unified-panel-header-inner").append(config.app.viz_config.title+" "+config.app.viz_config.dbkey);var p=create_icon_buttons_menu([{icon_class:"plus-button",title:"Add tracks",on_click:function(){i.select_datasets(config.root+"visualization/list_current_history_datasets",config.root+"api/datasets",o.get("dbkey"),function(r){o.add_tracks(r)})}},{icon_class:"disk--arrow",title:"Save",on_click:function(){show_modal("Saving...","progress");var r=config.app.viz_config;$.ajax({url:config.root+"visualization/save",type:"POST",dataType:"json",data:{id:r.vis_id,title:r.title,dbkey:r.dbkey,type:"trackster",vis_json:JSON.stringify(r)}}).success(function(s){hide_modal();r.vis_id=s.vis_id;r.has_changes=false;window.history.pushState({},"",s.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=config.root+"visualization/list"}}],{tooltip_config:{placement:"bottom"}});p.$el.attr("style","float: right");$("#center .unified-panel-header-inner").append(p.$el);$(".menu-button").tooltip({placement:"bottom"})}});return{GalaxyApp:e}});
\ No newline at end of file
diff -r 3f85113b7476767ef1dc76c7f3312b423ff743db -r 2c3f4163da4ef47bb3f04da580e5015961dc0c67 static/scripts/packed/viz/trackster.js
--- a/static/scripts/packed/viz/trackster.js
+++ b/static/scripts/packed/viz/trackster.js
@@ -1,1 +1,1 @@
-var ui=null;var view=null;var browser_router=null;require(["utils/galaxy.css","libs/jquery/jstorage","libs/jquery/jquery.event.drag","libs/jquery/jquery.event.hover","libs/jquery/jquery.mousewheel","libs/jquery/jquery-ui","libs/jquery/jquery-ui-combobox","libs/farbtastic","libs/jquery/jquery.form","libs/jquery/jquery.rating","mvc/ui"],function(a){a.load_file("/static/style/jquery.rating.css");a.load_file("/static/style/history.css");a.load_file("/static/style/autocomplete_tagging.css");a.load_file("/static/style/jquery-ui/smoothness/jquery-ui.css");a.load_file("/static/style/library.css");a.load_file("/static/style/trackster.css")});define(["libs/backbone/backbone-relational","viz/visualization","viz/trackster_ui"],function(c,a,b){var d=Backbone.View.extend({initialize:function(){ui=new b.TracksterUI(config.root);ui.createButtonMenu();ui.buttonMenu.$el.attr("style","float: right");$("#center .unified-panel-header-inner").append(ui.buttonMenu.$el);$("#right .unified-panel-title").append("Bookmarks");$("#right .unified-panel-icons").append("<a id='add-bookmark-button' class='icon-button menu-button plus-button' href='javascript:void(0);' title='Add bookmark'></a>");$("#right-border").click(function(){view.resize_window()});force_right_panel("hide");if(config.app.id){this.view_existing()}else{this.view_new()}},set_up_router:function(e){browser_router=new a.TrackBrowserRouter(e);Backbone.history.start()},view_existing:function(){var e=config.app.viz_config;view=ui.create_visualization({container:$("#center .unified-panel-body"),name:e.title,vis_id:e.vis_id,dbkey:e.dbkey},e.viewport,e.tracks,e.bookmarks,true);this.init_editor()},view_new:function(){var e=this;$.ajax({url:config.root+"api/genomes?chrom_info=True",data:{},error:function(){alert("Couldn't create new browser.")},success:function(f){show_modal("New Visualization",e.template_view_new(f),{Cancel:function(){window.location=config.root+"visualization/list"},Create:function(){e.create_browser($("#new-title").val(),$("#new-dbkey").val())}});if(config.app.default_dbkey){$("#new-dbkey option[value='"+config.default_dbkey+"']").attr("selected",true)}$("#new-title").focus();$("select[name='dbkey']").combobox({appendTo:$("#overlay"),size:40});$("#overlay").css("overflow","auto")}})},template_view_new:function(e){var g='<form id="new-browser-form" action="javascript:void(0);" method="post" onsubmit="return false;"><div class="form-row"><label for="new-title">Browser name:</label><div class="form-row-input"><input type="text" name="title" id="new-title" value="Unnamed"></input></div><div style="clear: both;"></div></div><div class="form-row"><label for="new-dbkey">Reference genome build (dbkey): </label><div class="form-row-input"><select name="dbkey" id="new-dbkey">';for(var f in e){g+='<option value="'+e[f][1]+'">'+e[f][0]+"</option>"}g+='</select></div><div style="clear: both;"></div></div><div class="form-row">Is the build not listed here?<br><a href="'+config.root+'user/dbkeys?use_panels=True">Add a Custom Build</a></div></form>';return g},create_browser:function(f,e){$(document).trigger("convert_to_values");view=ui.create_visualization({container:$("#center .unified-panel-body"),name:f,dbkey:e},config.app.gene_region);this.init_editor();view.editor=true;hide_modal()},init_editor:function(){$("#center .unified-panel-title").text(view.name+" ("+view.dbkey+")");if(config.app.add_dataset){$.ajax({url:config.root+"api/datasets/"+config.app.add_dataset,data:{hda_ldda:"hda",data_type:"track_config"},dataType:"json",success:function(e){view.add_drawable(b.object_from_template(e,view,view))}})}$("#add-bookmark-button").click(function(){var f=view.chrom+":"+view.low+"-"+view.high,e="Bookmark description";return ui.add_bookmark(f,e,true)});ui.init_keyboard_nav(view);this.set_up_router({view:view})}});return{GalaxyApp:d}});
\ No newline at end of file
+var ui=null;var view=null;var browser_router=null;require(["utils/galaxy.css","libs/jquery/jstorage","libs/jquery/jquery.event.drag","libs/jquery/jquery.event.hover","libs/jquery/jquery.mousewheel","libs/jquery/jquery-ui","libs/jquery/jquery-ui-combobox","libs/farbtastic","libs/jquery/jquery.form","libs/jquery/jquery.rating","mvc/ui"],function(a){a.load_file("/static/style/jquery.rating.css");a.load_file("/static/style/history.css");a.load_file("/static/style/autocomplete_tagging.css");a.load_file("/static/style/jquery-ui/smoothness/jquery-ui.css");a.load_file("/static/style/library.css");a.load_file("/static/style/trackster.css")});define(["libs/backbone/backbone-relational","viz/visualization","viz/trackster_ui"],function(c,a,b){var d=Backbone.View.extend({initialize:function(){ui=new b.TracksterUI(config.root);ui.createButtonMenu();ui.buttonMenu.$el.attr("style","float: right");$("#center .unified-panel-header-inner").append(ui.buttonMenu.$el);$("#right .unified-panel-title").append("Bookmarks");$("#right .unified-panel-icons").append("<a id='add-bookmark-button' class='icon-button menu-button plus-button' href='javascript:void(0);' title='Add bookmark'></a>");$("#right-border").click(function(){view.resize_window()});force_right_panel("hide");if(config.app.id){this.view_existing()}else{this.view_new()}},set_up_router:function(e){browser_router=new a.TrackBrowserRouter(e);Backbone.history.start()},view_existing:function(){var e=config.app.viz_config;view=ui.create_visualization({container:$("#center .unified-panel-body"),name:e.title,vis_id:e.vis_id,dbkey:e.dbkey},e.viewport,e.tracks,e.bookmarks,true);this.init_editor()},view_new:function(){var e=this;$.ajax({url:config.root+"api/genomes?chrom_info=True",data:{},error:function(){alert("Couldn't create new browser.")},success:function(f){show_modal("New Visualization",e.template_view_new(f),{Cancel:function(){window.location=config.root+"visualization/list"},Create:function(){e.create_browser($("#new-title").val(),$("#new-dbkey").val())}});if(config.app.default_dbkey){$("#new-dbkey option[value='"+config.default_dbkey+"']").attr("selected",true)}$("#new-title").focus();$("select[name='dbkey']").combobox({appendTo:$("#overlay"),size:40});$("#overlay").css("overflow","auto")}})},template_view_new:function(e){var g='<form id="new-browser-form" action="javascript:void(0);" method="post" onsubmit="return false;"><div class="form-row"><label for="new-title">Browser name:</label><div class="form-row-input"><input type="text" name="title" id="new-title" value="Unnamed"></input></div><div style="clear: both;"></div></div><div class="form-row"><label for="new-dbkey">Reference genome build (dbkey): </label><div class="form-row-input"><select name="dbkey" id="new-dbkey">';for(var f in e){g+='<option value="'+e[f][1]+'">'+e[f][0]+"</option>"}g+='</select></div><div style="clear: both;"></div></div><div class="form-row">Is the build not listed here? <a href="'+config.root+'user/dbkeys?use_panels=True">Add a Custom Build</a></div></form>';return g},create_browser:function(f,e){$(document).trigger("convert_to_values");view=ui.create_visualization({container:$("#center .unified-panel-body"),name:f,dbkey:e},config.app.gene_region);this.init_editor();view.editor=true;hide_modal()},init_editor:function(){$("#center .unified-panel-title").text(view.name+" ("+view.dbkey+")");if(config.app.add_dataset){$.ajax({url:config.root+"api/datasets/"+config.app.add_dataset,data:{hda_ldda:"hda",data_type:"track_config"},dataType:"json",success:function(e){view.add_drawable(b.object_from_template(e,view,view))}})}$("#add-bookmark-button").click(function(){var f=view.chrom+":"+view.low+"-"+view.high,e="Bookmark description";return ui.add_bookmark(f,e,true)});ui.init_keyboard_nav(view);this.set_up_router({view:view})}});return{GalaxyApp:d}});
\ No newline at end of file
diff -r 3f85113b7476767ef1dc76c7f3312b423ff743db -r 2c3f4163da4ef47bb3f04da580e5015961dc0c67 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,w,k,t,L,X,i){var p=ab.extend;var m={};var j=function(ac,ad){m[ac.attr("id")]=ad};var l=function(ac,ae,ag,af){ag=".group";var ad={};m[ac.attr("id")]=af;ac.bind("drag",{handle:"."+ae,relative:true},function(ao,ap){var an=$(this),at=$(this).parent(),ak=at.children(),am=m[$(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=m[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=m[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)}m[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);m[at.attr("id")].move_drawable(am,al)}}else{if(this!==ak.get(al)){$(this).insertBefore(ak.get(al));m[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)})};var aa=16,G=9,D=20,z=100,I=12000,S=400,K=5000,v=100,n="Cannot display dataset due to an error. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",u="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",x="Tool cannot be rerun: ",a="Loading data...",U="Ready for display",R=10,H=20,A=["Histogram","Line","Filled","Intensity"];function V(ad,ac){if(!ac){ac=0}var ae=Math.pow(10,ac);return Math.round(ad*ae)/ae}var q=function(ad,ac,af){if(!q.id_counter){q.id_counter=0}this.id=q.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)}};q.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()}}];p(q.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(ac){},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 y=function(ad,ac,ae){q.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};p(y.prototype,q.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=o(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(ac){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad]._draw(ac)}},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},get_tracks:function(af){var ac=this.drawables.slice(0),ad=[],ae;while(ac.length!==0){ae=ac.shift();if(ae instanceof af){ad.push(ae)}else{if(ae.drawables){ac=ac.concat(ae.drawables)}}}return ad}});var Q=function(ad,ac,af){p(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});y.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);j(this.container_div,this);j(this.content_div,this);l(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()}}};p(Q.prototype,q.prototype,y.prototype,{action_icons_def:[q.prototype.action_icons_def[0],q.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({clear_tile_cache:true})}ac.filters_manager.toggle()}},q.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 ad=new f(this.view,this.view,{name:this.name,drawables:this.drawables});var ac=this.container.replace_drawable(this,ad,true);ad.request_draw()},add_drawable:function(ac){y.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){y.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=p(y.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){ab.each(this.drawables,function(ad){ad.request_draw(ac)})}});var Y=Backbone.View.extend({initialize:function(ac){p(ac,{obj_type:"View"});y.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.render();this.canvas_manager=new w.CanvasManager(this.container.get(0).ownerDocument);this.reset();this.config=new F({track:this,params:[{key:"a_color",label:"A Color",type:"color",default_value:"#FF0000"},{key:"c_color",label:"C Color",type:"color",default_value:"#00FF00"},{key:"g_color",label:"G Color",type:"color",default_value:"#0000FF"},{key:"t_color",label:"T Color",type:"color",default_value:"#FF00FF"},{key:"n_color",label:"N Color",type:"color",default_value:"#AAAAAA"},],saved_values:ac.prefs,onchange:function(){track.request_redraw({clear_tile_cache:true})}})},render: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;j(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(){w.select_datasets(config.root+"visualization/list_current_history_datasets",config.root+"api/datasets",{"f-dbkey":ac.dbkey},function(ag){ab.each(ag,function(ah){ac.add_drawable(o(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_tracks(c),function(ak){return ak.data_manager.search_features(ai.term).success(function(al){aj=aj.concat(al)})});$.when.apply($,ah).done(function(){ag($.map(aj,function(ak){return{label:ak[0],value:ak[1]}}))})}})});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a/>").attr("id","zoom-out").attr("title","Zoom out").tooltip({placement:"bottom"}).click(function(){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 W(this,{content_div:this.top_labeltrack}));this.add_label_track(new W(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")},get_base_color:function(ac){return this.config.values[ac.toLowerCase()+"_color"]||this.config.values.n_color}});p(Y.prototype,y.prototype,{changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(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=v;var ac=this,ad=$.Deferred();$.ajax({url:config.root+"api/genomes/"+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 '+v+"</option>"}if(ag.next_chroms){aj+='<option value="next">Next '+v+"</option>"}ac.chrom_select.html(aj);ac.chrom_start_index=ag.start_index;ad.resolve(ag.chrom_info)},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-v});return}if(ah==="next"){ae.load_chroms({low:this.chrom_start_index+v});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();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&&aj){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,"");ag=ag.replace(/:|\-/g," ");var ad=ag.split(/\s+/),af=ad[0],ae=(ad[1]?parseInt(ad[1],10):null),ac=(ad[2]?parseInt(ad[2],10):null);if(!ac){ae=ae-15;ac=ae+15}this.change_chrom(af,ae,ac)},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({data_fetch:false});if(this.redraw_on_move_fn){clearTimeout(this.redraw_on_move_fn)}this.redraw_on_move_fn=setTimeout(function(){ac.request_redraw()},200);var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){y.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){y.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(ad,ae){var ac=this,af=(ae?[ae]:ac.drawables);ab.each(af,function(ag){var ah=ab.find(ac.tracks_to_be_redrawn,function(ai){return ai[0]===ag});if(ah){ah[1]=ad}else{ac.tracks_to_be_redrawn.push([ag,ad])}});if(!this.requested_redraw){requestAnimationFrame(function(){ac._redraw()});this.requested_redraw=true}},_redraw:function(){this.requested_redraw=false;var ac=this.low,ag=this.high;if(ac<this.max_low){ac=this.max_low}if(ag>this.max_high){ag=this.max_high}var ad=this.high-this.low;if(this.high!==0&&ad<this.min_separation){ag=ac+this.min_separation}this.low=Math.floor(ac);this.high=Math.ceil(ag);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=1/this.resolution_b_px;var af=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ah=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ae=13;this.overview_box.css({left:af,width:Math.max(ae,ah)}).show();if(ah<ae){this.overview_box.css("left",af-(ae-ah)/2)}if(this.overview_highlight){this.overview_highlight.css({left:af,width:ah})}ab.each(this.tracks_to_be_redrawn,function(ak){var ai=ak[0],aj=ak[1];if(ai){ai._draw(aj)}});this.tracks_to_be_redrawn=[];ab.each(this.label_tracks,function(ai){ai._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 r=function(ae,aj,af){this.track=ae;this.id=aj.id;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 O(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()}};p(r.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.dataset.id,action:"rerun",tool_id:ac.id},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 ai=new w.GenomeRegion({chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}),ad={target_dataset_id:this.track.dataset.id,action:"rerun",tool_id:this.id,regions:[ai.toJSON()]},ah=this.track,ae=ad.tool_id+ah.tool_region_and_parameters_str(ai),ac;if(ah.container===view){var ag=new Q(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 aj=new ah.constructor(view,ac,{name:ae,hda_ldda:"hda"});aj.init_for_tool_data();aj.change_mode(ah.mode);aj.set_filters_manager(ah.filters_manager.copy(aj));aj.update_icons();ac.add_drawable(aj);aj.tiles_div.text("Starting job.");this.update_params();this.run(ad,aj,function(ak){aj.set_dataset(new X.Dataset(ak));aj.tiles_div.text("Running job.");aj.init()})},run:function(ac,ae,af){ac.inputs=this.get_param_values_dict();var ad=new k.ServerStateDeferred({ajax_settings:{url:config.root+"/api/tools",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(x+ag.message)}else{af(ag)}}})}});var O=function(ad,ac,ae,af){this.name=ad;this.label=ac;this.html=$(ae);this.value=af};p(O.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ae,ad,ag,ah,af,ac){O.call(this,ae,ad,ag,ah);this.min=af;this.max=ac};p(e.prototype,O.prototype,{update_value:function(){O.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};p(F.prototype,{set_param_default_value:function(ad,ac){var ae=ab.find(this.params,function(af){return af.key===ad});if(ae){ae.default_value=ac}},set_param_value:function(ac,ad){var ae=ab.find(this.params,function(af){return af.key===ac});if(ae){if(typeof ad==="string"||ad instanceof String){if(ad.trim()===""){ad=ae.default_value}else{if(ae.type==="float"){ad=parseFloat(ad)}else{if(ae.type==="int"){ad=parseInt(ad,10)}}}}}if(this.values[ac]!==ad){this.values[ac]=ad;return true}else{return false}},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(k.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==="bool"){ag=ac.find("#"+ai).is(":checked")}ad=ae.set_param_value(ah.key,ag)||ad}});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 M=function(ac,ag,ae,ad,af){b.call(this,ac,ag,ae,ad,af)};M.prototype.predisplay_actions=function(){};var P=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 w.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()}).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()}).dblclick(function(ar){ar.stopPropagation()})}};p(P.prototype,b.prototype);P.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"?V(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){p(ae,{drag_handle_class:"draghandle"});q.call(this,ad,ac,ae);this.dataset=new X.Dataset(ae.dataset);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 w.GenomeDataManager({dataset:this.dataset,genome:new w.Genome({key:ad.dbkey,chroms_info:{chrom_info:ad.chrom_data}}),data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=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()}}};p(g.prototype,q.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},q.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)}},q.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 w.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new w.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=config.root+"visualization/sweepster?"+$.param({dataset_id:ac.dataset.id,hda_ldda:ac.dataset.get("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})}},q.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset.id&&q.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},set_dataset:function(ac){this.dataset=ac;this.data_manager.set("dataset",ac)},on_resize:function(){this.request_draw({clear_tile_cache:true})},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(){q.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 W){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 Z){return"VariantTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(ae){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.tiles_div.css("height","auto");ad.tiles_div.text("").children().remove();ad.container_div.removeClass("nodata error pending");if(!ad.dataset.id){return}var ac=$.Deferred(),af={hda_ldda:ad.dataset.get("hda_ldda"),data_type:this.dataset_check_type,chrom:ad.view.chrom,retry:ae};$.getJSON(this.dataset.url(),af,function(ag){if(!ag||ag==="error"||ag.kind==="error"){ad.container_div.addClass("error");ad.tiles_div.text(n);if(ag.message){ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ag.message+"</pre>",{Close:hide_modal})}));ad.tiles_div.append($("<span/>").text(" "));ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ad.init(true)}))}}else{if(ag==="no converter"){ad.container_div.addClass("error");ad.tiles_div.text(J)}else{if(ag==="no data"||(ag.data!==undefined&&(ag.data===null||ag.data.length===0))){ad.container_div.addClass("nodata");ad.tiles_div.text(E)}else{if(ag==="pending"){ad.container_div.addClass("pending");ad.tiles_div.html(u);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(ag==="data"||ag.status==="data"){if(ag.valid_chroms){ad.valid_chroms=ag.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.apply($,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(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){ac.container_div.addClass("line-track");var af=ad.data;if(af&&af.min&&af.max){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.config.set_param_default_value("min_value",ae);ac.config.set_param_default_value("max_value",ag);ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},get_drawables:function(){return this}});var N=function(ae,ad,af){g.call(this,ae,ad,af);var ac=this;l(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 r(this,af.tool,af.tool_state):null);this.tile_cache=new w.Cache(R);this.left_offset=0;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)}};p(N.prototype,q.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({clear_tile_cache:true})},hide:true}]),copy:function(ac){var ad=this.to_dict();p(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,dataset:{id:this.dataset.id,hda_ldda:this.dataset.get("hda_ldda")},prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},set_min_max:function(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){var af=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.values.mode=ad;if(ad==="Auto"){this.data_manager.clear()}ac.request_draw({clear_tile_cache:true});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,ac){return ad+"_"+ac},request_draw:function(ac){if(ac&&ac.clear_tile_cache){this.tile_cache.clear()}this.view.request_redraw(ac,this)},before_draw:function(){this.max_height_px=0},_draw:function(ap){if(!this.can_draw()){return}var am=ap&&ap.clear_after,ak=this.view.low,ag=this.view.high,aj=ag-ak,ad=this.view.container.width(),ao=this.view.resolution_px_b,af=this.view.resolution_b_px;if(this.is_overview){ak=this.view.max_low;ag=this.view.max_high;af=(view.max_high-view.max_low)/ad;ao=1/af}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(ak/(af*S)),al,ah,ai=[],an=[];while((ac*S*af)<ag){al=this._get_tile_bounds(ac,af);ah=this.draw_helper(al,af,ao,ap);ai.push(ah);$.when(ah).then(function(aq){an.push(aq)});ac+=1}if(!am){this.tiles_div.children(".remove").removeClass("remove").remove()}var ae=this;$.when.apply($,ai).then(function(){ae.tiles_div.children(".remove").remove();an=ab.filter(an,function(aq){return aq!==null});if(an.length!==0){ae.postdraw_actions(an,ad,ao,am)}})},_add_yaxis_label:function(af,ah){var ad=this,ag=(af==="max"?"top":"bottom"),ai=(af==="max"?"max":"min"),ac=(af==="max"?"max_value":"min_value"),ah=ah||function(){ad.request_draw({clear_tile_cache:true})},ae=this.container_div.find(".yaxislabel."+ag);if(ae.length!==0){ae.text(ad.prefs[ac])}else{ae=$("<div/>").text(ad.prefs[ac]).make_text_editable({num_cols:12,on_finish:function(aj){$(".bs-tooltip").remove();ad.config.set_param_value(ac,aj);ah()},help_text:"Set "+ai+" value"}).addClass("yaxislabel "+ag).css("color",this.prefs.label_color);this.container_div.prepend(ae)}},postdraw_actions:function(af,ag,ai,ac){var ae=ab.filter(af,function(aj){return(aj instanceof M)});if(ae.length>0){this.max_height_px=0;var ad=this;ab.each(af,function(aj){if(!(aj instanceof M)){aj.html_elt.remove();ad.draw_helper(aj.region,aj.resolution,ai,{force:true,mode:"Coverage"})}});ad._add_yaxis_label("max")}else{this.container_div.find(".yaxislabel").remove();var ah=ab.find(af,function(aj){return aj.has_icons});if(ah){ab.each(af,function(aj){if(!aj.has_icons){aj.html_elt.css("padding-top",D)}})}}},get_mode:function(ac){return this.mode},update_auto_mode:function(ac){},_get_drawables:function(){return[this]},draw_helper:function(al,af,ao,ap){if(!ap){ap={}}var ad=ap.force,an=!(ap.data_fetch===false),ai=ap.mode||this.mode,ae=this,ag=this._get_drawables(),am=this._gen_tile_cache_key(ao,al),ah=function(aq){return(aq&&"track" in aq)};var aj=(ad?undefined:ae.tile_cache.get_elt(am));if(aj){if(ah(aj)){ae.show_tile(aj,ao)}return aj}if(!an){return null}var ak=function(){var aq=(ab.find(A,function(at){return at===ai})?"Coverage":ai);var ar=ab.map(ag,function(at){return at.data_manager.get_data(al,aq,af,ae.data_url_extra_params)});if(view.reference_track){ar.push(view.reference_track.data_manager.get_data(al,ai,af,view.reference_track.data_url_extra_params))}return ar};var ac=$.Deferred();ae.tile_cache.set_elt(am,ac);$.when.apply($,ak()).then(function(){var aq=ak(),aw=aq,aC;if(view.reference_track){aC=view.reference_track.data_manager.subset_entry(aq.pop(),al)}var ax=[],au=[];ab.each(ag,function(aH,aE){var aG=aH.mode,aF=aw[aE];if(aG==="Auto"){aG=aH.get_mode(aF);aH.update_auto_mode(aG)}ax.push(aG);au.push(aH.get_canvas_height(aF,aG,ao,ar))});var av=ae.view.canvas_manager.new_canvas(),ay=al.get("start"),aD=al.get("end"),at=0,ar=Math.ceil((aD-ay)*ao)+ae.left_offset,aA=ab.max(au),az;av.width=ar;av.height=(ap.height||aA);var aB=av.getContext("2d");aB.translate(ae.left_offset,0);if(ag.length>1){aB.globalAlpha=0.5;aB.globalCompositeOperation="source-over"}ab.each(ag,function(aF,aE){az=aF.draw_tile(aw[aE],aB,ax[aE],af,al,ao,aC)});if(az!==undefined){ae.tile_cache.set_elt(am,az);ae.show_tile(az,ao)}ac.resolve(az)});return ac},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},_draw_line_track_tile:function(ac,ae,ai,ag,ah,aj){var af=ae.canvas,ad=new L.LinePainter(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai);ad.draw(ae,af.width,af.height,aj);return new M(this,ah,ag,af,ac.data)},draw_tile:function(ac,ad,ah,af,ag,ai,ae){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ae,ah){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var ag=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ah;if(this.left_offset){ag-=this.left_offset}ac.css({position:"absolute",top:0,left:ag});if(ac.hasClass("remove")){ac.removeClass("remove")}else{this.tiles_div.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 w.GenomeRegion({chrom:this.view.chrom,start:af,end:ae})},tool_region_and_parameters_str:function(ae){var ac=this,ad=(ae!==undefined?ae.toString():"all");return" - region=["+ad+"], parameters=["+ac.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="bigwig"}else{if(ac.extra_info==="no_detail"){return false}else{return true}}}},can_subset:function(ac){if(ac.dataset_type==="bigwig"||ac.message||ac.extra_info==="no_detail"){return false}return true},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state";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 k.ServerStateDeferred({url:ad.dataset_state_url,url_params:{dataset_id:ad.dataset.id,hda_ldda:ad.dataset.get("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 W=function(ad,ac){var ae={resize:false};g.call(this,ad,ac,ae);this.container_div.addClass("label-track")};p(W.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},predraw_init:function(){},_draw:function(ag){var ae=this.view,af=ae.high-ae.low,aj=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/aj)*aj,ah=this.view.container.width(),ad=$("<div style='position: relative; height: 1.3em;'></div>");while(ac<ae.high){var ai=(ac-ae.low)/af*ah;ad.append($("<div class='label'>"+commatize(ac)+"</div>").css({position:"absolute",left:ai-1}));ac+=aj}this.content_div.children(":first").remove();this.content_div.append(ad)}});var f=function(ad,ac,ag){this.display_modes=A;N.call(this,ad,ac,ag);this.drawables=[];if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=o(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}ab.each(this.drawables,function(ah){if(ah instanceof c||ah instanceof T){ah.change_mode("Coverage")}});this.update_icons();this.obj_type="CompositeTrack"};p(f.prototype,N.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(N.prototype.action_icons_def),to_dict:y.prototype.to_dict,add_drawable:y.prototype.add_drawable,unpack_drawables:y.prototype.unpack_drawables,change_mode:function(ac){N.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:q.prototype.can_draw,_get_drawables:function(){return this.drawables},show_group:function(){var af=new Q(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({clear_tile_cache:true})},before_draw:function(){N.prototype.before_draw.call(this);var ad=ab.min(ab.map(this.drawables,function(ae){return ae.prefs.min_value})),ac=ab.max(ab.map(this.drawables,function(ae){return ae.prefs.max_value}));this.prefs.min_value=ad;this.prefs.max_value=ac;ab.each(this.drawables,function(ae){ae.prefs.min_value=ad;ae.prefs.max_value=ac})},update_all_min_max:function(){var ac=this;ab.each(this.drawables,function(ad){ad.prefs.min_value=ac.prefs.min_value;ad.prefs.max_value=ac.prefs.max_value});this.request_draw({clear_tile_cache:true})},postdraw_actions:function(ai,ac,al,ah){N.prototype.postdraw_actions.call(this,ai,ac,al,ah);var ag=-1;for(var ae=0;ae<ai.length;ae++){var aj=ai[ae].html_elt.find("canvas").height();if(aj>ag){ag=aj}}for(var ae=0;ae<ai.length;ae++){var af=ai[ae];if(af.html_elt.find("canvas").height()!==ag){this.draw_helper(af.region,af.resolution,al,{force:true,height:ag});af.html_elt.remove()}}var ad=this,ak=function(){ad.update_all_min_max()};this._add_yaxis_label("min",ak);this._add_yaxis_label("max",ak)}});var B=function(ac){N.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=config.root+"api/genomes//"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new w.GenomeReferenceDataManager({data_url:this.data_url,can_subset:this.can_subset});this.hide_contents()};p(B.prototype,q.prototype,N.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},predraw_init:function(){},can_draw:q.prototype.can_draw,draw_helper:function(ae,ad,af,ac){if(af>this.view.canvas_manager.char_width_px){this.tiles_div.show();return N.prototype.draw_helper.call(this,ae,ad,af,ac)}else{this.tiles_div.hide();return null}},can_subset:function(ac){return true},draw_tile:function(af,al,ag,ad,ai,am){var ae=this.data_manager.subset_entry(af,ai),ak=ae.data;var ac=al.canvas;al.font=al.canvas.manager.default_font;al.textAlign="center";for(var ah=0,aj=ak.length;ah<aj;ah++){al.fillStyle=this.view.get_base_color(ak[ah]);al.fillText(ak[ah],Math.floor(ah*am),10)}return new b(this,ai,ad,ac,ae)}});var h=function(ae,ad,af){var ac=this;this.display_modes=A;this.mode="Histogram";N.call(this,ae,ad,af);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:k.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.request_redraw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height};p(h.prototype,q.prototype,N.prototype,{before_draw:function(){},draw_tile:function(ac,ad,ag,ae,af,ah){return this._draw_line_track_tile(ac,ad,ag,ae,af,ah)},can_subset:function(ac){return(ac.data[1][0]-ac.data[0][0]===1)},postdraw_actions:function(ad,ae,af,ac){this._add_yaxis_label("max");this._add_yaxis_label("min")}});var s=function(ae,ad,af){var ac=this;this.display_modes=["Heatmap"];this.mode="Heatmap";N.call(this,ae,ad,af);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:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"min_value",label:"Min Value",type:"float",default_value:-1},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);this.request_redraw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height};p(s.prototype,q.prototype,N.prototype,{draw_tile:function(ac,ae,ai,ag,ah,aj){var af=ae.canvas,ad=new L.DiagonalHeatmapPainter(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai);ad.draw(ae,af.width,af.height,aj);return new b(this,ah,ag,af,ac.data)}});var c=function(af,ae,ah){var ad=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];N.call(this,af,ae,ah);var ag=k.get_random_color(),ac=k.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:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:this.visible_height_px,hidden:true}],saved_values:ah.prefs,onchange:function(){ad.set_name(ad.prefs.name);ad.set_painter_from_config();ad.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");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()};p(c.prototype,q.prototype,N.prototype,{set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},postdraw_actions:function(am,ae,an,al){N.prototype.postdraw_actions.call(this,am,ae,an,al);var ag=this,ah;if(ag.filters_manager){var af=ag.filters_manager.filters;for(var aj=0;aj<af.length;aj++){af[aj].update_ui_elt()}var ai=false,ak,ad;for(ah=0;ah<am.length;ah++){if(am[ah].data.length){ak=am[ah].data[0];for(var aj=0;aj<af.length;aj++){ad=af[aj];if(ad.applies_to(ak)&&ad.min!==ad.max){ai=true;break}}}}if(ag.filters_available!==ai){ag.filters_available=ai;if(!ag.filters_available){ag.filters_manager.hide()}ag.update_icons()}}if(am[0] instanceof P){var ac=true;for(ah=0;ah<am.length;ah++){if(!am[ah].all_slotted){ac=false;break}}if(!ac){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"}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 (t.FeatureSlotter)(ag,af,z,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){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==="Coverage"||ac.dataset_type==="bigwig"){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(am.dataset_type==="bigwig"){return this._draw_line_track_tile(am,aq,ao,ar,af,aj)}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),az=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null),aA=new (this.painter)(ai,ay,ac,this.prefs,ao,aB,az,ae,function(aD){return ap.view.get_base_color(aD)});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 P(ap,af,ar,ad,am.data,aj,ao,am.message,all_slotted,aw)}});var Z=function(ad,ac,ae){this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];N.call(this,ad,ac,ae);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Histogram color",type:"color",default_value:k.get_random_color()},{key:"show_sample_data",label:"Show sample data",type:"bool",default_value:true},{key:"show_labels",label:"Show summary and sample labels",type:"bool",default_value:true},{key:"summary_height",label:"Locus summary height",type:"float",default_value:20},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ae.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.painter=L.VariantPainter;this.summary_draw_height=30;this.left_offset=30};p(Z.prototype,q.prototype,N.prototype,{draw_tile:function(ac,af,ai,ag,ah,aj){if(ac.dataset_type==="bigwig"){return this._draw_line_track_tile(ac,af,"Histogram",ag,ah,aj)}else{var ae=this.view,ad=new (this.painter)(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai,function(ak){return ae.get_base_color(ak)});ad.draw(af,af.canvas.width,af.canvas.height,aj);return new b(this,ah,ag,af.canvas,ac.data)}},get_canvas_height:function(ac,ag,ah,ae){if(ac.dataset_type==="bigwig"){return this.summary_draw_height}else{var af=new (this.painter)(null,null,null,this.prefs,ag);var ad=(this.dataset.get_metadata("sample_names")?this.dataset.get_metadata("sample_names").length:0);if(ad===0&&ac.data.length!==0){ad=ac.data[0][7].match(/,/g);if(ad===null){ad=1}else{ad=ad.length+1}}return af.get_required_height(ad)}},predraw_init:function(){var ac=[g.prototype.predraw_init.call(this)];if(!this.dataset.get_metadata("sample_names")){ac.push(this.dataset.fetch())}return ac},postdraw_actions:function(af,ag,ai,ad){N.prototype.postdraw_actions.call(this,af,ag,ai,ad);var ae=ab.filter(af,function(aj){return(aj instanceof M)});if(ae.length===0&&this.prefs.show_labels){var ac;if(this.container_div.find(".yaxislabel.variant").length===0){ac=this.prefs.summary_height/2;this.tiles_div.prepend($("<div/>").text("Summary").addClass("yaxislabel variant top").css({"font-size":ac+"px",top:(this.prefs.summary_height-ac)/2+"px"}));if(this.prefs.show_sample_data){var ah=this.dataset.get("metadata").get("sample_names").join("<br/>");this.tiles_div.prepend($("<div/>").html(ah).addClass("yaxislabel variant top sample").css({top:this.prefs.summary_height+2,}))}}ac=(this.mode==="Squish"?5:10)+"px";$(this.tiles_div).find(".sample").css({"font-size":ac,"line-height":ac});$(this.tiles_div).find(".yaxislabel").css("color",this.prefs.label_color)}else{this.container_div.find(".yaxislabel.variant").remove()}}});var T=function(ae,ad,ag){c.call(this,ae,ad,ag);var af=k.get_random_color(),ac=k.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:"mode",type:"string",default_value:this.mode,hidden:true},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.painter=(ae.reference_track?L.RefBasedReadPainter:L.ReadPainter);this.update_icons()};p(T.prototype,q.prototype,N.prototype,c.prototype);var d={CompositeTrack:f,DrawableGroup:Q,DiagonalHeatmapTrack:s,FeatureTrack:c,LineTrack:h,ReadTrack:T,VariantTrack:Z,VcfTrack:Z};var o=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{TracksterView:Y,DrawableGroup:Q,LineTrack:h,FeatureTrack:c,DiagonalHeatmapTrack:s,ReadTrack:T,VariantTrack:Z,CompositeTrack:f,object_from_template:o}});
\ No newline at end of file
+define(["libs/underscore","viz/visualization","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters","viz/trackster/filters","mvc/data","mvc/tools"],function(ac,w,j,s,L,h,X,R){var o=ac.extend;var l={};var i=function(ad,ae){l[ad.attr("id")]=ae};var k=function(ad,af,ah,ag){ah=".group";var ae={};l[ad.attr("id")]=ag;ad.bind("drag",{handle:"."+af,relative:true},function(ap,aq){var ao=$(this),au=$(this).parent(),al=au.children(),an=l[$(this).attr("id")],ak,aj,ar,ai,am;aj=$(this).parents(ah);if(aj.length!==0){ar=aj.position().top;ai=ar+aj.outerHeight();if(aq.offsetY<ar){$(this).insertBefore(aj);var at=l[aj.attr("id")];at.remove_drawable(an);at.container.add_drawable_before(an,at);return}else{if(aq.offsetY>ai){$(this).insertAfter(aj);var at=l[aj.attr("id")];at.remove_drawable(an);at.container.add_drawable(an);return}}}aj=null;for(am=0;am<al.length;am++){ak=$(al.get(am));ar=ak.position().top;ai=ar+ak.outerHeight();if(ak.is(ah)&&this!==ak.get(0)&&aq.offsetY>=ar&&aq.offsetY<=ai){if(aq.offsetY-ar<ai-aq.offsetY){ak.find(".content-div").prepend(this)}else{ak.find(".content-div").append(this)}if(an.container){an.container.remove_drawable(an)}l[ak.attr("id")].add_drawable(an);return}}for(am=0;am<al.length;am++){ak=$(al.get(am));if(aq.offsetY<ak.position().top&&!(ak.hasClass("reference-track")||ak.hasClass("intro"))){break}}if(am===al.length){if(this!==al.get(am-1)){au.append(this);l[au.attr("id")].move_drawable(an,am)}}else{if(this!==al.get(am)){$(this).insertBefore(al.get(am));l[au.attr("id")].move_drawable(an,(aq.deltaY>0?am-1:am))}}}).bind("dragstart",function(){ae["border-top"]=ad.css("border-top");ae["border-bottom"]=ad.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(ae)})};var aa=16,G=9,D=20,z=100,I=12000,S=400,K=5000,v=100,m="Cannot display dataset due to an error. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",u="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",x="Tool cannot be rerun: ",a="Loading data...",U="Ready for display",Q=10,H=20,A=["Histogram","Line","Filled","Intensity"];function V(ae,ad){if(!ad){ad=0}var af=Math.pow(10,ad);return Math.round(ae*af)/af}var p=function(ae,ad,ag){if(!p.id_counter){p.id_counter=0}this.id=p.id_counter++;this.name=ag.name;this.view=ae;this.container=ad;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=ag.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(ah){ah.stopPropagation()});var af=this;this.container_div.hover(function(){af.icons_div.show()},function(){af.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};p.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ad){if(ad.content_visible){ad.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ad.hide_contents();ad.content_visible=false}else{ad.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ad.content_visible=true;ad.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(ae){var ag=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ad=function(){ae.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},af=function(ah){if((ah.keyCode||ah.which)===27){ag()}else{if((ah.keyCode||ah.which)===13){ad()}}};$(window).bind("keypress.check_enter_esc",af);show_modal("Configure",ae.config.build_form(),{Cancel:ag,OK:ad})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ad){$(".bs-tooltip").remove();ad.remove()}}];o(p.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(ad){},to_dict:function(){},set_name:function(ad){this.old_name=this.name;this.name=ad;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 ad=this.view;this.container_div.hide(0,function(){$(this).remove();ad.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ae,aj,ai,ah,ad,ag){var af=this;this.action_icons[ae]=$("<a/>").attr("href","javascript:void(0);").attr("title",aj).addClass("icon-button").addClass(ai).tooltip().click(function(){ah(af)}).appendTo(this.icons_div);if(ag){this.action_icons[ae].hide()}},build_action_icons:function(ad){var af;for(var ae=0;ae<ad.length;ae++){af=ad[ae];this.add_action_icon(af.name,af.title,af.css_class,af.on_click_fn,af.prepend,af.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var y=function(ae,ad,af){p.call(this,ae,ad,af);this.obj_type=af.obj_type;this.drawables=[]};o(y.prototype,p.prototype,{unpack_drawables:function(af){this.drawables=[];var ae;for(var ad=0;ad<af.length;ad++){ae=n(af[ad],this.view,this);this.add_drawable(ae)}},init:function(){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].init()}},_draw:function(ad){for(var ae=0;ae<this.drawables.length;ae++){this.drawables[ae]._draw(ad)}},to_dict:function(){var ae=[];for(var ad=0;ad<this.drawables.length;ad++){ae.push(this.drawables[ad].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:ae}},add_drawable:function(ad){this.drawables.push(ad);ad.container=this;this.changed()},add_drawable_before:function(af,ad){this.changed();var ae=this.drawables.indexOf(ad);if(ae!==-1){this.drawables.splice(ae,0,af);return true}return false},replace_drawable:function(af,ad,ae){var ag=this.drawables.indexOf(af);if(ag!==-1){this.drawables[ag]=ad;if(ae){af.container_div.replaceWith(ad.container_div)}this.changed()}return ag},remove_drawable:function(ae){var ad=this.drawables.indexOf(ae);if(ad!==-1){this.drawables.splice(ad,1);ae.container=null;this.changed();return true}return false},move_drawable:function(ae,af){var ad=this.drawables.indexOf(ae);if(ad!==-1){this.drawables.splice(ad,1);this.drawables.splice(af,0,ae);this.changed();return true}return false},get_drawables:function(){return this.drawables},get_tracks:function(ag){var ad=this.drawables.slice(0),ae=[],af;while(ad.length!==0){af=ad.shift();if(af instanceof ag){ae.push(af)}else{if(af.drawables){ad=ad.concat(af.drawables)}}}return ae}});var P=function(ae,ad,ag){o(ag,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});y.call(this,ae,ad,ag);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);i(this.container_div,this);i(this.content_div,this);k(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new h.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in ag){this.unpack_drawables(ag.drawables)}if("filters" in ag){var af=this.filters_manager;this.filters_manager=new h.FiltersManager(this,ag.filters);af.parent_div.replaceWith(this.filters_manager.parent_div);if(ag.filters.visible){this.setup_multitrack_filtering()}}};o(P.prototype,p.prototype,y.prototype,{action_icons_def:[p.prototype.action_icons_def[0],p.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ad){$(".bs-tooltip").remove();ad.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ad){if(ad.filters_manager.visible()){ad.filters_manager.clear_filters();ad._restore_filter_managers()}else{ad.setup_multitrack_filtering();ad.request_draw({clear_tile_cache:true})}ad.filters_manager.toggle()}},p.prototype.action_icons_def[2]],build_container_div:function(){var ad=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ad)}return ad},build_header_div:function(){var ad=$("<div/>").addClass("track-header");ad.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(ad);return ad},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var af=this.drawables.length;if(af===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(af===1){if(this.drawables[0] instanceof e){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var am,al,aj,ap=true,ah=this.drawables[0].get_type(),ad=0;for(am=0;am<af;am++){aj=this.drawables[am];if(aj.get_type()!==ah){can_composite=false;break}if(aj instanceof c){ad++}}if(ap||ad===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(ad>1&&ad===this.drawables.length){var aq={},ae;aj=this.drawables[0];for(al=0;al<aj.filters_manager.filters.length;al++){ae=aj.filters_manager.filters[al];aq[ae.name]=[ae]}for(am=1;am<this.drawables.length;am++){aj=this.drawables[am];for(al=0;al<aj.filters_manager.filters.length;al++){ae=aj.filters_manager.filters[al];if(ae.name in aq){aq[ae.name].push(ae)}}}this.filters_manager.remove_all();var ag,ai,ak,an;for(var ao in aq){ag=aq[ao];if(ag.length===ad){ai=new h.NumberFilter({name:ag[0].name,index:ag[0].index});this.filters_manager.add_filter(ai)}}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 ad=0;ad<this.drawables.length;ad++){this.drawables[ad].filters_manager=this.saved_filters_managers[ad]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ad=0;ad<this.drawables.length;ad++){drawable=this.drawables[ad];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ae=new e(this.view,this.view,{name:this.name,drawables:this.drawables});var ad=this.container.replace_drawable(this,ae,true);ae.request_draw()},add_drawable:function(ad){y.prototype.add_drawable.call(this,ad);this.update_icons()},remove_drawable:function(ad){y.prototype.remove_drawable.call(this,ad);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ad=o(y.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ad},request_draw:function(ad){ac.each(this.drawables,function(ae){ae.request_draw(ad)})}});var Y=Backbone.View.extend({initialize:function(ad){o(ad,{obj_type:"View"});y.call(this,"View",ad.container,ad);this.chrom=null;this.vis_id=ad.vis_id;this.dbkey=ad.dbkey;this.label_tracks=[];this.tracks_to_be_redrawn=[];this.max_low=0;this.max_high=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.load_chroms_deferred=null;this.render();this.canvas_manager=new w.CanvasManager(this.container.get(0).ownerDocument);this.reset();this.config=new F({track:this,params:[{key:"a_color",label:"A Color",type:"color",default_value:"#FF0000"},{key:"c_color",label:"C Color",type:"color",default_value:"#00FF00"},{key:"g_color",label:"G Color",type:"color",default_value:"#0000FF"},{key:"t_color",label:"T Color",type:"color",default_value:"#FF00FF"},{key:"n_color",label:"N Color",type:"color",default_value:"#AAAAAA"},],saved_values:ad.prefs,onchange:function(){track.request_redraw({clear_tile_cache:true})}})},render:function(){this.requested_redraw=false;var af=this.container,ad=this;this.top_container=$("<div/>").addClass("top-container").appendTo(af);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(af);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(af);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").attr("id","viewport-container").appendTo(this.browser_content_div);this.content_div=this.viewport_container;i(this.viewport_container,ad);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var ag=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){w.select_datasets(config.root+"visualization/list_current_history_datasets",config.root+"api/datasets",{"f-dbkey":ad.dbkey},function(ah){ac.each(ah,function(ai){ad.add_drawable(n(ai,ad,ad))})})});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 ae=function(ah){if(ah.type==="focusout"||(ah.keyCode||ah.which)===13||(ah.keyCode||ah.which)===27){if((ah.keyCode||ah.which)!==27){ad.go_to($(this).val())}$(this).hide();$(this).val("");ad.location_span.show();ad.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ae).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(){ad.location_span.hide();ad.chrom_select.hide();ad.nav_input.val(ad.chrom+":"+ad.low+"-"+ad.high);ad.nav_input.css("display","inline-block");ad.nav_input.select();ad.nav_input.focus();ad.nav_input.autocomplete({source:function(aj,ah){var ak=[],ai=$.map(ad.get_tracks(c),function(al){return al.data_manager.search_features(aj.term).success(function(am){ak=ak.concat(am)})});$.when.apply($,ai).done(function(){ah($.map(ak,function(al){return{label:al[0],value:al[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(){ad.zoom_out();ad.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ad.zoom_in();ad.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ad.change_chrom(ad.chrom_select.val())});this.browser_content_div.click(function(ah){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ah){ad.zoom_in(ah.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ah,ai){this.current_x=ai.offsetX}).bind("drag",function(ah,aj){var ak=aj.offsetX-this.current_x;this.current_x=aj.offsetX;var ai=Math.round(ak/ad.viewport_container.width()*(ad.max_high-ad.max_low));ad.move_delta(-ai)});this.overview_close.click(function(){ad.reset_overview()});this.viewport_container.bind("draginit",function(ah,ai){if(ah.clientX>ad.viewport_container.width()-16){return false}}).bind("dragstart",function(ah,ai){ai.original_low=ad.low;ai.current_height=ah.clientY;ai.current_x=ai.offsetX}).bind("drag",function(aj,al){var ah=$(this);var am=al.offsetX-al.current_x;var ai=ah.scrollTop()-(aj.clientY-al.current_height);ah.scrollTop(ai);al.current_height=aj.clientY;al.current_x=al.offsetX;var ak=Math.round(am/ad.viewport_container.width()*(ad.high-ad.low));ad.move_delta(ak)}).bind("mousewheel",function(aj,al,ai,ah){if(ai){ai*=50;var ak=Math.round(-ai/ad.viewport_container.width()*(ad.high-ad.low));ad.move_delta(ak)}});this.top_labeltrack.bind("dragstart",function(ah,ai){return $("<div />").css({height:ad.browser_content_div.height()+ad.top_labeltrack.height()+ad.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(al,am){$(am.proxy).css({left:Math.min(al.pageX,am.startX)-ad.container.offset().left,width:Math.abs(al.pageX-am.startX)});var ai=Math.min(al.pageX,am.startX)-ad.container.offset().left,ah=Math.max(al.pageX,am.startX)-ad.container.offset().left,ak=(ad.high-ad.low),aj=ad.viewport_container.width();ad.update_location(Math.round(ai/aj*ak)+ad.low,Math.round(ah/aj*ak)+ad.low)}).bind("dragend",function(am,an){var ai=Math.min(am.pageX,an.startX),ah=Math.max(am.pageX,an.startX),ak=(ad.high-ad.low),aj=ad.viewport_container.width(),al=ad.low;ad.low=Math.round(ai/aj*ak)+al;ad.high=Math.round(ah/aj*ak)+al;$(an.proxy).remove();ad.request_redraw()});this.add_label_track(new W(this,{content_div:this.top_labeltrack}));this.add_label_track(new W(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ad.resize_window()},500)});$(document).bind("redraw",function(){ad.redraw()});this.reset();$(window).trigger("resize")},get_base_color:function(ad){return this.config.values[ad.toLowerCase()+"_color"]||this.config.values.n_color}});o(Y.prototype,y.prototype,{changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(ae,ag,ad,ah){if(this.timer){clearTimeout(this.timer)}if(ah){var af=this;this.timer=setTimeout(function(){af.trigger("navigate",ae+":"+ag+"-"+ad)},500)}else{view.trigger("navigate",ae+":"+ag+"-"+ad)}},update_location:function(ad,af){this.location_span.text(commatize(ad)+" - "+commatize(af));this.nav_input.val(this.chrom+":"+commatize(ad)+"-"+commatize(af));var ae=view.chrom_select.val();if(ae!==""){this.trigger_navigate(ae,view.low,view.high,true)}},load_chroms:function(af){af.num=v;var ad=this,ae=$.Deferred();$.ajax({url:config.root+"api/genomes/"+this.dbkey,data:af,dataType:"json",success:function(ah){if(ah.chrom_info.length===0){return}if(ah.reference){ad.add_label_track(new B(ad))}ad.chrom_data=ah.chrom_info;var ak='<option value="">Select Chrom/Contig</option>';for(var aj=0,ag=ad.chrom_data.length;aj<ag;aj++){var ai=ad.chrom_data[aj].chrom;ak+='<option value="'+ai+'">'+ai+"</option>"}if(ah.prev_chroms){ak+='<option value="previous">Previous '+v+"</option>"}if(ah.next_chroms){ak+='<option value="next">Next '+v+"</option>"}ad.chrom_select.html(ak);ad.chrom_start_index=ah.start_index;ae.resolve(ah.chrom_info)},error:function(){alert("Could not load chroms for this dbkey:",ad.dbkey)}});return ae},change_chrom:function(ai,ae,ak){var af=this;if(!af.chrom_data){af.load_chroms_deferred.then(function(){af.change_chrom(ai,ae,ak)});return}if(!ai||ai==="None"){return}if(ai==="previous"){af.load_chroms({low:this.chrom_start_index-v});return}if(ai==="next"){af.load_chroms({low:this.chrom_start_index+v});return}var aj=$.grep(af.chrom_data,function(al,am){return al.chrom===ai})[0];if(aj===undefined){af.load_chroms({chrom:ai},function(){af.change_chrom(ai,ae,ak)});return}else{if(ai!==af.chrom){af.chrom=ai;af.chrom_select.val(af.chrom);af.max_high=aj.len-1;af.reset();for(var ah=0,ad=af.drawables.length;ah<ad;ah++){var ag=af.drawables[ah];if(ag.init){ag.init()}}if(af.reference_track){af.reference_track.init()}}if(ae&&ak){af.low=Math.max(ae,0);af.high=Math.min(ak,af.max_high)}else{af.low=0;af.high=af.max_high}af.reset_overview();af.request_redraw()}},go_to:function(ah){ah=ah.replace(/,/g,"");ah=ah.replace(/:|\-/g," ");var ae=ah.split(/\s+/),ag=ae[0],af=(ae[1]?parseInt(ae[1],10):null),ad=(ae[2]?parseInt(ae[2],10):null);if(!ad){af=af-15;ad=af+15}this.change_chrom(ag,af,ad)},move_fraction:function(af){var ad=this;var ae=ad.high-ad.low;this.move_delta(af*ae)},move_delta:function(ag){var ad=this;var af=ad.high-ad.low;if(ad.low-ag<ad.max_low){ad.low=ad.max_low;ad.high=ad.max_low+af}else{if(ad.high-ag>ad.max_high){ad.high=ad.max_high;ad.low=ad.max_high-af}else{ad.high-=ag;ad.low-=ag}}ad.request_redraw({data_fetch:false});if(this.redraw_on_move_fn){clearTimeout(this.redraw_on_move_fn)}this.redraw_on_move_fn=setTimeout(function(){ad.request_redraw()},200);var ae=ad.chrom_select.val();this.trigger_navigate(ae,ad.low,ad.high,true)},add_drawable:function(ad){y.prototype.add_drawable.call(this,ad);ad.init();this.changed();this.update_intro_div()},add_label_track:function(ad){ad.view=this;ad.init();this.label_tracks.push(ad)},remove_drawable:function(af,ae){y.prototype.remove_drawable.call(this,af);if(ae){var ad=this;af.container_div.hide(0,function(){$(this).remove();ad.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ae,af){var ad=this,ag=(af?[af]:ad.drawables);ac.each(ag,function(ah){var ai=ac.find(ad.tracks_to_be_redrawn,function(aj){return aj[0]===ah});if(ai){ai[1]=ae}else{ad.tracks_to_be_redrawn.push([ah,ae])}});if(!this.requested_redraw){requestAnimationFrame(function(){ad._redraw()});this.requested_redraw=true}},_redraw:function(){this.requested_redraw=false;var ad=this.low,ah=this.high;if(ad<this.max_low){ad=this.max_low}if(ah>this.max_high){ah=this.max_high}var ae=this.high-this.low;if(this.high!==0&&ae<this.min_separation){ah=ad+this.min_separation}this.low=Math.floor(ad);this.high=Math.ceil(ah);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=1/this.resolution_b_px;var ag=(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 af=13;this.overview_box.css({left:ag,width:Math.max(af,ai)}).show();if(ai<af){this.overview_box.css("left",ag-(af-ai)/2)}if(this.overview_highlight){this.overview_highlight.css({left:ag,width:ai})}ac.each(this.tracks_to_be_redrawn,function(al){var aj=al[0],ak=al[1];if(aj){aj._draw(ak)}});this.tracks_to_be_redrawn=[];ac.each(this.label_tracks,function(aj){aj._draw()})},zoom_in:function(ae,af){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var ag=this.high-this.low,ah=ag/2+this.low,ad=(ag/this.zoom_factor)/2;if(ae){ah=ae/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ah-ad);this.high=Math.round(ah+ad);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ae=this.high-this.low,af=ae/2+this.low,ad=(ae*this.zoom_factor)/2;this.low=Math.round(af-ad);this.high=Math.round(af+ad);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(af){if(this.overview_drawable){if(this.overview_drawable.dataset.id===af.dataset.id){return}this.overview_viewport.find(".track").remove()}var ae=af.copy({content_div:this.overview_viewport}),ad=this;ae.header_div.hide();ae.is_overview=true;ad.overview_drawable=ae;this.overview_drawable.postdraw_actions=function(){ad.overview_highlight.show().height(ad.overview_drawable.content_div.height());ad.overview_viewport.height(ad.overview_drawable.content_div.height()+ad.overview_box.outerHeight());ad.overview_close.show();ad.resize_window()};ad.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 q=Backbone.RelationalModel.extend({defaults:{track:null,tool:null,},relations:[{type:Backbone.HasOne,key:"tool",relatedModel:R.Tool}]});var t=Backbone.View.extend({events:{"change input":"update_value"},render:function(){var af=this.$el.addClass("param-row"),ag=this.model;var ad=$("<div>").addClass("param-label").text(ag.get("label")).appendTo(af);var ae=$("<div/>").addClass("param-input").html(ag.get("html")).appendTo(af);ae.find(":input").val(ag.get("value"));$("<div style='clear: both;'/>").appendTo(af)},update_value:function(ad){this.model.set_value($(ad.target).val())}});var ab=Backbone.View.extend({render:function(){var ae=this;tool=this.model.get("tool"),parent_div=this.$el.addClass("dynamic-tool").hide();parent_div.bind("drag",function(ai){ai.stopPropagation()}).click(function(ai){ai.stopPropagation()}).bind("dblclick",function(ai){ai.stopPropagation()}).keydown(function(ai){ai.stopPropagation()});var af=$("<div class='tool-name'>").appendTo(parent_div).text(tool.get("name"));tool.get("inputs").each(function(aj){var ai=new t({model:aj});ai.render();parent_div.append(ai.$el)});parent_div.find("input").click(function(){$(this).select()});var ag=$("<div>").addClass("param-row").appendTo(parent_div);var ah=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(ag);var ad=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(ag);ad.click(function(){ae.run_on_region()});ah.click(function(){ae.run_on_dataset()})},update_params:function(){for(var ad=0;ad<this.params.length;ad++){this.params[ad].update_value()}},state_dict:function(){var ad=this.model.get("tool").get_param_values_dict();ad.visible=this.parent_div.is(":visible");return ad},run_on_dataset:function(){var ad=this.model.get("tool");this.run({target_dataset_id:this.model.get("track").dataset.id,action:"rerun",tool_id:ad.id},null,function(ae){show_modal(ad.get("name")+" is Running",ad.get("name")+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var ae=this.model.get("track"),ah=this.model.get("tool"),aj=new w.GenomeRegion({chrom:ae.view.chrom,start:ae.view.low,end:ae.view.high}),ak={target_dataset_id:ae.dataset.id,action:"rerun",tool_id:ah.id,regions:[aj.toJSON()]},ai=ae,am=ak.tool_id+ai.tool_region_and_parameters_str(aj),ad;if(ai.container===view){var al=new P(view,view,{name:this.name});var ag=ai.container.replace_drawable(ai,al,false);al.container_div.insertBefore(ai.view.content_div.children()[ag]);al.add_drawable(ai);ai.container_div.appendTo(al.content_div);ad=al}else{ad=ai.container}var af=new ai.constructor(view,ad,{name:am,hda_ldda:"hda"});af.init_for_tool_data();af.change_mode(ai.mode);af.set_filters_manager(ai.filters_manager.copy(af));af.update_icons();ad.add_drawable(af);af.tiles_div.text("Starting job.");this.run(ak,af,function(an){af.set_dataset(new X.Dataset(an));af.tiles_div.text("Running job.");af.init()})},run:function(ad,af,ag){ad.inputs=this.model.get("tool").get_inputs_dict();var ae=new j.ServerStateDeferred({ajax_settings:{url:config.root+"api/tools",data:JSON.stringify(ad),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ah){return ah!=="pending"}});$.when(ae.go()).then(function(ah){if(ah==="no converter"){af.container_div.addClass("error");af.content_div.text(J)}else{if(ah.error){af.container_div.addClass("error");af.content_div.text(x+ah.message)}else{ag(ah)}}})}});var C=function(ad,ae){L.Scaler.call(this,ae);this.filter=ad};C.prototype.gen_val=function(ad){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(ad[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var F=function(ad){this.track=ad.track;this.params=ad.params;this.values={};this.restore_values((ad.saved_values?ad.saved_values:{}));this.onchange=ad.onchange};o(F.prototype,{set_param_default_value:function(ae,ad){var af=ac.find(this.params,function(ag){return ag.key===ae});if(af){af.default_value=ad}},set_param_value:function(ad,ae){var af=ac.find(this.params,function(ag){return ag.key===ad});if(af){if(typeof ae==="string"||ae instanceof String){if(ae.trim()===""){ae=af.default_value}else{if(af.type==="float"){ae=parseFloat(ae)}else{if(af.type==="int"){ae=parseInt(ae,10)}}}}}if(this.values[ad]!==ae){this.values[ad]=ae;return true}else{return false}},restore_values:function(ad){var ae=this;$.each(this.params,function(af,ag){if(ad[ag.key]!==undefined){ae.values[ag.key]=ad[ag.key]}else{ae.values[ag.key]=ag.default_value}})},build_form:function(){var ag=this;var ad=$("<div />");var af;function ae(al,ah){for(var ap=0;ap<al.length;ap++){af=al[ap];if(af.hidden){continue}var aj="param_"+ap;var au=ag.values[af.key];var aw=$("<div class='form-row' />").appendTo(ah);aw.append($("<label />").attr("for",aj).text(af.label+":"));if(af.type==="bool"){aw.append($('<input type="checkbox" />').attr("id",aj).attr("name",aj).attr("checked",au))}else{if(af.type==="text"){aw.append($('<input type="text"/>').attr("id",aj).val(au).click(function(){$(this).select()}))}else{if(af.type==="select"){var ar=$("<select />").attr("id",aj);for(var an=0;an<af.options.length;an++){$("<option/>").text(af.options[an].label).attr("value",af.options[an].value).appendTo(ar)}ar.val(au);aw.append(ar)}else{if(af.type==="color"){var av=$("<div/>").appendTo(aw),aq=$("<input />").attr("id",aj).attr("name",aj).val(au).css("float","left").appendTo(av).click(function(ay){$(".bs-tooltip").removeClass("in");var ax=$(this).siblings(".bs-tooltip").addClass("in");ax.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(ax).height()/2)+($(this).height()/2)}).show();ax.click(function(az){az.stopPropagation()});$(document).bind("click.color-picker",function(){ax.hide();$(document).unbind("click.color-picker")});ay.stopPropagation()}),ao=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(av).attr("title","Set new random color").tooltip(),at=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(av).hide(),ak=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(at),ai=$("<div class='tooltip-arrow'></div>").appendTo(at),am=$.farbtastic(ak,{width:100,height:100,callback:aq,color:au});av.append($("<div/>").css("clear","both"));(function(ax){ao.click(function(){ax.setColor(j.get_random_color())})})(am)}else{aw.append($("<input />").attr("id",aj).attr("name",aj).val(au))}}}}if(af.help){aw.append($("<div class='help'/>").text(af.help))}}}ae(this.params,ad);return ad},update_from_form:function(ad){var af=this;var ae=false;$.each(this.params,function(ag,ai){if(!ai.hidden){var aj="param_"+ag;var ah=ad.find("#"+aj).val();if(ai.type==="bool"){ah=ad.find("#"+aj).is(":checked")}ae=af.set_param_value(ai.key,ah)||ae}});if(ae){this.onchange();this.track.changed()}}});var b=function(ad,ah,af,ae,ag){this.track=ad;this.region=ah;this.low=ah.get("start");this.high=ah.get("end");this.resolution=af;this.html_elt=$("<div class='track-tile'/>").append(ae).height($(ae).attr("height"));this.data=ag;this.stale=false};b.prototype.predisplay_actions=function(){};var M=function(ad,ah,af,ae,ag){b.call(this,ad,ah,af,ae,ag)};M.prototype.predisplay_actions=function(){};var O=function(ag,ao,ah,af,aj,aq,ak,ar,ae,an){b.call(this,ag,ao,ah,af,aj);this.mode=ak;this.all_slotted=ae;this.feature_mapper=an;this.has_icons=false;if(ar){this.has_icons=true;var al=this;af=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:D-1,width:af.width}).prependTo(this.html_elt);var am=new w.GenomeRegion({chrom:ag.view.chrom,start:this.low,end:this.high}),ap=aj.length,ai=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+ap+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ad=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+ap+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ai.click(function(){al.stale=true;ag.data_manager.get_more_data(am,ag.mode,al.resolution,{},ag.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();ag.request_draw()}).dblclick(function(at){at.stopPropagation()});ad.click(function(){al.stale=true;ag.data_manager.get_more_data(am,ag.mode,al.resolution,{},ag.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();ag.request_draw()}).dblclick(function(at){at.stopPropagation()})}};o(O.prototype,b.prototype);O.prototype.predisplay_actions=function(){var ae=this,ad={};if(ae.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(ap){if(!this.hovered){return}var ak=$(this).offset(),ao=ap.pageX-ak.left,an=ap.pageY-ak.top,au=ae.feature_mapper.get_feature_data(ao,an),al=(au?au[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!al||$(this).attr("id")!==al.toString()){$(this).remove()}});if(au){var ag=ad[al];if(!ag){var al=au[0],aq={name:au[3],start:au[1],end:au[2],strand:au[4]},aj=ae.track.filters_manager.filters,ai;for(var am=0;am<aj.length;am++){ai=aj[am];aq[ai.name]=au[ai.index]}var ag=$("<div/>").attr("id",al).addClass("feature-popup"),av=$("<table/>"),at,ar,aw;for(at in aq){ar=aq[at];aw=$("<tr/>").appendTo(av);$("<th/>").appendTo(aw).text(at);$("<td/>").attr("align","left").appendTo(aw).text(typeof(ar)==="number"?V(ar,2):ar)}ag.append($("<div class='feature-popup-inner'>").append(av));ad[al]=ag}ag.appendTo($(this).parents(".track-content").children(".overlay"));var ah=ao+parseInt(ae.html_elt.css("left"))-ag.width()/2,af=an+parseInt(ae.html_elt.css("top"))+7;ag.css("left",ah+"px").css("top",af+"px")}else{if(!ap.isPropagationStopped()){ap.stopPropagation();$(this).siblings().each(function(){$(this).trigger(ap)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var f=function(ae,ad,af){o(af,{drag_handle_class:"draghandle"});p.call(this,ae,ad,af);this.dataset=new X.Dataset(af.dataset);this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in af?af.data_query_wait:K);this.data_manager=("data_manager" in af?af.data_manager:new w.GenomeDataManager({dataset:this.dataset,genome:new w.Genome({key:ae.dbkey,chroms_info:{chrom_info:ae.chrom_data}}),data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=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 af)||af.resize){this.add_resize_handle()}}};o(f.prototype,p.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},p.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(ad){ad.view.set_overview(ad)}},p.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ad){if(ad.filters_manager.visible()){ad.filters_manager.clear_filters()}else{ad.filters_manager.init_filters()}ad.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ad){ad.dynamic_tool_div.toggle();if(ad.dynamic_tool_div.is(":visible")){ad.set_name(ad.name+ad.tool_region_and_parameters_str())}else{ad.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ad){var ag='<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>',af=ac.template(ag,{track:ad});var ai=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ae=function(){var ak=$('select[name="regions"] option:selected').val(),am,aj=new w.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),al=ac.map($(".bookmark"),function(an){return new w.GenomeRegion({from_str:$(an).children(".position").text()})});if(ak==="cur"){am=[aj]}else{if(ak==="bookmarks"){am=al}else{am=[aj].concat(al)}}hide_modal();window.location.href=config.root+"visualization/sweepster?"+$.param({dataset_id:ad.dataset.id,hda_ldda:ad.dataset.get("hda_ldda"),regions:JSON.stringify(new Backbone.Collection(am).toJSON())})},ah=function(aj){if((aj.keyCode||aj.which)===27){ai()}else{if((aj.keyCode||aj.which)===13){ae()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",af,{No:ai,Yes:ae})}},p.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset.id&&p.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 ad=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ad)}this.name_div=$("<div/>").addClass("track-name").appendTo(ad).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ad},set_dataset:function(ad){this.dataset=ad;this.data_manager.set("dataset",ad)},on_resize:function(){this.request_draw({clear_tile_cache:true})},add_resize_handle:function(){var ad=this;var ag=false;var af=false;var ae=$("<div class='track-resize'>");$(ad.container_div).hover(function(){if(ad.content_visible){ag=true;ae.show()}},function(){ag=false;if(!af){ae.hide()}});ae.hide().bind("dragstart",function(ah,ai){af=true;ai.original_height=$(ad.content_div).height()}).bind("drag",function(ai,aj){var ah=Math.min(Math.max(aj.original_height+aj.deltaY,ad.min_height_px),ad.max_height_px);$(ad.tiles_div).css("height",ah);ad.visible_height_px=(ad.max_height_px===ah?0:ah);ad.on_resize()}).bind("dragend",function(ah,ai){ad.tile_cache.clear();af=false;if(!ag){ae.hide()}ad.config.values.height=ad.visible_height_px;ad.changed()}).appendTo(ad.container_div)},set_display_modes:function(ag,aj){this.display_modes=ag;this.mode=(aj?aj:(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 ae=this,ah={};for(var af=0,ad=ae.display_modes.length;af<ad;af++){var ai=ae.display_modes[af];ah[ai]=function(ak){return function(){ae.change_mode(ak);ae.icons_div.show();ae.container_div.mouseleave(function(){ae.icons_div.hide()})}}(ai)}make_popupmenu(this.action_icons.mode_icon,ah)},build_action_icons:function(){p.prototype.build_action_icons.call(this,this.action_icons_def);if(this.display_modes!==undefined){this.set_display_modes(this.display_modes)}},hide_contents:function(){this.tiles_div.hide();this.container_div.find(".yaxislabel, .track-resize").hide()},show_contents:function(){this.tiles_div.show();this.container_div.find(".yaxislabel, .track-resize").show();this.request_draw()},get_type:function(){if(this instanceof W){return"LabelTrack"}else{if(this instanceof B){return"ReferenceTrack"}else{if(this instanceof g){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof Z){return"VariantTrack"}else{if(this instanceof e){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(af){var ae=this;ae.enabled=false;ae.tile_cache.clear();ae.data_manager.clear();ae.tiles_div.css("height","auto");ae.tiles_div.text("").children().remove();ae.container_div.removeClass("nodata error pending");if(!ae.dataset.id){return}var ad=$.Deferred(),ag={hda_ldda:ae.dataset.get("hda_ldda"),data_type:this.dataset_check_type,chrom:ae.view.chrom,retry:af};$.getJSON(this.dataset.url(),ag,function(ah){if(!ah||ah==="error"||ah.kind==="error"){ae.container_div.addClass("error");ae.tiles_div.text(m);if(ah.message){ae.tiles_div.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ah.message+"</pre>",{Close:hide_modal})}));ae.tiles_div.append($("<span/>").text(" "));ae.tiles_div.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ae.init(true)}))}}else{if(ah==="no converter"){ae.container_div.addClass("error");ae.tiles_div.text(J)}else{if(ah==="no data"||(ah.data!==undefined&&(ah.data===null||ah.data.length===0))){ae.container_div.addClass("nodata");ae.tiles_div.text(E)}else{if(ah==="pending"){ae.container_div.addClass("pending");ae.tiles_div.html(u);setTimeout(function(){ae.init()},ae.data_query_wait)}else{if(ah==="data"||ah.status==="data"){if(ah.valid_chroms){ae.valid_chroms=ah.valid_chroms;ae.update_icons()}ae.tiles_div.text(U);if(ae.view.chrom){ae.tiles_div.text("");ae.tiles_div.css("height",ae.visible_height_px+"px");ae.enabled=true;$.when.apply($,ae.predraw_init()).done(function(){ad.resolve();ae.container_div.removeClass("nodata error pending");ae.request_draw()})}else{ad.resolve()}}}}}}});this.update_icons();return ad},predraw_init:function(){var ad=this;return $.getJSON(ad.dataset.url(),{data_type:"data",stats:true,chrom:ad.view.chrom,low:0,high:ad.view.max_high,hda_ldda:ad.dataset.get("hda_ldda")},function(ae){ad.container_div.addClass("line-track");var ag=ae.data;if(ag&&ag.min&&ag.max){var af=ag.min,ah=ag.max;af=Math.floor(Math.min(0,Math.max(af,ag.mean-2*ag.sd)));ah=Math.ceil(Math.max(0,Math.min(ah,ag.mean+2*ag.sd)));ad.config.set_param_default_value("min_value",af);ad.config.set_param_default_value("max_value",ah);ad.prefs.min_value=af;ad.prefs.max_value=ah}})},get_drawables:function(){return this}});var N=function(af,ae,ah){f.call(this,af,ae,ah);var ad=this;k(ad.container_div,ad.drag_handle_class,".group",ad);this.filters_manager=new h.FiltersManager(this,("filters" in ah?ah.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=(ah.tool?new q({track:this,tool:ah.tool,tool_state:ah.tool_state}):null);this.tile_cache=new w.Cache(Q);this.left_offset=0;if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){var ag=new ab({model:this.tool});ag.render();this.dynamic_tool_div=ag.$el;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(ah.mode){this.change_mode(ah.mode)}};o(N.prototype,p.prototype,f.prototype,{action_icons_def:f.prototype.action_icons_def.concat([{name:"show_more_rows_icon",title:"To minimize track height, not all feature rows are displayed. Click to display more rows.",css_class:"exclamation",on_click_fn:function(ad){$(".bs-tooltip").remove();ad.slotters[ad.view.resolution_px_b].max_rows*=2;ad.request_draw({clear_tile_cache:true})},hide:true}]),copy:function(ad){var ae=this.to_dict();o(ae,{data_manager:this.data_manager});var af=new this.constructor(this.view,ad,ae);af.change_mode(this.mode);af.enabled=this.enabled;return af},set_filters_manager:function(ad){this.filters_manager=ad;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,dataset:{id:this.dataset.id,hda_ldda:this.dataset.get("hda_ldda")},prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},set_min_max:function(){var ad=this;return $.getJSON(ad.dataset.url(),{data_type:"data",stats:true,chrom:ad.view.chrom,low:0,high:ad.view.max_high,hda_ldda:ad.dataset.get("hda_ldda")},function(ae){var ag=ae.data;if(isNaN(parseFloat(ad.prefs.min_value))||isNaN(parseFloat(ad.prefs.max_value))){var af=ag.min,ah=ag.max;af=Math.floor(Math.min(0,Math.max(af,ag.mean-2*ag.sd)));ah=Math.ceil(Math.max(0,Math.min(ah,ag.mean+2*ag.sd)));ad.prefs.min_value=af;ad.prefs.max_value=ah}})},change_mode:function(ae){var ad=this;ad.mode=ae;ad.config.values.mode=ae;if(ae==="Auto"){this.data_manager.clear()}ad.request_draw({clear_tile_cache:true});this.action_icons.mode_icon.attr("title","Set display mode (now: "+ad.mode+")");return ad},update_icons:function(){var ad=this;if(ad.filters_available){ad.action_icons.filters_icon.show()}else{ad.action_icons.filters_icon.hide()}if(ad.tool){ad.action_icons.tools_icon.show();ad.action_icons.param_space_viz_icon.show()}else{ad.action_icons.tools_icon.hide();ad.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ae,ad){return ae+"_"+ad},request_draw:function(ad){if(ad&&ad.clear_tile_cache){this.tile_cache.clear()}this.view.request_redraw(ad,this)},before_draw:function(){this.max_height_px=0},_draw:function(aq){if(!this.can_draw()){return}var an=aq&&aq.clear_after,al=this.view.low,ah=this.view.high,ak=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 ad=Math.floor(al/(ag*S)),am,ai,aj=[],ao=[];while((ad*S*ag)<ah){am=this._get_tile_bounds(ad,ag);ai=this.draw_helper(am,ag,ap,aq);aj.push(ai);$.when(ai).then(function(ar){ao.push(ar)});ad+=1}if(!an){this.tiles_div.children(".remove").removeClass("remove").remove()}var af=this;$.when.apply($,aj).then(function(){af.tiles_div.children(".remove").remove();ao=ac.filter(ao,function(ar){return ar!==null});if(ao.length!==0){af.postdraw_actions(ao,ae,ap,an)}})},_add_yaxis_label:function(ag,ai){var ae=this,ah=(ag==="max"?"top":"bottom"),aj=(ag==="max"?"max":"min"),ad=(ag==="max"?"max_value":"min_value"),ai=ai||function(){ae.request_draw({clear_tile_cache:true})},af=this.container_div.find(".yaxislabel."+ah);if(af.length!==0){af.text(ae.prefs[ad])}else{af=$("<div/>").text(ae.prefs[ad]).make_text_editable({num_cols:12,on_finish:function(ak){$(".bs-tooltip").remove();ae.config.set_param_value(ad,ak);ai()},help_text:"Set "+aj+" value"}).addClass("yaxislabel "+ah).css("color",this.prefs.label_color);this.container_div.prepend(af)}},postdraw_actions:function(ag,ah,aj,ad){var af=ac.filter(ag,function(ak){return(ak instanceof M)});if(af.length>0){this.max_height_px=0;var ae=this;ac.each(ag,function(ak){if(!(ak instanceof M)){ak.html_elt.remove();ae.draw_helper(ak.region,ak.resolution,aj,{force:true,mode:"Coverage"})}});ae._add_yaxis_label("max")}else{this.container_div.find(".yaxislabel").remove();var ai=ac.find(ag,function(ak){return ak.has_icons});if(ai){ac.each(ag,function(ak){if(!ak.has_icons){ak.html_elt.css("padding-top",D)}})}}},get_mode:function(ad){return this.mode},update_auto_mode:function(ad){},_get_drawables:function(){return[this]},draw_helper:function(am,ag,ap,aq){if(!aq){aq={}}var ae=aq.force,ao=!(aq.data_fetch===false),aj=aq.mode||this.mode,af=this,ah=this._get_drawables(),an=this._gen_tile_cache_key(ap,am),ai=function(ar){return(ar&&"track" in ar)};var ak=(ae?undefined:af.tile_cache.get_elt(an));if(ak){if(ai(ak)){af.show_tile(ak,ap)}return ak}if(!ao){return null}var al=function(){var ar=(ac.find(A,function(au){return au===aj})?"Coverage":aj);var at=ac.map(ah,function(au){return au.data_manager.get_data(am,ar,ag,af.data_url_extra_params)});if(view.reference_track){at.push(view.reference_track.data_manager.get_data(am,aj,ag,view.reference_track.data_url_extra_params))}return at};var ad=$.Deferred();af.tile_cache.set_elt(an,ad);$.when.apply($,al()).then(function(){var ar=al(),ax=ar,aD;if(view.reference_track){aD=view.reference_track.data_manager.subset_entry(ar.pop(),am)}var ay=[],av=[];ac.each(ah,function(aI,aF){var aH=aI.mode,aG=ax[aF];if(aH==="Auto"){aH=aI.get_mode(aG);aI.update_auto_mode(aH)}ay.push(aH);av.push(aI.get_canvas_height(aG,aH,ap,at))});var aw=af.view.canvas_manager.new_canvas(),az=am.get("start"),aE=am.get("end"),au=0,at=Math.ceil((aE-az)*ap)+af.left_offset,aB=ac.max(av),aA;aw.width=at;aw.height=(aq.height||aB);var aC=aw.getContext("2d");aC.translate(af.left_offset,0);if(ah.length>1){aC.globalAlpha=0.5;aC.globalCompositeOperation="source-over"}ac.each(ah,function(aG,aF){aA=aG.draw_tile(ax[aF],aC,ay[aF],ag,am,ap,aD)});if(aA!==undefined){af.tile_cache.set_elt(an,aA);af.show_tile(aA,ap)}ad.resolve(aA)});return ad},get_canvas_height:function(ad,af,ag,ae){return this.visible_height_px},_draw_line_track_tile:function(ad,af,aj,ah,ai,ak){var ag=af.canvas,ae=new L.LinePainter(ad.data,ai.get("start"),ai.get("end"),this.prefs,aj);ae.draw(af,ag.width,ag.height,ak);return new M(this,ai,ah,ag,ad.data)},draw_tile:function(ad,ae,ai,ag,ah,aj,af){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(af,ai){var ae=this,ad=af.html_elt;af.predisplay_actions();var ah=(af.low-(this.is_overview?this.view.max_low:this.view.low))*ai;if(this.left_offset){ah-=this.left_offset}ad.css({position:"absolute",top:0,left:ah});if(ad.hasClass("remove")){ad.removeClass("remove")}else{this.tiles_div.append(ad)}af.html_elt.height("auto");this.max_height_px=Math.max(this.max_height_px,af.html_elt.height());af.html_elt.parent().children().css("height",this.max_height_px+"px");var ag=this.max_height_px;if(this.visible_height_px!==0){ag=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",ag+"px")},_get_tile_bounds:function(ad,ae){var ag=Math.floor(ad*S*ae),ah=Math.ceil(S*ae),af=(ag+ah<=this.view.max_high?ag+ah:this.view.max_high);return new w.GenomeRegion({chrom:this.view.chrom,start:ag,end:af})},tool_region_and_parameters_str:function(ag){var ad=this,af=(ag!==undefined?ag.toString():"all"),ae=ac.values(ad.tool.get("tool").get_inputs_dict()).join(", ");return" - region=["+af+"], parameters=["+ae+"]"},data_and_mode_compatible:function(ad,ae){if(ae==="Auto"){return true}else{if(ae==="Coverage"){return ad.dataset_type==="bigwig"}else{if(ad.extra_info==="no_detail"){return false}else{return true}}}},can_subset:function(ad){if(ad.dataset_type==="bigwig"||ad.message||ad.extra_info==="no_detail"){return false}return true},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state";this.normal_postdraw_actions=this.postdraw_actions;this.postdraw_actions=function(af,ag,ai,ad){var ae=this;ae.normal_postdraw_actions(af,ag,ai,ad);ae.dataset_check_type="converted_datasets_state";ae.data_query_wait=K;var ah=new j.ServerStateDeferred({url:ae.dataset_state_url,url_params:{dataset_id:ae.dataset.id,hda_ldda:ae.dataset.get("hda_ldda")},interval:ae.data_query_wait,success_fn:function(aj){return aj!=="pending"}});$.when(ah.go()).then(function(){ae.data_manager.set("data_type","data")});ae.postdraw_actions=ae.normal_postdraw_actions}}});var W=function(ae,ad){var af={resize:false};f.call(this,ae,ad,af);this.container_div.addClass("label-track")};o(W.prototype,f.prototype,{build_header_div:function(){},init:function(){this.enabled=true},predraw_init:function(){},_draw:function(ah){var af=this.view,ag=af.high-af.low,ak=Math.floor(Math.pow(10,Math.floor(Math.log(ag)/Math.log(10)))),ad=Math.floor(af.low/ak)*ak,ai=this.view.container.width(),ae=$("<div style='position: relative; height: 1.3em;'></div>");while(ad<af.high){var aj=(ad-af.low)/ag*ai;ae.append($("<div class='label'>"+commatize(ad)+"</div>").css({position:"absolute",left:aj-1}));ad+=ak}this.content_div.children(":first").remove();this.content_div.append(ae)}});var e=function(ae,ad,ah){this.display_modes=A;N.call(this,ae,ad,ah);this.drawables=[];if("drawables" in ah){var ag;for(var af=0;af<ah.drawables.length;af++){ag=ah.drawables[af];this.drawables[af]=n(ag,ae,null);if(ag.left_offset>this.left_offset){this.left_offset=ag.left_offset}}this.enabled=true}ac.each(this.drawables,function(ai){if(ai instanceof c||ai instanceof T){ai.change_mode("Coverage")}});this.update_icons();this.obj_type="CompositeTrack"};o(e.prototype,N.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ad){$(".bs-tooltip").remove();ad.show_group()}}].concat(N.prototype.action_icons_def),to_dict:y.prototype.to_dict,add_drawable:y.prototype.add_drawable,unpack_drawables:y.prototype.unpack_drawables,change_mode:function(ad){N.prototype.change_mode.call(this,ad);for(var ae=0;ae<this.drawables.length;ae++){this.drawables[ae].change_mode(ad)}},init:function(){var af=[];for(var ae=0;ae<this.drawables.length;ae++){af.push(this.drawables[ae].init())}var ad=this;$.when.apply($,af).then(function(){ad.enabled=true;ad.request_draw()})},update_icons:function(){this.action_icons.filters_icon.hide();this.action_icons.tools_icon.hide();this.action_icons.param_space_viz_icon.hide()},can_draw:p.prototype.can_draw,_get_drawables:function(){return this.drawables},show_group:function(){var ag=new P(this.view,this.container,{name:this.name}),ad;for(var af=0;af<this.drawables.length;af++){ad=this.drawables[af];ad.update_icons();ag.add_drawable(ad);ad.container=ag;ag.content_div.append(ad.container_div)}var ae=this.container.replace_drawable(this,ag,true);ag.request_draw({clear_tile_cache:true})},before_draw:function(){N.prototype.before_draw.call(this);var ae=ac.min(ac.map(this.drawables,function(af){return af.prefs.min_value})),ad=ac.max(ac.map(this.drawables,function(af){return af.prefs.max_value}));this.prefs.min_value=ae;this.prefs.max_value=ad;ac.each(this.drawables,function(af){af.prefs.min_value=ae;af.prefs.max_value=ad})},update_all_min_max:function(){var ad=this;ac.each(this.drawables,function(ae){ae.prefs.min_value=ad.prefs.min_value;ae.prefs.max_value=ad.prefs.max_value});this.request_draw({clear_tile_cache:true})},postdraw_actions:function(aj,ad,am,ai){N.prototype.postdraw_actions.call(this,aj,ad,am,ai);var ah=-1;for(var af=0;af<aj.length;af++){var ak=aj[af].html_elt.find("canvas").height();if(ak>ah){ah=ak}}for(var af=0;af<aj.length;af++){var ag=aj[af];if(ag.html_elt.find("canvas").height()!==ah){this.draw_helper(ag.region,ag.resolution,am,{force:true,height:ah});ag.html_elt.remove()}}var ae=this,al=function(){ae.update_all_min_max()};this._add_yaxis_label("min",al);this._add_yaxis_label("max",al)}});var B=function(ad){N.call(this,ad,{content_div:ad.top_labeltrack},{resize:false});ad.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=config.root+"api/genomes//"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new w.GenomeReferenceDataManager({data_url:this.data_url,can_subset:this.can_subset});this.hide_contents()};o(B.prototype,p.prototype,N.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},predraw_init:function(){},can_draw:p.prototype.can_draw,draw_helper:function(af,ae,ag,ad){if(ag>this.view.canvas_manager.char_width_px){this.tiles_div.show();return N.prototype.draw_helper.call(this,af,ae,ag,ad)}else{this.tiles_div.hide();return null}},can_subset:function(ad){return true},draw_tile:function(ag,am,ah,ae,aj,an){var af=this.data_manager.subset_entry(ag,aj),al=af.data;var ad=am.canvas;am.font=am.canvas.manager.default_font;am.textAlign="center";for(var ai=0,ak=al.length;ai<ak;ai++){am.fillStyle=this.view.get_base_color(al[ai]);am.fillText(al[ai],Math.floor(ai*an),10)}return new b(this,aj,ae,ad,af)}});var g=function(af,ae,ag){var ad=this;this.display_modes=A;this.mode="Histogram";N.call(this,af,ae,ag);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:j.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:ag.prefs,onchange:function(){ad.set_name(ad.prefs.name);ad.request_redraw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height};o(g.prototype,p.prototype,N.prototype,{before_draw:function(){},draw_tile:function(ad,ae,ah,af,ag,ai){return this._draw_line_track_tile(ad,ae,ah,af,ag,ai)},can_subset:function(ad){return(ad.data[1][0]-ad.data[0][0]===1)},postdraw_actions:function(ae,af,ag,ad){this._add_yaxis_label("max");this._add_yaxis_label("min")}});var r=function(af,ae,ag){var ad=this;this.display_modes=["Heatmap"];this.mode="Heatmap";N.call(this,af,ae,ag);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:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"min_value",label:"Min Value",type:"float",default_value:-1},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}],saved_values:ag.prefs,onchange:function(){ad.set_name(ad.prefs.name);this.request_redraw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height};o(r.prototype,p.prototype,N.prototype,{draw_tile:function(ad,af,aj,ah,ai,ak){var ag=af.canvas,ae=new L.DiagonalHeatmapPainter(ad.data,ai.get("start"),ai.get("end"),this.prefs,aj);ae.draw(af,ag.width,ag.height,ak);return new b(this,ai,ah,ag,ad.data)}});var c=function(ag,af,ai){var ae=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];N.call(this,ag,af,ai);var ah=j.get_random_color(),ad=j.get_random_color([ah,"#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:ah},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ad},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true,help:"Show the number of items in each bin when drawing summary histogram"},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:this.visible_height_px,hidden:true}],saved_values:ai.prefs,onchange:function(){ae.set_name(ae.prefs.name);ae.set_painter_from_config();ae.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");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()};o(c.prototype,p.prototype,N.prototype,{set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},postdraw_actions:function(an,af,ao,am){N.prototype.postdraw_actions.call(this,an,af,ao,am);var ah=this,ai;if(ah.filters_manager){var ag=ah.filters_manager.filters;for(var ak=0;ak<ag.length;ak++){ag[ak].update_ui_elt()}var aj=false,al,ae;for(ai=0;ai<an.length;ai++){if(an[ai].data.length){al=an[ai].data[0];for(var ak=0;ak<ag.length;ak++){ae=ag[ak];if(ae.applies_to(al)&&ae.min!==ae.max){aj=true;break}}}}if(ah.filters_available!==aj){ah.filters_available=aj;if(!ah.filters_available){ah.filters_manager.hide()}ah.update_icons()}}if(an[0] instanceof O){var ad=true;for(ai=0;ai<an.length;ai++){if(!an[ai].all_slotted){ad=false;break}}if(!ad){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(ad){var ad;if(this.mode==="Auto"){if(ad==="no_detail"){ad="feature spans"}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ad+")")}},incremental_slots:function(ah,ad,ag){var ae=this.view.canvas_manager.dummy_context,af=this.slotters[ah];if(!af||(af.mode!==ag)){af=new (s.FeatureSlotter)(ah,ag,z,function(ai){return ae.measureText(ai)});this.slotters[ah]=af}return af.slot_features(ad)},get_mode:function(ad){if(ad.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(ad,ah,ai,ae){if(ah==="Coverage"||ad.dataset_type==="bigwig"){return this.summary_draw_height}else{var ag=this.incremental_slots(ai,ad.data,ah);var af=new (this.painter)(null,null,null,this.prefs,ah);return Math.max(aa,af.get_required_height(ag,ae))}},draw_tile:function(an,ar,ap,at,ag,ak,af){var aq=this,ae=ar.canvas,az=ag.get("start"),ad=ag.get("end"),ah=this.left_offset;if(an.dataset_type==="bigwig"){return this._draw_line_track_tile(an,ar,ap,at,ag,ak)}var aj=[],ao=this.slotters[ak].slots;all_slotted=true;if(an.data){var al=this.filters_manager.filters;for(var au=0,aw=an.data.length;au<aw;au++){var ai=an.data[au];var av=false;var am;for(var ay=0,aD=al.length;ay<aD;ay++){am=al[ay];am.update_attrs(ai);if(!am.keep(ai)){av=true;break}}if(!av){aj.push(ai);if(!(ai[0] in ao)){all_slotted=false}}}}var aC=(this.filters_manager.alpha_filter?new C(this.filters_manager.alpha_filter):null),aA=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null),aB=new (this.painter)(aj,az,ad,this.prefs,ap,aC,aA,af,function(aE){return aq.view.get_base_color(aE)});var ax=null;ar.fillStyle=this.prefs.block_color;ar.font=ar.canvas.manager.default_font;ar.textAlign="right";if(an.data){ax=aB.draw(ar,ae.width,ae.height,ak,ao);ax.translation=-ah}return new O(aq,ag,at,ae,an.data,ak,ap,an.message,all_slotted,ax)}});var Z=function(ae,ad,af){this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];N.call(this,ae,ad,af);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Histogram color",type:"color",default_value:j.get_random_color()},{key:"show_sample_data",label:"Show sample data",type:"bool",default_value:true},{key:"show_labels",label:"Show summary and sample labels",type:"bool",default_value:true},{key:"summary_height",label:"Locus summary height",type:"float",default_value:20},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:af.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.painter=L.VariantPainter;this.summary_draw_height=30;this.left_offset=30};o(Z.prototype,p.prototype,N.prototype,{draw_tile:function(ad,ag,aj,ah,ai,ak){if(ad.dataset_type==="bigwig"){return this._draw_line_track_tile(ad,ag,"Histogram",ah,ai,ak)}else{var af=this.view,ae=new (this.painter)(ad.data,ai.get("start"),ai.get("end"),this.prefs,aj,function(al){return af.get_base_color(al)});ae.draw(ag,ag.canvas.width,ag.canvas.height,ak);return new b(this,ai,ah,ag.canvas,ad.data)}},get_canvas_height:function(ad,ah,ai,af){if(ad.dataset_type==="bigwig"){return this.summary_draw_height}else{var ag=new (this.painter)(null,null,null,this.prefs,ah);var ae=(this.dataset.get_metadata("sample_names")?this.dataset.get_metadata("sample_names").length:0);if(ae===0&&ad.data.length!==0){ae=ad.data[0][7].match(/,/g);if(ae===null){ae=1}else{ae=ae.length+1}}return ag.get_required_height(ae)}},predraw_init:function(){var ad=[f.prototype.predraw_init.call(this)];if(!this.dataset.get_metadata("sample_names")){ad.push(this.dataset.fetch())}return ad},postdraw_actions:function(ag,ah,aj,ae){N.prototype.postdraw_actions.call(this,ag,ah,aj,ae);var af=ac.filter(ag,function(ak){return(ak instanceof M)});if(af.length===0&&this.prefs.show_labels){var ad;if(this.container_div.find(".yaxislabel.variant").length===0){ad=this.prefs.summary_height/2;this.tiles_div.prepend($("<div/>").text("Summary").addClass("yaxislabel variant top").css({"font-size":ad+"px",top:(this.prefs.summary_height-ad)/2+"px"}));if(this.prefs.show_sample_data){var ai=this.dataset.get("metadata").get("sample_names").join("<br/>");this.tiles_div.prepend($("<div/>").html(ai).addClass("yaxislabel variant top sample").css({top:this.prefs.summary_height+2,}))}}ad=(this.mode==="Squish"?5:10)+"px";$(this.tiles_div).find(".sample").css({"font-size":ad,"line-height":ad});$(this.tiles_div).find(".yaxislabel").css("color",this.prefs.label_color)}else{this.container_div.find(".yaxislabel.variant").remove()}}});var T=function(af,ae,ah){c.call(this,af,ae,ah);var ag=j.get_random_color(),ad=j.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 and sense strand color",type:"color",default_value:ag},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ad},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"}],saved_values:ah.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.painter=(af.reference_track?L.RefBasedReadPainter:L.ReadPainter);this.update_icons()};o(T.prototype,p.prototype,N.prototype,c.prototype);var d={CompositeTrack:e,DrawableGroup:P,DiagonalHeatmapTrack:r,FeatureTrack:c,LineTrack:g,ReadTrack:T,VariantTrack:Z,VcfTrack:Z};var n=function(af,ae,ad){if("copy" in af){return af.copy(ad)}else{var ag=af.obj_type;if(!ag){ag=af.track_type}return new d[ag](ae,ad,af)}};return{TracksterView:Y,DrawableGroup:P,LineTrack:g,FeatureTrack:c,DiagonalHeatmapTrack:r,ReadTrack:T,VariantTrack:Z,CompositeTrack:e,object_from_template:n}});
\ No newline at end of file
diff -r 3f85113b7476767ef1dc76c7f3312b423ff743db -r 2c3f4163da4ef47bb3f04da580e5015961dc0c67 templates/webapps/galaxy/base_panels.mako
--- a/templates/webapps/galaxy/base_panels.mako
+++ b/templates/webapps/galaxy/base_panels.mako
@@ -4,7 +4,11 @@
<%def name="title()">Galaxy</%def><%def name="javascripts()">
- ${parent.javascripts()}
+${parent.javascripts()}
+
+<!-- quota meter -->
+${h.templates( "helpers-common-templates", "template-user-quotaMeter-quota", "template-user-quotaMeter-usage" )}
+${h.js( "mvc/base-mvc", "mvc/user/user-model", "mvc/user/user-quotameter" )}
</%def><%def name="get_user_json()">
@@ -35,10 +39,6 @@
<%def name="late_javascripts()">
${parent.late_javascripts()}
-
-<!-- quota meter -->
-${h.templates( "helpers-common-templates", "template-user-quotaMeter-quota", "template-user-quotaMeter-usage" )}
-${h.js( "mvc/base-mvc", "mvc/user/user-model", "mvc/user/user-quotameter" )}
<script type="text/javascript">
// start a Galaxy namespace for objects created
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: carlfeberhard: Dataproviders, QA: fix counters in FilteredDataProvider, rewrite BlockDataProvider, remove instance checks from dataset dprovs to prevent circular imports; Add unit tests for line dprovs
by commits-noreply@bitbucket.org 14 Aug '13
by commits-noreply@bitbucket.org 14 Aug '13
14 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/3f85113b7476/
Changeset: 3f85113b7476
User: carlfeberhard
Date: 2013-08-14 17:42:25
Summary: Dataproviders, QA: fix counters in FilteredDataProvider, rewrite BlockDataProvider, remove instance checks from dataset dprovs to prevent circular imports; Add unit tests for line dprovs
Affected #: 5 files
diff -r 009088d5e76fb00794da78dc0ee3cdaa8524b7d8 -r 3f85113b7476767ef1dc76c7f3312b423ff743db lib/galaxy/datatypes/dataproviders/base.py
--- a/lib/galaxy/datatypes/dataproviders/base.py
+++ b/lib/galaxy/datatypes/dataproviders/base.py
@@ -247,17 +247,22 @@
`offset`, begin providing datat, and stop when `num_data_returned`
is greater than `offset`.
"""
+ if self.limit != None and self.limit <= 0:
+ return
+ yield
+
parent_gen = super( LimitedOffsetDataProvider, self ).__iter__()
for datum in parent_gen:
-
- if self.limit != None and self.num_data_returned > self.limit:
- break
+ self.num_data_returned -= 1
+ #print 'self.num_data_returned:', self.num_data_returned
+ #print 'self.num_valid_data_read:', self.num_valid_data_read
if self.num_valid_data_read > self.offset:
+ self.num_data_returned += 1
yield datum
- else:
- # wot a cheezy way of doing this...
- self.num_data_returned -= 1
+
+ if self.limit != None and self.num_data_returned >= self.limit:
+ break
#TODO: skipping lines is inefficient - somehow cache file position/line_num pair and allow provider
# to seek to a pos/line and then begin providing lines
diff -r 009088d5e76fb00794da78dc0ee3cdaa8524b7d8 -r 3f85113b7476767ef1dc76c7f3312b423ff743db lib/galaxy/datatypes/dataproviders/dataset.py
--- a/lib/galaxy/datatypes/dataproviders/dataset.py
+++ b/lib/galaxy/datatypes/dataproviders/dataset.py
@@ -6,19 +6,13 @@
(e.g. parsing genomic regions from their source)
"""
+from galaxy import eggs
+
import pkg_resources
pkg_resources.require( 'bx-python' )
from bx import seq as bx_seq
from bx import wiggle as bx_wig
-import galaxy.model
-import galaxy.datatypes
-import galaxy.datatypes.data
-
-#TODO: can't import these due to circular ref in model/registry
-#import galaxy.datatypes.binary
-#import galaxy.datatypes.tabular
-
import exceptions
import base
import line
@@ -27,8 +21,9 @@
_TODO = """
use bx as much as possible
-the use of DatasetInstance seems to create some import problems
gff3 hierarchies
+
+change SamtoolsDataProvider to use pysam
"""
import logging
@@ -50,11 +45,8 @@
"""
:param dataset: the Galaxy dataset whose file will be the source
:type dataset: model.DatasetInstance
-
- :raises exceptions.InvalidDataProviderSource: if not a DatsetInstance
"""
- if not isinstance( dataset, galaxy.model.DatasetInstance ):
- raise exceptions.InvalidDataProviderSource( "Data provider can only be used with a DatasetInstance" )
+ #precondition: dataset is a galaxy.model.DatasetInstance
self.dataset = dataset
# this dataset file is obviously the source
#TODO: this might be a good place to interface with the object_store...
@@ -615,13 +607,7 @@
"""
#TODO: into validate_source
- #TODO: have to import these here due to circular ref in model/datatypes
- import galaxy.datatypes.binary
- import galaxy.datatypes.tabular
- if( not( isinstance( dataset.datatype, galaxy.datatypes.tabular.Sam )
- or isinstance( dataset.datatype, galaxy.datatypes.binary.Bam ) ) ):
- raise exceptions.InvalidDataProviderSource(
- 'dataset must be a Sam or Bam datatype: %s' %( str( dataset.datatype ) ) )
+ #precondition: dataset.datatype is a tabular.Sam or binary.Bam
self.dataset = dataset
options_dict = options_dict or {}
@@ -661,8 +647,9 @@
validated_flag_list = set([ flag for flag in options_string if flag in self.FLAGS_WO_ARGS ])
# if sam add -S
- if( ( isinstance( self.dataset.datatype, galaxy.datatypes.tabular.Sam )
- and ( 'S' not in validated_flag_list ) ) ):
+ #TODO: not the best test in the world...
+ if( ( self.dataset.ext == 'sam' )
+ and ( 'S' not in validated_flag_list ) ):
validated_flag_list.append( 'S' )
if validated_flag_list:
diff -r 009088d5e76fb00794da78dc0ee3cdaa8524b7d8 -r 3f85113b7476767ef1dc76c7f3312b423ff743db lib/galaxy/datatypes/dataproviders/line.py
--- a/lib/galaxy/datatypes/dataproviders/line.py
+++ b/lib/galaxy/datatypes/dataproviders/line.py
@@ -28,18 +28,25 @@
"""
DEFAULT_COMMENT_CHAR = '#'
settings = {
- 'string_lines' : 'bool',
+ 'strip_lines' : 'bool',
+ 'strip_newlines': 'bool',
'provide_blank' : 'bool',
'comment_char' : 'str',
}
- def __init__( self, source, strip_lines=True, provide_blank=False, comment_char=DEFAULT_COMMENT_CHAR, **kwargs ):
+ def __init__( self, source, strip_lines=True, strip_newlines=False, provide_blank=False,
+ comment_char=DEFAULT_COMMENT_CHAR, **kwargs ):
"""
:param strip_lines: remove whitespace from the beginning an ending
of each line (or not).
Optional: defaults to True
:type strip_lines: bool
+ :param strip_newlines: remove newlines only
+ (only functions when ``strip_lines`` is false)
+ Optional: defaults to False
+ :type strip_lines: bool
+
:param provide_blank: are empty lines considered valid and provided?
Optional: defaults to False
:type provide_blank: bool
@@ -51,6 +58,7 @@
"""
super( FilteredLineDataProvider, self ).__init__( source, **kwargs )
self.strip_lines = strip_lines
+ self.strip_newlines = strip_newlines
self.provide_blank = provide_blank
self.comment_char = comment_char
@@ -62,17 +70,18 @@
:type line: str
:returns: a line or `None`
"""
- line = super( FilteredLineDataProvider, self ).filter( line )
if line != None:
- # is this the proper order?
+ #??: shouldn't it strip newlines regardless, if not why not use on of the base.dprovs
if self.strip_lines:
line = line.strip()
+ elif self.strip_newlines:
+ line = line.strip( '\n' )
if not self.provide_blank and line == '':
return None
elif line.startswith( self.comment_char ):
return None
- return line
+ return super( FilteredLineDataProvider, self ).filter( line )
class RegexLineDataProvider( FilteredLineDataProvider ):
@@ -108,6 +117,7 @@
#NOTE: no support for flags
def filter( self, line ):
+ #NOTE: filter_fn will occur BEFORE any matching
line = super( RegexLineDataProvider, self ).filter( line )
if line != None and self.compiled_regex_list:
line = self.filter_by_regex( line )
@@ -144,16 +154,15 @@
:type block_filter_fn: function
"""
# composition - not inheritance
- #TODO: don't pass any?
- line_provider = FilteredLineDataProvider( source )
- super( BlockDataProvider, self ).__init__( line_provider, **kwargs )
+ #TODO: not a fan of this:
+ ( filter_fn, limit, offset ) = ( kwargs.pop( 'filter_fn', None ),
+ kwargs.pop( 'limit', None ), kwargs.pop( 'offset', 0 ) )
+ line_provider = FilteredLineDataProvider( source, **kwargs )
+ super( BlockDataProvider, self ).__init__( line_provider, filter_fn=filter_fn, limit=limit, offset=offset )
self.new_block_delim_fn = new_block_delim_fn
self.block_filter_fn = block_filter_fn
self.init_new_block()
- # ...well, this is kinda lame - but prevents returning first empty block
- #TODO: maybe better way in iter
- self.is_inside_block = False
def init_new_block( self ):
"""
@@ -161,7 +170,6 @@
"""
# called in __init__ and after yielding the prev. block
self.block_lines = collections.deque([])
- self.block = {}
def __iter__( self ):
"""
@@ -171,8 +179,8 @@
for block in parent_gen:
yield block
- last_block = self.filter_block( self.assemble_current_block() )
- if last_block != None and self.num_data_returned < self.limit:
+ last_block = self.handle_last_block()
+ if last_block != None:
self.num_data_returned += 1
yield last_block
@@ -186,26 +194,23 @@
:returns: a block or `None`
"""
line = super( BlockDataProvider, self ).filter( line )
+ #HACK
+ self.num_data_read -= 1
if line == None:
return None
+ block_to_return = None
if self.is_new_block( line ):
# if we're already in a block, return the prev. block and add the line to a new block
- #TODO: maybe better way in iter
- if self.is_inside_block:
- filtered_block = self.filter_block( self.assemble_current_block() )
+ if self.block_lines:
+ block_to_return = self.assemble_current_block()
+ block_to_return = self.filter_block( block_to_return )
+ self.num_data_read += 1
+
self.init_new_block()
- self.add_line_to_block( line )
-
- # return an assembled block datum if it passed the filter
- if filtered_block != None:
- return filtered_block
-
- else:
- self.is_inside_block = True
self.add_line_to_block( line )
- return None
+ return block_to_return
def is_new_block( self, line ):
"""
@@ -239,7 +244,6 @@
Called per block (just before providing).
"""
# empty block_lines and assemble block
- # NOTE: we don't want to have mem == 2*data here so - careful
return list( ( self.block_lines.popleft() for i in xrange( len( self.block_lines ) ) ) )
def filter_block( self, block ):
@@ -251,3 +255,20 @@
if self.block_filter_fn:
return self.block_filter_fn( block )
return block
+
+ def handle_last_block( self ):
+ """
+ Handle any blocks remaining after the main loop.
+ """
+ if self.limit != None and self.num_data_returned >= self.limit:
+ return None
+
+ last_block = self.assemble_current_block()
+ self.num_data_read += 1
+
+ last_block = self.filter_block( last_block )
+ if last_block != None:
+ self.num_valid_data_read += 1
+
+ return last_block
+
diff -r 009088d5e76fb00794da78dc0ee3cdaa8524b7d8 -r 3f85113b7476767ef1dc76c7f3312b423ff743db test/unit/datatypes/dataproviders/test_base_dataproviders.py
--- a/test/unit/datatypes/dataproviders/test_base_dataproviders.py
+++ b/test/unit/datatypes/dataproviders/test_base_dataproviders.py
@@ -15,8 +15,9 @@
log = utility.set_up_filelogger( __name__ + '.log' )
-utility.add_galaxy_lib_to_path( '/test/unit/datatypes/dataproviders' )
-from galaxy.datatypes import dataproviders
+utility.add_galaxy_lib_to_path( 'test/unit/datatypes/dataproviders' )
+from galaxy.datatypes.dataproviders import base, exceptions
+from galaxy import eggs
class BaseTestCase( unittest.TestCase ):
@@ -53,9 +54,12 @@
log.debug( 'file contents:\n%s', contents )
return contents
+ def parses_default_content_as( self ):
+ return [ 'One\n', 'Two\n', 'Three\n' ]
+
class Test_BaseDataProvider( BaseTestCase ):
- provider_class = dataproviders.base.DataProvider
+ provider_class = base.DataProvider
def contents_provider_and_data( self,
filename=None, contents=None, source=None, *provider_args, **provider_kwargs ):
@@ -74,38 +78,38 @@
return ( contents, provider, data )
def test_iterators( self ):
- source = ( x for x in xrange( 1, 10 ) )
+ source = ( str( x ) for x in xrange( 1, 10 ) )
provider = self.provider_class( source )
data = list( provider )
log.debug( 'data: %s', str( data ) )
- self.assertEqual( data, [ x for x in xrange( 1, 10 ) ] )
+ self.assertEqual( data, [ str( x ) for x in xrange( 1, 10 ) ] )
- source = [ x for x in xrange( 1, 10 ) ]
+ source = ( str( x ) for x in xrange( 1, 10 ) )
provider = self.provider_class( source )
data = list( provider )
log.debug( 'data: %s', str( data ) )
- self.assertEqual( data, [ x for x in xrange( 1, 10 ) ] )
+ self.assertEqual( data, [ str( x ) for x in xrange( 1, 10 ) ] )
- source = ( x for x in xrange( 1, 10 ) )
+ source = ( str( x ) for x in xrange( 1, 10 ) )
provider = self.provider_class( source )
data = list( provider )
log.debug( 'data: %s', str( data ) )
- self.assertEqual( data, [ x for x in xrange( 1, 10 ) ] )
+ self.assertEqual( data, [ str( x ) for x in xrange( 1, 10 ) ] )
def test_validate_source( self ):
"""validate_source should throw an error if the source doesn't have attr '__iter__'
"""
def non_iterator_dprov( source ):
return self.provider_class( source )
- self.assertRaises( dataproviders.exceptions.InvalidDataProviderSource,
+ self.assertRaises( exceptions.InvalidDataProviderSource,
non_iterator_dprov, 'one two three' )
- self.assertRaises( dataproviders.exceptions.InvalidDataProviderSource,
+ self.assertRaises( exceptions.InvalidDataProviderSource,
non_iterator_dprov, 40 )
def test_writemethods( self ):
"""should throw an error if any write methods are called
"""
- source = ( x for x in xrange( 1, 10 ) )
+ source = ( str( x ) for x in xrange( 1, 10 ) )
provider = self.provider_class( source )
# should throw error
def call_method( provider, method_name, *args ):
@@ -118,11 +122,11 @@
def test_readlines( self ):
"""readlines should return all the data in list form
"""
- source = ( x for x in xrange( 1, 10 ) )
+ source = ( str( x ) for x in xrange( 1, 10 ) )
provider = self.provider_class( source )
data = provider.readlines()
log.debug( 'data: %s', str( data ) )
- self.assertEqual( data, [ x for x in xrange( 1, 10 ) ] )
+ self.assertEqual( data, [ str( x ) for x in xrange( 1, 10 ) ] )
def test_stringio( self ):
"""should work with StringIO
@@ -137,21 +141,21 @@
data = list( provider )
log.debug( 'data: %s', str( data ) )
# provider should call close on file
- self.assertEqual( ''.join( data ), contents )
+ self.assertEqual( data, self.parses_default_content_as() )
self.assertTrue( source.closed )
def test_file( self ):
"""should work with files
"""
( contents, provider, data ) = self.contents_provider_and_data()
- self.assertEqual( ''.join( data ), contents )
+ self.assertEqual( data, self.parses_default_content_as() )
# provider should call close on file
self.assertTrue( isinstance( provider.source, file ) )
self.assertTrue( provider.source.closed )
class Test_FilteredDataProvider( Test_BaseDataProvider ):
- provider_class = dataproviders.base.FilteredDataProvider
+ provider_class = base.FilteredDataProvider
def assertCounters( self, provider, read, valid, returned ):
self.assertEqual( provider.num_data_read, read )
@@ -177,13 +181,13 @@
class Test_LimitedOffsetDataProvider( Test_FilteredDataProvider ):
- provider_class = dataproviders.base.LimitedOffsetDataProvider
+ provider_class = base.LimitedOffsetDataProvider
def test_offset_1( self ):
"""when offset is 1, should skip first
"""
( contents, provider, data ) = self.contents_provider_and_data( offset=1 )
- self.assertEqual( data, [ 'Two\n', 'Three\n' ] )
+ self.assertEqual( data, self.parses_default_content_as()[1:] )
self.assertCounters( provider, 3, 3, 2 )
def test_offset_all( self ):
@@ -197,29 +201,28 @@
"""when offset is 0, should return all
"""
( contents, provider, data ) = self.contents_provider_and_data( offset=0 )
- self.assertEqual( ''.join( data ), contents )
+ self.assertEqual( data, self.parses_default_content_as() )
self.assertCounters( provider, 3, 3, 3 )
def test_offset_negative( self ):
"""when offset is negative, should return all
"""
( contents, provider, data ) = self.contents_provider_and_data( offset=-1 )
- self.assertEqual( ''.join( data ), contents )
+ self.assertEqual( data, self.parses_default_content_as() )
self.assertCounters( provider, 3, 3, 3 )
def test_limit_1( self ):
"""when limit is one, should return first
"""
( contents, provider, data ) = self.contents_provider_and_data( limit=1 )
- self.assertEqual( data, [ 'One\n' ] )
- #TODO: currently reads 2 in all counters before ending
- #self.assertCounters( provider, 1, 1, 1 )
+ self.assertEqual( data, self.parses_default_content_as()[:1] )
+ self.assertCounters( provider, 1, 1, 1 )
def test_limit_all( self ):
"""when limit >= num lines, should return all
"""
( contents, provider, data ) = self.contents_provider_and_data( limit=4 )
- self.assertEqual( ''.join( data ), contents )
+ self.assertEqual( data, self.parses_default_content_as() )
self.assertCounters( provider, 3, 3, 3 )
def test_limit_zero( self ):
@@ -227,14 +230,13 @@
"""
( contents, provider, data ) = self.contents_provider_and_data( limit=0 )
self.assertEqual( data, [] )
- #TODO: currently reads 1 before ending
- self.assertCounters( provider, 3, 0, 0 )
+ self.assertCounters( provider, 0, 0, 0 )
def test_limit_zero( self ):
"""when limit is None, should return all
"""
( contents, provider, data ) = self.contents_provider_and_data( limit=None )
- self.assertEqual( ''.join( data ), contents )
+ self.assertEqual( data, self.parses_default_content_as() )
self.assertCounters( provider, 3, 3, 3 )
#TODO: somehow re-use tmpfile here
@@ -243,17 +245,18 @@
( contents, provider, data ) = self.contents_provider_and_data( limit=limit, offset=offset )
self.assertEqual( data, data_should_be )
#self.assertCounters( provider, read, valid, returned )
+ result_data = self.parses_default_content_as()
test_data = [
( 0, 0, [], 0, 0, 0 ),
- ( 1, 0, [ 'One\n' ], 1, 1, 1 ),
- ( 2, 0, [ 'One\n', 'Two\n' ], 2, 2, 2 ),
- ( 3, 0, [ 'One\n', 'Two\n', 'Three\n' ], 3, 3, 3 ),
- ( 1, 1, [ 'Two\n' ], 1, 1, 1 ),
- ( 2, 1, [ 'Two\n', 'Three\n' ], 2, 2, 2 ),
- ( 3, 1, [ 'Two\n', 'Three\n' ], 2, 2, 2 ),
- ( 1, 2, [ 'Three\n' ], 1, 1, 1 ),
- ( 2, 2, [ 'Three\n' ], 1, 1, 1 ),
- ( 3, 2, [ 'Three\n' ], 1, 1, 1 ),
+ ( 1, 0, self.parses_default_content_as()[:1], 1, 1, 1 ),
+ ( 2, 0, self.parses_default_content_as()[:2], 2, 2, 2 ),
+ ( 3, 0, self.parses_default_content_as()[:3], 3, 3, 3 ),
+ ( 1, 1, self.parses_default_content_as()[1:2], 1, 1, 1 ),
+ ( 2, 1, self.parses_default_content_as()[1:3], 2, 2, 2 ),
+ ( 3, 1, self.parses_default_content_as()[1:3], 2, 2, 2 ),
+ ( 1, 2, self.parses_default_content_as()[2:3], 1, 1, 1 ),
+ ( 2, 2, self.parses_default_content_as()[2:3], 1, 1, 1 ),
+ ( 3, 2, self.parses_default_content_as()[2:3], 1, 1, 1 ),
]
for test in test_data:
log.debug( 'limit_offset_combo: %s', ', '.join([ str( e ) for e in test ]) )
@@ -269,14 +272,15 @@
limit=limit, offset=offset, filter_fn=only_ts )
self.assertEqual( data, data_should_be )
#self.assertCounters( provider, read, valid, returned )
+ result_data = [ c for c in self.parses_default_content_as() if c.lower().startswith( 't' ) ]
test_data = [
( 0, 0, [], 0, 0, 0 ),
- ( 1, 0, [ 'Two\n' ], 1, 1, 1 ),
- ( 2, 0, [ 'Two\n', 'Three\n' ], 2, 2, 2 ),
- ( 3, 0, [ 'Two\n', 'Three\n' ], 2, 2, 2 ),
- ( 1, 1, [ 'Three\n' ], 1, 1, 1 ),
- ( 2, 1, [ 'Three\n' ], 1, 1, 1 ),
- ( 1, 2, [], 0, 0, 0 ),
+ ( 1, 0, result_data[:1], 1, 1, 1 ),
+ ( 2, 0, result_data[:2], 2, 2, 2 ),
+ ( 3, 0, result_data[:3], 2, 2, 2 ),
+ ( 1, 1, result_data[1:2], 1, 1, 1 ),
+ ( 2, 1, result_data[1:3], 1, 1, 1 ),
+ ( 1, 2, result_data[2:3], 0, 0, 0 ),
]
for test in test_data:
log.debug( 'limit_offset_combo: %s', ', '.join([ str( e ) for e in test ]) )
@@ -284,7 +288,7 @@
class Test_MultiSourceDataProvider( BaseTestCase ):
- provider_class = dataproviders.base.MultiSourceDataProvider
+ provider_class = base.MultiSourceDataProvider
def contents_and_tmpfile( self, contents=None ):
#TODO: hmmmm...
@@ -355,9 +359,9 @@
def no_youtube( string ):
return None if ( 'youtu.be' in string ) else string
source_list = [
- dataproviders.base.LimitedOffsetDataProvider( source_list[0], filter_fn=no_Fs, limit=2, offset=1 ),
- dataproviders.base.LimitedOffsetDataProvider( source_list[1], limit=1, offset=3 ),
- dataproviders.base.FilteredDataProvider( source_list[2], filter_fn=no_youtube ),
+ base.LimitedOffsetDataProvider( source_list[0], filter_fn=no_Fs, limit=2, offset=1 ),
+ base.LimitedOffsetDataProvider( source_list[1], limit=1, offset=3 ),
+ base.FilteredDataProvider( source_list[2], filter_fn=no_youtube ),
]
provider = self.provider_class( source_list )
log.debug( 'provider: %s', provider )
diff -r 009088d5e76fb00794da78dc0ee3cdaa8524b7d8 -r 3f85113b7476767ef1dc76c7f3312b423ff743db test/unit/datatypes/dataproviders/test_line_dataproviders.py
--- /dev/null
+++ b/test/unit/datatypes/dataproviders/test_line_dataproviders.py
@@ -0,0 +1,298 @@
+"""
+Unit tests for base DataProviders.
+.. seealso:: galaxy.datatypes.dataproviders.base
+"""
+# currently because of dataproviders.dataset importing galaxy.model this doesn't work
+#TODO: fix imports there after dist and retry
+
+#TODO: fix off by ones in FilteredDataProvider counters
+
+import unittest
+import StringIO
+
+import tempfilecache
+import utility
+
+import test_base_dataproviders
+
+log = utility.set_up_filelogger( __name__ + '.log' )
+
+utility.add_galaxy_lib_to_path( 'test/unit/datatypes/dataproviders' )
+from galaxy import eggs
+from galaxy.datatypes.dataproviders import line
+
+_TODO = """
+TestCase hierarchy is a bit of mess here.
+"""
+
+
+class Test_FilteredLineDataProvider( test_base_dataproviders.Test_FilteredDataProvider ):
+ provider_class = line.FilteredLineDataProvider
+ default_file_contents = """
+ # this should be stripped out
+ One
+ # as should blank lines
+
+ # preceding/trailing whitespace too
+ Two
+ Three
+ """
+
+ def parses_default_content_as( self ):
+ return [ 'One', 'Two', 'Three' ]
+
+ def test_counters( self ):
+ """should count: lines read, lines that passed the filter, lines returned
+ """
+ ( contents, provider, data ) = self.contents_provider_and_data()
+ self.assertCounters( provider, 7, 3, 3 )
+
+ def test_filter_fn( self ):
+ """should filter out lines using filter_fn and set counters properly
+ based on filter
+ """
+ def filter_ts( string ):
+ if string.lower().startswith( 't' ):
+ return None
+ return string
+ ( contents, provider, data ) = self.contents_provider_and_data( filter_fn=filter_ts )
+ self.assertCounters( provider, 7, 1, 1 )
+
+ def test_limit_with_offset( self ):
+ def limit_offset_combo( limit, offset, data_should_be, read, valid, returned ):
+ ( contents, provider, data ) = self.contents_provider_and_data( limit=limit, offset=offset )
+ self.assertEqual( data, data_should_be )
+ #self.assertCounters( provider, read, valid, returned )
+ result_data = self.parses_default_content_as()
+ test_data = [
+ ( 0, 0, [], 0, 0, 0 ),
+ ( 1, 0, self.parses_default_content_as()[:1], 1, 1, 1 ),
+ ( 2, 0, self.parses_default_content_as()[:2], 2, 2, 2 ),
+ ( 3, 0, self.parses_default_content_as()[:3], 3, 3, 3 ),
+ ( 1, 1, self.parses_default_content_as()[1:2], 1, 1, 1 ),
+ ( 2, 1, self.parses_default_content_as()[1:3], 2, 2, 2 ),
+ ( 3, 1, self.parses_default_content_as()[1:3], 2, 2, 2 ),
+ ( 1, 2, self.parses_default_content_as()[2:3], 1, 1, 1 ),
+ ( 2, 2, self.parses_default_content_as()[2:3], 1, 1, 1 ),
+ ( 3, 2, self.parses_default_content_as()[2:3], 1, 1, 1 ),
+ ]
+ for test in test_data:
+ log.debug( 'limit_offset_combo: %s', ', '.join([ str( e ) for e in test ]) )
+ limit_offset_combo( *test )
+
+ def test_provide_blank( self ):
+ """should return blank lines if ``provide_blank`` is true.
+ """
+ ( contents, provider, data ) = self.contents_provider_and_data( provide_blank=True )
+ self.assertEqual( data, [ 'One', '', 'Two', 'Three' ] )
+ self.assertCounters( provider, 7, 4, 4 )
+
+ def test_strip_lines( self ):
+ """should return unstripped lines if ``strip_lines`` is false.
+ """
+ ( contents, provider, data ) = self.contents_provider_and_data( strip_lines=False )
+ self.assertEqual( data, ['One\n', '\n', ' Two\n', 'Three\n'] )
+ self.assertCounters( provider, 7, 4, 4 )
+
+ def test_comment_char( self ):
+ """should return unstripped lines if ``strip_lines`` is false.
+ """
+ ( contents, provider, data ) = self.contents_provider_and_data( comment_char='T' )
+ self.assertEqual( data, [ '# this should be stripped out', 'One',
+ '# as should blank lines', '# preceding/trailing whitespace too' ] )
+ self.assertCounters( provider, 7, 4, 4 )
+
+
+class Test_RegexLineDataProvider( Test_FilteredLineDataProvider ):
+ provider_class = line.RegexLineDataProvider
+ default_file_contents = """
+ # this should be stripped out
+ One
+ # as should blank lines
+
+ # preceding/trailing whitespace too
+ Two
+ Three
+ """
+
+ def test_regex( self ):
+ """should return lines matching regex (AFTER strip, comments, blanks).
+ """
+ ( contents, provider, data ) = self.contents_provider_and_data( regex_list=[ r'^O' ] )
+ self.assertEqual( data, [ 'One' ] )
+ self.assertCounters( provider, 7, 1, 1 )
+
+ def test_regex_list( self ):
+ """should return regex matches using more than one regex by ORing them.
+ """
+ ( contents, provider, data ) = self.contents_provider_and_data( regex_list=[ r'^O', r'T' ] )
+ self.assertEqual( data, [ 'One', 'Two', 'Three' ] )
+ self.assertCounters( provider, 7, 3, 3 )
+
+ def test_inverse( self ):
+ """should return inverse matches when ``invert`` is true.
+ """
+ ( contents, provider, data ) = self.contents_provider_and_data( regex_list=[ r'^O' ], invert=True )
+ self.assertEqual( data, [ 'Two', 'Three' ] )
+ self.assertCounters( provider, 7, 2, 2 )
+
+ def test_regex_no_match( self ):
+ """should return empty if no regex matches.
+ """
+ ( contents, provider, data ) = self.contents_provider_and_data( regex_list=[ r'^Z' ] )
+ self.assertEqual( data, [] )
+ self.assertCounters( provider, 7, 0, 0 )
+
+ def test_regex_w_limit_offset( self ):
+ """regex should play well with limit and offset
+ """
+ ( contents, provider, data ) = self.contents_provider_and_data( regex_list=[ r'^T' ], limit=1 )
+ self.assertEqual( data, [ 'Two' ] )
+ #TODO: once again, valid data, returned data is off
+ self.assertCounters( provider, 6, 1, 1 )
+
+ ( contents, provider, data ) = self.contents_provider_and_data( regex_list=[ r'^T' ], limit=1, offset=1 )
+ self.assertEqual( data, [ 'Three' ] )
+ self.assertCounters( provider, 7, 2, 1 )
+
+
+class Test_BlockDataProvider( test_base_dataproviders.Test_FilteredDataProvider ):
+ provider_class = line.BlockDataProvider
+ default_file_contents = """
+ One
+ ABCD
+ Two
+ ABCD
+ EFGH
+ Three
+ """
+
+ def parses_default_content_as( self ):
+ return [ ['One'], ['ABCD'], ['Two'], ['ABCD'], ['EFGH'], ['Three'] ]
+
+ #TODO: well, this is ham-handed...
+ def test_stringio( self ): pass
+ def test_iterators( self ): pass
+ def test_readlines( self ): pass
+
+ def test_file( self ):
+ """should work with files
+ """
+ ( contents, provider, data ) = self.contents_provider_and_data()
+ self.assertEqual( data, self.parses_default_content_as() )
+ self.assertTrue( isinstance( provider.source, line.FilteredLineDataProvider ) )
+ self.assertTrue( isinstance( provider.source.source, file ) )
+ # provider should call close on file
+ self.assertTrue( provider.source.source.closed )
+
+ def test_counters( self ):
+ """should count: lines read, lines that passed the filter, lines returned
+ """
+ ( contents, provider, data ) = self.contents_provider_and_data()
+ self.assertCounters( provider, 6, 6, 6 )
+
+ def test_filter_fn( self ):
+ """should filter out lines using filter_fn and set counters properly
+ based on filter
+ """
+ def filter_ts( string ):
+ if string.lower().startswith( 't' ):
+ return None
+ return string
+ ( contents, provider, data ) = self.contents_provider_and_data( filter_fn=filter_ts )
+ # no block fns here, so will parse as lines
+ self.assertEqual( data, [ ['One'], ['ABCD'], ['ABCD'], ['EFGH'] ] )
+ self.assertCounters( provider, 4, 4, 4 )
+
+ def test_new_block_delim_fn( self ):
+ """should return blocks based on ``new_block_delim_fn``
+ """
+ def is_not_indented( line ):
+ strip_diff = len( line ) - len( line.lstrip() )
+ return ( strip_diff == 0 )
+ # in order to use indentation as a delimiter, we need to strip the newlines only
+ ( contents, provider, data ) = self.contents_provider_and_data( strip_lines=False, strip_newlines=True,
+ new_block_delim_fn=is_not_indented )
+ self.assertEqual( data, [[ 'One', ' ABCD' ], [ 'Two', ' ABCD', ' EFGH' ], [ 'Three' ]] )
+ self.assertCounters( provider, 3, 3, 3 )
+
+ def test_block_filter_fn( self ):
+ """should return blocks only blocks that pass ``block_filter_fn``
+ """
+ def is_not_indented( line ):
+ strip_diff = len( line ) - len( line.lstrip() )
+ return ( strip_diff == 0 )
+ #def empty_block( block ):
+ # if len( block ) <= 1:
+ # return None
+ # return block
+ def no_tw( block ):
+ if block[0].startswith( 'Tw' ):
+ return None
+ return block
+ ( contents, provider, data ) = self.contents_provider_and_data( strip_lines=False, strip_newlines=True,
+ new_block_delim_fn=is_not_indented, block_filter_fn=no_tw )
+ self.assertEqual( data, [[ 'One', ' ABCD' ], [ 'Three' ]] )
+ self.assertCounters( provider, 3, 2, 2 )
+
+ def test_hack_block_filter_fn( self ):
+ """should allow other aggregating/mod use in filter_fn
+
+ Although, it would be better to subclass and override assemble_current_block
+ """
+ def is_not_indented( line ):
+ strip_diff = len( line ) - len( line.lstrip() )
+ return ( strip_diff == 0 )
+ def empty_block( block ):
+ if len( block ) <= 1:
+ return None
+ return { 'header': block[0].strip(), 'data': [ b.strip() for b in block[1:] if b.strip() ] }
+ ( contents, provider, data ) = self.contents_provider_and_data(
+ strip_lines=False, strip_newlines=True,
+ new_block_delim_fn=is_not_indented, block_filter_fn=empty_block )
+ self.assertEqual( data, [ { 'header': 'One', 'data': [ 'ABCD' ]},
+ { 'header': 'Two', 'data': [ 'ABCD', 'EFGH' ]} ])
+ self.assertCounters( provider, 3, 2, 2 )
+
+ def test_block_filter_fn_w_limit_offset( self ):
+ """should allow both block fns and limit, offset
+ """
+ def is_not_indented( line ):
+ strip_diff = len( line ) - len( line.lstrip() )
+ return ( strip_diff == 0 )
+ def empty_block( block ):
+ if len( block ) <= 1:
+ return None
+ return block
+ ( contents, provider, data ) = self.contents_provider_and_data( strip_lines=False, strip_newlines=True,
+ new_block_delim_fn=is_not_indented, block_filter_fn=empty_block, limit=1 )
+ self.assertEqual( data, [[ 'One', ' ABCD' ]] )
+ self.assertCounters( provider, 1, 1, 1 )
+ ( contents, provider, data ) = self.contents_provider_and_data( strip_lines=False, strip_newlines=True,
+ new_block_delim_fn=is_not_indented, block_filter_fn=empty_block, limit=2, offset=1 )
+ self.assertEqual( data, [[ 'Two', ' ABCD', ' EFGH' ]] )
+ self.assertCounters( provider, 3, 2, 1 )
+
+ def test_simple_example( self ):
+ """
+ """
+ file_contents = """
+ >One
+ ABCD
+
+ # this comment (and the blank line above) won't be included
+ >Two
+ ABCD
+ EFGH
+ """
+ def fasta_header( line ):
+ return line.startswith( '>' )
+ def id_seq( block ):
+ return { 'id': block[0][1:], 'seq': ( ''.join( block[1:] ) ) }
+ ( contents, provider, data ) = self.contents_provider_and_data( contents=file_contents,
+ new_block_delim_fn=fasta_header, block_filter_fn=id_seq )
+ self.assertEqual( data, [{ 'id': 'One', 'seq': 'ABCD' }, { 'id': 'Two', 'seq': 'ABCDEFGH' }] )
+ self.assertCounters( provider, 2, 2, 2 )
+
+if __name__ == '__main__':
+ unittest.main()
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/1e7ce74fe941/
Changeset: 1e7ce74fe941
Branch: next-stable
User: natefoo
Date: 2013-08-12 17:53:34
Summary: Close next-stable branch for merge to stable.
Affected #: 0 files
https://bitbucket.org/galaxy/galaxy-central/commits/1ae95b3aa98d/
Changeset: 1ae95b3aa98d
Branch: stable
User: natefoo
Date: 2013-08-12 17:54:39
Summary: Merge next-stable to stable.
Affected #: 340 files
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 .coveragerc
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+branch = True
+include = lib/galaxy/*
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 .hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -60,7 +60,7 @@
job_conf.xml
data_manager_conf.xml
shed_data_manager_conf.xml
-visualizations_conf.xml
+config/visualizations/*.xml
static/welcome.html.*
static/welcome.html
@@ -82,6 +82,9 @@
# Test output
run_functional_tests.html
test/tool_shed/tmp/*
+.coverage
+htmlcov
+run_unit_tests.html
# Project files
*.kpf
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 README.txt
--- a/README.txt
+++ b/README.txt
@@ -7,7 +7,7 @@
HOW TO START
============
-Galaxy requires Python 2.5, 2.6 or 2.7. To check your python version, run:
+Galaxy requires Python 2.6 or 2.7. To check your python version, run:
% python -V
Python 2.7.3
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 buildbot_setup.sh
--- a/buildbot_setup.sh
+++ b/buildbot_setup.sh
@@ -65,6 +65,7 @@
"
SAMPLES="
+tool_conf.xml.sample
datatypes_conf.xml.sample
universe_wsgi.ini.sample
tool_data_table_conf.xml.sample
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 config/visualizations/circster.xml.sample
--- /dev/null
+++ b/config/visualizations/circster.xml.sample
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE visualization SYSTEM "visualization.dtd">
+<visualization name="circster">
+ <data_sources>
+ <data_source>
+ <model_class>HistoryDatasetAssociation</model_class>
+ <test type="isinstance" test_attr="datatype" result_type="datatype">data.Data</test>
+ <to_param param_attr="id">dataset_id</to_param>
+ <to_param assign="hda">hda_ldda</to_param>
+ </data_source>
+ <data_source>
+ <model_class>LibraryDatasetDatasetAssociation</model_class>
+ <test type="isinstance" test_attr="datatype" result_type="datatype">data.Data</test>
+ <to_param param_attr="id">dataset_id</to_param>
+ <to_param assign="ldda">hda_ldda</to_param>
+ </data_source>
+ </data_sources>
+ <params>
+ <param type="visualization">id</param>
+ <param type="hda_or_ldda">dataset_id</param>
+ <param_modifier type="string" modifies="dataset_id">hda_ldda</param_modifier>
+ <param type="dbkey">dbkey</param>
+ </params>
+ <template>circster.mako</template>
+ <render_location>_top</render_location>
+</visualization>
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 config/visualizations/phyloviz.xml.sample
--- /dev/null
+++ b/config/visualizations/phyloviz.xml.sample
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE visualization SYSTEM "visualization.dtd">
+<visualization name="phyloviz">
+ <data_sources>
+ <data_source>
+ <model_class>HistoryDatasetAssociation</model_class>
+ <test type="isinstance" test_attr="datatype" result_type="datatype">data.Newick</test>
+ <test type="isinstance" test_attr="datatype" result_type="datatype">data.Nexus</test>
+ <to_param param_attr="id">dataset_id</to_param>
+ </data_source>
+ </data_sources>
+ <params>
+ <param type="dataset" var_name_in_template="hda" required="true">dataset_id</param>
+ <param type="integer" default="0">tree_index</param>
+ </params>
+ <template>phyloviz.mako</template>
+ <render_location>_top</render_location>
+</visualization>
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 config/visualizations/scatterplot.xml.sample
--- /dev/null
+++ b/config/visualizations/scatterplot.xml.sample
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE visualization SYSTEM "visualization.dtd">
+<visualization name="scatterplot">
+ <data_sources>
+ <data_source>
+ <model_class>HistoryDatasetAssociation</model_class>
+ <test type="isinstance" test_attr="datatype" result_type="datatype">tabular.Tabular</test>
+ <to_param param_attr="id">dataset_id</to_param>
+ </data_source>
+ </data_sources>
+ <params>
+ <param type="dataset" var_name_in_template="hda" required="true">dataset_id</param>
+ </params>
+ <template>scatterplot.mako</template>
+</visualization>
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 config/visualizations/sweepster.xml.sample
--- /dev/null
+++ b/config/visualizations/sweepster.xml.sample
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE visualization SYSTEM "visualization.dtd">
+<visualization name="sweepster">
+ <data_sources>
+ <data_source>
+ <model_class>HistoryDatasetAssociation</model_class>
+ <test type="isinstance" test_attr="datatype" result_type="datatype">data.Data</test>
+ <to_param param_attr="id">dataset_id</to_param>
+ <to_param assign="hda">hda_ldda</to_param>
+ </data_source>
+ <data_source>
+ <model_class>LibraryDatasetDatasetAssociation</model_class>
+ <test type="isinstance" test_attr="datatype" result_type="datatype">data.Data</test>
+ <to_param param_attr="id">dataset_id</to_param>
+ <to_param assign="ldda">hda_ldda</to_param>
+ </data_source>
+ </data_sources>
+ <params>
+ <param type="visualization" var_name_in_template="viz">visualization</param>
+ <param type="hda_or_ldda" var_name_in_template="dataset">dataset_id</param>
+ <param_modifier type="string" modifies="dataset_id">hda_ldda</param_modifier>
+ </params>
+ <template>sweepster.mako</template>
+ <render_location>_top</render_location>
+</visualization>
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 config/visualizations/trackster.xml.sample
--- /dev/null
+++ b/config/visualizations/trackster.xml.sample
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE visualization SYSTEM "visualization.dtd">
+<visualization name="trackster">
+ <!--not tested yet -->
+ <data_sources>
+ <data_source>
+ <model_class>HistoryDatasetAssociation</model_class>
+ <test type="isinstance" test_attr="datatype" result_type="datatype">data.Data</test>
+ <to_param param_attr="id">dataset_id</to_param>
+ <to_param assign="hda">hda_ldda</to_param>
+ <to_param param_attr="dbkey">dbkey</to_param>
+ </data_source>
+ <data_source>
+ <model_class>LibraryDatasetDatasetAssociation</model_class>
+ <test type="isinstance" test_attr="datatype" result_type="datatype">data.Data</test>
+ <to_param param_attr="id">dataset_id</to_param>
+ <to_param assign="ldda">hda_ldda</to_param>
+ </data_source>
+ </data_sources>
+ <params>
+ <param type="visualization">id</param>
+ <param type="dataset">dataset_id</param>
+ <param type="genome_region">genome_region</param>
+ <param type="dbkey">dbkey</param>
+ </params>
+ <template_root>tracks</template_root>
+ <template>browser.mako</template>
+ <render_location>_top</render_location>
+</visualization>
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 config/visualizations/visualization.dtd
--- /dev/null
+++ b/config/visualizations/visualization.dtd
@@ -0,0 +1,132 @@
+<!-- runnable on NIX with xmllint -->
+
+<!-- each visualization must have a template (all other elements are optional) -->
+<!ELEMENT visualization (data_sources*,params*,template_root*,template,link_text*,render_location*)>
+<!-- visualization name (e.g. 'trackster', 'scatterplot', etc.) is required -->
+<!ATTLIST visualization
+ name CDATA #REQUIRED
+>
+
+<!ELEMENT data_sources (data_source*)>
+<!-- data sources are elements that describe what objects (HDAs, LDDAs, Job, User, etc.)
+ are applicable to a visualization. Often these are used to fetch applicable links
+ to the visualizations that use them.
+-->
+ <!ELEMENT data_source (model_class,(test|to_param)*)>
+ <!ELEMENT model_class (#PCDATA)>
+ <!-- model_class is currently the class name of the object you want to make a visualization
+ applicable to (e.g. HistoryDatasetAssociation). Currently only classes in galaxy.model
+ can be used.
+ REQUIRED and currently limited to: 'HistoryDatasetAssociation', 'LibraryDatasetDatasetAssociation'
+ -->
+ <!ELEMENT test (#PCDATA)>
+ <!-- tests help define what conditions the visualization can be applied to the model_class/target.
+ Currently, all tests are OR'd and there is no logical grouping. Tests are run in order.
+ (text): the text of this element is what the given target will be compared to (REQUIRED)
+ type: what type of test to run (e.g. when the target is an HDA the test will often be of type 'isinstance'
+ and test whether the HDA's datatype isinstace of a class)
+ DEFAULT: string comparison.
+ test_attr: what attribute of the target object should be used in the test. For instance, 'datatype'
+ will attempt to get the HDA.datatype from a target HDA. If the given object doesn't have
+ that attribute the test will fail (with no error). test_attr can be dot separated attributes,
+ looking up each in turn. For example, if the target was a history, one could access the
+ history.user.email by setting test_attr to 'user.email' (why you would want that, I don't know)
+ DEFAULT: to comparing the object itself (and not any of it's attributes)
+ result_type: if the result (the text of the element mentioned above) needs to be parsed into
+ something other than a string, result_type will tell the registry how to do this. E.g.
+ if result_type is 'datatype' the registry will assume the text is a datatype class name
+ and parse it into the proper class before the test (often 'isinstance') is run.
+ DEFAULT: no parsing (result should be a string)
+ -->
+ <!ATTLIST test
+ type CDATA #IMPLIED
+ test_attr CDATA #IMPLIED
+ result_type CDATA #IMPLIED
+ >
+
+ <!ELEMENT to_param (#PCDATA)>
+ <!-- to_param tells the registry how to parse the data_source into a query string param.
+ For example, HDA data_sources can set param_to text to 'dataset_id' and param_attr to 'id' and the
+ the target HDA (if it passes the tests) will be passed as "dataset_id=HDA.id"
+ (text): the query string param key this source will be parsed into (e.g. dataset_id)
+ REQUIRED
+ param_attr: the attribute of the data_source object to use as the value in the query string param.
+ E.g. param_attr='id' for an HDA data_source would use the (encoded) id.
+ NOTE: a to_param MUST have either a param_attr or assign
+ assign: you can use this to directly assign a value to a query string's param. E.g. if the
+ data_source is a LDDA we can set 'hda_or_ldda=ldda' using assign='ldda'.
+ NOTE: a to_param MUST have either a param_attr or assign
+ -->
+ <!ATTLIST to_param
+ param_attr CDATA #IMPLIED
+ assign CDATA #IMPLIED
+ >
+
+<!ELEMENT params ((param|param_modifier)*)>
+<!-- params describe what data will be sent to a visualization template and
+ how to convert them from a query string in a URL into variables usable in a template.
+ For example,
+ param_modifiers are a special class of parameters that modify other params
+ (e.g. hda_ldda can be 'hda' or 'ldda' and modifies/informs dataset_id to fetch an HDA or LDDA)
+-->
+ <!ELEMENT param (#PCDATA)>
+ <!-- param tells the registry how to parse the query string param back into a resource/data_source.
+ For example, if a query string has "dataset_id=NNN" and the type is 'dataset', the registry
+ will attempt to fetch the hda with id of NNN from the database and pass it to the template.
+ (text): the query string param key this source will be parsed from (e.g. dataset_id)
+ REQUIRED
+ type: the type of the resource.
+ Can be: str (DEFAULT), bool, int, float, json, visualization, dbkey, dataset, or hda_ldda.
+ default: if a param is not passed on the query string (and is not required) OR the given param
+ fails to parse, this value is used instead.
+ DEFAULT: None
+ required: set this to true if the param is required for the template. Rendering will with an error
+ if the param hasn't been sent.
+ DEFAULT: false
+ csv: set this to true if the param is a comma separated list. The registry will attempt to
+ parse each value as the given type and send the result as a list to the template.
+ DEFAULT: false
+ constrain_to: (currently unused) constain a param to a set of values, error if not valid.
+ DEFAULT: don't constrain
+ var_name_in_template: a new name for the resource/variable to use in the template. E.g. an initial
+ query string param key might be 'dataset_id' in the URL, the registry parses it into an HDA,
+ and if var_name_in_template is set to 'hda', the template will be able to access the HDA
+ with the variable name 'hda' (as in hda.title).
+ DEFAULT: keep the original query string name
+ -->
+ <!ATTLIST param
+ type CDATA #IMPLIED
+ default CDATA #IMPLIED
+ required CDATA #IMPLIED
+ csv CDATA #IMPLIED
+ constrain_to CDATA #IMPLIED
+ var_name_in_template CDATA #IMPLIED
+ >
+ <!-- param_modifiers are the same as param but have a REQUIRED 'modifies' attribute.
+ 'modifies' must point to the param name (the text part of param element) that it will modify.
+ E.g. <param_modifier modifies="dataset_id">hda_ldda</param_modifier>
+ -->
+ <!ELEMENT param_modifier (#PCDATA)>
+ <!ATTLIST param_modifier
+ modifies CDATA #REQUIRED
+ type CDATA #IMPLIED
+ default CDATA #IMPLIED
+ required CDATA #IMPLIED
+ csv CDATA #IMPLIED
+ constrain_to CDATA #IMPLIED
+ var_name_in_template CDATA #IMPLIED
+ >
+
+<!-- template_root: the directory to search for the template relative to templates/webapps/galaxy
+ (optional) DEFAULT: visualizations
+-->
+<!ELEMENT template_root (#PCDATA)>
+<!-- template: the template used to render the visualization. REQUIRED -->
+<!ELEMENT template (#PCDATA)>
+<!-- link_text: the text component of an html anchor displayed when the registry builds the link information -->
+<!ELEMENT link_text (#PCDATA)>
+<!-- render_location: used as the target attribute of the link to the visualization.
+ Can be 'galaxy_main', '_top', '_blank'. DEFAULT: 'galaxy_main'
+-->
+<!-- TODO: rename -> render_target -->
+<!ELEMENT render_location (#PCDATA)>
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 eggs.ini
--- a/eggs.ini
+++ b/eggs.ini
@@ -19,7 +19,7 @@
mercurial = 2.2.3
MySQL_python = 1.2.3c1
numpy = 1.6.0
-pbs_python = 4.1.0
+pbs_python = 4.3.5
psycopg2 = 2.0.13
pycrypto = 2.5
pysam = 0.4.2
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 job_conf.xml.sample_advanced
--- a/job_conf.xml.sample_advanced
+++ b/job_conf.xml.sample_advanced
@@ -54,7 +54,15 @@
<param id="shell_hostname">foo.example.org</param><param id="Job_Execution_Time">24:00:00</param></destination>
- <destination id="condor" runner="condor"/>
+ <destination id="condor" runner="condor">
+ <!-- With no params, jobs are submitted to the 'vanilla' universe with:
+ notification = NEVER
+ getenv = true
+ Additional/override query ClassAd params can be specified with
+ <param> tags.
+ -->
+ <param id="request_cpus">8</param>
+ </destination></destinations><tools><!-- Tools can be configured to use specific destinations or handlers,
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 lib/galaxy/actions/admin.py
--- a/lib/galaxy/actions/admin.py
+++ b/lib/galaxy/actions/admin.py
@@ -4,7 +4,7 @@
import logging
from galaxy import util
-from galaxy.exceptions import MessageException
+from galaxy.exceptions import ActionInputError
log = logging.getLogger( __name__ )
@@ -21,21 +21,21 @@
except AssertionError:
create_amount = False
if not params.name or not params.description:
- raise MessageException( "Enter a valid name and a description.", type='error' )
+ raise ActionInputError( "Enter a valid name and a description." )
elif self.sa_session.query( self.app.model.Quota ).filter( self.app.model.Quota.table.c.name==params.name ).first():
- raise MessageException( "Quota names must be unique and a quota with that name already exists, so choose another name.", type='error' )
+ raise ActionInputError( "Quota names must be unique and a quota with that name already exists, so choose another name." )
elif not params.get( 'amount', None ):
- raise MessageException( "Enter a valid quota amount.", type='error' )
+ raise ActionInputError( "Enter a valid quota amount." )
elif create_amount is False:
- raise MessageException( "Unable to parse the provided amount.", type='error' )
+ raise ActionInputError( "Unable to parse the provided amount." )
elif params.operation not in self.app.model.Quota.valid_operations:
- raise MessageException( "Enter a valid operation.", type='error' )
+ raise ActionInputError( "Enter a valid operation." )
elif params.default != 'no' and params.default not in self.app.model.DefaultQuotaAssociation.types.__dict__.values():
- raise MessageException( "Enter a valid default type.", type='error' )
+ raise ActionInputError( "Enter a valid default type." )
elif params.default != 'no' and params.operation != '=':
- raise MessageException( "Operation for a default quota must be '='.", type='error' )
+ raise ActionInputError( "Operation for a default quota must be '='." )
elif create_amount is None and params.operation != '=':
- raise MessageException( "Operation for an unlimited quota must be '='.", type='error' )
+ raise ActionInputError( "Operation for an unlimited quota must be '='." )
else:
# Create the quota
quota = self.app.model.Quota( name=params.name, description=params.description, amount=create_amount, operation=params.operation )
@@ -59,9 +59,9 @@
def _rename_quota( self, quota, params ):
if not params.name:
- raise MessageException( 'Enter a valid name', type='error' )
+ raise ActionInputError( 'Enter a valid name' )
elif params.name != quota.name and self.sa_session.query( self.app.model.Quota ).filter( self.app.model.Quota.table.c.name==params.name ).first():
- raise MessageException( 'A quota with that name already exists', type='error' )
+ raise ActionInputError( 'A quota with that name already exists' )
else:
old_name = quota.name
quota.name = params.name
@@ -73,7 +73,7 @@
def _manage_users_and_groups_for_quota( self, quota, params ):
if quota.default:
- raise MessageException( 'Default quotas cannot be associated with specific users and groups', type='error' )
+ raise ActionInputError( 'Default quotas cannot be associated with specific users and groups' )
else:
in_users = [ self.sa_session.query( self.app.model.User ).get( x ) for x in util.listify( params.in_users ) ]
in_groups = [ self.sa_session.query( self.app.model.Group ).get( x ) for x in util.listify( params.in_groups ) ]
@@ -91,11 +91,11 @@
except AssertionError:
new_amount = False
if not params.amount:
- raise MessageException( 'Enter a valid amount', type='error' )
+ raise ActionInputError( 'Enter a valid amount' )
elif new_amount is False:
- raise MessageException( 'Unable to parse the provided amount', type='error' )
+ raise ActionInputError( 'Unable to parse the provided amount' )
elif params.operation not in self.app.model.Quota.valid_operations:
- raise MessageException( 'Enter a valid operation', type='error' )
+ raise ActionInputError( 'Enter a valid operation' )
else:
quota.amount = new_amount
quota.operation = params.operation
@@ -106,7 +106,7 @@
def _set_quota_default( self, quota, params ):
if params.default != 'no' and params.default not in self.app.model.DefaultQuotaAssociation.types.__dict__.values():
- raise MessageException( 'Enter a valid default type.', type='error' )
+ raise ActionInputError( 'Enter a valid default type.' )
else:
if params.default != 'no':
self.app.quota_agent.set_default_quota( params.default, quota )
@@ -123,7 +123,7 @@
def _unset_quota_default( self, quota, params ):
if not quota.default:
- raise MessageException( "Quota '%s' is not a default." % quota.name, type='error' )
+ raise ActionInputError( "Quota '%s' is not a default." % quota.name )
else:
message = "Quota '%s' is no longer the default for %s users." % ( quota.name, quota.default[0].type )
for dqa in quota.default:
@@ -138,9 +138,9 @@
if q.default:
names.append( q.name )
if len( names ) == 1:
- raise MessageException( "Quota '%s' is a default, please unset it as a default before deleting it" % ( names[0] ), type='error' )
+ raise ActionInputError( "Quota '%s' is a default, please unset it as a default before deleting it" % ( names[0] ) )
elif len( names ) > 1:
- raise MessageException( "Quotas are defaults, please unset them as defaults before deleting them: " + ', '.join( names ), type='error' )
+ raise ActionInputError( "Quotas are defaults, please unset them as defaults before deleting them: " + ', '.join( names ) )
message = "Deleted %d quotas: " % len( quotas )
for q in quotas:
q.deleted = True
@@ -157,9 +157,9 @@
if not q.deleted:
names.append( q.name )
if len( names ) == 1:
- raise MessageException( "Quota '%s' has not been deleted, so it cannot be undeleted." % ( names[0] ), type='error' )
+ raise ActionInputError( "Quota '%s' has not been deleted, so it cannot be undeleted." % ( names[0] ) )
elif len( names ) > 1:
- raise MessageException( "Quotas have not been deleted so they cannot be undeleted: " + ', '.join( names ), type='error' )
+ raise ActionInputError( "Quotas have not been deleted so they cannot be undeleted: " + ', '.join( names ) )
message = "Undeleted %d quotas: " % len( quotas )
for q in quotas:
q.deleted = False
@@ -182,9 +182,9 @@
if not q.deleted:
names.append( q.name )
if len( names ) == 1:
- raise MessageException( "Quota '%s' has not been deleted, so it cannot be purged." % ( names[0] ), type='error' )
+ raise ActionInputError( "Quota '%s' has not been deleted, so it cannot be purged." % ( names[0] ) )
elif len( names ) > 1:
- raise MessageException( "Quotas have not been deleted so they cannot be undeleted: " + ', '.join( names ), type='error' )
+ raise ActionInputError( "Quotas have not been deleted so they cannot be undeleted: " + ', '.join( names ) )
message = "Purged %d quotas: " % len( quotas )
for q in quotas:
# Delete UserQuotaAssociations
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 lib/galaxy/app.py
--- a/lib/galaxy/app.py
+++ b/lib/galaxy/app.py
@@ -54,7 +54,7 @@
from tool_shed.galaxy_install.migrate.check import verify_tools
verify_tools( self, db_url, kwargs.get( 'global_conf', {} ).get( '__file__', None ), self.config.database_engine_options )
# Object store manager
- self.object_store = build_object_store_from_config(self.config)
+ self.object_store = build_object_store_from_config(self.config, fsmon=True)
# Setup the database engine and ORM
from galaxy.model import mapping
self.model = mapping.init( self.config.file_path,
@@ -92,7 +92,7 @@
# Load additional entries defined by self.config.shed_tool_data_table_config into tool data tables.
self.tool_data_tables.load_from_config_file( config_filename=self.config.shed_tool_data_table_config,
tool_data_path=self.tool_data_tables.tool_data_path,
- from_shed_config=True )
+ from_shed_config=False )
# Initialize the job management configuration
self.job_config = jobs.JobConfiguration(self)
# Initialize the tools, making sure the list of tool configs includes the reserved migrated_tools_conf.xml file.
@@ -123,8 +123,10 @@
# Load genome indexer tool.
load_genome_index_tools( self.toolbox )
# visualizations registry: associates resources with visualizations, controls how to render
- self.visualizations_registry = ( VisualizationsRegistry( self.config.root, self.config.visualizations_conf_path )
- if self.config.visualizations_conf_path else None )
+ self.visualizations_registry = None
+ if self.config.visualizations_config_directory:
+ self.visualizations_registry = VisualizationsRegistry( self.config.root,
+ self.config.visualizations_config_directory )
# Load security policy.
self.security_agent = self.model.security_agent
self.host_security_agent = galaxy.security.HostAgent( model=self.security_agent.model, permitted_actions=self.security_agent.permitted_actions )
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -64,21 +64,33 @@
tcf = kwargs[ 'tool_config_files' ]
else:
tcf = 'tool_conf.xml'
+ self.tool_filters = listify( kwargs.get( "tool_filters", [] ) )
+ self.tool_label_filters = listify( kwargs.get( "tool_label_filters", [] ) )
+ self.tool_section_filters = listify( kwargs.get( "tool_section_filters", [] ) )
self.tool_configs = [ resolve_path( p, self.root ) for p in listify( tcf ) ]
+ self.shed_tool_data_path = kwargs.get( "shed_tool_data_path", None )
+ if self.shed_tool_data_path:
+ self.shed_tool_data_path = resolve_path( self.shed_tool_data_path, self.root )
+ else:
+ self.shed_tool_data_path = self.tool_data_path
self.tool_data_table_config_path = resolve_path( kwargs.get( 'tool_data_table_config_path', 'tool_data_table_conf.xml' ), self.root )
self.shed_tool_data_table_config = resolve_path( kwargs.get( 'shed_tool_data_table_config', 'shed_tool_data_table_conf.xml' ), self.root )
self.enable_tool_shed_check = string_as_bool( kwargs.get( 'enable_tool_shed_check', False ) )
+ self.hours_between_check = kwargs.get( 'hours_between_check', 12 )
try:
- self.hours_between_check = kwargs.get( 'hours_between_check', 12 )
- if isinstance( self.hours_between_check, float ):
+ hbc_test = int( self.hours_between_check )
+ self.hours_between_check = hbc_test
+ if self.hours_between_check < 1 or self.hours_between_check > 24:
+ self.hours_between_check = 12
+ except:
+ try:
# Float values are supported for functional tests.
+ hbc_test = float( self.hours_between_check )
+ self.hours_between_check = hbc_test
if self.hours_between_check < 0.001 or self.hours_between_check > 24.0:
self.hours_between_check = 12.0
- else:
- if self.hours_between_check < 1 or self.hours_between_check > 24:
- self.hours_between_check = 12
- except:
- self.hours_between_check = 12
+ except:
+ self.hours_between_check = 12
self.update_integrated_tool_panel = kwargs.get( "update_integrated_tool_panel", True )
self.enable_data_manager_user_view = string_as_bool( kwargs.get( "enable_data_manager_user_view", "False" ) )
self.data_manager_config_file = resolve_path( kwargs.get('data_manager_config_file', 'data_manager_conf.xml' ), self.root )
@@ -154,6 +166,7 @@
self.ucsc_display_sites = kwargs.get( 'ucsc_display_sites', "main,test,archaea,ucla" ).lower().split(",")
self.gbrowse_display_sites = kwargs.get( 'gbrowse_display_sites', "modencode,sgd_yeast,tair,wormbase,wormbase_ws120,wormbase_ws140,wormbase_ws170,wormbase_ws180,wormbase_ws190,wormbase_ws200,wormbase_ws204,wormbase_ws210,wormbase_ws220,wormbase_ws225" ).lower().split(",")
self.brand = kwargs.get( 'brand', None )
+ self.welcome_url = kwargs.get( 'welcome_url', '/static/welcome.html' )
# Configuration for the message box directly below the masthead.
self.message_box_visible = kwargs.get( 'message_box_visible', False )
self.message_box_content = kwargs.get( 'message_box_content', None )
@@ -276,8 +289,8 @@
self.fluent_log = string_as_bool( kwargs.get( 'fluent_log', False ) )
self.fluent_host = kwargs.get( 'fluent_host', 'localhost' )
self.fluent_port = int( kwargs.get( 'fluent_port', 24224 ) )
- # visualizations registry config path
- self.visualizations_conf_path = kwargs.get( 'visualizations_conf_path', None )
+ # visualization registries config directory
+ self.visualizations_config_directory = kwargs.get( 'visualizations_config_directory', None )
@property
def sentry_dsn_public( self ):
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 lib/galaxy/datatypes/binary.py
--- a/lib/galaxy/datatypes/binary.py
+++ b/lib/galaxy/datatypes/binary.py
@@ -22,6 +22,7 @@
from galaxy.datatypes.metadata import MetadataElement
from galaxy.datatypes import metadata
from galaxy.datatypes.sniff import *
+import dataproviders
log = logging.getLogger(__name__)
@@ -74,6 +75,7 @@
trans.response.headers["Content-Disposition"] = 'attachment; filename="Galaxy%s-[%s].%s"' % (dataset.hid, fname, to_ext)
return open( dataset.file_name )
+
class Ab1( Binary ):
"""Class describing an ab1 binary sequence file"""
file_ext = "ab1"
@@ -93,12 +95,15 @@
Binary.register_unsniffable_binary_ext("ab1")
+
class GenericAsn1Binary( Binary ):
"""Class for generic ASN.1 binary format"""
file_ext = "asn1-binary"
Binary.register_unsniffable_binary_ext("asn1-binary")
+
+(a)dataproviders.decorators.has_dataproviders
class Bam( Binary ):
"""Class describing a BAM binary file"""
file_ext = "bam"
@@ -255,9 +260,92 @@
return dataset.peek
except:
return "Binary bam alignments file (%s)" % ( data.nice_size( dataset.get_size() ) )
+
+ # ------------- Dataproviders
+ # pipe through samtools view
+ #ALSO: (as Sam)
+ # bam does not use '#' to indicate comments/headers - we need to strip out those headers from the std. providers
+ #TODO:?? seems like there should be an easier way to do/inherit this - metadata.comment_char?
+ #TODO: incorporate samtools options to control output: regions first, then flags, etc.
+ @dataproviders.decorators.dataprovider_factory( 'line', dataproviders.line.FilteredLineDataProvider.settings )
+ def line_dataprovider( self, dataset, **settings ):
+ samtools_source = dataproviders.dataset.SamtoolsDataProvider( dataset )
+ settings[ 'comment_char' ] = '@'
+ return dataproviders.line.FilteredLineDataProvider( samtools_source, **settings )
+
+ @dataproviders.decorators.dataprovider_factory( 'regex-line', dataproviders.line.RegexLineDataProvider.settings )
+ def regex_line_dataprovider( self, dataset, **settings ):
+ samtools_source = dataproviders.dataset.SamtoolsDataProvider( dataset )
+ settings[ 'comment_char' ] = '@'
+ return dataproviders.line.RegexLineDataProvider( samtools_source, **settings )
+ @dataproviders.decorators.dataprovider_factory( 'column', dataproviders.column.ColumnarDataProvider.settings )
+ def column_dataprovider( self, dataset, **settings ):
+ samtools_source = dataproviders.dataset.SamtoolsDataProvider( dataset )
+ settings[ 'comment_char' ] = '@'
+ return dataproviders.column.ColumnarDataProvider( samtools_source, **settings )
+
+ @dataproviders.decorators.dataprovider_factory( 'dict', dataproviders.column.DictDataProvider.settings )
+ def dict_dataprovider( self, dataset, **settings ):
+ samtools_source = dataproviders.dataset.SamtoolsDataProvider( dataset )
+ settings[ 'comment_char' ] = '@'
+ return dataproviders.column.DictDataProvider( samtools_source, **settings )
+
+ # these can't be used directly - may need BamColumn, BamDict (Bam metadata -> column/dict)
+ # OR - see genomic_region_dataprovider
+ #(a)dataproviders.decorators.dataprovider_factory( 'dataset-column', dataproviders.column.ColumnarDataProvider.settings )
+ #def dataset_column_dataprovider( self, dataset, **settings ):
+ # settings[ 'comment_char' ] = '@'
+ # return super( Sam, self ).dataset_column_dataprovider( dataset, **settings )
+
+ #(a)dataproviders.decorators.dataprovider_factory( 'dataset-dict', dataproviders.column.DictDataProvider.settings )
+ #def dataset_dict_dataprovider( self, dataset, **settings ):
+ # settings[ 'comment_char' ] = '@'
+ # return super( Sam, self ).dataset_dict_dataprovider( dataset, **settings )
+
+ @dataproviders.decorators.dataprovider_factory( 'header', dataproviders.line.RegexLineDataProvider.settings )
+ def header_dataprovider( self, dataset, **settings ):
+ # in this case we can use an option of samtools view to provide just what we need (w/o regex)
+ samtools_source = dataproviders.dataset.SamtoolsDataProvider( dataset, '-H' )
+ return dataproviders.line.RegexLineDataProvider( samtools_source, **settings )
+
+ @dataproviders.decorators.dataprovider_factory( 'id-seq-qual', dataproviders.column.DictDataProvider.settings )
+ def id_seq_qual_dataprovider( self, dataset, **settings ):
+ settings[ 'indeces' ] = [ 0, 9, 10 ]
+ settings[ 'column_types' ] = [ 'str', 'str', 'str' ]
+ settings[ 'column_names' ] = [ 'id', 'seq', 'qual' ]
+ return self.dict_dataprovider( dataset, **settings )
+
+ @dataproviders.decorators.dataprovider_factory( 'genomic-region', dataproviders.column.ColumnarDataProvider.settings )
+ def genomic_region_dataprovider( self, dataset, **settings ):
+ # GenomicRegionDataProvider currently requires a dataset as source - may not be necc.
+ #TODO:?? consider (at least) the possible use of a kwarg: metadata_source (def. to source.dataset),
+ # or remove altogether...
+ #samtools_source = dataproviders.dataset.SamtoolsDataProvider( dataset )
+ #return dataproviders.dataset.GenomicRegionDataProvider( samtools_source, metadata_source=dataset,
+ # 2, 3, 3, **settings )
+
+ # instead, set manually and use in-class column gen
+ settings[ 'indeces' ] = [ 2, 3, 3 ]
+ settings[ 'column_types' ] = [ 'str', 'int', 'int' ]
+ return self.column_dataprovider( dataset, **settings )
+
+ @dataproviders.decorators.dataprovider_factory( 'genomic-region-dict', dataproviders.column.DictDataProvider.settings )
+ def genomic_region_dict_dataprovider( self, dataset, **settings ):
+ settings[ 'indeces' ] = [ 2, 3, 3 ]
+ settings[ 'column_types' ] = [ 'str', 'int', 'int' ]
+ settings[ 'column_names' ] = [ 'chrom', 'start', 'end' ]
+ return self.dict_dataprovider( dataset, **settings )
+
+ @dataproviders.decorators.dataprovider_factory( 'samtools' )
+ def samtools_dataprovider( self, dataset, **settings ):
+ """Generic samtools interface - all options available through settings."""
+ dataset_source = dataproviders.dataset.DatasetDataProvider( dataset )
+ return dataproviders.dataset.SamtoolsDataProvider( dataset_source, **settings )
+
Binary.register_sniffable_binary_format("bam", "bam", Bam)
+
class H5( Binary ):
"""Class describing an HDF5 file"""
file_ext = "h5"
@@ -277,6 +365,7 @@
Binary.register_unsniffable_binary_ext("h5")
+
class Scf( Binary ):
"""Class describing an scf binary sequence file"""
file_ext = "scf"
@@ -296,6 +385,7 @@
Binary.register_unsniffable_binary_ext("scf")
+
class Sff( Binary ):
""" Standard Flowgram Format (SFF) """
file_ext = "sff"
@@ -327,6 +417,7 @@
Binary.register_sniffable_binary_format("sff", "sff", Sff)
+
class BigWig(Binary):
"""
Accessing binary BigWig files from UCSC.
@@ -363,6 +454,7 @@
Binary.register_sniffable_binary_format("bigwig", "bigwig", BigWig)
+
class BigBed(BigWig):
"""BigBed support from UCSC."""
@@ -375,6 +467,7 @@
Binary.register_sniffable_binary_format("bigbed", "bigbed", BigBed)
+
class TwoBit (Binary):
"""Class describing a TwoBit format nucleotide file"""
@@ -399,3 +492,5 @@
return dataset.peek
except:
return "Binary TwoBit format nucleotide file (%s)" % (data.nice_size(dataset.get_size()))
+
+Binary.register_sniffable_binary_format("twobit", "twobit", TwoBit)
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 lib/galaxy/datatypes/converters/bam_to_bigwig_converter.xml
--- a/lib/galaxy/datatypes/converters/bam_to_bigwig_converter.xml
+++ b/lib/galaxy/datatypes/converters/bam_to_bigwig_converter.xml
@@ -1,5 +1,9 @@
<tool id="CONVERTER_bam_to_bigwig_0" name="Convert BAM to BigWig" version="1.0.0" hidden="true"><!-- <description>__NOT_USED_CURRENTLY_FOR_CONVERTERS__</description> -->
+ <requirements>
+ <requirement type="package">ucsc_tools</requirement>
+ <requirement type="package">bedtools</requirement>
+ </requirements><command>
bedtools genomecov -bg -split -ibam $input -g $chromInfo
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 lib/galaxy/datatypes/converters/bed_gff_or_vcf_to_bigwig_converter.xml
--- a/lib/galaxy/datatypes/converters/bed_gff_or_vcf_to_bigwig_converter.xml
+++ b/lib/galaxy/datatypes/converters/bed_gff_or_vcf_to_bigwig_converter.xml
@@ -1,5 +1,9 @@
<tool id="CONVERTER_bed_gff_or_vcf_to_bigwig_0" name="Convert BED, GFF, or VCF to BigWig" version="1.0.0" hidden="true"><!-- <description>__NOT_USED_CURRENTLY_FOR_CONVERTERS__</description> -->
+ <requirements>
+ <requirement type="package">ucsc_tools</requirement>
+ <requirement type="package">bedtools</requirement>
+ </requirements><command>
## Remove comments and sort by chromosome.
grep -v '^#' $input | sort -k1,1 |
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 lib/galaxy/datatypes/converters/interval_to_bigwig_converter.xml
--- a/lib/galaxy/datatypes/converters/interval_to_bigwig_converter.xml
+++ b/lib/galaxy/datatypes/converters/interval_to_bigwig_converter.xml
@@ -1,6 +1,10 @@
<tool id="CONVERTER_interval_to_bigwig_0" name="Convert Genomic Intervals To Coverage"><!-- <description>__NOT_USED_CURRENTLY_FOR_CONVERTERS__</description> --><!-- Used on the metadata edit page. -->
+ <requirements>
+ <requirement type="package">ucsc_tools</requirement>
+ <requirement type="package">bedtools</requirement>
+ </requirements><command>
## Remove comments and sort by chromosome.
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 lib/galaxy/datatypes/converters/interval_to_interval_index_converter.py
--- a/lib/galaxy/datatypes/converters/interval_to_interval_index_converter.py
+++ b/lib/galaxy/datatypes/converters/interval_to_interval_index_converter.py
@@ -11,15 +11,13 @@
from __future__ import division
-import sys, fileinput, optparse
+import optparse
from galaxy import eggs
-import pkg_resources; pkg_resources.require( "bx-python" )
-from galaxy.visualization.tracks.summary import *
-from galaxy.datatypes.util.gff_util import convert_gff_coords_to_bed
+eggs.require( "bx-python" )
from bx.interval_index_file import Indexes
def main():
-
+
# Read options, args.
parser = optparse.OptionParser()
parser.add_option( '-c', '--chr-col', type='int', dest='chrom_col', default=1 )
@@ -27,12 +25,12 @@
parser.add_option( '-e', '--end-col', type='int', dest='end_col', default=3 )
(options, args) = parser.parse_args()
input_fname, output_fname = args
-
+
# Make column indices 0-based.
options.chrom_col -= 1
options.start_col -= 1
options.end_col -= 1
-
+
# Do conversion.
index = Indexes()
offset = 0
@@ -46,9 +44,9 @@
chrom_end = int( feature[ options.end_col ] )
index.add( chrom, chrom_start, chrom_end, offset )
offset += len(line)
-
+
index.write( open(output_fname, "w") )
-if __name__ == "__main__":
+if __name__ == "__main__":
main()
-
\ No newline at end of file
+
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 lib/galaxy/datatypes/converters/pileup_to_interval_index_converter.py
--- a/lib/galaxy/datatypes/converters/pileup_to_interval_index_converter.py
+++ b/lib/galaxy/datatypes/converters/pileup_to_interval_index_converter.py
@@ -8,20 +8,18 @@
from __future__ import division
-import sys, fileinput, optparse
+import optparse
from galaxy import eggs
-import pkg_resources; pkg_resources.require( "bx-python" )
-from galaxy.visualization.tracks.summary import *
-from galaxy.datatypes.util.gff_util import convert_gff_coords_to_bed
+eggs.require( "bx-python" )
from bx.interval_index_file import Indexes
def main():
-
+
# Read options, args.
parser = optparse.OptionParser()
(options, args) = parser.parse_args()
input_fname, output_fname = args
-
+
# Do conversion.
index = Indexes()
offset = 0
@@ -31,9 +29,9 @@
start = int( start ) - 1
index.add( chrom, start, start + 1, offset )
offset += len( line )
-
+
index.write( open(output_fname, "w") )
-if __name__ == "__main__":
+if __name__ == "__main__":
main()
-
\ No newline at end of file
+
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 lib/galaxy/datatypes/converters/sam_to_bigwig_converter.xml
--- a/lib/galaxy/datatypes/converters/sam_to_bigwig_converter.xml
+++ b/lib/galaxy/datatypes/converters/sam_to_bigwig_converter.xml
@@ -1,4 +1,9 @@
<tool id="CONVERTER_sam_to_bigwig_0" name="Convert SAM to BigWig" version="1.0.0" hidden="true">
+ <requirements>
+ <requirement type="package">ucsc_tools</requirement>
+ <requirement type="package">samtools</requirement>
+ <requirement type="package">bedtools</requirement>
+ </requirements><command>
samtools view -bh $input | bedtools genomecov -bg -split -ibam stdin -g $chromInfo
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 lib/galaxy/datatypes/data.py
--- a/lib/galaxy/datatypes/data.py
+++ b/lib/galaxy/datatypes/data.py
@@ -7,6 +7,7 @@
import tempfile
import zipfile
from cgi import escape
+from inspect import isclass
from galaxy import util
from galaxy.datatypes.metadata import MetadataElement #import directly to maintain ease of use in Datatype class definitions
from galaxy.util import inflector
@@ -14,6 +15,8 @@
from galaxy.util.odict import odict
from galaxy.util.sanitize_html import sanitize_html
+import dataproviders
+
from galaxy import eggs
eggs.require( "Paste" )
import paste
@@ -56,6 +59,7 @@
cls.metadata_spec.update( base.metadata_spec ) #add contents of metadata spec of base class to cls
metadata.Statement.process( cls )
+(a)dataproviders.decorators.has_dataproviders
class Data( object ):
"""
Base class for all datatypes. Implements basic interfaces as well
@@ -545,7 +549,13 @@
def has_resolution(self):
return False
-
+ def matches_any( self, target_datatypes ):
+ """
+ Check if this datatype is of any of the target_datatypes or is
+ a subtype thereof.
+ """
+ datatype_classes = tuple( [ datatype if isclass( datatype ) else datatype.__class__ for datatype in target_datatypes ] )
+ return isinstance( self, datatype_classes )
def merge( split_files, output_file):
"""
Merge files with copy.copyfileobj() will not hit the
@@ -572,6 +582,39 @@
return [ 'trackster', 'circster' ]
return []
+ # ------------- Dataproviders
+ def has_dataprovider( self, data_format ):
+ """
+ Returns True if `data_format` is available in `dataproviders`.
+ """
+ return ( data_format in self.dataproviders )
+
+ def dataprovider( self, dataset, data_format, **settings ):
+ """
+ Base dataprovider factory for all datatypes that returns the proper provider
+ for the given `data_format` or raises a `NoProviderAvailable`.
+ """
+ if self.has_dataprovider( data_format ):
+ return self.dataproviders[ data_format ]( self, dataset, **settings )
+ raise dataproviders.exceptions.NoProviderAvailable( self, data_format )
+
+ @dataproviders.decorators.dataprovider_factory( 'base' )
+ def base_dataprovider( self, dataset, **settings ):
+ dataset_source = dataproviders.dataset.DatasetDataProvider( dataset )
+ return dataproviders.base.DataProvider( dataset_source, **settings )
+
+ @dataproviders.decorators.dataprovider_factory( 'chunk', dataproviders.chunk.ChunkDataProvider.settings )
+ def chunk_dataprovider( self, dataset, **settings ):
+ dataset_source = dataproviders.dataset.DatasetDataProvider( dataset )
+ return dataproviders.chunk.ChunkDataProvider( dataset_source, **settings )
+
+ @dataproviders.decorators.dataprovider_factory( 'chunk64', dataproviders.chunk.Base64ChunkDataProvider.settings )
+ def chunk64_dataprovider( self, dataset, **settings ):
+ dataset_source = dataproviders.dataset.DatasetDataProvider( dataset )
+ return dataproviders.chunk.Base64ChunkDataProvider( dataset_source, **settings )
+
+
+(a)dataproviders.decorators.has_dataproviders
class Text( Data ):
file_ext = 'txt'
line_class = 'line'
@@ -741,10 +784,31 @@
f.close()
split = classmethod(split)
+ # ------------- Dataproviders
+ @dataproviders.decorators.dataprovider_factory( 'line', dataproviders.line.FilteredLineDataProvider.settings )
+ def line_dataprovider( self, dataset, **settings ):
+ """
+ Returns an iterator over the dataset's lines (that have been `strip`ed)
+ optionally excluding blank lines and lines that start with a comment character.
+ """
+ dataset_source = dataproviders.dataset.DatasetDataProvider( dataset )
+ return dataproviders.line.FilteredLineDataProvider( dataset_source, **settings )
+
+ @dataproviders.decorators.dataprovider_factory( 'regex-line', dataproviders.line.RegexLineDataProvider.settings )
+ def regex_line_dataprovider( self, dataset, **settings ):
+ """
+ Returns an iterator over the dataset's lines
+ optionally including/excluding lines that match one or more regex filters.
+ """
+ dataset_source = dataproviders.dataset.DatasetDataProvider( dataset )
+ return dataproviders.line.RegexLineDataProvider( dataset_source, **settings )
+
+
class GenericAsn1( Text ):
"""Class for generic ASN.1 text format"""
file_ext = 'asn1'
+
class LineCount( Text ):
"""
Dataset contains a single line with a single integer that denotes the
@@ -752,6 +816,7 @@
"""
pass
+
class Newick( Text ):
"""New Hampshire/Newick Format"""
file_ext = "nhx"
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 lib/galaxy/datatypes/dataproviders/__init__.py
--- /dev/null
+++ b/lib/galaxy/datatypes/dataproviders/__init__.py
@@ -0,0 +1,28 @@
+
+#TODO: ---- This is a work in progress ----
+"""
+Dataproviders are iterators with context managers that provide data to some
+consumer datum by datum.
+
+As well as subclassing and overriding to get the proper data, Dataproviders
+can be piped from one to the other.
+..example::
+
+.. note:: be careful to NOT pipe providers into subclasses of those providers.
+ Subclasses provide all the functionality of their superclasses,
+ so there's generally no need.
+
+.. note:: be careful to when using piped providers that accept the same keywords
+ in their __init__ functions (such as limit or offset) to pass those
+ keywords to the proper (often final) provider. These errors that result
+ can be hard to diagnose.
+"""
+import decorators
+import exceptions
+
+import base
+import chunk
+import line
+import column
+import external
+import dataset
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 lib/galaxy/datatypes/dataproviders/base.py
--- /dev/null
+++ b/lib/galaxy/datatypes/dataproviders/base.py
@@ -0,0 +1,305 @@
+"""
+Base class(es) for all DataProviders.
+"""
+# there's a blurry line between functionality here and functionality in datatypes module
+# attempting to keep parsing to a minimum here and focus on chopping/pagination/reformat(/filtering-maybe?)
+# and using as much pre-computed info/metadata from the datatypes module as possible
+# also, this shouldn't be a replacement/re-implementation of the tool layer
+# (which provides traceability/versioning/reproducibility)
+
+from collections import deque
+import exceptions
+
+_TODO = """
+hooks into datatypes (define providers inside datatype modules) as factories
+capture tell() when provider is done
+ def stop( self ): self.endpoint = source.tell(); raise StopIteration()
+implement __len__ sensibly where it can be (would be good to have where we're giving some progress - '100 of 300')
+ seems like sniffed files would have this info
+unit tests
+add datum entry/exit point methods: possibly decode, encode
+ or create a class that pipes source through - how would decode work then?
+
+icorporate existing visualization/dataproviders
+some of the sources (esp. in datasets) don't need to be re-created
+YAGNI: InterleavingMultiSourceDataProvider, CombiningMultiSourceDataProvider
+
+datasets API entry point:
+ kwargs should be parsed from strings 2 layers up (in the DatasetsAPI) - that's the 'proper' place for that.
+ but how would it know how/what to parse if it doesn't have access to the classes used in the provider?
+ Building a giant list by sweeping all possible dprov classes doesn't make sense
+ For now - I'm burying them in the class __init__s - but I don't like that
+"""
+
+import logging
+log = logging.getLogger( __name__ )
+
+
+# ----------------------------------------------------------------------------- base classes
+class HasSettings( type ):
+ """
+ Metaclass for data providers that allows defining and inheriting
+ a dictionary named 'settings'.
+
+ Useful for allowing class level access to expected variable types
+ passed to class `__init__` functions so they can be parsed from a query string.
+ """
+ # yeah - this is all too acrobatic
+ def __new__( cls, name, base_classes, attributes ):
+ settings = {}
+ # get settings defined in base classes
+ for base_class in base_classes:
+ base_settings = getattr( base_class, 'settings', None )
+ if base_settings:
+ settings.update( base_settings )
+ # get settings defined in this class
+ new_settings = attributes.pop( 'settings', None )
+ if new_settings:
+ settings.update( new_settings )
+ attributes[ 'settings' ] = settings
+ return type.__new__( cls, name, base_classes, attributes )
+
+
+# ----------------------------------------------------------------------------- base classes
+class DataProvider( object ):
+ """
+ Base class for all data providers. Data providers:
+ (a) have a source (which must be another file-like object)
+ (b) implement both the iterator and context manager interfaces
+ (c) do not allow write methods
+ (but otherwise implement the other file object interface methods)
+ """
+ # a definition of expected types for keyword arguments sent to __init__
+ # useful for controlling how query string dictionaries can be parsed into correct types for __init__
+ # empty in this base class
+ __metaclass__ = HasSettings
+ settings = {}
+
+ def __init__( self, source, **kwargs ):
+ """
+ :param source: the source that this iterator will loop over.
+ (Should implement the iterable interface and ideally have the
+ context manager interface as well)
+ """
+ self.source = self.validate_source( source )
+
+ def validate_source( self, source ):
+ """
+ Is this a valid source for this provider?
+
+ :raises InvalidDataProviderSource: if the source is considered invalid.
+
+ Meant to be overridden in subclasses.
+ """
+ if not source or not hasattr( source, '__iter__' ):
+ # that's by no means a thorough check
+ raise exceptions.InvalidDataProviderSource( source )
+ return source
+
+ #TODO: (this might cause problems later...)
+ #TODO: some providers (such as chunk's seek and read) rely on this... remove
+ def __getattr__( self, name ):
+ if name == 'source':
+ # if we're inside this fn, source hasn't been set - provide some safety just for this attr
+ return None
+ # otherwise, try to get the attr from the source - allows us to get things like provider.encoding, etc.
+ if hasattr( self.source, name ):
+ return getattr( self.source, name )
+ # raise the proper error
+ return self.__getattribute__( name )
+
+ # write methods should not be allowed
+ def truncate( self, size ):
+ raise NotImplementedError( 'Write methods are purposely disabled' )
+ def write( self, string ):
+ raise NotImplementedError( 'Write methods are purposely disabled' )
+ def writelines( self, sequence ):
+ raise NotImplementedError( 'Write methods are purposely disabled' )
+
+ #TODO: route read methods through next?
+ #def readline( self ):
+ # return self.next()
+ def readlines( self ):
+ return [ line for line in self ]
+
+ # iterator interface
+ def __iter__( self ):
+ # it's generators all the way up, Timmy
+ with self as source:
+ for datum in self.source:
+ yield datum
+ def next( self ):
+ return self.source.next()
+
+ # context manager interface
+ def __enter__( self ):
+ # make the source's context manager interface optional
+ if hasattr( self.source, '__enter__' ):
+ self.source.__enter__()
+ return self
+ def __exit__( self, *args ):
+ # make the source's context manager interface optional, call on source if there
+ if hasattr( self.source, '__exit__' ):
+ self.source.__exit__( *args )
+ # alternately, call close()
+ elif hasattr( self.source, 'close' ):
+ self.source.close()
+
+ def __str__( self ):
+ """
+ String representation for easier debugging.
+
+ Will call `__str__` on it's source so this will display piped dataproviders.
+ """
+ # we need to protect against recursion (in __getattr__) if self.source hasn't been set
+ source_str = str( self.source ) if hasattr( self, 'source' ) else ''
+ return '%s(%s)' %( self.__class__.__name__, str( source_str ) )
+
+
+class FilteredDataProvider( DataProvider ):
+ """
+ Passes each datum through a filter function and yields it if that function
+ returns a non-`None` value.
+
+ Also maintains counters:
+ - `num_data_read`: how many data have been consumed from the source.
+ - `num_valid_data_read`: how many data have been returned from `filter`.
+ - `num_data_returned`: how many data has this provider yielded.
+ """
+ # not useful here - we don't want functions over the query string
+ #settings.update({ 'filter_fn': 'function' })
+
+ def __init__( self, source, filter_fn=None, **kwargs ):
+ """
+ :param filter_fn: a lambda or function that will be passed a datum and
+ return either the (optionally modified) datum or None.
+ """
+ super( FilteredDataProvider, self ).__init__( source, **kwargs )
+ self.filter_fn = filter_fn if hasattr( filter_fn, '__call__' ) else None
+ # count how many data we got from the source
+ self.num_data_read = 0
+ # how many valid data have we gotten from the source
+ # IOW, data that's passed the filter and been either provided OR have been skipped due to offset
+ self.num_valid_data_read = 0
+ # how many lines have been provided/output
+ self.num_data_returned = 0
+
+ def __iter__( self ):
+ parent_gen = super( FilteredDataProvider, self ).__iter__()
+ for datum in parent_gen:
+ self.num_data_read += 1
+ datum = self.filter( datum )
+ if datum != None:
+ self.num_valid_data_read += 1
+ self.num_data_returned += 1
+ yield datum
+
+ #TODO: may want to squash this into DataProvider
+ def filter( self, datum ):
+ """
+ When given a datum from the provider's source, return None if the datum
+ 'does not pass' the filter or is invalid. Return the datum if it's valid.
+
+ :param datum: the datum to check for validity.
+ :returns: the datum, a modified datum, or None
+
+ Meant to be overridden.
+ """
+ if self.filter_fn:
+ return self.filter_fn( datum )
+ # also can be overriden entirely
+ return datum
+
+
+class LimitedOffsetDataProvider( FilteredDataProvider ):
+ """
+ A provider that uses the counters from FilteredDataProvider to limit the
+ number of data and/or skip `offset` number of data before providing.
+
+ Useful for grabbing sections from a source (e.g. pagination).
+ """
+ # define the expected types of these __init__ arguments so they can be parsed out from query strings
+ settings = {
+ 'limit' : 'int',
+ 'offset': 'int'
+ }
+
+ #TODO: may want to squash this into DataProvider
+ def __init__( self, source, offset=0, limit=None, **kwargs ):
+ """
+ :param offset: the number of data to skip before providing.
+ :param limit: the final number of data to provide.
+ """
+ super( LimitedOffsetDataProvider, self ).__init__( source, **kwargs )
+
+ # how many valid data to skip before we start outputing data - must be positive
+ # (diff to support neg. indeces - must be pos.)
+ self.offset = max( offset, 0 )
+
+ # how many valid data to return - must be positive (None indicates no limit)
+ self.limit = limit
+ if self.limit != None:
+ self.limit = max( self.limit, 0 )
+
+ def __iter__( self ):
+ """
+ Iterate over the source until `num_valid_data_read` is greater than
+ `offset`, begin providing datat, and stop when `num_data_returned`
+ is greater than `offset`.
+ """
+ parent_gen = super( LimitedOffsetDataProvider, self ).__iter__()
+ for datum in parent_gen:
+
+ if self.limit != None and self.num_data_returned > self.limit:
+ break
+
+ if self.num_valid_data_read > self.offset:
+ yield datum
+ else:
+ # wot a cheezy way of doing this...
+ self.num_data_returned -= 1
+
+ #TODO: skipping lines is inefficient - somehow cache file position/line_num pair and allow provider
+ # to seek to a pos/line and then begin providing lines
+ # the important catch here is that we need to have accurate pos/line pairs
+ # in order to preserve the functionality of limit and offset
+ #if file_seek and len( file_seek ) == 2:
+ # seek_pos, new_line_num = file_seek
+ # self.seek_and_set_curr_line( seek_pos, new_line_num )
+
+ #def seek_and_set_curr_line( self, file_seek, new_curr_line_num ):
+ # self.seek( file_seek, os.SEEK_SET )
+ # self.curr_line_num = new_curr_line_num
+
+
+class MultiSourceDataProvider( DataProvider ):
+ """
+ A provider that iterates over a list of given sources and provides data
+ from one after another.
+
+ An iterator over iterators.
+ """
+ def __init__( self, source_list, **kwargs ):
+ """
+ :param source_list: an iterator of iterables
+ """
+ self.source_list = deque( source_list )
+
+ def __iter__( self ):
+ """
+ Iterate over the source_list, then iterate over the data in each source.
+
+ Skip a given source in `source_list` if it is `None` or invalid.
+ """
+ for source in self.source_list:
+ # just skip falsy sources
+ if not source:
+ continue
+ try:
+ self.source = self.validate_source( source )
+ except exceptions.InvalidDataProviderSource, invalid_source:
+ continue
+
+ parent_gen = super( MultiSourceDataProvider, self ).__iter__()
+ for datum in parent_gen:
+ yield datum
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 lib/galaxy/datatypes/dataproviders/chunk.py
--- /dev/null
+++ b/lib/galaxy/datatypes/dataproviders/chunk.py
@@ -0,0 +1,84 @@
+"""
+Chunk (N number of bytes at M offset to a source's beginning) provider.
+
+Primarily for file sources but usable by any iterator that has both
+seek and read( N ).
+"""
+import os
+import base64
+
+import base
+import exceptions
+
+_TODO = """
+"""
+
+import logging
+log = logging.getLogger( __name__ )
+
+
+# -----------------------------------------------------------------------------
+class ChunkDataProvider( base.DataProvider ):
+ """
+ Data provider that yields chunks of data from it's file.
+
+ Note: this version does not account for lines and works with Binary datatypes.
+ """
+ MAX_CHUNK_SIZE = 2**16
+ DEFAULT_CHUNK_SIZE = MAX_CHUNK_SIZE
+ settings = {
+ 'chunk_index' : 'int',
+ 'chunk_size' : 'int'
+ }
+
+ #TODO: subclass from LimitedOffsetDataProvider?
+ # see web/framework/base.iterate_file, util/__init__.file_reader, and datatypes.tabular
+ def __init__( self, source, chunk_index=0, chunk_size=DEFAULT_CHUNK_SIZE, **kwargs ):
+ """
+ :param chunk_index: if a source can be divided into N number of
+ `chunk_size` sections, this is the index of which section to
+ return.
+ :param chunk_size: how large are the desired chunks to return
+ (gen. in bytes).
+ """
+ super( ChunkDataProvider, self ).__init__( source, **kwargs )
+ self.chunk_size = int( chunk_size )
+ self.chunk_pos = int( chunk_index ) * self.chunk_size
+
+ def validate_source( self, source ):
+ """
+ Does the given source have both the methods `seek` and `read`?
+ :raises InvalidDataProviderSource: if not.
+ """
+ source = super( ChunkDataProvider, self ).validate_source( source )
+ if( ( not hasattr( source, 'seek' ) )
+ or ( not hasattr( source, 'read' ) ) ):
+ raise exceptions.InvalidDataProviderSource( source )
+ return source
+
+ def __iter__( self ):
+ # not reeeally an iterator per se
+ self.__enter__()
+ self.source.seek( self.chunk_pos, os.SEEK_SET )
+ chunk = self.encode( self.source.read( self.chunk_size ) )
+ yield chunk
+ self.__exit__()
+
+ def encode( self, chunk ):
+ """
+ Called on the chunk before returning.
+
+ Overrride to modify, encode, or decode chunks.
+ """
+ return chunk
+
+
+class Base64ChunkDataProvider( ChunkDataProvider ):
+ """
+ Data provider that yields chunks of base64 encoded data from it's file.
+ """
+ def encode( self, chunk ):
+ """
+ Return chunks encoded in base 64.
+ """
+ return base64.b64encode( chunk )
diff -r cd6fec2f5cba878de9943dd00abe816a65dc96db -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 lib/galaxy/datatypes/dataproviders/column.py
--- /dev/null
+++ b/lib/galaxy/datatypes/dataproviders/column.py
@@ -0,0 +1,254 @@
+"""
+Providers that provide lists of lists generally where each line of a source
+is further subdivided into multiple data (e.g. columns from a line).
+"""
+
+import line
+
+_TODO = """
+move ColumnarDataProvider parsers to more sensible location
+
+TransposedColumnarDataProvider: provides each column as a single array
+ - see existing visualizations/dataprovider/basic.ColumnDataProvider
+"""
+
+import logging
+log = logging.getLogger( __name__ )
+
+
+# ----------------------------------------------------------------------------- base classes
+class ColumnarDataProvider( line.RegexLineDataProvider ):
+ """
+ Data provider that provide a list of columns from the lines of it's source.
+
+ Columns are returned in the order given in indeces, so this provider can
+ re-arrange columns.
+
+ If any desired index is outside the actual number of columns
+ in the source, this provider will None-pad the output and you are guaranteed
+ the same number of columns as the number of indeces asked for (even if they
+ are filled with None).
+ """
+ settings = {
+ 'indeces' : 'list:int',
+ 'column_count' : 'int',
+ 'column_types' : 'list:str',
+ 'parse_columns' : 'bool',
+ 'deliminator' : 'str'
+ }
+
+ def __init__( self, source, indeces=None,
+ column_count=None, column_types=None, parsers=None, parse_columns=True,
+ deliminator='\t', **kwargs ):
+ """
+ :param indeces: a list of indeces of columns to gather from each row
+ Optional: will default to `None`.
+ If `None`, this provider will return all rows (even when a
+ particular row contains more/less than others).
+ If a row/line does not contain an element at a given index, the
+ provider will-return/fill-with a `None` value as the element.
+ :type indeces: list or None
+
+ :param column_count: an alternate means of defining indeces, use an int
+ here to effectively provide the first N columns.
+ Optional: will default to `None`.
+ :type column_count: int
+
+ :param column_types: a list of string names of types that the
+ provider will use to look up an appropriate parser for the column.
+ (e.g. 'int', 'float', 'str', 'bool')
+ Optional: will default to parsing all columns as strings.
+ :type column_types: list of strings
+
+ :param parsers: a dictionary keyed with column type strings
+ and with values that are functions to use when parsing those
+ types.
+ Optional: will default to using the function `_get_default_parsers`.
+ :type parsers: dictionary
+
+ :param parse_columns: attempt to parse columns?
+ Optional: defaults to `True`.
+ :type parse_columns: bool
+
+ :param deliminator: character(s) used to split each row/line of the source.
+ Optional: defaults to the tab character.
+ :type deliminator: str
+
+ .. note: that the subclass constructors are passed kwargs - so they're
+ params (limit, offset, etc.) are also applicable here.
+ """
+ #TODO: other columnar formats: csv, etc.
+ super( ColumnarDataProvider, self ).__init__( source, **kwargs )
+
+ #IMPLICIT: if no indeces, column_count, or column_types passed: return all columns
+ self.selected_column_indeces = indeces
+ self.column_count = column_count
+ self.column_types = column_types or []
+ # if no column count given, try to infer from indeces or column_types
+ if not self.column_count:
+ if self.selected_column_indeces:
+ self.column_count = len( self.selected_column_indeces )
+ elif self.column_types:
+ self.column_count = len( self.column_types )
+ # if no indeces given, infer from column_count
+ if not self.selected_column_indeces and self.column_count:
+ self.selected_column_indeces = list( xrange( self.column_count ) )
+
+ self.deliminator = deliminator
+
+ # how/whether to parse each column value
+ self.parsers = {}
+ if parse_columns:
+ self.parsers = self.get_default_parsers()
+ # overwrite with user desired parsers
+ self.parsers.update( parsers or {} )
+
+ def get_default_parsers( self ):
+ """
+ Return parser dictionary keyed for each columnar type
+ (as defined in datatypes).
+
+ .. note: primitives only by default (str, int, float, boolean, None).
+ Other (more complex) types are retrieved as strings.
+ :returns: a dictionary of the form:
+ `{ <parser type name> : <function used to parse type> }`
+ """
+ #TODO: move to module level (or datatypes, util)
+ return {
+ # str is default and not needed here
+ 'int' : int,
+ 'float' : float,
+ 'bool' : bool,
+
+ # unfortunately, 'list' is used in dataset metadata both for
+ # query style maps (9th col gff) AND comma-sep strings.
+ # (disabled for now)
+ #'list' : lambda v: v.split( ',' ),
+ #'csv' : lambda v: v.split( ',' ),
+ ## i don't like how urlparses does sub-lists...
+ #'querystr' : lambda v: dict([ ( p.split( '=', 1 ) if '=' in p else ( p, True ) )
+ # for p in v.split( ';', 1 ) ])
+
+ #'scifloat': #floating point which may be in scientific notation
+
+ # always with the 1 base, biologists?
+ #'int1' : ( lambda i: int( i ) - 1 ),
+
+ #'gffval': string or '.' for None
+ #'gffint': # int or '.' for None
+ #'gffphase': # 0, 1, 2, or '.' for None
+ #'gffstrand': # -, +, ?, or '.' for None, etc.
+ }
+
+ def parse_value( self, val, type ):
+ """
+ Attempt to parse and return the given value based on the given type.
+
+ :param val: the column value to parse (often a string)
+ :param type: the string type 'name' used to find the appropriate parser
+ :returns: the parsed value
+ or `value` if no `type` found in `parsers`
+ or `None` if there was a parser error (ValueError)
+ """
+ if type == 'str' or type == None: return val
+ try:
+ return self.parsers[ type ]( val )
+ except KeyError, err:
+ # no parser - return as string
+ pass
+ except ValueError, err:
+ # bad value - return None
+ return None
+ return val
+
+ def get_column_type( self, index ):
+ """
+ Get the column type for the parser from `self.column_types` or `None`
+ if the type is unavailable.
+ :param index: the column index
+ :returns: string name of type (e.g. 'float', 'int', etc.)
+ """
+ try:
+ return self.column_types[ index ]
+ except IndexError, ind_err:
+ return None
+
+ def parse_column_at_index( self, columns, parser_index, index ):
+ """
+ Get the column type for the parser from `self.column_types` or `None`
+ if the type is unavailable.
+ """
+ try:
+ return self.parse_value( columns[ index ], self.get_column_type( parser_index ) )
+ # if a selected index is not within columns, return None
+ except IndexError, index_err:
+ return None
+
+ def parse_columns_from_line( self, line ):
+ """
+ Returns a list of the desired, parsed columns.
+ :param line: the line to parse
+ :type line: str
+ """
+ #TODO: too much going on in this loop - the above should all be precomputed AMAP...
+ all_columns = line.split( self.deliminator )
+ # if no indeces were passed to init, return all columns
+ selected_indeces = self.selected_column_indeces or list( xrange( len( all_columns ) ) )
+ parsed_columns = []
+ for parser_index, column_index in enumerate( selected_indeces ):
+ parsed_columns.append( self.parse_column_at_index( all_columns, parser_index, column_index ) )
+ return parsed_columns
+
+ def __iter__( self ):
+ parent_gen = super( ColumnarDataProvider, self ).__iter__()
+ for line in parent_gen:
+ columns = self.parse_columns_from_line( line )
+ yield columns
+
+ #TODO: implement column filters here and not below - flatten hierarchy
+
+class FilteredByColumnDataProvider( ColumnarDataProvider ):
+ """
+ Data provider that provide a list of columns from the lines of it's source
+ _only_ if they pass a given filter function.
+
+ e.g. column #3 is type int and > N
+ """
+ # TODO: how to do this and still have limit and offset work?
+ def __init__( self, source, **kwargs ):
+ raise NotImplementedError()
+ super( FilteredByColumnDataProvider, self ).__init__( source, **kwargs )
+
+
+class DictDataProvider( ColumnarDataProvider ):
+ """
+ Data provider that zips column_names and columns from the source's contents
+ into a dictionary.
+
+ A combination use of both `column_names` and `indeces` allows 'picking'
+ key/value pairs from the source.
+
+ .. note: that the subclass constructors are passed kwargs - so they're
+ params (limit, offset, etc.) are also applicable here.
+ """
+ settings = {
+ 'column_names' : 'list:str',
+ }
+
+ def __init__( self, source, column_names=None, **kwargs ):
+ """
+ :param column_names: an ordered list of strings that will be used as the keys
+ for each column in the returned dictionaries.
+ The number of key, value pairs each returned dictionary has will
+ be as short as the number of column names provided.
+ :type column_names:
+ """
+ #TODO: allow passing in a map instead of name->index { 'name1': index1, ... }
+ super( DictDataProvider, self ).__init__( source, **kwargs )
+ self.column_names = column_names or []
+
+ def __iter__( self ):
+ parent_gen = super( DictDataProvider, self ).__iter__()
+ for column_values in parent_gen:
+ map = dict( zip( self.column_names, column_values ) )
+ yield map
This diff is so big that we needed to truncate the remainder.
https://bitbucket.org/galaxy/galaxy-central/commits/d05bf67aefa6/
Changeset: d05bf67aefa6
Branch: stable
User: natefoo
Date: 2013-08-12 17:55:41
Summary: Added tag release_2013.08.12 for changeset 1ae95b3aa98d
Affected #: 1 file
diff -r 1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 -r d05bf67aefa670f4d004db3c1494e9052c0c0d9c .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -3,3 +3,4 @@
75f09617abaadbc8cc732bb8ee519decaeb56ea7 release_2013.04.01
2cc8d10988e03257dc7b97f8bb332c7df745d1dd security_2013.04.08
524f246ca85395082719ae7a6ff72260d7ad5612 release_2013.06.03
+1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 release_2013.08.12
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: fubar: Patch for missing options in FromDataTableOutputActionOption when these are used in an output filter
by commits-noreply@bitbucket.org 10 Aug '13
by commits-noreply@bitbucket.org 10 Aug '13
10 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/009088d5e76f/
Changeset: 009088d5e76f
User: fubar
Date: 2013-08-10 03:28:28
Summary: Patch for missing options in FromDataTableOutputActionOption when these are used in an output filter
Affected #: 1 file
diff -r 31d2d58ebf102f87c21f170b16452d06fd510a14 -r 009088d5e76fb00794da78dc0ee3cdaa8524b7d8 lib/galaxy/tools/parameters/output.py
--- a/lib/galaxy/tools/parameters/output.py
+++ b/lib/galaxy/tools/parameters/output.py
@@ -217,7 +217,10 @@
else:
self.missing_tool_data_table_name = self.name
def get_value( self, other_values ):
- options = self.options
+ try:
+ options = self.options
+ except:
+ options = []
for filter in self.filters:
options = filter.filter_options( options, other_values )
try:
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: jgoecks: Unify Trackster tool objects with generic tool objects. This unification enhances the generic tool framework and simplifies the trackster tool framework. Also, backbone-ify Trackster tool handling.
by commits-noreply@bitbucket.org 09 Aug '13
by commits-noreply@bitbucket.org 09 Aug '13
09 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/31d2d58ebf10/
Changeset: 31d2d58ebf10
User: jgoecks
Date: 2013-08-08 23:05:51
Summary: Unify Trackster tool objects with generic tool objects. This unification enhances the generic tool framework and simplifies the trackster tool framework. Also, backbone-ify Trackster tool handling.
Affected #: 3 files
diff -r 8c3b553871bbcce9170d235f5188b9803094ad3b -r 31d2d58ebf102f87c21f170b16452d06fd510a14 lib/galaxy/visualization/genome/visual_analytics.py
--- a/lib/galaxy/visualization/genome/visual_analytics.py
+++ b/lib/galaxy/visualization/genome/visual_analytics.py
@@ -38,6 +38,8 @@
def get_tool_def( trans, hda ):
""" Returns definition of an interactive tool for an HDA. """
+
+ #FIXME: use tools.to_dict rather than custom code here.
job = get_dataset_job( hda )
# TODO: could use this assertion to provide more information.
@@ -71,10 +73,10 @@
tool_params.append( param_dict )
elif type( input ) == SelectToolParameter and type( input.options ) != DynamicOptions:
tool_params.append( { 'name' : name, 'label' : input.label, 'type' : 'select', \
- 'value' : tool_param_values.get( name, None ), \
+ 'value' : tool_param_values.get( name, '' ), \
'html' : urllib.quote( input.get_html() ) } )
# If tool has parameters that can be interactively modified, return tool.
if len( tool_params ) != 0:
- return { 'id': tool.id, 'name' : tool.name, 'params' : tool_params }
+ return { 'id': tool.id, 'name' : tool.name, 'inputs' : tool_params }
return None
\ No newline at end of file
diff -r 8c3b553871bbcce9170d235f5188b9803094ad3b -r 31d2d58ebf102f87c21f170b16452d06fd510a14 static/scripts/mvc/tools.js
--- a/static/scripts/mvc/tools.js
+++ b/static/scripts/mvc/tools.js
@@ -41,6 +41,7 @@
label: null,
type: null,
value: null,
+ html: null,
num_samples: 5
},
@@ -70,7 +71,51 @@
}
return samples;
- }
+ },
+
+ set_value: function(value) {
+ this.set('value', value || '');
+ }
+},
+{
+ /**
+ * Dictionary mapping parameter type strings to parameter classes.
+ */
+ TYPE_DICT: {
+ 'number': IntegerToolParameter
+ },
+
+ /**
+ * Create new parameter from a dictionary.
+ */
+ create: function(options) {
+ var param_class = ToolParameter.TYPE_DICT[options.type] || ToolParameter;
+ return new param_class(options);
+ }
+});
+
+/**
+ * A number tool parameter.
+ */
+var IntegerToolParameter = ToolParameter.extend({
+ defaults: _.extend({}, ToolParameter.prototype.defaults, {
+ min: null,
+ max: null
+ }),
+
+ initialize: function() {
+ ToolParameter.prototype.initialize.call(this);
+ if (this.attributes.min) {
+ this.attributes.min = parseInt(this.attributes.min, 10);
+ }
+ if (this.attributes.max) {
+ this.attributes.max = parseInt(this.attributes.max, 10);
+ }
+ },
+
+ set_value: function(value) {
+ this.set('value', parseInt(value, 10))
+ }
});
/**
@@ -79,22 +124,22 @@
var Tool = BaseModel.extend({
// Default attributes.
defaults: {
+ id: null,
+ name: null,
description: null,
target: null,
inputs: []
},
-
- relations: [
- {
- type: Backbone.HasMany,
- key: 'inputs',
- relatedModel: ToolParameter,
- reverseRelation: {
- key: 'tool',
- includeInJSON: false
- }
- }
- ],
+
+ initialize: function(options) {
+ // Unpack parameters manually so that different parameter types can be created.
+ this.attributes.inputs = new Backbone.Collection( _.map(options.inputs, function(param_dict) {
+ // FIXME: it is still useful to be able to save/restore tool state?
+ // Update parameter value from tool state dict.
+ //param_dict.value = tool_state_dict[ param_dict[name] ] || param_dict.value;
+ return ToolParameter.create(param_dict);
+ }));
+ },
urlRoot: galaxy_paths.get('tool_url'),
@@ -209,6 +254,13 @@
});
/**
+ * Tool view.
+ */
+var ToolView = Backbone.View.extend({
+
+});
+
+/**
* Wrap collection of tools for fast access/manipulation.
*/
var ToolCollection = Backbone.Collection.extend({
@@ -697,6 +749,8 @@
// Exports
return {
+ ToolParameter: ToolParameter,
+ IntegerToolParameter: IntegerToolParameter,
Tool: Tool,
ToolSearch: ToolSearch,
ToolPanel: ToolPanel,
diff -r 8c3b553871bbcce9170d235f5188b9803094ad3b -r 31d2d58ebf102f87c21f170b16452d06fd510a14 static/scripts/viz/trackster/tracks.js
--- a/static/scripts/viz/trackster/tracks.js
+++ b/static/scripts/viz/trackster/tracks.js
@@ -1,7 +1,7 @@
define( ["libs/underscore", "viz/visualization", "viz/trackster/util",
- "viz/trackster/slotting", "viz/trackster/painters", "mvc/data",
- "viz/trackster/filters" ],
- function( _, visualization, util, slotting, painters, data, filters_mod ) {
+ "viz/trackster/slotting", "viz/trackster/painters", "viz/trackster/filters",
+ "mvc/data", "mvc/tools" ],
+ function(_, visualization, util, slotting, painters, filters_mod, data, tools_mod) {
var extend = _.extend;
@@ -1622,89 +1622,103 @@
/**
* Encapsulation of a tool that users can apply to tracks/datasets.
*/
-var Tool = function(track, tool_dict, tool_state_dict) {
- //
- // Unpack tool information from dictionary.
- //
- this.track = track;
- this.id = tool_dict.id;
- this.name = tool_dict.name;
- this.params = [];
- var params_dict = tool_dict.params;
- for (var i = 0; i < params_dict.length; i++) {
- // FIXME: use dict for creating parameters.
- var param_dict = params_dict[i],
- name = param_dict.name,
- label = param_dict.label,
- html = unescape(param_dict.html),
- value = param_dict.value,
- type = param_dict.type;
- if (type === "number") {
- this.params.push(
- new NumberParameter(name, label, html,
- (name in tool_state_dict ? tool_state_dict[name] : value),
- param_dict.min, param_dict.max)
- );
+var TracksterTool = Backbone.RelationalModel.extend({
+ defaults: {
+ track: null,
+ tool: null,
+ },
+
+ relations: [
+ {
+ type: Backbone.HasOne,
+ key: 'tool',
+ relatedModel: tools_mod.Tool
}
- else if (type === "select") {
- this.params.push(
- new ToolParameter(name, label, html,
- (name in tool_state_dict ? tool_state_dict[name] : value))
- );
- }
- else {
- console.log("WARNING: unrecognized tool parameter type:", name, type);
- }
- }
-
- //
- // Create div elt for tool UI.
- //
- this.parent_div = $("<div/>").addClass("dynamic-tool").hide();
- // Disable dragging, clicking, double clicking on div so that actions on slider do not impact viz.
- this.parent_div.bind("drag", function(e) {
- e.stopPropagation();
- }).click(function(e) {
- e.stopPropagation();
- }).bind("dblclick", function(e) {
- e.stopPropagation();
- });
- var name_div = $("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);
- var tool_params = this.params;
- var tool = this;
- $.each(this.params, function(index, param) {
- var param_div = $("<div>").addClass("param-row").appendTo(tool.parent_div);
+ ]
+
+});
+
+/**
+ * View renders tool parameter HTML and updates parameter value as it is changed in the HTML.
+ */
+ var ToolParameterView = Backbone.View.extend({
+
+ events: {
+ 'change input': 'update_value'
+ },
+
+ render: function() {
+ var param_div = this.$el.addClass("param-row"),
+ param = this.model;
+
// Param label.
- var label_div = $("<div>").addClass("param-label").text(param.label).appendTo(param_div);
+ var label_div = $("<div>").addClass("param-label").text(param.get('label')).appendTo(param_div);
// Param HTML.
- var html_div = $("<div/>").addClass("param-input").html(param.html).appendTo(param_div);
+ var html_div = $("<div/>").addClass("param-input").html(param.get('html')).appendTo(param_div);
// Set initial value.
- html_div.find(":input").val(param.value);
+ html_div.find(":input").val(param.get('value'));
// Add to clear floating layout.
$("<div style='clear: both;'/>").appendTo(param_div);
- });
-
- // Highlight value for inputs for easy replacement.
- this.parent_div.find("input").click(function() { $(this).select(); });
-
- // Add buttons for running on dataset, region.
- var run_tool_row = $("<div>").addClass("param-row").appendTo(this.parent_div);
- var run_on_dataset_button = $("<input type='submit'>").attr("value", "Run on complete dataset").appendTo(run_tool_row);
- var run_on_region_button = $("<input type='submit'>").attr("value", "Run on visible region").css("margin-left", "3em").appendTo(run_tool_row);
- run_on_region_button.click( function() {
- // Run tool to create new track.
- tool.run_on_region();
- });
- run_on_dataset_button.click( function() {
- tool.run_on_dataset();
- });
-
- if ('visible' in tool_state_dict && tool_state_dict.visible) {
- this.parent_div.show();
+ },
+
+ update_value: function(update_event) {
+ this.model.set_value($(update_event.target).val());
}
-};
-extend(Tool.prototype, {
+ });
+
+/**
+ * View for TracksterTool.
+ */
+var TracksterToolView = Backbone.View.extend({
+
+ /**
+ * Render tool UI.
+ */
+ render: function() {
+ var self = this;
+ tool = this.model.get('tool'),
+ parent_div = this.$el.addClass("dynamic-tool").hide();
+
+ // Prevent div events from propogating to other elements.
+ parent_div.bind("drag", function(e) {
+ e.stopPropagation();
+ }).click(function(e) {
+ e.stopPropagation();
+ }).bind("dblclick", function(e) {
+ e.stopPropagation();
+ }).keydown(function(e) { e.stopPropagation(); });
+
+ // Add name, inputs.
+ var name_div = $("<div class='tool-name'>").appendTo(parent_div).text(tool.get('name'));
+ tool.get('inputs').each(function(param) {
+ var param_view = new ToolParameterView({ model: param });
+ param_view.render();
+ parent_div.append(param_view.$el);
+ });
+
+ // Highlight value for inputs for easy replacement.
+ parent_div.find("input").click(function() { $(this).select(); });
+
+ // Add buttons for running on dataset, region.
+ var run_tool_row = $("<div>").addClass("param-row").appendTo(parent_div);
+ var run_on_dataset_button = $("<input type='submit'>").attr("value", "Run on complete dataset").appendTo(run_tool_row);
+ var run_on_region_button = $("<input type='submit'>").attr("value", "Run on visible region").css("margin-left", "3em").appendTo(run_tool_row);
+ run_on_region_button.click( function() {
+ // Run tool to create new track.
+ self.run_on_region();
+ });
+ run_on_dataset_button.click( function() {
+ self.run_on_dataset();
+ });
+
+ /*
+ if ('visible' in tool_state_dict && tool_state_dict.visible) {
+ this.parent_div.show();
+ }
+ */
+ },
+
/**
* Update tool parameters.
*/
@@ -1713,68 +1727,42 @@
this.params[i].update_value();
}
},
+
/**
* Returns a dict with tool state information.
*/
state_dict: function() {
// Save parameter values.
- var tool_state = {};
- for (var i = 0; i < this.params.length; i++) {
- tool_state[this.params[i].name] = this.params[i].value;
- }
+ var tool_state = this.model.get('tool').get_param_values_dict();
// Save visibility.
tool_state.visible = this.parent_div.is(":visible");
return tool_state;
},
- /**
- * Returns dictionary of parameter name-values.
- */
- get_param_values_dict: function() {
- var param_dict = {};
- this.parent_div.find(":input").each(function() {
- var name = $(this).attr("name"), value = $(this).val();
- param_dict[name] = value;
- });
- return param_dict;
- },
- /**
- * Returns array of parameter values.
- */
- get_param_values: function() {
- var param_values = [];
- this.parent_div.find(":input").each(function() {
- // Only include inputs with names; this excludes Run button.
- var name = $(this).attr("name"), value = $(this).val();
- if (name) {
- param_values[param_values.length] = value;
- }
- });
- return param_values;
- },
+
/**
* Run tool on dataset. Output is placed in dataset's history and no changes to viz are made.
*/
run_on_dataset: function() {
- var tool = this;
- tool.run(
- // URL params.
- {
- target_dataset_id: this.track.dataset.id,
- action: 'rerun',
- tool_id: tool.id
- },
- null,
- // Success callback.
- function(track_data) {
- show_modal(tool.name + " is Running",
- tool.name + " is running on the complete dataset. Tool outputs are in dataset's history.",
- { "Close" : hide_modal } );
- }
- );
-
+ var tool = this.model.get('tool');
+ this.run(
+ // URL params.
+ {
+ target_dataset_id: this.model.get('track').dataset.id,
+ action: 'rerun',
+ tool_id: tool.id
+ },
+ null,
+ // Success callback.
+ function(track_data) {
+ show_modal(tool.get('name') + " is Running",
+ tool.get('name') + " is running on the complete dataset. Tool outputs are in dataset's history.",
+ { "Close" : hide_modal } );
+ }
+ );
},
+
/**
* Run dataset on visible region. This creates a new track and sets the track's contents
* to the tool's output.
@@ -1783,21 +1771,23 @@
//
// Create track for tool's output immediately to provide user feedback.
//
- var region = new visualization.GenomeRegion({
- chrom: this.track.view.chrom,
- start: this.track.view.low,
- end: this.track.view.high
+ var track = this.model.get('track'),
+ tool = this.model.get('tool'),
+ region = new visualization.GenomeRegion({
+ chrom: track.view.chrom,
+ start: track.view.low,
+ end: track.view.high
}),
url_params =
{
- target_dataset_id: this.track.dataset.id,
+ target_dataset_id: track.dataset.id,
action: 'rerun',
- tool_id: this.id,
+ tool_id: tool.id,
regions: [
region.toJSON()
]
},
- current_track = this.track,
+ current_track = track,
// Set name of track to include tool name, parameters, and region used.
track_name = url_params.tool_id +
current_track.tool_region_and_parameters_str(region),
@@ -1838,25 +1828,25 @@
new_track.tiles_div.text("Starting job.");
// Run tool.
- this.update_params();
this.run(url_params, new_track,
- // Success callback.
- function(track_data) {
- new_track.set_dataset(new data.Dataset(track_data));
- new_track.tiles_div.text("Running job.");
- new_track.init();
- }
- );
+ // Success callback.
+ function(track_data) {
+ new_track.set_dataset(new data.Dataset(track_data));
+ new_track.tiles_div.text("Running job.");
+ new_track.init();
+ }
+ );
},
+
/**
* Run tool using a set of URL params and a success callback.
*/
run: function(url_params, new_track, success_callback) {
// Run tool.
- url_params.inputs = this.get_param_values_dict();
+ url_params.inputs = this.model.get('tool').get_inputs_dict();
var ss_deferred = new util.ServerStateDeferred({
ajax_settings: {
- url: config.root + "/api/tools",
+ url: config.root + "api/tools",
data: JSON.stringify(url_params),
dataType: "json",
contentType: 'application/json',
@@ -1889,36 +1879,7 @@
}
});
}
-});
-
-/**
- * Tool parameters.
- */
-var ToolParameter = function(name, label, html, value) {
- this.name = name;
- this.label = label;
- // Need to use jQuery for HTML so that value can be queried and updated dynamically.
- this.html = $(html);
- this.value = value;
-};
-
-extend(ToolParameter.prototype, {
- update_value: function() {
- this.value = $(this.html).val();
- }
-});
-
-var NumberParameter = function(name, label, html, value, min, max) {
- ToolParameter.call(this, name, label, html, value);
- this.min = min;
- this.max = max;
-};
-
-extend(NumberParameter.prototype, ToolParameter.prototype, {
- update_value: function() {
- ToolParameter.prototype.update_value.call(this);
- this.value = parseFloat(this.value);
- }
+
});
/**
@@ -2819,7 +2780,12 @@
// FIXME: prolly need function to set filters and update data_manager reference.
this.data_manager.set('filters_manager', this.filters_manager);
this.filters_available = false;
- this.tool = ('tool' in obj_dict && obj_dict.tool ? new Tool(this, obj_dict.tool, obj_dict.tool_state) : null);
+ this.tool = (obj_dict.tool ? new TracksterTool({
+ 'track': this,
+ 'tool': obj_dict.tool,
+ 'tool_state': obj_dict.tool_state
+ })
+ : null);
this.tile_cache = new visualization.Cache(TILE_CACHE_SIZE);
this.left_offset = 0;
@@ -2830,10 +2796,12 @@
this.set_filters_manager(this.filters_manager);
//
- // Create dynamic tool div.
+ // Create dynamic tool view.
//
- if (this.tool) {
- this.dynamic_tool_div = this.tool.parent_div;
+ if (this.tool) {
+ var tool_view = new TracksterToolView({ model: this.tool });
+ tool_view.render();
+ this.dynamic_tool_div = tool_view.$el;
this.header_div.after(this.dynamic_tool_div);
}
}
@@ -3427,8 +3395,9 @@
*/
tool_region_and_parameters_str: function(region) {
var track = this,
- region_str = (region !== undefined ? region.toString() : "all");
- return " - region=[" + region_str + "], parameters=[" + track.tool.get_param_values().join(", ") + "]";
+ region_str = (region !== undefined ? region.toString() : "all"),
+ param_str = _.values( track.tool.get('tool').get_inputs_dict()).join(', ');
+ return " - region=[" + region_str + "], parameters=[" + param_str + "]";
},
/**
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: carlfeberhard: pull request #168 from Kyle Ellrott: add graphview visualization as visualization plugin
by commits-noreply@bitbucket.org 09 Aug '13
by commits-noreply@bitbucket.org 09 Aug '13
09 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/8c3b553871bb/
Changeset: 8c3b553871bb
User: carlfeberhard
Date: 2013-08-08 22:48:56
Summary: pull request #168 from Kyle Ellrott: add graphview visualization as visualization plugin
Affected #: 5 files
diff -r 6d3d5e571a43dc2defa94c0baef8c96461818a53 -r 8c3b553871bbcce9170d235f5188b9803094ad3b config/plugins/visualizations/graphview/config/graphview.xml
--- /dev/null
+++ b/config/plugins/visualizations/graphview/config/graphview.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE visualization SYSTEM "../../visualization.dtd">
+<visualization name="Graphview">
+ <data_sources>
+ <data_source>
+ <model_class>HistoryDatasetAssociation</model_class>
+ <test type="has_dataprovider" test_attr="datatype">node-edge</test>
+ <to_param param_attr="id">dataset_id</to_param>
+ </data_source>
+ <data_source>
+ <model_class>HistoryDatasetAssociation</model_class>
+ <test type="isinstance" test_attr="datatype" result_type="datatype">graph.Rdf</test>
+ <to_param param_attr="id">dataset_id</to_param>
+ </data_source>
+ </data_sources>
+ <params>
+ <param type="dataset" var_name_in_template="hda" required="true">dataset_id</param>
+ </params>
+ <template>graphview/templates/graphview.mako</template>
+</visualization>
diff -r 6d3d5e571a43dc2defa94c0baef8c96461818a53 -r 8c3b553871bbcce9170d235f5188b9803094ad3b config/plugins/visualizations/graphview/static/graphview.css
--- /dev/null
+++ b/config/plugins/visualizations/graphview/static/graphview.css
@@ -0,0 +1,70 @@
+svg {
+ border: 1px solid lightgrey;
+ background-color: #FFF;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ -o-user-select: none;
+ user-select: none;
+}
+
+svg:not(.active):not(.ctrl) {
+ cursor: crosshair;
+}
+
+path.link {
+ fill: none;
+ stroke: #000;
+ stroke-width: 4px;
+ cursor: default;
+}
+
+svg:not(.active):not(.ctrl) path.link {
+ cursor: pointer;
+}
+
+path.link.selected {
+ stroke-dasharray: 10,2;
+}
+
+path.link.dragline {
+ pointer-events: none;
+}
+
+path.link.hidden {
+ stroke-width: 0;
+}
+
+circle.node {
+ stroke-width: 1.0px;
+ cursor: pointer;
+}
+
+circle.node.reflexive {
+ stroke: #000 !important;
+ stroke-width: 2.5px;
+}
+
+text {
+ font: 12px sans-serif;
+ pointer-events: none;
+}
+
+text.id {
+ text-anchor: middle;
+ font-weight: bold;
+}
+
+div.tooltip {
+ position: absolute;
+ text-align: center;
+ width: 60px;
+ height: 28px;
+ padding: 2px;
+ font: 12px sans-serif;
+ background: lightsteelblue;
+ border: 0px;
+ border-radius: 8px;
+ pointer-events: none;
+}
diff -r 6d3d5e571a43dc2defa94c0baef8c96461818a53 -r 8c3b553871bbcce9170d235f5188b9803094ad3b config/plugins/visualizations/graphview/static/graphview.js
--- /dev/null
+++ b/config/plugins/visualizations/graphview/static/graphview.js
@@ -0,0 +1,175 @@
+function get_firstChild(n) {
+ y=n.firstChild;
+ while (y && y.nodeType!=1) {
+ y=y.nextSibling;
+ }
+ return y;
+}
+
+function get_nextSibling(n) {
+ y=n.nextSibling;
+ while (y) {
+ if (y.nodeType==1) {
+ return y;
+ }
+ y=y.nextSibling;
+ }
+ return y;
+}
+
+function parse_xgmml_attr(elm) {
+ out = {};
+ var c = get_firstChild(elm);
+ while (c) {
+ if (c.nodeName == "att") {
+ if (c.attributes['type'].value == "string") {
+ out[c.attributes['name'].value] = c.attributes['value'].value;
+ }
+ }
+ c = get_nextSibling(c);
+ }
+ return out
+}
+
+function parse_xgmml(root, add_node, add_edge) {
+ graph=root.getElementsByTagName("graph")[0];
+ elm = get_firstChild(graph);
+ while (elm) {
+ if (elm.nodeName == "node") {
+ var attr = parse_xgmml_attr(elm);
+ add_node( elm.attributes['id'].value, elm.attributes['label'].value, attr );
+ }
+ if (elm.nodeName == "edge") {
+ var attr = parse_xgmml_attr(elm);
+ add_edge( elm.attributes['source'].value, elm.attributes['target'].value, attr );
+ }
+
+ elm = get_nextSibling(elm);
+ }
+}
+
+function parse_sif(data, add_node, add_edge) {
+ var lines = data.split("\n")
+ for (var i in lines) {
+ var tmp = lines[i].split("\t");
+ if (tmp.length == 3) {
+ add_edge(tmp[0], tmp[2], {type:tmp[1]});
+ }
+ }
+
+}
+
+jQuery.fn.graphViewer = function(config) {
+
+ var svg, colors;
+ var nodes = [],
+ links = [];
+
+ var height = config.height;
+ var width = config.width;
+
+
+ colors = d3.scale.category10();
+
+ this.each(function() {
+ svg = d3.select(this)
+ .append('svg')
+ .attr('width', width)
+ .attr('height', height);
+ }
+ );
+
+ var tooltip_div = d3.select("#tooltip").attr("class", "tooltip").style("opacity", 0);;
+
+ this.add_node = function(node_id, node_label, attr) {
+ nodes.push( {id: node_id, label:node_label, attr:attr} );
+ }
+
+ this.add_edge = function(src_id, dst_id, attr) {
+ var src, target;
+ for (var i in nodes) {
+ if (nodes[i].id == src_id) {
+ src = nodes[i];
+ }
+ if (nodes[i].id == dst_id) {
+ target = nodes[i];
+ }
+ }
+ if (typeof src==="undefined") {
+ i = nodes.length
+ nodes.push( {id:src_id, label:src_id, attr:{}} )
+ src = nodes[i]
+ }
+ if (typeof target==="undefined") {
+ i = nodes.length
+ nodes.push( {id:dst_id, label:dst_id, attr:{}} )
+ target = nodes[i]
+ }
+ if (src && target) {
+ links.push( {source: src, target: target, left: false, right: true } );
+ }
+ }
+
+ this.render = function() {
+ var path = svg.append('svg:g').selectAll('path'),
+ circle = svg.append('svg:g').selectAll('g');
+
+
+ circle = circle.data(nodes, function(d) { return d.id; });
+ var g = circle.enter().append('svg:g');
+
+ circle.on('mouseover', function(d) {
+ tooltip_div.transition()
+ .duration(200)
+ .style("opacity", .9);
+ tooltip_div.html( "<div>" + d.label + "</div><div>" + d.attr.type + "</div>" ).style("left", (d3.event.pageX + 40) + "px")
+ .style("top", (d3.event.pageY - 35) + "px");
+ })
+ .on("mouseout", function(d) {
+ tooltip_div.transition()
+ .duration(500)
+ .style("opacity", 0);
+ });
+
+ path = path.data(links);
+
+
+ function tick() {
+ path.attr('d', function(d) {
+ return 'M' + d.source.x + ',' + d.source.y + 'L' + d.target.x + ',' + d.target.y;
+ });
+ circle.attr('transform', function(d) {
+ return 'translate(' + d.x + ',' + d.y + ')';
+ });
+ }
+
+
+ g.append('svg:circle')
+ .attr('class', 'node')
+ .attr('r', 8)
+ .style('stroke', 'black')
+ .attr('fill', function(d) {
+ return colors(d['attr']['type'])
+ });
+
+ path.enter().append('svg:path')
+ .attr('class', 'link')
+
+
+ // init D3 force layout
+ var force = d3.layout.force()
+ .nodes(nodes)
+ .links(links)
+ .size([width, height])
+ .linkDistance(25)
+ .charge(-50)
+ .on('tick', tick)
+ circle.call(force.drag)
+ force.start()
+
+ }
+
+ return this
+
+}
+
This diff is so big that we needed to truncate the remainder.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: Update jquery.mousewheel plugin from version 3.0.4 to 3.1.3, introducing a necessary (for now) hack. This makes the plugin compatable with the most recent version of jquery.
by commits-noreply@bitbucket.org 09 Aug '13
by commits-noreply@bitbucket.org 09 Aug '13
09 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/6d3d5e571a43/
Changeset: 6d3d5e571a43
User: jgoecks
Date: 2013-08-08 22:41:18
Summary: Update jquery.mousewheel plugin from version 3.0.4 to 3.1.3, introducing a necessary (for now) hack. This makes the plugin compatable with the most recent version of jquery.
Affected #: 1 file
diff -r 61ddd0d07950fafc18fed95354459e7715e6b1d7 -r 6d3d5e571a43dc2defa94c0baef8c96461818a53 static/scripts/libs/jquery/jquery.mousewheel.js
--- a/static/scripts/libs/jquery/jquery.mousewheel.js
+++ b/static/scripts/libs/jquery/jquery.mousewheel.js
@@ -1,78 +1,125 @@
-/* Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
+/*! Copyright (c) 2013 Brandon Aaron (http://brandonaaron.net)
* Licensed under the MIT License (LICENSE.txt).
*
* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
* Thanks to: Seamus Leahy for adding deltaX and deltaY
*
- * Version: 3.0.4
- *
+ * Version: 3.1.3
+ *
* Requires: 1.2.2+
*/
-(function($) {
+(function (factory) {
+ // GALAXY HACK
+ // (JG): Galaxy's mixing of a global jQuery and require modules doesn't work with
+ // the logic below. Instead, do the right thing for this configuration without any checks.
+ factory(jQuery);
+ // END HACK
-var types = ['DOMMouseScroll', 'mousewheel'];
+ /*
+ if ( typeof define === 'function' && define.amd ) {
+ // AMD. Register as an anonymous module.
+ define(['jquery'], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS style for Browserify
+ module.exports = factory;
+ } else {
+ // Browser globals
+ factory(jQuery);
+ }
+ */
+}(function ($) {
-$.event.special.mousewheel = {
- setup: function() {
- if ( this.addEventListener ) {
- for ( var i=types.length; i; ) {
- this.addEventListener( types[--i], handler, false );
- }
- } else {
- this.onmousewheel = handler;
- }
- },
-
- teardown: function() {
- if ( this.removeEventListener ) {
- for ( var i=types.length; i; ) {
- this.removeEventListener( types[--i], handler, false );
- }
- } else {
- this.onmousewheel = null;
+ var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
+ var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
+ var lowestDelta, lowestDeltaXY;
+
+ if ( $.event.fixHooks ) {
+ for ( var i = toFix.length; i; ) {
+ $.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks;
}
}
-};
-$.fn.extend({
- mousewheel: function(fn) {
- return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
- },
-
- unmousewheel: function(fn) {
- return this.unbind("mousewheel", fn);
+ $.event.special.mousewheel = {
+ setup: function() {
+ if ( this.addEventListener ) {
+ for ( var i = toBind.length; i; ) {
+ this.addEventListener( toBind[--i], handler, false );
+ }
+ } else {
+ this.onmousewheel = handler;
+ }
+ },
+
+ teardown: function() {
+ if ( this.removeEventListener ) {
+ for ( var i = toBind.length; i; ) {
+ this.removeEventListener( toBind[--i], handler, false );
+ }
+ } else {
+ this.onmousewheel = null;
+ }
+ }
+ };
+
+ $.fn.extend({
+ mousewheel: function(fn) {
+ return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
+ },
+
+ unmousewheel: function(fn) {
+ return this.unbind("mousewheel", fn);
+ }
+ });
+
+
+ function handler(event) {
+ var orgEvent = event || window.event,
+ args = [].slice.call(arguments, 1),
+ delta = 0,
+ deltaX = 0,
+ deltaY = 0,
+ absDelta = 0,
+ absDeltaXY = 0,
+ fn;
+ event = $.event.fix(orgEvent);
+ event.type = "mousewheel";
+
+ // Old school scrollwheel delta
+ if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
+ if ( orgEvent.detail ) { delta = orgEvent.detail * -1; }
+
+ // New school wheel delta (wheel event)
+ if ( orgEvent.deltaY ) {
+ deltaY = orgEvent.deltaY * -1;
+ delta = deltaY;
+ }
+ if ( orgEvent.deltaX ) {
+ deltaX = orgEvent.deltaX;
+ delta = deltaX * -1;
+ }
+
+ // Webkit
+ if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
+ if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX * -1; }
+
+ // Look for lowest delta to normalize the delta values
+ absDelta = Math.abs(delta);
+ if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
+ absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
+ if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
+
+ // Get a whole value for the deltas
+ fn = delta > 0 ? 'floor' : 'ceil';
+ delta = Math[fn](delta / lowestDelta);
+ deltaX = Math[fn](deltaX / lowestDeltaXY);
+ deltaY = Math[fn](deltaY / lowestDeltaXY);
+
+ // Add event and delta to the front of the arguments
+ args.unshift(event, delta, deltaX, deltaY);
+
+ return ($.event.dispatch || $.event.handle).apply(this, args);
}
-});
-
-function handler(event) {
- var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0;
- event = $.event.fix(orgEvent);
- event.type = "mousewheel";
-
- // Old school scrollwheel delta
- if ( event.wheelDelta ) { delta = event.wheelDelta/120; }
- if ( event.detail ) { delta = -event.detail/3; }
-
- // New school multidimensional scroll (touchpads) deltas
- deltaY = delta;
-
- // Gecko
- if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
- deltaY = 0;
- deltaX = -1*delta;
- }
-
- // Webkit
- if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; }
- if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; }
-
- // Add event and delta to the front of the arguments
- args.unshift(event, delta, deltaX, deltaY);
-
- return $.event.handle.apply(this, args);
-}
-
-})(jQuery);
+}));
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/e7e82003f235/
Changeset: e7e82003f235
Branch: next-stable
User: natefoo
Date: 2013-08-08 21:40:00
Summary: Define the ActionInputError exception that was being caught in the quotas API controller. Thanks Jim Johnson.
Affected #: 3 files
diff -r 8d8429484ac3ffef21fedd1077acf050c8aed459 -r e7e82003f235c4cca84939e04aa432d128093866 lib/galaxy/actions/admin.py
--- a/lib/galaxy/actions/admin.py
+++ b/lib/galaxy/actions/admin.py
@@ -4,7 +4,7 @@
import logging
from galaxy import util
-from galaxy.exceptions import MessageException
+from galaxy.exceptions import ActionInputError
log = logging.getLogger( __name__ )
@@ -21,21 +21,21 @@
except AssertionError:
create_amount = False
if not params.name or not params.description:
- raise MessageException( "Enter a valid name and a description.", type='error' )
+ raise ActionInputError( "Enter a valid name and a description." )
elif self.sa_session.query( self.app.model.Quota ).filter( self.app.model.Quota.table.c.name==params.name ).first():
- raise MessageException( "Quota names must be unique and a quota with that name already exists, so choose another name.", type='error' )
+ raise ActionInputError( "Quota names must be unique and a quota with that name already exists, so choose another name." )
elif not params.get( 'amount', None ):
- raise MessageException( "Enter a valid quota amount.", type='error' )
+ raise ActionInputError( "Enter a valid quota amount." )
elif create_amount is False:
- raise MessageException( "Unable to parse the provided amount.", type='error' )
+ raise ActionInputError( "Unable to parse the provided amount." )
elif params.operation not in self.app.model.Quota.valid_operations:
- raise MessageException( "Enter a valid operation.", type='error' )
+ raise ActionInputError( "Enter a valid operation." )
elif params.default != 'no' and params.default not in self.app.model.DefaultQuotaAssociation.types.__dict__.values():
- raise MessageException( "Enter a valid default type.", type='error' )
+ raise ActionInputError( "Enter a valid default type." )
elif params.default != 'no' and params.operation != '=':
- raise MessageException( "Operation for a default quota must be '='.", type='error' )
+ raise ActionInputError( "Operation for a default quota must be '='." )
elif create_amount is None and params.operation != '=':
- raise MessageException( "Operation for an unlimited quota must be '='.", type='error' )
+ raise ActionInputError( "Operation for an unlimited quota must be '='." )
else:
# Create the quota
quota = self.app.model.Quota( name=params.name, description=params.description, amount=create_amount, operation=params.operation )
@@ -59,9 +59,9 @@
def _rename_quota( self, quota, params ):
if not params.name:
- raise MessageException( 'Enter a valid name', type='error' )
+ raise ActionInputError( 'Enter a valid name' )
elif params.name != quota.name and self.sa_session.query( self.app.model.Quota ).filter( self.app.model.Quota.table.c.name==params.name ).first():
- raise MessageException( 'A quota with that name already exists', type='error' )
+ raise ActionInputError( 'A quota with that name already exists' )
else:
old_name = quota.name
quota.name = params.name
@@ -73,7 +73,7 @@
def _manage_users_and_groups_for_quota( self, quota, params ):
if quota.default:
- raise MessageException( 'Default quotas cannot be associated with specific users and groups', type='error' )
+ raise ActionInputError( 'Default quotas cannot be associated with specific users and groups' )
else:
in_users = [ self.sa_session.query( self.app.model.User ).get( x ) for x in util.listify( params.in_users ) ]
in_groups = [ self.sa_session.query( self.app.model.Group ).get( x ) for x in util.listify( params.in_groups ) ]
@@ -91,11 +91,11 @@
except AssertionError:
new_amount = False
if not params.amount:
- raise MessageException( 'Enter a valid amount', type='error' )
+ raise ActionInputError( 'Enter a valid amount' )
elif new_amount is False:
- raise MessageException( 'Unable to parse the provided amount', type='error' )
+ raise ActionInputError( 'Unable to parse the provided amount' )
elif params.operation not in self.app.model.Quota.valid_operations:
- raise MessageException( 'Enter a valid operation', type='error' )
+ raise ActionInputError( 'Enter a valid operation' )
else:
quota.amount = new_amount
quota.operation = params.operation
@@ -106,7 +106,7 @@
def _set_quota_default( self, quota, params ):
if params.default != 'no' and params.default not in self.app.model.DefaultQuotaAssociation.types.__dict__.values():
- raise MessageException( 'Enter a valid default type.', type='error' )
+ raise ActionInputError( 'Enter a valid default type.' )
else:
if params.default != 'no':
self.app.quota_agent.set_default_quota( params.default, quota )
@@ -123,7 +123,7 @@
def _unset_quota_default( self, quota, params ):
if not quota.default:
- raise MessageException( "Quota '%s' is not a default." % quota.name, type='error' )
+ raise ActionInputError( "Quota '%s' is not a default." % quota.name )
else:
message = "Quota '%s' is no longer the default for %s users." % ( quota.name, quota.default[0].type )
for dqa in quota.default:
@@ -138,9 +138,9 @@
if q.default:
names.append( q.name )
if len( names ) == 1:
- raise MessageException( "Quota '%s' is a default, please unset it as a default before deleting it" % ( names[0] ), type='error' )
+ raise ActionInputError( "Quota '%s' is a default, please unset it as a default before deleting it" % ( names[0] ) )
elif len( names ) > 1:
- raise MessageException( "Quotas are defaults, please unset them as defaults before deleting them: " + ', '.join( names ), type='error' )
+ raise ActionInputError( "Quotas are defaults, please unset them as defaults before deleting them: " + ', '.join( names ) )
message = "Deleted %d quotas: " % len( quotas )
for q in quotas:
q.deleted = True
@@ -157,9 +157,9 @@
if not q.deleted:
names.append( q.name )
if len( names ) == 1:
- raise MessageException( "Quota '%s' has not been deleted, so it cannot be undeleted." % ( names[0] ), type='error' )
+ raise ActionInputError( "Quota '%s' has not been deleted, so it cannot be undeleted." % ( names[0] ) )
elif len( names ) > 1:
- raise MessageException( "Quotas have not been deleted so they cannot be undeleted: " + ', '.join( names ), type='error' )
+ raise ActionInputError( "Quotas have not been deleted so they cannot be undeleted: " + ', '.join( names ) )
message = "Undeleted %d quotas: " % len( quotas )
for q in quotas:
q.deleted = False
@@ -182,9 +182,9 @@
if not q.deleted:
names.append( q.name )
if len( names ) == 1:
- raise MessageException( "Quota '%s' has not been deleted, so it cannot be purged." % ( names[0] ), type='error' )
+ raise ActionInputError( "Quota '%s' has not been deleted, so it cannot be purged." % ( names[0] ) )
elif len( names ) > 1:
- raise MessageException( "Quotas have not been deleted so they cannot be undeleted: " + ', '.join( names ), type='error' )
+ raise ActionInputError( "Quotas have not been deleted so they cannot be undeleted: " + ', '.join( names ) )
message = "Purged %d quotas: " % len( quotas )
for q in quotas:
# Delete UserQuotaAssociations
diff -r 8d8429484ac3ffef21fedd1077acf050c8aed459 -r e7e82003f235c4cca84939e04aa432d128093866 lib/galaxy/exceptions/__init__.py
--- a/lib/galaxy/exceptions/__init__.py
+++ b/lib/galaxy/exceptions/__init__.py
@@ -21,6 +21,10 @@
class ItemOwnershipException( MessageException ):
pass
+class ActionInputError( MessageException ):
+ def __init__( self, err_msg, type="error" ):
+ super( ActionInputError, self ).__init__( err_msg, type )
+
class ObjectNotFound( Exception ):
""" Accessed object was not found """
pass
diff -r 8d8429484ac3ffef21fedd1077acf050c8aed459 -r e7e82003f235c4cca84939e04aa432d128093866 lib/galaxy/webapps/galaxy/api/quotas.py
--- a/lib/galaxy/webapps/galaxy/api/quotas.py
+++ b/lib/galaxy/webapps/galaxy/api/quotas.py
@@ -11,7 +11,7 @@
from galaxy.actions.admin import AdminActions
from paste.httpexceptions import HTTPBadRequest
-from galaxy.exceptions import *
+from galaxy.exceptions import ActionInputError
log = logging.getLogger( __name__ )
https://bitbucket.org/galaxy/galaxy-central/commits/61ddd0d07950/
Changeset: 61ddd0d07950
User: natefoo
Date: 2013-08-08 21:50:05
Summary: Merge next-stable.
Affected #: 3 files
diff -r 3778811f053a5f71c68408a9e8beb627f6ccdede -r 61ddd0d07950fafc18fed95354459e7715e6b1d7 lib/galaxy/actions/admin.py
--- a/lib/galaxy/actions/admin.py
+++ b/lib/galaxy/actions/admin.py
@@ -4,7 +4,7 @@
import logging
from galaxy import util
-from galaxy.exceptions import MessageException
+from galaxy.exceptions import ActionInputError
log = logging.getLogger( __name__ )
@@ -21,21 +21,21 @@
except AssertionError:
create_amount = False
if not params.name or not params.description:
- raise MessageException( "Enter a valid name and a description.", type='error' )
+ raise ActionInputError( "Enter a valid name and a description." )
elif self.sa_session.query( self.app.model.Quota ).filter( self.app.model.Quota.table.c.name==params.name ).first():
- raise MessageException( "Quota names must be unique and a quota with that name already exists, so choose another name.", type='error' )
+ raise ActionInputError( "Quota names must be unique and a quota with that name already exists, so choose another name." )
elif not params.get( 'amount', None ):
- raise MessageException( "Enter a valid quota amount.", type='error' )
+ raise ActionInputError( "Enter a valid quota amount." )
elif create_amount is False:
- raise MessageException( "Unable to parse the provided amount.", type='error' )
+ raise ActionInputError( "Unable to parse the provided amount." )
elif params.operation not in self.app.model.Quota.valid_operations:
- raise MessageException( "Enter a valid operation.", type='error' )
+ raise ActionInputError( "Enter a valid operation." )
elif params.default != 'no' and params.default not in self.app.model.DefaultQuotaAssociation.types.__dict__.values():
- raise MessageException( "Enter a valid default type.", type='error' )
+ raise ActionInputError( "Enter a valid default type." )
elif params.default != 'no' and params.operation != '=':
- raise MessageException( "Operation for a default quota must be '='.", type='error' )
+ raise ActionInputError( "Operation for a default quota must be '='." )
elif create_amount is None and params.operation != '=':
- raise MessageException( "Operation for an unlimited quota must be '='.", type='error' )
+ raise ActionInputError( "Operation for an unlimited quota must be '='." )
else:
# Create the quota
quota = self.app.model.Quota( name=params.name, description=params.description, amount=create_amount, operation=params.operation )
@@ -59,9 +59,9 @@
def _rename_quota( self, quota, params ):
if not params.name:
- raise MessageException( 'Enter a valid name', type='error' )
+ raise ActionInputError( 'Enter a valid name' )
elif params.name != quota.name and self.sa_session.query( self.app.model.Quota ).filter( self.app.model.Quota.table.c.name==params.name ).first():
- raise MessageException( 'A quota with that name already exists', type='error' )
+ raise ActionInputError( 'A quota with that name already exists' )
else:
old_name = quota.name
quota.name = params.name
@@ -73,7 +73,7 @@
def _manage_users_and_groups_for_quota( self, quota, params ):
if quota.default:
- raise MessageException( 'Default quotas cannot be associated with specific users and groups', type='error' )
+ raise ActionInputError( 'Default quotas cannot be associated with specific users and groups' )
else:
in_users = [ self.sa_session.query( self.app.model.User ).get( x ) for x in util.listify( params.in_users ) ]
in_groups = [ self.sa_session.query( self.app.model.Group ).get( x ) for x in util.listify( params.in_groups ) ]
@@ -91,11 +91,11 @@
except AssertionError:
new_amount = False
if not params.amount:
- raise MessageException( 'Enter a valid amount', type='error' )
+ raise ActionInputError( 'Enter a valid amount' )
elif new_amount is False:
- raise MessageException( 'Unable to parse the provided amount', type='error' )
+ raise ActionInputError( 'Unable to parse the provided amount' )
elif params.operation not in self.app.model.Quota.valid_operations:
- raise MessageException( 'Enter a valid operation', type='error' )
+ raise ActionInputError( 'Enter a valid operation' )
else:
quota.amount = new_amount
quota.operation = params.operation
@@ -106,7 +106,7 @@
def _set_quota_default( self, quota, params ):
if params.default != 'no' and params.default not in self.app.model.DefaultQuotaAssociation.types.__dict__.values():
- raise MessageException( 'Enter a valid default type.', type='error' )
+ raise ActionInputError( 'Enter a valid default type.' )
else:
if params.default != 'no':
self.app.quota_agent.set_default_quota( params.default, quota )
@@ -123,7 +123,7 @@
def _unset_quota_default( self, quota, params ):
if not quota.default:
- raise MessageException( "Quota '%s' is not a default." % quota.name, type='error' )
+ raise ActionInputError( "Quota '%s' is not a default." % quota.name )
else:
message = "Quota '%s' is no longer the default for %s users." % ( quota.name, quota.default[0].type )
for dqa in quota.default:
@@ -138,9 +138,9 @@
if q.default:
names.append( q.name )
if len( names ) == 1:
- raise MessageException( "Quota '%s' is a default, please unset it as a default before deleting it" % ( names[0] ), type='error' )
+ raise ActionInputError( "Quota '%s' is a default, please unset it as a default before deleting it" % ( names[0] ) )
elif len( names ) > 1:
- raise MessageException( "Quotas are defaults, please unset them as defaults before deleting them: " + ', '.join( names ), type='error' )
+ raise ActionInputError( "Quotas are defaults, please unset them as defaults before deleting them: " + ', '.join( names ) )
message = "Deleted %d quotas: " % len( quotas )
for q in quotas:
q.deleted = True
@@ -157,9 +157,9 @@
if not q.deleted:
names.append( q.name )
if len( names ) == 1:
- raise MessageException( "Quota '%s' has not been deleted, so it cannot be undeleted." % ( names[0] ), type='error' )
+ raise ActionInputError( "Quota '%s' has not been deleted, so it cannot be undeleted." % ( names[0] ) )
elif len( names ) > 1:
- raise MessageException( "Quotas have not been deleted so they cannot be undeleted: " + ', '.join( names ), type='error' )
+ raise ActionInputError( "Quotas have not been deleted so they cannot be undeleted: " + ', '.join( names ) )
message = "Undeleted %d quotas: " % len( quotas )
for q in quotas:
q.deleted = False
@@ -182,9 +182,9 @@
if not q.deleted:
names.append( q.name )
if len( names ) == 1:
- raise MessageException( "Quota '%s' has not been deleted, so it cannot be purged." % ( names[0] ), type='error' )
+ raise ActionInputError( "Quota '%s' has not been deleted, so it cannot be purged." % ( names[0] ) )
elif len( names ) > 1:
- raise MessageException( "Quotas have not been deleted so they cannot be undeleted: " + ', '.join( names ), type='error' )
+ raise ActionInputError( "Quotas have not been deleted so they cannot be undeleted: " + ', '.join( names ) )
message = "Purged %d quotas: " % len( quotas )
for q in quotas:
# Delete UserQuotaAssociations
diff -r 3778811f053a5f71c68408a9e8beb627f6ccdede -r 61ddd0d07950fafc18fed95354459e7715e6b1d7 lib/galaxy/exceptions/__init__.py
--- a/lib/galaxy/exceptions/__init__.py
+++ b/lib/galaxy/exceptions/__init__.py
@@ -21,6 +21,10 @@
class ItemOwnershipException( MessageException ):
pass
+class ActionInputError( MessageException ):
+ def __init__( self, err_msg, type="error" ):
+ super( ActionInputError, self ).__init__( err_msg, type )
+
class ObjectNotFound( Exception ):
""" Accessed object was not found """
pass
diff -r 3778811f053a5f71c68408a9e8beb627f6ccdede -r 61ddd0d07950fafc18fed95354459e7715e6b1d7 lib/galaxy/webapps/galaxy/api/quotas.py
--- a/lib/galaxy/webapps/galaxy/api/quotas.py
+++ b/lib/galaxy/webapps/galaxy/api/quotas.py
@@ -11,7 +11,7 @@
from galaxy.actions.admin import AdminActions
from paste.httpexceptions import HTTPBadRequest
-from galaxy.exceptions import *
+from galaxy.exceptions import ActionInputError
log = logging.getLogger( __name__ )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: Graph datatype: add data providers for SIF & XGMML; simple graph data structure to util
by commits-noreply@bitbucket.org 09 Aug '13
by commits-noreply@bitbucket.org 09 Aug '13
09 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/3778811f053a/
Changeset: 3778811f053a
User: carlfeberhard
Date: 2013-08-08 21:04:53
Summary: Graph datatype: add data providers for SIF & XGMML; simple graph data structure to util
Affected #: 2 files
diff -r 2e0abb7f9b04540e616458a90a87191ed98a3ba4 -r 3778811f053a5f71c68408a9e8beb627f6ccdede lib/galaxy/datatypes/graph.py
--- a/lib/galaxy/datatypes/graph.py
+++ b/lib/galaxy/datatypes/graph.py
@@ -2,12 +2,18 @@
Graph content classes.
"""
-import data, tabular, xml
+import data
+import tabular
+import xml
+
+import dataproviders
+from galaxy.util import simplegraph
import logging
log = logging.getLogger( __name__ )
+(a)dataproviders.decorators.has_dataproviders
class Xgmml( xml.GenericXml ):
"""
XGMML graph format
@@ -48,7 +54,13 @@
#For one file only, use base class method (move/copy)
data.Text.merge( split_files, output_file )
+ @dataproviders.decorators.dataprovider_factory( 'node-edge', dataproviders.hierarchy.XMLDataProvider.settings )
+ def node_edge_dataprovider( self, dataset, **settings ):
+ dataset_source = dataproviders.dataset.DatasetDataProvider( dataset )
+ return XGMMLGraphDataProvider( dataset_source, **settings )
+
+(a)dataproviders.decorators.has_dataproviders
class Sif( tabular.Tabular ):
"""
SIF graph format
@@ -75,7 +87,6 @@
"""
Determines whether the file is SIF
"""
- print '---------------------------------------- sniffing Siffing'
line = ''
with open( filename ) as infile:
correct = True
@@ -92,6 +103,11 @@
def merge( split_files, output_file ):
data.Text.merge( split_files, output_file )
+ @dataproviders.decorators.dataprovider_factory( 'node-edge', dataproviders.column.ColumnarDataProvider.settings )
+ def node_edge_dataprovider( self, dataset, **settings ):
+ dataset_source = dataproviders.dataset.DatasetDataProvider( dataset )
+ return SIFGraphDataProvider( dataset_source, **settings )
+
#TODO: we might want to look at rdflib or a similar, larger lib/egg
class Rdf( xml.GenericXml ):
@@ -108,3 +124,75 @@
else:
dataset.peek = 'file does not exist'
dataset.blurb = 'file purged from disk'
+
+ #TODO: won't be as simple
+ #(a)dataproviders.decorators.dataprovider_factory( 'node-edge', dataproviders.column.ColumnarDataProvider.settings )
+ #def node_edge_dataprovider( self, dataset, **settings ):
+ # dataset_source = dataproviders.dataset.DatasetDataProvider( dataset )
+ # return None
+
+
+# ----------------------------------------------------------------------------- graph specific data providers
+class XGMMLGraphDataProvider( dataproviders.hierarchy.XMLDataProvider ):
+ """
+ Provide two lists: nodes, edges::
+
+ 'nodes': contains objects of the form:
+ { 'id' : <some string id>, 'data': <any extra data> }
+ 'edges': contains objects of the form:
+ { 'source' : <an index into nodes>, 'target': <an index into nodes>, 'data': <any extra data> }
+ """
+ def __iter__( self ):
+ # use simple graph to store nodes and links, later providing them as a dict
+ # essentially this is a form of aggregation
+ graph = simplegraph.SimpleGraph()
+
+ parent_gen = super( XGMMLGraphDataProvider, self ).__iter__()
+ for graph_elem in parent_gen:
+ if 'children' not in graph_elem:
+ continue
+ for elem in graph_elem[ 'children' ]:
+ # use endswith to work around Elementtree namespaces
+ if elem[ 'tag' ].endswith( 'node' ):
+ node_id = elem[ 'attrib' ][ 'id' ]
+ # pass the entire, parsed xml element as the data
+ graph.add_node( node_id, **elem )
+
+ elif elem[ 'tag' ].endswith( 'edge' ):
+ source_id = elem[ 'attrib' ][ 'source' ]
+ target_id = elem[ 'attrib' ][ 'target' ]
+ graph.add_edge( source_id, target_id, **elem )
+
+ yield graph.as_dict()
+
+
+class SIFGraphDataProvider( dataproviders.column.ColumnarDataProvider ):
+ """
+ Provide two lists: nodes, edges::
+
+ 'nodes': contains objects of the form:
+ { 'id' : <some string id>, 'data': <any extra data> }
+ 'edges': contains objects of the form:
+ { 'source' : <an index into nodes>, 'target': <an index into nodes>, 'data': <any extra data> }
+ """
+ def __iter__( self ):
+ # use simple graph to store nodes and links, later providing them as a dict
+ # essentially this is a form of aggregation
+ graph = simplegraph.SimpleGraph()
+ # SIF is tabular with the source, link-type, and all targets in the columns
+ parent_gen = super( SIFGraphDataProvider, self ).__iter__()
+ for columns in parent_gen:
+ if columns:
+ source_id = columns[0]
+ # there's no extra data for nodes (or links) in the examples I've seen
+ graph.add_node( source_id )
+
+ # targets are the (variadic) remaining columns
+ if len( columns ) >= 3:
+ relation = columns[1]
+ targets = columns[2:]
+ for target_id in targets:
+ graph.add_node( target_id )
+ graph.add_edge( source_id, target_id, type=relation )
+
+ yield graph.as_dict()
diff -r 2e0abb7f9b04540e616458a90a87191ed98a3ba4 -r 3778811f053a5f71c68408a9e8beb627f6ccdede lib/galaxy/util/simplegraph.py
--- /dev/null
+++ b/lib/galaxy/util/simplegraph.py
@@ -0,0 +1,127 @@
+"""
+Fencepost-simple graph structure implementation.
+"""
+# Currently (2013.7.12) only used in easing the parsing of graph datatype data.
+
+from galaxy.util.odict import odict
+
+
+class SimpleGraphNode( object ):
+ """
+ Node representation.
+ """
+ def __init__( self, index, **data ):
+ """
+ :param index: index of this node in some parent list
+ :type index: int
+ :param data: any extra data that needs to be saved
+ :type data: (variadic dictionary)
+ """
+ # a bit application specific (could be 'id')
+ self.index = index
+ self.data = data
+
+
+class SimpleGraphEdge( object ):
+ """
+ Edge representation.
+ """
+ def __init__( self, source_index, target_index, **data ):
+ """
+ :param source_index: index of the edge's source node in some parent list
+ :type source_index: int
+ :param target_index: index of the edge's target node in some parent list
+ :type target_index: int
+ :param data: any extra data that needs to be saved
+ :type data: (variadic dictionary)
+ """
+ self.source_index = source_index
+ self.target_index = target_index
+ self.data = data
+
+
+class SimpleGraph( object ):
+ """
+ Each node is unique (by id) and stores it's own index in the node list/odict.
+ Each edge is represented as two indeces into the node list/odict.
+ Both nodes and edges allow storing extra information if needed.
+
+ Allows:
+ multiple edges between two nodes
+ self referential edges (an edge from a node to itself)
+
+ These graphs are not specifically directed but since source and targets on the
+ edges are listed - it could easily be used that way.
+ """
+ def __init__( self, nodes=None, edges=None ):
+ # use an odict so that edge indeces actually match the final node list indeces
+ self.nodes = nodes or odict()
+ self.edges = edges or []
+
+ def add_node( self, node_id, **data ):
+ """
+ Adds a new node only if it doesn't already exist.
+ :param node_id: some unique identifier
+ :type node_id: (hashable)
+ :param data: any extra data that needs to be saved
+ :type data: (variadic dictionary)
+ :returns: the new node
+ """
+ if node_id in self.nodes:
+ return self.nodes[ node_id ]
+ node_index = len( self.nodes )
+ new_node = SimpleGraphNode( node_index, **data )
+ self.nodes[ node_id ] = new_node
+ return new_node
+
+ def add_edge( self, source_id, target_id, **data ):
+ """
+ Adds a new node only if it doesn't already exist.
+ :param source_id: the id of the source node
+ :type source_id: (hashable)
+ :param target_id: the id of the target node
+ :type target_id: (hashable)
+ :param data: any extra data that needs to be saved for the edge
+ :type data: (variadic dictionary)
+ :returns: the new node
+
+ ..note: that, although this will create new nodes if necessary, there's
+ no way to pass `data` to them - so if you need to assoc. more data with
+ the nodes, use `add_node` first.
+ """
+ # adds target_id to source_id's edge list
+ # adding source_id and/or target_id to nodes if not there already
+ if source_id not in self.nodes:
+ self.add_node( source_id )
+ if target_id not in self.nodes:
+ self.add_node( target_id )
+ new_edge = SimpleGraphEdge( self.nodes[ source_id ].index, self.nodes[ target_id ].index, **data )
+ self.edges.append( new_edge )
+ return new_edge
+
+ def gen_node_dicts( self ):
+ """
+ Returns a generator that yields node dictionaries in the form:
+ { 'id': <the nodes unique id>, 'data': <any additional node data> }
+ """
+ for node_id, node in self.nodes.items():
+ yield { 'id': node_id, 'data': node.data }
+
+ def gen_edge_dicts( self ):
+ """
+ Returns a generator that yields node dictionaries in the form:
+ {
+ 'source': <the index of the source node in the graph's node list>,
+ 'target': <the index of the target node in the graph's node list>,
+ 'data' : <any additional edge data>
+ }
+ """
+ for edge in self.edges:
+ yield { 'source': edge.source_index, 'target': edge.target_index, 'data': edge.data }
+
+ def as_dict( self ):
+ """
+ Returns a dictionary of the form
+ { 'nodes': <a list of node dictionaries>, 'edges': <a list of node dictionaries> }
+ """
+ return { 'nodes': list( self.gen_node_dicts() ), 'edges': list( self.gen_edge_dicts() ) }
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: Update jquery.autocomplete.js to 2.4.4
by commits-noreply@bitbucket.org 08 Aug '13
by commits-noreply@bitbucket.org 08 Aug '13
08 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/2e0abb7f9b04/
Changeset: 2e0abb7f9b04
User: guerler
Date: 2013-08-08 20:22:42
Summary: Update jquery.autocomplete.js to 2.4.4
Affected #: 2 files
diff -r bf6bf3b5edfdc409f235cb91edcc9d91246df816 -r 2e0abb7f9b04540e616458a90a87191ed98a3ba4 static/scripts/galaxy.autocom_tagging.js
--- a/static/scripts/galaxy.autocom_tagging.js
+++ b/static/scripts/galaxy.autocom_tagging.js
@@ -100,12 +100,6 @@
var new_value = this.value;
- // Do nothing if return key was used to autocomplete.
- if (return_key_pressed_for_autocomplete === true) {
- return_key_pressed_for_autocomplete = false;
- return false;
- }
-
// Suppress space after a ":"
if ( new_value.indexOf(": ", new_value.length - 2) !== -1) {
this.value = new_value.substring(0, new_value.length-1);
@@ -166,7 +160,7 @@
// Flush autocomplete cache because it's not out of date.
// TODO: in the future, we could remove the particular item
// that was chosen from the cache rather than flush it.
- zz.flushCache();
+ zz.data('autocompleter').cacheFlush();
}
});
diff -r bf6bf3b5edfdc409f235cb91edcc9d91246df816 -r 2e0abb7f9b04540e616458a90a87191ed98a3ba4 static/scripts/libs/jquery/jquery.autocomplete.js
--- a/static/scripts/libs/jquery/jquery.autocomplete.js
+++ b/static/scripts/libs/jquery/jquery.autocomplete.js
@@ -1,832 +1,1152 @@
-/*
- * Autocomplete - jQuery plugin 1.0.2
- *
- * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
- *
- * Dual licensed under the MIT and GPL licenses:
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
- *
- * Revision: $Id: jquery.autocomplete.js 5747 2008-06-25 18:30:55Z joern.zaefferer $
- *
+/**
+ * @fileOverview jquery-autocomplete, the jQuery Autocompleter
+ * @author <a href="mailto:dylan@dyve.net">Dylan Verheul</a>
+ * @version 2.4.4
+ * @requires jQuery 1.6+
+ * @license MIT | GPL | Apache 2.0, see LICENSE.txt
+ * @see https://github.com/dyve/jquery-autocomplete
*/
+(function($) {
+ "use strict";
-String.prototype.endsWith = function(str) {return (this.match(str+"$")==str)}
-
-// JG HACK: each autocomplete object should have its own return_key flag.
-var return_key_pressed_for_autocomplete = false;
-
-;(function($) {
-
-$.fn.extend({
- autocomplete: function(urlOrData, options) {
- var isUrl = typeof urlOrData == "string";
- options = $.extend({}, $.Autocompleter.defaults, {
- url: isUrl ? urlOrData : null,
- data: isUrl ? null : urlOrData,
- delay: isUrl ? $.Autocompleter.defaults.delay : 10,
- max: options && !options.scroll ? 10 : 150
- }, options);
-
- // if highlight is set to false, replace it with a do-nothing function
- options.highlight = options.highlight || function(value) { return value; };
-
- // if the formatMatch option is not specified, then use formatItem for backwards compatibility
- options.formatMatch = options.formatMatch || options.formatItem;
-
+ /**
+ * jQuery autocomplete plugin
+ * @param {object|string} options
+ * @returns (object} jQuery object
+ */
+ $.fn.autocomplete = function(options) {
+ var url;
+ if (arguments.length > 1) {
+ url = options;
+ options = arguments[1];
+ options.url = url;
+ } else if (typeof options === 'string') {
+ url = options;
+ options = { url: url };
+ }
+ var opts = $.extend({}, $.fn.autocomplete.defaults, options);
return this.each(function() {
- new $.Autocompleter(this, options);
+ var $this = $(this);
+ $this.data('autocompleter', new $.Autocompleter(
+ $this,
+ $.meta ? $.extend({}, opts, $this.data()) : opts
+ ));
});
- },
- result: function(handler) {
- return this.bind("result", handler);
- },
- search: function(handler) {
- return this.trigger("search", [handler]);
- },
- flushCache: function() {
- return this.trigger("flushCache");
- },
- setOptions: function(options){
- return this.trigger("setOptions", [options]);
- },
- unautocomplete: function() {
- return this.trigger("unautocomplete");
- },
- // JG: add method to show all data in cache.
- showAllInCache: function() {
- return this.trigger("showAllInCache");
- }
-});
-
-$.Autocompleter = function(input, options) {
-
- var KEY = {
- UP: 38,
- DOWN: 40,
- DEL: 46,
- TAB: 9,
- RETURN: 13,
- ESC: 27,
- COMMA: 188,
- PAGEUP: 33,
- PAGEDOWN: 34,
- BACKSPACE: 8,
- COLON: 16
};
- // Create $ object for input element
- var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
+ /**
+ * Store default options
+ * @type {object}
+ */
+ $.fn.autocomplete.defaults = {
+ inputClass: 'acInput',
+ loadingClass: 'acLoading',
+ resultsClass: 'acResults',
+ selectClass: 'acSelect',
+ queryParamName: 'q',
+ extraParams: {},
+ remoteDataType: false,
+ lineSeparator: '\n',
+ cellSeparator: '|',
+ minChars: 2,
+ maxItemsToShow: 10,
+ delay: 400,
+ useCache: true,
+ maxCacheLength: 10,
+ matchSubset: true,
+ matchCase: false,
+ matchInside: true,
+ mustMatch: false,
+ selectFirst: false,
+ selectOnly: false,
+ showResult: null,
+ preventDefaultReturn: 1,
+ preventDefaultTab: 0,
+ autoFill: false,
+ filterResults: true,
+ filter: true,
+ sortResults: true,
+ sortFunction: null,
+ onItemSelect: null,
+ onNoMatch: null,
+ onFinish: null,
+ matchStringConverter: null,
+ beforeUseConverter: null,
+ autoWidth: 'min-width',
+ useDelimiter: false,
+ delimiterChar: ',',
+ delimiterKeyCode: 188,
+ processData: null,
+ onError: null,
+ enabled: true
+ };
- var timeout;
- var previousValue = "";
- var cache = $.Autocompleter.Cache(options);
- var hasFocus = 0;
- var lastKeyPressCode;
- var config = {
- mouseDownOnSelect: false
+ /**
+ * Sanitize result
+ * @param {Object} result
+ * @returns {Object} object with members value (String) and data (Object)
+ * @private
+ */
+ var sanitizeResult = function(result) {
+ var value, data;
+ var type = typeof result;
+ if (type === 'string') {
+ value = result;
+ data = {};
+ } else if ($.isArray(result)) {
+ value = result[0];
+ data = result.slice(1);
+ } else if (type === 'object') {
+ value = result.value;
+ data = result.data;
+ }
+ value = String(value);
+ if (typeof data !== 'object') {
+ data = {};
+ }
+ return {
+ value: value,
+ data: data
+ };
};
- var select = $.Autocompleter.Select(options, input, selectCurrent, config);
-
- var blockSubmit;
-
- // prevent form submit in opera when selecting with return key
- $.browser.opera && $(input.form).bind("submit.autocomplete", function() {
- if (blockSubmit) {
- blockSubmit = false;
- return false;
+
+ /**
+ * Sanitize integer
+ * @param {mixed} value
+ * @param {Object} options
+ * @returns {Number} integer
+ * @private
+ */
+ var sanitizeInteger = function(value, stdValue, options) {
+ var num = parseInt(value, 10);
+ options = options || {};
+ if (isNaN(num) || (options.min && num < options.min)) {
+ num = stdValue;
}
- });
-
- // Firefox only triggers holding down a key with keypress
- $input.bind(($.browser.mozilla ? "keypress" : "keydown") + ".autocomplete", function(event) {
- // track last key pressed
- lastKeyPressCode = event.keyCode;
- switch(event.keyCode) {
-
- case KEY.UP:
- event.preventDefault();
- if ( select.visible() ) {
- select.prev();
- } else {
- onChange(0, true);
- }
+ return num;
+ };
+
+ /**
+ * Create partial url for a name/value pair
+ */
+ var makeUrlParam = function(name, value) {
+ return [name, encodeURIComponent(value)].join('=');
+ };
+
+ /**
+ * Build an url
+ * @param {string} url Base url
+ * @param {object} [params] Dictionary of parameters
+ */
+ var makeUrl = function(url, params) {
+ var urlAppend = [];
+ $.each(params, function(index, value) {
+ urlAppend.push(makeUrlParam(index, value));
+ });
+ if (urlAppend.length) {
+ url += url.indexOf('?') === -1 ? '?' : '&';
+ url += urlAppend.join('&');
+ }
+ return url;
+ };
+
+ /**
+ * Default sort filter
+ * @param {object} a
+ * @param {object} b
+ * @param {boolean} matchCase
+ * @returns {number}
+ */
+ var sortValueAlpha = function(a, b, matchCase) {
+ a = String(a.value);
+ b = String(b.value);
+ if (!matchCase) {
+ a = a.toLowerCase();
+ b = b.toLowerCase();
+ }
+ if (a > b) {
+ return 1;
+ }
+ if (a < b) {
+ return -1;
+ }
+ return 0;
+ };
+
+ /**
+ * Parse data received in text format
+ * @param {string} text Plain text input
+ * @param {string} lineSeparator String that separates lines
+ * @param {string} cellSeparator String that separates cells
+ * @returns {array} Array of autocomplete data objects
+ */
+ var plainTextParser = function(text, lineSeparator, cellSeparator) {
+ var results = [];
+ var i, j, data, line, value, lines;
+ // Be nice, fix linebreaks before splitting on lineSeparator
+ lines = String(text).replace('\r\n', '\n').split(lineSeparator);
+ for (i = 0; i < lines.length; i++) {
+ line = lines[i].split(cellSeparator);
+ data = [];
+ for (j = 0; j < line.length; j++) {
+ data.push(decodeURIComponent(line[j]));
+ }
+ value = data.shift();
+ results.push({ value: value, data: data });
+ }
+ return results;
+ };
+
+ /**
+ * Autocompleter class
+ * @param {object} $elem jQuery object with one input tag
+ * @param {object} options Settings
+ * @constructor
+ */
+ $.Autocompleter = function($elem, options) {
+
+ /**
+ * Assert parameters
+ */
+ if (!$elem || !($elem instanceof $) || $elem.length !== 1 || ($elem.get(0).tagName.toUpperCase() !== 'INPUT' && $elem.get(0).tagName.toUpperCase() !== 'TEXTAREA')) {
+ throw new Error('Invalid parameter for jquery.Autocompleter, jQuery object with one element with INPUT or TEXTAREA tag expected.');
+ }
+
+ /**
+ * @constant Link to this instance
+ * @type object
+ * @private
+ */
+ var self = this;
+
+ /**
+ * @property {object} Options for this instance
+ * @public
+ */
+ this.options = options;
+
+ /**
+ * @property object Cached data for this instance
+ * @private
+ */
+ this.cacheData_ = {};
+
+ /**
+ * @property {number} Number of cached data items
+ * @private
+ */
+ this.cacheLength_ = 0;
+
+ /**
+ * @property {string} Class name to mark selected item
+ * @private
+ */
+ this.selectClass_ = 'jquery-autocomplete-selected-item';
+
+ /**
+ * @property {number} Handler to activation timeout
+ * @private
+ */
+ this.keyTimeout_ = null;
+
+ /**
+ * @property {number} Handler to finish timeout
+ * @private
+ */
+ this.finishTimeout_ = null;
+
+ /**
+ * @property {number} Last key pressed in the input field (store for behavior)
+ * @private
+ */
+ this.lastKeyPressed_ = null;
+
+ /**
+ * @property {string} Last value processed by the autocompleter
+ * @private
+ */
+ this.lastProcessedValue_ = null;
+
+ /**
+ * @property {string} Last value selected by the user
+ * @private
+ */
+ this.lastSelectedValue_ = null;
+
+ /**
+ * @property {boolean} Is this autocompleter active (showing results)?
+ * @see showResults
+ * @private
+ */
+ this.active_ = false;
+
+ /**
+ * @property {boolean} Is this autocompleter allowed to finish on blur?
+ * @private
+ */
+ this.finishOnBlur_ = true;
+
+ /**
+ * Sanitize options
+ */
+ this.options.minChars = sanitizeInteger(this.options.minChars, $.fn.autocomplete.defaults.minChars, { min: 0 });
+ this.options.maxItemsToShow = sanitizeInteger(this.options.maxItemsToShow, $.fn.autocomplete.defaults.maxItemsToShow, { min: 0 });
+ this.options.maxCacheLength = sanitizeInteger(this.options.maxCacheLength, $.fn.autocomplete.defaults.maxCacheLength, { min: 1 });
+ this.options.delay = sanitizeInteger(this.options.delay, $.fn.autocomplete.defaults.delay, { min: 0 });
+ if (this.options.preventDefaultReturn != 2) {
+ this.options.preventDefaultReturn = this.options.preventDefaultReturn ? 1 : 0;
+ }
+ if (this.options.preventDefaultTab != 2) {
+ this.options.preventDefaultTab = this.options.preventDefaultTab ? 1 : 0;
+ }
+
+ /**
+ * Init DOM elements repository
+ */
+ this.dom = {};
+
+ /**
+ * Store the input element we're attached to in the repository
+ */
+ this.dom.$elem = $elem;
+
+ /**
+ * Switch off the native autocomplete and add the input class
+ */
+ this.dom.$elem.attr('autocomplete', 'off').addClass(this.options.inputClass);
+
+ /**
+ * Create DOM element to hold results, and force absolute position
+ */
+ this.dom.$results = $('<div></div>').hide().addClass(this.options.resultsClass).css({
+ position: 'absolute'
+ });
+ $('body').append(this.dom.$results);
+
+ /**
+ * Attach keyboard monitoring to $elem
+ */
+ $elem.keydown(function(e) {
+ self.lastKeyPressed_ = e.keyCode;
+ switch(self.lastKeyPressed_) {
+
+ case self.options.delimiterKeyCode: // comma = 188
+ if (self.options.useDelimiter && self.active_) {
+ self.selectCurrent();
+ }
+ break;
+
+ // ignore navigational & special keys
+ case 35: // end
+ case 36: // home
+ case 16: // shift
+ case 17: // ctrl
+ case 18: // alt
+ case 37: // left
+ case 39: // right
+ break;
+
+ case 38: // up
+ e.preventDefault();
+ if (self.active_) {
+ self.focusPrev();
+ } else {
+ self.activate();
+ }
+ return false;
+
+ case 40: // down
+ e.preventDefault();
+ if (self.active_) {
+ self.focusNext();
+ } else {
+ self.activate();
+ }
+ return false;
+
+ case 9: // tab
+ if (self.active_) {
+ self.selectCurrent();
+ if (self.options.preventDefaultTab) {
+ e.preventDefault();
+ return false;
+ }
+ }
+ if (self.options.preventDefaultTab === 2) {
+ e.preventDefault();
+ return false;
+ }
break;
-
- case KEY.DOWN:
- event.preventDefault();
- if ( select.visible() ) {
- select.next();
- } else {
- onChange(0, true);
- }
+
+ case 13: // return
+ if (self.active_) {
+ self.selectCurrent();
+ if (self.options.preventDefaultReturn) {
+ e.preventDefault();
+ return false;
+ }
+ }
+ if (self.options.preventDefaultReturn === 2) {
+ e.preventDefault();
+ return false;
+ }
break;
-
- case KEY.PAGEUP:
- event.preventDefault();
- if ( select.visible() ) {
- select.pageUp();
- } else {
- onChange(0, true);
- }
+
+ case 27: // escape
+ if (self.active_) {
+ e.preventDefault();
+ self.deactivate(true);
+ return false;
+ }
break;
-
- case KEY.PAGEDOWN:
- event.preventDefault();
- if ( select.visible() ) {
- select.pageDown();
- } else {
- onChange(0, true);
- }
- break;
-
- // matches also semicolon
- case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
- case KEY.TAB:
- case KEY.RETURN:
- if (event.keyCode == KEY.RETURN)
- return_key_pressed_for_autocomplete = false;
- if( selectCurrent() ) {
- // stop default to prevent a form submit, Opera needs special handling
- event.preventDefault();
- blockSubmit = true;
-
- // JG: set flag to indicate that a selection just occurred using the return key. FYI:
- // event.stopPropagation() does not work.
- if (event.keyCode == KEY.RETURN)
- return_key_pressed_for_autocomplete = true;
-
- return false;
- }
-
- case KEY.ESC:
- select.hide();
- break;
- case KEY.COLON:
- break;
-
- default:
- clearTimeout(timeout);
- timeout = setTimeout(onChange, options.delay);
- break;
- }
- }).focus(function(){
- // track whether the field has focus, we shouldn't process any
- // results if the field no longer has focus
- hasFocus++;
- }).blur(function() {
- hasFocus = 0;
- if (!config.mouseDownOnSelect) {
- // JG: if blur and user is not selecting with mouse, hide
- // object.
- select.hide();
- }
- return this;
- }).click(function() {
- // show select when clicking in a focused field
- if ( hasFocus++ > 1 && !select.visible() ) {
- onChange(0, true);
- }
- return this;
- }).bind("search", function() {
- // TODO why not just specifying both arguments?
- var fn = (arguments.length > 1) ? arguments[1] : null;
- function findValueCallback(q, data) {
- var result;
- if( data && data.length ) {
- for (var i=0; i < data.length; i++) {
- if( data[i].result.toLowerCase() == q.toLowerCase() ) {
- result = data[i];
- break;
- }
- }
+
+ default:
+ self.activate();
+
}
- if( typeof fn == "function" ) fn(result);
- else $input.trigger("result", result && [result.data, result.value]);
- }
- $.each(trimWords($input.val()), function(i, value) {
- request(value, findValueCallback, findValueCallback);
});
- return this;
- }).bind("flushCache", function() {
- cache.flush();
- }).bind("setOptions", function() {
- $.extend(options, arguments[1]);
- // if we've updated the data, repopulate
- if ( "data" in arguments[1] )
- cache.populate();
- }).bind("unautocomplete", function() {
- select.unbind();
- $input.unbind();
- $(input.form).unbind(".autocomplete");
- })
- // JG: Show all data in cache.
- .bind("showAllInCache", function() {
- receiveData('', cache.load(''));
- });
-
- function selectCurrent() {
- var selected = select.selected();
- if( !selected )
- return false;
-
- var v = selected.result;
- previousValue = v;
-
- if ( options.multiple ) {
- var words = trimWords($input.val());
- if ( words.length > 1 ) {
- v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v;
+ /**
+ * Attach paste event listener because paste may occur much later then keydown or even without a keydown at all
+ */
+ $elem.on('paste', function() {
+ self.activate();
+ });
+
+ /**
+ * Finish on blur event
+ * Use a timeout because instant blur gives race conditions
+ */
+ var onBlurFunction = function() {
+ self.deactivate(true);
+ }
+ $elem.blur(function() {
+ if (self.finishOnBlur_) {
+ self.finishTimeout_ = setTimeout(onBlurFunction, 200);
}
- v += options.multipleSeparator;
+ });
+ /**
+ * Catch a race condition on form submit
+ */
+ $elem.parents('form').on('submit', onBlurFunction);
+
+ };
+
+ /**
+ * Position output DOM elements
+ * @private
+ */
+ $.Autocompleter.prototype.position = function() {
+ var offset = this.dom.$elem.offset();
+ var height = this.dom.$results.outerHeight();
+ var totalHeight = $(window).outerHeight();
+ var inputBottom = offset.top + this.dom.$elem.outerHeight();
+ var bottomIfDown = inputBottom + height;
+ // Set autocomplete results at the bottom of input
+ var position = {top: inputBottom, left: offset.left};
+ if (bottomIfDown > totalHeight) {
+ // Try to set autocomplete results at the top of input
+ var topIfUp = offset.top - height;
+ if (topIfUp >= 0) {
+ position.top = topIfUp;
+ }
}
-
- $input.val(v);
- hideResultsNow();
- $input.trigger("result", [selected.data, selected.value]);
- return true;
- }
-
- function onChange(crap, skipPrevCheck) {
- if( lastKeyPressCode == KEY.DEL ) {
- select.hide();
- return;
+ this.dom.$results.css(position);
+ };
+
+ /**
+ * Read from cache
+ * @private
+ */
+ $.Autocompleter.prototype.cacheRead = function(filter) {
+ var filterLength, searchLength, search, maxPos, pos;
+ if (this.options.useCache) {
+ filter = String(filter);
+ filterLength = filter.length;
+ if (this.options.matchSubset) {
+ searchLength = 1;
+ } else {
+ searchLength = filterLength;
+ }
+ while (searchLength <= filterLength) {
+ if (this.options.matchInside) {
+ maxPos = filterLength - searchLength;
+ } else {
+ maxPos = 0;
+ }
+ pos = 0;
+ while (pos <= maxPos) {
+ search = filter.substr(0, searchLength);
+ if (this.cacheData_[search] !== undefined) {
+ return this.cacheData_[search];
+ }
+ pos++;
+ }
+ searchLength++;
+ }
}
+ return false;
+ };
- var currentValue = $input.val();
-
- if ( !skipPrevCheck && currentValue == previousValue )
- return;
-
- previousValue = currentValue;
-
- currentValue = lastWord(currentValue);
- if ( currentValue.length >= options.minChars) {
- $input.addClass(options.loadingClass);
- if (!options.matchCase)
- currentValue = currentValue.toLowerCase();
- request(currentValue, receiveData, hideResultsNow);
- } else {
- stopLoading();
- select.hide();
+ /**
+ * Write to cache
+ * @private
+ */
+ $.Autocompleter.prototype.cacheWrite = function(filter, data) {
+ if (this.options.useCache) {
+ if (this.cacheLength_ >= this.options.maxCacheLength) {
+ this.cacheFlush();
+ }
+ filter = String(filter);
+ if (this.cacheData_[filter] !== undefined) {
+ this.cacheLength_++;
+ }
+ this.cacheData_[filter] = data;
+ return this.cacheData_[filter];
}
+ return false;
};
-
- function trimWords(value) {
- if ( !value ) {
- return [""];
+
+ /**
+ * Flush cache
+ * @public
+ */
+ $.Autocompleter.prototype.cacheFlush = function() {
+ this.cacheData_ = {};
+ this.cacheLength_ = 0;
+ };
+
+ /**
+ * Call hook
+ * Note that all called hooks are passed the autocompleter object
+ * @param {string} hook
+ * @param data
+ * @returns Result of called hook, false if hook is undefined
+ */
+ $.Autocompleter.prototype.callHook = function(hook, data) {
+ var f = this.options[hook];
+ if (f && $.isFunction(f)) {
+ return f(data, this);
}
- var words = value.split( options.multipleSeparator );
- var result = [];
- $.each(words, function(i, value) {
- if ( $.trim(value) )
- result[i] = $.trim(value);
- });
- return result;
- }
-
- function lastWord(value) {
- if ( !options.multiple )
- return value;
- var words = trimWords(value);
- return words[words.length - 1];
- }
-
- // fills in the input box w/the first match (assumed to be the best match)
- // q: the term entered
- // sValue: the first matching result
- function autoFill(q, sValue){
- // autofill in the complete box w/the first match as long as the user hasn't entered in more data
- // if the last user key pressed was backspace, don't autofill
- if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
- // fill in the value (keep the case the user has typed)
- $input.val($input.val() + sValue.substring(lastWord(previousValue).length));
- // select the portion of the value not typed by the user (so the next character will erase)
- $.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
+ return false;
+ };
+
+ /**
+ * Set timeout to activate autocompleter
+ */
+ $.Autocompleter.prototype.activate = function() {
+ if (!this.options.enabled) return;
+ var self = this;
+ if (this.keyTimeout_) {
+ clearTimeout(this.keyTimeout_);
+ }
+ this.keyTimeout_ = setTimeout(function() {
+ self.activateNow();
+ }, this.options.delay);
+ };
+
+ /**
+ * Activate autocompleter immediately
+ */
+ $.Autocompleter.prototype.activateNow = function() {
+ var value = this.beforeUseConverter(this.dom.$elem.val());
+ if (value !== this.lastProcessedValue_ && value !== this.lastSelectedValue_) {
+ this.fetchData(value);
}
};
- function hideResults() {
- clearTimeout(timeout);
- timeout = setTimeout(hideResultsNow, 200);
- };
-
- function hideResultsNow() {
- var wasVisible = select.visible();
- select.hide();
- clearTimeout(timeout);
- stopLoading();
- if (options.mustMatch) {
- // call search and run callback
- $input.search(
- function (result){
- // if no value found, clear the input box
- if( !result ) {
- if (options.multiple) {
- var words = trimWords($input.val()).slice(0, -1);
- $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
- }
- else
- $input.val( "" );
- }
- }
- );
- }
- if (wasVisible)
- // position cursor at end of input field
- $.Autocompleter.Selection(input, input.value.length, input.value.length);
- };
-
- function receiveData(q, data) {
- if ( data && data.length && hasFocus ) {
- stopLoading();
- select.display(data, q);
- autoFill(q, data[0].value);
- select.show();
+ /**
+ * Get autocomplete data for a given value
+ * @param {string} value Value to base autocompletion on
+ * @private
+ */
+ $.Autocompleter.prototype.fetchData = function(value) {
+ var self = this;
+ var processResults = function(results, filter) {
+ if (self.options.processData) {
+ results = self.options.processData(results);
+ }
+ self.showResults(self.filterResults(results, filter), filter);
+ };
+ this.lastProcessedValue_ = value;
+ if (value.length < this.options.minChars) {
+ processResults([], value);
+ } else if (this.options.data) {
+ processResults(this.options.data, value);
} else {
- hideResultsNow();
+ this.fetchRemoteData(value, function(remoteData) {
+ processResults(remoteData, value);
+ });
}
};
- function request(term, success, failure) {
- if (!options.matchCase)
- term = term.toLowerCase();
- var data = cache.load(term);
-
- // JG: hack: if term ends with ':', kill data to force an ajax request.
- if (term.endsWith(":"))
- data = null;
-
- // recieve the cached data
- if (data && data.length) {
- success(term, data);
- // if an AJAX url has been supplied, try loading the data now
- } else if( (typeof options.url == "string") && (options.url.length > 0) ){
- var extraParams = {
- timestamp: +new Date()
+ /**
+ * Get remote autocomplete data for a given value
+ * @param {string} filter The filter to base remote data on
+ * @param {function} callback The function to call after data retrieval
+ * @private
+ */
+ $.Autocompleter.prototype.fetchRemoteData = function(filter, callback) {
+ var data = this.cacheRead(filter);
+ if (data) {
+ callback(data);
+ } else {
+ var self = this;
+ var dataType = self.options.remoteDataType === 'json' ? 'json' : 'text';
+ var ajaxCallback = function(data) {
+ var parsed = false;
+ if (data !== false) {
+ parsed = self.parseRemoteData(data);
+ self.cacheWrite(filter, parsed);
+ }
+ self.dom.$elem.removeClass(self.options.loadingClass);
+ callback(parsed);
};
- $.each(options.extraParams, function(key, param) {
- extraParams[key] = typeof param == "function" ? param() : param;
+ this.dom.$elem.addClass(this.options.loadingClass);
+ $.ajax({
+ url: this.makeUrl(filter),
+ success: ajaxCallback,
+ error: function(jqXHR, textStatus, errorThrown) {
+ if($.isFunction(self.options.onError)) {
+ self.options.onError(jqXHR, textStatus, errorThrown);
+ } else {
+ ajaxCallback(false);
+ }
+ },
+ dataType: dataType
});
-
- $.ajax({
- // try to leverage ajaxQueue plugin to abort previous requests
- mode: "abort",
- // limit abortion to this input
- port: "autocomplete" + input.name,
- dataType: options.dataType,
- url: options.url,
- data: $.extend({
- q: lastWord(term),
- limit: options.max
- }, extraParams),
- success: function(data) {
- var parsed = options.parse && options.parse(data) || parse(data);
- cache.add(term, parsed);
- success(term, parsed);
- }
- });
- } else {
- // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
- select.emptyList();
- failure(term);
}
};
-
- function parse(data) {
- var parsed = [];
- var rows = data.split("\n");
- for (var i=0; i < rows.length; i++) {
- var row = $.trim(rows[i]);
- if (row) {
- row = row.split("|");
- parsed[parsed.length] = {
- data: row,
- value: row[0],
- result: options.formatResult && options.formatResult(row, row[0]) || row[0]
- };
+
+ /**
+ * Create or update an extra parameter for the remote request
+ * @param {string} name Parameter name
+ * @param {string} value Parameter value
+ * @public
+ */
+ $.Autocompleter.prototype.setExtraParam = function(name, value) {
+ var index = $.trim(String(name));
+ if (index) {
+ if (!this.options.extraParams) {
+ this.options.extraParams = {};
+ }
+ if (this.options.extraParams[index] !== value) {
+ this.options.extraParams[index] = value;
+ this.cacheFlush();
}
}
- return parsed;
+
+ return this;
};
- function stopLoading() {
- $input.removeClass(options.loadingClass);
+ /**
+ * Build the url for a remote request
+ * If options.queryParamName === false, append query to url instead of using a GET parameter
+ * @param {string} param The value parameter to pass to the backend
+ * @returns {string} The finished url with parameters
+ */
+ $.Autocompleter.prototype.makeUrl = function(param) {
+ var self = this;
+ var url = this.options.url;
+ var params = $.extend({}, this.options.extraParams);
+
+ if (this.options.queryParamName === false) {
+ url += encodeURIComponent(param);
+ } else {
+ params[this.options.queryParamName] = param;
+ }
+
+ return makeUrl(url, params);
};
-};
+ /**
+ * Parse data received from server
+ * @param remoteData Data received from remote server
+ * @returns {array} Parsed data
+ */
+ $.Autocompleter.prototype.parseRemoteData = function(remoteData) {
+ var remoteDataType;
+ var data = remoteData;
+ if (this.options.remoteDataType === 'json') {
+ remoteDataType = typeof(remoteData);
+ switch (remoteDataType) {
+ case 'object':
+ data = remoteData;
+ break;
+ case 'string':
+ data = $.parseJSON(remoteData);
+ break;
+ default:
+ throw new Error("Unexpected remote data type: " + remoteDataType);
+ }
+ return data;
+ }
+ return plainTextParser(data, this.options.lineSeparator, this.options.cellSeparator);
+ };
-$.Autocompleter.defaults = {
- inputClass: "ac_input",
- resultsClass: "ac_results",
- loadingClass: "ac_loading",
- minChars: 1,
- delay: 400,
- matchCase: false,
- matchSubset: true,
- matchContains: false,
- cacheLength: 10,
- max: 100,
- mustMatch: false,
- extraParams: {},
- selectFirst: true,
- formatItem: function(row) { return row[0]; },
- formatMatch: null,
- autoFill: false,
- width: 0,
- multiple: false,
- multipleSeparator: ", ",
- highlight: function(value, term) {
- // JG: short-circuit highlighting if term is empty string.
- if (term == "")
- return value;
- return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
- },
- scroll: true,
- scrollHeight: 180
-};
+ /**
+ * Default filter for results
+ * @param {Object} result
+ * @param {String} filter
+ * @returns {boolean} Include this result
+ * @private
+ */
+ $.Autocompleter.prototype.defaultFilter = function(result, filter) {
+ if (!result.value) {
+ return false;
+ }
+ if (this.options.filterResults) {
+ var pattern = this.matchStringConverter(filter);
+ var testValue = this.matchStringConverter(result.value);
+ if (!this.options.matchCase) {
+ pattern = pattern.toLowerCase();
+ testValue = testValue.toLowerCase();
+ }
+ var patternIndex = testValue.indexOf(pattern);
+ if (this.options.matchInside) {
+ return patternIndex > -1;
+ } else {
+ return patternIndex === 0;
+ }
+ }
+ return true;
+ };
-$.Autocompleter.Cache = function(options) {
+ /**
+ * Filter result
+ * @param {Object} result
+ * @param {String} filter
+ * @returns {boolean} Include this result
+ * @private
+ */
+ $.Autocompleter.prototype.filterResult = function(result, filter) {
+ // No filter
+ if (this.options.filter === false) {
+ return true;
+ }
+ // Custom filter
+ if ($.isFunction(this.options.filter)) {
+ return this.options.filter(result, filter);
+ }
+ // Default filter
+ return this.defaultFilter(result, filter);
+ };
- var data = {};
- var length = 0;
+ /**
+ * Filter results
+ * @param results
+ * @param filter
+ */
+ $.Autocompleter.prototype.filterResults = function(results, filter) {
+ var filtered = [];
+ var i, result;
- function matchSubset(s, sub) {
- if (!options.matchCase)
- s = s.toLowerCase();
- var i = s.indexOf(sub);
- if (i == -1) return false;
- return i == 0 || options.matchContains;
+ for (i = 0; i < results.length; i++) {
+ result = sanitizeResult(results[i]);
+ if (this.filterResult(result, filter)) {
+ filtered.push(result);
+ }
+ }
+ if (this.options.sortResults) {
+ filtered = this.sortResults(filtered, filter);
+ }
+ if (this.options.maxItemsToShow > 0 && this.options.maxItemsToShow < filtered.length) {
+ filtered.length = this.options.maxItemsToShow;
+ }
+ return filtered;
};
-
- function add(q, value) {
- if (length > options.cacheLength){
- flush();
+
+ /**
+ * Sort results
+ * @param results
+ * @param filter
+ */
+ $.Autocompleter.prototype.sortResults = function(results, filter) {
+ var self = this;
+ var sortFunction = this.options.sortFunction;
+ if (!$.isFunction(sortFunction)) {
+ sortFunction = function(a, b, f) {
+ return sortValueAlpha(a, b, self.options.matchCase);
+ };
}
- if (!data[q]){
- length++;
+ results.sort(function(a, b) {
+ return sortFunction(a, b, filter, self.options);
+ });
+ return results;
+ };
+
+ /**
+ * Convert string before matching
+ * @param s
+ * @param a
+ * @param b
+ */
+ $.Autocompleter.prototype.matchStringConverter = function(s, a, b) {
+ var converter = this.options.matchStringConverter;
+ if ($.isFunction(converter)) {
+ s = converter(s, a, b);
}
- data[q] = value;
- }
-
- function populate(){
- if( !options.data ) return false;
- // track the matches
- var stMatchSets = {},
- nullData = 0;
+ return s;
+ };
- // no url was specified, we need to adjust the cache length to make sure it fits the local data store
- if( !options.url ) options.cacheLength = 1;
-
- // track all options for minChars = 0
- stMatchSets[""] = [];
-
- // loop through the array and create a lookup structure
- for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
- var rawValue = options.data[i];
- // if rawValue is a string, make an array otherwise just reference the array
- rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
-
- var value = options.formatMatch(rawValue, i+1, options.data.length);
- if ( value === false )
- continue;
-
- if( !stMatchSets[value] ) {
- stMatchSets[value] = [];
+ /**
+ * Convert string before use
+ * @param {String} s
+ */
+ $.Autocompleter.prototype.beforeUseConverter = function(s) {
+ s = this.getValue(s);
+ var converter = this.options.beforeUseConverter;
+ if ($.isFunction(converter)) {
+ s = converter(s);
+ }
+ return s;
+ };
+
+ /**
+ * Enable finish on blur event
+ */
+ $.Autocompleter.prototype.enableFinishOnBlur = function() {
+ this.finishOnBlur_ = true;
+ };
+
+ /**
+ * Disable finish on blur event
+ */
+ $.Autocompleter.prototype.disableFinishOnBlur = function() {
+ this.finishOnBlur_ = false;
+ };
+
+ /**
+ * Create a results item (LI element) from a result
+ * @param result
+ */
+ $.Autocompleter.prototype.createItemFromResult = function(result) {
+ var self = this;
+ var $li = $('<li/>');
+ $li.html(this.showResult(result.value, result.data));
+ $li.data({value: result.value, data: result.data})
+ .click(function() {
+ self.selectItem($li);
+ })
+ .mousedown(self.disableFinishOnBlur)
+ .mouseup(self.enableFinishOnBlur)
+ ;
+ return $li;
+ };
+
+ /**
+ * Get all items from the results list
+ * @param result
+ */
+ $.Autocompleter.prototype.getItems = function() {
+ return $('>ul>li', this.dom.$results);
+ };
+
+ /**
+ * Show all results
+ * @param results
+ * @param filter
+ */
+ $.Autocompleter.prototype.showResults = function(results, filter) {
+ var numResults = results.length;
+ var self = this;
+ var $ul = $('<ul></ul>');
+ var i, result, $li, autoWidth, first = false, $first = false;
+
+ if (numResults) {
+ for (i = 0; i < numResults; i++) {
+ result = results[i];
+ $li = this.createItemFromResult(result);
+ $ul.append($li);
+ if (first === false) {
+ first = String(result.value);
+ $first = $li;
+ $li.addClass(this.options.firstItemClass);
+ }
+ if (i === numResults - 1) {
+ $li.addClass(this.options.lastItemClass);
+ }
}
- // if the match is a string
- var row = {
- value: value,
- data: rawValue,
- result: options.formatResult && options.formatResult(rawValue) || value
- };
-
- // push the current match into the set list
- stMatchSets[value].push(row);
+ this.dom.$results.html($ul).show();
- // keep track of minChars zero items
- if ( nullData++ < options.max ) {
- stMatchSets[""].push(row);
+ // Always recalculate position since window size or
+ // input element location may have changed.
+ this.position();
+ if (this.options.autoWidth) {
+ autoWidth = this.dom.$elem.outerWidth() - this.dom.$results.outerWidth() + this.dom.$results.width();
+ this.dom.$results.css(this.options.autoWidth, autoWidth);
}
- };
-
- // add the data items to the cache
- $.each(stMatchSets, function(i, value) {
- // increase the cache size
- options.cacheLength++;
- // add to the cache
- add(i, value);
- });
- }
-
- // populate any existing data
- setTimeout(populate, 25);
-
- function flush(){
- data = {};
- length = 0;
- }
-
- return {
- flush: flush,
- add: add,
- populate: populate,
- load: function(q) {
- if (!options.cacheLength || !length)
- return null;
-
- /*
- * if dealing w/local data and matchContains than we must make sure
- * to loop through all the data collections looking for matches
- */
- if( !options.url && options.matchContains ) {
- // track all matches
- var csub = [];
- // loop through all the data grids for matches
- for( var k in data ) {
- // don't search through the stMatchSets[""] (minChars: 0) cache
- // this prevents duplicates
- if( k.length > 0 ){
- var c = data[k];
- $.each(c, function(i, x) {
- // if we've got a match, add it to the array
- if (matchSubset(x.value, q)) {
- csub.push(x);
- }
- });
- }
- }
- return csub;
- } else
- // if the exact item exists, use it
- if (data[q]) {
- return data[q];
- } else
- if (options.matchSubset) {
- for (var i = q.length - 1; i >= options.minChars; i--) {
- var c = data[q.substr(0, i)];
- if (c) {
- var csub = [];
- $.each(c, function(i, x) {
- if ( (x.data.indexOf("#Header") == 0) ||
- (matchSubset(x.value, q)) ) {
- csub[csub.length] = x;
- }
- });
- return csub;
- }
- }
-
+ this.getItems().hover(
+ function() { self.focusItem(this); },
+ function() { /* void */ }
+ );
+ if (this.autoFill(first, filter) || this.options.selectFirst || (this.options.selectOnly && numResults === 1)) {
+ this.focusItem($first);
}
- return null;
+ this.active_ = true;
+ } else {
+ this.hideResults();
+ this.active_ = false;
}
};
-};
-$.Autocompleter.Select = function (options, input, select, config) {
- var CLASSES = {
- ACTIVE: "ac_over"
+ $.Autocompleter.prototype.showResult = function(value, data) {
+ if ($.isFunction(this.options.showResult)) {
+ return this.options.showResult(value, data);
+ } else {
+ return $('<p></p>').text(value).html();
+ }
};
-
- var listItems,
- active = -1,
- data,
- term = "",
- needsInit = true,
- element,
- list;
-
- // Create results
- function init() {
- if (!needsInit)
- return;
-
- element = $("<div/>")
- .hide()
- .addClass(options.resultsClass)
- .css("position", "absolute")
- .bind("mouseleave", function() {
- element.hide();
- })
- .appendTo(document.body);
- list = $("<ul/>").appendTo(element).mouseover( function(event) {
- if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
- active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
- // JG: Only add active class if target is not a header.
- if (!headerAtPosition(active))
- $(target(event)).addClass(CLASSES.ACTIVE);
+ $.Autocompleter.prototype.autoFill = function(value, filter) {
+ var lcValue, lcFilter, valueLength, filterLength;
+ if (this.options.autoFill && this.lastKeyPressed_ !== 8) {
+ lcValue = String(value).toLowerCase();
+ lcFilter = String(filter).toLowerCase();
+ valueLength = value.length;
+ filterLength = filter.length;
+ if (lcValue.substr(0, filterLength) === lcFilter) {
+ var d = this.getDelimiterOffsets();
+ var pad = d.start ? ' ' : ''; // if there is a preceding delimiter
+ this.setValue( pad + value );
+ var start = filterLength + d.start + pad.length;
+ var end = valueLength + d.start + pad.length;
+ this.selectRange(start, end);
+ return true;
}
- }).click(function(event) {
- // JG: Ignore click on header.
- active = $("li", list).index(target(event));
- if (headerAtPosition(active))
- return;
+ }
+ return false;
+ };
- // Handle click on autocomplete options.
- $(target(event)).addClass(CLASSES.ACTIVE);
- select();
- // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
- input.focus();
- return false;
- }).mousedown(function() {
- config.mouseDownOnSelect = true;
- }).mouseup(function() {
- config.mouseDownOnSelect = false;
- });
+ $.Autocompleter.prototype.focusNext = function() {
+ this.focusMove(+1);
+ };
- if( options.width > 0 )
- element.css("width", options.width);
+ $.Autocompleter.prototype.focusPrev = function() {
+ this.focusMove(-1);
+ };
- needsInit = false;
- }
-
- function target(event) {
- var element = event.target;
- while(element && element.tagName != "LI")
- element = element.parentNode;
- // more fun with IE, sometimes event.target is empty, just ignore it then
- if(!element)
- return [];
- return element;
- }
+ $.Autocompleter.prototype.focusMove = function(modifier) {
+ var $items = this.getItems();
+ modifier = sanitizeInteger(modifier, 0);
+ if (modifier) {
+ for (var i = 0; i < $items.length; i++) {
+ if ($($items[i]).hasClass(this.selectClass_)) {
+ this.focusItem(i + modifier);
+ return;
+ }
+ }
+ }
+ this.focusItem(0);
+ };
- // JG: Returns true iff there is a header element at the given position.
- function headerAtPosition(position) {
- dataAtPosition = data[position].data;
- return (dataAtPosition[0].indexOf("#Header") == 0);
- }
-
- function moveSelect(step) {
- listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
- // JG: while active item is a header, continue stepping.
- var isHeader = false;
- do {
- movePosition(step);
- isHeader = headerAtPosition(active);
- }
- while (isHeader);
- var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
-
- if(options.scroll) {
- var offset = 0;
- listItems.slice(0, active).each(function() {
- offset += this.offsetHeight;
- });
- if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
- list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
- } else if(offset < list.scrollTop()) {
- list.scrollTop(offset);
+ $.Autocompleter.prototype.focusItem = function(item) {
+ var $item, $items = this.getItems();
+ if ($items.length) {
+ $items.removeClass(this.selectClass_).removeClass(this.options.selectClass);
+ if (typeof item === 'number') {
+ if (item < 0) {
+ item = 0;
+ } else if (item >= $items.length) {
+ item = $items.length - 1;
+ }
+ $item = $($items[item]);
+ } else {
+ $item = $(item);
+ }
+ if ($item) {
+ $item.addClass(this.selectClass_).addClass(this.options.selectClass);
}
}
};
-
- function movePosition(step) {
- active += step;
- if (active < 0) {
- active = listItems.size() - 1;
- } else if (active >= listItems.size()) {
- active = 0;
- }
- }
-
- function limitNumberOfItems(available) {
- return options.max && options.max < available
- ? options.max
- : available;
- }
-
- function fillList() {
- list.empty();
- var max = limitNumberOfItems(data.length);
- for (var i=0; i < max; i++) {
- if (!data[i])
- continue;
-
- var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
- if ( formatted === false )
- continue;
- // JG: Build list item by formatting the item and choosing a CSS class.
- if (headerAtPosition(i)) {
- // Found header element; only add header if there are subsequent elements.
- if (i != max-1)
- var li = $("<li/>").html(data[i].data[1]).addClass("ac_header").appendTo(list)[0];
- } else {
- // Found completion element.
- var li = $("<li/>").html(options.highlight(formatted, term)).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
- }
-
- $.data(li, "ac_data", data[i]);
- }
- listItems = list.find("li");
- if ( options.selectFirst ) {
- listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
- active = 0;
- }
- // apply bgiframe if available
- if ( $.fn.bgiframe )
- list.bgiframe();
- }
-
- return {
- display: function(d, q) {
- init();
- data = d;
- term = q;
- fillList();
- },
- next: function() {
- moveSelect(1);
- },
- prev: function() {
- moveSelect(-1);
- },
- pageUp: function() {
- if (active != 0 && active - 8 < 0) {
- moveSelect( -active );
- } else {
- moveSelect(-8);
- }
- },
- pageDown: function() {
- if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
- moveSelect( listItems.size() - 1 - active );
- } else {
- moveSelect(8);
- }
- },
- hide: function() {
- element && element.hide();
- listItems && listItems.removeClass(CLASSES.ACTIVE);
- active = -1;
- },
- visible : function() {
- return element && element.is(":visible");
- },
- current: function() {
- return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
- },
- show: function() {
- var offset = $(input).offset();
- element.css({
- width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
- top: offset.top + input.offsetHeight,
- left: offset.left
- }).show();
- if(options.scroll) {
- list.scrollTop(0);
- list.css({
- maxHeight: options.scrollHeight,
- overflow: 'auto'
- });
-
- if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
- var listHeight = 0;
- listItems.each(function() {
- listHeight += this.offsetHeight;
- });
- var scrollbarsVisible = listHeight > options.scrollHeight;
- list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
- if (!scrollbarsVisible) {
- // IE doesn't recalculate width when scrollbar disappears
- listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
- }
- }
-
- }
- },
- selected: function() {
- var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
- return selected && selected.length && $.data(selected[0], "ac_data");
- },
- emptyList: function (){
- list && list.empty();
- },
- unbind: function() {
- element && element.remove();
+ $.Autocompleter.prototype.selectCurrent = function() {
+ var $item = $('li.' + this.selectClass_, this.dom.$results);
+ if ($item.length === 1) {
+ this.selectItem($item);
+ } else {
+ this.deactivate(false);
}
};
-};
-$.Autocompleter.Selection = function(field, start, end) {
- if( field.createTextRange ){
- var selRange = field.createTextRange();
- selRange.collapse(true);
- selRange.moveStart("character", start);
- selRange.moveEnd("character", end);
- selRange.select();
- } else if( field.setSelectionRange ){
- field.setSelectionRange(start, end);
- } else {
- if( field.selectionStart ){
- field.selectionStart = start;
- field.selectionEnd = end;
+ $.Autocompleter.prototype.selectItem = function($li) {
+ var value = $li.data('value');
+ var data = $li.data('data');
+ var displayValue = this.displayValue(value, data);
+ var processedDisplayValue = this.beforeUseConverter(displayValue);
+ this.lastProcessedValue_ = processedDisplayValue;
+ this.lastSelectedValue_ = processedDisplayValue;
+ var d = this.getDelimiterOffsets();
+ var delimiter = this.options.delimiterChar;
+ var elem = this.dom.$elem;
+ var extraCaretPos = 0;
+ if ( this.options.useDelimiter ) {
+ // if there is a preceding delimiter, add a space after the delimiter
+ if ( elem.val().substring(d.start-1, d.start) == delimiter && delimiter != ' ' ) {
+ displayValue = ' ' + displayValue;
+ }
+ // if there is not already a delimiter trailing this value, add it
+ if ( elem.val().substring(d.end, d.end+1) != delimiter && this.lastKeyPressed_ != this.options.delimiterKeyCode ) {
+ displayValue = displayValue + delimiter;
+ } else {
+ // move the cursor after the existing trailing delimiter
+ extraCaretPos = 1;
+ }
}
- }
- field.focus();
-};
+ this.setValue(displayValue);
+ this.setCaret(d.start + displayValue.length + extraCaretPos);
+ this.callHook('onItemSelect', { value: value, data: data });
+ this.deactivate(true);
+ elem.focus();
+ };
-})(jQuery);
+ $.Autocompleter.prototype.displayValue = function(value, data) {
+ if ($.isFunction(this.options.displayValue)) {
+ return this.options.displayValue(value, data);
+ }
+ return value;
+ };
+
+ $.Autocompleter.prototype.hideResults = function() {
+ this.dom.$results.hide();
+ };
+
+ $.Autocompleter.prototype.deactivate = function(finish) {
+ if (this.finishTimeout_) {
+ clearTimeout(this.finishTimeout_);
+ }
+ if (this.keyTimeout_) {
+ clearTimeout(this.keyTimeout_);
+ }
+ if (finish) {
+ if (this.lastProcessedValue_ !== this.lastSelectedValue_) {
+ if (this.options.mustMatch) {
+ this.setValue('');
+ }
+ this.callHook('onNoMatch');
+ }
+ if (this.active_) {
+ this.callHook('onFinish');
+ }
+ this.lastKeyPressed_ = null;
+ this.lastProcessedValue_ = null;
+ this.lastSelectedValue_ = null;
+ this.active_ = false;
+ }
+ this.hideResults();
+ };
+
+ $.Autocompleter.prototype.selectRange = function(start, end) {
+ var input = this.dom.$elem.get(0);
+ if (input.setSelectionRange) {
+ input.focus();
+ input.setSelectionRange(start, end);
+ } else if (input.createTextRange) {
+ var range = input.createTextRange();
+ range.collapse(true);
+ range.moveEnd('character', end);
+ range.moveStart('character', start);
+ range.select();
+ }
+ };
+
+ /**
+ * Move caret to position
+ * @param {Number} pos
+ */
+ $.Autocompleter.prototype.setCaret = function(pos) {
+ this.selectRange(pos, pos);
+ };
+
+ /**
+ * Get caret position
+ */
+ $.Autocompleter.prototype.getCaret = function() {
+ var $elem = this.dom.$elem;
+ var elem = $elem[0];
+ var val, selection, range, start, end, stored_range;
+ if (elem.createTextRange) { // IE
+ selection = document.selection;
+ if (elem.tagName.toLowerCase() != 'textarea') {
+ val = $elem.val();
+ range = selection.createRange().duplicate();
+ range.moveEnd('character', val.length);
+ if (range.text === '') {
+ start = val.length;
+ } else {
+ start = val.lastIndexOf(range.text);
+ }
+ range = selection.createRange().duplicate();
+ range.moveStart('character', -val.length);
+ end = range.text.length;
+ } else {
+ range = selection.createRange();
+ stored_range = range.duplicate();
+ stored_range.moveToElementText(elem);
+ stored_range.setEndPoint('EndToEnd', range);
+ start = stored_range.text.length - range.text.length;
+ end = start + range.text.length;
+ }
+ } else {
+ start = $elem[0].selectionStart;
+ end = $elem[0].selectionEnd;
+ }
+ return {
+ start: start,
+ end: end
+ };
+ };
+
+ /**
+ * Set the value that is currently being autocompleted
+ * @param {String} value
+ */
+ $.Autocompleter.prototype.setValue = function(value) {
+ if ( this.options.useDelimiter ) {
+ // set the substring between the current delimiters
+ var val = this.dom.$elem.val();
+ var d = this.getDelimiterOffsets();
+ var preVal = val.substring(0, d.start);
+ var postVal = val.substring(d.end);
+ value = preVal + value + postVal;
+ }
+ this.dom.$elem.val(value);
+ };
+
+ /**
+ * Get the value currently being autocompleted
+ * @param {String} value
+ */
+ $.Autocompleter.prototype.getValue = function(value) {
+ if ( this.options.useDelimiter ) {
+ var d = this.getDelimiterOffsets();
+ return value.substring(d.start, d.end).trim();
+ } else {
+ return value;
+ }
+ };
+
+ /**
+ * Get the offsets of the value currently being autocompleted
+ */
+ $.Autocompleter.prototype.getDelimiterOffsets = function() {
+ var val = this.dom.$elem.val();
+ if ( this.options.useDelimiter ) {
+ var preCaretVal = val.substring(0, this.getCaret().start);
+ var start = preCaretVal.lastIndexOf(this.options.delimiterChar) + 1;
+ var postCaretVal = val.substring(this.getCaret().start);
+ var end = postCaretVal.indexOf(this.options.delimiterChar);
+ if ( end == -1 ) end = val.length;
+ end += this.getCaret().start;
+ } else {
+ start = 0;
+ end = val.length;
+ }
+ return {
+ start: start,
+ end: end
+ };
+ };
+
+})(jQuery);
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: DataProviders: add hierarchy module and xml provider, add provider to datatype
by commits-noreply@bitbucket.org 08 Aug '13
by commits-noreply@bitbucket.org 08 Aug '13
08 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/bf6bf3b5edfd/
Changeset: bf6bf3b5edfd
User: carlfeberhard
Date: 2013-08-08 18:59:34
Summary: DataProviders: add hierarchy module and xml provider, add provider to datatype
Affected #: 5 files
diff -r f46505803e8f0efd26be16f9e18353fbdc969205 -r bf6bf3b5edfdc409f235cb91edcc9d91246df816 lib/galaxy/datatypes/dataproviders/__init__.py
--- a/lib/galaxy/datatypes/dataproviders/__init__.py
+++ b/lib/galaxy/datatypes/dataproviders/__init__.py
@@ -23,6 +23,7 @@
import base
import chunk
import line
+import hierarchy
import column
import external
import dataset
diff -r f46505803e8f0efd26be16f9e18353fbdc969205 -r bf6bf3b5edfdc409f235cb91edcc9d91246df816 lib/galaxy/datatypes/dataproviders/decorators.py
--- a/lib/galaxy/datatypes/dataproviders/decorators.py
+++ b/lib/galaxy/datatypes/dataproviders/decorators.py
@@ -134,6 +134,7 @@
Parse the values in `query_kwargs` from strings to the proper types
listed in the same key in `settings`.
"""
+ #TODO: this was a relatively late addition: review and re-think
def list_from_query_string( s ):
# assume csv
return s.split( ',' )
@@ -155,10 +156,11 @@
#TODO: this would be the place to sanitize any strings
query_value = query_kwargs[ key ]
needed_type = settings[ key ]
- try:
- query_kwargs[ key ] = parsers[ needed_type ]( query_value )
- except ( KeyError, ValueError ):
- del query_kwargs[ key ]
+ if needed_type != 'str':
+ try:
+ query_kwargs[ key ] = parsers[ needed_type ]( query_value )
+ except ( KeyError, ValueError ):
+ del query_kwargs[ key ]
#TODO:?? do we want to remove query_kwarg entries NOT in settings?
return query_kwargs
diff -r f46505803e8f0efd26be16f9e18353fbdc969205 -r bf6bf3b5edfdc409f235cb91edcc9d91246df816 lib/galaxy/datatypes/dataproviders/hierarchy.py
--- /dev/null
+++ b/lib/galaxy/datatypes/dataproviders/hierarchy.py
@@ -0,0 +1,142 @@
+"""
+Dataproviders that iterate over lines from their sources.
+"""
+
+import line
+import xml.etree.ElementTree as elementtree
+
+_TODO = """
+"""
+
+import logging
+log = logging.getLogger( __name__ )
+
+
+# ----------------------------------------------------------------------------- hierarchal/tree data providers
+class HierarchalDataProvider( line.BlockDataProvider ):
+ """
+ Class that uses formats where a datum may have a parent or children
+ data.
+
+ e.g. XML, HTML, GFF3, Phylogenetic
+ """
+ def __init__( self, source, **kwargs ):
+ #TODO: (and defer to better (than I can write) parsers for each subtype)
+ super( HierarchalDataProvider, self ).__init__( source, **kwargs )
+
+
+# ----------------------------------------------------------------------------- xml
+class XMLDataProvider( HierarchalDataProvider ):
+ """
+ Data provider that converts selected XML elements to dictionaries.
+ """
+ # using elementtree's iterparse method to keep mem down
+ #TODO: this, however (AFAIK), prevents the use of xpath
+ settings = {
+ 'selector' : 'str', #urlencoded
+ 'max_depth' : 'int',
+ }
+ ITERPARSE_ALL_EVENTS = ( 'start', 'end', 'start-ns', 'end-ns' )
+ #TODO: move appropo into super
+
+ def __init__( self, source, selector=None, max_depth=None, **kwargs ):
+ """
+ :param selector: some partial string in the desired tags to return
+ :param max_depth: the number of generations of descendents to return
+ """
+ self.selector = selector
+ self.max_depth = max_depth
+ self.namespaces = {}
+
+ super( XMLDataProvider, self ).__init__( source, **kwargs )
+
+ def matches_selector( self, element, selector=None ):
+ """
+ Returns true if the ``element`` matches the ``selector``.
+
+ :param element: an XML ``ElementTree.Element``
+ :param selector: some partial string in the desired tags to return
+
+ Change point for more sophisticated selectors.
+ """
+ # search for partial match of selector to the element tag
+ #TODO: add more flexibility here w/o re-implementing xpath
+ #TODO: fails with '#' - browser thinks it's anchor - use urlencode
+ #TODO: need removal/replacement of etree namespacing here - then move to string match
+ return bool( ( selector == None )
+ or ( isinstance( element, elementtree.Element ) and selector in element.tag ) )
+
+ def element_as_dict( self, element ):
+ """
+ Converts an XML element (its text, tag, and attributes) to dictionary form.
+
+ :param element: an XML ``ElementTree.Element``
+ """
+ #TODO: Key collision is unlikely here, but still should be better handled
+ return {
+ 'tag' : element.tag,
+ 'text' : element.text.strip() if element.text else None,
+ # needs shallow copy to protect v. element.clear()
+ 'attrib' : dict( element.attrib )
+ }
+
+ def get_children( self, element, max_depth=None ):
+ """
+ Yield all children of element (and their children - recursively)
+ in dictionary form.
+ :param element: an XML ``ElementTree.Element``
+ :param max_depth: the number of generations of descendents to return
+ """
+ if not isinstance( max_depth, int ) or max_depth >= 1:
+ for child in element.getchildren():
+ child_data = self.element_as_dict( child )
+
+ next_depth = max_depth - 1 if isinstance( max_depth, int ) else None
+ grand_children = list( self.get_children( child, next_depth ) )
+ if grand_children:
+ child_data[ 'children' ] = grand_children
+
+ yield child_data
+
+ def __iter__( self ):
+ context = elementtree.iterparse( self.source, events=self.ITERPARSE_ALL_EVENTS )
+ context = iter( context )
+
+ selected_element = None
+ for event, element in context:
+ #print 'iterparse, event:', event
+ #print 'iterparse, element:', element, ( element.tag if hasattr( element, 'tag' ) else '' )
+
+ if event == 'start-ns':
+ ns, uri = element
+ self.namespaces[ ns ] = uri
+
+ elif event == 'start':
+ if( ( selected_element == None )
+ and ( self.matches_selector( element, self.selector ) ) ):
+ # start tag of selected element - wait for 'end' to emit/yield
+ selected_element = element
+
+ elif event == 'end':
+ if( ( selected_element != None )
+ and ( element == selected_element ) ):
+ self.num_valid_data_read += 1
+
+ # offset
+ if self.num_valid_data_read > self.offset:
+ # convert to dict and yield
+ selected_element_dict = self.element_as_dict( selected_element )
+ children = list( self.get_children( selected_element, self.max_depth ) )
+ if children:
+ selected_element_dict[ 'children' ] = children
+ yield selected_element_dict
+
+ # limit
+ self.num_data_returned += 1
+ if self.limit is not None and self.num_data_returned >= self.limit:
+ break
+
+ selected_element.clear()
+ selected_element = None
+
+ self.num_data_read += 1
diff -r f46505803e8f0efd26be16f9e18353fbdc969205 -r bf6bf3b5edfdc409f235cb91edcc9d91246df816 lib/galaxy/datatypes/dataproviders/line.py
--- a/lib/galaxy/datatypes/dataproviders/line.py
+++ b/lib/galaxy/datatypes/dataproviders/line.py
@@ -132,7 +132,7 @@
e.g. Fasta, GenBank, MAF, hg log
Note: mem intensive (gathers list of lines before output)
"""
- def __init__( self, source, new_block_delim_fn, block_filter_fn=None, **kwargs ):
+ def __init__( self, source, new_block_delim_fn=None, block_filter_fn=None, **kwargs ):
"""
:param new_block_delim_fn: T/F function to determine whether a given line
is the start of a new block.
@@ -214,7 +214,7 @@
"""
if self.new_block_delim_fn:
return self.new_block_delim_fn( line )
- return False
+ return True
# NOTE:
# some formats have one block attr per line
@@ -251,17 +251,3 @@
if self.block_filter_fn:
return self.block_filter_fn( block )
return block
-
-
-# ----------------------------------------------------------------------------- hierarchal/tree data providers
-class HierarchalDataProvider( BlockDataProvider ):
- """
- Class that uses formats where a datum may have a parent or children
- data.
-
- e.g. XML, HTML, GFF3, Phylogenetic
- """
- def __init__( self, source, **kwargs ):
- #TODO: (and defer to better (than I can write) parsers for each subtype)
- raise NotImplementedError( 'Abstract class' )
- super( HierarchalDataProvider, self ).__init__( source, **kwargs )
diff -r f46505803e8f0efd26be16f9e18353fbdc969205 -r bf6bf3b5edfdc409f235cb91edcc9d91246df816 lib/galaxy/datatypes/xml.py
--- a/lib/galaxy/datatypes/xml.py
+++ b/lib/galaxy/datatypes/xml.py
@@ -4,9 +4,11 @@
import data
import logging
from galaxy.datatypes.sniff import *
+import dataproviders
log = logging.getLogger(__name__)
+(a)dataproviders.decorators.has_dataproviders
class GenericXml( data.Text ):
"""Base format class for any XML file."""
file_ext = "xml"
@@ -47,6 +49,12 @@
data.Text.merge(split_files, output_file)
merge = staticmethod(merge)
+ @dataproviders.decorators.dataprovider_factory( 'xml', dataproviders.hierarchy.XMLDataProvider.settings )
+ def xml_dataprovider( self, dataset, **settings ):
+ dataset_source = dataproviders.dataset.DatasetDataProvider( dataset )
+ return dataproviders.hierarchy.XMLDataProvider( dataset_source, **settings )
+
+
class MEMEXml( GenericXml ):
"""MEME XML Output data"""
file_ext = "memexml"
@@ -62,6 +70,7 @@
def sniff( self, filename ):
return False
+
class CisML( GenericXml ):
"""CisML XML data""" #see: http://www.ncbi.nlm.nih.gov/pubmed/15001475
file_ext = "cisml"
@@ -77,6 +86,7 @@
def sniff( self, filename ):
return False
+
class Phyloxml( GenericXml ):
"""Format for defining phyloxml data http://www.phyloxml.org/"""
file_ext = "phyloxml"
@@ -105,4 +115,4 @@
Returns a list of visualizations for datatype.
"""
- return [ 'phyloviz' ]
\ No newline at end of file
+ return [ 'phyloviz' ]
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/8d8429484ac3/
Changeset: 8d8429484ac3
Branch: next-stable
User: carlfeberhard
Date: 2013-08-08 16:40:27
Summary: History view: fix broken scrollbar
Affected #: 1 file
diff -r 8ee4176d44bad2c1029356e869d601752ae54cd0 -r 8d8429484ac3ffef21fedd1077acf050c8aed459 templates/webapps/galaxy/history/view.mako
--- a/templates/webapps/galaxy/history/view.mako
+++ b/templates/webapps/galaxy/history/view.mako
@@ -27,6 +27,7 @@
<style type="text/css">
+ /* these don't appear to be used? */
.page-body
{
padding: 10px;
@@ -44,20 +45,38 @@
border-top: 4px solid #DDDDDD;
}
+
+ body {
+ padding: 0px;
+ margin: 0px;
+ }
+
div.unified-panel-body {
- position: relative;
+ position: absolute;
top: 0px;
- width: auto;
+ width: 100%;
+ }
+
+ #history-name-area {
+ margin: 12px 0px 0px 16px;
+ font-size: 120%;
+ }
+ #top-links {
+ margin: 4px 0px 8px 16px;
}
.historyItemContainer {
- padding-right: 3px;
- border-right-style: solid;
- border-right-color: #66AA66;
+ /*padding-right: 3px;*/
}
.historyItemBody {
display: none;
}
+ div.historyItemWrapper {
+ margin: 0px 4px 0px 4px ;
+ border-left: 1px solid #999999;
+ border-right: 1px solid #999999;
+ }
+ /* TODO: unify with other history css and into .less */
</style><noscript>
@@ -92,14 +111,13 @@
href_to_user_histories = h.url_for( controller='/history', action='list_published' )##should this instead be be None or empty string?
%>
- %if context.get( 'use_panels' ):
- <div class="unified-panel-header" unselectable="on">
- </div>
- %endif
-
<div class="unified-panel-body">
- <div class="wrapping" style="overflow: auto; height: 100%;">
+ <div style="overflow: auto; height: 100%;">
## Render view of history.
+ <div id="history-name-area" class="historyLinks" style="color: gray; font-weight: bold; padding: 0px 0px 5px 0px">
+ <div id="history-name">${history.get_display_name()}</div>
+ </div>
+
<div id="top-links" class="historyLinks" style="padding: 0px 0px 5px 0px">
%if not history.purged:
<a href="${h.url_for(controller='history', action='imp', id=trans.security.encode_id(history.id) )}">import and start using history</a> |
@@ -113,10 +131,6 @@
<a href="#" class="toggle">collapse all</a></div>
- <div id="history-name-area" class="historyLinks" style="color: gray; font-weight: bold; padding: 0px 0px 5px 0px">
- <div id="history-name">${history.get_display_name()}</div>
- </div>
-
%if history.deleted:
<div class="warningmessagesmall">
${_('You are currently viewing a deleted history!')}
https://bitbucket.org/galaxy/galaxy-central/commits/f46505803e8f/
Changeset: f46505803e8f
User: carlfeberhard
Date: 2013-08-08 16:41:18
Summary: merge next-stable
Affected #: 2 files
diff -r 3f8f52fa01f807b624ce05ef2186284b947c2e34 -r f46505803e8f0efd26be16f9e18353fbdc969205 templates/webapps/galaxy/history/view.mako
--- a/templates/webapps/galaxy/history/view.mako
+++ b/templates/webapps/galaxy/history/view.mako
@@ -27,6 +27,7 @@
<style type="text/css">
+ /* these don't appear to be used? */
.page-body
{
padding: 10px;
@@ -44,20 +45,38 @@
border-top: 4px solid #DDDDDD;
}
+
+ body {
+ padding: 0px;
+ margin: 0px;
+ }
+
div.unified-panel-body {
- position: relative;
+ position: absolute;
top: 0px;
- width: auto;
+ width: 100%;
+ }
+
+ #history-name-area {
+ margin: 12px 0px 0px 16px;
+ font-size: 120%;
+ }
+ #top-links {
+ margin: 4px 0px 8px 16px;
}
.historyItemContainer {
- padding-right: 3px;
- border-right-style: solid;
- border-right-color: #66AA66;
+ /*padding-right: 3px;*/
}
.historyItemBody {
display: none;
}
+ div.historyItemWrapper {
+ margin: 0px 4px 0px 4px ;
+ border-left: 1px solid #999999;
+ border-right: 1px solid #999999;
+ }
+ /* TODO: unify with other history css and into .less */
</style><noscript>
@@ -92,14 +111,13 @@
href_to_user_histories = h.url_for( controller='/history', action='list_published' )##should this instead be be None or empty string?
%>
- %if context.get( 'use_panels' ):
- <div class="unified-panel-header" unselectable="on">
- </div>
- %endif
-
<div class="unified-panel-body">
- <div class="wrapping" style="overflow: auto; height: 100%;">
+ <div style="overflow: auto; height: 100%;">
## Render view of history.
+ <div id="history-name-area" class="historyLinks" style="color: gray; font-weight: bold; padding: 0px 0px 5px 0px">
+ <div id="history-name">${history.get_display_name()}</div>
+ </div>
+
<div id="top-links" class="historyLinks" style="padding: 0px 0px 5px 0px">
%if not history.purged:
<a href="${h.url_for(controller='history', action='imp', id=trans.security.encode_id(history.id) )}">import and start using history</a> |
@@ -113,10 +131,6 @@
<a href="#" class="toggle">collapse all</a></div>
- <div id="history-name-area" class="historyLinks" style="color: gray; font-weight: bold; padding: 0px 0px 5px 0px">
- <div id="history-name">${history.get_display_name()}</div>
- </div>
-
%if history.deleted:
<div class="warningmessagesmall">
${_('You are currently viewing a deleted history!')}
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: Fix precision formatting in Circster
by commits-noreply@bitbucket.org 08 Aug '13
by commits-noreply@bitbucket.org 08 Aug '13
08 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/3f8f52fa01f8/
Changeset: 3f8f52fa01f8
User: guerler
Date: 2013-08-08 10:10:36
Summary: Fix precision formatting in Circster
Affected #: 1 file
diff -r ba8330a9fdefe0431ee1869e3a60c55caebc937c -r 3f8f52fa01f807b624ce05ef2186284b947c2e34 static/scripts/viz/circster.js
--- a/static/scripts/viz/circster.js
+++ b/static/scripts/viz/circster.js
@@ -85,10 +85,14 @@
*/
formatNum: function(num, sigDigits) {
// Use default of 2 sig. digits.
- if (sigDigits === undefined) {
+ if (sigDigits === undefined)
sigDigits = 2;
- }
-
+
+ // Verify input number
+ if (num === null)
+ return null;
+
+ // Calculate return value
var rval = null;
if (num < 1) {
rval = num.toPrecision(sigDigits);
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: Fix by adding jquery-ui to viz template
by commits-noreply@bitbucket.org 08 Aug '13
by commits-noreply@bitbucket.org 08 Aug '13
08 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ba8330a9fdef/
Changeset: ba8330a9fdef
User: guerler
Date: 2013-08-08 09:44:34
Summary: Fix by adding jquery-ui to viz template
Affected #: 1 file
diff -r f06d793860c40c59200c1441374ca4993854e94a -r ba8330a9fdefe0431ee1869e3a60c55caebc937c templates/webapps/galaxy/galaxy.panels.mako
--- a/templates/webapps/galaxy/galaxy.panels.mako
+++ b/templates/webapps/galaxy/galaxy.panels.mako
@@ -30,6 +30,7 @@
## load jscript libraries
${h.js(
'libs/jquery/jquery',
+ 'libs/jquery/jquery-ui',
'libs/bootstrap',
'libs/underscore',
'libs/backbone/backbone',
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: Remove new_browser.mako and instead use js-template and api function
by commits-noreply@bitbucket.org 08 Aug '13
by commits-noreply@bitbucket.org 08 Aug '13
08 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/f06d793860c4/
Changeset: f06d793860c4
User: guerler
Date: 2013-08-08 07:15:49
Summary: Remove new_browser.mako and instead use js-template and api function
Affected #: 7 files
diff -r f3a985005267a8c2022da3c0c8d9af496f8e5901 -r f06d793860c40c59200c1441374ca4993854e94a lib/galaxy/webapps/galaxy/api/genomes.py
--- a/lib/galaxy/webapps/galaxy/api/genomes.py
+++ b/lib/galaxy/webapps/galaxy/api/genomes.py
@@ -20,7 +20,7 @@
GET /api/genomes: returns a list of installed genomes
"""
- return self.app.genomes.get_dbkeys( trans )
+ return self.app.genomes.get_dbkeys( trans, **kwd )
@web.json
def show( self, trans, id, num=None, chrom=None, low=None, high=None, **kwd ):
diff -r f3a985005267a8c2022da3c0c8d9af496f8e5901 -r f06d793860c40c59200c1441374ca4993854e94a lib/galaxy/webapps/galaxy/controllers/visualization.py
--- a/lib/galaxy/webapps/galaxy/controllers/visualization.py
+++ b/lib/galaxy/webapps/galaxy/controllers/visualization.py
@@ -684,16 +684,6 @@
#
# Visualizations.
#
-
- @web.expose
- @web.require_login()
- def new_browser( self, trans, **kwargs ):
- """
- Provide info necessary for creating a new trackster browser.
- """
- return trans.fill_template( "tracks/new_browser.mako",
- dbkeys=trans.app.genomes.get_dbkeys( trans, chrom_info=True ),
- default_dbkey=kwargs.get("default_dbkey", None) )
@web.expose
@web.require_login( "use Galaxy visualizations", use_panels=True )
@@ -769,9 +759,6 @@
# save database key
app['default_dbkey'] = dbkey
-
- # add url
- app['new_browser'] = web.url_for( controller='visualization', action='new_browser', default_dbkey=dbkey )
else:
# load saved visualization
vis = self.get_visualization( trans, id, check_ownership=False, check_accessible=True )
diff -r f3a985005267a8c2022da3c0c8d9af496f8e5901 -r f06d793860c40c59200c1441374ca4993854e94a static/scripts/packed/viz/trackster.js
--- a/static/scripts/packed/viz/trackster.js
+++ b/static/scripts/packed/viz/trackster.js
@@ -1,1 +1,1 @@
-var ui=null;var view=null;var browser_router=null;require(["utils/galaxy.css","libs/jquery/jstorage","libs/jquery/jquery.event.drag","libs/jquery/jquery.event.hover","libs/jquery/jquery.mousewheel","libs/jquery/jquery-ui","libs/jquery/jquery-ui-combobox","libs/farbtastic","libs/jquery/jquery.form","libs/jquery/jquery.rating","mvc/ui"],function(a){a.load_file("/static/style/jquery.rating.css");a.load_file("/static/style/history.css");a.load_file("/static/style/autocomplete_tagging.css");a.load_file("/static/style/jquery-ui/smoothness/jquery-ui.css");a.load_file("/static/style/library.css");a.load_file("/static/style/trackster.css")});define(["libs/backbone/backbone-relational","viz/visualization","viz/trackster_ui"],function(c,a,b){var d=Backbone.View.extend({initialize:function(){ui=new b.TracksterUI(config.root);ui.createButtonMenu();ui.buttonMenu.$el.attr("style","float: right");$("#center .unified-panel-header-inner").append(ui.buttonMenu.$el);$("#right .unified-panel-title").append("Bookmarks");$("#right .unified-panel-icons").append("<a id='add-bookmark-button' class='icon-button menu-button plus-button' href='javascript:void(0);' title='Add bookmark'></a>");$("#right-border").click(function(){view.resize_window()});force_right_panel("hide");if(config.app.id){this.view_existing()}else{this.view_new()}},set_up_router:function(e){browser_router=new a.TrackBrowserRouter(e);Backbone.history.start()},view_existing:function(){var e=config.app.viz_config;view=ui.create_visualization({container:$("#center .unified-panel-body"),name:e.title,vis_id:e.vis_id,dbkey:e.dbkey},e.viewport,e.tracks,e.bookmarks,true);this.init_editor()},view_new:function(){var e=this;$.ajax({url:config.app.new_browser,data:{},error:function(){alert("Couldn't create new browser.")},success:function(f){show_modal("New Visualization",f,{Cancel:function(){window.location=config.root+"visualization/list"},Create:function(){e.create_browser($("#new-title").val(),$("#new-dbkey").val())}});$("#new-title").focus();$("select[name='dbkey']").combobox({appendTo:$("#overlay"),size:40});$("#overlay").css("overflow","auto")}})},create_browser:function(f,e){$(document).trigger("convert_to_values");view=ui.create_visualization({container:$("#center .unified-panel-body"),name:f,dbkey:e},config.app.gene_region);this.init_editor();view.editor=true;hide_modal()},init_editor:function(){$("#center .unified-panel-title").text(view.name+" ("+view.dbkey+")");if(config.app.add_dataset){$.ajax({url:config.root+"api/datasets/"+config.app.add_dataset,data:{hda_ldda:"hda",data_type:"track_config"},dataType:"json",success:function(e){view.add_drawable(b.object_from_template(e,view,view))}})}$("#add-bookmark-button").click(function(){var f=view.chrom+":"+view.low+"-"+view.high,e="Bookmark description";return ui.add_bookmark(f,e,true)});ui.init_keyboard_nav(view);this.set_up_router({view:view})}});return{GalaxyApp:d}});
\ No newline at end of file
+var ui=null;var view=null;var browser_router=null;require(["utils/galaxy.css","libs/jquery/jstorage","libs/jquery/jquery.event.drag","libs/jquery/jquery.event.hover","libs/jquery/jquery.mousewheel","libs/jquery/jquery-ui","libs/jquery/jquery-ui-combobox","libs/farbtastic","libs/jquery/jquery.form","libs/jquery/jquery.rating","mvc/ui"],function(a){a.load_file("/static/style/jquery.rating.css");a.load_file("/static/style/history.css");a.load_file("/static/style/autocomplete_tagging.css");a.load_file("/static/style/jquery-ui/smoothness/jquery-ui.css");a.load_file("/static/style/library.css");a.load_file("/static/style/trackster.css")});define(["libs/backbone/backbone-relational","viz/visualization","viz/trackster_ui"],function(c,a,b){var d=Backbone.View.extend({initialize:function(){ui=new b.TracksterUI(config.root);ui.createButtonMenu();ui.buttonMenu.$el.attr("style","float: right");$("#center .unified-panel-header-inner").append(ui.buttonMenu.$el);$("#right .unified-panel-title").append("Bookmarks");$("#right .unified-panel-icons").append("<a id='add-bookmark-button' class='icon-button menu-button plus-button' href='javascript:void(0);' title='Add bookmark'></a>");$("#right-border").click(function(){view.resize_window()});force_right_panel("hide");if(config.app.id){this.view_existing()}else{this.view_new()}},set_up_router:function(e){browser_router=new a.TrackBrowserRouter(e);Backbone.history.start()},view_existing:function(){var e=config.app.viz_config;view=ui.create_visualization({container:$("#center .unified-panel-body"),name:e.title,vis_id:e.vis_id,dbkey:e.dbkey},e.viewport,e.tracks,e.bookmarks,true);this.init_editor()},view_new:function(){var e=this;$.ajax({url:config.root+"api/genomes?chrom_info=True",data:{},error:function(){alert("Couldn't create new browser.")},success:function(f){show_modal("New Visualization",e.template_view_new(f),{Cancel:function(){window.location=config.root+"visualization/list"},Create:function(){e.create_browser($("#new-title").val(),$("#new-dbkey").val())}});if(config.app.default_dbkey){$("#new-dbkey option[value='"+config.default_dbkey+"']").attr("selected",true)}$("#new-title").focus();$("select[name='dbkey']").combobox({appendTo:$("#overlay"),size:40});$("#overlay").css("overflow","auto")}})},template_view_new:function(e){var g='<form id="new-browser-form" action="javascript:void(0);" method="post" onsubmit="return false;"><div class="form-row"><label for="new-title">Browser name:</label><div class="form-row-input"><input type="text" name="title" id="new-title" value="Unnamed"></input></div><div style="clear: both;"></div></div><div class="form-row"><label for="new-dbkey">Reference genome build (dbkey): </label><div class="form-row-input"><select name="dbkey" id="new-dbkey">';for(var f in e){g+='<option value="'+e[f][1]+'">'+e[f][0]+"</option>"}g+='</select></div><div style="clear: both;"></div></div><div class="form-row">Is the build not listed here?<br><a href="'+config.root+'user/dbkeys?use_panels=True">Add a Custom Build</a></div></form>';return g},create_browser:function(f,e){$(document).trigger("convert_to_values");view=ui.create_visualization({container:$("#center .unified-panel-body"),name:f,dbkey:e},config.app.gene_region);this.init_editor();view.editor=true;hide_modal()},init_editor:function(){$("#center .unified-panel-title").text(view.name+" ("+view.dbkey+")");if(config.app.add_dataset){$.ajax({url:config.root+"api/datasets/"+config.app.add_dataset,data:{hda_ldda:"hda",data_type:"track_config"},dataType:"json",success:function(e){view.add_drawable(b.object_from_template(e,view,view))}})}$("#add-bookmark-button").click(function(){var f=view.chrom+":"+view.low+"-"+view.high,e="Bookmark description";return ui.add_bookmark(f,e,true)});ui.init_keyboard_nav(view);this.set_up_router({view:view})}});return{GalaxyApp:d}});
\ No newline at end of file
diff -r f3a985005267a8c2022da3c0c8d9af496f8e5901 -r f06d793860c40c59200c1441374ca4993854e94a 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,w,k,t,L,X,i){var p=ab.extend;var m={};var j=function(ac,ad){m[ac.attr("id")]=ad};var l=function(ac,ae,ag,af){ag=".group";var ad={};m[ac.attr("id")]=af;ac.bind("drag",{handle:"."+ae,relative:true},function(ao,ap){var an=$(this),at=$(this).parent(),ak=at.children(),am=m[$(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=m[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=m[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)}m[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);m[at.attr("id")].move_drawable(am,al)}}else{if(this!==ak.get(al)){$(this).insertBefore(ak.get(al));m[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)})};var aa=16,G=9,D=20,z=100,I=12000,S=400,K=5000,v=100,n="Cannot display dataset due to an error. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",u="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",x="Tool cannot be rerun: ",a="Loading data...",U="Ready for display",R=10,H=20,A=["Histogram","Line","Filled","Intensity"];function V(ad,ac){if(!ac){ac=0}var ae=Math.pow(10,ac);return Math.round(ad*ae)/ae}var q=function(ad,ac,af){if(!q.id_counter){q.id_counter=0}this.id=q.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)}};q.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()}}];p(q.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(ac){},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 y=function(ad,ac,ae){q.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};p(y.prototype,q.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=o(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(ac){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad]._draw(ac)}},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},get_tracks:function(af){var ac=this.drawables.slice(0),ad=[],ae;while(ac.length!==0){ae=ac.shift();if(ae instanceof af){ad.push(ae)}else{if(ae.drawables){ac=ac.concat(ae.drawables)}}}return ad}});var Q=function(ad,ac,af){p(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});y.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);j(this.container_div,this);j(this.content_div,this);l(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()}}};p(Q.prototype,q.prototype,y.prototype,{action_icons_def:[q.prototype.action_icons_def[0],q.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({clear_tile_cache:true})}ac.filters_manager.toggle()}},q.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 ad=new f(this.view,this.view,{name:this.name,drawables:this.drawables});var ac=this.container.replace_drawable(this,ad,true);ad.request_draw()},add_drawable:function(ac){y.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){y.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=p(y.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){ab.each(this.drawables,function(ad){ad.request_draw(ac)})}});var Y=Backbone.View.extend({initialize:function(ac){p(ac,{obj_type:"View"});y.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.render();this.canvas_manager=new w.CanvasManager(this.container.get(0).ownerDocument);this.reset();this.config=new F({track:this,params:[{key:"a_color",label:"A Color",type:"color",default_value:"#FF0000"},{key:"c_color",label:"C Color",type:"color",default_value:"#00FF00"},{key:"g_color",label:"G Color",type:"color",default_value:"#0000FF"},{key:"t_color",label:"T Color",type:"color",default_value:"#FF00FF"},{key:"n_color",label:"N Color",type:"color",default_value:"#AAAAAA"},],saved_values:ac.prefs,onchange:function(){track.request_redraw({clear_tile_cache:true})}})},render: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;j(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(){w.select_datasets(config.root+"/visualization/list_current_history_datasets",config.root+"/api/datasets",{"f-dbkey":ac.dbkey},function(ag){ab.each(ag,function(ah){ac.add_drawable(o(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_tracks(c),function(ak){return ak.data_manager.search_features(ai.term).success(function(al){aj=aj.concat(al)})});$.when.apply($,ah).done(function(){ag($.map(aj,function(ak){return{label:ak[0],value:ak[1]}}))})}})});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a/>").attr("id","zoom-out").attr("title","Zoom out").tooltip({placement:"bottom"}).click(function(){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 W(this,{content_div:this.top_labeltrack}));this.add_label_track(new W(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")},get_base_color:function(ac){return this.config.values[ac.toLowerCase()+"_color"]||this.config.values.n_color}});p(Y.prototype,y.prototype,{changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(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=v;var ac=this,ad=$.Deferred();$.ajax({url:config.root+"api/genomes/"+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 '+v+"</option>"}if(ag.next_chroms){aj+='<option value="next">Next '+v+"</option>"}ac.chrom_select.html(aj);ac.chrom_start_index=ag.start_index;ad.resolve(ag.chrom_info)},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-v});return}if(ah==="next"){ae.load_chroms({low:this.chrom_start_index+v});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();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&&aj){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,"");ag=ag.replace(/:|\-/g," ");var ad=ag.split(/\s+/),af=ad[0],ae=(ad[1]?parseInt(ad[1],10):null),ac=(ad[2]?parseInt(ad[2],10):null);if(!ac){ae=ae-15;ac=ae+15}this.change_chrom(af,ae,ac)},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({data_fetch:false});if(this.redraw_on_move_fn){clearTimeout(this.redraw_on_move_fn)}this.redraw_on_move_fn=setTimeout(function(){ac.request_redraw()},200);var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){y.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){y.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(ad,ae){var ac=this,af=(ae?[ae]:ac.drawables);ab.each(af,function(ag){var ah=ab.find(ac.tracks_to_be_redrawn,function(ai){return ai[0]===ag});if(ah){ah[1]=ad}else{ac.tracks_to_be_redrawn.push([ag,ad])}});if(!this.requested_redraw){requestAnimationFrame(function(){ac._redraw()});this.requested_redraw=true}},_redraw:function(){this.requested_redraw=false;var ac=this.low,ag=this.high;if(ac<this.max_low){ac=this.max_low}if(ag>this.max_high){ag=this.max_high}var ad=this.high-this.low;if(this.high!==0&&ad<this.min_separation){ag=ac+this.min_separation}this.low=Math.floor(ac);this.high=Math.ceil(ag);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=1/this.resolution_b_px;var af=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ah=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ae=13;this.overview_box.css({left:af,width:Math.max(ae,ah)}).show();if(ah<ae){this.overview_box.css("left",af-(ae-ah)/2)}if(this.overview_highlight){this.overview_highlight.css({left:af,width:ah})}ab.each(this.tracks_to_be_redrawn,function(ak){var ai=ak[0],aj=ak[1];if(ai){ai._draw(aj)}});this.tracks_to_be_redrawn=[];ab.each(this.label_tracks,function(ai){ai._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 r=function(ae,aj,af){this.track=ae;this.id=aj.id;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 O(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()}};p(r.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.dataset.id,action:"rerun",tool_id:ac.id},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 ai=new w.GenomeRegion({chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}),ad={target_dataset_id:this.track.dataset.id,action:"rerun",tool_id:this.id,regions:[ai.toJSON()]},ah=this.track,ae=ad.tool_id+ah.tool_region_and_parameters_str(ai),ac;if(ah.container===view){var ag=new Q(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 aj=new ah.constructor(view,ac,{name:ae,hda_ldda:"hda"});aj.init_for_tool_data();aj.change_mode(ah.mode);aj.set_filters_manager(ah.filters_manager.copy(aj));aj.update_icons();ac.add_drawable(aj);aj.tiles_div.text("Starting job.");this.update_params();this.run(ad,aj,function(ak){aj.set_dataset(new X.Dataset(ak));aj.tiles_div.text("Running job.");aj.init()})},run:function(ac,ae,af){ac.inputs=this.get_param_values_dict();var ad=new k.ServerStateDeferred({ajax_settings:{url:config.root+"/api/tools",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(x+ag.message)}else{af(ag)}}})}});var O=function(ad,ac,ae,af){this.name=ad;this.label=ac;this.html=$(ae);this.value=af};p(O.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ae,ad,ag,ah,af,ac){O.call(this,ae,ad,ag,ah);this.min=af;this.max=ac};p(e.prototype,O.prototype,{update_value:function(){O.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};p(F.prototype,{set_param_default_value:function(ad,ac){var ae=ab.find(this.params,function(af){return af.key===ad});if(ae){ae.default_value=ac}},set_param_value:function(ac,ad){var ae=ab.find(this.params,function(af){return af.key===ac});if(ae){if(typeof ad==="string"||ad instanceof String){if(ad.trim()===""){ad=ae.default_value}else{if(ae.type==="float"){ad=parseFloat(ad)}else{if(ae.type==="int"){ad=parseInt(ad,10)}}}}}if(this.values[ac]!==ad){this.values[ac]=ad;return true}else{return false}},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(k.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==="bool"){ag=ac.find("#"+ai).is(":checked")}ad=ae.set_param_value(ah.key,ag)||ad}});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 M=function(ac,ag,ae,ad,af){b.call(this,ac,ag,ae,ad,af)};M.prototype.predisplay_actions=function(){};var P=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 w.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()}).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()}).dblclick(function(ar){ar.stopPropagation()})}};p(P.prototype,b.prototype);P.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"?V(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){p(ae,{drag_handle_class:"draghandle"});q.call(this,ad,ac,ae);this.dataset=new X.Dataset(ae.dataset);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 w.GenomeDataManager({dataset:this.dataset,genome:new w.Genome({key:ad.dbkey,chroms_info:{chrom_info:ad.chrom_data}}),data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=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()}}};p(g.prototype,q.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},q.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)}},q.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 w.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new w.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=config.root+"visualization/sweepster?"+$.param({dataset_id:ac.dataset.id,hda_ldda:ac.dataset.get("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})}},q.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset.id&&q.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},set_dataset:function(ac){this.dataset=ac;this.data_manager.set("dataset",ac)},on_resize:function(){this.request_draw({clear_tile_cache:true})},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(){q.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 W){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 Z){return"VariantTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(ae){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.tiles_div.css("height","auto");ad.tiles_div.text("").children().remove();ad.container_div.removeClass("nodata error pending");if(!ad.dataset.id){return}var ac=$.Deferred(),af={hda_ldda:ad.dataset.get("hda_ldda"),data_type:this.dataset_check_type,chrom:ad.view.chrom,retry:ae};$.getJSON(this.dataset.url(),af,function(ag){if(!ag||ag==="error"||ag.kind==="error"){ad.container_div.addClass("error");ad.tiles_div.text(n);if(ag.message){ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ag.message+"</pre>",{Close:hide_modal})}));ad.tiles_div.append($("<span/>").text(" "));ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ad.init(true)}))}}else{if(ag==="no converter"){ad.container_div.addClass("error");ad.tiles_div.text(J)}else{if(ag==="no data"||(ag.data!==undefined&&(ag.data===null||ag.data.length===0))){ad.container_div.addClass("nodata");ad.tiles_div.text(E)}else{if(ag==="pending"){ad.container_div.addClass("pending");ad.tiles_div.html(u);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(ag==="data"||ag.status==="data"){if(ag.valid_chroms){ad.valid_chroms=ag.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.apply($,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(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){ac.container_div.addClass("line-track");var af=ad.data;if(af&&af.min&&af.max){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.config.set_param_default_value("min_value",ae);ac.config.set_param_default_value("max_value",ag);ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},get_drawables:function(){return this}});var N=function(ae,ad,af){g.call(this,ae,ad,af);var ac=this;l(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 r(this,af.tool,af.tool_state):null);this.tile_cache=new w.Cache(R);this.left_offset=0;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)}};p(N.prototype,q.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({clear_tile_cache:true})},hide:true}]),copy:function(ac){var ad=this.to_dict();p(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,dataset:{id:this.dataset.id,hda_ldda:this.dataset.get("hda_ldda")},prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},set_min_max:function(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){var af=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.values.mode=ad;if(ad==="Auto"){this.data_manager.clear()}ac.request_draw({clear_tile_cache:true});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,ac){return ad+"_"+ac},request_draw:function(ac){if(ac&&ac.clear_tile_cache){this.tile_cache.clear()}this.view.request_redraw(ac,this)},before_draw:function(){this.max_height_px=0},_draw:function(ap){if(!this.can_draw()){return}var am=ap&&ap.clear_after,ak=this.view.low,ag=this.view.high,aj=ag-ak,ad=this.view.container.width(),ao=this.view.resolution_px_b,af=this.view.resolution_b_px;if(this.is_overview){ak=this.view.max_low;ag=this.view.max_high;af=(view.max_high-view.max_low)/ad;ao=1/af}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(ak/(af*S)),al,ah,ai=[],an=[];while((ac*S*af)<ag){al=this._get_tile_bounds(ac,af);ah=this.draw_helper(al,af,ao,ap);ai.push(ah);$.when(ah).then(function(aq){an.push(aq)});ac+=1}if(!am){this.tiles_div.children(".remove").removeClass("remove").remove()}var ae=this;$.when.apply($,ai).then(function(){ae.tiles_div.children(".remove").remove();an=ab.filter(an,function(aq){return aq!==null});if(an.length!==0){ae.postdraw_actions(an,ad,ao,am)}})},_add_yaxis_label:function(af,ah){var ad=this,ag=(af==="max"?"top":"bottom"),ai=(af==="max"?"max":"min"),ac=(af==="max"?"max_value":"min_value"),ah=ah||function(){ad.request_draw({clear_tile_cache:true})},ae=this.container_div.find(".yaxislabel."+ag);if(ae.length!==0){ae.text(ad.prefs[ac])}else{ae=$("<div/>").text(ad.prefs[ac]).make_text_editable({num_cols:12,on_finish:function(aj){$(".bs-tooltip").remove();ad.config.set_param_value(ac,aj);ah()},help_text:"Set "+ai+" value"}).addClass("yaxislabel "+ag).css("color",this.prefs.label_color);this.container_div.prepend(ae)}},postdraw_actions:function(af,ag,ai,ac){var ae=ab.filter(af,function(aj){return(aj instanceof M)});if(ae.length>0){this.max_height_px=0;var ad=this;ab.each(af,function(aj){if(!(aj instanceof M)){aj.html_elt.remove();ad.draw_helper(aj.region,aj.resolution,ai,{force:true,mode:"Coverage"})}});ad._add_yaxis_label("max")}else{this.container_div.find(".yaxislabel").remove();var ah=ab.find(af,function(aj){return aj.has_icons});if(ah){ab.each(af,function(aj){if(!aj.has_icons){aj.html_elt.css("padding-top",D)}})}}},get_mode:function(ac){return this.mode},update_auto_mode:function(ac){},_get_drawables:function(){return[this]},draw_helper:function(al,af,ao,ap){if(!ap){ap={}}var ad=ap.force,an=!(ap.data_fetch===false),ai=ap.mode||this.mode,ae=this,ag=this._get_drawables(),am=this._gen_tile_cache_key(ao,al),ah=function(aq){return(aq&&"track" in aq)};var aj=(ad?undefined:ae.tile_cache.get_elt(am));if(aj){if(ah(aj)){ae.show_tile(aj,ao)}return aj}if(!an){return null}var ak=function(){var aq=(ab.find(A,function(at){return at===ai})?"Coverage":ai);var ar=ab.map(ag,function(at){return at.data_manager.get_data(al,aq,af,ae.data_url_extra_params)});if(view.reference_track){ar.push(view.reference_track.data_manager.get_data(al,ai,af,view.reference_track.data_url_extra_params))}return ar};var ac=$.Deferred();ae.tile_cache.set_elt(am,ac);$.when.apply($,ak()).then(function(){var aq=ak(),aw=aq,aC;if(view.reference_track){aC=view.reference_track.data_manager.subset_entry(aq.pop(),al)}var ax=[],au=[];ab.each(ag,function(aH,aE){var aG=aH.mode,aF=aw[aE];if(aG==="Auto"){aG=aH.get_mode(aF);aH.update_auto_mode(aG)}ax.push(aG);au.push(aH.get_canvas_height(aF,aG,ao,ar))});var av=ae.view.canvas_manager.new_canvas(),ay=al.get("start"),aD=al.get("end"),at=0,ar=Math.ceil((aD-ay)*ao)+ae.left_offset,aA=ab.max(au),az;av.width=ar;av.height=(ap.height||aA);var aB=av.getContext("2d");aB.translate(ae.left_offset,0);if(ag.length>1){aB.globalAlpha=0.5;aB.globalCompositeOperation="source-over"}ab.each(ag,function(aF,aE){az=aF.draw_tile(aw[aE],aB,ax[aE],af,al,ao,aC)});if(az!==undefined){ae.tile_cache.set_elt(am,az);ae.show_tile(az,ao)}ac.resolve(az)});return ac},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},_draw_line_track_tile:function(ac,ae,ai,ag,ah,aj){var af=ae.canvas,ad=new L.LinePainter(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai);ad.draw(ae,af.width,af.height,aj);return new M(this,ah,ag,af,ac.data)},draw_tile:function(ac,ad,ah,af,ag,ai,ae){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ae,ah){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var ag=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ah;if(this.left_offset){ag-=this.left_offset}ac.css({position:"absolute",top:0,left:ag});if(ac.hasClass("remove")){ac.removeClass("remove")}else{this.tiles_div.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 w.GenomeRegion({chrom:this.view.chrom,start:af,end:ae})},tool_region_and_parameters_str:function(ae){var ac=this,ad=(ae!==undefined?ae.toString():"all");return" - region=["+ad+"], parameters=["+ac.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="bigwig"}else{if(ac.extra_info==="no_detail"){return false}else{return true}}}},can_subset:function(ac){if(ac.dataset_type==="bigwig"||ac.message||ac.extra_info==="no_detail"){return false}return true},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state";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 k.ServerStateDeferred({url:ad.dataset_state_url,url_params:{dataset_id:ad.dataset.id,hda_ldda:ad.dataset.get("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 W=function(ad,ac){var ae={resize:false};g.call(this,ad,ac,ae);this.container_div.addClass("label-track")};p(W.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},predraw_init:function(){},_draw:function(ag){var ae=this.view,af=ae.high-ae.low,aj=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/aj)*aj,ah=this.view.container.width(),ad=$("<div style='position: relative; height: 1.3em;'></div>");while(ac<ae.high){var ai=(ac-ae.low)/af*ah;ad.append($("<div class='label'>"+commatize(ac)+"</div>").css({position:"absolute",left:ai-1}));ac+=aj}this.content_div.children(":first").remove();this.content_div.append(ad)}});var f=function(ad,ac,ag){this.display_modes=A;N.call(this,ad,ac,ag);this.drawables=[];if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=o(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}ab.each(this.drawables,function(ah){if(ah instanceof c||ah instanceof T){ah.change_mode("Coverage")}});this.update_icons();this.obj_type="CompositeTrack"};p(f.prototype,N.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(N.prototype.action_icons_def),to_dict:y.prototype.to_dict,add_drawable:y.prototype.add_drawable,unpack_drawables:y.prototype.unpack_drawables,change_mode:function(ac){N.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:q.prototype.can_draw,_get_drawables:function(){return this.drawables},show_group:function(){var af=new Q(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({clear_tile_cache:true})},before_draw:function(){N.prototype.before_draw.call(this);var ad=ab.min(ab.map(this.drawables,function(ae){return ae.prefs.min_value})),ac=ab.max(ab.map(this.drawables,function(ae){return ae.prefs.max_value}));this.prefs.min_value=ad;this.prefs.max_value=ac;ab.each(this.drawables,function(ae){ae.prefs.min_value=ad;ae.prefs.max_value=ac})},update_all_min_max:function(){var ac=this;ab.each(this.drawables,function(ad){ad.prefs.min_value=ac.prefs.min_value;ad.prefs.max_value=ac.prefs.max_value});this.request_draw({clear_tile_cache:true})},postdraw_actions:function(ai,ac,al,ah){N.prototype.postdraw_actions.call(this,ai,ac,al,ah);var ag=-1;for(var ae=0;ae<ai.length;ae++){var aj=ai[ae].html_elt.find("canvas").height();if(aj>ag){ag=aj}}for(var ae=0;ae<ai.length;ae++){var af=ai[ae];if(af.html_elt.find("canvas").height()!==ag){this.draw_helper(af.region,af.resolution,al,{force:true,height:ag});af.html_elt.remove()}}var ad=this,ak=function(){ad.update_all_min_max()};this._add_yaxis_label("min",ak);this._add_yaxis_label("max",ak)}});var B=function(ac){N.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=config.root+"api/genomes//"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new w.GenomeReferenceDataManager({data_url:this.data_url,can_subset:this.can_subset});this.hide_contents()};p(B.prototype,q.prototype,N.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},predraw_init:function(){},can_draw:q.prototype.can_draw,draw_helper:function(ae,ad,af,ac){if(af>this.view.canvas_manager.char_width_px){this.tiles_div.show();return N.prototype.draw_helper.call(this,ae,ad,af,ac)}else{this.tiles_div.hide();return null}},can_subset:function(ac){return true},draw_tile:function(af,al,ag,ad,ai,am){var ae=this.data_manager.subset_entry(af,ai),ak=ae.data;var ac=al.canvas;al.font=al.canvas.manager.default_font;al.textAlign="center";for(var ah=0,aj=ak.length;ah<aj;ah++){al.fillStyle=this.view.get_base_color(ak[ah]);al.fillText(ak[ah],Math.floor(ah*am),10)}return new b(this,ai,ad,ac,ae)}});var h=function(ae,ad,af){var ac=this;this.display_modes=A;this.mode="Histogram";N.call(this,ae,ad,af);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:k.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.request_redraw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height};p(h.prototype,q.prototype,N.prototype,{before_draw:function(){},draw_tile:function(ac,ad,ag,ae,af,ah){return this._draw_line_track_tile(ac,ad,ag,ae,af,ah)},can_subset:function(ac){return(ac.data[1][0]-ac.data[0][0]===1)},postdraw_actions:function(ad,ae,af,ac){this._add_yaxis_label("max");this._add_yaxis_label("min")}});var s=function(ae,ad,af){var ac=this;this.display_modes=["Heatmap"];this.mode="Heatmap";N.call(this,ae,ad,af);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:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"min_value",label:"Min Value",type:"float",default_value:-1},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);this.request_redraw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height};p(s.prototype,q.prototype,N.prototype,{draw_tile:function(ac,ae,ai,ag,ah,aj){var af=ae.canvas,ad=new L.DiagonalHeatmapPainter(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai);ad.draw(ae,af.width,af.height,aj);return new b(this,ah,ag,af,ac.data)}});var c=function(af,ae,ah){var ad=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];N.call(this,af,ae,ah);var ag=k.get_random_color(),ac=k.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:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:this.visible_height_px,hidden:true}],saved_values:ah.prefs,onchange:function(){ad.set_name(ad.prefs.name);ad.set_painter_from_config();ad.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");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()};p(c.prototype,q.prototype,N.prototype,{set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},postdraw_actions:function(am,ae,an,al){N.prototype.postdraw_actions.call(this,am,ae,an,al);var ag=this,ah;if(ag.filters_manager){var af=ag.filters_manager.filters;for(var aj=0;aj<af.length;aj++){af[aj].update_ui_elt()}var ai=false,ak,ad;for(ah=0;ah<am.length;ah++){if(am[ah].data.length){ak=am[ah].data[0];for(var aj=0;aj<af.length;aj++){ad=af[aj];if(ad.applies_to(ak)&&ad.min!==ad.max){ai=true;break}}}}if(ag.filters_available!==ai){ag.filters_available=ai;if(!ag.filters_available){ag.filters_manager.hide()}ag.update_icons()}}if(am[0] instanceof P){var ac=true;for(ah=0;ah<am.length;ah++){if(!am[ah].all_slotted){ac=false;break}}if(!ac){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"}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 (t.FeatureSlotter)(ag,af,z,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){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==="Coverage"||ac.dataset_type==="bigwig"){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(am.dataset_type==="bigwig"){return this._draw_line_track_tile(am,aq,ao,ar,af,aj)}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),az=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null),aA=new (this.painter)(ai,ay,ac,this.prefs,ao,aB,az,ae,function(aD){return ap.view.get_base_color(aD)});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 P(ap,af,ar,ad,am.data,aj,ao,am.message,all_slotted,aw)}});var Z=function(ad,ac,ae){this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];N.call(this,ad,ac,ae);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Histogram color",type:"color",default_value:k.get_random_color()},{key:"show_sample_data",label:"Show sample data",type:"bool",default_value:true},{key:"show_labels",label:"Show summary and sample labels",type:"bool",default_value:true},{key:"summary_height",label:"Locus summary height",type:"float",default_value:20},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ae.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.painter=L.VariantPainter;this.summary_draw_height=30;this.left_offset=30};p(Z.prototype,q.prototype,N.prototype,{draw_tile:function(ac,af,ai,ag,ah,aj){if(ac.dataset_type==="bigwig"){return this._draw_line_track_tile(ac,af,"Histogram",ag,ah,aj)}else{var ae=this.view,ad=new (this.painter)(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai,function(ak){return ae.get_base_color(ak)});ad.draw(af,af.canvas.width,af.canvas.height,aj);return new b(this,ah,ag,af.canvas,ac.data)}},get_canvas_height:function(ac,ag,ah,ae){if(ac.dataset_type==="bigwig"){return this.summary_draw_height}else{var af=new (this.painter)(null,null,null,this.prefs,ag);var ad=(this.dataset.get_metadata("sample_names")?this.dataset.get_metadata("sample_names").length:0);if(ad===0&&ac.data.length!==0){ad=ac.data[0][7].match(/,/g);if(ad===null){ad=1}else{ad=ad.length+1}}return af.get_required_height(ad)}},predraw_init:function(){var ac=[g.prototype.predraw_init.call(this)];if(!this.dataset.get_metadata("sample_names")){ac.push(this.dataset.fetch())}return ac},postdraw_actions:function(af,ag,ai,ad){N.prototype.postdraw_actions.call(this,af,ag,ai,ad);var ae=ab.filter(af,function(aj){return(aj instanceof M)});if(ae.length===0&&this.prefs.show_labels){var ac;if(this.container_div.find(".yaxislabel.variant").length===0){ac=this.prefs.summary_height/2;this.tiles_div.prepend($("<div/>").text("Summary").addClass("yaxislabel variant top").css({"font-size":ac+"px",top:(this.prefs.summary_height-ac)/2+"px"}));if(this.prefs.show_sample_data){var ah=this.dataset.get("metadata").get("sample_names").join("<br/>");this.tiles_div.prepend($("<div/>").html(ah).addClass("yaxislabel variant top sample").css({top:this.prefs.summary_height+2,}))}}ac=(this.mode==="Squish"?5:10)+"px";$(this.tiles_div).find(".sample").css({"font-size":ac,"line-height":ac});$(this.tiles_div).find(".yaxislabel").css("color",this.prefs.label_color)}else{this.container_div.find(".yaxislabel.variant").remove()}}});var T=function(ae,ad,ag){c.call(this,ae,ad,ag);var af=k.get_random_color(),ac=k.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:"mode",type:"string",default_value:this.mode,hidden:true},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.painter=(ae.reference_track?L.RefBasedReadPainter:L.ReadPainter);this.update_icons()};p(T.prototype,q.prototype,N.prototype,c.prototype);var d={CompositeTrack:f,DrawableGroup:Q,DiagonalHeatmapTrack:s,FeatureTrack:c,LineTrack:h,ReadTrack:T,VariantTrack:Z,VcfTrack:Z};var o=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{TracksterView:Y,DrawableGroup:Q,LineTrack:h,FeatureTrack:c,DiagonalHeatmapTrack:s,ReadTrack:T,VariantTrack:Z,CompositeTrack:f,object_from_template:o}});
\ 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,w,k,t,L,X,i){var p=ab.extend;var m={};var j=function(ac,ad){m[ac.attr("id")]=ad};var l=function(ac,ae,ag,af){ag=".group";var ad={};m[ac.attr("id")]=af;ac.bind("drag",{handle:"."+ae,relative:true},function(ao,ap){var an=$(this),at=$(this).parent(),ak=at.children(),am=m[$(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=m[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=m[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)}m[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);m[at.attr("id")].move_drawable(am,al)}}else{if(this!==ak.get(al)){$(this).insertBefore(ak.get(al));m[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)})};var aa=16,G=9,D=20,z=100,I=12000,S=400,K=5000,v=100,n="Cannot display dataset due to an error. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",u="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",x="Tool cannot be rerun: ",a="Loading data...",U="Ready for display",R=10,H=20,A=["Histogram","Line","Filled","Intensity"];function V(ad,ac){if(!ac){ac=0}var ae=Math.pow(10,ac);return Math.round(ad*ae)/ae}var q=function(ad,ac,af){if(!q.id_counter){q.id_counter=0}this.id=q.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)}};q.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()}}];p(q.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(ac){},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 y=function(ad,ac,ae){q.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};p(y.prototype,q.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=o(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(ac){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad]._draw(ac)}},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},get_tracks:function(af){var ac=this.drawables.slice(0),ad=[],ae;while(ac.length!==0){ae=ac.shift();if(ae instanceof af){ad.push(ae)}else{if(ae.drawables){ac=ac.concat(ae.drawables)}}}return ad}});var Q=function(ad,ac,af){p(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});y.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);j(this.container_div,this);j(this.content_div,this);l(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()}}};p(Q.prototype,q.prototype,y.prototype,{action_icons_def:[q.prototype.action_icons_def[0],q.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({clear_tile_cache:true})}ac.filters_manager.toggle()}},q.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 ad=new f(this.view,this.view,{name:this.name,drawables:this.drawables});var ac=this.container.replace_drawable(this,ad,true);ad.request_draw()},add_drawable:function(ac){y.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){y.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=p(y.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){ab.each(this.drawables,function(ad){ad.request_draw(ac)})}});var Y=Backbone.View.extend({initialize:function(ac){p(ac,{obj_type:"View"});y.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.render();this.canvas_manager=new w.CanvasManager(this.container.get(0).ownerDocument);this.reset();this.config=new F({track:this,params:[{key:"a_color",label:"A Color",type:"color",default_value:"#FF0000"},{key:"c_color",label:"C Color",type:"color",default_value:"#00FF00"},{key:"g_color",label:"G Color",type:"color",default_value:"#0000FF"},{key:"t_color",label:"T Color",type:"color",default_value:"#FF00FF"},{key:"n_color",label:"N Color",type:"color",default_value:"#AAAAAA"},],saved_values:ac.prefs,onchange:function(){track.request_redraw({clear_tile_cache:true})}})},render: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;j(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(){w.select_datasets(config.root+"visualization/list_current_history_datasets",config.root+"api/datasets",{"f-dbkey":ac.dbkey},function(ag){ab.each(ag,function(ah){ac.add_drawable(o(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_tracks(c),function(ak){return ak.data_manager.search_features(ai.term).success(function(al){aj=aj.concat(al)})});$.when.apply($,ah).done(function(){ag($.map(aj,function(ak){return{label:ak[0],value:ak[1]}}))})}})});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a/>").attr("id","zoom-out").attr("title","Zoom out").tooltip({placement:"bottom"}).click(function(){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 W(this,{content_div:this.top_labeltrack}));this.add_label_track(new W(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")},get_base_color:function(ac){return this.config.values[ac.toLowerCase()+"_color"]||this.config.values.n_color}});p(Y.prototype,y.prototype,{changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(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=v;var ac=this,ad=$.Deferred();$.ajax({url:config.root+"api/genomes/"+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 '+v+"</option>"}if(ag.next_chroms){aj+='<option value="next">Next '+v+"</option>"}ac.chrom_select.html(aj);ac.chrom_start_index=ag.start_index;ad.resolve(ag.chrom_info)},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-v});return}if(ah==="next"){ae.load_chroms({low:this.chrom_start_index+v});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();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&&aj){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,"");ag=ag.replace(/:|\-/g," ");var ad=ag.split(/\s+/),af=ad[0],ae=(ad[1]?parseInt(ad[1],10):null),ac=(ad[2]?parseInt(ad[2],10):null);if(!ac){ae=ae-15;ac=ae+15}this.change_chrom(af,ae,ac)},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({data_fetch:false});if(this.redraw_on_move_fn){clearTimeout(this.redraw_on_move_fn)}this.redraw_on_move_fn=setTimeout(function(){ac.request_redraw()},200);var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){y.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){y.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(ad,ae){var ac=this,af=(ae?[ae]:ac.drawables);ab.each(af,function(ag){var ah=ab.find(ac.tracks_to_be_redrawn,function(ai){return ai[0]===ag});if(ah){ah[1]=ad}else{ac.tracks_to_be_redrawn.push([ag,ad])}});if(!this.requested_redraw){requestAnimationFrame(function(){ac._redraw()});this.requested_redraw=true}},_redraw:function(){this.requested_redraw=false;var ac=this.low,ag=this.high;if(ac<this.max_low){ac=this.max_low}if(ag>this.max_high){ag=this.max_high}var ad=this.high-this.low;if(this.high!==0&&ad<this.min_separation){ag=ac+this.min_separation}this.low=Math.floor(ac);this.high=Math.ceil(ag);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=1/this.resolution_b_px;var af=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ah=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ae=13;this.overview_box.css({left:af,width:Math.max(ae,ah)}).show();if(ah<ae){this.overview_box.css("left",af-(ae-ah)/2)}if(this.overview_highlight){this.overview_highlight.css({left:af,width:ah})}ab.each(this.tracks_to_be_redrawn,function(ak){var ai=ak[0],aj=ak[1];if(ai){ai._draw(aj)}});this.tracks_to_be_redrawn=[];ab.each(this.label_tracks,function(ai){ai._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 r=function(ae,aj,af){this.track=ae;this.id=aj.id;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 O(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()}};p(r.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.dataset.id,action:"rerun",tool_id:ac.id},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 ai=new w.GenomeRegion({chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}),ad={target_dataset_id:this.track.dataset.id,action:"rerun",tool_id:this.id,regions:[ai.toJSON()]},ah=this.track,ae=ad.tool_id+ah.tool_region_and_parameters_str(ai),ac;if(ah.container===view){var ag=new Q(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 aj=new ah.constructor(view,ac,{name:ae,hda_ldda:"hda"});aj.init_for_tool_data();aj.change_mode(ah.mode);aj.set_filters_manager(ah.filters_manager.copy(aj));aj.update_icons();ac.add_drawable(aj);aj.tiles_div.text("Starting job.");this.update_params();this.run(ad,aj,function(ak){aj.set_dataset(new X.Dataset(ak));aj.tiles_div.text("Running job.");aj.init()})},run:function(ac,ae,af){ac.inputs=this.get_param_values_dict();var ad=new k.ServerStateDeferred({ajax_settings:{url:config.root+"/api/tools",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(x+ag.message)}else{af(ag)}}})}});var O=function(ad,ac,ae,af){this.name=ad;this.label=ac;this.html=$(ae);this.value=af};p(O.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ae,ad,ag,ah,af,ac){O.call(this,ae,ad,ag,ah);this.min=af;this.max=ac};p(e.prototype,O.prototype,{update_value:function(){O.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};p(F.prototype,{set_param_default_value:function(ad,ac){var ae=ab.find(this.params,function(af){return af.key===ad});if(ae){ae.default_value=ac}},set_param_value:function(ac,ad){var ae=ab.find(this.params,function(af){return af.key===ac});if(ae){if(typeof ad==="string"||ad instanceof String){if(ad.trim()===""){ad=ae.default_value}else{if(ae.type==="float"){ad=parseFloat(ad)}else{if(ae.type==="int"){ad=parseInt(ad,10)}}}}}if(this.values[ac]!==ad){this.values[ac]=ad;return true}else{return false}},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(k.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==="bool"){ag=ac.find("#"+ai).is(":checked")}ad=ae.set_param_value(ah.key,ag)||ad}});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 M=function(ac,ag,ae,ad,af){b.call(this,ac,ag,ae,ad,af)};M.prototype.predisplay_actions=function(){};var P=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 w.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()}).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()}).dblclick(function(ar){ar.stopPropagation()})}};p(P.prototype,b.prototype);P.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"?V(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){p(ae,{drag_handle_class:"draghandle"});q.call(this,ad,ac,ae);this.dataset=new X.Dataset(ae.dataset);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 w.GenomeDataManager({dataset:this.dataset,genome:new w.Genome({key:ad.dbkey,chroms_info:{chrom_info:ad.chrom_data}}),data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=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()}}};p(g.prototype,q.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},q.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)}},q.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 w.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new w.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=config.root+"visualization/sweepster?"+$.param({dataset_id:ac.dataset.id,hda_ldda:ac.dataset.get("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})}},q.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset.id&&q.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},set_dataset:function(ac){this.dataset=ac;this.data_manager.set("dataset",ac)},on_resize:function(){this.request_draw({clear_tile_cache:true})},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(){q.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 W){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 Z){return"VariantTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(ae){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.tiles_div.css("height","auto");ad.tiles_div.text("").children().remove();ad.container_div.removeClass("nodata error pending");if(!ad.dataset.id){return}var ac=$.Deferred(),af={hda_ldda:ad.dataset.get("hda_ldda"),data_type:this.dataset_check_type,chrom:ad.view.chrom,retry:ae};$.getJSON(this.dataset.url(),af,function(ag){if(!ag||ag==="error"||ag.kind==="error"){ad.container_div.addClass("error");ad.tiles_div.text(n);if(ag.message){ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ag.message+"</pre>",{Close:hide_modal})}));ad.tiles_div.append($("<span/>").text(" "));ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ad.init(true)}))}}else{if(ag==="no converter"){ad.container_div.addClass("error");ad.tiles_div.text(J)}else{if(ag==="no data"||(ag.data!==undefined&&(ag.data===null||ag.data.length===0))){ad.container_div.addClass("nodata");ad.tiles_div.text(E)}else{if(ag==="pending"){ad.container_div.addClass("pending");ad.tiles_div.html(u);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(ag==="data"||ag.status==="data"){if(ag.valid_chroms){ad.valid_chroms=ag.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.apply($,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(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){ac.container_div.addClass("line-track");var af=ad.data;if(af&&af.min&&af.max){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.config.set_param_default_value("min_value",ae);ac.config.set_param_default_value("max_value",ag);ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},get_drawables:function(){return this}});var N=function(ae,ad,af){g.call(this,ae,ad,af);var ac=this;l(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 r(this,af.tool,af.tool_state):null);this.tile_cache=new w.Cache(R);this.left_offset=0;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)}};p(N.prototype,q.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({clear_tile_cache:true})},hide:true}]),copy:function(ac){var ad=this.to_dict();p(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,dataset:{id:this.dataset.id,hda_ldda:this.dataset.get("hda_ldda")},prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},set_min_max:function(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){var af=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.values.mode=ad;if(ad==="Auto"){this.data_manager.clear()}ac.request_draw({clear_tile_cache:true});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,ac){return ad+"_"+ac},request_draw:function(ac){if(ac&&ac.clear_tile_cache){this.tile_cache.clear()}this.view.request_redraw(ac,this)},before_draw:function(){this.max_height_px=0},_draw:function(ap){if(!this.can_draw()){return}var am=ap&&ap.clear_after,ak=this.view.low,ag=this.view.high,aj=ag-ak,ad=this.view.container.width(),ao=this.view.resolution_px_b,af=this.view.resolution_b_px;if(this.is_overview){ak=this.view.max_low;ag=this.view.max_high;af=(view.max_high-view.max_low)/ad;ao=1/af}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(ak/(af*S)),al,ah,ai=[],an=[];while((ac*S*af)<ag){al=this._get_tile_bounds(ac,af);ah=this.draw_helper(al,af,ao,ap);ai.push(ah);$.when(ah).then(function(aq){an.push(aq)});ac+=1}if(!am){this.tiles_div.children(".remove").removeClass("remove").remove()}var ae=this;$.when.apply($,ai).then(function(){ae.tiles_div.children(".remove").remove();an=ab.filter(an,function(aq){return aq!==null});if(an.length!==0){ae.postdraw_actions(an,ad,ao,am)}})},_add_yaxis_label:function(af,ah){var ad=this,ag=(af==="max"?"top":"bottom"),ai=(af==="max"?"max":"min"),ac=(af==="max"?"max_value":"min_value"),ah=ah||function(){ad.request_draw({clear_tile_cache:true})},ae=this.container_div.find(".yaxislabel."+ag);if(ae.length!==0){ae.text(ad.prefs[ac])}else{ae=$("<div/>").text(ad.prefs[ac]).make_text_editable({num_cols:12,on_finish:function(aj){$(".bs-tooltip").remove();ad.config.set_param_value(ac,aj);ah()},help_text:"Set "+ai+" value"}).addClass("yaxislabel "+ag).css("color",this.prefs.label_color);this.container_div.prepend(ae)}},postdraw_actions:function(af,ag,ai,ac){var ae=ab.filter(af,function(aj){return(aj instanceof M)});if(ae.length>0){this.max_height_px=0;var ad=this;ab.each(af,function(aj){if(!(aj instanceof M)){aj.html_elt.remove();ad.draw_helper(aj.region,aj.resolution,ai,{force:true,mode:"Coverage"})}});ad._add_yaxis_label("max")}else{this.container_div.find(".yaxislabel").remove();var ah=ab.find(af,function(aj){return aj.has_icons});if(ah){ab.each(af,function(aj){if(!aj.has_icons){aj.html_elt.css("padding-top",D)}})}}},get_mode:function(ac){return this.mode},update_auto_mode:function(ac){},_get_drawables:function(){return[this]},draw_helper:function(al,af,ao,ap){if(!ap){ap={}}var ad=ap.force,an=!(ap.data_fetch===false),ai=ap.mode||this.mode,ae=this,ag=this._get_drawables(),am=this._gen_tile_cache_key(ao,al),ah=function(aq){return(aq&&"track" in aq)};var aj=(ad?undefined:ae.tile_cache.get_elt(am));if(aj){if(ah(aj)){ae.show_tile(aj,ao)}return aj}if(!an){return null}var ak=function(){var aq=(ab.find(A,function(at){return at===ai})?"Coverage":ai);var ar=ab.map(ag,function(at){return at.data_manager.get_data(al,aq,af,ae.data_url_extra_params)});if(view.reference_track){ar.push(view.reference_track.data_manager.get_data(al,ai,af,view.reference_track.data_url_extra_params))}return ar};var ac=$.Deferred();ae.tile_cache.set_elt(am,ac);$.when.apply($,ak()).then(function(){var aq=ak(),aw=aq,aC;if(view.reference_track){aC=view.reference_track.data_manager.subset_entry(aq.pop(),al)}var ax=[],au=[];ab.each(ag,function(aH,aE){var aG=aH.mode,aF=aw[aE];if(aG==="Auto"){aG=aH.get_mode(aF);aH.update_auto_mode(aG)}ax.push(aG);au.push(aH.get_canvas_height(aF,aG,ao,ar))});var av=ae.view.canvas_manager.new_canvas(),ay=al.get("start"),aD=al.get("end"),at=0,ar=Math.ceil((aD-ay)*ao)+ae.left_offset,aA=ab.max(au),az;av.width=ar;av.height=(ap.height||aA);var aB=av.getContext("2d");aB.translate(ae.left_offset,0);if(ag.length>1){aB.globalAlpha=0.5;aB.globalCompositeOperation="source-over"}ab.each(ag,function(aF,aE){az=aF.draw_tile(aw[aE],aB,ax[aE],af,al,ao,aC)});if(az!==undefined){ae.tile_cache.set_elt(am,az);ae.show_tile(az,ao)}ac.resolve(az)});return ac},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},_draw_line_track_tile:function(ac,ae,ai,ag,ah,aj){var af=ae.canvas,ad=new L.LinePainter(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai);ad.draw(ae,af.width,af.height,aj);return new M(this,ah,ag,af,ac.data)},draw_tile:function(ac,ad,ah,af,ag,ai,ae){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ae,ah){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var ag=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ah;if(this.left_offset){ag-=this.left_offset}ac.css({position:"absolute",top:0,left:ag});if(ac.hasClass("remove")){ac.removeClass("remove")}else{this.tiles_div.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 w.GenomeRegion({chrom:this.view.chrom,start:af,end:ae})},tool_region_and_parameters_str:function(ae){var ac=this,ad=(ae!==undefined?ae.toString():"all");return" - region=["+ad+"], parameters=["+ac.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="bigwig"}else{if(ac.extra_info==="no_detail"){return false}else{return true}}}},can_subset:function(ac){if(ac.dataset_type==="bigwig"||ac.message||ac.extra_info==="no_detail"){return false}return true},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state";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 k.ServerStateDeferred({url:ad.dataset_state_url,url_params:{dataset_id:ad.dataset.id,hda_ldda:ad.dataset.get("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 W=function(ad,ac){var ae={resize:false};g.call(this,ad,ac,ae);this.container_div.addClass("label-track")};p(W.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},predraw_init:function(){},_draw:function(ag){var ae=this.view,af=ae.high-ae.low,aj=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/aj)*aj,ah=this.view.container.width(),ad=$("<div style='position: relative; height: 1.3em;'></div>");while(ac<ae.high){var ai=(ac-ae.low)/af*ah;ad.append($("<div class='label'>"+commatize(ac)+"</div>").css({position:"absolute",left:ai-1}));ac+=aj}this.content_div.children(":first").remove();this.content_div.append(ad)}});var f=function(ad,ac,ag){this.display_modes=A;N.call(this,ad,ac,ag);this.drawables=[];if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=o(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}ab.each(this.drawables,function(ah){if(ah instanceof c||ah instanceof T){ah.change_mode("Coverage")}});this.update_icons();this.obj_type="CompositeTrack"};p(f.prototype,N.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(N.prototype.action_icons_def),to_dict:y.prototype.to_dict,add_drawable:y.prototype.add_drawable,unpack_drawables:y.prototype.unpack_drawables,change_mode:function(ac){N.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:q.prototype.can_draw,_get_drawables:function(){return this.drawables},show_group:function(){var af=new Q(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({clear_tile_cache:true})},before_draw:function(){N.prototype.before_draw.call(this);var ad=ab.min(ab.map(this.drawables,function(ae){return ae.prefs.min_value})),ac=ab.max(ab.map(this.drawables,function(ae){return ae.prefs.max_value}));this.prefs.min_value=ad;this.prefs.max_value=ac;ab.each(this.drawables,function(ae){ae.prefs.min_value=ad;ae.prefs.max_value=ac})},update_all_min_max:function(){var ac=this;ab.each(this.drawables,function(ad){ad.prefs.min_value=ac.prefs.min_value;ad.prefs.max_value=ac.prefs.max_value});this.request_draw({clear_tile_cache:true})},postdraw_actions:function(ai,ac,al,ah){N.prototype.postdraw_actions.call(this,ai,ac,al,ah);var ag=-1;for(var ae=0;ae<ai.length;ae++){var aj=ai[ae].html_elt.find("canvas").height();if(aj>ag){ag=aj}}for(var ae=0;ae<ai.length;ae++){var af=ai[ae];if(af.html_elt.find("canvas").height()!==ag){this.draw_helper(af.region,af.resolution,al,{force:true,height:ag});af.html_elt.remove()}}var ad=this,ak=function(){ad.update_all_min_max()};this._add_yaxis_label("min",ak);this._add_yaxis_label("max",ak)}});var B=function(ac){N.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=config.root+"api/genomes//"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new w.GenomeReferenceDataManager({data_url:this.data_url,can_subset:this.can_subset});this.hide_contents()};p(B.prototype,q.prototype,N.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},predraw_init:function(){},can_draw:q.prototype.can_draw,draw_helper:function(ae,ad,af,ac){if(af>this.view.canvas_manager.char_width_px){this.tiles_div.show();return N.prototype.draw_helper.call(this,ae,ad,af,ac)}else{this.tiles_div.hide();return null}},can_subset:function(ac){return true},draw_tile:function(af,al,ag,ad,ai,am){var ae=this.data_manager.subset_entry(af,ai),ak=ae.data;var ac=al.canvas;al.font=al.canvas.manager.default_font;al.textAlign="center";for(var ah=0,aj=ak.length;ah<aj;ah++){al.fillStyle=this.view.get_base_color(ak[ah]);al.fillText(ak[ah],Math.floor(ah*am),10)}return new b(this,ai,ad,ac,ae)}});var h=function(ae,ad,af){var ac=this;this.display_modes=A;this.mode="Histogram";N.call(this,ae,ad,af);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:k.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.request_redraw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height};p(h.prototype,q.prototype,N.prototype,{before_draw:function(){},draw_tile:function(ac,ad,ag,ae,af,ah){return this._draw_line_track_tile(ac,ad,ag,ae,af,ah)},can_subset:function(ac){return(ac.data[1][0]-ac.data[0][0]===1)},postdraw_actions:function(ad,ae,af,ac){this._add_yaxis_label("max");this._add_yaxis_label("min")}});var s=function(ae,ad,af){var ac=this;this.display_modes=["Heatmap"];this.mode="Heatmap";N.call(this,ae,ad,af);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:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"min_value",label:"Min Value",type:"float",default_value:-1},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);this.request_redraw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height};p(s.prototype,q.prototype,N.prototype,{draw_tile:function(ac,ae,ai,ag,ah,aj){var af=ae.canvas,ad=new L.DiagonalHeatmapPainter(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai);ad.draw(ae,af.width,af.height,aj);return new b(this,ah,ag,af,ac.data)}});var c=function(af,ae,ah){var ad=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];N.call(this,af,ae,ah);var ag=k.get_random_color(),ac=k.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:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:this.visible_height_px,hidden:true}],saved_values:ah.prefs,onchange:function(){ad.set_name(ad.prefs.name);ad.set_painter_from_config();ad.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");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()};p(c.prototype,q.prototype,N.prototype,{set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},postdraw_actions:function(am,ae,an,al){N.prototype.postdraw_actions.call(this,am,ae,an,al);var ag=this,ah;if(ag.filters_manager){var af=ag.filters_manager.filters;for(var aj=0;aj<af.length;aj++){af[aj].update_ui_elt()}var ai=false,ak,ad;for(ah=0;ah<am.length;ah++){if(am[ah].data.length){ak=am[ah].data[0];for(var aj=0;aj<af.length;aj++){ad=af[aj];if(ad.applies_to(ak)&&ad.min!==ad.max){ai=true;break}}}}if(ag.filters_available!==ai){ag.filters_available=ai;if(!ag.filters_available){ag.filters_manager.hide()}ag.update_icons()}}if(am[0] instanceof P){var ac=true;for(ah=0;ah<am.length;ah++){if(!am[ah].all_slotted){ac=false;break}}if(!ac){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"}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 (t.FeatureSlotter)(ag,af,z,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){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==="Coverage"||ac.dataset_type==="bigwig"){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(am.dataset_type==="bigwig"){return this._draw_line_track_tile(am,aq,ao,ar,af,aj)}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),az=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null),aA=new (this.painter)(ai,ay,ac,this.prefs,ao,aB,az,ae,function(aD){return ap.view.get_base_color(aD)});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 P(ap,af,ar,ad,am.data,aj,ao,am.message,all_slotted,aw)}});var Z=function(ad,ac,ae){this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];N.call(this,ad,ac,ae);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Histogram color",type:"color",default_value:k.get_random_color()},{key:"show_sample_data",label:"Show sample data",type:"bool",default_value:true},{key:"show_labels",label:"Show summary and sample labels",type:"bool",default_value:true},{key:"summary_height",label:"Locus summary height",type:"float",default_value:20},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ae.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.painter=L.VariantPainter;this.summary_draw_height=30;this.left_offset=30};p(Z.prototype,q.prototype,N.prototype,{draw_tile:function(ac,af,ai,ag,ah,aj){if(ac.dataset_type==="bigwig"){return this._draw_line_track_tile(ac,af,"Histogram",ag,ah,aj)}else{var ae=this.view,ad=new (this.painter)(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai,function(ak){return ae.get_base_color(ak)});ad.draw(af,af.canvas.width,af.canvas.height,aj);return new b(this,ah,ag,af.canvas,ac.data)}},get_canvas_height:function(ac,ag,ah,ae){if(ac.dataset_type==="bigwig"){return this.summary_draw_height}else{var af=new (this.painter)(null,null,null,this.prefs,ag);var ad=(this.dataset.get_metadata("sample_names")?this.dataset.get_metadata("sample_names").length:0);if(ad===0&&ac.data.length!==0){ad=ac.data[0][7].match(/,/g);if(ad===null){ad=1}else{ad=ad.length+1}}return af.get_required_height(ad)}},predraw_init:function(){var ac=[g.prototype.predraw_init.call(this)];if(!this.dataset.get_metadata("sample_names")){ac.push(this.dataset.fetch())}return ac},postdraw_actions:function(af,ag,ai,ad){N.prototype.postdraw_actions.call(this,af,ag,ai,ad);var ae=ab.filter(af,function(aj){return(aj instanceof M)});if(ae.length===0&&this.prefs.show_labels){var ac;if(this.container_div.find(".yaxislabel.variant").length===0){ac=this.prefs.summary_height/2;this.tiles_div.prepend($("<div/>").text("Summary").addClass("yaxislabel variant top").css({"font-size":ac+"px",top:(this.prefs.summary_height-ac)/2+"px"}));if(this.prefs.show_sample_data){var ah=this.dataset.get("metadata").get("sample_names").join("<br/>");this.tiles_div.prepend($("<div/>").html(ah).addClass("yaxislabel variant top sample").css({top:this.prefs.summary_height+2,}))}}ac=(this.mode==="Squish"?5:10)+"px";$(this.tiles_div).find(".sample").css({"font-size":ac,"line-height":ac});$(this.tiles_div).find(".yaxislabel").css("color",this.prefs.label_color)}else{this.container_div.find(".yaxislabel.variant").remove()}}});var T=function(ae,ad,ag){c.call(this,ae,ad,ag);var af=k.get_random_color(),ac=k.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:"mode",type:"string",default_value:this.mode,hidden:true},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.painter=(ae.reference_track?L.RefBasedReadPainter:L.ReadPainter);this.update_icons()};p(T.prototype,q.prototype,N.prototype,c.prototype);var d={CompositeTrack:f,DrawableGroup:Q,DiagonalHeatmapTrack:s,FeatureTrack:c,LineTrack:h,ReadTrack:T,VariantTrack:Z,VcfTrack:Z};var o=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{TracksterView:Y,DrawableGroup:Q,LineTrack:h,FeatureTrack:c,DiagonalHeatmapTrack:s,ReadTrack:T,VariantTrack:Z,CompositeTrack:f,object_from_template:o}});
\ No newline at end of file
diff -r f3a985005267a8c2022da3c0c8d9af496f8e5901 -r f06d793860c40c59200c1441374ca4993854e94a static/scripts/viz/trackster.js
--- a/static/scripts/viz/trackster.js
+++ b/static/scripts/viz/trackster.js
@@ -110,17 +110,23 @@
// ajax
$.ajax(
{
- url: config.app.new_browser,
+ url: config.root + "api/genomes?chrom_info=True",
data: {},
error: function() { alert( "Couldn't create new browser." ); },
- success: function(form_html)
+ success: function(response)
{
- show_modal("New Visualization", form_html,
+ // show dialog
+ show_modal("New Visualization", self.template_view_new(response),
{
"Cancel": function() { window.location = config.root + "visualization/list"; },
"Create": function() { self.create_browser($("#new-title").val(), $("#new-dbkey").val()); }
});
+ // select default
+ if (config.app.default_dbkey)
+ $("#new-dbkey option[value='" + config.default_dbkey +"']").attr("selected", true);
+
+ // change focus
$("#new-title").focus();
$("select[name='dbkey']").combobox(
{
@@ -134,6 +140,42 @@
});
},
+ // new browser form
+ template_view_new: function(response)
+ {
+ // start template
+ var html = '<form id="new-browser-form" action="javascript:void(0);" method="post" onsubmit="return false;">' +
+ '<div class="form-row">' +
+ '<label for="new-title">Browser name:</label>' +
+ '<div class="form-row-input">' +
+ '<input type="text" name="title" id="new-title" value="Unnamed"></input>' +
+ '</div>' +
+ '<div style="clear: both;"></div>' +
+ '</div>' +
+ '<div class="form-row">' +
+ '<label for="new-dbkey">Reference genome build (dbkey): </label>' +
+ '<div class="form-row-input">' +
+ '<select name="dbkey" id="new-dbkey">';
+
+ // add dbkeys
+ for (var key in response)
+ html += '<option value="' + response[key][1] + '">' + response[key][0] + '</option>';
+
+ // close selection/finalize template
+ html += '</select>' +
+ '</div>' +
+ '<div style="clear: both;"></div>' +
+ '</div>' +
+ '<div class="form-row">' +
+ 'Is the build not listed here? ' +
+ '<a href="' + config.root + 'user/dbkeys?use_panels=True">Add a Custom Build</a>' +
+ '</div>' +
+ '</form>';
+
+ // return
+ return html;
+ },
+
// create
create_browser : function(name, dbkey)
{
diff -r f3a985005267a8c2022da3c0c8d9af496f8e5901 -r f06d793860c40c59200c1441374ca4993854e94a static/scripts/viz/trackster/tracks.js
--- a/static/scripts/viz/trackster/tracks.js
+++ b/static/scripts/viz/trackster/tracks.js
@@ -951,7 +951,7 @@
// Introduction div shown when there are no tracks.
this.intro_div = $("<div/>").addClass("intro").appendTo(this.viewport_container).hide();
var add_tracks_button = $("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function () {
- visualization.select_datasets(config.root + "/visualization/list_current_history_datasets", config.root + "/api/datasets", { 'f-dbkey': view.dbkey }, function(tracks) {
+ visualization.select_datasets(config.root + "visualization/list_current_history_datasets", config.root + "api/datasets", { 'f-dbkey': view.dbkey }, function(tracks) {
_.each(tracks, function(track) {
view.add_drawable( object_from_template(track, view, view) );
});
diff -r f3a985005267a8c2022da3c0c8d9af496f8e5901 -r f06d793860c40c59200c1441374ca4993854e94a templates/webapps/galaxy/tracks/new_browser.mako
--- a/templates/webapps/galaxy/tracks/new_browser.mako
+++ /dev/null
@@ -1,29 +0,0 @@
-<form id="new-browser-form" action="javascript:void(0);" method="post" onsubmit="return false;">
- <div class="form-row">
- <label for="new-title">Browser name:</label>
- <div class="form-row-input">
- <input type="text" name="title" id="new-title" value="Unnamed"></input>
- </div>
- <div style="clear: both;"></div>
- </div>
- <div class="form-row">
- <label for="new-dbkey">Reference genome build (dbkey): </label>
- <div class="form-row-input">
- <select name="dbkey" id="new-dbkey">
- %for dbkey in dbkeys:
- <option value="${dbkey[1]}">${dbkey[0]}</option>
- %endfor
- </select>
- </div>
- <div style="clear: both;"></div>
- </div>
- <div class="form-row">
- Is the build not listed here?
- <a href="${h.url_for( controller='user', action='dbkeys', use_panels=True )}">Add a Custom Build</a>
- </div>
- %if default_dbkey is not None:
- <script type="text/javascript">
- $("#new-dbkey option[value='${default_dbkey}']").attr("selected", true);
- </script>
- %endif
-</form>
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: carlfeberhard: Pull request #168 from Kyle Ellrott: add graph content datatypes SIF, XGMML, RDF
by commits-noreply@bitbucket.org 08 Aug '13
by commits-noreply@bitbucket.org 08 Aug '13
08 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/f3a985005267/
Changeset: f3a985005267
User: carlfeberhard
Date: 2013-08-08 00:07:46
Summary: Pull request #168 from Kyle Ellrott: add graph content datatypes SIF, XGMML, RDF
Affected #: 3 files
diff -r 31774ed13ae2fc137d231df4b0cb710b8bb47797 -r f3a985005267a8c2022da3c0c8d9af496f8e5901 datatypes_conf.xml.sample
--- a/datatypes_conf.xml.sample
+++ b/datatypes_conf.xml.sample
@@ -245,6 +245,10 @@
<datatype extension="snpmatrix" type="galaxy.datatypes.genetics:SNPMatrix" display_in_upload="true"/><datatype extension="xls" type="galaxy.datatypes.tabular:Tabular"/><!-- End RGenetics Datatypes -->
+ <!-- graph datatypes -->
+ <datatype extension="xgmml" type="galaxy.datatypes.graph:Xgmml" display_in_upload="true"/>
+ <datatype extension="sif" type="galaxy.datatypes.graph:Sif" display_in_upload="true"/>
+ <datatype extension="rdf" type="galaxy.datatypes.graph:Rdf" display_in_upload="true"/></registration><sniffers><!--
@@ -281,6 +285,9 @@
<sniffer type="galaxy.datatypes.tabular:Sam"/><sniffer type="galaxy.datatypes.data:Newick"/><sniffer type="galaxy.datatypes.data:Nexus"/>
+ <sniffer type="galaxy.datatypes.graph:Xgmml"/>
+ <sniffer type="galaxy.datatypes.graph:Sif"/>
+ <sniffer type="galaxy.datatypes.graph:Rdf"/><sniffer type="galaxy.datatypes.images:Jpg"/><sniffer type="galaxy.datatypes.images:Png"/><sniffer type="galaxy.datatypes.images:Tiff"/>
diff -r 31774ed13ae2fc137d231df4b0cb710b8bb47797 -r f3a985005267a8c2022da3c0c8d9af496f8e5901 lib/galaxy/datatypes/graph.py
--- /dev/null
+++ b/lib/galaxy/datatypes/graph.py
@@ -0,0 +1,110 @@
+"""
+Graph content classes.
+"""
+
+import data, tabular, xml
+
+import logging
+log = logging.getLogger( __name__ )
+
+
+class Xgmml( xml.GenericXml ):
+ """
+ XGMML graph format
+ (http://wiki.cytoscape.org/Cytoscape_User_Manual/Network_Formats)
+ """
+ file_ext = "xgmml"
+
+ def set_peek( self, dataset, is_multi_byte=False ):
+ """
+ Set the peek and blurb text
+ """
+ if not dataset.dataset.purged:
+ dataset.peek = data.get_file_peek( dataset.file_name, is_multi_byte=is_multi_byte )
+ dataset.blurb = 'XGMML data'
+ else:
+ dataset.peek = 'file does not exist'
+ dataset.blurb = 'file purged from disk'
+
+ def sniff( self, filename ):
+ """
+ Determines whether the file is XML or not, should probably actually check if it is a real xgmml file....
+ """
+ line = ''
+ with open( filename ) as handle:
+ line = handle.readline()
+
+ #TODO - Is there a more robust way to do this?
+ return line.startswith( '<?xml ' )
+
+ @staticmethod
+ def merge( split_files, output_file ):
+ """
+ Merging multiple XML files is non-trivial and must be done in subclasses.
+ """
+ if len( split_files ) > 1:
+ raise NotImplementedError( "Merging multiple XML files is non-trivial "
+ + "and must be implemented for each XML type" )
+ #For one file only, use base class method (move/copy)
+ data.Text.merge( split_files, output_file )
+
+
+class Sif( tabular.Tabular ):
+ """
+ SIF graph format
+ (http://wiki.cytoscape.org/Cytoscape_User_Manual/Network_Formats)
+
+ First column: node id
+ Second column: relationship type
+ Third to Nth column: target ids for link
+ """
+ file_ext = "sif"
+
+ def set_peek( self, dataset, is_multi_byte=False ):
+ """
+ Set the peek and blurb text
+ """
+ if not dataset.dataset.purged:
+ dataset.peek = data.get_file_peek( dataset.file_name, is_multi_byte=is_multi_byte )
+ dataset.blurb = 'SIF data'
+ else:
+ dataset.peek = 'file does not exist'
+ dataset.blurb = 'file purged from disk'
+
+ def sniff( self, filename ):
+ """
+ Determines whether the file is SIF
+ """
+ print '---------------------------------------- sniffing Siffing'
+ line = ''
+ with open( filename ) as infile:
+ correct = True
+ for line in infile:
+ if not line.strip():
+ continue
+ tlen = len( line.split( "\t" ) )
+ # may contain 1 or >= 3 columns
+ if tlen == 2:
+ correct = False
+ return correct
+
+ @staticmethod
+ def merge( split_files, output_file ):
+ data.Text.merge( split_files, output_file )
+
+
+#TODO: we might want to look at rdflib or a similar, larger lib/egg
+class Rdf( xml.GenericXml ):
+ """
+ Resource Description Framework format (http://www.w3.org/RDF/)
+ """
+ file_ext = "rdf"
+
+ def set_peek( self, dataset, is_multi_byte=False ):
+ """Set the peek and blurb text"""
+ if not dataset.dataset.purged:
+ dataset.peek = data.get_file_peek( dataset.file_name, is_multi_byte=is_multi_byte )
+ dataset.blurb = 'RDF data'
+ else:
+ dataset.peek = 'file does not exist'
+ dataset.blurb = 'file purged from disk'
diff -r 31774ed13ae2fc137d231df4b0cb710b8bb47797 -r f3a985005267a8c2022da3c0c8d9af496f8e5901 lib/galaxy/datatypes/registry.py
--- a/lib/galaxy/datatypes/registry.py
+++ b/lib/galaxy/datatypes/registry.py
@@ -2,7 +2,7 @@
Provides mapping between extensions and datatypes, mime-types, etc.
"""
import os, sys, tempfile, threading, logging, imp
-import data, tabular, interval, images, sequence, qualityscore, genetics, xml, coverage, tracks, chrominfo, binary, assembly, ngsindex
+import data, tabular, interval, images, sequence, qualityscore, genetics, xml, coverage, tracks, chrominfo, binary, assembly, ngsindex, graph
import galaxy.util
from galaxy.util.odict import odict
from display_applications.application import DisplayApplication
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: jgoecks: Remove JSON2 library because it is no longer needed: all modern web browsers natively support JSON.stringify and JSON.parse
by commits-noreply@bitbucket.org 08 Aug '13
by commits-noreply@bitbucket.org 08 Aug '13
08 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/31774ed13ae2/
Changeset: 31774ed13ae2
User: jgoecks
Date: 2013-08-07 22:02:23
Summary: Remove JSON2 library because it is no longer needed: all modern web browsers natively support JSON.stringify and JSON.parse
Affected #: 6 files
diff -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 -r 31774ed13ae2fc137d231df4b0cb710b8bb47797 static/scripts/libs/json2.js
--- a/static/scripts/libs/json2.js
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- http://www.JSON.org/json2.js
- 2011-02-23
-
- Public Domain.
-
- NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
-
- See http://www.JSON.org/js.html
-
-
- This code should be minified before deployment.
- See http://javascript.crockford.com/jsmin.html
-
- USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
- NOT CONTROL.
-
-
- This file creates a global JSON object containing two methods: stringify
- and parse.
-
- JSON.stringify(value, replacer, space)
- value any JavaScript value, usually an object or array.
-
- replacer an optional parameter that determines how object
- values are stringified for objects. It can be a
- function or an array of strings.
-
- space an optional parameter that specifies the indentation
- of nested structures. If it is omitted, the text will
- be packed without extra whitespace. If it is a number,
- it will specify the number of spaces to indent at each
- level. If it is a string (such as '\t' or ' '),
- it contains the characters used to indent at each level.
-
- This method produces a JSON text from a JavaScript value.
-
- When an object value is found, if the object contains a toJSON
- method, its toJSON method will be called and the result will be
- stringified. A toJSON method does not serialize: it returns the
- value represented by the name/value pair that should be serialized,
- or undefined if nothing should be serialized. The toJSON method
- will be passed the key associated with the value, and this will be
- bound to the value
-
- For example, this would serialize Dates as ISO strings.
-
- Date.prototype.toJSON = function (key) {
- function f(n) {
- // Format integers to have at least two digits.
- return n < 10 ? '0' + n : n;
- }
-
- return this.getUTCFullYear() + '-' +
- f(this.getUTCMonth() + 1) + '-' +
- f(this.getUTCDate()) + 'T' +
- f(this.getUTCHours()) + ':' +
- f(this.getUTCMinutes()) + ':' +
- f(this.getUTCSeconds()) + 'Z';
- };
-
- You can provide an optional replacer method. It will be passed the
- key and value of each member, with this bound to the containing
- object. The value that is returned from your method will be
- serialized. If your method returns undefined, then the member will
- be excluded from the serialization.
-
- If the replacer parameter is an array of strings, then it will be
- used to select the members to be serialized. It filters the results
- such that only members with keys listed in the replacer array are
- stringified.
-
- Values that do not have JSON representations, such as undefined or
- functions, will not be serialized. Such values in objects will be
- dropped; in arrays they will be replaced with null. You can use
- a replacer function to replace those with JSON values.
- JSON.stringify(undefined) returns undefined.
-
- The optional space parameter produces a stringification of the
- value that is filled with line breaks and indentation to make it
- easier to read.
-
- If the space parameter is a non-empty string, then that string will
- be used for indentation. If the space parameter is a number, then
- the indentation will be that many spaces.
-
- Example:
-
- text = JSON.stringify(['e', {pluribus: 'unum'}]);
- // text is '["e",{"pluribus":"unum"}]'
-
-
- text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
- // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
-
- text = JSON.stringify([new Date()], function (key, value) {
- return this[key] instanceof Date ?
- 'Date(' + this[key] + ')' : value;
- });
- // text is '["Date(---current time---)"]'
-
-
- JSON.parse(text, reviver)
- This method parses a JSON text to produce an object or array.
- It can throw a SyntaxError exception.
-
- The optional reviver parameter is a function that can filter and
- transform the results. It receives each of the keys and values,
- and its return value is used instead of the original value.
- If it returns what it received, then the structure is not modified.
- If it returns undefined then the member is deleted.
-
- Example:
-
- // Parse the text. Values that look like ISO date strings will
- // be converted to Date objects.
-
- myData = JSON.parse(text, function (key, value) {
- var a;
- if (typeof value === 'string') {
- a =
-/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
- if (a) {
- return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
- +a[5], +a[6]));
- }
- }
- return value;
- });
-
- myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
- var d;
- if (typeof value === 'string' &&
- value.slice(0, 5) === 'Date(' &&
- value.slice(-1) === ')') {
- d = new Date(value.slice(5, -1));
- if (d) {
- return d;
- }
- }
- return value;
- });
-
-
- This is a reference implementation. You are free to copy, modify, or
- redistribute.
-*/
-
-/*jslint evil: true, strict: false, regexp: false */
-
-/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
- call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
- getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
- lastIndex, length, parse, prototype, push, replace, slice, stringify,
- test, toJSON, toString, valueOf
-*/
-
-
-// Create a JSON object only if one does not already exist. We create the
-// methods in a closure to avoid creating global variables.
-
-var JSON;
-if (!JSON) {
- JSON = {};
-}
-
-(function () {
- "use strict";
-
- function f(n) {
- // Format integers to have at least two digits.
- return n < 10 ? '0' + n : n;
- }
-
- if (typeof Date.prototype.toJSON !== 'function') {
-
- Date.prototype.toJSON = function (key) {
-
- return isFinite(this.valueOf()) ?
- this.getUTCFullYear() + '-' +
- f(this.getUTCMonth() + 1) + '-' +
- f(this.getUTCDate()) + 'T' +
- f(this.getUTCHours()) + ':' +
- f(this.getUTCMinutes()) + ':' +
- f(this.getUTCSeconds()) + 'Z' : null;
- };
-
- String.prototype.toJSON =
- Number.prototype.toJSON =
- Boolean.prototype.toJSON = function (key) {
- return this.valueOf();
- };
- }
-
- var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
- escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
- gap,
- indent,
- meta = { // table of character substitutions
- '\b': '\\b',
- '\t': '\\t',
- '\n': '\\n',
- '\f': '\\f',
- '\r': '\\r',
- '"' : '\\"',
- '\\': '\\\\'
- },
- rep;
-
-
- function quote(string) {
-
-// If the string contains no control characters, no quote characters, and no
-// backslash characters, then we can safely slap some quotes around it.
-// Otherwise we must also replace the offending characters with safe escape
-// sequences.
-
- escapable.lastIndex = 0;
- return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
- var c = meta[a];
- return typeof c === 'string' ? c :
- '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
- }) + '"' : '"' + string + '"';
- }
-
-
- function str(key, holder) {
-
-// Produce a string from holder[key].
-
- var i, // The loop counter.
- k, // The member key.
- v, // The member value.
- length,
- mind = gap,
- partial,
- value = holder[key];
-
-// If the value has a toJSON method, call it to obtain a replacement value.
-
- if (value && typeof value === 'object' &&
- typeof value.toJSON === 'function') {
- value = value.toJSON(key);
- }
-
-// If we were called with a replacer function, then call the replacer to
-// obtain a replacement value.
-
- if (typeof rep === 'function') {
- value = rep.call(holder, key, value);
- }
-
-// What happens next depends on the value's type.
-
- switch (typeof value) {
- case 'string':
- return quote(value);
-
- case 'number':
-
-// JSON numbers must be finite. Encode non-finite numbers as null.
-
- return isFinite(value) ? String(value) : 'null';
-
- case 'boolean':
- case 'null':
-
-// If the value is a boolean or null, convert it to a string. Note:
-// typeof null does not produce 'null'. The case is included here in
-// the remote chance that this gets fixed someday.
-
- return String(value);
-
-// If the type is 'object', we might be dealing with an object or an array or
-// null.
-
- case 'object':
-
-// Due to a specification blunder in ECMAScript, typeof null is 'object',
-// so watch out for that case.
-
- if (!value) {
- return 'null';
- }
-
-// Make an array to hold the partial results of stringifying this object value.
-
- gap += indent;
- partial = [];
-
-// Is the value an array?
-
- if (Object.prototype.toString.apply(value) === '[object Array]') {
-
-// The value is an array. Stringify every element. Use null as a placeholder
-// for non-JSON values.
-
- length = value.length;
- for (i = 0; i < length; i += 1) {
- partial[i] = str(i, value) || 'null';
- }
-
-// Join all of the elements together, separated with commas, and wrap them in
-// brackets.
-
- v = partial.length === 0 ? '[]' : gap ?
- '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
- '[' + partial.join(',') + ']';
- gap = mind;
- return v;
- }
-
-// If the replacer is an array, use it to select the members to be stringified.
-
- if (rep && typeof rep === 'object') {
- length = rep.length;
- for (i = 0; i < length; i += 1) {
- if (typeof rep[i] === 'string') {
- k = rep[i];
- v = str(k, value);
- if (v) {
- partial.push(quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- } else {
-
-// Otherwise, iterate through all of the keys in the object.
-
- for (k in value) {
- if (Object.prototype.hasOwnProperty.call(value, k)) {
- v = str(k, value);
- if (v) {
- partial.push(quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- }
-
-// Join all of the member texts together, separated with commas,
-// and wrap them in braces.
-
- v = partial.length === 0 ? '{}' : gap ?
- '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
- '{' + partial.join(',') + '}';
- gap = mind;
- return v;
- }
- }
-
-// If the JSON object does not yet have a stringify method, give it one.
-
- if (typeof JSON.stringify !== 'function') {
- JSON.stringify = function (value, replacer, space) {
-
-// The stringify method takes a value and an optional replacer, and an optional
-// space parameter, and returns a JSON text. The replacer can be a function
-// that can replace values, or an array of strings that will select the keys.
-// A default replacer method can be provided. Use of the space parameter can
-// produce text that is more easily readable.
-
- var i;
- gap = '';
- indent = '';
-
-// If the space parameter is a number, make an indent string containing that
-// many spaces.
-
- if (typeof space === 'number') {
- for (i = 0; i < space; i += 1) {
- indent += ' ';
- }
-
-// If the space parameter is a string, it will be used as the indent string.
-
- } else if (typeof space === 'string') {
- indent = space;
- }
-
-// If there is a replacer, it must be a function or an array.
-// Otherwise, throw an error.
-
- rep = replacer;
- if (replacer && typeof replacer !== 'function' &&
- (typeof replacer !== 'object' ||
- typeof replacer.length !== 'number')) {
- throw new Error('JSON.stringify');
- }
-
-// Make a fake root object containing our value under the key of ''.
-// Return the result of stringifying the value.
-
- return str('', {'': value});
- };
- }
-
-
-// If the JSON object does not yet have a parse method, give it one.
-
- if (typeof JSON.parse !== 'function') {
- JSON.parse = function (text, reviver) {
-
-// The parse method takes a text and an optional reviver function, and returns
-// a JavaScript value if the text is a valid JSON text.
-
- var j;
-
- function walk(holder, key) {
-
-// The walk method is used to recursively walk the resulting structure so
-// that modifications can be made.
-
- var k, v, value = holder[key];
- if (value && typeof value === 'object') {
- for (k in value) {
- if (Object.prototype.hasOwnProperty.call(value, k)) {
- v = walk(value, k);
- if (v !== undefined) {
- value[k] = v;
- } else {
- delete value[k];
- }
- }
- }
- }
- return reviver.call(holder, key, value);
- }
-
-
-// Parsing happens in four stages. In the first stage, we replace certain
-// Unicode characters with escape sequences. JavaScript handles many characters
-// incorrectly, either silently deleting them, or treating them as line endings.
-
- text = String(text);
- cx.lastIndex = 0;
- if (cx.test(text)) {
- text = text.replace(cx, function (a) {
- return '\\u' +
- ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
- });
- }
-
-// In the second stage, we run the text against regular expressions that look
-// for non-JSON patterns. We are especially concerned with '()' and 'new'
-// because they can cause invocation, and '=' because it can cause mutation.
-// But just to be safe, we want to reject all unexpected forms.
-
-// We split the second stage into 4 regexp operations in order to work around
-// crippling inefficiencies in IE's and Safari's regexp engines. First we
-// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
-// replace all simple value tokens with ']' characters. Third, we delete all
-// open brackets that follow a colon or comma or that begin the text. Finally,
-// we look to see that the remaining characters are only whitespace or ']' or
-// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
-
- if (/^[\],:{}\s]*$/
- .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
- .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
- .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
-
-// In the third stage we use the eval function to compile the text into a
-// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
-// in JavaScript: it can begin a block or an object literal. We wrap the text
-// in parens to eliminate the ambiguity.
-
- j = eval('(' + text + ')');
-
-// In the optional fourth stage, we recursively walk the new structure, passing
-// each name/value pair to a reviver function for possible transformation.
-
- return typeof reviver === 'function' ?
- walk({'': j}, '') : j;
- }
-
-// If the text is not JSON parseable, then a SyntaxError is thrown.
-
- throw new SyntaxError('JSON.parse');
- };
- }
-}());
diff -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 -r 31774ed13ae2fc137d231df4b0cb710b8bb47797 static/scripts/packed/libs/json2.js
--- a/static/scripts/packed/libs/json2.js
+++ /dev/null
@@ -1,1 +0,0 @@
-var JSON;if(!JSON){JSON={}}(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){if(typeof rep[i]==="string"){k=rep[i];v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.prototype.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof JSON.stringify!=="function"){JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.prototype.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}}());
\ No newline at end of file
diff -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 -r 31774ed13ae2fc137d231df4b0cb710b8bb47797 templates/base.mako
--- a/templates/base.mako
+++ b/templates/base.mako
@@ -40,7 +40,6 @@
"libs/jquery/jquery",
"libs/jquery/jquery.migrate",
"libs/jquery/select2",
- "libs/json2",
"libs/bootstrap",
"libs/underscore",
"libs/backbone/backbone",
diff -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 -r 31774ed13ae2fc137d231df4b0cb710b8bb47797 templates/base/base_panels.mako
--- a/templates/base/base_panels.mako
+++ b/templates/base/base_panels.mako
@@ -52,7 +52,6 @@
${h.js(
'libs/jquery/jquery',
'libs/jquery/jquery.migrate',
- 'libs/json2',
'libs/jquery/select2',
'libs/bootstrap',
'libs/underscore',
diff -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 -r 31774ed13ae2fc137d231df4b0cb710b8bb47797 templates/search/search.mako
--- a/templates/search/search.mako
+++ b/templates/search/search.mako
@@ -3,7 +3,6 @@
${h.js(
'libs/jquery/jquery',
- 'libs/json2'
)}
</%def>
diff -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 -r 31774ed13ae2fc137d231df4b0cb710b8bb47797 templates/webapps/galaxy/library/common/browse_library_opt.mako
--- a/templates/webapps/galaxy/library/common/browse_library_opt.mako
+++ b/templates/webapps/galaxy/library/common/browse_library_opt.mako
@@ -48,7 +48,6 @@
<%def name="javascripts()">
${parent.javascripts()}
- ${h.js("libs/json2")}
${h.js("libs/jquery/jstorage")}
${common_javascripts()}
${self.grid_javascripts()}
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: carlfeberhard: Visualization framework: add plugin version of scatterplot to be managed in the repo
by commits-noreply@bitbucket.org 08 Aug '13
by commits-noreply@bitbucket.org 08 Aug '13
08 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/42cbb2d2014c/
Changeset: 42cbb2d2014c
User: carlfeberhard
Date: 2013-08-07 21:43:44
Summary: Visualization framework: add plugin version of scatterplot to be managed in the repo
Affected #: 14 files
diff -r c623f3d38221c588de3976c05b688387933cbf29 -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 config/plugins/visualizations/scatterplot/Gruntfile.js
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/Gruntfile.js
@@ -0,0 +1,56 @@
+// NOTE: use 'sudo npm install .', then 'grunt' to use this file
+
+module.exports = function(grunt) {
+
+ grunt.initConfig({
+ pkg: grunt.file.readJSON( 'package.json' ),
+
+ handlebars: {
+ compile: {
+ options: {
+ namespace: 'Templates',
+ processName : function( filepath ){
+ return filepath.match( /\w*\.handlebars/ )[0].replace( '.handlebars', '' );
+ }
+ },
+ files: {
+ "build/compiled-templates.js" : "src/handlebars/*.handlebars"
+ }
+ }
+ },
+
+ concat: {
+ options: {
+ separator: ';\n'
+ },
+ dist: {
+ //NOTE: mvc references templates - templates must be cat'd first
+ src : [ 'build/compiled-templates.js', 'src/**/*.js' ],
+ dest: 'build/scatterplot-concat.js'
+ }
+ },
+
+ uglify: {
+ options: {
+ },
+ dist: {
+ src : 'build/scatterplot-concat.js',
+ // uglify directly into static dir
+ dest: 'static/scatterplot.js'
+ }
+ },
+
+ watch: {
+ files: [ 'src/**.js', 'src/handlebars/*.handlebars' ],
+ tasks: [ 'default' ]
+ }
+ });
+
+ grunt.loadNpmTasks( 'grunt-contrib-handlebars' );
+ grunt.loadNpmTasks( 'grunt-contrib-concat' );
+ grunt.loadNpmTasks( 'grunt-contrib-uglify' );
+ grunt.loadNpmTasks( 'grunt-contrib-watch' );
+
+ grunt.registerTask( 'default', [ 'handlebars', 'concat', 'uglify' ]);
+ grunt.registerTask( 'watch', [ 'handlebars', 'concat', 'uglify', 'watch' ]);
+};
diff -r c623f3d38221c588de3976c05b688387933cbf29 -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 config/plugins/visualizations/scatterplot/config/scatterplot.xml
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/config/scatterplot.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE visualization SYSTEM "../../visualization.dtd">
+<visualization name="scatterplot">
+ <data_sources>
+ <data_source>
+ <model_class>HistoryDatasetAssociation</model_class>
+ <test type="isinstance" test_attr="datatype" result_type="datatype">tabular.Tabular</test>
+ <to_param param_attr="id">dataset_id</to_param>
+ </data_source>
+ </data_sources>
+ <params>
+ <param type="dataset" var_name_in_template="hda" required="true">dataset_id</param>
+ </params>
+ <template>scatterplot/templates/scatterplot.mako</template>
+</visualization>
diff -r c623f3d38221c588de3976c05b688387933cbf29 -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 config/plugins/visualizations/scatterplot/package.json
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "galaxy-scatterplot",
+ "version": "0.0.0",
+ "description": "Scatterplot visualization plugin for the Galaxy informatics framework",
+ "main": " ",
+ "scripts": {
+ "test": "test"
+ },
+ "keywords": [
+ "galaxy",
+ "visualization",
+ "d3"
+ ],
+ "author": "Carl Eberhard",
+ "license": "BSD",
+ "devDependencies": {
+ "grunt": "~0.4.1",
+ "grunt-cli": "~0.1.9",
+ "grunt-contrib-handlebars": "~0.5.10",
+ "grunt-contrib-concat": "~0.3.0",
+ "grunt-contrib-uglify": "~0.2.2",
+ "grunt-contrib-watch": "~0.5.1"
+ }
+}
diff -r c623f3d38221c588de3976c05b688387933cbf29 -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 config/plugins/visualizations/scatterplot/src/handlebars/chartControl.handlebars
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/src/handlebars/chartControl.handlebars
@@ -0,0 +1,56 @@
+<p class="help-text">
+ Use the following controls to how the chart is displayed.
+ The slide controls can be moved by the mouse or, if the 'handle' is in focus, your keyboard's arrow keys.
+ Move the focus between controls by using the tab or shift+tab keys on your keyboard.
+ Use the 'Draw' button to render (or re-render) the chart with the current settings.
+ </p>
+
+ <div id="datapointSize" class="form-input numeric-slider-input">
+ <label for="datapointSize">Size of data point: </label>
+ <div class="slider-output">{{datapointSize}}</div>
+ <div class="slider"></div>
+ <p class="form-help help-text-small">
+ Size of the graphic representation of each data point
+ </p>
+ </div>
+
+ <div id="animDuration" class="form-input checkbox-input">
+ <label for="animate-chart">Animate chart transitions?: </label>
+ <input type="checkbox" id="animate-chart"
+ class="checkbox control"{{#if animDuration}} checked="true"{{/if}} />
+ <p class="form-help help-text-small">
+ Uncheck this to disable the animations used on the chart
+ </p>
+ </div>
+
+ <div id="width" class="form-input numeric-slider-input">
+ <label for="width">Chart width: </label>
+ <div class="slider-output">{{width}}</div>
+ <div class="slider"></div>
+ <p class="form-help help-text-small">
+ (not including chart margins and axes)
+ </p>
+ </div>
+
+ <div id="height" class="form-input numeric-slider-input">
+ <label for="height">Chart height: </label>
+ <div class="slider-output">{{height}}</div>
+ <div class="slider"></div>
+ <p class="form-help help-text-small">
+ (not including chart margins and axes)
+ </p>
+ </div>
+
+ <div id="X-axis-label"class="text-input form-input">
+ <label for="X-axis-label">Re-label the X axis: </label>
+ <input type="text" name="X-axis-label" id="X-axis-label" value="{{xLabel}}" />
+ <p class="form-help help-text-small"></p>
+ </div>
+
+ <div id="Y-axis-label" class="text-input form-input">
+ <label for="Y-axis-label">Re-label the Y axis: </label>
+ <input type="text" name="Y-axis-label" id="Y-axis-label" value="{{yLabel}}" />
+ <p class="form-help help-text-small"></p>
+ </div>
+
+ <input id="render-button" type="button" value="Draw" />
\ No newline at end of file
diff -r c623f3d38221c588de3976c05b688387933cbf29 -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 config/plugins/visualizations/scatterplot/src/handlebars/chartDisplay.handlebars
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/src/handlebars/chartDisplay.handlebars
@@ -0,0 +1,1 @@
+<svg width="{{width}}" height="{{height}}"></svg>
\ No newline at end of file
diff -r c623f3d38221c588de3976c05b688387933cbf29 -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 config/plugins/visualizations/scatterplot/src/handlebars/dataControl.handlebars
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/src/handlebars/dataControl.handlebars
@@ -0,0 +1,56 @@
+<p class="help-text">
+ Use the following controls to change the data used by the chart.
+ Use the 'Draw' button to render (or re-render) the chart with the current settings.
+ </p>
+
+ {{! column selector containers }}
+ <div class="column-select">
+ <label for="X-select">Data column for X: </label>
+ <select name="X" id="X-select">
+ {{#each numericColumns}}
+ <option value="{{index}}">{{name}}</option>
+ {{/each}}
+ </select>
+ </div>
+ <div class="column-select">
+ <label for="Y-select">Data column for Y: </label>
+ <select name="Y" id="Y-select">
+ {{#each numericColumns}}
+ <option value="{{index}}">{{name}}</option>
+ {{/each}}
+ </select>
+ </div>
+
+ {{! optional id column }}
+ <div id="include-id">
+ <label for="include-id-checkbox">Include a third column as data point IDs?</label>
+ <input type="checkbox" name="include-id" id="include-id-checkbox" />
+ <p class="help-text-small">
+ These will be displayed (along with the x and y values) when you hover over
+ a data point.
+ </p>
+ </div>
+ <div class="column-select" style="display: none">
+ <label for="ID-select">Data column for IDs: </label>
+ <select name="ID" id="ID-select">
+ {{#each allColumns}}
+ <option value="{{index}}">{{name}}</option>
+ {{/each}}
+ </select>
+ </div>
+
+ {{! if we're using generic column selection names ('column 1') - allow the user to use the first line }}
+ <div id="first-line-header" style="display: none;">
+ <p>Possible headers: {{ possibleHeaders }}
+ </p>
+ <label for="first-line-header-checkbox">Use the above as column headers?</label>
+ <input type="checkbox" name="include-id" id="first-line-header-checkbox"
+ {{#if usePossibleHeaders }}checked="true"{{/if}}/>
+ <p class="help-text-small">
+ It looks like Galaxy couldn't get proper column headers for this data.
+ Would you like to use the column headers above as column names to select columns?
+ </p>
+ </div>
+
+ <input id="render-button" type="button" value="Draw" />
+ <div class="clear"></div>
\ No newline at end of file
diff -r c623f3d38221c588de3976c05b688387933cbf29 -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 config/plugins/visualizations/scatterplot/src/handlebars/scatterplotControlForm.handlebars
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/src/handlebars/scatterplotControlForm.handlebars
@@ -0,0 +1,46 @@
+{{! main layout }}
+
+<div class="scatterplot-container chart-container tabbable tabs-left">
+ {{! tab buttons/headers using Bootstrap }}
+ <ul class="nav nav-tabs">
+ {{! start with the data controls as the displayed tab }}
+ <li class="active"><a href="#data-control" data-toggle="tab" class="tooltip"
+ title="Use this tab to change which data are used">Data Controls</a></li>
+ <li><a href="#chart-control" data-toggle="tab" class="tooltip"
+ title="Use this tab to change how the chart is drawn">Chart Controls</a></li>
+ <li><a href="#stats-display" data-toggle="tab" class="tooltip"
+ title="This tab will display overall statistics for your data">Statistics</a></li>
+ <li><a href="#chart-display" data-toggle="tab" class="tooltip"
+ title="This tab will display the chart">Chart</a>
+ {{! loading indicator - initially hidden }}
+ <div id="loading-indicator" style="display: none;">
+ <img class="loading-img" src="{{loadingIndicatorImagePath}}" />
+ <span class="loading-message">{{message}}</span>
+ </div>
+ </li>
+ </ul>
+
+ {{! data form, chart config form, stats, and chart all get their own tab }}
+ <div class="tab-content">
+ {{! ---------------------------- tab for data settings form }}
+ <div id="data-control" class="tab-pane active">
+ {{! rendered separately }}
+ </div>
+
+ {{! ---------------------------- tab for chart graphics control form }}
+ <div id="chart-control" class="tab-pane">
+ {{! rendered separately }}
+ </div>
+
+ {{! ---------------------------- tab for data statistics }}
+ <div id="stats-display" class="tab-pane">
+ {{! rendered separately }}
+ </div>
+
+ {{! ---------------------------- tab for actual chart }}
+ <div id="chart-display" class="tab-pane">
+ {{! chart rendered separately }}
+ </div>
+
+ </div>{{! end .tab-content }}
+</div>{{! end .chart-control }}
\ No newline at end of file
diff -r c623f3d38221c588de3976c05b688387933cbf29 -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 config/plugins/visualizations/scatterplot/src/handlebars/statsDisplay.handlebars
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/src/handlebars/statsDisplay.handlebars
@@ -0,0 +1,8 @@
+<p class="help-text">By column:</p>
+ <table id="chart-stats-table">
+ <thead><th></th><th>X</th><th>Y</th></thead>
+ {{#each stats}}
+ <tr><td>{{name}}</td><td>{{xval}}</td><td>{{yval}}</td></tr>
+ </tr>
+ {{/each}}
+ </table>
\ No newline at end of file
diff -r c623f3d38221c588de3976c05b688387933cbf29 -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 config/plugins/visualizations/scatterplot/src/scatterplot.js
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/src/scatterplot.js
@@ -0,0 +1,488 @@
+/* =============================================================================
+todo:
+ outside this:
+ BUG: setting width, height in plot controls doesn't re-interpolate data locations!!
+ BUG?: get metadata_column_names (from datatype if necessary)
+ BUG: single vis in popupmenu should have tooltip with that name NOT 'Visualizations'
+
+ wire label setters, anim setter
+
+ TwoVarScatterplot:
+ ??: maybe better to do this with a canvas...
+ save as visualization
+ to seperate file?
+ remove underscore dependencies
+ add interface to change values (seperate)?
+ download svg -> base64 encode
+ incorporate glyphs, glyph state renderers
+
+ ScatterplotSettingsForm:
+ some css bug that lowers the width of settings form when plot-controls tab is open
+ causes chart to shift
+ what can be abstracted/reused for other graphs?
+ avoid direct manipulation of this.plot
+ allow option to put plot into seperate tab of interface (for small multiples)
+
+ provide callback in view to load data incrementally - for large sets
+ paginate
+ handle rerender
+ use endpoint (here and on the server (fileptr))
+ fetch (new?) data
+ handle rerender
+ use d3.TSV?
+ render warning on long data (> maxDataPoints)
+ adjust endpoint
+
+ selectable list of preset column comparisons (rnaseq etc.)
+ how to know what sort of Tabular the data is?
+ smarter about headers
+ validate columns selection (here or server)
+
+ set stats column names by selected columns
+ move chart into tabbed area...
+
+ Scatterplot.mako:
+ multiple plots on one page (small multiples)
+ ?? ensure svg styles thru d3 or css?
+ d3: configable (easily)
+ css: standard - better maintenance
+ ? override at config
+
+============================================================================= */
+/**
+ * Two Variable scatterplot visualization using d3
+ * Uses semi transparent circles to show density of data in x, y grid
+ * usage :
+ * var plot = new TwoVarScatterplot({ containerSelector : 'div#my-plot', ... })
+ * plot.render( xColumnData, yColumnData );
+ *
+ * depends on: d3, underscore
+ */
+function TwoVarScatterplot( config ){
+ var TICK_LINE_AND_PADDING = 10,
+ GUESS_AT_SVG_CHAR_WIDTH = 7,
+ GUESS_AT_SVG_CHAR_HEIGHT = 10,
+ PADDING = 8,
+ X_LABEL_TOO_LONG_AT = 5;
+
+ // set up logging
+ //this.debugging = true;
+ this.log = function(){
+ if( this.debugging && console && console.debug ){
+ var args = Array.prototype.slice.call( arguments );
+ args.unshift( this.toString() );
+ console.debug.apply( console, args );
+ }
+ };
+ this.log( 'new TwoVarScatterplot:', config );
+
+ // ........................................................ set up chart config
+ // config will default to these values when not passed in
+ //NOTE: called on new
+ this.defaults = {
+ id : 'TwoVarScatterplot',
+ containerSelector : 'body',
+ //TODO??: needed?
+ maxDataPoints : 30000,
+ datapointSize : 4,
+ animDuration : 500,
+ //TODO: variable effect (not always exactly # of ticks set to)
+ xNumTicks : 10,
+ yNumTicks : 10,
+ xAxisLabelBumpY : 40,
+ yAxisLabelBumpX : -40,
+ width : 400,
+ height : 400,
+ //TODO: anyway to make this a sub-obj?
+ 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, config );
+ this.log( 'intial config:', this.config );
+
+ this.updateConfig = function( newConfig, rerender ){
+ // setter for chart config
+ //TODO: validate here
+ _.extend( this.config, newConfig );
+ this.log( this + '.updateConfig:', this.config );
+ //TODO: implement rerender flag
+ };
+
+ // ........................................................ helpers
+ this.toString = function(){
+ return this.config.id;
+ };
+ // conv. methods for svg transforms
+ this.translateStr = function( x, y ){
+ return 'translate(' + x + ',' + y + ')';
+ };
+ this.rotateStr = function( d, x, y ){
+ return 'rotate(' + d + ',' + x + ',' + y + ')';
+ };
+
+ // ........................................................ initial element creation
+ this.adjustChartDimensions = function( top, right, bottom, left ){
+ //this.log( this + '.adjustChartDimensions', arguments );
+ top = top || 0;
+ right = right || 0;
+ bottom = bottom || 0;
+ left = left || 0;
+ this.svg
+ .attr( "width", this.config.width + ( this.config.marginRight + right )
+ + ( this.config.marginLeft + left ) )
+ .attr( "height", this.config.height + ( this.config.marginTop + top )
+ + ( this.config.marginBottom + bottom ) )
+ // initial is hidden - show it
+ .style( 'display', 'block' );
+
+ // move content group away from margins
+ //TODO: allow top, right axis
+ this.content = this.svg.select( "g.content" )
+ .attr( "transform", this.translateStr( this.config.marginLeft + left, this.config.marginTop + top ) );
+ };
+
+ // ........................................................ data and scales
+ this.preprocessData = function( data, min, max ){
+ //this.log( this + '.preprocessData', arguments );
+ //TODO: filter by min, max if set
+
+ // set a cap on the data, limit to first n points
+ return ( data.length > this.config.maxDataPoints )? ( data.slice( 0, this.config.maxDataPoints ) ): ( data );
+ };
+
+ this.findMinMaxes = function( xCol, yCol, meta ){
+ //this.log( this + '.findMinMaxes', arguments );
+ // configuration takes priority, otherwise meta (from the server) if passed, last-resort: compute it here
+ this.xMin = this.config.xMin || ( meta )?( meta[0].min ):( d3.min( xCol ) );
+ this.xMax = this.config.xMax || ( meta )?( meta[0].max ):( d3.max( xCol ) );
+ this.yMin = this.config.yMin || ( meta )?( meta[1].min ):( d3.min( yCol ) );
+ this.yMax = this.config.yMax || ( meta )?( meta[1].max ):( d3.max( yCol ) );
+ };
+
+ this.setUpScales = function(){
+ //this.log( this + '.setUpScales', arguments );
+ // Interpolation for x, y based on data domains
+ 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 ]);
+ };
+
+ // ........................................................ axis and ticks
+ this.setUpXAxis = function(){
+ //this.log( this + '.setUpXAxis', arguments );
+ // origin: bottom, left
+ //TODO: incoporate top, right
+ this.xAxisFn = d3.svg.axis()
+ .scale( this.xScale )
+ .ticks( this.config.xNumTicks )
+ .orient( 'bottom' );
+ this.xAxis// = content.select( 'g#x-axis' )
+ .attr( 'transform', this.translateStr( 0, this.config.height ) )
+ .call( this.xAxisFn );
+ //this.log( 'xAxis:', this.xAxis );
+
+ //TODO: adjust ticks when tick labels are long - move odds down and extend tick line
+ // (for now) hide them
+ var xLongestTickLabel = d3.max( _.map( [ this.xMin, this.xMax ],
+ function( number ){ return ( String( number ) ).length; } ) );
+ //this.log( 'xLongestTickLabel:', xLongestTickLabel );
+ if( xLongestTickLabel >= X_LABEL_TOO_LONG_AT ){
+ this.xAxis.selectAll( 'g' ).filter( ':nth-child(odd)' ).style( 'display', 'none' );
+ }
+
+ this.log( 'this.config.xLabel:', this.config.xLabel );
+ this.xAxisLabel// = xAxis.select( 'text#x-axis-label' )
+ .attr( 'x', this.config.width / 2 )
+ .attr( 'y', this.config.xAxisLabelBumpY )
+ .attr( 'text-anchor', 'middle' )
+ .text( this.config.xLabel );
+ this.log( 'xAxisLabel:', this.xAxisLabel );
+ };
+
+ this.setUpYAxis = function(){
+ //this.log( this + '.setUpYAxis', arguments );
+ this.yAxisFn = d3.svg.axis()
+ .scale( this.yScale )
+ .ticks( this.config.yNumTicks )
+ .orient( 'left' );
+ this.yAxis// = content.select( 'g#y-axis' )
+ .call( this.yAxisFn );
+ //this.log( 'yAxis:', this.yAxis );
+
+ // a too complicated section for increasing the left margin when tick labels are long
+ // get the tick labels for the y axis
+ var yTickLabels = this.yAxis.selectAll( 'text' ).filter( function( e, i ){ return i !== 0; } );
+ this.log( 'yTickLabels:', yTickLabels );
+
+ // get the longest label length (or 0 if no labels)
+ this.yLongestLabel = d3.max(
+ //NOTE: d3 returns an nested array - use the plain array inside ([0])
+ yTickLabels[0].map( function( e, i ){
+ return ( d3.select( e ).text() ).length;
+ })
+ ) || 0;
+ //this.log( 'yLongestLabel:', this.yLongestLabel );
+ //TODO: lose the guessing if possible
+ var neededY = TICK_LINE_AND_PADDING + ( this.yLongestLabel * GUESS_AT_SVG_CHAR_WIDTH )
+ + PADDING + GUESS_AT_SVG_CHAR_HEIGHT;
+ //this.log( 'neededY:', neededY );
+
+ // increase width for yLongerStr, increase margin for y
+ //TODO??: (or transform each number: 2k)
+ this.config.yAxisLabelBumpX = -( neededY - GUESS_AT_SVG_CHAR_HEIGHT );
+ if( this.config.marginLeft < neededY ){
+ var adjusting = ( neededY ) - this.config.marginLeft;
+ adjusting = ( adjusting < 0 )?( 0 ):( adjusting );
+ //this.log( 'adjusting:', adjusting );
+
+ // update dimensions, translations
+ this.adjustChartDimensions( 0, 0, 0, adjusting );
+ }
+ //this.log( 'this.config.yAxisLableBumpx, this.config.marginLeft:',
+ // this.config.yAxisLabelBumpX, this.config.marginLeft );
+
+ this.yAxisLabel// = yAxis.select( 'text#y-axis-label' )
+ .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.log( 'yAxisLabel:', this.yAxisLabel );
+ };
+
+ // ........................................................ grid lines
+ this.renderGrid = function(){
+ //this.log( this + '.renderGrid', arguments );
+ // VERTICAL
+ // select existing
+ this.vGridLines = this.content.selectAll( 'line.v-grid-line' )
+ .data( this.xScale.ticks( this.xAxisFn.ticks()[0] ) );
+
+ // append any extra lines needed (more ticks)
+ this.vGridLines.enter().append( 'svg:line' )
+ .classed( 'grid-line v-grid-line', true );
+
+ // update the attributes of existing and appended
+ this.vGridLines
+ .attr( 'x1', this.xScale )
+ .attr( 'y1', 0 )
+ .attr( 'x2', this.xScale )
+ .attr( 'y2', this.config.height );
+
+ // remove unneeded (less ticks)
+ this.vGridLines.exit().remove();
+ //this.log( 'vGridLines:', this.vGridLines );
+
+ // HORIZONTAL
+ 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.log( 'hGridLines:', this.hGridLines );
+ };
+
+ // ........................................................ data points
+ this.renderDatapoints = function( xCol, yCol, ids ){
+ this.log( this + '.renderDatapoints', arguments );
+ var count = 0,
+ plot = this,
+ xPosFn = function( d, i ){
+ //if( d ){ this.log( 'x.data:', newXCol[ i ], 'plotted:', plot.xScale( newXCol[ i ] ) ); }
+ return plot.xScale( xCol[ i ] );
+ },
+ yPosFn = function( d, i ){
+ //if( d ){ this.log( 'y.data:', newYCol[ i ], 'plotted:', plot.yScale( newYCol[ i ] ) ); }
+ return plot.yScale( yCol[ i ] );
+ };
+
+ //this.datapoints = this.addDatapoints( xCol, yCol, ids, ".glyph" );
+ var datapoints = this.content.selectAll( '.glyph' ).data( xCol );
+
+ // enter - NEW data to be added as glyphs: give them a 'entry' position and style
+ count = 0;
+ datapoints.enter()
+ .append( 'svg:circle' )
+ .each( function(){ count += 1; } )
+ .classed( "glyph", true )
+ .attr( "cx", 0 )
+ .attr( "cy", this.config.height )
+ // start all bubbles small...
+ .attr( "r", 0 );
+ this.log( count, ' new glyphs created' );
+
+ // for all EXISTING glyphs and those that need to be added: transition anim to final state
+ count = 0;
+ datapoints
+ // ...animate to final position
+ .transition().duration( this.config.animDuration )
+ .each( function(){ count += 1; } )
+ .attr( "cx", xPosFn )
+ .attr( "cy", yPosFn )
+ .attr( "r", plot.config.datapointSize );
+ this.log( count, ' existing glyphs transitioned' );
+
+ // events
+ // glyphs that need to be removed: transition to from normal state to 'exit' state, remove from DOM
+ datapoints.exit()
+ .each( function(){ count += 1; } )
+ .transition().duration( this.config.animDuration )
+ .attr( "cy", this.config.height )
+ .attr( "r", 0 )
+ .remove();
+ this.log( count, ' glyphs removed' );
+
+ this._addDatapointEventhandlers( datapoints, xCol, yCol, ids );
+ };
+
+ this._addDatapointEventhandlers = function( datapoints, xCol, yCol, ids ){
+ var plot = this;
+ datapoints
+ //TODO: remove magic numbers
+ .on( 'mouseover', function( d, i ){
+ var datapoint = d3.select( this );
+ datapoint
+ .style( 'fill', 'red' )
+ .style( 'fill-opacity', 1 );
+
+ // create horiz, vert lines to axis
+ plot.content.append( 'line' )
+ .attr( 'stroke', 'red' )
+ .attr( 'stroke-width', 1 )
+ // start not at center, but at the edge of the circle - to prevent mouseover thrashing
+ .attr( 'x1', datapoint.attr( 'cx' ) - plot.config.datapointSize )
+ .attr( 'y1', datapoint.attr( 'cy' ) )
+ .attr( 'x2', 0 )
+ .attr( 'y2', datapoint.attr( 'cy' ) )
+ .classed( 'hoverline', true );
+
+ // if the vertical hoverline
+ if( datapoint.attr( 'cy' ) < plot.config.height ){
+ plot.content.append( 'line' )
+ .attr( 'stroke', 'red' )
+ .attr( 'stroke-width', 1 )
+ .attr( 'x1', datapoint.attr( 'cx' ) )
+ .attr( 'y1', datapoint.attr( 'cy' ) + plot.config.datapointSize )
+ .attr( 'x2', datapoint.attr( 'cx' ) )
+ .attr( 'y2', plot.config.height )
+ .classed( 'hoverline', true );
+ }
+
+ var datapointWindowPos = $( this ).offset();
+ plot.datapointInfoBox = plot.infoBox(
+ datapointWindowPos.top, datapointWindowPos.left,
+ plot.infoHtml( xCol[ i ], yCol[ i ], ( ids )?( ids[ i ] ):( undefined ) )
+ );
+ $( 'body' ).append( plot.datapointInfoBox );
+ })
+ .on( 'mouseout', function(){
+ d3.select( this )
+ .style( 'fill', 'black' )
+ .style( 'fill-opacity', 0.2 );
+ plot.content.selectAll( '.hoverline' ).remove();
+ if( plot.datapointInfoBox ){
+ plot.datapointInfoBox.remove();
+ }
+ });
+ },
+
+ this.render = function( columnData, meta ){
+ this.log( this + '.render', arguments );
+ this.log( '\t config:', this.config );
+
+ // prepare the data
+ //pre: columns passed are numeric
+ //pre: at least two columns are passed
+ //assume: first column is x, second column is y, any remaining aren't used
+ var xCol = columnData[0],
+ yCol = columnData[1],
+ ids = ( columnData.length > 2 )?( columnData[2] ):( undefined );
+ //this.log( this + '.render', xCol.length, yCol.length, this.config );
+
+ //pre: xCol.len == yCol.len
+ xCol = this.preprocessData( xCol );
+ yCol = this.preprocessData( yCol );
+ this.log( 'xCol len', xCol.length, 'yCol len', yCol.length );
+
+ this.findMinMaxes( xCol, yCol, meta );
+ //this.log( 'xMin, xMax, yMin, yMax:', this.xMin, this.xMax, this.yMin, this.yMax );
+ this.setUpScales();
+
+ // find (or build if it doesn't exist) the svg dom infrastructure
+ if( !this.svg ){ this.svg = d3.select( 'svg' ).attr( "class", "chart" ); }
+ if( !this.content ){
+ this.content = this.svg.append( "svg:g" ).attr( "class", "content" ).attr( 'id', this.config.id );
+ }
+ //this.log( 'svg:', this.svg );
+ //this.log( 'content:', this.content );
+
+ this.adjustChartDimensions();
+
+ if( !this.xAxis ){ this.xAxis = this.content.append( 'g' ).attr( 'class', 'axis' ).attr( 'id', 'x-axis' ); }
+ if( !this.xAxisLabel ){
+ this.xAxisLabel = this.xAxis.append( 'text' ).attr( 'class', 'axis-label' ).attr( 'id', 'x-axis-label' );
+ }
+ //this.log( 'xAxis:', this.xAxis, 'xAxisLabel:', this.xAxisLabel );
+
+ if( !this.yAxis ){ this.yAxis = this.content.append( 'g' ).attr( 'class', 'axis' ).attr( 'id', 'y-axis' ); }
+ if( !this.yAxisLabel ){
+ this.yAxisLabel = this.yAxis.append( 'text' ).attr( 'class', 'axis-label' ).attr( 'id', 'y-axis-label' );
+ }
+ //this.log( 'yAxis:', this.yAxis, 'yAxisLabel:', this.yAxisLabel );
+
+ this.setUpXAxis();
+ this.setUpYAxis();
+
+ this.renderGrid();
+ this.renderDatapoints( xCol, yCol, ids );
+ };
+
+ this.infoHtml = function( x, y, id ){
+ var retDiv = $( '<div/>' );
+ if( id ){
+ $( '<div/>' ).text( id ).css( 'font-weight', 'bold' ).appendTo( retDiv );
+ }
+ $( '<div/>' ).text( x ).appendTo( retDiv );
+ $( '<div/>' ).text( y ).appendTo( retDiv );
+ return retDiv.html();
+ };
+
+ //TODO: html for now
+ this.infoBox = function( top, left, html, adjTop, adjLeft ){
+ adjTop = adjTop || 0;
+ adjLeft = adjLeft || 20;
+ var infoBox = $( '<div />' )
+ .addClass( 'chart-info-box' )
+ .css({
+ 'position' : 'absolute',
+ 'top' : top + adjTop,
+ 'left' : left + adjLeft
+ });
+ infoBox.html( html );
+ return infoBox;
+ };
+
+}
+
+//==============================================================================
diff -r c623f3d38221c588de3976c05b688387933cbf29 -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 config/plugins/visualizations/scatterplot/src/scatterplotControlForm.js
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/src/scatterplotControlForm.js
@@ -0,0 +1,631 @@
+/* =============================================================================
+todo:
+ I'd like to move the svg creation out of the splot constr. to:
+ allow adding splots to an existing canvas
+ allow mult. splots sharing a canvas
+
+
+ outside this:
+ BUG: setting width, height in plot controls doesn't re-interpolate data locations!!
+ BUG?: get metadata_column_names (from datatype if necessary)
+ BUG: single vis in popupmenu should have tooltip with that name NOT 'Visualizations'
+
+ wire label setters, anim setter
+
+ TwoVarScatterplot:
+ ??: maybe better to do this with a canvas...
+ save as visualization
+ to seperate file?
+ remove underscore dependencies
+ add interface to change values (seperate)?
+ download svg -> base64 encode
+ incorporate glyphs, glyph state renderers
+
+ ScatterplotSettingsForm:
+ some css bug that lowers the width of settings form when plot-controls tab is open
+ causes chart to shift
+ what can be abstracted/reused for other graphs?
+ avoid direct manipulation of this.plot
+ allow option to put plot into seperate tab of interface (for small multiples)
+
+ provide callback in view to load data incrementally - for large sets
+ paginate
+ handle rerender
+ use endpoint (here and on the server (fileptr))
+ fetch (new?) data
+ handle rerender
+ use d3.TSV?
+ render warning on long data (> maxDataPoints)
+ adjust endpoint
+
+ selectable list of preset column comparisons (rnaseq etc.)
+ how to know what sort of Tabular the data is?
+ smarter about headers
+ validate columns selection (here or server)
+
+ set stats column names by selected columns
+ move chart into tabbed area...
+
+ Scatterplot.mako:
+ multiple plots on one page (small multiples)
+ ?? ensure svg styles thru d3 or css?
+ d3: configable (easily)
+ css: standard - better maintenance
+ ? override at config
+
+============================================================================= */
+/**
+ * Scatterplot control UI as a backbone view
+ * handles:
+ * getting the desired data
+ * configuring the plot display
+ * showing (general) statistics
+ *
+ * initialize attributes REQUIRES a dataset and an apiDatasetsURL
+ */
+var ScatterplotControlForm = BaseView.extend( LoggableMixin ).extend({
+ //logger : console,
+ className : 'scatterplot-control-form',
+
+ //NOTE: should include time needed to render
+ dataLoadDelay : 4000,
+ dataLoadSize : 5000,
+
+ loadingIndicatorImage : 'loading_small_white_bg.gif',
+ fetchMsg : 'Fetching data...',
+ renderMsg : 'Rendering...',
+
+ initialize : function( attributes ){
+ this.log( this + '.initialize, attributes:', attributes );
+
+ this.dataset = null;
+ this.chartConfig = null;
+ this.chart = null;
+ this.loader = null;
+
+ // set up refs to the four tab areas
+ this.$dataControl = null;
+ this.$chartControl = null;
+ this.$statsDisplay = null;
+ this.$chartDisplay = null;
+
+ this.dataFetch = null;
+
+ this.initializeFromAttributes( attributes );
+ this.initializeChart( attributes );
+ this.initializeDataLoader( attributes );
+ },
+
+ initializeFromAttributes : function( attributes ){
+ // required settings: ensure certain vars we need are passed in attributes
+ if( !attributes || !attributes.dataset ){
+ throw( "ScatterplotView requires a dataset" );
+ } else {
+ this.dataset = attributes.dataset;
+ }
+ if( jQuery.type( this.dataset.metadata_column_types ) === 'string' ){
+ this.dataset.metadata_column_types = this.dataset.metadata_column_types.split( ', ' );
+ }
+ this.log( '\t dataset:', this.dataset );
+
+ // attempt to get possible headers from the data's first line
+ if( this.dataset.comment_lines && this.dataset.comment_lines.length ){
+ //TODO:??
+ var firstLine = this.dataset.comment_lines[0],
+ possibleHeaders = firstLine.split( '\t' );
+ if( possibleHeaders.length === this.dataset.metadata_column_types.length ){
+ this.possibleHeaders = possibleHeaders;
+ }
+ }
+
+ // passed from mako helper
+ //TODO: integrate to galaxyPaths
+ //TODO: ?? seems like data loader section would be better
+ if( !attributes.apiDatasetsURL ){
+ throw( "ScatterplotView requires a apiDatasetsURL" );
+ } else {
+ this.dataURL = attributes.apiDatasetsURL + '/' + this.dataset.id + '?';
+ }
+ this.log( '\t dataURL:', this.dataURL );
+ },
+
+ initializeChart : function( attributes ){
+ // set up the basic chart infrastructure and config (if any)
+ this.chartConfig = attributes.chartConfig || {};
+ //if( this.logger ){ this.chartConfig.debugging = true; }
+ this.log( '\t initial chartConfig:', this.chartConfig );
+
+ this.chart = new TwoVarScatterplot( this.chartConfig );
+ //TODO: remove 2nd ref, use this.chart.config
+ this.chartConfig = this.chart.config;
+ },
+
+ initializeDataLoader : function( attributes ){
+ // set up data loader
+ var view = this;
+ this.loader = new LazyDataLoader({
+ //logger : ( this.logger )?( this.logger ):( null ),
+ // we'll generate this when columns are chosen
+ url : null,
+ start : attributes.start || 0,
+ //NOTE: metadata_data_lines can be null (so we won't know the total)
+ total : attributes.total || this.dataset.metadata_data_lines,
+ delay : this.dataLoadDelay,
+ size : this.dataLoadSize,
+
+ buildUrl : function( start, size ){
+ // currently VERY SPECIFIC to using data_providers.py start_val, max_vals params
+ return this.url + '&' + jQuery.param({
+ start_val: start,
+ max_vals: size
+ });
+ }
+ });
+ $( this.loader ).bind( 'error', function( event, status, error ){
+ view.log( 'ERROR:', status, error );
+ alert( 'ERROR fetching data:\n' + status + '\n' + error );
+ view.hideLoadingIndicator();
+ });
+ },
+
+ // ------------------------------------------------------------------------- CONTROLS RENDERING
+ render : function(){
+ this.log( this + '.render' );
+
+ // render the tab controls, areas and loading indicator
+ this.$el.append( ScatterplotControlForm.templates.mainLayout({
+ loadingIndicatorImagePath : '/static/images/' + this.loadingIndicatorImage,
+ message : ''
+ }));
+
+ // render the tab content
+ this.$dataControl = this._render_dataControl();
+ this.$chartControl = this._render_chartControl();
+ this.$statsDisplay = this.$el.find( '.tab-pane#stats-display' );
+ this.$chartDisplay = this._render_chartDisplay();
+
+ // auto render if given both x, y column choices in query for page
+ //TODO:?? add autoRender=1 to query maybe?
+ if( this.chartConfig.xColumn && this.chartConfig.yColumn ){
+ this.renderChart();
+ }
+
+ // set up behaviours
+ this.$el.find( '.tooltip' ).tooltip();
+
+ // uncomment any of the following to have that tab show on initial load (for testing)
+ //this.$el.find( 'ul.nav' ).find( 'a[href="#data-control"]' ).tab( 'show' );
+ //this.$el.find( 'ul.nav' ).find( 'a[href="#chart-control"]' ).tab( 'show' );
+ //this.$el.find( 'ul.nav' ).find( 'a[href="#stats-display"]' ).tab( 'show' );
+ //this.$el.find( 'ul.nav' ).find( 'a[href="#chart-display"]' ).tab( 'show' );
+ return this;
+ },
+
+ _render_dataControl : function(){
+ // controls for which columns are used to plot datapoints (and ids/additional info to attach if desired)
+ var view = this,
+ allColumns = [],
+ numericColumns = [],
+ usePossibleHeaders = ( this.possibleHeaders && this.$dataControl )?
+ ( this.$dataControl.find( '#first-line-header-checkbox' ).is( ':checked' ) ):( false );
+
+ // gather column indeces (from metadata_column_types) and names (from metadata_columnnames)
+ _.each( this.dataset.metadata_column_types, function( type, index ){
+ // use a 1 based index in names/values within the form (will be dec. when parsed out)
+ var oneBasedIndex = index + 1,
+ // default name is 'column <index>'...
+ name = 'column ' + oneBasedIndex;
+
+ // ...but label with the name if available...
+ if( view.dataset.metadata_column_names ){
+ name = view.dataset.metadata_column_names[ index ];
+
+ // ...or, use the first line as headers if the user wants
+ } else if( usePossibleHeaders ){
+ name = view.possibleHeaders[ index ];
+ }
+
+ // cache all columns here
+ allColumns.push({ index: oneBasedIndex, name: name });
+
+ // filter numeric columns to their own list
+ if( type === 'int' || type === 'float' ){
+ numericColumns.push({ index: oneBasedIndex, name: name });
+ }
+ });
+ //TODO: other vals: max_vals, start_val, pagination (chart-settings)
+
+ // render the html
+ var $dataControl = this.$el.find( '.tab-pane#data-control' );
+ $dataControl.html( ScatterplotControlForm.templates.dataControl({
+ allColumns : allColumns,
+ numericColumns : numericColumns,
+ possibleHeaders : ( this.possibleHeaders )?( this.possibleHeaders.join( ', ' ) ):( '' ),
+ usePossibleHeaders : usePossibleHeaders
+ }));
+
+ if( !this.dataset.metadata_column_names && this.possibleHeaders ){
+ $dataControl.find( '#first-line-header' ).show();
+ }
+
+ // preset to column selectors if they were passed in the config in the query string
+ $dataControl.find( '#X-select' ).val( this.chartConfig.xColumn );
+ $dataControl.find( '#Y-select' ).val( this.chartConfig.yColumn );
+ if( this.chartConfig.idColumn !== undefined ){
+ $dataControl.find( '#include-id-checkbox' )
+ .attr( 'checked', true ).trigger( 'change' );
+ $dataControl.find( '#ID-select' ).val( this.chartConfig.idColumn );
+ }
+
+ return $dataControl;
+ },
+
+ _render_chartControl : function(){
+ // tab content to control how the chart is rendered (data glyph size, chart size, etc.)
+ var view = this,
+ $chartControl = this.$el.find( '.tab-pane#chart-control' ),
+ // limits for controls (by control/chartConfig id)
+ //TODO: move into TwoVarScatterplot
+ controlRanges = {
+ 'datapointSize' : { min: 2, max: 10, step: 1 },
+ 'width' : { min: 200, max: 800, step: 20 },
+ 'height' : { min: 200, max: 800, step: 20 }
+ };
+
+ // render the html
+ $chartControl.append( ScatterplotControlForm.templates.chartControl( this.chartConfig ) );
+
+ // set up behaviours, js on sliders
+ $chartControl.find( '.numeric-slider-input' ).each( function(){
+ var $this = $( this ),
+ $output = $this.find( '.slider-output' ),
+ $slider = $this.find( '.slider' ),
+ id = $this.attr( 'id' );
+ //chartControl.log( 'slider set up', 'this:', $this, 'slider:', $slider, 'id', id );
+
+ // what to do when the slider changes: update display and update chartConfig
+ //TODO: move out of loop
+ function onSliderChange(){
+ var $this = $( this ),
+ newValue = $this.slider( 'value' );
+ //chartControl.log( 'slider change', 'this:', $this, 'output:', $output, 'value', newValue );
+ $output.text( newValue );
+ //chartControl.chartConfig[ id ] = newValue;
+ }
+
+ $slider.slider( _.extend( controlRanges[ id ], {
+ value : view.chartConfig[ id ],
+ change : onSliderChange,
+ slide : onSliderChange
+ }));
+ });
+
+ return $chartControl;
+ },
+
+ _render_chartDisplay : function(){
+ // render the tab content where the chart is displayed (but not the chart itself)
+ var $chartDisplay = this.$el.find( '.tab-pane#chart-display' );
+ $chartDisplay.append( ScatterplotControlForm.templates.chartDisplay( this.chartConfig ) );
+ return $chartDisplay;
+ },
+
+ // ------------------------------------------------------------------------- EVENTS
+ events : {
+ 'change #include-id-checkbox' : 'toggleThirdColumnSelector',
+ 'change #first-line-header-checkbox' : 'rerenderDataControl',
+ 'click #data-control #render-button' : 'renderChart',
+ 'click #chart-control #render-button' : 'changeChartSettings'
+ },
+
+ toggleThirdColumnSelector : function(){
+ // show/hide the id selector on the data settings panel
+ this.$el.find( 'select[name="ID"]' ).parent().toggle();
+ },
+
+ rerenderDataControl : function(){
+ this.$dataControl = this._render_dataControl();
+ },
+
+ showLoadingIndicator : function( message, callback ){
+ // display the loading indicator over the tab panels if hidden, update message (if passed)
+ message = message || '';
+ var indicator = this.$el.find( 'div#loading-indicator' );
+ messageBox = indicator.find( '.loading-message' );
+
+ if( indicator.is( ':visible' ) ){
+ if( message ){
+ messageBox.fadeOut( 'fast', function(){
+ messageBox.text( message );
+ messageBox.fadeIn( 'fast', callback );
+ });
+ } else {
+ callback();
+ }
+
+ } else {
+ if( message ){ messageBox.text( message ); }
+ indicator.fadeIn( 'fast', callback );
+ }
+ },
+
+ hideLoadingIndicator : function( callback ){
+ this.$el.find( 'div#loading-indicator' ).fadeOut( 'fast', callback );
+ },
+
+ // ------------------------------------------------------------------------- CHART/STATS RENDERING
+ renderChart : function(){
+ // fetch the data, (re-)render the chart
+ this.log( this + '.renderChart' );
+
+ //TODO: separate data fetch
+
+ // this is a complete re-render, so clear the prev. data
+ this.data = null;
+ this.meta = null;
+
+ // update the chartConfig (here and chart) using chart settings
+ //TODO: separate and improve (used in changeChartSettings too)
+ _.extend( this.chartConfig, this.getChartSettings() );
+ this.log( '\t chartConfig:', this.chartConfig );
+ this.chart.updateConfig( this.chartConfig, false );
+
+ // build the url with the current data settings
+ this.loader.url = this.dataURL + '&' + jQuery.param( this.getDataSettings() );
+ this.log( '\t loader: total lines:', this.loader.total, ' url:', this.loader.url );
+
+ // bind the new data event to: aggregate data, update the chart and stats with new data
+ var view = this;
+ $( this.loader ).bind( 'loaded.new', function( event, response ){
+ view.log( view + ' loaded.new', response );
+
+ // aggregate data and meta
+ view.postProcessDataFetchResponse( response );
+ view.log( '\t postprocessed data:', view.data );
+ view.log( '\t postprocessed meta:', view.meta );
+
+ // update the chart and stats
+ view.showLoadingIndicator( view.renderMsg, function(){
+ view.chart.render( view.data, view.meta );
+ view.renderStats( view.data, view.meta );
+ view.hideLoadingIndicator();
+ });
+ });
+ // when all data loaded - unbind (or we'll start doubling event handlers)
+ $( this.loader ).bind( 'complete', function( event, data ){
+ view.log( view + ' complete', data );
+ $( view.loader ).unbind();
+ });
+
+ // begin loading the data, switch to the chart display tab
+ view.showLoadingIndicator( view.fetchMsg, function(){
+ view.$el.find( 'ul.nav' ).find( 'a[href="#chart-display"]' ).tab( 'show' );
+ view.loader.load();
+ });
+ },
+
+ renderStats : function(){
+ this.log( this + '.renderStats' );
+ // render the stats table in the stats panel
+ //TODO: there's a better way
+ this.$statsDisplay.html( ScatterplotControlForm.templates.statsDisplay({
+ 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(){
+ // re-render the chart with new chart settings and OLD data
+ var view = this;
+ newChartSettings = this.getChartSettings();
+
+ // update the chart config from the chartSettings panel controls
+ _.extend( this.chartConfig, newChartSettings );
+ this.log( 'this.chartConfig:', this.chartConfig );
+ this.chart.updateConfig( this.chartConfig, false );
+
+ // if there's current data, call chart.render with it (no data fetch)
+ if( view.data && view.meta ){
+ view.showLoadingIndicator( view.renderMsg, function(){
+ view.$el.find( 'ul.nav' ).find( 'a[href="#chart-display"]' ).tab( 'show' );
+ view.chart.render( view.data, view.meta );
+ view.hideLoadingIndicator();
+ });
+
+ // no current data, call renderChart instead (which will fetch data)
+ } else {
+ this.renderChart();
+ }
+ },
+
+ // ------------------------------------------------------------------------- DATA AGGREGATION
+ postProcessDataFetchResponse : function( response ){
+ // the loader only returns new data - it's up to this to munge the fetches together properly
+ //TODO: we're now storing data in two places: loader and here
+ // can't we reduce incoming data into loader.data[0]? are there concurrency problems?
+ this.postProcessData( response.data );
+ this.postProcessMeta( response.meta );
+ },
+
+ postProcessData : function( newData ){
+ // stack the column data on top of each other into this.data
+ //this.log( this + '.postProcessData:', newData );
+ var view = this;
+
+ // if we already have data: aggregate
+ if( view.data ){
+ _.each( newData, function( newColData, colIndex ){
+ //view.log( colIndex + ' data:', newColData );
+ //TODO??: time, space efficiency of this?
+ view.data[ colIndex ] = view.data[ colIndex ].concat( newColData );
+ });
+
+ // otherwise: assign (first load)
+ } else {
+ view.data = newData;
+ }
+ },
+
+ postProcessMeta : function( newMeta ){
+ // munge the meta data (stats) from the server fetches together
+ //pre: this.data must be preprocessed (needed for medians)
+ //this.log( this + '.postProcessMeta:', newMeta );
+ var view = this,
+ colTypes = this.dataset.metadata_column_types;
+
+ // if we already have meta: aggregate
+ if( view.meta ){
+ _.each( newMeta, function( newColMeta, colIndex ){
+ var colMeta = view.meta[ colIndex ],
+ colType = colTypes[ colIndex ];
+ //view.log( '\t ' + colIndex + ' postprocessing meta:', newColMeta );
+ //view.log( colIndex + ' old meta:',
+ // 'min:', colMeta.min,
+ // 'max:', colMeta.max,
+ // 'sum:', colMeta.sum,
+ // 'mean:', colMeta.mean,
+ // 'median:', colMeta.median
+ //);
+
+ //!TODO: at what point are we getting int/float overflow on these?!
+ //??: need to be null safe?
+ colMeta.count += ( newColMeta.count )?( newColMeta.count ):( 0 );
+ //view.log( colIndex, 'count:', colMeta.count );
+
+ if( ( colType === 'int' ) || ( colType === 'float' ) ){
+ //view.log( colIndex + ' incoming meta:',
+ // 'min:', newColMeta.min,
+ // 'max:', newColMeta.max,
+ // 'sum:', newColMeta.sum,
+ // 'mean:', newColMeta.mean,
+ // 'median:', newColMeta.median
+ //);
+
+ colMeta.min = Math.min( newColMeta.min, colMeta.min );
+ colMeta.max = Math.max( newColMeta.max, colMeta.max );
+ colMeta.sum = newColMeta.sum + colMeta.sum;
+ colMeta.mean = ( colMeta.count )?( colMeta.sum / colMeta.count ):( null );
+
+ // median's a pain bc of sorting (requires the data as well)
+ var sortedCol = view.data[ colIndex ].slice().sort(),
+ middleIndex = Math.floor( sortedCol.length / 2 );
+
+ if( sortedCol.length % 2 === 0 ){
+ colMeta.median = ( ( sortedCol[ middleIndex ] + sortedCol[( middleIndex + 1 )] ) / 2 );
+
+ } else {
+ colMeta.median = sortedCol[ middleIndex ];
+ }
+
+ //view.log( colIndex + ' new meta:',
+ // 'min:', colMeta.min,
+ // 'max:', colMeta.max,
+ // 'sum:', colMeta.sum,
+ // 'mean:', colMeta.mean,
+ // 'median:', colMeta.median
+ //);
+ }
+ });
+
+ // otherwise: assign (first load)
+ } else {
+ view.meta = newMeta;
+ //view.log( '\t meta (first load):', view.meta );
+ }
+ },
+
+ // ------------------------------------------------------------------------- GET DATA/CHART SETTINGS
+ getDataSettings : function(){
+ // parse the column values for both indeces (for the data fetch) and names (for the chart)
+ var columnSelections = this.getColumnSelections(),
+ columns = [];
+ this.log( '\t columnSelections:', columnSelections );
+
+ //TODO: validate columns - minimally: we can assume either set by selectors or via a good query string
+
+ // get column indices for params, include the desired ID column (if any)
+ //NOTE: these are presented in human-readable 1 base index (to match the data.peek) - adjust
+ columns = [
+ columnSelections.X.colIndex - 1,
+ columnSelections.Y.colIndex - 1
+ ];
+ if( this.$dataControl.find( '#include-id-checkbox' ).attr( 'checked' ) ){
+ columns.push( columnSelections.ID.colIndex - 1 );
+ }
+ //TODO: other vals: max, start, page
+
+ var params = {
+ data_type : 'raw_data',
+ provider : 'column_with_stats',
+ columns : '[' + columns + ']'
+ };
+ this.log( '\t data settings (url params):', params );
+ return params;
+ },
+
+ getColumnSelections : function(){
+ // gets the current user-selected values for which columns to fetch from the data settings panel
+ // returns a map: { column-select name (eg. X) : { colIndex : column-selector val,
+ // colName : selected option text }, ... }
+ var selections = {};
+ this.$dataControl.find( 'div.column-select select' ).each( function(){
+ var $this = $( this ),
+ val = $this.val();
+ selections[ $this.attr( 'name' ) ] = {
+ colIndex : val,
+ colName : $this.children( '[value="' + val + '"]' ).text()
+ };
+ });
+ return selections;
+ },
+
+ getChartSettings : function(){
+ // gets the user-selected chartConfig from the chart settings panel
+ var settings = {},
+ colSelections = this.getColumnSelections();
+ //this.log( 'colSelections:', colSelections );
+
+ //TODO: simplify with keys and loop
+ settings.datapointSize = this.$chartControl.find( '#datapointSize.numeric-slider-input' )
+ .find( '.slider' ).slider( 'value' );
+ settings.width = this.$chartControl.find( '#width.numeric-slider-input' )
+ .find( '.slider' ).slider( 'value' );
+ settings.height = this.$chartControl.find( '#height.numeric-slider-input' )
+ .find( '.slider' ).slider( 'value' );
+
+ // update axes labels using chartSettings inputs (if not at defaults), otherwise the selects' colName
+ //TODO: a little confusing
+ var chartSettingsXLabel = this.$chartControl.find( 'input#X-axis-label' ).val(),
+ chartSettingsYLabel = this.$chartControl.find( 'input#Y-axis-label' ).val();
+ settings.xLabel = ( chartSettingsXLabel === 'X' )?
+ ( colSelections.X.colName ):( chartSettingsXLabel );
+ settings.yLabel = ( chartSettingsYLabel === 'Y' )?
+ ( colSelections.Y.colName ):( chartSettingsYLabel );
+
+ settings.animDuration = ( this.$chartControl.find( '#animate-chart' ).is( ':checked' ) )?
+ ( this.chart.defaults.animDuration ):( 0 );
+
+ this.log( '\t chartSettings:', settings );
+ return settings;
+ },
+
+ toString : function(){
+ return 'ScatterplotControlForm(' + (( this.dataset )?( this.dataset.id ):( '' )) + ')';
+ }
+});
+
+ScatterplotControlForm.templates = {
+ mainLayout : Templates.scatterplotControlForm,
+ dataControl : Templates.dataControl,
+ chartControl : Templates.chartControl,
+ statsDisplay : Templates.statsDisplay,
+ chartDisplay : Templates.chartDisplay
+};
+
+//==============================================================================
diff -r c623f3d38221c588de3976c05b688387933cbf29 -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 config/plugins/visualizations/scatterplot/src/visualization-templates.html
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/src/visualization-templates.html
@@ -0,0 +1,182 @@
+<script type="text/template" class="template-visualization" id="template-visualization-scatterplotControlForm">
+{{! main layout }}
+
+<div class="scatterplot-container chart-container tabbable tabs-left">
+ {{! tab buttons/headers using Bootstrap }}
+ <ul class="nav nav-tabs">
+ {{! start with the data controls as the displayed tab }}
+ <li class="active"><a href="#data-control" data-toggle="tab" class="tooltip"
+ title="Use this tab to change which data are used">Data Controls</a></li>
+ <li><a href="#chart-control" data-toggle="tab" class="tooltip"
+ title="Use this tab to change how the chart is drawn">Chart Controls</a></li>
+ <li><a href="#stats-display" data-toggle="tab" class="tooltip"
+ title="This tab will display overall statistics for your data">Statistics</a></li>
+ <li><a href="#chart-display" data-toggle="tab" class="tooltip"
+ title="This tab will display the chart">Chart</a>
+ {{! loading indicator - initially hidden }}
+ <div id="loading-indicator" style="display: none;">
+ <img class="loading-img" src="{{loadingIndicatorImagePath}}" />
+ <span class="loading-message">{{message}}</span>
+ </div>
+ </li>
+ </ul>
+
+ {{! data form, chart config form, stats, and chart all get their own tab }}
+ <div class="tab-content">
+ {{! ---------------------------- tab for data settings form }}
+ <div id="data-control" class="tab-pane active">
+ {{! rendered separately }}
+ </div>
+
+ {{! ---------------------------- tab for chart graphics control form }}
+ <div id="chart-control" class="tab-pane">
+ {{! rendered separately }}
+ </div>
+
+ {{! ---------------------------- tab for data statistics }}
+ <div id="stats-display" class="tab-pane">
+ {{! rendered separately }}
+ </div>
+
+ {{! ---------------------------- tab for actual chart }}
+ <div id="chart-display" class="tab-pane">
+ {{! chart rendered separately }}
+ </div>
+
+ </div>{{! end .tab-content }}
+</div>{{! end .chart-control }}
+</script>
+
+<script type="text/template" class="template-visualization" id="template-visualization-dataControl">
+
+ <p class="help-text">
+ Use the following controls to change the data used by the chart.
+ Use the 'Draw' button to render (or re-render) the chart with the current settings.
+ </p>
+
+ {{! column selector containers }}
+ <div class="column-select">
+ <label for="X-select">Data column for X: </label>
+ <select name="X" id="X-select">
+ {{#each numericColumns}}
+ <option value="{{index}}">{{name}}</option>
+ {{/each}}
+ </select>
+ </div>
+ <div class="column-select">
+ <label for="Y-select">Data column for Y: </label>
+ <select name="Y" id="Y-select">
+ {{#each numericColumns}}
+ <option value="{{index}}">{{name}}</option>
+ {{/each}}
+ </select>
+ </div>
+
+ {{! optional id column }}
+ <div id="include-id">
+ <label for="include-id-checkbox">Include a third column as data point IDs?</label>
+ <input type="checkbox" name="include-id" id="include-id-checkbox" />
+ <p class="help-text-small">
+ These will be displayed (along with the x and y values) when you hover over
+ a data point.
+ </p>
+ </div>
+ <div class="column-select" style="display: none">
+ <label for="ID-select">Data column for IDs: </label>
+ <select name="ID" id="ID-select">
+ {{#each allColumns}}
+ <option value="{{index}}">{{name}}</option>
+ {{/each}}
+ </select>
+ </div>
+
+ {{! if we're using generic column selection names ('column 1') - allow the user to use the first line }}
+ <div id="first-line-header" style="display: none;">
+ <p>Possible headers: {{ possibleHeaders }}
+ </p>
+ <label for="first-line-header-checkbox">Use the above as column headers?</label>
+ <input type="checkbox" name="include-id" id="first-line-header-checkbox"
+ {{#if usePossibleHeaders }}checked="true"{{/if}}/>
+ <p class="help-text-small">
+ It looks like Galaxy couldn't get proper column headers for this data.
+ Would you like to use the column headers above as column names to select columns?
+ </p>
+ </div>
+
+ <input id="render-button" type="button" value="Draw" />
+ <div class="clear"></div>
+</script>
+
+<script type="text/template" class="template-visualization" id="template-visualization-chartControl">
+ <p class="help-text">
+ Use the following controls to how the chart is displayed.
+ The slide controls can be moved by the mouse or, if the 'handle' is in focus, your keyboard's arrow keys.
+ Move the focus between controls by using the tab or shift+tab keys on your keyboard.
+ Use the 'Draw' button to render (or re-render) the chart with the current settings.
+ </p>
+
+ <div id="datapointSize" class="form-input numeric-slider-input">
+ <label for="datapointSize">Size of data point: </label>
+ <div class="slider-output">{{datapointSize}}</div>
+ <div class="slider"></div>
+ <p class="form-help help-text-small">
+ Size of the graphic representation of each data point
+ </p>
+ </div>
+
+ <div id="animDuration" class="form-input checkbox-input">
+ <label for="animate-chart">Animate chart transitions?: </label>
+ <input type="checkbox" id="animate-chart"
+ class="checkbox control"{{#if animDuration}} checked="true"{{/if}} />
+ <p class="form-help help-text-small">
+ Uncheck this to disable the animations used on the chart
+ </p>
+ </div>
+
+ <div id="width" class="form-input numeric-slider-input">
+ <label for="width">Chart width: </label>
+ <div class="slider-output">{{width}}</div>
+ <div class="slider"></div>
+ <p class="form-help help-text-small">
+ (not including chart margins and axes)
+ </p>
+ </div>
+
+ <div id="height" class="form-input numeric-slider-input">
+ <label for="height">Chart height: </label>
+ <div class="slider-output">{{height}}</div>
+ <div class="slider"></div>
+ <p class="form-help help-text-small">
+ (not including chart margins and axes)
+ </p>
+ </div>
+
+ <div id="X-axis-label"class="text-input form-input">
+ <label for="X-axis-label">Re-label the X axis: </label>
+ <input type="text" name="X-axis-label" id="X-axis-label" value="{{xLabel}}" />
+ <p class="form-help help-text-small"></p>
+ </div>
+
+ <div id="Y-axis-label" class="text-input form-input">
+ <label for="Y-axis-label">Re-label the Y axis: </label>
+ <input type="text" name="Y-axis-label" id="Y-axis-label" value="{{yLabel}}" />
+ <p class="form-help help-text-small"></p>
+ </div>
+
+ <input id="render-button" type="button" value="Draw" />
+</script>
+
+<script type="text/template" class="template-visualization" id="template-visualization-statsDisplay">
+ <p class="help-text">By column:</p>
+ <table id="chart-stats-table">
+ <thead><th></th><th>X</th><th>Y</th></thead>
+ {{#each stats}}
+ <tr><td>{{name}}</td><td>{{xval}}</td><td>{{yval}}</td></tr>
+ </tr>
+ {{/each}}
+ </table>
+</script>
+
+<script type="text/template" class="template-visualization" id="template-visualization-chartDisplay">
+ <svg width="{{width}}" height="{{height}}"></svg>
+</script>
diff -r c623f3d38221c588de3976c05b688387933cbf29 -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 config/plugins/visualizations/scatterplot/static/scatterplot.css
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/static/scatterplot.css
@@ -0,0 +1,181 @@
+/*TODO: use/move into base.less*/
+* { margin: 0px; padding: 0px; }
+
+/* -------------------------------------------- general layout */
+div.tab-pane {
+ padding: 8px;
+}
+
+/* -------------------------------------------- header */
+.header {
+ margin-bottom: 8px;
+}
+
+#chart-header {
+ padding : 8px;
+ background-color: #ebd9b2;
+ margin-bottom: 16px;
+ overflow: auto;
+}
+
+#chart-header .subtitle {
+ margin: -4px 0px 0px 4px;
+ padding : 0;
+ color: white;
+ font-size: small;
+}
+
+/* -------------------------------------------- main layout */
+#scatterplot {
+ /*from width + margin of chart?*/
+}
+
+.scatterplot-container .tab-pane {
+}
+
+/* -------------------------------------------- all controls */
+
+#scatterplot input[type=button],
+#scatterplot select {
+ width: 100%;
+ max-width: 256px;
+ margin-bottom: 8px;
+}
+
+#scatterplot .help-text,
+#scatterplot .help-text-small {
+ color: grey;
+}
+
+#scatterplot .help-text {
+ padding-bottom: 16px;
+}
+
+#scatterplot .help-text-small {
+ padding: 4px;
+ font-size: smaller;
+}
+
+#scatterplot > * {
+}
+
+#scatterplot input[value=Draw] {
+ display: block;
+ margin-top: 16px;
+}
+
+#scatterplot .numeric-slider-input {
+ max-width: 70%;
+}
+
+/* -------------------------------------------- data controls */
+
+/* -------------------------------------------- chart controls */
+#chart-control .form-input {
+ /*display: table-row;*/
+}
+
+#chart-control label {
+ /*text-align: right;*/
+ margin-bottom: 8px;
+ /*display: table-cell;*/
+}
+
+#chart-control .slider {
+ /*display: table-cell;*/
+ height: 8px;
+ display: block;
+ margin: 8px 0px 0px 8px;
+}
+
+#chart-control .slider-output {
+ /*display: table-cell;*/
+ float: right;
+}
+
+#chart-control input[type="text"] {
+ border: 1px solid lightgrey;
+}
+
+
+/* -------------------------------------------- statistics */
+#stats-display table#chart-stats-table {
+ width: 100%;
+}
+
+#stats-display #chart-stats-table th {
+ width: 30%;
+ padding: 4px;
+ font-weight: bold;
+ color: grey;
+}
+
+#stats-display #chart-stats-table td {
+ border: solid lightgrey;
+ border-width: 1px 0px 0px 1px;
+ padding: 4px;
+}
+
+#stats-display #chart-stats-table td:nth-child(1) {
+ border-width: 1px 0px 0px 0px;
+ padding-right: 1em;
+ text-align: right;
+ font-weight: bold;
+ color: grey;
+}
+
+/* -------------------------------------------- load indicators */
+#loading-indicator {
+ margin: 12px 0px 0px 8px;
+}
+
+#scatterplot #loading-indicator .loading-message {
+ font-style: italic;
+ font-size: smaller;
+ color: grey;
+}
+
+/* -------------------------------------------- chart area */
+#chart-holder {
+ overflow: auto;
+ margin-left: 8px;
+}
+
+svg .grid-line {
+ fill: none;
+ stroke: lightgrey;
+ stroke-opacity: 0.5;
+ shape-rendering: crispEdges;
+ stroke-dasharray: 3, 3;
+}
+
+svg .axis path, svg .axis line {
+ fill: none;
+ stroke: black;
+ shape-rendering: crispEdges;
+}
+
+svg .axis text {
+ font-family: monospace;
+ font-size: 12px;
+}
+
+svg #x-axis-label, svg #y-axis-label {
+ font-family: sans-serif;
+ font-size: 10px;
+}
+
+svg .glyph {
+ stroke: none;
+ fill: black;
+ fill-opacity: 0.2;
+}
+
+/* -------------------------------------------- info box */
+.chart-info-box {
+ border-radius: 4px;
+ padding: 4px;
+ background-color: white;
+ border: 1px solid black;
+}
+
diff -r c623f3d38221c588de3976c05b688387933cbf29 -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 config/plugins/visualizations/scatterplot/static/scatterplot.js
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/static/scatterplot.js
@@ -0,0 +1,1 @@
+function TwoVarScatterplot(a){var b=10,c=7,d=10,e=8,f=5;this.log=function(){if(this.debugging&&console&&console.debug){var a=Array.prototype.slice.call(arguments);a.unshift(this.toString()),console.debug.apply(console,a)}},this.log("new TwoVarScatterplot:",a),this.defaults={id:"TwoVarScatterplot",containerSelector:"body",maxDataPoints:3e4,datapointSize:4,animDuration:500,xNumTicks:10,yNumTicks:10,xAxisLabelBumpY:40,yAxisLabelBumpX:-40,width:400,height:400,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,a),this.log("intial config:",this.config),this.updateConfig=function(a){_.extend(this.config,a),this.log(this+".updateConfig:",this.config)},this.toString=function(){return this.config.id},this.translateStr=function(a,b){return"translate("+a+","+b+")"},this.rotateStr=function(a,b,c){return"rotate("+a+","+b+","+c+")"},this.adjustChartDimensions=function(a,b,c,d){a=a||0,b=b||0,c=c||0,d=d||0,this.svg.attr("width",this.config.width+(this.config.marginRight+b)+(this.config.marginLeft+d)).attr("height",this.config.height+(this.config.marginTop+a)+(this.config.marginBottom+c)).style("display","block"),this.content=this.svg.select("g.content").attr("transform",this.translateStr(this.config.marginLeft+d,this.config.marginTop+a))},this.preprocessData=function(a){return a.length>this.config.maxDataPoints?a.slice(0,this.config.maxDataPoints):a},this.findMinMaxes=function(a,b,c){this.xMin=this.config.xMin||c?c[0].min:d3.min(a),this.xMax=this.config.xMax||c?c[0].max:d3.max(a),this.yMin=this.config.yMin||c?c[1].min:d3.min(b),this.yMax=this.config.yMax||c?c[1].max:d3.max(b)},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);var a=d3.max(_.map([this.xMin,this.xMax],function(a){return String(a).length}));a>=f&&this.xAxis.selectAll("g").filter(":nth-child(odd)").style("display","none"),this.log("this.config.xLabel:",this.config.xLabel),this.xAxisLabel.attr("x",this.config.width/2).attr("y",this.config.xAxisLabelBumpY).attr("text-anchor","middle").text(this.config.xLabel),this.log("xAxisLabel:",this.xAxisLabel)},this.setUpYAxis=function(){this.yAxisFn=d3.svg.axis().scale(this.yScale).ticks(this.config.yNumTicks).orient("left"),this.yAxis.call(this.yAxisFn);var a=this.yAxis.selectAll("text").filter(function(a,b){return 0!==b});this.log("yTickLabels:",a),this.yLongestLabel=d3.max(a[0].map(function(a){return d3.select(a).text().length}))||0;var f=b+this.yLongestLabel*c+e+d;if(this.config.yAxisLabelBumpX=-(f-d),this.config.marginLeft<f){var g=f-this.config.marginLeft;g=0>g?0:g,this.adjustChartDimensions(0,0,0,g)}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",!0),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",!0),this.hGridLines.attr("x1",0).attr("y1",this.yScale).attr("x2",this.config.width).attr("y2",this.yScale),this.hGridLines.exit().remove()},this.renderDatapoints=function(a,b,c){this.log(this+".renderDatapoints",arguments);var d=0,e=this,f=function(b,c){return e.xScale(a[c])},g=function(a,c){return e.yScale(b[c])},h=this.content.selectAll(".glyph").data(a);d=0,h.enter().append("svg:circle").each(function(){d+=1}).classed("glyph",!0).attr("cx",0).attr("cy",this.config.height).attr("r",0),this.log(d," new glyphs created"),d=0,h.transition().duration(this.config.animDuration).each(function(){d+=1}).attr("cx",f).attr("cy",g).attr("r",e.config.datapointSize),this.log(d," existing glyphs transitioned"),h.exit().each(function(){d+=1}).transition().duration(this.config.animDuration).attr("cy",this.config.height).attr("r",0).remove(),this.log(d," glyphs removed"),this._addDatapointEventhandlers(h,a,b,c)},this._addDatapointEventhandlers=function(a,b,c,d){var e=this;a.on("mouseover",function(a,f){var g=d3.select(this);g.style("fill","red").style("fill-opacity",1),e.content.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",g.attr("cx")-e.config.datapointSize).attr("y1",g.attr("cy")).attr("x2",0).attr("y2",g.attr("cy")).classed("hoverline",!0),g.attr("cy")<e.config.height&&e.content.append("line").attr("stroke","red").attr("stroke-width",1).attr("x1",g.attr("cx")).attr("y1",g.attr("cy")+e.config.datapointSize).attr("x2",g.attr("cx")).attr("y2",e.config.height).classed("hoverline",!0);var h=$(this).offset();e.datapointInfoBox=e.infoBox(h.top,h.left,e.infoHtml(b[f],c[f],d?d[f]:void 0)),$("body").append(e.datapointInfoBox)}).on("mouseout",function(){d3.select(this).style("fill","black").style("fill-opacity",.2),e.content.selectAll(".hoverline").remove(),e.datapointInfoBox&&e.datapointInfoBox.remove()})},this.render=function(a,b){this.log(this+".render",arguments),this.log(" config:",this.config);var c=a[0],d=a[1],e=a.length>2?a[2]:void 0;c=this.preprocessData(c),d=this.preprocessData(d),this.log("xCol len",c.length,"yCol len",d.length),this.findMinMaxes(c,d,b),this.setUpScales(),this.svg||(this.svg=d3.select("svg").attr("class","chart")),this.content||(this.content=this.svg.append("svg:g").attr("class","content").attr("id",this.config.id)),this.adjustChartDimensions(),this.xAxis||(this.xAxis=this.content.append("g").attr("class","axis").attr("id","x-axis")),this.xAxisLabel||(this.xAxisLabel=this.xAxis.append("text").attr("class","axis-label").attr("id","x-axis-label")),this.yAxis||(this.yAxis=this.content.append("g").attr("class","axis").attr("id","y-axis")),this.yAxisLabel||(this.yAxisLabel=this.yAxis.append("text").attr("class","axis-label").attr("id","y-axis-label")),this.setUpXAxis(),this.setUpYAxis(),this.renderGrid(),this.renderDatapoints(c,d,e)},this.infoHtml=function(a,b,c){var d=$("<div/>");return c&&$("<div/>").text(c).css("font-weight","bold").appendTo(d),$("<div/>").text(a).appendTo(d),$("<div/>").text(b).appendTo(d),d.html()},this.infoBox=function(a,b,c,d,e){d=d||0,e=e||20;var f=$("<div />").addClass("chart-info-box").css({position:"absolute",top:a+d,left:b+e});return f.html(c),f}}this.Templates=this.Templates||{},this.Templates.chartControl=Handlebars.template(function(a,b,c,d,e){function f(){return' checked="true"'}this.compilerInfo=[4,">= 1.0.0"],c=this.merge(c,a.helpers),e=e||{};var g,h="",i="function",j=this.escapeExpression,k=this;return h+='<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">',(g=c.datapointSize)?g=g.call(b,{hash:{},data:e}):(g=b.datapointSize,g=typeof g===i?g.apply(b):g),h+=j(g)+'</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="animate-chart">Animate chart transitions?: </label>\n <input type="checkbox" id="animate-chart"\n class="checkbox control"',g=c["if"].call(b,b.animDuration,{hash:{},inverse:k.noop,fn:k.program(1,f,e),data:e}),(g||0===g)&&(h+=g),h+=' />\n <p class="form-help help-text-small">\n Uncheck this to disable the animations used on the chart\n </p>\n </div>\n\n <div id="width" class="form-input numeric-slider-input">\n <label for="width">Chart width: </label>\n <div class="slider-output">',(g=c.width)?g=g.call(b,{hash:{},data:e}):(g=b.width,g=typeof g===i?g.apply(b):g),h+=j(g)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including chart margins and axes)\n </p>\n </div>\n\n <div id="height" class="form-input numeric-slider-input">\n <label for="height">Chart height: </label>\n <div class="slider-output">',(g=c.height)?g=g.call(b,{hash:{},data:e}):(g=b.height,g=typeof g===i?g.apply(b):g),h+=j(g)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including chart 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="',(g=c.xLabel)?g=g.call(b,{hash:{},data:e}):(g=b.xLabel,g=typeof g===i?g.apply(b):g),h+=j(g)+'" />\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="',(g=c.yLabel)?g=g.call(b,{hash:{},data:e}):(g=b.yLabel,g=typeof g===i?g.apply(b):g),h+=j(g)+'" />\n <p class="form-help help-text-small"></p>\n </div>\n\n <input id="render-button" type="button" value="Draw" />'}),this.Templates.chartDisplay=Handlebars.template(function(a,b,c,d,e){this.compilerInfo=[4,">= 1.0.0"],c=this.merge(c,a.helpers),e=e||{};var f,g="",h="function",i=this.escapeExpression;return g+='<svg width="',(f=c.width)?f=f.call(b,{hash:{},data:e}):(f=b.width,f=typeof f===h?f.apply(b):f),g+=i(f)+'" height="',(f=c.height)?f=f.call(b,{hash:{},data:e}):(f=b.height,f=typeof f===h?f.apply(b):f),g+=i(f)+'"></svg>'}),this.Templates.dataControl=Handlebars.template(function(a,b,c,d,e){function f(a,b){var d,e="";return e+='\n <option value="',(d=c.index)?d=d.call(a,{hash:{},data:b}):(d=a.index,d=typeof d===j?d.apply(a):d),e+=k(d)+'">',(d=c.name)?d=d.call(a,{hash:{},data:b}):(d=a.name,d=typeof d===j?d.apply(a):d),e+=k(d)+"</option>\n "}function g(){return'checked="true"'}this.compilerInfo=[4,">= 1.0.0"],c=this.merge(c,a.helpers),e=e||{};var h,i="",j="function",k=this.escapeExpression,l=this;return i+='<p class="help-text">\n Use the following controls to change the data used by the chart.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n </p>\n\n \n <div class="column-select">\n <label for="X-select">Data column for X: </label>\n <select name="X" id="X-select">\n ',h=c.each.call(b,b.numericColumns,{hash:{},inverse:l.noop,fn:l.program(1,f,e),data:e}),(h||0===h)&&(i+=h),i+='\n </select>\n </div>\n <div class="column-select">\n <label for="Y-select">Data column for Y: </label>\n <select name="Y" id="Y-select">\n ',h=c.each.call(b,b.numericColumns,{hash:{},inverse:l.noop,fn:l.program(1,f,e),data:e}),(h||0===h)&&(i+=h),i+='\n </select>\n </div>\n\n \n <div id="include-id">\n <label for="include-id-checkbox">Include a third column as data point IDs?</label>\n <input type="checkbox" name="include-id" id="include-id-checkbox" />\n <p class="help-text-small">\n These will be displayed (along with the x and y values) when you hover over\n a data point.\n </p>\n </div>\n <div class="column-select" style="display: none">\n <label for="ID-select">Data column for IDs: </label>\n <select name="ID" id="ID-select">\n ',h=c.each.call(b,b.allColumns,{hash:{},inverse:l.noop,fn:l.program(1,f,e),data:e}),(h||0===h)&&(i+=h),i+='\n </select>\n </div>\n\n \n <div id="first-line-header" style="display: none;">\n <p>Possible headers: ',(h=c.possibleHeaders)?h=h.call(b,{hash:{},data:e}):(h=b.possibleHeaders,h=typeof h===j?h.apply(b):h),i+=k(h)+'\n </p>\n <label for="first-line-header-checkbox">Use the above as column headers?</label>\n <input type="checkbox" name="include-id" id="first-line-header-checkbox"\n ',h=c["if"].call(b,b.usePossibleHeaders,{hash:{},inverse:l.noop,fn:l.program(3,g,e),data:e}),(h||0===h)&&(i+=h),i+='/>\n <p class="help-text-small">\n It looks like Galaxy couldn\'t get proper column headers for this data.\n Would you like to use the column headers above as column names to select columns?\n </p>\n </div>\n\n <input id="render-button" type="button" value="Draw" />\n <div class="clear"></div>'}),this.Templates.scatterplotControlForm=Handlebars.template(function(a,b,c,d,e){this.compilerInfo=[4,">= 1.0.0"],c=this.merge(c,a.helpers),e=e||{};var f,g="",h="function",i=this.escapeExpression;return g+='\n\n<div class="scatterplot-container chart-container tabbable tabs-left">\n \n <ul class="nav nav-tabs">\n \n <li class="active"><a href="#data-control" data-toggle="tab" class="tooltip"\n title="Use this tab to change which data are used">Data Controls</a></li>\n <li><a href="#chart-control" data-toggle="tab" class="tooltip"\n title="Use this tab to change how the chart is drawn">Chart Controls</a></li>\n <li><a href="#stats-display" data-toggle="tab" class="tooltip"\n title="This tab will display overall statistics for your data">Statistics</a></li>\n <li><a href="#chart-display" data-toggle="tab" class="tooltip"\n title="This tab will display the chart">Chart</a>\n \n <div id="loading-indicator" style="display: none;">\n <img class="loading-img" src="',(f=c.loadingIndicatorImagePath)?f=f.call(b,{hash:{},data:e}):(f=b.loadingIndicatorImagePath,f=typeof f===h?f.apply(b):f),g+=i(f)+'" />\n <span class="loading-message">',(f=c.message)?f=f.call(b,{hash:{},data:e}):(f=b.message,f=typeof f===h?f.apply(b):f),g+=i(f)+"</span>\n </div>\n </li>\n </ul>\n\n "+'\n <div class="tab-content">\n '+'\n <div id="data-control" class="tab-pane active">\n '+"\n </div>\n \n "+'\n <div id="chart-control" class="tab-pane">\n '+"\n </div>\n\n "+'\n <div id="stats-display" class="tab-pane">\n '+"\n </div>\n\n "+'\n <div id="chart-display" class="tab-pane">\n '+"\n </div>\n\n </div>"+"\n</div>"}),this.Templates.statsDisplay=Handlebars.template(function(a,b,c,d,e){function f(a,b){var d,e="";return e+="\n <tr><td>",(d=c.name)?d=d.call(a,{hash:{},data:b}):(d=a.name,d=typeof d===i?d.apply(a):d),e+=j(d)+"</td><td>",(d=c.xval)?d=d.call(a,{hash:{},data:b}):(d=a.xval,d=typeof d===i?d.apply(a):d),e+=j(d)+"</td><td>",(d=c.yval)?d=d.call(a,{hash:{},data:b}):(d=a.yval,d=typeof d===i?d.apply(a):d),e+=j(d)+"</td></tr>\n </tr>\n "}this.compilerInfo=[4,">= 1.0.0"],c=this.merge(c,a.helpers),e=e||{};var g,h="",i="function",j=this.escapeExpression,k=this;return h+='<p class="help-text">By column:</p>\n <table id="chart-stats-table">\n <thead><th></th><th>X</th><th>Y</th></thead>\n ',g=c.each.call(b,b.stats,{hash:{},inverse:k.noop,fn:k.program(1,f,e),data:e}),(g||0===g)&&(h+=g),h+="\n </table>"});var ScatterplotControlForm=BaseView.extend(LoggableMixin).extend({className:"scatterplot-control-form",dataLoadDelay:4e3,dataLoadSize:5e3,loadingIndicatorImage:"loading_small_white_bg.gif",fetchMsg:"Fetching data...",renderMsg:"Rendering...",initialize:function(a){this.log(this+".initialize, attributes:",a),this.dataset=null,this.chartConfig=null,this.chart=null,this.loader=null,this.$dataControl=null,this.$chartControl=null,this.$statsDisplay=null,this.$chartDisplay=null,this.dataFetch=null,this.initializeFromAttributes(a),this.initializeChart(a),this.initializeDataLoader(a)},initializeFromAttributes:function(a){if(!a||!a.dataset)throw"ScatterplotView requires a dataset";if(this.dataset=a.dataset,"string"===jQuery.type(this.dataset.metadata_column_types)&&(this.dataset.metadata_column_types=this.dataset.metadata_column_types.split(", ")),this.log(" dataset:",this.dataset),this.dataset.comment_lines&&this.dataset.comment_lines.length){var b=this.dataset.comment_lines[0],c=b.split(" ");c.length===this.dataset.metadata_column_types.length&&(this.possibleHeaders=c)}if(!a.apiDatasetsURL)throw"ScatterplotView requires a apiDatasetsURL";this.dataURL=a.apiDatasetsURL+"/"+this.dataset.id+"?",this.log(" dataURL:",this.dataURL)},initializeChart:function(a){this.chartConfig=a.chartConfig||{},this.log(" initial chartConfig:",this.chartConfig),this.chart=new TwoVarScatterplot(this.chartConfig),this.chartConfig=this.chart.config},initializeDataLoader:function(a){var b=this;this.loader=new LazyDataLoader({url:null,start:a.start||0,total:a.total||this.dataset.metadata_data_lines,delay:this.dataLoadDelay,size:this.dataLoadSize,buildUrl:function(a,b){return this.url+"&"+jQuery.param({start_val:a,max_vals:b})}}),$(this.loader).bind("error",function(a,c,d){b.log("ERROR:",c,d),alert("ERROR fetching data:\n"+c+"\n"+d),b.hideLoadingIndicator()})},render:function(){return this.log(this+".render"),this.$el.append(ScatterplotControlForm.templates.mainLayout({loadingIndicatorImagePath:"/static/images/"+this.loadingIndicatorImage,message:""})),this.$dataControl=this._render_dataControl(),this.$chartControl=this._render_chartControl(),this.$statsDisplay=this.$el.find(".tab-pane#stats-display"),this.$chartDisplay=this._render_chartDisplay(),this.chartConfig.xColumn&&this.chartConfig.yColumn&&this.renderChart(),this.$el.find(".tooltip").tooltip(),this},_render_dataControl:function(){var a=this,b=[],c=[],d=this.possibleHeaders&&this.$dataControl?this.$dataControl.find("#first-line-header-checkbox").is(":checked"):!1;_.each(this.dataset.metadata_column_types,function(e,f){var g=f+1,h="column "+g;a.dataset.metadata_column_names?h=a.dataset.metadata_column_names[f]:d&&(h=a.possibleHeaders[f]),b.push({index:g,name:h}),("int"===e||"float"===e)&&c.push({index:g,name:h})});var e=this.$el.find(".tab-pane#data-control");return e.html(ScatterplotControlForm.templates.dataControl({allColumns:b,numericColumns:c,possibleHeaders:this.possibleHeaders?this.possibleHeaders.join(", "):"",usePossibleHeaders:d})),!this.dataset.metadata_column_names&&this.possibleHeaders&&e.find("#first-line-header").show(),e.find("#X-select").val(this.chartConfig.xColumn),e.find("#Y-select").val(this.chartConfig.yColumn),void 0!==this.chartConfig.idColumn&&(e.find("#include-id-checkbox").attr("checked",!0).trigger("change"),e.find("#ID-select").val(this.chartConfig.idColumn)),e},_render_chartControl:function(){var a=this,b=this.$el.find(".tab-pane#chart-control"),c={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};return b.append(ScatterplotControlForm.templates.chartControl(this.chartConfig)),b.find(".numeric-slider-input").each(function(){function b(){var a=$(this),b=a.slider("value");e.text(b)}var d=$(this),e=d.find(".slider-output"),f=d.find(".slider"),g=d.attr("id");f.slider(_.extend(c[g],{value:a.chartConfig[g],change:b,slide:b}))}),b},_render_chartDisplay:function(){var a=this.$el.find(".tab-pane#chart-display");return a.append(ScatterplotControlForm.templates.chartDisplay(this.chartConfig)),a},events:{"change #include-id-checkbox":"toggleThirdColumnSelector","change #first-line-header-checkbox":"rerenderDataControl","click #data-control #render-button":"renderChart","click #chart-control #render-button":"changeChartSettings"},toggleThirdColumnSelector:function(){this.$el.find('select[name="ID"]').parent().toggle()},rerenderDataControl:function(){this.$dataControl=this._render_dataControl()},showLoadingIndicator:function(a,b){a=a||"";var c=this.$el.find("div#loading-indicator");messageBox=c.find(".loading-message"),c.is(":visible")?a?messageBox.fadeOut("fast",function(){messageBox.text(a),messageBox.fadeIn("fast",b)}):b():(a&&messageBox.text(a),c.fadeIn("fast",b))},hideLoadingIndicator:function(a){this.$el.find("div#loading-indicator").fadeOut("fast",a)},renderChart:function(){this.log(this+".renderChart"),this.data=null,this.meta=null,_.extend(this.chartConfig,this.getChartSettings()),this.log(" chartConfig:",this.chartConfig),this.chart.updateConfig(this.chartConfig,!1),this.loader.url=this.dataURL+"&"+jQuery.param(this.getDataSettings()),this.log(" loader: total lines:",this.loader.total," url:",this.loader.url);var a=this;$(this.loader).bind("loaded.new",function(b,c){a.log(a+" loaded.new",c),a.postProcessDataFetchResponse(c),a.log(" postprocessed data:",a.data),a.log(" postprocessed meta:",a.meta),a.showLoadingIndicator(a.renderMsg,function(){a.chart.render(a.data,a.meta),a.renderStats(a.data,a.meta),a.hideLoadingIndicator()})}),$(this.loader).bind("complete",function(b,c){a.log(a+" complete",c),$(a.loader).unbind()}),a.showLoadingIndicator(a.fetchMsg,function(){a.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show"),a.loader.load()})},renderStats:function(){this.log(this+".renderStats"),this.$statsDisplay.html(ScatterplotControlForm.templates.statsDisplay({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 a=this;newChartSettings=this.getChartSettings(),_.extend(this.chartConfig,newChartSettings),this.log("this.chartConfig:",this.chartConfig),this.chart.updateConfig(this.chartConfig,!1),a.data&&a.meta?a.showLoadingIndicator(a.renderMsg,function(){a.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show"),a.chart.render(a.data,a.meta),a.hideLoadingIndicator()}):this.renderChart()},postProcessDataFetchResponse:function(a){this.postProcessData(a.data),this.postProcessMeta(a.meta)},postProcessData:function(a){var b=this;b.data?_.each(a,function(a,c){b.data[c]=b.data[c].concat(a)}):b.data=a},postProcessMeta:function(a){var b=this,c=this.dataset.metadata_column_types;b.meta?_.each(a,function(a,d){var e=b.meta[d],f=c[d];if(e.count+=a.count?a.count:0,"int"===f||"float"===f){e.min=Math.min(a.min,e.min),e.max=Math.max(a.max,e.max),e.sum=a.sum+e.sum,e.mean=e.count?e.sum/e.count:null;var g=b.data[d].slice().sort(),h=Math.floor(g.length/2);e.median=0===g.length%2?(g[h]+g[h+1])/2:g[h]}}):b.meta=a},getDataSettings:function(){var a=this.getColumnSelections(),b=[];this.log(" columnSelections:",a),b=[a.X.colIndex-1,a.Y.colIndex-1],this.$dataControl.find("#include-id-checkbox").attr("checked")&&b.push(a.ID.colIndex-1);var c={data_type:"raw_data",provider:"column_with_stats",columns:"["+b+"]"};return this.log(" data settings (url params):",c),c},getColumnSelections:function(){var a={};return this.$dataControl.find("div.column-select select").each(function(){var b=$(this),c=b.val();a[b.attr("name")]={colIndex:c,colName:b.children('[value="'+c+'"]').text()}}),a},getChartSettings:function(){var a={},b=this.getColumnSelections();a.datapointSize=this.$chartControl.find("#datapointSize.numeric-slider-input").find(".slider").slider("value"),a.width=this.$chartControl.find("#width.numeric-slider-input").find(".slider").slider("value"),a.height=this.$chartControl.find("#height.numeric-slider-input").find(".slider").slider("value");var c=this.$chartControl.find("input#X-axis-label").val(),d=this.$chartControl.find("input#Y-axis-label").val();return a.xLabel="X"===c?b.X.colName:c,a.yLabel="Y"===d?b.Y.colName:d,a.animDuration=this.$chartControl.find("#animate-chart").is(":checked")?this.chart.defaults.animDuration:0,this.log(" chartSettings:",a),a},toString:function(){return"ScatterplotControlForm("+(this.dataset?this.dataset.id:"")+")"}});ScatterplotControlForm.templates={mainLayout:Templates.scatterplotControlForm,dataControl:Templates.dataControl,chartControl:Templates.chartControl,statsDisplay:Templates.statsDisplay,chartDisplay:Templates.chartDisplay};
\ No newline at end of file
diff -r c623f3d38221c588de3976c05b688387933cbf29 -r 42cbb2d2014cbdb4e227faefa69f0c9808d5b1e7 config/plugins/visualizations/scatterplot/templates/scatterplot.mako
--- /dev/null
+++ b/config/plugins/visualizations/scatterplot/templates/scatterplot.mako
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>${hda.name} | ${visualization_name}</title>
+
+## ----------------------------------------------------------------------------
+<link type="text/css" rel="Stylesheet" media="screen" href="/static/style/base.css">
+<link type="text/css" rel="Stylesheet" media="screen" href="/static/style/jquery-ui/smoothness/jquery-ui.css">
+
+<link type="text/css" rel="Stylesheet" media="screen" href="/plugins/visualizations/scatterplot/static/scatterplot.css">
+
+## ----------------------------------------------------------------------------
+<script type="text/javascript" src="/static/scripts/libs/jquery/jquery.js"></script>
+<script type="text/javascript" src="/static/scripts/libs/jquery/jquery.migrate.js"></script>
+<script type="text/javascript" src="/static/scripts/libs/underscore.js"></script>
+<script type="text/javascript" src="/static/scripts/libs/backbone/backbone.js"></script>
+<script type="text/javascript" src="/static/scripts/libs/backbone/backbone-relational.js"></script>
+<script type="text/javascript" src="/static/scripts/libs/handlebars.runtime.js"></script>
+<script type="text/javascript" src="/static/scripts/libs/d3.js"></script>
+<script type="text/javascript" src="/static/scripts/libs/bootstrap.js"></script>
+<script type="text/javascript" src="/static/scripts/libs/jquery/jquery-ui.js"></script>
+<script type="text/javascript" src="/static/scripts/utils/LazyDataLoader.js"></script>
+<script type="text/javascript" src="/static/scripts/mvc/base-mvc.js"></script>
+
+<script type="text/javascript" src="/plugins/visualizations/scatterplot/static/scatterplot.js"></script>
+
+</head>
+
+## ----------------------------------------------------------------------------
+<body>
+%if not embedded:
+## dataset info: only show if on own page
+<div id="chart-header" class="header">
+ <h2 class="title">Scatterplot of '${hda.name}'</h2>
+ <p class="subtitle">${hda.info}</p>
+</div>
+%endif
+
+<div id="scatterplot" class="scatterplot-control-form"></div>
+
+<script type="text/javascript">
+$(function(){
+ var hda = ${h.to_json_string( trans.security.encode_dict_ids( hda.get_api_value() ) )},
+ querySettings = ${h.to_json_string( query_args )},
+ chartConfig = _.extend( querySettings, {
+ containerSelector : '#chart',
+ //TODO: move to ScatterplotControlForm.initialize
+ marginTop : ( querySettings.marginTop > 20 )?( querySettings.marginTop ):( 20 ),
+
+ xColumn : querySettings.xColumn,
+ yColumn : querySettings.yColumn,
+ idColumn : querySettings.idColumn
+ });
+ //console.debug( querySettings );
+
+ var settingsForm = new ScatterplotControlForm({
+ dataset : hda,
+ apiDatasetsURL : "${h.url_for( controller='/api/datasets', action='index' )}",
+ el : $( '#scatterplot' ),
+ chartConfig : chartConfig
+ }).render();
+
+});
+</script>
+
+</body>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: Fix for Datatype.matches_any() introduced in 10027:b999689a0130. Fixes issue seen where external display applications requiring format conversions would always fail with server error.
by commits-noreply@bitbucket.org 08 Aug '13
by commits-noreply@bitbucket.org 08 Aug '13
08 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/8ee4176d44ba/
Changeset: 8ee4176d44ba
Branch: next-stable
User: dan
Date: 2013-08-07 21:23:30
Summary: Fix for Datatype.matches_any() introduced in 10027:b999689a0130. Fixes issue seen where external display applications requiring format conversions would always fail with server error.
Affected #: 1 file
diff -r 3615504d0a43b511c44a4aa6a8fa520260373694 -r 8ee4176d44bad2c1029356e869d601752ae54cd0 lib/galaxy/datatypes/data.py
--- a/lib/galaxy/datatypes/data.py
+++ b/lib/galaxy/datatypes/data.py
@@ -7,6 +7,7 @@
import tempfile
import zipfile
from cgi import escape
+from inspect import isclass
from galaxy import util
from galaxy.datatypes.metadata import MetadataElement #import directly to maintain ease of use in Datatype class definitions
from galaxy.util import inflector
@@ -553,7 +554,7 @@
Check if this datatype is of any of the target_datatypes or is
a subtype thereof.
"""
- datatype_classes = tuple( [ datatype.__class__ for datatype in target_datatypes ] )
+ datatype_classes = tuple( [ datatype if isclass( datatype ) else datatype.__class__ for datatype in target_datatypes ] )
return isinstance( self, datatype_classes )
def merge( split_files, output_file):
"""
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: Fix for Datatype.matches_any() introduced in 10027:b999689a0130. Fixes issue seen where external display applications requiring format conversions would always fail with server error.
by commits-noreply@bitbucket.org 08 Aug '13
by commits-noreply@bitbucket.org 08 Aug '13
08 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/c623f3d38221/
Changeset: c623f3d38221
User: dan
Date: 2013-08-07 21:23:30
Summary: Fix for Datatype.matches_any() introduced in 10027:b999689a0130. Fixes issue seen where external display applications requiring format conversions would always fail with server error.
Affected #: 1 file
diff -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 -r c623f3d38221c588de3976c05b688387933cbf29 lib/galaxy/datatypes/data.py
--- a/lib/galaxy/datatypes/data.py
+++ b/lib/galaxy/datatypes/data.py
@@ -7,6 +7,7 @@
import tempfile
import zipfile
from cgi import escape
+from inspect import isclass
from galaxy import util
from galaxy.datatypes.metadata import MetadataElement #import directly to maintain ease of use in Datatype class definitions
from galaxy.util import inflector
@@ -554,7 +555,7 @@
Check if this datatype is of any of the target_datatypes or is
a subtype thereof.
"""
- datatype_classes = tuple( [ datatype.__class__ for datatype in target_datatypes ] )
+ datatype_classes = tuple( [ datatype if isclass( datatype ) else datatype.__class__ for datatype in target_datatypes ] )
return isinstance( self, datatype_classes )
def merge( split_files, output_file):
"""
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: Handlebars.runtime.js: update to 1.0.0, recompile templates, pack (devs need to update their handlebars.compilers to 1.0.12)
by commits-noreply@bitbucket.org 08 Aug '13
by commits-noreply@bitbucket.org 08 Aug '13
08 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/1f45ab84c121/
Changeset: 1f45ab84c121
User: carlfeberhard
Date: 2013-08-07 21:12:35
Summary: Handlebars.runtime.js: update to 1.0.0, recompile templates, pack (devs need to update their handlebars.compilers to 1.0.12)
Affected #: 50 files
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/libs/handlebars.runtime.js
--- a/static/scripts/libs/handlebars.runtime.js
+++ b/static/scripts/libs/handlebars.runtime.js
@@ -1,39 +1,80 @@
+/*
+
+Copyright (C) 2011 by Yehuda Katz
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+// lib/handlebars/browser-prefix.js
+var Handlebars = {};
+
+(function(Handlebars, undefined) {
+;
// lib/handlebars/base.js
-/*jshint eqnull:true*/
-this.Handlebars = {};
+Handlebars.VERSION = "1.0.0";
+Handlebars.COMPILER_REVISION = 4;
-(function(Handlebars) {
-
-Handlebars.VERSION = "1.0.rc.1";
+Handlebars.REVISION_CHANGES = {
+ 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
+ 2: '== 1.0.0-rc.3',
+ 3: '== 1.0.0-rc.4',
+ 4: '>= 1.0.0'
+};
Handlebars.helpers = {};
Handlebars.partials = {};
+var toString = Object.prototype.toString,
+ functionType = '[object Function]',
+ objectType = '[object Object]';
+
Handlebars.registerHelper = function(name, fn, inverse) {
- if(inverse) { fn.not = inverse; }
- this.helpers[name] = fn;
+ if (toString.call(name) === objectType) {
+ if (inverse || fn) { throw new Handlebars.Exception('Arg not supported with multiple helpers'); }
+ Handlebars.Utils.extend(this.helpers, name);
+ } else {
+ if (inverse) { fn.not = inverse; }
+ this.helpers[name] = fn;
+ }
};
Handlebars.registerPartial = function(name, str) {
- this.partials[name] = str;
+ if (toString.call(name) === objectType) {
+ Handlebars.Utils.extend(this.partials, name);
+ } else {
+ this.partials[name] = str;
+ }
};
Handlebars.registerHelper('helperMissing', function(arg) {
if(arguments.length === 2) {
return undefined;
} else {
- throw new Error("Could not find property '" + arg + "'");
+ throw new Error("Missing helper: '" + arg + "'");
}
});
-var toString = Object.prototype.toString, functionType = "[object Function]";
-
Handlebars.registerHelper('blockHelperMissing', function(context, options) {
var inverse = options.inverse || function() {}, fn = options.fn;
-
- var ret = "";
var type = toString.call(context);
if(type === functionType) { context = context.call(this); }
@@ -62,63 +103,97 @@
return obj;
};
+Handlebars.logger = {
+ DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3,
+
+ methodMap: {0: 'debug', 1: 'info', 2: 'warn', 3: 'error'},
+
+ // can be overridden in the host environment
+ log: function(level, obj) {
+ if (Handlebars.logger.level <= level) {
+ var method = Handlebars.logger.methodMap[level];
+ if (typeof console !== 'undefined' && console[method]) {
+ console[method].call(console, obj);
+ }
+ }
+ }
+};
+
+Handlebars.log = function(level, obj) { Handlebars.logger.log(level, obj); };
+
Handlebars.registerHelper('each', function(context, options) {
var fn = options.fn, inverse = options.inverse;
- var ret = "", data;
+ var i = 0, ret = "", data;
+
+ var type = toString.call(context);
+ if(type === functionType) { context = context.call(this); }
if (options.data) {
data = Handlebars.createFrame(options.data);
}
- if(context && context.length > 0) {
- for(var i=0, j=context.length; i<j; i++) {
- if (data) { data.index = i; }
- ret = ret + fn(context[i], { data: data });
+ if(context && typeof context === 'object') {
+ if(context instanceof Array){
+ for(var j = context.length; i<j; i++) {
+ if (data) { data.index = i; }
+ ret = ret + fn(context[i], { data: data });
+ }
+ } else {
+ for(var key in context) {
+ if(context.hasOwnProperty(key)) {
+ if(data) { data.key = key; }
+ ret = ret + fn(context[key], {data: data});
+ i++;
+ }
+ }
}
- } else {
+ }
+
+ if(i === 0){
ret = inverse(this);
}
+
return ret;
});
-Handlebars.registerHelper('if', function(context, options) {
- var type = toString.call(context);
- if(type === functionType) { context = context.call(this); }
+Handlebars.registerHelper('if', function(conditional, options) {
+ var type = toString.call(conditional);
+ if(type === functionType) { conditional = conditional.call(this); }
- if(!context || Handlebars.Utils.isEmpty(context)) {
+ if(!conditional || Handlebars.Utils.isEmpty(conditional)) {
return options.inverse(this);
} else {
return options.fn(this);
}
});
-Handlebars.registerHelper('unless', function(context, options) {
- var fn = options.fn, inverse = options.inverse;
- options.fn = inverse;
- options.inverse = fn;
-
- return Handlebars.helpers['if'].call(this, context, options);
+Handlebars.registerHelper('unless', function(conditional, options) {
+ return Handlebars.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn});
});
Handlebars.registerHelper('with', function(context, options) {
- return options.fn(context);
+ var type = toString.call(context);
+ if(type === functionType) { context = context.call(this); }
+
+ if (!Handlebars.Utils.isEmpty(context)) return options.fn(context);
});
-Handlebars.registerHelper('log', function(context) {
- Handlebars.log(context);
+Handlebars.registerHelper('log', function(context, options) {
+ var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
+ Handlebars.log(level, context);
});
-
-}(this.Handlebars));
;
// lib/handlebars/utils.js
+
+var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
+
Handlebars.Exception = function(message) {
var tmp = Error.prototype.constructor.apply(this, arguments);
- for (var p in tmp) {
- if (tmp.hasOwnProperty(p)) { this[p] = tmp[p]; }
+ // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
+ for (var idx = 0; idx < errorProps.length; idx++) {
+ this[errorProps[idx]] = tmp[errorProps[idx]];
}
-
- this.message = tmp.message;
};
Handlebars.Exception.prototype = new Error();
@@ -130,52 +205,61 @@
return this.string.toString();
};
-(function() {
- var escape = {
- "&": "&",
- "<": "<",
- ">": ">",
- '"': """,
- "'": "'",
- "`": "`"
- };
+var escape = {
+ "&": "&",
+ "<": "<",
+ ">": ">",
+ '"': """,
+ "'": "'",
+ "`": "`"
+};
- var badChars = /[&<>"'`]/g;
- var possible = /[&<>"'`]/;
+var badChars = /[&<>"'`]/g;
+var possible = /[&<>"'`]/;
- var escapeChar = function(chr) {
- return escape[chr] || "&";
- };
+var escapeChar = function(chr) {
+ return escape[chr] || "&";
+};
- Handlebars.Utils = {
- escapeExpression: function(string) {
- // don't escape SafeStrings, since they're already safe
- if (string instanceof Handlebars.SafeString) {
- return string.toString();
- } else if (string == null || string === false) {
- return "";
- }
-
- if(!possible.test(string)) { return string; }
- return string.replace(badChars, escapeChar);
- },
-
- isEmpty: function(value) {
- if (typeof value === "undefined") {
- return true;
- } else if (value === null) {
- return true;
- } else if (value === false) {
- return true;
- } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) {
- return true;
- } else {
- return false;
+Handlebars.Utils = {
+ extend: function(obj, value) {
+ for(var key in value) {
+ if(value.hasOwnProperty(key)) {
+ obj[key] = value[key];
}
}
- };
-})();;
+ },
+
+ escapeExpression: function(string) {
+ // don't escape SafeStrings, since they're already safe
+ if (string instanceof Handlebars.SafeString) {
+ return string.toString();
+ } else if (string == null || string === false) {
+ return "";
+ }
+
+ // Force a string conversion as this will be done by the append regardless and
+ // the regex test will do this transparently behind the scenes, causing issues if
+ // an object's to string has escaped characters in it.
+ string = string.toString();
+
+ if(!possible.test(string)) { return string; }
+ return string.replace(badChars, escapeChar);
+ },
+
+ isEmpty: function(value) {
+ if (!value && value !== 0) {
+ return true;
+ } else if(toString.call(value) === "[object Array]" && value.length === 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+};
+;
// lib/handlebars/runtime.js
+
Handlebars.VM = {
template: function(templateSpec) {
// Just add water
@@ -186,39 +270,73 @@
program: function(i, fn, data) {
var programWrapper = this.programs[i];
if(data) {
- return Handlebars.VM.program(fn, data);
- } else if(programWrapper) {
- return programWrapper;
- } else {
- programWrapper = this.programs[i] = Handlebars.VM.program(fn);
- return programWrapper;
+ programWrapper = Handlebars.VM.program(i, fn, data);
+ } else if (!programWrapper) {
+ programWrapper = this.programs[i] = Handlebars.VM.program(i, fn);
}
+ return programWrapper;
+ },
+ merge: function(param, common) {
+ var ret = param || common;
+
+ if (param && common) {
+ ret = {};
+ Handlebars.Utils.extend(ret, common);
+ Handlebars.Utils.extend(ret, param);
+ }
+ return ret;
},
programWithDepth: Handlebars.VM.programWithDepth,
- noop: Handlebars.VM.noop
+ noop: Handlebars.VM.noop,
+ compilerInfo: null
};
return function(context, options) {
options = options || {};
- return templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data);
+ var result = templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data);
+
+ var compilerInfo = container.compilerInfo || [],
+ compilerRevision = compilerInfo[0] || 1,
+ currentRevision = Handlebars.COMPILER_REVISION;
+
+ if (compilerRevision !== currentRevision) {
+ if (compilerRevision < currentRevision) {
+ var runtimeVersions = Handlebars.REVISION_CHANGES[currentRevision],
+ compilerVersions = Handlebars.REVISION_CHANGES[compilerRevision];
+ throw "Template was precompiled with an older version of Handlebars than the current runtime. "+
+ "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+").";
+ } else {
+ // Use the embedded version info since the runtime doesn't know about this revision yet
+ throw "Template was precompiled with a newer version of Handlebars than the current runtime. "+
+ "Please update your runtime to a newer version ("+compilerInfo[1]+").";
+ }
+ }
+
+ return result;
};
},
- programWithDepth: function(fn, data, $depth) {
- var args = Array.prototype.slice.call(arguments, 2);
+ programWithDepth: function(i, fn, data /*, $depth */) {
+ var args = Array.prototype.slice.call(arguments, 3);
- return function(context, options) {
+ var program = function(context, options) {
options = options || {};
return fn.apply(this, [context, options.data || data].concat(args));
};
+ program.program = i;
+ program.depth = args.length;
+ return program;
},
- program: function(fn, data) {
- return function(context, options) {
+ program: function(i, fn, data) {
+ var program = function(context, options) {
options = options || {};
return fn(context, options.data || data);
};
+ program.program = i;
+ program.depth = 0;
+ return program;
},
noop: function() { return ""; },
invokePartial: function(partial, name, context, helpers, partials, data) {
@@ -239,3 +357,6 @@
Handlebars.template = Handlebars.VM.template;
;
+// lib/handlebars/browser-suffix.js
+})(Handlebars);
+;
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/libs/handlebars.runtime.js
--- a/static/scripts/packed/libs/handlebars.runtime.js
+++ b/static/scripts/packed/libs/handlebars.runtime.js
@@ -1,1 +1,1 @@
-this.Handlebars={};(function(c){c.VERSION="1.0.rc.1";c.helpers={};c.partials={};c.registerHelper=function(e,f,d){if(d){f.not=d}this.helpers[e]=f};c.registerPartial=function(d,e){this.partials[d]=e};c.registerHelper("helperMissing",function(d){if(arguments.length===2){return undefined}else{throw new Error("Could not find property '"+d+"'")}});var a=Object.prototype.toString,b="[object Function]";c.registerHelper("blockHelperMissing",function(g,f){var d=f.inverse||function(){},i=f.fn;var e="";var h=a.call(g);if(h===b){g=g.call(this)}if(g===true){return i(this)}else{if(g===false||g==null){return d(this)}else{if(h==="[object Array]"){if(g.length>0){return c.helpers.each(g,f)}else{return d(this)}}else{return i(g)}}}});c.K=function(){};c.createFrame=Object.create||function(d){c.K.prototype=d;var e=new c.K();c.K.prototype=null;return e};c.registerHelper("each",function(k,g){var l=g.fn,d=g.inverse;var f="",m;if(g.data){m=c.createFrame(g.data)}if(k&&k.length>0){for(var h=0,e=k.length;h<e;h++){if(m){m.index=h}f=f+l(k[h],{data:m})}}else{f=d(this)}return f});c.registerHelper("if",function(e,d){var f=a.call(e);if(f===b){e=e.call(this)}if(!e||c.Utils.isEmpty(e)){return d.inverse(this)}else{return d.fn(this)}});c.registerHelper("unless",function(f,e){var g=e.fn,d=e.inverse;e.fn=d;e.inverse=g;return c.helpers["if"].call(this,f,e)});c.registerHelper("with",function(e,d){return d.fn(e)});c.registerHelper("log",function(d){c.log(d)})}(this.Handlebars));Handlebars.Exception=function(b){var a=Error.prototype.constructor.apply(this,arguments);for(var c in a){if(a.hasOwnProperty(c)){this[c]=a[c]}}this.message=a.message};Handlebars.Exception.prototype=new Error();Handlebars.SafeString=function(a){this.string=a};Handlebars.SafeString.prototype.toString=function(){return this.string.toString()};(function(){var c={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"};var d=/[&<>"'`]/g;var b=/[&<>"'`]/;var a=function(e){return c[e]||"&"};Handlebars.Utils={escapeExpression:function(e){if(e instanceof Handlebars.SafeString){return e.toString()}else{if(e==null||e===false){return""}}if(!b.test(e)){return e}return e.replace(d,a)},isEmpty:function(e){if(typeof e==="undefined"){return true}else{if(e===null){return true}else{if(e===false){return true}else{if(Object.prototype.toString.call(e)==="[object Array]"&&e.length===0){return true}else{return false}}}}}}})();Handlebars.VM={template:function(a){var b={escapeExpression:Handlebars.Utils.escapeExpression,invokePartial:Handlebars.VM.invokePartial,programs:[],program:function(d,e,f){var c=this.programs[d];if(f){return Handlebars.VM.program(e,f)}else{if(c){return c}else{c=this.programs[d]=Handlebars.VM.program(e);return c}}},programWithDepth:Handlebars.VM.programWithDepth,noop:Handlebars.VM.noop};return function(d,c){c=c||{};return a.call(b,Handlebars,d,c.helpers,c.partials,c.data)}},programWithDepth:function(b,d,c){var a=Array.prototype.slice.call(arguments,2);return function(f,e){e=e||{};return b.apply(this,[f,e.data||d].concat(a))}},program:function(a,b){return function(d,c){c=c||{};return a(d,c.data||b)}},noop:function(){return""},invokePartial:function(a,c,e,f,d,g){var b={helpers:f,partials:d,data:g};if(a===undefined){throw new Handlebars.Exception("The partial "+c+" could not be found")}else{if(a instanceof Function){return a(e,b)}else{if(!Handlebars.compile){throw new Handlebars.Exception("The partial "+c+" could not be compiled when running in runtime-only mode")}else{d[c]=Handlebars.compile(a,{data:g!==undefined});return d[c](e,b)}}}}};Handlebars.template=Handlebars.VM.template;
\ No newline at end of file
+var Handlebars={};(function(c,e){c.VERSION="1.0.0";c.COMPILER_REVISION=4;c.REVISION_CHANGES={1:"<= 1.0.rc.2",2:"== 1.0.0-rc.3",3:"== 1.0.0-rc.4",4:">= 1.0.0"};c.helpers={};c.partials={};var d=Object.prototype.toString,f="[object Function]",b="[object Object]";c.registerHelper=function(l,m,k){if(d.call(l)===b){if(k||m){throw new c.Exception("Arg not supported with multiple helpers")}c.Utils.extend(this.helpers,l)}else{if(k){m.not=k}this.helpers[l]=m}};c.registerPartial=function(k,l){if(d.call(k)===b){c.Utils.extend(this.partials,k)}else{this.partials[k]=l}};c.registerHelper("helperMissing",function(k){if(arguments.length===2){return e}else{throw new Error("Missing helper: '"+k+"'")}});c.registerHelper("blockHelperMissing",function(m,l){var k=l.inverse||function(){},o=l.fn;var n=d.call(m);if(n===f){m=m.call(this)}if(m===true){return o(this)}else{if(m===false||m==null){return k(this)}else{if(n==="[object Array]"){if(m.length>0){return c.helpers.each(m,l)}else{return k(this)}}else{return o(m)}}}});c.K=function(){};c.createFrame=Object.create||function(k){c.K.prototype=k;var l=new c.K();c.K.prototype=null;return l};c.logger={DEBUG:0,INFO:1,WARN:2,ERROR:3,level:3,methodMap:{0:"debug",1:"info",2:"warn",3:"error"},log:function(m,k){if(c.logger.level<=m){var l=c.logger.methodMap[m];if(typeof console!=="undefined"&&console[l]){console[l].call(console,k)}}}};c.log=function(l,k){c.logger.log(l,k)};c.registerHelper("each",function(k,t){var r=t.fn,m=t.inverse;var o=0,p="",n;var q=d.call(k);if(q===f){k=k.call(this)}if(t.data){n=c.createFrame(t.data)}if(k&&typeof k==="object"){if(k instanceof Array){for(var l=k.length;o<l;o++){if(n){n.index=o}p=p+r(k[o],{data:n})}}else{for(var s in k){if(k.hasOwnProperty(s)){if(n){n.key=s}p=p+r(k[s],{data:n});o++}}}}if(o===0){p=m(this)}return p});c.registerHelper("if",function(l,k){var m=d.call(l);if(m===f){l=l.call(this)}if(!l||c.Utils.isEmpty(l)){return k.inverse(this)}else{return k.fn(this)}});c.registerHelper("unless",function(l,k){return c.helpers["if"].call(this,l,{fn:k.inverse,inverse:k.fn})});c.registerHelper("with",function(l,k){var m=d.call(l);if(m===f){l=l.call(this)}if(!c.Utils.isEmpty(l)){return k.fn(l)}});c.registerHelper("log",function(l,k){var m=k.data&&k.data.level!=null?parseInt(k.data.level,10):1;c.log(m,l)});var i=["description","fileName","lineNumber","message","name","number","stack"];c.Exception=function(m){var l=Error.prototype.constructor.apply(this,arguments);for(var k=0;k<i.length;k++){this[i[k]]=l[i[k]]}};c.Exception.prototype=new Error();c.SafeString=function(k){this.string=k};c.SafeString.prototype.toString=function(){return this.string.toString()};var h={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"};var a=/[&<>"'`]/g;var g=/[&<>"'`]/;var j=function(k){return h[k]||"&"};c.Utils={extend:function(m,l){for(var k in l){if(l.hasOwnProperty(k)){m[k]=l[k]}}},escapeExpression:function(k){if(k instanceof c.SafeString){return k.toString()}else{if(k==null||k===false){return""}}k=k.toString();if(!g.test(k)){return k}return k.replace(a,j)},isEmpty:function(k){if(!k&&k!==0){return true}else{if(d.call(k)==="[object Array]"&&k.length===0){return true}else{return false}}}};c.VM={template:function(k){var l={escapeExpression:c.Utils.escapeExpression,invokePartial:c.VM.invokePartial,programs:[],program:function(n,o,p){var m=this.programs[n];if(p){m=c.VM.program(n,o,p)}else{if(!m){m=this.programs[n]=c.VM.program(n,o)}}return m},merge:function(o,n){var m=o||n;if(o&&n){m={};c.Utils.extend(m,n);c.Utils.extend(m,o)}return m},programWithDepth:c.VM.programWithDepth,noop:c.VM.noop,compilerInfo:null};return function(q,p){p=p||{};var n=k.call(l,c,q,p.helpers,p.partials,p.data);var r=l.compilerInfo||[],o=r[0]||1,t=c.COMPILER_REVISION;if(o!==t){if(o<t){var m=c.REVISION_CHANGES[t],s=c.REVISION_CHANGES[o];throw"Template was precompiled with an older version of Handlebars than the current runtime. Please update your precompiler to a newer version ("+m+") or downgrade your runtime to an older version ("+s+")."}else{throw"Template was precompiled with a newer version of Handlebars than the current runtime. Please update your runtime to a newer version ("+r[1]+")."}}return n}},programWithDepth:function(m,n,o){var l=Array.prototype.slice.call(arguments,3);var k=function(q,p){p=p||{};return n.apply(this,[q,p.data||o].concat(l))};k.program=m;k.depth=l.length;return k},program:function(l,m,n){var k=function(p,o){o=o||{};return m(p,o.data||n)};k.program=l;k.depth=0;return k},noop:function(){return""},invokePartial:function(k,m,o,p,n,q){var l={helpers:p,partials:n,data:q};if(k===e){throw new c.Exception("The partial "+m+" could not be found")}else{if(k instanceof Function){return k(o,l)}else{if(!c.compile){throw new c.Exception("The partial "+m+" could not be compiled when running in runtime-only mode")}else{n[m]=c.compile(k,{data:q!==e});return n[m](o,l)}}}}};c.template=c.VM.template})(Handlebars);
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/helpers-common-templates.js
--- a/static/scripts/packed/templates/compiled/helpers-common-templates.js
+++ b/static/scripts/packed/templates/compiled/helpers-common-templates.js
@@ -1,1 +1,1 @@
-Handlebars.registerPartial("clearFloatDiv",function(a){return'<div class="clear"></div>'});Handlebars.registerHelper("warningmessagesmall",function(a){return'<div class="warningmessagesmall"><strong>'+a.fn(this)+"</strong></div>"});Handlebars.registerHelper("local",function(a){return _l(a.fn(this))});Handlebars.registerPartial("iconButton",function(c,b){var a="";a+=(c.enabled)?("<a"):("<span");if(c.title){a+=' title="'+c.title+'"'}a+=' class="icon-button';if(c.isMenuButton){a+=" menu-button"}if(c.title){a+=" tooltip"}a+=" "+c.icon_class;if(!c.enabled){a+="_disabled"}a+='"';if(c.id){a+=' id="'+c.id+'"'}a+=' href="'+((c.href)?(c.href):("javascript:void(0);"))+'"';if(c.target){a+=' target="'+c.target+'"'}if(!c.visible){a+=' style="display: none;"'}a+=">"+((c.enabled)?("</a>"):("</span>"));return a});
\ No newline at end of file
+Handlebars.registerPartial("clearFloatDiv",function(a){return'<div class="clear"></div>'});Handlebars.registerHelper("warningmessagesmall",function(a){return'<div class="warningmessagesmall"><strong>'+a.fn(this)+"</strong></div>"});Handlebars.registerHelper("local",function(a){return _l(a.fn(this))});
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/panel_section.js
--- a/static/scripts/packed/templates/compiled/panel_section.js
+++ b/static/scripts/packed/templates/compiled/panel_section.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.panel_section=b(function(e,k,d,j,i){this.compilerInfo=[2,">= 1.0.0-rc.3"];d=d||e.helpers;i=i||{};var g="",c,f="function",h=this.escapeExpression;g+='<div class="toolSectionTitle" id="title_';if(c=d.id){c=c.call(k,{hash:{},data:i})}else{c=k.id;c=typeof c===f?c.apply(k):c}g+=h(c)+'">\n <a href="javascript:void(0)"><span>';if(c=d.name){c=c.call(k,{hash:{},data:i})}else{c=k.name;c=typeof c===f?c.apply(k):c}g+=h(c)+'</span></a>\n</div>\n<div id="';if(c=d.id){c=c.call(k,{hash:{},data:i})}else{c=k.id;c=typeof c===f?c.apply(k):c}g+=h(c)+'" class="toolSectionBody" style="display: none; ">\n <div class="toolSectionBg"></div>\n<div>';return g})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.panel_section=b(function(e,k,d,j,i){this.compilerInfo=[4,">= 1.0.0"];d=this.merge(d,e.helpers);i=i||{};var g="",c,f="function",h=this.escapeExpression;g+='<div class="toolSectionTitle" id="title_';if(c=d.id){c=c.call(k,{hash:{},data:i})}else{c=k.id;c=typeof c===f?c.apply(k):c}g+=h(c)+'">\n <a href="javascript:void(0)"><span>';if(c=d.name){c=c.call(k,{hash:{},data:i})}else{c=k.name;c=typeof c===f?c.apply(k):c}g+=h(c)+'</span></a>\n</div>\n<div id="';if(c=d.id){c=c.call(k,{hash:{},data:i})}else{c=k.id;c=typeof c===f?c.apply(k):c}g+=h(c)+'" class="toolSectionBody" style="display: none; ">\n <div class="toolSectionBg"></div>\n<div>';return g})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-hda-annotationArea.js
--- a/static/scripts/packed/templates/compiled/template-hda-annotationArea.js
+++ b/static/scripts/packed/templates/compiled/template-hda-annotationArea.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-annotationArea"]=b(function(g,q,f,o,n){f=f||g.helpers;var l="",d,k,j,s=this,h="function",p=f.helperMissing,i=void 0,m=this.escapeExpression,r=f.blockHelperMissing;function e(u,t){return"Annotation"}function c(u,t){return"Edit dataset annotation"}l+='\n<div id="';k=f.id;d=k||q.id;if(typeof d===h){d=d.call(q,{hash:{}})}else{if(d===i){d=p.call(q,"id",{hash:{}})}}l+=m(d)+'-annotation-area" class="annotation-area" style="display: none;">\n <strong>';k=f.local;d=k||q.local;j=s.program(1,e,n);j.hash={};j.fn=j;j.inverse=s.noop;if(k&&typeof d===h){d=d.call(q,j)}else{d=r.call(q,d,j)}if(d||d===0){l+=d}l+=':</strong>\n <div id="';k=f.id;d=k||q.id;if(typeof d===h){d=d.call(q,{hash:{}})}else{if(d===i){d=p.call(q,"id",{hash:{}})}}l+=m(d)+'-anotation-elt" class="annotation-elt tooltip editable-text"\n style="margin: 1px 0px 1px 0px" title="';k=f.local;d=k||q.local;j=s.program(3,c,n);j.hash={};j.fn=j;j.inverse=s.noop;if(k&&typeof d===h){d=d.call(q,j)}else{d=r.call(q,d,j)}if(d||d===0){l+=d}l+='">\n </div>\n</div>';return l})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-annotationArea"]=b(function(g,m,f,l,k){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);k=k||{};var i="",d,p,h="function",j=this.escapeExpression,o=this,n=f.blockHelperMissing;function e(r,q){return"Annotation"}function c(r,q){return"Edit dataset annotation"}i+='\n<div id="';if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+'-annotation-area" class="annotation-area" style="display: none;">\n <strong>';p={hash:{},inverse:o.noop,fn:o.program(1,e,k),data:k};if(d=f.local){d=d.call(m,p)}else{d=m.local;d=typeof d===h?d.apply(m):d}if(!f.local){d=n.call(m,d,p)}if(d||d===0){i+=d}i+=':</strong>\n <div id="';if(d=f.id){d=d.call(m,{hash:{},data:k})}else{d=m.id;d=typeof d===h?d.apply(m):d}i+=j(d)+'-anotation-elt" class="annotation-elt tooltip editable-text"\n style="margin: 1px 0px 1px 0px" title="';p={hash:{},inverse:o.noop,fn:o.program(3,c,k),data:k};if(d=f.local){d=d.call(m,p)}else{d=m.local;d=typeof d===h?d.apply(m):d}if(!f.local){d=n.call(m,d,p)}if(d||d===0){i+=d}i+='">\n </div>\n</div>';return i})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-hda-displayApps.js
--- a/static/scripts/packed/templates/compiled/template-hda-displayApps.js
+++ b/static/scripts/packed/templates/compiled/template-hda-displayApps.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-displayApps"]=b(function(h,s,r,k,t){r=r||h.helpers;var j,g,i,p,o=this,f="function",q=r.helperMissing,d=void 0,e=this.escapeExpression,c=r.blockHelperMissing;function n(y,x){var u="",w,v;u+="\n ";i=r.label;w=i||y.label;if(typeof w===f){w=w.call(y,{hash:{}})}else{if(w===d){w=q.call(y,"label",{hash:{}})}}u+=e(w)+"\n ";i=r.links;w=i||y.links;v=r.each;p=o.program(2,m,x);p.hash={};p.fn=p;p.inverse=o.noop;w=v.call(y,w,p);if(w||w===0){u+=w}u+="\n <br />\n";return u}function m(x,w){var u="",v;u+='\n <a target="';i=r.target;v=i||x.target;if(typeof v===f){v=v.call(x,{hash:{}})}else{if(v===d){v=q.call(x,"target",{hash:{}})}}u+=e(v)+'" href="';i=r.href;v=i||x.href;if(typeof v===f){v=v.call(x,{hash:{}})}else{if(v===d){v=q.call(x,"href",{hash:{}})}}u+=e(v)+'">';i=r.local;v=i||x.local;p=o.program(3,l,w);p.hash={};p.fn=p;p.inverse=o.noop;if(i&&typeof v===f){v=v.call(x,p)}else{v=c.call(x,v,p)}if(v||v===0){u+=v}u+="</a>\n ";return u}function l(w,v){var u;i=r.text;u=i||w.text;if(typeof u===f){u=u.call(w,{hash:{}})}else{if(u===d){u=q.call(w,"text",{hash:{}})}}return e(u)}i=r.displayApps;j=i||s.displayApps;g=r.each;p=o.program(1,n,t);p.hash={};p.fn=p;p.inverse=o.noop;j=g.call(s,j,p);if(j||j===0){return j}else{return""}})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-displayApps"]=b(function(h,m,g,l,k){this.compilerInfo=[4,">= 1.0.0"];g=this.merge(g,h.helpers);k=k||{};var d,i="function",j=this.escapeExpression,o=this,n=g.blockHelperMissing;function f(s,r){var p="",q;p+="\n ";if(q=g.label){q=q.call(s,{hash:{},data:r})}else{q=s.label;q=typeof q===i?q.apply(s):q}p+=j(q)+"\n ";q=g.each.call(s,s.links,{hash:{},inverse:o.noop,fn:o.program(2,e,r),data:r});if(q||q===0){p+=q}p+="\n <br />\n";return p}function e(t,s){var p="",r,q;p+='\n <a target="';if(r=g.target){r=r.call(t,{hash:{},data:s})}else{r=t.target;r=typeof r===i?r.apply(t):r}p+=j(r)+'" href="';if(r=g.href){r=r.call(t,{hash:{},data:s})}else{r=t.href;r=typeof r===i?r.apply(t):r}p+=j(r)+'">';q={hash:{},inverse:o.noop,fn:o.program(3,c,s),data:s};if(r=g.local){r=r.call(t,q)}else{r=t.local;r=typeof r===i?r.apply(t):r}if(!g.local){r=n.call(t,r,q)}if(r||r===0){p+=r}p+="</a>\n ";return p}function c(r,q){var p;if(p=g.text){p=p.call(r,{hash:{},data:q})}else{p=r.text;p=typeof p===i?p.apply(r):p}return j(p)}d=g.each.call(m,m.displayApps,{hash:{},inverse:o.noop,fn:o.program(1,f,k),data:k});if(d||d===0){return d}else{return""}})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-hda-downloadLinks.js
--- a/static/scripts/packed/templates/compiled/template-hda-downloadLinks.js
+++ b/static/scripts/packed/templates/compiled/template-hda-downloadLinks.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-downloadLinks"]=b(function(i,v,u,n,y){u=u||i.helpers;var k,h,j,s,r=this,f="function",t=u.helperMissing,d=void 0,e=this.escapeExpression,c=u.blockHelperMissing;function q(D,C){var z="",B,A;z+='\n<div popupmenu="dataset-';j=u.id;B=j||D.id;if(typeof B===f){B=B.call(D,{hash:{}})}else{if(B===d){B=t.call(D,"id",{hash:{}})}}z+=e(B)+'-popup">\n <a class="action-button" href="';j=u.urls;B=j||D.urls;B=(B===null||B===undefined||B===false?B:B.download);if(typeof B===f){B=B.call(D,{hash:{}})}else{if(B===d){B=t.call(D,"urls.download",{hash:{}})}}z+=e(B)+'">';j=u.local;B=j||D.local;s=r.program(2,p,C);s.hash={};s.fn=s;s.inverse=r.noop;if(j&&typeof B===f){B=B.call(D,s)}else{B=c.call(D,B,s)}if(B||B===0){z+=B}z+="</a>\n <a>";j=u.local;B=j||D.local;s=r.program(4,o,C);s.hash={};s.fn=s;s.inverse=r.noop;if(j&&typeof B===f){B=B.call(D,s)}else{B=c.call(D,B,s)}if(B||B===0){z+=B}z+="</a>\n ";j=u.urls;B=j||D.urls;B=(B===null||B===undefined||B===false?B:B.meta_download);A=u.each;s=r.program(6,m,C);s.hash={};s.fn=s;s.inverse=r.noop;B=A.call(D,B,s);if(B||B===0){z+=B}z+='\n</div>\n<div style="float:left;" class="menubutton split popup" id="dataset-';j=u.id;B=j||D.id;if(typeof B===f){B=B.call(D,{hash:{}})}else{if(B===d){B=t.call(D,"id",{hash:{}})}}z+=e(B)+'-popup">\n <a href="';j=u.urls;B=j||D.urls;B=(B===null||B===undefined||B===false?B:B.download);if(typeof B===f){B=B.call(D,{hash:{}})}else{if(B===d){B=t.call(D,"urls.download",{hash:{}})}}z+=e(B)+'" title="';j=u.local;B=j||D.local;s=r.program(9,g,C);s.hash={};s.fn=s;s.inverse=r.noop;if(j&&typeof B===f){B=B.call(D,s)}else{B=c.call(D,B,s)}if(B||B===0){z+=B}z+='" class="icon-button disk tooltip"></a>\n</div>\n';return z}function p(A,z){return"Download Dataset"}function o(A,z){return"Additional Files"}function m(C,B){var z="",A;z+='\n <a class="action-button" href="';j=u.url;A=j||C.url;if(typeof A===f){A=A.call(C,{hash:{}})}else{if(A===d){A=t.call(C,"url",{hash:{}})}}z+=e(A)+'">';j=u.local;A=j||C.local;s=r.program(7,l,B);s.hash={};s.fn=s;s.inverse=r.noop;if(j&&typeof A===f){A=A.call(C,s)}else{A=c.call(C,A,s)}if(A||A===0){z+=A}z+=" ";j=u.file_type;A=j||C.file_type;if(typeof A===f){A=A.call(C,{hash:{}})}else{if(A===d){A=t.call(C,"file_type",{hash:{}})}}z+=e(A)+"</a>\n ";return z}function l(A,z){return"Download"}function g(A,z){return"Download"}function x(C,B){var z="",A;z+="\n";z+='\n<a href="';j=u.urls;A=j||C.urls;A=(A===null||A===undefined||A===false?A:A.download);if(typeof A===f){A=A.call(C,{hash:{}})}else{if(A===d){A=t.call(C,"urls.download",{hash:{}})}}z+=e(A)+'" title="';j=u.local;A=j||C.local;s=r.program(12,w,B);s.hash={};s.fn=s;s.inverse=r.noop;if(j&&typeof A===f){A=A.call(C,s)}else{A=c.call(C,A,s)}if(A||A===0){z+=A}z+='" class="icon-button disk tooltip"></a>\n';return z}function w(A,z){return"Download"}j=u.urls;k=j||v.urls;k=(k===null||k===undefined||k===false?k:k.meta_download);h=u["if"];s=r.program(1,q,y);s.hash={};s.fn=s;s.inverse=r.program(11,x,y);k=h.call(v,k,s);if(k||k===0){return k}else{return""}})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-downloadLinks"]=b(function(g,l,f,k,j){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);j=j||{};var c,s,h="function",i=this.escapeExpression,q=this,m=f.blockHelperMissing;function e(y,x){var t="",w,v,u;t+='\n<div popupmenu="dataset-';if(w=f.id){w=w.call(y,{hash:{},data:x})}else{w=y.id;w=typeof w===h?w.apply(y):w}t+=i(w)+'-popup">\n <a class="action-button" href="'+i(((w=((w=y.urls),w==null||w===false?w:w.download)),typeof w===h?w.apply(y):w))+'">';u={hash:{},inverse:q.noop,fn:q.program(2,d,x),data:x};if(v=f.local){v=v.call(y,u)}else{v=y.local;v=typeof v===h?v.apply(y):v}if(!f.local){v=m.call(y,v,u)}if(v||v===0){t+=v}t+="</a>\n <a>";u={hash:{},inverse:q.noop,fn:q.program(4,r,x),data:x};if(v=f.local){v=v.call(y,u)}else{v=y.local;v=typeof v===h?v.apply(y):v}if(!f.local){v=m.call(y,v,u)}if(v||v===0){t+=v}t+="</a>\n ";v=f.each.call(y,((w=y.urls),w==null||w===false?w:w.meta_download),{hash:{},inverse:q.noop,fn:q.program(6,p,x),data:x});if(v||v===0){t+=v}t+='\n</div>\n<div style="float:left;" class="menubutton split popup" id="dataset-';if(v=f.id){v=v.call(y,{hash:{},data:x})}else{v=y.id;v=typeof v===h?v.apply(y):v}t+=i(v)+'-popup">\n <a href="'+i(((w=((w=y.urls),w==null||w===false?w:w.download)),typeof w===h?w.apply(y):w))+'" title="';u={hash:{},inverse:q.noop,fn:q.program(7,o,x),data:x};if(v=f.local){v=v.call(y,u)}else{v=y.local;v=typeof v===h?v.apply(y):v}if(!f.local){v=m.call(y,v,u)}if(v||v===0){t+=v}t+='" class="icon-button disk tooltip"></a>\n</div>\n';return t}function d(u,t){return"Download Dataset"}function r(u,t){return"Additional Files"}function p(x,w){var t="",v,u;t+='\n <a class="action-button" href="';if(v=f.url){v=v.call(x,{hash:{},data:w})}else{v=x.url;v=typeof v===h?v.apply(x):v}t+=i(v)+'">';u={hash:{},inverse:q.noop,fn:q.program(7,o,w),data:w};if(v=f.local){v=v.call(x,u)}else{v=x.local;v=typeof v===h?v.apply(x):v}if(!f.local){v=m.call(x,v,u)}if(v||v===0){t+=v}t+=" ";if(v=f.file_type){v=v.call(x,{hash:{},data:w})}else{v=x.file_type;v=typeof v===h?v.apply(x):v}t+=i(v)+"</a>\n ";return t}function o(u,t){return"Download"}function n(y,x){var t="",w,v,u;t+='\n\n<a href="'+i(((w=((w=y.urls),w==null||w===false?w:w.download)),typeof w===h?w.apply(y):w))+'" title="';u={hash:{},inverse:q.noop,fn:q.program(7,o,x),data:x};if(v=f.local){v=v.call(y,u)}else{v=y.local;v=typeof v===h?v.apply(y):v}if(!f.local){v=m.call(y,v,u)}if(v||v===0){t+=v}t+='" class="icon-button disk tooltip"></a>\n';return t}s=f["if"].call(l,((c=l.urls),c==null||c===false?c:c.meta_download),{hash:{},inverse:q.program(9,n,j),fn:q.program(1,e,j),data:j});if(s||s===0){return s}else{return""}})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-hda-failedMetadata.js
--- a/static/scripts/packed/templates/compiled/template-hda-failedMetadata.js
+++ b/static/scripts/packed/templates/compiled/template-hda-failedMetadata.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-failedMetadata"]=b(function(g,p,f,n,m){f=f||g.helpers;var c,k,j,r=this,h="function",q=f.blockHelperMissing,o=f.helperMissing,i=void 0,l=this.escapeExpression;function e(v,u){var s="",t;s+="\n";k=f.local;t=k||v.local;j=r.program(2,d,u);j.hash={};j.fn=j;j.inverse=r.noop;if(k&&typeof t===h){t=t.call(v,j)}else{t=q.call(v,t,j)}if(t||t===0){s+=t}s+='\nYou may be able to <a href="';k=f.urls;t=k||v.urls;t=(t===null||t===undefined||t===false?t:t.edit);if(typeof t===h){t=t.call(v,{hash:{}})}else{if(t===i){t=o.call(v,"urls.edit",{hash:{}})}}s+=l(t)+'" target="galaxy_main">set it manually or retry auto-detection</a>.\n';return s}function d(t,s){return"An error occurred setting the metadata for this dataset."}k=f.warningmessagesmall;c=k||p.warningmessagesmall;j=r.program(1,e,m);j.hash={};j.fn=j;j.inverse=r.noop;if(k&&typeof c===h){c=c.call(p,j)}else{c=q.call(p,c,j)}if(c||c===0){return c}else{return""}})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-failedMetadata"]=b(function(g,l,f,k,j){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);j=j||{};var c,o,n=this,h="function",m=f.blockHelperMissing,i=this.escapeExpression;function e(t,s){var p="",r,q;p+="\n";q={hash:{},inverse:n.noop,fn:n.program(2,d,s),data:s};if(r=f.local){r=r.call(t,q)}else{r=t.local;r=typeof r===h?r.apply(t):r}if(!f.local){r=m.call(t,r,q)}if(r||r===0){p+=r}p+='\nYou may be able to <a href="'+i(((r=((r=t.urls),r==null||r===false?r:r.edit)),typeof r===h?r.apply(t):r))+'" target="galaxy_main">set it manually or retry auto-detection</a>.\n';return p}function d(q,p){return"An error occurred setting the metadata for this dataset."}o={hash:{},inverse:n.noop,fn:n.program(1,e,j),data:j};if(c=f.warningmessagesmall){c=c.call(l,o)}else{c=l.warningmessagesmall;c=typeof c===h?c.apply(l):c}if(!f.warningmessagesmall){c=m.call(l,c,o)}if(c||c===0){return c}else{return""}})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-hda-hdaSummary.js
--- a/static/scripts/packed/templates/compiled/template-hda-hdaSummary.js
+++ b/static/scripts/packed/templates/compiled/template-hda-hdaSummary.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-hdaSummary"]=b(function(i,v,t,n,w){t=t||i.helpers;var u="",k,h,j,r,q=this,f="function",s=t.helperMissing,d=void 0,e=this.escapeExpression,c=t.blockHelperMissing;function p(y,x){return"format: "}function o(y,x){return"database: "}function m(A,z){var x="",y;x+='\n <a class="metadata-dbkey" href="';j=t.urls;y=j||A.urls;y=(y===null||y===undefined||y===false?y:y.edit);if(typeof y===f){y=y.call(A,{hash:{}})}else{if(y===d){y=s.call(A,"urls.edit",{hash:{}})}}x+=e(y)+'" target="galaxy_main">';j=t.metadata_dbkey;y=j||A.metadata_dbkey;if(typeof y===f){y=y.call(A,{hash:{}})}else{if(y===d){y=s.call(A,"metadata_dbkey",{hash:{}})}}x+=e(y)+"</a>\n ";return x}function l(A,z){var x="",y;x+='\n <span class="metadata-dbkey ';j=t.metadata_dbkey;y=j||A.metadata_dbkey;if(typeof y===f){y=y.call(A,{hash:{}})}else{if(y===d){y=s.call(A,"metadata_dbkey",{hash:{}})}}x+=e(y)+'">';j=t.metadata_dbkey;y=j||A.metadata_dbkey;if(typeof y===f){y=y.call(A,{hash:{}})}else{if(y===d){y=s.call(A,"metadata_dbkey",{hash:{}})}}x+=e(y)+"</span>\n ";return x}function g(A,z){var x="",y;x+='\n<div class="hda-info"> ';j=t.misc_info;y=j||A.misc_info;if(typeof y===f){y=y.call(A,{hash:{}})}else{if(y===d){y=s.call(A,"misc_info",{hash:{}})}}x+=e(y)+" </div>\n";return x}u+='<div class="hda-summary">\n ';j=t.misc_blurb;k=j||v.misc_blurb;if(typeof k===f){k=k.call(v,{hash:{}})}else{if(k===d){k=s.call(v,"misc_blurb",{hash:{}})}}u+=e(k)+"<br />\n ";j=t.local;k=j||v.local;r=q.program(1,p,w);r.hash={};r.fn=r;r.inverse=q.noop;if(j&&typeof k===f){k=k.call(v,r)}else{k=c.call(v,k,r)}if(k||k===0){u+=k}u+='<span class="';j=t.data_type;k=j||v.data_type;if(typeof k===f){k=k.call(v,{hash:{}})}else{if(k===d){k=s.call(v,"data_type",{hash:{}})}}u+=e(k)+'">';j=t.data_type;k=j||v.data_type;if(typeof k===f){k=k.call(v,{hash:{}})}else{if(k===d){k=s.call(v,"data_type",{hash:{}})}}u+=e(k)+"</span>,\n ";j=t.local;k=j||v.local;r=q.program(3,o,w);r.hash={};r.fn=r;r.inverse=q.noop;if(j&&typeof k===f){k=k.call(v,r)}else{k=c.call(v,k,r)}if(k||k===0){u+=k}u+="\n ";j=t.dbkey_unknown_and_editable;k=j||v.dbkey_unknown_and_editable;h=t["if"];r=q.program(5,m,w);r.hash={};r.fn=r;r.inverse=q.program(7,l,w);k=h.call(v,k,r);if(k||k===0){u+=k}u+="\n</div>\n";j=t.misc_info;k=j||v.misc_info;h=t["if"];r=q.program(9,g,w);r.hash={};r.fn=r;r.inverse=q.noop;k=h.call(v,k,r);if(k||k===0){u+=k}return u})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-hdaSummary"]=b(function(g,m,f,l,k){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);k=k||{};var i="",d,s,h="function",j=this.escapeExpression,r=this,n=f.blockHelperMissing;function e(u,t){return"format: "}function c(u,t){return"database: "}function q(x,w){var t="",v,u;t+='\n <a class="metadata-dbkey" href="'+j(((v=((v=x.urls),v==null||v===false?v:v.edit)),typeof v===h?v.apply(x):v))+'" target="galaxy_main">';if(u=f.metadata_dbkey){u=u.call(x,{hash:{},data:w})}else{u=x.metadata_dbkey;u=typeof u===h?u.apply(x):u}t+=j(u)+"</a>\n ";return t}function p(w,v){var t="",u;t+='\n <span class="metadata-dbkey ';if(u=f.metadata_dbkey){u=u.call(w,{hash:{},data:v})}else{u=w.metadata_dbkey;u=typeof u===h?u.apply(w):u}t+=j(u)+'">';if(u=f.metadata_dbkey){u=u.call(w,{hash:{},data:v})}else{u=w.metadata_dbkey;u=typeof u===h?u.apply(w):u}t+=j(u)+"</span>\n ";return t}function o(w,v){var t="",u;t+='\n<div class="hda-info"> ';if(u=f.misc_info){u=u.call(w,{hash:{},data:v})}else{u=w.misc_info;u=typeof u===h?u.apply(w):u}t+=j(u)+" </div>\n";return t}i+='<div class="hda-summary">\n ';if(d=f.misc_blurb){d=d.call(m,{hash:{},data:k})}else{d=m.misc_blurb;d=typeof d===h?d.apply(m):d}i+=j(d)+"<br />\n ";s={hash:{},inverse:r.noop,fn:r.program(1,e,k),data:k};if(d=f.local){d=d.call(m,s)}else{d=m.local;d=typeof d===h?d.apply(m):d}if(!f.local){d=n.call(m,d,s)}if(d||d===0){i+=d}i+='<span class="';if(d=f.data_type){d=d.call(m,{hash:{},data:k})}else{d=m.data_type;d=typeof d===h?d.apply(m):d}i+=j(d)+'">';if(d=f.data_type){d=d.call(m,{hash:{},data:k})}else{d=m.data_type;d=typeof d===h?d.apply(m):d}i+=j(d)+"</span>,\n ";s={hash:{},inverse:r.noop,fn:r.program(3,c,k),data:k};if(d=f.local){d=d.call(m,s)}else{d=m.local;d=typeof d===h?d.apply(m):d}if(!f.local){d=n.call(m,d,s)}if(d||d===0){i+=d}i+="\n ";d=f["if"].call(m,m.dbkey_unknown_and_editable,{hash:{},inverse:r.program(7,p,k),fn:r.program(5,q,k),data:k});if(d||d===0){i+=d}i+="\n</div>\n";d=f["if"].call(m,m.misc_info,{hash:{},inverse:r.noop,fn:r.program(9,o,k),data:k});if(d||d===0){i+=d}return i})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-hda-tagArea.js
--- a/static/scripts/packed/templates/compiled/template-hda-tagArea.js
+++ b/static/scripts/packed/templates/compiled/template-hda-tagArea.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-tagArea"]=b(function(f,m,e,l,k){e=e||f.helpers;var j="",c,i,h,o=this,g="function",n=e.blockHelperMissing;function d(q,p){return"Tags"}j+='\n<div class="tag-area" style="display: none;">\n <strong>';i=e.local;c=i||m.local;h=o.program(1,d,k);h.hash={};h.fn=h;h.inverse=o.noop;if(i&&typeof c===g){c=c.call(m,h)}else{c=n.call(m,c,h)}if(c||c===0){j+=c}j+=':</strong>\n <div class="tag-elt">\n </div>\n</div>';return j})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-tagArea"]=b(function(f,k,e,j,i){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,f.helpers);i=i||{};var h="",c,n,m=this,g="function",l=e.blockHelperMissing;function d(p,o){return"Tags"}h+='\n<div class="tag-area" style="display: none;">\n <strong>';n={hash:{},inverse:m.noop,fn:m.program(1,d,i),data:i};if(c=e.local){c=c.call(k,n)}else{c=k.local;c=typeof c===g?c.apply(k):c}if(!e.local){c=l.call(k,c,n)}if(c||c===0){h+=c}h+=':</strong>\n <div class="tag-elt">\n </div>\n</div>';return h})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-hda-titleLink.js
--- a/static/scripts/packed/templates/compiled/template-hda-titleLink.js
+++ b/static/scripts/packed/templates/compiled/template-hda-titleLink.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-titleLink"]=b(function(e,n,d,l,k){d=d||e.helpers;var i="",c,h,o=this,f="function",m=d.helperMissing,g=void 0,j=this.escapeExpression;i+='<span class="historyItemTitle">';h=d.hid;c=h||n.hid;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"hid",{hash:{}})}}i+=j(c)+": ";h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+"</span>";return i})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-titleLink"]=b(function(e,k,d,j,i){this.compilerInfo=[4,">= 1.0.0"];d=this.merge(d,e.helpers);i=i||{};var g="",c,f="function",h=this.escapeExpression;g+='<span class="historyItemTitle">';if(c=d.hid){c=c.call(k,{hash:{},data:i})}else{c=k.hid;c=typeof c===f?c.apply(k):c}g+=h(c)+": ";if(c=d.name){c=c.call(k,{hash:{},data:i})}else{c=k.name;c=typeof c===f?c.apply(k):c}g+=h(c)+"</span>";return g})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-hda-warning-messages.js
--- a/static/scripts/packed/templates/compiled/template-hda-warning-messages.js
+++ b/static/scripts/packed/templates/compiled/template-hda-warning-messages.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-warning-messages"]=b(function(j,z,x,q,H){x=x||j.helpers;var y="",m,i,l,v,u=this,f="function",w=x.helperMissing,d=void 0,e=this.escapeExpression,c=x.blockHelperMissing;function t(L,K){var I="",J;I+='\n<div class="errormessagesmall">\n ';l=x.local;J=l||L.local;v=u.program(2,s,K);v.hash={};v.fn=v;v.inverse=u.noop;if(l&&typeof J===f){J=J.call(L,v)}else{J=c.call(L,J,v)}if(J||J===0){I+=J}I+=":\n ";l=x.local;J=l||L.local;v=u.program(4,r,K);v.hash={};v.fn=v;v.inverse=u.noop;if(l&&typeof J===f){J=J.call(L,v)}else{J=c.call(L,J,v)}if(J||J===0){I+=J}I+="\n</div>\n";return I}function s(J,I){return"There was an error getting the data for this dataset"}function r(K,J){var I;l=x.error;I=l||K.error;if(typeof I===f){I=I.call(K,{hash:{}})}else{if(I===d){I=w.call(K,"error",{hash:{}})}}return e(I)}function p(L,K){var J,I;l=x.purged;J=l||L.purged;I=x.unless;v=u.program(7,o,K);v.hash={};v.fn=v;v.inverse=u.noop;J=I.call(L,J,v);if(J||J===0){return J}else{return""}}function o(L,K){var I="",J;I+="\n";l=x.warningmessagesmall;J=l||L.warningmessagesmall;v=u.program(8,k,K);v.hash={};v.fn=v;v.inverse=u.noop;if(l&&typeof J===f){J=J.call(L,v)}else{J=c.call(L,J,v)}if(J||J===0){I+=J}I+="\n";return I}function k(M,L){var I="",K,J;I+="\n ";l=x.local;K=l||M.local;v=u.program(9,h,L);v.hash={};v.fn=v;v.inverse=u.noop;if(l&&typeof K===f){K=K.call(M,v)}else{K=c.call(M,K,v)}if(K||K===0){I+=K}I+="\n ";l=x.urls;K=l||M.urls;K=(K===null||K===undefined||K===false?K:K.undelete);J=x["if"];v=u.program(11,G,L);v.hash={};v.fn=v;v.inverse=u.noop;K=J.call(M,K,v);if(K||K===0){I+=K}I+="\n";return I}function h(J,I){return"This dataset has been deleted."}function G(M,L){var I="",K,J;I+="\n ";I+='\n Click <a href="';l=x.urls;K=l||M.urls;K=(K===null||K===undefined||K===false?K:K.undelete);if(typeof K===f){K=K.call(M,{hash:{}})}else{if(K===d){K=w.call(M,"urls.undelete",{hash:{}})}}I+=e(K)+'" class="historyItemUndelete" id="historyItemUndeleter-';l=x.id;K=l||M.id;if(typeof K===f){K=K.call(M,{hash:{}})}else{if(K===d){K=w.call(M,"id",{hash:{}})}}I+=e(K)+'"\n target="galaxy_history">here</a> to undelete it\n ';l=x.urls;K=l||M.urls;K=(K===null||K===undefined||K===false?K:K.purge);J=x["if"];v=u.program(12,F,L);v.hash={};v.fn=v;v.inverse=u.noop;K=J.call(M,K,v);if(K||K===0){I+=K}I+="\n ";return I}function F(L,K){var I="",J;I+='\n or <a href="';l=x.urls;J=l||L.urls;J=(J===null||J===undefined||J===false?J:J.purge);if(typeof J===f){J=J.call(L,{hash:{}})}else{if(J===d){J=w.call(L,"urls.purge",{hash:{}})}}I+=e(J)+'" class="historyItemPurge" id="historyItemPurger-';l=x.id;J=l||L.id;if(typeof J===f){J=J.call(L,{hash:{}})}else{if(J===d){J=w.call(L,"id",{hash:{}})}}I+=e(J)+'"\n target="galaxy_history">here</a> to immediately remove it from disk\n ';return I}function E(K,J){var I;l=x.warningmessagesmall;I=l||K.warningmessagesmall;v=u.program(15,D,J);v.hash={};v.fn=v;v.inverse=u.noop;if(l&&typeof I===f){I=I.call(K,v)}else{I=c.call(K,I,v)}if(I||I===0){return I}else{return""}}function D(L,K){var I="",J;I+="\n ";l=x.local;J=l||L.local;v=u.program(16,C,K);v.hash={};v.fn=v;v.inverse=u.noop;if(l&&typeof J===f){J=J.call(L,v)}else{J=c.call(L,J,v)}if(J||J===0){I+=J}I+="\n";return I}function C(J,I){return"This dataset has been deleted and removed from disk."}function B(K,J){var I;l=x.warningmessagesmall;I=l||K.warningmessagesmall;v=u.program(19,A,J);v.hash={};v.fn=v;v.inverse=u.noop;if(l&&typeof I===f){I=I.call(K,v)}else{I=c.call(K,I,v)}if(I||I===0){return I}else{return""}}function A(M,L){var I="",K,J;I+="\n ";l=x.local;K=l||M.local;v=u.program(20,n,L);v.hash={};v.fn=v;v.inverse=u.noop;if(l&&typeof K===f){K=K.call(M,v)}else{K=c.call(M,K,v)}if(K||K===0){I+=K}I+="\n ";l=x.urls;K=l||M.urls;K=(K===null||K===undefined||K===false?K:K.unhide);J=x["if"];v=u.program(22,g,L);v.hash={};v.fn=v;v.inverse=u.noop;K=J.call(M,K,v);if(K||K===0){I+=K}I+="\n";return I}function n(J,I){return"This dataset has been hidden."}function g(L,K){var I="",J;I+='\n Click <a href="';l=x.urls;J=l||L.urls;J=(J===null||J===undefined||J===false?J:J.unhide);if(typeof J===f){J=J.call(L,{hash:{}})}else{if(J===d){J=w.call(L,"urls.unhide",{hash:{}})}}I+=e(J)+'" class="historyItemUnhide" id="historyItemUnhider-';l=x.id;J=l||L.id;if(typeof J===f){J=J.call(L,{hash:{}})}else{if(J===d){J=w.call(L,"id",{hash:{}})}}I+=e(J)+'"\n target="galaxy_history">here</a> to unhide it\n ';return I}l=x.error;m=l||z.error;i=x["if"];v=u.program(1,t,H);v.hash={};v.fn=v;v.inverse=u.noop;m=i.call(z,m,v);if(m||m===0){y+=m}y+="\n\n";l=x.deleted;m=l||z.deleted;i=x["if"];v=u.program(6,p,H);v.hash={};v.fn=v;v.inverse=u.noop;m=i.call(z,m,v);if(m||m===0){y+=m}y+="\n\n";l=x.purged;m=l||z.purged;i=x["if"];v=u.program(14,E,H);v.hash={};v.fn=v;v.inverse=u.noop;m=i.call(z,m,v);if(m||m===0){y+=m}y+="\n\n";l=x.visible;m=l||z.visible;i=x.unless;v=u.program(18,B,H);v.hash={};v.fn=v;v.inverse=u.noop;m=i.call(z,m,v);if(m||m===0){y+=m}return y})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-warning-messages"]=b(function(h,u,s,n,C){this.compilerInfo=[4,">= 1.0.0"];s=this.merge(s,h.helpers);C=C||{};var t="",j,e="function",d=this.escapeExpression,r=this,c=s.blockHelperMissing;function q(H,G){var D="",F,E;D+='\n<div class="errormessagesmall">\n ';E={hash:{},inverse:r.noop,fn:r.program(2,p,G),data:G};if(F=s.local){F=F.call(H,E)}else{F=H.local;F=typeof F===e?F.apply(H):F}if(!s.local){F=c.call(H,F,E)}if(F||F===0){D+=F}D+=":\n ";E={hash:{},inverse:r.noop,fn:r.program(4,o,G),data:G};if(F=s.local){F=F.call(H,E)}else{F=H.local;F=typeof F===e?F.apply(H):F}if(!s.local){F=c.call(H,F,E)}if(F||F===0){D+=F}D+="\n</div>\n";return D}function p(E,D){return"There was an error getting the data for this dataset"}function o(F,E){var D;if(D=s.error){D=D.call(F,{hash:{},data:E})}else{D=F.error;D=typeof D===e?D.apply(F):D}return d(D)}function m(F,E){var D;D=s.unless.call(F,F.purged,{hash:{},inverse:r.noop,fn:r.program(7,l,E),data:E});if(D||D===0){return D}else{return""}}function l(H,G){var D="",F,E;D+="\n";E={hash:{},inverse:r.noop,fn:r.program(8,i,G),data:G};if(F=s.warningmessagesmall){F=F.call(H,E)}else{F=H.warningmessagesmall;F=typeof F===e?F.apply(H):F}if(!s.warningmessagesmall){F=c.call(H,F,E)}if(F||F===0){D+=F}D+="\n";return D}function i(I,H){var D="",G,F,E;D+="\n ";E={hash:{},inverse:r.noop,fn:r.program(9,g,H),data:H};if(G=s.local){G=G.call(I,E)}else{G=I.local;G=typeof G===e?G.apply(I):G}if(!s.local){G=c.call(I,G,E)}if(G||G===0){D+=G}D+="\n ";F=s["if"].call(I,((G=I.urls),G==null||G===false?G:G.undelete),{hash:{},inverse:r.noop,fn:r.program(11,B,H),data:H});if(F||F===0){D+=F}D+="\n";return D}function g(E,D){return"This dataset has been deleted."}function B(H,G){var D="",F,E;D+='\n \n Click <a href="'+d(((F=((F=H.urls),F==null||F===false?F:F.undelete)),typeof F===e?F.apply(H):F))+'" class="historyItemUndelete" id="historyItemUndeleter-';if(E=s.id){E=E.call(H,{hash:{},data:G})}else{E=H.id;E=typeof E===e?E.apply(H):E}D+=d(E)+'"\n target="galaxy_history">here</a> to undelete it\n ';E=s["if"].call(H,((F=H.urls),F==null||F===false?F:F.purge),{hash:{},inverse:r.noop,fn:r.program(12,A,G),data:G});if(E||E===0){D+=E}D+="\n ";return D}function A(H,G){var D="",F,E;D+='\n or <a href="'+d(((F=((F=H.urls),F==null||F===false?F:F.purge)),typeof F===e?F.apply(H):F))+'" class="historyItemPurge" id="historyItemPurger-';if(E=s.id){E=E.call(H,{hash:{},data:G})}else{E=H.id;E=typeof E===e?E.apply(H):E}D+=d(E)+'"\n target="galaxy_history">here</a> to immediately remove it from disk\n ';return D}function z(G,F){var E,D;D={hash:{},inverse:r.noop,fn:r.program(15,y,F),data:F};if(E=s.warningmessagesmall){E=E.call(G,D)}else{E=G.warningmessagesmall;E=typeof E===e?E.apply(G):E}if(!s.warningmessagesmall){E=c.call(G,E,D)}if(E||E===0){return E}else{return""}}function y(H,G){var D="",F,E;D+="\n ";E={hash:{},inverse:r.noop,fn:r.program(16,x,G),data:G};if(F=s.local){F=F.call(H,E)}else{F=H.local;F=typeof F===e?F.apply(H):F}if(!s.local){F=c.call(H,F,E)}if(F||F===0){D+=F}D+="\n";return D}function x(E,D){return"This dataset has been deleted and removed from disk."}function w(G,F){var E,D;D={hash:{},inverse:r.noop,fn:r.program(19,v,F),data:F};if(E=s.warningmessagesmall){E=E.call(G,D)}else{E=G.warningmessagesmall;E=typeof E===e?E.apply(G):E}if(!s.warningmessagesmall){E=c.call(G,E,D)}if(E||E===0){return E}else{return""}}function v(I,H){var D="",G,F,E;D+="\n ";E={hash:{},inverse:r.noop,fn:r.program(20,k,H),data:H};if(G=s.local){G=G.call(I,E)}else{G=I.local;G=typeof G===e?G.apply(I):G}if(!s.local){G=c.call(I,G,E)}if(G||G===0){D+=G}D+="\n ";F=s["if"].call(I,((G=I.urls),G==null||G===false?G:G.unhide),{hash:{},inverse:r.noop,fn:r.program(22,f,H),data:H});if(F||F===0){D+=F}D+="\n";return D}function k(E,D){return"This dataset has been hidden."}function f(H,G){var D="",F,E;D+='\n Click <a href="'+d(((F=((F=H.urls),F==null||F===false?F:F.unhide)),typeof F===e?F.apply(H):F))+'" class="historyItemUnhide" id="historyItemUnhider-';if(E=s.id){E=E.call(H,{hash:{},data:G})}else{E=H.id;E=typeof E===e?E.apply(H):E}D+=d(E)+'"\n target="galaxy_history">here</a> to unhide it\n ';return D}j=s["if"].call(u,u.error,{hash:{},inverse:r.noop,fn:r.program(1,q,C),data:C});if(j||j===0){t+=j}t+="\n\n";j=s["if"].call(u,u.deleted,{hash:{},inverse:r.noop,fn:r.program(6,m,C),data:C});if(j||j===0){t+=j}t+="\n\n";j=s["if"].call(u,u.purged,{hash:{},inverse:r.noop,fn:r.program(14,z,C),data:C});if(j||j===0){t+=j}t+="\n\n";j=s.unless.call(u,u.visible,{hash:{},inverse:r.noop,fn:r.program(18,w,C),data:C});if(j||j===0){t+=j}return t})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-history-historyPanel.js
--- a/static/scripts/packed/templates/compiled/template-history-historyPanel.js
+++ b/static/scripts/packed/templates/compiled/template-history-historyPanel.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(G,d,F,p,M){F=F||G.helpers;var m="",s,q,c,L,g=this,l="function",v=F.blockHelperMissing,E=F.helperMissing,t=void 0,H=this.escapeExpression;function D(Q,P){var N="",O;N+='\n <div id="history-name" class="tooltip editable-text"\n title="';c=F.local;O=c||Q.local;L=g.program(2,C,P);L.hash={};L.fn=L;L.inverse=g.noop;if(c&&typeof O===l){O=O.call(Q,L)}else{O=v.call(Q,O,L)}if(O||O===0){N+=O}N+='">';c=F.name;O=c||Q.name;if(typeof O===l){O=O.call(Q,{hash:{}})}else{if(O===t){O=E.call(Q,"name",{hash:{}})}}N+=H(O)+"</div>\n ";return N}function C(O,N){return"Click to rename history"}function B(Q,P){var N="",O;N+='\n <div id="history-name" class="tooltip"\n title="';c=F.local;O=c||Q.local;L=g.program(5,A,P);L.hash={};L.fn=L;L.inverse=g.noop;if(c&&typeof O===l){O=O.call(Q,L)}else{O=v.call(Q,O,L)}if(O||O===0){N+=O}N+='">';c=F.name;O=c||Q.name;if(typeof O===l){O=O.call(Q,{hash:{}})}else{if(O===t){O=E.call(Q,"name",{hash:{}})}}N+=H(O)+"</div>\n ";return N}function A(O,N){return"You must be logged in to edit your history name"}function y(Q,P){var N="",O;N+='\n <a id="history-tag" title="';c=F.local;O=c||Q.local;L=g.program(8,x,P);L.hash={};L.fn=L;L.inverse=g.noop;if(c&&typeof O===l){O=O.call(Q,L)}else{O=v.call(Q,O,L)}if(O||O===0){N+=O}N+='"\n class="icon-button tags tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n <a id="history-annotate" title="';c=F.local;O=c||Q.local;L=g.program(10,z,P);L.hash={};L.fn=L;L.inverse=g.noop;if(c&&typeof O===l){O=O.call(Q,L)}else{O=v.call(Q,O,L)}if(O||O===0){N+=O}N+='"\n class="icon-button annotate tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n ';return N}function x(O,N){return"Edit history tags"}function z(O,N){return"Edit history annotation"}function w(R,Q){var N="",P,O;N+='\n <div id="history-tag-annotation">\n\n <div id="history-tag-area" style="display: none">\n <strong>';c=F.local;P=c||R.local;L=g.program(13,u,Q);L.hash={};L.fn=L;L.inverse=g.noop;if(c&&typeof P===l){P=P.call(R,L)}else{P=v.call(R,P,L)}if(P||P===0){N+=P}N+=':</strong>\n <div class="tag-elt"></div>\n </div>\n\n <div id="history-annotation-area" style="display: none">\n <strong>';c=F.local;P=c||R.local;L=g.program(15,r,Q);L.hash={};L.fn=L;L.inverse=g.noop;if(c&&typeof P===l){P=P.call(R,L)}else{P=v.call(R,P,L)}if(P||P===0){N+=P}N+=':</strong>\n <div id="history-annotation-container">\n <div id="history-annotation" class="tooltip editable-text"\n title="';c=F.local;P=c||R.local;L=g.program(17,o,Q);L.hash={};L.fn=L;L.inverse=g.noop;if(c&&typeof P===l){P=P.call(R,L)}else{P=v.call(R,P,L)}if(P||P===0){N+=P}N+='">\n ';c=F.annotation;P=c||R.annotation;O=F["if"];L=g.program(19,n,Q);L.hash={};L.fn=L;L.inverse=g.program(21,k,Q);P=O.call(R,P,L);if(P||P===0){N+=P}N+="\n </div>\n </div>\n </div>\n </div>\n ";return N}function u(O,N){return"Tags"}function r(O,N){return"Annotation"}function o(O,N){return"Click to edit annotation"}function n(Q,P){var N="",O;N+="\n ";c=F.annotation;O=c||Q.annotation;if(typeof O===l){O=O.call(Q,{hash:{}})}else{if(O===t){O=E.call(Q,"annotation",{hash:{}})}}N+=H(O)+"\n ";return N}function k(Q,P){var N="",O;N+="\n <em>";c=F.local;O=c||Q.local;L=g.program(22,j,P);L.hash={};L.fn=L;L.inverse=g.noop;if(c&&typeof O===l){O=O.call(Q,L)}else{O=v.call(Q,O,L)}if(O||O===0){N+=O}N+="</em>\n ";return N}function j(O,N){return"Describe or add notes to history"}function i(Q,P){var N="",O;N+="\n ";c=F.warningmessagesmall;O=c||Q.warningmessagesmall;L=g.program(25,h,P);L.hash={};L.fn=L;L.inverse=g.noop;if(c&&typeof O===l){O=O.call(Q,L)}else{O=v.call(Q,O,L)}if(O||O===0){N+=O}N+="\n ";return N}function h(P,O){var N;c=F.local;N=c||P.local;L=g.program(26,f,O);L.hash={};L.fn=L;L.inverse=g.noop;if(c&&typeof N===l){N=N.call(P,L)}else{N=v.call(P,N,L)}if(N||N===0){return N}else{return""}}function f(O,N){return"You are currently viewing a deleted history!"}function e(Q,P){var N="",O;N+='\n <div class="';c=F.status;O=c||Q.status;if(typeof O===l){O=O.call(Q,{hash:{}})}else{if(O===t){O=E.call(Q,"status",{hash:{}})}}N+=H(O)+'message">';c=F.message;O=c||Q.message;if(typeof O===l){O=O.call(Q,{hash:{}})}else{if(O===t){O=E.call(Q,"message",{hash:{}})}}N+=H(O)+"</div>\n ";return N}function K(O,N){return"You are over your disk quota"}function J(O,N){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function I(O,N){return"Your history is empty. Click 'Get Data' on the left pane to start"}m+='<div id="history-controls">\n\n <div id="history-title-area" class="historyLinks">\n ';m+='\n <div id="history-name-container">\n ';m+="\n ";c=F.user;s=c||d.user;s=(s===null||s===undefined||s===false?s:s.email);q=F["if"];L=g.program(1,D,M);L.hash={};L.fn=L;L.inverse=g.program(4,B,M);s=q.call(d,s,L);if(s||s===0){m+=s}m+='\n </div>\n </div>\n\n <div id="history-subtitle-area">\n <div id="history-size" style="float:left;">';c=F.nice_size;s=c||d.nice_size;if(typeof s===l){s=s.call(d,{hash:{}})}else{if(s===t){s=E.call(d,"nice_size",{hash:{}})}}m+=H(s)+'</div>\n\n <div id="history-secondary-links" style="float: right;">\n ';c=F.user;s=c||d.user;s=(s===null||s===undefined||s===false?s:s.email);q=F["if"];L=g.program(7,y,M);L.hash={};L.fn=L;L.inverse=g.noop;s=q.call(d,s,L);if(s||s===0){m+=s}m+='\n </div>\n <div style="clear: both;"></div>\n </div>\n\n ';m+="\n ";m+="\n ";c=F.user;s=c||d.user;s=(s===null||s===undefined||s===false?s:s.email);q=F["if"];L=g.program(12,w,M);L.hash={};L.fn=L;L.inverse=g.noop;s=q.call(d,s,L);if(s||s===0){m+=s}m+="\n\n ";c=F.deleted;s=c||d.deleted;q=F["if"];L=g.program(24,i,M);L.hash={};L.fn=L;L.inverse=g.noop;s=q.call(d,s,L);if(s||s===0){m+=s}m+='\n\n <div id="message-container">\n ';c=F.message;s=c||d.message;q=F["if"];L=g.program(28,e,M);L.hash={};L.fn=L;L.inverse=g.noop;s=q.call(d,s,L);if(s||s===0){m+=s}m+='\n </div>\n\n <div id="quota-message-container" style="display: none">\n <div id="quota-message" class="errormessage">\n ';c=F.local;s=c||d.local;L=g.program(30,K,M);L.hash={};L.fn=L;L.inverse=g.noop;if(c&&typeof s===l){s=s.call(d,L)}else{s=v.call(d,s,L)}if(s||s===0){m+=s}m+=".\n ";c=F.local;s=c||d.local;L=g.program(32,J,M);L.hash={};L.fn=L;L.inverse=g.noop;if(c&&typeof s===l){s=s.call(d,L)}else{s=v.call(d,s,L)}if(s||s===0){m+=s}m+='.\n </div>\n </div>\n</div>\n\n<div id="';c=F.id;s=c||d.id;if(typeof s===l){s=s.call(d,{hash:{}})}else{if(s===t){s=E.call(d,"id",{hash:{}})}}m+=H(s)+'-datasets" class="history-datasets-list"></div>\n\n<div class="infomessagesmall" id="emptyHistoryMessage" style="display: none;">\n ';c=F.local;s=c||d.local;L=g.program(34,I,M);L.hash={};L.fn=L;L.inverse=g.noop;if(c&&typeof s===l){s=s.call(d,L)}else{s=v.call(d,s,L)}if(s||s===0){m+=s}m+="\n</div>";return m})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(m,C,A,s,J){this.compilerInfo=[4,">= 1.0.0"];A=this.merge(A,m.helpers);J=J||{};var B="",p,l,h,x=this,e="function",c=A.blockHelperMissing,d=this.escapeExpression;function v(O,N){var K="",M,L;K+='\n <div id="history-name" class="tooltip editable-text"\n title="';L={hash:{},inverse:x.noop,fn:x.program(2,u,N),data:N};if(M=A.local){M=M.call(O,L)}else{M=O.local;M=typeof M===e?M.apply(O):M}if(!A.local){M=c.call(O,M,L)}if(M||M===0){K+=M}K+='">';if(M=A.name){M=M.call(O,{hash:{},data:N})}else{M=O.name;M=typeof M===e?M.apply(O):M}K+=d(M)+"</div>\n ";return K}function u(L,K){return"Click to rename history"}function t(O,N){var K="",M,L;K+='\n <div id="history-name" class="tooltip"\n title="';L={hash:{},inverse:x.noop,fn:x.program(5,r,N),data:N};if(M=A.local){M=M.call(O,L)}else{M=O.local;M=typeof M===e?M.apply(O):M}if(!A.local){M=c.call(O,M,L)}if(M||M===0){K+=M}K+='">';if(M=A.name){M=M.call(O,{hash:{},data:N})}else{M=O.name;M=typeof M===e?M.apply(O):M}K+=d(M)+"</div>\n ";return K}function r(L,K){return"You must be logged in to edit your history name"}function q(O,N){var K="",M,L;K+='\n <a id="history-tag" title="';L={hash:{},inverse:x.noop,fn:x.program(8,o,N),data:N};if(M=A.local){M=M.call(O,L)}else{M=O.local;M=typeof M===e?M.apply(O):M}if(!A.local){M=c.call(O,M,L)}if(M||M===0){K+=M}K+='"\n class="icon-button tags tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n <a id="history-annotate" title="';L={hash:{},inverse:x.noop,fn:x.program(10,I,N),data:N};if(M=A.local){M=M.call(O,L)}else{M=O.local;M=typeof M===e?M.apply(O):M}if(!A.local){M=c.call(O,M,L)}if(M||M===0){K+=M}K+='"\n class="icon-button annotate tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n ';return K}function o(L,K){return"Edit history tags"}function I(L,K){return"Edit history annotation"}function H(O,N){var K="",M,L;K+='\n <div id="history-tag-annotation">\n\n <div id="history-tag-area" style="display: none">\n <strong>';L={hash:{},inverse:x.noop,fn:x.program(13,G,N),data:N};if(M=A.local){M=M.call(O,L)}else{M=O.local;M=typeof M===e?M.apply(O):M}if(!A.local){M=c.call(O,M,L)}if(M||M===0){K+=M}K+=':</strong>\n <div class="tag-elt"></div>\n </div>\n\n <div id="history-annotation-area" style="display: none">\n <strong>';L={hash:{},inverse:x.noop,fn:x.program(15,F,N),data:N};if(M=A.local){M=M.call(O,L)}else{M=O.local;M=typeof M===e?M.apply(O):M}if(!A.local){M=c.call(O,M,L)}if(M||M===0){K+=M}K+=':</strong>\n <div id="history-annotation-container">\n <div id="history-annotation" class="tooltip editable-text"\n title="';L={hash:{},inverse:x.noop,fn:x.program(17,E,N),data:N};if(M=A.local){M=M.call(O,L)}else{M=O.local;M=typeof M===e?M.apply(O):M}if(!A.local){M=c.call(O,M,L)}if(M||M===0){K+=M}K+='">\n ';M=A["if"].call(O,O.annotation,{hash:{},inverse:x.program(21,n,N),fn:x.program(19,D,N),data:N});if(M||M===0){K+=M}K+="\n </div>\n </div>\n </div>\n </div>\n ";return K}function G(L,K){return"Tags"}function F(L,K){return"Annotation"}function E(L,K){return"Click to edit annotation"}function D(N,M){var K="",L;K+="\n ";if(L=A.annotation){L=L.call(N,{hash:{},data:M})}else{L=N.annotation;L=typeof L===e?L.apply(N):L}K+=d(L)+"\n ";return K}function n(O,N){var K="",M,L;K+="\n <em>";L={hash:{},inverse:x.noop,fn:x.program(22,k,N),data:N};if(M=A.local){M=M.call(O,L)}else{M=O.local;M=typeof M===e?M.apply(O):M}if(!A.local){M=c.call(O,M,L)}if(M||M===0){K+=M}K+="</em>\n ";return K}function k(L,K){return"Describe or add notes to history"}function j(O,N){var K="",M,L;K+="\n ";L={hash:{},inverse:x.noop,fn:x.program(25,i,N),data:N};if(M=A.warningmessagesmall){M=M.call(O,L)}else{M=O.warningmessagesmall;M=typeof M===e?M.apply(O):M}if(!A.warningmessagesmall){M=c.call(O,M,L)}if(M||M===0){K+=M}K+="\n ";return K}function i(N,M){var L,K;K={hash:{},inverse:x.noop,fn:x.program(26,g,M),data:M};if(L=A.local){L=L.call(N,K)}else{L=N.local;L=typeof L===e?L.apply(N):L}if(!A.local){L=c.call(N,L,K)}if(L||L===0){return L}else{return""}}function g(L,K){return"You are currently viewing a deleted history!"}function f(N,M){var K="",L;K+='\n <div class="';if(L=A.status){L=L.call(N,{hash:{},data:M})}else{L=N.status;L=typeof L===e?L.apply(N):L}K+=d(L)+'message">';if(L=A.message){L=L.call(N,{hash:{},data:M})}else{L=N.message;L=typeof L===e?L.apply(N):L}K+=d(L)+"</div>\n ";return K}function z(L,K){return"You are over your disk quota"}function y(L,K){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function w(L,K){return"Your history is empty. Click 'Get Data' on the left pane to start"}B+='<div id="history-controls">\n\n <div id="history-title-area" class="historyLinks">\n \n <div id="history-name-container">\n \n ';l=A["if"].call(C,((p=C.user),p==null||p===false?p:p.email),{hash:{},inverse:x.program(4,t,J),fn:x.program(1,v,J),data:J});if(l||l===0){B+=l}B+='\n </div>\n </div>\n\n <div id="history-subtitle-area">\n <div id="history-size" style="float:left;">';if(l=A.nice_size){l=l.call(C,{hash:{},data:J})}else{l=C.nice_size;l=typeof l===e?l.apply(C):l}B+=d(l)+'</div>\n\n <div id="history-secondary-links" style="float: right;">\n ';l=A["if"].call(C,((p=C.user),p==null||p===false?p:p.email),{hash:{},inverse:x.noop,fn:x.program(7,q,J),data:J});if(l||l===0){B+=l}B+='\n </div>\n <div style="clear: both;"></div>\n </div>\n\n \n \n ';l=A["if"].call(C,((p=C.user),p==null||p===false?p:p.email),{hash:{},inverse:x.noop,fn:x.program(12,H,J),data:J});if(l||l===0){B+=l}B+="\n\n ";l=A["if"].call(C,C.deleted,{hash:{},inverse:x.noop,fn:x.program(24,j,J),data:J});if(l||l===0){B+=l}B+='\n\n <div id="message-container">\n ';l=A["if"].call(C,C.message,{hash:{},inverse:x.noop,fn:x.program(28,f,J),data:J});if(l||l===0){B+=l}B+='\n </div>\n\n <div id="quota-message-container" style="display: none">\n <div id="quota-message" class="errormessage">\n ';h={hash:{},inverse:x.noop,fn:x.program(30,z,J),data:J};if(l=A.local){l=l.call(C,h)}else{l=C.local;l=typeof l===e?l.apply(C):l}if(!A.local){l=c.call(C,l,h)}if(l||l===0){B+=l}B+=".\n ";h={hash:{},inverse:x.noop,fn:x.program(32,y,J),data:J};if(l=A.local){l=l.call(C,h)}else{l=C.local;l=typeof l===e?l.apply(C):l}if(!A.local){l=c.call(C,l,h)}if(l||l===0){B+=l}B+='.\n </div>\n </div>\n</div>\n\n<div id="';if(l=A.id){l=l.call(C,{hash:{},data:J})}else{l=C.id;l=typeof l===e?l.apply(C):l}B+=d(l)+'-datasets" class="history-datasets-list"></div>\n\n<div class="infomessagesmall" id="emptyHistoryMessage" style="display: none;">\n ';h={hash:{},inverse:x.noop,fn:x.program(34,w,J),data:J};if(l=A.local){l=l.call(C,h)}else{l=C.local;l=typeof l===e?l.apply(C):l}if(!A.local){l=c.call(C,l,h)}if(l||l===0){B+=l}B+="\n</div>";return B})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-iconButton.js
--- a/static/scripts/packed/templates/compiled/template-iconButton.js
+++ b/static/scripts/packed/templates/compiled/template-iconButton.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-iconButton"]=b(function(e,j,d,i,h){d=d||e.helpers;i=i||e.partials;var g="",c,f,k=this;g+="\n";c=j;c=k.invokePartial(i.iconButton,"iconButton",c,d,i);if(c||c===0){g+=c}return g})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-iconButton"]=b(function(i,j,g,e,h){this.compilerInfo=[4,">= 1.0.0"];g=this.merge(g,i.helpers);e=this.merge(e,i.partials);h=h||{};var c="",f,d=this;c+="\n";f=d.invokePartial(e.iconButton,"iconButton",j,g,e,h);if(f||f===0){c+=f}return c})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-popupmenu-menu.js
--- a/static/scripts/packed/templates/compiled/template-popupmenu-menu.js
+++ b/static/scripts/packed/templates/compiled/template-popupmenu-menu.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-popupmenu-menu"]=b(function(h,w,u,n,B){u=u||h.helpers;var v="",k,g,j,s,r=this,e="function",t=u.helperMissing,c=void 0,d=this.escapeExpression;function q(G,F){var C="",E,D;C+="\n ";j=u.options;E=j||G.options;D=u.each;s=r.program(2,p,F);s.hash={};s.fn=s;s.inverse=r.noop;E=D.call(G,E,s);if(E||E===0){C+=E}C+="\n";return C}function p(G,F){var C="",E,D;C+="\n ";j=u.divider;E=j||G.divider;D=u["if"];s=r.program(3,o,F);s.hash={};s.fn=s;s.inverse=r.program(5,m,F);E=D.call(G,E,s);if(E||E===0){C+=E}C+="\n ";return C}function o(D,C){return'\n <li class="divider"></li>\n '}function m(G,F){var C="",E,D;C+="\n ";j=u.header;E=j||G.header;D=u["if"];s=r.program(6,l,F);s.hash={};s.fn=s;s.inverse=r.program(8,i,F);E=D.call(G,E,s);if(E||E===0){C+=E}C+="\n ";return C}function l(F,E){var C="",D;C+='\n <li class="head"><a href=""javascript:void(0);">';j=u.html;D=j||F.html;if(typeof D===e){D=D.call(F,{hash:{}})}else{if(D===c){D=t.call(F,"html",{hash:{}})}}if(D||D===0){C+=D}C+="</a></li>\n ";return C}function i(G,F){var C="",E,D;C+="\n ";C+='\n <li><a href="';j=u.href;E=j||G.href;D=u["if"];s=r.program(9,f,F);s.hash={};s.fn=s;s.inverse=r.program(11,A,F);E=D.call(G,E,s);if(E||E===0){C+=E}C+='"\n ';j=u.href;E=j||G.href;D=u["if"];s=r.program(13,z,F);s.hash={};s.fn=s;s.inverse=r.noop;E=D.call(G,E,s);if(E||E===0){C+=E}C+=' class="popupmenu-option">\n ';j=u.checked;E=j||G.checked;D=u["if"];s=r.program(15,y,F);s.hash={};s.fn=s;s.inverse=r.noop;E=D.call(G,E,s);if(E||E===0){C+=E}C+="\n ";j=u.html;E=j||G.html;if(typeof E===e){E=E.call(G,{hash:{}})}else{if(E===c){E=t.call(G,"html",{hash:{}})}}if(E||E===0){C+=E}C+="\n </a></li>\n ";return C}function f(E,D){var C;j=u.href;C=j||E.href;if(typeof C===e){C=C.call(E,{hash:{}})}else{if(C===c){C=t.call(E,"href",{hash:{}})}}return d(C)}function A(D,C){return"javascript:void(0);"}function z(F,E){var C="",D;C+='target="';j=u.target;D=j||F.target;if(typeof D===e){D=D.call(F,{hash:{}})}else{if(D===c){D=t.call(F,"target",{hash:{}})}}C+=d(D)+'"';return C}function y(D,C){return'<span class="fa-icon-ok"></span>'}function x(D,C){return"\n <li>No Options.</li>\n"}v+='<ul id="';j=u.id;k=j||w.id;if(typeof k===e){k=k.call(w,{hash:{}})}else{if(k===c){k=t.call(w,"id",{hash:{}})}}v+=d(k)+'-menu" class="dropdown-menu">\n';j=u.options;k=j||w.options;k=(k===null||k===undefined||k===false?k:k.length);g=u["if"];s=r.program(1,q,B);s.hash={};s.fn=s;s.inverse=r.program(17,x,B);k=g.call(w,k,s);if(k||k===0){v+=k}v+="\n</ul>";return v})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-popupmenu-menu"]=b(function(g,s,q,l,x){this.compilerInfo=[4,">= 1.0.0"];q=this.merge(q,g.helpers);x=x||{};var r="",i,f,d="function",c=this.escapeExpression,p=this;function o(B,A){var y="",z;y+="\n ";z=q.each.call(B,B.options,{hash:{},inverse:p.noop,fn:p.program(2,n,A),data:A});if(z||z===0){y+=z}y+="\n";return y}function n(B,A){var y="",z;y+="\n ";z=q["if"].call(B,B.divider,{hash:{},inverse:p.program(5,k,A),fn:p.program(3,m,A),data:A});if(z||z===0){y+=z}y+="\n ";return y}function m(z,y){return'\n <li class="divider"></li>\n '}function k(B,A){var y="",z;y+="\n ";z=q["if"].call(B,B.header,{hash:{},inverse:p.program(8,h,A),fn:p.program(6,j,A),data:A});if(z||z===0){y+=z}y+="\n ";return y}function j(B,A){var y="",z;y+='\n <li class="head"><a href=""javascript:void(0);">';if(z=q.html){z=z.call(B,{hash:{},data:A})}else{z=B.html;z=typeof z===d?z.apply(B):z}if(z||z===0){y+=z}y+="</a></li>\n ";return y}function h(B,A){var y="",z;y+='\n \n <li><a href="';z=q["if"].call(B,B.href,{hash:{},inverse:p.program(11,w,A),fn:p.program(9,e,A),data:A});if(z||z===0){y+=z}y+='"\n ';z=q["if"].call(B,B.href,{hash:{},inverse:p.noop,fn:p.program(13,v,A),data:A});if(z||z===0){y+=z}y+=' class="popupmenu-option">\n ';z=q["if"].call(B,B.checked,{hash:{},inverse:p.noop,fn:p.program(15,u,A),data:A});if(z||z===0){y+=z}y+="\n ";if(z=q.html){z=z.call(B,{hash:{},data:A})}else{z=B.html;z=typeof z===d?z.apply(B):z}if(z||z===0){y+=z}y+="\n </a></li>\n ";return y}function e(A,z){var y;if(y=q.href){y=y.call(A,{hash:{},data:z})}else{y=A.href;y=typeof y===d?y.apply(A):y}return c(y)}function w(z,y){return"javascript:void(0);"}function v(B,A){var y="",z;y+='target="';if(z=q.target){z=z.call(B,{hash:{},data:A})}else{z=B.target;z=typeof z===d?z.apply(B):z}y+=c(z)+'"';return y}function u(z,y){return'<span class="fa-icon-ok"></span>'}function t(z,y){return"\n <li>No Options.</li>\n"}r+='<ul id="';if(i=q.id){i=i.call(s,{hash:{},data:x})}else{i=s.id;i=typeof i===d?i.apply(s):i}r+=c(i)+'-menu" class="dropdown-menu">\n';f=q["if"].call(s,((i=s.options),i==null||i===false?i:i.length),{hash:{},inverse:p.program(17,t,x),fn:p.program(1,o,x),data:x});if(f||f===0){r+=f}r+="\n</ul>";return r})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-user-quotaMeter-quota.js
--- a/static/scripts/packed/templates/compiled/template-user-quotaMeter-quota.js
+++ b/static/scripts/packed/templates/compiled/template-user-quotaMeter-quota.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-user-quotaMeter-quota"]=b(function(h,s,q,k,t){q=q||h.helpers;var r="",j,g,i,o,n=this,f="function",p=q.helperMissing,d=void 0,e=this.escapeExpression,c=q.blockHelperMissing;function m(x,w){var u="",v;u+=' title="Using ';i=q.nice_total_disk_usage;v=i||x.nice_total_disk_usage;if(typeof v===f){v=v.call(x,{hash:{}})}else{if(v===d){v=p.call(x,"nice_total_disk_usage",{hash:{}})}}u+=e(v)+'"';return u}function l(v,u){return"Using"}r+='<div id="quota-meter" class="quota-meter progress">\n <div id="quota-meter-bar" class="quota-meter-bar bar" style="width: ';i=q.quota_percent;j=i||s.quota_percent;if(typeof j===f){j=j.call(s,{hash:{}})}else{if(j===d){j=p.call(s,"quota_percent",{hash:{}})}}r+=e(j)+'%"></div>\n ';r+='\n <div id="quota-meter-text" class="quota-meter-text tooltip"\n style="top: 6px"';i=q.nice_total_disk_usage;j=i||s.nice_total_disk_usage;g=q["if"];o=n.program(1,m,t);o.hash={};o.fn=o;o.inverse=n.noop;j=g.call(s,j,o);if(j||j===0){r+=j}r+=">\n ";i=q.local;j=i||s.local;o=n.program(3,l,t);o.hash={};o.fn=o;o.inverse=n.noop;if(i&&typeof j===f){j=j.call(s,o)}else{j=c.call(s,j,o)}if(j||j===0){r+=j}r+=" ";i=q.quota_percent;j=i||s.quota_percent;if(typeof j===f){j=j.call(s,{hash:{}})}else{if(j===d){j=p.call(s,"quota_percent",{hash:{}})}}r+=e(j)+"%\n </div>\n</div>";return r})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-user-quotaMeter-quota"]=b(function(g,m,f,l,k){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);k=k||{};var i="",d,p,h="function",j=this.escapeExpression,o=this,n=f.blockHelperMissing;function e(t,s){var q="",r;q+=' title="Using ';if(r=f.nice_total_disk_usage){r=r.call(t,{hash:{},data:s})}else{r=t.nice_total_disk_usage;r=typeof r===h?r.apply(t):r}q+=j(r)+'"';return q}function c(r,q){return"Using"}i+='<div id="quota-meter" class="quota-meter progress">\n <div id="quota-meter-bar" class="quota-meter-bar bar" style="width: ';if(d=f.quota_percent){d=d.call(m,{hash:{},data:k})}else{d=m.quota_percent;d=typeof d===h?d.apply(m):d}i+=j(d)+'%"></div>\n \n <div id="quota-meter-text" class="quota-meter-text tooltip"\n style="top: 6px"';d=f["if"].call(m,m.nice_total_disk_usage,{hash:{},inverse:o.noop,fn:o.program(1,e,k),data:k});if(d||d===0){i+=d}i+=">\n ";p={hash:{},inverse:o.noop,fn:o.program(3,c,k),data:k};if(d=f.local){d=d.call(m,p)}else{d=m.local;d=typeof d===h?d.apply(m):d}if(!f.local){d=n.call(m,d,p)}if(d||d===0){i+=d}i+=" ";if(d=f.quota_percent){d=d.call(m,{hash:{},data:k})}else{d=m.quota_percent;d=typeof d===h?d.apply(m):d}i+=j(d)+"%\n </div>\n</div>";return i})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-user-quotaMeter-usage.js
--- a/static/scripts/packed/templates/compiled/template-user-quotaMeter-usage.js
+++ b/static/scripts/packed/templates/compiled/template-user-quotaMeter-usage.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-user-quotaMeter-usage"]=b(function(h,s,q,k,t){q=q||h.helpers;var r="",j,g,i,o,n=this,f="function",c=q.blockHelperMissing,p=q.helperMissing,d=void 0,e=this.escapeExpression;function m(x,w){var u="",v;i=q.local;v=i||x.local;o=n.program(2,l,w);o.hash={};o.fn=o;o.inverse=n.noop;if(i&&typeof v===f){v=v.call(x,o)}else{v=c.call(x,v,o)}if(v||v===0){u+=v}u+=" ";i=q.nice_total_disk_usage;v=i||x.nice_total_disk_usage;if(typeof v===f){v=v.call(x,{hash:{}})}else{if(v===d){v=p.call(x,"nice_total_disk_usage",{hash:{}})}}u+=e(v);return u}function l(v,u){return"Using"}r+='<div id="quota-meter" class="quota-meter" style="background-color: transparent">\n <div id="quota-meter-text" class="quota-meter-text" style="top: 6px; color: white">\n ';i=q.nice_total_disk_usage;j=i||s.nice_total_disk_usage;g=q["if"];o=n.program(1,m,t);o.hash={};o.fn=o;o.inverse=n.noop;j=g.call(s,j,o);if(j||j===0){r+=j}r+="\n </div>\n</div>";return r})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-user-quotaMeter-usage"]=b(function(g,m,f,l,k){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);k=k||{};var i="",c,o=this,h="function",n=f.blockHelperMissing,j=this.escapeExpression;function e(t,s){var p="",r,q;q={hash:{},inverse:o.noop,fn:o.program(2,d,s),data:s};if(r=f.local){r=r.call(t,q)}else{r=t.local;r=typeof r===h?r.apply(t):r}if(!f.local){r=n.call(t,r,q)}if(r||r===0){p+=r}p+=" ";if(r=f.nice_total_disk_usage){r=r.call(t,{hash:{},data:s})}else{r=t.nice_total_disk_usage;r=typeof r===h?r.apply(t):r}p+=j(r);return p}function d(q,p){return"Using"}i+='<div id="quota-meter" class="quota-meter" style="background-color: transparent">\n <div id="quota-meter-text" class="quota-meter-text" style="top: 6px; color: white">\n ';c=f["if"].call(m,m.nice_total_disk_usage,{hash:{},inverse:o.noop,fn:o.program(1,e,k),data:k});if(c||c===0){i+=c}i+="\n </div>\n</div>";return i})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-visualization-chartControl.js
--- a/static/scripts/packed/templates/compiled/template-visualization-chartControl.js
+++ b/static/scripts/packed/templates/compiled/template-visualization-chartControl.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-chartControl"]=b(function(f,p,e,n,m){e=e||f.helpers;var k="",c,r,j,i,q=this,g="function",o=e.helperMissing,h=void 0,l=this.escapeExpression;function d(t,s){return' checked="true"'}k+='<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">';j=e.datapointSize;c=j||p.datapointSize;if(typeof c===g){c=c.call(p,{hash:{}})}else{if(c===h){c=o.call(p,"datapointSize",{hash:{}})}}k+=l(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="animate-chart">Animate chart transitions?: </label>\n <input type="checkbox" id="animate-chart"\n class="checkbox control"';j=e.animDuration;c=j||p.animDuration;r=e["if"];i=q.program(1,d,m);i.hash={};i.fn=i;i.inverse=q.noop;c=r.call(p,c,i);if(c||c===0){k+=c}k+=' />\n <p class="form-help help-text-small">\n Uncheck this to disable the animations used on the chart\n </p>\n </div>\n\n <div id="width" class="form-input numeric-slider-input">\n <label for="width">Chart width: </label>\n <div class="slider-output">';j=e.width;c=j||p.width;if(typeof c===g){c=c.call(p,{hash:{}})}else{if(c===h){c=o.call(p,"width",{hash:{}})}}k+=l(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including chart margins and axes)\n </p>\n </div>\n\n <div id="height" class="form-input numeric-slider-input">\n <label for="height">Chart height: </label>\n <div class="slider-output">';j=e.height;c=j||p.height;if(typeof c===g){c=c.call(p,{hash:{}})}else{if(c===h){c=o.call(p,"height",{hash:{}})}}k+=l(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including chart 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="';j=e.xLabel;c=j||p.xLabel;if(typeof c===g){c=c.call(p,{hash:{}})}else{if(c===h){c=o.call(p,"xLabel",{hash:{}})}}k+=l(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="';j=e.yLabel;c=j||p.yLabel;if(typeof c===g){c=c.call(p,{hash:{}})}else{if(c===h){c=o.call(p,"yLabel",{hash:{}})}}k+=l(c)+'" />\n <p class="form-help help-text-small"></p>\n </div>\n\n <input id="render-button" type="button" value="Draw" />';return k})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-chartControl"]=b(function(f,l,e,k,j){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,f.helpers);j=j||{};var h="",c,g="function",i=this.escapeExpression,m=this;function d(o,n){return' checked="true"'}h+='<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">';if(c=e.datapointSize){c=c.call(l,{hash:{},data:j})}else{c=l.datapointSize;c=typeof c===g?c.apply(l):c}h+=i(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="animate-chart">Animate chart transitions?: </label>\n <input type="checkbox" id="animate-chart"\n class="checkbox control"';c=e["if"].call(l,l.animDuration,{hash:{},inverse:m.noop,fn:m.program(1,d,j),data:j});if(c||c===0){h+=c}h+=' />\n <p class="form-help help-text-small">\n Uncheck this to disable the animations used on the chart\n </p>\n </div>\n\n <div id="width" class="form-input numeric-slider-input">\n <label for="width">Chart width: </label>\n <div class="slider-output">';if(c=e.width){c=c.call(l,{hash:{},data:j})}else{c=l.width;c=typeof c===g?c.apply(l):c}h+=i(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including chart margins and axes)\n </p>\n </div>\n\n <div id="height" class="form-input numeric-slider-input">\n <label for="height">Chart height: </label>\n <div class="slider-output">';if(c=e.height){c=c.call(l,{hash:{},data:j})}else{c=l.height;c=typeof c===g?c.apply(l):c}h+=i(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including chart 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="';if(c=e.xLabel){c=c.call(l,{hash:{},data:j})}else{c=l.xLabel;c=typeof c===g?c.apply(l):c}h+=i(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="';if(c=e.yLabel){c=c.call(l,{hash:{},data:j})}else{c=l.yLabel;c=typeof c===g?c.apply(l):c}h+=i(c)+'" />\n <p class="form-help help-text-small"></p>\n </div>\n\n <input id="render-button" type="button" value="Draw" />';return h})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-visualization-chartDisplay.js
--- a/static/scripts/packed/templates/compiled/template-visualization-chartDisplay.js
+++ b/static/scripts/packed/templates/compiled/template-visualization-chartDisplay.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-chartDisplay"]=b(function(e,n,d,l,k){d=d||e.helpers;var i="",c,h,o=this,f="function",m=d.helperMissing,g=void 0,j=this.escapeExpression;i+='<svg width="';h=d.width;c=h||n.width;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"width",{hash:{}})}}i+=j(c)+'" height="';h=d.height;c=h||n.height;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"height",{hash:{}})}}i+=j(c)+'"></svg>';return i})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-chartDisplay"]=b(function(e,k,d,j,i){this.compilerInfo=[4,">= 1.0.0"];d=this.merge(d,e.helpers);i=i||{};var g="",c,f="function",h=this.escapeExpression;g+='<svg width="';if(c=d.width){c=c.call(k,{hash:{},data:i})}else{c=k.width;c=typeof c===f?c.apply(k):c}g+=h(c)+'" height="';if(c=d.height){c=c.call(k,{hash:{},data:i})}else{c=k.height;c=typeof c===f?c.apply(k):c}g+=h(c)+'"></svg>';return g})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-visualization-dataControl.js
--- a/static/scripts/packed/templates/compiled/template-visualization-dataControl.js
+++ b/static/scripts/packed/templates/compiled/template-visualization-dataControl.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-dataControl"]=b(function(g,t,r,l,u){r=r||g.helpers;var s="",i,f,h,p,o=this,e="function",q=r.helperMissing,c=void 0,d=this.escapeExpression;function n(y,x){var v="",w;v+='\n <option value="';h=r.index;w=h||y.index;if(typeof w===e){w=w.call(y,{hash:{}})}else{if(w===c){w=q.call(y,"index",{hash:{}})}}v+=d(w)+'">';h=r.name;w=h||y.name;if(typeof w===e){w=w.call(y,{hash:{}})}else{if(w===c){w=q.call(y,"name",{hash:{}})}}v+=d(w)+"</option>\n ";return v}function m(y,x){var v="",w;v+='\n <option value="';h=r.index;w=h||y.index;if(typeof w===e){w=w.call(y,{hash:{}})}else{if(w===c){w=q.call(y,"index",{hash:{}})}}v+=d(w)+'">';h=r.name;w=h||y.name;if(typeof w===e){w=w.call(y,{hash:{}})}else{if(w===c){w=q.call(y,"name",{hash:{}})}}v+=d(w)+"</option>\n ";return v}function k(y,x){var v="",w;v+='\n <option value="';h=r.index;w=h||y.index;if(typeof w===e){w=w.call(y,{hash:{}})}else{if(w===c){w=q.call(y,"index",{hash:{}})}}v+=d(w)+'">';h=r.name;w=h||y.name;if(typeof w===e){w=w.call(y,{hash:{}})}else{if(w===c){w=q.call(y,"name",{hash:{}})}}v+=d(w)+"</option>\n ";return v}function j(w,v){return'checked="true"'}s+="<p class=\"help-text\">\n Use the following controls to change the data used by the chart.\n Use the 'Draw' button to render (or re-render) the chart with the current settings.\n </p>\n\n ";s+='\n <div class="column-select">\n <label for="X-select">Data column for X: </label>\n <select name="X" id="X-select">\n ';h=r.numericColumns;i=h||t.numericColumns;f=r.each;p=o.program(1,n,u);p.hash={};p.fn=p;p.inverse=o.noop;i=f.call(t,i,p);if(i||i===0){s+=i}s+='\n </select>\n </div>\n <div class="column-select">\n <label for="Y-select">Data column for Y: </label>\n <select name="Y" id="Y-select">\n ';h=r.numericColumns;i=h||t.numericColumns;f=r.each;p=o.program(3,m,u);p.hash={};p.fn=p;p.inverse=o.noop;i=f.call(t,i,p);if(i||i===0){s+=i}s+="\n </select>\n </div>\n\n ";s+='\n <div id="include-id">\n <label for="include-id-checkbox">Include a third column as data point IDs?</label>\n <input type="checkbox" name="include-id" id="include-id-checkbox" />\n <p class="help-text-small">\n These will be displayed (along with the x and y values) when you hover over\n a data point.\n </p>\n </div>\n <div class="column-select" style="display: none">\n <label for="ID-select">Data column for IDs: </label>\n <select name="ID" id="ID-select">\n ';h=r.allColumns;i=h||t.allColumns;f=r.each;p=o.program(5,k,u);p.hash={};p.fn=p;p.inverse=o.noop;i=f.call(t,i,p);if(i||i===0){s+=i}s+="\n </select>\n </div>\n\n ";s+='\n <div id="first-line-header" style="display: none;">\n <p>Possible headers: ';h=r.possibleHeaders;i=h||t.possibleHeaders;if(typeof i===e){i=i.call(t,{hash:{}})}else{if(i===c){i=q.call(t,"possibleHeaders",{hash:{}})}}s+=d(i)+'\n </p>\n <label for="first-line-header-checkbox">Use the above as column headers?</label>\n <input type="checkbox" name="include-id" id="first-line-header-checkbox"\n ';h=r.usePossibleHeaders;i=h||t.usePossibleHeaders;f=r["if"];p=o.program(7,j,u);p.hash={};p.fn=p;p.inverse=o.noop;i=f.call(t,i,p);if(i||i===0){s+=i}s+='/>\n <p class="help-text-small">\n It looks like Galaxy couldn\'t get proper column headers for this data.\n Would you like to use the column headers above as column names to select columns?\n </p>\n </div>\n\n <input id="render-button" type="button" value="Draw" />\n <div class="clear"></div>';return s})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-dataControl"]=b(function(g,m,f,l,k){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,g.helpers);k=k||{};var i="",d,h="function",j=this.escapeExpression,n=this;function e(r,q){var o="",p;o+='\n <option value="';if(p=f.index){p=p.call(r,{hash:{},data:q})}else{p=r.index;p=typeof p===h?p.apply(r):p}o+=j(p)+'">';if(p=f.name){p=p.call(r,{hash:{},data:q})}else{p=r.name;p=typeof p===h?p.apply(r):p}o+=j(p)+"</option>\n ";return o}function c(p,o){return'checked="true"'}i+='<p class="help-text">\n Use the following controls to change the data used by the chart.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n </p>\n\n \n <div class="column-select">\n <label for="X-select">Data column for X: </label>\n <select name="X" id="X-select">\n ';d=f.each.call(m,m.numericColumns,{hash:{},inverse:n.noop,fn:n.program(1,e,k),data:k});if(d||d===0){i+=d}i+='\n </select>\n </div>\n <div class="column-select">\n <label for="Y-select">Data column for Y: </label>\n <select name="Y" id="Y-select">\n ';d=f.each.call(m,m.numericColumns,{hash:{},inverse:n.noop,fn:n.program(1,e,k),data:k});if(d||d===0){i+=d}i+='\n </select>\n </div>\n\n \n <div id="include-id">\n <label for="include-id-checkbox">Include a third column as data point IDs?</label>\n <input type="checkbox" name="include-id" id="include-id-checkbox" />\n <p class="help-text-small">\n These will be displayed (along with the x and y values) when you hover over\n a data point.\n </p>\n </div>\n <div class="column-select" style="display: none">\n <label for="ID-select">Data column for IDs: </label>\n <select name="ID" id="ID-select">\n ';d=f.each.call(m,m.allColumns,{hash:{},inverse:n.noop,fn:n.program(1,e,k),data:k});if(d||d===0){i+=d}i+='\n </select>\n </div>\n\n \n <div id="first-line-header" style="display: none;">\n <p>Possible headers: ';if(d=f.possibleHeaders){d=d.call(m,{hash:{},data:k})}else{d=m.possibleHeaders;d=typeof d===h?d.apply(m):d}i+=j(d)+'\n </p>\n <label for="first-line-header-checkbox">Use the above as column headers?</label>\n <input type="checkbox" name="include-id" id="first-line-header-checkbox"\n ';d=f["if"].call(m,m.usePossibleHeaders,{hash:{},inverse:n.noop,fn:n.program(3,c,k),data:k});if(d||d===0){i+=d}i+='/>\n <p class="help-text-small">\n It looks like Galaxy couldn\'t get proper column headers for this data.\n Would you like to use the column headers above as column names to select columns?\n </p>\n </div>\n\n <input id="render-button" type="button" value="Draw" />\n <div class="clear"></div>';return i})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-visualization-scatterplotControlForm.js
--- a/static/scripts/packed/templates/compiled/template-visualization-scatterplotControlForm.js
+++ b/static/scripts/packed/templates/compiled/template-visualization-scatterplotControlForm.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-scatterplotControlForm"]=b(function(e,n,d,l,k){d=d||e.helpers;var i="",c,h,o=this,f="function",m=d.helperMissing,g=void 0,j=this.escapeExpression;i+='\n\n<div class="scatterplot-container chart-container tabbable tabs-left">\n ';i+='\n <ul class="nav nav-tabs">\n ';i+='\n <li class="active"><a href="#data-control" data-toggle="tab" class="tooltip"\n title="Use this tab to change which data are used">Data Controls</a></li>\n <li><a href="#chart-control" data-toggle="tab" class="tooltip"\n title="Use this tab to change how the chart is drawn">Chart Controls</a></li>\n <li><a href="#stats-display" data-toggle="tab" class="tooltip"\n title="This tab will display overall statistics for your data">Statistics</a></li>\n <li><a href="#chart-display" data-toggle="tab" class="tooltip"\n title="This tab will display the chart">Chart</a>\n ';i+='\n <div id="loading-indicator" style="display: none;">\n <img class="loading-img" src="';h=d.loadingIndicatorImagePath;c=h||n.loadingIndicatorImagePath;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"loadingIndicatorImagePath",{hash:{}})}}i+=j(c)+'" />\n <span class="loading-message">';h=d.message;c=h||n.message;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"message",{hash:{}})}}i+=j(c)+"</span>\n </div>\n </li>\n </ul>\n\n ";i+='\n <div class="tab-content">\n ';i+='\n <div id="data-control" class="tab-pane active">\n ';i+="\n </div>\n \n ";i+='\n <div id="chart-control" class="tab-pane">\n ';i+="\n </div>\n\n ";i+='\n <div id="stats-display" class="tab-pane">\n ';i+="\n </div>\n\n ";i+='\n <div id="chart-display" class="tab-pane">\n ';i+="\n </div>\n\n </div>";i+="\n</div>";return i})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-scatterplotControlForm"]=b(function(e,k,d,j,i){this.compilerInfo=[4,">= 1.0.0"];d=this.merge(d,e.helpers);i=i||{};var g="",c,f="function",h=this.escapeExpression;g+='\n\n<div class="scatterplot-container chart-container tabbable tabs-left">\n \n <ul class="nav nav-tabs">\n \n <li class="active"><a href="#data-control" data-toggle="tab" class="tooltip"\n title="Use this tab to change which data are used">Data Controls</a></li>\n <li><a href="#chart-control" data-toggle="tab" class="tooltip"\n title="Use this tab to change how the chart is drawn">Chart Controls</a></li>\n <li><a href="#stats-display" data-toggle="tab" class="tooltip"\n title="This tab will display overall statistics for your data">Statistics</a></li>\n <li><a href="#chart-display" data-toggle="tab" class="tooltip"\n title="This tab will display the chart">Chart</a>\n \n <div id="loading-indicator" style="display: none;">\n <img class="loading-img" src="';if(c=d.loadingIndicatorImagePath){c=c.call(k,{hash:{},data:i})}else{c=k.loadingIndicatorImagePath;c=typeof c===f?c.apply(k):c}g+=h(c)+'" />\n <span class="loading-message">';if(c=d.message){c=c.call(k,{hash:{},data:i})}else{c=k.message;c=typeof c===f?c.apply(k):c}g+=h(c)+'</span>\n </div>\n </li>\n </ul>\n\n \n <div class="tab-content">\n \n <div id="data-control" class="tab-pane active">\n \n </div>\n \n \n <div id="chart-control" class="tab-pane">\n \n </div>\n\n \n <div id="stats-display" class="tab-pane">\n \n </div>\n\n \n <div id="chart-display" class="tab-pane">\n \n </div>\n\n </div>\n</div>';return g})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-visualization-statsDisplay.js
--- a/static/scripts/packed/templates/compiled/template-visualization-statsDisplay.js
+++ b/static/scripts/packed/templates/compiled/template-visualization-statsDisplay.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-statsDisplay"]=b(function(f,p,e,n,m){e=e||f.helpers;var k="",c,r,j,i,q=this,g="function",o=e.helperMissing,h=void 0,l=this.escapeExpression;function d(v,u){var s="",t;s+="\n <tr><td>";j=e.name;t=j||v.name;if(typeof t===g){t=t.call(v,{hash:{}})}else{if(t===h){t=o.call(v,"name",{hash:{}})}}s+=l(t)+"</td><td>";j=e.xval;t=j||v.xval;if(typeof t===g){t=t.call(v,{hash:{}})}else{if(t===h){t=o.call(v,"xval",{hash:{}})}}s+=l(t)+"</td><td>";j=e.yval;t=j||v.yval;if(typeof t===g){t=t.call(v,{hash:{}})}else{if(t===h){t=o.call(v,"yval",{hash:{}})}}s+=l(t)+"</td></tr>\n </tr>\n ";return s}k+='<p class="help-text">By column:</p>\n <table id="chart-stats-table">\n <thead><th></th><th>X</th><th>Y</th></thead>\n ';j=e.stats;c=j||p.stats;r=e.each;i=q.program(1,d,m);i.hash={};i.fn=i;i.inverse=q.noop;c=r.call(p,c,i);if(c||c===0){k+=c}k+="\n </table>";return k})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-statsDisplay"]=b(function(f,l,e,k,j){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,f.helpers);j=j||{};var h="",c,g="function",i=this.escapeExpression,m=this;function d(q,p){var n="",o;n+="\n <tr><td>";if(o=e.name){o=o.call(q,{hash:{},data:p})}else{o=q.name;o=typeof o===g?o.apply(q):o}n+=i(o)+"</td><td>";if(o=e.xval){o=o.call(q,{hash:{},data:p})}else{o=q.xval;o=typeof o===g?o.apply(q):o}n+=i(o)+"</td><td>";if(o=e.yval){o=o.call(q,{hash:{},data:p})}else{o=q.yval;o=typeof o===g?o.apply(q):o}n+=i(o)+"</td></tr>\n </tr>\n ";return n}h+='<p class="help-text">By column:</p>\n <table id="chart-stats-table">\n <thead><th></th><th>X</th><th>Y</th></thead>\n ';c=e.each.call(l,l.stats,{hash:{},inverse:m.noop,fn:m.program(1,d,j),data:j});if(c||c===0){h+=c}h+="\n </table>";return h})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/template-warningmessagesmall.js
--- a/static/scripts/packed/templates/compiled/template-warningmessagesmall.js
+++ b/static/scripts/packed/templates/compiled/template-warningmessagesmall.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-warningmessagesmall"]=b(function(e,m,d,k,j){d=d||e.helpers;var i="",c,h,n=this,f="function",l=d.helperMissing,g=void 0;i+=' \n <div class="warningmessagesmall"><strong>';h=d.warning;c=h||m.warning;if(typeof c===f){c=c.call(m,{hash:{}})}else{if(c===g){c=l.call(m,"warning",{hash:{}})}}if(c||c===0){i+=c}i+="</strong></div>";return i})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-warningmessagesmall"]=b(function(i,j,f,d,g){this.compilerInfo=[4,">= 1.0.0"];f=this.merge(f,i.helpers);g=g||{};var c="",e,h="function";c+=' \n <div class="warningmessagesmall"><strong>';if(e=f.warning){e=e.call(j,{hash:{},data:g})}else{e=j.warning;e=typeof e===h?e.apply(j):e}if(e||e===0){c+=e}c+="</strong></div>";return c})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/tool_form.js
--- a/static/scripts/packed/templates/compiled/tool_form.js
+++ b/static/scripts/packed/templates/compiled/tool_form.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_form=b(function(f,l,e,k,j){this.compilerInfo=[2,">= 1.0.0-rc.3"];e=e||f.helpers;j=j||{};var h="",c,g="function",i=this.escapeExpression,m=this;function d(q,p){var n="",o;n+='\n <div class="form-row">\n <label for="';if(o=e.name){o=o.call(q,{hash:{},data:p})}else{o=q.name;o=typeof o===g?o.apply(q):o}n+=i(o)+'">';if(o=e.label){o=o.call(q,{hash:{},data:p})}else{o=q.label;o=typeof o===g?o.apply(q):o}n+=i(o)+':</label>\n <div class="form-row-input">\n ';if(o=e.html){o=o.call(q,{hash:{},data:p})}else{o=q.html;o=typeof o===g?o.apply(q):o}if(o||o===0){n+=o}n+='\n </div>\n <div class="toolParamHelp" style="clear: both;">\n ';if(o=e.help){o=o.call(q,{hash:{},data:p})}else{o=q.help;o=typeof o===g?o.apply(q):o}n+=i(o)+'\n </div>\n <div style="clear: both;"></div>\n </div>\n ';return n}h+='<div class="toolFormTitle">';if(c=e.name){c=c.call(l,{hash:{},data:j})}else{c=l.name;c=typeof c===g?c.apply(l):c}h+=i(c)+" (version ";if(c=e.version){c=c.call(l,{hash:{},data:j})}else{c=l.version;c=typeof c===g?c.apply(l):c}h+=i(c)+')</div>\n <div class="toolFormBody">\n ';c=e.each.call(l,l.inputs,{hash:{},inverse:m.noop,fn:m.program(1,d,j),data:j});if(c||c===0){h+=c}h+='\n </div>\n <div class="form-row form-actions">\n <input type="submit" class="btn btn-primary" name="runtool_btn" value="Execute">\n</div>\n<div class="toolHelp">\n <div class="toolHelpBody">';if(c=e.help){c=c.call(l,{hash:{},data:j})}else{c=l.help;c=typeof c===g?c.apply(l):c}h+=i(c)+"</div>\n</div>";return h})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_form=b(function(f,l,e,k,j){this.compilerInfo=[4,">= 1.0.0"];e=this.merge(e,f.helpers);j=j||{};var h="",c,g="function",i=this.escapeExpression,m=this;function d(q,p){var n="",o;n+='\n <div class="form-row">\n <label for="';if(o=e.name){o=o.call(q,{hash:{},data:p})}else{o=q.name;o=typeof o===g?o.apply(q):o}n+=i(o)+'">';if(o=e.label){o=o.call(q,{hash:{},data:p})}else{o=q.label;o=typeof o===g?o.apply(q):o}n+=i(o)+':</label>\n <div class="form-row-input">\n ';if(o=e.html){o=o.call(q,{hash:{},data:p})}else{o=q.html;o=typeof o===g?o.apply(q):o}if(o||o===0){n+=o}n+='\n </div>\n <div class="toolParamHelp" style="clear: both;">\n ';if(o=e.help){o=o.call(q,{hash:{},data:p})}else{o=q.help;o=typeof o===g?o.apply(q):o}n+=i(o)+'\n </div>\n <div style="clear: both;"></div>\n </div>\n ';return n}h+='<div class="toolFormTitle">';if(c=e.name){c=c.call(l,{hash:{},data:j})}else{c=l.name;c=typeof c===g?c.apply(l):c}h+=i(c)+" (version ";if(c=e.version){c=c.call(l,{hash:{},data:j})}else{c=l.version;c=typeof c===g?c.apply(l):c}h+=i(c)+')</div>\n <div class="toolFormBody">\n ';c=e.each.call(l,l.inputs,{hash:{},inverse:m.noop,fn:m.program(1,d,j),data:j});if(c||c===0){h+=c}h+='\n </div>\n <div class="form-row form-actions">\n <input type="submit" class="btn btn-primary" name="runtool_btn" value="Execute">\n</div>\n<div class="toolHelp">\n <div class="toolHelpBody">';if(c=e.help){c=c.call(l,{hash:{},data:j})}else{c=l.help;c=typeof c===g?c.apply(l):c}h+=i(c)+"</div>\n</div>";return h})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/tool_link.js
--- a/static/scripts/packed/templates/compiled/tool_link.js
+++ b/static/scripts/packed/templates/compiled/tool_link.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_link=b(function(e,k,d,j,i){this.compilerInfo=[2,">= 1.0.0-rc.3"];d=d||e.helpers;i=i||{};var g="",c,f="function",h=this.escapeExpression;g+='<a class="';if(c=d.id){c=c.call(k,{hash:{},data:i})}else{c=k.id;c=typeof c===f?c.apply(k):c}g+=h(c)+' tool-link" href="';if(c=d.link){c=c.call(k,{hash:{},data:i})}else{c=k.link;c=typeof c===f?c.apply(k):c}g+=h(c)+'" target="';if(c=d.target){c=c.call(k,{hash:{},data:i})}else{c=k.target;c=typeof c===f?c.apply(k):c}g+=h(c)+'" minsizehint="';if(c=d.min_width){c=c.call(k,{hash:{},data:i})}else{c=k.min_width;c=typeof c===f?c.apply(k):c}g+=h(c)+'">';if(c=d.name){c=c.call(k,{hash:{},data:i})}else{c=k.name;c=typeof c===f?c.apply(k):c}g+=h(c)+"</a> ";if(c=d.description){c=c.call(k,{hash:{},data:i})}else{c=k.description;c=typeof c===f?c.apply(k):c}g+=h(c);return g})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_link=b(function(e,k,d,j,i){this.compilerInfo=[4,">= 1.0.0"];d=this.merge(d,e.helpers);i=i||{};var g="",c,f="function",h=this.escapeExpression;g+='<a class="';if(c=d.id){c=c.call(k,{hash:{},data:i})}else{c=k.id;c=typeof c===f?c.apply(k):c}g+=h(c)+' tool-link" href="';if(c=d.link){c=c.call(k,{hash:{},data:i})}else{c=k.link;c=typeof c===f?c.apply(k):c}g+=h(c)+'" target="';if(c=d.target){c=c.call(k,{hash:{},data:i})}else{c=k.target;c=typeof c===f?c.apply(k):c}g+=h(c)+'" minsizehint="';if(c=d.min_width){c=c.call(k,{hash:{},data:i})}else{c=k.min_width;c=typeof c===f?c.apply(k):c}g+=h(c)+'">';if(c=d.name){c=c.call(k,{hash:{},data:i})}else{c=k.name;c=typeof c===f?c.apply(k):c}g+=h(c)+"</a> ";if(c=d.description){c=c.call(k,{hash:{},data:i})}else{c=k.description;c=typeof c===f?c.apply(k):c}g+=h(c);return g})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/packed/templates/compiled/tool_search.js
--- a/static/scripts/packed/templates/compiled/tool_search.js
+++ b/static/scripts/packed/templates/compiled/tool_search.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_search=b(function(e,k,d,j,i){this.compilerInfo=[2,">= 1.0.0-rc.3"];d=d||e.helpers;i=i||{};var g="",c,f="function",h=this.escapeExpression;g+='<input type="text" name="query" value="';if(c=d.search_hint_string){c=c.call(k,{hash:{},data:i})}else{c=k.search_hint_string;c=typeof c===f?c.apply(k):c}g+=h(c)+'" id="tool-search-query" autocomplete="off" class="search-query parent-width" />\n<a id="search-clear-btn" class="tooltip" title="clear search (esc)"></a>\n<img src="';if(c=d.spinner_url){c=c.call(k,{hash:{},data:i})}else{c=k.spinner_url;c=typeof c===f?c.apply(k):c}g+=h(c)+'" id="search-spinner" class="search-spinner"/>';return g})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_search=b(function(e,k,d,j,i){this.compilerInfo=[4,">= 1.0.0"];d=this.merge(d,e.helpers);i=i||{};var g="",c,f="function",h=this.escapeExpression;g+='<input type="text" name="query" value="';if(c=d.search_hint_string){c=c.call(k,{hash:{},data:i})}else{c=k.search_hint_string;c=typeof c===f?c.apply(k):c}g+=h(c)+'" id="tool-search-query" autocomplete="off" class="search-query parent-width" />\n<a id="search-clear-btn" class="tooltip" title="clear search (esc)"></a>\n<img src="';if(c=d.spinner_url){c=c.call(k,{hash:{},data:i})}else{c=k.spinner_url;c=typeof c===f?c.apply(k):c}g+=h(c)+'" id="search-spinner" class="search-spinner"/>';return g})})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/templates/compiled/helpers-common-templates.js
--- a/static/scripts/templates/compiled/helpers-common-templates.js
+++ b/static/scripts/templates/compiled/helpers-common-templates.js
@@ -13,31 +13,4 @@
*/
Handlebars.registerHelper( 'local', function( options ){
return _l( options.fn( this ) );
-});
-/** Renders a glx style icon-button (see IconButton in mvc/ui.js)
- * can be used in either of the following ways:
- * within a template: {{> iconButton buttonData}}
- * from js: var templated = ( Handlebars.partials.iconButton( buttonData ) );
- */
-Handlebars.registerPartial( 'iconButton', function( buttonData, options ){
- var buffer = "";
- buffer += ( buttonData.enabled )?( '<a' ):( '<span' );
-
- if( buttonData.title ){ buffer += ' title="' + buttonData.title + '"'; }
-
- buffer += ' class="icon-button';
- if( buttonData.isMenuButton ){ buffer += ' menu-button'; }
- if( buttonData.title ){ buffer += ' tooltip'; }
- buffer += ' ' + buttonData.icon_class;
- if( !buttonData.enabled ){ buffer += '_disabled'; }
- buffer += '"';
-
- if( buttonData.id ){ buffer += ' id="' + buttonData.id + '"'; }
- buffer += ' href="' + ( ( buttonData.href )?( buttonData.href ):( 'javascript:void(0);' ) ) + '"';
- if( buttonData.target ){ buffer += ' target="' + buttonData.target + '"'; }
-
- if( !buttonData.visible ){ buffer += ' style="display: none;"'; }
-
- buffer += '>' + ( ( buttonData.enabled )?( '</a>' ):( '</span>' ) );
- return buffer;
});
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/templates/compiled/panel_section.js
--- a/static/scripts/templates/compiled/panel_section.js
+++ b/static/scripts/templates/compiled/panel_section.js
@@ -1,8 +1,8 @@
(function() {
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
templates['panel_section'] = template(function (Handlebars,depth0,helpers,partials,data) {
- this.compilerInfo = [2,'>= 1.0.0-rc.3'];
-helpers = helpers || Handlebars.helpers; data = data || {};
+ this.compilerInfo = [4,'>= 1.0.0'];
+helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression;
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/templates/compiled/template-hda-annotationArea.js
--- a/static/scripts/templates/compiled/template-hda-annotationArea.js
+++ b/static/scripts/templates/compiled/template-hda-annotationArea.js
@@ -1,49 +1,43 @@
(function() {
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
templates['template-hda-annotationArea'] = template(function (Handlebars,depth0,helpers,partials,data) {
- helpers = helpers || Handlebars.helpers;
- var buffer = "", stack1, foundHelper, tmp1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression, blockHelperMissing=helpers.blockHelperMissing;
+ this.compilerInfo = [4,'>= 1.0.0'];
+helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
+ var buffer = "", stack1, options, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing;
function program1(depth0,data) {
- return "Annotation";}
+ return "Annotation";
+ }
function program3(depth0,data) {
- return "Edit dataset annotation";}
+ return "Edit dataset annotation";
+ }
buffer += "\n<div id=\"";
- foundHelper = helpers.id;
- stack1 = foundHelper || depth0.id;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "id", { hash: {} }); }
- buffer += escapeExpression(stack1) + "-annotation-area\" class=\"annotation-area\" style=\"display: none;\">\n <strong>";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(1, program1, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ if (stack1 = helpers.id) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.id; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + "-annotation-area\" class=\"annotation-area\" style=\"display: none;\">\n <strong>";
+ options = {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += ":</strong>\n <div id=\"";
- foundHelper = helpers.id;
- stack1 = foundHelper || depth0.id;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "id", { hash: {} }); }
- buffer += escapeExpression(stack1) + "-anotation-elt\" class=\"annotation-elt tooltip editable-text\"\n style=\"margin: 1px 0px 1px 0px\" title=\"";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(3, program3, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ if (stack1 = helpers.id) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.id; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + "-anotation-elt\" class=\"annotation-elt tooltip editable-text\"\n style=\"margin: 1px 0px 1px 0px\" title=\"";
+ options = {hash:{},inverse:self.noop,fn:self.program(3, program3, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\">\n </div>\n</div>";
- return buffer;});
+ return buffer;
+ });
})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/templates/compiled/template-hda-displayApps.js
--- a/static/scripts/templates/compiled/template-hda-displayApps.js
+++ b/static/scripts/templates/compiled/template-hda-displayApps.js
@@ -1,71 +1,53 @@
(function() {
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
templates['template-hda-displayApps'] = template(function (Handlebars,depth0,helpers,partials,data) {
- helpers = helpers || Handlebars.helpers;
- var stack1, stack2, foundHelper, tmp1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression, blockHelperMissing=helpers.blockHelperMissing;
+ this.compilerInfo = [4,'>= 1.0.0'];
+helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
+ var stack1, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing;
function program1(depth0,data) {
- var buffer = "", stack1, stack2;
+ var buffer = "", stack1;
buffer += "\n ";
- foundHelper = helpers.label;
- stack1 = foundHelper || depth0.label;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "label", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\n ";
- foundHelper = helpers.links;
- stack1 = foundHelper || depth0.links;
- stack2 = helpers.each;
- tmp1 = self.program(2, program2, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- stack1 = stack2.call(depth0, stack1, tmp1);
+ if (stack1 = helpers.label) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.label; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + "\n ";
+ stack1 = helpers.each.call(depth0, depth0.links, {hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n <br />\n";
- return buffer;}
+ return buffer;
+ }
function program2(depth0,data) {
- var buffer = "", stack1;
+ var buffer = "", stack1, options;
buffer += "\n <a target=\"";
- foundHelper = helpers.target;
- stack1 = foundHelper || depth0.target;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "target", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\" href=\"";
- foundHelper = helpers.href;
- stack1 = foundHelper || depth0.href;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "href", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\">";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(3, program3, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ if (stack1 = helpers.target) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.target; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + "\" href=\"";
+ if (stack1 = helpers.href) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.href; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + "\">";
+ options = {hash:{},inverse:self.noop,fn:self.program(3, program3, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "</a>\n ";
- return buffer;}
+ return buffer;
+ }
function program3(depth0,data) {
var stack1;
- foundHelper = helpers.text;
- stack1 = foundHelper || depth0.text;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "text", { hash: {} }); }
- return escapeExpression(stack1);}
+ if (stack1 = helpers.text) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.text; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ return escapeExpression(stack1);
+ }
- foundHelper = helpers.displayApps;
- stack1 = foundHelper || depth0.displayApps;
- stack2 = helpers.each;
- tmp1 = self.program(1, program1, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- stack1 = stack2.call(depth0, stack1, tmp1);
+ stack1 = helpers.each.call(depth0, depth0.displayApps, {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data});
if(stack1 || stack1 === 0) { return stack1; }
- else { return ''; }});
+ else { return ''; }
+ });
})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/templates/compiled/template-hda-downloadLinks.js
--- a/static/scripts/templates/compiled/template-hda-downloadLinks.js
+++ b/static/scripts/templates/compiled/template-hda-downloadLinks.js
@@ -1,158 +1,105 @@
(function() {
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
templates['template-hda-downloadLinks'] = template(function (Handlebars,depth0,helpers,partials,data) {
- helpers = helpers || Handlebars.helpers;
- var stack1, stack2, foundHelper, tmp1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression, blockHelperMissing=helpers.blockHelperMissing;
+ this.compilerInfo = [4,'>= 1.0.0'];
+helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
+ var stack1, stack2, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing;
function program1(depth0,data) {
- var buffer = "", stack1, stack2;
+ var buffer = "", stack1, stack2, options;
buffer += "\n<div popupmenu=\"dataset-";
- foundHelper = helpers.id;
- stack1 = foundHelper || depth0.id;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "id", { hash: {} }); }
- buffer += escapeExpression(stack1) + "-popup\">\n <a class=\"action-button\" href=\"";
- foundHelper = helpers.urls;
- stack1 = foundHelper || depth0.urls;
- stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.download);
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "urls.download", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\">";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(2, program2, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
- if(stack1 || stack1 === 0) { buffer += stack1; }
+ if (stack1 = helpers.id) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.id; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + "-popup\">\n <a class=\"action-button\" href=\""
+ + escapeExpression(((stack1 = ((stack1 = depth0.urls),stack1 == null || stack1 === false ? stack1 : stack1.download)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
+ + "\">";
+ options = {hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data};
+ if (stack2 = helpers.local) { stack2 = stack2.call(depth0, options); }
+ else { stack2 = depth0.local; stack2 = typeof stack2 === functionType ? stack2.apply(depth0) : stack2; }
+ if (!helpers.local) { stack2 = blockHelperMissing.call(depth0, stack2, options); }
+ if(stack2 || stack2 === 0) { buffer += stack2; }
buffer += "</a>\n <a>";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(4, program4, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
- if(stack1 || stack1 === 0) { buffer += stack1; }
+ options = {hash:{},inverse:self.noop,fn:self.program(4, program4, data),data:data};
+ if (stack2 = helpers.local) { stack2 = stack2.call(depth0, options); }
+ else { stack2 = depth0.local; stack2 = typeof stack2 === functionType ? stack2.apply(depth0) : stack2; }
+ if (!helpers.local) { stack2 = blockHelperMissing.call(depth0, stack2, options); }
+ if(stack2 || stack2 === 0) { buffer += stack2; }
buffer += "</a>\n ";
- foundHelper = helpers.urls;
- stack1 = foundHelper || depth0.urls;
- stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.meta_download);
- stack2 = helpers.each;
- tmp1 = self.program(6, program6, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- stack1 = stack2.call(depth0, stack1, tmp1);
- if(stack1 || stack1 === 0) { buffer += stack1; }
+ stack2 = helpers.each.call(depth0, ((stack1 = depth0.urls),stack1 == null || stack1 === false ? stack1 : stack1.meta_download), {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data});
+ if(stack2 || stack2 === 0) { buffer += stack2; }
buffer += "\n</div>\n<div style=\"float:left;\" class=\"menubutton split popup\" id=\"dataset-";
- foundHelper = helpers.id;
- stack1 = foundHelper || depth0.id;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "id", { hash: {} }); }
- buffer += escapeExpression(stack1) + "-popup\">\n <a href=\"";
- foundHelper = helpers.urls;
- stack1 = foundHelper || depth0.urls;
- stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.download);
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "urls.download", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\" title=\"";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(9, program9, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
- if(stack1 || stack1 === 0) { buffer += stack1; }
+ if (stack2 = helpers.id) { stack2 = stack2.call(depth0, {hash:{},data:data}); }
+ else { stack2 = depth0.id; stack2 = typeof stack2 === functionType ? stack2.apply(depth0) : stack2; }
+ buffer += escapeExpression(stack2)
+ + "-popup\">\n <a href=\""
+ + escapeExpression(((stack1 = ((stack1 = depth0.urls),stack1 == null || stack1 === false ? stack1 : stack1.download)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
+ + "\" title=\"";
+ options = {hash:{},inverse:self.noop,fn:self.program(7, program7, data),data:data};
+ if (stack2 = helpers.local) { stack2 = stack2.call(depth0, options); }
+ else { stack2 = depth0.local; stack2 = typeof stack2 === functionType ? stack2.apply(depth0) : stack2; }
+ if (!helpers.local) { stack2 = blockHelperMissing.call(depth0, stack2, options); }
+ if(stack2 || stack2 === 0) { buffer += stack2; }
buffer += "\" class=\"icon-button disk tooltip\"></a>\n</div>\n";
- return buffer;}
+ return buffer;
+ }
function program2(depth0,data) {
- return "Download Dataset";}
+ return "Download Dataset";
+ }
function program4(depth0,data) {
- return "Additional Files";}
+ return "Additional Files";
+ }
function program6(depth0,data) {
- var buffer = "", stack1;
+ var buffer = "", stack1, options;
buffer += "\n <a class=\"action-button\" href=\"";
- foundHelper = helpers.url;
- stack1 = foundHelper || depth0.url;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "url", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\">";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(7, program7, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ if (stack1 = helpers.url) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.url; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + "\">";
+ options = {hash:{},inverse:self.noop,fn:self.program(7, program7, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += " ";
- foundHelper = helpers.file_type;
- stack1 = foundHelper || depth0.file_type;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "file_type", { hash: {} }); }
- buffer += escapeExpression(stack1) + "</a>\n ";
- return buffer;}
+ if (stack1 = helpers.file_type) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.file_type; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + "</a>\n ";
+ return buffer;
+ }
function program7(depth0,data) {
- return "Download";}
+ return "Download";
+ }
function program9(depth0,data) {
-
- return "Download";}
+ var buffer = "", stack1, stack2, options;
+ buffer += "\n"
+ + "\n<a href=\""
+ + escapeExpression(((stack1 = ((stack1 = depth0.urls),stack1 == null || stack1 === false ? stack1 : stack1.download)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
+ + "\" title=\"";
+ options = {hash:{},inverse:self.noop,fn:self.program(7, program7, data),data:data};
+ if (stack2 = helpers.local) { stack2 = stack2.call(depth0, options); }
+ else { stack2 = depth0.local; stack2 = typeof stack2 === functionType ? stack2.apply(depth0) : stack2; }
+ if (!helpers.local) { stack2 = blockHelperMissing.call(depth0, stack2, options); }
+ if(stack2 || stack2 === 0) { buffer += stack2; }
+ buffer += "\" class=\"icon-button disk tooltip\"></a>\n";
+ return buffer;
+ }
-function program11(depth0,data) {
-
- var buffer = "", stack1;
- buffer += "\n";
- buffer += "\n<a href=\"";
- foundHelper = helpers.urls;
- stack1 = foundHelper || depth0.urls;
- stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.download);
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "urls.download", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\" title=\"";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(12, program12, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
- if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\" class=\"icon-button disk tooltip\"></a>\n";
- return buffer;}
-function program12(depth0,data) {
-
-
- return "Download";}
-
- foundHelper = helpers.urls;
- stack1 = foundHelper || depth0.urls;
- stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.meta_download);
- stack2 = helpers['if'];
- tmp1 = self.program(1, program1, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.program(11, program11, data);
- stack1 = stack2.call(depth0, stack1, tmp1);
- if(stack1 || stack1 === 0) { return stack1; }
- else { return ''; }});
+ stack2 = helpers['if'].call(depth0, ((stack1 = depth0.urls),stack1 == null || stack1 === false ? stack1 : stack1.meta_download), {hash:{},inverse:self.program(9, program9, data),fn:self.program(1, program1, data),data:data});
+ if(stack2 || stack2 === 0) { return stack2; }
+ else { return ''; }
+ });
})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/templates/compiled/template-hda-failedMetadata.js
--- a/static/scripts/templates/compiled/template-hda-failedMetadata.js
+++ b/static/scripts/templates/compiled/template-hda-failedMetadata.js
@@ -1,43 +1,35 @@
(function() {
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
templates['template-hda-failedMetadata'] = template(function (Handlebars,depth0,helpers,partials,data) {
- helpers = helpers || Handlebars.helpers;
- var stack1, foundHelper, tmp1, self=this, functionType="function", blockHelperMissing=helpers.blockHelperMissing, helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression;
+ this.compilerInfo = [4,'>= 1.0.0'];
+helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
+ var stack1, options, self=this, functionType="function", blockHelperMissing=helpers.blockHelperMissing, escapeExpression=this.escapeExpression;
function program1(depth0,data) {
- var buffer = "", stack1;
+ var buffer = "", stack1, options;
buffer += "\n";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(2, program2, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ options = {hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\nYou may be able to <a href=\"";
- foundHelper = helpers.urls;
- stack1 = foundHelper || depth0.urls;
- stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.edit);
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "urls.edit", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\" target=\"galaxy_main\">set it manually or retry auto-detection</a>.\n";
- return buffer;}
+ buffer += "\nYou may be able to <a href=\""
+ + escapeExpression(((stack1 = ((stack1 = depth0.urls),stack1 == null || stack1 === false ? stack1 : stack1.edit)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
+ + "\" target=\"galaxy_main\">set it manually or retry auto-detection</a>.\n";
+ return buffer;
+ }
function program2(depth0,data) {
- return "An error occurred setting the metadata for this dataset.";}
+ return "An error occurred setting the metadata for this dataset.";
+ }
- foundHelper = helpers.warningmessagesmall;
- stack1 = foundHelper || depth0.warningmessagesmall;
- tmp1 = self.program(1, program1, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ options = {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data};
+ if (stack1 = helpers.warningmessagesmall) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.warningmessagesmall; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.warningmessagesmall) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { return stack1; }
- else { return ''; }});
+ else { return ''; }
+ });
})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/templates/compiled/template-hda-hdaSummary.js
--- a/static/scripts/templates/compiled/template-hda-hdaSummary.js
+++ b/static/scripts/templates/compiled/template-hda-hdaSummary.js
@@ -1,117 +1,91 @@
(function() {
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
templates['template-hda-hdaSummary'] = template(function (Handlebars,depth0,helpers,partials,data) {
- helpers = helpers || Handlebars.helpers;
- var buffer = "", stack1, stack2, foundHelper, tmp1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression, blockHelperMissing=helpers.blockHelperMissing;
+ this.compilerInfo = [4,'>= 1.0.0'];
+helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
+ var buffer = "", stack1, options, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing;
function program1(depth0,data) {
- return "format: ";}
+ return "format: ";
+ }
function program3(depth0,data) {
- return "database: ";}
+ return "database: ";
+ }
function program5(depth0,data) {
- var buffer = "", stack1;
- buffer += "\n <a class=\"metadata-dbkey\" href=\"";
- foundHelper = helpers.urls;
- stack1 = foundHelper || depth0.urls;
- stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.edit);
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "urls.edit", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\" target=\"galaxy_main\">";
- foundHelper = helpers.metadata_dbkey;
- stack1 = foundHelper || depth0.metadata_dbkey;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "metadata_dbkey", { hash: {} }); }
- buffer += escapeExpression(stack1) + "</a>\n ";
- return buffer;}
+ var buffer = "", stack1, stack2;
+ buffer += "\n <a class=\"metadata-dbkey\" href=\""
+ + escapeExpression(((stack1 = ((stack1 = depth0.urls),stack1 == null || stack1 === false ? stack1 : stack1.edit)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
+ + "\" target=\"galaxy_main\">";
+ if (stack2 = helpers.metadata_dbkey) { stack2 = stack2.call(depth0, {hash:{},data:data}); }
+ else { stack2 = depth0.metadata_dbkey; stack2 = typeof stack2 === functionType ? stack2.apply(depth0) : stack2; }
+ buffer += escapeExpression(stack2)
+ + "</a>\n ";
+ return buffer;
+ }
function program7(depth0,data) {
var buffer = "", stack1;
buffer += "\n <span class=\"metadata-dbkey ";
- foundHelper = helpers.metadata_dbkey;
- stack1 = foundHelper || depth0.metadata_dbkey;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "metadata_dbkey", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\">";
- foundHelper = helpers.metadata_dbkey;
- stack1 = foundHelper || depth0.metadata_dbkey;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "metadata_dbkey", { hash: {} }); }
- buffer += escapeExpression(stack1) + "</span>\n ";
- return buffer;}
+ if (stack1 = helpers.metadata_dbkey) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.metadata_dbkey; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + "\">";
+ if (stack1 = helpers.metadata_dbkey) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.metadata_dbkey; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + "</span>\n ";
+ return buffer;
+ }
function program9(depth0,data) {
var buffer = "", stack1;
buffer += "\n<div class=\"hda-info\"> ";
- foundHelper = helpers.misc_info;
- stack1 = foundHelper || depth0.misc_info;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "misc_info", { hash: {} }); }
- buffer += escapeExpression(stack1) + " </div>\n";
- return buffer;}
+ if (stack1 = helpers.misc_info) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.misc_info; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + " </div>\n";
+ return buffer;
+ }
buffer += "<div class=\"hda-summary\">\n ";
- foundHelper = helpers.misc_blurb;
- stack1 = foundHelper || depth0.misc_blurb;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "misc_blurb", { hash: {} }); }
- buffer += escapeExpression(stack1) + "<br />\n ";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(1, program1, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ if (stack1 = helpers.misc_blurb) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.misc_blurb; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + "<br />\n ";
+ options = {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "<span class=\"";
- foundHelper = helpers.data_type;
- stack1 = foundHelper || depth0.data_type;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "data_type", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\">";
- foundHelper = helpers.data_type;
- stack1 = foundHelper || depth0.data_type;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "data_type", { hash: {} }); }
- buffer += escapeExpression(stack1) + "</span>,\n ";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(3, program3, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ if (stack1 = helpers.data_type) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.data_type; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + "\">";
+ if (stack1 = helpers.data_type) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.data_type; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + "</span>,\n ";
+ options = {hash:{},inverse:self.noop,fn:self.program(3, program3, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n ";
- foundHelper = helpers.dbkey_unknown_and_editable;
- stack1 = foundHelper || depth0.dbkey_unknown_and_editable;
- stack2 = helpers['if'];
- tmp1 = self.program(5, program5, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.program(7, program7, data);
- stack1 = stack2.call(depth0, stack1, tmp1);
+ stack1 = helpers['if'].call(depth0, depth0.dbkey_unknown_and_editable, {hash:{},inverse:self.program(7, program7, data),fn:self.program(5, program5, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n</div>\n";
- foundHelper = helpers.misc_info;
- stack1 = foundHelper || depth0.misc_info;
- stack2 = helpers['if'];
- tmp1 = self.program(9, program9, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- stack1 = stack2.call(depth0, stack1, tmp1);
+ stack1 = helpers['if'].call(depth0, depth0.misc_info, {hash:{},inverse:self.noop,fn:self.program(9, program9, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
- return buffer;});
+ return buffer;
+ });
})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/templates/compiled/template-hda-tagArea.js
--- a/static/scripts/templates/compiled/template-hda-tagArea.js
+++ b/static/scripts/templates/compiled/template-hda-tagArea.js
@@ -1,24 +1,23 @@
(function() {
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
templates['template-hda-tagArea'] = template(function (Handlebars,depth0,helpers,partials,data) {
- helpers = helpers || Handlebars.helpers;
- var buffer = "", stack1, foundHelper, tmp1, self=this, functionType="function", blockHelperMissing=helpers.blockHelperMissing;
+ this.compilerInfo = [4,'>= 1.0.0'];
+helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
+ var buffer = "", stack1, options, self=this, functionType="function", blockHelperMissing=helpers.blockHelperMissing;
function program1(depth0,data) {
- return "Tags";}
+ return "Tags";
+ }
buffer += "\n<div class=\"tag-area\" style=\"display: none;\">\n <strong>";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(1, program1, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ options = {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += ":</strong>\n <div class=\"tag-elt\">\n </div>\n</div>";
- return buffer;});
+ return buffer;
+ });
})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/templates/compiled/template-hda-titleLink.js
--- a/static/scripts/templates/compiled/template-hda-titleLink.js
+++ b/static/scripts/templates/compiled/template-hda-titleLink.js
@@ -1,20 +1,20 @@
(function() {
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
templates['template-hda-titleLink'] = template(function (Handlebars,depth0,helpers,partials,data) {
- helpers = helpers || Handlebars.helpers;
- var buffer = "", stack1, foundHelper, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression;
+ this.compilerInfo = [4,'>= 1.0.0'];
+helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
+ var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression;
buffer += "<span class=\"historyItemTitle\">";
- foundHelper = helpers.hid;
- stack1 = foundHelper || depth0.hid;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "hid", { hash: {} }); }
- buffer += escapeExpression(stack1) + ": ";
- foundHelper = helpers.name;
- stack1 = foundHelper || depth0.name;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); }
- buffer += escapeExpression(stack1) + "</span>";
- return buffer;});
+ if (stack1 = helpers.hid) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.hid; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + ": ";
+ if (stack1 = helpers.name) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.name; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ buffer += escapeExpression(stack1)
+ + "</span>";
+ return buffer;
+ });
})();
\ No newline at end of file
diff -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef -r 1f45ab84c1217c0b65a840a90ef60ff267d0d946 static/scripts/templates/compiled/template-hda-warning-messages.js
--- a/static/scripts/templates/compiled/template-hda-warning-messages.js
+++ b/static/scripts/templates/compiled/template-hda-warning-messages.js
@@ -1,284 +1,194 @@
(function() {
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
templates['template-hda-warning-messages'] = template(function (Handlebars,depth0,helpers,partials,data) {
- helpers = helpers || Handlebars.helpers;
- var buffer = "", stack1, stack2, foundHelper, tmp1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression, blockHelperMissing=helpers.blockHelperMissing;
+ this.compilerInfo = [4,'>= 1.0.0'];
+helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
+ var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression, self=this, blockHelperMissing=helpers.blockHelperMissing;
function program1(depth0,data) {
- var buffer = "", stack1;
+ var buffer = "", stack1, options;
buffer += "\n<div class=\"errormessagesmall\">\n ";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(2, program2, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ options = {hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += ":\n ";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(4, program4, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ options = {hash:{},inverse:self.noop,fn:self.program(4, program4, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n</div>\n";
- return buffer;}
+ return buffer;
+ }
function program2(depth0,data) {
- return "There was an error getting the data for this dataset";}
+ return "There was an error getting the data for this dataset";
+ }
function program4(depth0,data) {
var stack1;
- foundHelper = helpers.error;
- stack1 = foundHelper || depth0.error;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "error", { hash: {} }); }
- return escapeExpression(stack1);}
+ if (stack1 = helpers.error) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+ else { stack1 = depth0.error; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ return escapeExpression(stack1);
+ }
function program6(depth0,data) {
- var stack1, stack2;
- foundHelper = helpers.purged;
- stack1 = foundHelper || depth0.purged;
- stack2 = helpers.unless;
- tmp1 = self.program(7, program7, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- stack1 = stack2.call(depth0, stack1, tmp1);
+ var stack1;
+ stack1 = helpers.unless.call(depth0, depth0.purged, {hash:{},inverse:self.noop,fn:self.program(7, program7, data),data:data});
if(stack1 || stack1 === 0) { return stack1; }
- else { return ''; }}
+ else { return ''; }
+ }
function program7(depth0,data) {
- var buffer = "", stack1;
+ var buffer = "", stack1, options;
buffer += "\n";
- foundHelper = helpers.warningmessagesmall;
- stack1 = foundHelper || depth0.warningmessagesmall;
- tmp1 = self.program(8, program8, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ options = {hash:{},inverse:self.noop,fn:self.program(8, program8, data),data:data};
+ if (stack1 = helpers.warningmessagesmall) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.warningmessagesmall; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.warningmessagesmall) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n";
- return buffer;}
+ return buffer;
+ }
function program8(depth0,data) {
- var buffer = "", stack1, stack2;
+ var buffer = "", stack1, stack2, options;
buffer += "\n ";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(9, program9, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ options = {hash:{},inverse:self.noop,fn:self.program(9, program9, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n ";
- foundHelper = helpers.urls;
- stack1 = foundHelper || depth0.urls;
- stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.undelete);
- stack2 = helpers['if'];
- tmp1 = self.program(11, program11, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- stack1 = stack2.call(depth0, stack1, tmp1);
- if(stack1 || stack1 === 0) { buffer += stack1; }
+ stack2 = helpers['if'].call(depth0, ((stack1 = depth0.urls),stack1 == null || stack1 === false ? stack1 : stack1.undelete), {hash:{},inverse:self.noop,fn:self.program(11, program11, data),data:data});
+ if(stack2 || stack2 === 0) { buffer += stack2; }
buffer += "\n";
- return buffer;}
+ return buffer;
+ }
function program9(depth0,data) {
- return "This dataset has been deleted.";}
+ return "This dataset has been deleted.";
+ }
function program11(depth0,data) {
var buffer = "", stack1, stack2;
- buffer += "\n ";
- buffer += "\n Click <a href=\"";
- foundHelper = helpers.urls;
- stack1 = foundHelper || depth0.urls;
- stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.undelete);
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "urls.undelete", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\" class=\"historyItemUndelete\" id=\"historyItemUndeleter-";
- foundHelper = helpers.id;
- stack1 = foundHelper || depth0.id;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "id", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\"\n target=\"galaxy_history\">here</a> to undelete it\n ";
- foundHelper = helpers.urls;
- stack1 = foundHelper || depth0.urls;
- stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.purge);
- stack2 = helpers['if'];
- tmp1 = self.program(12, program12, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- stack1 = stack2.call(depth0, stack1, tmp1);
- if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n "
+ + "\n Click <a href=\""
+ + escapeExpression(((stack1 = ((stack1 = depth0.urls),stack1 == null || stack1 === false ? stack1 : stack1.undelete)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
+ + "\" class=\"historyItemUndelete\" id=\"historyItemUndeleter-";
+ if (stack2 = helpers.id) { stack2 = stack2.call(depth0, {hash:{},data:data}); }
+ else { stack2 = depth0.id; stack2 = typeof stack2 === functionType ? stack2.apply(depth0) : stack2; }
+ buffer += escapeExpression(stack2)
+ + "\"\n target=\"galaxy_history\">here</a> to undelete it\n ";
+ stack2 = helpers['if'].call(depth0, ((stack1 = depth0.urls),stack1 == null || stack1 === false ? stack1 : stack1.purge), {hash:{},inverse:self.noop,fn:self.program(12, program12, data),data:data});
+ if(stack2 || stack2 === 0) { buffer += stack2; }
buffer += "\n ";
- return buffer;}
+ return buffer;
+ }
function program12(depth0,data) {
- var buffer = "", stack1;
- buffer += "\n or <a href=\"";
- foundHelper = helpers.urls;
- stack1 = foundHelper || depth0.urls;
- stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.purge);
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "urls.purge", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\" class=\"historyItemPurge\" id=\"historyItemPurger-";
- foundHelper = helpers.id;
- stack1 = foundHelper || depth0.id;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "id", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\"\n target=\"galaxy_history\">here</a> to immediately remove it from disk\n ";
- return buffer;}
+ var buffer = "", stack1, stack2;
+ buffer += "\n or <a href=\""
+ + escapeExpression(((stack1 = ((stack1 = depth0.urls),stack1 == null || stack1 === false ? stack1 : stack1.purge)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
+ + "\" class=\"historyItemPurge\" id=\"historyItemPurger-";
+ if (stack2 = helpers.id) { stack2 = stack2.call(depth0, {hash:{},data:data}); }
+ else { stack2 = depth0.id; stack2 = typeof stack2 === functionType ? stack2.apply(depth0) : stack2; }
+ buffer += escapeExpression(stack2)
+ + "\"\n target=\"galaxy_history\">here</a> to immediately remove it from disk\n ";
+ return buffer;
+ }
function program14(depth0,data) {
- var stack1;
- foundHelper = helpers.warningmessagesmall;
- stack1 = foundHelper || depth0.warningmessagesmall;
- tmp1 = self.program(15, program15, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ var stack1, options;
+ options = {hash:{},inverse:self.noop,fn:self.program(15, program15, data),data:data};
+ if (stack1 = helpers.warningmessagesmall) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.warningmessagesmall; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.warningmessagesmall) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { return stack1; }
- else { return ''; }}
+ else { return ''; }
+ }
function program15(depth0,data) {
- var buffer = "", stack1;
+ var buffer = "", stack1, options;
buffer += "\n ";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(16, program16, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ options = {hash:{},inverse:self.noop,fn:self.program(16, program16, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n";
- return buffer;}
+ return buffer;
+ }
function program16(depth0,data) {
- return "This dataset has been deleted and removed from disk.";}
+ return "This dataset has been deleted and removed from disk.";
+ }
function program18(depth0,data) {
- var stack1;
- foundHelper = helpers.warningmessagesmall;
- stack1 = foundHelper || depth0.warningmessagesmall;
- tmp1 = self.program(19, program19, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ var stack1, options;
+ options = {hash:{},inverse:self.noop,fn:self.program(19, program19, data),data:data};
+ if (stack1 = helpers.warningmessagesmall) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.warningmessagesmall; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.warningmessagesmall) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { return stack1; }
- else { return ''; }}
+ else { return ''; }
+ }
function program19(depth0,data) {
- var buffer = "", stack1, stack2;
+ var buffer = "", stack1, stack2, options;
buffer += "\n ";
- foundHelper = helpers.local;
- stack1 = foundHelper || depth0.local;
- tmp1 = self.program(20, program20, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- if(foundHelper && typeof stack1 === functionType) { stack1 = stack1.call(depth0, tmp1); }
- else { stack1 = blockHelperMissing.call(depth0, stack1, tmp1); }
+ options = {hash:{},inverse:self.noop,fn:self.program(20, program20, data),data:data};
+ if (stack1 = helpers.local) { stack1 = stack1.call(depth0, options); }
+ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+ if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n ";
- foundHelper = helpers.urls;
- stack1 = foundHelper || depth0.urls;
- stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.unhide);
- stack2 = helpers['if'];
- tmp1 = self.program(22, program22, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- stack1 = stack2.call(depth0, stack1, tmp1);
- if(stack1 || stack1 === 0) { buffer += stack1; }
+ stack2 = helpers['if'].call(depth0, ((stack1 = depth0.urls),stack1 == null || stack1 === false ? stack1 : stack1.unhide), {hash:{},inverse:self.noop,fn:self.program(22, program22, data),data:data});
+ if(stack2 || stack2 === 0) { buffer += stack2; }
buffer += "\n";
- return buffer;}
+ return buffer;
+ }
function program20(depth0,data) {
- return "This dataset has been hidden.";}
+ return "This dataset has been hidden.";
+ }
function program22(depth0,data) {
- var buffer = "", stack1;
- buffer += "\n Click <a href=\"";
- foundHelper = helpers.urls;
- stack1 = foundHelper || depth0.urls;
- stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.unhide);
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "urls.unhide", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\" class=\"historyItemUnhide\" id=\"historyItemUnhider-";
- foundHelper = helpers.id;
- stack1 = foundHelper || depth0.id;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "id", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\"\n target=\"galaxy_history\">here</a> to unhide it\n ";
- return buffer;}
+ var buffer = "", stack1, stack2;
+ buffer += "\n Click <a href=\""
+ + escapeExpression(((stack1 = ((stack1 = depth0.urls),stack1 == null || stack1 === false ? stack1 : stack1.unhide)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
+ + "\" class=\"historyItemUnhide\" id=\"historyItemUnhider-";
+ if (stack2 = helpers.id) { stack2 = stack2.call(depth0, {hash:{},data:data}); }
+ else { stack2 = depth0.id; stack2 = typeof stack2 === functionType ? stack2.apply(depth0) : stack2; }
+ buffer += escapeExpression(stack2)
+ + "\"\n target=\"galaxy_history\">here</a> to unhide it\n ";
+ return buffer;
+ }
- foundHelper = helpers.error;
- stack1 = foundHelper || depth0.error;
- stack2 = helpers['if'];
- tmp1 = self.program(1, program1, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- stack1 = stack2.call(depth0, stack1, tmp1);
+ stack1 = helpers['if'].call(depth0, depth0.error, {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n\n";
- foundHelper = helpers.deleted;
- stack1 = foundHelper || depth0.deleted;
- stack2 = helpers['if'];
- tmp1 = self.program(6, program6, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- stack1 = stack2.call(depth0, stack1, tmp1);
+ stack1 = helpers['if'].call(depth0, depth0.deleted, {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n\n";
- foundHelper = helpers.purged;
- stack1 = foundHelper || depth0.purged;
- stack2 = helpers['if'];
- tmp1 = self.program(14, program14, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- stack1 = stack2.call(depth0, stack1, tmp1);
+ stack1 = helpers['if'].call(depth0, depth0.purged, {hash:{},inverse:self.noop,fn:self.program(14, program14, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n\n";
- foundHelper = helpers.visible;
- stack1 = foundHelper || depth0.visible;
- stack2 = helpers.unless;
- tmp1 = self.program(18, program18, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- stack1 = stack2.call(depth0, stack1, tmp1);
+ stack1 = helpers.unless.call(depth0, depth0.visible, {hash:{},inverse:self.noop,fn:self.program(18, program18, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
- return buffer;});
+ return buffer;
+ });
})();
\ No newline at end of file
This diff is so big that we needed to truncate the remainder.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: Bowtie2: Update test case
by commits-noreply@bitbucket.org 08 Aug '13
by commits-noreply@bitbucket.org 08 Aug '13
08 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/0d6d8af41543/
Changeset: 0d6d8af41543
User: guerler
Date: 2013-08-07 20:44:17
Summary: Bowtie2: Update test case
Affected #: 1 file
diff -r fff3d1c445f81fa43d5cfbce06b6445375cb6986 -r 0d6d8af4154353a60ab3c8d95d80a0b2447409ef test-data/bowtie2/phix_mapped.bam
Binary file test-data/bowtie2/phix_mapped.bam has changed
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: Bowtie2: Update test case
by commits-noreply@bitbucket.org 08 Aug '13
by commits-noreply@bitbucket.org 08 Aug '13
08 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/fff3d1c445f8/
Changeset: fff3d1c445f8
User: guerler
Date: 2013-08-07 20:40:09
Summary: Bowtie2: Update test case
Affected #: 1 file
diff -r 446e2fee6b8f978472e67031f429aeda6cdfffdd -r fff3d1c445f81fa43d5cfbce06b6445375cb6986 test-data/bowtie2/phix_mapped.bam
Binary file test-data/bowtie2/phix_mapped.bam has changed
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