galaxy-commits
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
May 2010
- 2 participants
- 158 discussions

10 May '10
details: http://www.bx.psu.edu/hg/galaxy/rev/c7607fba91b9
changeset: 3741:c7607fba91b9
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Tue May 04 14:21:21 2010 -0400
description:
Fix the recentrly introduced grid filter / search bug. Revert the recently introduced grid filter_params hack for generating links since we now use a different approach to rendering links. Convert a few more 'message_type' params to be 'status' instead. Many fixes for the community space app.
diffstat:
lib/galaxy/tools/__init__.py | 4 +-
lib/galaxy/web/framework/__init__.py | 2 +-
lib/galaxy/web/framework/helpers/grids.py | 17 +-
lib/galaxy/webapps/community/controllers/admin.py | 154 +++++++++++++-------
lib/galaxy/webapps/community/controllers/common.py | 90 ++++++++---
lib/galaxy/webapps/community/controllers/tool.py | 157 +++++++++++---------
lib/galaxy/webapps/community/controllers/upload.py | 33 ++--
lib/galaxy/webapps/community/model/__init__.py | 4 +-
templates/dataset/display_application/display.mako | 4 +-
templates/display_common.mako | 4 +-
templates/grid_base.mako | 16 +-
templates/grid_base_async.mako | 2 +-
templates/message.mako | 12 +-
templates/page/select_items_grid_async.mako | 2 +-
templates/webapps/community/admin/center.mako | 39 ++++-
templates/webapps/community/tool/edit_tool.mako | 19 +-
templates/webapps/community/tool/view_tool.mako | 25 ++-
17 files changed, 354 insertions(+), 230 deletions(-)
diffs (1213 lines):
diff -r 68fc85a43bb8 -r c7607fba91b9 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py Tue May 04 14:19:44 2010 -0400
+++ b/lib/galaxy/tools/__init__.py Tue May 04 14:21:21 2010 -0400
@@ -837,7 +837,7 @@
assert isinstance( out_data, odict )
return 'tool_executed.mako', dict( out_data=out_data )
except:
- return 'message.mako', dict( message_type='error', message='odict not returned from tool execution', refresh_frames=[] )
+ return 'message.mako', dict( status='error', message='odict not returned from tool execution', refresh_frames=[] )
# Otherwise move on to the next page
else:
state.page += 1
@@ -890,7 +890,7 @@
self.sa_session.add( data )
self.sa_session.flush()
# It's unlikely the user will ever see this.
- return 'message.mako', dict( message_type='error', message='Your upload was interrupted. If this was uninentional, please retry it.', refresh_frames=[], cont=None )
+ return 'message.mako', dict( status='error', message='Your upload was interrupted. If this was uninentional, please retry it.', refresh_frames=[], cont=None )
def update_state( self, trans, inputs, state, incoming, prefix="", context=None,
update_only=False, old_errors={}, item_callback=None ):
diff -r 68fc85a43bb8 -r c7607fba91b9 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py Tue May 04 14:19:44 2010 -0400
+++ b/lib/galaxy/web/framework/__init__.py Tue May 04 14:21:21 2010 -0400
@@ -591,7 +591,7 @@
`refresh_frames`: names of frames in the interface that should be
refreshed when the message is displayed
"""
- return self.fill_template( "message.mako", message_type=type, message=message, refresh_frames=refresh_frames, cont=cont, use_panels=use_panels, active_view=active_view )
+ return self.fill_template( "message.mako", status=type, message=message, refresh_frames=refresh_frames, cont=cont, use_panels=use_panels, active_view=active_view )
def show_error_message( self, message, refresh_frames=[], use_panels=False, active_view="" ):
"""
Convenience method for displaying an error message. See `show_message`.
diff -r 68fc85a43bb8 -r c7607fba91b9 lib/galaxy/web/framework/helpers/grids.py
--- a/lib/galaxy/web/framework/helpers/grids.py Tue May 04 14:19:44 2010 -0400
+++ b/lib/galaxy/web/framework/helpers/grids.py Tue May 04 14:21:21 2010 -0400
@@ -134,13 +134,16 @@
column_filter = unicode(column_filter)
extra_url_args[ "f-" + column.key ] = column_filter.encode("utf-8")
# Process sort arguments.
- sort_key = sort_order = None
+ sort_key = None
+ sort_order = None
if 'sort' in kwargs:
sort_key = kwargs['sort']
elif base_sort_key:
sort_key = base_sort_key
encoded_sort_key = sort_key
if sort_key:
+ # TODO: what if the model object of the grid column being sorted is not
+ # the same object as self.model_class?
if sort_key.startswith( "-" ):
sort_key = sort_key[1:]
sort_order = 'desc'
@@ -230,10 +233,10 @@
current_item=current_item,
ids = kwargs.get( 'id', [] ),
url = url,
- message_type = status,
+ status = status,
message = message,
use_panels=use_panels,
- webapp=self.webapp,
+ webapp=webapp,
# Pass back kwargs so that grid template can set and use args without
# grid explicitly having to pass them.
kwargs=kwargs )
@@ -290,9 +293,7 @@
if self.format:
value = self.format( value )
return value
- def get_link( self, trans, grid, item, filter_params ):
- # FIXME: filter_params is only here so we can do grid filtering from
- # column links. remove once a better way is created.
+ def get_link( self, trans, grid, item ):
if self.link and self.link( item ):
return self.link( item )
return None
@@ -449,7 +450,7 @@
class PublicURLColumn( TextColumn ):
""" Column displays item's public URL based on username and slug. """
- def get_link( self, trans, grid, item, filter_params ):
+ def get_link( self, trans, grid, item ):
if item.user.username and item.slug:
return dict( action='display_by_username_and_slug', username=item.user.username, slug=item.slug )
elif not item.user.username:
@@ -485,7 +486,7 @@
if item.published:
sharing_statuses.append( "Published" )
return ", ".join( sharing_statuses )
- def get_link( self, trans, grid, item, filter_params ):
+ def get_link( self, trans, grid, item ):
if not item.deleted and ( item.users_shared_with or item.importable or item.published ):
return dict( operation="share or publish", id=item.id )
return None
diff -r 68fc85a43bb8 -r c7607fba91b9 lib/galaxy/webapps/community/controllers/admin.py
--- a/lib/galaxy/webapps/community/controllers/admin.py Tue May 04 14:19:44 2010 -0400
+++ b/lib/galaxy/webapps/community/controllers/admin.py Tue May 04 14:21:21 2010 -0400
@@ -47,7 +47,7 @@
return ""
class ToolsColumn( grids.TextColumn ):
def get_value( self, trans, grid, user ):
- return '<a href="browse_tools_by_user?operation=browse&id=%s">%s</a>' % ( trans.security.encode_id( user.id ), str( len( user.tools ) ) )
+ return '<a href="browse_tools_by_user?operation=browse&id=%s&webapp=community">%s</a>' % ( trans.security.encode_id( user.id ), str( len( user.tools ) ) )
# Grid definition
webapp = "community"
@@ -77,7 +77,10 @@
attach_popup=False,
filterable="advanced" ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
cols_to_filter=[ columns[0], columns[1] ],
@@ -168,7 +171,10 @@
UsersColumn( "Users", attach_popup=False ),
StatusColumn( "Status", attach_popup=False ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
cols_to_filter=[ columns[0], columns[1], columns[2] ],
@@ -238,16 +244,20 @@
default_sort_key = "name"
columns = [
NameColumn( "Name",
- key="name",
+ #key="name",
link=( lambda item: dict( operation="Manage users and roles", id=item.id, webapp="community" ) ),
model_class=model.Group,
- attach_popup=True,
- filterable="advanced" ),
+ attach_popup=True
+ #filterable="advanced"
+ ),
UsersColumn( "Users", attach_popup=False ),
RolesColumn( "Roles", attach_popup=False ),
StatusColumn( "Status", attach_popup=False ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
cols_to_filter=[ columns[0], columns[1], columns[2] ],
@@ -309,14 +319,18 @@
attach_popup=False,
filterable="advanced" ),
DescriptionColumn( "Description",
+ key="description",
model_class=model.Category,
attach_popup=False,
filterable="advanced" ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
- cols_to_filter=[ columns[0], columns[1], columns[2] ],
+ cols_to_filter=[ columns[0], columns[1] ],
key="free-text-search",
visible=False,
filterable="standard" ) )
@@ -370,24 +384,34 @@
default_sort_key = "name"
columns = [
NameColumn( "Name",
- key="name",
+ # TODO: we cannot currently sort by columns since the grid may be filtered by tool ids
+ # and it is not clear if / how that will work. We need to be able to send to the grid helper
+ # the list of ids on which to filter when sorting on the column.
+ #key="name",
+ model_class=model.Category,
link=( lambda item: dict( operation="Browse Category", id=item.id, webapp="community" ) ),
- model_class=model.Category,
- attach_popup=True,
- filterable="advanced" ),
+ attach_popup=False
+ #filterable="advanced"
+ ),
DescriptionColumn( "Description",
+ #key="description",
model_class=model.Category,
- attach_popup=False,
- filterable="advanced" ),
+ attach_popup=False
+ #filterable="advanced"
+ ),
ToolsColumn( "Tools",
- model_class=model.Category,
+ model_class=model.Tool,
attach_popup=False,
filterable="advanced" ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
- cols_to_filter=[ columns[0], columns[1], columns[2] ],
+ #cols_to_filter=[ columns[0], columns[1] ],
+ cols_to_filter=[],
key="free-text-search",
visible=False,
filterable="standard" ) )
@@ -399,10 +423,17 @@
num_rows_per_page = 50
preserve_state = False
use_paging = True
- def get_current_item( self, trans ):
- return None
def build_initial_query( self, session ):
return session.query( self.model_class )
+ def apply_default_filter( self, trans, query, **kwd ):
+ ids = kwd.get( 'ids', False )
+ if ids:
+ if str( ids ).lower() == 'none':
+ # No tools for display
+ return query.filter( model.Tool.id == None )
+ ids = util.listify( ids )
+ query = query.filter( or_( *map( lambda id: self.model_class.id == id, ids ) ) )
+ return query
class ToolListGrid( grids.Grid ):
class NameColumn( grids.TextColumn ):
@@ -419,7 +450,7 @@
if tool.categories:
rval = ''
for tca in tool.categories:
- rval += '<a href="browse_category?id=%s">%s</a><br/>\n' % ( trans.security.encode_id( tca.category.id ), tca.category.name )
+ rval += '<a href="browse_category?id=%s&webapp=community">%s</a><br/>\n' % ( trans.security.encode_id( tca.category.id ), tca.category.name )
return rval
return 'not set'
class StateColumn( grids.GridColumn ):
@@ -450,7 +481,7 @@
return accepted_filters
class UserColumn( grids.TextColumn ):
def get_value( self, trans, grid, tool ):
- return '<a href="browse_tools_by_user?operation=browse&id=%s">%s</a>' % ( trans.security.encode_id( tool.user.id ), tool.user.username )
+ return '<a href="browse_tools_by_user?operation=browse&id=%s&webapp=community">%s</a>' % ( trans.security.encode_id( tool.user.id ), tool.user.username )
# Grid definition
title = "Tools"
model_class = model.Tool
@@ -458,19 +489,25 @@
default_sort_key = "name"
columns = [
NameColumn( "Name",
- key="name",
+ # TODO: we cannot currently sort by columns since the grid may be filtered by tool ids
+ # and it is not clear if / how that will work. We need to be able to send to the grid helper
+ # the list of ids on which to filter when sorting on the column.
+ #key="name",
+ link=( lambda item: dict( operation="View Tool", id=item.id, cntrller="admin", webapp="community" ) ),
model_class=model.Tool,
- link=( lambda item: dict( operation="View Tool", id=item.id, cntrller='admin', webapp="community" ) ),
- attach_popup=True,
- filterable="advanced" ),
+ attach_popup=True
+ #filterable="advanced"
+ ),
VersionColumn( "Version",
model_class=model.Tool,
attach_popup=False,
filterable="advanced" ),
DescriptionColumn( "Description",
- model_class=model.Tool,
- attach_popup=False,
- filterable="advanced" ),
+ #key="description",
+ model_class=model.Tool,
+ attach_popup=False
+ #filterable="advanced"
+ ),
CategoryColumn( "Category",
model_class=model.Category,
attach_popup=False,
@@ -479,15 +516,19 @@
model_class=model.Event,
attach_popup=False ),
UserColumn( "Uploaded By",
- key="username",
model_class=model.User,
attach_popup=False,
filterable="advanced" ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", model_class=model.Tool, key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ model_class=model.Tool,
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
- cols_to_filter=[ columns[0], columns[1] ],
+ #cols_to_filter=[ columns[0], columns[2], columns[5] ],
+ cols_to_filter=[],
key="free-text-search",
visible=False,
filterable="standard" ) )
@@ -499,7 +540,7 @@
]
standard_filters = [
grids.GridColumnFilter( "Deleted", args=dict( deleted=True ) ),
- grids.GridColumnFilter( "All", args=dict( deleted='All' ) )
+ grids.GridColumnFilter( "All", args=dict( deleted='All' ) ),
]
default_filter = dict( name="All", deleted="False" )
num_rows_per_page = 50
@@ -508,15 +549,14 @@
def build_initial_query( self, session ):
return session.query( self.model_class )
def apply_default_filter( self, trans, query, **kwd ):
- tool_id = kwd.get( 'tool_id', False )
- if tool_id:
- if str( tool_id ).lower() in [ '', 'none' ]:
- # Return an empty query since the current user cannot view any
- # tools (possibly due to state not being approved, etc).
+ ids = kwd.get( 'ids', False )
+ if ids:
+ if str( ids ).lower() == 'none':
+ # No tools for display
return query.filter( model.Tool.id == None )
- tool_id = util.listify( tool_id )
- query = query.filter( or_( *map( lambda id: self.model_class.id == id, tool_id ) ) )
- return query.filter( self.model_class.deleted==False )
+ ids = util.listify( ids )
+ query = query.filter( or_( *map( lambda id: self.model_class.id == id, ids ) ) )
+ return query
class AdminController( BaseController, Admin ):
@@ -616,12 +656,12 @@
status='error' ) )
event = get_event( trans, id )
state = event.state
- tool_id = get_tools_by_state( trans, state )
- if not tool_id:
- tool_id = 'None'
+ ids = get_tools_by_state( trans, state )
+ if not ids:
+ ids = 'none'
return trans.response.send_redirect( web.url_for( controller='admin',
action='browse_tools',
- tool_id=tool_id ) )
+ ids=ids ) )
@web.expose
@web.require_admin
def browse_category( self, trans, **kwd ):
@@ -681,7 +721,10 @@
# If we're approving a tool, all previous versions must be set to archived
for version in get_versions( trans, tool ):
if version != tool and version.is_approved():
- self.set_tool_state( trans, trans.app.model.Tool.states.ARCHIVED, id=trans.app.security.encode_id( version.id ), redirect='False' )
+ self.set_tool_state( trans,
+ trans.app.model.Tool.states.ARCHIVED,
+ id=trans.security.encode_id( version.id ),
+ redirect='False' )
event = trans.model.Event( state )
# Flush so we an get an id
trans.sa_session.add( event )
@@ -842,33 +885,34 @@
## ---- Utility methods -------------------------------------------------------
def get_tools_by_state( trans, state ):
- tool_id = []
+ # TODO: write this as a query using eagerload - will be much faster.
+ ids = []
if state == trans.model.Tool.states.NEW:
for tool in get_tools( trans ):
if tool.is_new():
- tool_id.append( tool.id )
+ ids.append( tool.id )
elif state == trans.model.Tool.states.ERROR:
for tool in get_tools( trans ):
if tool.is_error():
- tool_id.append( tool.id )
+ ids.append( tool.id )
elif state == trans.model.Tool.states.DELETED:
for tool in get_tools( trans ):
if tool.is_deleted():
- tool_id.append( tool.id )
+ ids.append( tool.id )
elif state == trans.model.Tool.states.WAITING:
for tool in get_tools( trans ):
if tool.is_waiting():
- tool_id.append( tool.id )
+ ids.append( tool.id )
elif state == trans.model.Tool.states.APPROVED:
for tool in get_tools( trans ):
if tool.is_approved():
- tool_id.append( tool.id )
+ ids.append( tool.id )
elif state == trans.model.Tool.states.REJECTED:
for tool in get_tools( trans ):
if tool.is_rejected():
- tool_id.append( tool.id )
+ ids.append( tool.id )
elif state == trans.model.Tool.states.ARCHIVED:
for tool in get_tools( trans ):
if tool.is_archived():
- tool_id.append( tool.id )
- return tool_id
+ ids.append( tool.id )
+ return ids
diff -r 68fc85a43bb8 -r c7607fba91b9 lib/galaxy/webapps/community/controllers/common.py
--- a/lib/galaxy/webapps/community/controllers/common.py Tue May 04 14:19:44 2010 -0400
+++ b/lib/galaxy/webapps/community/controllers/common.py Tue May 04 14:21:21 2010 -0400
@@ -91,6 +91,35 @@
message=message,
status=status )
@web.expose
+ def delete_tool( self, trans, cntrller, **kwd ):
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ id = params.get( 'id', None )
+ if not id:
+ message='Select a tool to delete'
+ status='error'
+ else:
+ tool = get_tool( trans, id )
+ # Create a new event
+ event = trans.model.Event( state=trans.model.Tool.states.DELETED )
+ # Flush so we can get an event id
+ trans.sa_session.add( event )
+ trans.sa_session.flush()
+ # Associate the tool with the event
+ tea = trans.model.ToolEventAssociation( tool=tool, event=event )
+ # Delete the tool, keeping state for categories, events and versions
+ tool.deleted = True
+ trans.sa_session.add_all( ( tool, tea ) )
+ trans.sa_session.flush()
+ # TODO: What if the tool has versions, should they all be deleted?
+ message = "Tool '%s' has been marked deleted"
+ status = 'done'
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='browse_tools',
+ message=message,
+ status=status ) )
+ @web.expose
def upload_new_tool_version( self, trans, cntrller, **kwd ):
params = util.Params( kwd )
message = util.restore_text( params.get( 'message', '' ) )
@@ -122,15 +151,15 @@
# If request came from the tool controller, then we need to filter by the state of the
# tool in addition to the category.
if cntrller == 'tool':
- tool_id = get_approved_tools( trans, category=category )
+ ids = get_approved_tools( trans, category=category )
else:
# If request came from the admin controller, we don't filter on tool state.
- tool_id = [ tca.tool.id for tca in category.tools ]
- if not tool_id:
- tool_id = 'None'
+ ids = [ tca.tool.id for tca in category.tools ]
+ if not ids:
+ ids = 'none'
return trans.response.send_redirect( web.url_for( controller=cntrller,
action='browse_tools',
- tool_id=tool_id ) )
+ ids=ids ) )
@web.expose
def browse_tools_by_user( self, trans, cntrller, **kwd ):
params = util.Params( kwd )
@@ -146,15 +175,21 @@
# If request came from the tool controller, then we need to filter by the state of the
# tool if the user is not viewing his own tools
if cntrller == 'tool':
- tool_id = get_approved_tools( trans, user=user )
+ ids = get_tools_uploaded_by( trans, user )
else:
- # If request came from the admin controller, we don't filter on tool state.
- tool_id = [ tool.id for tool in user.tools ]
- if not tool_id:
- tool_id = 'None'
+ # If request came from the admin controller we don't filter on tool state.
+ ids = [ tool.id for tool in user.tools ]
+ if not ids:
+ ids = 'none'
+ if cntrller == 'tool' and user != trans.user:
+ # If the user is browsing someone else's tools, then we do not want to
+ # use the BrowseToolsByUser list grid since it includes a status column.
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='browse_tools',
+ ids=ids ) )
return trans.response.send_redirect( web.url_for( controller=cntrller,
action='browse_tools_by_user',
- tool_id=tool_id ) )
+ ids=ids ) )
## ---- Utility methods -------------------------------------------------------
@@ -202,30 +237,33 @@
return trans.sa_session.query( trans.model.Tool ).get( trans.app.security.decode_id( id ) )
def get_tools( trans ):
return trans.sa_session.query( trans.model.Tool ).order_by( trans.model.Tool.name )
-def get_approved_tools( trans, category=None, user=None ):
- tool_id = []
+def get_approved_tools( trans, category=None ):
+ # TODO: write this as a query using eagerload - will be much faster.
+ ids = []
if category:
# Return only the approved tools in the category
for tca in category.tools:
tool = tca.tool
if tool.is_approved():
- tool_id.append( tool.id )
- elif user:
- if trans.user == user:
- # If the current user is browsing his own tools, then don't filter on state
- tool_id = [ tool.id for tool in user.tools ]
- else:
- # The current user is viewing all tools uploaded by another user, so show only
- # approved tools
- for tool in user.active_tools:
- if tool.is_approved():
- tool_id.append( tool.id )
+ ids.append( tool.id )
else:
# Return all approved tools
for tool in get_tools( trans ):
if tool.is_approved():
- tool_id.append( tool.id )
- return tool_id
+ ids.append( tool.id )
+ return ids
+def get_tools_uploaded_by( trans, user ):
+ # TODO: write this as a query using eagerload - will be much faster.
+ ids = []
+ if trans.user == user:
+ # If the current user is browsing his own tools, then don't filter on state
+ ids = [ tool.id for tool in user.tools ]
+ else:
+ # The current user is viewing tools uploaded by another user, so show only approved tools
+ for tool in user.active_tools:
+ if tool.is_approved():
+ ids.append( tool.id )
+ return ids
def get_event( trans, id ):
return trans.sa_session.query( trans.model.Event ).get( trans.security.decode_id( id ) )
def get_user( trans, id ):
diff -r 68fc85a43bb8 -r c7607fba91b9 lib/galaxy/webapps/community/controllers/tool.py
--- a/lib/galaxy/webapps/community/controllers/tool.py Tue May 04 14:19:44 2010 -0400
+++ b/lib/galaxy/webapps/community/controllers/tool.py Tue May 04 14:21:21 2010 -0400
@@ -26,12 +26,12 @@
if tool.categories:
rval = ''
for tca in tool.categories:
- rval += '<a href="browse_category?id=%s">%s</a><br/>\n' % ( trans.security.encode_id( tca.category.id ), tca.category.name )
+ rval += '<a href="browse_category?id=%s&webapp=community">%s</a><br/>\n' % ( trans.security.encode_id( tca.category.id ), tca.category.name )
return rval
return 'not set'
class UserColumn( grids.TextColumn ):
def get_value( self, trans, grid, tool ):
- return '<a href="browse_tools_by_user?operation=browse&id=%s">%s</a>' % ( trans.security.encode_id( tool.user.id ), tool.user.username )
+ return '<a href="browse_tools_by_user?operation=browse&id=%s&webapp=community">%s</a>' % ( trans.security.encode_id( tool.user.id ), tool.user.username )
# Grid definition
title = "Tools"
model_class = model.Tool
@@ -39,33 +39,44 @@
default_sort_key = "name"
columns = [
NameColumn( "Name",
- key="name",
+ # TODO: we cannot currently sort by columns since the grid may be filtered by tool ids
+ # and it is not clear if / how that will work. We need to be able to send to the grid helper
+ # the list of ids on which to filter when sorting on the column.
+ #key="name",
model_class=model.Tool,
link=( lambda item: dict( operation="View Tool", id=item.id, cntrller='tool', webapp="community" ) ),
- attach_popup=True,
- filterable="advanced" ),
+ attach_popup=True
+ #filterable="advanced"
+ ),
VersionColumn( "Version",
model_class=model.Tool,
attach_popup=False,
filterable="advanced" ),
DescriptionColumn( "Description",
- model_class=model.Tool,
- attach_popup=False,
- filterable="advanced" ),
+ #key="description",
+ model_class=model.Tool,
+ attach_popup=False
+ #filterable="advanced"
+ ),
CategoryColumn( "Categories",
model_class=model.Category,
attach_popup=False,
filterable="advanced" ),
UserColumn( "Uploaded By",
- key="username",
+ #key="username",
model_class=model.User,
- attach_popup=False,
- filterable="advanced" ),
+ attach_popup=False
+ #filterable="advanced"
+ ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
- cols_to_filter=[ columns[0], columns[1] ],
+ #cols_to_filter=[ columns[0], columns[2], columns[4] ],
+ cols_to_filter=[],
key="free-text-search",
visible=False,
filterable="standard" ) )
@@ -86,21 +97,15 @@
def build_initial_query( self, session ):
return session.query( self.model_class )
def apply_default_filter( self, trans, query, **kwd ):
- def filter_query( query, tool_id ):
- if str( tool_id ).lower() in [ '', 'none' ]:
- # Return an empty query since the current user cannot view any
- # tools (possibly due to state not being approved, etc).
- return query.filter( model.Tool.id == None )
- tool_id = util.listify( tool_id )
- query = query.filter( or_( *map( lambda id: self.model_class.id == id, tool_id ) ) )
- return query.filter( self.model_class.deleted==False )
- tool_id = kwd.get( 'tool_id', False )
- if not tool_id:
+ ids = kwd.get( 'ids', False )
+ if not ids:
# Display only approved tools
- tool_id = get_approved_tools( trans )
- if not tool_id:
- tool_id = 'None'
- return filter_query( query, tool_id )
+ ids = get_approved_tools( trans )
+ if not ids or str( ids ).lower() == 'none':
+ return query.filter( trans.model.Tool.id == None )
+ ids = util.listify( ids )
+ query = query.filter( or_( *map( lambda id: self.model_class.id == id, ids ) ) )
+ return query
class ToolsByUserListGrid( grids.Grid ):
class NameColumn( grids.TextColumn ):
@@ -117,7 +122,7 @@
if tool.categories:
rval = ''
for tca in tool.categories:
- rval += '<a href="browse_category?id=%s">%s</a><br/>\n' % ( trans.security.encode_id( tca.category.id ), tca.category.name )
+ rval += '<a href="browse_category?id=%s&webapp=community">%s</a><br/>\n' % ( trans.security.encode_id( tca.category.id ), tca.category.name )
return rval
return 'not set'
class StateColumn( grids.GridColumn ):
@@ -148,7 +153,7 @@
return accepted_filters
class UserColumn( grids.TextColumn ):
def get_value( self, trans, grid, tool ):
- return '<a href="browse_tools_by_user?operation=browse&id=%s">%s</a>' % ( trans.security.encode_id( tool.user.id ), tool.user.username )
+ return '<a href="browse_tools_by_user?operation=browse&id=%s&webapp=community">%s</a>' % ( trans.security.encode_id( tool.user.id ), tool.user.username )
# Grid definition
title = "Tools By User"
model_class = model.Tool
@@ -156,19 +161,24 @@
default_sort_key = "name"
columns = [
NameColumn( "Name",
- key="name",
+ # TODO: we cannot currently sort by columns since the grid may be filtered by tool ids
+ # and it is not clear if / how that will work. We need to be able to send to the grid helper
+ # the list of ids on which to filter when sorting on the column.
+ #key="name",
model_class=model.Tool,
link=( lambda item: dict( operation="View Tool", id=item.id, cntrller='tool', webapp="community" ) ),
- attach_popup=True,
- filterable="advanced" ),
+ attach_popup=True
+ #filterable="advanced"
+ ),
VersionColumn( "Version",
model_class=model.Tool,
- attach_popup=False,
- filterable="advanced" ),
+ attach_popup=False ),
DescriptionColumn( "Description",
- model_class=model.Tool,
- attach_popup=False,
- filterable="advanced" ),
+ #key="description",
+ model_class=model.Tool,
+ attach_popup=False
+ #filterable="advanced"
+ ),
CategoryColumn( "Categories",
model_class=model.Category,
attach_popup=False,
@@ -177,15 +187,20 @@
model_class=model.Event,
attach_popup=False ),
UserColumn( "Uploaded By",
- key="username",
+ #key="username",
model_class=model.User,
- attach_popup=False,
- filterable="advanced" ),
+ attach_popup=False
+ #filterable="advanced"
+ ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
- cols_to_filter=[ columns[0], columns[1] ],
+ #cols_to_filter=[ columns[0], columns[2], columns[5] ],
+ cols_to_filter=[],
key="free-text-search",
visible=False,
filterable="standard" ) )
@@ -199,30 +214,24 @@
grids.GridColumnFilter( "Deleted", args=dict( deleted=True ) ),
grids.GridColumnFilter( "All", args=dict( deleted='All' ) )
]
- default_filter = dict( name="All", deleted="False", username="All" )
+ default_filter = dict( name="All", deleted="False" )
num_rows_per_page = 50
preserve_state = False
use_paging = True
def build_initial_query( self, session ):
return session.query( self.model_class )
def apply_default_filter( self, trans, query, **kwd ):
- def filter_query( query, tool_id ):
- if str( tool_id ).lower() in [ '', 'none' ]:
- # Return an empty query since the current user cannot view any
- # tools (possibly due to state not being approved, etc).
- return query.filter( model.Tool.id == None )
- tool_id = util.listify( tool_id )
- query = query.filter( or_( *map( lambda id: self.model_class.id == id, tool_id ) ) )
- return query.filter( self.model_class.deleted==False )
- tool_id = kwd.get( 'tool_id', False )
- if not tool_id:
+ ids = kwd.get( 'ids', False )
+ if not ids:
# Display only approved tools
- tool_id = get_approved_tools( trans )
- if not tool_id:
- tool_id = 'None'
- return filter_query( query, tool_id )
+ ids = get_approved_tools( trans )
+ if not ids or str( ids ).lower() == 'none':
+ return query.filter( trans.model.Tool.id == None )
+ ids = util.listify( ids )
+ query = query.filter( or_( *map( lambda id: self.model_class.id == id, ids ) ) )
+ return query
-class CategoryListGrid( grids.Grid ):
+class ToolsByCategoryListGrid( grids.Grid ):
class NameColumn( grids.TextColumn ):
def get_value( self, trans, grid, category ):
return category.name
@@ -242,28 +251,36 @@
# Grid definition
webapp = "community"
- title = "Tool Categories"
+ title = "Tools by Category"
model_class = model.Category
template='/webapps/community/category/grid.mako'
default_sort_key = "name"
columns = [
NameColumn( "Name",
- key="name",
+ # TODO: we cannot currently sort by columns since the grid may be filtered by tool ids
+ # and it is not clear if / how that will work. We need to be able to send to the grid helper
+ # the list of ids on which to filter when sorting on the column.
+ #key="name",
model_class=model.Category,
link=( lambda item: dict( operation="Browse Category", id=item.id, webapp="community" ) ),
- attach_popup=False,
- filterable="advanced" ),
+ attach_popup=False
+ #filterable="advanced"
+ ),
DescriptionColumn( "Description",
- key="description",
- model_class=model.Category,
- attach_popup=False,
- filterable="advanced" ),
+ #key="description",
+ model_class=model.Category,
+ attach_popup=False
+ #filterable="advanced"
+ ),
ToolsColumn( "Tools",
model_class=model.Tool,
attach_popup=False,
filterable="advanced" ),
# Columns that are valid for filtering but are not visible.
- grids.DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" )
+ grids.DeletedColumn( "Deleted",
+ key="deleted",
+ visible=False,
+ filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
cols_to_filter=[ columns[0], columns[1] ],
@@ -280,14 +297,12 @@
use_paging = True
def build_initial_query( self, session ):
return session.query( self.model_class )
- def apply_default_filter( self, trans, query, **kwd ):
- return query.filter( self.model_class.deleted==False )
class ToolController( BaseController ):
tool_list_grid = ToolListGrid()
tools_by_user_list_grid = ToolsByUserListGrid()
- category_list_grid = CategoryListGrid()
+ tools_by_category_list_grid = ToolsByCategoryListGrid()
@web.expose
def index( self, trans, **kwd ):
@@ -312,7 +327,7 @@
cntrller='tool',
**kwd ) )
# Render the list view
- return self.category_list_grid( trans, **kwd )
+ return self.tools_by_category_list_grid( trans, **kwd )
@web.expose
def browse_category( self, trans, **kwd ):
return trans.response.send_redirect( web.url_for( controller='common',
diff -r 68fc85a43bb8 -r c7607fba91b9 lib/galaxy/webapps/community/controllers/upload.py
--- a/lib/galaxy/webapps/community/controllers/upload.py Tue May 04 14:19:44 2010 -0400
+++ b/lib/galaxy/webapps/community/controllers/upload.py Tue May 04 14:21:21 2010 -0400
@@ -60,28 +60,26 @@
obj = datatype.create_model_object( meta )
trans.sa_session.add( obj )
if isinstance( obj, trans.app.model.Tool ):
- existing = trans.sa_session.query( trans.app.model.Tool ).filter_by( tool_id = meta.id ).all()
+ existing = trans.sa_session.query( trans.app.model.Tool ).filter_by( tool_id = meta.id ).first()
if existing and replace_id is None:
raise UploadError( 'A tool with the same ID already exists. If you are trying to update this tool to a new version, please use the upload form on the "Edit Tool" page. Otherwise, please choose a new ID.' )
elif existing:
- replace_version = trans.sa_session.query( trans.app.model.Tool ).get( int( trans.app.security.decode_id( replace_id ) ) )
+ replace_version = trans.sa_session.query( trans.app.model.Tool ).get( trans.security.decode_id( replace_id ) )
if replace_version.newer_version:
# If the user has picked an old version, switch to the newest version
replace_version = get_versions( trans, replace_version )[0]
- if trans.user != replace_version.user:
- raise UploadError( 'You are not the owner of this tool and may not upload new versions of it.' )
if replace_version.tool_id != meta.id:
- raise UploadError( 'The new tool id (%s) does not match the old tool id (%s). Please check the tool XML file' % ( meta.id, replace_version.tool_id ) )
+ raise UploadError( 'The new tool id (%s) does not match the old tool id (%s). Check the tool XML file' % ( meta.id, replace_version.tool_id ) )
for old_version in get_versions( trans, replace_version ):
if old_version.version == meta.version:
- raise UploadError( 'The new version (%s) matches an old version. Please check your version in the tool XML file' % meta.version )
+ raise UploadError( 'The new version (%s) matches an old version. Check your version in the tool XML file' % meta.version )
if old_version.is_new():
- raise UploadError( 'There is an existing version of this tool which is unsubmitted. Please either <a href="%s">submit or delete it</a> before uploading a new version.' % url_for( controller='common',
- action='view_tool',
- cntrller='tool',
- id=trans.app.security.encode_id( old_version.id ) ) )
+ raise UploadError( 'There is an existing version of this tool which has not yet been submitted for approval, so either <a href="%s">submit or delete it</a> before uploading a new version.' % url_for( controller='common',
+ action='view_tool',
+ cntrller='tool',
+ id=trans.security.encode_id( old_version.id ) ) )
if old_version.is_waiting():
- raise UploadError( 'There is an existing version of this tool which is waiting for administrative approval. Please contact an administrator for help.' )
+ raise UploadError( 'There is an existing version of this tool which is waiting for administrative approval, so contact an administrator for help.' )
# Defer setting the id since the newer version id doesn't exist until the new Tool object is flushed
if category_ids:
for category_id in category_ids:
@@ -91,12 +89,15 @@
trans.sa_session.add( tca )
# Initialize the tool event
event = trans.app.model.Event( state=trans.app.model.Tool.states.NEW )
+ # Flush to get an event id
+ trans.sa_session.add( event )
+ trans.sa_session.flush()
tea = trans.app.model.ToolEventAssociation( obj, event )
- trans.sa_session.add_all( ( event, tea ) )
- trans.sa_session.flush()
+ trans.sa_session.add( tea )
if replace_version and replace_id:
replace_version.newer_version_id = obj.id
- trans.sa_session.flush()
+ trans.sa_session.add( replace_version )
+ trans.sa_session.flush()
try:
os.link( uploaded_file.name, obj.file_name )
except OSError:
@@ -117,10 +118,10 @@
old_version = None
for old_version in get_versions( trans, replace_version ):
if old_version.is_new():
- message = 'There is an existing version of this tool which is unsubmitted. Please either submit or delete it before uploading a new version.'
+ message = 'There is an existing version of this tool which has not been submitted for approval, so either submit or delete it before uploading a new version.'
break
if old_version.is_waiting():
- message = 'There is an existing version of this tool which is waiting for administrative approval. Please contact an administrator for help.'
+ message = 'There is an existing version of this tool which is waiting for administrative approval, so contact an administrator for help.'
break
else:
old_version = None
diff -r 68fc85a43bb8 -r c7607fba91b9 lib/galaxy/webapps/community/model/__init__.py
--- a/lib/galaxy/webapps/community/model/__init__.py Tue May 04 14:19:44 2010 -0400
+++ b/lib/galaxy/webapps/community/model/__init__.py Tue May 04 14:21:21 2010 -0400
@@ -94,7 +94,8 @@
APPROVED = 'approved',
REJECTED = 'rejected',
ARCHIVED = 'archived' )
- def __init__( self, guid=None, tool_id=None, name=None, description=None, user_description=None, category=None, version=None, user_id=None, external_filename=None ):
+ def __init__( self, guid=None, tool_id=None, name=None, description=None, user_description=None,
+ category=None, version=None, user_id=None, external_filename=None ):
self.guid = guid
self.tool_id = tool_id
self.name = name or "Unnamed tool"
@@ -103,6 +104,7 @@
self.version = version or "1.0.0"
self.user_id = user_id
self.external_filename = external_filename
+ self.deleted = False
self.__extension = None
def get_file_name( self ):
if not self.external_filename:
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/dataset/display_application/display.mako
--- a/templates/dataset/display_application/display.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/dataset/display_application/display.mako Tue May 04 14:21:21 2010 -0400
@@ -1,8 +1,8 @@
<%inherit file="/base.mako"/>
<%namespace file="/message.mako" import="render_msg" />
<%def name="title()">Display Application: ${display_link.link.display_application.name} ${display_link.link.name}</%def>
-%for message, message_type in msg:
- ${render_msg( message, message_type )}
+%for message, status in msg:
+ ${render_msg( message, status )}
%endfor
%if refresh:
<%def name="metas()"><meta http-equiv="refresh" content="10" /></%def>
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/display_common.mako
--- a/templates/display_common.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/display_common.mako Tue May 04 14:21:21 2010 -0400
@@ -129,10 +129,10 @@
</%def>
## Render message.
-<%def name="render_message( message, message_type )">
+<%def name="render_message( message, status )">
%if message:
<p>
- <div class="${message_type}message transient-message">${util.restore_text( message )}</div>
+ <div class="${status}message transient-message">${util.restore_text( message )}</div>
<div style="clear: both"></div>
</p>
%endif
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/grid_base.mako
--- a/templates/grid_base.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/grid_base.mako Tue May 04 14:21:21 2010 -0400
@@ -508,12 +508,10 @@
webapp = href_parms[index].split('=')[1];
}
}
-
// Do operation.
do_operation(webapp, operation, id);
return false;
}
-
}
// Navigate window to the URL defined by url_args. This method should be used to short-circuit grid AJAXing.
@@ -678,7 +676,7 @@
<tr>
<td width="75%">${self.render_grid_header( grid )}</td>
<td></td>
- <td width="25%" id="grid-message" valign="top">${render_message( message, message_type )}</td>
+ <td width="25%" id="grid-message" valign="top">${render_message( message, status )}</td>
</tr>
</table>
@@ -774,10 +772,6 @@
## Render grid table body contents.
<%def name="render_grid_table_body_contents(grid, show_item_checkboxes=False)">
- ## Include the webapp value in the form
- <td style="width: 1.5em;">
- <input type="hidden" name="webapp" value="${webapp}" />
- </td>
<% num_rows_rendered = 0 %>
%if query.count() == 0:
## No results.
@@ -801,12 +795,8 @@
%for column in grid.columns:
%if column.visible:
<%
- # Get filter params for generating filter links
- filter_params = {}
- for k, v in cur_filter_dict.items():
- filter_params['f-' + k] = v
# Link
- link = column.get_link( trans, grid, item, filter_params )
+ link = column.get_link( trans, grid, item )
if link:
href = url( **link )
else:
@@ -831,6 +821,7 @@
cls = "menubutton"
if column.attach_popup and href:
cls = "menubutton split"
+
%>
%if href:
<td><div id="${id}" class="${cls}" style="float: left;"><a class="label" href="${href}">${v}</a></div></td>
@@ -915,3 +906,4 @@
</tr>
%endif
</%def>
+
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/grid_base_async.mako
--- a/templates/grid_base_async.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/grid_base_async.mako Tue May 04 14:21:21 2010 -0400
@@ -13,4 +13,4 @@
*****
${num_pages}
*****
-${render_message( message, message_type )}
\ No newline at end of file
+${render_message( message, status )}
\ No newline at end of file
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/message.mako
--- a/templates/message.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/message.mako Tue May 04 14:21:21 2010 -0400
@@ -66,21 +66,21 @@
##
<%def name="center_panel()">
- ${render_large_message( message, message_type )}
+ ${render_large_message( message, status )}
</%def>
<%def name="body()">
- ${render_large_message( message, message_type )}
+ ${render_large_message( message, status )}
</%def>
## Render large message.
-<%def name="render_large_message( message, message_type )">
- <div class="${message_type}messagelarge" style="margin: 1em">${_(message)}</div>
+<%def name="render_large_message( message, status )">
+ <div class="${status}messagelarge" style="margin: 1em">${_(message)}</div>
</%def>
## Render a message
-<%def name="render_msg( msg, messagetype='done' )">
- <div class="${messagetype}message">${_(msg)}</div>
+<%def name="render_msg( msg, status='done' )">
+ <div class="${status}message">${_(msg)}</div>
<br/>
</%def>
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/page/select_items_grid_async.mako
--- a/templates/page/select_items_grid_async.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/page/select_items_grid_async.mako Tue May 04 14:21:21 2010 -0400
@@ -6,4 +6,4 @@
*****
${num_pages}
*****
-${render_message( message, message_type )}
\ No newline at end of file
+${render_message( message, status )}
\ No newline at end of file
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/webapps/community/admin/center.mako
--- a/templates/webapps/community/admin/center.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/webapps/community/admin/center.mako Tue May 04 14:21:21 2010 -0400
@@ -6,7 +6,36 @@
<p>The menu on the left provides the following features</p>
<ul>
- <li><strong>Security</strong> - see the <strong>Data Security and Data Libraries</strong> section below for details
+ <li>
+ <strong>Tools</strong>
+ <p/>
+ <ul>
+ <li>
+ <strong>Tools awaiting approval</strong>
+ </li>
+ <p/>
+ <li>
+ <strong>Browse by category</strong>
+ </li>
+ <p/>
+ <li>
+ <strong>Browse all tools</strong>
+ </li>
+ <p/>
+ </ul>
+ </li>
+ <li>
+ <strong>Categories</strong>
+ <p/>
+ <ul>
+ <li>
+ <strong>Manage categories</strong>
+ </li>
+ <p/>
+ </ul>
+ </li>
+ <li>
+ <strong>Security</strong>
<p/>
<ul>
<li>
@@ -29,13 +58,5 @@
</ul>
</li>
<p/>
- <li><strong>Tools</strong>
- <p/>
- <ul>
- <li>
- <strong>Manage tools</strong> - coming soon...
- </li>
- </ul>
- </li>
</ul>
<br/>
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/webapps/community/tool/edit_tool.mako
--- a/templates/webapps/community/tool/edit_tool.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/webapps/community/tool/edit_tool.mako Tue May 04 14:21:21 2010 -0400
@@ -51,16 +51,21 @@
${render_msg( message, status )}
%endif
-%if cntrller == 'admin' or ( tool.is_new() and trans.user == tool.user ):
+%if cntrller == 'admin' or trans.user == tool.user:
<form id="edit_tool" name="edit_tool" action="${h.url_for( controller='common', action='edit_tool' )}" method="post">
<div class="toolForm">
<div class="toolFormTitle">${tool.name}
- <a id="tool-${tool.id}-popup" class="popup-arrow" style="display: none;">▼</a>
- <div popupmenu="tool-${tool.id}-popup">
- <a class="action-button" href="${h.url_for( controller='common', action='view_tool', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">View information</a>
- <a class="action-button" href="${h.url_for( controller='common', action='upload_new_tool_version', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Upload a new version</a>
- <a class="action-button" href="${h.url_for( controller='tool', action='download_tool', id=trans.app.security.encode_id( tool.id ) )}">Download tool</a>
- </div>
+ %if not tool.deleted:
+ <a id="tool-${tool.id}-popup" class="popup-arrow" style="display: none;">▼</a>
+ <div popupmenu="tool-${tool.id}-popup">
+ <a class="action-button" href="${h.url_for( controller='common', action='view_tool', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">View information</a>
+ <a class="action-button" href="${h.url_for( controller='tool', action='download_tool', id=trans.app.security.encode_id( tool.id ) )}">Download tool</a>
+ <a class="action-button" href="${h.url_for( controller='common', action='delete_tool', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Delete tool</a>
+ %if not tool.is_new() and not tool.is_waiting():
+ <a class="action-button" href="${h.url_for( controller='common', action='upload_new_tool_version', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Upload a new version</a>
+ %endif
+ </div>
+ %endif
</div>
<div class="toolFormBody">
<input type="hidden" name="id" value="${trans.app.security.encode_id( tool.id )}"/>
diff -r 68fc85a43bb8 -r c7607fba91b9 templates/webapps/community/tool/view_tool.mako
--- a/templates/webapps/community/tool/view_tool.mako Tue May 04 14:19:44 2010 -0400
+++ b/templates/webapps/community/tool/view_tool.mako Tue May 04 14:21:21 2010 -0400
@@ -85,16 +85,21 @@
<div class="toolForm">
<div class="toolFormTitle">${tool.name}
- <a id="tool-${tool.id}-popup" class="popup-arrow" style="display: none;">▼</a>
- <div popupmenu="tool-${tool.id}-popup">
- %if cntrller=='admin' or can_edit:
- <a class="action-button" href="${h.url_for( controller='common', action='edit_tool', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Edit information</a>
- %endif
- %if cntrller=='admin' or can_upload_new_version:
- <a class="action-button" href="${h.url_for( controller='common', action='upload_new_tool_version', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Upload a new version</a>
- %endif
- <a class="action-button" href="${h.url_for( controller='tool', action='download_tool', id=trans.app.security.encode_id( tool.id ) )}">Download tool</a>
- </div>
+ %if not tool.deleted:
+ <a id="tool-${tool.id}-popup" class="popup-arrow" style="display: none;">▼</a>
+ <div popupmenu="tool-${tool.id}-popup">
+ %if cntrller=='admin' or can_edit:
+ <a class="action-button" href="${h.url_for( controller='common', action='edit_tool', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Edit information</a>
+ %endif
+ <a class="action-button" href="${h.url_for( controller='tool', action='download_tool', id=trans.app.security.encode_id( tool.id ) )}">Download tool</a>
+ %if cntrller=='admin' or trans.user==tool.user:
+ <a class="action-button" href="${h.url_for( controller='common', action='delete_tool', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Delete tool</a>
+ %endif
+ %if cntrller=='admin' or can_upload_new_version:
+ <a class="action-button" href="${h.url_for( controller='common', action='upload_new_tool_version', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Upload a new version</a>
+ %endif
+ </div>
+ %endif
</div>
<div class="toolFormBody">
<div class="form-row">
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/9057a05dc7d3
changeset: 3739:9057a05dc7d3
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Tue May 04 13:45:57 2010 -0400
description:
Update types for cuffcompare output files.
diffstat:
tools/ngs_rna/cuffcompare_wrapper.xml | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diffs (31 lines):
diff -r a3f32c37d423 -r 9057a05dc7d3 tools/ngs_rna/cuffcompare_wrapper.xml
--- a/tools/ngs_rna/cuffcompare_wrapper.xml Tue May 04 12:50:48 2010 -0400
+++ b/tools/ngs_rna/cuffcompare_wrapper.xml Tue May 04 13:45:57 2010 -0400
@@ -50,21 +50,21 @@
</inputs>
<outputs>
- <data format="tmap" name="input1_tmap" label="${tool.name} on ${on_string}: data ${input1.hid} tmap file"/>
- <data format="refmap" name="input1_refmap" label="${tool.name} on ${on_string}: data ${input1.hid} refmap file"/>
- <data format="tmap" name="input2_tmap" label="${tool.name} on ${on_string}: data ${second_gtf.input2.hid} tmap file">
+ <data format="tabular" name="input1_tmap" label="${tool.name} on ${on_string}: data ${input1.hid} tmap file"/>
+ <data format="tabular" name="input1_refmap" label="${tool.name} on ${on_string}: data ${input1.hid} refmap file"/>
+ <data format="tabular" name="input2_tmap" label="${tool.name} on ${on_string}: data ${second_gtf.input2.hid} tmap file">
<filter>second_gtf['use_second_gtf'] == "Yes"</filter>
</data>
- <data format="refmap" name="input2_refmap" label="${tool.name} on ${on_string}: data ${second_gtf.input2.hid} refmap file">
+ <data format="tabular" name="input2_refmap" label="${tool.name} on ${on_string}: data ${second_gtf.input2.hid} refmap file">
<filter>second_gtf['use_second_gtf'] == "Yes"</filter>
</data>
<data format="gtf" name="transcripts_combined" label="${tool.name} on ${on_string}: combined transcripts">
<filter>second_gtf['use_second_gtf'] == "Yes"</filter>
</data>
- <data format="tracking" name="transcripts_tracking" label="${tool.name} on ${on_string}: transcript tracking">
+ <data format="tabular" name="transcripts_tracking" label="${tool.name} on ${on_string}: transcript tracking">
<filter>second_gtf['use_second_gtf'] == "Yes"</filter>
</data>
- <data format="gtf" name="transcripts_accuracy" label="${tool.name} on ${on_string}: transcript accuracy"/>
+ <data format="txt" name="transcripts_accuracy" label="${tool.name} on ${on_string}: transcript accuracy"/>
</outputs>
<tests>
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/a3f32c37d423
changeset: 3738:a3f32c37d423
user: Kanwei Li <kanwei(a)gmail.com>
date: Tue May 04 12:50:48 2010 -0400
description:
trackster: add filled line display
diffstat:
static/scripts/trackster.js | 48 ++++++++++++++++++++++++++++++---------------
1 files changed, 32 insertions(+), 16 deletions(-)
diffs (128 lines):
diff -r 3b81af3f51ab -r a3f32c37d423 static/scripts/trackster.js
--- a/static/scripts/trackster.js Tue May 04 10:18:42 2010 -0400
+++ b/static/scripts/trackster.js Tue May 04 12:50:48 2010 -0400
@@ -352,7 +352,6 @@
TiledTrack.call( this );
this.height_px = 100;
- this.container_div.addClass( "line-track" );
this.dataset_id = dataset_id;
this.data_cache = new Cache(CACHED_DATA);
this.tile_cache = new Cache(CACHED_TILES_LINE);
@@ -369,6 +368,8 @@
track.vertical_range = undefined;
this.init_each({ stats: true, chrom: track.view.chrom, low: null, high: null,
dataset_id: track.dataset_id }, function(result) {
+
+ track.container_div.addClass( "line-track" );
data = result.data;
if ( isNaN(parseFloat(track.prefs.min_value)) || isNaN(parseFloat(track.prefs.max_value)) ) {
track.prefs.min_value = data.min;
@@ -387,10 +388,10 @@
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.css({ position: "relative", top: "25px", left: "10px" });
max_label.prependTo(track.container_div);
- min_label.css({ position: "relative", top: track.height_px + 55 + "px" });
+ min_label.css({ position: "relative", top: track.height_px + 55 + "px", left: "10px" });
min_label.prependTo(track.container_div);
});
},
@@ -455,7 +456,8 @@
max_value = this.prefs.max_value,
vertical_range = this.vertical_range,
total_frequency = this.total_frequency,
- height_px = this.height_px;
+ height_px = this.height_px,
+ mode = this.prefs.mode;
ctx.beginPath();
@@ -466,16 +468,17 @@
var delta_x_px = 10;
}
+ var x_scaled, y;
+
for ( var i = 0; i < data.length; i++ ) {
- var x = data[i][0] - tile_low;
- var y = data[i][1];
+ x_scaled = (data[i][0] - tile_low) * w_scale;
+ y = data[i][1];
- if ( this.prefs.mode == "Intensity" ) {
+ if ( mode == "Intensity" ) {
// DRAW INTENSITY
if (y === null) {
continue;
}
- x = x * w_scale;
if (y <= min_value) {
y = min_value;
} else if (y >= max_value) {
@@ -483,16 +486,17 @@
}
y = 255 - Math.floor( (y - min_value) / vertical_range * 255 );
ctx.fillStyle = "rgb(" +y+ "," +y+ "," +y+ ")";
- ctx.fillRect(x, 0, delta_x_px, this.height_px);
+ ctx.fillRect(x_scaled, 0, delta_x_px, this.height_px);
}
else {
// Missing data causes us to stop drawing
if (y === null) {
+ if (in_path && mode === "Filled") {
+ ctx.lineTo(x_scaled, height_px);
+ }
in_path = false;
continue;
} else {
- // 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 <= min_value) {
y = min_value;
@@ -501,16 +505,28 @@
}
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 );
+ if (in_path) {
+ ctx.lineTo(x_scaled, y);
} else {
- ctx.moveTo( x, y );
in_path = true;
+ if (mode === "Filled") {
+ ctx.moveTo(x_scaled, height_px);
+ ctx.lineTo(x_scaled, y);
+ } else {
+ ctx.moveTo(x_scaled, y);
+ }
}
}
}
}
- ctx.stroke();
+ if (mode === "Filled") {
+ if (in_path) {
+ ctx.lineTo(x_scaled, height_px);
+ }
+ ctx.fill();
+ } else {
+ ctx.stroke();
+ }
parent_element.append( canvas );
return canvas;
}, gen_options: function(track_id) {
@@ -527,7 +543,7 @@
max_input = $('<input></input>').attr("id", maxval).val(max_val),
mode_label = $('<label></label>').attr("for", mode).text("Display mode:"),
mode_val = (this.prefs.mode === undefined ? "Line" : this.prefs.mode),
- mode_input = $('<select id="' +mode+ '"><option value="Line" id="mode_Line">Line</option><option value="Intensity" id="mode_Intensity">Intensity</option></select>');
+ mode_input = $('<select id="' +mode+ '"><option value="Line" id="mode_Line">Line</option><option value="Filled" id="mode_Filled">Filled</option><option value="Intensity" id="mode_Intensity">Intensity</option></select>');
mode_input.children("#mode_"+mode_val).attr('selected', 'selected');
1
0

10 May '10
details: http://www.bx.psu.edu/hg/galaxy/rev/3b81af3f51ab
changeset: 3737:3b81af3f51ab
user: Nate Coraor <nate(a)bx.psu.edu>
date: Tue May 04 10:18:42 2010 -0400
description:
Add a tip to the upload tool about using url paste for big files
diffstat:
tools/data_source/upload.xml | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diffs (12 lines):
diff -r eec050533545 -r 3b81af3f51ab tools/data_source/upload.xml
--- a/tools/data_source/upload.xml Mon May 03 17:35:54 2010 -0400
+++ b/tools/data_source/upload.xml Tue May 04 10:18:42 2010 -0400
@@ -25,7 +25,7 @@
</param>
<param name="async_datasets" type="hidden" value="None"/>
<upload_dataset name="files" title="Specify Files for Dataset" file_type_name="file_type" metadata_ref="files_metadata">
- <param name="file_data" type="file" size="30" label="File" ajax-upload="true">
+ <param name="file_data" type="file" size="30" label="File" ajax-upload="true" help="TIP: For NGS and other large files (>~2GB), uploading via HTTP/FTP URL (below) is the most reliable method.">
<validator type="expression" message="You will need to reselect the file you specified (%s)." substitute_value_in_message="True">not ( ( isinstance( value, unicode ) or isinstance( value, str ) ) and value != "" )</validator> <!-- use validator to post message to user about needing to reselect the file, since most browsers won't accept the value attribute for file inputs -->
</param>
<param name="url_paste" type="text" area="true" size="5x35" label="URL/Text" help="Here you may specify a list of URLs (one per line) or paste the contents of a file."/>
1
0

10 May '10
details: http://www.bx.psu.edu/hg/galaxy/rev/eec050533545
changeset: 3736:eec050533545
user: James Taylor <james(a)jamestaylor.org>
date: Mon May 03 17:35:54 2010 -0400
description:
Very basic support for exporting and importing workflows among instances
diffstat:
lib/galaxy/tools/__init__.py | 24 +++--
lib/galaxy/web/__init__.py | 2 +-
lib/galaxy/web/controllers/workflow.py | 153 ++++++++++++++++++++++++++++++++-
lib/galaxy/web/framework/__init__.py | 9 +
lib/galaxy/workflow/modules.py | 14 +-
templates/form.mako | 6 +-
6 files changed, 187 insertions(+), 21 deletions(-)
diffs (327 lines):
diff -r c75c0f9b0bf7 -r eec050533545 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py Mon May 03 16:32:35 2010 -0400
+++ b/lib/galaxy/tools/__init__.py Mon May 03 17:35:54 2010 -0400
@@ -203,7 +203,7 @@
def __init__( self ):
self.page = 0
self.inputs = None
- def encode( self, tool, app ):
+ def encode( self, tool, app, secure=True ):
"""
Convert the data to a string
"""
@@ -213,18 +213,22 @@
value["__page__"] = self.page
value = simplejson.dumps( value )
# Make it secure
- a = hmac_new( app.config.tool_secret, value )
- b = binascii.hexlify( value )
- return "%s:%s" % ( a, b )
- def decode( self, value, tool, app ):
+ if secure:
+ a = hmac_new( app.config.tool_secret, value )
+ b = binascii.hexlify( value )
+ return "%s:%s" % ( a, b )
+ else:
+ return value
+ def decode( self, value, tool, app, secure=True ):
"""
Restore the state from a string
"""
- # Extract and verify hash
- a, b = value.split( ":" )
- value = binascii.unhexlify( b )
- test = hmac_new( app.config.tool_secret, value )
- assert a == test
+ if secure:
+ # Extract and verify hash
+ a, b = value.split( ":" )
+ value = binascii.unhexlify( b )
+ test = hmac_new( app.config.tool_secret, value )
+ assert a == test
# Restore from string
values = json_fix( simplejson.loads( value ) )
self.page = values.pop( "__page__" )
diff -r c75c0f9b0bf7 -r eec050533545 lib/galaxy/web/__init__.py
--- a/lib/galaxy/web/__init__.py Mon May 03 16:32:35 2010 -0400
+++ b/lib/galaxy/web/__init__.py Mon May 03 17:35:54 2010 -0400
@@ -2,6 +2,6 @@
The Galaxy web application.
"""
-from framework import expose, json, require_login, require_admin, url_for, error, form, FormBuilder
+from framework import expose, json, json_pretty, require_login, require_admin, url_for, error, form, FormBuilder
from framework.base import httpexceptions
diff -r c75c0f9b0bf7 -r eec050533545 lib/galaxy/web/controllers/workflow.py
--- a/lib/galaxy/web/controllers/workflow.py Mon May 03 16:32:35 2010 -0400
+++ b/lib/galaxy/web/controllers/workflow.py Mon May 03 17:35:54 2010 -0400
@@ -18,6 +18,8 @@
from galaxy.model.mapping import desc
from galaxy.model.orm import *
+import urllib2
+
class StoredWorkflowListGrid( grids.Grid ):
class StepsColumn( grids.GridColumn ):
def get_value(self, trans, grid, workflow):
@@ -621,7 +623,6 @@
step_dict['position'] = step.position
# Add to return value
data['steps'][step.order_index] = step_dict
- print data['upgrade_messages']
return data
@web.json
@@ -660,7 +661,6 @@
workflow.has_errors = True
# Stick this in the step temporarily
step.temp_input_connections = step_dict['input_connections']
-
# Save step annotation.
annotation = step_dict[ 'annotation' ]
if annotation:
@@ -698,6 +698,155 @@
rval['name'] = workflow.name
return rval
+ @web.json_pretty
+ def export_workflow( self, trans, id ):
+ """
+ Get the latest Workflow for the StoredWorkflow identified by `id` and
+ encode it as a json string that can be imported back into Galaxy
+
+ This has slightly different information than the above. In particular,
+ it does not attempt to decode forms and build UIs, it just stores
+ the raw state.
+ """
+ user = trans.get_user()
+ id = trans.security.decode_id( id )
+ trans.workflow_building_mode = True
+ # Load encoded workflow from database
+ stored = trans.sa_session.query( model.StoredWorkflow ).get( id )
+ self.security_check( trans.get_user(), stored, False, True )
+ workflow = stored.latest_workflow
+ # Pack workflow data into a dictionary and return
+ data = {}
+ data['name'] = workflow.name
+ data['steps'] = {}
+ # For each step, rebuild the form and encode the state
+ for step in workflow.steps:
+ # Load from database representation
+ module = module_factory.from_workflow_step( trans, step )
+ # Get user annotation.
+ step_annotation = self.get_item_annotation_obj( trans, trans.user, step )
+ annotation_str = ""
+ if step_annotation:
+ annotation_str = step_annotation.annotation
+ # Pack attributes into plain dictionary
+ step_dict = {
+ 'id': step.order_index,
+ 'type': module.type,
+ 'tool_id': module.get_tool_id(),
+ 'name': module.get_name(),
+ 'tool_state': module.get_state( secure=False ),
+ 'tool_errors': module.get_errors(),
+ ## 'data_inputs': module.get_data_inputs(),
+ ## 'data_outputs': module.get_data_outputs(),
+ 'annotation' : annotation_str
+ }
+ # Connections
+ input_connections = step.input_connections
+ if step.type is None or step.type == 'tool':
+ # Determine full (prefixed) names of valid input datasets
+ data_input_names = {}
+ def callback( input, value, prefixed_name, prefixed_label ):
+ if isinstance( input, DataToolParameter ):
+ data_input_names[ prefixed_name ] = True
+ visit_input_values( module.tool.inputs, module.state.inputs, callback )
+ # Filter
+ # FIXME: this removes connection without displaying a message currently!
+ input_connections = [ conn for conn in input_connections if conn.input_name in data_input_names ]
+ # Encode input connections as dictionary
+ input_conn_dict = {}
+ for conn in input_connections:
+ input_conn_dict[ conn.input_name ] = \
+ dict( id=conn.output_step.order_index, output_name=conn.output_name )
+ step_dict['input_connections'] = input_conn_dict
+ # Position
+ step_dict['position'] = step.position
+ # Add to return value
+ data['steps'][step.order_index] = step_dict
+ return data
+
+ @web.expose
+ def import_workflow( self, trans, workflow_text=None, url=None ):
+ if workflow_text is None and url is None:
+ return form( url_for(), "Import Workflow", submit_text="Import" ) \
+ .add_text( "url", "URL to load workflow from", "" ) \
+ .add_input( "textarea", "Encoded workflow (as generated by export workflow)", "workflow_text", "" )
+ if url:
+ # Load workflow from external URL
+ # NOTE: blocks the web thread.
+ try:
+ workflow_data = urllib2.urlopen( url ).read()
+ except Exception, e:
+ return trans.show_error_message( "Failed to open URL %s<br><br>Message: %s" % ( url, str( e ) ) )
+ else:
+ workflow_data = workflow_text
+ # Convert incoming workflow data from json
+ try:
+ data = simplejson.loads( workflow_data )
+ except Exception, e:
+ return trans.show_error_message( "Data at '%s' does not appear to be a Galaxy workflow<br><br>Message: %s" % ( url, str( e ) ) )
+ # Put parameters in workflow mode
+ trans.workflow_building_mode = True
+ # Create new workflow from incoming data
+ workflow = model.Workflow()
+ # Just keep the last name (user can rename later)
+ workflow.name = data['name']
+ # Assume no errors until we find a step that has some
+ workflow.has_errors = False
+ # Create each step
+ steps = []
+ # The editor will provide ids for each step that we don't need to save,
+ # but do need to use to make connections
+ steps_by_external_id = {}
+ # First pass to build step objects and populate basic values
+ for key, step_dict in data['steps'].iteritems():
+ # Create the model class for the step
+ step = model.WorkflowStep()
+ steps.append( step )
+ steps_by_external_id[ step_dict['id' ] ] = step
+ # FIXME: Position should be handled inside module
+ step.position = step_dict['position']
+ module = module_factory.from_dict( trans, step_dict, secure=False )
+ module.save_to_step( step )
+ if step.tool_errors:
+ workflow.has_errors = True
+ # Stick this in the step temporarily
+ step.temp_input_connections = step_dict['input_connections']
+ # Save step annotation.
+ annotation = step_dict[ 'annotation' ]
+ if annotation:
+ annotation = sanitize_html( annotation, 'utf-8', 'text/html' )
+ self.add_item_annotation( trans, step, annotation )
+ # Second pass to deal with connections between steps
+ for step in steps:
+ # Input connections
+ for input_name, conn_dict in step.temp_input_connections.iteritems():
+ if conn_dict:
+ conn = model.WorkflowStepConnection()
+ conn.input_step = step
+ conn.input_name = input_name
+ conn.output_name = conn_dict['output_name']
+ conn.output_step = steps_by_external_id[ conn_dict['id'] ]
+ del step.temp_input_connections
+ # Order the steps if possible
+ attach_ordered_steps( workflow, steps )
+ # Connect up
+ stored = model.StoredWorkflow()
+ stored.name = workflow.name
+ workflow.stored_workflow = stored
+ stored.latest_workflow = workflow
+ stored.user = trans.user
+ # Persist
+ trans.sa_session.add( stored )
+ trans.sa_session.flush()
+ # Return something informative
+ errors = []
+ if workflow.has_errors:
+ return trans.show_warn_message( "Imported, but some steps in this workflow have validation errors" )
+ if workflow.has_cycles:
+ return trans.show_warn_message( "Imported, but this workflow contains cycles" )
+ else:
+ return trans.show_message( "Workflow '%s' imported" % workflow.name )
+
@web.json
def get_datatypes( self, trans ):
ext_to_class_name = dict()
diff -r c75c0f9b0bf7 -r eec050533545 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py Mon May 03 16:32:35 2010 -0400
+++ b/lib/galaxy/web/framework/__init__.py Mon May 03 17:35:54 2010 -0400
@@ -66,6 +66,15 @@
decorator.exposed = True
return decorator
+def json_pretty( func ):
+ def decorator( self, trans, *args, **kwargs ):
+ trans.response.set_content_type( "text/javascript" )
+ return simplejson.dumps( func( self, trans, *args, **kwargs ), indent=4, sort_keys=True )
+ if not hasattr(func, '_orig'):
+ decorator._orig = func
+ decorator.exposed = True
+ return decorator
+
def require_login( verb="perform this action", use_panels=False, webapp='galaxy' ):
def argcatcher( func ):
def decorator( self, trans, *args, **kwargs ):
diff -r c75c0f9b0bf7 -r eec050533545 lib/galaxy/workflow/modules.py
--- a/lib/galaxy/workflow/modules.py Mon May 03 16:32:35 2010 -0400
+++ b/lib/galaxy/workflow/modules.py Mon May 03 17:35:54 2010 -0400
@@ -96,7 +96,7 @@
module.state = dict( name="Input Dataset" )
return module
@classmethod
- def from_dict( Class, trans, d ):
+ def from_dict( Class, trans, d, secure=False ):
module = Class( trans )
state = from_json_string( d["tool_state"] )
module.state = dict( name=state.get( "name", "Input Dataset" ) )
@@ -172,11 +172,11 @@
module.state = module.tool.new_state( trans, all_pages=True )
return module
@classmethod
- def from_dict( Class, trans, d ):
+ def from_dict( Class, trans, d, secure=False ):
tool_id = d['tool_id']
module = Class( trans, tool_id )
module.state = DefaultToolState()
- module.state.decode( d["tool_state"], module.tool, module.trans.app )
+ module.state.decode( d["tool_state"], module.tool, module.trans.app, secure=False )
module.errors = d.get( "tool_errors", None )
return module
@@ -199,8 +199,8 @@
return self.tool.name
def get_tool_id( self ):
return self.tool_id
- def get_state( self ):
- return self.state.encode( self.tool, self.trans.app )
+ def get_state( self, secure=True ):
+ return self.state.encode( self.tool, self.trans.app, secure=secure )
def get_errors( self ):
return self.errors
def get_tooltip( self ):
@@ -278,13 +278,13 @@
"""
assert type in self.module_types
return self.module_types[type].new( trans, tool_id )
- def from_dict( self, trans, d ):
+ def from_dict( self, trans, d, **kwargs ):
"""
Return module initialized from the data in dictionary `d`.
"""
type = d['type']
assert type in self.module_types
- return self.module_types[type].from_dict( trans, d )
+ return self.module_types[type].from_dict( trans, d, **kwargs )
def from_workflow_step( self, trans, step ):
"""
Return module initializd from the WorkflowStep object `step`.
diff -r c75c0f9b0bf7 -r eec050533545 templates/form.mako
--- a/templates/form.mako Mon May 03 16:32:35 2010 -0400
+++ b/templates/form.mako Mon May 03 17:35:54 2010 -0400
@@ -60,7 +60,11 @@
</label>
%endif
<div class="form-row-input">
- <input type="${input.type}" name="${input.name}" value="${input.value}" size="40">
+ %if input.type == 'textarea':
+ <textarea name="${input.name}" cols="40">${input.value}</textarea>
+ %else:
+ <input type="${input.type}" name="${input.name}" value="${input.value}" size="40">
+ %endif
</div>
%if input.error:
<div class="form-row-error-message">${input.error}</div>
1
0

10 May '10
details: http://www.bx.psu.edu/hg/galaxy/rev/c75c0f9b0bf7
changeset: 3735:c75c0f9b0bf7
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Mon May 03 16:32:35 2010 -0400
description:
Enable users not logged in to view a shared/accessible/published visualization.
diffstat:
lib/galaxy/web/base/controller.py | 3 ++-
lib/galaxy/web/controllers/tracks.py | 21 ++++++++++++++-------
lib/galaxy/web/framework/__init__.py | 5 +++++
templates/tracks/browser.mako | 2 +-
templates/visualization/display.mako | 2 +-
5 files changed, 23 insertions(+), 10 deletions(-)
diffs (105 lines):
diff -r 5ebac527fa31 -r c75c0f9b0bf7 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py Mon May 03 15:33:34 2010 -0400
+++ b/lib/galaxy/web/base/controller.py Mon May 03 16:32:35 2010 -0400
@@ -208,7 +208,8 @@
if dbkey is None: dbkey = dataset.dbkey # Hack for backward compat
## TODO: chrom needs to be able to be set; right now it's empty.
- config = { "title": visualization.title, "vis_id": id, "tracks": tracks, "chrom": "", "dbkey": dbkey }
+ config = { "title": visualization.title, "vis_id": trans.security.encode_id( visualization.id ),
+ "tracks": tracks, "chrom": "", "dbkey": dbkey }
return config
diff -r 5ebac527fa31 -r c75c0f9b0bf7 lib/galaxy/web/controllers/tracks.py
--- a/lib/galaxy/web/controllers/tracks.py Mon May 03 15:33:34 2010 -0400
+++ b/lib/galaxy/web/controllers/tracks.py Mon May 03 16:32:35 2010 -0400
@@ -72,7 +72,7 @@
.filter( model.HistoryDatasetAssociation.extension.in_(self.available_tracks) ) \
.filter( model.Dataset.state != "error")
-class TracksController( BaseController ):
+class TracksController( BaseController, UsesVisualization ):
"""
Controller for track browser interface. Handles building a new browser from
datasets in the current history, and display of the resulting browser.
@@ -158,8 +158,7 @@
return trans.fill_template( 'tracks/browser.mako', config=config )
@web.json
- @web.require_login()
- def chroms(self, trans, dbkey=None ):
+ def chroms(self, trans, vis_id=None ):
"""
Returns a naturally sorted list of chroms/contigs for the given dbkey
"""
@@ -171,18 +170,26 @@
def split_by_number(s):
return [ check_int(c) for c in re.split('([0-9]+)', s) ]
-
- chroms = self._chroms( trans, dbkey )
+
+ # Get visualization and config.
+ visualization = self.get_visualization( trans, vis_id, check_ownership=False, check_accessible=True )
+ visualization.config = self.get_visualization_config( trans, visualization )
+ if visualization is None:
+ raise web.httpexceptions.HTTPNotFound()
+
+ # Get chroms data.
+ chroms = self._chroms( trans, visualization )
to_sort = [{ 'chrom': chrom, 'len': length } for chrom, length in chroms.iteritems()]
to_sort.sort(lambda a,b: cmp( split_by_number(a['chrom']), split_by_number(b['chrom']) ))
return to_sort
- def _chroms( self, trans, dbkey ):
+ def _chroms( self, trans, visualization ):
"""
Called by the browser to get a list of valid chromosomes and lengths
"""
# If there is any dataset in the history of extension `len`, this will use it
- user = trans.get_user()
+ user = visualization.user
+ dbkey = visualization.config['dbkey']
if 'dbkeys' in user.preferences:
user_keys = from_json_string( user.preferences['dbkeys'] )
if dbkey in user_keys:
diff -r 5ebac527fa31 -r c75c0f9b0bf7 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py Mon May 03 15:33:34 2010 -0400
+++ b/lib/galaxy/web/framework/__init__.py Mon May 03 16:32:35 2010 -0400
@@ -675,6 +675,11 @@
"""
Returns the db_file dataset associated/needed by `dataset`, or `None`.
"""
+
+ # If no history, return None.
+ if self.history is None:
+ return None
+
datasets = self.sa_session.query( self.app.model.HistoryDatasetAssociation ) \
.filter_by( deleted=False, history_id=self.history.id, extension="len" )
for ds in datasets:
diff -r 5ebac527fa31 -r c75c0f9b0bf7 templates/tracks/browser.mako
--- a/templates/tracks/browser.mako Mon May 03 15:33:34 2010 -0400
+++ b/templates/tracks/browser.mako Mon May 03 16:32:35 2010 -0400
@@ -272,7 +272,7 @@
$.ajax({
url: "${h.url_for( action='chroms' )}",
- data: { dbkey: view.dbkey },
+ data: { vis_id: view.vis_id },
dataType: "json",
success: function ( data ) {
view.chrom_data = data;
diff -r 5ebac527fa31 -r c75c0f9b0bf7 templates/visualization/display.mako
--- a/templates/visualization/display.mako Mon May 03 15:33:34 2010 -0400
+++ b/templates/visualization/display.mako Mon May 03 16:32:35 2010 -0400
@@ -124,7 +124,7 @@
$.ajax({
## JG: added controller name
url: "${h.url_for( controller='/tracks', action='chroms' )}",
- data: { dbkey: view.dbkey },
+ data: { vis_id: view.vis_id },
dataType: "json",
success: function ( data ) {
view.chrom_data = data;
1
0

10 May '10
details: http://www.bx.psu.edu/hg/galaxy/rev/5ebac527fa31
changeset: 3734:5ebac527fa31
user: Nate Coraor <nate(a)bx.psu.edu>
date: Mon May 03 15:33:34 2010 -0400
description:
Community: add help for tool-related operations
diffstat:
lib/galaxy/webapps/community/controllers/tool.py | 6 +
lib/galaxy/webapps/community/security/__init__.py | 2 +-
templates/webapps/community/base_panels.mako | 1 +
templates/webapps/community/tool/help.mako | 125 ++++++++++++++++++++++
templates/webapps/community/tool/view_tool.mako | 8 +-
templates/webapps/community/upload/upload.mako | 8 +-
6 files changed, 139 insertions(+), 11 deletions(-)
diffs (205 lines):
diff -r 8bdbd5fc8721 -r 5ebac527fa31 lib/galaxy/webapps/community/controllers/tool.py
--- a/lib/galaxy/webapps/community/controllers/tool.py Mon May 03 14:03:01 2010 -0400
+++ b/lib/galaxy/webapps/community/controllers/tool.py Mon May 03 15:33:34 2010 -0400
@@ -402,3 +402,9 @@
tool_file = tarfile.open( tool.file_name ).extractfile( tool_file_name )
trans.response.set_content_type( 'text/plain' )
return tool_file
+ @web.expose
+ def help( self, trans, **kwd ):
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ return trans.fill_template( '/webapps/community/tool/help.mako', message=message, status=status, **kwd )
diff -r 8bdbd5fc8721 -r 5ebac527fa31 lib/galaxy/webapps/community/security/__init__.py
--- a/lib/galaxy/webapps/community/security/__init__.py Mon May 03 14:03:01 2010 -0400
+++ b/lib/galaxy/webapps/community/security/__init__.py Mon May 03 15:33:34 2010 -0400
@@ -170,7 +170,7 @@
def can_upload_new_version( self, user, item, versions ):
state_ok = True
for version in versions:
- if version.is_new() or version.is_approved():
+ if version.is_new() or version.is_waiting():
state_ok = False
return user and user==item.user and state_ok
diff -r 8bdbd5fc8721 -r 5ebac527fa31 templates/webapps/community/base_panels.mako
--- a/templates/webapps/community/base_panels.mako Mon May 03 14:03:01 2010 -0400
+++ b/templates/webapps/community/base_panels.mako Mon May 03 15:33:34 2010 -0400
@@ -33,6 +33,7 @@
<a>Help</a>
<div class="submenu">
<ul>
+ <li><a target="galaxy_main" href="${h.url_for( controller='tool', action='help' )}">How to upload, download and install tools</a></li>
<li><a href="${app.config.get( "bugs_email", "mailto:galaxy-bugs@bx.psu.edu" )}">Email comments, bug reports, or suggestions</a></li>
<li><a target="_blank" href="${app.config.get( "wiki_url", "http://bitbucket.org/galaxy/galaxy-central/wiki" )}">Galaxy Wiki</a></li>
<li><a target="_blank" href="${app.config.get( "screencasts_url", "http://galaxycast.org" )}">Video tutorials (screencasts)</a></li>
diff -r 8bdbd5fc8721 -r 5ebac527fa31 templates/webapps/community/tool/help.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/webapps/community/tool/help.mako Mon May 03 15:33:34 2010 -0400
@@ -0,0 +1,125 @@
+<%namespace file="/message.mako" import="render_msg" />
+
+<%!
+ def inherit(context):
+ if context.get('use_panels'):
+ return '/webapps/community/base_panels.mako'
+ else:
+ return '/base.mako'
+%>
+<%inherit file="${inherit(context)}"/>
+
+<%def name="title()">Tool Help</%def>
+
+<h2>Tool Help</h2>
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<h3>Uploading Tools</h3>
+
+<p><strong>Tool File Format</strong></p>
+<p>
+
+ A tool file is a tar-format (bzipped or gzipped tar are valid) archive
+ containing all the files necessary to load the tool in Galaxy. At the very
+ least, it must contain a
+ <a href="http://bitbucket.org/galaxy/galaxy-central/wiki/ToolConfigSyntax" target="_blank">Tool XML File</a>,
+ and will probably also include a tool script. If any steps are necessary
+ to install your tool beyond the basic instructions below, please include a
+ README file which details these steps. If the tool (or parts of it) are
+ written in C, the source code can be included (or put links to the source
+ in the README). Please do not include precompiled binaries without source,
+ since Galaxy is run on a wide variety of platforms. Also, if you are only
+ wrapping or providing a Galaxy config for a tool that is not your own,
+ please be sure the license allows for redistribution before including any
+ part of that tool in the tar archive!
+</p>
+<p>
+ There are no requirements about the directory structure inside the tar
+ archive, but for ease of use, it's generally a good idea to put everything
+ inside of a subdirectory, instead of directly at the top level.
+</p>
+
+<p><strong>Tool File Example</strong></p>
+<p>
+ To package up the LASTZ tool's config file, Galaxy wrapper, and the C source:
+ <pre>
+ user@host:~% tar jcvf ~/Desktop/galaxy_lastz_tool.tar.bz2 lastz
+ lastz/
+ lastz/README
+ lastz/lastz_wrapper.py
+ lastz/lastz_wrapper.xml
+ lastz/lastz-distrib-1.02.00/
+ lastz/lastz-distrib-1.02.00/src/
+ lastz/lastz-distrib-1.02.00/src/Makefile
+ lastz/lastz-distrib-1.02.00/src/version.mak
+ lastz/lastz-distrib-1.02.00/src/lastz.c
+ lastz/lastz-distrib-1.02.00/src/lastz.h
+ ...
+ </pre>
+ <code>~/Desktop/galaxy_lastz_tool.tar.bz2</code> is now ready to be uploaded.
+</p>
+
+<p><strong>Editing Information, Categories, and Submitting For Approval</strong></p>
+
+<p>
+ Simply uploading a tool to the Community will not allow other users to find
+ and download your tool. It will need to be approved by an administrator
+ before it appears in the tool list.
+</p>
+<p>
+ After the tool has successfully uploaded, you will be redirected to the
+ Edit Tool page. Please provide a detailed description of what the tool
+ does - this will be used by administrators to understand the tool before
+ approving it for display on the site. Once approved, this information will
+ be displayed to users who view your tool. In addition, the site
+ administrators will have configured a number of categories with which you
+ can associate your tool to make it easily findable by users looking to
+ solve specific problems. Please associate as many categories as are
+ relevant to your tool. You may change the description and associated
+ categories as often as you'd like until you click the "<strong>Submit for
+ approval</strong>" button. Once submitted, the tool will be approved or
+ rejected by an administrator. Once approved, it will be visible to
+ everyone. At that point, the description and associated categories can
+ only be changed by an administrator.
+</p>
+<p>
+ Once the tool has been approved or rejected, you may upload a new version
+ by browsing to the tool's "View Tool" page, clicking the context menu to
+ the right of the tool's name, and selecting "Upload a new version."
+</p>
+
+<hr/>
+
+<h3>Downloading and Installing Tools</h3>
+
+<p>
+ A tool's download link will send you the tool tar archive. Once
+ downloaded, unpack the tool on your local Galaxy instance's server:
+ <pre>
+ user@host:~% tar xvf galaxy_tool.tar
+ ...
+ user@host:~% tar zxvf galaxy_tool.tar.gz
+ ...
+ user@host:~% tar jxvf galaxy_tool.tar.bz2
+ ...
+ </pre>
+ If the tar archive includes a README file, consult it for installation
+ instructions. If not, follow these basic steps:
+ <ol>
+ <li>Create a directory under <code>galaxy_dist/tools/</code> to house downloaded tool(s).</li>
+ <li>In the new directory, place the XML and any script file(s) which were contained in the tar archive.</li>
+ <li>If the tool includes binaries, you'll need to copy them to a directory on your <code>$PATH</code>. If the tool depends on C binaries but does not come with them (only source), you'll need to compile the source first.</li>
+ <li>Add the tool to <code>galaxy_dist/tool_conf.xml</code>.</li>
+ <li>Restart the Galaxy server process.</li>
+ </ol>
+</p>
+
+<p>
+ We plan to implement a more direct method to install tools via the Galaxy
+ administrator user interface instead of placing files on the filesystem and
+ managing the <code>tool_conf.xml</code> file by hand. In the meantime,
+ this is the process.
+</p>
diff -r 8bdbd5fc8721 -r 5ebac527fa31 templates/webapps/community/tool/view_tool.mako
--- a/templates/webapps/community/tool/view_tool.mako Mon May 03 14:03:01 2010 -0400
+++ b/templates/webapps/community/tool/view_tool.mako Mon May 03 15:33:34 2010 -0400
@@ -125,9 +125,11 @@
<div class="form-row">
<label>Categories:</label>
%if categories:
- %for category in categories:
- ${category.name}
- %endfor
+ <ul>
+ %for category in categories:
+ <li>${category.name}</li>
+ %endfor
+ </ul>
%else:
none set
%endif
diff -r 8bdbd5fc8721 -r 5ebac527fa31 templates/webapps/community/upload/upload.mako
--- a/templates/webapps/community/upload/upload.mako Mon May 03 14:03:01 2010 -0400
+++ b/templates/webapps/community/upload/upload.mako Mon May 03 15:33:34 2010 -0400
@@ -39,7 +39,7 @@
</select>
</div>
<div class="toolParamHelp" style="clear: both;">
- Need help creating a tool file? See help below.
+ Need help creating a tool file? See the <a href="${h.url_for( controller='tool', action='help' )}">Tool Help</a> page.
</div>
<div style="clear: both"></div>
</div>
@@ -77,9 +77,3 @@
</form>
</div>
</div>
-<div class="toolHelp">
- <div class="toolHelpBody">
- <p><strong>Creating tool files</strong></p>
- <p>Help coming...</p>
- </div>
-</div>
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/8bdbd5fc8721
changeset: 3733:8bdbd5fc8721
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Mon May 03 14:03:01 2010 -0400
description:
Pack scripts.
diffstat:
static/scripts/packed/trackster.js | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diffs (8 lines):
diff -r 2cf1ad5edaa6 -r 8bdbd5fc8721 static/scripts/packed/trackster.js
--- a/static/scripts/packed/trackster.js Mon May 03 14:02:08 2010 -0400
+++ b/static/scripts/packed/trackster.js Mon May 03 14:03:01 2010 -0400
@@ -1,1 +1,1 @@
-var DEBUG=false;var DENSITY=200,FEATURE_LEVELS=10,DATA_ERROR="There was an error in indexing this dataset.",DATA_NOCONVERTER="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",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=5,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.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 Drawer=function(){};$.extend(Drawer.prototype,{intensity:function(b,a,c){},});drawer=new Drawer();var View=function(b,d,c,a){this.vis_id=c;this.dbkey=a;this.title=d;this.chrom=b;this.tracks=[];this.label_tracks=[];this.max_low=0;this.max_hi!
gh=0;this.center=(this.max_high-this.max_low)/2;this.zoom_factor=3;thi
s.zoom_level=0;this.track_id_counter=0};$.extend(View.prototype,{add_track:function(a){a.view=this;a.track_id=this.track_id_counter;this.tracks.push(a);if(a.init){a.init()}a.container_div.attr("id","track_"+a.track_id);this.track_id_counter+=1},add_label_track:function(a){a.view=this;this.label_tracks.push(a)},remove_track:function(a){a.container_div.fadeOut("slow",function(){$(this).remove()});delete this.tracks[a]},update_options:function(){var b=$("ul#sortable-ul").sortable("toArray");var d=[];var c=$("#viewport > div").sort(function(g,f){return b.indexOf($(g).attr("id"))>b.indexOf($(f).attr("id"))});$("#viewport > div").remove();$("#viewport").html(c);for(var e in view.tracks){var a=view.tracks[e];if(a.update_options){a.update_options(e)}}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.center=this.center=(this.max_high-this.max_low)/2;this.zoom_level=0;$(".yaxislabel").remove()},redraw:function(f){this.span=this.max_high-this.max_low;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)/200)/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));if(!f){for(var c=0,a=this.tracks.length;c<a;c++){if(this.tracks[c].enabled){this.tracks[c].draw()}}for(var c=0,a=this.label_tracks.length;c<a;c++){this.label_tracks[c].draw()}}},zoom_in:function(a,b){if(this.max_high===0||this.high-this.low<30){return}if(a){this.center=a/b.width()*(this.hi!
gh-this.low)+this.low}this.zoom_level+=1;this.redraw()},zoom_out:funct
ion(){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.init_global()};$.extend(Track.prototype,{init_global:function(){this.header_div=$("<div class='track-header'>").text(this.name);this.content_div=$("<div class='track-content'>");this.container_div=$("<div></div>").addClass("track").append(this.header_div).append(this.content_div);this.parent_element.append(this.container_div)},init_each:function(c,b){var a=this;a.enabled=false;a.data_queue={};a.tile_cache.clear();a.data_cache.clear();a.content_div.css("height","30px");if(!a.content_div.text()){a.content_div.text(DATA_LOADING)}a.container_div.removeClass("nodata error pending");if(a.view.chrom){$.getJSON(data_url,c,function(d){if(!d||d==="error"){a.container_div.addClass("error");a.content_div.text(DATA_ERROR)}else{if(d==="no converter"){a.container_div.addClass("error");a.content_div.text(DATA_NO!
CONVERTER)}else{if(d.data&&d.data.length===0||d.data===null){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");a.enabled=true;b(d);a.draw()}}}}})}else{a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}}});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>"),l=this.content_div.width()/f,h;this.content_div.children(":first").remove();this.content_div.append(k),this.max_height=0;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());this.content_div.css("height",this.max_height+"px")}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+"px")}}},50)}});var LabelTrack=function(a){Track.call(this,null,a);this.track_type="LabelTrack";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.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,a,b){this.track_type="LineTrack";Track.call(this,c,$("#viewport"));TiledTrack.call(this);this.height_px=100;this.container_div.addClass("line-track");this.dataset_id=a;this.data_cache=new Cache(CACHED_DATA);this.tile_cache=new Cache(CACHED_TILES_LINE);this.prefs={min_value:undefined,max_value:undefined,mode:"Line"};if(b.min_value!==undefined){this.prefs.min_value=b.min_value}if(b.max_value!==undefined){this.prefs.max_value=b.max_value}if(b.mode!==undefined){this.prefs.mode=b.mode}};$.extend(LineTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b=a.view.tracks.indexOf(a);a.vertical_range=undefined;this.init_each({stats:true,chrom:a.view.chrom,low:null,high:null,dataset_id:a.dataset_id},function(c){data=c.data;if(isNaN(parseFloat(a.prefs.min_value))||isNaN(parseFloat(a.prefs.max_value))){a.prefs.min_value=data.min;a.prefs.max_value=data.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;a.total_frequency=data.total_frequency;$("#linetrack_"+b+"_minval").remove();$("#linetrack_"+b+"_maxval").remove();var e=$("<div></div>").addClass("yaxislabel").attr("id","linetrack_"+b+"_minval").text(a.prefs.min_value);var d=$("<div></div>").addClass("yaxislabel").attr("id","linetrack_"+b+"_maxval").text(a.prefs.max_value);d.css({position:"relative",top:"25px"});d.prependTo(a.container_div);e.css({position:"relative",top:a.height_px+55+"px"});e.prependTo(a.container_div)})},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;$.ajax({url:data_url,dataType:"json",data:{chrom:this.view.chrom,low:a,high:f,dataset_id:this.dataset_id,resolution:this.view.resolution},success:function(g){data=g.data;c.data_cache.set(e,data);delete c.data_queue[e];c.draw()},error:function(h,g,i){console.log(h,g,i)}})}},draw_tile:function(o,q,c,e){if(this.vert!
ical_range===undefined){return}var r=q*DENSITY*o,a=DENSITY*o,b=$("<canvas class='tile'></canvas>"),u=o+"_"+q;if(this.data_cache.get(u)===undefined){this.get_data(o,q);return}var t=this.data_cache.get(u);if(t===null){return}b.css({position:"absolute",top:0,left:(r-this.view.low)*e});b.get(0).width=Math.ceil(a*e);b.get(0).height=this.height_px;var n=b.get(0).getContext("2d"),k=false,l=this.prefs.min_value,g=this.prefs.max_value,m=this.vertical_range,s=this.total_frequency,d=this.height_px;n.beginPath();if(t.length>1){var f=Math.ceil((t[1][0]-t[0][0])*e)}else{var f=10}for(var p=0;p<t.length;p++){var j=t[p][0]-r;var h=t[p][1];if(this.prefs.mode=="Intensity"){if(h===null){continue}j=j*e;if(h<=l){h=l}else{if(h>=g){h=g}}h=255-Math.floor((h-l)/m*255);n.fillStyle="rgb("+h+","+h+","+h+")";n.fillRect(j,0,f,this.height_px)}else{if(h===null){k=false;continue}else{j=j*e;if(h<=l){h=l}else{if(h>=g){h=g}}h=Math.round(d-(h-l)/m*d);if(k){n.lineTo(j,h)}else{n.moveTo(j,h);k=true}}}}n.stroke();c!
.append(b);return b},gen_options:function(n){var a=$("<div></div>").ad
dClass("form-row");var h="track_"+n+"_minval",k="track_"+n+"_maxval",e="track_"+n+"_mode",l=$("<label></label>").attr("for",h).text("Min value:"),b=(this.prefs.min_value===undefined?"":this.prefs.min_value),m=$("<input></input>").attr("id",h).val(b),g=$("<label></label>").attr("for",k).text("Max value:"),j=(this.prefs.max_value===undefined?"":this.prefs.max_value),f=$("<input></input>").attr("id",k).val(j),d=$("<label></label>").attr("for",e).text("Display mode:"),i=(this.prefs.mode===undefined?"Line":this.prefs.mode),c=$('<select id="'+e+'"><option value="Line" id="mode_Line">Line</option><option value="Intensity" id="mode_Intensity">Intensity</option></select>');c.children("#mode_"+i).attr("selected","selected");return a.append(l).append(m).append(g).append(f).append(d).append(c)},update_options:function(d){var a=$("#track_"+d+"_minval").val(),c=$("#track_"+d+"_maxval").val(),b=$("#track_"+d+"_mode option:selected").val();if(a!==this.prefs.min_value||c!==this.prefs.max_val!
ue||b!=this.prefs.mode){this.prefs.min_value=parseFloat(a);this.prefs.max_value=parseFloat(c);this.prefs.mode=b;this.vertical_range=this.prefs.max_value-this.prefs.min_value;$("#linetrack_"+d+"_minval").text(this.prefs.min_value);$("#linetrack_"+d+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.draw()}}});var FeatureTrack=function(c,a,b){this.track_type="FeatureTrack";Track.call(this,c,$("#viewport"));TiledTrack.call(this);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.tile_cache=new Cache(CACHED_TILES_FEATURE);this.data_cache=new Cache(20);this.prefs={block_color:"black",label_color:"black",show_counts:false};if(b.block_color!==undefined){this.prefs.block_!
color=b.block_color}if(b.label_color!==undefined){this.prefs.label_col
or=b.label_color}if(b.show_counts!==undefined){this.prefs.show_counts=b.show_counts}};$.extend(FeatureTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b=a.view.max_low+"_"+a.view.max_high;this.init_each({low:a.view.max_low,high:a.view.max_high,dataset_id:a.dataset_id,chrom:a.view.chrom,resolution:this.view.resolution},function(c){a.data_cache.set(b,c);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,{chrom:b.view.chrom,low:a,high:d,dataset_id:b.dataset_id,resolution:this.view.resolution},function(e){b.data_cache.set(c,e);delete b.data_queue[c];b.draw()})}},incremental_slots:function(a,g,c){if(!this.inc_slots[a]){this.inc_slots[a]={};this.inc_slots[a].w_scale=1/a;this.s_e_by_tile[a]={}}var m=this.inc_slots[a].w_scale,v=[],h=0,b=$("<canvas></canvas>").get(0).getContext("2d"),n=this.view.max_low;var d,f,x=[];for(var s=0,t=g.length;s<t;s++){var e=g[s],l=e[0];if(this.inc_slots[a][l]!==undefined){h!
=Math.max(h,this.inc_slots[a][l]);x.push(this.inc_slots[a][l])}else{v.push(s)}}for(var s=0,t=v.length;s<t;s++){var e=g[v[s]];l=e[0],feature_start=e[1],feature_end=e[2],feature_name=e[3];d=Math.floor((feature_start-n)*m);f=Math.ceil((feature_end-n)*m);if(!c){var p=b.measureText(feature_name).width;if(d-p<0){f+=p}else{d-=p}}var r=0;while(true){var o=true;if(this.s_e_by_tile[a][r]!==undefined){for(var q=0,w=this.s_e_by_tile[a][r].length;q<w;q++){var u=this.s_e_by_tile[a][r][q];if(f>u[0]&&d<u[1]){o=false;break}}}if(o){if(this.s_e_by_tile[a][r]===undefined){this.s_e_by_tile[a][r]=[]}this.s_e_by_tile[a][r].push([d,f]);this.inc_slots[a][l]=r;h=Math.max(h,r);break}r++}}return h},rect_or_text:function(n,o,g,f,m,b,d,k,e,i){n.textAlign="center";var j=Math.round(o/2);if(d!==undefined&&o>g){n.fillStyle="#555";n.fillRect(k,i+1,e,9);n.fillStyle="#eee";for(var h=0,l=d.length;h<l;h++){if(b+h>=f&&b+h<=m){var a=Math.floor(Math.max(0,(b+h-f)*o));n.fillText(d[h],a+this.left_offset+j,i+9)}}}else!
{n.fillStyle="#555";n.fillRect(k,i+4,e,3)}},draw_tile:function(W,h,m,a
k){var D=h*DENSITY*W,ac=(h+1)*DENSITY*W,C=DENSITY*W;var aj,r;var ad=D+"_"+ac;var w=this.data_cache.get(ad);if(w===undefined){this.data_queue[[D,ac]]=true;this.get_data(D,ac);return}if(w.dataset_type==="summary_tree"){r=30}else{var U=(w.extra_info==="no_detail");var al=(U?this.vertical_nodetail_px:this.vertical_detail_px);r=this.incremental_slots(this.view.zoom_res,w.data,U)*al+15;m.parent().css("height",Math.max(this.height_px,r)+"px");aj=this.inc_slots[this.view.zoom_res]}var a=Math.ceil(C*ak),K=$("<canvas class='tile'></canvas>"),Y=this.prefs.label_color,f=this.prefs.block_color,O=this.left_offset;K.css({position:"absolute",top:0,left:(D-this.view.low)*ak-O});K.get(0).width=a+O;K.get(0).height=r;var z=K.get(0).getContext("2d"),ah=z.measureText("A").width;z.fillStyle=this.prefs.block_color;z.font=this.default_font;z.textAlign="right";if(w.dataset_type=="summary_tree"){var J,G=55,ab=255-G,g=ab*2/3,Q=w.data,B=w.max,l=w.avg;if(Q.length>2){var b=Math.ceil((Q[1][0]-Q[0][0])*ak)}!
else{var b=50}for(var af=0,v=Q.length;af<v;af++){var S=Math.ceil((Q[af][0]-D)*ak);var R=Q[af][1];if(!R){continue}J=Math.floor(ab-(R/B)*ab);z.fillStyle="rgb("+J+","+J+","+J+")";z.fillRect(S+O,0,b,20);if(this.prefs.show_counts){if(J>g){z.fillStyle="black"}else{z.fillStyle="#ddd"}z.textAlign="center";z.fillText(Q[af][1],S+O+(b/2),12)}}m.append(K);return K}var ai=w.data;var ae=0;for(var af=0,v=ai.length;af<v;af++){var L=ai[af],I=L[0],ag=L[1],T=L[2],E=L[3];if(ag<=ac&&T>=D){var V=Math.floor(Math.max(0,(ag-D)*ak)),A=Math.ceil(Math.min(a,Math.max(0,(T-D)*ak))),P=aj[I]*al;if(w.dataset_type==="bai"){z.fillStyle="#555";if(L[4] instanceof Array){var s=Math.floor(Math.max(0,(L[4][0]-D)*ak)),H=Math.ceil(Math.min(a,Math.max(0,(L[4][1]-D)*ak))),q=Math.floor(Math.max(0,(L[5][0]-D)*ak)),o=Math.ceil(Math.min(a,Math.max(0,(L[5][1]-D)*ak)));if(L[4][1]>=D&&L[4][0]<=ac){this.rect_or_text(z,ak,ah,D,ac,L[4][0],L[4][2],s+O,H-s,P)}if(L[5][1]>=D&&L[5][0]<=ac){this.rect_or_text(z,ak,ah,D,ac,L[5][0],L[5!
][2],q+O,o-q,P)}if(q>H){z.fillStyle="#999";z.fillRect(H+O,P+5,q-H,1)}}
else{z.fillStyle="#555";this.rect_or_text(z,ak,ah,D,ac,ag,E,V+O,A-V,P)}if(!U&&ag>D){z.fillStyle=this.prefs.label_color;if(h===0&&V-z.measureText(E).width<0){z.textAlign="left";z.fillText(I,A+2+O,P+8)}else{z.textAlign="right";z.fillText(I,V-2+O,P+8)}z.fillStyle="#555"}}else{if(w.dataset_type==="interval_index"){if(U){z.fillRect(V+O,P+5,A-V,1)}else{var u=L[4],N=L[5],X=L[6],e=L[7];var t,Z,F=null,am=null;if(N&&X){F=Math.floor(Math.max(0,(N-D)*ak));am=Math.ceil(Math.min(a,Math.max(0,(X-D)*ak)))}if(E!==undefined&&ag>D){z.fillStyle=Y;if(h===0&&V-z.measureText(E).width<0){z.textAlign="left";z.fillText(E,A+2+O,P+8)}else{z.textAlign="right";z.fillText(E,V-2+O,P+8)}z.fillStyle=f}if(e){if(u){if(u=="+"){z.fillStyle=RIGHT_STRAND}else{if(u=="-"){z.fillStyle=LEFT_STRAND}}z.fillRect(V+O,P,A-V,10);z.fillStyle=f}for(var ad=0,d=e.length;ad<d;ad++){var n=e[ad],c=Math.floor(Math.max(0,(n[0]-D)*ak)),M=Math.ceil(Math.min(a,Math.max((n[1]-D)*ak)));if(c>M){continue}t=5;Z=3;z.fillRect(c+O,P+Z,M-c,t);i!
f(F!==undefined&&!(c>am||M<F)){t=9;Z=1;var aa=Math.max(c,F),p=Math.min(M,am);z.fillRect(aa+O,P+Z,p-aa,t)}}}else{t=9;Z=1;z.fillRect(V+O,P+Z,A-V,t);if(L.strand){if(L.strand=="+"){z.fillStyle=RIGHT_STRAND_INV}else{if(L.strand=="-"){z.fillStyle=LEFT_STRAND_INV}}z.fillRect(V+O,P,A-V,10);z.fillStyle=prefs.block_color}}}}}ae++}}m.append(K);return K},gen_options:function(i){var a=$("<div></div>").addClass("form-row");var e="track_"+i+"_block_color",k=$("<label></label>").attr("for",e).text("Block color:"),l=$("<input></input>").attr("id",e).attr("name",e).val(this.prefs.block_color),j="track_"+i+"_label_color",g=$("<label></label>").attr("for",j).text("Text color:"),h=$("<input></input>").attr("id",j).attr("name",j).val(this.prefs.label_color),f="track_"+i+"_show_count",c=$("<label></label>").attr("for",f).text("Show summary counts"),b=$('<input type="checkbox" style="float:left;"></input>').attr("id",f).attr("name",f).attr("checked",this.prefs.show_counts),d=$("<div></div>").appen!
d(b).append(c);return a.append(k).append(l).append(g).append(h).append
(d)},update_options:function(d){var b=$("#track_"+d+"_block_color").val(),c=$("#track_"+d+"_label_color").val(),a=$("#track_"+d+"_show_count").attr("checked");if(b!==this.prefs.block_color||c!==this.prefs.label_color||a!=this.prefs.show_counts){this.prefs.block_color=b;this.prefs.label_color=c;this.prefs.show_counts=a;this.tile_cache.clear();this.draw()}}});var ReadTrack=function(c,a,b){FeatureTrack.call(this,c,a,b);this.track_type="ReadTrack";this.vertical_detail_px=10;this.vertical_nodetail_px=5};$.extend(ReadTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype,{});
\ No newline at end of file
+var DEBUG=false;var DENSITY=200,FEATURE_LEVELS=10,DATA_ERROR="There was an error in indexing this dataset.",DATA_NOCONVERTER="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",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=5,CONTEXT=$("<canvas></canvas>").get(0).getContext("2d"),RIGHT_STRAND,LEFT_STRAND;var right_img=new Image();right_img.src="/static/images/visualization/strand_right.png";right_img.onload=function(){RIGHT_STRAND=CONTEXT.createPattern(right_img,"repeat")};var left_img=new Image();left_img.src="/static/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="/static/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="/static/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.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 Drawer=function(){};$.extend(Drawer.prototype,{intensity:function(b,a,c){},});drawer=new Drawer();var View=function(b,d,c,a){this.vis_id=c;this.dbkey=a;this.title=d;this.chrom=b;this.tracks=[];this.label_tracks=[];this.m!
ax_low=0;this.max_high=0;this.center=(this.max_high-this.max_low)/2;th
is.zoom_factor=3;this.zoom_level=0;this.track_id_counter=0};$.extend(View.prototype,{add_track:function(a){a.view=this;a.track_id=this.track_id_counter;this.tracks.push(a);if(a.init){a.init()}a.container_div.attr("id","track_"+a.track_id);this.track_id_counter+=1},add_label_track:function(a){a.view=this;this.label_tracks.push(a)},remove_track:function(a){a.container_div.fadeOut("slow",function(){$(this).remove()});delete this.tracks[a]},update_options:function(){var b=$("ul#sortable-ul").sortable("toArray");var d=[];var c=$("#viewport > div").sort(function(g,f){return b.indexOf($(g).attr("id"))>b.indexOf($(f).attr("id"))});$("#viewport > div").remove();$("#viewport").html(c);for(var e in view.tracks){var a=view.tracks[e];if(a.update_options){a.update_options(e)}}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.center=this.center=(this.max_high-this.max_low)/2;this.zoom_level=0;$(".yaxislabel").remove()},redraw:function(f){this.span=this.max_high-this.max!
_low;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)/200)/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));if(!f){for(var c=0,a=this.tracks.length;c<a;c++){if(this.tracks[c].enabled){this.tracks[c].draw()}}for(var c=0,a=this.label_tracks.length;c<a;c++){this.label_tracks[c].draw()}}},zoom_in:function(a,b){if(this.max_high===0||this.high-this.low<30){return}if(a){this.center=!
a/b.width()*(this.high-this.low)+this.low}this.zoom_level+=1;this.redr
aw()},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.init_global()};$.extend(Track.prototype,{init_global:function(){this.header_div=$("<div class='track-header'>").text(this.name);this.content_div=$("<div class='track-content'>");this.container_div=$("<div></div>").addClass("track").append(this.header_div).append(this.content_div);this.parent_element.append(this.container_div)},init_each:function(c,b){var a=this;a.enabled=false;a.data_queue={};a.tile_cache.clear();a.data_cache.clear();a.content_div.css("height","30px");if(!a.content_div.text()){a.content_div.text(DATA_LOADING)}a.container_div.removeClass("nodata error pending");if(a.view.chrom){$.getJSON(data_url,c,function(d){if(!d||d==="error"){a.container_div.addClass("error");a.content_div.text(DATA_ERROR)}else{if(d==="no converter"){a.container_div.addClass("error");a.cont!
ent_div.text(DATA_NOCONVERTER)}else{if(d.data&&d.data.length===0||d.data===null){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");a.enabled=true;b(d);a.draw()}}}}})}else{a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}}});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>"),l=this.content_div.width()/f,h;this.content_div.children(":first").remove();this.content_div.append(k),this.max_height=0;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_of
fset}c.css({left:b});k.append(c);this.max_height=Math.max(this.max_height,c.height());this.content_div.css("height",this.max_height+"px")}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+"px")}}},50)}});var LabelTrack=function(a){Track.call(this,null,a);this.track_type="LabelTrack";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.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,a,b){this.track_type="LineTrack";Track.call(this,c,$("#viewport"));TiledTrack.call(this);this.height_px=100;this.container_div.addClass("line-track");this.dataset_id=a;this.data_cache=new Cache(CACHED_DATA);this.tile_cache=new Cache(CACHED_TILES_LINE);this.prefs={min_value:undefined,max_value:undefined,mode:"Line"};if(b.min_value!==undefined){this.prefs.min_value=b.min_value}if(b.max_value!==undefined){this.prefs.max_value=b.max_value}if(b.mode!==undefined){this.prefs.mode=b.mode}};$.extend(LineTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b=a.view.tracks.indexOf(a);a.vertical_range=undefined;this.init_each({stats:true,chrom:a.view.chrom,low:null,high:null,dataset_id:a.dataset_id},function(c){data=c.data;if(isNaN(parseFloat(a.prefs.min_value))||isNaN(parseFloat(a.prefs.max_value))){a.prefs.min_value=data.min;a.prefs.ma!
x_value=data.max;$("#track_"+b+"_minval").val(a.prefs.min_value);$("#t
rack_"+b+"_maxval").val(a.prefs.max_value)}a.vertical_range=a.prefs.max_value-a.prefs.min_value;a.total_frequency=data.total_frequency;$("#linetrack_"+b+"_minval").remove();$("#linetrack_"+b+"_maxval").remove();var e=$("<div></div>").addClass("yaxislabel").attr("id","linetrack_"+b+"_minval").text(a.prefs.min_value);var d=$("<div></div>").addClass("yaxislabel").attr("id","linetrack_"+b+"_maxval").text(a.prefs.max_value);d.css({position:"relative",top:"25px"});d.prependTo(a.container_div);e.css({position:"relative",top:a.height_px+55+"px"});e.prependTo(a.container_div)})},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;$.ajax({url:data_url,dataType:"json",data:{chrom:this.view.chrom,low:a,high:f,dataset_id:this.dataset_id,resolution:this.view.resolution},success:function(g){data=g.data;c.data_cache.set(e,data);delete c.data_queue[e];c.draw()},error:function(h,g,i){console.log(h,g,i)}})}},draw_tile:function(o!
,q,c,e){if(this.vertical_range===undefined){return}var r=q*DENSITY*o,a=DENSITY*o,b=$("<canvas class='tile'></canvas>"),u=o+"_"+q;if(this.data_cache.get(u)===undefined){this.get_data(o,q);return}var t=this.data_cache.get(u);if(t===null){return}b.css({position:"absolute",top:0,left:(r-this.view.low)*e});b.get(0).width=Math.ceil(a*e);b.get(0).height=this.height_px;var n=b.get(0).getContext("2d"),k=false,l=this.prefs.min_value,g=this.prefs.max_value,m=this.vertical_range,s=this.total_frequency,d=this.height_px;n.beginPath();if(t.length>1){var f=Math.ceil((t[1][0]-t[0][0])*e)}else{var f=10}for(var p=0;p<t.length;p++){var j=t[p][0]-r;var h=t[p][1];if(this.prefs.mode=="Intensity"){if(h===null){continue}j=j*e;if(h<=l){h=l}else{if(h>=g){h=g}}h=255-Math.floor((h-l)/m*255);n.fillStyle="rgb("+h+","+h+","+h+")";n.fillRect(j,0,f,this.height_px)}else{if(h===null){k=false;continue}else{j=j*e;if(h<=l){h=l}else{if(h>=g){h=g}}h=Math.round(d-(h-l)/m*d);if(k){n.lineTo(j,h)}else{n.moveTo(j,h);k=!
true}}}}n.stroke();c.append(b);return b},gen_options:function(n){var a
=$("<div></div>").addClass("form-row");var h="track_"+n+"_minval",k="track_"+n+"_maxval",e="track_"+n+"_mode",l=$("<label></label>").attr("for",h).text("Min value:"),b=(this.prefs.min_value===undefined?"":this.prefs.min_value),m=$("<input></input>").attr("id",h).val(b),g=$("<label></label>").attr("for",k).text("Max value:"),j=(this.prefs.max_value===undefined?"":this.prefs.max_value),f=$("<input></input>").attr("id",k).val(j),d=$("<label></label>").attr("for",e).text("Display mode:"),i=(this.prefs.mode===undefined?"Line":this.prefs.mode),c=$('<select id="'+e+'"><option value="Line" id="mode_Line">Line</option><option value="Intensity" id="mode_Intensity">Intensity</option></select>');c.children("#mode_"+i).attr("selected","selected");return a.append(l).append(m).append(g).append(f).append(d).append(c)},update_options:function(d){var a=$("#track_"+d+"_minval").val(),c=$("#track_"+d+"_maxval").val(),b=$("#track_"+d+"_mode option:selected").val();if(a!==this.prefs.min_value||c!!
==this.prefs.max_value||b!=this.prefs.mode){this.prefs.min_value=parseFloat(a);this.prefs.max_value=parseFloat(c);this.prefs.mode=b;this.vertical_range=this.prefs.max_value-this.prefs.min_value;$("#linetrack_"+d+"_minval").text(this.prefs.min_value);$("#linetrack_"+d+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.draw()}}});var FeatureTrack=function(c,a,b){this.track_type="FeatureTrack";Track.call(this,c,$("#viewport"));TiledTrack.call(this);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.tile_cache=new Cache(CACHED_TILES_FEATURE);this.data_cache=new Cache(20);this.prefs={block_color:"black",label_color:"black",show_counts:false};if(b.block_color!==undefine!
d){this.prefs.block_color=b.block_color}if(b.label_color!==undefined){
this.prefs.label_color=b.label_color}if(b.show_counts!==undefined){this.prefs.show_counts=b.show_counts}};$.extend(FeatureTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b=a.view.max_low+"_"+a.view.max_high;this.init_each({low:a.view.max_low,high:a.view.max_high,dataset_id:a.dataset_id,chrom:a.view.chrom,resolution:this.view.resolution},function(c){a.data_cache.set(b,c);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,{chrom:b.view.chrom,low:a,high:d,dataset_id:b.dataset_id,resolution:this.view.resolution},function(e){b.data_cache.set(c,e);delete b.data_queue[c];b.draw()})}},incremental_slots:function(a,g,c){if(!this.inc_slots[a]){this.inc_slots[a]={};this.inc_slots[a].w_scale=1/a;this.s_e_by_tile[a]={}}var m=this.inc_slots[a].w_scale,v=[],h=0,b=$("<canvas></canvas>").get(0).getContext("2d"),n=this.view.max_low;var d,f,x=[];for(var s=0,t=g.length;s<t;s++){var e=g[s],l=e[0];if(this.inc_slots[!
a][l]!==undefined){h=Math.max(h,this.inc_slots[a][l]);x.push(this.inc_slots[a][l])}else{v.push(s)}}for(var s=0,t=v.length;s<t;s++){var e=g[v[s]];l=e[0],feature_start=e[1],feature_end=e[2],feature_name=e[3];d=Math.floor((feature_start-n)*m);f=Math.ceil((feature_end-n)*m);if(!c){var p=b.measureText(feature_name).width;if(d-p<0){f+=p}else{d-=p}}var r=0;while(true){var o=true;if(this.s_e_by_tile[a][r]!==undefined){for(var q=0,w=this.s_e_by_tile[a][r].length;q<w;q++){var u=this.s_e_by_tile[a][r][q];if(f>u[0]&&d<u[1]){o=false;break}}}if(o){if(this.s_e_by_tile[a][r]===undefined){this.s_e_by_tile[a][r]=[]}this.s_e_by_tile[a][r].push([d,f]);this.inc_slots[a][l]=r;h=Math.max(h,r);break}r++}}return h},rect_or_text:function(n,o,g,f,m,b,d,k,e,i){n.textAlign="center";var j=Math.round(o/2);if(d!==undefined&&o>g){n.fillStyle="#555";n.fillRect(k,i+1,e,9);n.fillStyle="#eee";for(var h=0,l=d.length;h<l;h++){if(b+h>=f&&b+h<=m){var a=Math.floor(Math.max(0,(b+h-f)*o));n.fillText(d[h],a+this.left_!
offset+j,i+9)}}}else{n.fillStyle="#555";n.fillRect(k,i+4,e,3)}},draw_t
ile:function(W,h,m,ak){var D=h*DENSITY*W,ac=(h+1)*DENSITY*W,C=DENSITY*W;var aj,r;var ad=D+"_"+ac;var w=this.data_cache.get(ad);if(w===undefined){this.data_queue[[D,ac]]=true;this.get_data(D,ac);return}if(w.dataset_type==="summary_tree"){r=30}else{var U=(w.extra_info==="no_detail");var al=(U?this.vertical_nodetail_px:this.vertical_detail_px);r=this.incremental_slots(this.view.zoom_res,w.data,U)*al+15;m.parent().css("height",Math.max(this.height_px,r)+"px");aj=this.inc_slots[this.view.zoom_res]}var a=Math.ceil(C*ak),K=$("<canvas class='tile'></canvas>"),Y=this.prefs.label_color,f=this.prefs.block_color,O=this.left_offset;K.css({position:"absolute",top:0,left:(D-this.view.low)*ak-O});K.get(0).width=a+O;K.get(0).height=r;var z=K.get(0).getContext("2d"),ah=z.measureText("A").width;z.fillStyle=this.prefs.block_color;z.font=this.default_font;z.textAlign="right";if(w.dataset_type=="summary_tree"){var J,G=55,ab=255-G,g=ab*2/3,Q=w.data,B=w.max,l=w.avg;if(Q.length>2){var b=Math.ceil((Q!
[1][0]-Q[0][0])*ak)}else{var b=50}for(var af=0,v=Q.length;af<v;af++){var S=Math.ceil((Q[af][0]-D)*ak);var R=Q[af][1];if(!R){continue}J=Math.floor(ab-(R/B)*ab);z.fillStyle="rgb("+J+","+J+","+J+")";z.fillRect(S+O,0,b,20);if(this.prefs.show_counts){if(J>g){z.fillStyle="black"}else{z.fillStyle="#ddd"}z.textAlign="center";z.fillText(Q[af][1],S+O+(b/2),12)}}m.append(K);return K}var ai=w.data;var ae=0;for(var af=0,v=ai.length;af<v;af++){var L=ai[af],I=L[0],ag=L[1],T=L[2],E=L[3];if(ag<=ac&&T>=D){var V=Math.floor(Math.max(0,(ag-D)*ak)),A=Math.ceil(Math.min(a,Math.max(0,(T-D)*ak))),P=aj[I]*al;if(w.dataset_type==="bai"){z.fillStyle="#555";if(L[4] instanceof Array){var s=Math.floor(Math.max(0,(L[4][0]-D)*ak)),H=Math.ceil(Math.min(a,Math.max(0,(L[4][1]-D)*ak))),q=Math.floor(Math.max(0,(L[5][0]-D)*ak)),o=Math.ceil(Math.min(a,Math.max(0,(L[5][1]-D)*ak)));if(L[4][1]>=D&&L[4][0]<=ac){this.rect_or_text(z,ak,ah,D,ac,L[4][0],L[4][2],s+O,H-s,P)}if(L[5][1]>=D&&L[5][0]<=ac){this.rect_or_text(z,ak!
,ah,D,ac,L[5][0],L[5][2],q+O,o-q,P)}if(q>H){z.fillStyle="#999";z.fillR
ect(H+O,P+5,q-H,1)}}else{z.fillStyle="#555";this.rect_or_text(z,ak,ah,D,ac,ag,E,V+O,A-V,P)}if(!U&&ag>D){z.fillStyle=this.prefs.label_color;if(h===0&&V-z.measureText(E).width<0){z.textAlign="left";z.fillText(I,A+2+O,P+8)}else{z.textAlign="right";z.fillText(I,V-2+O,P+8)}z.fillStyle="#555"}}else{if(w.dataset_type==="interval_index"){if(U){z.fillRect(V+O,P+5,A-V,1)}else{var u=L[4],N=L[5],X=L[6],e=L[7];var t,Z,F=null,am=null;if(N&&X){F=Math.floor(Math.max(0,(N-D)*ak));am=Math.ceil(Math.min(a,Math.max(0,(X-D)*ak)))}if(E!==undefined&&ag>D){z.fillStyle=Y;if(h===0&&V-z.measureText(E).width<0){z.textAlign="left";z.fillText(E,A+2+O,P+8)}else{z.textAlign="right";z.fillText(E,V-2+O,P+8)}z.fillStyle=f}if(e){if(u){if(u=="+"){z.fillStyle=RIGHT_STRAND}else{if(u=="-"){z.fillStyle=LEFT_STRAND}}z.fillRect(V+O,P,A-V,10);z.fillStyle=f}for(var ad=0,d=e.length;ad<d;ad++){var n=e[ad],c=Math.floor(Math.max(0,(n[0]-D)*ak)),M=Math.ceil(Math.min(a,Math.max((n[1]-D)*ak)));if(c>M){continue}t=5;Z=3;z.fillR!
ect(c+O,P+Z,M-c,t);if(F!==undefined&&!(c>am||M<F)){t=9;Z=1;var aa=Math.max(c,F),p=Math.min(M,am);z.fillRect(aa+O,P+Z,p-aa,t)}}}else{t=9;Z=1;z.fillRect(V+O,P+Z,A-V,t);if(L.strand){if(L.strand=="+"){z.fillStyle=RIGHT_STRAND_INV}else{if(L.strand=="-"){z.fillStyle=LEFT_STRAND_INV}}z.fillRect(V+O,P,A-V,10);z.fillStyle=prefs.block_color}}}}}ae++}}m.append(K);return K},gen_options:function(i){var a=$("<div></div>").addClass("form-row");var e="track_"+i+"_block_color",k=$("<label></label>").attr("for",e).text("Block color:"),l=$("<input></input>").attr("id",e).attr("name",e).val(this.prefs.block_color),j="track_"+i+"_label_color",g=$("<label></label>").attr("for",j).text("Text color:"),h=$("<input></input>").attr("id",j).attr("name",j).val(this.prefs.label_color),f="track_"+i+"_show_count",c=$("<label></label>").attr("for",f).text("Show summary counts"),b=$('<input type="checkbox" style="float:left;"></input>').attr("id",f).attr("name",f).attr("checked",this.prefs.show_counts),d=$(!
"<div></div>").append(b).append(c);return a.append(k).append(l).append
(g).append(h).append(d)},update_options:function(d){var b=$("#track_"+d+"_block_color").val(),c=$("#track_"+d+"_label_color").val(),a=$("#track_"+d+"_show_count").attr("checked");if(b!==this.prefs.block_color||c!==this.prefs.label_color||a!=this.prefs.show_counts){this.prefs.block_color=b;this.prefs.label_color=c;this.prefs.show_counts=a;this.tile_cache.clear();this.draw()}}});var ReadTrack=function(c,a,b){FeatureTrack.call(this,c,a,b);this.track_type="ReadTrack";this.vertical_detail_px=10;this.vertical_nodetail_px=5};$.extend(ReadTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype,{});
\ No newline at end of file
1
0

10 May '10
details: http://www.bx.psu.edu/hg/galaxy/rev/2cf1ad5edaa6
changeset: 3732:2cf1ad5edaa6
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Mon May 03 14:02:08 2010 -0400
description:
Enable viewing of shared/accessible/published visualizations.
diffstat:
lib/galaxy/web/base/controller.py | 38 ++++
lib/galaxy/web/controllers/visualization.py | 8 +-
static/scripts/trackster.js | 8 +-
templates/visualization/display.mako | 219 +++++++++++++++++++++++++++-
4 files changed, 263 insertions(+), 10 deletions(-)
diffs (349 lines):
diff -r 5f93447d642d -r 2cf1ad5edaa6 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py Mon May 03 09:42:51 2010 -0400
+++ b/lib/galaxy/web/base/controller.py Mon May 03 14:02:08 2010 -0400
@@ -7,6 +7,7 @@
from galaxy.web import error, form, url_for
from galaxy.model.orm import *
from galaxy.workflow.modules import *
+from galaxy.web.framework import simplejson
from Cheetah.Template import Template
@@ -164,6 +165,7 @@
class UsesVisualization( SharableItemSecurity ):
""" Mixin for controllers that use Visualization objects. """
+
def get_visualization( self, trans, id, check_ownership=True, check_accessible=False ):
""" Get a Visualization from the database by id, verifying ownership. """
# Load workflow from database
@@ -173,6 +175,42 @@
error( "Visualization not found" )
else:
return self.security_check( trans.get_user(), visualization, check_ownership, check_accessible )
+
+ def get_visualization_config( self, trans, visualization ):
+ """ Returns a visualization's configuration. Only works for trackster visualizations right now. """
+
+ config = None
+ if visualization.type == 'trackster':
+ # Trackster config; taken from tracks/browser
+ latest_revision = visualization.latest_revision
+ tracks = []
+
+ try:
+ dbkey = latest_revision.config['dbkey']
+ except KeyError:
+ dbkey = None
+
+ hda_query = trans.sa_session.query( trans.model.HistoryDatasetAssociation )
+ for t in visualization.latest_revision.config['tracks']:
+ dataset_id = t['dataset_id']
+ try:
+ prefs = t['prefs']
+ except KeyError:
+ prefs = {}
+ dataset = hda_query.get( dataset_id )
+ track_type, _ = dataset.datatype.get_track_type()
+ tracks.append( {
+ "track_type": track_type,
+ "name": dataset.name,
+ "dataset_id": dataset.id,
+ "prefs": simplejson.dumps(prefs),
+ } )
+ if dbkey is None: dbkey = dataset.dbkey # Hack for backward compat
+
+ ## TODO: chrom needs to be able to be set; right now it's empty.
+ config = { "title": visualization.title, "vis_id": id, "tracks": tracks, "chrom": "", "dbkey": dbkey }
+
+ return config
class UsesStoredWorkflow( SharableItemSecurity ):
""" Mixin for controllers that use StoredWorkflow objects. """
diff -r 5f93447d642d -r 2cf1ad5edaa6 lib/galaxy/web/controllers/visualization.py
--- a/lib/galaxy/web/controllers/visualization.py Mon May 03 09:42:51 2010 -0400
+++ b/lib/galaxy/web/controllers/visualization.py Mon May 03 14:02:08 2010 -0400
@@ -256,9 +256,13 @@
visualization = trans.sa_session.query( model.Visualization ).filter_by( user=user, slug=slug, deleted=False ).first()
if visualization is None:
raise web.httpexceptions.HTTPNotFound()
+
# Security check raises error if user cannot access visualization.
- self.security_check( trans.get_user(), visualization, False, True)
- return trans.fill_template_mako( "visualization/display.mako", item=visualization, item_data=None, content_only=True )
+ self.security_check( trans.get_user(), visualization, False, True)
+
+ # Display.
+ visualization_config = self.get_visualization_config( trans, visualization )
+ return trans.fill_template_mako( "visualization/display.mako", item=visualization, item_data=visualization_config, content_only=True )
@web.expose
@web.json
diff -r 5f93447d642d -r 2cf1ad5edaa6 static/scripts/trackster.js
--- a/static/scripts/trackster.js Mon May 03 09:42:51 2010 -0400
+++ b/static/scripts/trackster.js Mon May 03 14:02:08 2010 -0400
@@ -17,22 +17,22 @@
RIGHT_STRAND, LEFT_STRAND;
var right_img = new Image();
-right_img.src = "../images/visualization/strand_right.png";
+right_img.src = "/static/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.src = "/static/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.src = "/static/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.src = "/static/images/visualization/strand_left_inv.png";
left_img_inv.onload = function() {
LEFT_STRAND_INV = CONTEXT.createPattern(left_img_inv, "repeat");
};
diff -r 5f93447d642d -r 2cf1ad5edaa6 templates/visualization/display.mako
--- a/templates/visualization/display.mako Mon May 03 09:42:51 2010 -0400
+++ b/templates/visualization/display.mako Mon May 03 14:02:08 2010 -0400
@@ -2,18 +2,229 @@
<%def name="javascripts()">
${parent.javascripts()}
- ## Need visualization JS.
+ ${h.js( "jquery.event.drag", "jquery.autocomplete", "jquery.mousewheel", "trackster", "ui.core", "ui.sortable" )}
+
+ ## HACK: set config as item_data.
+ <% config = item_data %>
+
+ ## TODO: Copied from browser.mako -- probably should create JS file for visualization code and include visualization JS above.
+ <script type="text/javascript">
+
+ ## JG: add controller name.
+ var data_url = "${h.url_for( controller='/tracks', action='data' )}";
+ var view;
+
+ $(function() {
+
+ %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['prefs']} )
+ );
+ %endfor
+ init();
+ %else:
+ continue_fn = function() {
+ view = new View( undefined, $("#new-title").val(), undefined, $("#new-dbkey").val() );
+ init();
+ hide_modal();
+ };
+ $.ajax({
+ url: "${h.url_for( action='new_browser' )}",
+ data: {},
+ error: function() { alert( "Couldn't create new browser" ) },
+ success: function(form_html) {
+ show_modal("New Track Browser", form_html, {
+ "Cancel": function() { window.location = "/"; },
+ "Continue": function() { $(document).trigger("convert_dbkeys"); continue_fn(); }
+ });
+ $("#new-title").focus();
+ replace_big_select_inputs();
+ }
+ });
+ %endif
+
+ // 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];
+ }
+ }
+ });
+
+ $(document).bind( "redraw", function( e ) {
+ view.redraw();
+ });
+
+ $("#content").bind("mousewheel", function( e, delta ) {
+ if (delta > 0) {
+ view.zoom_in(e.pageX, $("#viewport-container"));
+ } else {
+ view.zoom_out();
+ }
+ e.preventDefault();
+ });
+
+ $("#content").bind("dblclick", function( e ) {
+ view.zoom_in(e.pageX, $("#viewport-container"));
+ });
+
+ // 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 ) {
+ $("#viewport-container").height( $(window).height() - 120 );
+ $("#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-container").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);
+ 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();
+ });
+
+ ## JG: Removed 'add-track' init code.
+
+ ## JG: Removed 'save-button' init code
+
+ view.add_label_track( new LabelTrack( $("#top-labeltrack" ) ) );
+ view.add_label_track( new LabelTrack( $("#nav-labeltrack" ) ) );
+
+ $.ajax({
+ ## JG: added controller name
+ url: "${h.url_for( controller='/tracks', action='chroms' )}",
+ data: { dbkey: view.dbkey },
+ dataType: "json",
+ success: function ( data ) {
+ view.chrom_data = data;
+ var chrom_options = '<option value="">Select Chrom/Contig</option>';
+ for (i in data) {
+ var chrom = data[i]['chrom']
+ chrom_options += '<option value="' + chrom + '">' + chrom + '</option>';
+ }
+ $("#chrom").html(chrom_options);
+ $("#chrom").bind( "change", function () {
+ 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.reset();
+ view.redraw(true);
+
+ for (var track_id in view.tracks) {
+ var track = view.tracks[track_id];
+ if (track.init) {
+ track.init();
+ }
+ }
+ view.redraw();
+ });
+ },
+ error: function() {
+ alert( "Could not load chroms for this dbkey:", view.dbkey );
+ }
+ });
+
+ ## JG: Removed function sidebar_box() and sidebar init code.
+
+ $(window).trigger("resize");
+ };
+
+ });
+
+ </script>
+
</%def>
<%def name="stylesheets()">
${parent.stylesheets()}
- ## Need visualization CSS.
+
+ ${h.css( "history" )}
+ <link rel="stylesheet" type="text/css" href="${h.url_for('/static/trackster.css')}" />
+
+ <style type="text/css">
+ ul#sortable-ul {
+ list-style: none;
+ padding: 0;
+ margin: 5px;
+ }
+ ul#sortable-ul li {
+ display: block;
+ margin: 5px 0;
+ background: #eee;
+ }
+ </style>
</%def>
<%def name="render_item_links( visualization )">
## TODO
</%def>
-<%def name="render_item( visualization, visualization_data )">
- ## TODO
+<%def name="render_item( visualization, config )">
+ <br><br>
+ ## Copied from center_panel() in browser.mako -- probably need to create visualization_common.mako to render view.
+ <div id="content">
+ <div id="top-labeltrack"></div>
+ <div id="viewport-container" style="overflow-x: hidden; overflow-y: auto;">
+ <div id="viewport"></div>
+ </div>
+ </div>
+ <div id="nav-container" style="width:100%;">
+ <div id="nav-labeltrack"></div>
+ <div id="nav">
+ <div id="overview">
+ <div id="overview-viewport">
+ <div id="overview-box"></div>
+ </div>
+ </div>
+ <div id="nav-controls">
+ <form action="#">
+ <select id="chrom" name="chrom" style="width: 15em;">
+ <option value="">Loading</option>
+ </select>
+ <input id="low" size="12" />:<input id="high" size="12" />
+ <input type="hidden" name="id" value="${config.get('vis_id', '')}" />
+ <a href="#" onclick="javascript:view.zoom_in();view.redraw();">
+ <img src="${h.url_for('/static/images/fugue/magnifier-zoom.png')}" />
+ </a>
+ <a href="#" onclick="javascript:view.zoom_out();view.redraw();">
+ <img src="${h.url_for('/static/images/fugue/magnifier-zoom-out.png')}" />
+ </a>
+ </form>
+ <div id="debug" style="float: right"></div>
+ </div>
+ </div>
+ </div>
</%def>
\ No newline at end of file
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/5f93447d642d
changeset: 3731:5f93447d642d
user: rc
date: Mon May 03 09:42:51 2010 -0400
description:
forms default value bug fixed
diffstat:
lib/galaxy/web/controllers/forms.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diffs (12 lines):
diff -r e12587356892 -r 5f93447d642d lib/galaxy/web/controllers/forms.py
--- a/lib/galaxy/web/controllers/forms.py Mon May 03 09:34:13 2010 -0400
+++ b/lib/galaxy/web/controllers/forms.py Mon May 03 09:42:51 2010 -0400
@@ -565,7 +565,7 @@
# helptext
self.helptext.value = field['helptext']
# default value
- self.default.value = field.get('default', TextField('field_default_'+str(index), 40, ''))
+ self.default.value = field.get('default', '')
# type
self.fieldtype = SelectField('field_type_'+str(self.index),
refresh_on_change=True,
1
0