1 new changeset in galaxy-central:
http://bitbucket.org/galaxy/galaxy-central/changeset/61b82db00101/ changeset: 61b82db00101 user: jgoecks date: 2011-09-24 16:45:34 summary: Trackster: (1) save and restore track groups; (2) support nested groups; (3) make View a DrawableCollection. affected #: 5 files (-1 bytes)
--- a/lib/galaxy/web/base/controller.py Fri Sep 23 14:27:29 2011 -0400 +++ b/lib/galaxy/web/base/controller.py Sat Sep 24 10:45:34 2011 -0400 @@ -310,40 +310,62 @@
config = None if visualization.type == 'trackster': - # Trackster config; taken from tracks/browser + # Unpack Trackster config. latest_revision = visualization.latest_revision bookmarks = latest_revision.config.get( 'bookmarks', [] ) - tracks = [] + + def pack_track( track_dict ): + dataset_id = track_dict['dataset_id'] + hda_ldda = track_dict.get('hda_ldda', 'hda') + if hda_ldda == "hda": + dataset = self.get_dataset( trans, dataset_id, check_ownership=False, check_accessible=True ) + else: + dataset = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id(dataset_id) ) + + try: + prefs = track_dict['prefs'] + except KeyError: + prefs = {} + + track_type, _ = dataset.datatype.get_track_type() + track_data_provider_class = get_data_provider( original_dataset=dataset ) + track_data_provider = track_data_provider_class( original_dataset=dataset ) + + return { + "track_type": track_type, + "name": track_dict['name'], + "hda_ldda": track_dict.get("hda_ldda", "hda"), + "dataset_id": trans.security.encode_id( dataset.id ), + "prefs": prefs, + "filters": track_data_provider.get_filters(), + "tool": get_tool_def( trans, dataset ) + } + + def pack_collection( collection_dict ): + drawables = [] + for drawable_dict in collection_dict[ 'drawables' ]: + if 'track_type' in drawable_dict: + drawables.append( pack_track( drawable_dict ) ) + else: + drawables.append( pack_collection( drawable_dict ) ) + return { + 'obj_type': collection_dict[ 'obj_type' ], + 'drawables': drawables + }
# Set tracks. + tracks = [] if 'tracks' in latest_revision.config: - for t in visualization.latest_revision.config['tracks']: - dataset_id = t['dataset_id'] - hda_ldda = t.get('hda_ldda', 'hda') - if hda_ldda == "hda": - dataset = self.get_dataset( trans, dataset_id, check_ownership=False, check_accessible=True ) + # Legacy code. + for track_dict in visualization.latest_revision.config[ 'tracks' ]: + tracks.append( pack_track( track_dict ) ) + elif 'view' in latest_revision.config: + for drawable_dict in visualization.latest_revision.config[ 'view' ][ 'drawables' ]: + if 'track_type' in drawable_dict: + tracks.append( pack_track( drawable_dict ) ) else: - dataset = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id(dataset_id) ) - - try: - prefs = t['prefs'] - except KeyError: - prefs = {} - - track_type, _ = dataset.datatype.get_track_type() - track_data_provider_class = get_data_provider( original_dataset=dataset ) - track_data_provider = track_data_provider_class( original_dataset=dataset ) - - tracks.append( { - "track_type": track_type, - "name": t['name'], - "hda_ldda": t.get("hda_ldda", "hda"), - "dataset_id": trans.security.encode_id( dataset.id ), - "prefs": prefs, - "filters": track_data_provider.get_filters(), - "tool": get_tool_def( trans, dataset ) - } ) - + tracks.append( pack_collection( drawable_dict ) ) + config = { "title": visualization.title, "vis_id": trans.security.encode_id( visualization.id ), "tracks": tracks, "bookmarks": bookmarks, "chrom": "", "dbkey": visualization.dbkey }
--- a/lib/galaxy/web/controllers/tracks.py Fri Sep 23 14:27:29 2011 -0400 +++ b/lib/galaxy/web/controllers/tracks.py Sat Sep 24 10:45:34 2011 -0400 @@ -615,19 +615,40 @@ vis_rev.visualization = vis vis_rev.title = vis.title vis_rev.dbkey = dbkey - # Tracks from payload - tracks = [] - # TODO: why go through the trouble of unpacking config only to repack and - # put in database? How about sticking JSON directly into database? - for track in decoded_payload['tracks']: - tracks.append( { "dataset_id": track['dataset_id'], - "hda_ldda": track.get('hda_ldda', "hda"), - "name": track['name'], - "track_type": track['track_type'], - "prefs": track['prefs'] - } ) - bookmarks = decoded_payload[ 'bookmarks' ] - vis_rev.config = { "tracks": tracks, "bookmarks": bookmarks } + + def unpack_track( track_json ): + """ Unpack a track from its json. """ + return { + "dataset_id": track_json['dataset_id'], + "hda_ldda": track_json.get('hda_ldda', "hda"), + "name": track_json['name'], + "track_type": track_json['track_type'], + "prefs": track_json['prefs'] + } + + def unpack_collection( collection_json ): + """ Unpack a collection from its json. """ + unpacked_drawables = [] + drawables = collection_json[ 'drawables' ] + for drawable_json in drawables: + if 'track_type' in drawable_json: + drawable = unpack_track( drawable_json ) + else: + drawable = unpack_collection( drawable_json ) + unpacked_drawables.append( drawable ) + return { + "obj_type": collection_json[ 'obj_type' ], + "drawables": unpacked_drawables + } + + # TODO: unpack and validate bookmarks: + def unpack_bookmarks( bookmarks_json ): + return + + # Unpack and validate view content. + view_content = unpack_collection( decoded_payload[ 'view' ] ) + bookmarks = unpack_bookmarks( decoded_payload[ 'bookmarks' ] ) + vis_rev.config = { "view": view_content, "bookmarks": bookmarks } # Viewport from payload if 'viewport' in decoded_payload: chrom = decoded_payload['viewport']['chrom']
--- a/static/scripts/trackster.js Fri Sep 23 14:27:29 2011 -0400 +++ b/static/scripts/trackster.js Sat Sep 24 10:45:34 2011 -0400 @@ -213,7 +213,7 @@ } }
- // Handle dragging into container. + // Handle dragging into container. Child is appended to container's content_div. container = null; for ( i = 0; i < children.length; i++ ) { child = $(children.get(i)); @@ -229,8 +229,10 @@ else { child.find(".content-div").append(this); } - // Update containers. - this_obj.container.remove_drawable(this_obj); + // Update containers. Object may not have container if it is being moved quickly. + if (this_obj.container) { + this_obj.container.remove_drawable(this_obj); + } html_elt_js_obj_dict[child.attr("id")].add_drawable(this_obj); return; } @@ -250,7 +252,6 @@ if ( i === children.length ) { if ( this !== children.get(i - 1) ) { parent.append(this); - // Update container. html_elt_js_obj_dict[parent.attr("id")].move_drawable(this_obj, i); } } @@ -574,32 +575,58 @@ /** * Base interface for all drawable objects. */ -var Drawable = function(name, view, parent_element, container) { +var Drawable = function(name, view, parent_element, drag_handle_class, container) { this.name = name; this.view = view; this.parent_element = parent_element; + this.drag_handle_class = drag_handle_class; this.container = container; };
+Drawable.prototype.init = function() {}; Drawable.prototype.request_draw = function() {}; -Drawable.prototype.draw = function() {}; +Drawable.prototype._draw = function() {}; +Drawable.prototype.to_json = function() {};
/** * A collection of drawable objects. */ -var DrawableCollection = function(name, view, parent_element, container) { +var DrawableCollection = function(obj_type, name, view, parent_element, container) { Drawable.call(this, name, view, parent_element, container);
// Attribute init. + this.obj_type = obj_type; this.drawables = []; }; extend(DrawableCollection.prototype, Drawable.prototype, { + /** + * Init each drawable in the collection. + */ + init: function() { + for (var i = 0; i < this.drawables.length; i++) { + this.drawables[i].init(); + } + }, + /** + * Draw each drawable in the collection. + */ + _draw: function() { + for (var i = 0; i < this.drawables.length; i++) { + this.drawables[i]._draw(); + } + }, + /** + * Returns jsonified representation of collection. + */ to_json: function() { - // For now, just return list of drawables in collection. - var json_obj = []; + var jsonified_drawables = []; for (var i = 0; i < this.drawables.length; i++) { - + jsonified_drawables.push(this.drawables[i].to_json()); } + return { + obj_type: this.obj_type, + drawables: jsonified_drawables + }; }, /** * Add a drawable to the end of the collection. @@ -652,25 +679,30 @@ * A group of drawables that are moveable, visible. */ var DrawableGroup = function(name, view, parent_element, container) { - DrawableCollection.call(this, name, view, parent_element, container); - - this.drag_handle_class = "group-handle"; + DrawableCollection.call(this, "DrawableGroup", name, view, parent_element, "group-handle", container);
// HTML elements. - this.container_div = $("<div/>").addClass("group").appendTo(this.parent_element); + if (!DrawableGroup.id_counter) { DrawableGroup.id_counter = 0; } + var group_id = DrawableGroup.id_counter++ + this.container_div = $("<div/>").addClass("group").attr("id", "group_" + group_id).appendTo(this.parent_element); this.container_div.append($("<div/>").addClass(this.drag_handle_class)); this.name_div = $("<div/>").addClass("group-name").text(this.name).appendTo(this.container_div); - this.content_div = $("<div/>").addClass("content-div").appendTo(this.container_div); + this.content_div = $("<div/>").addClass("content-div").attr("id", "group_" + group_id + "_content_div").appendTo(this.container_div); + + // Set up containers/moving for group: register both container and content div as container + // because both are used as containers. Group can be moved. is_container(this.container_div, this); + is_container(this.content_div, this); + moveable(this.container_div, this.drag_handle_class, ".group", this); };
-extend(DrawableGroup.prototype, DrawableCollection.prototype, Drawable.prototype); +extend(DrawableGroup.prototype, Drawable.prototype, DrawableCollection.prototype);
/** * View object manages complete viz view, including tracks and user interactions. */ var View = function(container, title, vis_id, dbkey, callback) { - DrawableCollection.call(this); + DrawableCollection.call(this, "View"); this.container = container; this.chrom = null; this.vis_id = vis_id; @@ -682,8 +714,6 @@ this.tracks_to_be_redrawn = []; this.max_low = 0; this.max_high = 0; - this.num_tracks = 0; - this.track_id_counter = 0; this.zoom_factor = 3; this.min_separation = 30; this.has_changes = false; @@ -870,22 +900,6 @@ $(window).trigger("resize"); this.update_intro_div(); }, - /** JSONify view. */ - to_json: function() { - var - view = this, - jsonified_drawables = []; - this.viewport_container.children(".track,.group").each(function() { - // Get object ID. - var id = $(this).attr("id"); - id = parseInt( id.slice(id.lastIndexOf("_") + 1) ); - - // JSONify drawable. - jsonified_drawables.push(view.tracks[id].to_json()); - }); - - return jsonified_drawables; - }, /** Add or remove intro div depending on view state. */ update_intro_div: function() { if (this.num_tracks === 0) { @@ -1039,17 +1053,11 @@ view.request_redraw(); }, /** - * Add a track to the view. + * Add a drawable to the view. */ - add_track: function(track) { - track.view = this; - track.track_id = this.track_id_counter; - this.tracks.push(track); - if (track.init) { track.init(); } - track.container_div.attr('id', 'track_' + track.track_id); - moveable(track.container_div, track.drag_handle_class, ".group", track); - this.track_id_counter += 1; - this.num_tracks += 1; + add_drawable: function(drawable) { + DrawableCollection.prototype.add_drawable.call(this, drawable); + if (drawable.init) { drawable.init(); } this.has_changes = true; this.update_intro_div(); }, @@ -1058,17 +1066,18 @@ this.label_tracks.push(label_track); }, /** - * Remove a track from the view. + * Remove drawable from the view. */ - remove_track: function(track) { - this.has_changes = true; - this.tracks.splice(this.tracks.indexOf(track), 1); - this.num_tracks -= 1; - var view = this; - track.container_div.fadeOut('slow', function() { - $(this).remove(); - view.update_intro_div(); - }); + remove_drawable: function(drawable, hide) { + DrawableCollection.prototype.remove_drawable.call(this, drawable); + if (hide) { + var view = this; + drawable.container_div.fadeOut('slow', function() { + $(this).remove(); + view.update_intro_div(); + }); + this.has_changes = true; + } }, reset: function() { this.low = this.max_low; @@ -1161,7 +1170,7 @@ track = this.tracks_to_be_redrawn[i][0]; force = this.tracks_to_be_redrawn[i][1]; clear_after = this.tracks_to_be_redrawn[i][2]; - if (track && track.enabled) { + if (track) { track._draw(force, clear_after); } } @@ -1310,9 +1319,9 @@ run_on_region_button.click( function() { // Create group for track + new tracks and put track in group. var - parent_elt = this.track.parent_element, - new_group = new DrawableCollection("New Group", parent_elt); - //this.track.view.add_track(new_group); + parent_elt = this.track.parent_element; + //new_group = new DrawableCollection("New Group", parent_elt); + //this.track.view.add_drawable(new_group);
// Run tool to create new track. @@ -1399,7 +1408,7 @@ new_track = new ToolDataFeatureTrack(track_name, view, current_track.hda_ldda, undefined, {}, {}, current_track); new_track.change_mode(current_track.mode); } - this.track.view.add_track(new_track); + this.track.view.add_drawable(new_track); new_track.content_div.text("Starting job.");
// Run tool. @@ -2007,7 +2016,7 @@ */ var Track = function(name, view, parent_element, data_url, data_query_wait) { // For now, track's container is always view. - Drawable.call(this, name, view, parent_element, view); + Drawable.call(this, name, view, parent_element, "draghandle", view);
// // Attribute init. @@ -2016,12 +2025,12 @@ this.data_url_extra_params = {} this.data_query_wait = (data_query_wait ? data_query_wait : DEFAULT_DATA_QUERY_WAIT); this.dataset_check_url = converted_datasets_state_url; - this.drag_handle_class = "draghandle";
// // Create HTML element structure for track. // - this.container_div = $("<div />").addClass('track').css("position", "relative"); + if (!Track.id_counter) { Track.id_counter = 0; } + this.container_div = $("<div />").addClass('track').attr("id", "track_" + Track.id_counter++).css("position", "relative"); if (!this.hidden) { this.header_div = $("<div class='track-header' />").appendTo(this.container_div); if (this.view.editor) { this.drag_div = $("<div/>").addClass(this.drag_handle_class).appendTo(this.header_div); } @@ -2154,6 +2163,9 @@ var TiledTrack = function(filters_list, tool_dict, parent_track) { var track = this, view = track.view; + + // Make track moveable. + moveable(track.container_div, track.drag_handle_class, ".group", track);
// Attribute init. this.filters_manager = (filters_list !== undefined ? new FiltersManager(this, filters_list) : undefined); @@ -2327,8 +2339,8 @@ // Remove option. // track_dropdown.Remove = function() { - view.remove_track(track); - if (parent_obj.num_tracks === 0) { + view.remove_drawable(track, true); + if (view.num_tracks === 0) { $("#no-tracks").show(); } }; @@ -2401,6 +2413,8 @@ * can manage drawing. */ _draw: function(force, clear_after) { + if (!this.enabled) { return; } + // HACK: ReferenceTrack can draw without dataset ID, but other tracks cannot. if ( !(this instanceof ReferenceTrack) && (!this.dataset_id) ) { return; }
--- a/static/scripts/trackster_ui.js Fri Sep 23 14:27:29 2011 -0400 +++ b/static/scripts/trackster_ui.js Sat Sep 24 10:45:34 2011 -0400 @@ -29,20 +29,54 @@ };
/** - * Types of tracks that can be added to a view. + * Objects that can be added to a view. */ -var addable_track_types = { "LineTrack": LineTrack, "FeatureTrack": FeatureTrack, "ReadTrack": ReadTrack }; +var addable_objects = { "LineTrack": LineTrack, "FeatureTrack": FeatureTrack, "ReadTrack": ReadTrack, "DrawableGroup": DrawableGroup };
/** * Decode a track from a dictionary. */ var track_from_dict = function(track_dict) { - return new addable_track_types[track_dict.track_type]( + return new addable_objects[track_dict.track_type]( track_dict.name, view, track_dict.hda_ldda, track_dict.dataset_id, track_dict.prefs, track_dict.filters, track_dict.tool); };
/** + * Decode a drawable collection from a dictionary. + */ +var drawable_collection_from_dict = function(collection_dict) { + var collection = new addable_objects[collection_dict.obj_type]("New Group", view, view.viewport_container, view); + for (var i = 0; i < collection_dict.drawables.length; i++) { + var + drawable_dict = collection_dict.drawables[i], + drawable; + if (drawable_dict['track_type']) { + drawable = track_from_dict(drawable_dict); + } + else { + drawable = drawable_collection_from_dict(drawable_dict); + } + collection.add_drawable(drawable); + // HACK: move track from view to collection's content_div. + // FIX: Tracks should be able to be be added to arbitrary containers; + // every moveable should have a container_div, and every container should have + // a content_div (though perhaps name changes are needed). + collection.content_div.append(drawable.container_div); + } + return collection; +}; + +/** + * Decode a drawable from a dict. + */ +var drawable_from_dict = function(drawable_dict) { + return (drawable_dict['track_type'] ? + track_from_dict(drawable_dict) : + drawable_collection_from_dict(drawable_dict)); +}; + +/** * Create a complete Trackster visualization. Returns view. */ var create_visualization = function(parent_elt, title, id, dbkey, callback, tracks_config, bookmarks_config) { @@ -51,21 +85,12 @@ view = new View(parent_elt, title, id, dbkey, callback); view.editor = true;
- // Add tracks to view. + // Add drawables to view. if (tracks_config) { - var track_config, track, parent_track, parent_obj; + var track_config; for (var i = 0; i < tracks_config.length; i++) { track_config = tracks_config[i]; - track = track_from_dict(track_config); - parent_obj = view; - if (track_config.is_child) { - parent_obj = parent_track; - } - else { - // New parent track is this track. - parent_track = track; - } - parent_obj.add_track(track); + view.add_drawable( drawable_from_dict(track_config) ); } }
--- a/templates/tracks/browser.mako Fri Sep 23 14:27:29 2011 -0400 +++ b/templates/tracks/browser.mako Sat Sep 24 10:45:34 2011 -0400 @@ -101,7 +101,7 @@ [ arguments[0] ] ); for (var i= 0; i < track_defs.length; i++) { - view.add_track( track_from_dict(track_defs[i]) ); + view.add_drawable( track_from_dict(track_defs[i]) ); } }); hide_modal(); @@ -186,7 +186,7 @@ url: "${h.url_for( action='add_track_async' )}", data: { hda_id: "${add_dataset}" }, dataType: "json", - success: function(track_data) { view.add_track( track_from_dict(track_data) ) } + success: function(track_data) { view.add_drawable( track_from_dict(track_data) ) } });
%endif @@ -199,15 +199,12 @@ "Add Tracks": add_tracks, "Add Group": function() { var group = new DrawableGroup("New Group", view, view.viewport_container, view); - view.add_track(group); + view.add_drawable(group); }, "Save": function() { // Show saving dialog box show_modal("Saving...", "<img src='${h.url_for('/static/images/yui/rel_interstitial_loading.gif')}'/>"); - - // Save tracks. - var saved_tracks = view.to_json(); - + // Save bookmarks. var bookmarks = []; $(".bookmark").each(function() { @@ -219,7 +216,7 @@
var overview_track_name = (view.overview_track ? view.overview_track.name : null); var payload = { - 'tracks': saved_tracks, + 'view': view.to_json(), 'viewport': { 'chrom': view.chrom, 'start': view.low , 'end': view.high, 'overview': overview_track_name }, 'bookmarks': bookmarks };
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.
galaxy-commits@lists.galaxyproject.org