mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-21 13:50:20 +08:00
Visualizations Registry: default to on
This commit is contained in:
@@ -7,9 +7,15 @@
|
||||
<test type="isinstance" test_attr="datatype" result_type="datatype">tabular.Tabular</test>
|
||||
<to_param param_attr="id">dataset_id</to_param>
|
||||
</data_source>
|
||||
<data_source>
|
||||
<model_class>Visualization</model_class>
|
||||
<test test_attr="type">scatterplot</test>
|
||||
<to_param param_attr="id">visualization_id</to_param>
|
||||
</data_source>
|
||||
</data_sources>
|
||||
<params>
|
||||
<param type="dataset" var_name_in_template="hda" required="true">dataset_id</param>
|
||||
<param type="visualization" var_name_in_template="visualization">visualization_id</param>
|
||||
</params>
|
||||
<template>scatterplot.mako</template>
|
||||
</visualization>
|
||||
|
||||
@@ -10,6 +10,7 @@ todo:
|
||||
Allow setting perPage of config
|
||||
Auto render if given data and/or config
|
||||
Allow option to auto set width/height based on screen real estate avail.
|
||||
Handle large number of pages better (Known genes hg19)
|
||||
Use d3.nest to allow grouping, pagination/filtration by group (e.g. chromCol)
|
||||
Semantic HTML (figure, caption)
|
||||
Save as visualization, load from visualization
|
||||
@@ -29,26 +30,28 @@ todo:
|
||||
* configuring which data will be used
|
||||
* configuring the plot display
|
||||
*/
|
||||
var ScatterplotConfigEditor = BaseView.extend( LoggableMixin ).extend({
|
||||
var ScatterplotConfigEditor = Backbone.View.extend( LoggableMixin ).extend({
|
||||
//TODO: !should be a view on a visualization model
|
||||
//logger : console,
|
||||
className : 'scatterplot-control-form',
|
||||
|
||||
/** initialize requires a configuration Object containing a dataset Object */
|
||||
initialize : function( attributes ){
|
||||
//console.log( this + '.initialize, attributes:', attributes );
|
||||
if( !attributes || !attributes.config || !attributes.dataset ){
|
||||
throw new Error( "ScatterplotView requires a configuration and dataset" );
|
||||
if( !this.model ){
|
||||
this.model = new Visualization({ type: 'scatterplot' });
|
||||
}
|
||||
//console.log( 'config:', attributes.config );
|
||||
console.log( this + '.initialize, attributes:', attributes );
|
||||
|
||||
if( !attributes || !attributes.dataset ){
|
||||
throw new Error( "ScatterplotConfigEditor requires a dataset" );
|
||||
}
|
||||
this.dataset = attributes.dataset;
|
||||
//console.log( 'dataset:', this.dataset );
|
||||
console.log( 'dataset:', this.dataset );
|
||||
|
||||
//TODO: ScatterplotView -> ScatterplotDisplay, this.plotView -> this.display
|
||||
this.plotView = new ScatterplotView({
|
||||
dataset : attributes.dataset,
|
||||
config : attributes.config
|
||||
model : this.model
|
||||
//TODO: if data
|
||||
});
|
||||
},
|
||||
@@ -58,8 +61,7 @@ var ScatterplotConfigEditor = BaseView.extend( LoggableMixin ).extend({
|
||||
//console.log( this + '.render' );
|
||||
|
||||
// render the tab controls, areas and loading indicator
|
||||
this.$el.append( ScatterplotConfigEditor.templates.mainLayout({
|
||||
}));
|
||||
this.$el.append( ScatterplotConfigEditor.templates.mainLayout({}));
|
||||
|
||||
// render the tab content
|
||||
this.$el.find( '#data-control' ).append( this._render_dataControl() );
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,3 +1,24 @@
|
||||
<%
|
||||
hda_dict = trans.security.encode_dict_ids( hda.to_dict() )
|
||||
|
||||
config = query_args
|
||||
title = "Scatterplot of '" + hda.name + "'"
|
||||
info = hda.info
|
||||
|
||||
visualization = context.get( 'visualization' )
|
||||
if visualization is not None:
|
||||
config = visualization.latest_revision.config
|
||||
config.update( query_args )
|
||||
title = visualization.title
|
||||
info = config.get( 'description', info )
|
||||
|
||||
config[ 'type' ] = 'scatterplot'
|
||||
|
||||
# optionally bootstrap data from dprov
|
||||
##data = list( hda.datatype.dataset_column_dataprovider( hda, limit=10000 ) )
|
||||
%>
|
||||
## ----------------------------------------------------------------------------
|
||||
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
@@ -13,14 +34,15 @@
|
||||
## ----------------------------------------------------------------------------
|
||||
<script type="text/javascript" src="/static/scripts/libs/jquery/jquery.js"></script>
|
||||
<script type="text/javascript" src="/static/scripts/libs/jquery/jquery.migrate.js"></script>
|
||||
<script type="text/javascript" src="/static/scripts/libs/jquery/jquery-ui.js"></script>
|
||||
<script type="text/javascript" src="/static/scripts/libs/bootstrap.js"></script>
|
||||
<script type="text/javascript" src="/static/scripts/libs/underscore.js"></script>
|
||||
<script type="text/javascript" src="/static/scripts/libs/backbone/backbone.js"></script>
|
||||
<script type="text/javascript" src="/static/scripts/libs/handlebars.runtime.js"></script>
|
||||
<script type="text/javascript" src="/static/scripts/libs/d3.js"></script>
|
||||
<script type="text/javascript" src="/static/scripts/libs/bootstrap.js"></script>
|
||||
<script type="text/javascript" src="/static/scripts/libs/jquery/jquery-ui.js"></script>
|
||||
<script type="text/javascript" src="/static/scripts/utils/LazyDataLoader.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/static/scripts/mvc/base-mvc.js"></script>
|
||||
<script type="text/javascript" src="/static/scripts/mvc/visualization/visualization-model.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/plugins/visualizations/scatterplot/static/scatterplot-edit.js"></script>
|
||||
</head>
|
||||
@@ -30,25 +52,20 @@
|
||||
%if not embedded:
|
||||
## dataset info: only show if on own page
|
||||
<div class="chart-header">
|
||||
<h2>Scatterplot of '${hda.name}'</h2>
|
||||
<p>${hda.info}</p>
|
||||
<h2>${title}</h2>
|
||||
<p>${info}</p>
|
||||
</div>
|
||||
|
||||
<div class="scatterplot-editor"></div>
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
<%
|
||||
# optionally, bootstrap data from dprov
|
||||
data = None
|
||||
##data = list( hda.datatype.dataset_column_dataprovider( hda, limit=10000 ) )
|
||||
%>
|
||||
var hda = ${h.to_json_string( trans.security.encode_dict_ids( hda.to_dict() ) )};
|
||||
|
||||
var editor = new ScatterplotConfigEditor({
|
||||
el : $( '.scatterplot-editor' ).attr( 'id', 'scatterplot-editor-hda-' + hda.id ),
|
||||
config : ${h.to_json_string( query_args )},
|
||||
dataset : ${h.to_json_string( trans.security.encode_dict_ids( hda.to_dict() ) )}
|
||||
}).render();
|
||||
var model = new ScatterplotModel( ${h.to_json_string( config )} ),
|
||||
hdaJson = ${h.to_json_string( hda_dict )},
|
||||
editor = new ScatterplotConfigEditor({
|
||||
el : $( '.scatterplot-editor' ).attr( 'id', 'scatterplot-editor-hda-' + hdaJson.id ),
|
||||
model : model,
|
||||
dataset : hdaJson
|
||||
}).render();
|
||||
window.editor = editor;
|
||||
// uncomment to auto render for development
|
||||
//$( '.render-button:visible' ).click();
|
||||
|
||||
+2
-2
@@ -87,9 +87,9 @@ class UniverseApplication( object, config.ConfiguresGalaxyMixin ):
|
||||
load_genome_index_tools( self.toolbox )
|
||||
# visualizations registry: associates resources with visualizations, controls how to render
|
||||
self.visualizations_registry = None
|
||||
if self.config.visualizations_plugins_directory:
|
||||
if self.config.visualization_plugins_directory:
|
||||
self.visualizations_registry = VisualizationsRegistry( self,
|
||||
directories_setting=self.config.visualizations_plugins_directory,
|
||||
directories_setting=self.config.visualization_plugins_directory,
|
||||
template_cache_dir=self.config.template_cache )
|
||||
# Load security policy.
|
||||
self.security_agent = self.model.security_agent
|
||||
|
||||
@@ -343,7 +343,7 @@ class Configuration( object ):
|
||||
self.fluent_host = kwargs.get( 'fluent_host', 'localhost' )
|
||||
self.fluent_port = int( kwargs.get( 'fluent_port', 24224 ) )
|
||||
# visualization plugin framework
|
||||
self.visualizations_plugins_directory = kwargs.get( 'visualizations_plugins_directory', None )
|
||||
self.visualization_plugins_directory = kwargs.get( 'visualization_plugins_directory', None )
|
||||
|
||||
@property
|
||||
def sentry_dsn_public( self ):
|
||||
|
||||
@@ -38,6 +38,61 @@ add description element to visualization.
|
||||
user_pref for ordering/ex/inclusion of particular visualizations
|
||||
"""
|
||||
|
||||
# ------------------------------------------------------------------- misc
|
||||
#TODO: move to utils?
|
||||
def getattr_recursive( item, attr_key, *args ):
|
||||
"""
|
||||
Allows dot member notation in attribute name when getting an item's attribute.
|
||||
|
||||
NOTE: also searches dictionaries
|
||||
"""
|
||||
#print '\n\t getattr_recursive:', item, attr_key
|
||||
using_default = len( args ) >= 1
|
||||
default = args[0] if using_default else None
|
||||
#print '\t defaults:', using_default, default
|
||||
|
||||
for attr_key in attr_key.split( '.' ):
|
||||
try:
|
||||
#print '\t\t attr:', attr_key, 'item:', item
|
||||
if isinstance( item, dict ):
|
||||
item = item.__getitem__( attr_key )
|
||||
else:
|
||||
item = getattr( item, attr_key )
|
||||
|
||||
except ( KeyError, AttributeError ), err:
|
||||
#print '\t\t error:', err
|
||||
if using_default:
|
||||
#print '\t\t\t default:', default
|
||||
return default
|
||||
raise
|
||||
|
||||
return item
|
||||
|
||||
def hasattr_recursive( item, attr_key ):
|
||||
"""
|
||||
Allows dot member notation in attribute name when getting an item's attribute.
|
||||
|
||||
NOTE: also searches dictionaries
|
||||
"""
|
||||
if '.' in attr_key:
|
||||
attr_key, last_key = attr_key.rsplit( '.', 1 )
|
||||
item = getattr_recursive( item, attr_key, None )
|
||||
if item is None:
|
||||
return False
|
||||
attr_key = last_key
|
||||
|
||||
try:
|
||||
#print '\t\t attr:', attr_key, 'item:', item
|
||||
if isinstance( item, dict ):
|
||||
return item.__contains__( attr_key )
|
||||
else:
|
||||
return hasattr( item, attr_key )
|
||||
|
||||
except ( KeyError, AttributeError ), err:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
# ------------------------------------------------------------------- the registry
|
||||
class VisualizationsRegistry( pluginframework.PageServingPluginManager ):
|
||||
"""
|
||||
@@ -141,21 +196,26 @@ class VisualizationsRegistry( pluginframework.PageServingPluginManager ):
|
||||
`visualization_name` if it's applicable to `target_object` or
|
||||
`None` if it's not.
|
||||
"""
|
||||
#log.debug( 'VisReg.get_visualization: %s, %s', visualization_name, target_object )
|
||||
visualization = self.plugins.get( visualization_name, None )
|
||||
if not visualization:
|
||||
return None
|
||||
|
||||
data_sources = visualization.config[ 'data_sources' ]
|
||||
for data_source in data_sources:
|
||||
#log.debug( 'data_source: %s', data_source )
|
||||
# currently a model class is required
|
||||
model_class = data_source[ 'model_class' ]
|
||||
#log.debug( '\t model_class: %s', model_class )
|
||||
if not isinstance( target_object, model_class ):
|
||||
continue
|
||||
#log.debug( '\t passed model_class' )
|
||||
|
||||
# tests are optional - default is the above class test
|
||||
tests = data_source[ 'tests' ]
|
||||
if tests and not self.is_object_applicable( trans, target_object, tests ):
|
||||
continue
|
||||
#log.debug( '\t passed tests' )
|
||||
|
||||
param_data = data_source[ 'to_params' ]
|
||||
url = self.get_visualization_url( trans, target_object, visualization_name, param_data )
|
||||
@@ -199,7 +259,7 @@ class VisualizationsRegistry( pluginframework.PageServingPluginManager ):
|
||||
|
||||
#NOTE: tests are OR'd, if any test passes - the visualization can be applied
|
||||
if test_fn( target_object, test_result ):
|
||||
#log.debug( 'test passed' )
|
||||
#log.debug( '\t test passed' )
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -212,6 +272,8 @@ class VisualizationsRegistry( pluginframework.PageServingPluginManager ):
|
||||
#precondition: the target_object should be usable by the visualization (accrd. to data_sources)
|
||||
# convert params using vis.data_source.to_params
|
||||
params = self.get_url_params( trans, target_object, param_data )
|
||||
#for param in params:
|
||||
# print param
|
||||
|
||||
# we want existing visualizations to work as normal but still be part of the registry (without mod'ing)
|
||||
# so generate their urls differently
|
||||
@@ -238,13 +300,20 @@ class VisualizationsRegistry( pluginframework.PageServingPluginManager ):
|
||||
# one or the other is needed
|
||||
# assign takes precedence (goes last, overwrites)?
|
||||
#NOTE this is only one level
|
||||
if target_attr and hasattr( target_object, target_attr ):
|
||||
params[ to_param_name ] = getattr( target_object, target_attr )
|
||||
|
||||
#print 'target_object:', target_object
|
||||
#print 'target_attr:', target_attr
|
||||
|
||||
if target_attr and hasattr_recursive( target_object, target_attr ):
|
||||
params[ to_param_name ] = getattr_recursive( target_object, target_attr )
|
||||
#print 'params[ %s ]:' %( to_param_name ), params[ to_param_name ]
|
||||
|
||||
if assign:
|
||||
params[ to_param_name ] = assign
|
||||
|
||||
#NOTE!: don't expose raw ids: encode id, _id
|
||||
if params:
|
||||
#TODO: double encodes if from config
|
||||
params = trans.security.encode_dict_ids( params )
|
||||
return params
|
||||
|
||||
@@ -407,6 +476,7 @@ class DataSourceParser( object ):
|
||||
# these are the allowed classes to associate visualizations with (as strings)
|
||||
# any model_class element not in this list will throw a parsing ParsingExcepion
|
||||
ALLOWED_MODEL_CLASSES = [
|
||||
'Visualization',
|
||||
'HistoryDatasetAssociation',
|
||||
'LibraryDatasetDatasetAssociation'
|
||||
]
|
||||
@@ -683,6 +753,9 @@ class ResourceParser( object ):
|
||||
|
||||
If param is required and not present, raises a `KeyError`.
|
||||
"""
|
||||
# first parse any params from any visualizations that were passed
|
||||
query_params = self.get_params_from_visualization_param( trans, controller, param_config_dict, query_params )
|
||||
|
||||
# parse the modifiers first since they modify the params coming next
|
||||
#TODO: this is all really for hda_ldda - which we could replace with model polymorphism
|
||||
params_that_modify_other_params = self.parse_parameter_modifiers(
|
||||
@@ -761,6 +834,44 @@ class ResourceParser( object ):
|
||||
# (and adding this code to the xml parser)
|
||||
return self.parse_parameter( trans, param_config, default )
|
||||
|
||||
def get_params_from_visualization_param( self, trans, controller, param_config_dict, query_params ):
|
||||
log.debug( 'parse_visualization_params: %s', param_config_dict )
|
||||
log.debug( ' : %s', query_params )
|
||||
|
||||
# first, find the visualization in the parameters if any
|
||||
visualization = None
|
||||
#precondition: assume one visualization
|
||||
for param_name, param_config in param_config_dict.items():
|
||||
if param_config.get( 'type' ) == 'visualization':
|
||||
query_val = query_params.get( param_name )
|
||||
if query_val is None:
|
||||
continue
|
||||
|
||||
log.debug( 'found visualization param: %s, %s', param_name, query_val )
|
||||
visualization = self.parse_parameter( trans, controller, param_config, query_val )
|
||||
if visualization:
|
||||
break
|
||||
|
||||
# if no vis is found, can't get any new params from it: return the original query_params
|
||||
if not visualization:
|
||||
log.debug( 'visualization not found' )
|
||||
return query_params
|
||||
log.debug( 'found visualization: %s', visualization )
|
||||
|
||||
# next, attempt to copy any params from the visualizations config
|
||||
visualization_config = visualization.latest_revision.config
|
||||
log.debug( '\t config: %s', visualization_config )
|
||||
params_from_visualization = {}
|
||||
for param_name, param_config in param_config_dict.items():
|
||||
if param_name in visualization_config:
|
||||
params_from_visualization[ param_name ] = visualization_config[ param_name ]
|
||||
log.debug( 'params_from_visualization: %s', params_from_visualization )
|
||||
|
||||
# layer the query_params over the params from the visualization, returning the combined
|
||||
params_from_visualization.update( query_params )
|
||||
return params_from_visualization
|
||||
|
||||
#TODO: make parse_visualization separate
|
||||
def parse_parameter( self, trans, controller, expected_param_data, query_param,
|
||||
recurse=True, param_modifiers=None ):
|
||||
"""
|
||||
@@ -808,6 +919,7 @@ class ResourceParser( object ):
|
||||
#TODO: subclass here?
|
||||
elif param_type == 'visualization':
|
||||
encoded_visualization_id = query_param
|
||||
log.debug( 'visualization param, id : %s', encoded_visualization_id )
|
||||
#TODO:?? some fallback if there's no get_X in controller that's passed?
|
||||
parsed_param = controller.get_visualization( trans, encoded_visualization_id,
|
||||
check_ownership=False, check_accessible=True )
|
||||
|
||||
@@ -248,7 +248,6 @@ var HDAEditView = hdaBase.HDABaseView.extend( LoggableMixin ).extend(
|
||||
classes : 'dataset-visualize-btn',
|
||||
faIcon : 'fa-bar-chart-o'
|
||||
});
|
||||
$icon.addClass( 'visualize-icon' ); // needed?
|
||||
|
||||
// No need for popup menu because there's a single visualization.
|
||||
if( _.keys( visualizations ).length === 1 ) {
|
||||
@@ -259,9 +258,21 @@ var HDAEditView = hdaBase.HDABaseView.extend( LoggableMixin ).extend(
|
||||
} else {
|
||||
var popup_menu_options = [];
|
||||
_.each( visualizations, function( linkData ) {
|
||||
linkData.func = function(){
|
||||
if( Galaxy.frame.active ){
|
||||
Galaxy.frame.add({
|
||||
title : "Visualization",
|
||||
type : "url",
|
||||
content : linkData.href
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
popup_menu_options.push( linkData );
|
||||
return false;
|
||||
});
|
||||
var popup = new PopupMenu( $icon, popup_menu_options );
|
||||
PopupMenu.create( $icon, popup_menu_options );
|
||||
}
|
||||
return $icon;
|
||||
},
|
||||
|
||||
@@ -359,6 +359,10 @@ var PopupMenu = Backbone.View.extend({
|
||||
return 'PopupMenu';
|
||||
}
|
||||
});
|
||||
/** shortcut to new for when you don't need to preserve the ref */
|
||||
PopupMenu.create = function _create( $button, options ){
|
||||
return new PopupMenu( $button, options );
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// the following class functions are bridges from the original make_popupmenu and make_popup_menus
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
//define([
|
||||
//], function(){
|
||||
|
||||
//function saveVis( title, config ){
|
||||
// var xhr = jQuery.ajax( '/api/visualizations', {
|
||||
// type : 'POST',
|
||||
// data : {
|
||||
// type : 'scatterplot',
|
||||
// title : title,
|
||||
// config : JSON.stringify( config )
|
||||
// }
|
||||
// });
|
||||
// xhr.fail( function( xhr, status, message ){
|
||||
// console.debug( jQuery.makeArray( arguments ) );
|
||||
// console.error( 'Error saving visualization:', xhr.responseJSON.error );
|
||||
// });
|
||||
// return xhr.then( function( saveInfo ){
|
||||
// return saveInfo;
|
||||
// });
|
||||
//}
|
||||
|
||||
//==============================================================================
|
||||
/** @class Model for a saved Galaxy visualization.
|
||||
*
|
||||
* @augments Backbone.Model
|
||||
* @borrows LoggableMixin#logger as #logger
|
||||
* @borrows LoggableMixin#log as #log
|
||||
* @constructs
|
||||
*/
|
||||
var Visualization = Backbone.Model.extend( LoggableMixin ).extend(
|
||||
/** @lends Visualization.prototype */{
|
||||
|
||||
///** logger used to record this.log messages, commonly set to console */
|
||||
//// comment this out to suppress log output
|
||||
//logger : console,
|
||||
|
||||
/** default attributes for a model */
|
||||
defaults : {
|
||||
//id : null,
|
||||
//type : null,
|
||||
//title : null,
|
||||
//dbkey : null,
|
||||
//user_id : null,
|
||||
//slug : null,
|
||||
//revisions : [],
|
||||
//latest_revision : null
|
||||
|
||||
//(this is unusual in that visualizations don't have configs, revisions do)
|
||||
//config : {}
|
||||
},
|
||||
|
||||
url : function(){
|
||||
return galaxy_config.root + 'api/visualizations';
|
||||
},
|
||||
|
||||
/** Set up the model, determine if accessible, bind listeners
|
||||
* @see Backbone.Model#initialize
|
||||
*/
|
||||
initialize : function( data ){
|
||||
this.log( this + '.initialize', data, this.attributes );
|
||||
this._setUpListeners();
|
||||
},
|
||||
|
||||
/** set up any event listeners
|
||||
*/
|
||||
_setUpListeners : function(){
|
||||
},
|
||||
|
||||
// ........................................................................ config
|
||||
setConfig: function( config ){
|
||||
var oldConfig = this.get( 'config' );
|
||||
// extend if already exists (and clone in order to trigger change)
|
||||
if( _.isObject( oldConfig ) ){
|
||||
config = _.extend( _.clone( oldConfig ), config );
|
||||
}
|
||||
this.set( 'config', config );
|
||||
return this;
|
||||
},
|
||||
|
||||
// ........................................................................ common queries
|
||||
// ........................................................................ ajax
|
||||
// ........................................................................ misc
|
||||
/** String representation */
|
||||
toString : function(){
|
||||
var idAndTitle = this.get( 'id' ) || '';
|
||||
if( this.get( 'title' ) ){
|
||||
idAndTitle += ':' + this.get( 'title' );
|
||||
}
|
||||
return 'Visualization(' + idAndTitle + ')';
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** @class Backbone collection of visualization models
|
||||
*
|
||||
* @borrows LoggableMixin#logger as #logger
|
||||
* @borrows LoggableMixin#log as #log
|
||||
* @constructs
|
||||
*/
|
||||
var VisualizationCollection = Backbone.Collection.extend( LoggableMixin ).extend(
|
||||
/** @lends VisualizationCollection.prototype */{
|
||||
model : Visualization,
|
||||
|
||||
///** logger used to record this.log messages, commonly set to console */
|
||||
//// comment this out to suppress log output
|
||||
//logger : console,
|
||||
|
||||
url : function(){
|
||||
return galaxy_config.root + 'api/visualizations';
|
||||
},
|
||||
|
||||
/** Set up.
|
||||
* @see Backbone.Collection#initialize
|
||||
*/
|
||||
initialize : function( models, options ){
|
||||
options = options || {};
|
||||
//this._setUpListeners();
|
||||
},
|
||||
|
||||
//_setUpListeners : function(){
|
||||
//},
|
||||
|
||||
// ........................................................................ common queries
|
||||
// ........................................................................ ajax
|
||||
// ........................................................................ misc
|
||||
set : function( models, options ){
|
||||
// arrrrrrrrrrrrrrrrrg...
|
||||
// override to get a correct/smarter merge when incoming data is partial (e.g. stupid backbone)
|
||||
// w/o this partial models from the server will fill in missing data with model defaults
|
||||
// and overwrite existing data on the client
|
||||
// see Backbone.Collection.set and _prepareModel
|
||||
var collection = this;
|
||||
models = _.map( models, function( model ){
|
||||
var existing = collection.get( model.id );
|
||||
if( !existing ){ return model; }
|
||||
|
||||
// merge the models _BEFORE_ calling the superclass version
|
||||
var merged = existing.toJSON();
|
||||
_.extend( merged, model );
|
||||
return merged;
|
||||
});
|
||||
// now call superclass when the data is filled
|
||||
Backbone.Collection.prototype.set.call( this, models, options );
|
||||
},
|
||||
|
||||
/** String representation. */
|
||||
toString : function(){
|
||||
return ([ 'VisualizationCollection(', [ this.historyId, this.length ].join(), ')' ].join( '' ));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//==============================================================================
|
||||
//return {
|
||||
// Visualization : Visualization,
|
||||
// VisualizationCollection : VisualizationCollection
|
||||
//};});
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -216,7 +216,7 @@ ${h.templates(
|
||||
)}
|
||||
|
||||
${h.js(
|
||||
"mvc/visualizations/scatterplotControlForm",
|
||||
"mvc/visualization/scatterplotControlForm",
|
||||
)}
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
@@ -177,7 +177,7 @@ paste.app_factory = galaxy.web.buildapp:app_factory
|
||||
# Visualizations config directory: where to look for individual visualization plugins.
|
||||
# The path is relative to the Galaxy root dir. To use an absolute path begin the path
|
||||
# with '/'.
|
||||
#visualizations_plugins_directory = config/plugins/visualizations
|
||||
visualization_plugins_directory = config/plugins/visualizations
|
||||
|
||||
# Each job is given a unique empty directory as its current working directory.
|
||||
# This option defines in what parent directory those directories will be
|
||||
|
||||
Reference in New Issue
Block a user