galaxy-commits
Threads by month
- ----- 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: Remove Whoosh handling for Python version 2.4 and remove minscore when searching.
by Bitbucket 12 Oct '12
by Bitbucket 12 Oct '12
12 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/18ab38e43d8b/
changeset: 18ab38e43d8b
user: jgoecks
date: 2012-10-12 04:37:44
summary: Remove Whoosh handling for Python version 2.4 and remove minscore when searching.
affected #: 1 file
diff -r d9e8a7eee7aac7e0ed15fce27592eb0182144889 -r 18ab38e43d8bf4e95b64b1939f243c370fdad2d9 lib/galaxy/tools/search/__init__.py
--- a/lib/galaxy/tools/search/__init__.py
+++ b/lib/galaxy/tools/search/__init__.py
@@ -1,19 +1,13 @@
from galaxy.eggs import require
from galaxy.web.framework.helpers import to_unicode
-# Whoosh is compatible with Python 2.5+ Try to import Whoosh and set flag to indicate whether tool search is enabled.
-try:
- require( "Whoosh" )
+require( "Whoosh" )
- from whoosh.filedb.filestore import RamStorage
- from whoosh.fields import Schema, STORED, ID, KEYWORD, TEXT
- from whoosh.index import Index
- from whoosh.scoring import BM25F
- from whoosh.qparser import MultifieldParser
- tool_search_enabled = True
- schema = Schema( id = STORED, title = TEXT, description = TEXT, help = TEXT )
-except ImportError, e:
- tool_search_enabled = False
- schema = None
+from whoosh.filedb.filestore import RamStorage
+from whoosh.fields import Schema, STORED, ID, KEYWORD, TEXT
+from whoosh.index import Index
+from whoosh.scoring import BM25F
+from whoosh.qparser import MultifieldParser
+schema = Schema( id = STORED, title = TEXT, description = TEXT, help = TEXT )
class ToolBoxSearch( object ):
"""
@@ -26,9 +20,7 @@
Create a searcher for `toolbox`.
"""
self.toolbox = toolbox
- self.enabled = tool_search_enabled
- if tool_search_enabled:
- self.build_index()
+ self.build_index()
def build_index( self ):
self.storage = RamStorage()
@@ -40,13 +32,11 @@
writer.commit()
def search( self, query, return_attribute='id' ):
- if not tool_search_enabled:
- return []
# Change field boosts for searcher to place more weight on title, description than help.
searcher = self.index.searcher( \
weighting=BM25F( field_B={ 'title_B' : 3, 'description_B' : 2, 'help_B' : 1 } \
) )
# Set query to search title, description, and help.
parser = MultifieldParser( [ 'title', 'description', 'help' ], schema = schema )
- results = searcher.search( parser.parse( query ), minscore=2.0 )
+ results = searcher.search( parser.parse( query ) )
return [ result[ return_attribute ] for result in results ]
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: scatterplot.js: fixes after testing; utils/LazyDataLoader.js: basic lazy ajax loading object;
by Bitbucket 11 Oct '12
by Bitbucket 11 Oct '12
11 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/d9e8a7eee7aa/
changeset: d9e8a7eee7aa
user: carlfeberhard
date: 2012-10-11 23:25:51
summary: scatterplot.js: fixes after testing; utils/LazyDataLoader.js: basic lazy ajax loading object;
affected #: 3 files
diff -r 419d87dd65149285d6c9f0043ea898b365d2dbde -r d9e8a7eee7aac7e0ed15fce27592eb0182144889 static/scripts/utils/LazyDataLoader.js
--- /dev/null
+++ b/static/scripts/utils/LazyDataLoader.js
@@ -0,0 +1,183 @@
+/*
+TODO:
+ ?? superclass dataloader, subclass lazydataloader??
+
+*/
+//==============================================================================
+/**
+ * Object to progressively load JSON data from a REST url, delaying some time between loading chunks
+ *
+ * Data from ajax loading is aggregated in a list, with one element for each ajax response.
+ * It's up to the calling code to combine the results in a meaningful, correct way
+ *
+ * example:
+ * var loader = new scatterplot.LazyDataLoader({
+ * //logger : console,
+ * url : ( apiDatasetsURL + '/' + hda.id + '?data_type=raw_data'
+ * + '&columns=[10,14]' ),
+ * total : hda.metadata_data_lines,
+ * size : 500,
+ *
+ * initialize : function( config ){
+ * // ... do some stuff
+ * },
+ *
+ * buildUrl : function( start, size ){
+ * // change the formation of start, size in query string
+ * return loader.url + '&' + jQuery.param({
+ * start_val: start,
+ * max_vals: size
+ * });
+ * },
+ *
+ * loadedPartialEvent : 'loader.partial',
+ * loadedAllEvent : 'loader.all',
+ * });
+ * $( loader ).bind( 'loader.partial', function( event, data ){
+ * console.info( 'partial load complete:', event, data );
+ * // ... do stuff with new data
+ * });
+ * $( loader ).bind( 'loader.all', function( event, data ){
+ * console.info( 'final load complete:', event, data );
+ * // ... do stuff with all data
+ * });
+ *
+ * loader.load( function( dataArray ){ console.debug( 'FINISHED!', x, y, z ); } );
+ */
+function LazyDataLoader( config ){
+ // for now assume:
+ // get, async, and params sent via url query string
+ // we want json
+ // we know the size of the data on the server beforehand
+ var loader = this;
+
+ jQuery.extend( loader, LoggableMixin );
+ jQuery.extend( loader, {
+
+ //NOTE: the next two need to be sent in config (required)
+ // total size of data on server
+ total : undefined,
+ // url of service to get the data
+ url : undefined,
+
+ // holds the interval id for the current load delay
+ currentIntervalId : undefined,
+
+ // optional events to trigger when partial, last data are loaded
+ // loadedPartialEvent will be sent: the ajax response data, start value, and size
+ loadedPartialEvent : undefined,
+ // loadedAllEvent will be sent: the final loader's data array and the total
+ loadedAllEvent : undefined,
+
+ // each load call will add an element to this array
+ // it's the responsibility of the code using this to combine them properly
+ data : [],
+ // ms btwn recursive loads
+ delay : 500,
+ // starting line, element, whatever
+ start : 0,
+ // size to fetch per load
+ size : 1000,
+
+ // loader init func: extends loader with config and calls config.init if there
+ //@param {object} config : object containing variables to override (or additional)
+ initialize : function( config ){
+ jQuery.extend( loader, config );
+
+ // call the custom initialize function if any
+ // only dangerous if the user tries LazyDataLoader.prototype.init
+ if( config.hasOwnProperty( 'initialize' ) ){
+ config.initialize.call( loader, config );
+ }
+
+ // ensure necessary stuff
+ if( !loader.total ){ throw( loader + ' requires a total (total size of the data)' ); }
+ if( !loader.url ){ throw( loader + ' requires a url' ); }
+
+ this.log( this + ' initialized:', loader );
+ },
+
+ // returns query string formatted start and size (for the next fetch) appended to the loader.url
+ //OVERRIDE: to change how params are passed, param names, etc.
+ //@param {int} start : the line/row/datum indicating where in the dataset the next load begins
+ //@param {int} size : the number of lines/rows/data to get on the next load
+ buildUrl : function( start, size ){
+ // currently VERY SPECIFIC to using data_providers.py start_val, max_vals params
+ return loader.url + '&' + jQuery.param({
+ start_val: start,
+ max_vals: size
+ });
+ },
+
+ //OVERRIDE: to handle ajax errors differently
+ ajaxErrorFn : function( xhr, status, error ){
+ alert( loader + ' ERROR:' + status + '\n' + error );
+ },
+
+ // interface to begin load (and first recursive call)
+ //@param {Function} callback : function to execute when all data is loaded. callback is passed loader.data
+ load : function( callback ){
+
+ // subsequent recursive calls
+ function loadHelper( start, size ){
+ loader.log( loader + '.loadHelper, start:', start, 'size:', size );
+ var url = loader.buildUrl( start, size );
+ loader.log( '\t url:', url );
+
+ jQuery.ajax({
+ url : loader.buildUrl( start, size ),
+ dataType : 'json',
+ error : function( xhr, status, error ){
+ loader.log( '\t ajax error, status:', status, 'error:', error );
+ if( loader.currentIntervalId ){
+ clearInterval( loader.currentIntervalId );
+ }
+ loader.ajaxErrorFn( xhr, status, error );
+ },
+
+ success : function( response ){
+ var next = start + size,
+ remainder = Math.min( loader.total - next, loader.size );
+ loader.log( '\t ajax success, next:', next, 'remainder:', remainder );
+
+ // store the response as is in a new element
+ //TODO:?? store start, size as well?
+ loader.data.push( response );
+
+ // fire the partial load event
+ if( loader.loadedPartialEvent ){
+ loader.log( '\t firing:', loader.loadedPartialEvent );
+ $( loader ).trigger( loader.loadedPartialEvent, response, start, size );
+ }
+
+ // if we haven't gotten everything yet,
+ // set up for next recursive call and set the timer
+ if( remainder > 0 ){
+ loader.currentIntervalId = setTimeout(
+ function(){ loadHelper( next, remainder ); },
+ loader.delay
+ );
+ loader.log( '\t currentIntervalId:', loader.currentIntervalId );
+
+ // otherwise (base-case), don't do anything
+ } else {
+ loader.log( loader + '.loadHelper, has finished:', loader.data );
+ if( loader.loadedAllEvent ){
+ loader.log( '\t firing:', loader.loadedAllEvent );
+ $( loader ).trigger( loader.loadedAllEvent, loader.data, loader.total );
+ }
+ if( callback ){ callback( loader.data ); }
+ }
+ }
+ });
+ }
+ loadHelper( loader.start, Math.min( loader.total, loader.size ) );
+ },
+
+ toString : function(){ return 'LazyDataLoader'; }
+ });
+
+ loader.initialize( config );
+ return loader;
+}
+
diff -r 419d87dd65149285d6c9f0043ea898b365d2dbde -r d9e8a7eee7aac7e0ed15fce27592eb0182144889 static/scripts/viz/scatterplot.js
--- a/static/scripts/viz/scatterplot.js
+++ b/static/scripts/viz/scatterplot.js
@@ -1,6 +1,8 @@
define([
"../libs/underscore",
+
"../mvc/base-mvc",
+ "../utils/LazyDataLoader",
"../templates/compiled/template-visualization-scatterplotControlForm",
"../templates/compiled/template-visualization-statsTable",
"../templates/compiled/template-visualization-chartSettings",
@@ -14,7 +16,7 @@
/* =============================================================================
todo:
outside this:
- BUG: visualization menu doesn't disappear
+ 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'
@@ -78,7 +80,7 @@
PADDING = 8,
X_LABEL_TOO_LONG_AT = 5;
- //this.debugging = true;
+ this.debugging = true;
this.log = function(){
if( this.debugging && console && console.debug ){
var args = Array.prototype.slice.call( arguments );
@@ -102,8 +104,8 @@
yNumTicks : 10,
xAxisLabelBumpY : 40,
yAxisLabelBumpX : -35,
- width : 320,
- height : 320,
+ width : 500,
+ height : 500,
//TODO: anyway to make this a sub-obj?
marginTop : 50,
marginRight : 50,
@@ -120,7 +122,7 @@
};
this.config = _.extend( {}, this.defaults, config );
- this.updateConfig = function( newConfig ){
+ this.updateConfig = function( newConfig, rerender ){
_.extend( this.config, newConfig );
};
@@ -148,9 +150,10 @@
this.yAxis = this.content.append( 'g' ).attr( 'class', 'axis' ).attr( 'id', 'y-axis' );
this.yAxisLabel = this.yAxis.append( 'text' ).attr( 'class', 'axis-label' ).attr( 'id', 'y-axis-label' );
- this.log( 'built svg:', d3.selectAll( 'svg' ) );
+ //this.log( 'built svg:', d3.selectAll( 'svg' ) );
this.adjustChartDimensions = function( top, right, bottom, left ){
+ //this.log( this + '.adjustChartDimensions', arguments );
top = top || 0;
right = right || 0;
bottom = bottom || 0;
@@ -171,6 +174,7 @@
// ........................................................ 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
@@ -178,7 +182,7 @@
};
this.setUpDomains = function( xCol, yCol, meta ){
- this.log( 'setUpDomains' );
+ //this.log( this + '.setUpDomains', 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 ) );
@@ -187,6 +191,7 @@
};
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 ])
@@ -198,6 +203,7 @@
// ........................................................ axis and ticks
this.setUpXAxis = function(){
+ //this.log( this + '.setUpXAxis', arguments );
// origin: bottom, left
//TODO: incoporate top, right
this.xAxisFn = d3.svg.axis()
@@ -228,13 +234,14 @@
};
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 );
+ //this.log( 'yAxis:', this.yAxis );
// get the tick labels for the y axis
var yTickLabels = this.yAxis.selectAll( 'text' ).filter( function( e, i ){ return i !== 0; } );
@@ -259,7 +266,7 @@
if( this.config.marginLeft < neededY ){
var adjusting = ( neededY ) - this.config.marginLeft;
adjusting = ( adjusting < 0 )?( 0 ):( adjusting );
- this.log( 'adjusting:', adjusting );
+ //this.log( 'adjusting:', adjusting );
// update dimensions, translations
this.adjustChartDimensions( 0, 0, 0, adjusting );
@@ -278,6 +285,7 @@
// ........................................................ grid lines
this.renderGrid = function(){
+ //this.log( this + '.renderGrid', arguments );
// VERTICAL
// select existing
this.vGridLines = this.content.selectAll( 'line.v-grid-line' )
@@ -328,51 +336,70 @@
};
+ // initial render or complete re-render (REPLACE datapoints)
this.renderDatapoints = function( xCol, yCol, ids ){
- // initial render, complete re-render (REPLACE datapoints)
+ this.log( this + '.renderDatapoints', arguments );
+ var count = 0;
this.datapoints = this.addDatapoints( xCol, yCol, ids, ".glyph" );
// glyphs that need to be removed: transition to from normal state to 'exit' state, remove from DOM
this.datapoints.exit()
+ .each( function(){ count += 1; } )
.transition().duration( this.config.entryAnimDuration )
.attr( "cy", this.config.height )
.attr( "r", 0 )
.remove();
+ this.log( count, ' glyphs removed' );
- this.log( this.datapoints, 'glyphs rendered' );
+ //this.log( this.datapoints.length, ' glyphs in the graph' );
};
+ // adding points to existing
this.addDatapoints = function( newXCol, newYCol, ids, selectorForExisting ){
+ this.log( this + '.addDatapoints', arguments );
// ADD datapoints to plot that's already rendered
// if selectorForExisting === undefined (as in not passed), addDatapoints won't update existing
// pass in the class ( '.glyph' ) to update exising datapoints
var plot = this,
+ count = 0,
xPosFn = function( d, i ){
+ //if( d ){ this.log( 'x.data:', newXCol[ i ], 'plotted:', plot.xScale( newXCol[ i ] ) ); }
return plot.xScale( newXCol[ i ] );
},
yPosFn = function( d, i ){
+ //if( d ){ this.log( 'y.data:', newYCol[ i ], 'plotted:', plot.yScale( newYCol[ i ] ) ); }
return plot.yScale( newYCol[ i ] );
};
// select all existing glyphs and compare to incoming data
// enter() will yield those glyphs that need to be added
- var newDatapoints = this.content.selectAll( selectorForExisting ).data( newXCol );
+ var newDatapoints = this.content.selectAll( selectorForExisting );
+ this.log( 'existing datapoints:', newDatapoints );
+ newDatapoints = newDatapoints.data( newXCol );
// enter - new data to be added as glyphs: give them a 'entry' position and style
+ count = 0;
newDatapoints.enter()
- .append( "svg:circle" )
+ .append( 'svg:circle' )
+ .each( function(){ count += 1; } )
.classed( "glyph", true )
- // start all bubbles small...
.attr( "cx", xPosFn )
.attr( "cy", yPosFn )
+ // 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;
newDatapoints
// ...animate to final position
.transition().duration( this.config.entryAnimDuration )
- .attr( "r", this.config.datapointSize );
+ .each( function(){ count += 1; } )
+ .attr( "cx", xPosFn )
+ .attr( "cy", yPosFn )
+ .attr( "r", plot.config.datapointSize );
+ this.log( count, ' existing glyphs transitioned' );
// attach ids
if( ids ){
@@ -419,21 +446,22 @@
};
this.render = function( columnData, meta ){
+ this.log( this + '.render', arguments );
//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( 'renderScatterplot', xCol.length, yCol.length, this.config );
+ //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.log( 'xCol len', xCol.length, 'yCol len', yCol.length );
this.setUpDomains( xCol, yCol, meta );
- this.log( 'xMin, xMax, yMin, yMax:', this.xMin, this.xMax, this.yMin, this.yMax );
+ //this.log( 'xMin, xMax, yMin, yMax:', this.xMin, this.xMax, this.yMin, this.yMax );
this.setUpScales();
this.adjustChartDimensions();
@@ -515,7 +543,7 @@
this.$chartSettingsPanel = this._render_chartSettings();
this.$statsPanel = this.$el.find( '.tab-pane#chart-stats' );
- this.$el.find( 'ul.nav' ).find( 'a[href="#chart-settings"]' ).tab( 'show' );
+ //this.$el.find( 'ul.nav' ).find( 'a[href="#chart-settings"]' ).tab( 'show' );
return this;
},
@@ -523,6 +551,7 @@
var chartControl = this,
$chartSettingsPanel = this.$el.find( '.tab-pane#chart-settings' ),
// limits for controls (by control/chartConfig id)
+ //TODO: move into TwoVarScatterplot
controlRanges = {
'maxDataPoints' : { min: 1000, max: 30000, step: 100 },
'datapointSize' : { min: 2, max: 10, step: 1 },
@@ -559,7 +588,6 @@
});
//TODO: anim checkbox
- //TODO: labels -> renderPlot
return $chartSettingsPanel;
},
@@ -639,7 +667,7 @@
columns = [];
this.log( 'columnSelections:', columnSelections );
- //TODO: ?? could be moved into getColumnVals;
+ //TODO: move this data/chart settings form crap out
this.log( columnSelections.X.val, columnSelections.Y.val );
this.xColIndex = columnSelections.X.colIndex;
this.yColIndex = columnSelections.Y.colIndex;
@@ -650,15 +678,18 @@
columns.push( columnSelections.ID.colIndex );
}
- this.log( columnSelections.X.colName, columnSelections.Y.colName );
- this.plot.xLabel = this.chartConfig.xLabel = columnSelections.X.colName;
- this.plot.xLabel = this.chartConfig.yLabel = columnSelections.Y.colName;
+ // update labels using chartSettings inputs (if not at defaults), otherwise the selects' colName
+ var chartSettingsXLabel = this.$chartSettingsPanel.find( 'input#X-axis-label' ).val(),
+ chartSettingsYLabel = this.$chartSettingsPanel.find( 'input#Y-axis-label' ).val();
+ this.chartConfig.xLabel = ( chartSettingsXLabel === 'X' )?
+ ( columnSelections.X.colName ):( chartSettingsXLabel );
+ this.chartConfig.yLabel = ( chartSettingsYLabel === 'Y' )?
+ ( columnSelections.Y.colName ):( chartSettingsYLabel );
+ //this.log( 'this.chartConfig:', this.chartConfig );
+ view.plot.updateConfig( this.chartConfig, false );
- //TODO: alter directly
- view.plot.updateConfig( this.chartConfig, false );
//TODO: validate columns - minimally: we can assume either set by selectors or via a good query string
//TODO: other vals: max, start, page
- //TODO: chart config
// fetch the data, sending chosen columns to the server
var params = {
@@ -705,6 +736,7 @@
//==============================================================================
return {
+ LazyDataLoader : LazyDataLoader,
TwoVarScatterplot : TwoVarScatterplot,
ScatterplotControlForm : ScatterplotControlForm
};});
diff -r 419d87dd65149285d6c9f0043ea898b365d2dbde -r d9e8a7eee7aac7e0ed15fce27592eb0182144889 templates/visualization/scatterplot.mako
--- a/templates/visualization/scatterplot.mako
+++ b/templates/visualization/scatterplot.mako
@@ -209,7 +209,7 @@
var hda = ${h.to_json_string( hda )},
historyID = '${historyID}'
apiDatasetsURL = "${h.url_for( controller='/api/datasets' )}";
-
+
var settingsForm = new scatterplot.ScatterplotControlForm({
dataset : hda,
el : $( '#chart-settings-form' ),
@@ -243,3 +243,4 @@
<div id="test"></div></%def>
+
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/419d87dd6514/
changeset: 419d87dd6514
user: dan
date: 2012-10-11 22:43:37
summary: Fix minor typos in db_shell.py
affected #: 1 file
diff -r 26a72076eb75683e1fe1dca95e1a356f501d9393 -r 419d87dd65149285d6c9f0043ea898b365d2dbde scripts/db_shell.py
--- a/scripts/db_shell.py
+++ b/scripts/db_shell.py
@@ -1,14 +1,14 @@
# This script allows easy access to Galaxy's database layer via the
-# Galaxy models. For example:q
-# % python -i scripts/db_shel.py
+# Galaxy models. For example:
+# % python -i scripts/db_shell.py
# >>> new_user = User("admin(a)gmail.com")
# >>> new_user.set_password
# >>> sa_session.add(new_user)
# >>> sa_session.commit()
# >>> sa_session.query(User).all()
#
-# You can also use this script as a library, for instance see https://gist.github.com/1979583q
-# TODO: This script overlaps alot wth manage_db.py and create_db.py,
+# You can also use this script as a library, for instance see https://gist.github.com/1979583
+# TODO: This script overlaps a lot with manage_db.py and create_db.py,
# these should maybe be refactored to remove duplication.
import sys, os.path, logging
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
4 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/d2258c1bcbc9/
changeset: d2258c1bcbc9
user: dan
date: 2012-10-11 22:36:45
summary: Unicode fixes for copying datasets.
affected #: 1 file
diff -r 7549962ac83381ab92ac806b168d45b0b4b9a107 -r d2258c1bcbc9344dc376c11fceeec039b1b23709 templates/dataset/copy_view.mako
--- a/templates/dataset/copy_view.mako
+++ b/templates/dataset/copy_view.mako
@@ -57,7 +57,7 @@
%><option value="${trans.security.encode_id(hist.id)}" ${selected}>
- ${i + 1}: ${h.truncate(hist.name, 30)}${current_history_text}
+ ${i + 1}: ${h.truncate(util.unicodify( hist.name ), 30)}${current_history_text}
</option>
%endfor
</select>
@@ -98,7 +98,7 @@
if encoded_id == target_history_id:
selected = " selected='selected'"
%>
- <option value="${encoded_id}"${selected}>${i + 1}: ${h.truncate(hist.name, 30)}${source_history_text}</option>
+ <option value="${encoded_id}"${selected}>${i + 1}: ${h.truncate( util.unicodify( hist.name ), 30)}${source_history_text}</option>
%endfor
</select><br /><br /><a style="margin-left: 10px;" href="javascript:void(0);" id="select-multiple">Choose multiple histories</a>
@@ -113,7 +113,7 @@
%><div class="form-row"><input type="checkbox" name="target_history_ids" id="hist_${encoded_id}" value="${encoded_id}"/>
- <label for="hist_${encoded_id}" style="display: inline; font-weight:normal;">${i + 1}: ${hist.name}${cur_history_text}</label>
+ <label for="hist_${encoded_id}" style="display: inline; font-weight:normal;">${i + 1}: ${ util.unicodify( hist.name ) }${cur_history_text}</label></div>
%endfor
</div>
https://bitbucket.org/galaxy/galaxy-central/changeset/6ef979d7cab5/
changeset: 6ef979d7cab5
user: dan
date: 2012-10-11 22:36:45
summary: Unicode fixes for Galaxy Forms.
affected #: 1 file
diff -r d2258c1bcbc9344dc376c11fceeec039b1b23709 -r 6ef979d7cab519ceef3727a069a55ec7c5a8c21f templates/form.mako
--- a/templates/form.mako
+++ b/templates/form.mako
@@ -53,7 +53,7 @@
%endif
<div class="form" style="margin: 1em">
- <div class="form-title">${form.title}</div>
+ <div class="form-title">${util.unicodify( form.title )}</div><div class="form-body"><%
has_file_input = False
https://bitbucket.org/galaxy/galaxy-central/changeset/5f67671bafdf/
changeset: 5f67671bafdf
user: dan
date: 2012-10-11 22:36:45
summary: Unicode fixes for sharing histories.
affected #: 1 file
diff -r 6ef979d7cab519ceef3727a069a55ec7c5a8c21f -r 5f67671bafdfb3fa4986f1059035bbf177f586f8 templates/history/share.mako
--- a/templates/history/share.mako
+++ b/templates/history/share.mako
@@ -20,7 +20,7 @@
<tr><td><input type="hidden" name="id" value="${trans.security.encode_id( history.id )}">
- ${history.name}
+ ${ util.unicodify( history.name )}
</td><td>
%if len( history.datasets ) < 1:
@@ -81,7 +81,7 @@
%for history, hdas in no_change_needed.items():
<div class="form-row"><label>History</label>
- ${history.name}
+ ${util.unicodify( history.name )}
</div><div style="clear: both"></div><div class="form-row">
@@ -89,7 +89,7 @@
</div>
%for hda in hdas:
<div class="form-row">
- ${hda.name}
+ ${util.unicodify( hda.name )}
%if hda.deleted:
(deleted)
%endif
@@ -108,7 +108,7 @@
%for history, hdas in can_change.items():
<div class="form-row"><label>History</label>
- ${history.name}
+ ${util.unicodify( history.name )}
</div><div style="clear: both"></div><div class="form-row">
@@ -116,7 +116,7 @@
</div>
%for hda in hdas:
<div class="form-row">
- ${hda.name}
+ ${util.unicodify( hda.name )}
%if hda.deleted:
(deleted)
%endif
@@ -136,7 +136,7 @@
%for history, hdas in cannot_change.items():
<div class="form-row"><label>History</label>
- ${history.name}
+ ${util.unicodify( history.name )}
</div><div style="clear: both"></div><div class="form-row">
@@ -144,7 +144,7 @@
</div>
%for hda in hdas:
<div class="form-row">
- ${hda.name}
+ ${util.unicodify( hda.name )}
%if hda.deleted:
(deleted)
%endif
https://bitbucket.org/galaxy/galaxy-central/changeset/26a72076eb75/
changeset: 26a72076eb75
user: dan
date: 2012-10-11 22:36:46
summary: Unicode fixes for workflow configuration menu.
affected #: 1 file
diff -r 5f67671bafdfb3fa4986f1059035bbf177f586f8 -r 26a72076eb75683e1fe1dca95e1a356f501d9393 templates/workflow/configure_menu.mako
--- a/templates/workflow/configure_menu.mako
+++ b/templates/workflow/configure_menu.mako
@@ -31,7 +31,7 @@
%for i, workflow in enumerate( workflows ):
<tr><td>
- ${workflow.name}
+ ${util.unicodify( workflow.name )}
</td><td>You</td><td>${len(workflow.latest_workflow.steps)}</td>
@@ -53,7 +53,7 @@
<% workflow = association.stored_workflow %><tr><td>
- ${workflow.name}
+ ${util.unicodify( workflow.name )}
</td><td>${workflow.user.email}</td><td>${len(workflow.latest_workflow.steps)}</td>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/3fc27b7125cc/
changeset: 3fc27b7125cc
user: dan
date: 2012-10-11 20:06:10
summary: Only allow errors to be viewed if the user can access the dataset.
affected #: 1 file
diff -r b27aa5db944d3c3a79c9bedf9d91fe2a2e89e01d -r 3fc27b7125ccca13354558e355832de8f1f5f51a lib/galaxy/webapps/galaxy/controllers/dataset.py
--- a/lib/galaxy/webapps/galaxy/controllers/dataset.py
+++ b/lib/galaxy/webapps/galaxy/controllers/dataset.py
@@ -166,6 +166,8 @@
@web.expose
def errors( self, trans, id ):
hda = trans.sa_session.query( model.HistoryDatasetAssociation ).get( id )
+ if not hda or not trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), hda.dataset ):
+ return trans.show_error_message( "Either this dataset does not exist or you do not have permission to access it." )
return trans.fill_template( "dataset/errors.mako", hda=hda )
@web.expose
def stdoutX( self, trans, dataset_id=None, **kwargs ):
https://bitbucket.org/galaxy/galaxy-central/changeset/7549962ac833/
changeset: 7549962ac833
user: dan
date: 2012-10-11 20:06:18
summary: Only copy the user on bug reports if the user can access the dataset.
affected #: 1 file
diff -r 3fc27b7125ccca13354558e355832de8f1f5f51a -r 7549962ac83381ab92ac806b168d45b0b4b9a107 lib/galaxy/webapps/galaxy/controllers/dataset.py
--- a/lib/galaxy/webapps/galaxy/controllers/dataset.py
+++ b/lib/galaxy/webapps/galaxy/controllers/dataset.py
@@ -248,7 +248,7 @@
# Check email a bit
email = email.strip()
parts = email.split()
- if len( parts ) == 1 and len( email ) > 0:
+ if len( parts ) == 1 and len( email ) > 0 and trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), hda.dataset ):
to = to_address + ", " + email
else:
to = to_address
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/837eb8d9098e/
changeset: 837eb8d9098e
user: dan
date: 2012-10-11 19:47:10
summary: Fix for viewing errors by bug link on a copied dataset.
affected #: 1 file
diff -r 046634d0500730333eb181399eaa097b1d9f4343 -r 837eb8d9098ed1e9faa3e651dc7552ef014238fe lib/galaxy/webapps/galaxy/controllers/dataset.py
--- a/lib/galaxy/webapps/galaxy/controllers/dataset.py
+++ b/lib/galaxy/webapps/galaxy/controllers/dataset.py
@@ -221,7 +221,7 @@
return trans.show_error_message( "Error reporting has been disabled for this galaxy instance" )
# Get the dataset and associated job
hda = trans.sa_session.query( model.HistoryDatasetAssociation ).get( id )
- job = hda.creating_job_associations[0].job
+ job = hda.creating_job
# Get the name of the server hosting the Galaxy instance from which this report originated
host = trans.request.host
history_view_link = "%s/history/view?id=%s" % ( str( host ), trans.security.encode_id( hda.history_id ) )
https://bitbucket.org/galaxy/galaxy-central/changeset/b27aa5db944d/
changeset: b27aa5db944d
user: dan
date: 2012-10-11 19:47:11
summary: When sending bug report email on a copied dataset, fill in Job info.
affected #: 1 file
diff -r 837eb8d9098ed1e9faa3e651dc7552ef014238fe -r b27aa5db944d3c3a79c9bedf9d91fe2a2e89e01d templates/dataset/errors.mako
--- a/templates/dataset/errors.mako
+++ b/templates/dataset/errors.mako
@@ -19,9 +19,9 @@
<body><h2>Dataset generation errors</h2><p><b>Dataset ${hda.hid}: ${hda.display_name()}</b></p>
-
- %if hda.creating_job_associations:
- <% job = hda.creating_job_associations[0].job %>
+ <% job = hda.creating_job %>
+ %if job:
+
%if job.traceback:
The Galaxy framework encountered the following error while attempting to run the tool:
<pre>${ util.unicodify( job.traceback ) | h}</pre>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/32ea61c97ac8/
changeset: 32ea61c97ac8
user: dan
date: 2012-10-11 18:28:21
summary: Add creating_job as a property to DatasetInstance.
affected #: 1 file
diff -r 05dfdda805908059de813a303e6ed02ea5e97117 -r 32ea61c97ac8472a781c9f4056c2044da0d06356 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -1261,6 +1261,18 @@
log.warning( e )
return lst
return _source_dataset_chain( self, [] )
+ @property
+ def creating_job( self ):
+ creating_job_associations = None
+ if self.creating_job_associations:
+ creating_job_associations = self.creating_job_associations
+ else:
+ inherit_chain = self.source_dataset_chain
+ if inherit_chain:
+ creating_job_associations = inherit_chain[-1][0].creating_job_associations
+ if creating_job_associations:
+ return creating_job_associations[0].job
+ return None
def get_display_applications( self, trans ):
return self.datatype.get_display_applications_by_dataset( self, trans )
https://bitbucket.org/galaxy/galaxy-central/changeset/046634d05007/
changeset: 046634d05007
user: dan
date: 2012-10-11 18:28:21
summary: Have DatasetInstance controller use .creating_job property for call to _get_job_for_dataset().
affected #: 1 file
diff -r 32ea61c97ac8472a781c9f4056c2044da0d06356 -r 046634d0500730333eb181399eaa097b1d9f4343 lib/galaxy/webapps/galaxy/controllers/dataset.py
--- a/lib/galaxy/webapps/galaxy/controllers/dataset.py
+++ b/lib/galaxy/webapps/galaxy/controllers/dataset.py
@@ -157,14 +157,11 @@
def _get_job_for_dataset( self, trans, dataset_id ):
'''
Return the job for the given dataset. This will throw an error if the
- dataset is either nonexistent or inaccessible to the user. This looks
- up the job by mapping the dataset to an HDA and then mapping the HDA
- to its job. This will throw exceptions so that the caller can determine
- the appropriate response.
+ dataset is either nonexistent or inaccessible to the user.
'''
hda = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.security.decode_id( dataset_id ) )
assert hda and trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), hda.dataset )
- return hda.creating_job_associations[0].job
+ return hda.creating_job
@web.expose
def errors( self, trans, id ):
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/a21e7bd8a41d/
changeset: a21e7bd8a41d
user: dan
date: 2012-10-11 18:09:06
summary: Add source_dataset_chain as a property to DatasetInstance.
affected #: 1 file
diff -r 62b89df24ab159aa12b6a15d63001c4cd01cab2e -r a21e7bd8a41d6d84b9acd63095ea18de80eba76f lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -1242,7 +1242,25 @@
return source
return ( None, None )
return get_source( self )
-
+ @property
+ def source_dataset_chain( self ):
+ def _source_dataset_chain( dataset, lst ):
+ try:
+ cp_from_ldda = dataset.copied_from_library_dataset_dataset_association
+ if cp_from_ldda:
+ lst.append( (cp_from_ldda, "(Data Library)") )
+ return _source_dataset_chain( cp_from_ldda, lst )
+ except Exception, e:
+ log.warning( e )
+ try:
+ cp_from_hda = dataset.copied_from_history_dataset_association
+ if cp_from_hda:
+ lst.append( (cp_from_hda, cp_from_hda.history.name) )
+ return _source_dataset_chain( cp_from_hda, lst )
+ except Exception, e:
+ log.warning( e )
+ return lst
+ return _source_dataset_chain( self, [] )
def get_display_applications( self, trans ):
return self.datatype.get_display_applications_by_dataset( self, trans )
https://bitbucket.org/galaxy/galaxy-central/changeset/05dfdda80590/
changeset: 05dfdda80590
user: dan
date: 2012-10-11 18:09:06
summary: Refactor show_params for hda controller.
affected #: 1 file
diff -r a21e7bd8a41d6d84b9acd63095ea18de80eba76f -r 05dfdda805908059de813a303e6ed02ea5e97117 lib/galaxy/webapps/galaxy/controllers/dataset.py
--- a/lib/galaxy/webapps/galaxy/controllers/dataset.py
+++ b/lib/galaxy/webapps/galaxy/controllers/dataset.py
@@ -977,21 +977,6 @@
"""
Show the parameters used for an HDA
"""
-
- def source_dataset_chain( dataset, lst ):
- try:
- cp_from_ldda = dataset.copied_from_library_dataset_dataset_association
- cp_from_hda = dataset.copied_from_history_dataset_association
- if cp_from_ldda:
- lst.append( (cp_from_ldda, "(Data Library)") )
- return source_dataset_chain( cp_from_ldda, lst )
- elif cp_from_hda:
- lst.append( (cp_from_hda, cp_from_hda.history.name) )
- return source_dataset_chain( cp_from_hda, lst )
- except:
- pass
- return lst
-
hda = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.security.decode_id( dataset_id ) )
if not hda:
raise paste.httpexceptions.HTTPRequestRangeNotSatisfiable( "Invalid reference dataset id: %s." % str( dataset_id ) )
@@ -999,15 +984,17 @@
return trans.show_error_message( "You are not allowed to access this dataset" )
# Get the associated job, if any. If this hda was copied from another,
- # we need to find the job that created the origial hda
+ # we need to find the job that created the origial dataset association.
params_objects = None
+ job = None
tool = None
- job_hda = hda
- while job_hda.copied_from_history_dataset_association:
- job_hda = job_hda.copied_from_history_dataset_association
- if job_hda.creating_job_associations:
- job = None
- for assoc in job_hda.creating_job_associations:
+ inherit_chain = hda.source_dataset_chain
+ if inherit_chain:
+ job_dataset_association, dataset_association_container_name = inherit_chain[-1]
+ else:
+ job_dataset_association = hda
+ if job_dataset_association.creating_job_associations:
+ for assoc in job_dataset_association.creating_job_associations:
job = assoc.job
break
if job:
@@ -1020,8 +1007,8 @@
params_objects = job.get_param_values( trans.app )
except:
pass
-
- inherit_chain = source_dataset_chain(hda, [])
+ if job is None:
+ return trans.show_error_message( "Job information is not available for this dataset." )
return trans.fill_template( "show_params.mako", inherit_chain=inherit_chain, history=trans.get_history(), hda=hda, job=job, tool=tool, params_objects=params_objects )
@web.expose
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: Do not use backrefs for copied_from_library_dataset/history_dataset_association as it confuses sqlalchemy ('is not available, due to conflicting property').
by Bitbucket 11 Oct '12
by Bitbucket 11 Oct '12
11 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/62b89df24ab1/
changeset: 62b89df24ab1
user: dan
date: 2012-10-11 17:49:47
summary: Do not use backrefs for copied_from_library_dataset/history_dataset_association as it confuses sqlalchemy ('is not available, due to conflicting property').
affected #: 1 file
diff -r 1b031693bd3470172c90533726e4ad6dd7d54e5f -r 62b89df24ab159aa12b6a15d63001c4cd01cab2e lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -1222,14 +1222,21 @@
Dataset,
primaryjoin=( Dataset.table.c.id == HistoryDatasetAssociation.table.c.dataset_id ), lazy=False ),
# .history defined in History mapper
+ copied_from_history_dataset_association=relation(
+ HistoryDatasetAssociation,
+ primaryjoin=( HistoryDatasetAssociation.table.c.copied_from_history_dataset_association_id == HistoryDatasetAssociation.table.c.id ),
+ remote_side=[HistoryDatasetAssociation.table.c.id],
+ uselist=False ),
copied_to_history_dataset_associations=relation(
HistoryDatasetAssociation,
- primaryjoin=( HistoryDatasetAssociation.table.c.copied_from_history_dataset_association_id == HistoryDatasetAssociation.table.c.id ),
- backref=backref( "copied_from_history_dataset_association", primaryjoin=( HistoryDatasetAssociation.table.c.copied_from_history_dataset_association_id == HistoryDatasetAssociation.table.c.id ), remote_side=[HistoryDatasetAssociation.table.c.id], uselist=False ) ),
+ primaryjoin=( HistoryDatasetAssociation.table.c.copied_from_history_dataset_association_id == HistoryDatasetAssociation.table.c.id ) ),
+ copied_from_library_dataset_dataset_association=relation(
+ LibraryDatasetDatasetAssociation,
+ primaryjoin=( HistoryDatasetAssociation.table.c.copied_from_library_dataset_dataset_association_id == LibraryDatasetDatasetAssociation.table.c.id ),
+ uselist=False ),
copied_to_library_dataset_dataset_associations=relation(
LibraryDatasetDatasetAssociation,
- primaryjoin=( HistoryDatasetAssociation.table.c.copied_from_library_dataset_dataset_association_id == LibraryDatasetDatasetAssociation.table.c.id ),
- backref=backref( "copied_from_history_dataset_association", primaryjoin=( HistoryDatasetAssociation.table.c.copied_from_library_dataset_dataset_association_id == LibraryDatasetDatasetAssociation.table.c.id ), remote_side=[LibraryDatasetDatasetAssociation.table.c.id], uselist=False ) ),
+ primaryjoin=( HistoryDatasetAssociation.table.c.copied_from_library_dataset_dataset_association_id == LibraryDatasetDatasetAssociation.table.c.id ) ),
implicitly_converted_datasets=relation(
ImplicitlyConvertedDatasetAssociation,
primaryjoin=( ImplicitlyConvertedDatasetAssociation.table.c.hda_parent_id == HistoryDatasetAssociation.table.c.id ) ),
@@ -1484,14 +1491,21 @@
library_dataset = relation( LibraryDataset,
primaryjoin=( LibraryDatasetDatasetAssociation.table.c.library_dataset_id == LibraryDataset.table.c.id ) ),
user=relation( User.mapper ),
+ copied_from_library_dataset_dataset_association=relation(
+ LibraryDatasetDatasetAssociation,
+ primaryjoin=( LibraryDatasetDatasetAssociation.table.c.copied_from_library_dataset_dataset_association_id == LibraryDatasetDatasetAssociation.table.c.id ),
+ remote_side=[LibraryDatasetDatasetAssociation.table.c.id],
+ uselist=False ),
copied_to_library_dataset_dataset_associations=relation(
LibraryDatasetDatasetAssociation,
- primaryjoin=( LibraryDatasetDatasetAssociation.table.c.copied_from_library_dataset_dataset_association_id == LibraryDatasetDatasetAssociation.table.c.id ),
- backref=backref( "copied_from_library_dataset_dataset_association", primaryjoin=( LibraryDatasetDatasetAssociation.table.c.copied_from_library_dataset_dataset_association_id == LibraryDatasetDatasetAssociation.table.c.id ), remote_side=[LibraryDatasetDatasetAssociation.table.c.id] ) ),
+ primaryjoin=( LibraryDatasetDatasetAssociation.table.c.copied_from_library_dataset_dataset_association_id == LibraryDatasetDatasetAssociation.table.c.id ) ),
+ copied_from_history_dataset_association=relation(
+ HistoryDatasetAssociation,
+ primaryjoin=( LibraryDatasetDatasetAssociation.table.c.copied_from_history_dataset_association_id == HistoryDatasetAssociation.table.c.id ),
+ uselist=False ),
copied_to_history_dataset_associations=relation(
HistoryDatasetAssociation,
- primaryjoin=( HistoryDatasetAssociation.table.c.copied_from_library_dataset_dataset_association_id == LibraryDatasetDatasetAssociation.table.c.id ),
- backref=backref( "copied_from_library_dataset_dataset_association", primaryjoin=( HistoryDatasetAssociation.table.c.copied_from_library_dataset_dataset_association_id == LibraryDatasetDatasetAssociation.table.c.id ), remote_side=[LibraryDatasetDatasetAssociation.table.c.id], uselist=False ) ),
+ primaryjoin=( HistoryDatasetAssociation.table.c.copied_from_library_dataset_dataset_association_id == LibraryDatasetDatasetAssociation.table.c.id ) ),
implicitly_converted_datasets=relation(
ImplicitlyConvertedDatasetAssociation,
primaryjoin=( ImplicitlyConvertedDatasetAssociation.table.c.ldda_parent_id == LibraryDatasetDatasetAssociation.table.c.id ) ),
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: Circster: support data indexing and loading for datasets not previously indexed. Also add visual indicator when drawing/loading tracks.
by Bitbucket 11 Oct '12
by Bitbucket 11 Oct '12
11 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/1b031693bd34/
changeset: 1b031693bd34
user: jgoecks
date: 2012-10-11 16:31:13
summary: Circster: support data indexing and loading for datasets not previously indexed. Also add visual indicator when drawing/loading tracks.
affected #: 5 files
diff -r 60757a1ab16476d3fc19b21bc1fb9bd42f567cf3 -r 1b031693bd3470172c90533726e4ad6dd7d54e5f lib/galaxy/visualization/data_providers/genome.py
--- a/lib/galaxy/visualization/data_providers/genome.py
+++ b/lib/galaxy/visualization/data_providers/genome.py
@@ -184,9 +184,15 @@
chrom = chrom_info[ 'chrom' ]
chrom_len = chrom_info[ 'len' ]
chrom_data = self.get_data( chrom, 0, chrom_len, **kwargs )
- if chrom_data:
- chrom_data[ 'region' ] = "%s:%i-%i" % ( chrom, 0, chrom_len )
- genome_data.append( chrom_data )
+ # FIXME: data providers probably should never return None.
+ # Some data providers return None when there's no data, so
+ # create a dummy dict if necessary.
+ if not chrom_data:
+ chrom_data = {
+ 'data': None
+ }
+ chrom_data[ 'region' ] = "%s:%i-%i" % ( chrom, 0, chrom_len )
+ genome_data.append( chrom_data )
return {
'data': genome_data,
diff -r 60757a1ab16476d3fc19b21bc1fb9bd42f567cf3 -r 1b031693bd3470172c90533726e4ad6dd7d54e5f lib/galaxy/webapps/galaxy/api/datasets.py
--- a/lib/galaxy/webapps/galaxy/api/datasets.py
+++ b/lib/galaxy/webapps/galaxy/api/datasets.py
@@ -52,7 +52,7 @@
elif data_type == 'track_config':
rval = self.get_new_track_config( trans, dataset )
elif data_type == 'genome_data':
- rval = self._get_genome_data( self, trans, dataset, kwd.get('dbkey', None) )
+ rval = self._get_genome_data( trans, dataset, kwd.get('dbkey', None) )
else:
# Default: return dataset as API value.
rval = dataset.get_api_value()
@@ -89,12 +89,13 @@
if msg:
return msg
- # Check for data in the genome window.
- data_provider_registry = trans.app.data_provider_registry
- data_provider = trans.app.data_provider_registry.get_data_provider( trans, original_dataset= dataset, source='index' )
- if not data_provider.has_data( chrom ):
- return messages.NO_DATA
-
+ # If there is a chrom, check for data on the chrom.
+ if chrom:
+ data_provider_registry = trans.app.data_provider_registry
+ data_provider = trans.app.data_provider_registry.get_data_provider( trans, original_dataset= dataset, source='index' )
+ if not data_provider.has_data( chrom ):
+ return messages.NO_DATA
+
# Have data if we get here
return { "status": messages.DATA, "valid_chroms": None }
diff -r 60757a1ab16476d3fc19b21bc1fb9bd42f567cf3 -r 1b031693bd3470172c90533726e4ad6dd7d54e5f static/scripts/viz/circster.js
--- a/static/scripts/viz/circster.js
+++ b/static/scripts/viz/circster.js
@@ -143,9 +143,12 @@
initialize: function(options) {
this.options = options;
this.options.bg_stroke = 'ccc';
+ // Fill color when loading data.
+ this.options.loading_bg_fill = '000';
+ // Fill color when data has been loaded.
this.options.bg_fill = 'ccc';
this.options.chroms_layout = this._chroms_layout();
- this.options.data_bounds = this.get_data_bounds(this.options.track.get_genome_wide_data(this.options.genome));
+ this.options.data_bounds = [];
this.options.scale = 1;
this.options.parent_elt = null;
},
@@ -154,34 +157,49 @@
* Render track's data by adding SVG elements to parent.
*/
render: function(parent) {
- // Create track group element.
+ // -- Create track group element. --
this.options.parent_elt = parent.append("g").attr("id", "parent-" + this.options.track_index);
var track_parent_elt = this.options.parent_elt;
- // Render background arcs.
+ // -- Render background arcs. --
var genome_arcs = this.options.chroms_layout,
arc_gen = d3.svg.arc()
.innerRadius(this.options.radius_bounds[0])
.outerRadius(this.options.radius_bounds[1]),
+ // Attach data to group element.
chroms_elts = track_parent_elt.selectAll('g')
- .data(genome_arcs).enter().append('svg:g');
+ .data(genome_arcs).enter().append('svg:g'),
- // Draw arcs.
- chroms_elts.append("path")
- .attr("d", arc_gen)
- .style("stroke", this.options.bg_stroke)
- .style("fill", this.options.bg_fill)
- .append("title").text(function(d) { return d.data.chrom; });
+ // Draw chrom arcs/paths.
+ chroms_paths = chroms_elts.append("path")
+ .attr("d", arc_gen)
+ .style("stroke", this.options.bg_stroke)
+ .style("fill", this.options.loading_bg_fill);
+
+ // Append titles to paths.
+ chroms_paths.append("title").text(function(d) { return d.data.chrom; });
- // Render track data.
- this._render_data(track_parent_elt);
+ // -- Render track data and, when track data is rendered, apply preferences and update chrom_elts fill. --
- // Apply prefs.
- var prefs = this.options.track.get('prefs'),
- block_color = prefs.block_color;
- if (!block_color) { block_color = prefs.color; }
- track_parent_elt.selectAll('path.chrom-data').style('stroke', block_color).style('fill', block_color);
+ var self = this,
+ data_manager = self.options.track.get('data_manager'),
+ // If track has a data manager, get deferred that resolves when data is ready.
+ data_ready_deferred = (data_manager ? data_manager.data_is_ready() : true );
+
+ // When data is ready, render track.
+ $.when(data_ready_deferred).then(function() {
+ $.when(self._render_data(track_parent_elt)).then(function() {
+ // Apply prefs to all track data.
+ // TODO: move to _render_data?
+ var prefs = self.options.track.get('prefs'),
+ block_color = prefs.block_color;
+ if (!block_color) { block_color = prefs.color; }
+ track_parent_elt.selectAll('path.chrom-data').style('stroke', block_color).style('fill', block_color);
+
+ chroms_paths.style("fill", self.options.bg_fill);
+ });
+ });
},
/**
@@ -243,7 +261,7 @@
* Update data bounds.
*/
_update_data_bounds: function() {
- this.options.data_bounds = this.get_data_bounds(this.options.track.get_genome_wide_data(this.options.genome));
+ //this.options.data_bounds = this.get_data_bounds(this.options.track.get_genome_wide_data(this.options.genome));
// TODO: transition all paths to use the new data bounds.
},
@@ -255,8 +273,13 @@
var self = this,
chrom_arcs = this.options.chroms_layout,
track = this.options.track,
- genome_wide_data = track.get_genome_wide_data(this.options.genome),
-
+ rendered_deferred = $.Deferred();
+
+ // When genome-wide data is available, render data.
+ $.when(track.get('data_manager').get_genome_wide_data(this.options.genome)).then(function(genome_wide_data) {
+ // Set bounds.
+ self.options.data_bounds = self.get_data_bounds(genome_wide_data);
+
// Merge chroms layout with data.
layout_and_data = _.zip(chrom_arcs, genome_wide_data),
@@ -267,7 +290,10 @@
return self._render_chrom_data(svg, chrom_arc, data);
});
- return svg;
+ rendered_deferred.resolve(svg);
+ });
+
+ return rendered_deferred;
},
/**
@@ -348,7 +374,7 @@
*/
_render_chrom_data: function(svg, chrom_arc, chrom_data) {
// If no chrom data, return null.
- if (!chrom_data || typeof chrom_data === "string" || chrom_data.data.length === 0) {
+ if (typeof chrom_data === "string" || !chrom_data.data || chrom_data.data.length === 0) {
return null;
}
@@ -407,7 +433,7 @@
get_data_bounds: function(data) {
// Get max across data.
var max_data = _.map(data, function(d) {
- if (!d || typeof d === 'string') { return 0; }
+ if (typeof d === 'string' || !d.max) { return 0; }
return d.max;
});
return [ 0, (max_data && typeof max_data !== 'string' ? _.max(max_data) : 0) ];
diff -r 60757a1ab16476d3fc19b21bc1fb9bd42f567cf3 -r 1b031693bd3470172c90533726e4ad6dd7d54e5f static/scripts/viz/sweepster.js
--- a/static/scripts/viz/sweepster.js
+++ b/static/scripts/viz/sweepster.js
@@ -928,7 +928,7 @@
}, output.first().get('track_config')),
track_obj = tracks.object_from_template(track_config, self, null);
- // Track uses only raw data.
+ // Track uses raw data.
track_obj.data_manager.set('data_type', 'raw_data');
// Set track block colors.
diff -r 60757a1ab16476d3fc19b21bc1fb9bd42f567cf3 -r 1b031693bd3470172c90533726e4ad6dd7d54e5f static/scripts/viz/visualization.js
--- a/static/scripts/viz/visualization.js
+++ b/static/scripts/viz/visualization.js
@@ -136,6 +136,7 @@
var GenomeDataManager = Cache.extend({
defaults: _.extend({}, Cache.prototype.defaults, {
dataset: null,
+ init_data: null,
filters_manager: null,
data_type: "data",
data_mode_compatible: function(entry, mode) { return true; },
@@ -143,18 +144,52 @@
}),
/**
+ * Initialization.
+ */
+ initialize: function(options) {
+ Cache.prototype.initialize.call(this);
+
+ // Set initial entries in data manager.
+ var initial_entries = this.get('init_data');
+ if (initial_entries) {
+ this.add_data(initial_entries);
+ }
+ },
+
+ /**
+ * Add data entries to manager; each entry should be a dict with attributes region (key), data, and data_type.
+ * If necessary, manager size is increased to hold all data.
+ */
+ add_data: function(entries) {
+ // Increase size to accomodate all entries.
+ if (this.get('num_elements') < entries.length) {
+ this.set('num_elements', entries.length);
+ }
+
+ // Put data into manager.
+ var self = this;
+ _.each(entries, function(entry) {
+ self.set_data(entry.region, entry);
+ });
+ },
+
+ /**
* Returns deferred that resolves to true when dataset is ready (or false if dataset
* cannot be used).
*/
data_is_ready: function() {
var dataset = this.get('dataset'),
ready_deferred = $.Deferred(),
+ // If requesting raw data, query dataset state; if requesting (converted) data,
+ // need to query converted datasets state.
+ query_type = (this.get('data_type') == 'raw_data' ? 'state' :
+ this.get('data_type') == 'data' ? 'converted_datasets_state' : "error" ),
ss_deferred = new util_mod.ServerStateDeferred({
ajax_settings: {
url: this.get('dataset').url(),
data: {
hda_ldda: dataset.get('hda_ldda'),
- data_type: 'state'
+ data_type: query_type
},
dataType: "json"
},
@@ -312,8 +347,7 @@
// Get additional data, append to current data, and set new data. Use a custom deferred object
// to signal when new data is available.
//
- var
- data_manager = this,
+ var data_manager = this,
new_data_request = this.load_data(query_region, mode, resolution, extra_params),
new_data_available = $.Deferred();
// load_data sets cache to new_data_request, but use custom deferred object so that signal and data
@@ -372,6 +406,49 @@
entry.stale = true;
return entry;
},
+
+ /**
+ * Returns an array of data with each entry representing one chromosome/contig
+ * of data or, if data is not available, returns a Deferred that resolves to the
+ * data when it becomes available.
+ */
+ get_genome_wide_data: function(genome) {
+ // -- Get all data. --
+
+ var self = this,
+ all_data_available = true,
+
+ // Map chromosome info into genome data.
+ gw_data = _.map(genome.get('chroms_info').chrom_info, function(chrom_info) {
+ var chrom_data = self.get_elt(
+ new GenomeRegion({
+ chrom: chrom_info.chrom,
+ start: 0,
+ end: chrom_info.len
+ })
+ );
+
+ // Set flag if data is not available.
+ if (!chrom_data) { all_data_available = false; }
+
+ return chrom_data;
+ });
+
+ // -- If all data is available, return it. --
+ if (all_data_available) {
+ return gw_data;
+ }
+
+ // -- All data is not available, so load from server. --
+
+ var deferred = $.Deferred();
+ $.getJSON(this.get('dataset').url(), { data_type: 'genome_data' }, function(genome_wide_data) {
+ self.add_data(genome_wide_data.data);
+ deferred.resolve(genome_wide_data.data);
+ });
+
+ return deferred;
+ },
/**
* Get data from the cache.
@@ -397,7 +474,6 @@
},
load_data: function(region, mode, resolution, extra_params) {
- console.log(region, mode, resolution);
if (resolution > 1) {
// Now that data is pre-fetched before draw, we don't load reference tracks
// unless it's at the bottom level.
@@ -598,41 +674,17 @@
this.set('id', options.dataset_id);
// Set up data manager.
- var data_manager = new GenomeDataManager({
- dataset: this
- });
- this.set('data_manager', data_manager);
-
- // If there's preloaded data, add it to data manager.
var preloaded_data = this.get('preloaded_data');
if (preloaded_data) {
- // Increase size to accomodate all preloaded data.
- data_manager.set('num_elements', preloaded_data.data.length);
-
- // Put data into manager.
- _.each(preloaded_data.data, function(entry) {
- data_manager.set_data(entry.region, entry);
- });
+ preloaded_data = preloaded_data.data
}
- },
-
- /**
- * Returns an array of data with each entry representing one chromosome/contig
- * of data.
- */
- get_genome_wide_data: function(genome) {
- var data_manager = this.get('data_manager');
-
- // Map chromosome data into track data.
- return _.map(genome.get('chroms_info').chrom_info, function(chrom_info) {
- return data_manager.get_elt(
- new GenomeRegion({
- chrom: chrom_info.chrom,
- start: 0,
- end: chrom_info.len
- })
- );
- });
+ else {
+ preloaded_data = [];
+ }
+ this.set('data_manager', new GenomeDataManager({
+ dataset: this,
+ init_data: preloaded_data
+ }));
}
});
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: scatterplot.js: minor changes; data_providers/basic.py: ensure numeric stats only on numeric columns;
by Bitbucket 11 Oct '12
by Bitbucket 11 Oct '12
11 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/60757a1ab164/
changeset: 60757a1ab164
user: carlfeberhard
date: 2012-10-11 16:24:43
summary: scatterplot.js: minor changes; data_providers/basic.py: ensure numeric stats only on numeric columns;
affected #: 5 files
diff -r 3b9db9c4206602859dee02164aa32a925138866e -r 60757a1ab16476d3fc19b21bc1fb9bd42f567cf3 lib/galaxy/visualization/data_providers/basic.py
--- a/lib/galaxy/visualization/data_providers/basic.py
+++ b/lib/galaxy/visualization/data_providers/basic.py
@@ -163,16 +163,19 @@
f.close()
for index, meta in enumerate( response[ 'meta' ] ):
- count = meta[ 'count' ]
- meta[ 'mean' ] = float( meta[ 'sum' ] ) / count
+ column_type = column_types[ index ]
- sorted_data = sorted( response[ 'data' ][ index ] )
- # even data count -
- middle_index = count / 2 - 1
- if count % 2 == 0:
- meta[ 'median' ] = sum( sorted_data[ middle_index : ( middle_index + 1 ) ] ) / 2.0
+ if( column_type == 'float' or column_type == 'int' ):
+ count = meta[ 'count' ]
+ meta[ 'mean' ] = float( meta[ 'sum' ] ) / count
- else:
- meta[ 'median' ] = sorted_data[ middle_index ]
+ sorted_data = sorted( response[ 'data' ][ index ] )
+ # even data count -
+ middle_index = count / 2 - 1
+ if count % 2 == 0:
+ meta[ 'median' ] = sum( sorted_data[ middle_index : ( middle_index + 1 ) ] ) / 2.0
+
+ else:
+ meta[ 'median' ] = sorted_data[ middle_index ]
return response
diff -r 3b9db9c4206602859dee02164aa32a925138866e -r 60757a1ab16476d3fc19b21bc1fb9bd42f567cf3 static/scripts/templates/compiled/template-visualization-chartSettings.js
--- a/static/scripts/templates/compiled/template-visualization-chartSettings.js
+++ b/static/scripts/templates/compiled/template-visualization-chartSettings.js
@@ -13,7 +13,7 @@
foundHelper = helpers.maxDataPoints;
if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
else { stack1 = depth0.maxDataPoints; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
- buffer += escapeExpression(stack1) + "</div>\n <div class=\"slider\"></div>\n <p class=\"form-help help-text-small\">\n Change the maximum number of data points displayable on this graph (higher values will\n load significantly slower)\n </p>\n </div>\n\n <div id=\"datapointSize\" class=\"form-input numeric-slider-input\">\n <label for=\"datapointSize\">Size of data point: </label>\n <div class=\"slider-output\">";
+ buffer += escapeExpression(stack1) + "</div>\n <div style=\"clear: both;\"></div>\n <div class=\"slider\"></div>\n <p class=\"form-help help-text-small\">\n Change the maximum number of data points displayable on this graph (higher values will\n load significantly slower)\n </p>\n </div>\n\n <div id=\"datapointSize\" class=\"form-input numeric-slider-input\">\n <label for=\"datapointSize\">Size of data point: </label>\n <div class=\"slider-output\">";
foundHelper = helpers.datapointSize;
if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
else { stack1 = depth0.datapointSize; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
diff -r 3b9db9c4206602859dee02164aa32a925138866e -r 60757a1ab16476d3fc19b21bc1fb9bd42f567cf3 static/scripts/templates/visualization-templates.html
--- a/static/scripts/templates/visualization-templates.html
+++ b/static/scripts/templates/visualization-templates.html
@@ -97,6 +97,7 @@
<div id="maxDataPoints" class="form-input numeric-slider-input"><label for="maxDataPoints">Maximum data points allowed on graph: </label><div class="slider-output">{{maxDataPoints}}</div>
+ <div style="clear: both;"></div><div class="slider"></div><p class="form-help help-text-small">
Change the maximum number of data points displayable on this graph (higher values will
@@ -152,4 +153,4 @@
</div><input id="render-button" type="button" value="Draw" />
-</script>
\ No newline at end of file
+</script>
diff -r 3b9db9c4206602859dee02164aa32a925138866e -r 60757a1ab16476d3fc19b21bc1fb9bd42f567cf3 static/scripts/viz/scatterplot.js
--- a/static/scripts/viz/scatterplot.js
+++ b/static/scripts/viz/scatterplot.js
@@ -1,6 +1,4 @@
define([
- //"../libs/jquery/jquery",
-
"../libs/underscore",
"../mvc/base-mvc",
"../templates/compiled/template-visualization-scatterplotControlForm",
@@ -13,8 +11,6 @@
"../libs/jquery/jquery-ui-1.8.23.custom.min"
], function(){
-
-
/* =============================================================================
todo:
outside this:
@@ -54,6 +50,9 @@
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)
@@ -103,8 +102,8 @@
yNumTicks : 10,
xAxisLabelBumpY : 40,
yAxisLabelBumpX : -35,
- width : 500,
- height : 500,
+ width : 320,
+ height : 320,
//TODO: anyway to make this a sub-obj?
marginTop : 50,
marginRight : 50,
@@ -456,16 +455,10 @@
*/
var ScatterplotControlForm = BaseView.extend( LoggableMixin ).extend({
//logger : console,
- tagName : 'form',
className : 'scatterplot-settings-form',
loadingIndicatorImage : 'loading_large_white_bg.gif',
- events : {
- 'click #render-button' : 'renderPlot',
- 'click #include-id-checkbox' : 'toggleThirdColumnSelector'
- },
-
initialize : function( attributes ){
if( !attributes || !attributes.dataset ){
@@ -571,6 +564,11 @@
return $chartSettingsPanel;
},
+ events : {
+ 'click #render-button' : 'renderPlot',
+ 'click #include-id-checkbox' : 'toggleThirdColumnSelector'
+ },
+
toggleThirdColumnSelector : function(){
this.$el.find( 'select[name="ID"]' ).parent().toggle();
},
@@ -709,4 +707,4 @@
return {
TwoVarScatterplot : TwoVarScatterplot,
ScatterplotControlForm : ScatterplotControlForm
-};});
\ No newline at end of file
+};});
diff -r 3b9db9c4206602859dee02164aa32a925138866e -r 60757a1ab16476d3fc19b21bc1fb9bd42f567cf3 templates/visualization/scatterplot.mako
--- a/templates/visualization/scatterplot.mako
+++ b/templates/visualization/scatterplot.mako
@@ -20,11 +20,11 @@
.left-column {
float: left;
- width: 30%;
+ width: 40%;
}
.right-column {
- margin-left: 32%;
+ margin-left: 41%;
}
div.tab-pane {
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Galaxy admin menu option for resetting metadata on selected tool shed repositories.
by Bitbucket 11 Oct '12
by Bitbucket 11 Oct '12
11 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/3b9db9c42066/
changeset: 3b9db9c42066
user: greg
date: 2012-10-11 16:22:04
summary: Galaxy admin menu option for resetting metadata on selected tool shed repositories.
affected #: 1 file
diff -r b037978114caede484df1b25bd4004e0591820f5 -r 3b9db9c4206602859dee02164aa32a925138866e templates/webapps/galaxy/admin/index.mako
--- a/templates/webapps/galaxy/admin/index.mako
+++ b/templates/webapps/galaxy/admin/index.mako
@@ -75,6 +75,7 @@
<div class="toolTitle"><a href="${h.url_for( controller='admin_toolshed', action='monitor_repository_installation', tool_shed_repository_ids=installing_repository_ids )}" target="galaxy_main">Monitor installing tool shed repositories</a></div>
%endif
%if installed_repositories:
+ <div class="toolTitle"><a href="${h.url_for( controller='admin_toolshed', action='reset_metadata_on_selected_repositories' )}" target="galaxy_main">Reset metadata for tool shed repositories</a></div><div class="toolTitle"><a href="${h.url_for( controller='admin_toolshed', action='browse_repositories' )}" target="galaxy_main">Manage installed tool shed repositories</a></div>
%endif
</div>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Add the abiltiy for a Galaxy admin to reset metadata on selected installed tool shed repositories.
by Bitbucket 11 Oct '12
by Bitbucket 11 Oct '12
11 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/b037978114ca/
changeset: b037978114ca
user: greg
date: 2012-10-11 16:20:57
summary: Add the abiltiy for a Galaxy admin to reset metadata on selected installed tool shed repositories.
affected #: 2 files
diff -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b -r b037978114caede484df1b25bd4004e0591820f5 lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
@@ -1447,7 +1447,59 @@
status=status )
@web.expose
@web.require_admin
- def reset_repository_metadata( self, trans, id ):
+ def reset_metadata_on_selected_repositories( self, trans, **kwd ):
+ # TODO: merge this with the similar method in the repository controller.
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ repository_ids = util.listify( kwd.get( 'repository_names_by_owner', None ) )
+ if 'reset_metadata_on_selected_repositories_button' in kwd:
+ if repository_ids:
+ successful_count = 0
+ unsuccessful_count = 0
+ for repository_id in repository_ids:
+ repository = get_repository( trans, repository_id )
+ try:
+ invalid_file_tups, metadata_dict = self.reset_repository_metadata( trans,
+ trans.security.encode_id( repository.id ),
+ resetting_all_repositories=True )
+ if invalid_file_tups:
+ unsuccessful_count += 1
+ else:
+ successful_count += 1
+ except Exception, e:
+ log.debug( "Error attempting to reset metadata on repository '%s': %s" % ( repository.name, str( e ) ) )
+ unsuccessful_count += 1
+ message = "Successfully reset metadata on %d %s. " % ( successful_count,
+ inflector.cond_plural( successful_count, "repository" ) )
+ if unsuccessful_count:
+ message += "Error setting metadata on %d %s - see the paster log for details. " % ( unsuccessful_count,
+ inflector.cond_plural( unsuccessful_count,
+ "repository" ) )
+ trans.response.send_redirect( web.url_for( controller='admin_toolshed',
+ action='browse_repositories',
+ message=util.sanitize_text( message ),
+ status=status ) )
+ else:
+ 'Select at least one repository to on which to reset all metadata.'
+ status = 'error'
+ repositories_select_field = SelectField( name='repository_names_by_owner',
+ multiple=True,
+ display='checkboxes' )
+ for repository in trans.sa_session.query( trans.model.ToolShedRepository ) \
+ .filter( trans.model.ToolShedRepository.table.c.uninstalled == False ) \
+ .order_by( trans.model.ToolShedRepository.table.c.name,
+ trans.model.ToolShedRepository.table.c.owner ):
+ option_label = '%s (%s)' % ( repository.name, repository.owner )
+ option_value = trans.security.encode_id( repository.id )
+ repositories_select_field.add_option( option_label, option_value )
+ return trans.fill_template( '/admin/tool_shed_repository/reset_metadata_on_selected_repositories.mako',
+ repositories_select_field=repositories_select_field,
+ message=message,
+ status=status )
+ @web.expose
+ @web.require_admin
+ def reset_repository_metadata( self, trans, id, resetting_all_repositories=False ):
"""Reset all metadata on the installed tool shed repository."""
repository = get_repository( trans, id )
tool_shed_url = get_url_from_repository_tool_shed( trans.app, repository )
@@ -1465,23 +1517,33 @@
updating_installed_repository=False )
repository.metadata = metadata_dict
if metadata_dict != original_metadata_dict:
- update_in_shed_tool_config( trans.app, repository )#def update_in_shed_tool_config( trans, shed_tool_conf_dict, elem_list ):
+ update_in_shed_tool_config( trans.app, repository )
trans.sa_session.add( repository )
trans.sa_session.flush()
- message = 'Metadata has been reset on repository <b>%s</b>.' % repository.name
- status = 'done'
+ if resetting_all_repositories:
+ log.debug( 'Metadata has been reset on repository %s.' % repository.name )
+ else:
+ message = 'Metadata has been reset on repository <b>%s</b>.' % repository.name
+ status = 'done'
else:
- message = 'Metadata did not need to be reset on repository <b>%s</b>.' % repository.name
- status = 'done'
+ if resetting_all_repositories:
+ log.debug( 'Metadata did not need to be reset on repository %s.' % repository.name )
+ else:
+ message = 'Metadata did not need to be reset on repository <b>%s</b>.' % repository.name
+ status = 'done'
else:
- message = 'Error locating installation directory for repository <b>%s</b>.' % repository.name
- status = 'error'
- new_kwd = dict( id=id,
- message=message,
- status=status )
- return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
- action='manage_repository',
- **new_kwd ) )
+ if resetting_all_repositories:
+ log.debug( 'Error locating installation directory for repository %s.' % repository.name )
+ else:
+ message = 'Error locating installation directory for repository <b>%s</b>.' % repository.name
+ status = 'error'
+ if resetting_all_repositories:
+ return invalid_file_tups, metadata_dict
+ else:
+ new_kwd = dict( id=id, message=message, status=status )
+ return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
+ action='manage_repository',
+ **new_kwd ) )
@web.expose
@web.require_admin
def reset_to_install( self, trans, **kwd ):
diff -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b -r b037978114caede484df1b25bd4004e0591820f5 templates/admin/tool_shed_repository/reset_metadata_on_selected_repositories.mako
--- /dev/null
+++ b/templates/admin/tool_shed_repository/reset_metadata_on_selected_repositories.mako
@@ -0,0 +1,71 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+<%def name="local_javascripts()">
+ <script type="text/javascript">
+ function checkAllFields()
+ {
+ var chkAll = document.getElementById('checkAll');
+ var checks = document.getElementsByTagName('input');
+ var boxLength = checks.length;
+ var allChecked = false;
+ var totalChecked = 0;
+ if ( chkAll.checked == true )
+ {
+ for ( i=0; i < boxLength; i++ )
+ {
+ if ( checks[i].name.indexOf( 'repository_names_by_owner' ) != -1)
+ {
+ checks[i].checked = true;
+ }
+ }
+ }
+ else
+ {
+ for ( i=0; i < boxLength; i++ )
+ {
+ if ( checks[i].name.indexOf( 'repository_names_by_owner' ) != -1)
+ {
+ checks[i].checked = false
+ }
+ }
+ }
+ }
+ </script>
+</%def>
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ ${local_javascripts()}
+</%def>
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<div class="warningmessage">
+ Resetting metadata may take a while, so wait until this page redirects after clicking the <b>Reset metadata on selected repositories</b> button, as
+ doing anything else will not be helpful.
+</div>
+
+<div class="toolForm">
+ <div class="toolFormTitle">Reset all metadata on each selected tool shed repository</div>
+ <form name="reset_metadata_on_selected_repositories" id="reset_metadata_on_selected_repositories" action="${h.url_for( controller='admin_toolshed', action='reset_metadata_on_selected_repositories' )}" method="post" >
+ <div class="form-row">
+ Check each repository for which you want to reset metadata. Repository names are followed by owners in parentheses.
+ </div>
+ <div style="clear: both"></div>
+ <div class="form-row">
+ <input type="checkbox" id="checkAll" name=select_all_repositories_checkbox value="true" onclick='checkAllFields(1);'/><input type="hidden" name=select_all_repositories_checkbox value="true"/><b>Select/unselect all repositories</b>
+ </div>
+ <div style="clear: both"></div>
+ <div class="form-row">
+ ${repositories_select_field.get_html()}
+ </div>
+ <div style="clear: both"></div>
+ <div class="form-row">
+ <input type="submit" name="reset_metadata_on_selected_repositories_button" value="Reset metadata on selected repositories"/>
+ </div>
+ </form>
+ </div>
+</div>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
10 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/0684f69e527d/
changeset: 0684f69e527d
user: carlfeberhard
date: 2012-10-10 23:55:34
summary: scatterplot: added stats panel, added chart config panel; dataproviders/basic.py: compute, pass gen. stats in response.meta; base-mvc: fixed bug in chrome LoggableMixin; pack scripts
affected #: 17 files
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b lib/galaxy/visualization/data_providers/basic.py
--- a/lib/galaxy/visualization/data_providers/basic.py
+++ b/lib/galaxy/visualization/data_providers/basic.py
@@ -105,7 +105,12 @@
# set up the response, column lists
response = {}
response[ 'data' ] = data = [ [] for column in columns ]
- response[ 'meta' ] = meta = [ { 'min': None, 'max': None } for column in columns ]
+ response[ 'meta' ] = meta = [{
+ 'min' : None,
+ 'max' : None,
+ 'count' : 0,
+ 'sum' : 0
+ } for column in columns ]
column_types = [ self.original_dataset.metadata.column_types[ column ] for column in columns ]
@@ -135,18 +140,39 @@
#NOTE: this will return None/null for abberrant column values (including bad indeces)
for index, column in enumerate( columns ):
column_val = None
+ column_type = column_types[ index ]
if column < fields_len:
- column_val = cast_val( fields[ column ], column_types[ index ] )
+ column_val = cast_val( fields[ column ], column_type )
if column_val != None:
- if( meta[ index ][ 'min' ] == None
- or column_val < meta[ index ][ 'min' ] ):
- meta[ index ][ 'min' ] = column_val
- if( meta[ index ][ 'max' ] == None
- or column_val > meta[ index ][ 'max' ] ):
- meta[ index ][ 'max' ] = column_val
+
+ # if numeric, maintain min, max, sum
+ if( column_type == 'float' or column_type == 'int' ):
+ if( ( meta[ index ][ 'min' ] == None ) or ( column_val < meta[ index ][ 'min' ] ) ):
+ meta[ index ][ 'min' ] = column_val
+
+ if( ( meta[ index ][ 'max' ] == None ) or ( column_val > meta[ index ][ 'max' ] ) ):
+ meta[ index ][ 'max' ] = column_val
+
+ meta[ index ][ 'sum' ] += column_val
+
+ # maintain a count - for other stats
+ meta[ index ][ 'count' ] += 1
data[ index ].append( column_val )
response[ 'endpoint' ] = dict( last_line=( count - 1 ), file_ptr=f.tell() )
f.close()
+ for index, meta in enumerate( response[ 'meta' ] ):
+ count = meta[ 'count' ]
+ meta[ 'mean' ] = float( meta[ 'sum' ] ) / count
+
+ sorted_data = sorted( response[ 'data' ][ index ] )
+ # even data count -
+ middle_index = count / 2 - 1
+ if count % 2 == 0:
+ meta[ 'median' ] = sum( sorted_data[ middle_index : ( middle_index + 1 ) ] ) / 2.0
+
+ else:
+ meta[ 'median' ] = sorted_data[ middle_index ]
+
return response
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b static/scripts/libs/jquery/jquery-ui-1.8.23.custom.min.js
--- a/static/scripts/libs/jquery/jquery-ui-1.8.23.custom.min.js
+++ b/static/scripts/libs/jquery/jquery-ui-1.8.23.custom.min.js
@@ -22,4 +22,4 @@
* https://github.com/jquery/jquery-ui
* Includes: jquery.ui.slider.js
* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
-(function(a,b){var c=5;a.widget("ui.slider",a.ui.mouse,{widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null},_create:function(){var b=this,d=this.options,e=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",g=d.values&&d.values.length||1,h=[];this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"+(d.disabled?" ui-slider-disabled ui-disabled":"")),this.range=a([]),d.range&&(d.range===!0&&(d.values||(d.values=[this._valueMin(),this._valueMin()]),d.values.length&&d.values.length!==2&&(d.values=[d.values[0],d.values[0]])),this.range=a("<div></div>").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(d.range==="min"||d.range==="max"?" ui-slider-range-"+d.range:"")));for(var i=e.length;i<g;i+=1)h.push(f);this.handles=e.add(a(h.join("")).appendTo(b.element)),this.handle=this.handles.eq(0),this.handles.add(this.range).filter("a").click(function(a){a.preventDefault()}).hover(function(){d.disabled||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}).focus(function(){d.disabled?a(this).blur():(a(".ui-slider .ui-state-focus").removeClass("ui-state-focus"),a(this).addClass("ui-state-focus"))}).blur(function(){a(this).removeClass("ui-state-focus")}),this.handles.each(function(b){a(this).data("index.ui-slider-handle",b)}),this.handles.keydown(function(d){var e=a(this).data("index.ui-slider-handle"),f,g,h,i;if(b.options.disabled)return;switch(d.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.PAGE_UP:case a.ui.keyCode.PAGE_DOWN:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:d.preventDefault();if(!b._keySliding){b._keySliding=!0,a(this).addClass("ui-state-active"),f=b._start(d,e);if(f===!1)return}}i=b.options.step,b.options.values&&b.options.values.length?g=h=b.values(e):g=h=b.value();switch(d.keyCode){case a.ui.keyCode.HOME:h=b._valueMin();break;case a.ui.keyCode.END:h=b._valueMax();break;case a.ui.keyCode.PAGE_UP:h=b._trimAlignValue(g+(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.PAGE_DOWN:h=b._trimAlignValue(g-(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(g===b._valueMax())return;h=b._trimAlignValue(g+i);break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(g===b._valueMin())return;h=b._trimAlignValue(g-i)}b._slide(d,e,h)}).keyup(function(c){var d=a(this).data("index.ui-slider-handle");b._keySliding&&(b._keySliding=!1,b._stop(c,d),b._change(c,d),a(this).removeClass("ui-state-active"))}),this._refreshValue(),this._animateOff=!1},destroy:function(){return this.handles.remove(),this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options,d,e,f,g,h,i,j,k,l;return c.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),d={x:b.pageX,y:b.pageY},e=this._normValueFromMouse(d),f=this._valueMax()-this._valueMin()+1,h=this,this.handles.each(function(b){var c=Math.abs(e-h.values(b));f>c&&(f=c,g=a(this),i=b)}),c.range===!0&&this.values(1)===c.min&&(i+=1,g=a(this.handles[i])),j=this._start(b,i),j===!1?!1:(this._mouseSliding=!0,h._handleIndex=i,g.addClass("ui-state-active").focus(),k=g.offset(),l=!a(b.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:b.pageX-k.left-g.width()/2,top:b.pageY-k.top-g.height()/2-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(b,i,e),this._animateOff=!0,!0))},_mouseStart:function(a){return!0},_mouseDrag:function(a){var b={x:a.pageX,y:a.pageY},c=this._normValueFromMouse(b);return this._slide(a,this._handleIndex,c),!1},_mouseStop:function(a){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(a,this._handleIndex),this._change(a,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b,c,d,e,f;return this.orientation==="horizontal"?(b=this.elementSize.width,c=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(b=this.elementSize.height,c=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),d=c/b,d>1&&(d=1),d<0&&(d=0),this.orientation==="vertical"&&(d=1-d),e=this._valueMax()-this._valueMin(),f=this._valueMin()+d*e,this._trimAlignValue(f)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};return this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("start",a,c)},_slide:function(a,b,c){var d,e,f;this.options.values&&this.options.values.length?(d=this.values(b?0:1),this.options.values.length===2&&this.options.range===!0&&(b===0&&c>d||b===1&&c<d)&&(c=d),c!==this.values(b)&&(e=this.values(),e[b]=c,f=this._trigger("slide",a,{handle:this.handles[b],value:c,values:e}),d=this.values(b?0:1),f!==!1&&this.values(b,c,!0))):c!==this.value()&&(f=this._trigger("slide",a,{handle:this.handles[b],value:c}),f!==!1&&this.value(c))},_stop:function(a,b){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("stop",a,c)},_change:function(a,b){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("change",a,c)}},value:function(a){if(arguments.length){this.options.value=this._trimAlignValue(a),this._refreshValue(),this._change(null,0);return}return this._value()},values:function(b,c){var d,e,f;if(arguments.length>1){this.options.values[b]=this._trimAlignValue(c),this._refreshValue(),this._change(null,b);return}if(!arguments.length)return this._values();if(!a.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(b):this.value();d=this.options.values,e=arguments[0];for(f=0;f<d.length;f+=1)d[f]=this._trimAlignValue(e[f]),this._change(null,f);this._refreshValue()},_setOption:function(b,c){var d,e=0;a.isArray(this.options.values)&&(e=this.options.values.length),a.Widget.prototype._setOption.apply(this,arguments);switch(b){case"disabled":c?(this.handles.filter(".ui-state-focus").blur(),this.handles.removeClass("ui-state-hover"),this.handles.propAttr("disabled",!0),this.element.addClass("ui-disabled")):(this.handles.propAttr("disabled",!1),this.element.removeClass("ui-disabled"));break;case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":this._animateOff=!0,this._refreshValue();for(d=0;d<e;d+=1)this._change(null,d);this._animateOff=!1}},_value:function(){var a=this.options.value;return a=this._trimAlignValue(a),a},_values:function(a){var b,c,d;if(arguments.length)return b=this.options.values[a],b=this._trimAlignValue(b),b;c=this.options.values.slice();for(d=0;d<c.length;d+=1)c[d]=this._trimAlignValue(c[d]);return c},_trimAlignValue:function(a){if(a<=this._valueMin())return this._valueMin();if(a>=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b,d=a-c;return Math.abs(c)*2>=b&&(d+=c>0?b:-b),parseFloat(d.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var b=this.options.range,c=this.options,d=this,e=this._animateOff?!1:c.animate,f,g={},h,i,j,k;this.options.values&&this.options.values.length?this.handles.each(function(b,i){f=(d.values(b)-d._valueMin())/(d._valueMax()-d._valueMin())*100,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",a(this).stop(1,1)[e?"animate":"css"](g,c.animate),d.options.range===!0&&(d.orientation==="horizontal"?(b===0&&d.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({width:f-h+"%"},{queue:!1,duration:c.animate})):(b===0&&d.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({height:f-h+"%"},{queue:!1,duration:c.animate}))),h=f}):(i=this.value(),j=this._valueMin(),k=this._valueMax(),f=k!==j?(i-j)/(k-j)*100:0,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",this.handle.stop(1,1)[e?"animate":"css"](g,c.animate),b==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},c.animate),b==="max"&&this.orientation==="horizontal"&&this.range[e?"animate":"css"]({width:100-f+"%"},{queue:!1,duration:c.animate}),b==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},c.animate),b==="max"&&this.orientation==="vertical"&&this.range[e?"animate":"css"]({height:100-f+"%"},{queue:!1,duration:c.animate}))}}),a.extend(a.ui.slider,{version:"1.8.23"})})(jQuery);;
\ No newline at end of file
+(function(a,b){var c=5;a.widget("ui.slider",a.ui.mouse,{widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null},_create:function(){var b=this,d=this.options,e=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",g=d.values&&d.values.length||1,h=[];this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"+(d.disabled?" ui-slider-disabled ui-disabled":"")),this.range=a([]),d.range&&(d.range===!0&&(d.values||(d.values=[this._valueMin(),this._valueMin()]),d.values.length&&d.values.length!==2&&(d.values=[d.values[0],d.values[0]])),this.range=a("<div></div>").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(d.range==="min"||d.range==="max"?" ui-slider-range-"+d.range:"")));for(var i=e.length;i<g;i+=1)h.push(f);this.handles=e.add(a(h.join("")).appendTo(b.element)),this.handle=this.handles.eq(0),this.handles.add(this.range).filter("a").click(function(a){a.preventDefault()}).hover(function(){d.disabled||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}).focus(function(){d.disabled?a(this).blur():(a(".ui-slider .ui-state-focus").removeClass("ui-state-focus"),a(this).addClass("ui-state-focus"))}).blur(function(){a(this).removeClass("ui-state-focus")}),this.handles.each(function(b){a(this).data("index.ui-slider-handle",b)}),this.handles.keydown(function(d){var e=a(this).data("index.ui-slider-handle"),f,g,h,i;if(b.options.disabled)return;switch(d.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.PAGE_UP:case a.ui.keyCode.PAGE_DOWN:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:d.preventDefault();if(!b._keySliding){b._keySliding=!0,a(this).addClass("ui-state-active"),f=b._start(d,e);if(f===!1)return}}i=b.options.step,b.options.values&&b.options.values.length?g=h=b.values(e):g=h=b.value();switch(d.keyCode){case a.ui.keyCode.HOME:h=b._valueMin();break;case a.ui.keyCode.END:h=b._valueMax();break;case a.ui.keyCode.PAGE_UP:h=b._trimAlignValue(g+(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.PAGE_DOWN:h=b._trimAlignValue(g-(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(g===b._valueMax())return;h=b._trimAlignValue(g+i);break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(g===b._valueMin())return;h=b._trimAlignValue(g-i)}b._slide(d,e,h)}).keyup(function(c){var d=a(this).data("index.ui-slider-handle");b._keySliding&&(b._keySliding=!1,b._stop(c,d),b._change(c,d),a(this).removeClass("ui-state-active"))}),this._refreshValue(),this._animateOff=!1},destroy:function(){return this.handles.remove(),this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options,d,e,f,g,h,i,j,k,l;return c.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),d={x:b.pageX,y:b.pageY},e=this._normValueFromMouse(d),f=this._valueMax()-this._valueMin()+1,h=this,this.handles.each(function(b){var c=Math.abs(e-h.values(b));f>c&&(f=c,g=a(this),i=b)}),c.range===!0&&this.values(1)===c.min&&(i+=1,g=a(this.handles[i])),j=this._start(b,i),j===!1?!1:(this._mouseSliding=!0,h._handleIndex=i,g.addClass("ui-state-active").focus(),k=g.offset(),l=!a(b.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:b.pageX-k.left-g.width()/2,top:b.pageY-k.top-g.height()/2-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(b,i,e),this._animateOff=!0,!0))},_mouseStart:function(a){return!0},_mouseDrag:function(a){var b={x:a.pageX,y:a.pageY},c=this._normValueFromMouse(b);return this._slide(a,this._handleIndex,c),!1},_mouseStop:function(a){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(a,this._handleIndex),this._change(a,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b,c,d,e,f;return this.orientation==="horizontal"?(b=this.elementSize.width,c=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(b=this.elementSize.height,c=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),d=c/b,d>1&&(d=1),d<0&&(d=0),this.orientation==="vertical"&&(d=1-d),e=this._valueMax()-this._valueMin(),f=this._valueMin()+d*e,this._trimAlignValue(f)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};return this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("start",a,c)},_slide:function(a,b,c){var d,e,f;this.options.values&&this.options.values.length?(d=this.values(b?0:1),this.options.values.length===2&&this.options.range===!0&&(b===0&&c>d||b===1&&c<d)&&(c=d),c!==this.values(b)&&(e=this.values(),e[b]=c,f=this._trigger("slide",a,{handle:this.handles[b],value:c,values:e}),d=this.values(b?0:1),f!==!1&&this.values(b,c,!0))):c!==this.value()&&(f=this._trigger("slide",a,{handle:this.handles[b],value:c}),f!==!1&&this.value(c))},_stop:function(a,b){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("stop",a,c)},_change:function(a,b){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("change",a,c)}},value:function(a){if(arguments.length){this.options.value=this._trimAlignValue(a),this._refreshValue(),this._change(null,0);return}return this._value()},values:function(b,c){var d,e,f;if(arguments.length>1){this.options.values[b]=this._trimAlignValue(c),this._refreshValue(),this._change(null,b);return}if(!arguments.length)return this._values();if(!a.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(b):this.value();d=this.options.values,e=arguments[0];for(f=0;f<d.length;f+=1)d[f]=this._trimAlignValue(e[f]),this._change(null,f);this._refreshValue()},_setOption:function(b,c){var d,e=0;a.isArray(this.options.values)&&(e=this.options.values.length),a.Widget.prototype._setOption.apply(this,arguments);switch(b){case"disabled":c?(this.handles.filter(".ui-state-focus").blur(),this.handles.removeClass("ui-state-hover"),this.handles.propAttr("disabled",!0),this.element.addClass("ui-disabled")):(this.handles.propAttr("disabled",!1),this.element.removeClass("ui-disabled"));break;case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":this._animateOff=!0,this._refreshValue();for(d=0;d<e;d+=1)this._change(null,d);this._animateOff=!1}},_value:function(){var a=this.options.value;return a=this._trimAlignValue(a),a},_values:function(a){var b,c,d;if(arguments.length)return b=this.options.values[a],b=this._trimAlignValue(b),b;c=this.options.values.slice();for(d=0;d<c.length;d+=1)c[d]=this._trimAlignValue(c[d]);return c},_trimAlignValue:function(a){if(a<=this._valueMin())return this._valueMin();if(a>=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b,d=a-c;return Math.abs(c)*2>=b&&(d+=c>0?b:-b),parseFloat(d.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var b=this.options.range,c=this.options,d=this,e=this._animateOff?!1:c.animate,f,g={},h,i,j,k;this.options.values&&this.options.values.length?this.handles.each(function(b,i){f=(d.values(b)-d._valueMin())/(d._valueMax()-d._valueMin())*100,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",a(this).stop(1,1)[e?"animate":"css"](g,c.animate),d.options.range===!0&&(d.orientation==="horizontal"?(b===0&&d.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({width:f-h+"%"},{queue:!1,duration:c.animate})):(b===0&&d.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({height:f-h+"%"},{queue:!1,duration:c.animate}))),h=f}):(i=this.value(),j=this._valueMin(),k=this._valueMax(),f=k!==j?(i-j)/(k-j)*100:0,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",this.handle.stop(1,1)[e?"animate":"css"](g,c.animate),b==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},c.animate),b==="max"&&this.orientation==="horizontal"&&this.range[e?"animate":"css"]({width:100-f+"%"},{queue:!1,duration:c.animate}),b==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},c.animate),b==="max"&&this.orientation==="vertical"&&this.range[e?"animate":"css"]({height:100-f+"%"},{queue:!1,duration:c.animate}))}}),a.extend(a.ui.slider,{version:"1.8.23"})})(jQuery);;
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b static/scripts/mvc/base-mvc.js
--- a/static/scripts/mvc/base-mvc.js
+++ b/static/scripts/mvc/base-mvc.js
@@ -65,8 +65,10 @@
logger : null,
log : function(){
- return ( this.logger )?( this.logger.log.apply( this, arguments ) )
- :( undefined );
+ if( this.logger ){
+ return this.logger.log.apply( this.logger, arguments );
+ }
+ return undefined;
}
};
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b static/scripts/packed/mvc/base-mvc.js
--- a/static/scripts/packed/mvc/base-mvc.js
+++ b/static/scripts/packed/mvc/base-mvc.js
@@ -1,1 +1,1 @@
-var BaseModel=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 BaseView=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){if(this.model.attributes.hidden){this.$el.hide()}else{this.$el.show()}}});var LoggableMixin={logger:null,log:function(){return(this.logger)?(this.logger.log.apply(this,arguments)):(undefined)}};var GalaxyLocalization=jQuery.extend({},{aliasName:"_l",localizedStrings:{},setLocalizedString:function(b,a){var c=this;var d=function(f,e){if(f!==e){c.localizedStrings[f]=e}};if(jQuery.type(b)==="string"){d(b,a)}else{if(jQuery.type(b)==="object"){jQuery.each(b,function(e,f){d(e,f)})}else{throw ("Localization.setLocalizedString needs either a string or object as the first argument, given: "+b)}}},localize:function(b){var a=b;if(_.has(this.localizedStrings,b)){a=this.localizedStrings[b]}return a},toString:function(){return"GalaxyLocalization"}});window[GalaxyLocalization.aliasName]=function(a){return GalaxyLocalization.localize(a)};var TemplateLoader=_.extend({},LoggableMixin,{getTemplateLoadFn:function(){throw ("There is no templateLoadFn. Make sure you're using a subclass of TemplateLoader")},getTemplates:function(d,e){e=e||false;this.log(this,"getTemplates:",d,", forceReload:",e);var c={},a=this,b=this.getTemplateLoadFn();if(!d){return c}jQuery.each(d,function(f,g){jQuery.each(g,function(h,i){a.log(a+", templateFile:",f,"templateName:",h,", templateID:",i);c[h]=b.call(a,f,h,i)})});return c}});var CompiledTemplateLoader=_.extend({},TemplateLoader,{getTemplateLoadFn:function(){return this.loadCompiledHandlebarsTemplate},loadCompiledHandlebarsTemplate:function(b,a,c){this.log("getInDomTemplates, templateFile:",b,"templateName:",a,", templateID:",c);if(!Handlebars.templates||!Handlebars.templates[c]){throw ("Template not found: Handlebars."+c+". Check your h.templates() call in the mako file that rendered this page")}this.log("found template function:",c);return Handlebars.templates[c]}});var InDomTemplateLoader=_.extend({},TemplateLoader,{compileTemplate:function(a){if(!Handlebars||!Handlebars.compile){throw ("No Handlebars.compile found. You may only have Handlebars.runtime loaded.Include handlebars.full for this to work")}this.log("compiling template:",a);return Handlebars.compile(a)},findTemplateInDom:function(b,a,c){return $("script#"+c).last()},getTemplateLoadFn:function(){return this.loadInDomTemplate},loadInDomTemplate:function(b,a,c){this.log("getInDomTemplate, templateFile:",b,"templateName:",a,", templateID:",c);var d=this.findTemplateInDom(b,a,c);if(!d||!d.length){throw ("Template not found within the DOM: "+c+". Check that this template has been included in the page")}this.log("found template in dom:",d.html());return this.compileTemplate(d.html())}});var RemoteTemplateLoader=_.extend({},InDomTemplateLoader,{templateBaseURL:"static/scripts/templates/",getTemplateLoadFn:function(){return this.loadViaHttpGet},loadViaHttpGet:function(d,c,f){var b="static/scripts/templates/";this.log("loadViaHttpGet, templateFile:",d,"templateName:",c,", templateID:",f,"templateBaseURL:",this.templateBaseURL);var h=null;try{h=this.loadInDomTemplate(d,c,f)}catch(g){this.log("getInDomTemplate exception:"+g);if(!Handlebars.compile){throw (g)}this.log("Couldn't locate template in DOM: "+f);var a=this;var e=b+d;jQuery.ajax(e,{method:"GET",async:false,success:function(i){a.log(d+" loaded via GET. Attempting compile...");$("body").append(i);h=a.loadInDomTemplate(d,c,f)},error:function(j,i,k){throw ("Failed to fetch "+e+":"+i)}})}if(!h){throw ("Couldn't load or fetch template: "+f)}return h}});
\ No newline at end of file
+var BaseModel=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 BaseView=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){if(this.model.attributes.hidden){this.$el.hide()}else{this.$el.show()}}});var LoggableMixin={logger:null,log:function(){if(this.logger){return this.logger.log.apply(this.logger,arguments)}return undefined}};var GalaxyLocalization=jQuery.extend({},{ALIAS_NAME:"_l",localizedStrings:{},setLocalizedString:function(b,a){var c=this;var d=function(f,e){if(f!==e){c.localizedStrings[f]=e}};if(jQuery.type(b)==="string"){d(b,a)}else{if(jQuery.type(b)==="object"){jQuery.each(b,function(e,f){d(e,f)})}else{throw ("Localization.setLocalizedString needs either a string or object as the first argument, given: "+b)}}},localize:function(b){var a=b;if(_.has(this.localizedStrings,b)){a=this.localizedStrings[b]}return a},toString:function(){return"GalaxyLocalization"}});window[GalaxyLocalization.ALIAS_NAME]=function(a){return GalaxyLocalization.localize(a)};var PersistantStorage=function(g,d){if(!g){throw ("PersistantStorage needs storageKey argument")}d=d||{};var b=jQuery.jStorage.get,c=jQuery.jStorage.set,a=jQuery.jStorage.deleteKey;var e=function(i,h){i=i||{};h=h||null;return{get:function(j){if(j===undefined){return i}else{if(i.hasOwnProperty(j)){return(jQuery.type(i[j])==="object")?(new e(i[j],this)):(i[j])}}return undefined},set:function(j,k){i[j]=k;this.save();return this},deleteKey:function(j){delete i[j];this.save();return this},save:function(){return h.save()},toString:function(){return("StorageRecursionHelper("+i+")")}}};var f={};data=b(g);if(data===null){data=jQuery.extend(true,{},d);c(g,data)}f=new e(data);f.save=function(h){c(g,f.get())};f.destroy=function(){a(g)};f.toString=function(){return"PersistantStorage("+data+")"};return f};
\ No newline at end of file
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b static/scripts/packed/mvc/history.js
--- a/static/scripts/packed/mvc/history.js
+++ b/static/scripts/packed/mvc/history.js
@@ -1,1 +1,1 @@
-var HistoryItem=BaseModel.extend(LoggableMixin).extend({defaults:{id:null,name:"",data_type:null,file_size:0,genome_build:null,metadata_data_lines:0,metadata_dbkey:null,metadata_sequences:0,misc_blurb:"",misc_info:"",model_class:"",state:"",deleted:false,purged:false,visible:true,for_editing:true,bodyIsShown:false},initialize:function(){this.log(this+".initialize",this.attributes);this.log("\tparent history_id: "+this.get("history_id"));if(!this.get("accessible")){this.set("state",HistoryItem.STATES.NOT_VIEWABLE)}},isEditable:function(){return(!(this.get("deleted")||this.get("purged")))},hasData:function(){return(this.get("file_size")>0)},toString:function(){var a=this.get("id")||"";if(this.get("name")){a+=':"'+this.get("name")+'"'}return"HistoryItem("+a+")"}});HistoryItem.STATES={NOT_VIEWABLE:"not_viewable",NEW:"new",UPLOAD:"upload",QUEUED:"queued",RUNNING:"running",OK:"ok",EMPTY:"empty",ERROR:"error",DISCARDED:"discarded",SETTING_METADATA:"setting_metadata",FAILED_METADATA:"failed_metadata"};var HistoryItemView=BaseView.extend(LoggableMixin).extend({tagName:"div",className:"historyItemContainer",initialize:function(){this.log(this+".initialize:",this,this.model)},render:function(){var c=this.model.get("id"),b=this.model.get("state");this.clearReferences();this.$el.attr("id","historyItemContainer-"+c);var a=$("<div/>").attr("id","historyItem-"+c).addClass("historyItemWrapper").addClass("historyItem").addClass("historyItem-"+b);a.append(this._render_warnings());a.append(this._render_titleBar());this.body=$(this._render_body());a.append(this.body);a.find(".tooltip").tooltip({placement:"bottom"});make_popup_menus(a);this.$el.children().remove();return this.$el.append(a)},clearReferences:function(){this.displayButton=null;this.editButton=null;this.deleteButton=null;this.errButton=null},_render_warnings:function(){return $(jQuery.trim(HistoryItemView.templates.messages(this.model.toJSON())))},_render_titleBar:function(){var a=$('<div class="historyItemTitleBar" style="overflow: hidden"></div>');a.append(this._render_titleButtons());a.append('<span class="state-icon"></span>');a.append(this._render_titleLink());return a},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());a.append(this._render_editButton());a.append(this._render_deleteButton());return a},_render_displayButton:function(){if(this.model.get("state")===HistoryItem.STATES.UPLOAD){return null}displayBtnData=(this.model.get("purged"))?({title:"Cannot display datasets removed from disk",enabled:false,icon_class:"display"}):({title:"Display data in browser",href:this.model.get("display_url"),target:(this.model.get("for_editing"))?("galaxy_main"):(null),icon_class:"display"});this.displayButton=new IconButtonView({model:new IconButton(displayBtnData)});return this.displayButton.render().$el},_render_editButton:function(){if((this.model.get("state")===HistoryItem.STATES.UPLOAD)||(!this.model.get("for_editing"))){return null}var c=this.model.get("purged"),a=this.model.get("deleted"),b={title:"Edit attributes",href:this.model.get("edit_url"),target:"galaxy_main",icon_class:"edit"};if(a||c){b.enabled=false}if(a){b.title="Undelete dataset to edit attributes"}else{if(c){b.title="Cannot edit attributes of datasets removed from disk"}}this.editButton=new IconButtonView({model:new IconButton(b)});return this.editButton.render().$el},_render_deleteButton:function(){if(!this.model.get("for_editing")){return null}var a={title:"Delete",href:this.model.get("delete_url"),id:"historyItemDeleter-"+this.model.get("id"),icon_class:"delete"};if((this.model.get("deleted")||this.model.get("purged"))&&(!this.model.get("delete_url"))){a={title:"Dataset is already deleted",icon_class:"delete",enabled:false}}this.deleteButton=new IconButtonView({model:new IconButton(a)});return this.deleteButton.render().$el},_render_titleLink:function(){return $(jQuery.trim(HistoryItemView.templates.titleLink(this.model.toJSON())))},_render_hdaSummary:function(){var a=this.model.toJSON();if(this.model.get("metadata_dbkey")==="?"&&this.model.isEditable()){_.extend(a,{dbkey_unknown_and_editable:true})}return HistoryItemView.templates.hdaSummary(a)},_render_primaryActionButtons:function(c){var b=$("<div/>").attr("id","primary-actions-"+this.model.get("id")),a=this;_.each(c,function(d){b.append(d.call(a))});return b},_render_downloadButton:function(){if(this.model.get("purged")){return null}var a=HistoryItemView.templates.downloadLinks(this.model.toJSON());return $(a)},_render_errButton:function(){if((this.model.get("state")!==HistoryItem.STATES.ERROR)||(!this.model.get("for_editing"))){return null}this.errButton=new IconButtonView({model:new IconButton({title:"View or report this error",href:this.model.get("report_error_url"),target:"galaxy_main",icon_class:"bug"})});return this.errButton.render().$el},_render_showParamsButton:function(){this.showParamsButton=new IconButtonView({model:new IconButton({title:"View details",href:this.model.get("show_params_url"),target:"galaxy_main",icon_class:"information"})});return this.showParamsButton.render().$el},_render_rerunButton:function(){if(!this.model.get("for_editing")){return null}this.rerunButton=new IconButtonView({model:new IconButton({title:"Run this job again",href:this.model.get("rerun_url"),target:"galaxy_main",icon_class:"arrow-circle"})});return this.rerunButton.render().$el},_render_tracksterButton:function(){var a=this.model.get("trackster_urls");if(!(this.model.hasData())||!(this.model.get("for_editing"))||!(a)){return null}this.tracksterButton=new IconButtonView({model:new IconButton({title:"View in Trackster",icon_class:"chart_curve"})});this.errButton.render();this.errButton.$el.addClass("trackster-add").attr({"data-url":a["data-url"],"action-url":a["action-url"],"new-url":a["new-url"]});return this.errButton.$el},_render_secondaryActionButtons:function(b){var c=$("<div/>"),a=this;c.attr("style","float: right;").attr("id","secondary-actions-"+this.model.get("id"));_.each(b,function(d){c.append(d.call(a))});return c},_render_tagButton:function(){if(!(this.model.hasData())||!(this.model.get("for_editing"))||(!this.model.get("retag_url"))){return null}this.tagButton=new IconButtonView({model:new IconButton({title:"Edit dataset tags",target:"galaxy_main",href:this.model.get("retag_url"),icon_class:"tags"})});return this.tagButton.render().$el},_render_annotateButton:function(){if(!(this.model.hasData())||!(this.model.get("for_editing"))||(!this.model.get("annotate_url"))){return null}this.annotateButton=new IconButtonView({model:new IconButton({title:"Edit dataset annotation",target:"galaxy_main",href:this.model.get("annotate_url"),icon_class:"annotate"})});return this.annotateButton.render().$el},_render_tagArea:function(){if(!this.model.get("retag_url")){return null}return $(HistoryItemView.templates.tagArea(this.model.toJSON()))},_render_annotationArea:function(){if(!this.model.get("annotate_url")){return null}return $(HistoryItemView.templates.annotationArea(this.model.toJSON()))},_render_displayApps:function(){if(!this.model.hasData()){return null}var a=$("<div/>").addClass("display-apps");if(!_.isEmpty(this.model.get("display_types"))){a.append(HistoryItemView.templates.displayApps({displayApps:this.model.toJSON().display_types}))}if(!_.isEmpty(this.model.get("display_apps"))){a.append(HistoryItemView.templates.displayApps({displayApps:this.model.toJSON().display_apps}))}return a},_render_peek:function(){if(!this.model.get("peek")){return null}return $("<div/>").append($("<pre/>").attr("id","peek"+this.model.get("id")).addClass("peek").append(this.model.get("peek")))},_render_body_not_viewable:function(a){a.append($("<div>You do not have permission to view dataset.</div>"))},_render_body_uploading:function(a){a.append($("<div>Dataset is uploading</div>"))},_render_body_queued:function(a){a.append($("<div>Job is waiting to run.</div>"));a.append(this._render_primaryActionButtons([this._render_showParamsButton,this._render_rerunButton]))},_render_body_running:function(a){a.append("<div>Job is currently running.</div>");a.append(this._render_primaryActionButtons([this._render_showParamsButton,this._render_rerunButton]))},_render_body_error:function(a){if(!this.model.get("purged")){a.append($("<div>"+this.model.get("misc_blurb")+"</div>"))}a.append(("An error occurred running this job: <i>"+$.trim(this.model.get("misc_info"))+"</i>"));a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_errButton,this._render_showParamsButton,this._render_rerunButton]))},_render_body_discarded:function(a){a.append("<div>The job creating this dataset was cancelled before completion.</div>");a.append(this._render_primaryActionButtons([this._render_showParamsButton,this._render_rerunButton]))},_render_body_setting_metadata:function(a){a.append($("<div>Metadata is being auto-detected.</div>"))},_render_body_empty:function(a){a.append($("<div>No data: <i>"+this.model.get("misc_blurb")+"</i></div>"));a.append(this._render_primaryActionButtons([this._render_showParamsButton,this._render_rerunButton]))},_render_body_failed_metadata:function(a){a.append($(HistoryItemView.templates.failedMetadata(this.model.toJSON())));this._render_body_ok(a)},_render_body_ok:function(a){a.append(this._render_hdaSummary());a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_errButton,this._render_showParamsButton,this._render_rerunButton]));a.append(this._render_secondaryActionButtons([this._render_tagButton,this._render_annotateButton]));a.append('<div class="clear"/>');a.append(this._render_tagArea());a.append(this._render_annotationArea());a.append(this._render_displayApps());a.append(this._render_peek())},_render_body:function(){var b=this.model.get("state");var a=$("<div/>").attr("id","info-"+this.model.get("id")).addClass("historyItemBody").attr("style","display: block");switch(b){case HistoryItem.STATES.NOT_VIEWABLE:this._render_body_not_viewable(a);break;case HistoryItem.STATES.UPLOAD:this._render_body_uploading(a);break;case HistoryItem.STATES.QUEUED:this._render_body_queued(a);break;case HistoryItem.STATES.RUNNING:this._render_body_running(a);break;case HistoryItem.STATES.ERROR:this._render_body_error(a);break;case HistoryItem.STATES.DISCARDED:this._render_body_discarded(a);break;case HistoryItem.STATES.SETTING_METADATA:this._render_body_setting_metadata(a);break;case HistoryItem.STATES.EMPTY:this._render_body_empty(a);break;case HistoryItem.STATES.FAILED_METADATA:this._render_body_failed_metadata(a);break;case HistoryItem.STATES.OK:this._render_body_ok(a);break;default:a.append($('<div>Error: unknown dataset state "'+b+'".</div>'))}a.append('<div style="clear: both"></div>');if(this.model.get("bodyIsShown")===false){a.hide()}return a},events:{"click .historyItemTitle":"toggleBodyVisibility","click a.icon-button.tags":"loadAndDisplayTags","click a.icon-button.annotate":"loadAndDisplayAnnotation"},loadAndDisplayTags:function(b){this.log(this+".loadAndDisplayTags",b);var c=this.$el.find(".tag-area"),a=c.find(".tag-elt");if(c.is(":hidden")){if(!jQuery.trim(a.html())){$.ajax({url:this.model.get("ajax_get_tag_url"),error:function(){alert("Tagging failed")},success:function(d){a.html(d);a.find(".tooltip").tooltip();c.slideDown("fast")}})}else{c.slideDown("fast")}}else{c.slideUp("fast")}return false},loadAndDisplayAnnotation:function(b){this.log(this+".loadAndDisplayAnnotation",b);var d=this.$el.find(".annotation-area"),c=d.find(".annotation-elt"),a=this.model.get("ajax_set_annotation_url");if(d.is(":hidden")){if(!jQuery.trim(c.html())){$.ajax({url:this.model.get("ajax_get_annotation_url"),error:function(){alert("Annotations failed")},success:function(e){if(e===""){e="<em>Describe or add notes to dataset</em>"}c.html(e);d.find(".tooltip").tooltip();async_save_text(c.attr("id"),c.attr("id"),a,"new_annotation",18,true,4);d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toggleBodyVisibility:function(){this.log(this+".toggleBodyVisibility");this.$el.find(".historyItemBody").toggle()},toString:function(){var a=(this.model)?(this.model+""):("");return"HistoryItemView("+a+")"}});HistoryItemView.templates=CompiledTemplateLoader.getTemplates({"common-templates.html":{warningMsg:"template-warningmessagesmall"},"history-templates.html":{messages:"template-history-warning-messages",titleLink:"template-history-titleLink",hdaSummary:"template-history-hdaSummary",downloadLinks:"template-history-downloadLinks",failedMetadata:"template-history-failedMetaData",tagArea:"template-history-tagArea",annotationArea:"template-history-annotationArea",displayApps:"template-history-displayApps"}});var HistoryCollection=Backbone.Collection.extend({model:HistoryItem,toString:function(){return("HistoryCollection()")}});var History=BaseModel.extend(LoggableMixin).extend({defaults:{id:"",name:"",state:"",state_details:{discarded:0,empty:0,error:0,failed_metadata:0,ok:0,queued:0,running:0,setting_metadata:0,upload:0},userIsAdmin:false,userRoles:[],itemsLength:0,showDeleted:false,showHidden:false,diskSize:0,deleted:false,tags:[],annotation:null,message:null,quotaMsg:false,baseURL:null,hideDeletedURL:null,hideHiddenURL:null,tagURL:null,annotateURL:null},initialize:function(b,a){this.items=new HistoryCollection()},toJSON:function(){var a=Backbone.Model.prototype.toJSON.call(this);a.itemsLength=this.items.length;return a},loadDatasetsAsHistoryItems:function(c){var a=this,b=this.get("id"),d=this.get("state_details");_.each(c,function(f,e){var h=new HistoryItem(_.extend(f,{history_id:b}));a.items.add(h);var g=f.state;d[g]+=1});this.set("state_details",d);this._stateFromStateDetails();return this},_stateFromStateDetails:function(){this.set("state","");var a=this.get("state_details");if((a.error>0)||(a.failed_metadata>0)){this.set("state",HistoryItem.STATES.ERROR)}else{if((a.running>0)||(a.setting_metadata>0)){this.set("state",HistoryItem.STATES.RUNNING)}else{if(a.queued>0){this.set("state",HistoryItem.STATES.QUEUED)}else{if(a.ok===this.items.length){this.set("state",HistoryItem.STATES.OK)}else{throw ("_stateFromStateDetails: unable to determine history state from state details: "+this.state_details)}}}}return this},toString:function(){var a=(this.get("name"))?(","+this.get("name")):("");return"History("+this.get("id")+a+")"}});var HistoryView=BaseView.extend(LoggableMixin).extend({el:"body.historyPage",initialize:function(){this.log(this+".initialize:",this);this.itemViews=[];var a=this;this.model.items.each(function(c){var b=new HistoryItemView({model:c});a.itemViews.push(b)})},render:function(){this.$el.append(HistoryView.templates.historyPanel(this.model.toJSON()));this.log(this+" rendered from template:",this.$el);this.itemsDiv=this.$el.find("#"+this.model.get("id")+"-datasets");if(this.model.items.length){var a=this._render_items();this.itemsDiv.append(a.children());a.remove()}},_render_items:function(){var b=$("<div/>"),a=this;_.each(this.itemViews,function(c){a.log(a+".render_items:",c);b.prepend(c.render())});return b},toString:function(){var a=this.model.get("name")||"";return"HistoryView("+a+")"}});HistoryView.templates=CompiledTemplateLoader.getTemplates({"history-templates.html":{historyPanel:"template-history-historyPanel"}});
\ No newline at end of file
+var HistoryItem=BaseModel.extend(LoggableMixin).extend({defaults:{id:null,name:"",data_type:null,file_size:0,genome_build:null,metadata_data_lines:0,metadata_dbkey:null,metadata_sequences:0,misc_blurb:"",misc_info:"",model_class:"",state:"",deleted:false,purged:false,visible:true,for_editing:true,bodyIsShown:false},initialize:function(){this.log(this+".initialize",this.attributes);this.log("\tparent history_id: "+this.get("history_id"));if(!this.get("accessible")){this.set("state",HistoryItem.STATES.NOT_VIEWABLE)}},isEditable:function(){return(!(this.get("deleted")||this.get("purged")))},hasData:function(){return(this.get("file_size")>0)},toString:function(){var a=this.get("id")||"";if(this.get("name")){a+=':"'+this.get("name")+'"'}return"HistoryItem("+a+")"}});HistoryItem.STATES={NOT_VIEWABLE:"not_viewable",NEW:"new",UPLOAD:"upload",QUEUED:"queued",RUNNING:"running",OK:"ok",EMPTY:"empty",ERROR:"error",DISCARDED:"discarded",SETTING_METADATA:"setting_metadata",FAILED_METADATA:"failed_metadata"};var HistoryItemView=BaseView.extend(LoggableMixin).extend({tagName:"div",className:"historyItemContainer",initialize:function(a){this.log(this+".initialize:",this,this.model);this.visible=a.visible},render:function(){var c=this.model.get("id"),b=this.model.get("state");this.clearReferences();this.$el.attr("id","historyItemContainer-"+c);var a=$("<div/>").attr("id","historyItem-"+c).addClass("historyItemWrapper").addClass("historyItem").addClass("historyItem-"+b);a.append(this._render_warnings());a.append(this._render_titleBar());this.body=$(this._render_body());a.append(this.body);a.find(".tooltip").tooltip({placement:"bottom"});make_popup_menus(a);this.$el.children().remove();return this.$el.append(a)},clearReferences:function(){this.displayButton=null;this.editButton=null;this.deleteButton=null;this.errButton=null},_render_warnings:function(){return $(jQuery.trim(HistoryItemView.templates.messages(this.model.toJSON())))},_render_titleBar:function(){var a=$('<div class="historyItemTitleBar" style="overflow: hidden"></div>');a.append(this._render_titleButtons());a.append('<span class="state-icon"></span>');a.append(this._render_titleLink());return a},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());a.append(this._render_editButton());a.append(this._render_deleteButton());return a},_render_displayButton:function(){if(this.model.get("state")===HistoryItem.STATES.UPLOAD){return null}displayBtnData=(this.model.get("purged"))?({title:"Cannot display datasets removed from disk",enabled:false,icon_class:"display"}):({title:"Display data in browser",href:this.model.get("display_url"),target:(this.model.get("for_editing"))?("galaxy_main"):(null),icon_class:"display"});this.displayButton=new IconButtonView({model:new IconButton(displayBtnData)});return this.displayButton.render().$el},_render_editButton:function(){if((this.model.get("state")===HistoryItem.STATES.UPLOAD)||(!this.model.get("for_editing"))){return null}var c=this.model.get("purged"),a=this.model.get("deleted"),b={title:"Edit attributes",href:this.model.get("edit_url"),target:"galaxy_main",icon_class:"edit"};if(a||c){b.enabled=false}if(a){b.title="Undelete dataset to edit attributes"}else{if(c){b.title="Cannot edit attributes of datasets removed from disk"}}this.editButton=new IconButtonView({model:new IconButton(b)});return this.editButton.render().$el},_render_deleteButton:function(){if(!this.model.get("for_editing")){return null}var a={title:"Delete",href:this.model.get("delete_url"),id:"historyItemDeleter-"+this.model.get("id"),icon_class:"delete"};if((this.model.get("deleted")||this.model.get("purged"))&&(!this.model.get("delete_url"))){a={title:"Dataset is already deleted",icon_class:"delete",enabled:false}}this.deleteButton=new IconButtonView({model:new IconButton(a)});return this.deleteButton.render().$el},_render_titleLink:function(){return $(jQuery.trim(HistoryItemView.templates.titleLink(this.model.toJSON())))},_render_hdaSummary:function(){var a=this.model.toJSON();if(this.model.get("metadata_dbkey")==="?"&&this.model.isEditable()){_.extend(a,{dbkey_unknown_and_editable:true})}return HistoryItemView.templates.hdaSummary(a)},_render_primaryActionButtons:function(c){var b=$("<div/>").attr("id","primary-actions-"+this.model.get("id")),a=this;_.each(c,function(d){b.append(d.call(a))});return b},_render_downloadButton:function(){if(this.model.get("purged")){return null}var a=HistoryItemView.templates.downloadLinks(this.model.toJSON());return $(a)},_render_errButton:function(){if((this.model.get("state")!==HistoryItem.STATES.ERROR)||(!this.model.get("for_editing"))){return null}this.errButton=new IconButtonView({model:new IconButton({title:"View or report this error",href:this.model.get("report_error_url"),target:"galaxy_main",icon_class:"bug"})});return this.errButton.render().$el},_render_showParamsButton:function(){this.showParamsButton=new IconButtonView({model:new IconButton({title:"View details",href:this.model.get("show_params_url"),target:"galaxy_main",icon_class:"information"})});return this.showParamsButton.render().$el},_render_rerunButton:function(){if(!this.model.get("for_editing")){return null}this.rerunButton=new IconButtonView({model:new IconButton({title:"Run this job again",href:this.model.get("rerun_url"),target:"galaxy_main",icon_class:"arrow-circle"})});return this.rerunButton.render().$el},_render_tracksterButton:function(){var a=this.model.get("trackster_urls");if(!(this.model.hasData())||!(this.model.get("for_editing"))||!(a)){return null}this.tracksterButton=new IconButtonView({model:new IconButton({title:"View in Trackster",icon_class:"chart_curve"})});this.errButton.render();this.errButton.$el.addClass("trackster-add").attr({"data-url":a["data-url"],"action-url":a["action-url"],"new-url":a["new-url"]});return this.errButton.$el},_render_secondaryActionButtons:function(b){var c=$("<div/>"),a=this;c.attr("style","float: right;").attr("id","secondary-actions-"+this.model.get("id"));_.each(b,function(d){c.append(d.call(a))});return c},_render_tagButton:function(){if(!(this.model.hasData())||!(this.model.get("for_editing"))||(!this.model.get("retag_url"))){return null}this.tagButton=new IconButtonView({model:new IconButton({title:"Edit dataset tags",target:"galaxy_main",href:this.model.get("retag_url"),icon_class:"tags"})});return this.tagButton.render().$el},_render_annotateButton:function(){if(!(this.model.hasData())||!(this.model.get("for_editing"))||(!this.model.get("annotate_url"))){return null}this.annotateButton=new IconButtonView({model:new IconButton({title:"Edit dataset annotation",target:"galaxy_main",href:this.model.get("annotate_url"),icon_class:"annotate"})});return this.annotateButton.render().$el},_render_tagArea:function(){if(!this.model.get("retag_url")){return null}return $(HistoryItemView.templates.tagArea(this.model.toJSON()))},_render_annotationArea:function(){if(!this.model.get("annotate_url")){return null}return $(HistoryItemView.templates.annotationArea(this.model.toJSON()))},_render_displayApps:function(){if(!this.model.hasData()){return null}var a=$("<div/>").addClass("display-apps");if(!_.isEmpty(this.model.get("display_types"))){a.append(HistoryItemView.templates.displayApps({displayApps:this.model.toJSON().display_types}))}if(!_.isEmpty(this.model.get("display_apps"))){a.append(HistoryItemView.templates.displayApps({displayApps:this.model.toJSON().display_apps}))}return a},_render_peek:function(){if(!this.model.get("peek")){return null}return $("<div/>").append($("<pre/>").attr("id","peek"+this.model.get("id")).addClass("peek").append(this.model.get("peek")))},_render_body_not_viewable:function(a){a.append($("<div>You do not have permission to view dataset.</div>"))},_render_body_uploading:function(a){a.append($("<div>Dataset is uploading</div>"))},_render_body_queued:function(a){a.append($("<div>Job is waiting to run.</div>"));a.append(this._render_primaryActionButtons([this._render_showParamsButton,this._render_rerunButton]))},_render_body_running:function(a){a.append("<div>Job is currently running.</div>");a.append(this._render_primaryActionButtons([this._render_showParamsButton,this._render_rerunButton]))},_render_body_error:function(a){if(!this.model.get("purged")){a.append($("<div>"+this.model.get("misc_blurb")+"</div>"))}a.append(("An error occurred running this job: <i>"+$.trim(this.model.get("misc_info"))+"</i>"));a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_errButton,this._render_showParamsButton,this._render_rerunButton]))},_render_body_discarded:function(a){a.append("<div>The job creating this dataset was cancelled before completion.</div>");a.append(this._render_primaryActionButtons([this._render_showParamsButton,this._render_rerunButton]))},_render_body_setting_metadata:function(a){a.append($("<div>Metadata is being auto-detected.</div>"))},_render_body_empty:function(a){a.append($("<div>No data: <i>"+this.model.get("misc_blurb")+"</i></div>"));a.append(this._render_primaryActionButtons([this._render_showParamsButton,this._render_rerunButton]))},_render_body_failed_metadata:function(a){a.append($(HistoryItemView.templates.failedMetadata(this.model.toJSON())));this._render_body_ok(a)},_render_body_ok:function(a){a.append(this._render_hdaSummary());a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_errButton,this._render_showParamsButton,this._render_rerunButton]));a.append(this._render_secondaryActionButtons([this._render_tagButton,this._render_annotateButton]));a.append('<div class="clear"/>');a.append(this._render_tagArea());a.append(this._render_annotationArea());a.append(this._render_displayApps());a.append(this._render_peek())},_render_body:function(){var b=this.model.get("state");var a=$("<div/>").attr("id","info-"+this.model.get("id")).addClass("historyItemBody").attr("style","display: block");switch(b){case HistoryItem.STATES.NOT_VIEWABLE:this._render_body_not_viewable(a);break;case HistoryItem.STATES.UPLOAD:this._render_body_uploading(a);break;case HistoryItem.STATES.QUEUED:this._render_body_queued(a);break;case HistoryItem.STATES.RUNNING:this._render_body_running(a);break;case HistoryItem.STATES.ERROR:this._render_body_error(a);break;case HistoryItem.STATES.DISCARDED:this._render_body_discarded(a);break;case HistoryItem.STATES.SETTING_METADATA:this._render_body_setting_metadata(a);break;case HistoryItem.STATES.EMPTY:this._render_body_empty(a);break;case HistoryItem.STATES.FAILED_METADATA:this._render_body_failed_metadata(a);break;case HistoryItem.STATES.OK:this._render_body_ok(a);break;default:a.append($('<div>Error: unknown dataset state "'+b+'".</div>'))}a.append('<div style="clear: both"></div>');if(this.model.get("bodyIsShown")===false){a.hide()}if(this.visible){a.show()}else{a.hide()}return a},events:{"click .historyItemTitle":"toggleBodyVisibility","click a.icon-button.tags":"loadAndDisplayTags","click a.icon-button.annotate":"loadAndDisplayAnnotation"},loadAndDisplayTags:function(b){this.log(this+".loadAndDisplayTags",b);var c=this.$el.find(".tag-area"),a=c.find(".tag-elt");if(c.is(":hidden")){if(!jQuery.trim(a.html())){$.ajax({url:this.model.get("ajax_get_tag_url"),error:function(){alert("Tagging failed")},success:function(d){a.html(d);a.find(".tooltip").tooltip();c.slideDown("fast")}})}else{c.slideDown("fast")}}else{c.slideUp("fast")}return false},loadAndDisplayAnnotation:function(b){this.log(this+".loadAndDisplayAnnotation",b);var d=this.$el.find(".annotation-area"),c=d.find(".annotation-elt"),a=this.model.get("ajax_set_annotation_url");if(d.is(":hidden")){if(!jQuery.trim(c.html())){$.ajax({url:this.model.get("ajax_get_annotation_url"),error:function(){alert("Annotations failed")},success:function(e){if(e===""){e="<em>Describe or add notes to dataset</em>"}c.html(e);d.find(".tooltip").tooltip();async_save_text(c.attr("id"),c.attr("id"),a,"new_annotation",18,true,4);d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toggleBodyVisibility:function(b){var a=this.$el.find(".historyItemBody");if(b===undefined){a.toggle()}else{if(b){a.show()}else{a.hide()}}this.trigger("toggleBodyVisibility",this.model.get("id"),a.is(":visible"))},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HistoryItemView("+a+")"}});HistoryItemView.templates={warningMsg:Handlebars.templates["template-warningmessagesmall"],messages:Handlebars.templates["template-history-warning-messages"],titleLink:Handlebars.templates["template-history-titleLink"],hdaSummary:Handlebars.templates["template-history-hdaSummary"],downloadLinks:Handlebars.templates["template-history-downloadLinks"],failedMetadata:Handlebars.templates["template-history-failedMetaData"],tagArea:Handlebars.templates["template-history-tagArea"],annotationArea:Handlebars.templates["template-history-annotationArea"],displayApps:Handlebars.templates["template-history-displayApps"]};var HistoryCollection=Backbone.Collection.extend({model:HistoryItem,toString:function(){return("HistoryCollection()")}});var History=BaseModel.extend(LoggableMixin).extend({defaults:{id:"",name:"",state:"",state_details:{discarded:0,empty:0,error:0,failed_metadata:0,ok:0,queued:0,running:0,setting_metadata:0,upload:0},userIsAdmin:false,userRoles:[],itemsLength:0,showDeleted:false,showHidden:false,diskSize:0,deleted:false,tags:[],annotation:null,message:null,quotaMsg:false,baseURL:null,hideDeletedURL:null,hideHiddenURL:null,tagURL:null,annotateURL:null},initialize:function(b,a){this.items=new HistoryCollection()},toJSON:function(){var a=Backbone.Model.prototype.toJSON.call(this);a.itemsLength=this.items.length;return a},loadDatasetsAsHistoryItems:function(c){var a=this,b=this.get("id"),d=this.get("state_details");_.each(c,function(f,e){var h=new HistoryItem(_.extend(f,{history_id:b}));a.items.add(h);var g=f.state;d[g]+=1});this.set("state_details",d);this._stateFromStateDetails();return this},_stateFromStateDetails:function(){this.set("state","");var a=this.get("state_details");if((a.error>0)||(a.failed_metadata>0)){this.set("state",HistoryItem.STATES.ERROR)}else{if((a.running>0)||(a.setting_metadata>0)){this.set("state",HistoryItem.STATES.RUNNING)}else{if(a.queued>0){this.set("state",HistoryItem.STATES.QUEUED)}else{if(a.ok===this.items.length){this.set("state",HistoryItem.STATES.OK)}else{throw ("_stateFromStateDetails: unable to determine history state from state details: "+this.state_details)}}}}return this},toString:function(){var a=(this.get("name"))?(","+this.get("name")):("");return"History("+this.get("id")+a+")"}});var HistoryView=BaseView.extend(LoggableMixin).extend({el:"body.historyPage",initialize:function(){this.log(this+".initialize:",this);this.storage=new PersistantStorage("HistoryView."+this.model.get("id"),{visibleItems:{}});this.initializeItems()},initializeItems:function(){this.itemViews={};var a=this;this.model.items.each(function(c){var e=c.get("id"),d=a.storage.get("visibleItems").get(e),b=new HistoryItemView({model:c,visible:d});a.setUpItemListeners(b);a.itemViews[e]=b})},setUpItemListeners:function(b){var a=this;b.bind("toggleBodyVisibility",function(d,c){if(c){a.storage.get("visibleItems").set(d,true)}else{a.storage.get("visibleItems").deleteKey(d)}})},render:function(){this.$el.append(HistoryView.templates.historyPanel(this.model.toJSON()));this.log(this+" rendered from template:",this.$el);this.itemsDiv=this.$el.find("#"+this.model.get("id")+"-datasets");async_save_text("history-name-container","history-name",this.model.get("renameURL"),"new_name",18);this.$el.find(".tooltip").tooltip();var b=this.$el.find("#history-annotation-area");$("#history-annotate").click(function(){if(b.is(":hidden")){b.slideDown("fast")}else{b.slideUp("fast")}return false});async_save_text("history-annotation-container","history-annotation",this.model.get("annotateURL"),"new_annotation",18,true,4);if(this.model.items.length){var a=this._render_items();this.itemsDiv.append(a.children());a.remove()}},_render_items:function(){var b=$("<div/>"),a=this;_.each(this.itemViews,function(d,c){a.log(a+".render_items:",c,d);b.prepend(d.render())});return b},events:{"click #history-collapse-all":"hideAllItemBodies","click #history-tag":"loadAndDisplayTags"},hideAllItemBodies:function(){_.each(this.itemViews,function(a){a.toggleBodyVisibility(false)})},loadAndDisplayTags:function(c){this.log(this+".loadAndDisplayTags",c);var d=this.$el.find("#history-tag-area"),b=d.find(".tag-elt");this.log("\t tagArea",d," tagElt",b);if(d.is(":hidden")){if(!jQuery.trim(b.html())){var a=this;$.ajax({url:this.model.get("tagURL"),error:function(){alert("Tagging failed")},success:function(e){a.log(a+" tag elt html (ajax)",e);b.html(e);b.find(".tooltip").tooltip();d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toString:function(){var a=this.model.get("name")||"";return"HistoryView("+a+")"}});HistoryView.templates={historyPanel:Handlebars.templates["template-history-historyPanel"]};
\ No newline at end of file
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b 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(k,C,A,s,J){A=A||k.helpers;var B="",o,n,y=this,f="function",c=A.blockHelperMissing,e=this.escapeExpression;function u(L,K){return"refresh"}function t(L,K){return"collapse all"}function r(O,N){var L="",M,K;L+='\n <div style="width: 40px; float: right; white-space: nowrap;">\n <a id="history-tag" title="';K=A.local;if(K){M=K.call(O,{hash:{},inverse:y.noop,fn:y.program(6,q,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:y.noop,fn:y.program(6,q,N)})}if(M||M===0){L+=M}L+='"\n class="icon-button tags tooltip" target="galaxy_main" href="';K=A.tagURL;if(K){M=K.call(O,{hash:{}})}else{M=O.tagURL;M=typeof M===f?M():M}L+=e(M)+'"></a>\n <a id="history-annotate" title="';K=A.local;if(K){M=K.call(O,{hash:{},inverse:y.noop,fn:y.program(8,m,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:y.noop,fn:y.program(8,m,N)})}if(M||M===0){L+=M}L+='"\n class="icon-button annotate tooltip" target="galaxy_main" href="';K=A.annotateURL;if(K){M=K.call(O,{hash:{}})}else{M=O.annotateURL;M=typeof M===f?M():M}L+=e(M)+'"></a>\n </div>\n ';return L}function q(L,K){return"Edit history tags"}function m(L,K){return"Edit history annotation"}function I(O,N){var L="",M,K;L+='\n<div class="historyLinks">\n <a href="';K=A.hideDeletedURL;if(K){M=K.call(O,{hash:{}})}else{M=O.hideDeletedURL;M=typeof M===f?M():M}L+=e(M)+'">';K=A.local;if(K){M=K.call(O,{hash:{},inverse:y.noop,fn:y.program(11,H,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:y.noop,fn:y.program(11,H,N)})}if(M||M===0){L+=M}L+="</a>\n</div>\n";return L}function H(L,K){return"hide deleted"}function G(O,N){var L="",M,K;L+='\n<div class="historyLinks">\n <a href="';K=A.hideHiddenURL;if(K){M=K.call(O,{hash:{}})}else{M=O.hideHiddenURL;M=typeof M===f?M():M}L+=e(M)+'">';K=A.local;if(K){M=K.call(O,{hash:{},inverse:y.noop,fn:y.program(14,F,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:y.noop,fn:y.program(14,F,N)})}if(M||M===0){L+=M}L+="</a>\n</div>\n";return L}function F(L,K){return"hide hidden"}function E(O,N){var L="",M,K;L+="\n ";L+='\n <div id="history-size" style="position: absolute; top: 3px; right: 0px;">';K=A.diskSize;if(K){M=K.call(O,{hash:{}})}else{M=O.diskSize;M=typeof M===f?M():M}L+=e(M)+'</div>\n <div id="history-name" style="margin-right: 50px;" class="tooltip editable-text" title="Click to rename history">';K=A.name;if(K){M=K.call(O,{hash:{}})}else{M=O.name;M=typeof M===f?M():M}L+=e(M)+"</div>\n \n ";return L}function D(O,N){var L="",M,K;L+='\n <div id="history-size">';K=A.diskSize;if(K){M=K.call(O,{hash:{}})}else{M=O.diskSize;M=typeof M===f?M():M}L+=e(M)+"</div>\n ";return L}function p(O,N){var L="",M,K;L+="\n";K=A.warningmessagesmall;if(K){M=K.call(O,{hash:{},inverse:y.noop,fn:y.program(21,l,N)})}else{M=O.warningmessagesmall;M=typeof M===f?M():M}if(!A.warningmessagesmall){M=c.call(O,M,{hash:{},inverse:y.noop,fn:y.program(21,l,N)})}if(M||M===0){L+=M}L+="\n";return L}function l(N,M){var L,K;K=A.local;if(K){L=K.call(N,{hash:{},inverse:y.noop,fn:y.program(22,j,M)})}else{L=N.local;L=typeof L===f?L():L}if(!A.local){L=c.call(N,L,{hash:{},inverse:y.noop,fn:y.program(22,j,M)})}if(L||L===0){return L}else{return""}}function j(L,K){return"You are currently viewing a deleted history!"}function i(N,M){var K="",L;K+="\n";K+='\n<div style="margin: 0px 5px 10px 5px">\n\n <div id="history-tag-area" style="display: none">\n <b>Tags:</b>\n ';K+="\n ";K+='\n </div>\n\n <div id="history-annotation-area" style="display: none">\n <strong>Annotation / Notes:</strong>\n <div id="history-annotation-container">\n <div id="history-annotation" class="tooltip editable-text" title="Click to edit annotation">\n ';L=N.annotation;L=A["if"].call(N,L,{hash:{},inverse:y.program(27,g,M),fn:y.program(25,h,M)});if(L||L===0){K+=L}K+="\n </div>\n </div>\n </div>\n</div>\n";return K}function h(O,N){var L="",M,K;L+="\n ";K=A.annotation;if(K){M=K.call(O,{hash:{}})}else{M=O.annotation;M=typeof M===f?M():M}L+=e(M)+"\n ";return L}function g(L,K){return"\n <em>Describe or add notes to history</em>\n "}function d(O,N){var L="",M,K;L+='\n<div id="message-container">\n <div class="';K=A.status;if(K){M=K.call(O,{hash:{}})}else{M=O.status;M=typeof M===f?M():M}L+=e(M)+'message">\n ';K=A.message;if(K){M=K.call(O,{hash:{}})}else{M=O.message;M=typeof M===f?M():M}L+=e(M)+"\n </div><br />\n</div>\n";return L}function z(L,K){return'\n <div id="quota-message" class="errormessage">\n You are over your disk quota. Tool execution is on hold until your disk usage drops below your allocated quota.\n </div>\n <br/>\n '}function x(O,N){var L="",M,K;L+='\n<div id="';K=A.id;if(K){M=K.call(O,{hash:{}})}else{M=O.id;M=typeof M===f?M():M}L+=e(M)+'-datasets" class="history-datasets-list">\n ';L+="\n</div>\n\n";return L}function w(O,N){var L="",M,K;L+='\n<div class="infomessagesmall" id="emptyHistoryMessage">\n';K=A.local;if(K){M=K.call(O,{hash:{},inverse:y.noop,fn:y.program(36,v,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:y.noop,fn:y.program(36,v,N)})}if(M||M===0){L+=M}L+="\n</div>\n";return L}function v(L,K){return"Your history is empty. Click 'Get Data' on the left pane to start"}B+='<div id="top-links" class="historyLinks">\n <a title="';n=A.local;if(n){o=n.call(C,{hash:{},inverse:y.noop,fn:y.program(1,u,J)})}else{o=C.local;o=typeof o===f?o():o}if(!A.local){o=c.call(C,o,{hash:{},inverse:y.noop,fn:y.program(1,u,J)})}if(o||o===0){B+=o}B+='" class="icon-button arrow-circle tooltip" href="';n=A.baseURL;if(n){o=n.call(C,{hash:{}})}else{o=C.baseURL;o=typeof o===f?o():o}B+=e(o)+"\"></a>\n <a title='";n=A.local;if(n){o=n.call(C,{hash:{},inverse:y.noop,fn:y.program(3,t,J)})}else{o=C.local;o=typeof o===f?o():o}if(!A.local){o=c.call(C,o,{hash:{},inverse:y.noop,fn:y.program(3,t,J)})}if(o||o===0){B+=o}B+="' class='icon-button toggle tooltip' href='#' style=\"display: none\"></a>\n ";o=C.userRoles;o=A["if"].call(C,o,{hash:{},inverse:y.noop,fn:y.program(5,r,J)});if(o||o===0){B+=o}B+='\n</div>\n<div class="clear"></div>\n\n';B+="\n";o=C.showDeleted;o=A["if"].call(C,o,{hash:{},inverse:y.noop,fn:y.program(10,I,J)});if(o||o===0){B+=o}B+="\n\n";o=C.showHidden;o=A["if"].call(C,o,{hash:{},inverse:y.noop,fn:y.program(13,G,J)});if(o||o===0){B+=o}B+="\n\n";B+='\n<div id="history-name-area" class="historyLinks">\n <div id="history-name-container" style="position: relative;">\n ';o=C.userRoles;o=A["if"].call(C,o,{hash:{},inverse:y.program(18,D,J),fn:y.program(16,E,J)});if(o||o===0){B+=o}B+='\n </div> \n</div>\n<div style="clear: both;"></div>\n\n';o=C.deleted;o=A["if"].call(C,o,{hash:{},inverse:y.noop,fn:y.program(20,p,J)});if(o||o===0){B+=o}B+="\n\n";B+="\n";B+="\n";o=C.userRoles;o=A["if"].call(C,o,{hash:{},inverse:y.noop,fn:y.program(24,i,J)});if(o||o===0){B+=o}B+="\n\n";o=C.message;o=A["if"].call(C,o,{hash:{},inverse:y.noop,fn:y.program(29,d,J)});if(o||o===0){B+=o}B+='\n\n<div id="quota-message-container">\n ';o=C.over_quota;o=A["if"].call(C,o,{hash:{},inverse:y.noop,fn:y.program(31,z,J)});if(o||o===0){B+=o}B+="\n</div>\n\n";o=C.itemsLength;o=A["if"].call(C,o,{hash:{},inverse:y.program(35,w,J),fn:y.program(33,x,J)});if(o||o===0){B+=o}return B})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(k,C,A,s,J){A=A||k.helpers;var B="",o,n,y=this,f="function",c=A.blockHelperMissing,e=this.escapeExpression;function u(L,K){return"refresh"}function t(L,K){return"collapse all"}function r(O,N){var L="",M,K;L+='\n <div style="width: 40px; float: right; white-space: nowrap;">\n <a id="history-tag" title="';K=A.local;if(K){M=K.call(O,{hash:{},inverse:y.noop,fn:y.program(6,q,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:y.noop,fn:y.program(6,q,N)})}if(M||M===0){L+=M}L+='"\n class="icon-button tags tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n <a id="history-annotate" title="';K=A.local;if(K){M=K.call(O,{hash:{},inverse:y.noop,fn:y.program(8,m,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:y.noop,fn:y.program(8,m,N)})}if(M||M===0){L+=M}L+='"\n class="icon-button annotate tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n </div>\n ';return L}function q(L,K){return"Edit history tags"}function m(L,K){return"Edit history annotation"}function I(O,N){var L="",M,K;L+='\n<div class="historyLinks">\n <a href="';K=A.hideDeletedURL;if(K){M=K.call(O,{hash:{}})}else{M=O.hideDeletedURL;M=typeof M===f?M():M}L+=e(M)+'">';K=A.local;if(K){M=K.call(O,{hash:{},inverse:y.noop,fn:y.program(11,H,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:y.noop,fn:y.program(11,H,N)})}if(M||M===0){L+=M}L+="</a>\n</div>\n";return L}function H(L,K){return"hide deleted"}function G(O,N){var L="",M,K;L+='\n<div class="historyLinks">\n <a href="';K=A.hideHiddenURL;if(K){M=K.call(O,{hash:{}})}else{M=O.hideHiddenURL;M=typeof M===f?M():M}L+=e(M)+'">';K=A.local;if(K){M=K.call(O,{hash:{},inverse:y.noop,fn:y.program(14,F,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:y.noop,fn:y.program(14,F,N)})}if(M||M===0){L+=M}L+="</a>\n</div>\n";return L}function F(L,K){return"hide hidden"}function E(O,N){var L="",M,K;L+="\n ";L+='\n <div id="history-size" style="position: absolute; top: 3px; right: 0px;">';K=A.diskSize;if(K){M=K.call(O,{hash:{}})}else{M=O.diskSize;M=typeof M===f?M():M}L+=e(M)+'</div>\n <div id="history-name" style="margin-right: 50px;" class="tooltip editable-text" title="Click to rename history">';K=A.name;if(K){M=K.call(O,{hash:{}})}else{M=O.name;M=typeof M===f?M():M}L+=e(M)+"</div>\n \n ";return L}function D(O,N){var L="",M,K;L+='\n <div id="history-size">';K=A.diskSize;if(K){M=K.call(O,{hash:{}})}else{M=O.diskSize;M=typeof M===f?M():M}L+=e(M)+"</div>\n ";return L}function p(O,N){var L="",M,K;L+="\n";K=A.warningmessagesmall;if(K){M=K.call(O,{hash:{},inverse:y.noop,fn:y.program(21,l,N)})}else{M=O.warningmessagesmall;M=typeof M===f?M():M}if(!A.warningmessagesmall){M=c.call(O,M,{hash:{},inverse:y.noop,fn:y.program(21,l,N)})}if(M||M===0){L+=M}L+="\n";return L}function l(N,M){var L,K;K=A.local;if(K){L=K.call(N,{hash:{},inverse:y.noop,fn:y.program(22,j,M)})}else{L=N.local;L=typeof L===f?L():L}if(!A.local){L=c.call(N,L,{hash:{},inverse:y.noop,fn:y.program(22,j,M)})}if(L||L===0){return L}else{return""}}function j(L,K){return"You are currently viewing a deleted history!"}function i(N,M){var K="",L;K+="\n";K+='\n<div style="margin: 0px 5px 10px 5px">\n\n <div id="history-tag-area" style="display: none">\n ';K+="\n ";K+='\n <strong>Tags:</strong>\n <div class="tag-elt"></div>\n </div>\n\n <div id="history-annotation-area" style="display: none">\n <strong>Annotation / Notes:</strong>\n <div id="history-annotation-container">\n <div id="history-annotation" class="tooltip editable-text" title="Click to edit annotation">\n ';L=N.annotation;L=A["if"].call(N,L,{hash:{},inverse:y.program(27,g,M),fn:y.program(25,h,M)});if(L||L===0){K+=L}K+="\n </div>\n </div>\n </div>\n</div>\n";return K}function h(O,N){var L="",M,K;L+="\n ";K=A.annotation;if(K){M=K.call(O,{hash:{}})}else{M=O.annotation;M=typeof M===f?M():M}L+=e(M)+"\n ";return L}function g(L,K){return"\n <em>Describe or add notes to history</em>\n "}function d(O,N){var L="",M,K;L+='\n<div id="message-container">\n <div class="';K=A.status;if(K){M=K.call(O,{hash:{}})}else{M=O.status;M=typeof M===f?M():M}L+=e(M)+'message">\n ';K=A.message;if(K){M=K.call(O,{hash:{}})}else{M=O.message;M=typeof M===f?M():M}L+=e(M)+"\n </div><br />\n</div>\n";return L}function z(L,K){return'\n <div id="quota-message" class="errormessage">\n You are over your disk quota. Tool execution is on hold until your disk usage drops below your allocated quota.\n </div>\n <br/>\n '}function x(O,N){var L="",M,K;L+='\n<div id="';K=A.id;if(K){M=K.call(O,{hash:{}})}else{M=O.id;M=typeof M===f?M():M}L+=e(M)+'-datasets" class="history-datasets-list">\n ';L+="\n</div>\n\n";return L}function w(O,N){var L="",M,K;L+='\n<div class="infomessagesmall" id="emptyHistoryMessage">\n';K=A.local;if(K){M=K.call(O,{hash:{},inverse:y.noop,fn:y.program(36,v,N)})}else{M=O.local;M=typeof M===f?M():M}if(!A.local){M=c.call(O,M,{hash:{},inverse:y.noop,fn:y.program(36,v,N)})}if(M||M===0){L+=M}L+="\n</div>\n";return L}function v(L,K){return"Your history is empty. Click 'Get Data' on the left pane to start"}B+='<div id="top-links" class="historyLinks">\n <a title="';n=A.local;if(n){o=n.call(C,{hash:{},inverse:y.noop,fn:y.program(1,u,J)})}else{o=C.local;o=typeof o===f?o():o}if(!A.local){o=c.call(C,o,{hash:{},inverse:y.noop,fn:y.program(1,u,J)})}if(o||o===0){B+=o}B+='" class="icon-button arrow-circle tooltip" href="';n=A.baseURL;if(n){o=n.call(C,{hash:{}})}else{o=C.baseURL;o=typeof o===f?o():o}B+=e(o)+"\"></a>\n <a title='";n=A.local;if(n){o=n.call(C,{hash:{},inverse:y.noop,fn:y.program(3,t,J)})}else{o=C.local;o=typeof o===f?o():o}if(!A.local){o=c.call(C,o,{hash:{},inverse:y.noop,fn:y.program(3,t,J)})}if(o||o===0){B+=o}B+="' id=\"history-collapse-all\"\n class='icon-button toggle tooltip' href='javascript:void(0);'></a>\n ";o=C.userRoles;o=A["if"].call(C,o,{hash:{},inverse:y.noop,fn:y.program(5,r,J)});if(o||o===0){B+=o}B+='\n</div>\n<div class="clear"></div>\n\n';B+="\n";o=C.showDeleted;o=A["if"].call(C,o,{hash:{},inverse:y.noop,fn:y.program(10,I,J)});if(o||o===0){B+=o}B+="\n\n";o=C.showHidden;o=A["if"].call(C,o,{hash:{},inverse:y.noop,fn:y.program(13,G,J)});if(o||o===0){B+=o}B+="\n\n";B+='\n<div id="history-name-area" class="historyLinks">\n <div id="history-name-container" style="position: relative;">\n ';o=C.userRoles;o=A["if"].call(C,o,{hash:{},inverse:y.program(18,D,J),fn:y.program(16,E,J)});if(o||o===0){B+=o}B+='\n </div> \n</div>\n<div style="clear: both;"></div>\n\n';o=C.deleted;o=A["if"].call(C,o,{hash:{},inverse:y.noop,fn:y.program(20,p,J)});if(o||o===0){B+=o}B+="\n\n";B+="\n";o=C.userRoles;o=A["if"].call(C,o,{hash:{},inverse:y.noop,fn:y.program(24,i,J)});if(o||o===0){B+=o}B+="\n\n";o=C.message;o=A["if"].call(C,o,{hash:{},inverse:y.noop,fn:y.program(29,d,J)});if(o||o===0){B+=o}B+='\n\n<div id="quota-message-container">\n ';o=C.over_quota;o=A["if"].call(C,o,{hash:{},inverse:y.noop,fn:y.program(31,z,J)});if(o||o===0){B+=o}B+="\n</div>\n\n";o=C.itemsLength;o=A["if"].call(C,o,{hash:{},inverse:y.program(35,w,J),fn:y.program(33,x,J)});if(o||o===0){B+=o}return B})})();
\ No newline at end of file
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b static/scripts/packed/templates/compiled/template-visualization-chartSettings.js
--- /dev/null
+++ b/static/scripts/packed/templates/compiled/template-visualization-chartSettings.js
@@ -0,0 +1,1 @@
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-chartSettings"]=b(function(f,m,e,l,k){e=e||f.helpers;var i="",c,h,g="function",j=this.escapeExpression,n=this;function d(p,o){return"checked"}i+='<p class="help-text">\n Use the following controls to how the chart is displayed.\n The slide controls can be moved by the mouse or, if the \'handle\' is in focus, your keyboard\'s arrow keys.\n Move the focus between controls by using the tab or shift+tab keys on your keyboard.\n Use the \'Draw\' button to render (or re-render) the chart with the current settings.\n </p>\n \n <div id="maxDataPoints" class="form-input numeric-slider-input">\n <label for="maxDataPoints">Maximum data points allowed on graph: </label>\n <div class="slider-output">';h=e.maxDataPoints;if(h){c=h.call(m,{hash:{}})}else{c=m.maxDataPoints;c=typeof c===g?c():c}i+=j(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n Change the maximum number of data points displayable on this graph (higher values will\n load significantly slower)\n </p>\n </div>\n\n <div id="datapointSize" class="form-input numeric-slider-input">\n <label for="datapointSize">Size of data point: </label>\n <div class="slider-output">';h=e.datapointSize;if(h){c=h.call(m,{hash:{}})}else{c=m.datapointSize;c=typeof c===g?c():c}i+=j(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n Size of the graphic representation of each data point\n </p>\n </div>\n\n <div id="entryAnimDuration" class="form-input checkbox-input">\n <label for="animated">Animate graph transitions?: </label>\n <input type="checkbox" id="animated" class="checkbox control" value="';c=m.entryAnimDuration;c=e["if"].call(m,c,{hash:{},inverse:n.noop,fn:n.program(1,d,k)});if(c||c===0){i+=c}i+='" />\n <p class="form-help help-text-small">\n Uncheck this to disable the animations used on the graph\n </p>\n </div>\n\n <div id="width" class="form-input numeric-slider-input">\n <label for="width">Graph width: </label>\n <div class="slider-output">';h=e.width;if(h){c=h.call(m,{hash:{}})}else{c=m.width;c=typeof c===g?c():c}i+=j(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including graph margins and axes)\n </p>\n </div>\n\n <div id="height" class="form-input numeric-slider-input">\n <label for="height">Graph height: </label>\n <div class="slider-output">';h=e.height;if(h){c=h.call(m,{hash:{}})}else{c=m.height;c=typeof c===g?c():c}i+=j(c)+'</div>\n <div class="slider"></div>\n <p class="form-help help-text-small">\n (not including graph margins and axes)\n </p>\n </div>\n\n <div id="X-axis-label"class="text-input form-input">\n <label for="X-axis-label">Re-label the X axis: </label>\n <input type="text" name="X-axis-label" id="X-axis-label" value="';h=e.xLabel;if(h){c=h.call(m,{hash:{}})}else{c=m.xLabel;c=typeof c===g?c():c}i+=j(c)+'" />\n <p class="form-help help-text-small"></p>\n </div>\n\n <div id="Y-axis-label" class="text-input form-input">\n <label for="Y-axis-label">Re-label the Y axis: </label>\n <input type="text" name="Y-axis-label" id="Y-axis-label" value="';h=e.yLabel;if(h){c=h.call(m,{hash:{}})}else{c=m.yLabel;c=typeof c===g?c():c}i+=j(c)+'" />\n <p class="form-help help-text-small"></p>\n </div>\n\n <input id="render-button" type="button" value="Draw" />';return i})})();
\ No newline at end of file
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b static/scripts/packed/templates/compiled/template-visualization-statsTable.js
--- /dev/null
+++ b/static/scripts/packed/templates/compiled/template-visualization-statsTable.js
@@ -0,0 +1,1 @@
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-statsTable"]=b(function(f,l,e,k,j){e=e||f.helpers;var h="",c,g="function",i=this.escapeExpression,m=this;function d(r,q){var o="",p,n;o+="\n <tr><td>";n=e.name;if(n){p=n.call(r,{hash:{}})}else{p=r.name;p=typeof p===g?p():p}o+=i(p)+"</td><td>";n=e.xval;if(n){p=n.call(r,{hash:{}})}else{p=r.xval;p=typeof p===g?p():p}o+=i(p)+"</td><td>";n=e.yval;if(n){p=n.call(r,{hash:{}})}else{p=r.yval;p=typeof p===g?p():p}o+=i(p)+"</td></tr>\n </tr>\n ";return o}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=l.stats;c=e.each.call(l,c,{hash:{},inverse:m.noop,fn:m.program(1,d,j)});if(c||c===0){h+=c}h+="\n </table>";return h})})();
\ No newline at end of file
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b static/scripts/packed/viz/phyloviz.js
--- a/static/scripts/packed/viz/phyloviz.js
+++ b/static/scripts/packed/viz/phyloviz.js
@@ -1,1 +1,1 @@
-define(["libs/d3","viz/visualization"],function(l,f){var k=Backbone.View.extend({className:"UserMenuBase",isAcceptableValue:function(q,o,m){var n=this,r=q.val(),s=q.attr("displayLabel")||q.attr("id").replace("phyloViz","");function p(t){return !isNaN(parseFloat(t))&&isFinite(t)}if(!p(r)){alert(s+" is not a number!");return false}if(r>m){alert(s+" is too large.");return false}else{if(r<o){alert(s+" is too small.");return false}}return true},hasIllegalJsonCharacters:function(m){if(m.val().search(/"|'|\\/)!==-1){alert("Named fields cannot contain these illegal characters: double quote(\"), single guote('), or back slash(\\). ");return true}return false}});function g(){var v=this,q=l.layout.hierarchy().sort(null).value(null),u=360,p="Linear",t=18,r=200,s=0,o=0.5,m=50;v.leafHeight=function(w){if(typeof w==="undefined"){return t}else{t=w;return v}};v.layoutMode=function(w){if(typeof w==="undefined"){return p}else{p=w;return v}};v.layoutAngle=function(w){if(typeof w==="undefined"){return u}if(isNaN(w)||w<0||w>360){return v}else{u=w;return v}};v.separation=function(w){if(typeof w==="undefined"){return r}else{r=w;return v}};v.links=function(w){return l.layout.tree().links(w)};v.nodes=function(z,x){var y=q.call(v,z,x),w=[],B=0,A=0;y.forEach(function(C){var D=C.data;D.depth=C.depth;B=D.depth>B?D.depth:B;w.push(D)});w.forEach(function(C){if(!C.children){A+=1;C.depth=B}});t=p==="Circular"?u/A:t;s=0;n(w[0],B,t,null);return w};function n(A,C,z,y){var x=A.children,w=0;var B=A.dist||o;B=B>1?1:B;A.dist=B;if(y!==null){A.y0=y.y0+B*r}else{A.y0=m}if(!x){A.x0=s++*z}else{x.forEach(function(D){D.parent=A;w+=n(D,C,z,A)});A.x0=w/x.length}A.x=A.x0;A.y=A.y0;return A.x0}return v}var b=f.Visualization.extend({defaults:{layout:"Linear",separation:250,leafHeight:18,type:"phyloviz",title:"Title",scaleFactor:1,translate:[0,0],fontSize:12,selectedNode:null,nodeAttrChangedTime:0},root:{},toggle:function(m){if(typeof m==="undefined"){return}if(m.children){m._children=m.children;m.children=null}else{m.children=m._children;m._children=null}},toggleAll:function(m){if(m.children&&m.children.length!==0){m.children.forEach(this.toggleAll);toggle(m)}},getData:function(){return this.root},save:function(){var m=this.root;n(m);this.set("root",m);function n(p){delete p.parent;if(p._selected){delete p._selected}if(p.children){p.children.forEach(n)}if(p._children){p._children.forEach(n)}}var o=jQuery.extend(true,{},this.attributes);o.selectedNode=null;show_message("Saving to Galaxy","progress");return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(o)},success:function(p){var q=p.url.split("id=")[1].split("&")[0],r="/phyloviz/visualization?id="+q;window.history.pushState({},"",r+window.location.hash);hide_modal()}})}});var d=Backbone.View.extend({defaults:{nodeRadius:4.5},stdInit:function(n){var m=this;m.model.on("change:separation change:leafHeight change:fontSize change:nodeAttrChangedTime",m.updateAndRender,m);m.vis=n.vis;m.i=0;m.maxDepth=-1;m.width=n.width;m.height=n.height},updateAndRender:function(o){var n=l.select(".vis"),m=this;o=o||m.model.root;m.renderNodes(o);m.renderLinks(o);m.addTooltips()},renderLinks:function(m){var v=this;var n=v.diagonal;var o=v.duration;var q=v.layoutMode;var s=v.vis.selectAll("g.completeLink").data(v.tree.links(v.nodes),function(w){return w.target.id});var u=function(w){w.pos0=w.source.y0+" "+w.source.x0;w.pos1=w.source.y0+" "+w.target.x0;w.pos2=w.target.y0+" "+w.target.x0};var t=s.enter().insert("svg:g","g.node").attr("class","completeLink");t.append("svg:path").attr("class","link").attr("d",function(w){u(w);return"M "+w.pos0+" L "+w.pos1});var r=s.transition().duration(500);r.select("path.link").attr("d",function(w){u(w);return"M "+w.pos0+" L "+w.pos1+" L "+w.pos2});var p=s.exit().remove()},selectNode:function(n){var m=this;l.selectAll("g.node").classed("selectedHighlight",function(o){if(n.id===o.id){if(n._selected){delete n._selected;return false}else{n._selected=true;return true}}return false});m.model.set("selectedNode",n);$("#phyloVizSelectedNodeName").val(n.name);$("#phyloVizSelectedNodeDist").val(n.dist);$("#phyloVizSelectedNodeAnnotation").val(n.annotation||"")},addTooltips:function(){$(".bs-tooltip").remove();$(".node").attr("data-original-title",function(){var n=this.__data__,m=n.annotation||"None";return n?(n.name?n.name+"<br/>":"")+"Dist: "+n.dist+" <br/>Annotation: "+m:""}).tooltip({placement:"top",trigger:"hover"})}});var a=d.extend({initialize:function(n){var m=this;m.margins=n.margins;m.layoutMode="Linear";m.stdInit(n);m.layout();m.updateAndRender(m.model.root)},layout:function(){var m=this;m.tree=new g().layoutMode("Linear");m.diagonal=l.svg.diagonal().projection(function(n){return[n.y,n.x]})},renderNodes:function(m){var t=this,u=t.model.get("fontSize")+"px";t.tree.separation(t.model.get("separation")).leafHeight(t.model.get("leafHeight"));var p=500,n=t.tree.separation(t.model.get("separation")).nodes(t.model.root);var o=t.vis.selectAll("g.node").data(n,function(v){return v.name+v.id||(v.id=++t.i)});t.nodes=n;t.duration=p;var q=o.enter().append("svg:g").attr("class","node").on("dblclick",function(){l.event.stopPropagation()}).on("click",function(v){if(l.event.altKey){t.selectNode(v)}else{if(v.children&&v.children.length===0){return}t.model.toggle(v);t.updateAndRender(v)}});q.attr("transform",function(v){return"translate("+m.y0+","+m.x0+")"});q.append("svg:circle").attr("r",0.000001).style("fill",function(v){return v._children?"lightsteelblue":"#fff"});q.append("svg:text").attr("class","nodeLabel").attr("x",function(v){return v.children||v._children?-10:10}).attr("dy",".35em").attr("text-anchor",function(v){return v.children||v._children?"end":"start"}).style("fill-opacity",0.000001);var r=o.transition().duration(p);r.attr("transform",function(v){return"translate("+v.y+","+v.x+")"});r.select("circle").attr("r",t.defaults.nodeRadius).style("fill",function(v){return v._children?"lightsteelblue":"#fff"});r.select("text").style("fill-opacity",1).style("font-size",u).text(function(v){return v.name});var s=o.exit().transition().duration(p).remove();s.select("circle").attr("r",0.000001);s.select("text").style("fill-opacity",0.000001);n.forEach(function(v){v.x0=v.x;v.y0=v.y})}});var i=Backbone.View.extend({className:"phyloviz",initialize:function(n){var m=this;m.MIN_SCALE=0.05;m.MAX_SCALE=5;m.MAX_DISPLACEMENT=500;m.margins=[10,60,10,80];m.width=$("#PhyloViz").width();m.height=$("#PhyloViz").height();m.radius=m.width;m.data=n.data;$(window).resize(function(){m.width=$("#PhyloViz").width();m.height=$("#PhyloViz").height();m.render()});m.phyloTree=new b(n.config);m.phyloTree.root=m.data;m.zoomFunc=l.behavior.zoom().scaleExtent([m.MIN_SCALE,m.MAX_SCALE]);m.zoomFunc.translate(m.phyloTree.get("translate"));m.zoomFunc.scale(m.phyloTree.get("scaleFactor"));m.navMenu=new c(m);m.settingsMenu=new h({phyloTree:m.phyloTree});m.nodeSelectionView=new e({phyloTree:m.phyloTree});m.search=new j();setTimeout(function(){m.zoomAndPan()},1000)},render:function(){var n=this;$("#PhyloViz").empty();n.mainSVG=l.select("#PhyloViz").append("svg:svg").attr("width",n.width).attr("height",n.height).attr("pointer-events","all").call(n.zoomFunc.on("zoom",function(){n.zoomAndPan()}));n.boundingRect=n.mainSVG.append("svg:rect").attr("class","boundingRect").attr("width",n.width).attr("height",n.height).attr("stroke","black").attr("fill","white");n.vis=n.mainSVG.append("svg:g").attr("class","vis");n.layoutOptions={model:n.phyloTree,width:n.width,height:n.height,vis:n.vis,margins:n.margins};$("#title").text("Phylogenetic Tree from "+n.phyloTree.get("title")+":");var m=new a(n.layoutOptions)},zoomAndPan:function(m){var s,o;if(typeof m!=="undefined"){s=m.zoom;o=m.translate}var v=this,q=v.zoomFunc.scale(),u=v.zoomFunc.translate(),r="",t="";switch(s){case"reset":q=1;u=[0,0];break;case"+":q*=1.1;break;case"-":q*=0.9;break;default:if(typeof s==="number"){q=s}else{if(l.event!==null){q=l.event.scale}}}if(q<v.MIN_SCALE||q>v.MAX_SCALE){return}v.zoomFunc.scale(q);r="translate("+v.margins[3]+","+v.margins[0]+") scale("+q+")";if(l.event!==null){t="translate("+l.event.translate+")"}else{if(typeof o!=="undefined"){var p=o.split(",")[0];var n=o.split(",")[1];if(!isNaN(p)&&!isNaN(n)){u=[u[0]+parseFloat(p),u[1]+parseFloat(n)]}}v.zoomFunc.translate(u);t="translate("+u+")"}v.phyloTree.set("scaleFactor",q);v.phyloTree.set("translate",u);v.vis.attr("transform",t+r)},reloadViz:function(){var n=this,p=$("#phylovizNexSelector :selected").val(),m=n.phyloTree.get("dataset_id"),o="phyloviz/getJsonData?dataset_id="+m+"&treeIndex="+String(p);$.getJSON(o,function(q){window.initPhyloViz(q.data,q.config)})}});var c=Backbone.View.extend({initialize:function(n){var m=this;m.phylovizView=n;$("#panelHeaderRightBtns").empty();$("#phyloVizNavBtns").empty();$("#phylovizNexSelector").off();m.initNavBtns();m.initRightHeaderBtns();$("#phylovizNexSelector").off().on("change",function(){m.phylovizView.reloadViz()})},initRightHeaderBtns:function(){var m=this;rightMenu=create_icon_buttons_menu([{icon_class:"gear",title:"PhyloViz Settings",on_click:function(){$("#SettingsMenu").show();m.settingsMenu.updateUI()}},{icon_class:"disk",title:"Save visualization",on_click:function(){var n=$("#phylovizNexSelector option:selected").text();if(n){m.phylovizView.phyloTree.set("title",n)}m.phylovizView.phyloTree.save()}},{icon_class:"chevron-expand",title:"Search / Edit Nodes",on_click:function(){$("#nodeSelectionView").show()}},{icon_class:"information",title:"Phyloviz Help",on_click:function(){window.open("http://wiki.g2.bx.psu.edu/Learn/Visualization/PhylogeneticTree")}}],{tooltip_config:{placement:"bottom"}});$("#panelHeaderRightBtns").append(rightMenu.$el)},initNavBtns:function(){var m=this,n=create_icon_buttons_menu([{icon_class:"zoom-in",title:"Zoom in",on_click:function(){m.phylovizView.zoomAndPan({zoom:"+"})}},{icon_class:"zoom-out",title:"Zoom out",on_click:function(){m.phylovizView.zoomAndPan({zoom:"-"})}},{icon_class:"arrow-circle",title:"Reset Zoom/Pan",on_click:function(){m.phylovizView.zoomAndPan({zoom:"reset"})}}],{tooltip_config:{placement:"bottom"}});$("#phyloVizNavBtns").append(n.$el)}});var h=k.extend({className:"Settings",initialize:function(n){var m=this;m.phyloTree=n.phyloTree;m.el=$("#SettingsMenu");m.inputs={separation:$("#phyloVizTreeSeparation"),leafHeight:$("#phyloVizTreeLeafHeight"),fontSize:$("#phyloVizTreeFontSize")};$("#settingsCloseBtn").off().on("click",function(){m.el.hide()});$("#phylovizResetSettingsBtn").off().on("click",function(){m.resetToDefaults()});$("#phylovizApplySettingsBtn").off().on("click",function(){m.apply()})},apply:function(){var m=this;if(!m.isAcceptableValue(m.inputs.separation,50,2500)||!m.isAcceptableValue(m.inputs.leafHeight,5,30)||!m.isAcceptableValue(m.inputs.fontSize,5,20)){return}$.each(m.inputs,function(n,o){m.phyloTree.set(n,o.val())})},updateUI:function(){var m=this;$.each(m.inputs,function(n,o){o.val(m.phyloTree.get(n))})},resetToDefaults:function(){$(".bs-tooltip").remove();var m=this;$.each(m.phyloTree.defaults,function(n,o){m.phyloTree.set(n,o)});m.updateUI()},render:function(){}});var e=k.extend({className:"Settings",initialize:function(n){var m=this;m.el=$("#nodeSelectionView");m.phyloTree=n.phyloTree;m.UI={enableEdit:$("#phylovizEditNodesCheck"),saveChanges:$("#phylovizNodeSaveChanges"),cancelChanges:$("#phylovizNodeCancelChanges"),name:$("#phyloVizSelectedNodeName"),dist:$("#phyloVizSelectedNodeDist"),annotation:$("#phyloVizSelectedNodeAnnotation")};m.valuesOfConcern={name:null,dist:null,annotation:null};$("#nodeSelCloseBtn").off().on("click",function(){m.el.hide()});m.UI.saveChanges.off().on("click",function(){m.updateNodes()});m.UI.cancelChanges.off().on("click",function(){m.cancelChanges()});(function(o){o.fn.enable=function(p){return o(this).each(function(){if(p){o(this).removeAttr("disabled")}else{o(this).attr("disabled","disabled")}})}})(jQuery);m.UI.enableEdit.off().on("click",function(){m.toggleUI()})},toggleUI:function(){var m=this,n=m.UI.enableEdit.is(":checked");if(!n){m.cancelChanges()}$.each(m.valuesOfConcern,function(o,p){m.UI[o].enable(n)});if(n){m.UI.saveChanges.show();m.UI.cancelChanges.show()}else{m.UI.saveChanges.hide();m.UI.cancelChanges.hide()}},cancelChanges:function(){var m=this,n=m.phyloTree.get("selectedNode");if(n){$.each(m.valuesOfConcern,function(o,p){m.UI[o].val(n[o])})}},updateNodes:function(){var m=this,n=m.phyloTree.get("selectedNode");if(n){if(!m.isAcceptableValue(m.UI.dist,0,1)||m.hasIllegalJsonCharacters(m.UI.name)||m.hasIllegalJsonCharacters(m.UI.annotation)){return}$.each(m.valuesOfConcern,function(o,p){(n[o])=m.UI[o].val()});m.phyloTree.set("nodeAttrChangedTime",new Date())}else{alert("No node selected")}}});var j=k.extend({initialize:function(){var m=this;$("#phyloVizSearchBtn").on("click",function(){var o=$("#phyloVizSearchTerm"),p=$("#phyloVizSearchCondition").val().split("-"),n=p[0],q=p[1];m.hasIllegalJsonCharacters(o);if(n==="dist"){m.isAcceptableValue(o,0,1)}m.searchTree(n,q,o.val())})},searchTree:function(m,o,n){l.selectAll("g.node").classed("searchHighlight",function(q){var p=q[m];if(typeof p!=="undefined"&&p!==null){if(m==="dist"){switch(o){case"greaterEqual":return p>=+n;case"lesserEqual":return p<=+n;default:return}}else{if(m==="name"||m==="annotation"){return p.toLowerCase().indexOf(n.toLowerCase())!==-1}}}})}});return{PhylovizView:i}});
\ No newline at end of file
+define(["libs/d3","viz/visualization","mvc/data"],function(m,f,g){var l=Backbone.View.extend({className:"UserMenuBase",isAcceptableValue:function(r,p,n){var o=this,s=r.val(),t=r.attr("displayLabel")||r.attr("id").replace("phyloViz","");function q(u){return !isNaN(parseFloat(u))&&isFinite(u)}if(!q(s)){alert(t+" is not a number!");return false}if(s>n){alert(t+" is too large.");return false}else{if(s<p){alert(t+" is too small.");return false}}return true},hasIllegalJsonCharacters:function(n){if(n.val().search(/"|'|\\/)!==-1){alert("Named fields cannot contain these illegal characters: double quote(\"), single guote('), or back slash(\\). ");return true}return false}});function h(){var w=this,r=m.layout.hierarchy().sort(null).value(null),v=360,q="Linear",u=18,s=200,t=0,p=0.5,n=50;w.leafHeight=function(x){if(typeof x==="undefined"){return u}else{u=x;return w}};w.layoutMode=function(x){if(typeof x==="undefined"){return q}else{q=x;return w}};w.layoutAngle=function(x){if(typeof x==="undefined"){return v}if(isNaN(x)||x<0||x>360){return w}else{v=x;return w}};w.separation=function(x){if(typeof x==="undefined"){return s}else{s=x;return w}};w.links=function(x){return m.layout.tree().links(x)};w.nodes=function(A,y){var z=r.call(w,A,y),x=[],C=0,B=0;z.forEach(function(D){var E=D.data;E.depth=D.depth;C=E.depth>C?E.depth:C;x.push(E)});x.forEach(function(D){if(!D.children){B+=1;D.depth=C}});u=q==="Circular"?v/B:u;t=0;o(x[0],C,u,null);return x};function o(B,D,A,z){var y=B.children,x=0;var C=B.dist||p;C=C>1?1:C;B.dist=C;if(z!==null){B.y0=z.y0+C*s}else{B.y0=n}if(!y){B.x0=t++*A}else{y.forEach(function(E){E.parent=B;x+=o(E,D,A,B)});B.x0=x/y.length}B.x=B.x0;B.y=B.y0;return B.x0}return w}var b=f.Visualization.extend({defaults:{layout:"Linear",separation:250,leafHeight:18,type:"phyloviz",title:"Title",scaleFactor:1,translate:[0,0],fontSize:12,selectedNode:null,nodeAttrChangedTime:0},initialize:function(n){this.set("dataset",new g.Dataset({id:n.dataset_id}))},root:{},toggle:function(n){if(typeof n==="undefined"){return}if(n.children){n._children=n.children;n.children=null}else{n.children=n._children;n._children=null}},toggleAll:function(n){if(n.children&&n.children.length!==0){n.children.forEach(this.toggleAll);toggle(n)}},getData:function(){return this.root},save:function(){var n=this.root;o(n);this.set("root",n);function o(q){delete q.parent;if(q._selected){delete q._selected}if(q.children){q.children.forEach(o)}if(q._children){q._children.forEach(o)}}var p=jQuery.extend(true,{},this.attributes);p.selectedNode=null;show_message("Saving to Galaxy","progress");return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(p)},success:function(q){var r=q.url.split("id=")[1].split("&")[0],s="/visualization?id="+r;window.history.pushState({},"",s+window.location.hash);hide_modal()}})}});var d=Backbone.View.extend({defaults:{nodeRadius:4.5},stdInit:function(o){var n=this;n.model.on("change:separation change:leafHeight change:fontSize change:nodeAttrChangedTime",n.updateAndRender,n);n.vis=o.vis;n.i=0;n.maxDepth=-1;n.width=o.width;n.height=o.height},updateAndRender:function(p){var o=m.select(".vis"),n=this;p=p||n.model.root;n.renderNodes(p);n.renderLinks(p);n.addTooltips()},renderLinks:function(n){var w=this;var o=w.diagonal;var p=w.duration;var r=w.layoutMode;var t=w.vis.selectAll("g.completeLink").data(w.tree.links(w.nodes),function(x){return x.target.id});var v=function(x){x.pos0=x.source.y0+" "+x.source.x0;x.pos1=x.source.y0+" "+x.target.x0;x.pos2=x.target.y0+" "+x.target.x0};var u=t.enter().insert("svg:g","g.node").attr("class","completeLink");u.append("svg:path").attr("class","link").attr("d",function(x){v(x);return"M "+x.pos0+" L "+x.pos1});var s=t.transition().duration(500);s.select("path.link").attr("d",function(x){v(x);return"M "+x.pos0+" L "+x.pos1+" L "+x.pos2});var q=t.exit().remove()},selectNode:function(o){var n=this;m.selectAll("g.node").classed("selectedHighlight",function(p){if(o.id===p.id){if(o._selected){delete o._selected;return false}else{o._selected=true;return true}}return false});n.model.set("selectedNode",o);$("#phyloVizSelectedNodeName").val(o.name);$("#phyloVizSelectedNodeDist").val(o.dist);$("#phyloVizSelectedNodeAnnotation").val(o.annotation||"")},addTooltips:function(){$(".bs-tooltip").remove();$(".node").attr("data-original-title",function(){var o=this.__data__,n=o.annotation||"None";return o?(o.name?o.name+"<br/>":"")+"Dist: "+o.dist+" <br/>Annotation: "+n:""}).tooltip({placement:"top",trigger:"hover"})}});var a=d.extend({initialize:function(o){var n=this;n.margins=o.margins;n.layoutMode="Linear";n.stdInit(o);n.layout();n.updateAndRender(n.model.root)},layout:function(){var n=this;n.tree=new h().layoutMode("Linear");n.diagonal=m.svg.diagonal().projection(function(o){return[o.y,o.x]})},renderNodes:function(n){var u=this,v=u.model.get("fontSize")+"px";u.tree.separation(u.model.get("separation")).leafHeight(u.model.get("leafHeight"));var q=500,o=u.tree.separation(u.model.get("separation")).nodes(u.model.root);var p=u.vis.selectAll("g.node").data(o,function(w){return w.name+w.id||(w.id=++u.i)});u.nodes=o;u.duration=q;var r=p.enter().append("svg:g").attr("class","node").on("dblclick",function(){m.event.stopPropagation()}).on("click",function(w){if(m.event.altKey){u.selectNode(w)}else{if(w.children&&w.children.length===0){return}u.model.toggle(w);u.updateAndRender(w)}});r.attr("transform",function(w){return"translate("+n.y0+","+n.x0+")"});r.append("svg:circle").attr("r",0.000001).style("fill",function(w){return w._children?"lightsteelblue":"#fff"});r.append("svg:text").attr("class","nodeLabel").attr("x",function(w){return w.children||w._children?-10:10}).attr("dy",".35em").attr("text-anchor",function(w){return w.children||w._children?"end":"start"}).style("fill-opacity",0.000001);var s=p.transition().duration(q);s.attr("transform",function(w){return"translate("+w.y+","+w.x+")"});s.select("circle").attr("r",u.defaults.nodeRadius).style("fill",function(w){return w._children?"lightsteelblue":"#fff"});s.select("text").style("fill-opacity",1).style("font-size",v).text(function(w){return w.name});var t=p.exit().transition().duration(q).remove();t.select("circle").attr("r",0.000001);t.select("text").style("fill-opacity",0.000001);o.forEach(function(w){w.x0=w.x;w.y0=w.y})}});var j=Backbone.View.extend({className:"phyloviz",initialize:function(o){var n=this;n.MIN_SCALE=0.05;n.MAX_SCALE=5;n.MAX_DISPLACEMENT=500;n.margins=[10,60,10,80];n.width=$("#PhyloViz").width();n.height=$("#PhyloViz").height();n.radius=n.width;n.data=o.data;$(window).resize(function(){n.width=$("#PhyloViz").width();n.height=$("#PhyloViz").height();n.render()});n.phyloTree=new b(o.config);n.phyloTree.root=n.data;n.zoomFunc=m.behavior.zoom().scaleExtent([n.MIN_SCALE,n.MAX_SCALE]);n.zoomFunc.translate(n.phyloTree.get("translate"));n.zoomFunc.scale(n.phyloTree.get("scaleFactor"));n.navMenu=new c(n);n.settingsMenu=new i({phyloTree:n.phyloTree});n.nodeSelectionView=new e({phyloTree:n.phyloTree});n.search=new k();setTimeout(function(){n.zoomAndPan()},1000)},render:function(){var o=this;$("#PhyloViz").empty();o.mainSVG=m.select("#PhyloViz").append("svg:svg").attr("width",o.width).attr("height",o.height).attr("pointer-events","all").call(o.zoomFunc.on("zoom",function(){o.zoomAndPan()}));o.boundingRect=o.mainSVG.append("svg:rect").attr("class","boundingRect").attr("width",o.width).attr("height",o.height).attr("stroke","black").attr("fill","white");o.vis=o.mainSVG.append("svg:g").attr("class","vis");o.layoutOptions={model:o.phyloTree,width:o.width,height:o.height,vis:o.vis,margins:o.margins};$("#title").text("Phylogenetic Tree from "+o.phyloTree.get("title")+":");var n=new a(o.layoutOptions)},zoomAndPan:function(n){var t,p;if(typeof n!=="undefined"){t=n.zoom;p=n.translate}var w=this,r=w.zoomFunc.scale(),v=w.zoomFunc.translate(),s="",u="";switch(t){case"reset":r=1;v=[0,0];break;case"+":r*=1.1;break;case"-":r*=0.9;break;default:if(typeof t==="number"){r=t}else{if(m.event!==null){r=m.event.scale}}}if(r<w.MIN_SCALE||r>w.MAX_SCALE){return}w.zoomFunc.scale(r);s="translate("+w.margins[3]+","+w.margins[0]+") scale("+r+")";if(m.event!==null){u="translate("+m.event.translate+")"}else{if(typeof p!=="undefined"){var q=p.split(",")[0];var o=p.split(",")[1];if(!isNaN(q)&&!isNaN(o)){v=[v[0]+parseFloat(q),v[1]+parseFloat(o)]}}w.zoomFunc.translate(v);u="translate("+v+")"}w.phyloTree.set("scaleFactor",r);w.phyloTree.set("translate",v);w.vis.attr("transform",u+s)},reloadViz:function(){var n=this,o=$("#phylovizNexSelector :selected").val();$.getJSON(n.phyloTree.get("dataset").url(),{tree_index:o,data_type:"raw_data"},function(p){n.data=p.data;n.config=p;n.render()})}});var c=Backbone.View.extend({initialize:function(o){var n=this;n.phylovizView=o;$("#panelHeaderRightBtns").empty();$("#phyloVizNavBtns").empty();$("#phylovizNexSelector").off();n.initNavBtns();n.initRightHeaderBtns();$("#phylovizNexSelector").off().on("change",function(){n.phylovizView.reloadViz()})},initRightHeaderBtns:function(){var n=this;rightMenu=create_icon_buttons_menu([{icon_class:"gear",title:"PhyloViz Settings",on_click:function(){$("#SettingsMenu").show();n.settingsMenu.updateUI()}},{icon_class:"disk",title:"Save visualization",on_click:function(){var o=$("#phylovizNexSelector option:selected").text();if(o){n.phylovizView.phyloTree.set("title",o)}n.phylovizView.phyloTree.save()}},{icon_class:"chevron-expand",title:"Search / Edit Nodes",on_click:function(){$("#nodeSelectionView").show()}},{icon_class:"information",title:"Phyloviz Help",on_click:function(){window.open("http://wiki.g2.bx.psu.edu/Learn/Visualization/PhylogeneticTree")}}],{tooltip_config:{placement:"bottom"}});$("#panelHeaderRightBtns").append(rightMenu.$el)},initNavBtns:function(){var n=this,o=create_icon_buttons_menu([{icon_class:"zoom-in",title:"Zoom in",on_click:function(){n.phylovizView.zoomAndPan({zoom:"+"})}},{icon_class:"zoom-out",title:"Zoom out",on_click:function(){n.phylovizView.zoomAndPan({zoom:"-"})}},{icon_class:"arrow-circle",title:"Reset Zoom/Pan",on_click:function(){n.phylovizView.zoomAndPan({zoom:"reset"})}}],{tooltip_config:{placement:"bottom"}});$("#phyloVizNavBtns").append(o.$el)}});var i=l.extend({className:"Settings",initialize:function(o){var n=this;n.phyloTree=o.phyloTree;n.el=$("#SettingsMenu");n.inputs={separation:$("#phyloVizTreeSeparation"),leafHeight:$("#phyloVizTreeLeafHeight"),fontSize:$("#phyloVizTreeFontSize")};$("#settingsCloseBtn").off().on("click",function(){n.el.hide()});$("#phylovizResetSettingsBtn").off().on("click",function(){n.resetToDefaults()});$("#phylovizApplySettingsBtn").off().on("click",function(){n.apply()})},apply:function(){var n=this;if(!n.isAcceptableValue(n.inputs.separation,50,2500)||!n.isAcceptableValue(n.inputs.leafHeight,5,30)||!n.isAcceptableValue(n.inputs.fontSize,5,20)){return}$.each(n.inputs,function(o,p){n.phyloTree.set(o,p.val())})},updateUI:function(){var n=this;$.each(n.inputs,function(o,p){p.val(n.phyloTree.get(o))})},resetToDefaults:function(){$(".bs-tooltip").remove();var n=this;$.each(n.phyloTree.defaults,function(o,p){n.phyloTree.set(o,p)});n.updateUI()},render:function(){}});var e=l.extend({className:"Settings",initialize:function(o){var n=this;n.el=$("#nodeSelectionView");n.phyloTree=o.phyloTree;n.UI={enableEdit:$("#phylovizEditNodesCheck"),saveChanges:$("#phylovizNodeSaveChanges"),cancelChanges:$("#phylovizNodeCancelChanges"),name:$("#phyloVizSelectedNodeName"),dist:$("#phyloVizSelectedNodeDist"),annotation:$("#phyloVizSelectedNodeAnnotation")};n.valuesOfConcern={name:null,dist:null,annotation:null};$("#nodeSelCloseBtn").off().on("click",function(){n.el.hide()});n.UI.saveChanges.off().on("click",function(){n.updateNodes()});n.UI.cancelChanges.off().on("click",function(){n.cancelChanges()});(function(p){p.fn.enable=function(q){return p(this).each(function(){if(q){p(this).removeAttr("disabled")}else{p(this).attr("disabled","disabled")}})}})(jQuery);n.UI.enableEdit.off().on("click",function(){n.toggleUI()})},toggleUI:function(){var n=this,o=n.UI.enableEdit.is(":checked");if(!o){n.cancelChanges()}$.each(n.valuesOfConcern,function(p,q){n.UI[p].enable(o)});if(o){n.UI.saveChanges.show();n.UI.cancelChanges.show()}else{n.UI.saveChanges.hide();n.UI.cancelChanges.hide()}},cancelChanges:function(){var n=this,o=n.phyloTree.get("selectedNode");if(o){$.each(n.valuesOfConcern,function(p,q){n.UI[p].val(o[p])})}},updateNodes:function(){var n=this,o=n.phyloTree.get("selectedNode");if(o){if(!n.isAcceptableValue(n.UI.dist,0,1)||n.hasIllegalJsonCharacters(n.UI.name)||n.hasIllegalJsonCharacters(n.UI.annotation)){return}$.each(n.valuesOfConcern,function(p,q){(o[p])=n.UI[p].val()});n.phyloTree.set("nodeAttrChangedTime",new Date())}else{alert("No node selected")}}});var k=l.extend({initialize:function(){var n=this;$("#phyloVizSearchBtn").on("click",function(){var p=$("#phyloVizSearchTerm"),q=$("#phyloVizSearchCondition").val().split("-"),o=q[0],r=q[1];n.hasIllegalJsonCharacters(p);if(o==="dist"){n.isAcceptableValue(p,0,1)}n.searchTree(o,r,p.val())})},searchTree:function(n,p,o){m.selectAll("g.node").classed("searchHighlight",function(r){var q=r[n];if(typeof q!=="undefined"&&q!==null){if(n==="dist"){switch(p){case"greaterEqual":return q>=+o;case"lesserEqual":return q<=+o;default:return}}else{if(n==="name"||n==="annotation"){return q.toLowerCase().indexOf(o.toLowerCase())!==-1}}}})}});return{PhylovizView:j}});
\ No newline at end of file
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b 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(ac,x,l,u,L,aa,i){var q=ac.extend;var Q=l.get_random_color;var ad=function(ae,ag,af){$.ajax({url:ae,data:{"f-dbkey":view.dbkey},error:function(){alert("Grid failed")},success:function(ah){show_modal("Select datasets for new tracks",ah,{Cancel:function(){hide_modal()},Add:function(){var ai=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var aj={data_type:"track_config",hda_ldda:"hda"},ak=$(this).val();if($(this).attr("name")!=="id"){aj.hda_ldda="ldda"}ai[ai.length]=$.ajax({url:ag+"/"+ak,data:aj,dataType:"json"})});$.when.apply($,ai).then(function(){var aj=(arguments[0] instanceof Array?$.map(arguments,function(ak){return ak[0]}):[arguments[0]]);af(aj)});hide_modal()}})}})};var W=function(ae){return("isResolved" in ae)};var n={};var k=function(ae,af){n[ae.attr("id")]=af};var m=function(ae,ag,ai,ah){ai=".group";var af={};n[ae.attr("id")]=ah;ae.bind("drag",{handle:"."+ag,relative:true},function(aq,ar){var ap=$(this),av=$(this).parent(),am=av.children(),ao=n[$(this).attr("id")],al,ak,at,aj,an;ak=$(this).parents(ai);if(ak.length!==0){at=ak.position().top;aj=at+ak.outerHeight();if(ar.offsetY<at){$(this).insertBefore(ak);var au=n[ak.attr("id")];au.remove_drawable(ao);au.container.add_drawable_before(ao,au);return}else{if(ar.offsetY>aj){$(this).insertAfter(ak);var au=n[ak.attr("id")];au.remove_drawable(ao);au.container.add_drawable(ao);return}}}ak=null;for(an=0;an<am.length;an++){al=$(am.get(an));at=al.position().top;aj=at+al.outerHeight();if(al.is(ai)&&this!==al.get(0)&&ar.offsetY>=at&&ar.offsetY<=aj){if(ar.offsetY-at<aj-ar.offsetY){al.find(".content-div").prepend(this)}else{al.find(".content-div").append(this)}if(ao.container){ao.container.remove_drawable(ao)}n[al.attr("id")].add_drawable(ao);return}}for(an=0;an<am.length;an++){al=$(am.get(an));if(ar.offsetY<al.position().top&&!(al.hasClass("reference-track")||al.hasClass("intro"))){break}}if(an===am.length){if(this!==am.get(an-1)){av.append(this);n[av.attr("id")].move_drawable(ao,an)}}else{if(this!==am.get(an)){$(this).insertBefore(am.get(an));n[av.attr("id")].move_drawable(ao,(ar.deltaY>0?an-1:an))}}}).bind("dragstart",function(){af["border-top"]=ae.css("border-top");af["border-bottom"]=ae.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(af)})};exports.moveable=m;var ab=16,G=9,D=20,A=100,I=12000,T=400,K=5000,w=100,o="There was an error in indexing this dataset. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",v="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",y="Tool cannot be rerun: ",a="Loading data...",V="Ready for display",R=10,H=20;function X(af,ae){if(!ae){ae=0}var ag=Math.pow(10,ae);return Math.round(af*ag)/ag}var r=function(af,ae,ah){if(!r.id_counter){r.id_counter=0}this.id=r.id_counter++;this.name=ah.name;this.view=af;this.container=ae;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:ah.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=ah.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(ai){ai.stopPropagation()});var ag=this;this.container_div.hover(function(){ag.icons_div.show()},function(){ag.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};r.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ae){if(ae.content_visible){ae.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ae.hide_contents();ae.content_visible=false}else{ae.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ae.content_visible=true;ae.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(af){var ah=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ae=function(){af.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},ag=function(ai){if((ai.keyCode||ai.which)===27){ah()}else{if((ai.keyCode||ai.which)===13){ae()}}};$(window).bind("keypress.check_enter_esc",ag);show_modal("Configure",af.config.build_form(),{Cancel:ah,OK:ae})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ae){$(".bs-tooltip").remove();ae.remove()}}];q(r.prototype,{init:function(){},changed:function(){this.view.changed()},can_draw:function(){if(this.enabled&&this.content_visible){return true}return false},request_draw:function(){},_draw:function(){},to_dict:function(){},set_name:function(ae){this.old_name=this.name;this.name=ae;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 ae=this.view;this.container_div.hide(0,function(){$(this).remove();ae.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(af,ak,aj,ai,ae,ah){var ag=this;this.action_icons[af]=$("<a/>").attr("href","javascript:void(0);").attr("title",ak).addClass("icon-button").addClass(aj).tooltip().click(function(){ai(ag)}).appendTo(this.icons_div);if(ah){this.action_icons[af].hide()}},build_action_icons:function(ae){var ag;for(var af=0;af<ae.length;af++){ag=ae[af];this.add_action_icon(ag.name,ag.title,ag.css_class,ag.on_click_fn,ag.prepend,ag.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var z=function(af,ae,ag){r.call(this,af,ae,ag);this.obj_type=ag.obj_type;this.drawables=[]};q(z.prototype,r.prototype,{unpack_drawables:function(ag){this.drawables=[];var af;for(var ae=0;ae<ag.length;ae++){af=p(ag[ae],this.view,this);this.add_drawable(af)}},init:function(){for(var ae=0;ae<this.drawables.length;ae++){this.drawables[ae].init()}},_draw:function(){for(var ae=0;ae<this.drawables.length;ae++){this.drawables[ae]._draw()}},to_dict:function(){var af=[];for(var ae=0;ae<this.drawables.length;ae++){af.push(this.drawables[ae].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:af}},add_drawable:function(ae){this.drawables.push(ae);ae.container=this;this.changed()},add_drawable_before:function(ag,ae){this.changed();var af=this.drawables.indexOf(ae);if(af!==-1){this.drawables.splice(af,0,ag);return true}return false},replace_drawable:function(ag,ae,af){var ah=this.drawables.indexOf(ag);if(ah!==-1){this.drawables[ah]=ae;if(af){ag.container_div.replaceWith(ae.container_div)}this.changed()}return ah},remove_drawable:function(af){var ae=this.drawables.indexOf(af);if(ae!==-1){this.drawables.splice(ae,1);af.container=null;this.changed();return true}return false},move_drawable:function(af,ag){var ae=this.drawables.indexOf(af);if(ae!==-1){this.drawables.splice(ae,1);this.drawables.splice(ag,0,af);this.changed();return true}return false},get_drawables:function(){return this.drawables}});var P=function(af,ae,ah){q(ah,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});z.call(this,af,ae,ah);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);m(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new i.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in ah){this.unpack_drawables(ah.drawables)}if("filters" in ah){var ag=this.filters_manager;this.filters_manager=new i.FiltersManager(this,ah.filters);ag.parent_div.replaceWith(this.filters_manager.parent_div);if(ah.filters.visible){this.setup_multitrack_filtering()}}};q(P.prototype,r.prototype,z.prototype,{action_icons_def:[r.prototype.action_icons_def[0],r.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ae){$(".bs-tooltip").remove();ae.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ae){if(ae.filters_manager.visible()){ae.filters_manager.clear_filters();ae._restore_filter_managers()}else{ae.setup_multitrack_filtering();ae.request_draw(true)}ae.filters_manager.toggle()}},r.prototype.action_icons_def[2]],build_container_div:function(){var ae=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ae)}return ae},build_header_div:function(){var ae=$("<div/>").addClass("track-header");ae.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(ae);return ae},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ag=this.drawables.length;if(ag===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ag===1){if(this.drawables[0] instanceof f){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var an,am,ak,aq=true,ai=this.drawables[0].get_type(),ae=0;for(an=0;an<ag;an++){ak=this.drawables[an];if(ak.get_type()!==ai){can_composite=false;break}if(ak instanceof c){ae++}}if(aq||ae===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(ae>1&&ae===this.drawables.length){var ar={},af;ak=this.drawables[0];for(am=0;am<ak.filters_manager.filters.length;am++){af=ak.filters_manager.filters[am];ar[af.name]=[af]}for(an=1;an<this.drawables.length;an++){ak=this.drawables[an];for(am=0;am<ak.filters_manager.filters.length;am++){af=ak.filters_manager.filters[am];if(af.name in ar){ar[af.name].push(af)}}}this.filters_manager.remove_all();var ah,aj,al,ao;for(var ap in ar){ah=ar[ap];if(ah.length===ae){aj=new i.NumberFilter({name:ah[0].name,index:ah[0].index});this.filters_manager.add_filter(aj)}}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 ae=0;ae<this.drawables.length;ae++){this.drawables[ae].filters_manager=this.saved_filters_managers[ae]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ae=0;ae<this.drawables.length;ae++){drawable=this.drawables[ae];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ai=[];for(var af=0;af<this.drawables.length;af++){ai.push(this.drawables[af].name)}var ag="Composite Track of "+this.drawables.length+" tracks ("+ai.join(", ")+")";var ah=new f(this.view,this.view,{name:ag,drawables:this.drawables});var ae=this.container.replace_drawable(this,ah,true);ah.request_draw()},add_drawable:function(ae){z.prototype.add_drawable.call(this,ae);this.update_icons()},remove_drawable:function(ae){z.prototype.remove_drawable.call(this,ae);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ae=q(z.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ae},request_draw:function(ae,ag){for(var af=0;af<this.drawables.length;af++){this.drawables[af].request_draw(ae,ag)}}});var Z=function(ae){q(ae,{obj_type:"View"});z.call(this,"View",ae.container,ae);this.chrom=null;this.vis_id=ae.vis_id;this.dbkey=ae.dbkey;this.label_tracks=[];this.tracks_to_be_redrawn=[];this.max_low=0;this.max_high=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.load_chroms_deferred=null;this.init();this.canvas_manager=new x.CanvasManager(this.container.get(0).ownerDocument);this.reset()};ac.extend(Z.prototype,Backbone.Events);q(Z.prototype,z.prototype,{init:function(){this.requested_redraw=false;var ag=this.container,ae=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ag);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ag);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ag);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").attr("id","viewport-container").appendTo(this.browser_content_div);this.content_div=this.viewport_container;k(this.viewport_container,ae);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var ah=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){ad(add_datasets_url,add_track_async_url,function(ai){ac.each(ai,function(aj){ae.add_drawable(p(aj,ae,ae))})})});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 af=function(ai){if(ai.type==="focusout"||(ai.keyCode||ai.which)===13||(ai.keyCode||ai.which)===27){if((ai.keyCode||ai.which)!==27){ae.go_to($(this).val())}$(this).hide();$(this).val("");ae.location_span.show();ae.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",af).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(){ae.location_span.hide();ae.chrom_select.hide();ae.nav_input.val(ae.chrom+":"+ae.low+"-"+ae.high);ae.nav_input.css("display","inline-block");ae.nav_input.select();ae.nav_input.focus();ae.nav_input.autocomplete({source:function(ak,ai){var al=[],aj=$.map(ae.get_drawables(),function(am){return am.data_manager.search_features(ak.term).success(function(an){al=al.concat(an)})});$.when.apply($,aj).done(function(){ai($.map(al,function(am){return{label:am[0],value:am[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(){ae.zoom_out();ae.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ae.zoom_in();ae.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ae.change_chrom(ae.chrom_select.val())});this.browser_content_div.click(function(ai){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ai){ae.zoom_in(ai.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ai,aj){this.current_x=aj.offsetX}).bind("drag",function(ai,ak){var al=ak.offsetX-this.current_x;this.current_x=ak.offsetX;var aj=Math.round(al/ae.viewport_container.width()*(ae.max_high-ae.max_low));ae.move_delta(-aj)});this.overview_close.click(function(){ae.reset_overview()});this.viewport_container.bind("draginit",function(ai,aj){if(ai.clientX>ae.viewport_container.width()-16){return false}}).bind("dragstart",function(ai,aj){aj.original_low=ae.low;aj.current_height=ai.clientY;aj.current_x=aj.offsetX}).bind("drag",function(ak,am){var ai=$(this);var an=am.offsetX-am.current_x;var aj=ai.scrollTop()-(ak.clientY-am.current_height);ai.scrollTop(aj);am.current_height=ak.clientY;am.current_x=am.offsetX;var al=Math.round(an/ae.viewport_container.width()*(ae.high-ae.low));ae.move_delta(al)}).bind("mousewheel",function(ak,am,aj,ai){if(aj){aj*=50;var al=Math.round(-aj/ae.viewport_container.width()*(ae.high-ae.low));ae.move_delta(al)}});this.top_labeltrack.bind("dragstart",function(ai,aj){return $("<div />").css({height:ae.browser_content_div.height()+ae.top_labeltrack.height()+ae.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(am,an){$(an.proxy).css({left:Math.min(am.pageX,an.startX)-ae.container.offset().left,width:Math.abs(am.pageX-an.startX)});var aj=Math.min(am.pageX,an.startX)-ae.container.offset().left,ai=Math.max(am.pageX,an.startX)-ae.container.offset().left,al=(ae.high-ae.low),ak=ae.viewport_container.width();ae.update_location(Math.round(aj/ak*al)+ae.low,Math.round(ai/ak*al)+ae.low)}).bind("dragend",function(an,ao){var aj=Math.min(an.pageX,ao.startX),ai=Math.max(an.pageX,ao.startX),al=(ae.high-ae.low),ak=ae.viewport_container.width(),am=ae.low;ae.low=Math.round(aj/ak*al)+am;ae.high=Math.round(ai/ak*al)+am;$(ao.proxy).remove();ae.request_redraw()});this.add_label_track(new Y(this,{content_div:this.top_labeltrack}));this.add_label_track(new Y(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ae.resize_window()},500)});$(document).bind("redraw",function(){ae.redraw()});this.reset();$(window).trigger("resize")},changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(af,ah,ae,ai){if(this.timer){clearTimeout(this.timer)}if(ai){var ag=this;this.timer=setTimeout(function(){ag.trigger("navigate",af+":"+ah+"-"+ae)},500)}else{view.trigger("navigate",af+":"+ah+"-"+ae)}},update_location:function(ae,ag){this.location_span.text(commatize(ae)+" - "+commatize(ag));this.nav_input.val(this.chrom+":"+commatize(ae)+"-"+commatize(ag));var af=view.chrom_select.val();if(af!==""){this.trigger_navigate(af,view.low,view.high,true)}},load_chroms:function(ag){ag.num=w;var ae=this,af=$.Deferred();$.ajax({url:chrom_url+"/"+this.dbkey,data:ag,dataType:"json",success:function(ai){if(ai.chrom_info.length===0){return}if(ai.reference){ae.add_label_track(new B(ae))}ae.chrom_data=ai.chrom_info;var al='<option value="">Select Chrom/Contig</option>';for(var ak=0,ah=ae.chrom_data.length;ak<ah;ak++){var aj=ae.chrom_data[ak].chrom;al+='<option value="'+aj+'">'+aj+"</option>"}if(ai.prev_chroms){al+='<option value="previous">Previous '+w+"</option>"}if(ai.next_chroms){al+='<option value="next">Next '+w+"</option>"}ae.chrom_select.html(al);ae.chrom_start_index=ai.start_index;af.resolve(ai)},error:function(){alert("Could not load chroms for this dbkey:",ae.dbkey)}});return af},change_chrom:function(aj,af,al){var ag=this;if(!ag.chrom_data){ag.load_chroms_deferred.then(function(){ag.change_chrom(aj,af,al)});return}if(!aj||aj==="None"){return}if(aj==="previous"){ag.load_chroms({low:this.chrom_start_index-w});return}if(aj==="next"){ag.load_chroms({low:this.chrom_start_index+w});return}var ak=$.grep(ag.chrom_data,function(am,an){return am.chrom===aj})[0];if(ak===undefined){ag.load_chroms({chrom:aj},function(){ag.change_chrom(aj,af,al)});return}else{if(aj!==ag.chrom){ag.chrom=aj;ag.chrom_select.val(ag.chrom);ag.max_high=ak.len-1;ag.reset();ag.request_redraw(true);for(var ai=0,ae=ag.drawables.length;ai<ae;ai++){var ah=ag.drawables[ai];if(ah.init){ah.init()}}if(ag.reference_track){ag.reference_track.init()}}if(af!==undefined&&al!==undefined){ag.low=Math.max(af,0);ag.high=Math.min(al,ag.max_high)}else{ag.low=0;ag.high=ag.max_high}ag.reset_overview();ag.request_redraw()}},go_to:function(ai){ai=ai.replace(/ |,/g,"");var am=this,ae,ah,af=ai.split(":"),ak=af[0],al=af[1];if(al!==undefined){try{var aj=al.split("-");ae=parseInt(aj[0],10);ah=parseInt(aj[1],10)}catch(ag){return false}}am.change_chrom(ak,ae,ah)},move_fraction:function(ag){var ae=this;var af=ae.high-ae.low;this.move_delta(ag*af)},move_delta:function(ah){var ae=this;var ag=ae.high-ae.low;if(ae.low-ah<ae.max_low){ae.low=ae.max_low;ae.high=ae.max_low+ag}else{if(ae.high-ah>ae.max_high){ae.high=ae.max_high;ae.low=ae.max_high-ag}else{ae.high-=ah;ae.low-=ah}}ae.request_redraw();var af=ae.chrom_select.val();this.trigger_navigate(af,ae.low,ae.high,true)},add_drawable:function(ae){z.prototype.add_drawable.call(this,ae);ae.init();this.changed();this.update_intro_div()},add_label_track:function(ae){ae.view=this;ae.init();this.label_tracks.push(ae)},remove_drawable:function(ag,af){z.prototype.remove_drawable.call(this,ag);if(af){var ae=this;ag.container_div.hide(0,function(){$(this).remove();ae.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(am,ae,al,an){var ak=this,aj=(an?[an]:ak.drawables),ag;var af;for(var ai=0;ai<aj.length;ai++){af=aj[ai];ag=-1;for(var ah=0;ah<ak.tracks_to_be_redrawn.length;ah++){if(ak.tracks_to_be_redrawn[ah][0]===af){ag=ah;break}}if(ag<0){ak.tracks_to_be_redrawn.push([af,ae,al])}else{ak.tracks_to_be_redrawn[ai][1]=ae;ak.tracks_to_be_redrawn[ai][2]=al}}if(!this.requested_redraw){requestAnimationFrame(function(){ak._redraw(am)});this.requested_redraw=true}},_redraw:function(ao){this.requested_redraw=false;var al=this.low,ah=this.high;if(al<this.max_low){al=this.max_low}if(ah>this.max_high){ah=this.max_high}var an=this.high-this.low;if(this.high!==0&&an<this.min_separation){ah=al+this.min_separation}this.low=Math.floor(al);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=this.viewport_container.width()/(this.high-this.low);var ae=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ak=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ap=13;this.overview_box.css({left:ae,width:Math.max(ap,ak)}).show();if(ak<ap){this.overview_box.css("left",ae-(ap-ak)/2)}if(this.overview_highlight){this.overview_highlight.css({left:ae,width:ak})}if(!ao){var ag,af,am;for(var ai=0,aj=this.tracks_to_be_redrawn.length;ai<aj;ai++){ag=this.tracks_to_be_redrawn[ai][0];af=this.tracks_to_be_redrawn[ai][1];am=this.tracks_to_be_redrawn[ai][2];if(ag){ag._draw(af,am)}}this.tracks_to_be_redrawn=[];for(ai=0,aj=this.label_tracks.length;ai<aj;ai++){this.label_tracks[ai]._draw()}}},zoom_in:function(af,ag){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var ah=this.high-this.low,ai=ah/2+this.low,ae=(ah/this.zoom_factor)/2;if(af){ai=af/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ai-ae);this.high=Math.round(ai+ae);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var af=this.high-this.low,ag=af/2+this.low,ae=(af*this.zoom_factor)/2;this.low=Math.round(ag-ae);this.high=Math.round(ag+ae);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(ag){if(this.overview_drawable){if(this.overview_drawable.dataset_id===ag.dataset_id){return}this.overview_viewport.find(".track").remove()}var af=ag.copy({content_div:this.overview_viewport}),ae=this;af.header_div.hide();af.is_overview=true;ae.overview_drawable=af;this.overview_drawable.postdraw_actions=function(){ae.overview_highlight.show().height(ae.overview_drawable.content_div.height());ae.overview_viewport.height(ae.overview_drawable.content_div.height()+ae.overview_box.outerHeight());ae.overview_close.show();ae.resize_window()};ae.overview_drawable.request_draw();this.changed()},reset_overview:function(){$(".bs-tooltip").remove();this.overview_viewport.find(".track-tile").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide();view.resize_window();view.overview_drawable=null}});var s=function(ag,al,ah){this.track=ag;this.name=al.name;this.params=[];var at=al.params;for(var ai=0;ai<at.length;ai++){var an=at[ai],af=an.name,ar=an.label,aj=unescape(an.html),au=an.value,ap=an.type;if(ap==="number"){this.params.push(new e(af,ar,aj,(af in ah?ah[af]:au),an.min,an.max))}else{if(ap==="select"){this.params.push(new N(af,ar,aj,(af in ah?ah[af]:au)))}else{console.log("WARNING: unrecognized tool parameter type:",af,ap)}}}this.parent_div=$("<div/>").addClass("dynamic-tool").hide();this.parent_div.bind("drag",function(aw){aw.stopPropagation()}).click(function(aw){aw.stopPropagation()}).bind("dblclick",function(aw){aw.stopPropagation()});var aq=$("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);var ao=this.params;var am=this;$.each(this.params,function(ax,aA){var az=$("<div>").addClass("param-row").appendTo(am.parent_div);var aw=$("<div>").addClass("param-label").text(aA.label).appendTo(az);var ay=$("<div/>").addClass("param-input").html(aA.html).appendTo(az);ay.find(":input").val(aA.value);$("<div style='clear: both;'/>").appendTo(az)});this.parent_div.find("input").click(function(){$(this).select()});var av=$("<div>").addClass("param-row").appendTo(this.parent_div);var ak=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(av);var ae=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(av);ae.click(function(){am.run_on_region()});ak.click(function(){am.run_on_dataset()});if("visible" in ah&&ah.visible){this.parent_div.show()}};q(s.prototype,{update_params:function(){for(var ae=0;ae<this.params.length;ae++){this.params[ae].update_value()}},state_dict:function(){var af={};for(var ae=0;ae<this.params.length;ae++){af[this.params[ae].name]=this.params[ae].value}af.visible=this.parent_div.is(":visible");return af},get_param_values_dict:function(){var ae={};this.parent_div.find(":input").each(function(){var af=$(this).attr("name"),ag=$(this).val();ae[af]=ag});return ae},get_param_values:function(){var ae=[];this.parent_div.find(":input").each(function(){var af=$(this).attr("name"),ag=$(this).val();if(af){ae[ae.length]=ag}});return ae},run_on_dataset:function(){var ae=this;ae.run({target_dataset_id:this.track.original_dataset_id,tool_id:ae.name},null,function(af){show_modal(ae.name+" is Running",ae.name+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var af={target_dataset_id:this.track.original_dataset_id,action:"rerun",tool_id:this.name,regions:[{chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}]},aj=this.track,ag=af.tool_id+aj.tool_region_and_parameters_str(af.chrom,af.low,af.high),ae;if(aj.container===view){var ai=new P(view,view,{name:this.name});var ah=aj.container.replace_drawable(aj,ai,false);ai.container_div.insertBefore(aj.view.content_div.children()[ah]);ai.add_drawable(aj);aj.container_div.appendTo(ai.content_div);ae=ai}else{ae=aj.container}var ak=new aj.constructor(view,ae,{name:ag,hda_ldda:"hda"});ak.init_for_tool_data();ak.change_mode(aj.mode);ak.set_filters_manager(aj.filters_manager.copy(ak));ak.update_icons();ae.add_drawable(ak);ak.tiles_div.text("Starting job.");this.update_params();this.run(af,ak,function(al){ak.set_dataset(new aa.Dataset(al));ak.tiles_div.text("Running job.");ak.init()})},run:function(ae,ag,ah){ae.inputs=this.get_param_values_dict();var af=new l.ServerStateDeferred({ajax_settings:{url:galaxy_paths.get("tool_url"),data:JSON.stringify(ae),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ai){return ai!=="pending"}});$.when(af.go()).then(function(ai){if(ai==="no converter"){ag.container_div.addClass("error");ag.content_div.text(J)}else{if(ai.error){ag.container_div.addClass("error");ag.content_div.text(y+ai.message)}else{ah(ai)}}})}});var N=function(af,ae,ag,ah){this.name=af;this.label=ae;this.html=$(ag);this.value=ah};q(N.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ag,af,ai,aj,ah,ae){N.call(this,ag,af,ai,aj);this.min=ah;this.max=ae};q(e.prototype,N.prototype,{update_value:function(){N.prototype.update_value.call(this);this.value=parseFloat(this.value)}});var C=function(ae,af){L.Scaler.call(this,af);this.filter=ae};C.prototype.gen_val=function(ae){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(ae[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var F=function(ae){this.track=ae.track;this.params=ae.params;this.values={};this.restore_values((ae.saved_values?ae.saved_values:{}));this.onchange=ae.onchange};q(F.prototype,{restore_values:function(ae){var af=this;$.each(this.params,function(ag,ah){if(ae[ah.key]!==undefined){af.values[ah.key]=ae[ah.key]}else{af.values[ah.key]=ah.default_value}})},build_form:function(){var ah=this;var ae=$("<div />");var ag;function af(am,ai){for(var aq=0;aq<am.length;aq++){ag=am[aq];if(ag.hidden){continue}var ak="param_"+aq;var av=ah.values[ag.key];var ax=$("<div class='form-row' />").appendTo(ai);ax.append($("<label />").attr("for",ak).text(ag.label+":"));if(ag.type==="bool"){ax.append($('<input type="checkbox" />').attr("id",ak).attr("name",ak).attr("checked",av))}else{if(ag.type==="text"){ax.append($('<input type="text"/>').attr("id",ak).val(av).click(function(){$(this).select()}))}else{if(ag.type==="select"){var at=$("<select />").attr("id",ak);for(var ao=0;ao<ag.options.length;ao++){$("<option/>").text(ag.options[ao].label).attr("value",ag.options[ao].value).appendTo(at)}at.val(av);ax.append(at)}else{if(ag.type==="color"){var aw=$("<div/>").appendTo(ax),ar=$("<input />").attr("id",ak).attr("name",ak).val(av).css("float","left").appendTo(aw).click(function(az){$(".bs-tooltip").removeClass("in");var ay=$(this).siblings(".bs-tooltip").addClass("in");ay.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(ay).height()/2)+($(this).height()/2)}).show();ay.click(function(aA){aA.stopPropagation()});$(document).bind("click.color-picker",function(){ay.hide();$(document).unbind("click.color-picker")});az.stopPropagation()}),ap=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(aw).attr("title","Set new random color").tooltip(),au=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(aw).hide(),al=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(au),aj=$("<div class='tooltip-arrow'></div>").appendTo(au),an=$.farbtastic(al,{width:100,height:100,callback:ar,color:av});aw.append($("<div/>").css("clear","both"));(function(ay){ap.click(function(){ay.setColor(Q())})})(an)}else{ax.append($("<input />").attr("id",ak).attr("name",ak).val(av))}}}}if(ag.help){ax.append($("<div class='help'/>").text(ag.help))}}}af(this.params,ae);return ae},update_from_form:function(ae){var ag=this;var af=false;$.each(this.params,function(ah,aj){if(!aj.hidden){var ak="param_"+ah;var ai=ae.find("#"+ak).val();if(aj.type==="float"){ai=parseFloat(ai)}else{if(aj.type==="int"){ai=parseInt(ai)}else{if(aj.type==="bool"){ai=ae.find("#"+ak).is(":checked")}}}if(ai!==ag.values[aj.key]){ag.values[aj.key]=ai;af=true}}});if(af){this.onchange();this.track.changed()}}});var b=function(ae,ai,ag,af,ah){this.track=ae;this.region=ai;this.low=ai.get("start");this.high=ai.get("end");this.resolution=ag;this.html_elt=$("<div class='track-tile'/>").append(af).height($(af).attr("height"));this.data=ah;this.stale=false};b.prototype.predisplay_actions=function(){};var j=function(ae,aj,ag,af,ah,ai){b.call(this,ae,aj,ag,af,ah);this.max_val=ai};q(j.prototype,b.prototype);var O=function(ah,ap,ai,ag,ak,ar,al,at,af,ao){b.call(this,ah,ap,ai,ag,ak);this.mode=al;this.all_slotted=af;this.feature_mapper=ao;this.has_icons=false;if(at){this.has_icons=true;var am=this;ag=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:D-1,width:ag.width}).prependTo(this.html_elt);var an=new x.GenomeRegion({chrom:ah.view.chrom,start:this.low,end:this.high}),aq=ak.length,aj=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+aq+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ae=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+aq+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);aj.click(function(){am.stale=true;ah.data_manager.get_more_data(an,ah.mode,am.resolution,{},ah.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();ah.request_draw(true)}).dblclick(function(au){au.stopPropagation()});ae.click(function(){am.stale=true;ah.data_manager.get_more_data(an,ah.mode,am.resolution,{},ah.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();ah.request_draw(true)}).dblclick(function(au){au.stopPropagation()})}};q(O.prototype,b.prototype);O.prototype.predisplay_actions=function(){var af=this,ae={};if(af.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(aq){if(!this.hovered){return}var al=$(this).offset(),ap=aq.pageX-al.left,ao=aq.pageY-al.top,av=af.feature_mapper.get_feature_data(ap,ao),am=(av?av[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!am||$(this).attr("id")!==am.toString()){$(this).remove()}});if(av){var ah=ae[am];if(!ah){var am=av[0],ar={name:av[3],start:av[1],end:av[2],strand:av[4]},ak=af.track.filters_manager.filters,aj;for(var an=0;an<ak.length;an++){aj=ak[an];ar[aj.name]=av[aj.index]}var ah=$("<div/>").attr("id",am).addClass("feature-popup"),aw=$("<table/>"),au,at,ax;for(au in ar){at=ar[au];ax=$("<tr/>").appendTo(aw);$("<th/>").appendTo(ax).text(au);$("<td/>").attr("align","left").appendTo(ax).text(typeof(at)==="number"?X(at,2):at)}ah.append($("<div class='feature-popup-inner'>").append(aw));ae[am]=ah}ah.appendTo($(this).parents(".track-content").children(".overlay"));var ai=ap+parseInt(af.html_elt.css("left"))-ah.width()/2,ag=ao+parseInt(af.html_elt.css("top"))+7;ah.css("left",ai+"px").css("top",ag+"px")}else{if(!aq.isPropagationStopped()){aq.stopPropagation();$(this).siblings().each(function(){$(this).trigger(aq)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var g=function(af,ae,ag){q(ag,{drag_handle_class:"draghandle"});r.call(this,af,ae,ag);this.dataset=new aa.Dataset({id:ag.dataset_id,hda_ldda:ag.hda_ldda});this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ag?ag.data_query_wait:K);this.data_manager=("data_manager" in ag?ag.data_manager:new x.GenomeDataManager({dataset:this.dataset,data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=0;this.content_div=$("<div class='track-content'>").appendTo(this.container_div);if(this.container){this.container.content_div.append(this.container_div);if(!("resize" in ag)||ag.resize){this.add_resize_handle()}}};q(g.prototype,r.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},r.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(ae){ae.view.set_overview(ae)}},r.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ae){if(ae.filters_manager.visible()){ae.filters_manager.clear_filters()}else{ae.filters_manager.init_filters()}ae.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ae){ae.dynamic_tool_div.toggle();if(ae.dynamic_tool_div.is(":visible")){ae.set_name(ae.name+ae.tool_region_and_parameters_str())}else{ae.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ae){var ah='<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>',ag=ac.template(ah,{track:ae});var aj=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},af=function(){var al=$('select[name="regions"] option:selected').val(),an,ak=new x.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),am=ac.map($(".bookmark"),function(ao){return new x.GenomeRegion({from_str:$(ao).children(".position").text()})});if(al==="cur"){an=[ak]}else{if(al==="bookmarks"){an=am}else{an=[ak].concat(am)}}hide_modal();window.location.href=galaxy_paths.get("sweepster_url")+"?"+$.param({dataset_id:ae.dataset_id,hda_ldda:ae.hda_ldda,regions:JSON.stringify(new Backbone.Collection(an).toJSON())})},ai=function(ak){if((ak.keyCode||ak.which)===27){aj()}else{if((ak.keyCode||ak.which)===13){af()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",ag,{No:aj,Yes:af})}},r.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset_id&&r.prototype.can_draw.call(this)){return true}return false},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id).css("position","relative")},build_header_div:function(){var ae=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ae)}this.name_div=$("<div/>").addClass("track-name").appendTo(ae).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ae},on_resize:function(){},add_resize_handle:function(){var ae=this;var ah=false;var ag=false;var af=$("<div class='track-resize'>");$(ae.container_div).hover(function(){if(ae.content_visible){ah=true;af.show()}},function(){ah=false;if(!ag){af.hide()}});af.hide().bind("dragstart",function(ai,aj){ag=true;aj.original_height=$(ae.content_div).height()}).bind("drag",function(aj,ak){var ai=Math.min(Math.max(ak.original_height+ak.deltaY,ae.min_height_px),ae.max_height_px);$(ae.tiles_div).css("height",ai);ae.visible_height_px=(ae.max_height_px===ai?0:ai);ae.on_resize()}).bind("dragend",function(ai,aj){ae.tile_cache.clear();ag=false;if(!ah){af.hide()}ae.config.values.height=ae.visible_height_px;ae.changed()}).appendTo(ae.container_div)},set_display_modes:function(ah,ak){this.display_modes=ah;this.mode=(ak?ak:(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 af=this,ai={};for(var ag=0,ae=af.display_modes.length;ag<ae;ag++){var aj=af.display_modes[ag];ai[aj]=function(al){return function(){af.change_mode(al);af.icons_div.show();af.container_div.mouseleave(function(){af.icons_div.hide()})}}(aj)}make_popupmenu(this.action_icons.mode_icon,ai)},build_action_icons:function(){r.prototype.build_action_icons.call(this,this.action_icons_def);if(this.display_modes!==undefined){this.set_display_modes(this.display_modes)}},hide_contents:function(){this.tiles_div.hide();this.container_div.find(".yaxislabel, .track-resize").hide()},show_contents:function(){this.tiles_div.show();this.container_div.find(".yaxislabel, .track-resize").show();this.request_draw()},get_type:function(){if(this instanceof Y){return"LabelTrack"}else{if(this instanceof B){return"ReferenceTrack"}else{if(this instanceof h){return"LineTrack"}else{if(this instanceof U){return"ReadTrack"}else{if(this instanceof S){return"VcfTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(){var af=this;af.enabled=false;af.tile_cache.clear();af.data_manager.clear();af.content_div.css("height","auto");af.tiles_div.children().remove();af.container_div.removeClass("nodata error pending");if(!af.dataset_id){return}var ae=$.Deferred(),ag={hda_ldda:af.hda_ldda,data_type:this.dataset_check_type,chrom:af.view.chrom};$.getJSON(this.dataset.url(),ag,function(ah){if(!ah||ah==="error"||ah.kind==="error"){af.container_div.addClass("error");af.tiles_div.text(o);if(ah.message){var ai=$(" <a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ah.message+"</pre>",{Close:hide_modal})});af.tiles_div.append(ai)}}else{if(ah==="no converter"){af.container_div.addClass("error");af.tiles_div.text(J)}else{if(ah==="no data"||(ah.data!==undefined&&(ah.data===null||ah.data.length===0))){af.container_div.addClass("nodata");af.tiles_div.text(E)}else{if(ah==="pending"){af.container_div.addClass("pending");af.tiles_div.html(v);setTimeout(function(){af.init()},af.data_query_wait)}else{if(ah==="data"||ah.status==="data"){if(ah.valid_chroms){af.valid_chroms=ah.valid_chroms;af.update_icons()}af.tiles_div.text(V);if(af.view.chrom){af.tiles_div.text("");af.tiles_div.css("height",af.visible_height_px+"px");af.enabled=true;$.when(af.predraw_init()).done(function(){ae.resolve();af.container_div.removeClass("nodata error pending");af.request_draw()})}else{ae.resolve()}}}}}}});this.update_icons();return ae},predraw_init:function(){},get_drawables:function(){return this}});var M=function(ag,af,ah){g.call(this,ag,af,ah);var ae=this;m(ae.container_div,ae.drag_handle_class,".group",ae);this.filters_manager=new i.FiltersManager(this,("filters" in ah?ah.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=("tool" in ah&&ah.tool?new s(this,ah.tool,ah.tool_state):null);this.tile_cache=new x.Cache(R);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(ah.mode){this.change_mode(ah.mode)}};q(M.prototype,r.prototype,g.prototype,{action_icons_def:g.prototype.action_icons_def.concat([{name:"show_more_rows_icon",title:"To minimize track height, not all feature rows are displayed. Click to display more rows.",css_class:"exclamation",on_click_fn:function(ae){$(".bs-tooltip").remove();ae.slotters[ae.view.resolution_px_b].max_rows*=2;ae.request_draw(true)},hide:true}]),copy:function(ae){var af=this.to_dict();q(af,{data_manager:this.data_manager});var ag=new this.constructor(this.view,ae,af);ag.change_mode(this.mode);ag.enabled=this.enabled;return ag},set_filters_manager:function(ae){this.filters_manager=ae;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,hda_ldda:this.hda_ldda,dataset_id:this.dataset_id,prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},change_mode:function(af){var ae=this;ae.mode=af;ae.config.values.mode=af;ae.tile_cache.clear();ae.request_draw();this.action_icons.mode_icon.attr("title","Set display mode (now: "+ae.mode+")");return ae},update_icons:function(){var ae=this;if(ae.filters_available){ae.action_icons.filters_icon.show()}else{ae.action_icons.filters_icon.hide()}if(ae.tool){ae.action_icons.tools_icon.show();ae.action_icons.param_space_viz_icon.show()}else{ae.action_icons.tools_icon.hide();ae.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(af,ag,ae){return af+"_"+ag+"_"+ae},request_draw:function(af,ae){this.view.request_redraw(false,af,ae,this)},before_draw:function(){},_draw:function(af,ap){if(!this.can_draw()){return}var an=this.view.low,aj=this.view.high,al=aj-an,ag=this.view.container.width(),ar=this.view.resolution_px_b,ai=this.view.resolution_b_px;if(this.is_overview){an=this.view.max_low;aj=this.view.max_high;ai=(view.max_high-view.max_low)/ag;ar=1/ai}this.before_draw();this.tiles_div.children().addClass("remove");var ae=Math.floor(an/(ai*T)),am=true,aq=[],ak=function(at){return(at&&"track" in at)};while((ae*T*ai)<aj){var ao=this.draw_helper(af,ag,ae,ai,this.tiles_div,ar);if(ak(ao)){aq.push(ao)}else{am=false}ae+=1}if(!ap){this.tiles_div.children(".remove").removeClass("remove").remove()}var ah=this;if(am){this.tiles_div.children(".remove").remove();ah.postdraw_actions(aq,ag,ar,ap)}},postdraw_actions:function(ag,ah,aj,ae){var ai=false;for(var af=0;af<ag.length;af++){if(ag[af].has_icons){ai=true;break}}if(ai){for(var af=0;af<ag.length;af++){tile=ag[af];if(!tile.has_icons){tile.html_elt.css("padding-top",D)}}}},draw_helper:function(ae,aq,aw,au,aj,ak,ar){var ap=this,az=this._gen_tile_cache_key(aq,ak,aw),ah=this._get_tile_bounds(aw,au);if(!ar){ar={}}var ay=(ae?undefined:ap.tile_cache.get_elt(az));if(ay){ap.show_tile(ay,aj,ak);return ay}var an=true;var av=ap.data_manager.get_data(ah,ap.mode,au,ap.data_url_extra_params);if(W(av)){an=false}var al;if(view.reference_track&&ak>view.canvas_manager.char_width_px){al=view.reference_track.data_manager.get_data(ah,ap.mode,au,view.reference_track.data_url_extra_params);if(W(al)){an=false}}if(an){q(av,ar.more_tile_data);var am=ap.mode;if(am==="Auto"){am=ap.get_mode(av);ap.update_auto_mode(am)}var ag=ap.view.canvas_manager.new_canvas(),ax=ah.get("start"),af=ah.get("end"),aq=Math.ceil((af-ax)*ak)+ap.left_offset,ao=ap.get_canvas_height(av,am,ak,aq);ag.width=aq;ag.height=ao;var at=ag.getContext("2d");at.translate(this.left_offset,0);var ay=ap.draw_tile(av,at,am,au,ah,ak,al);if(ay!==undefined){ap.tile_cache.set_elt(az,ay);ap.show_tile(ay,aj,ak)}return ay}var ai=$.Deferred();$.when(av,al).then(function(){view.request_redraw(false,false,false,ap);ai.resolve()});return ai},get_canvas_height:function(ae,ag,ah,af){return this.visible_height_px},draw_tile:function(ae,af,aj,ah,ai,ak,ag){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ag,ai,aj){var af=this,ae=ag.html_elt;ag.predisplay_actions();var ah=(ag.low-(this.is_overview?this.view.max_low:this.view.low))*aj;if(this.left_offset){ah-=this.left_offset}ae.css({position:"absolute",top:0,left:ah});if(ae.hasClass("remove")){ae.removeClass("remove")}else{ai.append(ae)}af.after_show_tile(ag)},after_show_tile:function(ae){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(ae,af){var ah=Math.floor(ae*T*af),ai=Math.ceil(T*af),ag=(ah+ai<=this.view.max_high?ah+ai:this.view.max_high);return new x.GenomeRegion({chrom:this.view.chrom,start:ah,end:ag})},tool_region_and_parameters_str:function(ag,ae,ah){var af=this,ai=(ag!==undefined&&ae!==undefined&&ah!==undefined?ag+":"+ae+"-"+ah:"all");return" - region=["+ai+"], parameters=["+af.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(ae,af){return true},can_subset:function(ae){return false},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state";this.normal_postdraw_actions=this.postdraw_actions;this.postdraw_actions=function(ag,ah,aj,ae){var af=this;af.normal_postdraw_actions(ag,ah,aj,ae);af.dataset_check_type="converted_datasets_state";af.data_query_wait=K;var ai=new l.ServerStateDeferred({url:af.dataset_state_url,url_params:{dataset_id:af.dataset_id,hda_ldda:af.hda_ldda},interval:af.data_query_wait,success_fn:function(ak){return ak!=="pending"}});$.when(ai.go()).then(function(){af.data_manager.set("data_type","data")});af.postdraw_actions=af.normal_postdraw_actions}}});var Y=function(af,ae){var ag={resize:false};g.call(this,af,ae,ag);this.container_div.addClass("label-track")};q(Y.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},_draw:function(){var ag=this.view,ah=ag.high-ag.low,ak=Math.floor(Math.pow(10,Math.floor(Math.log(ah)/Math.log(10)))),ae=Math.floor(ag.low/ak)*ak,ai=this.view.container.width(),af=$("<div style='position: relative; height: 1.3em;'></div>");while(ae<ag.high){var aj=(ae-ag.low)/ah*ai;af.append($("<div class='label'>"+commatize(ae)+"</div>").css({position:"absolute",left:aj-1}));ae+=ak}this.content_div.children(":first").remove();this.content_div.append(af)}});var f=function(af,ae,ai){M.call(this,af,ae,ai);this.drawables=[];this.left_offset=0;if("drawables" in ai){var ah;for(var ag=0;ag<ai.drawables.length;ag++){ah=ai.drawables[ag];this.drawables[ag]=p(ah,af,null);if(ah.left_offset>this.left_offset){this.left_offset=ah.left_offset}}this.enabled=true}if(this.drawables.length!==0){this.set_display_modes(this.drawables[0].display_modes,this.drawables[0].mode)}this.update_icons();this.obj_type="CompositeTrack"};q(f.prototype,M.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ae){$(".bs-tooltip").remove();ae.show_group()}}].concat(M.prototype.action_icons_def),to_dict:z.prototype.to_dict,add_drawable:z.prototype.add_drawable,unpack_drawables:z.prototype.unpack_drawables,change_mode:function(ae){M.prototype.change_mode.call(this,ae);for(var af=0;af<this.drawables.length;af++){this.drawables[af].change_mode(ae)}},init:function(){var ag=[];for(var af=0;af<this.drawables.length;af++){ag.push(this.drawables[af].init())}var ae=this;$.when.apply($,ag).then(function(){ae.enabled=true;ae.request_draw()})},update_icons:function(){this.action_icons.filters_icon.hide();this.action_icons.tools_icon.hide();this.action_icons.param_space_viz_icon.hide()},can_draw:r.prototype.can_draw,draw_helper:function(af,av,aB,ay,am,ao,aw){var au=this,aF=this._gen_tile_cache_key(av,ao,aB),aj=this._get_tile_bounds(aB,ay);if(!aw){aw={}}var aE=(af?undefined:au.tile_cache.get_elt(aF));if(aE){au.show_tile(aE,am,ao);return aE}var an=[],au,ar=true,az,ap;for(var aA=0;aA<this.drawables.length;aA++){au=this.drawables[aA];az=au.data_manager.get_data(aj,au.mode,ay,au.data_url_extra_params);if(W(az)){ar=false}an.push(az);ap=null;if(view.reference_track&&ao>view.canvas_manager.char_width_px){ap=view.reference_track.data_manager.get_data(aj,au.mode,ay,view.reference_track.data_url_extra_params);if(W(ap)){ar=false}}an.push(ap)}if(ar){q(az,aw.more_tile_data);this.tile_predraw_init();var ai=au.view.canvas_manager.new_canvas(),ak=au._get_tile_bounds(aB,ay),aC=aj.get("start"),ag=aj.get("end"),aD=0,av=Math.ceil((ag-aC)*ao)+this.left_offset,at=0,ah=[],aA;var ae=0;for(aA=0;aA<this.drawables.length;aA++,aD+=2){au=this.drawables[aA];az=an[aD];var aq=au.mode;if(aq==="Auto"){aq=au.get_mode(az);au.update_auto_mode(aq)}ah.push(aq);ae=au.get_canvas_height(az,aq,ao,av);if(ae>at){at=ae}}ai.width=av;ai.height=(aw.height?aw.height:at);aD=0;var ax=ai.getContext("2d");ax.translate(this.left_offset,0);ax.globalAlpha=0.5;ax.globalCompositeOperation="source-over";for(aA=0;aA<this.drawables.length;aA++,aD+=2){au=this.drawables[aA];az=an[aD];ap=an[aD+1];aE=au.draw_tile(az,ax,ah[aA],ay,aj,ao,ap)}this.tile_cache.set_elt(aF,aE);this.show_tile(aE,am,ao);return aE}var al=$.Deferred(),au=this;$.when.apply($,an).then(function(){view.request_redraw(false,false,false,au);al.resolve()});return al},show_group:function(){var ah=new P(this.view,this.container,{name:this.name}),ae;for(var ag=0;ag<this.drawables.length;ag++){ae=this.drawables[ag];ae.update_icons();ah.add_drawable(ae);ae.container=ah;ah.content_div.append(ae.container_div)}var af=this.container.replace_drawable(this,ah,true);ah.request_draw()},tile_predraw_init:function(){var ah=Number.MAX_VALUE,ae=-ah,af;for(var ag=0;ag<this.drawables.length;ag++){af=this.drawables[ag];if(af instanceof h){if(af.prefs.min_value<ah){ah=af.prefs.min_value}if(af.prefs.max_value>ae){ae=af.prefs.max_value}}}for(var ag=0;ag<this.drawables.length;ag++){af=this.drawables[ag];af.prefs.min_value=ah;af.prefs.max_value=ae}},postdraw_actions:function(ag,aj,al,af){M.prototype.postdraw_actions.call(this,ag,aj,al,af);var ai=-1;for(var ah=0;ah<ag.length;ah++){var ae=ag[ah].html_elt.find("canvas").height();if(ae>ai){ai=ae}}for(var ah=0;ah<ag.length;ah++){var ak=ag[ah];if(ak.html_elt.find("canvas").height()!==ai){this.draw_helper(true,aj,ak.index,ak.resolution,ak.html_elt.parent(),al,{height:ai});ak.html_elt.remove()}}}});var B=function(ae){M.call(this,ae,{content_div:ae.top_labeltrack},{resize:false});ae.reference_track=this;this.left_offset=200;this.visible_height_px=12;this.container_div.addClass("reference-track");this.content_div.css("background","none");this.content_div.css("min-height","0px");this.content_div.css("border","none");this.data_url=reference_url+"/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new x.ReferenceTrackDataManager({data_url:this.data_url});this.hide_contents()};q(B.prototype,r.prototype,M.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},can_draw:r.prototype.can_draw,draw_helper:function(ai,ag,ae,af,aj,ak,ah){if(ak>this.view.canvas_manager.char_width_px){return M.prototype.draw_helper.call(this,ai,ag,ae,af,aj,ak,ah)}else{this.hide_contents();return null}},draw_tile:function(am,an,ai,ah,ak,ao){var ag=this;if(ao>this.view.canvas_manager.char_width_px){if(am.data===null){this.hide_contents();return}var af=an.canvas;an.font=an.canvas.manager.default_font;an.textAlign="center";am=am.data;for(var aj=0,al=am.length;aj<al;aj++){var ae=Math.floor(aj*ao);an.fillText(am[aj],ae,10)}this.show_contents();return new b(ag,ak,ah,af,am)}this.hide_contents()}});var h=function(ag,af,ah){var ae=this;this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";M.call(this,ag,af,ah);this.hda_ldda=ah.hda_ldda;this.dataset_id=ah.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Color",type:"color",default_value:Q()},{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:ah.prefs,onchange:function(){ae.set_name(ae.prefs.name);ae.vertical_range=ae.prefs.max_value-ae.prefs.min_value;ae.set_min_value(ae.prefs.min_value);ae.set_max_value(ae.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};q(h.prototype,r.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ae){this.prefs.min_value=ae;$("#linetrack_"+this.dataset_id+"_minval").text(this.prefs.min_value);this.tile_cache.clear();this.request_draw()},set_max_value:function(ae){this.prefs.max_value=ae;$("#linetrack_"+this.dataset_id+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.request_draw()},predraw_init:function(){var ae=this;ae.vertical_range=undefined;return $.getJSON(ae.dataset.url(),{data_type:"data",stats:true,chrom:ae.view.chrom,low:0,high:ae.view.max_high,hda_ldda:ae.hda_ldda},function(af){ae.container_div.addClass("line-track");var ai=af.data;if(isNaN(parseFloat(ae.prefs.min_value))||isNaN(parseFloat(ae.prefs.max_value))){var ag=ai.min,ak=ai.max;ag=Math.floor(Math.min(0,Math.max(ag,ai.mean-2*ai.sd)));ak=Math.ceil(Math.max(0,Math.min(ak,ai.mean+2*ai.sd)));ae.prefs.min_value=ag;ae.prefs.max_value=ak;$("#track_"+ae.dataset_id+"_minval").val(ae.prefs.min_value);$("#track_"+ae.dataset_id+"_maxval").val(ae.prefs.max_value)}ae.vertical_range=ae.prefs.max_value-ae.prefs.min_value;ae.total_frequency=ai.total_frequency;ae.container_div.find(".yaxislabel").remove();var aj=$("<div/>").text(X(ae.prefs.min_value,3)).make_text_editable({num_cols:6,on_finish:function(al){$(".bs-tooltip").remove();var al=parseFloat(al);if(!isNaN(al)){ae.set_min_value(al)}},help_text:"Set min value"}).addClass("yaxislabel bottom").attr("id","linetrack_"+ae.dataset_id+"_minval").prependTo(ae.container_div),ah=$("<div/>").text(X(ae.prefs.max_value,3)).make_text_editable({num_cols:6,on_finish:function(al){$(".bs-tooltip").remove();var al=parseFloat(al);if(!isNaN(al)){ae.set_max_value(al)}},help_text:"Set max value"}).addClass("yaxislabel top").attr("id","linetrack_"+ae.dataset_id+"_maxval").prependTo(ae.container_div)})},draw_tile:function(an,al,ag,af,ai,am){var ae=al.canvas,ah=ai.get("start"),ak=ai.get("end"),aj=new L.LinePainter(an.data,ah,ak,this.prefs,ag);aj.draw(al,ae.width,ae.height,am);return new b(this,ai,af,ae,an.data)},can_subset:function(ae){return false}});var t=function(ag,af,ah){var ae=this;this.display_modes=["Heatmap"];this.mode="Heatmap";M.call(this,ag,af,ah);this.hda_ldda=ah.hda_ldda;this.dataset_id=ah.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"pos_color",label:"Positive Color",type:"color",default_value:"4169E1"},{key:"negative_color",label:"Negative Color",type:"color",default_value:"FF8C00"},{key:"min_value",label:"Min Value",type:"float",default_value:0},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}],saved_values:ah.prefs,onchange:function(){ae.set_name(ae.prefs.name);ae.vertical_range=ae.prefs.max_value-ae.prefs.min_value;ae.set_min_value(ae.prefs.min_value);ae.set_max_value(ae.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};q(t.prototype,r.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ae){this.prefs.min_value=ae;this.tile_cache.clear();this.request_draw()},set_max_value:function(ae){this.prefs.max_value=ae;this.tile_cache.clear();this.request_draw()},draw_tile:function(ao,am,aj,ah,af,an){var ag=am.canvas,ae=this._get_tile_bounds(af,ah),ai=ae[0],al=ae[1],ak=new L.DiagonalHeatmapPainter(ao.data,ai,al,this.prefs,aj);ak.draw(am,ag.width,ag.height,an);return new b(this,af,ah,ag,ao.data)}});var c=function(ah,ag,aj){var af=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];M.call(this,ah,ag,aj);var ai=Q(),ae=Q([ai,"#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:ai},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ae},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true,help:"Show the number of items in each bin when drawing summary histogram"},{key:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:this.visible_height_px,hidden:true}],saved_values:aj.prefs,onchange:function(){af.set_name(af.prefs.name);af.tile_cache.clear();af.set_painter_from_config();af.request_draw()}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");this.hda_ldda=aj.hda_ldda;this.dataset_id=aj.dataset_id;this.original_dataset_id=aj.dataset_id;this.show_labels_scale=0.001;this.showing_details=false;this.summary_draw_height=30;this.slotters={};this.start_end_dct={};this.left_offset=200;this.set_painter_from_config()};q(c.prototype,r.prototype,M.prototype,{set_dataset:function(ae){this.dataset_id=ae.get("id");this.hda_ldda=ae.get("hda_ldda");this.dataset=ae;this.data_manager.set("dataset",ae)},set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},before_draw:function(){this.max_height_px=0},postdraw_actions:function(au,ao,aj,ai){M.prototype.postdraw_actions.call(this,au,ai);var an=this,aq;if(an.mode==="Coverage"){var af=-1;for(aq=0;aq<au.length;aq++){var ap=au[aq].max_val;if(ap>af){af=ap}}for(aq=0;aq<au.length;aq++){var aw=au[aq];if(aw.max_val!==af){aw.html_elt.remove();an.draw_helper(true,ao,aw.index,aw.resolution,aw.html_elt.parent(),aj,{more_tile_data:{max:af}})}}}if(an.filters_manager){var ak=an.filters_manager.filters;for(var at=0;at<ak.length;at++){ak[at].update_ui_elt()}var av=false,ae,al;for(aq=0;aq<au.length;aq++){if(au[aq].data.length){ae=au[aq].data[0];for(var at=0;at<ak.length;at++){al=ak[at];if(al.applies_to(ae)&&al.min!==al.max){av=true;break}}}}if(an.filters_available!==av){an.filters_available=av;if(!an.filters_available){an.filters_manager.hide()}an.update_icons()}}this.container_div.find(".yaxislabel").remove();var ah=au[0];if(ah instanceof j){var am=(this.prefs.histogram_max?this.prefs.histogram_max:ah.max_val),ag=$("<div/>").text(am).make_text_editable({num_cols:12,on_finish:function(ax){$(".bs-tooltip").remove();var ax=parseFloat(ax);an.prefs.histogram_max=(!isNaN(ax)?ax:null);an.tile_cache.clear();an.request_draw()},help_text:"Set max value; leave blank to use default"}).addClass("yaxislabel top").css("color",this.prefs.label_color);this.container_div.prepend(ag)}if(ah instanceof O){var ar=true;for(aq=0;aq<au.length;aq++){if(!au[aq].all_slotted){ar=false;break}}if(!ar){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(ae){var ae;if(this.mode==="Auto"){if(ae==="no_detail"){ae="feature spans"}else{if(ae==="summary_tree"){ae="coverage histogram"}}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ae+")")}},incremental_slots:function(ai,ae,ah){var af=this.view.canvas_manager.dummy_context,ag=this.slotters[ai];if(!ag||(ag.mode!==ah)){ag=new (u.FeatureSlotter)(ai,ah,A,function(aj){return af.measureText(aj)});this.slotters[ai]=ag}return ag.slot_features(ae)},get_mode:function(ae){if(ae.dataset_type==="summary_tree"){mode="summary_tree"}else{if(ae.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(ae,ai,aj,af){if(ai==="summary_tree"||ai==="Coverage"){return this.summary_draw_height}else{var ah=this.incremental_slots(aj,ae.data,ai);var ag=new (this.painter)(null,null,null,this.prefs,ai);return Math.max(ab,ag.get_required_height(ah,af))}},draw_tile:function(ao,at,aq,au,ah,al,ag){var ar=this,af=at.canvas,aA=ah.get("start"),ae=ah.get("end"),ai=this.left_offset;if(aq==="summary_tree"||aq==="Coverage"){var aC=new L.SummaryTreePainter(ao,aA,ae,this.prefs);aC.draw(at,af.width,af.height,al);return new j(ar,ah,au,af,ao.data,ao.max)}var ak=[],ap=this.slotters[al].slots;all_slotted=true;if(ao.data){var am=this.filters_manager.filters;for(var av=0,ax=ao.data.length;av<ax;av++){var aj=ao.data[av];var aw=false;var an;for(var az=0,aE=am.length;az<aE;az++){an=am[az];an.update_attrs(aj);if(!an.keep(aj)){aw=true;break}}if(!aw){ak.push(aj);if(!(aj[0] in ap)){all_slotted=false}}}}var aD=(this.filters_manager.alpha_filter?new C(this.filters_manager.alpha_filter):null);var aB=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null);var aC=new (this.painter)(ak,aA,ae,this.prefs,aq,aD,aB,ag);var ay=null;at.fillStyle=this.prefs.block_color;at.font=at.canvas.manager.default_font;at.textAlign="right";if(ao.data){ay=aC.draw(at,af.width,af.height,al,ap);ay.translation=-ai}return new O(ar,ah,au,af,ao.data,al,aq,ao.message,all_slotted,ay)},data_and_mode_compatible:function(ae,af){if(af==="Auto"){return true}else{if(af==="Coverage"){return ae.dataset_type==="summary_tree"}else{if(ae.extra_info==="no_detail"||ae.dataset_type==="summary_tree"){return false}else{return true}}}},can_subset:function(ae){if(ae.dataset_type==="summary_tree"||ae.message||ae.extra_info==="no_detail"){return false}return true}});var S=function(af,ae,ag){c.call(this,af,ae,ag);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:Q()},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter};q(S.prototype,r.prototype,M.prototype,c.prototype);var U=function(ag,af,ai){c.call(this,ag,af,ai);var ah=Q(),ae=Q([ah,"#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:ah},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ae},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"Clear value to set automatically"},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ai.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter;this.update_icons()};q(U.prototype,r.prototype,M.prototype,c.prototype);var d={LineTrack:h,FeatureTrack:c,VcfTrack:S,ReadTrack:U,CompositeTrack:f,DrawableGroup:P};var p=function(ag,af,ae){if("copy" in ag){return ag.copy(ae)}else{var ah=ag.obj_type;if(!ah){ah=ag.track_type}return new d[ah](af,ae,ag)}};return{View:Z,DrawableGroup:P,LineTrack:h,FeatureTrack:c,DiagonalHeatmapTrack:t,ReadTrack:U,VcfTrack:S,CompositeTrack:f,object_from_template:p,add_datasets:ad}});
\ 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(ac,x,l,u,L,aa,i){var q=ac.extend;var Q=l.get_random_color;var ad=function(ae,ag,af){$.ajax({url:ae,data:{"f-dbkey":view.dbkey},error:function(){alert("Grid failed")},success:function(ah){show_modal("Select datasets for new tracks",ah,{Cancel:function(){hide_modal()},Add:function(){var ai=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var aj={data_type:"track_config",hda_ldda:"hda"},ak=$(this).val();if($(this).attr("name")!=="id"){aj.hda_ldda="ldda"}ai[ai.length]=$.ajax({url:ag+"/"+ak,data:aj,dataType:"json"})});$.when.apply($,ai).then(function(){var aj=(arguments[0] instanceof Array?$.map(arguments,function(ak){return ak[0]}):[arguments[0]]);af(aj)});hide_modal()}})}})};var W=function(ae){return("isResolved" in ae)};var n={};var k=function(ae,af){n[ae.attr("id")]=af};var m=function(ae,ag,ai,ah){ai=".group";var af={};n[ae.attr("id")]=ah;ae.bind("drag",{handle:"."+ag,relative:true},function(aq,ar){var ap=$(this),av=$(this).parent(),am=av.children(),ao=n[$(this).attr("id")],al,ak,at,aj,an;ak=$(this).parents(ai);if(ak.length!==0){at=ak.position().top;aj=at+ak.outerHeight();if(ar.offsetY<at){$(this).insertBefore(ak);var au=n[ak.attr("id")];au.remove_drawable(ao);au.container.add_drawable_before(ao,au);return}else{if(ar.offsetY>aj){$(this).insertAfter(ak);var au=n[ak.attr("id")];au.remove_drawable(ao);au.container.add_drawable(ao);return}}}ak=null;for(an=0;an<am.length;an++){al=$(am.get(an));at=al.position().top;aj=at+al.outerHeight();if(al.is(ai)&&this!==al.get(0)&&ar.offsetY>=at&&ar.offsetY<=aj){if(ar.offsetY-at<aj-ar.offsetY){al.find(".content-div").prepend(this)}else{al.find(".content-div").append(this)}if(ao.container){ao.container.remove_drawable(ao)}n[al.attr("id")].add_drawable(ao);return}}for(an=0;an<am.length;an++){al=$(am.get(an));if(ar.offsetY<al.position().top&&!(al.hasClass("reference-track")||al.hasClass("intro"))){break}}if(an===am.length){if(this!==am.get(an-1)){av.append(this);n[av.attr("id")].move_drawable(ao,an)}}else{if(this!==am.get(an)){$(this).insertBefore(am.get(an));n[av.attr("id")].move_drawable(ao,(ar.deltaY>0?an-1:an))}}}).bind("dragstart",function(){af["border-top"]=ae.css("border-top");af["border-bottom"]=ae.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(af)})};exports.moveable=m;var ab=16,G=9,D=20,A=100,I=12000,T=400,K=5000,w=100,o="There was an error in indexing this dataset. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",v="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",y="Tool cannot be rerun: ",a="Loading data...",V="Ready for display",R=10,H=20;function X(af,ae){if(!ae){ae=0}var ag=Math.pow(10,ae);return Math.round(af*ag)/ag}var r=function(af,ae,ah){if(!r.id_counter){r.id_counter=0}this.id=r.id_counter++;this.name=ah.name;this.view=af;this.container=ae;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:ah.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=ah.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(ai){ai.stopPropagation()});var ag=this;this.container_div.hover(function(){ag.icons_div.show()},function(){ag.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};r.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ae){if(ae.content_visible){ae.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ae.hide_contents();ae.content_visible=false}else{ae.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ae.content_visible=true;ae.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(af){var ah=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ae=function(){af.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},ag=function(ai){if((ai.keyCode||ai.which)===27){ah()}else{if((ai.keyCode||ai.which)===13){ae()}}};$(window).bind("keypress.check_enter_esc",ag);show_modal("Configure",af.config.build_form(),{Cancel:ah,OK:ae})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ae){$(".bs-tooltip").remove();ae.remove()}}];q(r.prototype,{init:function(){},changed:function(){this.view.changed()},can_draw:function(){if(this.enabled&&this.content_visible){return true}return false},request_draw:function(){},_draw:function(){},to_dict:function(){},set_name:function(ae){this.old_name=this.name;this.name=ae;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 ae=this.view;this.container_div.hide(0,function(){$(this).remove();ae.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(af,ak,aj,ai,ae,ah){var ag=this;this.action_icons[af]=$("<a/>").attr("href","javascript:void(0);").attr("title",ak).addClass("icon-button").addClass(aj).tooltip().click(function(){ai(ag)}).appendTo(this.icons_div);if(ah){this.action_icons[af].hide()}},build_action_icons:function(ae){var ag;for(var af=0;af<ae.length;af++){ag=ae[af];this.add_action_icon(ag.name,ag.title,ag.css_class,ag.on_click_fn,ag.prepend,ag.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var z=function(af,ae,ag){r.call(this,af,ae,ag);this.obj_type=ag.obj_type;this.drawables=[]};q(z.prototype,r.prototype,{unpack_drawables:function(ag){this.drawables=[];var af;for(var ae=0;ae<ag.length;ae++){af=p(ag[ae],this.view,this);this.add_drawable(af)}},init:function(){for(var ae=0;ae<this.drawables.length;ae++){this.drawables[ae].init()}},_draw:function(){for(var ae=0;ae<this.drawables.length;ae++){this.drawables[ae]._draw()}},to_dict:function(){var af=[];for(var ae=0;ae<this.drawables.length;ae++){af.push(this.drawables[ae].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:af}},add_drawable:function(ae){this.drawables.push(ae);ae.container=this;this.changed()},add_drawable_before:function(ag,ae){this.changed();var af=this.drawables.indexOf(ae);if(af!==-1){this.drawables.splice(af,0,ag);return true}return false},replace_drawable:function(ag,ae,af){var ah=this.drawables.indexOf(ag);if(ah!==-1){this.drawables[ah]=ae;if(af){ag.container_div.replaceWith(ae.container_div)}this.changed()}return ah},remove_drawable:function(af){var ae=this.drawables.indexOf(af);if(ae!==-1){this.drawables.splice(ae,1);af.container=null;this.changed();return true}return false},move_drawable:function(af,ag){var ae=this.drawables.indexOf(af);if(ae!==-1){this.drawables.splice(ae,1);this.drawables.splice(ag,0,af);this.changed();return true}return false},get_drawables:function(){return this.drawables}});var P=function(af,ae,ah){q(ah,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});z.call(this,af,ae,ah);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);m(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new i.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in ah){this.unpack_drawables(ah.drawables)}if("filters" in ah){var ag=this.filters_manager;this.filters_manager=new i.FiltersManager(this,ah.filters);ag.parent_div.replaceWith(this.filters_manager.parent_div);if(ah.filters.visible){this.setup_multitrack_filtering()}}};q(P.prototype,r.prototype,z.prototype,{action_icons_def:[r.prototype.action_icons_def[0],r.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ae){$(".bs-tooltip").remove();ae.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ae){if(ae.filters_manager.visible()){ae.filters_manager.clear_filters();ae._restore_filter_managers()}else{ae.setup_multitrack_filtering();ae.request_draw(true)}ae.filters_manager.toggle()}},r.prototype.action_icons_def[2]],build_container_div:function(){var ae=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ae)}return ae},build_header_div:function(){var ae=$("<div/>").addClass("track-header");ae.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(ae);return ae},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ag=this.drawables.length;if(ag===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ag===1){if(this.drawables[0] instanceof f){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var an,am,ak,aq=true,ai=this.drawables[0].get_type(),ae=0;for(an=0;an<ag;an++){ak=this.drawables[an];if(ak.get_type()!==ai){can_composite=false;break}if(ak instanceof c){ae++}}if(aq||ae===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(ae>1&&ae===this.drawables.length){var ar={},af;ak=this.drawables[0];for(am=0;am<ak.filters_manager.filters.length;am++){af=ak.filters_manager.filters[am];ar[af.name]=[af]}for(an=1;an<this.drawables.length;an++){ak=this.drawables[an];for(am=0;am<ak.filters_manager.filters.length;am++){af=ak.filters_manager.filters[am];if(af.name in ar){ar[af.name].push(af)}}}this.filters_manager.remove_all();var ah,aj,al,ao;for(var ap in ar){ah=ar[ap];if(ah.length===ae){aj=new i.NumberFilter({name:ah[0].name,index:ah[0].index});this.filters_manager.add_filter(aj)}}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 ae=0;ae<this.drawables.length;ae++){this.drawables[ae].filters_manager=this.saved_filters_managers[ae]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ae=0;ae<this.drawables.length;ae++){drawable=this.drawables[ae];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ai=[];for(var af=0;af<this.drawables.length;af++){ai.push(this.drawables[af].name)}var ag="Composite Track of "+this.drawables.length+" tracks ("+ai.join(", ")+")";var ah=new f(this.view,this.view,{name:ag,drawables:this.drawables});var ae=this.container.replace_drawable(this,ah,true);ah.request_draw()},add_drawable:function(ae){z.prototype.add_drawable.call(this,ae);this.update_icons()},remove_drawable:function(ae){z.prototype.remove_drawable.call(this,ae);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ae=q(z.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ae},request_draw:function(ae,ag){for(var af=0;af<this.drawables.length;af++){this.drawables[af].request_draw(ae,ag)}}});var Z=function(ae){q(ae,{obj_type:"View"});z.call(this,"View",ae.container,ae);this.chrom=null;this.vis_id=ae.vis_id;this.dbkey=ae.dbkey;this.label_tracks=[];this.tracks_to_be_redrawn=[];this.max_low=0;this.max_high=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.load_chroms_deferred=null;this.init();this.canvas_manager=new x.CanvasManager(this.container.get(0).ownerDocument);this.reset()};ac.extend(Z.prototype,Backbone.Events);q(Z.prototype,z.prototype,{init:function(){this.requested_redraw=false;var ag=this.container,ae=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ag);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ag);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ag);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").attr("id","viewport-container").appendTo(this.browser_content_div);this.content_div=this.viewport_container;k(this.viewport_container,ae);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var ah=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){ad(add_datasets_url,add_track_async_url,function(ai){ac.each(ai,function(aj){ae.add_drawable(p(aj,ae,ae))})})});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 af=function(ai){if(ai.type==="focusout"||(ai.keyCode||ai.which)===13||(ai.keyCode||ai.which)===27){if((ai.keyCode||ai.which)!==27){ae.go_to($(this).val())}$(this).hide();$(this).val("");ae.location_span.show();ae.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",af).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(){ae.location_span.hide();ae.chrom_select.hide();ae.nav_input.val(ae.chrom+":"+ae.low+"-"+ae.high);ae.nav_input.css("display","inline-block");ae.nav_input.select();ae.nav_input.focus();ae.nav_input.autocomplete({source:function(ak,ai){var al=[],aj=$.map(ae.get_drawables(),function(am){return am.data_manager.search_features(ak.term).success(function(an){al=al.concat(an)})});$.when.apply($,aj).done(function(){ai($.map(al,function(am){return{label:am[0],value:am[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(){ae.zoom_out();ae.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ae.zoom_in();ae.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ae.change_chrom(ae.chrom_select.val())});this.browser_content_div.click(function(ai){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ai){ae.zoom_in(ai.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ai,aj){this.current_x=aj.offsetX}).bind("drag",function(ai,ak){var al=ak.offsetX-this.current_x;this.current_x=ak.offsetX;var aj=Math.round(al/ae.viewport_container.width()*(ae.max_high-ae.max_low));ae.move_delta(-aj)});this.overview_close.click(function(){ae.reset_overview()});this.viewport_container.bind("draginit",function(ai,aj){if(ai.clientX>ae.viewport_container.width()-16){return false}}).bind("dragstart",function(ai,aj){aj.original_low=ae.low;aj.current_height=ai.clientY;aj.current_x=aj.offsetX}).bind("drag",function(ak,am){var ai=$(this);var an=am.offsetX-am.current_x;var aj=ai.scrollTop()-(ak.clientY-am.current_height);ai.scrollTop(aj);am.current_height=ak.clientY;am.current_x=am.offsetX;var al=Math.round(an/ae.viewport_container.width()*(ae.high-ae.low));ae.move_delta(al)}).bind("mousewheel",function(ak,am,aj,ai){if(aj){aj*=50;var al=Math.round(-aj/ae.viewport_container.width()*(ae.high-ae.low));ae.move_delta(al)}});this.top_labeltrack.bind("dragstart",function(ai,aj){return $("<div />").css({height:ae.browser_content_div.height()+ae.top_labeltrack.height()+ae.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(am,an){$(an.proxy).css({left:Math.min(am.pageX,an.startX)-ae.container.offset().left,width:Math.abs(am.pageX-an.startX)});var aj=Math.min(am.pageX,an.startX)-ae.container.offset().left,ai=Math.max(am.pageX,an.startX)-ae.container.offset().left,al=(ae.high-ae.low),ak=ae.viewport_container.width();ae.update_location(Math.round(aj/ak*al)+ae.low,Math.round(ai/ak*al)+ae.low)}).bind("dragend",function(an,ao){var aj=Math.min(an.pageX,ao.startX),ai=Math.max(an.pageX,ao.startX),al=(ae.high-ae.low),ak=ae.viewport_container.width(),am=ae.low;ae.low=Math.round(aj/ak*al)+am;ae.high=Math.round(ai/ak*al)+am;$(ao.proxy).remove();ae.request_redraw()});this.add_label_track(new Y(this,{content_div:this.top_labeltrack}));this.add_label_track(new Y(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ae.resize_window()},500)});$(document).bind("redraw",function(){ae.redraw()});this.reset();$(window).trigger("resize")},changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(af,ah,ae,ai){if(this.timer){clearTimeout(this.timer)}if(ai){var ag=this;this.timer=setTimeout(function(){ag.trigger("navigate",af+":"+ah+"-"+ae)},500)}else{view.trigger("navigate",af+":"+ah+"-"+ae)}},update_location:function(ae,ag){this.location_span.text(commatize(ae)+" - "+commatize(ag));this.nav_input.val(this.chrom+":"+commatize(ae)+"-"+commatize(ag));var af=view.chrom_select.val();if(af!==""){this.trigger_navigate(af,view.low,view.high,true)}},load_chroms:function(ag){ag.num=w;var ae=this,af=$.Deferred();$.ajax({url:chrom_url+"/"+this.dbkey,data:ag,dataType:"json",success:function(ai){if(ai.chrom_info.length===0){return}if(ai.reference){ae.add_label_track(new B(ae))}ae.chrom_data=ai.chrom_info;var al='<option value="">Select Chrom/Contig</option>';for(var ak=0,ah=ae.chrom_data.length;ak<ah;ak++){var aj=ae.chrom_data[ak].chrom;al+='<option value="'+aj+'">'+aj+"</option>"}if(ai.prev_chroms){al+='<option value="previous">Previous '+w+"</option>"}if(ai.next_chroms){al+='<option value="next">Next '+w+"</option>"}ae.chrom_select.html(al);ae.chrom_start_index=ai.start_index;af.resolve(ai)},error:function(){alert("Could not load chroms for this dbkey:",ae.dbkey)}});return af},change_chrom:function(aj,af,al){var ag=this;if(!ag.chrom_data){ag.load_chroms_deferred.then(function(){ag.change_chrom(aj,af,al)});return}if(!aj||aj==="None"){return}if(aj==="previous"){ag.load_chroms({low:this.chrom_start_index-w});return}if(aj==="next"){ag.load_chroms({low:this.chrom_start_index+w});return}var ak=$.grep(ag.chrom_data,function(am,an){return am.chrom===aj})[0];if(ak===undefined){ag.load_chroms({chrom:aj},function(){ag.change_chrom(aj,af,al)});return}else{if(aj!==ag.chrom){ag.chrom=aj;ag.chrom_select.val(ag.chrom);ag.max_high=ak.len-1;ag.reset();ag.request_redraw(true);for(var ai=0,ae=ag.drawables.length;ai<ae;ai++){var ah=ag.drawables[ai];if(ah.init){ah.init()}}if(ag.reference_track){ag.reference_track.init()}}if(af!==undefined&&al!==undefined){ag.low=Math.max(af,0);ag.high=Math.min(al,ag.max_high)}else{ag.low=0;ag.high=ag.max_high}ag.reset_overview();ag.request_redraw()}},go_to:function(ai){ai=ai.replace(/ |,/g,"");var am=this,ae,ah,af=ai.split(":"),ak=af[0],al=af[1];if(al!==undefined){try{var aj=al.split("-");ae=parseInt(aj[0],10);ah=parseInt(aj[1],10)}catch(ag){return false}}am.change_chrom(ak,ae,ah)},move_fraction:function(ag){var ae=this;var af=ae.high-ae.low;this.move_delta(ag*af)},move_delta:function(ah){var ae=this;var ag=ae.high-ae.low;if(ae.low-ah<ae.max_low){ae.low=ae.max_low;ae.high=ae.max_low+ag}else{if(ae.high-ah>ae.max_high){ae.high=ae.max_high;ae.low=ae.max_high-ag}else{ae.high-=ah;ae.low-=ah}}ae.request_redraw();var af=ae.chrom_select.val();this.trigger_navigate(af,ae.low,ae.high,true)},add_drawable:function(ae){z.prototype.add_drawable.call(this,ae);ae.init();this.changed();this.update_intro_div()},add_label_track:function(ae){ae.view=this;ae.init();this.label_tracks.push(ae)},remove_drawable:function(ag,af){z.prototype.remove_drawable.call(this,ag);if(af){var ae=this;ag.container_div.hide(0,function(){$(this).remove();ae.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(am,ae,al,an){var ak=this,aj=(an?[an]:ak.drawables),ag;var af;for(var ai=0;ai<aj.length;ai++){af=aj[ai];ag=-1;for(var ah=0;ah<ak.tracks_to_be_redrawn.length;ah++){if(ak.tracks_to_be_redrawn[ah][0]===af){ag=ah;break}}if(ag<0){ak.tracks_to_be_redrawn.push([af,ae,al])}else{ak.tracks_to_be_redrawn[ai][1]=ae;ak.tracks_to_be_redrawn[ai][2]=al}}if(!this.requested_redraw){requestAnimationFrame(function(){ak._redraw(am)});this.requested_redraw=true}},_redraw:function(ao){this.requested_redraw=false;var al=this.low,ah=this.high;if(al<this.max_low){al=this.max_low}if(ah>this.max_high){ah=this.max_high}var an=this.high-this.low;if(this.high!==0&&an<this.min_separation){ah=al+this.min_separation}this.low=Math.floor(al);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=this.viewport_container.width()/(this.high-this.low);var ae=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ak=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ap=13;this.overview_box.css({left:ae,width:Math.max(ap,ak)}).show();if(ak<ap){this.overview_box.css("left",ae-(ap-ak)/2)}if(this.overview_highlight){this.overview_highlight.css({left:ae,width:ak})}if(!ao){var ag,af,am;for(var ai=0,aj=this.tracks_to_be_redrawn.length;ai<aj;ai++){ag=this.tracks_to_be_redrawn[ai][0];af=this.tracks_to_be_redrawn[ai][1];am=this.tracks_to_be_redrawn[ai][2];if(ag){ag._draw(af,am)}}this.tracks_to_be_redrawn=[];for(ai=0,aj=this.label_tracks.length;ai<aj;ai++){this.label_tracks[ai]._draw()}}},zoom_in:function(af,ag){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var ah=this.high-this.low,ai=ah/2+this.low,ae=(ah/this.zoom_factor)/2;if(af){ai=af/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ai-ae);this.high=Math.round(ai+ae);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var af=this.high-this.low,ag=af/2+this.low,ae=(af*this.zoom_factor)/2;this.low=Math.round(ag-ae);this.high=Math.round(ag+ae);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(ag){if(this.overview_drawable){if(this.overview_drawable.dataset_id===ag.dataset_id){return}this.overview_viewport.find(".track").remove()}var af=ag.copy({content_div:this.overview_viewport}),ae=this;af.header_div.hide();af.is_overview=true;ae.overview_drawable=af;this.overview_drawable.postdraw_actions=function(){ae.overview_highlight.show().height(ae.overview_drawable.content_div.height());ae.overview_viewport.height(ae.overview_drawable.content_div.height()+ae.overview_box.outerHeight());ae.overview_close.show();ae.resize_window()};ae.overview_drawable.request_draw();this.changed()},reset_overview:function(){$(".bs-tooltip").remove();this.overview_viewport.find(".track-tile").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide();view.resize_window();view.overview_drawable=null}});var s=function(ag,al,ah){this.track=ag;this.name=al.name;this.params=[];var at=al.params;for(var ai=0;ai<at.length;ai++){var an=at[ai],af=an.name,ar=an.label,aj=unescape(an.html),au=an.value,ap=an.type;if(ap==="number"){this.params.push(new e(af,ar,aj,(af in ah?ah[af]:au),an.min,an.max))}else{if(ap==="select"){this.params.push(new N(af,ar,aj,(af in ah?ah[af]:au)))}else{console.log("WARNING: unrecognized tool parameter type:",af,ap)}}}this.parent_div=$("<div/>").addClass("dynamic-tool").hide();this.parent_div.bind("drag",function(aw){aw.stopPropagation()}).click(function(aw){aw.stopPropagation()}).bind("dblclick",function(aw){aw.stopPropagation()});var aq=$("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);var ao=this.params;var am=this;$.each(this.params,function(ax,aA){var az=$("<div>").addClass("param-row").appendTo(am.parent_div);var aw=$("<div>").addClass("param-label").text(aA.label).appendTo(az);var ay=$("<div/>").addClass("param-input").html(aA.html).appendTo(az);ay.find(":input").val(aA.value);$("<div style='clear: both;'/>").appendTo(az)});this.parent_div.find("input").click(function(){$(this).select()});var av=$("<div>").addClass("param-row").appendTo(this.parent_div);var ak=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(av);var ae=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(av);ae.click(function(){am.run_on_region()});ak.click(function(){am.run_on_dataset()});if("visible" in ah&&ah.visible){this.parent_div.show()}};q(s.prototype,{update_params:function(){for(var ae=0;ae<this.params.length;ae++){this.params[ae].update_value()}},state_dict:function(){var af={};for(var ae=0;ae<this.params.length;ae++){af[this.params[ae].name]=this.params[ae].value}af.visible=this.parent_div.is(":visible");return af},get_param_values_dict:function(){var ae={};this.parent_div.find(":input").each(function(){var af=$(this).attr("name"),ag=$(this).val();ae[af]=ag});return ae},get_param_values:function(){var ae=[];this.parent_div.find(":input").each(function(){var af=$(this).attr("name"),ag=$(this).val();if(af){ae[ae.length]=ag}});return ae},run_on_dataset:function(){var ae=this;ae.run({target_dataset_id:this.track.original_dataset_id,tool_id:ae.name},null,function(af){show_modal(ae.name+" is Running",ae.name+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var af={target_dataset_id:this.track.original_dataset_id,action:"rerun",tool_id:this.name,regions:[{chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}]},aj=this.track,ag=af.tool_id+aj.tool_region_and_parameters_str(af.chrom,af.low,af.high),ae;if(aj.container===view){var ai=new P(view,view,{name:this.name});var ah=aj.container.replace_drawable(aj,ai,false);ai.container_div.insertBefore(aj.view.content_div.children()[ah]);ai.add_drawable(aj);aj.container_div.appendTo(ai.content_div);ae=ai}else{ae=aj.container}var ak=new aj.constructor(view,ae,{name:ag,hda_ldda:"hda"});ak.init_for_tool_data();ak.change_mode(aj.mode);ak.set_filters_manager(aj.filters_manager.copy(ak));ak.update_icons();ae.add_drawable(ak);ak.tiles_div.text("Starting job.");this.update_params();this.run(af,ak,function(al){ak.set_dataset(new aa.Dataset(al));ak.tiles_div.text("Running job.");ak.init()})},run:function(ae,ag,ah){ae.inputs=this.get_param_values_dict();var af=new l.ServerStateDeferred({ajax_settings:{url:galaxy_paths.get("tool_url"),data:JSON.stringify(ae),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ai){return ai!=="pending"}});$.when(af.go()).then(function(ai){if(ai==="no converter"){ag.container_div.addClass("error");ag.content_div.text(J)}else{if(ai.error){ag.container_div.addClass("error");ag.content_div.text(y+ai.message)}else{ah(ai)}}})}});var N=function(af,ae,ag,ah){this.name=af;this.label=ae;this.html=$(ag);this.value=ah};q(N.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ag,af,ai,aj,ah,ae){N.call(this,ag,af,ai,aj);this.min=ah;this.max=ae};q(e.prototype,N.prototype,{update_value:function(){N.prototype.update_value.call(this);this.value=parseFloat(this.value)}});var C=function(ae,af){L.Scaler.call(this,af);this.filter=ae};C.prototype.gen_val=function(ae){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(ae[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var F=function(ae){this.track=ae.track;this.params=ae.params;this.values={};this.restore_values((ae.saved_values?ae.saved_values:{}));this.onchange=ae.onchange};q(F.prototype,{restore_values:function(ae){var af=this;$.each(this.params,function(ag,ah){if(ae[ah.key]!==undefined){af.values[ah.key]=ae[ah.key]}else{af.values[ah.key]=ah.default_value}})},build_form:function(){var ah=this;var ae=$("<div />");var ag;function af(am,ai){for(var aq=0;aq<am.length;aq++){ag=am[aq];if(ag.hidden){continue}var ak="param_"+aq;var av=ah.values[ag.key];var ax=$("<div class='form-row' />").appendTo(ai);ax.append($("<label />").attr("for",ak).text(ag.label+":"));if(ag.type==="bool"){ax.append($('<input type="checkbox" />').attr("id",ak).attr("name",ak).attr("checked",av))}else{if(ag.type==="text"){ax.append($('<input type="text"/>').attr("id",ak).val(av).click(function(){$(this).select()}))}else{if(ag.type==="select"){var at=$("<select />").attr("id",ak);for(var ao=0;ao<ag.options.length;ao++){$("<option/>").text(ag.options[ao].label).attr("value",ag.options[ao].value).appendTo(at)}at.val(av);ax.append(at)}else{if(ag.type==="color"){var aw=$("<div/>").appendTo(ax),ar=$("<input />").attr("id",ak).attr("name",ak).val(av).css("float","left").appendTo(aw).click(function(az){$(".bs-tooltip").removeClass("in");var ay=$(this).siblings(".bs-tooltip").addClass("in");ay.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(ay).height()/2)+($(this).height()/2)}).show();ay.click(function(aA){aA.stopPropagation()});$(document).bind("click.color-picker",function(){ay.hide();$(document).unbind("click.color-picker")});az.stopPropagation()}),ap=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(aw).attr("title","Set new random color").tooltip(),au=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(aw).hide(),al=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(au),aj=$("<div class='tooltip-arrow'></div>").appendTo(au),an=$.farbtastic(al,{width:100,height:100,callback:ar,color:av});aw.append($("<div/>").css("clear","both"));(function(ay){ap.click(function(){ay.setColor(Q())})})(an)}else{ax.append($("<input />").attr("id",ak).attr("name",ak).val(av))}}}}if(ag.help){ax.append($("<div class='help'/>").text(ag.help))}}}af(this.params,ae);return ae},update_from_form:function(ae){var ag=this;var af=false;$.each(this.params,function(ah,aj){if(!aj.hidden){var ak="param_"+ah;var ai=ae.find("#"+ak).val();if(aj.type==="float"){ai=parseFloat(ai)}else{if(aj.type==="int"){ai=parseInt(ai)}else{if(aj.type==="bool"){ai=ae.find("#"+ak).is(":checked")}}}if(ai!==ag.values[aj.key]){ag.values[aj.key]=ai;af=true}}});if(af){this.onchange();this.track.changed()}}});var b=function(ae,ai,ag,af,ah){this.track=ae;this.region=ai;this.low=ai.get("start");this.high=ai.get("end");this.resolution=ag;this.html_elt=$("<div class='track-tile'/>").append(af).height($(af).attr("height"));this.data=ah;this.stale=false};b.prototype.predisplay_actions=function(){};var j=function(ae,aj,ag,af,ah,ai){b.call(this,ae,aj,ag,af,ah);this.max_val=ai};q(j.prototype,b.prototype);var O=function(ah,ap,ai,ag,ak,ar,al,at,af,ao){b.call(this,ah,ap,ai,ag,ak);this.mode=al;this.all_slotted=af;this.feature_mapper=ao;this.has_icons=false;if(at){this.has_icons=true;var am=this;ag=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:D-1,width:ag.width}).prependTo(this.html_elt);var an=new x.GenomeRegion({chrom:ah.view.chrom,start:this.low,end:this.high}),aq=ak.length,aj=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+aq+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ae=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+aq+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);aj.click(function(){am.stale=true;ah.data_manager.get_more_data(an,ah.mode,am.resolution,{},ah.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();ah.request_draw(true)}).dblclick(function(au){au.stopPropagation()});ae.click(function(){am.stale=true;ah.data_manager.get_more_data(an,ah.mode,am.resolution,{},ah.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();ah.request_draw(true)}).dblclick(function(au){au.stopPropagation()})}};q(O.prototype,b.prototype);O.prototype.predisplay_actions=function(){var af=this,ae={};if(af.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(aq){if(!this.hovered){return}var al=$(this).offset(),ap=aq.pageX-al.left,ao=aq.pageY-al.top,av=af.feature_mapper.get_feature_data(ap,ao),am=(av?av[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!am||$(this).attr("id")!==am.toString()){$(this).remove()}});if(av){var ah=ae[am];if(!ah){var am=av[0],ar={name:av[3],start:av[1],end:av[2],strand:av[4]},ak=af.track.filters_manager.filters,aj;for(var an=0;an<ak.length;an++){aj=ak[an];ar[aj.name]=av[aj.index]}var ah=$("<div/>").attr("id",am).addClass("feature-popup"),aw=$("<table/>"),au,at,ax;for(au in ar){at=ar[au];ax=$("<tr/>").appendTo(aw);$("<th/>").appendTo(ax).text(au);$("<td/>").attr("align","left").appendTo(ax).text(typeof(at)==="number"?X(at,2):at)}ah.append($("<div class='feature-popup-inner'>").append(aw));ae[am]=ah}ah.appendTo($(this).parents(".track-content").children(".overlay"));var ai=ap+parseInt(af.html_elt.css("left"))-ah.width()/2,ag=ao+parseInt(af.html_elt.css("top"))+7;ah.css("left",ai+"px").css("top",ag+"px")}else{if(!aq.isPropagationStopped()){aq.stopPropagation();$(this).siblings().each(function(){$(this).trigger(aq)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var g=function(af,ae,ag){q(ag,{drag_handle_class:"draghandle"});r.call(this,af,ae,ag);this.dataset=new aa.Dataset({id:ag.dataset_id,hda_ldda:ag.hda_ldda});this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ag?ag.data_query_wait:K);this.data_manager=("data_manager" in ag?ag.data_manager:new x.GenomeDataManager({dataset:this.dataset,data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=0;this.content_div=$("<div class='track-content'>").appendTo(this.container_div);if(this.container){this.container.content_div.append(this.container_div);if(!("resize" in ag)||ag.resize){this.add_resize_handle()}}};q(g.prototype,r.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},r.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(ae){ae.view.set_overview(ae)}},r.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ae){if(ae.filters_manager.visible()){ae.filters_manager.clear_filters()}else{ae.filters_manager.init_filters()}ae.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ae){ae.dynamic_tool_div.toggle();if(ae.dynamic_tool_div.is(":visible")){ae.set_name(ae.name+ae.tool_region_and_parameters_str())}else{ae.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ae){var ah='<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>',ag=ac.template(ah,{track:ae});var aj=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},af=function(){var al=$('select[name="regions"] option:selected').val(),an,ak=new x.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),am=ac.map($(".bookmark"),function(ao){return new x.GenomeRegion({from_str:$(ao).children(".position").text()})});if(al==="cur"){an=[ak]}else{if(al==="bookmarks"){an=am}else{an=[ak].concat(am)}}hide_modal();window.location.href=galaxy_paths.get("sweepster_url")+"?"+$.param({dataset_id:ae.dataset_id,hda_ldda:ae.hda_ldda,regions:JSON.stringify(new Backbone.Collection(an).toJSON())})},ai=function(ak){if((ak.keyCode||ak.which)===27){aj()}else{if((ak.keyCode||ak.which)===13){af()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",ag,{No:aj,Yes:af})}},r.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset_id&&r.prototype.can_draw.call(this)){return true}return false},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id).css("position","relative")},build_header_div:function(){var ae=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ae)}this.name_div=$("<div/>").addClass("track-name").appendTo(ae).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ae},on_resize:function(){},add_resize_handle:function(){var ae=this;var ah=false;var ag=false;var af=$("<div class='track-resize'>");$(ae.container_div).hover(function(){if(ae.content_visible){ah=true;af.show()}},function(){ah=false;if(!ag){af.hide()}});af.hide().bind("dragstart",function(ai,aj){ag=true;aj.original_height=$(ae.content_div).height()}).bind("drag",function(aj,ak){var ai=Math.min(Math.max(ak.original_height+ak.deltaY,ae.min_height_px),ae.max_height_px);$(ae.tiles_div).css("height",ai);ae.visible_height_px=(ae.max_height_px===ai?0:ai);ae.on_resize()}).bind("dragend",function(ai,aj){ae.tile_cache.clear();ag=false;if(!ah){af.hide()}ae.config.values.height=ae.visible_height_px;ae.changed()}).appendTo(ae.container_div)},set_display_modes:function(ah,ak){this.display_modes=ah;this.mode=(ak?ak:(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 af=this,ai={};for(var ag=0,ae=af.display_modes.length;ag<ae;ag++){var aj=af.display_modes[ag];ai[aj]=function(al){return function(){af.change_mode(al);af.icons_div.show();af.container_div.mouseleave(function(){af.icons_div.hide()})}}(aj)}make_popupmenu(this.action_icons.mode_icon,ai)},build_action_icons:function(){r.prototype.build_action_icons.call(this,this.action_icons_def);if(this.display_modes!==undefined){this.set_display_modes(this.display_modes)}},hide_contents:function(){this.tiles_div.hide();this.container_div.find(".yaxislabel, .track-resize").hide()},show_contents:function(){this.tiles_div.show();this.container_div.find(".yaxislabel, .track-resize").show();this.request_draw()},get_type:function(){if(this instanceof Y){return"LabelTrack"}else{if(this instanceof B){return"ReferenceTrack"}else{if(this instanceof h){return"LineTrack"}else{if(this instanceof U){return"ReadTrack"}else{if(this instanceof S){return"VcfTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(){var af=this;af.enabled=false;af.tile_cache.clear();af.data_manager.clear();af.content_div.css("height","auto");af.tiles_div.children().remove();af.container_div.removeClass("nodata error pending");if(!af.dataset_id){return}var ae=$.Deferred(),ag={hda_ldda:af.hda_ldda,data_type:this.dataset_check_type,chrom:af.view.chrom};$.getJSON(this.dataset.url(),ag,function(ah){if(!ah||ah==="error"||ah.kind==="error"){af.container_div.addClass("error");af.tiles_div.text(o);if(ah.message){var ai=$(" <a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ah.message+"</pre>",{Close:hide_modal})});af.tiles_div.append(ai)}}else{if(ah==="no converter"){af.container_div.addClass("error");af.tiles_div.text(J)}else{if(ah==="no data"||(ah.data!==undefined&&(ah.data===null||ah.data.length===0))){af.container_div.addClass("nodata");af.tiles_div.text(E)}else{if(ah==="pending"){af.container_div.addClass("pending");af.tiles_div.html(v);setTimeout(function(){af.init()},af.data_query_wait)}else{if(ah==="data"||ah.status==="data"){if(ah.valid_chroms){af.valid_chroms=ah.valid_chroms;af.update_icons()}af.tiles_div.text(V);if(af.view.chrom){af.tiles_div.text("");af.tiles_div.css("height",af.visible_height_px+"px");af.enabled=true;$.when(af.predraw_init()).done(function(){ae.resolve();af.container_div.removeClass("nodata error pending");af.request_draw()})}else{ae.resolve()}}}}}}});this.update_icons();return ae},predraw_init:function(){},get_drawables:function(){return this}});var M=function(ag,af,ah){g.call(this,ag,af,ah);var ae=this;m(ae.container_div,ae.drag_handle_class,".group",ae);this.filters_manager=new i.FiltersManager(this,("filters" in ah?ah.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=("tool" in ah&&ah.tool?new s(this,ah.tool,ah.tool_state):null);this.tile_cache=new x.Cache(R);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(ah.mode){this.change_mode(ah.mode)}};q(M.prototype,r.prototype,g.prototype,{action_icons_def:g.prototype.action_icons_def.concat([{name:"show_more_rows_icon",title:"To minimize track height, not all feature rows are displayed. Click to display more rows.",css_class:"exclamation",on_click_fn:function(ae){$(".bs-tooltip").remove();ae.slotters[ae.view.resolution_px_b].max_rows*=2;ae.request_draw(true)},hide:true}]),copy:function(ae){var af=this.to_dict();q(af,{data_manager:this.data_manager});var ag=new this.constructor(this.view,ae,af);ag.change_mode(this.mode);ag.enabled=this.enabled;return ag},set_filters_manager:function(ae){this.filters_manager=ae;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,hda_ldda:this.hda_ldda,dataset_id:this.dataset_id,prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},change_mode:function(af){var ae=this;ae.mode=af;ae.config.values.mode=af;ae.tile_cache.clear();ae.request_draw();this.action_icons.mode_icon.attr("title","Set display mode (now: "+ae.mode+")");return ae},update_icons:function(){var ae=this;if(ae.filters_available){ae.action_icons.filters_icon.show()}else{ae.action_icons.filters_icon.hide()}if(ae.tool){ae.action_icons.tools_icon.show();ae.action_icons.param_space_viz_icon.show()}else{ae.action_icons.tools_icon.hide();ae.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(af,ag,ae){return af+"_"+ag+"_"+ae},request_draw:function(af,ae){this.view.request_redraw(false,af,ae,this)},before_draw:function(){},_draw:function(af,ap){if(!this.can_draw()){return}var an=this.view.low,aj=this.view.high,al=aj-an,ag=this.view.container.width(),ar=this.view.resolution_px_b,ai=this.view.resolution_b_px;if(this.is_overview){an=this.view.max_low;aj=this.view.max_high;ai=(view.max_high-view.max_low)/ag;ar=1/ai}this.before_draw();this.tiles_div.children().addClass("remove");var ae=Math.floor(an/(ai*T)),am=true,aq=[],ak=function(at){return(at&&"track" in at)};while((ae*T*ai)<aj){var ao=this.draw_helper(af,ag,ae,ai,this.tiles_div,ar);if(ak(ao)){aq.push(ao)}else{am=false}ae+=1}if(!ap){this.tiles_div.children(".remove").removeClass("remove").remove()}var ah=this;if(am){this.tiles_div.children(".remove").remove();ah.postdraw_actions(aq,ag,ar,ap)}},postdraw_actions:function(ag,ah,aj,ae){var ai=false;for(var af=0;af<ag.length;af++){if(ag[af].has_icons){ai=true;break}}if(ai){for(var af=0;af<ag.length;af++){tile=ag[af];if(!tile.has_icons){tile.html_elt.css("padding-top",D)}}}},draw_helper:function(ae,aq,aw,au,aj,ak,ar){var ap=this,az=this._gen_tile_cache_key(aq,ak,aw),ah=this._get_tile_bounds(aw,au);if(!ar){ar={}}var ay=(ae?undefined:ap.tile_cache.get_elt(az));if(ay){ap.show_tile(ay,aj,ak);return ay}var an=true;var av=ap.data_manager.get_data(ah,ap.mode,au,ap.data_url_extra_params);if(W(av)){an=false}var al;if(view.reference_track&&ak>view.canvas_manager.char_width_px){al=view.reference_track.data_manager.get_data(ah,ap.mode,au,view.reference_track.data_url_extra_params);if(W(al)){an=false}}if(an){q(av,ar.more_tile_data);var am=ap.mode;if(am==="Auto"){am=ap.get_mode(av);ap.update_auto_mode(am)}var ag=ap.view.canvas_manager.new_canvas(),ax=ah.get("start"),af=ah.get("end"),aq=Math.ceil((af-ax)*ak)+ap.left_offset,ao=ap.get_canvas_height(av,am,ak,aq);ag.width=aq;ag.height=ao;var at=ag.getContext("2d");at.translate(this.left_offset,0);var ay=ap.draw_tile(av,at,am,au,ah,ak,al);if(ay!==undefined){ap.tile_cache.set_elt(az,ay);ap.show_tile(ay,aj,ak)}return ay}var ai=$.Deferred();$.when(av,al).then(function(){view.request_redraw(false,false,false,ap);ai.resolve()});return ai},get_canvas_height:function(ae,ag,ah,af){return this.visible_height_px},draw_tile:function(ae,af,aj,ah,ai,ak,ag){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ag,aj,ak){var af=this,ae=ag.html_elt;ag.predisplay_actions();var ai=(ag.low-(this.is_overview?this.view.max_low:this.view.low))*ak;if(this.left_offset){ai-=this.left_offset}ae.css({position:"absolute",top:0,left:ai});if(ae.hasClass("remove")){ae.removeClass("remove")}else{aj.append(ae)}ag.html_elt.height("auto");this.max_height_px=Math.max(this.max_height_px,ag.html_elt.height());ag.html_elt.parent().children().css("height",this.max_height_px+"px");var ah=this.max_height_px;if(this.visible_height_px!==0){ah=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",ah+"px")},_get_tile_bounds:function(ae,af){var ah=Math.floor(ae*T*af),ai=Math.ceil(T*af),ag=(ah+ai<=this.view.max_high?ah+ai:this.view.max_high);return new x.GenomeRegion({chrom:this.view.chrom,start:ah,end:ag})},tool_region_and_parameters_str:function(ag,ae,ah){var af=this,ai=(ag!==undefined&&ae!==undefined&&ah!==undefined?ag+":"+ae+"-"+ah:"all");return" - region=["+ai+"], parameters=["+af.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(ae,af){return true},can_subset:function(ae){return false},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state";this.normal_postdraw_actions=this.postdraw_actions;this.postdraw_actions=function(ag,ah,aj,ae){var af=this;af.normal_postdraw_actions(ag,ah,aj,ae);af.dataset_check_type="converted_datasets_state";af.data_query_wait=K;var ai=new l.ServerStateDeferred({url:af.dataset_state_url,url_params:{dataset_id:af.dataset_id,hda_ldda:af.hda_ldda},interval:af.data_query_wait,success_fn:function(ak){return ak!=="pending"}});$.when(ai.go()).then(function(){af.data_manager.set("data_type","data")});af.postdraw_actions=af.normal_postdraw_actions}}});var Y=function(af,ae){var ag={resize:false};g.call(this,af,ae,ag);this.container_div.addClass("label-track")};q(Y.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},_draw:function(){var ag=this.view,ah=ag.high-ag.low,ak=Math.floor(Math.pow(10,Math.floor(Math.log(ah)/Math.log(10)))),ae=Math.floor(ag.low/ak)*ak,ai=this.view.container.width(),af=$("<div style='position: relative; height: 1.3em;'></div>");while(ae<ag.high){var aj=(ae-ag.low)/ah*ai;af.append($("<div class='label'>"+commatize(ae)+"</div>").css({position:"absolute",left:aj-1}));ae+=ak}this.content_div.children(":first").remove();this.content_div.append(af)}});var f=function(af,ae,ai){M.call(this,af,ae,ai);this.drawables=[];this.left_offset=0;if("drawables" in ai){var ah;for(var ag=0;ag<ai.drawables.length;ag++){ah=ai.drawables[ag];this.drawables[ag]=p(ah,af,null);if(ah.left_offset>this.left_offset){this.left_offset=ah.left_offset}}this.enabled=true}if(this.drawables.length!==0){this.set_display_modes(this.drawables[0].display_modes,this.drawables[0].mode)}this.update_icons();this.obj_type="CompositeTrack"};q(f.prototype,M.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ae){$(".bs-tooltip").remove();ae.show_group()}}].concat(M.prototype.action_icons_def),to_dict:z.prototype.to_dict,add_drawable:z.prototype.add_drawable,unpack_drawables:z.prototype.unpack_drawables,change_mode:function(ae){M.prototype.change_mode.call(this,ae);for(var af=0;af<this.drawables.length;af++){this.drawables[af].change_mode(ae)}},init:function(){var ag=[];for(var af=0;af<this.drawables.length;af++){ag.push(this.drawables[af].init())}var ae=this;$.when.apply($,ag).then(function(){ae.enabled=true;ae.request_draw()})},update_icons:function(){this.action_icons.filters_icon.hide();this.action_icons.tools_icon.hide();this.action_icons.param_space_viz_icon.hide()},can_draw:r.prototype.can_draw,draw_helper:function(af,av,aB,ay,am,ao,aw){var au=this,aF=this._gen_tile_cache_key(av,ao,aB),aj=this._get_tile_bounds(aB,ay);if(!aw){aw={}}var aE=(af?undefined:au.tile_cache.get_elt(aF));if(aE){au.show_tile(aE,am,ao);return aE}var an=[],au,ar=true,az,ap;for(var aA=0;aA<this.drawables.length;aA++){au=this.drawables[aA];az=au.data_manager.get_data(aj,au.mode,ay,au.data_url_extra_params);if(W(az)){ar=false}an.push(az);ap=null;if(view.reference_track&&ao>view.canvas_manager.char_width_px){ap=view.reference_track.data_manager.get_data(aj,au.mode,ay,view.reference_track.data_url_extra_params);if(W(ap)){ar=false}}an.push(ap)}if(ar){q(az,aw.more_tile_data);this.tile_predraw_init();var ai=au.view.canvas_manager.new_canvas(),ak=au._get_tile_bounds(aB,ay),aC=aj.get("start"),ag=aj.get("end"),aD=0,av=Math.ceil((ag-aC)*ao)+this.left_offset,at=0,ah=[],aA;var ae=0;for(aA=0;aA<this.drawables.length;aA++,aD+=2){au=this.drawables[aA];az=an[aD];var aq=au.mode;if(aq==="Auto"){aq=au.get_mode(az);au.update_auto_mode(aq)}ah.push(aq);ae=au.get_canvas_height(az,aq,ao,av);if(ae>at){at=ae}}ai.width=av;ai.height=(aw.height?aw.height:at);aD=0;var ax=ai.getContext("2d");ax.translate(this.left_offset,0);ax.globalAlpha=0.5;ax.globalCompositeOperation="source-over";for(aA=0;aA<this.drawables.length;aA++,aD+=2){au=this.drawables[aA];az=an[aD];ap=an[aD+1];aE=au.draw_tile(az,ax,ah[aA],ay,aj,ao,ap)}this.tile_cache.set_elt(aF,aE);this.show_tile(aE,am,ao);return aE}var al=$.Deferred(),au=this;$.when.apply($,an).then(function(){view.request_redraw(false,false,false,au);al.resolve()});return al},show_group:function(){var ah=new P(this.view,this.container,{name:this.name}),ae;for(var ag=0;ag<this.drawables.length;ag++){ae=this.drawables[ag];ae.update_icons();ah.add_drawable(ae);ae.container=ah;ah.content_div.append(ae.container_div)}var af=this.container.replace_drawable(this,ah,true);ah.request_draw()},tile_predraw_init:function(){var ah=Number.MAX_VALUE,ae=-ah,af;for(var ag=0;ag<this.drawables.length;ag++){af=this.drawables[ag];if(af instanceof h){if(af.prefs.min_value<ah){ah=af.prefs.min_value}if(af.prefs.max_value>ae){ae=af.prefs.max_value}}}for(var ag=0;ag<this.drawables.length;ag++){af=this.drawables[ag];af.prefs.min_value=ah;af.prefs.max_value=ae}},postdraw_actions:function(ag,aj,al,af){M.prototype.postdraw_actions.call(this,ag,aj,al,af);var ai=-1;for(var ah=0;ah<ag.length;ah++){var ae=ag[ah].html_elt.find("canvas").height();if(ae>ai){ai=ae}}for(var ah=0;ah<ag.length;ah++){var ak=ag[ah];if(ak.html_elt.find("canvas").height()!==ai){this.draw_helper(true,aj,ak.index,ak.resolution,ak.html_elt.parent(),al,{height:ai});ak.html_elt.remove()}}}});var B=function(ae){M.call(this,ae,{content_div:ae.top_labeltrack},{resize:false});ae.reference_track=this;this.left_offset=200;this.visible_height_px=12;this.container_div.addClass("reference-track");this.content_div.css("background","none");this.content_div.css("min-height","0px");this.content_div.css("border","none");this.data_url=reference_url+"/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new x.ReferenceTrackDataManager({data_url:this.data_url});this.hide_contents()};q(B.prototype,r.prototype,M.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},can_draw:r.prototype.can_draw,draw_helper:function(ai,ag,ae,af,aj,ak,ah){if(ak>this.view.canvas_manager.char_width_px){return M.prototype.draw_helper.call(this,ai,ag,ae,af,aj,ak,ah)}else{this.hide_contents();return null}},draw_tile:function(am,an,ai,ah,ak,ao){var ag=this;if(ao>this.view.canvas_manager.char_width_px){if(am.data===null){this.hide_contents();return}var af=an.canvas;an.font=an.canvas.manager.default_font;an.textAlign="center";am=am.data;for(var aj=0,al=am.length;aj<al;aj++){var ae=Math.floor(aj*ao);an.fillText(am[aj],ae,10)}this.show_contents();return new b(ag,ak,ah,af,am)}this.hide_contents()}});var h=function(ag,af,ah){var ae=this;this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";M.call(this,ag,af,ah);this.hda_ldda=ah.hda_ldda;this.dataset_id=ah.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Color",type:"color",default_value:Q()},{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:ah.prefs,onchange:function(){ae.set_name(ae.prefs.name);ae.vertical_range=ae.prefs.max_value-ae.prefs.min_value;ae.set_min_value(ae.prefs.min_value);ae.set_max_value(ae.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};q(h.prototype,r.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ae){this.prefs.min_value=ae;$("#linetrack_"+this.dataset_id+"_minval").text(this.prefs.min_value);this.tile_cache.clear();this.request_draw()},set_max_value:function(ae){this.prefs.max_value=ae;$("#linetrack_"+this.dataset_id+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.request_draw()},predraw_init:function(){var ae=this;ae.vertical_range=undefined;return $.getJSON(ae.dataset.url(),{data_type:"data",stats:true,chrom:ae.view.chrom,low:0,high:ae.view.max_high,hda_ldda:ae.hda_ldda},function(af){ae.container_div.addClass("line-track");var ai=af.data;if(isNaN(parseFloat(ae.prefs.min_value))||isNaN(parseFloat(ae.prefs.max_value))){var ag=ai.min,ak=ai.max;ag=Math.floor(Math.min(0,Math.max(ag,ai.mean-2*ai.sd)));ak=Math.ceil(Math.max(0,Math.min(ak,ai.mean+2*ai.sd)));ae.prefs.min_value=ag;ae.prefs.max_value=ak;$("#track_"+ae.dataset_id+"_minval").val(ae.prefs.min_value);$("#track_"+ae.dataset_id+"_maxval").val(ae.prefs.max_value)}ae.vertical_range=ae.prefs.max_value-ae.prefs.min_value;ae.total_frequency=ai.total_frequency;ae.container_div.find(".yaxislabel").remove();var aj=$("<div/>").text(X(ae.prefs.min_value,3)).make_text_editable({num_cols:6,on_finish:function(al){$(".bs-tooltip").remove();var al=parseFloat(al);if(!isNaN(al)){ae.set_min_value(al)}},help_text:"Set min value"}).addClass("yaxislabel bottom").attr("id","linetrack_"+ae.dataset_id+"_minval").prependTo(ae.container_div),ah=$("<div/>").text(X(ae.prefs.max_value,3)).make_text_editable({num_cols:6,on_finish:function(al){$(".bs-tooltip").remove();var al=parseFloat(al);if(!isNaN(al)){ae.set_max_value(al)}},help_text:"Set max value"}).addClass("yaxislabel top").attr("id","linetrack_"+ae.dataset_id+"_maxval").prependTo(ae.container_div)})},draw_tile:function(an,al,ag,af,ai,am){var ae=al.canvas,ah=ai.get("start"),ak=ai.get("end"),aj=new L.LinePainter(an.data,ah,ak,this.prefs,ag);aj.draw(al,ae.width,ae.height,am);return new b(this,ai,af,ae,an.data)},can_subset:function(ae){return false}});var t=function(ag,af,ah){var ae=this;this.display_modes=["Heatmap"];this.mode="Heatmap";M.call(this,ag,af,ah);this.hda_ldda=ah.hda_ldda;this.dataset_id=ah.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"pos_color",label:"Positive Color",type:"color",default_value:"4169E1"},{key:"negative_color",label:"Negative Color",type:"color",default_value:"FF8C00"},{key:"min_value",label:"Min Value",type:"float",default_value:0},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}],saved_values:ah.prefs,onchange:function(){ae.set_name(ae.prefs.name);ae.vertical_range=ae.prefs.max_value-ae.prefs.min_value;ae.set_min_value(ae.prefs.min_value);ae.set_max_value(ae.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};q(t.prototype,r.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ae){this.prefs.min_value=ae;this.tile_cache.clear();this.request_draw()},set_max_value:function(ae){this.prefs.max_value=ae;this.tile_cache.clear();this.request_draw()},draw_tile:function(ao,am,aj,ah,af,an){var ag=am.canvas,ae=this._get_tile_bounds(af,ah),ai=ae[0],al=ae[1],ak=new L.DiagonalHeatmapPainter(ao.data,ai,al,this.prefs,aj);ak.draw(am,ag.width,ag.height,an);return new b(this,af,ah,ag,ao.data)}});var c=function(ah,ag,aj){var af=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];M.call(this,ah,ag,aj);var ai=Q(),ae=Q([ai,"#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:ai},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ae},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true,help:"Show the number of items in each bin when drawing summary histogram"},{key:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:this.visible_height_px,hidden:true}],saved_values:aj.prefs,onchange:function(){af.set_name(af.prefs.name);af.tile_cache.clear();af.set_painter_from_config();af.request_draw()}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");this.hda_ldda=aj.hda_ldda;this.dataset_id=aj.dataset_id;this.original_dataset_id=aj.dataset_id;this.show_labels_scale=0.001;this.showing_details=false;this.summary_draw_height=30;this.slotters={};this.start_end_dct={};this.left_offset=200;this.set_painter_from_config()};q(c.prototype,r.prototype,M.prototype,{set_dataset:function(ae){this.dataset_id=ae.get("id");this.hda_ldda=ae.get("hda_ldda");this.dataset=ae;this.data_manager.set("dataset",ae)},set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},before_draw:function(){this.max_height_px=0},postdraw_actions:function(au,ao,aj,ai){M.prototype.postdraw_actions.call(this,au,ai);var an=this,aq;if(an.mode==="Coverage"){var af=-1;for(aq=0;aq<au.length;aq++){var ap=au[aq].max_val;if(ap>af){af=ap}}for(aq=0;aq<au.length;aq++){var aw=au[aq];if(aw.max_val!==af){aw.html_elt.remove();an.draw_helper(true,ao,aw.index,aw.resolution,aw.html_elt.parent(),aj,{more_tile_data:{max:af}})}}}if(an.filters_manager){var ak=an.filters_manager.filters;for(var at=0;at<ak.length;at++){ak[at].update_ui_elt()}var av=false,ae,al;for(aq=0;aq<au.length;aq++){if(au[aq].data.length){ae=au[aq].data[0];for(var at=0;at<ak.length;at++){al=ak[at];if(al.applies_to(ae)&&al.min!==al.max){av=true;break}}}}if(an.filters_available!==av){an.filters_available=av;if(!an.filters_available){an.filters_manager.hide()}an.update_icons()}}this.container_div.find(".yaxislabel").remove();var ah=au[0];if(ah instanceof j){var am=(this.prefs.histogram_max?this.prefs.histogram_max:ah.max_val),ag=$("<div/>").text(am).make_text_editable({num_cols:12,on_finish:function(ax){$(".bs-tooltip").remove();var ax=parseFloat(ax);an.prefs.histogram_max=(!isNaN(ax)?ax:null);an.tile_cache.clear();an.request_draw()},help_text:"Set max value; leave blank to use default"}).addClass("yaxislabel top").css("color",this.prefs.label_color);this.container_div.prepend(ag)}if(ah instanceof O){var ar=true;for(aq=0;aq<au.length;aq++){if(!au[aq].all_slotted){ar=false;break}}if(!ar){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(ae){var ae;if(this.mode==="Auto"){if(ae==="no_detail"){ae="feature spans"}else{if(ae==="summary_tree"){ae="coverage histogram"}}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ae+")")}},incremental_slots:function(ai,ae,ah){var af=this.view.canvas_manager.dummy_context,ag=this.slotters[ai];if(!ag||(ag.mode!==ah)){ag=new (u.FeatureSlotter)(ai,ah,A,function(aj){return af.measureText(aj)});this.slotters[ai]=ag}return ag.slot_features(ae)},get_mode:function(ae){if(ae.dataset_type==="summary_tree"){mode="summary_tree"}else{if(ae.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(ae,ai,aj,af){if(ai==="summary_tree"||ai==="Coverage"){return this.summary_draw_height}else{var ah=this.incremental_slots(aj,ae.data,ai);var ag=new (this.painter)(null,null,null,this.prefs,ai);return Math.max(ab,ag.get_required_height(ah,af))}},draw_tile:function(ao,at,aq,au,ah,al,ag){var ar=this,af=at.canvas,aA=ah.get("start"),ae=ah.get("end"),ai=this.left_offset;if(aq==="summary_tree"||aq==="Coverage"){var aC=new L.SummaryTreePainter(ao,aA,ae,this.prefs);aC.draw(at,af.width,af.height,al);return new j(ar,ah,au,af,ao.data,ao.max)}var ak=[],ap=this.slotters[al].slots;all_slotted=true;if(ao.data){var am=this.filters_manager.filters;for(var av=0,ax=ao.data.length;av<ax;av++){var aj=ao.data[av];var aw=false;var an;for(var az=0,aE=am.length;az<aE;az++){an=am[az];an.update_attrs(aj);if(!an.keep(aj)){aw=true;break}}if(!aw){ak.push(aj);if(!(aj[0] in ap)){all_slotted=false}}}}var aD=(this.filters_manager.alpha_filter?new C(this.filters_manager.alpha_filter):null);var aB=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null);var aC=new (this.painter)(ak,aA,ae,this.prefs,aq,aD,aB,ag);var ay=null;at.fillStyle=this.prefs.block_color;at.font=at.canvas.manager.default_font;at.textAlign="right";if(ao.data){ay=aC.draw(at,af.width,af.height,al,ap);ay.translation=-ai}return new O(ar,ah,au,af,ao.data,al,aq,ao.message,all_slotted,ay)},data_and_mode_compatible:function(ae,af){if(af==="Auto"){return true}else{if(af==="Coverage"){return ae.dataset_type==="summary_tree"}else{if(ae.extra_info==="no_detail"||ae.dataset_type==="summary_tree"){return false}else{return true}}}},can_subset:function(ae){if(ae.dataset_type==="summary_tree"||ae.message||ae.extra_info==="no_detail"){return false}return true}});var S=function(af,ae,ag){c.call(this,af,ae,ag);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:Q()},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter};q(S.prototype,r.prototype,M.prototype,c.prototype);var U=function(ag,af,ai){c.call(this,ag,af,ai);var ah=Q(),ae=Q([ah,"#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:ah},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ae},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"Clear value to set automatically"},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ai.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter;this.update_icons()};q(U.prototype,r.prototype,M.prototype,c.prototype);var d={LineTrack:h,FeatureTrack:c,VcfTrack:S,ReadTrack:U,CompositeTrack:f,DrawableGroup:P};var p=function(ag,af,ae){if("copy" in ag){return ag.copy(ae)}else{var ah=ag.obj_type;if(!ah){ah=ag.track_type}return new d[ah](af,ae,ag)}};return{View:Z,DrawableGroup:P,LineTrack:h,FeatureTrack:c,DiagonalHeatmapTrack:t,ReadTrack:U,VcfTrack:S,CompositeTrack:f,object_from_template:p,add_datasets:ad}});
\ No newline at end of file
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b static/scripts/packed/viz/visualization.js
--- a/static/scripts/packed/viz/visualization.js
+++ b/static/scripts/packed/viz/visualization.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","mvc/data","viz/trackster/util"],function(q,h,j){var i=function(s){return("isResolved" in s)};var e=function(s){this.default_font=s!==undefined?s:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};q.extend(e.prototype,{load_pattern:function(s,w){var t=this.patterns,u=this.dummy_context,v=new Image();v.src=galaxy_paths.attributes.image_path+w;v.onload=function(){t[s]=u.createPattern(v,"repeat")}},get_pattern:function(s){return this.patterns[s]},new_canvas:function(){var s=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(s)}s.manager=this;return s}});var o=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(s){this.clear()},get_elt:function(t){var u=this.attributes.obj_cache,v=this.attributes.key_ary,s=v.indexOf(t);if(s!==-1){if(u[t].stale){v.splice(s,1);delete u[t]}else{this.move_key_to_end(t,s)}}return u[t]},set_elt:function(t,v){var w=this.attributes.obj_cache,x=this.attributes.key_ary,u=this.attributes.num_elements;if(!w[t]){if(x.length>=u){var s=x.shift();delete w[s]}x.push(t)}w[t]=v;return v},move_key_to_end:function(t,s){this.attributes.key_ary.splice(s,1);this.attributes.key_ary.push(t)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length}});var c=o.extend({defaults:q.extend({},o.prototype.defaults,{dataset:null,filters_manager:null,data_type:"data",data_mode_compatible:function(s,t){return true},can_subset:function(s){return false}}),data_is_ready:function(){var u=this.get("dataset"),t=$.Deferred(),s=new j.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:u.get("hda_ldda"),data_type:"state"},dataType:"json"},interval:5000,success_fn:function(v){return v!=="pending"}});$.when(s.go()).then(function(v){t.resolve(v==="ok"||v==="data")});return t},search_features:function(s){var t=this.get("dataset"),u={query:s,hda_ldda:t.get("hda_ldda"),data_type:"features"};return $.getJSON(t.url(),u)},load_data:function(A,z,t,y){var w=this.get("dataset"),v={data_type:this.get("data_type"),chrom:A.get("chrom"),low:A.get("start"),high:A.get("end"),mode:z,resolution:t,hda_ldda:w.get("hda_ldda")};$.extend(v,y);var C=this.get("filters_manager");if(C){var D=[];var s=C.filters;for(var x=0;x<s.length;x++){D.push(s[x].name)}v.filter_cols=JSON.stringify(D)}var u=this,B=$.getJSON(w.url(),v,function(E){u.set_data(A,E)});this.set_data(A,B);return B},get_data:function(y,x,u,w){var z=this.get_elt(y);if(z&&(i(z)||this.get("data_mode_compatible")(z,x))){return z}var A=this.get("key_ary"),t=this.get("obj_cache"),B,s;for(var v=0;v<A.length;v++){B=A[v];s=new f({from_str:B});if(s.contains(y)){z=t[B];if(i(z)||(this.get("data_mode_compatible")(z,x)&&this.get("can_subset")(z))){this.move_key_to_end(B,v);return z}}}return this.load_data(y,x,u,w)},set_data:function(t,s){this.set_elt(t,s)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(A,z,v,y,w){var C=this._mark_stale(A);if(!(C&&this.get("data_mode_compatible")(C,z))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var u=A.get("start");if(w===this.DEEP_DATA_REQ){$.extend(y,{start_val:C.data.length+1})}else{if(w===this.BROAD_DATA_REQ){u=(C.max_high?C.max_high:C.data[C.data.length-1][2])+1}}var B=A.copy().set("start",u);var t=this,x=this.load_data(B,z,v,y),s=$.Deferred();this.set_data(A,s);$.when(x).then(function(D){if(D.data){D.data=C.data.concat(D.data);if(D.max_low){D.max_low=C.max_low}if(D.message){D.message=D.message.replace(/[0-9]+/,D.data.length)}}t.set_data(A,D);s.resolve(D)});return s},get_more_detailed_data:function(v,x,t,w,u){var s=this._mark_stale(v);if(!s){console.log("ERROR getting more detailed data: no current data");return}if(!u){u={}}var x;if(s.dataset_type==="bigwig"){u.num_samples=s.data.length*w}else{if(s.dataset_type==="summary_tree"){u.level=Math.min(s.level-1,2)}}return this.load_data(v,x,t,u)},_mark_stale:function(t){var s=this.get_elt(t);if(!s){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),t.toString())}s.stale=true;return s},get_elt:function(s){return o.prototype.get_elt.call(this,s.toString())},set_elt:function(t,s){return o.prototype.set_elt.call(this,t.toString(),s)}});var m=c.extend({initialize:function(s){var t=new Backbone.Model();t.urlRoot=s.data_url;this.set("dataset",t)},load_data:function(u,v,s,t){console.log(u,v,s);if(s>1){return{data:null}}return c.prototype.load_data.call(this,u,v,s,t)}});var b=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(s){this.id=s.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(s){var t=q.find(this.get_chroms_info(),function(u){return u.chrom==s});return new f({chrom:t.chrom,end:t.len})}});var f=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0,DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006},initialize:function(t){if(t.from_str){var v=t.from_str.split(":"),u=v[0],s=v[1].split("-");this.set({chrom:u,start:parseInt(s[0],10),end:parseInt(s[1],10)})}},copy:function(){return new f({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(z){var t=this.get("chrom"),y=z.get("chrom"),x=this.get("start"),v=z.get("start"),w=this.get("end"),u=z.get("end"),s;if(t&&y&&t!==y){return this.get("DIF_CHROMS")}if(x<v){if(w<v){s=this.get("BEFORE")}else{if(w<=u){s=this.get("OVERLAP_START")}else{s=this.get("CONTAINS")}}}else{if(x>u){s=this.get("AFTER")}else{if(w<=u){s=this.get("CONTAINED_BY")}else{s=this.get("OVERLAP_END")}}}return s},contains:function(s){return this.compute_overlap(s)===this.get("CONTAINS")},overlaps:function(s){return q.intersection([this.compute_overlap(s)],[this.get("DIF_CHROMS"),this.get("BEFORE"),this.get("AFTER")]).length===0}});var l=Backbone.Collection.extend({model:f});var d=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:f}]});var p=Backbone.Collection.extend({model:d});var r=h.Dataset.extend({initialize:function(s){this.set("id",s.dataset_id);var t=new c({dataset:this});this.set("data_manager",t);var u=this.get("preloaded_data");if(u){t.set("num_elements",u.data.length);q.each(u.data,function(v){t.set_data(v.region,v)})}},get_genome_wide_data:function(s){var t=this.get("data_manager");return q.map(s.get("chroms_info").chrom_info,function(u){return t.get_elt(new f({chrom:u.chrom,start:0,end:u.len}))})}});var n=Backbone.RelationalModel.extend({defaults:{id:"",title:"",type:"",dbkey:"",tracks:null},relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:r}],url:function(){return galaxy_paths.get("visualization_url")},save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var k=n.extend({defaults:q.extend({},n.prototype.defaults,{bookmarks:null,viewport:null})});var a=Backbone.Model.extend({});var g=Backbone.Router.extend({initialize:function(t){this.view=t.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var s=this;s.view.on("navigate",function(u){s.navigate(u)})},change_location:function(s){this.view.go_to(s)}});return{BrowserBookmark:d,BrowserBookmarkCollection:p,Cache:o,CanvasManager:e,Genome:b,GenomeDataManager:c,GenomeRegion:f,GenomeRegionCollection:l,GenomeVisualization:k,ReferenceTrackDataManager:m,TrackBrowserRouter:g,TrackConfig:a,Visualization:n}});
\ No newline at end of file
+define(["libs/underscore","mvc/data","viz/trackster/util"],function(q,h,j){var i=function(s){return("isResolved" in s)};var e=function(s){this.default_font=s!==undefined?s:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};q.extend(e.prototype,{load_pattern:function(s,w){var t=this.patterns,u=this.dummy_context,v=new Image();v.src=galaxy_paths.attributes.image_path+w;v.onload=function(){t[s]=u.createPattern(v,"repeat")}},get_pattern:function(s){return this.patterns[s]},new_canvas:function(){var s=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(s)}s.manager=this;return s}});var o=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(s){this.clear()},get_elt:function(t){var u=this.attributes.obj_cache,v=this.attributes.key_ary,s=v.indexOf(t);if(s!==-1){if(u[t].stale){v.splice(s,1);delete u[t]}else{this.move_key_to_end(t,s)}}return u[t]},set_elt:function(t,v){var w=this.attributes.obj_cache,x=this.attributes.key_ary,u=this.attributes.num_elements;if(!w[t]){if(x.length>=u){var s=x.shift();delete w[s]}x.push(t)}w[t]=v;return v},move_key_to_end:function(t,s){this.attributes.key_ary.splice(s,1);this.attributes.key_ary.push(t)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length}});var c=o.extend({defaults:q.extend({},o.prototype.defaults,{dataset:null,filters_manager:null,data_type:"data",data_mode_compatible:function(s,t){return true},can_subset:function(s){return false}}),data_is_ready:function(){var u=this.get("dataset"),t=$.Deferred(),s=new j.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:u.get("hda_ldda"),data_type:"state"},dataType:"json"},interval:5000,success_fn:function(v){return v!=="pending"}});$.when(s.go()).then(function(v){t.resolve(v==="ok"||v==="data")});return t},search_features:function(s){var t=this.get("dataset"),u={query:s,hda_ldda:t.get("hda_ldda"),data_type:"features"};return $.getJSON(t.url(),u)},load_data:function(A,z,t,y){var w=this.get("dataset"),v={data_type:this.get("data_type"),chrom:A.get("chrom"),low:A.get("start"),high:A.get("end"),mode:z,resolution:t,hda_ldda:w.get("hda_ldda")};$.extend(v,y);var C=this.get("filters_manager");if(C){var D=[];var s=C.filters;for(var x=0;x<s.length;x++){D.push(s[x].name)}v.filter_cols=JSON.stringify(D)}var u=this,B=$.getJSON(w.url(),v,function(E){u.set_data(A,E)});this.set_data(A,B);return B},get_data:function(y,x,u,w){var z=this.get_elt(y);if(z&&(i(z)||this.get("data_mode_compatible")(z,x))){return z}var A=this.get("key_ary"),t=this.get("obj_cache"),B,s;for(var v=0;v<A.length;v++){B=A[v];s=new f({from_str:B});if(s.contains(y)){z=t[B];if(i(z)||(this.get("data_mode_compatible")(z,x)&&this.get("can_subset")(z))){this.move_key_to_end(B,v);return z}}}return this.load_data(y,x,u,w)},set_data:function(t,s){this.set_elt(t,s)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(A,z,v,y,w){var C=this._mark_stale(A);if(!(C&&this.get("data_mode_compatible")(C,z))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var u=A.get("start");if(w===this.DEEP_DATA_REQ){$.extend(y,{start_val:C.data.length+1})}else{if(w===this.BROAD_DATA_REQ){u=(C.max_high?C.max_high:C.data[C.data.length-1][2])+1}}var B=A.copy().set("start",u);var t=this,x=this.load_data(B,z,v,y),s=$.Deferred();this.set_data(A,s);$.when(x).then(function(D){if(D.data){D.data=C.data.concat(D.data);if(D.max_low){D.max_low=C.max_low}if(D.message){D.message=D.message.replace(/[0-9]+/,D.data.length)}}t.set_data(A,D);s.resolve(D)});return s},get_more_detailed_data:function(v,x,t,w,u){var s=this._mark_stale(v);if(!s){console.log("ERROR getting more detailed data: no current data");return}if(!u){u={}}if(s.dataset_type==="bigwig"){u.num_samples=s.data.length*w}else{if(s.dataset_type==="summary_tree"){u.level=Math.min(s.level-1,2)}}return this.load_data(v,x,t,u)},_mark_stale:function(t){var s=this.get_elt(t);if(!s){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),t.toString())}s.stale=true;return s},get_elt:function(s){return o.prototype.get_elt.call(this,s.toString())},set_elt:function(t,s){return o.prototype.set_elt.call(this,t.toString(),s)}});var m=c.extend({initialize:function(s){var t=new Backbone.Model();t.urlRoot=s.data_url;this.set("dataset",t)},load_data:function(u,v,s,t){console.log(u,v,s);if(s>1){return{data:null}}return c.prototype.load_data.call(this,u,v,s,t)}});var b=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(s){this.id=s.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(s){var t=q.find(this.get_chroms_info(),function(u){return u.chrom==s});return new f({chrom:t.chrom,end:t.len})}});var f=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0,DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006},initialize:function(t){if(t.from_str){var v=t.from_str.split(":"),u=v[0],s=v[1].split("-");this.set({chrom:u,start:parseInt(s[0],10),end:parseInt(s[1],10)})}},copy:function(){return new f({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(z){var t=this.get("chrom"),y=z.get("chrom"),x=this.get("start"),v=z.get("start"),w=this.get("end"),u=z.get("end"),s;if(t&&y&&t!==y){return this.get("DIF_CHROMS")}if(x<v){if(w<v){s=this.get("BEFORE")}else{if(w<=u){s=this.get("OVERLAP_START")}else{s=this.get("CONTAINS")}}}else{if(x>u){s=this.get("AFTER")}else{if(w<=u){s=this.get("CONTAINED_BY")}else{s=this.get("OVERLAP_END")}}}return s},contains:function(s){return this.compute_overlap(s)===this.get("CONTAINS")},overlaps:function(s){return q.intersection([this.compute_overlap(s)],[this.get("DIF_CHROMS"),this.get("BEFORE"),this.get("AFTER")]).length===0}});var l=Backbone.Collection.extend({model:f});var d=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:f}]});var p=Backbone.Collection.extend({model:d});var r=h.Dataset.extend({initialize:function(s){this.set("id",s.dataset_id);var t=new c({dataset:this});this.set("data_manager",t);var u=this.get("preloaded_data");if(u){t.set("num_elements",u.data.length);q.each(u.data,function(v){t.set_data(v.region,v)})}},get_genome_wide_data:function(s){var t=this.get("data_manager");return q.map(s.get("chroms_info").chrom_info,function(u){return t.get_elt(new f({chrom:u.chrom,start:0,end:u.len}))})}});var n=Backbone.RelationalModel.extend({defaults:{title:"",type:""},url:function(){return galaxy_paths.get("visualization_url")},save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var k=n.extend({defaults:q.extend({},n.prototype.defaults,{dbkey:"",tracks:null,bookmarks:null,viewport:null}),relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:r}],add_track:function(s){this.get("tracks").push(s)}});var a=Backbone.Model.extend({});var g=Backbone.Router.extend({initialize:function(t){this.view=t.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var s=this;s.view.on("navigate",function(u){s.navigate(u)})},change_location:function(s){this.view.go_to(s)}});return{BackboneTrack:r,BrowserBookmark:d,BrowserBookmarkCollection:p,Cache:o,CanvasManager:e,Genome:b,GenomeDataManager:c,GenomeRegion:f,GenomeRegionCollection:l,GenomeVisualization:k,ReferenceTrackDataManager:m,TrackBrowserRouter:g,TrackConfig:a,Visualization:n}});
\ No newline at end of file
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b static/scripts/templates/compiled/template-visualization-chartSettings.js
--- /dev/null
+++ b/static/scripts/templates/compiled/template-visualization-chartSettings.js
@@ -0,0 +1,42 @@
+(function() {
+ var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
+templates['template-visualization-chartSettings'] = template(function (Handlebars,depth0,helpers,partials,data) {
+ helpers = helpers || Handlebars.helpers;
+ var buffer = "", stack1, foundHelper, functionType="function", escapeExpression=this.escapeExpression, self=this;
+
+function program1(depth0,data) {
+
+
+ return "checked";}
+
+ buffer += "<p class=\"help-text\">\n Use the following controls to how the chart is displayed.\n The slide controls can be moved by the mouse or, if the 'handle' is in focus, your keyboard's arrow keys.\n Move the focus between controls by using the tab or shift+tab keys on your keyboard.\n Use the 'Draw' button to render (or re-render) the chart with the current settings.\n </p>\n \n <div id=\"maxDataPoints\" class=\"form-input numeric-slider-input\">\n <label for=\"maxDataPoints\">Maximum data points allowed on graph: </label>\n <div class=\"slider-output\">";
+ foundHelper = helpers.maxDataPoints;
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
+ else { stack1 = depth0.maxDataPoints; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
+ buffer += escapeExpression(stack1) + "</div>\n <div class=\"slider\"></div>\n <p class=\"form-help help-text-small\">\n Change the maximum number of data points displayable on this graph (higher values will\n load significantly slower)\n </p>\n </div>\n\n <div id=\"datapointSize\" class=\"form-input numeric-slider-input\">\n <label for=\"datapointSize\">Size of data point: </label>\n <div class=\"slider-output\">";
+ foundHelper = helpers.datapointSize;
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
+ else { stack1 = depth0.datapointSize; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
+ buffer += escapeExpression(stack1) + "</div>\n <div class=\"slider\"></div>\n <p class=\"form-help help-text-small\">\n Size of the graphic representation of each data point\n </p>\n </div>\n\n <div id=\"entryAnimDuration\" class=\"form-input checkbox-input\">\n <label for=\"animated\">Animate graph transitions?: </label>\n <input type=\"checkbox\" id=\"animated\" class=\"checkbox control\" value=\"";
+ stack1 = depth0.entryAnimDuration;
+ stack1 = helpers['if'].call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(1, program1, data)});
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\" />\n <p class=\"form-help help-text-small\">\n Uncheck this to disable the animations used on the graph\n </p>\n </div>\n\n <div id=\"width\" class=\"form-input numeric-slider-input\">\n <label for=\"width\">Graph width: </label>\n <div class=\"slider-output\">";
+ foundHelper = helpers.width;
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
+ else { stack1 = depth0.width; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
+ buffer += escapeExpression(stack1) + "</div>\n <div class=\"slider\"></div>\n <p class=\"form-help help-text-small\">\n (not including graph margins and axes)\n </p>\n </div>\n\n <div id=\"height\" class=\"form-input numeric-slider-input\">\n <label for=\"height\">Graph height: </label>\n <div class=\"slider-output\">";
+ foundHelper = helpers.height;
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
+ else { stack1 = depth0.height; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
+ buffer += escapeExpression(stack1) + "</div>\n <div class=\"slider\"></div>\n <p class=\"form-help help-text-small\">\n (not including graph margins and axes)\n </p>\n </div>\n\n <div id=\"X-axis-label\"class=\"text-input form-input\">\n <label for=\"X-axis-label\">Re-label the X axis: </label>\n <input type=\"text\" name=\"X-axis-label\" id=\"X-axis-label\" value=\"";
+ foundHelper = helpers.xLabel;
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
+ else { stack1 = depth0.xLabel; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
+ buffer += escapeExpression(stack1) + "\" />\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=\"";
+ foundHelper = helpers.yLabel;
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
+ else { stack1 = depth0.yLabel; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
+ buffer += escapeExpression(stack1) + "\" />\n <p class=\"form-help help-text-small\"></p>\n </div>\n\n <input id=\"render-button\" type=\"button\" value=\"Draw\" />";
+ return buffer;});
+})();
\ No newline at end of file
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b static/scripts/templates/compiled/template-visualization-scatterplotControlForm.js
--- a/static/scripts/templates/compiled/template-visualization-scatterplotControlForm.js
+++ b/static/scripts/templates/compiled/template-visualization-scatterplotControlForm.js
@@ -32,20 +32,45 @@
buffer += escapeExpression(stack1) + "</option>\n ";
return buffer;}
+function program5(depth0,data) {
+
+ var buffer = "", stack1, foundHelper;
+ buffer += "\n <option value=\"";
+ foundHelper = helpers.index;
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
+ else { stack1 = depth0.index; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
+ buffer += escapeExpression(stack1) + "\">";
+ foundHelper = helpers.name;
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
+ else { stack1 = depth0.name; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
+ buffer += escapeExpression(stack1) + "</option>\n ";
+ return buffer;}
+
+ buffer += "\n\n<ul class=\"nav nav-tabs\">\n <li class=\"active\">\n <a data-toggle=\"tab\" href=\"#data-settings\">Data Controls</a>\n </li>\n <li><a data-toggle=\"tab\" href=\"#chart-settings\">Plot Controls</a></li>\n <li><a data-toggle=\"tab\" href=\"#chart-stats\">Statistics</a></li>\n</ul>\n\n";
+ buffer += "\n<div class=\"tab-content\">\n<div id=\"data-settings\" class=\"tab-pane active\">\n\n <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 ";
+ buffer += "\n <div class=\"column-select\">\n <label for=\"X-select\">Data column for X: </label>\n <select name=\"X\" id=\"X-select\">\n ";
+ stack1 = depth0.numericColumns;
+ stack1 = helpers.each.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(1, program1, data)});
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\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 ";
+ stack1 = depth0.numericColumns;
+ stack1 = helpers.each.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(3, program3, data)});
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n </select>\n </div>\n \n ";
+ buffer += "\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 ";
+ stack1 = depth0.allColumns;
+ stack1 = helpers.each.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(5, program5, data)});
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n </select>\n </div>\n \n <input id=\"render-button\" type=\"button\" value=\"Draw\" />\n <input id=\"save-button\" type=\"button\" value=\"Download Plot as SVG\" style=\"display: none;\" />\n <div class=\"clear\"></div>\n</div>\n\n<div id=\"chart-settings\" class=\"tab-pane\">\n</div>\n\n<div id=\"chart-stats\" class=\"tab-pane\">\n</div>\n</div>";
+ buffer += "\n\n";
buffer += "\n<div id=\"loading-indicator\" style=\"display: none;\">\n <img class=\"loading-img\" src=\"";
foundHelper = helpers.loadingIndicatorImagePath;
if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
else { stack1 = depth0.loadingIndicatorImagePath; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
- buffer += escapeExpression(stack1) + "\" />\n <span class=\"loading-message\"></span>\n</div>\n\n";
- buffer += "\n<div id=\"chart-settings\">\n\n ";
- buffer += "\n <div id=\"x-column-input\">\n <label for=\"\">Data column for X: </label>\n <select name=\"x-column\">\n ";
- stack1 = depth0.availableColumns;
- stack1 = helpers.each.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(1, program1, data)});
- if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\n </select>\n </div>\n <div id=\"y-column-input\">\n <label for=\"\">Data column for Y: </label>\n <select name=\"y-column\">\n ";
- stack1 = depth0.availableColumns;
- stack1 = helpers.each.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(3, program3, data)});
- if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\n </select>\n </div>\n \n <input id=\"render-button\" type=\"button\" value=\"Draw\" />\n <div class=\"clear\"></div>\n</div>";
+ buffer += escapeExpression(stack1) + "\" />\n <span class=\"loading-message\">";
+ foundHelper = helpers.message;
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
+ else { stack1 = depth0.message; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
+ buffer += escapeExpression(stack1) + "</span>\n</div>";
return buffer;});
})();
\ No newline at end of file
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b static/scripts/templates/compiled/template-visualization-statsTable.js
--- /dev/null
+++ b/static/scripts/templates/compiled/template-visualization-statsTable.js
@@ -0,0 +1,31 @@
+(function() {
+ var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
+templates['template-visualization-statsTable'] = template(function (Handlebars,depth0,helpers,partials,data) {
+ helpers = helpers || Handlebars.helpers;
+ var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression, self=this;
+
+function program1(depth0,data) {
+
+ var buffer = "", stack1, foundHelper;
+ buffer += "\n <tr><td>";
+ foundHelper = helpers.name;
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
+ else { stack1 = depth0.name; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
+ buffer += escapeExpression(stack1) + "</td><td>";
+ foundHelper = helpers.xval;
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
+ else { stack1 = depth0.xval; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
+ buffer += escapeExpression(stack1) + "</td><td>";
+ foundHelper = helpers.yval;
+ if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
+ else { stack1 = depth0.yval; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
+ buffer += escapeExpression(stack1) + "</td></tr>\n </tr>\n ";
+ return buffer;}
+
+ buffer += "<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 ";
+ stack1 = depth0.stats;
+ stack1 = helpers.each.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(1, program1, data)});
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n </table>";
+ return buffer;});
+})();
\ No newline at end of file
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b static/scripts/templates/visualization-templates.html
--- a/static/scripts/templates/visualization-templates.html
+++ b/static/scripts/templates/visualization-templates.html
@@ -1,33 +1,155 @@
<script type="text/template" class="template-visualization" id="template-visualization-scatterplotControlForm">
+{{! main controls }}
-{{! loading indicator - initially hidden }}
-<div id="loading-indicator" style="display: none;">
- <img class="loading-img" src="{{loadingIndicatorImagePath}}" />
- <span class="loading-message"></span>
-</div>
+<ul class="nav nav-tabs">
+ <li class="active">
+ <a data-toggle="tab" href="#data-settings">Data Controls</a>
+ </li>
+ <li><a data-toggle="tab" href="#chart-settings">Plot Controls</a></li>
+ <li><a data-toggle="tab" href="#chart-stats">Statistics</a></li>
+</ul>
-{{! main controls }}
-<div id="chart-settings">
+{{! data settings }}
+<div class="tab-content">
+<div id="data-settings" class="tab-pane active">
+ <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 id="x-column-input">
- <label for="">Data column for X: </label>
- <select name="x-column">
- {{#each availableColumns}}
+ <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 id="y-column-input">
- <label for="">Data column for Y: </label>
- <select name="y-column">
- {{#each availableColumns}}
+ <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><input id="render-button" type="button" value="Draw" />
+ <input id="save-button" type="button" value="Download Plot as SVG" style="display: none;" /><div class="clear"></div></div>
+
+<div id="chart-settings" class="tab-pane">
+</div>
+
+<div id="chart-stats" class="tab-pane">
+</div>
+</div>{{! class="tab-content" }}
+
+{{! loading indicator - initially hidden }}
+<div id="loading-indicator" style="display: none;">
+ <img class="loading-img" src="{{loadingIndicatorImagePath}}" />
+ <span class="loading-message">{{message}}</span>
+</div>
+
</script>
+
+<script type="text/template" class="template-visualization" id="template-visualization-statsTable">
+ <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-chartSettings">
+
+ <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="maxDataPoints" class="form-input numeric-slider-input">
+ <label for="maxDataPoints">Maximum data points allowed on graph: </label>
+ <div class="slider-output">{{maxDataPoints}}</div>
+ <div class="slider"></div>
+ <p class="form-help help-text-small">
+ Change the maximum number of data points displayable on this graph (higher values will
+ load significantly slower)
+ </p>
+ </div>
+
+ <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="entryAnimDuration" class="form-input checkbox-input">
+ <label for="animated">Animate graph transitions?: </label>
+ <input type="checkbox" id="animated" class="checkbox control" value="{{#if entryAnimDuration}}checked{{/if}}" />
+ <p class="form-help help-text-small">
+ Uncheck this to disable the animations used on the graph
+ </p>
+ </div>
+
+ <div id="width" class="form-input numeric-slider-input">
+ <label for="width">Graph width: </label>
+ <div class="slider-output">{{width}}</div>
+ <div class="slider"></div>
+ <p class="form-help help-text-small">
+ (not including graph margins and axes)
+ </p>
+ </div>
+
+ <div id="height" class="form-input numeric-slider-input">
+ <label for="height">Graph height: </label>
+ <div class="slider-output">{{height}}</div>
+ <div class="slider"></div>
+ <p class="form-help help-text-small">
+ (not including graph 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>
\ No newline at end of file
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b static/scripts/viz/scatterplot.js
--- a/static/scripts/viz/scatterplot.js
+++ b/static/scripts/viz/scatterplot.js
@@ -1,54 +1,66 @@
define([
+ //"../libs/jquery/jquery",
+
"../libs/underscore",
+ "../mvc/base-mvc",
+ "../templates/compiled/template-visualization-scatterplotControlForm",
+ "../templates/compiled/template-visualization-statsTable",
+ "../templates/compiled/template-visualization-chartSettings",
+
"../libs/d3",
- "../mvc/base-mvc",
- "../templates/compiled/template-visualization-scatterplotControlForm"
+ "../libs/bootstrap",
+ "../libs/jquery/jquery-ui-1.8.23.custom.min"
], function(){
+
+
+
/* =============================================================================
todo:
outside this:
BUG: visualization menu doesn't disappear
- BUG?: get column_names (from datatype if necessary)
+ BUG?: get metadata_column_names (from datatype if necessary)
BUG: single vis in popupmenu should have tooltip with that name NOT 'Visualizations'
- ??: maybe better to do this with a canvas...
+ wire label setters, anim setter
- move renderScatter plot to obj, possibly view?
+ 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)
- fix x axis - adjust ticks when tick labels are long - move odds down and extend tick line
-
- 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
+ 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.)
- multiple plots on one page (small multiples)
-
- where are bad dataprovider params handled? api/datasets?
+ 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)
- config changes to the graph
- render stats on the data (max, min, count)
- render warning on long data (> maxDataPoints)
- adjust endpoint
-
- loading indicator
-
- download svg -> base64 encode
- dress up ui
-
- incorporate glyphs, glyph state renderers
-
- validate columns selection (here or server)
-
- ?? ensure svg styles thru d3 or css?
- d3: configable (easily)
- css: standard - better maintenance
- ? override at config
+ 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
============================================================================= */
/**
@@ -61,8 +73,7 @@
* depends on: d3, underscore
*/
function TwoVarScatterplot( config ){
- var plot = this,
- TICK_LINE_AND_PADDING = 10,
+ var TICK_LINE_AND_PADDING = 10,
GUESS_AT_SVG_CHAR_WIDTH = 7,
GUESS_AT_SVG_CHAR_HEIGHT = 10,
PADDING = 8,
@@ -73,7 +84,7 @@
if( this.debugging && console && console.debug ){
var args = Array.prototype.slice.call( arguments );
args.unshift( this.toString() );
- console.debug.apply( null, args );
+ console.debug.apply( console, args );
}
};
this.log( 'new TwoVarScatterplot:', config );
@@ -84,10 +95,10 @@
this.defaults = {
id : 'TwoVarScatterplot',
containerSelector : 'body',
- maxDataPoints : 30000,
- bubbleRadius : 4,
+ maxDataPoints : 10000,
+ datapointSize : 4,
entryAnimDuration : 500,
- //TODO: no effect?
+ //TODO: variable effect (not always exactly # of ticks set to)
xNumTicks : 10,
yNumTicks : 10,
xAxisLabelBumpY : 40,
@@ -99,10 +110,12 @@
marginRight : 50,
marginBottom : 50,
marginLeft : 50,
+
xMin : null,
xMax : null,
yMin : null,
yMax : null,
+
xLabel : "X",
yLabel : "Y"
};
@@ -126,8 +139,9 @@
// ........................................................ initial element creation
//NOTE: called on new
this.svg = d3.select( this.config.containerSelector )
- .append( "svg:svg" ).attr( "class", "chart" ).style( 'display', 'none' );
- this.content = this.svg.append( "svg:g" ).attr( "class", "content" );
+ .append( "svg:svg" ).attr( "class", "chart" );
+
+ this.content = this.svg.append( "svg:g" ).attr( "class", "content" ).attr( 'id', this.config.id );
this.xAxis = this.content.append( 'g' ).attr( 'class', 'axis' ).attr( 'id', 'x-axis' );
this.xAxisLabel = this.xAxis.append( 'text' ).attr( 'class', 'axis-label' ).attr( 'id', 'x-axis-label' );
@@ -157,7 +171,9 @@
};
// ........................................................ data and scales
- this.preprocessData = function( data ){
+ this.preprocessData = function( data, min, max ){
+ //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 );
};
@@ -313,63 +329,110 @@
};
- this.renderDatapoints = function( xCol, yCol ){
+ this.renderDatapoints = function( xCol, yCol, ids ){
+ // initial render, complete re-render (REPLACE datapoints)
- var xPosFn = function( d, i ){
- return plot.xScale( xCol[ i ] );
- };
- var yPosFn = function( d, i ){
- return plot.yScale( yCol[ i ] );
- };
-
- // select all existing glyphs and compare to incoming data
- // enter() will yield those glyphs that need to be added
- // exit() will yield existing glyphs that need to be removed
- this.datapoints = this.content.selectAll( ".glyph" )
- .data( xCol );
-
- // enter - new data to be added as glyphs: give them a 'entry' position and style
- this.datapoints.enter()
- .append( "svg:circle" ).attr( "class", "glyph" )
- // start all bubbles at corner...
- .attr( "cx", xPosFn )
- .attr( "cy", 0 )
- .attr( "r", 0 );
-
- // for all existing glyphs and those that need to be added: transition anim to final state
- this.datapoints
- // ...animate to final position
- .transition().duration( this.config.entryAnimDuration )
- .attr( "cx", xPosFn )
- .attr( "cy", yPosFn )
- .attr( "r", this.config.bubbleRadius );
+ this.datapoints = this.addDatapoints( xCol, yCol, ids, ".glyph" );
// glyphs that need to be removed: transition to from normal state to 'exit' state, remove from DOM
this.datapoints.exit()
.transition().duration( this.config.entryAnimDuration )
.attr( "cy", this.config.height )
.attr( "r", 0 )
- .style( "fill-opacity", 0 )
.remove();
- //this.log( this.datapoints, 'glyphs rendered' );
+ this.log( this.datapoints, 'glyphs rendered' );
+ };
+
+ this.addDatapoints = function( newXCol, newYCol, ids, selectorForExisting ){
+ // ADD datapoints to plot that's already rendered
+ // if selectorForExisting === undefined (as in not passed), addDatapoints won't update existing
+ // pass in the class ( '.glyph' ) to update exising datapoints
+ var plot = this,
+ xPosFn = function( d, i ){
+ return plot.xScale( newXCol[ i ] );
+ },
+ yPosFn = function( d, i ){
+ return plot.yScale( newYCol[ i ] );
+ };
+
+ // select all existing glyphs and compare to incoming data
+ // enter() will yield those glyphs that need to be added
+ var newDatapoints = this.content.selectAll( selectorForExisting ).data( newXCol );
+
+ // enter - new data to be added as glyphs: give them a 'entry' position and style
+ newDatapoints.enter()
+ .append( "svg:circle" )
+ .classed( "glyph", true )
+ // start all bubbles small...
+ .attr( "cx", xPosFn )
+ .attr( "cy", yPosFn )
+ .attr( "r", 0 );
+
+ // for all existing glyphs and those that need to be added: transition anim to final state
+ newDatapoints
+ // ...animate to final position
+ .transition().duration( this.config.entryAnimDuration )
+ .attr( "r", this.config.datapointSize );
+
+ // attach ids
+ if( ids ){
+ newDatapoints.attr( 'data', function( d, i ){ return ( ids[ i ] ); } );
+ }
+
+ // titles
+ newDatapoints.attr( 'title', function( d, i ){
+ return (( ids )?( ids[ i ] + ': ' ):( '' )) + newXCol[ i ] + ', ' + newYCol[ i ];
+ });
+
+ // events
+ newDatapoints
+ //TODO: remove magic numbers
+ .on( 'mouseover', function(){
+ 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 )
+ .attr( 'x1', datapoint.attr( 'cx' ) ).attr( 'y1', datapoint.attr( 'cy' ) )
+ .attr( 'x2', 0 ).attr( 'y2', datapoint.attr( 'cy' ) )
+ .classed( 'hoverline', true );
+ plot.content.append( 'line' )
+ .attr( 'stroke', 'red' )
+ .attr( 'stroke-width', 1 )
+ .attr( 'x1', datapoint.attr( 'cx' ) ).attr( 'y1', datapoint.attr( 'cy' ) )
+ .attr( 'x2', datapoint.attr( 'cx' ) ).attr( 'y2', plot.config.height )
+ .classed( 'hoverline', true );
+ })
+ .on( 'mouseout', function(){
+ d3.select( this )
+ .style( 'fill', 'black' )
+ .style( 'fill-opacity', 0.2 );
+
+ d3.selectAll( '.hoverline' ).remove();
+ });
+
+ return newDatapoints;
};
this.render = function( columnData, meta ){
//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
+ //assume: first column is x, second column is y, any remaining aren't used
var xCol = columnData[0],
- yCol = columnData[1];
+ yCol = columnData[1],
+ ids = ( columnData.length > 2 )?( columnData[2] ):( undefined );
this.log( 'renderScatterplot', xCol.length, yCol.length, this.config );
//pre: xCol.len == yCol.len
- //TODO: ^^ isn't necessarily true with current ColumnDataProvider
xCol = this.preprocessData( xCol );
yCol = this.preprocessData( yCol );
//this.log( 'xCol len', xCol.length, 'yCol len', yCol.length );
- //TODO: compute min, max on server.
this.setUpDomains( xCol, yCol, meta );
this.log( 'xMin, xMax, yMin, yMax:', this.xMin, this.xMax, this.yMin, this.yMax );
@@ -380,28 +443,31 @@
this.setUpYAxis();
this.renderGrid();
- this.renderDatapoints( xCol, yCol );
- //TODO: on hover red line to axes, display values
+ this.renderDatapoints( xCol, yCol, ids );
};
}
//==============================================================================
/**
* Scatterplot control UI as a backbone view
- *
+ * handles:
+ * getting the desired data
+ * configuring the plot display
*/
var ScatterplotControlForm = BaseView.extend( LoggableMixin ).extend({
//logger : console,
tagName : 'form',
className : 'scatterplot-settings-form',
- loadingIndicatorImagePath : ( galaxy_paths.get( 'image_path' ) + '/loading_large_white_bg.gif' ),
+ loadingIndicatorImage : 'loading_large_white_bg.gif',
events : {
- 'click #render-button' : 'renderScatterplot'
+ 'click #render-button' : 'renderPlot',
+ 'click #include-id-checkbox' : 'toggleThirdColumnSelector'
},
initialize : function( attributes ){
+
if( !attributes || !attributes.dataset ){
throw( "ScatterplotView requires a dataset" );
} else {
@@ -414,106 +480,230 @@
// set up the basic chart infrastructure with config (if any)
this.chartConfig = attributes.chartConfig || {};
- this.log( 'this.chartConfig:', this.chartConfig );
+ this.log( 'initial chartConfig:', this.chartConfig );
this.plot = new TwoVarScatterplot( this.chartConfig );
+ this.chartConfig = this.plot.config;
+
+ this.$statsPanel = null;
+ this.$chartSettingsPanel = null;
+ this.$dataSettingsPanel = null;
+ this.dataFetch = null;
},
render : function(){
var view = this,
- html = '';
+ formData = {
+ config : this.chartConfig,
+ allColumns : [],
+ numericColumns : [],
+ loadingIndicatorImagePath : galaxy_paths.get( 'image_path' ) + '/' + this.loadingIndicatorImage
+ };
+
+ // gather column indeces (from metadata_column_types) and names (from metadata_columnnames)
+ _.each( this.dataset.metadata_column_types.split( ', ' ), function( type, index ){
+ //TODO: using 0-based indeces
+ // label with the name if available (fall back on 'column <index>')
+ var name = 'column ' + ( index + 1 );
+ if( view.dataset.metadata_column_names ){
+ name = view.dataset.metadata_column_names[ index ];
+ }
- // build column select controls for each x, y (based on name if available)
- var formData = {
- loadingIndicatorImagePath : this.loadingIndicatorImagePath,
- config : this.chartConfig,
- availableColumns : []
- };
- _.each( this.dataset.metadata_column_types.split( ', ' ), function( type, index ){
- // use only numeric columns
+ // filter numeric columns to their own list
if( type === 'int' || type === 'float' ){
- //TODO: using 0-based indeces
- var name = 'column ' + index;
- // label with the name if available
- if( view.dataset.metadata_column_names ){
- name = view.dataset.metadata_column_names[ index ];
- }
- formData.availableColumns.push({ index: index, name: name });
+ formData.numericColumns.push({ index: index, name: name });
}
+ formData.allColumns.push({ index: index, name: name });
});
- //TODO: other vals: max_vals, start_val, pagination
- html = ScatterplotControlForm.templates.form( formData );
- this.$el.append( html );
+ //TODO: other vals: max_vals, start_val, pagination (plot-settings)
+
+ this.$el.append( ScatterplotControlForm.templates.form( formData ) );
+ this.$dataSettingsPanel = this.$el.find( '.tab-pane#data-settings' );
+ this.$chartSettingsPanel = this._render_chartSettings();
+ this.$statsPanel = this.$el.find( '.tab-pane#chart-stats' );
+
+ this.$el.find( 'ul.nav' ).find( 'a[href="#chart-settings"]' ).tab( 'show' );
return this;
},
- showLoadingIndicator : function( message ){
+ _render_chartSettings : function(){
+ var chartControl = this,
+ $chartSettingsPanel = this.$el.find( '.tab-pane#chart-settings' ),
+ // limits for controls (by control/chartConfig id)
+ controlRanges = {
+ 'maxDataPoints' : { min: 1000, max: 30000, step: 100 },
+ 'datapointSize' : { min: 2, max: 10, step: 1 },
+ 'width' : { min: 200, max: 800, step: 20 },
+ 'height' : { min: 200, max: 800, step: 20 }
+ };
+
+ // render the html
+ $chartSettingsPanel.append( ScatterplotControlForm.templates.chartSettings( this.chartConfig ) );
+
+ // set up js on controls
+ // sliders
+ $chartSettingsPanel.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
+ 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 : chartControl.chartConfig[ id ],
+ change : onSliderChange,
+ slide : onSliderChange
+ }));
+ });
+
+ //TODO: anim checkbox
+ //TODO: labels -> renderPlot
+
+ return $chartSettingsPanel;
+ },
+
+ toggleThirdColumnSelector : function(){
+ this.$el.find( 'select[name="ID"]' ).parent().toggle();
+ },
+
+ showLoadingIndicator : function( message, callback ){
message = message || '';
- this.$el.find( 'div#loading-indicator' ).children( '.loading-message' ).text( message );
- this.$el.find( 'div#loading-indicator' ).show( 'fast' );
+ 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(){
- this.$el.find( 'div#loading-indicator' ).hide( 'fast' );
+ hideLoadingIndicator : function( callback ){
+ this.$el.find( 'div#loading-indicator' ).fadeOut( 'fast', callback );
},
- renderScatterplot : function(){
+ getColumnVals : function(){
+ // returns a map: { column-select name (eg. X) : { colIndex : column-selector val,
+ // colName : selected option text }, ... }
+ var selections = {};
+ this.$el.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;
+ },
+
+ fetchData : function( params, callbackFn ){
+ var view = this,
+ url = this.apiDatasetsURL + '/' + this.dataset.id + '?data_type=raw_data&' + jQuery.param( params );
+ this.log( 'url:', url );
+
+ this.showLoadingIndicator( 'Fetching data...', function(){
+ jQuery.ajax({
+ url : url,
+ dataType : 'json',
+ success : callbackFn,
+ error : function( xhr, status, error ){
+ view.hideLoadingIndicator();
+ alert( 'ERROR:' + status + '\n' + error );
+ }
+ });
+ });
+ },
+
+ renderPlot : function(){
// parse the column values for both
// indeces (for the data fetch) and names (for the graph)
var view = this,
- url = this.apiDatasetsURL + '/' + this.dataset.id + '?data_type=raw_data&',
+ columnSelections = this.getColumnVals(),
+ columns = [];
+ this.log( 'columnSelections:', columnSelections );
- xSelector = this.$el.find( '[name="x-column"]' ),
- xVal = xSelector.val(),
- xName = xSelector.children( '[value="' + xVal + '"]' ).text(),
-
- ySelector = this.$el.find( '[name="y-column"]' ),
- yVal = ySelector.val(),
- yName = ySelector.children( '[value="' + yVal + '"]' ).text();
- this.log( xName, yName );
-
- this.chartConfig.xLabel = xName;
- this.chartConfig.yLabel = yName;
+ //TODO: ?? could be moved into getColumnVals;
+ this.log( columnSelections.X.val, columnSelections.Y.val );
+ this.xColIndex = columnSelections.X.colIndex;
+ this.yColIndex = columnSelections.Y.colIndex;
+ columns = [ this.xColIndex, this.yColIndex ];
+
+ // include the desired ID column
+ if( $( '#include-id-checkbox' ).attr( 'checked' ) ){
+ columns.push( columnSelections.ID.colIndex );
+ }
+
+ this.log( columnSelections.X.colName, columnSelections.Y.colName );
+ this.plot.xLabel = this.chartConfig.xLabel = columnSelections.X.colName;
+ this.plot.xLabel = this.chartConfig.yLabel = columnSelections.Y.colName;
//TODO: alter directly
- view.plot.updateConfig( this.chartConfig );
-
+ view.plot.updateConfig( this.chartConfig, false );
//TODO: validate columns - minimally: we can assume either set by selectors or via a good query string
//TODO: other vals: max, start, page
//TODO: chart config
// fetch the data, sending chosen columns to the server
- url += jQuery.param({
- columns : '[' + [ xVal, yVal ] + ']'
+ var params = {
+ columns : '[' + columns + ']'
+ };
+
+ //TODO: prob. better to use events rather than callback chains like this
+ this.fetchData( params, function( response ){
+ // save the endpoint (number of next line, fileptr) for this object
+ //TODO: server sends back an endpoint, cache for next pagination request
+ view.dataFetch = response;
+ view.showLoadingIndicator( 'Rendering...', function(){
+ view.plot.render( response.data, response.meta );
+
+ view.renderStats( response.data, response.meta );
+ view.$el.find( 'ul.nav' ).find( 'a[href="#chart-stats"]' ).tab( 'show' );
+
+ view.hideLoadingIndicator();
+ });
});
- this.log( 'url:', url );
-
- this.showLoadingIndicator( 'Fetching data...' );
- jQuery.ajax({
- url : url,
- dataType : 'json',
- success : function( response ){
- // save the endpoint (number of next line, fileptr) for this object
- //TODO: server sends back an endpoint, cache for next pagination request
- view.endpoint = response.endpoint;
-
- view.showLoadingIndicator( 'Rendering...' );
- view.plot.render( response.data, response.meta );
- view.hideLoadingIndicator();
- },
-
- error : function( xhr, status, error ){
- view.hideLoadingIndicator();
- alert( 'ERROR:' + status + '\n' + error );
- }
- });
+ },
+
+ renderStats : function(){
+ this.$statsPanel.html( ScatterplotControlForm.templates.statsTable({
+ stats: [
+ { name: 'Count', xval: this.dataFetch.meta[0].count, yval: this.dataFetch.meta[1].count },
+ { name: 'Min', xval: this.dataFetch.meta[0].min, yval: this.dataFetch.meta[1].min },
+ { name: 'Max', xval: this.dataFetch.meta[0].max, yval: this.dataFetch.meta[1].max },
+ { name: 'Mean', xval: this.dataFetch.meta[0].mean, yval: this.dataFetch.meta[1].mean },
+ { name: 'Median', xval: this.dataFetch.meta[0].median, yval: this.dataFetch.meta[1].median }
+ ]
+ }));
+ },
+
+ toString : function(){
+ return 'ScatterplotControlForm(' + attributes.dataset.id + ')';
}
});
-ScatterplotControlForm.templates = CompiledTemplateLoader.getTemplates({
- 'visualization-templates.html' : {
- form : 'template-visualization-scatterplotControlForm'
- }
-});
+ScatterplotControlForm.templates = {
+ form : Handlebars.templates[ 'template-visualization-scatterplotControlForm' ],
+ statsTable : Handlebars.templates[ 'template-visualization-statsTable' ],
+ chartSettings : Handlebars.templates[ 'template-visualization-chartSettings' ]
+};
//==============================================================================
return {
diff -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 -r 0684f69e527da908b27fc78e0f0d15ddef5ea33b templates/visualization/scatterplot.mako
--- a/templates/visualization/scatterplot.mako
+++ b/templates/visualization/scatterplot.mako
@@ -2,18 +2,45 @@
<%def name="stylesheets()">
${parent.stylesheets()}
+${h.css(
+ "base",
+ "autocomplete_tagging",
+ "jquery-ui/smoothness/jquery-ui-1.8.23.custom"
+)}
<style type="text/css">
/*TODO: use/move into base.less*/
* { margin: 0px; padding: 0px; }
+
+/* -------------------------------------------- layout */
+.column {
+ position:relative;
+ overflow: auto;
+}
+
+.left-column {
+ float: left;
+ width: 30%;
+}
+
+.right-column {
+ margin-left: 32%;
+}
+
+div.tab-pane {
+ padding: 8px;
+}
+
+/* -------------------------------------------- header */
+.header {
+ margin-bottom: 8px;
+}
+
#chart-header {
padding : 8px;
background-color: #ebd9b2;
}
-.title {
-}
-
#chart-header .subtitle {
margin: -4px 0px 0px 4px;
padding : 0;
@@ -21,33 +48,121 @@
font-size: small;
}
+/* -------------------------------------------- all controls */
#chart-settings-form {
/*from width + margin of chart?*/
- float: right;
- width: 100%;
- margin: 0px;
padding-top: 1em;
}
-#chart-settings > * {
- margin: 8px;
+#chart-settings-form input[type=button],
+#chart-settings-form select {
+ width: 100%;
+ max-width: 256px;
+ margin-bottom: 8px;
}
-#chart-settings-form input, #chart-settings-form select {
- width: 30%;
- max-width: 256px;
+#chart-settings-form .help-text,
+#chart-settings-form .help-text-small {
+ color: grey;
}
-#chart-holder {
- overflow: auto;
+#chart-settings-form .help-text {
+ padding-bottom: 16px;
+}
+
+#chart-settings-form .help-text-small {
+ padding: 4px;
+ font-size: smaller;
+}
+
+#chart-settings-form > * {
+}
+
+#chart-settings-form input[value=Draw] {
+ display: block;
+ margin-top: 16px;
+}
+
+/* -------------------------------------------- data controls */
+
+/* -------------------------------------------- chart controls */
+#chart-settings .form-input {
+ /*display: table-row;*/
+}
+
+#chart-settings label {
+ /*text-align: right;*/
+ margin-bottom: 8px;
+ /*display: table-cell;*/
+}
+
+#chart-settings .slider {
+ /*display: table-cell;*/
+ height: 8px;
+ display: block;
+ margin: 8px 0px 0px 8px;
+}
+
+#chart-settings .slider-output {
+ /*display: table-cell;*/
+ float: right;
+}
+
+#chart-settings input[type="text"] {
+ border: 1px solid lightgrey;
+}
+
+
+/* -------------------------------------------- statistics */
+#chart-stats table#chart-stats-table {
+ width: 100%;
+}
+
+#chart-stats #chart-stats-table th {
+ width: 30%;
+ padding: 4px;
+ font-weight: bold;
+ color: grey;
+}
+
+#chart-stats #chart-stats-table td {
+ border: solid lightgrey;
+ border-width: 1px 0px 0px 1px;
+ padding: 4px;
+}
+
+#chart-stats #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 {
+ z-index: 2;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background-color: white;
+ padding: 32px 0 0 32px;
}
#chart-settings-form #loading-indicator .loading-message {
- margin-left: 16px;
+ margin-left: 10px;
font-style: italic;
color: grey;
}
+/* -------------------------------------------- chart area */
+#chart-holder {
+ overflow: auto;
+ margin-left: 8px;
+}
+
svg .grid-line {
fill: none;
stroke: lightgrey;
@@ -94,8 +209,6 @@
var hda = ${h.to_json_string( hda )},
historyID = '${historyID}'
apiDatasetsURL = "${h.url_for( controller='/api/datasets' )}";
- //?? hmmmm
- //kwargs = ${h.to_json_string( kwargs )};
var settingsForm = new scatterplot.ScatterplotControlForm({
dataset : hda,
@@ -113,10 +226,20 @@
</%def><%def name="body()">
- <div id="chart-header">
+ <!--dataset info-->
+ <div id="chart-header" class="header"><h2 class="title">Scatterplot of '${hda['name']}'</h2><p class="subtitle">${hda['misc_info']}</p></div>
- <div id="chart-holder"></div>
- <div id="chart-settings-form"></div>
+ <div class="outer-container">
+ <!--plot controls-->
+ <div id="chart-settings-form" class="column left-column"></div>
+ <!--plot-->
+ <div class="column right-column">
+ <div id="chart-holder" class="inner-container"></div>
+ </div>
+ <div style="clear: both;"></div>
+ </div>
+ <div id="test"></div>
+
</%def>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
6 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/87641aaefe47/
changeset: 87641aaefe47
user: chapmanb
date: 2012-10-08 11:32:54
summary: Consistently return list of users from users/index for case where API user is not an admin
affected #: 1 file
diff -r 05fc04a70a3bcbfaeedfcf6f2ec16a7e38fc7c94 -r 87641aaefe47d1892bbbd4a7ea56cc21cab9d68c lib/galaxy/webapps/galaxy/api/users.py
--- a/lib/galaxy/webapps/galaxy/api/users.py
+++ b/lib/galaxy/webapps/galaxy/api/users.py
@@ -33,7 +33,7 @@
if not trans.user_is_admin():
item = trans.user.get_api_value( value_mapper={ 'id': trans.security.encode_id } )
item['url'] = url_for( route, id=item['id'] )
- return item
+ return [item]
for user in query:
item = user.get_api_value( value_mapper={ 'id': trans.security.encode_id } )
item['url'] = url_for( route, id=item['id'] )
https://bitbucket.org/galaxy/galaxy-central/changeset/9abbec24c356/
changeset: 9abbec24c356
user: chapmanb
date: 2012-10-08 12:25:49
summary: Provide retrieval of the current user and user history via the API
affected #: 2 files
diff -r 87641aaefe47d1892bbbd4a7ea56cc21cab9d68c -r 9abbec24c3566393b05a0744941361fbfba1a968 lib/galaxy/webapps/galaxy/api/histories.py
--- a/lib/galaxy/webapps/galaxy/api/histories.py
+++ b/lib/galaxy/webapps/galaxy/api/histories.py
@@ -48,6 +48,7 @@
"""
GET /api/histories/{encoded_history_id}
GET /api/histories/deleted/{encoded_history_id}
+ GET /api/histories/current
Displays information about a history.
"""
history_id = id
@@ -65,8 +66,13 @@
rval[item['state']] = rval[item['state']] + 1
return rval
try:
- history = self.get_history( trans, history_id, check_ownership=True, check_accessible=True, deleted=deleted )
+ if history_id == "current" and len(trans.user.galaxy_sessions) > 0:
+ # Most recent active history for user sessions, not deleted
+ history = trans.user.galaxy_sessions[0].histories[-1].history
+ else:
+ history = self.get_history( trans, history_id, check_ownership=True, check_accessible=True, deleted=deleted )
except Exception, e:
+ raise
return str( e )
try:
item = history.get_api_value(view='element', value_mapper={'id':trans.security.encode_id})
diff -r 87641aaefe47d1892bbbd4a7ea56cc21cab9d68c -r 9abbec24c3566393b05a0744941361fbfba1a968 lib/galaxy/webapps/galaxy/api/users.py
--- a/lib/galaxy/webapps/galaxy/api/users.py
+++ b/lib/galaxy/webapps/galaxy/api/users.py
@@ -45,11 +45,15 @@
"""
GET /api/users/{encoded_user_id}
GET /api/users/deleted/{encoded_user_id}
+ GET /api/users/current
Displays information about a user.
"""
deleted = util.string_as_bool( deleted )
try:
- user = self.get_user( trans, id, deleted=deleted )
+ if id == "current":
+ user = trans.user
+ else:
+ user = self.get_user( trans, id, deleted=deleted )
if not trans.user_is_admin():
assert trans.user == user
assert not user.deleted
https://bitbucket.org/galaxy/galaxy-central/changeset/f5772000c6d9/
changeset: f5772000c6d9
user: chapmanb
date: 2012-10-08 12:27:29
summary: Remove extra debugging statement
affected #: 1 file
diff -r 9abbec24c3566393b05a0744941361fbfba1a968 -r f5772000c6d9ea5d15b1332f2ea42330e645371d lib/galaxy/webapps/galaxy/api/histories.py
--- a/lib/galaxy/webapps/galaxy/api/histories.py
+++ b/lib/galaxy/webapps/galaxy/api/histories.py
@@ -72,7 +72,6 @@
else:
history = self.get_history( trans, history_id, check_ownership=True, check_accessible=True, deleted=deleted )
except Exception, e:
- raise
return str( e )
try:
item = history.get_api_value(view='element', value_mapper={'id':trans.security.encode_id})
https://bitbucket.org/galaxy/galaxy-central/changeset/2bfdbe09caf7/
changeset: 2bfdbe09caf7
user: chapmanb
date: 2012-10-09 11:39:15
summary: Defensively check for user and histories before retrieving current history from API
affected #: 1 file
diff -r f5772000c6d9ea5d15b1332f2ea42330e645371d -r 2bfdbe09caf7fd1e49fb5fcdfbb1665764ed39ed lib/galaxy/webapps/galaxy/api/histories.py
--- a/lib/galaxy/webapps/galaxy/api/histories.py
+++ b/lib/galaxy/webapps/galaxy/api/histories.py
@@ -66,9 +66,12 @@
rval[item['state']] = rval[item['state']] + 1
return rval
try:
- if history_id == "current" and len(trans.user.galaxy_sessions) > 0:
- # Most recent active history for user sessions, not deleted
- history = trans.user.galaxy_sessions[0].histories[-1].history
+ if history_id == "current":
+ if trans.user and len(trans.user.galaxy_sessions) > 0:
+ # Most recent active history for user sessions, not deleted
+ history = trans.user.galaxy_sessions[0].histories[-1].history
+ else:
+ history = None
else:
history = self.get_history( trans, history_id, check_ownership=True, check_accessible=True, deleted=deleted )
except Exception, e:
https://bitbucket.org/galaxy/galaxy-central/changeset/e7178dd7f9db/
changeset: e7178dd7f9db
user: chapmanb
date: 2012-10-10 12:53:33
summary: Rename history retrieval to reflect multiple sessions: most_recently_used
affected #: 1 file
diff -r 2bfdbe09caf7fd1e49fb5fcdfbb1665764ed39ed -r e7178dd7f9dbb22c880627c2fb9c05cb696392cf lib/galaxy/webapps/galaxy/api/histories.py
--- a/lib/galaxy/webapps/galaxy/api/histories.py
+++ b/lib/galaxy/webapps/galaxy/api/histories.py
@@ -48,7 +48,7 @@
"""
GET /api/histories/{encoded_history_id}
GET /api/histories/deleted/{encoded_history_id}
- GET /api/histories/current
+ GET /api/histories/most_recently_used
Displays information about a history.
"""
history_id = id
@@ -66,7 +66,7 @@
rval[item['state']] = rval[item['state']] + 1
return rval
try:
- if history_id == "current":
+ if history_id == "most_recently_used":
if trans.user and len(trans.user.galaxy_sessions) > 0:
# Most recent active history for user sessions, not deleted
history = trans.user.galaxy_sessions[0].histories[-1].history
https://bitbucket.org/galaxy/galaxy-central/changeset/666e873a21a0/
changeset: 666e873a21a0
user: jgoecks
date: 2012-10-10 15:43:15
summary: Merged in chapmanb/galaxy-central-apicurrent (pull request #77)
affected #: 2 files
diff -r 220b6683e8dad3028939ff6e5a7acd76d9e994b1 -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 lib/galaxy/webapps/galaxy/api/histories.py
--- a/lib/galaxy/webapps/galaxy/api/histories.py
+++ b/lib/galaxy/webapps/galaxy/api/histories.py
@@ -48,6 +48,7 @@
"""
GET /api/histories/{encoded_history_id}
GET /api/histories/deleted/{encoded_history_id}
+ GET /api/histories/most_recently_used
Displays information about a history.
"""
history_id = id
@@ -65,7 +66,14 @@
rval[item['state']] = rval[item['state']] + 1
return rval
try:
- history = self.get_history( trans, history_id, check_ownership=True, check_accessible=True, deleted=deleted )
+ if history_id == "most_recently_used":
+ if trans.user and len(trans.user.galaxy_sessions) > 0:
+ # Most recent active history for user sessions, not deleted
+ history = trans.user.galaxy_sessions[0].histories[-1].history
+ else:
+ history = None
+ else:
+ history = self.get_history( trans, history_id, check_ownership=True, check_accessible=True, deleted=deleted )
except Exception, e:
return str( e )
try:
diff -r 220b6683e8dad3028939ff6e5a7acd76d9e994b1 -r 666e873a21a0f8032a2f7b39204b5edb6ee47797 lib/galaxy/webapps/galaxy/api/users.py
--- a/lib/galaxy/webapps/galaxy/api/users.py
+++ b/lib/galaxy/webapps/galaxy/api/users.py
@@ -33,7 +33,7 @@
if not trans.user_is_admin():
item = trans.user.get_api_value( value_mapper={ 'id': trans.security.encode_id } )
item['url'] = url_for( route, id=item['id'] )
- return item
+ return [item]
for user in query:
item = user.get_api_value( value_mapper={ 'id': trans.security.encode_id } )
item['url'] = url_for( route, id=item['id'] )
@@ -45,11 +45,15 @@
"""
GET /api/users/{encoded_user_id}
GET /api/users/deleted/{encoded_user_id}
+ GET /api/users/current
Displays information about a user.
"""
deleted = util.string_as_bool( deleted )
try:
- user = self.get_user( trans, id, deleted=deleted )
+ if id == "current":
+ user = trans.user
+ else:
+ user = self.get_user( trans, id, deleted=deleted )
if not trans.user_is_admin():
assert trans.user == user
assert not user.deleted
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: Create and use mixin method for getting dataset's genome data.
by Bitbucket 10 Oct '12
by Bitbucket 10 Oct '12
10 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/220b6683e8da/
changeset: 220b6683e8da
user: jgoecks
date: 2012-10-10 05:49:01
summary: Create and use mixin method for getting dataset's genome data.
affected #: 4 files
diff -r 3231b9ca8d82219cbef87cfeb4fc57013c11f3c5 -r 220b6683e8dad3028939ff6e5a7acd76d9e994b1 lib/galaxy/visualization/data_providers/genome.py
--- a/lib/galaxy/visualization/data_providers/genome.py
+++ b/lib/galaxy/visualization/data_providers/genome.py
@@ -186,7 +186,6 @@
chrom_data = self.get_data( chrom, 0, chrom_len, **kwargs )
if chrom_data:
chrom_data[ 'region' ] = "%s:%i-%i" % ( chrom, 0, chrom_len )
- chrom_data[ 'dataset_type' ] = self.dataset_type
genome_data.append( chrom_data )
return {
diff -r 3231b9ca8d82219cbef87cfeb4fc57013c11f3c5 -r 220b6683e8dad3028939ff6e5a7acd76d9e994b1 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -602,6 +602,33 @@
return visualization
+ def _get_genome_data( self, trans, dataset, dbkey=None ):
+ """
+ Returns genome-wide data for dataset if available; if not, message is returned.
+ """
+ rval = None
+
+ # Get data sources.
+ data_sources = dataset.get_datasources( trans )
+ query_dbkey = dataset.dbkey
+ if query_dbkey == "?":
+ query_dbkey = dbkey
+ chroms_info = self.app.genomes.chroms( trans, dbkey=query_dbkey )
+
+ # If there are no messages (messages indicate data is not ready/available), preload data.
+ messages_list = [ data_source_dict[ 'message' ] for data_source_dict in data_sources.values() ]
+ message = get_highest_priority_msg( messages_list )
+ if message:
+ rval = message
+ else:
+ data_provider = trans.app.data_provider_registry.get_data_provider( trans,
+ original_dataset=dataset,
+ source='index' )
+ # HACK: pass in additional params, which are only used for summary tree data, not BBI data.
+ rval = data_provider.get_genome_data( chroms_info, level=4, detail_cutoff=0, draw_cutoff=0 )
+
+ return rval
+
class UsesStoredWorkflowMixin( SharableItemSecurityMixin ):
""" Mixin for controllers that use StoredWorkflow objects. """
def get_stored_workflow( self, trans, id, check_ownership=True, check_accessible=False ):
diff -r 3231b9ca8d82219cbef87cfeb4fc57013c11f3c5 -r 220b6683e8dad3028939ff6e5a7acd76d9e994b1 lib/galaxy/webapps/galaxy/api/datasets.py
--- a/lib/galaxy/webapps/galaxy/api/datasets.py
+++ b/lib/galaxy/webapps/galaxy/api/datasets.py
@@ -51,6 +51,8 @@
rval = self._raw_data( trans, dataset, **kwd )
elif data_type == 'track_config':
rval = self.get_new_track_config( trans, dataset )
+ elif data_type == 'genome_data':
+ rval = self._get_genome_data( self, trans, dataset, kwd.get('dbkey', None) )
else:
# Default: return dataset as API value.
rval = dataset.get_api_value()
diff -r 3231b9ca8d82219cbef87cfeb4fc57013c11f3c5 -r 220b6683e8dad3028939ff6e5a7acd76d9e994b1 lib/galaxy/webapps/galaxy/controllers/visualization.py
--- a/lib/galaxy/webapps/galaxy/controllers/visualization.py
+++ b/lib/galaxy/webapps/galaxy/controllers/visualization.py
@@ -772,18 +772,10 @@
# Add genome-wide summary tree data to each track in viz.
tracks = viz_config.get( 'tracks', [] )
for track in tracks:
- # Get dataset and data sources.
dataset = self.get_hda_or_ldda( trans, track[ 'hda_ldda'], track[ 'dataset_id' ] )
- data_sources = dataset.get_datasources( trans )
-
- # If there are no messages (messages indicate data is not ready/available), preload data.
- messages_list = [ data_source_dict[ 'message' ] for data_source_dict in data_sources.values() ]
- if not get_highest_priority_msg( messages_list ):
- data_provider = trans.app.data_provider_registry.get_data_provider( trans,
- original_dataset=dataset,
- source='index' )
- # HACK: pass in additional params, which are only used for summary tree data, not BBI data.
- track[ 'preloaded_data' ] = data_provider.get_genome_data( chroms_info, level=4, detail_cutoff=0, draw_cutoff=0 )
+ genome_data = self._get_genome_data( trans, dataset, dbkey )
+ if not isinstance( genome_data, str ):
+ track[ 'preloaded_data' ] = genome_data
return trans.fill_template( 'visualization/circster.mako', viz_config=viz_config, genome=genome )
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: history.js: fix to HistoryView tagging functionality
by Bitbucket 09 Oct '12
by Bitbucket 09 Oct '12
09 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/3231b9ca8d82/
changeset: 3231b9ca8d82
user: carlfeberhard
date: 2012-10-10 01:10:30
summary: history.js: fix to HistoryView tagging functionality
affected #: 4 files
diff -r dcb22217c17527427c17f4ca3edeb5d6a98f6f4d -r 3231b9ca8d82219cbef87cfeb4fc57013c11f3c5 static/scripts/mvc/history.js
--- a/static/scripts/mvc/history.js
+++ b/static/scripts/mvc/history.js
@@ -558,6 +558,14 @@
parent.append( this._render_displayApps() );
parent.append( this._render_peek() );
+
+ //TODO??: still needed?
+ //// If Mozilla, hide scrollbars in hidden items since they cause animation bugs
+ //if ( $.browser.mozilla ) {
+ // $( "div.historyItemBody" ).each( function() {
+ // if ( !$(this).is(":visible") ) { $(this).find( "pre.peek" ).css( "overflow", "hidden" ); }
+ // });
+ //}
},
_render_body : function(){
@@ -704,7 +712,13 @@
toggleBodyVisibility : function( visible ){
var $body = this.$el.find( '.historyItemBody' );
- $body.toggle();
+ if( visible === undefined ){
+ $body.toggle();
+ } else if( visible ){
+ $body.show();
+ } else {
+ $body.hide();
+ }
this.trigger( 'toggleBodyVisibility', this.model.get( 'id' ), $body.is( ':visible' ) );
},
@@ -715,9 +729,7 @@
}
});
-
//------------------------------------------------------------------------------
-//HistoryItemView.templates = InDomTemplateLoader.getTemplates({
HistoryItemView.templates = {
warningMsg : Handlebars.templates[ 'template-warningmessagesmall' ],
@@ -875,7 +887,6 @@
//------------------------------------------------------------------------------
// view for the HistoryCollection (as per current right hand panel)
-//var HistoryView = BaseView.extend( LoggableMixin ).extend( UsesStorageMixin ) .extend({
var HistoryView = BaseView.extend( LoggableMixin ).extend({
// uncomment this out see log messages
@@ -894,16 +905,20 @@
);
// set up the individual history items/datasets
this.initializeItems();
+
},
initializeItems : function(){
this.itemViews = {};
var historyPanel = this;
+
+ // set up a view for each item, init with model and listeners, cache to map ( model.id : view )
this.model.items.each( function( item ){
var itemId = item.get( 'id' ),
+ visible = historyPanel.storage.get( 'visibleItems' ).get( itemId ),
itemView = new HistoryItemView({
- model: item, visible:
- historyPanel.storage.get( 'visibleItems' ).get( itemId )
+ model: item,
+ visible: visible
});
historyPanel.setUpItemListeners( itemView );
historyPanel.itemViews[ itemId ] = itemView;
@@ -912,6 +927,7 @@
setUpItemListeners : function( itemView ){
var HistoryPanel = this;
+
// use storage to maintain a list of items whose bodies are visible
itemView.bind( 'toggleBodyVisibility', function( id, visible ){
if( visible ){
@@ -930,7 +946,34 @@
this.itemsDiv = this.$el.find( '#' + this.model.get( 'id' ) + '-datasets' );
//TODO: set up widgets, tooltips, etc.
+ async_save_text(
+ "history-name-container",
+ "history-name",
+ this.model.get( 'renameURL' ),
+ "new_name",
+ 18
+ );
+ this.$el.find( '.tooltip' ).tooltip();
+ var historyAnnotationArea = this.$el.find( '#history-annotation-area' );
+ $( '#history-annotate' ).click( function() {
+ if ( historyAnnotationArea.is( ":hidden" ) ) {
+ historyAnnotationArea.slideDown( "fast" );
+ } else {
+ historyAnnotationArea.slideUp( "fast" );
+ }
+ return false;
+ });
+ async_save_text(
+ "history-annotation-container",
+ "history-annotation",
+ this.model.get( 'annotateURL' ),
+ "new_annotation",
+ 18,
+ true,
+ 4
+ );
+
if( this.model.items.length ){
// render to temp, move all at once, remove temp holder
var tempDiv = this._render_items();
@@ -950,6 +993,53 @@
return div;
},
+ events : {
+ 'click #history-collapse-all' : 'hideAllItemBodies',
+ 'click #history-tag' : 'loadAndDisplayTags'
+ },
+
+ hideAllItemBodies : function(){
+ _.each( this.itemViews, function( item ){
+ item.toggleBodyVisibility( false );
+ });
+ },
+
+ loadAndDisplayTags : function( event ){
+ //BUG: broken with latest
+ //TODO: this is a drop in from history.mako - should use MV as well
+ this.log( this + '.loadAndDisplayTags', event );
+ var tagArea = this.$el.find( '#history-tag-area' ),
+ tagElt = tagArea.find( '.tag-elt' );
+ this.log( '\t tagArea', tagArea, ' tagElt', tagElt );
+
+ // Show or hide tag area; if showing tag area and it's empty, fill it.
+ if( tagArea.is( ":hidden" ) ){
+ if( !jQuery.trim( tagElt.html() ) ){
+ var view = this;
+ // Need to fill tag element.
+ $.ajax({
+ //TODO: the html from this breaks a couple of times
+ url: this.model.get( 'tagURL' ),
+ error: function() { alert( "Tagging failed" ); },
+ success: function(tag_elt_html) {
+ view.log( view + ' tag elt html (ajax)', tag_elt_html );
+ tagElt.html(tag_elt_html);
+ tagElt.find(".tooltip").tooltip();
+ tagArea.slideDown("fast");
+ }
+ });
+ } else {
+ // Tag element is filled; show.
+ tagArea.slideDown("fast");
+ }
+
+ } else {
+ // Hide.
+ tagArea.slideUp("fast");
+ }
+ return false;
+ },
+
toString : function(){
var nameString = this.model.get( 'name' ) || '';
return 'HistoryView(' + nameString + ')';
diff -r dcb22217c17527427c17f4ca3edeb5d6a98f6f4d -r 3231b9ca8d82219cbef87cfeb4fc57013c11f3c5 static/scripts/templates/compiled/template-history-historyPanel.js
--- a/static/scripts/templates/compiled/template-history-historyPanel.js
+++ b/static/scripts/templates/compiled/template-history-historyPanel.js
@@ -23,21 +23,13 @@
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(6, program6, data)}); }
if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\"\n class=\"icon-button tags tooltip\" target=\"galaxy_main\" href=\"";
- foundHelper = helpers.tagURL;
- if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
- else { stack1 = depth0.tagURL; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
- buffer += escapeExpression(stack1) + "\"></a>\n <a id=\"history-annotate\" title=\"";
+ buffer += "\"\n class=\"icon-button tags tooltip\" target=\"galaxy_main\" href=\"javascript:void(0)\"></a>\n <a id=\"history-annotate\" title=\"";
foundHelper = helpers.local;
if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},inverse:self.noop,fn:self.program(8, program8, data)}); }
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(8, program8, data)}); }
if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\"\n class=\"icon-button annotate tooltip\" target=\"galaxy_main\" href=\"";
- foundHelper = helpers.annotateURL;
- if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); }
- else { stack1 = depth0.annotateURL; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
- buffer += escapeExpression(stack1) + "\"></a>\n </div>\n ";
+ buffer += "\"\n class=\"icon-button annotate tooltip\" target=\"galaxy_main\" href=\"javascript:void(0)\"></a>\n </div>\n ";
return buffer;}
function program6(depth0,data) {
@@ -143,9 +135,9 @@
var buffer = "", stack1;
buffer += "\n";
- buffer += "\n<div style=\"margin: 0px 5px 10px 5px\">\n\n <div id=\"history-tag-area\" style=\"display: none\">\n <b>Tags:</b>\n ";
+ buffer += "\n<div style=\"margin: 0px 5px 10px 5px\">\n\n <div id=\"history-tag-area\" style=\"display: none\">\n ";
buffer += "\n ";
- buffer += "\n </div>\n\n <div id=\"history-annotation-area\" style=\"display: none\">\n <strong>Annotation / Notes:</strong>\n <div id=\"history-annotation-container\">\n <div id=\"history-annotation\" class=\"tooltip editable-text\" title=\"Click to edit annotation\">\n ";
+ buffer += "\n <strong>Tags:</strong>\n <div class=\"tag-elt\"></div>\n </div>\n\n <div id=\"history-annotation-area\" style=\"display: none\">\n <strong>Annotation / Notes:</strong>\n <div id=\"history-annotation-container\">\n <div id=\"history-annotation\" class=\"tooltip editable-text\" title=\"Click to edit annotation\">\n ";
stack1 = depth0.annotation;
stack1 = helpers['if'].call(depth0, stack1, {hash:{},inverse:self.program(27, program27, data),fn:self.program(25, program25, data)});
if(stack1 || stack1 === 0) { buffer += stack1; }
@@ -228,7 +220,7 @@
else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1() : stack1; }
if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(3, program3, data)}); }
if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "' class='icon-button toggle tooltip' href='#' style=\"display: none\"></a>\n ";
+ buffer += "' id=\"history-collapse-all\"\n class='icon-button toggle tooltip' href='javascript:void(0);'></a>\n ";
stack1 = depth0.userRoles;
stack1 = helpers['if'].call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(5, program5, data)});
if(stack1 || stack1 === 0) { buffer += stack1; }
@@ -252,7 +244,6 @@
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n\n";
buffer += "\n";
- buffer += "\n";
stack1 = depth0.userRoles;
stack1 = helpers['if'].call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(24, program24, data)});
if(stack1 || stack1 === 0) { buffer += stack1; }
diff -r dcb22217c17527427c17f4ca3edeb5d6a98f6f4d -r 3231b9ca8d82219cbef87cfeb4fc57013c11f3c5 static/scripts/templates/history-templates.html
--- a/static/scripts/templates/history-templates.html
+++ b/static/scripts/templates/history-templates.html
@@ -103,13 +103,14 @@
<script type="text/template" class="template-history" id="template-history-historyPanel"><div id="top-links" class="historyLinks"><a title="{{#local}}refresh{{/local}}" class="icon-button arrow-circle tooltip" href="{{baseURL}}"></a>
- <a title='{{#local}}collapse all{{/local}}' class='icon-button toggle tooltip' href='#' style="display: none"></a>
+ <a title='{{#local}}collapse all{{/local}}' id="history-collapse-all"
+ class='icon-button toggle tooltip' href='javascript:void(0);'></a>
{{#if userRoles}}
<div style="width: 40px; float: right; white-space: nowrap;"><a id="history-tag" title="{{#local}}Edit history tags{{/local}}"
- class="icon-button tags tooltip" target="galaxy_main" href="{{tagURL}}"></a>
+ class="icon-button tags tooltip" target="galaxy_main" href="javascript:void(0)"></a><a id="history-annotate" title="{{#local}}Edit history annotation{{/local}}"
- class="icon-button annotate tooltip" target="galaxy_main" href="{{annotateURL}}"></a>
+ class="icon-button annotate tooltip" target="galaxy_main" href="javascript:void(0)"></a></div>
{{/if}}
</div>
@@ -148,15 +149,15 @@
{{/if}}
{{! tags and annotations }}
-{{! TODO: wire these to js events }}
{{#if userRoles}}
{{! TODO: move inline styles out }}
<div style="margin: 0px 5px 10px 5px"><div id="history-tag-area" style="display: none">
- <b>Tags:</b>
{{! load via js render_individual_tagging_element }}
{{! render_individual_tagging_element(user=trans.get_user(), tagged_item=history, elt_context="history.mako", use_toggle_link=False, input_size="20") }}
+ <strong>Tags:</strong>
+ <div class="tag-elt"></div></div><div id="history-annotation-area" style="display: none">
@@ -202,6 +203,3 @@
</div>
{{/if}}
</script>
-
-
-
diff -r dcb22217c17527427c17f4ca3edeb5d6a98f6f4d -r 3231b9ca8d82219cbef87cfeb4fc57013c11f3c5 templates/root/alternate_history.mako
--- a/templates/root/alternate_history.mako
+++ b/templates/root/alternate_history.mako
@@ -291,9 +291,10 @@
##TODO: move to API
for_editing = True
+ encoded_history_id = trans.security.encode_id( history.id )
context_dict = {
'history' : {
- 'id' : trans.security.encode_id( history.id ),
+ 'id' : encoded_history_id,
'name' : history.name,
'status' : status,
@@ -324,11 +325,13 @@
'annotation' : h.to_unicode( annotation ),
##TODO: broken
- 'baseURL' : h.url_for( 'history', show_deleted=show_deleted ),
- 'hideDeletedURL' : h.url_for( 'history', show_deleted=False ),
- 'hideHiddenURL' : h.url_for( 'history', show_hidden=False ),
- 'tagURL' : h.url_for( controller='history', action='tag' ),
- 'annotateURL' : h.url_for( controller='history', action='annotate' )
+ 'baseURL' : h.url_for( controller="/history", show_deleted=show_deleted ),
+ 'hideDeletedURL' : h.url_for( controller="/history", show_deleted=False ),
+ 'hideHiddenURL' : h.url_for( controller="/history", show_hidden=False ),
+ 'renameURL' : h.url_for( controller="/history", action="rename_async", id=encoded_history_id ),
+ 'tagURL' : h.url_for( controller='tag', action='get_tagging_elt_async',
+ item_class=history.__class__.__name__, item_id=encoded_history_id ),
+ 'annotateURL' : h.url_for( controller="/history", action="annotate_async", id=encoded_history_id )
},
'hdas' : [ prep_hda( hda, for_editing ) for hda in datasets ],
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/changeset/9635e2cc9a24/
changeset: 9635e2cc9a24
user: jgoecks
date: 2012-10-09 18:33:02
summary: Trackster: accurately calculate track/tile heights by clearing previously set height before calculating new height.
affected #: 1 file
diff -r 79bb2432133f9b18450e142fc6b80ddab364b57e -r 9635e2cc9a249aea5d939c0f4ca955c5faa3dd58 static/scripts/viz/trackster/tracks.js
--- a/static/scripts/viz/trackster/tracks.js
+++ b/static/scripts/viz/trackster/tracks.js
@@ -3020,13 +3020,10 @@
* an existing tile rather than reshowing it.
*/
show_tile: function(tile, parent_element, w_scale) {
- var
- track = this,
+ var track = this,
tile_element = tile.html_elt;
- //
- // Show/move tile element.
- //
+ // -- Show/move tile element. --
tile.predisplay_actions();
@@ -3046,14 +3043,12 @@
// Showing new tile.
parent_element.append(tile_element);
}
+
+ // -- Update track, tile heights based on new tile. --
- track.after_show_tile(tile);
- },
-
- /**
- * Actions to be taken after showing tile.
- */
- after_show_tile: function(tile) {
+ // Clear any previous height settings for tile.
+ tile.html_elt.height('auto');
+
// Update max height based on current tile.
this.max_height_px = Math.max(this.max_height_px, tile.html_elt.height());
https://bitbucket.org/galaxy/galaxy-central/changeset/437b0d9ccb60/
changeset: 437b0d9ccb60
user: jgoecks
date: 2012-10-09 20:16:16
summary: For Circster: only preload data if indexing is complete.
affected #: 1 file
diff -r 9635e2cc9a249aea5d939c0f4ca955c5faa3dd58 -r 437b0d9ccb60141d9378642893ce13bd50187cea lib/galaxy/webapps/galaxy/controllers/visualization.py
--- a/lib/galaxy/webapps/galaxy/controllers/visualization.py
+++ b/lib/galaxy/webapps/galaxy/controllers/visualization.py
@@ -772,14 +772,18 @@
# Add genome-wide summary tree data to each track in viz.
tracks = viz_config.get( 'tracks', [] )
for track in tracks:
- # Get dataset and indexed datatype.
+ # Get dataset and data sources.
dataset = self.get_hda_or_ldda( trans, track[ 'hda_ldda'], track[ 'dataset_id' ] )
data_sources = dataset.get_datasources( trans )
- data_provider = trans.app.data_provider_registry.get_data_provider( trans,
- original_dataset=dataset,
- source='index' )
- # HACK: pass in additional params, which are only used for summary tree data, not BBI data.
- track[ 'preloaded_data' ] = data_provider.get_genome_data( chroms_info, level=4, detail_cutoff=0, draw_cutoff=0 )
+
+ # If there are no messages (messages indicate data is not ready/available), preload data.
+ messages_list = [ data_source_dict[ 'message' ] for data_source_dict in data_sources.values() ]
+ if not get_highest_priority_msg( messages_list ):
+ data_provider = trans.app.data_provider_registry.get_data_provider( trans,
+ original_dataset=dataset,
+ source='index' )
+ # HACK: pass in additional params, which are only used for summary tree data, not BBI data.
+ track[ 'preloaded_data' ] = data_provider.get_genome_data( chroms_info, level=4, detail_cutoff=0, draw_cutoff=0 )
return trans.fill_template( 'visualization/circster.mako', viz_config=viz_config, genome=genome )
https://bitbucket.org/galaxy/galaxy-central/changeset/dcb22217c175/
changeset: dcb22217c175
user: jgoecks
date: 2012-10-09 20:16:27
summary: Merge
affected #: 2 files
diff -r 437b0d9ccb60141d9378642893ce13bd50187cea -r dcb22217c17527427c17f4ca3edeb5d6a98f6f4d lib/galaxy/datatypes/metadata.py
--- a/lib/galaxy/datatypes/metadata.py
+++ b/lib/galaxy/datatypes/metadata.py
@@ -345,13 +345,13 @@
def get_html_field( self, value=None, context={}, other_values={}, values=None, **kwd ):
if values is None and context:
- column_range = range( 1, context.columns+1, 1 )
+ column_range = range( 1, ( context.columns or 0 ) + 1, 1 )
values = zip( column_range, column_range )
return RangeParameter.get_html_field( self, value=value, context=context, other_values=other_values, values=values, **kwd )
def get_html( self, value, context={}, other_values={}, values=None, **kwd ):
if values is None and context:
- column_range = range( 1, context.columns+1, 1 )
+ column_range = range( 1, ( context.columns or 0 ) + 1, 1 )
values = zip( column_range, column_range )
return RangeParameter.get_html( self, value, context=context, other_values=other_values, values=values, **kwd )
diff -r 437b0d9ccb60141d9378642893ce13bd50187cea -r dcb22217c17527427c17f4ca3edeb5d6a98f6f4d lib/galaxy/datatypes/tabular.py
--- a/lib/galaxy/datatypes/tabular.py
+++ b/lib/galaxy/datatypes/tabular.py
@@ -274,12 +274,18 @@
column_names = dataset.metadata.column_names
elif hasattr(dataset.datatype, 'column_names'):
column_names = dataset.datatype.column_names
+ column_types = dataset.metadata.column_types
+ if not column_types:
+ column_types = []
+ column_number = dataset.metadata.columns
+ if column_number is None:
+ column_number = 'null'
return trans.fill_template( "/dataset/tabular_chunked.mako",
dataset = dataset,
chunk = self.get_chunk(trans, dataset, 0),
- column_number = dataset.metadata.columns,
+ column_number = column_number,
column_names = column_names,
- column_types = dataset.metadata.column_types)
+ column_types = column_types )
def set_peek( self, dataset, line_count=None, is_multi_byte=False):
super(Tabular, self).set_peek( dataset, line_count=line_count, is_multi_byte=is_multi_byte)
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 displaying metadata ColumnParameter type when columns is None.
by Bitbucket 09 Oct '12
by Bitbucket 09 Oct '12
09 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/6f017bc991a6/
changeset: 6f017bc991a6
user: dan
date: 2012-10-09 19:57:19
summary: Fix for displaying metadata ColumnParameter type when columns is None.
affected #: 1 file
diff -r 8ce7bbba361a93a1a4a50029a3fd6a6266c1934d -r 6f017bc991a6e4617488768532adb56d49c1a688 lib/galaxy/datatypes/metadata.py
--- a/lib/galaxy/datatypes/metadata.py
+++ b/lib/galaxy/datatypes/metadata.py
@@ -345,13 +345,13 @@
def get_html_field( self, value=None, context={}, other_values={}, values=None, **kwd ):
if values is None and context:
- column_range = range( 1, context.columns+1, 1 )
+ column_range = range( 1, ( context.columns or 0 ) + 1, 1 )
values = zip( column_range, column_range )
return RangeParameter.get_html_field( self, value=value, context=context, other_values=other_values, values=values, **kwd )
def get_html( self, value, context={}, other_values={}, values=None, **kwd ):
if values is None and context:
- column_range = range( 1, context.columns+1, 1 )
+ column_range = range( 1, ( context.columns or 0 ) + 1, 1 )
values = zip( column_range, column_range )
return RangeParameter.get_html( self, value, context=context, other_values=other_values, values=values, **kwd )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: Fix for preview display of tabular items when column_number is None.
by Bitbucket 09 Oct '12
by Bitbucket 09 Oct '12
09 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/8ce7bbba361a/
changeset: 8ce7bbba361a
user: dan
date: 2012-10-09 19:50:47
summary: Fix for preview display of tabular items when column_number is None.
affected #: 1 file
diff -r 259a4e01f105b6f7396292db3ae0971d049b6ce7 -r 8ce7bbba361a93a1a4a50029a3fd6a6266c1934d lib/galaxy/datatypes/tabular.py
--- a/lib/galaxy/datatypes/tabular.py
+++ b/lib/galaxy/datatypes/tabular.py
@@ -277,10 +277,13 @@
column_types = dataset.metadata.column_types
if not column_types:
column_types = []
+ column_number = dataset.metadata.columns
+ if column_number is None:
+ column_number = 'null'
return trans.fill_template( "/dataset/tabular_chunked.mako",
dataset = dataset,
chunk = self.get_chunk(trans, dataset, 0),
- column_number = dataset.metadata.columns,
+ column_number = column_number,
column_names = column_names,
column_types = column_types )
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 preview display of tabular items when column_types is None.
by Bitbucket 09 Oct '12
by Bitbucket 09 Oct '12
09 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/259a4e01f105/
changeset: 259a4e01f105
user: dan
date: 2012-10-09 19:46:19
summary: Fix for preview display of tabular items when column_types is None.
affected #: 1 file
diff -r 79bb2432133f9b18450e142fc6b80ddab364b57e -r 259a4e01f105b6f7396292db3ae0971d049b6ce7 lib/galaxy/datatypes/tabular.py
--- a/lib/galaxy/datatypes/tabular.py
+++ b/lib/galaxy/datatypes/tabular.py
@@ -274,12 +274,15 @@
column_names = dataset.metadata.column_names
elif hasattr(dataset.datatype, 'column_names'):
column_names = dataset.datatype.column_names
+ column_types = dataset.metadata.column_types
+ if not column_types:
+ column_types = []
return trans.fill_template( "/dataset/tabular_chunked.mako",
dataset = dataset,
chunk = self.get_chunk(trans, dataset, 0),
column_number = dataset.metadata.columns,
column_names = column_names,
- column_types = dataset.metadata.column_types)
+ column_types = column_types )
def set_peek( self, dataset, line_count=None, is_multi_byte=False):
super(Tabular, self).set_peek( dataset, line_count=line_count, is_multi_byte=is_multi_byte)
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
09 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/79bb2432133f/
changeset: 79bb2432133f
user: jgoecks
date: 2012-10-09 17:59:59
summary: Fix typo in datasets API controller.
affected #: 1 file
diff -r 04229b267b3e8dd112d3e66fd6826d2f66404424 -r 79bb2432133f9b18450e142fc6b80ddab364b57e lib/galaxy/webapps/galaxy/api/datasets.py
--- a/lib/galaxy/webapps/galaxy/api/datasets.py
+++ b/lib/galaxy/webapps/galaxy/api/datasets.py
@@ -46,7 +46,7 @@
elif data_type == 'data':
rval = self._data( trans, dataset, **kwd )
elif data_type == 'features':
- rval = self._search_features( trans, dataset, kwd.get( 'query ' ) )
+ rval = self._search_features( trans, dataset, kwd.get( 'query' ) )
elif data_type == 'raw_data':
rval = self._raw_data( trans, dataset, **kwd )
elif data_type == 'track_config':
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/04229b267b3e/
changeset: 04229b267b3e
user: dan
date: 2012-10-09 16:27:54
summary: Some cleanup for shed_util.py
affected #: 1 file
diff -r 429e895ee1b3bfb2fea1632d34a01d54faeac866 -r 04229b267b3e8dd112d3e66fd6826d2f66404424 lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -387,8 +387,6 @@
else:
tmp_url = repository_clone_url
return tmp_url
-def tool_shed_from_repository_clone_url( repository_clone_url ):
- return clean_repository_clone_url( repository_clone_url ).split( 'repos' )[ 0 ].rstrip( '/' )
def clean_tool_shed_url( tool_shed_url ):
if tool_shed_url.find( ':' ) > 0:
# Eliminate the port, if any, since it will result in an invalid directory name.
@@ -1772,42 +1770,6 @@
config_elems.remove( config_elem )
# Persist the altered in-memory version of the tool config.
config_elems_to_xml_file( trans.app, config_elems, shed_tool_conf, tool_path )
-def update_in_shed_tool_config( app, repository ):
- # A tool shed repository is being updated so change the shed_tool_conf file. Parse the config file to generate the entire list
- # of config_elems instead of using the in-memory list.
- shed_conf_dict = repository.get_shed_config_dict( app )
- shed_tool_conf = shed_conf_dict[ 'config_filename' ]
- tool_path = shed_conf_dict[ 'tool_path' ]
-
- #hack for 'trans.app' used in lots of places. These places should just directly use app
- trans = util.bunch.Bunch()
- trans.app = app
-
- tool_panel_dict = generate_tool_panel_dict_from_shed_tool_conf_entries( trans, repository )
- repository_tools_tups = get_repository_tools_tups( app, repository.metadata )
- cleaned_repository_clone_url = clean_repository_clone_url( generate_clone_url( trans, repository ) )
- tool_shed = tool_shed_from_repository_clone_url( cleaned_repository_clone_url )
- owner = repository.owner
- if not owner:
- owner = get_repository_owner( cleaned_repository_clone_url )
- guid_to_tool_elem_dict = {}
- for tool_config_filename, guid, tool in repository_tools_tups:
- guid_to_tool_elem_dict[ guid ] = generate_tool_elem( tool_shed, repository.name, repository.changeset_revision, repository.owner or '', tool_config_filename, tool, None )
- config_elems = []
- tree = util.parse_xml( shed_tool_conf )
- root = tree.getroot()
- for elem in root:
- if elem.tag == 'section':
- for i, tool_elem in enumerate( elem ):
- guid = tool_elem.attrib.get( 'guid' )
- if guid in guid_to_tool_elem_dict:
- elem[i] = guid_to_tool_elem_dict[ guid ]
- elif elem.tag == 'tool':
- guid = elem.attrib.get( 'guid' )
- if guid in guid_to_tool_elem_dict:
- elem = guid_to_tool_elem_dict[ guid ]
- config_elems.append( elem )
- config_elems_to_xml_file( app, config_elems, shed_tool_conf, tool_path )
def remove_from_tool_panel( trans, repository, shed_tool_conf, uninstall ):
"""A tool shed repository is being deactivated or uninstalled so handle tool panel alterations accordingly."""
# Determine where the tools are currently defined in the tool panel and store this information so the tools can be displayed
@@ -2016,6 +1978,8 @@
elif c not in [ '\r' ]:
translated.append( '' )
return ''.join( translated )
+def tool_shed_from_repository_clone_url( repository_clone_url ):
+ return clean_repository_clone_url( repository_clone_url ).split( 'repos' )[ 0 ].rstrip( '/' )
def translate_string( raw_text, to_html=True ):
if raw_text:
if to_html:
@@ -2086,6 +2050,42 @@
sa_session.delete( tool_dependency )
sa_session.flush()
return new_tool_dependency
+def update_in_shed_tool_config( app, repository ):
+ # A tool shed repository is being updated so change the shed_tool_conf file. Parse the config file to generate the entire list
+ # of config_elems instead of using the in-memory list.
+ shed_conf_dict = repository.get_shed_config_dict( app )
+ shed_tool_conf = shed_conf_dict[ 'config_filename' ]
+ tool_path = shed_conf_dict[ 'tool_path' ]
+
+ #hack for 'trans.app' used in lots of places. These places should just directly use app
+ trans = util.bunch.Bunch()
+ trans.app = app
+
+ tool_panel_dict = generate_tool_panel_dict_from_shed_tool_conf_entries( trans, repository )
+ repository_tools_tups = get_repository_tools_tups( app, repository.metadata )
+ cleaned_repository_clone_url = clean_repository_clone_url( generate_clone_url( trans, repository ) )
+ tool_shed = tool_shed_from_repository_clone_url( cleaned_repository_clone_url )
+ owner = repository.owner
+ if not owner:
+ owner = get_repository_owner( cleaned_repository_clone_url )
+ guid_to_tool_elem_dict = {}
+ for tool_config_filename, guid, tool in repository_tools_tups:
+ guid_to_tool_elem_dict[ guid ] = generate_tool_elem( tool_shed, repository.name, repository.changeset_revision, repository.owner or '', tool_config_filename, tool, None )
+ config_elems = []
+ tree = util.parse_xml( shed_tool_conf )
+ root = tree.getroot()
+ for elem in root:
+ if elem.tag == 'section':
+ for i, tool_elem in enumerate( elem ):
+ guid = tool_elem.attrib.get( 'guid' )
+ if guid in guid_to_tool_elem_dict:
+ elem[i] = guid_to_tool_elem_dict[ guid ]
+ elif elem.tag == 'tool':
+ guid = elem.attrib.get( 'guid' )
+ if guid in guid_to_tool_elem_dict:
+ elem = guid_to_tool_elem_dict[ guid ]
+ config_elems.append( elem )
+ config_elems_to_xml_file( app, config_elems, shed_tool_conf, tool_path )
def update_repository( repo, ctx_rev=None ):
"""
Update the cloned repository to changeset_revision. It is critical that the installed repository is updated to the desired
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
4 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/921a612db28a/
changeset: 921a612db28a
user: dan
date: 2012-10-09 16:24:58
summary: Enhance Galaxy's model.ToolShedRepository to handle shed_conf_dict easier.
affected #: 1 file
diff -r 413cf15e4065a9f8d559ca110e6e86b84f8a6620 -r 921a612db28a69a33dc1ea8bef5ed20ffa63bba2 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -2987,6 +2987,78 @@
return relative_path
return None
@property
+ def tool_shed_path_name( self ):
+ tool_shed_url = self.tool_shed
+ if tool_shed_url.find( ':' ) > 0:
+ # Eliminate the port, if any, since it will result in an invalid directory name.
+ tool_shed_url = tool_shed_url.split( ':' )[ 0 ]
+ return tool_shed_url.rstrip( '/' )
+ def get_tool_relative_path( self, app ):
+ shed_conf_dict = self.get_shed_config_dict( app )
+ tool_path = None
+ relative_path = None
+ if shed_conf_dict:
+ tool_path = shed_conf_dict[ 'tool_path' ]
+ relative_path = os.path.join( self.tool_shed_path_name, 'repos', self.owner, self.name, self.installed_changeset_revision )
+ return tool_path, relative_path
+ def get_shed_config_filename( self ):
+ shed_config_filename = None
+ if self.metadata:
+ shed_config_filename = self.metadata.get( 'shed_config_filename', shed_config_filename )
+ return shed_config_filename
+ def set_shed_config_filename( self, value ):
+ self.metadata[ 'shed_config_filename' ] = value
+ shed_config_filename = property( get_shed_config_filename, set_shed_config_filename )
+ def guess_shed_config( self, app, default=None ):
+ tool_ids = []
+ metadata = self.metadata or {}
+ for tool in metadata.get( 'tools', [] ):
+ tool_ids.append( tool.get( 'guid' ) )
+ for shed_tool_conf_dict in app.toolbox.shed_tool_confs:
+ name = shed_tool_conf_dict[ 'config_filename' ]
+ for elem in shed_tool_conf_dict[ 'config_elems' ]:
+ if elem.tag == 'tool':
+ for sub_elem in elem.findall( 'id' ):
+ tool_id = sub_elem.text.strip()
+ if tool_id in tool_ids:
+ self.shed_config_filename = name
+ return shed_tool_conf_dict
+ elif elem.tag == "section":
+ for tool_elem in elem.findall( 'tool' ):
+ for sub_elem in tool_elem.findall( 'id' ):
+ tool_id = sub_elem.text.strip()
+ if tool_id in tool_ids:
+ self.shed_config_filename = name
+ return shed_tool_conf_dict
+ if self.includes_datatypes:
+ #we need to search by filepaths here, which is less desirable
+ tool_shed_url = self.tool_shed
+ if tool_shed_url.find( ':' ) > 0:
+ # Eliminate the port, if any, since it will result in an invalid directory name.
+ tool_shed_url = tool_shed_url.split( ':' )[ 0 ]
+ tool_shed = tool_shed_url.rstrip( '/' )
+ for shed_tool_conf_dict in app.toolbox.shed_tool_confs:
+ tool_path = shed_tool_conf_dict[ 'tool_path' ]
+ relative_path = os.path.join( tool_path, tool_shed, 'repos', self.owner, self.name, self.installed_changeset_revision )
+ if os.path.exists( relative_path ):
+ self.shed_config_filename = shed_tool_conf_dict[ 'config_filename' ]
+ return shed_tool_conf_dict
+ #if self.dist_to_shed:
+ # #return ./migrated_tools.xml
+ return default
+ def get_shed_config_dict( self, app, default=None ):
+ """
+ Return the in-memory version of the shed_tool_conf file, which is stored in the config_elems entry
+ in the shed_tool_conf_dict.
+ """
+ if not self.shed_config_filename:
+ self.guess_shed_config( app, default=default )
+ if self.shed_config_filename:
+ for shed_tool_conf_dict in app.toolbox.shed_tool_confs:
+ if self.shed_config_filename == shed_tool_conf_dict[ 'config_filename' ]:
+ return shed_tool_conf_dict
+ return default
+ @property
def can_install( self ):
return self.status == self.installation_status.NEW
@property
https://bitbucket.org/galaxy/galaxy-central/changeset/0263d37b08e6/
changeset: 0263d37b08e6
user: dan
date: 2012-10-09 16:24:58
summary: Add a helper method to the toolbox to provide a shed_config_dict based upon the provided filename.
affected #: 1 file
diff -r 921a612db28a69a33dc1ea8bef5ed20ffa63bba2 -r 0263d37b08e610e572b5f08940c19a6f19f0931d lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -150,6 +150,11 @@
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).
https://bitbucket.org/galaxy/galaxy-central/changeset/97eb5bde48da/
changeset: 97eb5bde48da
user: dan
date: 2012-10-09 16:24:59
summary: Enhance Galaxy's handling of Tool Shed Repositories to work with hierarchical relative paths.
affected #: 3 files
diff -r 0263d37b08e610e572b5f08940c19a6f19f0931d -r 97eb5bde48da4575e8de4fed64fe910a4df45dce lib/galaxy/tool_shed/install_manager.py
--- a/lib/galaxy/tool_shed/install_manager.py
+++ b/lib/galaxy/tool_shed/install_manager.py
@@ -33,9 +33,12 @@
root = tree.getroot()
self.tool_shed = clean_tool_shed_url( root.get( 'name' ) )
self.repository_owner = REPOSITORY_OWNER
+ index, self.shed_config_dict = get_shed_tool_conf_dict( app, self.migrated_tools_config )
for repository_elem in root:
self.install_repository( repository_elem, install_dependencies )
def get_guid( self, repository_clone_url, relative_install_dir, tool_config ):
+ if self.shed_config_dict.get( 'tool_path' ):
+ relative_install_dir = os.path.join( self.shed_config_dict['tool_path'], relative_install_dir )
found = False
for root, dirs, files in os.walk( relative_install_dir ):
if root.find( '.hg' ) < 0 and root.find( 'hgrc' ) < 0:
@@ -122,6 +125,10 @@
def handle_repository_contents( self, tool_shed_repository, repository_clone_url, relative_install_dir, repository_elem, install_dependencies ):
"""Generate the metadata for the installed tool shed repository, among other things."""
tool_panel_dict_for_display = odict()
+ if self.tool_path:
+ repo_install_dir = os.path.join( self.tool_path, relative_install_dir )
+ else:
+ repo_install_dir = relative_install_dir
for tool_elem in repository_elem:
# The tool_elem looks something like this: <tool id="EMBOSS: antigenic1" version="5.0.0" file="emboss_antigenic.xml" />
tool_config = tool_elem.get( 'file' )
@@ -135,6 +142,7 @@
metadata_dict, invalid_file_tups = generate_metadata_for_changeset_revision( app=self.app,
repository=tool_shed_repository,
repository_clone_url=repository_clone_url,
+ shed_config_dict = self.shed_config_dict,
relative_install_dir=relative_install_dir,
repository_files_dir=None,
resetting_all_metadata_on_repository=False,
@@ -150,7 +158,7 @@
if 'tools' in metadata_dict:
sample_files = metadata_dict.get( 'sample_files', [] )
tool_index_sample_files = get_tool_index_sample_files( sample_files )
- copy_sample_files( self.app, tool_index_sample_files )
+ copy_sample_files( self.app, tool_index_sample_files, tool_path=self.tool_path )
sample_files_copied = [ s for s in tool_index_sample_files ]
repository_tools_tups = get_repository_tools_tups( self.app, metadata_dict )
if repository_tools_tups:
@@ -163,14 +171,14 @@
repository_tools_tups,
sample_files_copied )
# Copy remaining sample files included in the repository to the ~/tool-data directory of the local Galaxy instance.
- copy_sample_files( self.app, sample_files, sample_files_copied=sample_files_copied )
+ copy_sample_files( self.app, sample_files, tool_path=self.tool_path, sample_files_copied=sample_files_copied )
if install_dependencies and tool_dependencies and 'tool_dependencies' in metadata_dict:
# Install tool dependencies.
update_tool_shed_repository_status( self.app,
tool_shed_repository,
self.app.model.ToolShedRepository.installation_status.INSTALLING_TOOL_DEPENDENCIES )
# Get the tool_dependencies.xml file from disk.
- tool_dependencies_config = get_config_from_disk( 'tool_dependencies.xml', relative_install_dir )
+ tool_dependencies_config = get_config_from_disk( 'tool_dependencies.xml', repo_install_dir )
installed_tool_dependencies = handle_tool_dependencies( app=self.app,
tool_shed_repository=tool_shed_repository,
tool_dependencies_config=tool_dependencies_config,
@@ -195,10 +203,10 @@
self.app.sa_session.add( tool_shed_repository )
self.app.sa_session.flush()
work_dir = tempfile.mkdtemp()
- datatypes_config = get_config_from_disk( 'datatypes_conf.xml', relative_install_dir )
+ datatypes_config = get_config_from_disk( 'datatypes_conf.xml', repo_install_dir )
# Load proprietary data types required by tools. The value of override is not important here since the Galaxy server will be started
# after this installation completes.
- converter_path, display_path = alter_config_and_load_prorietary_datatypes( self.app, datatypes_config, relative_install_dir, override=False )
+ converter_path, display_path = alter_config_and_load_prorietary_datatypes( self.app, datatypes_config, repo_install_dir, override=False ) #repo_install_dir was relative_install_dir
if converter_path or display_path:
# Create a dictionary of tool shed repository related information.
repository_dict = create_repository_dict_for_proprietary_datatypes( tool_shed=self.tool_shed,
@@ -224,13 +232,15 @@
description = repository_elem.get( 'description' )
installed_changeset_revision = repository_elem.get( 'changeset_revision' )
# Install path is of the form: <tool path>/<tool shed>/repos/<repository owner>/<repository name>/<installed changeset revision>
- clone_dir = os.path.join( self.tool_path, self.tool_shed, 'repos', self.repository_owner, name, installed_changeset_revision )
+ relative_clone_dir = os.path.join( self.tool_shed, 'repos', self.repository_owner, name, installed_changeset_revision )
+ clone_dir = os.path.join( self.tool_path, relative_clone_dir )
if self.__isinstalled( clone_dir ):
print "Skipping automatic install of repository '", name, "' because it has already been installed in location ", clone_dir
else:
tool_shed_url = self.__get_url_from_tool_shed( self.tool_shed )
repository_clone_url = os.path.join( tool_shed_url, 'repos', self.repository_owner, name )
- relative_install_dir = os.path.join( clone_dir, name )
+ relative_install_dir = os.path.join( relative_clone_dir, name )
+ install_dir = os.path.join( clone_dir, name )
ctx_rev = get_ctx_rev( tool_shed_url, name, self.repository_owner, installed_changeset_revision )
print "Adding new row (or updating an existing row) for repository '%s' in the tool_shed_repository table." % name
tool_shed_repository = create_or_update_tool_shed_repository( app=self.app,
@@ -245,7 +255,7 @@
owner=self.repository_owner,
dist_to_shed=True )
update_tool_shed_repository_status( self.app, tool_shed_repository, self.app.model.ToolShedRepository.installation_status.CLONING )
- cloned_ok, error_message = clone_repository( repository_clone_url, os.path.abspath( relative_install_dir ), ctx_rev )
+ cloned_ok, error_message = clone_repository( repository_clone_url, os.path.abspath( install_dir ), ctx_rev )
if cloned_ok:
self.handle_repository_contents( tool_shed_repository=tool_shed_repository,
repository_clone_url=repository_clone_url,
diff -r 0263d37b08e610e572b5f08940c19a6f19f0931d -r 97eb5bde48da4575e8de4fed64fe910a4df45dce lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -387,6 +387,8 @@
else:
tmp_url = repository_clone_url
return tmp_url
+def tool_shed_from_repository_clone_url( repository_clone_url ):
+ return clean_repository_clone_url( repository_clone_url ).split( 'repos' )[ 0 ].rstrip( '/' )
def clean_tool_shed_url( tool_shed_url ):
if tool_shed_url.find( ':' ) > 0:
# Eliminate the port, if any, since it will result in an invalid directory name.
@@ -421,7 +423,7 @@
# Only create the .loc file if it does not yet exist. We don't overwrite it in case it contains stuff proprietary to the local instance.
if not os.path.exists( os.path.join( dest_path, copied_file ) ):
shutil.copy( full_source_path, os.path.join( dest_path, copied_file ) )
-def copy_sample_files( app, sample_files, sample_files_copied=None, dest_path=None ):
+def copy_sample_files( app, sample_files, tool_path=None, sample_files_copied=None, dest_path=None ):
"""
Copy all files to dest_path in the local Galaxy environment that have not already been copied. Those that have been copied
are contained in sample_files_copied. The default value for dest_path is ~/tool-data.
@@ -429,6 +431,8 @@
sample_files_copied = util.listify( sample_files_copied )
for filename in sample_files:
if filename not in sample_files_copied:
+ if tool_path:
+ filename=os.path.join( tool_path, filename )
copy_sample_file( app, filename, dest_path=dest_path )
def create_repo_info_dict( repository, owner, repository_clone_url, changeset_revision, ctx_rev, metadata ):
repo_info_dict = {}
@@ -504,6 +508,9 @@
def create_tool_dependency_objects( app, tool_shed_repository, relative_install_dir, set_status=True ):
# Create or update a ToolDependency for each entry in tool_dependencies_config. This method is called when installing a new tool_shed_repository.
tool_dependency_objects = []
+ shed_config_dict = tool_shed_repository.get_shed_config_dict( app )
+ if shed_config_dict.get( 'tool_path' ):
+ relative_install_dir = os.path.join( shed_config_dict.get( 'tool_path' ), relative_install_dir )
# Get the tool_dependencies.xml file from the repository.
tool_dependencies_config = get_config_from_disk( 'tool_dependencies.xml', relative_install_dir )
try:
@@ -601,7 +608,7 @@
else:
tool_dependencies_dict[ 'set_environment' ] = [ requirements_dict ]
return tool_dependencies_dict
-def generate_metadata_for_changeset_revision( app, repository, repository_clone_url, relative_install_dir=None, repository_files_dir=None,
+def generate_metadata_for_changeset_revision( app, repository, repository_clone_url, shed_config_dict={}, relative_install_dir=None, repository_files_dir=None,
resetting_all_metadata_on_repository=False, updating_installed_repository=False ):
"""
Generate metadata for a repository using it's files on disk. To generate metadata for changeset revisions older than the repository tip,
@@ -616,7 +623,7 @@
else:
original_repository_metadata = None
readme_file_names = get_readme_file_names( repository.name )
- metadata_dict = {}
+ metadata_dict = { 'shed_config_filename': shed_config_dict.get( 'config_filename' ) }
invalid_file_tups = []
invalid_tool_configs = []
tool_dependencies_config = None
@@ -637,6 +644,8 @@
work_dir = tempfile.mkdtemp()
# All other files are on disk in the repository's repo_path, which is the value of relative_install_dir.
files_dir = relative_install_dir
+ if shed_config_dict.get( 'tool_path' ):
+ files_dir = os.path.join( shed_config_dict['tool_path'], files_dir )
app.config.tool_data_path = work_dir
app.config.tool_data_table_config_path = work_dir
# Handle proprietary datatypes, if any.
@@ -645,6 +654,7 @@
metadata_dict = generate_datatypes_metadata( datatypes_config, metadata_dict )
# Get the relative path to all sample files included in the repository for storage in the repository's metadata.
sample_file_metadata_paths, sample_file_copy_paths = get_sample_files_from_disk( repository_files_dir=files_dir,
+ tool_path=shed_config_dict.get( 'tool_path' ),
relative_install_dir=relative_install_dir,
resetting_all_metadata_on_repository=resetting_all_metadata_on_repository )
if sample_file_metadata_paths:
@@ -674,6 +684,8 @@
relative_path_to_readme = os.path.join( relative_install_dir, stripped_path_to_readme )
else:
relative_path_to_readme = os.path.join( root, name )
+ if relative_install_dir and shed_config_dict.get( 'tool_path' ) and relative_path_to_readme.startswith( os.path.join( shed_config_dict.get( 'tool_path' ), relative_install_dir ) ):
+ relative_path_to_readme = relative_path_to_readme[ len( shed_config_dict.get( 'tool_path' ) ) + 1: ]
metadata_dict[ 'readme' ] = relative_path_to_readme
# See if we have a tool config.
elif name not in NOT_TOOL_CONFIGS and name.endswith( '.xml' ):
@@ -711,6 +723,8 @@
relative_path_to_tool_config = os.path.join( relative_install_dir, stripped_path_to_tool_config )
else:
relative_path_to_tool_config = os.path.join( root, name )
+ if relative_install_dir and shed_config_dict.get( 'tool_path' ) and relative_path_to_tool_config.startswith( os.path.join( shed_config_dict.get( 'tool_path' ), relative_install_dir ) ):
+ relative_path_to_tool_config = relative_path_to_tool_config[ len( shed_config_dict.get( 'tool_path' ) ) + 1: ]
metadata_dict = generate_tool_metadata( relative_path_to_tool_config, tool, repository_clone_url, metadata_dict )
else:
for tup in invalid_files_and_errors_tups:
@@ -844,13 +858,35 @@
else:
metadata_dict[ 'tools' ] = [ tool_dict ]
return metadata_dict
+def generate_tool_elem( tool_shed, repository_name, changeset_revision, owner, tool_file_path, tool, tool_section ):
+ if tool_section is not None:
+ tool_elem = SubElement( tool_section, 'tool' )
+ else:
+ tool_elem = Element( 'tool' )
+ tool_elem.attrib[ 'file' ] = tool_file_path
+ tool_elem.attrib[ 'guid' ] = tool.guid
+ tool_shed_elem = SubElement( tool_elem, 'tool_shed' )
+ tool_shed_elem.text = tool_shed
+ repository_name_elem = SubElement( tool_elem, 'repository_name' )
+ repository_name_elem.text = repository_name
+ repository_owner_elem = SubElement( tool_elem, 'repository_owner' )
+ repository_owner_elem.text = owner
+ changeset_revision_elem = SubElement( tool_elem, 'installed_changeset_revision' )
+ changeset_revision_elem.text = changeset_revision
+ id_elem = SubElement( tool_elem, 'id' )
+ id_elem.text = tool.id
+ version_elem = SubElement( tool_elem, 'version' )
+ version_elem.text = tool.version
+ return tool_elem
+
def generate_tool_panel_elem_list( repository_name, repository_clone_url, changeset_revision, tool_panel_dict, repository_tools_tups, owner='' ):
"""Generate a list of ElementTree Element objects for each section or tool."""
elem_list = []
tool_elem = None
- tmp_url = clean_repository_clone_url( repository_clone_url )
+ cleaned_repository_clone_url = clean_repository_clone_url( repository_clone_url )
if not owner:
- owner = get_repository_owner( tmp_url )
+ owner = get_repository_owner( cleaned_repository_clone_url )
+ tool_shed = cleaned_repository_clone_url.split( 'repos' )[ 0 ].rstrip( '/' )
for guid, tool_section_dicts in tool_panel_dict.items():
for tool_section_dict in tool_section_dicts:
tool_section = None
@@ -874,23 +910,9 @@
if tup_guid == guid:
break
if inside_section:
- tool_elem = SubElement( tool_section, 'tool' )
+ tool_elem = generate_tool_elem( tool_shed, repository_name, changeset_revision, owner, tool_file_path, tool, tool_section )
else:
- tool_elem = Element( 'tool' )
- tool_elem.attrib[ 'file' ] = tool_file_path
- tool_elem.attrib[ 'guid' ] = guid
- tool_shed_elem = SubElement( tool_elem, 'tool_shed' )
- tool_shed_elem.text = tmp_url.split( 'repos' )[ 0 ].rstrip( '/' )
- repository_name_elem = SubElement( tool_elem, 'repository_name' )
- repository_name_elem.text = repository_name
- repository_owner_elem = SubElement( tool_elem, 'repository_owner' )
- repository_owner_elem.text = owner
- changeset_revision_elem = SubElement( tool_elem, 'installed_changeset_revision' )
- changeset_revision_elem.text = changeset_revision
- id_elem = SubElement( tool_elem, 'id' )
- id_elem.text = tool.id
- version_elem = SubElement( tool_elem, 'version' )
- version_elem.text = tool.version
+ tool_elem = generate_tool_elem( tool_shed, repository_name, changeset_revision, owner, tool_file_path, tool, None )
if inside_section:
if section_in_elem_list:
elem_list[ index ] = tool_section
@@ -1253,18 +1275,21 @@
return get_repository_owner( tmp_url )
def get_repository_tools_tups( app, metadata_dict ):
repository_tools_tups = []
+ index, shed_conf_dict = get_shed_tool_conf_dict( app, metadata_dict.get( 'shed_config_filename' ) )
if 'tools' in metadata_dict:
for tool_dict in metadata_dict[ 'tools' ]:
- relative_path = tool_dict.get( 'tool_config', None )
+ load_relative_path = relative_path = tool_dict.get( 'tool_config', None )
+ if shed_conf_dict.get( 'tool_path' ):
+ load_relative_path = os.path.join( shed_conf_dict.get( 'tool_path' ), relative_path )
guid = tool_dict.get( 'guid', None )
if relative_path and guid:
- tool = app.toolbox.load_tool( os.path.abspath( relative_path ), guid=guid )
+ tool = app.toolbox.load_tool( os.path.abspath( load_relative_path ), guid=guid )
else:
tool = None
if tool:
repository_tools_tups.append( ( relative_path, guid, tool ) )
return repository_tools_tups
-def get_sample_files_from_disk( repository_files_dir, relative_install_dir=None, resetting_all_metadata_on_repository=False ):
+def get_sample_files_from_disk( repository_files_dir, tool_path = None, relative_install_dir=None, resetting_all_metadata_on_repository=False ):
if resetting_all_metadata_on_repository:
# Keep track of the location where the repository is temporarily cloned so that we can strip it when setting metadata.
work_dir = repository_files_dir
@@ -1287,6 +1312,9 @@
else:
relative_path_to_sample_file = os.path.join( root, name )
sample_file_copy_paths.append( relative_path_to_sample_file )
+ if tool_path and relative_install_dir:
+ if relative_path_to_sample_file.startswith( os.path.join( tool_path, relative_install_dir ) ):
+ relative_path_to_sample_file = relative_path_to_sample_file[ len( tool_path ) + 1 :]
sample_file_metadata_paths.append( relative_path_to_sample_file )
return sample_file_metadata_paths, sample_file_copy_paths
def get_shed_tool_conf_dict( app, shed_tool_conf ):
@@ -1327,46 +1355,16 @@
partial_install_dir = '%s/repos/%s/%s/%s' % ( tool_shed, repository.owner, repository.name, repository.installed_changeset_revision )
# Get the relative tool installation paths from each of the shed tool configs.
relative_install_dir = None
- for shed_tool_conf_dict in app.toolbox.shed_tool_confs:
- shed_tool_conf = shed_tool_conf_dict[ 'config_filename' ]
- if repository.dist_to_shed:
- # The repository is owned by devteam and contains tools migrated from the Galaxy distribution to the tool shed, so
- # the reserved tool panel config is migrated_tools_conf.xml, to which app.config.migrated_tools_config refers.
- if shed_tool_conf == app.config.migrated_tools_config:
- tool_path = shed_tool_conf_dict[ 'tool_path' ]
- relative_install_dir = os.path.join( tool_path, partial_install_dir )
- if tool_path and relative_install_dir:
- return shed_tool_conf, tool_path, relative_install_dir
- elif repository.uninstalled:
- # Since the repository is uninstalled we don't know what tool panel config was originally used to
- # define the tools in the repository, so we'll just make sure not to use the reserved migrated_tools_conf.xml.
- if shed_tool_conf != app.config.migrated_tools_config:
- tool_path = shed_tool_conf_dict[ 'tool_path' ]
- relative_install_dir = os.path.join( tool_path, partial_install_dir )
- if tool_path and relative_install_dir:
- return shed_tool_conf, tool_path, relative_install_dir
- else:
- if repository.includes_tools:
- metadata = repository.metadata
- for tool_dict in metadata[ 'tools' ]:
- # Parse the tool panel config to get the entire set of config_elems. # We'll check config_elems until we
- # find an element that matches one of the tools in the repository's metadata.
- tool_panel_config = shed_tool_conf_dict[ 'config_filename' ]
- tree = util.parse_xml( tool_panel_config )
- root = tree.getroot()
- tool_path, relative_install_dir = get_tool_path_install_dir( partial_install_dir,
- shed_tool_conf_dict,
- tool_dict,
- root )
- if tool_path and relative_install_dir:
- return shed_tool_conf, tool_path, relative_install_dir
- else:
- # Nothing will be loaded into the tool panel, so look for the installed repository on disk.
- tool_path = shed_tool_conf_dict[ 'tool_path' ]
- relative_install_dir = os.path.join( tool_path, partial_install_dir )
- if tool_path and relative_install_dir and os.path.isdir( relative_install_dir ):
- return shed_tool_conf, tool_path, relative_install_dir
- return None, None, None
+ shed_config_dict = repository.get_shed_config_dict( app )
+ if not shed_config_dict:
+ #just pick a semi-random shed config
+ for shed_config_dict in app.toolbox.shed_tool_confs:
+ if ( repository.dist_to_shed and shed_config_dict['config_filename'] == app.config.migrated_tools_config ) or ( not repository.dist_to_shed and shed_config_dict['config_filename'] != app.config.migrated_tools_config ):
+ break
+ shed_tool_conf = shed_config_dict[ 'config_filename' ]
+ tool_path = shed_config_dict[ 'tool_path' ]
+ relative_install_dir = partial_install_dir
+ return shed_tool_conf, tool_path, relative_install_dir
def get_tool_path_install_dir( partial_install_dir, shed_tool_conf_dict, tool_dict, config_elems ):
for elem in config_elems:
if elem.tag == 'tool':
@@ -1774,6 +1772,42 @@
config_elems.remove( config_elem )
# Persist the altered in-memory version of the tool config.
config_elems_to_xml_file( trans.app, config_elems, shed_tool_conf, tool_path )
+def update_in_shed_tool_config( app, repository ):
+ # A tool shed repository is being updated so change the shed_tool_conf file. Parse the config file to generate the entire list
+ # of config_elems instead of using the in-memory list.
+ shed_conf_dict = repository.get_shed_config_dict( app )
+ shed_tool_conf = shed_conf_dict[ 'config_filename' ]
+ tool_path = shed_conf_dict[ 'tool_path' ]
+
+ #hack for 'trans.app' used in lots of places. These places should just directly use app
+ trans = util.bunch.Bunch()
+ trans.app = app
+
+ tool_panel_dict = generate_tool_panel_dict_from_shed_tool_conf_entries( trans, repository )
+ repository_tools_tups = get_repository_tools_tups( app, repository.metadata )
+ cleaned_repository_clone_url = clean_repository_clone_url( generate_clone_url( trans, repository ) )
+ tool_shed = tool_shed_from_repository_clone_url( cleaned_repository_clone_url )
+ owner = repository.owner
+ if not owner:
+ owner = get_repository_owner( cleaned_repository_clone_url )
+ guid_to_tool_elem_dict = {}
+ for tool_config_filename, guid, tool in repository_tools_tups:
+ guid_to_tool_elem_dict[ guid ] = generate_tool_elem( tool_shed, repository.name, repository.changeset_revision, repository.owner or '', tool_config_filename, tool, None )
+ config_elems = []
+ tree = util.parse_xml( shed_tool_conf )
+ root = tree.getroot()
+ for elem in root:
+ if elem.tag == 'section':
+ for i, tool_elem in enumerate( elem ):
+ guid = tool_elem.attrib.get( 'guid' )
+ if guid in guid_to_tool_elem_dict:
+ elem[i] = guid_to_tool_elem_dict[ guid ]
+ elif elem.tag == 'tool':
+ guid = elem.attrib.get( 'guid' )
+ if guid in guid_to_tool_elem_dict:
+ elem = guid_to_tool_elem_dict[ guid ]
+ config_elems.append( elem )
+ config_elems_to_xml_file( app, config_elems, shed_tool_conf, tool_path )
def remove_from_tool_panel( trans, repository, shed_tool_conf, uninstall ):
"""A tool shed repository is being deactivated or uninstalled so handle tool panel alterations accordingly."""
# Determine where the tools are currently defined in the tool panel and store this information so the tools can be displayed
diff -r 0263d37b08e610e572b5f08940c19a6f19f0931d -r 97eb5bde48da4575e8de4fed64fe910a4df45dce lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
@@ -655,15 +655,17 @@
update_tool_shed_repository_status( trans.app, tool_shed_repository, trans.model.ToolShedRepository.installation_status.CLONING )
repo_info_tuple = repo_info_dict[ tool_shed_repository.name ]
description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, tool_dependencies = repo_info_tuple
- clone_dir = os.path.join( tool_path, self.generate_tool_path( repository_clone_url, tool_shed_repository.installed_changeset_revision ) )
- relative_install_dir = os.path.join( clone_dir, tool_shed_repository.name )
- cloned_ok, error_message = clone_repository( repository_clone_url, os.path.abspath( relative_install_dir ), ctx_rev )
+ relative_clone_dir = self.generate_tool_path( repository_clone_url, tool_shed_repository.installed_changeset_revision )
+ clone_dir = os.path.join( tool_path, relative_clone_dir )
+ relative_install_dir = os.path.join( relative_clone_dir, tool_shed_repository.name )
+ install_dir = os.path.join( tool_path, relative_install_dir )
+ cloned_ok, error_message = clone_repository( repository_clone_url, os.path.abspath( install_dir ), ctx_rev )
if cloned_ok:
if reinstalling:
# Since we're reinstalling the repository we need to find the latest changeset revision to which is can be updated.
current_changeset_revision, current_ctx_rev = get_update_to_changeset_revision_and_ctx_rev( trans, tool_shed_repository )
if current_ctx_rev != ctx_rev:
- repo = hg.repository( get_configured_ui(), path=os.path.abspath( relative_install_dir ) )
+ repo = hg.repository( get_configured_ui(), path=os.path.abspath( install_dir ) )
pull_repository( repo, repository_clone_url, current_changeset_revision )
update_repository( repo, ctx_rev=current_ctx_rev )
self.handle_repository_contents( trans,
@@ -704,7 +706,7 @@
tool_shed_repository,
trans.model.ToolShedRepository.installation_status.INSTALLING_TOOL_DEPENDENCIES )
# Get the tool_dependencies.xml file from the repository.
- tool_dependencies_config = get_config_from_disk( 'tool_dependencies.xml', relative_install_dir )
+ tool_dependencies_config = get_config_from_disk( 'tool_dependencies.xml', install_dir )#relative_install_dir )
installed_tool_dependencies = handle_tool_dependencies( app=trans.app,
tool_shed_repository=tool_shed_repository,
tool_dependencies_config=tool_dependencies_config,
@@ -736,6 +738,7 @@
metadata_dict, invalid_file_tups = generate_metadata_for_changeset_revision( app=trans.app,
repository=tool_shed_repository,
repository_clone_url=repository_clone_url,
+ shed_config_dict = trans.app.toolbox.get_shed_config_dict_by_filename( shed_tool_conf ),
relative_install_dir=relative_install_dir,
repository_files_dir=None,
resetting_all_metadata_on_repository=False,
@@ -749,7 +752,7 @@
tool_panel_dict = generate_tool_panel_dict_for_new_install( metadata_dict[ 'tools' ], tool_section )
sample_files = metadata_dict.get( 'sample_files', [] )
tool_index_sample_files = get_tool_index_sample_files( sample_files )
- copy_sample_files( self.app, tool_index_sample_files )
+ copy_sample_files( self.app, tool_index_sample_files, tool_path=tool_path )
sample_files_copied = [ s for s in tool_index_sample_files ]
repository_tools_tups = get_repository_tools_tups( trans.app, metadata_dict )
if repository_tools_tups:
@@ -762,7 +765,7 @@
repository_tools_tups,
sample_files_copied )
# Copy remaining sample files included in the repository to the ~/tool-data directory of the local Galaxy instance.
- copy_sample_files( trans.app, sample_files, sample_files_copied=sample_files_copied )
+ copy_sample_files( trans.app, sample_files, tool_path=tool_path, sample_files_copied=sample_files_copied )
add_to_tool_panel( app=trans.app,
repository_name=tool_shed_repository.name,
repository_clone_url=repository_clone_url,
@@ -805,6 +808,8 @@
repository_id = kwd[ 'id' ]
operation = kwd.get( 'operation', None )
repository = get_repository( trans, repository_id )
+ if not repository:
+ return trans.show_error_message( 'Invalid repository specified.' )
if repository.status in [ trans.model.ToolShedRepository.installation_status.CLONING ]:
return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
action='monitor_repository_installation',
@@ -822,7 +827,7 @@
description = util.restore_text( params.get( 'description', repository.description ) )
shed_tool_conf, tool_path, relative_install_dir = get_tool_panel_config_tool_path_install_dir( trans.app, repository )
if relative_install_dir:
- repo_files_dir = os.path.abspath( os.path.join( relative_install_dir, repository.name ) )
+ repo_files_dir = os.path.abspath( os.path.join( tool_path, relative_install_dir, repository.name ) )
else:
repo_files_dir = None
if repository.in_error_state:
@@ -1447,20 +1452,27 @@
repository = get_repository( trans, id )
tool_shed_url = get_url_from_repository_tool_shed( trans.app, repository )
repository_clone_url = self.__generate_clone_url( trans, repository )
- relative_install_dir = repository.repo_path( trans.app )
+ tool_path, relative_install_dir = repository.get_tool_relative_path( trans.app )
if relative_install_dir:
+ original_metadata_dict = repository.metadata
metadata_dict, invalid_file_tups = generate_metadata_for_changeset_revision( app=trans.app,
repository=repository,
repository_clone_url=repository_clone_url,
+ shed_config_dict = repository.get_shed_config_dict( trans.app ),
relative_install_dir=relative_install_dir,
repository_files_dir=None,
resetting_all_metadata_on_repository=False,
updating_installed_repository=False )
repository.metadata = metadata_dict
- trans.sa_session.add( repository )
- trans.sa_session.flush()
- message = 'Metadata has been reset on repository <b>%s</b>.' % repository.name
- status = 'done'
+ if metadata_dict != original_metadata_dict:
+ update_in_shed_tool_config( trans.app, repository )#def update_in_shed_tool_config( trans, shed_tool_conf_dict, elem_list ):
+ trans.sa_session.add( repository )
+ trans.sa_session.flush()
+ message = 'Metadata has been reset on repository <b>%s</b>.' % repository.name
+ status = 'done'
+ else:
+ message = 'Metadata did not need to be reset on repository <b>%s</b>.' % repository.name
+ status = 'done'
else:
message = 'Error locating installation directory for repository <b>%s</b>.' % repository.name
status = 'error'
@@ -1618,7 +1630,10 @@
else:
shed_tool_conf, tool_path, relative_install_dir = get_tool_panel_config_tool_path_install_dir( trans.app, repository )
if relative_install_dir:
- repo_files_dir = os.path.abspath( os.path.join( relative_install_dir, name ) )
+ if tool_path:
+ repo_files_dir = os.path.abspath( os.path.join( tool_path, relative_install_dir, name ) )
+ else:
+ repo_files_dir = os.path.abspath( os.path.join( relative_install_dir, name ) )
repo = hg.repository( get_configured_ui(), path=repo_files_dir )
repository_clone_url = os.path.join( tool_shed_url, 'repos', owner, name )
pull_repository( repo, repository_clone_url, latest_ctx_rev )
@@ -1628,6 +1643,7 @@
metadata_dict, invalid_file_tups = generate_metadata_for_changeset_revision( app=trans.app,
repository=repository,
repository_clone_url=repository_clone_url,
+ shed_config_dict = repository.get_shed_config_dict( trans.app ),
relative_install_dir=relative_install_dir,
repository_files_dir=None,
resetting_all_metadata_on_repository=False,
@@ -1667,8 +1683,13 @@
status = params.get( 'status', 'done' )
repository = get_repository( trans, id )
metadata = repository.metadata
+ shed_config_dict = repository.get_shed_config_dict( trans.app )
+ tool_path = shed_config_dict.get( 'tool_path', None )
if metadata and 'readme' in metadata:
- f = open( metadata[ 'readme' ], 'r' )
+ readme_filename = metadata[ 'readme' ]
+ if tool_path:
+ readme_filename = os.path.join( tool_path, readme_filename )
+ f = open( readme_filename, 'r' )
raw_text = f.read()
f.close()
readme_text = translate_string( raw_text, to_html=True )
@@ -1691,6 +1712,7 @@
status = params.get( 'status', 'done' )
repository = get_repository( trans, repository_id )
repository_metadata = repository.metadata
+ shed_config_dict = repository.get_shed_config_dict( trans.app )
tool_metadata = {}
tool_lineage = []
tool = None
@@ -1698,7 +1720,10 @@
for tool_metadata_dict in repository_metadata[ 'tools' ]:
if tool_metadata_dict[ 'id' ] == tool_id:
tool_metadata = tool_metadata_dict
- tool = trans.app.toolbox.load_tool( os.path.abspath( tool_metadata[ 'tool_config' ] ), guid=tool_metadata[ 'guid' ] )
+ tool_config = tool_metadata[ 'tool_config' ]
+ if shed_config_dict and shed_config_dict.get( 'tool_path' ):
+ tool_config = os.path.join( shed_config_dict.get( 'tool_path' ), tool_config )
+ tool = trans.app.toolbox.load_tool( os.path.abspath( tool_config ), guid=tool_metadata[ 'guid' ] )
if tool:
tool_lineage = self.get_versions_of_tool( trans.app, tool.id )
break
https://bitbucket.org/galaxy/galaxy-central/changeset/429e895ee1b3/
changeset: 429e895ee1b3
user: dan
date: 2012-10-09 16:24:59
summary: Enhance manage_repository.mako to handle null repository metadata.
affected #: 1 file
diff -r 97eb5bde48da4575e8de4fed64fe910a4df45dce -r 429e895ee1b3bfb2fea1632d34a01d54faeac866 templates/admin/tool_shed_repository/manage_repository.mako
--- a/templates/admin/tool_shed_repository/manage_repository.mako
+++ b/templates/admin/tool_shed_repository/manage_repository.mako
@@ -95,7 +95,7 @@
<div class="toolFormTitle">${repository.name}</div><div class="toolFormBody"><%
- metadata = repository.metadata
+ metadata = repository.metadata or {}
missing_tool_dependencies = repository.missing_tool_dependencies
installed_tool_dependencies = repository.installed_tool_dependencies
%>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/40b252052087/
changeset: 40b252052087
user: chapmanb
date: 2012-10-04 21:31:16
summary: Correctly set history and handle output datasets for error cases in tool API. Allow specification of dataset name during uploads, exposing through API
affected #: 3 files
diff -r f3b183e756f9b209ef0904718ed547e04c74ab7a -r 40b252052087bc06fd1adc47f9633a496a7dd07c lib/galaxy/tools/parameters/grouping.py
--- a/lib/galaxy/tools/parameters/grouping.py
+++ b/lib/galaxy/tools/parameters/grouping.py
@@ -209,7 +209,7 @@
dataset_name = get_file_name( data_file['filename'] )
if not dataset_info:
dataset_info = 'uploaded file'
- return Bunch( type='file', path=data_file['local_filename'], name=get_file_name( data_file['filename'] ) )
+ return Bunch( type='file', path=data_file['local_filename'], name=dataset_name )
#return 'file', data_file['local_filename'], get_file_name( data_file.filename ), dataset_name, dataset_info
except:
# The uploaded file should've been persisted by the upload tool action
@@ -227,14 +227,13 @@
if line:
if not line.lower().startswith( 'http://' ) and not line.lower().startswith( 'ftp://' ) and not line.lower().startswith( 'https://' ):
continue # non-url line, ignore
- precreated_name = line
dataset_name = override_name
if not dataset_name:
dataset_name = line
dataset_info = override_info
if not dataset_info:
dataset_info = 'uploaded url'
- yield Bunch( type='url', path=line, name=precreated_name )
+ yield Bunch( type='url', path=line, name=dataset_name )
#yield ( 'url', line, precreated_name, dataset_name, dataset_info )
else:
dataset_name = dataset_info = precreated_name = 'Pasted Entry' #we need to differentiate between various url pastes here
diff -r f3b183e756f9b209ef0904718ed547e04c74ab7a -r 40b252052087bc06fd1adc47f9633a496a7dd07c lib/galaxy/webapps/galaxy/api/tools.py
--- a/lib/galaxy/webapps/galaxy/api/tools.py
+++ b/lib/galaxy/webapps/galaxy/api/tools.py
@@ -55,6 +55,17 @@
tool = trans.app.toolbox.get_tool( tool_id )
if not tool:
return { "message": { "type": "error", "text" : messages.NO_TOOL } }
+
+ # Set running history from payload parameters.
+ # History not set correctly as part of this API call for
+ # dataset upload.
+ history_id = payload.get("history_id", None)
+ if history_id:
+ target_history = trans.sa_session.query(trans.app.model.History).get(
+ trans.security.decode_id(history_id))
+ trans.galaxy_session.current_history = target_history
+ else:
+ target_history = None
# Set up inputs.
inputs = payload[ 'inputs' ]
@@ -62,10 +73,10 @@
inputs['runtool_btn'] = 'Execute'
# TODO: encode data ids and decode ids.
params = util.Params( inputs, sanitize = False )
- template, vars = tool.handle_input( trans, params.__dict__ )
-
+ template, vars = tool.handle_input( trans, params.__dict__, history=target_history)
+
# TODO: check for errors and ensure that output dataset(s) are available.
- output_datasets = vars[ 'out_data' ].values()
+ output_datasets = vars.get('out_data', {}).values()
rval = {
"outputs": []
}
diff -r f3b183e756f9b209ef0904718ed547e04c74ab7a -r 40b252052087bc06fd1adc47f9633a496a7dd07c tools/data_source/upload.xml
--- a/tools/data_source/upload.xml
+++ b/tools/data_source/upload.xml
@@ -41,6 +41,7 @@
<param name="space_to_tab" type="select" display="checkboxes" multiple="True" label="Convert spaces to tabs" help="Use this option if you are entering intervals by hand."><option value="Yes">Yes</option></param>
+ <param name="NAME" type="hidden" help="Name for dataset in upload"></param></upload_dataset><param name="dbkey" type="genomebuild" label="Genome" /><conditional name="files_metadata" title="Specify metadata" value_from="self:app.datatypes_registry.get_upload_metadata_params" value_ref="file_type" value_ref_in_group="False" />
https://bitbucket.org/galaxy/galaxy-central/changeset/413cf15e4065/
changeset: 413cf15e4065
user: jgoecks
date: 2012-10-09 05:44:02
summary: Merged in chapmanb/galaxy-central-apiupload (pull request #74)
affected #: 3 files
diff -r 8269f76312af60e356707bc660b6e9903e402106 -r 413cf15e4065a9f8d559ca110e6e86b84f8a6620 lib/galaxy/tools/parameters/grouping.py
--- a/lib/galaxy/tools/parameters/grouping.py
+++ b/lib/galaxy/tools/parameters/grouping.py
@@ -209,7 +209,7 @@
dataset_name = get_file_name( data_file['filename'] )
if not dataset_info:
dataset_info = 'uploaded file'
- return Bunch( type='file', path=data_file['local_filename'], name=get_file_name( data_file['filename'] ) )
+ return Bunch( type='file', path=data_file['local_filename'], name=dataset_name )
#return 'file', data_file['local_filename'], get_file_name( data_file.filename ), dataset_name, dataset_info
except:
# The uploaded file should've been persisted by the upload tool action
@@ -227,14 +227,13 @@
if line:
if not line.lower().startswith( 'http://' ) and not line.lower().startswith( 'ftp://' ) and not line.lower().startswith( 'https://' ):
continue # non-url line, ignore
- precreated_name = line
dataset_name = override_name
if not dataset_name:
dataset_name = line
dataset_info = override_info
if not dataset_info:
dataset_info = 'uploaded url'
- yield Bunch( type='url', path=line, name=precreated_name )
+ yield Bunch( type='url', path=line, name=dataset_name )
#yield ( 'url', line, precreated_name, dataset_name, dataset_info )
else:
dataset_name = dataset_info = precreated_name = 'Pasted Entry' #we need to differentiate between various url pastes here
diff -r 8269f76312af60e356707bc660b6e9903e402106 -r 413cf15e4065a9f8d559ca110e6e86b84f8a6620 lib/galaxy/webapps/galaxy/api/tools.py
--- a/lib/galaxy/webapps/galaxy/api/tools.py
+++ b/lib/galaxy/webapps/galaxy/api/tools.py
@@ -55,6 +55,17 @@
tool = trans.app.toolbox.get_tool( tool_id )
if not tool:
return { "message": { "type": "error", "text" : messages.NO_TOOL } }
+
+ # Set running history from payload parameters.
+ # History not set correctly as part of this API call for
+ # dataset upload.
+ history_id = payload.get("history_id", None)
+ if history_id:
+ target_history = trans.sa_session.query(trans.app.model.History).get(
+ trans.security.decode_id(history_id))
+ trans.galaxy_session.current_history = target_history
+ else:
+ target_history = None
# Set up inputs.
inputs = payload[ 'inputs' ]
@@ -62,10 +73,10 @@
inputs['runtool_btn'] = 'Execute'
# TODO: encode data ids and decode ids.
params = util.Params( inputs, sanitize = False )
- template, vars = tool.handle_input( trans, params.__dict__ )
-
+ template, vars = tool.handle_input( trans, params.__dict__, history=target_history)
+
# TODO: check for errors and ensure that output dataset(s) are available.
- output_datasets = vars[ 'out_data' ].values()
+ output_datasets = vars.get('out_data', {}).values()
rval = {
"outputs": []
}
diff -r 8269f76312af60e356707bc660b6e9903e402106 -r 413cf15e4065a9f8d559ca110e6e86b84f8a6620 tools/data_source/upload.xml
--- a/tools/data_source/upload.xml
+++ b/tools/data_source/upload.xml
@@ -41,6 +41,7 @@
<param name="space_to_tab" type="select" display="checkboxes" multiple="True" label="Convert spaces to tabs" help="Use this option if you are entering intervals by hand."><option value="Yes">Yes</option></param>
+ <param name="NAME" type="hidden" help="Name for dataset in upload"></param></upload_dataset><param name="dbkey" type="genomebuild" label="Genome" /><conditional name="files_metadata" title="Specify metadata" value_from="self:app.datatypes_registry.get_upload_metadata_params" value_ref="file_type" value_ref_in_group="False" />
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