details: http://www.bx.psu.edu/hg/galaxy/rev/432a32ba55bb changeset: 3349:432a32ba55bb user: Kanwei Li <kanwei@gmail.com> date: Fri Feb 05 19:08:37 2010 -0500 description: trackster: - New interface for new track browsers - Saving shows progress bar - Can now add tracks async - Switching dbkeys is now async diffstat: lib/galaxy/web/controllers/tracks.py | 128 ++++------ lib/galaxy/web/controllers/visualization.py | 2 +- static/scripts/trackster.js | 61 +++- static/trackster.css | 1 + templates/grid_base.mako | 4 + templates/tracks/add_tracks.mako | 3 +- templates/tracks/browser.mako | 344 ++++++++++++++++----------- templates/tracks/index.mako | 52 +++- templates/tracks/new_browser.mako | 81 +----- 9 files changed, 359 insertions(+), 317 deletions(-) diffs (955 lines): diff -r 99483ae6c738 -r 432a32ba55bb lib/galaxy/web/controllers/tracks.py --- a/lib/galaxy/web/controllers/tracks.py Fri Feb 05 16:34:30 2010 -0500 +++ b/lib/galaxy/web/controllers/tracks.py Fri Feb 05 19:08:37 2010 -0500 @@ -57,10 +57,7 @@ use_paging = False columns = [ grids.TextColumn( "Name", key="name", model_class=model.HistoryDatasetAssociation ), - # grids.IndividualTagsColumn( "Tags", "tags", model.History, model.HistoryTagAssociation, filterable="advanced"), grids.GridColumn( "Filetype", key="extension" ), - # Columns that are valid for filtering but are not visible. - # SharingColumn( "Shared", key="shared", visible=False, filterable="advanced" ) ] def apply_default_filter( self, trans, query, **kwargs ): if self.available_tracks is None: @@ -80,62 +77,40 @@ @web.expose def index( self, trans ): - return trans.fill_template( "tracks/index.mako" ) - + config = {} + + return trans.fill_template( "tracks/browser.mako", config=config ) + @web.expose @web.require_login() - def new_browser( self, trans, dbkey=None, dataset_ids=None, browse=None, title=None ): - """ - Build a new browser from datasets in the current history. Redirects - to 'browser' once datasets to browse have been selected. - """ - session = trans.sa_session - # If the user clicked the submit button explicitly, try to build the browser - if title and browse and dataset_ids: - if not isinstance( dataset_ids, list ): - dataset_ids = [ dataset_ids ] - # Build config - tracks = [] - for dataset_id in dataset_ids: - tracks.append( { "dataset_id": str( dataset_id ) } ) - config = { "tracks": tracks } - # Build visualization object - vis = model.Visualization() - vis.user = trans.user - vis.title = title - vis.type = "trackster" - vis_rev = model.VisualizationRevision() - vis_rev.visualization = vis - vis_rev.title = title - vis_rev.config = config - vis.latest_revision = vis_rev - session.add( vis ) - session.add( vis_rev ) - session.flush() - trans.response.send_redirect( web.url_for( controller='tracks', action='browser', id=trans.security.encode_id( vis.id ) ) ) + def new_browser( self, trans ): + dbkeys = [ d.metadata.dbkey for d in trans.get_history().datasets if not d.deleted ] + dbkey_set = set( dbkeys ) + if not dbkey_set: + return trans.show_error_message( "Current history has no valid datasets to visualize." ) else: - # Determine the set of all dbkeys that are used in the current history - dbkeys = [ d.metadata.dbkey for d in trans.get_history().datasets if not d.deleted ] - dbkey_set = set( dbkeys ) - if not dbkey_set: - return trans.show_error_message( "Current history has no valid datasets to visualize." ) - - # If a dbkey argument was not provided, or is no longer valid, default - # to the first one - if dbkey is None or dbkey not in dbkey_set: - dbkey = dbkeys[0] - # Find all datasets in the current history that are of that dbkey - # and can be displayed - datasets = {} - if self.available_tracks is None: - self.available_tracks = trans.app.datatypes_registry.get_available_tracks() - for dataset in session.query( model.HistoryDatasetAssociation ).filter_by( deleted=False, history_id=trans.history.id ): - if dataset.metadata.dbkey == dbkey and dataset.extension in self.available_tracks: - datasets[dataset.id] = (dataset.extension, dataset.name) - # Render the template - return trans.fill_template( "tracks/new_browser.mako", available_tracks=self.available_tracks, dbkey=dbkey, dbkey_set=dbkey_set, datasets=datasets ) - + return trans.fill_template( "tracks/new_browser.mako", dbkey_set=dbkey_set ) + + @web.json + @web.require_login() + def add_track_async(self, trans, id): + dataset_id = trans.security.decode_id( id ) + + hda_query = trans.sa_session.query( model.HistoryDatasetAssociation ) + dataset = hda_query.get( dataset_id ) + track_type, indexer = dataset.datatype.get_track_type() + + track = { + "track_type": track_type, + "indexer": indexer, + "name": dataset.name, + "dataset_id": dataset.id, + "prefs": {}, + } + return track + @web.expose + @web.require_login() def browser(self, trans, id, chrom=""): """ Display browser for the datasets listed in `dataset_ids`. @@ -143,8 +118,10 @@ decoded_id = trans.security.decode_id( id ) session = trans.sa_session vis = session.query( model.Visualization ).get( decoded_id ) + latest_revision = vis.latest_revision tracks = [] - dbkey = "" + + dbkey = latest_revision.config['dbkey'] hda_query = session.query( model.HistoryDatasetAssociation ) for t in vis.latest_revision.config['tracks']: dataset_id = t['dataset_id'] @@ -161,18 +138,10 @@ "dataset_id": dataset.id, "prefs": simplejson.dumps(prefs), } ) - dbkey = dataset.dbkey - chrom_lengths = self._chroms( trans, dbkey ) - if chrom_lengths is None: - error( "No chromosome lengths file found for '%s'" % dataset.name ) - return trans.fill_template( 'tracks/browser.mako', - #dataset_ids=dataset_ids, - title = vis.title, - id=id, - tracks=tracks, - chrom=chrom, - dbkey=dbkey, - LEN=chrom_lengths.get(chrom, 0) ) + if dbkey is None: dbkey = dataset.dbkey # Hack for backward compat + + config = { "title": vis.title, "vis_id": id, "tracks": tracks, "chrom": chrom, "dbkey": dbkey } + return trans.fill_template( 'tracks/browser.mako', config=config ) @web.json def chroms(self, trans, dbkey=None ): @@ -288,9 +257,19 @@ @web.json def save( self, trans, **kwargs ): - decoded_id = trans.security.decode_id( kwargs['id'] ) session = trans.sa_session - vis = session.query( model.Visualization ).get( decoded_id ) + vis_id = kwargs['vis_id'].strip('"') + dbkey = kwargs['dbkey'] + + if vis_id == "undefined": # new vis + vis = model.Visualization() + vis.user = trans.user + vis.title = kwargs['vis_title'] + vis.type = "trackster" + session.add( vis ) + else: + decoded_id = trans.security.decode_id( vis_id ) + vis = session.query( model.Visualization ).get( decoded_id ) decoded_payload = simplejson.loads( kwargs['payload'] ) vis_rev = model.VisualizationRevision() @@ -304,10 +283,11 @@ "track_type": track['track_type'], "prefs": track['prefs'] } ) - vis_rev.config = { "tracks": tracks } + vis_rev.config = { "dbkey": dbkey, "tracks": tracks } vis.latest_revision = vis_rev session.add( vis_rev ) session.flush() + return trans.security.encode_id(vis.id) data_grid = DatasetSelectionGrid() @@ -316,11 +296,5 @@ def list_datasets( self, trans, **kwargs ): """List all datasets that can be added as tracks""" - # Render the list view - # return trans.fill_template( 'tracks/add_tracks.mako', grid=data_grid( trans, status=status, message=message, **kwargs ) ) return self.data_grid( trans, **kwargs ) - - # - - \ No newline at end of file diff -r 99483ae6c738 -r 432a32ba55bb lib/galaxy/web/controllers/visualization.py --- a/lib/galaxy/web/controllers/visualization.py Fri Feb 05 16:34:30 2010 -0500 +++ b/lib/galaxy/web/controllers/visualization.py Fri Feb 05 19:08:37 2010 -0500 @@ -7,7 +7,7 @@ # Grid definition title = "Visualizations" model_class = model.Visualization - default_sort_key = "-create_time" + default_sort_key = "-update_time" columns = [ grids.GridColumn( "Title", key="title", attach_popup=True, link=( lambda item: dict( controller="tracks", action="browser", id=item.id ) ) ), diff -r 99483ae6c738 -r 432a32ba55bb static/scripts/trackster.js --- a/static/scripts/trackster.js Fri Feb 05 16:34:30 2010 -0500 +++ b/static/scripts/trackster.js Fri Feb 05 19:08:37 2010 -0500 @@ -77,14 +77,16 @@ } }); -var View = function( chrom, max_high, config ) { +var View = function( chrom, title, vis_id, dbkey ) { + this.vis_id = vis_id; + this.dbkey = dbkey; + this.title = title; this.chrom = chrom; - this.config = config; this.tracks = []; + this.label_tracks = []; this.max_low = 0; - this.max_high = max_high; + this.max_high = 0; this.center = (this.max_high - this.max_low) / 2; - this.span = this.max_high - this.max_low; this.zoom_factor = 3; this.zoom_level = 0; }; @@ -94,6 +96,10 @@ this.tracks.push( track ); if (track.init) { track.init(); } }, + add_label_track: function ( label_track ) { + label_track.view = this; + this.label_tracks.push( label_track ); + }, remove_track: function( track ) { delete this.tracks[track]; }, @@ -105,7 +111,8 @@ } } }, - redraw: function() { + redraw: function(nodraw) { + this.span = this.max_high - this.max_low; var span = this.span / Math.pow(this.zoom_factor, this.zoom_level), low = this.center - (span / 2), high = low + span; @@ -134,11 +141,14 @@ }).show(); $("#low").val( commatize(this.low) ); $("#high").val( commatize(this.high) ); - for ( var i = 0, len = this.tracks.length; i < len; i++ ) { - this.tracks[i].draw(); + if (!nodraw) { + for ( var i = 0, len = this.tracks.length; i < len; i++ ) { + this.tracks[i].draw(); + } + for ( var i = 0, len = this.label_tracks.length; i < len; i++ ) { + this.label_tracks[i].draw(); + } } - //$("#bottom-spacer").remove(); - //$("#viewport").append('<div id="bottom-spacer" style="height: 200px;"></div>'); }, zoom_in: function ( point ) { if (this.max_high === 0 || this.high - this.low < 30) { @@ -238,6 +248,7 @@ var LabelTrack = function ( parent_element ) { Track.call( this, null, parent_element ); + this.track_type = "LabelTrack"; this.hidden = true; this.container_div.addClass( "label-track" ); }; @@ -273,26 +284,27 @@ this.height_px = 100; this.container_div.addClass( "line-track" ); this.dataset_id = dataset_id; - this.data_queue = {}; - this.data_cache = new Cache(CACHED_DATA); // We need to cache some data because of - // asynchronous calls this.prefs = { 'min_value': undefined, 'max_value': undefined }; if (prefs.min_value !== undefined) { this.prefs.min_value = prefs.min_value; } if (prefs.max_value !== undefined) { this.prefs.max_value = prefs.max_value; } }; $.extend( LineTrack.prototype, TiledTrack.prototype, { init: function() { + this.data_queue = {}; + this.data_cache = new Cache(CACHED_DATA); // We need to cache some data because of + // asynchronous calls var track = this, track_id = track.view.tracks.indexOf(track); - + track.content_div.text(DATA_LOADING); + track.container_div.removeClass("nodata error pending"); $.getJSON( data_url, { stats: true, indexer: track.indexer, chrom: track.view.chrom, low: null, high: null, dataset_id: track.dataset_id }, function ( data ) { if (!data || data == "error") { track.container_div.addClass("error"); track.content_div.text(DATA_ERROR); - } else if (data == "no data") { + } else if (data.length === 0 || data == "no data") { track.container_div.addClass("nodata"); track.content_div.text(DATA_NONE); } else if (data == "pending") { @@ -313,15 +325,17 @@ } track.vertical_range = track.prefs.max_value - track.prefs.min_value; - // Draw y-axis labels - var min_label = $("<div></div>").addClass('yaxislabel').attr("id", 'linetrack_' + track_id + '_minval').text(track.prefs.min_value); - var max_label = $("<div></div>").addClass('yaxislabel').attr("id", 'linetrack_' + track_id + '_maxval').text(track.prefs.max_value); + // Draw y-axis labels if necessary + if ( $('#linetrack_' + track_id + '_minval').length === 0) { + var min_label = $("<div></div>").addClass('yaxislabel').attr("id", 'linetrack_' + track_id + '_minval').text(track.prefs.min_value); + var max_label = $("<div></div>").addClass('yaxislabel').attr("id", 'linetrack_' + track_id + '_maxval').text(track.prefs.max_value); - max_label.css({ position: "relative", top: "25px" }); - max_label.prependTo(track.container_div); + max_label.css({ position: "relative", top: "25px" }); + max_label.prependTo(track.container_div); - min_label.css({ position: "relative", top: track.height_px + 55 + "px" }); - min_label.prependTo(track.container_div); + min_label.css({ position: "relative", top: track.height_px + 55 + "px" }); + min_label.prependTo(track.container_div); + } track.draw(); } @@ -345,7 +359,7 @@ } }, draw_tile: function( resolution, tile_index, parent_element, w_scale ) { - if (!this.vertical_range) { // We don't have the necessary information yet + if (this.vertical_range === undefined) { // We don't have the necessary information yet return; } @@ -463,6 +477,7 @@ init: function() { var track = this; track.content_div.text(DATA_LOADING); + track.container_div.removeClass("nodata error pending"); $.getJSON( data_url, { indexer: track.indexer, low: track.view.max_low, high: track.view.max_high, dataset_id: track.dataset_id, chrom: track.view.chrom }, function ( data ) { @@ -473,7 +488,7 @@ track.container_div.addClass("nodata"); track.content_div.text(DATA_NONE); } else if (data == "pending") { - track.container_div.addClass("pending"); + track.container_div.adClass("pending"); track.content_div.text(DATA_PENDING); setTimeout(function() { track.init(); }, 5000); } else { diff -r 99483ae6c738 -r 432a32ba55bb static/trackster.css --- a/static/trackster.css Fri Feb 05 16:34:30 2010 -0500 +++ b/static/trackster.css Fri Feb 05 19:08:37 2010 -0500 @@ -8,6 +8,7 @@ #nav-container { position: fixed; + left: 0; bottom: 0; } diff -r 99483ae6c738 -r 432a32ba55bb templates/grid_base.mako --- a/templates/grid_base.mako Fri Feb 05 16:34:30 2010 -0500 +++ b/templates/grid_base.mako Fri Feb 05 19:08:37 2010 -0500 @@ -27,6 +27,10 @@ <%def name="javascripts()"> ${parent.javascripts()} + ${self.grid_javascripts()} +</%def> + +<%def name="grid_javascripts()"> ${h.js("jquery.autocomplete", "autocomplete_tagging" )} <script type="text/javascript"> ## TODO: generalize and move into galaxy.base.js diff -r 99483ae6c738 -r 432a32ba55bb templates/tracks/add_tracks.mako --- a/templates/tracks/add_tracks.mako Fri Feb 05 16:34:30 2010 -0500 +++ b/templates/tracks/add_tracks.mako Fri Feb 05 19:08:37 2010 -0500 @@ -1,8 +1,9 @@ ## Template generates a grid that enables user to add tracks <%namespace file="../grid_base.mako" import="*" /> -${javascripts()} ${stylesheets()} +${grid_javascripts()} + ${render_grid_table( grid, show_item_checkboxes=True )} ## Initialize the grid. diff -r 99483ae6c738 -r 432a32ba55bb templates/tracks/browser.mako --- a/templates/tracks/browser.mako Fri Feb 05 16:34:30 2010 -0500 +++ b/templates/tracks/browser.mako Fri Feb 05 19:08:37 2010 -0500 @@ -45,7 +45,7 @@ </div> </div> -<div id="nav-container"> +<div id="nav-container" style="width:100%;"> <div id="nav-labeltrack"></div> <div id="nav"> <div id="overview"> @@ -59,8 +59,7 @@ <option value="">Loading</option> </select> <input id="low" size="12" />:<input id="high" size="12" /> - ## <input type="hidden" name="dataset_ids" value="${dataset_ids}" /> - <input type="hidden" name="id" value="${id}" /> + <input type="hidden" name="id" value="${config.get('vis_id', '')}" /> <a href="#" onclick="javascript:view.zoom_in();view.redraw();">+</a> <a href="#" onclick="javascript:view.zoom_out();view.redraw();">-</a> </form> @@ -75,11 +74,10 @@ <div class="unified-panel-header-inner">Configuration</div> </div> <form action="${h.url_for( action='update_config' )}"> -## <input name="title" id="title" value="${title}" /> +## <input name="title" id="title" value="${config.title}" /> <div id="show-hide-move"> <ul id="sortable-ul"></ul> </div> -## <input type="submit" id="update-config" value="Save settings" /> <input type="button" id="refresh-button" value="Refresh" /> <input type="button" id="save-button" value="Save" /> <input id="add-track" type="button" value="Add Track" /> @@ -89,154 +87,227 @@ <%def name="javascripts()"> ${parent.javascripts()} -${h.js( "json2", "jquery", "jquery.event.drag", "jquery.mousewheel", "trackster", "ui.core", "ui.sortable" )} +${h.js( 'galaxy.base', 'galaxy.panels', "json2", "jquery", "jquery.event.drag", "jquery.mousewheel", "trackster", "ui.core", "ui.sortable" )} <script type="text/javascript"> var data_url = "${h.url_for( action='data' )}"; - var view = new View( "${chrom}", ${LEN} ); + var view; $(function() { - view.add_track( new LabelTrack( $("#top-labeltrack" ) ) ); - view.add_track( new LabelTrack( $("#nav-labeltrack" ) ) ); - - %for track in tracks: - view.add_track( - new ${track["track_type"]}( "${track['name']}", ${track['dataset_id']}, "${track['indexer']}", ${track['prefs']} ) - ); - %endfor - - $(document).bind( "redraw", function( e ) { - view.redraw(); - }); - - $("#content").bind("mousewheel", function( e, delta ) { - if (delta > 0) { - view.zoom_in(e.pageX); - } else { - view.zoom_out(); - } - e.preventDefault(); - }); - - $("#content").bind("dblclick", function( e ) { - view.zoom_in(e.pageX); - }); - - // To let the overview box be draggable - $("#overview-box").bind("dragstart", function( e ) { - this.current_x = e.offsetX; - }).bind("drag", function( e ) { - var delta = e.offsetX - this.current_x; - this.current_x = e.offsetX; - - var delta_chrom = Math.round(delta / $(document).width() * view.span); - view.center += delta_chrom; - view.redraw(); - }); - - // To adjust the size of the viewport to fit the fixed-height footer - var refresh = function( e ) { - $("#content").height( $(window).height() - $("#nav-container").height() - $("#masthead").height()); - $("#viewport-container").height( $("#content").height() - $("#top-labeltrack").height() - $("#nav-labeltrack").height() ); - $("#nav-container").width( $("#center").width() ); - view.redraw(); - }; - $(window).bind( "resize", function(e) { refresh(e); } ); - $("#right-border").bind( "click", function(e) { refresh(e); } ); - $("#right-border").bind( "dragend", function(e) { refresh(e); } ); - $(window).trigger( "resize" ); - - $("#viewport").bind( "dragstart", function( e ) { - this.original_low = view.low; - this.current_height = e.clientY; - this.current_x = e.offsetX; - }).bind( "drag", function( e ) { - var container = $(this).parent(); - var delta = e.offsetX - this.current_x; - var new_scroll = container.scrollTop() - (e.clientY - this.current_height); - if ( new_scroll < container.get(0).scrollHeight - container.height() ) { - container.scrollTop(new_scroll); - } - this.current_height = e.clientY; - this.current_x = e.offsetX; - - var delta_chrom = Math.round(delta / $(document).width() * (view.high - view.low)); - view.center -= delta_chrom; - view.redraw(); - }); - - $("#refresh-button").bind( "click", function(e) { - view.update_options(); - }); - - // Use a popup grid to add more tracks - $("#add-track").bind( "click", function(e) { + %if config: + view = new View( "${config.get('chrom')}", "${config.get('title') | h}", "${config.get('vis_id')}", "${config.get('dbkey')}" ); + %for track in config.get('tracks'): + view.add_track( + new ${track["track_type"]}( "${track['name'] | h}", ${track['dataset_id']}, "${track['indexer']}", ${track['prefs']} ) + ); + %endfor + init(); + %else: $.ajax({ - url: "${h.url_for( action='list_datasets' )}", + url: "${h.url_for( action='new_browser' )}", data: {}, - error: function() { alert( "Grid refresh failed" ) }, - success: function(table_html) { - show_modal("Add Track — Select Dataset(s)", table_html, { - "Insert": function() { - hide_modal(); - }, - "Cancel": function() { + error: function() { alert( "Couldn't create new browser" ) }, + success: function(form_html) { + show_modal("New Track Browser", form_html, { + "Continue": function() { + view = new View( undefined, $("#new-title").val(), undefined, $("#new-dbkey").val() ); + init(); hide_modal(); } }); } }); - }); + %endif - $("#save-button").bind("click", function(e) { - view.update_options(); - var sorted = $("ul#sortable-ul").sortable('toArray'); - var payload = []; - for (var i in sorted) { - var track_id = parseInt(sorted[i].split("track_")[1]), - track = view.tracks[track_id]; - - payload.push( { - "track_type": track.track_type, - "indexer": track.indexer, - "name": track.name, - "dataset_id": track.dataset_id, - "prefs": track.prefs - }); - } - $.ajax({ - url: "${h.url_for( action='save' )}", - data: { - 'id': '${id}', - 'payload': JSON.stringify(payload) + // Execute this when everything is ready + function init() { + $("ul#sortable-ul").sortable({ + update: function(event, ui) { + for (var track_id in view.tracks) { + var track = view.tracks[track_id]; + } } }); - }); - - // Execute this on page load - (function () { - $.getJSON( "${h.url_for( action='chroms' )}", { dbkey: "${dbkey}" }, function ( data ) { + + $(document).bind( "redraw", function( e ) { + view.redraw(); + }); + + $("#content").bind("mousewheel", function( e, delta ) { + if (delta > 0) { + view.zoom_in(e.pageX); + } else { + view.zoom_out(); + } + e.preventDefault(); + }); + + $("#content").bind("dblclick", function( e ) { + view.zoom_in(e.pageX); + }); + + // To let the overview box be draggable + $("#overview-box").bind("dragstart", function( e ) { + this.current_x = e.offsetX; + }).bind("drag", function( e ) { + var delta = e.offsetX - this.current_x; + this.current_x = e.offsetX; + + var delta_chrom = Math.round(delta / $(document).width() * view.span); + view.center += delta_chrom; + view.redraw(); + }); + + // To adjust the size of the viewport to fit the fixed-height footer + var refresh = function( e ) { + $("#content").height( $(window).height() - $("#nav-container").height() - $("#masthead").height()); + $("#viewport-container").height( $("#content").height() - $("#top-labeltrack").height() - $("#nav-labeltrack").height() ); + $("#nav-container").width( $("#center").width() ); + view.redraw(); + }; + $(window).bind( "resize", function(e) { refresh(e); } ); + $("#right-border").bind( "click", function(e) { refresh(e); } ); + $("#right-border").bind( "dragend", function(e) { refresh(e); } ); + $(window).trigger( "resize" ); + + $("#viewport").bind( "dragstart", function( e ) { + this.original_low = view.low; + this.current_height = e.clientY; + this.current_x = e.offsetX; + }).bind( "drag", function( e ) { + var container = $(this).parent(); + var delta = e.offsetX - this.current_x; + var new_scroll = container.scrollTop() - (e.clientY - this.current_height); + if ( new_scroll < container.get(0).scrollHeight - container.height() ) { + container.scrollTop(new_scroll); + } + this.current_height = e.clientY; + this.current_x = e.offsetX; + + var delta_chrom = Math.round(delta / $(document).width() * (view.high - view.low)); + view.center -= delta_chrom; + view.redraw(); + }); + + $("#refresh-button").bind( "click", function(e) { + view.update_options(); + }); + + // Use a popup grid to add more tracks + $("#add-track").bind( "click", function(e) { + $.ajax({ + url: "${h.url_for( action='list_datasets' )}", + data: {}, + error: function() { alert( "Grid refresh failed" ) }, + success: function(table_html) { + show_modal("Add Track — Select Dataset(s)", table_html, { + "Insert": function() { + $('input[name=id]:checked').each(function() { + var item_id = $(this).val(); + $.ajax( { + url: "${h.url_for( action='add_track_async' )}", + data: { id: item_id }, + dataType: "json", + error: function() {}, + success: function(track_data) { + var new_track; + var td = track_data; + switch(track_data.track_type) { + case "LineTrack": + new_track = new LineTrack( track_data.name, track_data.dataset_id, track_data.indexer, track_data.prefs ); + break; + case "FeatureTrack": + new_track = new FeatureTrack( track_data.name, track_data.dataset_id, track_data.indexer, track_data.prefs ); + break; + case "ReadTrack": + new_track = new ReadTrack( track_data.name, track_data.dataset_id, track_data.indexer, track_data.prefs ); + break; + } + view.add_track(new_track); + sidebar_box(new_track); + } + }); + + }); + + hide_modal(); + }, + "Cancel": function() { + hide_modal(); + } + }); + } + }); + }); + + $("#save-button").bind("click", function(e) { + view.update_options(); + var sorted = $("ul#sortable-ul").sortable('toArray'); + var payload = []; + for (var i in sorted) { + var track_id = parseInt(sorted[i].split("track_")[1]), + track = view.tracks[track_id]; + + payload.push( { + "track_type": track.track_type, + "indexer": track.indexer, + "name": track.name, + "dataset_id": track.dataset_id, + "prefs": track.prefs + }); + } + // Show saving dialog box + show_modal("Saving...", "<img src='${h.url_for('/static/images/yui/rel_interstitial_loading.gif')}'/>"); + + $.ajax({ + url: "${h.url_for( action='save' )}", + data: { + 'vis_id': view.vis_id, + 'vis_title': view.title, + 'dbkey': view.dbkey, + 'payload': JSON.stringify(payload) + }, + success: function(vis_id) { + view.vis_id = vis_id; + hide_modal(); + } + }); + }); + + view.add_label_track( new LabelTrack( $("#top-labeltrack" ) ) ); + view.add_label_track( new LabelTrack( $("#nav-labeltrack" ) ) ); + + $.getJSON( "${h.url_for( action='chroms' )}", { dbkey: view.dbkey }, function ( data ) { + view.chrom_data = data; var chrom_options = '<option value="">Select Chrom/Contig</option>'; for (i in data) { - chrom = data[i]['chrom'] - if( chrom == view.chrom ) { - chrom_options += '<option value="' + chrom + '" selected="true">' + chrom + '</option>'; - } else { - chrom_options += '<option value="' + chrom + '">' + chrom + '</option>'; - } + var chrom = data[i]['chrom'] + chrom_options += '<option value="' + chrom + '">' + chrom + '</option>'; } $("#chrom").html(chrom_options); $("#chrom").bind( "change", function () { - $("#chr").submit(); + view.chrom = $("#chrom").val(); + var found = $.grep(view.chrom_data, function(v, i) { + return v.chrom === view.chrom; + })[0]; + view.max_high = found.len; + view.redraw(true); + + for (var track_id in view.tracks) { + var track = view.tracks[track_id]; + if (track.init) { + track.init(); + } + } + // view.redraw(); }); }); - // Populate sort/move ul - for (var track_id in view.tracks) { - var track = view.tracks[track_id]; + function sidebar_box(track) { if (!track.hidden) { + var track_id = view.tracks.length -1; // Track was just added to view, so index is current length -1 var label = $('<label for="track_' + track_id + 'title">' + track.name + '</label>'); var title = $('<div class="historyItemTitle"></div>'); var del_icon = $('<a style="display:block; float:right" href="#" class="icon-button delete" />'); @@ -255,18 +326,17 @@ li.append(div); $("ul#sortable-ul").append(li); } + }; + + // Populate sort/move ul + for (var track_id in view.tracks) { + var track = view.tracks[track_id]; + sidebar_box(track); } - $("ul#sortable-ul").sortable({ - update: function(event, ui) { - for (var track_id in view.tracks) { - var track = view.tracks[track_id]; - } - } - }); - - })(); - $(window).trigger("resize"); + $(window).trigger("resize"); + }; + }); </script> diff -r 99483ae6c738 -r 432a32ba55bb templates/tracks/index.mako --- a/templates/tracks/index.mako Fri Feb 05 16:34:30 2010 -0500 +++ b/templates/tracks/index.mako Fri Feb 05 19:08:37 2010 -0500 @@ -1,16 +1,38 @@ -<%inherit file="/base_panels.mako"/> +<form id="form" method="POST"> + <div class="form-row"> + <label for="dbkey">Browser name:</label> + <div class="form-row-input"> + <input type="text" name="title" id="title" value="Unnamed Browser"></input> + </div> + <div style="clear: both;"></div> + </div> + <div class="form-row"> + <label for="dbkey">Reference genome build (dbkey): </label> + <div class="form-row-input"> + <select name="dbkey" id="dbkey" refresh_on_change="true"> + %for tmp_dbkey in dbkey_set: + <option value="${tmp_dbkey}" + %if tmp_dbkey == dbkey: + selected="selected" + %endif + >${tmp_dbkey}</option> + %endfor + </select> + </div> + <div style="clear: both;"></div> + </div> + <div class="form-row"> + <label for="dataset_ids">Datasets to visualize: (${", ".join(available_tracks)} files are supported)</label> + %for dataset_id, (dataset_ext, dataset_name) in datasets.iteritems(): + <div> + <input type="checkbox" id="${dataset_id}" name="dataset_ids" value="${dataset_id}" /> + <label style="display:inline; font-weight: normal" for="${dataset_id}">[${dataset_ext}] ${dataset_name}</label> + </div> + %endfor -<%def name="init()"> -<% - self.has_left_panel=False - self.has_right_panel=False - self.active_view="visualization" - self.message_box_visible=False -%> -</%def> - -<%def name="center_panel()"> - - <iframe name="galaxy_main" id="galaxy_main" frameborder="0" style="position: absolute; width: 100%; height: 100%;" src="${h.url_for( controller="tracks", action="new_browser" )}"> </iframe> - -</%def> \ No newline at end of file + <div style="clear: both;"></div> + </div> + <div class="form-row"> + <input type="submit" name="browse" value="Browse"/> + </div> +</form> diff -r 99483ae6c738 -r 432a32ba55bb templates/tracks/new_browser.mako --- a/templates/tracks/new_browser.mako Fri Feb 05 16:34:30 2010 -0500 +++ b/templates/tracks/new_browser.mako Fri Feb 05 19:08:37 2010 -0500 @@ -1,65 +1,20 @@ -<%inherit file="/base.mako"/> - -<%def name="javascripts()"> -${parent.javascripts()} -<script type="text/javascript"> -$( function() { - $( "select[refresh_on_change='true']").change( function() { - $("#form").submit(); - }); -}); -</script> -</%def> - -% if not available_tracks: - <div class="errormessagelarge"> - There are no available converters needed for visualization. Please verify that your tool_conf.xml file contains - converters for datatypes (see tool_conf.xml.sample) for examples. +<form id="form" method="POST"> + <div class="form-row"> + <label for="title">Browser name:</label> + <div class="form-row-input"> + <input type="text" name="title" id="new-title" value="Unnamed Browser"></input> + </div> + <div style="clear: both;"></div> </div> - -% else: - <div class="form"> - <div class="form-title">Create new track browser</div> - - <div id="dbkey" class="form-body"> - <form id="form" method="POST"> - <div class="form-row"> - <label for="dbkey">Browser name:</label> - <div class="form-row-input"> - <input type="text" name="title" id="title" value="Unnamed Browser"></input> - </div> - <div style="clear: both;"></div> - </div> - <div class="form-row"> - <label for="dbkey">Reference genome build (dbkey): </label> - <div class="form-row-input"> - <select name="dbkey" id="dbkey" refresh_on_change="true"> - %for tmp_dbkey in dbkey_set: - <option value="${tmp_dbkey}" - %if tmp_dbkey == dbkey: - selected="selected" - %endif - >${tmp_dbkey}</option> - %endfor - </select> - </div> - <div style="clear: both;"></div> - </div> - <div class="form-row"> - <label for="dataset_ids">Datasets to visualize: (${", ".join(available_tracks)} files are supported)</label> - %for dataset_id, (dataset_ext, dataset_name) in datasets.iteritems(): - <div> - <input type="checkbox" id="${dataset_id}" name="dataset_ids" value="${dataset_id}" /> - <label style="display:inline; font-weight: normal" for="${dataset_id}">[${dataset_ext}] ${dataset_name}</label> - </div> - %endfor - - <div style="clear: both;"></div> - </div> - </div> - <div class="form-row"> - <input type="submit" name="browse" value="Browse"/> - </div> - </form> + <div class="form-row"> + <label for="dbkey">Reference genome build (dbkey): </label> + <div class="form-row-input"> + <select name="dbkey" id="new-dbkey"> + %for dbkey in dbkey_set: + <option value="${dbkey}">${dbkey}</option> + %endfor + </select> + </div> + <div style="clear: both;"></div> </div> -% endif +</form>