[galaxy-dev] [hg] galaxy 3349: trackster:

Greg Von Kuster greg at bx.psu.edu
Tue Feb 9 11:29:17 EST 2010


details:   http://www.bx.psu.edu/hg/galaxy/rev/432a32ba55bb
changeset: 3349:432a32ba55bb
user:      Kanwei Li <kanwei at 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 &mdash; 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 &mdash; 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>


More information about the galaxy-dev mailing list