details: http://www.bx.psu.edu/hg/galaxy/rev/f1cc27efc29e changeset: 3304:f1cc27efc29e user: Kanwei Li <kanwei@gmail.com> date: Fri Jan 29 17:10:34 2010 -0500 description: trackster: - Can save configs - Make track configs look like history items instead of tool configs - Small performance tweaks - Implemented "Add Track" grid (doesn't actually add track yet) Grids: - Lowercase when sorting so that we sort strings case-independent - Can click on text to toggle appropriate checkbox diffstat: lib/galaxy/visualization/tracks/data/bam.py | 6 +- lib/galaxy/web/controllers/tracks.py | 84 ++++++++++++++- lib/galaxy/web/framework/helpers/grids.py | 8 +- static/scripts/packed/trackster.js | 2 +- static/scripts/packed/ui.core.js | 1 + static/scripts/packed/ui.sortable.js | 1 + static/scripts/trackster.js | 150 ++++++++++++++++----------- static/trackster.css | 17 --- templates/grid_base.mako | 10 +- templates/tracks/add_tracks.mako | 12 ++ templates/tracks/browser.mako | 65 ++++++++++-- 11 files changed, 246 insertions(+), 110 deletions(-) diffs (752 lines): diff -r 1748118a736b -r f1cc27efc29e lib/galaxy/visualization/tracks/data/bam.py --- a/lib/galaxy/visualization/tracks/data/bam.py Fri Jan 29 14:50:37 2010 -0500 +++ b/lib/galaxy/visualization/tracks/data/bam.py Fri Jan 29 17:10:34 2010 -0500 @@ -7,13 +7,14 @@ from pysam import csamtools from math import floor, ceil, log import logging +# log = logging.getLogger(__name__) class BamDataProvider( object ): """ Provides access to intervals from a sorted indexed BAM file. """ def __init__( self, index, original_dataset ): - # self.log = logging.getLogger(__name__) + self.index = index self.original_dataset = original_dataset @@ -27,8 +28,7 @@ try: data = bamfile.fetch(start=start, end=end, reference=chrom) except ValueError, e: - # Some BAM files do not prefix chromosome names with chr, try - # without + # Some BAM files do not prefix chromosome names with chr, try without if chrom.startswith( 'chr' ): data = bamfile.fetch( start=start, end=end, reference=chrom[3:] ) else: diff -r 1748118a736b -r f1cc27efc29e lib/galaxy/web/controllers/tracks.py --- a/lib/galaxy/web/controllers/tracks.py Fri Jan 29 14:50:37 2010 -0500 +++ b/lib/galaxy/web/controllers/tracks.py Fri Jan 29 17:10:34 2010 -0500 @@ -19,6 +19,7 @@ from galaxy.util.json import to_json_string from galaxy.web.base.controller import * from galaxy.web.framework import simplejson +from galaxy.web.framework.helpers import time_ago, grids from galaxy.util.bunch import Bunch from galaxy.visualization.tracks.data.array_tree import ArrayTreeDataProvider @@ -43,12 +44,40 @@ "bai": BamDataProvider } +class DatasetSelectionGrid( grids.Grid ): + # Grid definition. + available_tracks = None + title = "Add Tracks" + template = "/tracks/add_tracks.mako" + async_template = "/page/select_histories_grid_async.mako" + model_class = model.HistoryDatasetAssociation + default_filter = { "deleted" : "False" , "shared" : "All" } + default_sort_key = "name" + use_async = True + 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: + self.available_tracks = trans.app.datatypes_registry.get_available_tracks() + return query.select_from( model.HistoryDatasetAssociation.table \ + .join( model.History.table ) ) \ + .filter( model.History.user == trans.user ) \ + .filter( model.HistoryDatasetAssociation.extension.in_(self.available_tracks) ) + class TracksController( BaseController ): """ Controller for track browser interface. Handles building a new browser from datasets in the current history, and display of the resulting browser. """ - + + available_tracks = None + @web.expose def index( self, trans ): return trans.fill_template( "tracks/index.mako" ) @@ -98,12 +127,13 @@ # Find all datasets in the current history that are of that dbkey # and can be displayed datasets = {} - available_tracks = trans.app.datatypes_registry.get_available_tracks() + 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 available_tracks: + 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=available_tracks, dbkey=dbkey, dbkey_set=dbkey_set, datasets=datasets ) + return trans.fill_template( "tracks/new_browser.mako", available_tracks=self.available_tracks, dbkey=dbkey, dbkey_set=dbkey_set, datasets=datasets ) @web.expose def browser(self, trans, id, chrom=""): @@ -118,13 +148,18 @@ hda_query = session.query( model.HistoryDatasetAssociation ) for t in vis.latest_revision.config['tracks']: dataset_id = t['dataset_id'] + try: + prefs = t['prefs'] + except KeyError: + prefs = {} dataset = hda_query.get( dataset_id ) track_type, indexer = dataset.datatype.get_track_type() tracks.append( { - "type": track_type, + "track_type": track_type, "indexer": indexer, "name": dataset.name, - "dataset_id": dataset.id + "dataset_id": dataset.id, + "prefs": simplejson.dumps(prefs), } ) dbkey = dataset.dbkey chrom_lengths = self._chroms( trans, dbkey ) @@ -252,7 +287,40 @@ return new_dataset @web.json - def update_config( self, trans, **kwargs ): - raise RuntimeError + 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 ) + + decoded_payload = simplejson.loads( kwargs['payload'] ) + vis_rev = model.VisualizationRevision() + vis_rev.visualization = vis + vis_rev.title = vis.title + tracks = [] + for track in decoded_payload: + tracks.append( { "dataset_id": str(track['dataset_id']), + "name": track['name'], + "indexer": track['indexer'], + "track_type": track['track_type'], + "prefs": track['prefs'] + } ) + vis_rev.config = { "tracks": tracks } + vis.latest_revision = vis_rev + session.add( vis_rev ) + session.flush() + + data_grid = DatasetSelectionGrid() + + @web.expose + @web.require_login( "see all available datasets" ) + 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 1748118a736b -r f1cc27efc29e lib/galaxy/web/framework/helpers/grids.py --- a/lib/galaxy/web/framework/helpers/grids.py Fri Jan 29 14:50:37 2010 -0500 +++ b/lib/galaxy/web/framework/helpers/grids.py Fri Jan 29 17:10:34 2010 -0500 @@ -12,7 +12,7 @@ class Grid( object ): """ - Specifieds the content and format of a grid (data table). + Specifies the content and format of a grid (data table). """ title = "" exposed = True @@ -157,10 +157,10 @@ if sort_key.startswith( "-" ): sort_key = sort_key[1:] sort_order = 'desc' - query = query.order_by( self.model_class.table.c.get( sort_key ).desc() ) + query = query.order_by( func.lower( self.model_class.table.c.get( sort_key ) ).desc() ) else: sort_order = 'asc' - query = query.order_by( self.model_class.table.c.get( sort_key ).asc() ) + query = query.order_by( func.lower( self.model_class.table.c.get( sort_key ) ).asc() ) extra_url_args['sort'] = encoded_sort_key # There might be a current row @@ -230,7 +230,7 @@ else: new_kwargs[ 'id' ] = trans.security.encode_id( id ) return url_for( **new_kwargs ) - + async_request = ( ( self.use_async ) and ( 'async' in kwargs ) and ( kwargs['async'] in [ 'True', 'true'] ) ) return trans.fill_template( iff( async_request, self.async_template, self.template), grid=self, diff -r 1748118a736b -r f1cc27efc29e static/scripts/packed/trackster.js --- a/static/scripts/packed/trackster.js Fri Jan 29 14:50:37 2010 -0500 +++ b/static/scripts/packed/trackster.js Fri Jan 29 17:10:34 2010 -0500 @@ -1,1 +1,1 @@ -var DEBUG=false;var DENSITY=1000,FEATURE_LEVELS=100,DATA_ERROR="There was an error in indexing this dataset.",DATA_NONE="No data for this chrom/contig.",DATA_PENDING="Currently indexing... please wait",DATA_LOADING="Loading data...",CACHED_TILES_FEATURE=10,CACHED_TILES_LINE=30,CACHED_DATA=20,CONTEXT=$("<canvas></canvas>").get(0).getContext("2d"),RIGHT_STRAND,LEFT_STRAND;var right_img=new Image();right_img.src="../images/visualization/strand_right.png";right_img.onload=function(){RIGHT_STRAND=CONTEXT.createPattern(right_img,"repeat")};var left_img=new Image();left_img.src="../images/visualization/strand_left.png";left_img.onload=function(){LEFT_STRAND=CONTEXT.createPattern(left_img,"repeat")};var right_img_inv=new Image();right_img_inv.src="../images/visualization/strand_right_inv.png";right_img_inv.onload=function(){RIGHT_STRAND_INV=CONTEXT.createPattern(right_img_inv,"repeat")};var left_img_inv=new Image();left_img_inv.src="../images/visualization/strand_left_inv.png";left_ img_inv.onload=function(){LEFT_STRAND_INV=CONTEXT.createPattern(left_img_inv,"repeat")};function commatize(b){b+="";var a=/(\d+)(\d{3})/;while(a.test(b)){b=b.replace(a,"$1,$2")}return b}var Cache=function(a){this.num_elements=a;this.obj_cache={};this.key_ary=[]};$.extend(Cache.prototype,{get:function(b){var a=this.key_ary.indexOf(b);if(a!=-1){this.key_ary.splice(a,1);this.key_ary.push(b)}return this.obj_cache[b]},set:function(b,c){if(!this.obj_cache[b]){if(this.key_ary.length>=this.num_elements){var a=this.key_ary.shift();delete this.obj_cache[a]}this.key_ary.push(b)}this.obj_cache[b]=c;return c}});var View=function(b,a){this.chrom=b;this.tracks=[];this.max_low=0;this.max_high=a;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};$.extend(View.prototype,{add_track:function(a){a.view=this;this.tracks.push(a);if(a.init){a.init()}},redraw:function(){var d=this.span/Math.pow(this.zoom_factor,this.zoom_level),b=thi s.center-(d/2),e=b+d;if(b<0){b=0;e=b+d}else{if(e>this.max_high){e=this.max_high;b=e-d}}this.low=Math.floor(b);this.high=Math.ceil(e);this.center=Math.round(this.low+(this.high-this.low)/2);this.resolution=Math.pow(10,Math.ceil(Math.log((this.high-this.low)/DENSITY)/Math.LN10));this.zoom_res=Math.pow(FEATURE_LEVELS,Math.max(0,Math.ceil(Math.log(this.resolution,FEATURE_LEVELS)/Math.log(FEATURE_LEVELS))));$("#overview-box").css({left:(this.low/this.span)*$("#overview-viewport").width(),width:Math.max(12,((this.high-this.low)/this.span)*$("#overview-viewport").width())}).show();$("#low").val(commatize(this.low));$("#high").val(commatize(this.high));for(var c=0,a=this.tracks.length;c<a;c++){this.tracks[c].draw()}},zoom_in:function(a){if(this.max_high===0||this.high-this.low<30){return}if(a){this.center=a/$(document).width()*(this.high-this.low)+this.low}this.zoom_level+=1;this.redraw()},zoom_out:function(){if(this.max_high===0){return}if(this.zoom_level<=0){this.zoom_level=0;retu rn}this.zoom_level-=1;this.redraw()}});var Track=function(a,b){this.name=a;this.parent_element=b;this.make_container()};$.extend(Track.prototype,{make_container:function(){this.header_div=$("<div class='track-header'>").text(this.name);this.content_div=$("<div class='track-content'>");this.container_div=$("<div class='track'></div>").append(this.header_div).append(this.content_div);this.parent_element.append(this.container_div)}});var TiledTrack=function(){};$.extend(TiledTrack.prototype,Track.prototype,{draw:function(){var j=this.view.low,e=this.view.high,f=e-j,d=this.view.resolution;if(DEBUG){$("#debug").text(d+" "+this.view.zoom_res)}var l=$("<div style='position: relative;'></div>");this.content_div.children(":first").remove();this.content_div.append(l);var m=this.content_div.width()/f;var i=20;var h;var a=Math.floor(j/d/DENSITY);while((a*DENSITY*d)<e){var k=this.content_div.width()+"_"+this.view.zoom_level+"_"+a;var c=this.tile_cache.get(k);if(c){var g=a*DENSITY*d;var b =(g-j)*m;if(this.left_offset){b-=this.left_offset}c.css({left:b});l.append(c);i=Math.max(i,c.height())}else{h=this.draw_tile(d,a,l,m);if(h){this.tile_cache.set(k,h);i=Math.max(i,h.height())}}this.content_div.css("height",i);a+=1}}});var LabelTrack=function(a){Track.call(this,null,a);this.container_div.addClass("label-track")};$.extend(LabelTrack.prototype,Track.prototype,{draw:function(){var c=this.view,d=c.high-c.low,g=Math.floor(Math.pow(10,Math.floor(Math.log(d)/Math.log(10)))),a=Math.floor(c.low/g)*g,e=this.content_div.width(),b=$("<div style='position: relative; height: 1.3em;'></div>");while(a<c.high){var f=(a-c.low)/d*e;b.append($("<div class='label'>"+commatize(a)+"</div>").css({position:"absolute",left:f-1}));a+=g}this.content_div.children(":first").remove();this.content_div.append(b)}});var LineTrack=function(c,b,d,a){this.tile_cache=new Cache(CACHED_TILES_LINE);Track.call(this,c,$("#viewport"));TiledTrack.call(this);this.indexer=d;this.height_px=(a?a:100);this.con tainer_div.addClass("line-track");this.dataset_id=b;this.data_queue={};this.cache=new Cache(CACHED_DATA)};$.extend(LineTrack.prototype,TiledTrack.prototype,{init:function(){var a=this;a.content_div.text(DATA_LOADING);$.getJSON(data_url,{stats:true,indexer:a.indexer,chrom:a.view.chrom,low:null,high:null,dataset_id:a.dataset_id},function(c){if(!c||c=="error"){a.container_div.addClass("error");a.content_div.text(DATA_ERROR)}else{if(c=="no data"){a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}else{if(c=="pending"){a.container_div.addClass("pending");a.content_div.text(DATA_PENDING);setTimeout(function(){a.init()},5000)}else{a.content_div.text("");a.content_div.css("height",a.height_px+"px");a.min_value=c.min;a.max_value=c.max;a.vertical_range=a.max_value-a.min_value;var d=$("<div class='yaxislabel'>"+a.min_value+"</div>");var b=$("<div class='yaxislabel'>"+a.max_value+"</div>");b.css({position:"relative",top:"25px"});b.prependTo(a.container_div);d.css({position :"relative",top:a.height_px+55+"px"});d.prependTo(a.container_div);a.draw()}}}})},get_data:function(d,b){var c=this,a=b*DENSITY*d,f=(b+1)*DENSITY*d,e=d+"_"+b;if(!c.data_queue[e]){c.data_queue[e]=true;$.getJSON(data_url,{indexer:this.indexer,chrom:this.view.chrom,low:a,high:f,dataset_id:this.dataset_id,resolution:this.view.resolution},function(g){c.cache.set(e,g);delete c.data_queue[e];c.draw()})}},draw_tile:function(d,a,m,o){if(!this.vertical_range){return}var h=a*DENSITY*d,b=DENSITY*d,c=$("<canvas class='tile'></canvas>"),l=d+"_"+a;if(!this.cache.get(l)){this.get_data(d,a);return}var g=this.cache.get(l);c.css({position:"absolute",top:0,left:(h-this.view.low)*o});c.get(0).width=Math.ceil(b*o);c.get(0).height=this.height_px;var n=c.get(0).getContext("2d");var e=false;n.beginPath();for(var f=0;f<g.length-1;f++){var k=g[f][0]-h;var j=g[f][1];if(isNaN(j)){e=false}else{k=k*o;j=(j-this.min_value)/this.vertical_range*this.height_px;if(e){n.lineTo(k,j)}else{n.moveTo(k,j);e=true}}}n. stroke();m.append(c);return c}});var FeatureTrack=function(c,b,d,a){this.tile_cache=new Cache(CACHED_TILES_FEATURE);Track.call(this,c,$("#viewport"));TiledTrack.call(this);this.indexer=d;this.height_px=(a?a:100);this.container_div.addClass("feature-track");this.dataset_id=b;this.zo_slots={};this.show_labels_scale=0.001;this.showing_details=false;this.vertical_detail_px=10;this.vertical_nodetail_px=3;this.base_color="#2C3143";this.default_font="9px Monaco, Lucida Console, monospace";this.left_offset=200;this.inc_slots={};this.data_queue={};this.s_e_by_tile={};this.data_cache=new Cache(20)};$.extend(FeatureTrack.prototype,TiledTrack.prototype,{init:function(){var a=this;a.content_div.text(DATA_LOADING);$.getJSON(data_url,{indexer:a.indexer,low:a.view.max_low,high:a.view.max_high,dataset_id:a.dataset_id,chrom:a.view.chrom},function(b){if(b=="error"){a.container_div.addClass("error");a.content_div.text(DATA_ERROR)}else{if(b.length===0||b=="no data"){a.container_div.addClass("nod ata");a.content_div.text(DATA_NONE)}else{if(b=="pending"){a.container_div.addClass("pending");a.content_div.text(DATA_PENDING);setTimeout(function(){a.init()},5000)}else{a.content_div.text("");a.content_div.css("height",a.height_px+"px");a.values=b;a.calc_slots();a.slots=a.zo_slots;a.draw()}}}})},get_data:function(a,d){var b=this,c=a+"_"+d;if(!b.data_queue[c]){b.data_queue[c]=true;$.getJSON(data_url,{indexer:b.indexer,chrom:b.view.chrom,low:a,high:d,dataset_id:b.dataset_id,include_blocks:true},function(e){b.data_cache.set(c,e);delete b.data_queue[c];b.draw()})}},calc_slots:function(){var b=[],a=this.content_div.width()/(this.view.high-this.view.low),d=this.view.max_low;for(var e=0,f=this.values.length;e<f;e++){var g,h,k=this.values[e];g=Math.floor((k.start-d)*a);h=Math.ceil((k.end-d)*a);var c=0;while(true){if(b[c]===undefined||b[c]<g){b[c]=h;this.zo_slots[k.uid]=c;break}c++}}this.height_px=b.length*this.vertical_nodetail_px+15;this.content_div.css("height",this.height_px+"px ")},incremental_slots:function(a,f){if(!this.inc_slots[a]){this.inc_slots[a]={};this.inc_slots[a].w_scale=1/a;this.s_e_by_tile[a]={}}var h=this.inc_slots[a].w_scale,s=[],g=0,b=$("<canvas></canvas>").get(0).getContext("2d"),l=this.view.max_low;var c,e,u=[];for(var p=0,q=f.length;p<q;p++){var d=f[p];if(this.inc_slots[a][d.uid]!==undefined){g=Math.max(g,this.inc_slots[a][d.uid]);u.push(this.inc_slots[a][d.uid])}else{s.push(p)}}for(var p=0,q=s.length;p<q;p++){var d=f[s[p]];c=Math.floor((d.start-l)*h);c-=b.measureText(d.name).width;e=Math.ceil((d.end-l)*h);var o=0;while(true){var m=true;if(this.s_e_by_tile[a][o]!==undefined){for(var n=0,t=this.s_e_by_tile[a][o].length;n<t;n++){var r=this.s_e_by_tile[a][o][n];if(e>r[0]&&c<r[1]){m=false;break}}}if(m){if(this.s_e_by_tile[a][o]===undefined){this.s_e_by_tile[a][o]=[]}this.s_e_by_tile[a][o].push([c,e]);this.inc_slots[a][d.uid]=o;g=Math.max(g,o);break}o++}}return g},draw_tile:function(A,F,n,r){if(!this.values){return}var G=F*DENSITY*A,c =(F+1)*DENSITY*A,v=DENSITY*A;var K,u,h;if(r>this.show_labels_scale){if(!this.showing_details){this.showing_details=true}for(var B in this.data_cache.obj_cache){var p=B.split("_"),e=p[0],d=p[1];if(e<=G&&d>=c){K=this.data_cache.get(B);break}}if(!K){this.data_queue[[G,c]]=true;this.get_data(G,c);return}h=this.incremental_slots(this.view.zoom_res,K)*this.vertical_detail_px+15;u=this.inc_slots[this.view.zoom_res]}else{if(this.showing_details){this.showing_details=false}h=this.height_px;u=this.zo_slots;K=this.values}var y=Math.ceil(v*r),x=$("<canvas class='tile'></canvas>");x.css({position:"absolute",top:0,left:(G-this.view.low)*r-this.left_offset});x.get(0).width=y+this.left_offset;x.get(0).height=h;var z=x.get(0).getContext("2d");z.fillStyle=this.base_color;z.font=this.default_font;z.textAlign="right";var C=0;for(var D=0,E=K.length;D<E;D++){var m=K[D];if(m.start<=c&&m.end>=G){var g=Math.floor(Math.max(0,(m.start-G)*r)),l=Math.ceil(Math.min(y,(m.end-G)*r)),f=u[m.uid]*(this.showin g_details?this.vertical_detail_px:this.vertical_nodetail_px);var a,L,b=null,s=null;if(m.thick_start&&m.thick_end){b=Math.floor(Math.max(0,(m.thick_start-G)*r));s=Math.ceil(Math.min(y,(m.thick_end-G)*r))}if(!this.showing_details){z.fillRect(g+this.left_offset,f+5,l-g,1)}else{if(z.fillText&&m.start>G){z.fillText(m.name,g-1+this.left_offset,f+8)}var I=m.blocks;if(I){if(m.strand){if(m.strand=="+"){z.fillStyle=RIGHT_STRAND}else{if(m.strand=="-"){z.fillStyle=LEFT_STRAND}}z.fillRect(g+this.left_offset,f,l-g,10);z.fillStyle=this.base_color}for(var B=0,J=I.length;B<J;B++){var q=I[B],o=Math.floor(Math.max(0,(q[0]-G)*r)),H=Math.ceil(Math.min(y,(q[1]-G)*r));if(o>H){continue}a=5;L=3;z.fillRect(o+this.left_offset,f+L,H-o,a);if(b!==undefined&&(o<=s||H>=b)){a=9;L=1;var w=Math.max(o,b),t=Math.min(H,s);z.fillRect(w+this.left_offset,f+L,t-w,a)}}}else{a=9;L=1;z.fillRect(g+this.left_offset,f+L,l-g,a);if(m.strand){if(m.strand=="+"){z.fillStyle=RIGHT_STRAND_INV}else{if(m.strand=="-"){z.fillStyle=L EFT_STRAND_INV}}z.fillRect(g+this.left_offset,f,l-g,10);z.fillStyle=this.base_color}}}C++}}n.append(x);return x}});var ReadTrack=function(c,b,d,a){this.tile_cache=new Cache(CACHED_TILES_FEATURE);Track.call(this,c,$("#viewport"));TiledTrack.call(this);FeatureTrack.call(this,c,b,d,a);this.default_font="9px Monaco, Lucida Console, monospace"};$.extend(ReadTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype,{draw_tile:function(v,z,m,n){if(!this.values){return}var A=z*DENSITY*v,e=(z+1)*DENSITY*v,q=DENSITY*v;var D,p,h;h=this.height_px;p=this.zo_slots;D=this.values;var t=Math.ceil(q*n),r=$("<canvas class='tile'></canvas>");r.css({position:"absolute",top:0,left:(A-this.view.low)*n-this.left_offset});r.get(0).width=t+this.left_offset;r.get(0).height=h;var u=r.get(0).getContext("2d");u.fillStyle=this.base_color;u.font=this.default_font;u.textAlign="right";var s=u.measureText("A").width;var w=0;for(var x=0,y=D.length;x<y;x++){var l=D[x];if(l.start<=e&&l.end>=A){var g=Math.floor (Math.max(0,(l.start-A)*n)),k=Math.ceil(Math.min(t,(l.end-A)*n)),f=p[l.uid]*this.vertical_detail_px;var a,E,d=null,o=null;if(n>s){for(var B=0,b=l.name.length;B<b;B++){var C=Math.floor(Math.max(0,(l.start+B-A)*n));u.fillText(l.name[B],C+this.left_offset,f+8)}}else{u.fillRect(g+this.left_offset,f+4,k-g,3)}}}m.append(r);return r}}); \ No newline at end of file +var DEBUG=false;var DENSITY=1000,FEATURE_LEVELS=10,DATA_ERROR="There was an error in indexing this dataset.",DATA_NONE="No data for this chrom/contig.",DATA_PENDING="Currently indexing... please wait",DATA_LOADING="Loading data...",CACHED_TILES_FEATURE=10,CACHED_TILES_LINE=30,CACHED_DATA=20,CONTEXT=$("<canvas></canvas>").get(0).getContext("2d"),RIGHT_STRAND,LEFT_STRAND;var right_img=new Image();right_img.src="../images/visualization/strand_right.png";right_img.onload=function(){RIGHT_STRAND=CONTEXT.createPattern(right_img,"repeat")};var left_img=new Image();left_img.src="../images/visualization/strand_left.png";left_img.onload=function(){LEFT_STRAND=CONTEXT.createPattern(left_img,"repeat")};var right_img_inv=new Image();right_img_inv.src="../images/visualization/strand_right_inv.png";right_img_inv.onload=function(){RIGHT_STRAND_INV=CONTEXT.createPattern(right_img_inv,"repeat")};var left_img_inv=new Image();left_img_inv.src="../images/visualization/strand_left_inv.png";left_i mg_inv.onload=function(){LEFT_STRAND_INV=CONTEXT.createPattern(left_img_inv,"repeat")};function commatize(b){b+="";var a=/(\d+)(\d{3})/;while(a.test(b)){b=b.replace(a,"$1,$2")}return b}var Cache=function(a){this.num_elements=a;this.clear()};$.extend(Cache.prototype,{get:function(b){var a=this.key_ary.indexOf(b);if(a!=-1){this.key_ary.splice(a,1);this.key_ary.push(b)}return this.obj_cache[b]},set:function(b,c){if(!this.obj_cache[b]){if(this.key_ary.length>=this.num_elements){var a=this.key_ary.shift();delete this.obj_cache[a]}this.key_ary.push(b)}this.obj_cache[b]=c;return c},clear:function(){this.obj_cache={};this.key_ary=[]}});var View=function(c,a,b){this.chrom=c;this.config=b;this.tracks=[];this.max_low=0;this.max_high=a;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};$.extend(View.prototype,{add_track:function(a){a.view=this;this.tracks.push(a);if(a.init){a.init()}},remove_track:function(a){delete this .tracks[a]},update_options:function(){for(var b in view.tracks){var a=view.tracks[b];if(a.update_options){a.update_options(b)}}},redraw:function(){var d=this.span/Math.pow(this.zoom_factor,this.zoom_level),b=this.center-(d/2),e=b+d;if(b<0){b=0;e=b+d}else{if(e>this.max_high){e=this.max_high;b=e-d}}this.low=Math.floor(b);this.high=Math.ceil(e);this.center=Math.round(this.low+(this.high-this.low)/2);this.resolution=Math.pow(10,Math.ceil(Math.log((this.high-this.low)/DENSITY)/Math.LN10));this.zoom_res=Math.pow(FEATURE_LEVELS,Math.max(0,Math.ceil(Math.log(this.resolution,FEATURE_LEVELS)/Math.log(FEATURE_LEVELS))));$("#overview-box").css({left:(this.low/this.span)*$("#overview-viewport").width(),width:Math.max(12,((this.high-this.low)/this.span)*$("#overview-viewport").width())}).show();$("#low").val(commatize(this.low));$("#high").val(commatize(this.high));for(var c=0,a=this.tracks.length;c<a;c++){this.tracks[c].draw()}},zoom_in:function(a){if(this.max_high===0||this.high-this.lo w<30){return}if(a){this.center=a/$(document).width()*(this.high-this.low)+this.low}this.zoom_level+=1;this.redraw()},zoom_out:function(){if(this.max_high===0){return}if(this.zoom_level<=0){this.zoom_level=0;return}this.zoom_level-=1;this.redraw()}});var Track=function(a,b){this.name=a;this.parent_element=b;this.make_container()};$.extend(Track.prototype,{make_container:function(){this.header_div=$("<div class='track-header'>").text(this.name);this.content_div=$("<div class='track-content'>");this.container_div=$("<div class='track'></div>").append(this.header_div).append(this.content_div);this.parent_element.append(this.container_div)}});var TiledTrack=function(){};$.extend(TiledTrack.prototype,Track.prototype,{draw:function(){var i=this.view.low,e=this.view.high,f=e-i,d=this.view.resolution;if(DEBUG){$("#debug").text(d+" "+this.view.zoom_res)}var k=$("<div style='position: relative;'></div>");this.content_div.children(":first").remove();this.content_div.append(k);var l=this .content_div.width()/f;var h;var a=Math.floor(i/d/DENSITY);while((a*DENSITY*d)<e){var j=this.content_div.width()+"_"+this.view.zoom_level+"_"+a;var c=this.tile_cache.get(j);if(c){var g=a*DENSITY*d;var b=(g-i)*l;if(this.left_offset){b-=this.left_offset}c.css({left:b});k.append(c);this.max_height=Math.max(this.max_height,c.height())}else{this.delayed_draw(this,j,i,e,a,d,k,l)}a+=1}},delayed_draw:function(c,e,a,f,b,d,g,h){setTimeout(function(){if(!(a>c.view.high||f<c.view.low)){tile_element=c.draw_tile(d,b,g,h);if(tile_element){c.tile_cache.set(e,tile_element);c.max_height=Math.max(c.max_height,tile_element.height());c.content_div.css("height",c.max_height)}}},50)}});var LabelTrack=function(a){Track.call(this,null,a);this.hidden=true;this.container_div.addClass("label-track")};$.extend(LabelTrack.prototype,Track.prototype,{draw:function(){var c=this.view,d=c.high-c.low,g=Math.floor(Math.pow(10,Math.floor(Math.log(d)/Math.log(10)))),a=Math.floor(c.low/g)*g,e=this.content_div.widt h(),b=$("<div style='position: relative; height: 1.3em;'></div>");while(a<c.high){var f=(a-c.low)/d*e;b.append($("<div class='label'>"+commatize(a)+"</div>").css({position:"absolute",left:f-1}));a+=g}this.content_div.children(":first").remove();this.content_div.append(b)}});var LineTrack=function(c,a,d,b){this.track_type="LineTrack";this.tile_cache=new Cache(CACHED_TILES_LINE);Track.call(this,c,$("#viewport"));TiledTrack.call(this);this.indexer=d;this.height_px=100;this.container_div.addClass("line-track");this.dataset_id=a;this.data_queue={};this.data_cache=new Cache(CACHED_DATA);this.prefs={min_value:undefined,max_value:undefined};if(b.min_value!==undefined){this.prefs.min_value=b.min_value}if(b.max_value!==undefined){this.prefs.max_value=b.max_value}};$.extend(LineTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b=a.view.tracks.indexOf(a);a.content_div.text(DATA_LOADING);$.getJSON(data_url,{stats:true,indexer:a.indexer,chrom:a.view.chrom,low:null,high:null ,dataset_id:a.dataset_id},function(d){if(!d||d=="error"){a.container_div.addClass("error");a.content_div.text(DATA_ERROR)}else{if(d=="no data"){a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}else{if(d=="pending"){a.container_div.addClass("pending");a.content_div.text(DATA_PENDING);setTimeout(function(){a.init()},5000)}else{a.content_div.text("");a.content_div.css("height",a.height_px+"px");if(a.prefs.min_value===undefined||a.prefs.max_value===undefined){a.prefs.min_value=d.min;a.prefs.max_value=d.max;$("#track_"+b+"_minval").val(a.prefs.min_value);$("#track_"+b+"_maxval").val(a.prefs.max_value)}a.vertical_range=a.prefs.max_value-a.prefs.min_value;var e=$("<div></div>").addClass("yaxislabel").attr("id","linetrack_"+b+"_minval").text(a.prefs.min_value);var c=$("<div></div>").addClass("yaxislabel").attr("id","linetrack_"+b+"_maxval").text(a.prefs.max_value);c.css({position:"relative",top:"25px"});c.prependTo(a.container_div);e.css({position:"relative",top:a.he ight_px+55+"px"});e.prependTo(a.container_div);a.draw()}}}})},get_data:function(d,b){var c=this,a=b*DENSITY*d,f=(b+1)*DENSITY*d,e=d+"_"+b;if(!c.data_queue[e]){c.data_queue[e]=true;$.getJSON(data_url,{indexer:this.indexer,chrom:this.view.chrom,low:a,high:f,dataset_id:this.dataset_id,resolution:this.view.resolution},function(g){c.data_cache.set(e,g);delete c.data_queue[e];c.draw()})}},draw_tile:function(n,p,c,e){if(!this.vertical_range){return}var q=p*DENSITY*n,a=DENSITY*n,b=$("<canvas class='tile'></canvas>"),s=n+"_"+p;if(!this.data_cache.get(s)){this.get_data(n,p);return}var r=this.data_cache.get(s);b.css({position:"absolute",top:0,left:(q-this.view.low)*e});b.get(0).width=Math.ceil(a*e);b.get(0).height=this.height_px;var m=b.get(0).getContext("2d"),j=false,k=this.prefs.min_value,f=this.prefs.max_value,l=this.vertical_range,d=this.height_px;m.beginPath();for(var o=0;o<r.length-1;o++){var h=r[o][0]-q;var g=r[o][1];if(isNaN(g)){j=false}else{h=h*e;if(g<=k){g=k}else{if(g>=f){g=f }}g=Math.round(d-(g-k)/l*d);if(j){m.lineTo(h,g)}else{m.moveTo(h,g);j=true}}}m.stroke();c.append(b);return b},gen_options:function(j){var a=$("<div></div>").addClass("form-row");var e="track_"+j+"_minval",g="track_"+j+"_maxval",h=$("<label></label>").attr("for",e).text("Min value:"),b=(this.prefs.min_value===undefined?"":this.prefs.min_value),i=$("<input></input>").attr("id",e).val(b),d=$("<label></label>").attr("for",g).text("Max value:"),f=(this.prefs.max_value===undefined?"":this.prefs.max_value),c=$("<input></input>").attr("id",g).val(f);return a.append(h).append(i).append(d).append(c)},update_options:function(c){var a=$("#track_"+c+"_minval").val(),b=$("#track_"+c+"_maxval").val();if(a!==this.prefs.min_value||b!==this.prefs.max_value){this.prefs.min_value=parseFloat(a);this.prefs.max_value=parseFloat(b);this.vertical_range=this.prefs.max_value-this.prefs.min_value;$("#linetrack_"+c+"_minval").text(this.prefs.min_value);$("#linetrack_"+c+"_maxval").text(this.prefs.max_val ue);this.tile_cache.clear();this.draw()}}});var FeatureTrack=function(c,a,d,b){this.track_type="FeatureTrack";this.tile_cache=new Cache(CACHED_TILES_FEATURE);Track.call(this,c,$("#viewport"));TiledTrack.call(this);this.indexer=d;this.height_px=100;this.container_div.addClass("feature-track");this.dataset_id=a;this.zo_slots={};this.show_labels_scale=0.001;this.showing_details=false;this.vertical_detail_px=10;this.vertical_nodetail_px=3;this.default_font="9px Monaco, Lucida Console, monospace";this.left_offset=200;this.inc_slots={};this.data_queue={};this.s_e_by_tile={};this.data_cache=new Cache(20);this.prefs={block_color:"black",label_color:"black"};if(b.block_color!==undefined){this.prefs.block_color=b.block_color}if(b.label_color!==undefined){this.prefs.label_color=b.label_color}};$.extend(FeatureTrack.prototype,TiledTrack.prototype,{init:function(){var a=this;a.content_div.text(DATA_LOADING);$.getJSON(data_url,{indexer:a.indexer,low:a.view.max_low,high:a.view.max_high,dat aset_id:a.dataset_id,chrom:a.view.chrom},function(b){if(b=="error"){a.container_div.addClass("error");a.content_div.text(DATA_ERROR)}else{if(b.length===0||b=="no data"){a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}else{if(b=="pending"){a.container_div.addClass("pending");a.content_div.text(DATA_PENDING);setTimeout(function(){a.init()},5000)}else{a.content_div.text("");a.content_div.css("height",a.height_px+"px");a.values=b;a.calc_slots();a.slots=a.zo_slots;a.draw()}}}})},get_data:function(a,d){var b=this,c=a+"_"+d;if(!b.data_queue[c]){b.data_queue[c]=true;$.getJSON(data_url,{indexer:b.indexer,chrom:b.view.chrom,low:a,high:d,dataset_id:b.dataset_id,include_blocks:true},function(e){b.data_cache.set(c,e);delete b.data_queue[c];b.draw()})}},calc_slots:function(){var b=[],a=this.content_div.width()/(this.view.high-this.view.low),d=this.view.max_low;for(var e=0,f=this.values.length;e<f;e++){var g,h,k=this.values[e];g=Math.floor((k.start-d)*a);h=Math.ceil((k.end -d)*a);var c=0;while(true){if(b[c]===undefined||b[c]<g){b[c]=h;this.zo_slots[k.uid]=c;break}c++}}this.height_px=b.length*this.vertical_nodetail_px+15;this.content_div.css("height",this.height_px+"px")},incremental_slots:function(a,f){if(!this.inc_slots[a]){this.inc_slots[a]={};this.inc_slots[a].w_scale=1/a;this.s_e_by_tile[a]={}}var h=this.inc_slots[a].w_scale,s=[],g=0,b=$("<canvas></canvas>").get(0).getContext("2d"),l=this.view.max_low;var c,e,u=[];for(var p=0,q=f.length;p<q;p++){var d=f[p];if(this.inc_slots[a][d.uid]!==undefined){g=Math.max(g,this.inc_slots[a][d.uid]);u.push(this.inc_slots[a][d.uid])}else{s.push(p)}}for(var p=0,q=s.length;p<q;p++){var d=f[s[p]];c=Math.floor((d.start-l)*h);c-=b.measureText(d.name).width;e=Math.ceil((d.end-l)*h);var o=0;while(true){var m=true;if(this.s_e_by_tile[a][o]!==undefined){for(var n=0,t=this.s_e_by_tile[a][o].length;n<t;n++){var r=this.s_e_by_tile[a][o][n];if(e>r[0]&&c<r[1]){m=false;break}}}if(m){if(this.s_e_by_tile[a][o]===undefined ){this.s_e_by_tile[a][o]=[]}this.s_e_by_tile[a][o].push([c,e]);this.inc_slots[a][d.uid]=o;g=Math.max(g,o);break}o++}}return g},draw_tile:function(B,f,g,M){if(!this.values){return}var s=f*DENSITY*B,G=(f+1)*DENSITY*B,r=DENSITY*B;var K,L,m;if(M>this.show_labels_scale){if(!this.showing_details){this.showing_details=true}for(var H in this.data_cache.obj_cache){var C=H.split("_"),z=C[0],c=C[1];if(z<=s&&c>=G){K=this.data_cache.get(H);break}}if(!K){this.data_queue[[s,G]]=true;this.get_data(s,G);return}m=this.incremental_slots(this.view.zoom_res,K)*this.vertical_detail_px+15;L=this.inc_slots[this.view.zoom_res]}else{if(this.showing_details){this.showing_details=false}m=this.height_px;L=this.zo_slots;K=this.values}var a=Math.ceil(r*M),u=$("<canvas class='tile'></canvas>"),D=this.prefs.label_color,e=this.prefs.block_color,x=this.left_offset,N=this.showing_details,O=(this.showing_details?this.vertical_detail_px:this.vertical_nodetail_px);u.css({position:"absolute",top:0,left:(s-this.vie w.low)*M-x});u.get(0).width=a+x;u.get(0).height=m;var p=u.get(0).getContext("2d");p.fillStyle=this.prefs.block_color;p.font=this.default_font;p.textAlign="right";var I=0;for(var J=0,o=K.length;J<o;J++){var v=K[J];if(v.start<=G&&v.end>=s){var A=Math.floor(Math.max(0,(v.start-s)*M)),q=Math.ceil(Math.min(a,(v.end-s)*M)),y=L[v.uid]*O;var n,E,t=null,P=null;if(v.thick_start&&v.thick_end){t=Math.floor(Math.max(0,(v.thick_start-s)*M));P=Math.ceil(Math.min(a,(v.thick_end-s)*M))}if(!N){p.fillRect(A+x,y+5,q-A,1)}else{if(v.start>s){p.fillStyle=D;p.fillText(v.name,A-1+x,y+8);p.fillStyle=e}var Q=v.blocks;if(Q){if(v.strand){if(v.strand=="+"){p.fillStyle=RIGHT_STRAND}else{if(v.strand=="-"){p.fillStyle=LEFT_STRAND}}p.fillRect(A+x,y,q-A,10);p.fillStyle=e}for(var H=0,d=Q.length;H<d;H++){var h=Q[H],b=Math.floor(Math.max(0,(h[0]-s)*M)),w=Math.ceil(Math.min(a,(h[1]-s)*M));if(b>w){continue}n=5;E=3;p.fillRect(b+x,y+E,w-b,n);if(t!==undefined&&!(b>P||w<t)){n=9;E=1;var F=Math.max(b,t),l=Math.min(w,P); p.fillRect(F+x,y+E,l-F,n)}}}else{n=9;E=1;p.fillRect(A+x,y+E,q-A,n);if(v.strand){if(v.strand=="+"){p.fillStyle=RIGHT_STRAND_INV}else{if(v.strand=="-"){p.fillStyle=LEFT_STRAND_INV}}p.fillRect(A+x,y,q-A,10);p.fillStyle=prefs.block_color}}}I++}}g.append(u);return u},gen_options:function(g){var a=$("<div></div>").addClass("form-row");var d="track_"+g+"_block_color",c=$("<label></label>").attr("for",d).text("Block color:"),b=$("<input></input>").attr("id",d).attr("name",d).val(this.prefs.block_color),f="track_"+g+"_label_color",h=$("<label></label>").attr("for",f).text("Label color:"),e=$("<input></input>").attr("id",f).attr("name",f).val(this.prefs.label_color);return a.append(c).append(b).append(h).append(e)},update_options:function(c){var a=$("#track_"+c+"_block_color").val(),b=$("#track_"+c+"_label_color").val();if(a!==this.prefs.block_color||b!==this.prefs.label_color){this.prefs.block_color=a;this.prefs.label_color=b;this.tile_cache.clear();this.draw()}}});var ReadTrack=func tion(c,a,d,b){this.track_type="ReadTrack";this.tile_cache=new Cache(CACHED_TILES_FEATURE);Track.call(this,c,$("#viewport"));TiledTrack.call(this);FeatureTrack.call(this,c,a,d,b)};$.extend(ReadTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype,{draw_tile:function(v,z,m,n){if(!this.values){return}var A=z*DENSITY*v,e=(z+1)*DENSITY*v,q=DENSITY*v;var D,p,h;h=this.height_px;p=this.zo_slots;D=this.values;var t=Math.ceil(q*n),r=$("<canvas class='tile'></canvas>");r.css({position:"absolute",top:0,left:(A-this.view.low)*n-this.left_offset});r.get(0).width=t+this.left_offset;r.get(0).height=h;var u=r.get(0).getContext("2d");u.fillStyle=this.prefs.block_color;u.font=this.default_font;u.textAlign="right";var s=u.measureText("A").width;var w=0;for(var x=0,y=D.length;x<y;x++){var l=D[x];if(l.start<=e&&l.end>=A){var g=Math.floor(Math.max(0,(l.start-A)*n)),k=Math.ceil(Math.min(t,(l.end-A)*n)),f=p[l.uid]*this.vertical_detail_px;var a,E,d=null,o=null;if(n>s){for(var B=0,b=l.name.lengt h;B<b;B++){var C=Math.floor(Math.max(0,(l.start+B-A)*n));u.fillText(l.name[B],C+this.left_offset,f+8)}}else{u.fillRect(g+this.left_offset,f+4,k-g,3)}}}m.append(r);return r}}); \ No newline at end of file diff -r 1748118a736b -r f1cc27efc29e static/scripts/packed/ui.core.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/static/scripts/packed/ui.core.js Fri Jan 29 17:10:34 2010 -0500 @@ -0,0 +1,1 @@ +jQuery.ui||(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.browser.version)<1.9);c.ui={version:"1.7.2",plugin:{add:function(k,l,n){var m=c.ui[k].prototype;for(var j in n){m.plugins[j]=m.plugins[j]||[];m.plugins[j].push([l,n[j]])}},call:function(j,l,k){var n=j.plugins[l];if(!n||!j.element[0].parentNode){return}for(var m=0;m<n.length;m++){if(j.options[n[m][0]]){n[m][1].apply(j.element,k)}}}},contains:function(k,j){return document.compareDocumentPosition?k.compareDocumentPosition(j)&16:k!==j&&k.contains(j)},hasScroll:function(m,k){if(c(m).css("overflow")=="hidden"){return false}var j=(k&&k=="left")?"scrollLeft":"scrollTop",l=false;if(m[j]>0){return true}m[j]=1;l=(m[j]>0);m[j]=0;return l},isOverAxis:function(k,j,l){return(k>j)&&(k<(j+l))},isOver:function(o,k,n,m,j,l){return c.ui.isOverAxis(o,n,j)&&c.ui.isOverAxis(k,m,l)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NU MPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(d){var f=c.attr,e=c.fn.removeAttr,h="http://www.w3.org/2005/07/aaa",a=/^aria-/,b=/^wairole:/;c.attr=function(k,j,l){var m=l!==undefined;return(j=="role"?(m?f.call(this,k,j,"wairole:"+l):(f.apply(this,arguments)||"").replace(b,"")):(a.test(j)?(m?k.setAttributeNS(h,j.replace(a,"aaa:"),l):f.call(this,k,j.replace(a,"aaa:"))):f.apply(this,arguments)))};c.fn.removeAttr=function(j){return(a.test(j)?this.each(function(){this.removeAttributeNS(h,j.replace(a,""))}):e.call(this,j))}}c.fn.extend({remove:function(){c("*",this).add(this).each(function(){c(this).triggerHandler("remove")});return i.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","").unbind("selectstart.ui")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","no ne").bind("selectstart.ui",function(){return false})},scrollParent:function(){var j;if((c.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){j=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(c.curCSS(this,"position",1))&&(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}else{j=this.parents().filter(function(){return(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!j.length?c(document):j}});c.extend(c.expr[":"],{data:function(l,k,j){return !!c.data(l,j[3])},focusable:function(k){var l=k.nodeName.toLowerCase(),j=c.attr(k,"tabindex");return(/input|select|textarea|button|object/.test(l)?!k.disabled:"a"==l||"area"==l?k.href||!isNaN(j):!isNaN(j))&&!c(k)["area"==l?"parents":"closest"](":hidden").length},tabbable:function (k){var j=c.attr(k,"tabindex");return(isNaN(j)||j>=0)&&c(k).is(":focusable")}});function g(m,n,o,l){function k(q){var p=c[m][n][q]||[];return(typeof p=="string"?p.split(/,?\s+/):p)}var j=k("getter");if(l.length==1&&typeof l[0]=="string"){j=j.concat(k("getterSetter"))}return(c.inArray(o,j)!=-1)}c.widget=function(k,j){var l=k.split(".")[0];k=k.split(".")[1];c.fn[k]=function(p){var n=(typeof p=="string"),o=Array.prototype.slice.call(arguments,1);if(n&&p.substring(0,1)=="_"){return this}if(n&&g(l,k,p,o)){var m=c.data(this[0],k);return(m?m[p].apply(m,o):undefined)}return this.each(function(){var q=c.data(this,k);(!q&&!n&&c.data(this,k,new c[l][k](this,p))._init());(q&&n&&c.isFunction(q[p])&&q[p].apply(q,o))})};c[l]=c[l]||{};c[l][k]=function(o,n){var m=this;this.namespace=l;this.widgetName=k;this.widgetEventPrefix=c[l][k].eventPrefix||k;this.widgetBaseClass=l+"-"+k;this.options=c.extend({},c.widget.defaults,c[l][k].defaults,c.metadata&&c.metadata.get(o)[k],n);this.element=c(o).bin d("setData."+k,function(q,p,r){if(q.target==o){return m._setData(p,r)}}).bind("getData."+k,function(q,p){if(q.target==o){return m._getData(p)}}).bind("remove",function(){return m.destroy()})};c[l][k].prototype=c.extend({},c.widget.prototype,j);c[l][k].getterSetter="option"};c.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").removeAttr("aria-disabled")},option:function(l,m){var k=l,j=this;if(typeof l=="string"){if(m===undefined){return this._getData(l)}k={};k[l]=m}c.each(k,function(n,o){j._setData(n,o)})},_getData:function(j){return this.options[j]},_setData:function(j,k){this.options[j]=k;if(j=="disabled"){this.element[k?"addClass":"removeClass"](this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",k)}},enable:function(){this._setData("disabled",false)},disable:function(){this._setData("disabled",true)},_trigger:f unction(l,m,n){var p=this.options[l],j=(l==this.widgetEventPrefix?l:this.widgetEventPrefix+l);m=c.Event(m);m.type=j;if(m.originalEvent){for(var k=c.event.props.length,o;k;){o=c.event.props[--k];m[o]=m.originalEvent[o]}}this.element.trigger(m,n);return !(c.isFunction(p)&&p.call(this.element[0],m,n)===false||m.isDefaultPrevented())}};c.widget.defaults={disabled:false};c.ui.mouse={_mouseInit:function(){var j=this;this.element.bind("mousedown."+this.widgetName,function(k){return j._mouseDown(k)}).bind("click."+this.widgetName,function(k){if(j._preventClickEvent){j._preventClickEvent=false;k.stopImmediatePropagation();return false}});if(c.browser.msie){this._mouseUnselectable=this.element.attr("unselectable");this.element.attr("unselectable","on")}this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName);(c.browser.msie&&this.element.attr("unselectable",this._mouseUnselectable))},_mouseDown:function(l){l.originalEvent=l.originalEvent||{};if(l.originalE vent.mouseHandled){return}(this._mouseStarted&&this._mouseUp(l));this._mouseDownEvent=l;var k=this,m=(l.which==1),j=(typeof this.options.cancel=="string"?c(l.target).parents().add(l.target).filter(this.options.cancel).length:false);if(!m||j||!this._mouseCapture(l)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){k.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(l)&&this._mouseDelayMet(l)){this._mouseStarted=(this._mouseStart(l)!==false);if(!this._mouseStarted){l.preventDefault();return true}}this._mouseMoveDelegate=function(n){return k._mouseMove(n)};this._mouseUpDelegate=function(n){return k._mouseUp(n)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);(c.browser.safari||l.preventDefault());l.originalEvent.mouseHandled=true;return true},_mouseMove:function(j){if(c.browser.msie&&!j.button){return this._mouseUp(j )}if(this._mouseStarted){this._mouseDrag(j);return j.preventDefault()}if(this._mouseDistanceMet(j)&&this._mouseDelayMet(j)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,j)!==false);(this._mouseStarted?this._mouseDrag(j):this._mouseUp(j))}return !this._mouseStarted},_mouseUp:function(j){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=(j.target==this._mouseDownEvent.target);this._mouseStop(j)}return false},_mouseDistanceMet:function(j){return(Math.max(Math.abs(this._mouseDownEvent.pageX-j.pageX),Math.abs(this._mouseDownEvent.pageY-j.pageY))>=this.options.distance)},_mouseDelayMet:function(j){return this.mouseDelayMet},_mouseStart:function(j){},_mouseDrag:function(j){},_mouseStop:function(j){},_mouseCapture:function(j){return true}};c.ui.mouse.defaults={cancel:null,distance:1,delay:0}})(jQuery); \ No newline at end of file diff -r 1748118a736b -r f1cc27efc29e static/scripts/packed/ui.sortable.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/static/scripts/packed/ui.sortable.js Fri Jan 29 17:10:34 2010 -0500 @@ -0,0 +1,1 @@ +(function(a){a.widget("ui.sortable",a.extend({},a.ui.mouse,{_init:function(){var b=this.options;this.containerCache={};this.element.addClass("ui-sortable");this.refresh();this.floating=this.items.length?(/left|right/).test(this.items[0].item.css("float")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var b=this.items.length-1;b>=0;b--){this.items[b].item.removeData("sortable-item")}},_mouseCapture:function(e,f){if(this.reverting){return false}if(this.options.disabled||this.options.type=="static"){return false}this._refreshItems(e);var d=null,c=this,b=a(e.target).parents().each(function(){if(a.data(this,"sortable-item")==c){d=a(this);return false}});if(a.data(e.target,"sortable-item")==c){d=a(e.target)}if(!d){return false}if(this.options.handle&&!f){var g=false;a(this.options.handle,d).find("*").andSelf().each(functio n(){if(this==e.target){g=true}});if(!g){return false}}this.currentItem=d;this._removeCurrentsFromItems();return true},_mouseStart:function(e,f,b){var g=this.options,c=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(e);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");a.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(e);this.originalPageX=e.pageX;this.originalPageY=e.pageY;if(g.cursorAt){this._adjustOffsetFromHelper(g.cursorAt)}this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};if(this.helper[0]!=th is.currentItem[0]){this.currentItem.hide()}this._createPlaceholder();if(g.containment){this._setContainment()}if(g.cursor){if(a("body").css("cursor")){this._storedCursor=a("body").css("cursor")}a("body").css("cursor",g.cursor)}if(g.opacity){if(this.helper.css("opacity")){this._storedOpacity=this.helper.css("opacity")}this.helper.css("opacity",g.opacity)}if(g.zIndex){if(this.helper.css("zIndex")){this._storedZIndex=this.helper.css("zIndex")}this.helper.css("zIndex",g.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){this.overflowOffset=this.scrollParent.offset()}this._trigger("start",e,this._uiHash());if(!this._preserveHelperProportions){this._cacheHelperProportions()}if(!b){for(var d=this.containers.length-1;d>=0;d--){this.containers[d]._trigger("activate",e,c._uiHash(this))}}if(a.ui.ddmanager){a.ui.ddmanager.current=this}if(a.ui.ddmanager&&!g.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,e)}this.dragging=true;this.helper.addClass("ui-sorta ble-helper");this._mouseDrag(e);return true},_mouseDrag:function(f){this.position=this._generatePosition(f);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs){this.lastPositionAbs=this.positionAbs}if(this.options.scroll){var g=this.options,b=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if((this.overflowOffset.top+this.scrollParent[0].offsetHeight)-f.pageY<g.scrollSensitivity){this.scrollParent[0].scrollTop=b=this.scrollParent[0].scrollTop+g.scrollSpeed}else{if(f.pageY-this.overflowOffset.top<g.scrollSensitivity){this.scrollParent[0].scrollTop=b=this.scrollParent[0].scrollTop-g.scrollSpeed}}if((this.overflowOffset.left+this.scrollParent[0].offsetWidth)-f.pageX<g.scrollSensitivity){this.scrollParent[0].scrollLeft=b=this.scrollParent[0].scrollLeft+g.scrollSpeed}else{if(f.pageX-this.overflowOffset.left<g.scrollSensitivity){this.scrollParent[0].scrollLeft=b=this.scrollParent[0].scrollLeft-g.scrollSpeed}}}else{if(f.page Y-a(document).scrollTop()<g.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()-g.scrollSpeed)}else{if(a(window).height()-(f.pageY-a(document).scrollTop())<g.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()+g.scrollSpeed)}}if(f.pageX-a(document).scrollLeft()<g.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()-g.scrollSpeed)}else{if(a(window).width()-(f.pageX-a(document).scrollLeft())<g.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()+g.scrollSpeed)}}}if(b!==false&&a.ui.ddmanager&&!g.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,f)}}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y"){this.helper[0].style.left=this.position.left+"px"}if(!this.options.axis||this.options.axis!="x"){this.helper[0].style.top=this.position.top+"px"}for(var d=this.items.length-1;d>=0;d--){var e=this.items[d],c=e.item[0],h=this._intersectsWithPointer(e);if(!h){continue}if(c!=thi s.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=c&&!a.ui.contains(this.placeholder[0],c)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],c):true)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(e)){this._rearrange(f,e)}else{break}this._trigger("change",f,this._uiHash());break}}this._contactContainers(f);if(a.ui.ddmanager){a.ui.ddmanager.drag(this,f)}this._trigger("sort",f,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(c,d){if(!c){return}if(a.ui.ddmanager&&!this.options.dropBehaviour){a.ui.ddmanager.drop(this,c)}if(this.options.revert){var b=this;var e=b.placeholder.offset();b.reverting=true;a(this.helper).animate({left:e.left-this.offset.parent.left-b.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-b.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},par seInt(this.options.revert,10)||500,function(){b._clear(c)})}else{this._clear(c,d)}return false},cancel:function(){var b=this;if(this.dragging){this._mouseUp();if(this.options.helper=="original"){this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else{this.currentItem.show()}for(var c=this.containers.length-1;c>=0;c--){this.containers[c]._trigger("deactivate",null,b._uiHash(this));if(this.containers[c].containerCache.over){this.containers[c]._trigger("out",null,b._uiHash(this));this.containers[c].containerCache.over=0}}}if(this.placeholder[0].parentNode){this.placeholder[0].parentNode.removeChild(this.placeholder[0])}if(this.options.helper!="original"&&this.helper&&this.helper[0].parentNode){this.helper.remove()}a.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});if(this.domPosition.prev){a(this.domPosition.prev).after(this.currentItem)}else{a(this.domPosition.parent).prepend(this.currentItem)}return true},serialize:function(d){v ar b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};a(b).each(function(){var e=(a(d.item||this).attr(d.attribute||"id")||"").match(d.expression||(/(.+)[-=_](.+)/));if(e){c.push((d.key||e[1]+"[]")+"="+(d.key&&d.expression?e[1]:e[2]))}});return c.join("&")},toArray:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};b.each(function(){c.push(a(d.item||this).attr(d.attribute||"id")||"")});return c},_intersectsWith:function(m){var e=this.positionAbs.left,d=e+this.helperProportions.width,k=this.positionAbs.top,j=k+this.helperProportions.height;var f=m.left,c=f+m.width,n=m.top,i=n+m.height;var o=this.offset.click.top,h=this.offset.click.left;var g=(k+o)>n&&(k+o)<i&&(e+h)>f&&(e+h)<c;if(this.options.tolerance=="pointer"||this.options.forcePointerForContainers||(this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>m[this.floating?"width":"height"])){return g}else{return(f<e+(this.helperProportions.width/2)&&d-(this.he lperProportions.width/2)<c&&n<k+(this.helperProportions.height/2)&&j-(this.helperProportions.height/2)<i)}},_intersectsWithPointer:function(d){var e=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,d.top,d.height),c=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,d.left,d.width),g=e&&c,b=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();if(!g){return false}return this.floating?(((f&&f=="right")||b=="down")?2:1):(b&&(b=="down"?2:1))},_intersectsWithSides:function(e){var c=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,e.top+(e.height/2),e.height),d=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,e.left+(e.width/2),e.width),b=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();if(this.floating&&f){return((f=="right"&&d)||(f=="left"&&!d))}else{return b&&((b=="down"&&c)||(b=="up"&&!c))}},_getDragVerticalDirection:function(){var b=this.positionAbs.top-this.lastPositionAbs.top;return b!=0&&(b>0?" down":"up")},_getDragHorizontalDirection:function(){var b=this.positionAbs.left-this.lastPositionAbs.left;return b!=0&&(b>0?"right":"left")},refresh:function(b){this._refreshItems(b);this.refreshPositions()},_connectWith:function(){var b=this.options;return b.connectWith.constructor==String?[b.connectWith]:b.connectWith},_getItemsAsjQuery:function(b){var l=this;var g=[];var e=[];var h=this._connectWith();if(h&&b){for(var d=h.length-1;d>=0;d--){var k=a(h[d]);for(var c=k.length-1;c>=0;c--){var f=a.data(k[c],"sortable");if(f&&f!=this&&!f.options.disabled){e.push([a.isFunction(f.options.items)?f.options.items.call(f.element):a(f.options.items,f.element).not(".ui-sortable-helper"),f])}}}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper"),this]);for(var d=e.length-1;d>=0;d--){e[d][0].each(function(){g.push(this)})}return a(g)},_removeCurrentsF romItems:function(){var d=this.currentItem.find(":data(sortable-item)");for(var c=0;c<this.items.length;c++){for(var b=0;b<d.length;b++){if(d[b]==this.items[c].item[0]){this.items.splice(c,1)}}}},_refreshItems:function(b){this.items=[];this.containers=[this];var h=this.items;var p=this;var f=[[a.isFunction(this.options.items)?this.options.items.call(this.element[0],b,{item:this.currentItem}):a(this.options.items,this.element),this]];var l=this._connectWith();if(l){for(var e=l.length-1;e>=0;e--){var m=a(l[e]);for(var d=m.length-1;d>=0;d--){var g=a.data(m[d],"sortable");if(g&&g!=this&&!g.options.disabled){f.push([a.isFunction(g.options.items)?g.options.items.call(g.element[0],b,{item:this.currentItem}):a(g.options.items,g.element),g]);this.containers.push(g)}}}}for(var e=f.length-1;e>=0;e--){var k=f[e][1];var c=f[e][0];for(var d=0,n=c.length;d<n;d++){var o=a(c[d]);o.data("sortable-item",k);h.push({item:o,instance:k,width:0,height:0,left:0,top:0})}}},refreshPositions:function(b ){if(this.offsetParent&&this.helper){this.offset.parent=this._getParentOffset()}for(var d=this.items.length-1;d>=0;d--){var e=this.items[d];if(e.instance!=this.currentContainer&&this.currentContainer&&e.item[0]!=this.currentItem[0]){continue}var c=this.options.toleranceElement?a(this.options.toleranceElement,e.item):e.item;if(!b){e.width=c.outerWidth();e.height=c.outerHeight()}var f=c.offset();e.left=f.left;e.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers){this.options.custom.refreshContainers.call(this)}else{for(var d=this.containers.length-1;d>=0;d--){var f=this.containers[d].element.offset();this.containers[d].containerCache.left=f.left;this.containers[d].containerCache.top=f.top;this.containers[d].containerCache.width=this.containers[d].element.outerWidth();this.containers[d].containerCache.height=this.containers[d].element.outerHeight()}}},_createPlaceholder:function(d){var b=d||this,e=b.options;if(!e.placeholder||e.placeholder.constructor==Stri ng){var c=e.placeholder;e.placeholder={element:function(){var f=a(document.createElement(b.currentItem[0].nodeName)).addClass(c||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!c){f.style.visibility="hidden"}return f},update:function(f,g){if(c&&!e.forcePlaceholderSize){return}if(!g.height()){g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10))}if(!g.width()){g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=a(e.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);e.placeholder.update(b,b.placeholder)},_contactContainers:function(d){for(var c=this.containers.length-1;c>=0;c--){if(this._intersectsWith(this.containers[c].containerCache)){if(!this.containers[c].containerCache.over){if(this.currentContainer!=this.cont ainers[c]){var h=10000;var g=null;var e=this.positionAbs[this.containers[c].floating?"left":"top"];for(var b=this.items.length-1;b>=0;b--){if(!a.ui.contains(this.containers[c].element[0],this.items[b].item[0])){continue}var f=this.items[b][this.containers[c].floating?"left":"top"];if(Math.abs(f-e)<h){h=Math.abs(f-e);g=this.items[b]}}if(!g&&!this.options.dropOnEmpty){continue}this.currentContainer=this.containers[c];g?this._rearrange(d,g,null,true):this._rearrange(d,null,this.containers[c].element,true);this._trigger("change",d,this._uiHash());this.containers[c]._trigger("change",d,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder)}this.containers[c]._trigger("over",d,this._uiHash(this));this.containers[c].containerCache.over=1}}else{if(this.containers[c].containerCache.over){this.containers[c]._trigger("out",d,this._uiHash(this));this.containers[c].containerCache.over=0}}}},_createHelper:function(c){var d=this.options;var b=a.isFuncti on(d.helper)?a(d.helper.apply(this.element[0],[c,this.currentItem])):(d.helper=="clone"?this.currentItem.clone():this.currentItem);if(!b.parents("body").length){a(d.appendTo!="parent"?d.appendTo:this.currentItem[0].parentNode)[0].appendChild(b[0])}if(b[0]==this.currentItem[0]){this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}}if(b[0].style.width==""||d.forceHelperSize){b.width(this.currentItem.width())}if(b[0].style.height==""||d.forceHelperSize){b.height(this.currentItem.height())}return b},_adjustOffsetFromHelper:function(b){if(b.left!=undefined){this.offset.click.left=b.left+this.margins.left}if(b.right!=undefined){this.offset.click.left=this.helperProportions.width-b.right+this.margins.left}if(b.top!=undefined){this.offset.click.top=b.top+this.margins.top}if(b.bottom!=undefined){this.offset.click.top=this.helperProporti ons.height-b.bottom+this.margins.top}},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])){b.left+=this.scrollParent.scrollLeft();b.top+=this.scrollParent.scrollTop()}if((this.offsetParent[0]==document.body)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)){b={top:0,left:0}}return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var b=this.currentItem.position();return{top:b.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:b.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else{return{top:0,left:0}}},_cacheMargins:function(){this.margins={ left:(parseInt(this.currentItem.css("marginLeft"),10)||0),top:(parseInt(this.currentItem.css("marginTop"),10)||0)}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e=this.options;if(e.containment=="parent"){e.containment=this.helper[0].parentNode}if(e.containment=="document"||e.containment=="window"){this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(e.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(e.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]}if(!(/^(document|window|parent)$/).test(e.containment)){var c=a(e.containment)[0];var d=a(e.containment).offset();var b=(a(c).css("overflow")!="hidden");this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"), 10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(b?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(b?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(f,h){if(!h){h=this.position}var c=f=="absolute"?1:-1;var e=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=(/(html|body)/i).test(b[0].tagName);return{top:(h.top+this.offset.relative.top*c+this.offset.parent.top*c-(a.browser.safari&&this.cssPosition=="fix ed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(g?0:b.scrollTop()))*c)),left:(h.left+this.offset.relative.left*c+this.offset.parent.left*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:b.scrollLeft())*c))}},_generatePosition:function(e){var h=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,i=(/(html|body)/i).test(b[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0])){this.offset.relative=this._getRelativeOffset()}var d=e.pageX;var c=e.pageY;if(this.originalPosition){if(this.containment){if(e.pageX-this.offset.click.left<this.containment[0]){d=this.containment[0]+this.offset.click.left}if(e.pageY-this.offset.click.top<this.containment[1]){c=this.containment[1]+this.offset.click.top}if(e.pageX-this.offset .click.left>this.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:(!(g-this.offset.click.top<this.containment[1])?g-h.grid[1]:g+h.grid[1])):g;var f=this.originalPageX+Math.round((d-this.originalPageX)/h.grid[0])*h.grid[0];d=this.containment?(!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:(!(f-this.offset.click.left<this.containment[0])?f-h.grid[0]:f+h.grid[0])):f}}return{top:(c-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(i?0:b.scrollTop())))),left:(d-this.offset.click.left-this.offset.re lative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():i?0:b.scrollLeft())))}},_rearrange:function(g,f,c,e){c?c[0].appendChild(this.placeholder[0]):f.item[0].parentNode.insertBefore(this.placeholder[0],(this.direction=="down"?f.item[0]:f.item[0].nextSibling));this.counter=this.counter?++this.counter:1;var d=this,b=this.counter;window.setTimeout(function(){if(b==d.counter){d.refreshPositions(!e)}},0)},_clear:function(d,e){this.reverting=false;var f=[],b=this;if(!this._noFinalSort&&this.currentItem[0].parentNode){this.placeholder.before(this.currentItem)}this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var c in this._storedCSS){if(this._storedCSS[c]=="auto"||this._storedCSS[c]=="static"){this._storedCSS[c]=""}}this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else{this.currentItem.show()}if(this.fromOutside&&!e){f.push(function(g){this._trigger("receiv e",g,this._uiHash(this.fromOutside))})}if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!e){f.push(function(g){this._trigger("update",g,this._uiHash())})}if(!a.ui.contains(this.element[0],this.currentItem[0])){if(!e){f.push(function(g){this._trigger("remove",g,this._uiHash())})}for(var c=this.containers.length-1;c>=0;c--){if(a.ui.contains(this.containers[c].element[0],this.currentItem[0])&&!e){f.push((function(g){return function(h){g._trigger("receive",h,this._uiHash(this))}}).call(this,this.containers[c]));f.push((function(g){return function(h){g._trigger("update",h,this._uiHash(this))}}).call(this,this.containers[c]))}}}for(var c=this.containers.length-1;c>=0;c--){if(!e){f.push((function(g){return function(h){g._trigger("deactivate",h,this._uiHash(this))}}).call(this,this.containers[c]))}if(this.containers[c].containerCache.over){f.push((function(g){return function(h) {g._trigger("out",h,this._uiHash(this))}}).call(this,this.containers[c]));this.containers[c].containerCache.over=0}}if(this._storedCursor){a("body").css("cursor",this._storedCursor)}if(this._storedOpacity){this.helper.css("opacity",this._storedOpacity)}if(this._storedZIndex){this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex)}this.dragging=false;if(this.cancelHelperRemoval){if(!e){this._trigger("beforeStop",d,this._uiHash());for(var c=0;c<f.length;c++){f[c].call(this,d)}this._trigger("stop",d,this._uiHash())}return false}if(!e){this._trigger("beforeStop",d,this._uiHash())}this.placeholder[0].parentNode.removeChild(this.placeholder[0]);if(this.helper[0]!=this.currentItem[0]){this.helper.remove()}this.helper=null;if(!e){for(var c=0;c<f.length;c++){f[c].call(this,d)}this._trigger("stop",d,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){if(a.widget.prototype._trigger.apply(this,arguments)===false){this.cancel()}},_uiHash:function(c) {var b=c||this;return{helper:b.helper,placeholder:b.placeholder||a([]),position:b.position,absolutePosition:b.positionAbs,offset:b.positionAbs,item:b.currentItem,sender:c?c.element:null}}}));a.extend(a.ui.sortable,{getter:"serialize toArray",version:"1.7.2",eventPrefix:"sort",defaults:{appendTo:"parent",axis:false,cancel:":input,option",connectWith:false,containment:false,cursor:"auto",cursorAt:false,delay:0,distance:1,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1000}})})(jQuery); \ No newline at end of file diff -r 1748118a736b -r f1cc27efc29e static/scripts/trackster.js --- a/static/scripts/trackster.js Fri Jan 29 14:50:37 2010 -0500 +++ b/static/scripts/trackster.js Fri Jan 29 17:10:34 2010 -0500 @@ -94,7 +94,18 @@ this.tracks.push( track ); if (track.init) { track.init(); } }, - redraw: function () { + remove_track: function( track ) { + delete this.tracks[track]; + }, + update_options: function() { + for (var track_id in view.tracks) { + var track = view.tracks[track_id]; + if (track.update_options) { + track.update_options(track_id); + } + } + }, + redraw: function() { var span = this.span / Math.pow(this.zoom_factor, this.zoom_level), low = this.center - (span / 2), high = low + span; @@ -252,23 +263,22 @@ } }); -var LineTrack = function ( name, dataset_id, indexer, height, minval, maxval ) { +var LineTrack = function ( name, dataset_id, indexer, prefs ) { + this.track_type = "LineTrack"; this.tile_cache = new Cache(CACHED_TILES_LINE); Track.call( this, name, $("#viewport") ); TiledTrack.call( this ); this.indexer = indexer; - this.height_px = (height ? height : 100); + 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 - if (minval !== undefined && maxval !== undefined) { - this.min_value = minval; - this.max_value = maxval; - this.vertical_range = maxval - minval; - } + 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() { @@ -293,19 +303,19 @@ track.content_div.text(""); track.content_div.css( "height", track.height_px + "px" ); - if (track.min_value === undefined || track.max_value === undefined) { - track.min_value = data.min; - track.max_value = data.max; - track.vertical_range = track.max_value - track.min_value; - + if (track.prefs.min_value === undefined || track.prefs.max_value === undefined) { + track.prefs.min_value = data.min; + track.prefs.max_value = data.max; + // Update the config - $('#track_' + track_id + '_minval').val(track.min_value); - $('#track_' + track_id + '_maxval').val(track.max_value); + $('#track_' + track_id + '_minval').val(track.prefs.min_value); + $('#track_' + track_id + '_maxval').val(track.prefs.max_value); } + 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.min_value); - var max_label = $("<div></div>").addClass('yaxislabel').attr("id", 'linetrack_' + track_id + '_maxval').text(track.max_value); + 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); @@ -358,8 +368,13 @@ canvas.get(0).width = Math.ceil( tile_length * w_scale ); canvas.get(0).height = this.height_px; - var ctx = canvas.get(0).getContext("2d"); - var in_path = false; + var ctx = canvas.get(0).getContext("2d"), + in_path = false, + min_value = this.prefs.min_value, + max_value = this.prefs.max_value, + vertical_range = this.vertical_range, + height_px = this.height_px; + ctx.beginPath(); for ( var i = 0; i < data.length - 1; i++ ) { var x = data[i][0] - tile_low; @@ -371,12 +386,12 @@ // Translate x = x * w_scale; // console.log(y, this.min_value, this.vertical_range, (y - this.min_value) / this.vertical_range * this.height_px); - if (y <= this.min_value) { - y = this.min_value; - } else if (y >= this.max_value) { - y = this.max_value; + if (y <= min_value) { + y = min_value; + } else if (y >= max_value) { + y = max_value; } - y = Math.round( this.height_px - (y - this.min_value) / this.vertical_range * this.height_px ); + y = Math.round( height_px - (y - min_value) / vertical_range * height_px ); // console.log(canvas.get(0).height, canvas.get(0).width); if ( in_path ) { ctx.lineTo( x, y ); @@ -395,33 +410,37 @@ var minval = 'track_' + track_id + '_minval', maxval = 'track_' + track_id + '_maxval', min_label = $('<label></label>').attr("for", minval).text("Min value:"), - min_input = $('<input></input>').attr("id", minval).val(this.min_value || ""), + min_val = (this.prefs.min_value === undefined ? "" : this.prefs.min_value), + min_input = $('<input></input>').attr("id", minval).val(min_val), max_label = $('<label></label>').attr("for", maxval).text("Max value:"), - max_input = $('<input></input>').attr("id", maxval).val(this.max_value || ""); + max_val = (this.prefs.max_value === undefined ? "" : this.prefs.max_value), + max_input = $('<input></input>').attr("id", maxval).val(max_val); return container.append(min_label).append(min_input).append(max_label).append(max_input); }, update_options: function(track_id) { var min_value = $('#track_' + track_id + '_minval').val(), max_value = $('#track_' + track_id + '_maxval').val(); - if ( min_value !== this.min_value || max_value !== this.max_value) { - this.min_value = parseFloat(min_value); - this.max_value = parseFloat(max_value); - this.vertical_range = this.max_value - this.min_value; - $('#linetrack_' + track_id + '_minval').text(this.min_value); - $('#linetrack_' + track_id + '_maxval').text(this.max_value); + if ( min_value !== this.prefs.min_value || max_value !== this.prefs.max_value) { + this.prefs.min_value = parseFloat(min_value); + this.prefs.max_value = parseFloat(max_value); + this.vertical_range = this.prefs.max_value - this.prefs.min_value; + // Update the y-axis + $('#linetrack_' + track_id + '_minval').text(this.prefs.min_value); + $('#linetrack_' + track_id + '_maxval').text(this.prefs.max_value); this.tile_cache.clear(); this.draw(); } } }); -var FeatureTrack = function ( name, dataset_id, indexer, height ) { +var FeatureTrack = function ( name, dataset_id, indexer, prefs ) { + this.track_type = "FeatureTrack"; this.tile_cache = new Cache(CACHED_TILES_FEATURE); Track.call( this, name, $("#viewport") ); TiledTrack.call( this ); this.indexer = indexer; - this.height_px = (height ? height : 100); + this.height_px = 100; this.container_div.addClass( "feature-track" ); this.dataset_id = dataset_id; this.zo_slots = {}; @@ -429,14 +448,16 @@ this.showing_details = false; this.vertical_detail_px = 10; this.vertical_nodetail_px = 3; - this.block_color = "black"; - this.label_color = "black"; this.default_font = "9px Monaco, Lucida Console, monospace"; this.left_offset = 200; this.inc_slots = {}; this.data_queue = {}; this.s_e_by_tile = {}; this.data_cache = new Cache(20); + this.prefs = { 'block_color': 'black', 'label_color': 'black' }; + if (prefs.block_color !== undefined) { this.prefs.block_color = prefs.block_color; } + if (prefs.label_color !== undefined) { this.prefs.label_color = prefs.label_color; } + }; $.extend( FeatureTrack.prototype, TiledTrack.prototype, { init: function() { @@ -609,18 +630,23 @@ // console.log(tile_low, tile_high, tile_length, w_scale); var width = Math.ceil( tile_span * w_scale ), - new_canvas = $("<canvas class='tile'></canvas>"); + new_canvas = $("<canvas class='tile'></canvas>"), + label_color = this.prefs.label_color, + block_color = this.prefs.block_color, + left_offset = this.left_offset, + showing_details = this.showing_details, + y_scale = (this.showing_details ? this.vertical_detail_px : this.vertical_nodetail_px); new_canvas.css({ position: "absolute", top: 0, - left: ( tile_low - this.view.low ) * w_scale - this.left_offset + left: ( tile_low - this.view.low ) * w_scale - left_offset }); - new_canvas.get(0).width = width + this.left_offset; + new_canvas.get(0).width = width + left_offset; new_canvas.get(0).height = required_height; // console.log(( tile_low - this.view.low ) * w_scale, tile_index, w_scale); var ctx = new_canvas.get(0).getContext("2d"); - ctx.fillStyle = this.block_color; + ctx.fillStyle = this.prefs.block_color; ctx.font = this.default_font; ctx.textAlign = "right"; @@ -630,22 +656,22 @@ if (feature.start <= tile_high && feature.end >= tile_low) { var f_start = Math.floor( Math.max(0, (feature.start - tile_low) * w_scale) ), f_end = Math.ceil( Math.min(width, (feature.end - tile_low) * w_scale) ), - y_center = slots[feature.uid] * (this.showing_details ? this.vertical_detail_px : this.vertical_nodetail_px); + y_center = slots[feature.uid] * y_scale; var thickness, y_start, thick_start = null, thick_end = null; if (feature.thick_start && feature.thick_end) { thick_start = Math.floor( Math.max(0, (feature.thick_start - tile_low) * w_scale) ); thick_end = Math.ceil( Math.min(width, (feature.thick_end - tile_low) * w_scale) ); } - if (!this.showing_details) { + if (!showing_details) { // Non-detail levels - ctx.fillRect(f_start + this.left_offset, y_center + 5, f_end - f_start, 1); + ctx.fillRect(f_start + left_offset, y_center + 5, f_end - f_start, 1); } else { // Showing labels, blocks, details if (feature.start > tile_low) { - ctx.fillStyle = this.label_color; - ctx.fillText(feature.name, f_start - 1 + this.left_offset, y_center + 8); - ctx.fillStyle = this.block_color; + ctx.fillStyle = label_color; + ctx.fillText(feature.name, f_start - 1 + left_offset, y_center + 8); + ctx.fillStyle = block_color; } var blocks = feature.blocks; if (blocks) { @@ -656,8 +682,8 @@ } else if (feature.strand == "-") { ctx.fillStyle = LEFT_STRAND; } - ctx.fillRect(f_start + this.left_offset, y_center, f_end - f_start, 10); - ctx.fillStyle = this.block_color; + ctx.fillRect(f_start + left_offset, y_center, f_end - f_start, 10); + ctx.fillStyle = block_color; } for (var k = 0, k_len = blocks.length; k < k_len; k++) { @@ -668,7 +694,7 @@ // Draw the block thickness = 5; y_start = 3; - ctx.fillRect(block_start + this.left_offset, y_center + y_start, block_end - block_start, thickness); + ctx.fillRect(block_start + left_offset, y_center + y_start, block_end - block_start, thickness); // Draw thick regions: check if block intersects with thick region if (thick_start !== undefined && !(block_start > thick_end || block_end < thick_start) ) { @@ -676,7 +702,7 @@ y_start = 1; var block_thick_start = Math.max(block_start, thick_start), block_thick_end = Math.min(block_end, thick_end); - ctx.fillRect(block_thick_start + this.left_offset, y_center + y_start, block_thick_end - block_thick_start, thickness); + ctx.fillRect(block_thick_start + left_offset, y_center + y_start, block_thick_end - block_thick_start, thickness); } } @@ -684,15 +710,15 @@ // If there are no blocks, we treat the feature as one big exon thickness = 9; y_start = 1; - ctx.fillRect(f_start + this.left_offset, y_center + y_start, f_end - f_start, thickness); + ctx.fillRect(f_start + left_offset, y_center + y_start, f_end - f_start, thickness); if ( feature.strand ) { if (feature.strand == "+") { ctx.fillStyle = RIGHT_STRAND_INV; } else if (feature.strand == "-") { ctx.fillStyle = LEFT_STRAND_INV; } - ctx.fillRect(f_start + this.left_offset, y_center, f_end - f_start, 10); - ctx.fillStyle = this.block_color; + ctx.fillRect(f_start + left_offset, y_center, f_end - f_start, 10); + ctx.fillStyle = prefs.block_color; } } } @@ -707,29 +733,29 @@ var block_color = 'track_' + track_id + '_block_color', block_color_label = $('<label></label>').attr("for", block_color).text("Block color:"), - block_color_input = $('<input></input>').attr("id", block_color).attr("name", block_color).val(this.block_color), + block_color_input = $('<input></input>').attr("id", block_color).attr("name", block_color).val(this.prefs.block_color), label_color = 'track_' + track_id + '_label_color', label_color_label = $('<label></label>').attr("for", label_color).text("Label color:"), - label_color_input = $('<input></input>').attr("id", label_color).attr("name", label_color).val(this.label_color); + label_color_input = $('<input></input>').attr("id", label_color).attr("name", label_color).val(this.prefs.label_color); return container.append(block_color_label).append(block_color_input).append(label_color_label).append(label_color_input); }, update_options: function(track_id) { var block_color = $('#track_' + track_id + '_block_color').val(), label_color = $('#track_' + track_id + '_label_color').val(); - if (block_color !== this.block_color || label_color !== this.label_color) { - this.block_color = block_color; - this.label_color = label_color; + if (block_color !== this.prefs.block_color || label_color !== this.prefs.label_color) { + this.prefs.block_color = block_color; + this.prefs.label_color = label_color; this.tile_cache.clear(); this.draw(); } } }); -var ReadTrack = function ( name, dataset_id, indexer, height ) { +var ReadTrack = function ( name, dataset_id, indexer, prefs ) { + this.track_type = "ReadTrack"; this.tile_cache = new Cache(CACHED_TILES_FEATURE); Track.call( this, name, $("#viewport") ); TiledTrack.call( this ); - FeatureTrack.call( this, name, dataset_id, indexer, height ); - this.default_font = "9px Monaco, Lucida Console, monospace"; + FeatureTrack.call( this, name, dataset_id, indexer, prefs ); }; $.extend( ReadTrack.prototype, TiledTrack.prototype, FeatureTrack.prototype, { @@ -760,7 +786,7 @@ new_canvas.get(0).height = required_height; // console.log(( tile_low - this.view.low ) * w_scale, tile_index, w_scale); var ctx = new_canvas.get(0).getContext("2d"); - ctx.fillStyle = this.block_color; + ctx.fillStyle = this.prefs.block_color; ctx.font = this.default_font; ctx.textAlign = "right"; var px_per_char = ctx.measureText("A").width; diff -r 1748118a736b -r f1cc27efc29e static/trackster.css --- a/static/trackster.css Fri Jan 29 14:50:37 2010 -0500 +++ b/static/trackster.css Fri Jan 29 17:10:34 2010 -0500 @@ -1,16 +1,3 @@ -body, html { - height: 100%; -} - -body { - margin: 0 0; - padding: 0; - font-family: verdana; - font-size: 12px; - overflow: hidden; - background: #eeeeee; -} - #content { width: 100%; } @@ -24,10 +11,6 @@ bottom: 0; } -input { - font-size: 100%; -} - /*canvas{ border-left: 1px solid green; border-right: 1px solid red; } /* debugging */ diff -r 1748118a736b -r f1cc27efc29e templates/grid_base.mako --- a/templates/grid_base.mako Fri Jan 29 14:50:37 2010 -0500 +++ b/templates/grid_base.mako Fri Jan 29 17:10:34 2010 -0500 @@ -205,6 +205,7 @@ var grid = this; var checkboxes = $(this).find("input.grid-row-select-checkbox"); var update = $(this).find( "span.grid-selected-count" ); + update.text(""); $(checkboxes).each( function() { $(this).change( function() { var n = $(checkboxes).filter("[checked]").size(); @@ -834,6 +835,7 @@ <% num_rows_rendered = 1 %> %endif %for i, item in enumerate( query ): + <% encoded_id = trans.security.encode_id( item.id ) %> <tr \ %if current_item == item: class="current" \ @@ -842,7 +844,7 @@ ## Item selection column %if show_item_checkboxes: <td style="width: 1.5em;"> - <input type="checkbox" name="id" value=${trans.security.encode_id( item.id )} class="grid-row-select-checkbox" /> + <input type="checkbox" id="${encoded_id}" name="id" value="${encoded_id}" class="grid-row-select-checkbox" /> </td> %endif ## Data columns @@ -875,12 +877,12 @@ cls = "menubutton" if column.attach_popup and href: cls = "menubutton split" - + %> - %if href: + %if href: <td><div id="${id}" class="${cls}" style="float: left;"><a class="label" href="${href}">${v}</a></td> %else: - <td><div id="${id}" class="${cls}">${v}</div></td> + <td><div id="${id}" class="${cls}"><label for="${encoded_id}">${v}</label></div></td> %endif %endfor %endif diff -r 1748118a736b -r f1cc27efc29e templates/tracks/add_tracks.mako --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/tracks/add_tracks.mako Fri Jan 29 17:10:34 2010 -0500 @@ -0,0 +1,12 @@ +## Template generates a grid that enables user to add tracks +<%namespace file="../grid_base.mako" import="*" /> + +${javascripts()} +${stylesheets()} +${render_grid_table( grid, show_item_checkboxes=True )} + +## Initialize the grid. +<script type="text/javascript"> + init_grid_elements(); + init_grid_controls(); +</script> diff -r 1748118a736b -r f1cc27efc29e templates/tracks/browser.mako --- a/templates/tracks/browser.mako Fri Jan 29 14:50:37 2010 -0500 +++ b/templates/tracks/browser.mako Fri Jan 29 17:10:34 2010 -0500 @@ -78,16 +78,18 @@ ## <input name="title" id="title" value="${title}" /> <div id="show-hide-move"> <ul id="sortable-ul"></ul> -## <input type="submit" id="update-config" value="Save settings" /> - <input type="button" id="refresh-button" value="Refresh" /> </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" /> </form> </%def> <%def name="javascripts()"> ${parent.javascripts()} -${h.js( "jquery", "jquery.event.drag", "jquery.mousewheel", "trackster", "ui.core", "ui.sortable" )} +${h.js( "json2", "jquery", "jquery.event.drag", "jquery.mousewheel", "trackster", "ui.core", "ui.sortable" )} <script type="text/javascript"> @@ -100,7 +102,9 @@ view.add_track( new LabelTrack( $("#nav-labeltrack" ) ) ); %for track in tracks: - view.add_track( new ${track["type"]}( "${track['name']}", ${track['dataset_id']}, "${track['indexer']}" ) ); + view.add_track( + new ${track["track_type"]}( "${track['name']}", ${track['dataset_id']}, "${track['indexer']}", ${track['prefs']} ) + ); %endfor $(document).bind( "redraw", function( e ) { @@ -164,12 +168,51 @@ }); $("#refresh-button").bind( "click", function(e) { - for (var track_id in view.tracks) { - var track = view.tracks[track_id]; - if (track.update_options) { - track.update_options(track_id); + 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() { + 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 + }); } + $.ajax({ + url: "${h.url_for( action='save' )}", + data: { + 'id': '${id}', + 'payload': JSON.stringify(payload) + } + }); }); // Execute this on page load @@ -195,12 +238,12 @@ var track = view.tracks[track_id]; if (!track.hidden) { var label = $('<label for="track_' + track_id + 'title">' + track.name + '</label>'); - var title = $('<div class="toolFormTitle"></div>'); + var title = $('<div class="historyItemTitle"></div>'); var del_icon = $('<a style="display:block; float:right" href="#" class="icon-button delete" />'); - var body = $('<div class="toolFormBody"></div>'); + var body = $('<div class="historyItemBody"></div>'); // var checkbox = $('<input type="checkbox" checked="checked"></input>').attr("id", "track_" + track_id + "title"); var li = $('<li class="sortable"></li>').attr("id", "track_" + track_id); - var div = $('<div class="toolForm"></div>'); + var div = $('<div class="historyItemContainer historyItem"></div>'); del_icon.prependTo(title); label.appendTo(title); // checkbox.prependTo(title);