commit/galaxy-central: jgoecks: Unify Trackster tool objects with generic tool objects. This unification enhances the generic tool framework and simplifies the trackster tool framework. Also, backbone-ify Trackster tool handling.
1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/31d2d58ebf10/ Changeset: 31d2d58ebf10 User: jgoecks Date: 2013-08-08 23:05:51 Summary: Unify Trackster tool objects with generic tool objects. This unification enhances the generic tool framework and simplifies the trackster tool framework. Also, backbone-ify Trackster tool handling. Affected #: 3 files diff -r 8c3b553871bbcce9170d235f5188b9803094ad3b -r 31d2d58ebf102f87c21f170b16452d06fd510a14 lib/galaxy/visualization/genome/visual_analytics.py --- a/lib/galaxy/visualization/genome/visual_analytics.py +++ b/lib/galaxy/visualization/genome/visual_analytics.py @@ -38,6 +38,8 @@ def get_tool_def( trans, hda ): """ Returns definition of an interactive tool for an HDA. """ + + #FIXME: use tools.to_dict rather than custom code here. job = get_dataset_job( hda ) # TODO: could use this assertion to provide more information. @@ -71,10 +73,10 @@ tool_params.append( param_dict ) elif type( input ) == SelectToolParameter and type( input.options ) != DynamicOptions: tool_params.append( { 'name' : name, 'label' : input.label, 'type' : 'select', \ - 'value' : tool_param_values.get( name, None ), \ + 'value' : tool_param_values.get( name, '' ), \ 'html' : urllib.quote( input.get_html() ) } ) # If tool has parameters that can be interactively modified, return tool. if len( tool_params ) != 0: - return { 'id': tool.id, 'name' : tool.name, 'params' : tool_params } + return { 'id': tool.id, 'name' : tool.name, 'inputs' : tool_params } return None \ No newline at end of file diff -r 8c3b553871bbcce9170d235f5188b9803094ad3b -r 31d2d58ebf102f87c21f170b16452d06fd510a14 static/scripts/mvc/tools.js --- a/static/scripts/mvc/tools.js +++ b/static/scripts/mvc/tools.js @@ -41,6 +41,7 @@ label: null, type: null, value: null, + html: null, num_samples: 5 }, @@ -70,7 +71,51 @@ } return samples; - } + }, + + set_value: function(value) { + this.set('value', value || ''); + } +}, +{ + /** + * Dictionary mapping parameter type strings to parameter classes. + */ + TYPE_DICT: { + 'number': IntegerToolParameter + }, + + /** + * Create new parameter from a dictionary. + */ + create: function(options) { + var param_class = ToolParameter.TYPE_DICT[options.type] || ToolParameter; + return new param_class(options); + } +}); + +/** + * A number tool parameter. + */ +var IntegerToolParameter = ToolParameter.extend({ + defaults: _.extend({}, ToolParameter.prototype.defaults, { + min: null, + max: null + }), + + initialize: function() { + ToolParameter.prototype.initialize.call(this); + if (this.attributes.min) { + this.attributes.min = parseInt(this.attributes.min, 10); + } + if (this.attributes.max) { + this.attributes.max = parseInt(this.attributes.max, 10); + } + }, + + set_value: function(value) { + this.set('value', parseInt(value, 10)) + } }); /** @@ -79,22 +124,22 @@ var Tool = BaseModel.extend({ // Default attributes. defaults: { + id: null, + name: null, description: null, target: null, inputs: [] }, - - relations: [ - { - type: Backbone.HasMany, - key: 'inputs', - relatedModel: ToolParameter, - reverseRelation: { - key: 'tool', - includeInJSON: false - } - } - ], + + initialize: function(options) { + // Unpack parameters manually so that different parameter types can be created. + this.attributes.inputs = new Backbone.Collection( _.map(options.inputs, function(param_dict) { + // FIXME: it is still useful to be able to save/restore tool state? + // Update parameter value from tool state dict. + //param_dict.value = tool_state_dict[ param_dict[name] ] || param_dict.value; + return ToolParameter.create(param_dict); + })); + }, urlRoot: galaxy_paths.get('tool_url'), @@ -209,6 +254,13 @@ }); /** + * Tool view. + */ +var ToolView = Backbone.View.extend({ + +}); + +/** * Wrap collection of tools for fast access/manipulation. */ var ToolCollection = Backbone.Collection.extend({ @@ -697,6 +749,8 @@ // Exports return { + ToolParameter: ToolParameter, + IntegerToolParameter: IntegerToolParameter, Tool: Tool, ToolSearch: ToolSearch, ToolPanel: ToolPanel, diff -r 8c3b553871bbcce9170d235f5188b9803094ad3b -r 31d2d58ebf102f87c21f170b16452d06fd510a14 static/scripts/viz/trackster/tracks.js --- a/static/scripts/viz/trackster/tracks.js +++ b/static/scripts/viz/trackster/tracks.js @@ -1,7 +1,7 @@ define( ["libs/underscore", "viz/visualization", "viz/trackster/util", - "viz/trackster/slotting", "viz/trackster/painters", "mvc/data", - "viz/trackster/filters" ], - function( _, visualization, util, slotting, painters, data, filters_mod ) { + "viz/trackster/slotting", "viz/trackster/painters", "viz/trackster/filters", + "mvc/data", "mvc/tools" ], + function(_, visualization, util, slotting, painters, filters_mod, data, tools_mod) { var extend = _.extend; @@ -1622,89 +1622,103 @@ /** * Encapsulation of a tool that users can apply to tracks/datasets. */ -var Tool = function(track, tool_dict, tool_state_dict) { - // - // Unpack tool information from dictionary. - // - this.track = track; - this.id = tool_dict.id; - this.name = tool_dict.name; - this.params = []; - var params_dict = tool_dict.params; - for (var i = 0; i < params_dict.length; i++) { - // FIXME: use dict for creating parameters. - var param_dict = params_dict[i], - name = param_dict.name, - label = param_dict.label, - html = unescape(param_dict.html), - value = param_dict.value, - type = param_dict.type; - if (type === "number") { - this.params.push( - new NumberParameter(name, label, html, - (name in tool_state_dict ? tool_state_dict[name] : value), - param_dict.min, param_dict.max) - ); +var TracksterTool = Backbone.RelationalModel.extend({ + defaults: { + track: null, + tool: null, + }, + + relations: [ + { + type: Backbone.HasOne, + key: 'tool', + relatedModel: tools_mod.Tool } - else if (type === "select") { - this.params.push( - new ToolParameter(name, label, html, - (name in tool_state_dict ? tool_state_dict[name] : value)) - ); - } - else { - console.log("WARNING: unrecognized tool parameter type:", name, type); - } - } - - // - // Create div elt for tool UI. - // - this.parent_div = $("<div/>").addClass("dynamic-tool").hide(); - // Disable dragging, clicking, double clicking on div so that actions on slider do not impact viz. - this.parent_div.bind("drag", function(e) { - e.stopPropagation(); - }).click(function(e) { - e.stopPropagation(); - }).bind("dblclick", function(e) { - e.stopPropagation(); - }); - var name_div = $("<div class='tool-name'>").appendTo(this.parent_div).text(this.name); - var tool_params = this.params; - var tool = this; - $.each(this.params, function(index, param) { - var param_div = $("<div>").addClass("param-row").appendTo(tool.parent_div); + ] + +}); + +/** + * View renders tool parameter HTML and updates parameter value as it is changed in the HTML. + */ + var ToolParameterView = Backbone.View.extend({ + + events: { + 'change input': 'update_value' + }, + + render: function() { + var param_div = this.$el.addClass("param-row"), + param = this.model; + // Param label. - var label_div = $("<div>").addClass("param-label").text(param.label).appendTo(param_div); + var label_div = $("<div>").addClass("param-label").text(param.get('label')).appendTo(param_div); // Param HTML. - var html_div = $("<div/>").addClass("param-input").html(param.html).appendTo(param_div); + var html_div = $("<div/>").addClass("param-input").html(param.get('html')).appendTo(param_div); // Set initial value. - html_div.find(":input").val(param.value); + html_div.find(":input").val(param.get('value')); // Add to clear floating layout. $("<div style='clear: both;'/>").appendTo(param_div); - }); - - // Highlight value for inputs for easy replacement. - this.parent_div.find("input").click(function() { $(this).select(); }); - - // Add buttons for running on dataset, region. - var run_tool_row = $("<div>").addClass("param-row").appendTo(this.parent_div); - var run_on_dataset_button = $("<input type='submit'>").attr("value", "Run on complete dataset").appendTo(run_tool_row); - var run_on_region_button = $("<input type='submit'>").attr("value", "Run on visible region").css("margin-left", "3em").appendTo(run_tool_row); - run_on_region_button.click( function() { - // Run tool to create new track. - tool.run_on_region(); - }); - run_on_dataset_button.click( function() { - tool.run_on_dataset(); - }); - - if ('visible' in tool_state_dict && tool_state_dict.visible) { - this.parent_div.show(); + }, + + update_value: function(update_event) { + this.model.set_value($(update_event.target).val()); } -}; -extend(Tool.prototype, { + }); + +/** + * View for TracksterTool. + */ +var TracksterToolView = Backbone.View.extend({ + + /** + * Render tool UI. + */ + render: function() { + var self = this; + tool = this.model.get('tool'), + parent_div = this.$el.addClass("dynamic-tool").hide(); + + // Prevent div events from propogating to other elements. + parent_div.bind("drag", function(e) { + e.stopPropagation(); + }).click(function(e) { + e.stopPropagation(); + }).bind("dblclick", function(e) { + e.stopPropagation(); + }).keydown(function(e) { e.stopPropagation(); }); + + // Add name, inputs. + var name_div = $("<div class='tool-name'>").appendTo(parent_div).text(tool.get('name')); + tool.get('inputs').each(function(param) { + var param_view = new ToolParameterView({ model: param }); + param_view.render(); + parent_div.append(param_view.$el); + }); + + // Highlight value for inputs for easy replacement. + parent_div.find("input").click(function() { $(this).select(); }); + + // Add buttons for running on dataset, region. + var run_tool_row = $("<div>").addClass("param-row").appendTo(parent_div); + var run_on_dataset_button = $("<input type='submit'>").attr("value", "Run on complete dataset").appendTo(run_tool_row); + var run_on_region_button = $("<input type='submit'>").attr("value", "Run on visible region").css("margin-left", "3em").appendTo(run_tool_row); + run_on_region_button.click( function() { + // Run tool to create new track. + self.run_on_region(); + }); + run_on_dataset_button.click( function() { + self.run_on_dataset(); + }); + + /* + if ('visible' in tool_state_dict && tool_state_dict.visible) { + this.parent_div.show(); + } + */ + }, + /** * Update tool parameters. */ @@ -1713,68 +1727,42 @@ this.params[i].update_value(); } }, + /** * Returns a dict with tool state information. */ state_dict: function() { // Save parameter values. - var tool_state = {}; - for (var i = 0; i < this.params.length; i++) { - tool_state[this.params[i].name] = this.params[i].value; - } + var tool_state = this.model.get('tool').get_param_values_dict(); // Save visibility. tool_state.visible = this.parent_div.is(":visible"); return tool_state; }, - /** - * Returns dictionary of parameter name-values. - */ - get_param_values_dict: function() { - var param_dict = {}; - this.parent_div.find(":input").each(function() { - var name = $(this).attr("name"), value = $(this).val(); - param_dict[name] = value; - }); - return param_dict; - }, - /** - * Returns array of parameter values. - */ - get_param_values: function() { - var param_values = []; - this.parent_div.find(":input").each(function() { - // Only include inputs with names; this excludes Run button. - var name = $(this).attr("name"), value = $(this).val(); - if (name) { - param_values[param_values.length] = value; - } - }); - return param_values; - }, + /** * Run tool on dataset. Output is placed in dataset's history and no changes to viz are made. */ run_on_dataset: function() { - var tool = this; - tool.run( - // URL params. - { - target_dataset_id: this.track.dataset.id, - action: 'rerun', - tool_id: tool.id - }, - null, - // Success callback. - function(track_data) { - show_modal(tool.name + " is Running", - tool.name + " is running on the complete dataset. Tool outputs are in dataset's history.", - { "Close" : hide_modal } ); - } - ); - + var tool = this.model.get('tool'); + this.run( + // URL params. + { + target_dataset_id: this.model.get('track').dataset.id, + action: 'rerun', + tool_id: tool.id + }, + null, + // Success callback. + function(track_data) { + show_modal(tool.get('name') + " is Running", + tool.get('name') + " is running on the complete dataset. Tool outputs are in dataset's history.", + { "Close" : hide_modal } ); + } + ); }, + /** * Run dataset on visible region. This creates a new track and sets the track's contents * to the tool's output. @@ -1783,21 +1771,23 @@ // // Create track for tool's output immediately to provide user feedback. // - var region = new visualization.GenomeRegion({ - chrom: this.track.view.chrom, - start: this.track.view.low, - end: this.track.view.high + var track = this.model.get('track'), + tool = this.model.get('tool'), + region = new visualization.GenomeRegion({ + chrom: track.view.chrom, + start: track.view.low, + end: track.view.high }), url_params = { - target_dataset_id: this.track.dataset.id, + target_dataset_id: track.dataset.id, action: 'rerun', - tool_id: this.id, + tool_id: tool.id, regions: [ region.toJSON() ] }, - current_track = this.track, + current_track = track, // Set name of track to include tool name, parameters, and region used. track_name = url_params.tool_id + current_track.tool_region_and_parameters_str(region), @@ -1838,25 +1828,25 @@ new_track.tiles_div.text("Starting job."); // Run tool. - this.update_params(); this.run(url_params, new_track, - // Success callback. - function(track_data) { - new_track.set_dataset(new data.Dataset(track_data)); - new_track.tiles_div.text("Running job."); - new_track.init(); - } - ); + // Success callback. + function(track_data) { + new_track.set_dataset(new data.Dataset(track_data)); + new_track.tiles_div.text("Running job."); + new_track.init(); + } + ); }, + /** * Run tool using a set of URL params and a success callback. */ run: function(url_params, new_track, success_callback) { // Run tool. - url_params.inputs = this.get_param_values_dict(); + url_params.inputs = this.model.get('tool').get_inputs_dict(); var ss_deferred = new util.ServerStateDeferred({ ajax_settings: { - url: config.root + "/api/tools", + url: config.root + "api/tools", data: JSON.stringify(url_params), dataType: "json", contentType: 'application/json', @@ -1889,36 +1879,7 @@ } }); } -}); - -/** - * Tool parameters. - */ -var ToolParameter = function(name, label, html, value) { - this.name = name; - this.label = label; - // Need to use jQuery for HTML so that value can be queried and updated dynamically. - this.html = $(html); - this.value = value; -}; - -extend(ToolParameter.prototype, { - update_value: function() { - this.value = $(this.html).val(); - } -}); - -var NumberParameter = function(name, label, html, value, min, max) { - ToolParameter.call(this, name, label, html, value); - this.min = min; - this.max = max; -}; - -extend(NumberParameter.prototype, ToolParameter.prototype, { - update_value: function() { - ToolParameter.prototype.update_value.call(this); - this.value = parseFloat(this.value); - } + }); /** @@ -2819,7 +2780,12 @@ // FIXME: prolly need function to set filters and update data_manager reference. this.data_manager.set('filters_manager', this.filters_manager); this.filters_available = false; - this.tool = ('tool' in obj_dict && obj_dict.tool ? new Tool(this, obj_dict.tool, obj_dict.tool_state) : null); + this.tool = (obj_dict.tool ? new TracksterTool({ + 'track': this, + 'tool': obj_dict.tool, + 'tool_state': obj_dict.tool_state + }) + : null); this.tile_cache = new visualization.Cache(TILE_CACHE_SIZE); this.left_offset = 0; @@ -2830,10 +2796,12 @@ this.set_filters_manager(this.filters_manager); // - // Create dynamic tool div. + // Create dynamic tool view. // - if (this.tool) { - this.dynamic_tool_div = this.tool.parent_div; + if (this.tool) { + var tool_view = new TracksterToolView({ model: this.tool }); + tool_view.render(); + this.dynamic_tool_div = tool_view.$el; this.header_div.after(this.dynamic_tool_div); } } @@ -3427,8 +3395,9 @@ */ tool_region_and_parameters_str: function(region) { var track = this, - region_str = (region !== undefined ? region.toString() : "all"); - return " - region=[" + region_str + "], parameters=[" + track.tool.get_param_values().join(", ") + "]"; + region_str = (region !== undefined ? region.toString() : "all"), + param_str = _.values( track.tool.get('tool').get_inputs_dict()).join(', '); + return " - region=[" + region_str + "], parameters=[" + param_str + "]"; }, /** Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.
participants (1)
-
commits-noreply@bitbucket.org