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.